summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile-man.am5
-rw-r--r--Makefile.am14
-rw-r--r--TODO2
-rw-r--r--man/machine-id.xml15
-rw-r--r--man/sd_id128_get_machine.xml65
-rw-r--r--man/systemd.exec.xml15
-rw-r--r--man/systemd.network.xml14
-rw-r--r--src/basic/fd-util.c6
-rw-r--r--src/basic/fs-util.c13
-rw-r--r--src/basic/khash.c275
-rw-r--r--src/basic/khash.h53
-rw-r--r--src/basic/missing.h4
-rw-r--r--src/basic/rm-rf.c15
-rw-r--r--src/basic/util.c16
-rw-r--r--src/core/killall.c3
-rw-r--r--src/core/manager.c14
-rw-r--r--src/core/service.c26
-rw-r--r--src/core/service.h2
-rw-r--r--src/delta/delta.c10
-rw-r--r--src/libsystemd-network/network-internal.c34
-rw-r--r--src/libsystemd/libsystemd.sym5
-rw-r--r--src/libsystemd/sd-device/sd-device.c3
-rw-r--r--src/libsystemd/sd-id128/sd-id128.c32
-rw-r--r--src/libsystemd/sd-login/sd-login.c12
-rw-r--r--src/login/logind-dbus.c3
-rw-r--r--src/nspawn/nspawn.c4
-rw-r--r--src/shared/dropin.c17
-rw-r--r--src/shared/fdset.c7
-rw-r--r--src/systemd/sd-id128.h2
-rw-r--r--src/test/test-hash.c82
-rw-r--r--src/test/test-id128.c6
-rw-r--r--src/tmpfiles/tmpfiles.c15
-rw-r--r--src/udev/udev-builtin-net_id.c3
-rw-r--r--src/udev/udev-builtin-path_id.c4
-rw-r--r--src/udev/udev-node.c9
-rw-r--r--src/udev/udev-rules.c4
-rw-r--r--src/udev/udev-watch.c4
-rw-r--r--src/udev/udevadm-info.c4
-rwxr-xr-xtest/networkd-test.py54
40 files changed, 695 insertions, 177 deletions
diff --git a/.gitignore b/.gitignore
index baa975d813..016ba625e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -200,6 +200,7 @@
/test-fs-util
/test-fstab-util
/test-glob-util
+/test-hash
/test-hashmap
/test-hexdecoct
/test-hostname
diff --git a/Makefile-man.am b/Makefile-man.am
index 013e0d7967..228e29fc4f 100644
--- a/Makefile-man.am
+++ b/Makefile-man.am
@@ -397,6 +397,7 @@ MANPAGES_ALIAS += \
man/sd_id128_from_string.3 \
man/sd_id128_get_boot.3 \
man/sd_id128_get_invocation.3 \
+ man/sd_id128_get_machine_app_specific.3 \
man/sd_id128_is_null.3 \
man/sd_id128_t.3 \
man/sd_is_mq.3 \
@@ -750,6 +751,7 @@ man/sd_id128_equal.3: man/sd-id128.3
man/sd_id128_from_string.3: man/sd_id128_to_string.3
man/sd_id128_get_boot.3: man/sd_id128_get_machine.3
man/sd_id128_get_invocation.3: man/sd_id128_get_machine.3
+man/sd_id128_get_machine_app_specific.3: man/sd_id128_get_machine.3
man/sd_id128_is_null.3: man/sd-id128.3
man/sd_id128_t.3: man/sd-id128.3
man/sd_is_mq.3: man/sd_is_fifo.3
@@ -1531,6 +1533,9 @@ man/sd_id128_get_boot.html: man/sd_id128_get_machine.html
man/sd_id128_get_invocation.html: man/sd_id128_get_machine.html
$(html-alias)
+man/sd_id128_get_machine_app_specific.html: man/sd_id128_get_machine.html
+ $(html-alias)
+
man/sd_id128_is_null.html: man/sd-id128.html
$(html-alias)
diff --git a/Makefile.am b/Makefile.am
index 1895e33e05..9bc18d39d6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -943,7 +943,9 @@ libbasic_la_SOURCES = \
src/basic/alloc-util.h \
src/basic/alloc-util.c \
src/basic/format-util.h \
- src/basic/nss-util.h
+ src/basic/nss-util.h \
+ src/basic/khash.h \
+ src/basic/khash.c
nodist_libbasic_la_SOURCES = \
src/basic/errno-from-name.h \
@@ -4082,6 +4084,16 @@ tests += \
test-id128
# ------------------------------------------------------------------------------
+test_hash_SOURCES = \
+ src/test/test-hash.c
+
+test_hash_LDADD = \
+ libsystemd-shared.la
+
+tests += \
+ test-hash
+
+# ------------------------------------------------------------------------------
bin_PROGRAMS += \
systemd-socket-activate
diff --git a/TODO b/TODO
index 74183b5f47..00d1cd01fa 100644
--- a/TODO
+++ b/TODO
@@ -23,8 +23,6 @@ External:
Janitorial Clean-ups:
-* replace manual readdir() loops with FOREACH_DIRENT or FOREACH_DIRENT_ALL
-
* Rearrange tests so that the various test-xyz.c match a specific src/basic/xyz.c again
Features:
diff --git a/man/machine-id.xml b/man/machine-id.xml
index a722649de4..3c261bffcc 100644
--- a/man/machine-id.xml
+++ b/man/machine-id.xml
@@ -71,13 +71,14 @@
<para>This machine ID adheres to the same format and logic as the
D-Bus machine ID.</para>
- <para>This ID uniquely identifies the host. It should be considered "confidential", and must not
- be exposed in untrusted environments, in particular on the network. If a stable unique
- identifier that is tied to the machine is needed for some application, the machine ID or any
- part of it must not be used directly. Instead the machine ID should be hashed with a
- cryptographic, keyed hash function, using a fixed, application-specific key. That way the ID
- will be properly unique, and derived in a constant way from the machine ID but there will be no
- way to retrieve the original machine ID from the application-specific one.</para>
+ <para>This ID uniquely identifies the host. It should be considered "confidential", and must not be exposed in
+ untrusted environments, in particular on the network. If a stable unique identifier that is tied to the machine is
+ needed for some application, the machine ID or any part of it must not be used directly. Instead the machine ID
+ should be hashed with a cryptographic, keyed hash function, using a fixed, application-specific key. That way the
+ ID will be properly unique, and derived in a constant way from the machine ID but there will be no way to retrieve
+ the original machine ID from the application-specific one. The
+ <citerefentry><refentrytitle>sd_id128_get_machine_app_specific</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ API provides an implementation of such an algorithm.</para>
<para>The
<citerefentry><refentrytitle>systemd-machine-id-setup</refentrytitle><manvolnum>1</manvolnum></citerefentry>
diff --git a/man/sd_id128_get_machine.xml b/man/sd_id128_get_machine.xml
index 9a86c24aed..3938c6d836 100644
--- a/man/sd_id128_get_machine.xml
+++ b/man/sd_id128_get_machine.xml
@@ -44,6 +44,7 @@
<refnamediv>
<refname>sd_id128_get_machine</refname>
+ <refname>sd_id128_get_machine_app_specific</refname>
<refname>sd_id128_get_boot</refname>
<refname>sd_id128_get_invocation</refname>
<refpurpose>Retrieve 128-bit IDs</refpurpose>
@@ -59,6 +60,12 @@
</funcprototype>
<funcprototype>
+ <funcdef>int <function>sd_id128_get_machine_app_specific</function></funcdef>
+ <paramdef>sd_id128_t <parameter>app_id</parameter></paramdef>
+ <paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
<funcdef>int <function>sd_id128_get_boot</function></funcdef>
<paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
</funcprototype>
@@ -74,11 +81,22 @@
<refsect1>
<title>Description</title>
- <para><function>sd_id128_get_machine()</function> returns the
- machine ID of the executing host. This reads and parses the
- <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- file. This function caches the machine ID internally to make
- retrieving the machine ID a cheap operation.</para>
+ <para><function>sd_id128_get_machine()</function> returns the machine ID of the executing host. This reads and
+ parses the <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ file. This function caches the machine ID internally to make retrieving the machine ID a cheap operation. This ID
+ may be used wherever a unique identifier for the local system is needed. However, it is recommended to use this ID
+ as-is only in trusted environments. In untrusted environments it is recommended to derive an application specific
+ ID from this machine ID, in an irreversable (cryptographically secure) way. To make this easy
+ <function>sd_id128_get_machine_app_specific()</function> is provided, see below.</para>
+
+ <para><function>sd_id128_get_machine_app_specific()</function> is similar to
+ <function>sd_id128_get_machine()</function>, but retrieves a machine ID that is specific to the application that is
+ identified by the indicated application ID. It is recommended to use this function instead of
+ <function>sd_id128_get_machine()</function> when passing an ID to untrusted environments, in order to make sure
+ that the original machine ID may not be determined externally. The application-specific ID should be generated via
+ a tool like <command>journalctl --new-id128</command>, and may be compiled into the application. This function will
+ return the same application-specific ID for each combination of machine ID and application ID. Internally, this
+ function calculates HMAC-SHA256 of the application ID, keyed by the machine ID.</para>
<para><function>sd_id128_get_boot()</function> returns the boot ID
of the executing kernel. This reads and parses the
@@ -95,10 +113,10 @@
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details. The
ID is cached internally. In future a different mechanism to determine the invocation ID may be added.</para>
- <para>Note that <function>sd_id128_get_boot()</function> and <function>sd_id128_get_invocation()</function> always
- return UUID v4 compatible IDs. <function>sd_id128_get_machine()</function> will also return a UUID v4-compatible
- ID on new installations but might not on older. It is possible to convert the machine ID into a UUID v4-compatible
- one. For more information, see
+ <para>Note that <function>sd_id128_get_machine_app_specific()</function>, <function>sd_id128_get_boot()</function>
+ and <function>sd_id128_get_invocation()</function> always return UUID v4 compatible IDs.
+ <function>sd_id128_get_machine()</function> will also return a UUID v4-compatible ID on new installations but might
+ not on older. It is possible to convert the machine ID into a UUID v4-compatible one. For more information, see
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<para>For more information about the <literal>sd_id128_t</literal>
@@ -117,13 +135,36 @@
<refsect1>
<title>Notes</title>
- <para>The <function>sd_id128_get_machine()</function>, <function>sd_id128_get_boot()</function> and
- <function>sd_id128_get_invocation()</function> interfaces are available as a shared library, which can be compiled
- and linked to with the <literal>libsystemd</literal> <citerefentry
+ <para>The <function>sd_id128_get_machine()</function>, <function>sd_id128_get_machine_app_specific()</function>
+ <function>sd_id128_get_boot()</function> and <function>sd_id128_get_invocation()</function> interfaces are
+ available as a shared library, which can be compiled and linked to with the
+ <literal>libsystemd</literal> <citerefentry
project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para>
</refsect1>
<refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Application-specific machine ID</title>
+
+ <para>Here's a simple example for an application specific machine ID:</para>
+
+ <programlisting>#include &lt;systemd/sd-id128.h&gt;
+#include &lt;stdio.h&gt;
+
+#define OUR_APPLICATION_ID SD_ID128_MAKE(c2,73,27,73,23,db,45,4e,a6,3b,b9,6e,79,b5,3e,97)
+
+int main(int argc, char *argv[]) {
+ sd_id128_t id;
+ sd_id128_get_machine_app_specific(OUR_APPLICATION_ID, &amp;id);
+ printf("Our application ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
+ return 0;
+}</programlisting>
+ </example>
+ </refsect1>
+
+ <refsect1>
<title>See Also</title>
<para>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index ab83876eba..f27e4a5c04 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -1806,23 +1806,32 @@
<title>Summary of possible service result variable values</title>
<tgroup cols='3'>
<colspec colname='result' />
- <colspec colname='status' />
<colspec colname='code' />
+ <colspec colname='status' />
<thead>
<row>
<entry><varname>$SERVICE_RESULT</varname></entry>
- <entry><varname>$EXIT_STATUS</varname></entry>
<entry><varname>$EXIT_CODE</varname></entry>
+ <entry><varname>$EXIT_STATUS</varname></entry>
</row>
</thead>
<tbody>
<row>
+ <entry morerows="1" valign="top"><literal>protocol</literal></entry>
+ <entry valign="top">not set</entry>
+ <entry>not set</entry>
+ </row>
+ <row>
+ <entry><literal>exited</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+
+ <row>
<entry morerows="1" valign="top"><literal>timeout</literal></entry>
<entry valign="top"><literal>killed</literal></entry>
<entry><literal>TERM</literal>, <literal>KILL</literal></entry>
</row>
-
<row>
<entry valign="top"><literal>exited</literal></entry>
<entry><literal>0</literal>, <literal>1</literal>, <literal>2</literal>, <literal
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 53c49f817f..0fa68b7623 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -123,7 +123,10 @@
<listitem>
<para>A whitespace-separated list of shell-style globs
matching the persistent path, as exposed by the udev
- property <literal>ID_PATH</literal>.</para>
+ property <literal>ID_PATH</literal>. If the list is
+ prefixed with a "!", the test is inverted; i.e. it is
+ true when <literal>ID_PATH</literal> does not match any
+ item in the list.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -134,7 +137,8 @@
exposed by the udev property <literal>DRIVER</literal>
of its parent device, or if that is not set the driver
as exposed by <literal>ethtool -i</literal> of the
- device itself.</para>
+ device itself. If the list is prefixed with a "!", the
+ test is inverted.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -142,7 +146,8 @@
<listitem>
<para>A whitespace-separated list of shell-style globs
matching the device type, as exposed by the udev property
- <literal>DEVTYPE</literal>.</para>
+ <literal>DEVTYPE</literal>. If the list is prefixed with
+ a "!", the test is inverted.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -150,7 +155,8 @@
<listitem>
<para>A whitespace-separated list of shell-style globs
matching the device name, as exposed by the udev property
- <literal>INTERFACE</literal>.</para>
+ <literal>INTERFACE</literal>. If the list is prefixed
+ with a "!", the test is inverted.</para>
</listitem>
</varlistentry>
<varlistentry>
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
index 5c820332a5..19ad20789b 100644
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -24,6 +24,7 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "dirent-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "macro.h"
@@ -234,12 +235,9 @@ int close_all_fds(const int except[], unsigned n_except) {
return r;
}
- while ((de = readdir(d))) {
+ FOREACH_DIRENT(de, d, return -errno) {
int fd = -1;
- if (hidden_or_backup_file(de->d_name))
- continue;
-
if (safe_atoi(de->d_name, &fd) < 0)
/* Let's better ignore this, just in case */
continue;
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index b30cec4f92..5b23269109 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -17,7 +17,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <dirent.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
@@ -446,6 +445,7 @@ int mkfifo_atomic(const char *path, mode_t mode) {
int get_files_in_directory(const char *path, char ***list) {
_cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
size_t bufsize = 0, n = 0;
_cleanup_strv_free_ char **l = NULL;
@@ -459,16 +459,7 @@ int get_files_in_directory(const char *path, char ***list) {
if (!d)
return -errno;
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno > 0)
- return -errno;
- if (!de)
- break;
-
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
dirent_ensure_type(d, de);
if (!dirent_is_file(de))
diff --git a/src/basic/khash.c b/src/basic/khash.c
new file mode 100644
index 0000000000..9a2a3edb75
--- /dev/null
+++ b/src/basic/khash.c
@@ -0,0 +1,275 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <linux/if_alg.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "hexdecoct.h"
+#include "khash.h"
+#include "macro.h"
+#include "missing.h"
+#include "string-util.h"
+#include "util.h"
+
+/* On current kernels the maximum digest (according to "grep digestsize /proc/crypto | sort -u") is actually 32, but
+ * let's add some extra room, the few wasted bytes don't really matter... */
+#define LONGEST_DIGEST 128
+
+struct khash {
+ int fd;
+ char *algorithm;
+ uint8_t digest[LONGEST_DIGEST+1];
+ size_t digest_size;
+ bool digest_valid;
+};
+
+int khash_new_with_key(khash **ret, const char *algorithm, const void *key, size_t key_size) {
+ union {
+ struct sockaddr sa;
+ struct sockaddr_alg alg;
+ } sa = {
+ .alg.salg_family = AF_ALG,
+ .alg.salg_type = "hash",
+ };
+
+ _cleanup_(khash_unrefp) khash *h = NULL;
+ _cleanup_close_ int fd = -1;
+ ssize_t n;
+
+ assert(ret);
+ assert(key || key_size == 0);
+
+ /* Filter out an empty algorithm early, as we do not support an algorithm by that name. */
+ if (isempty(algorithm))
+ return -EINVAL;
+
+ /* Overly long hash algorithm names we definitely do not support */
+ if (strlen(algorithm) >= sizeof(sa.alg.salg_name))
+ return -EOPNOTSUPP;
+
+ fd = socket(AF_ALG, SOCK_SEQPACKET|SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return -errno;
+
+ strcpy((char*) sa.alg.salg_name, algorithm);
+ if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
+ if (errno == ENOENT)
+ return -EOPNOTSUPP;
+ return -errno;
+ }
+
+ if (key) {
+ if (setsockopt(fd, SOL_ALG, ALG_SET_KEY, key, key_size) < 0)
+ return -errno;
+ }
+
+ h = new0(khash, 1);
+ if (!h)
+ return -ENOMEM;
+
+ h->fd = accept4(fd, NULL, 0, SOCK_CLOEXEC);
+ if (h->fd < 0)
+ return -errno;
+
+ h->algorithm = strdup(algorithm);
+ if (!h->algorithm)
+ return -ENOMEM;
+
+ /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */
+ (void) send(h->fd, NULL, 0, 0);
+
+ /* Figure out the digest size */
+ n = recv(h->fd, h->digest, sizeof(h->digest), 0);
+ if (n < 0)
+ return -errno;
+ if (n >= LONGEST_DIGEST) /* longer than what we expected? If so, we don't support this */
+ return -EOPNOTSUPP;
+
+ h->digest_size = (size_t) n;
+ h->digest_valid = true;
+
+ /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */
+ (void) send(h->fd, NULL, 0, 0);
+
+ *ret = h;
+ h = NULL;
+
+ return 0;
+}
+
+int khash_new(khash **ret, const char *algorithm) {
+ return khash_new_with_key(ret, algorithm, NULL, 0);
+}
+
+khash* khash_unref(khash *h) {
+ if (!h)
+ return NULL;
+
+ safe_close(h->fd);
+ free(h->algorithm);
+ free(h);
+
+ return NULL;
+}
+
+int khash_dup(khash *h, khash **ret) {
+ _cleanup_(khash_unrefp) khash *copy = NULL;
+
+ assert(h);
+ assert(ret);
+
+ copy = newdup(khash, h, 1);
+ if (!copy)
+ return -ENOMEM;
+
+ copy->fd = -1;
+ copy->algorithm = strdup(h->algorithm);
+ if (!copy)
+ return -ENOMEM;
+
+ copy->fd = accept4(h->fd, NULL, 0, SOCK_CLOEXEC);
+ if (copy->fd < 0)
+ return -errno;
+
+ *ret = copy;
+ copy = NULL;
+
+ return 0;
+}
+
+const char *khash_get_algorithm(khash *h) {
+ assert(h);
+
+ return h->algorithm;
+}
+
+size_t khash_get_size(khash *h) {
+ assert(h);
+
+ return h->digest_size;
+}
+
+int khash_reset(khash *h) {
+ ssize_t n;
+
+ assert(h);
+
+ n = send(h->fd, NULL, 0, 0);
+ if (n < 0)
+ return -errno;
+
+ h->digest_valid = false;
+
+ return 0;
+}
+
+int khash_put(khash *h, const void *buffer, size_t size) {
+ ssize_t n;
+
+ assert(h);
+ assert(buffer || size == 0);
+
+ if (size <= 0)
+ return 0;
+
+ n = send(h->fd, buffer, size, MSG_MORE);
+ if (n < 0)
+ return -errno;
+
+ h->digest_valid = false;
+
+ return 0;
+}
+
+int khash_put_iovec(khash *h, const struct iovec *iovec, size_t n) {
+ struct msghdr mh = {
+ mh.msg_iov = (struct iovec*) iovec,
+ mh.msg_iovlen = n,
+ };
+ ssize_t k;
+
+ assert(h);
+ assert(iovec || n == 0);
+
+ if (n <= 0)
+ return 0;
+
+ k = sendmsg(h->fd, &mh, MSG_MORE);
+ if (k < 0)
+ return -errno;
+
+ h->digest_valid = false;
+
+ return 0;
+}
+
+static int retrieve_digest(khash *h) {
+ ssize_t n;
+
+ assert(h);
+
+ if (h->digest_valid)
+ return 0;
+
+ n = recv(h->fd, h->digest, h->digest_size, 0);
+ if (n < 0)
+ return n;
+ if ((size_t) n != h->digest_size) /* digest size changed? */
+ return -EIO;
+
+ h->digest_valid = true;
+
+ return 0;
+}
+
+int khash_digest_data(khash *h, const void **ret) {
+ int r;
+
+ assert(h);
+ assert(ret);
+
+ r = retrieve_digest(h);
+ if (r < 0)
+ return r;
+
+ *ret = h->digest;
+ return 0;
+}
+
+int khash_digest_string(khash *h, char **ret) {
+ int r;
+ char *p;
+
+ assert(h);
+ assert(ret);
+
+ r = retrieve_digest(h);
+ if (r < 0)
+ return r;
+
+ p = hexmem(h->digest, h->digest_size);
+ if (!p)
+ return -ENOMEM;
+
+ *ret = p;
+ return 0;
+}
diff --git a/src/basic/khash.h b/src/basic/khash.h
new file mode 100644
index 0000000000..f404a68236
--- /dev/null
+++ b/src/basic/khash.h
@@ -0,0 +1,53 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include "macro.h"
+
+typedef struct khash khash;
+
+/* For plain hash functions. Hash functions commonly supported on today's kernels are: crc32c, crct10dif, crc32,
+ * sha224, sha256, sha512, sha384, sha1, md5, md4, sha3-224, sha3-256, sha3-384, sha3-512, and more.*/
+int khash_new(khash **ret, const char *algorithm);
+
+/* For keyed hash functions. Hash functions commonly supported on today's kernels are: hmac(sha256), cmac(aes),
+ * cmac(des3_ede), hmac(sha3-512), hmac(sha3-384), hmac(sha3-256), hmac(sha3-224), hmac(rmd160), hmac(rmd128),
+ * hmac(sha224), hmac(sha512), hmac(sha384), hmac(sha1), hmac(md5), and more. */
+int khash_new_with_key(khash **ret, const char *algorithm, const void *key, size_t key_size);
+
+int khash_dup(khash *h, khash **ret);
+khash* khash_unref(khash *h);
+
+const char *khash_get_algorithm(khash *h);
+size_t khash_get_size(khash *h);
+
+int khash_reset(khash *h);
+
+int khash_put(khash *h, const void *buffer, size_t size);
+int khash_put_iovec(khash *h, const struct iovec *iovec, size_t n);
+
+int khash_digest_data(khash *h, const void **ret);
+int khash_digest_string(khash *h, char **ret);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(khash*, khash_unref);
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 8833617dc6..1502b3f4f4 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -1109,4 +1109,8 @@ struct ethtool_link_settings {
#endif
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
#include "missing_syscall.h"
diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c
index baa70c2c8d..07d42f78dd 100644
--- a/src/basic/rm-rf.c
+++ b/src/basic/rm-rf.c
@@ -17,7 +17,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
@@ -28,6 +27,7 @@
#include "btrfs-util.h"
#include "cgroup-util.h"
+#include "dirent-util.h"
#include "fd-util.h"
#include "log.h"
#include "macro.h"
@@ -43,6 +43,7 @@ static bool is_physical_fs(const struct statfs *sfs) {
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
_cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
int ret = 0, r;
struct statfs sfs;
@@ -78,19 +79,10 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
return errno == ENOENT ? 0 : -errno;
}
- for (;;) {
- struct dirent *de;
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
bool is_dir;
struct stat st;
- errno = 0;
- de = readdir(d);
- if (!de) {
- if (errno > 0 && ret == 0)
- ret = -errno;
- return ret;
- }
-
if (streq(de->d_name, ".") || streq(de->d_name, ".."))
continue;
@@ -178,6 +170,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
}
}
}
+ return ret;
}
int rm_rf(const char *path, RemoveFlags flags) {
diff --git a/src/basic/util.c b/src/basic/util.c
index c1b5ca1ef7..8a630049d7 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -18,7 +18,6 @@
***/
#include <alloca.h>
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
@@ -508,28 +507,17 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int on_ac_power(void) {
bool found_offline = false, found_online = false;
_cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
d = opendir("/sys/class/power_supply");
if (!d)
return errno == ENOENT ? true : -errno;
- for (;;) {
- struct dirent *de;
+ FOREACH_DIRENT(de, d, return -errno) {
_cleanup_close_ int fd = -1, device = -1;
char contents[6];
ssize_t n;
- errno = 0;
- de = readdir(d);
- if (!de && errno > 0)
- return -errno;
-
- if (!de)
- break;
-
- if (hidden_or_backup_file(de->d_name))
- continue;
-
device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (device < 0) {
if (errno == ENOENT || errno == ENOTDIR)
diff --git a/src/core/killall.c b/src/core/killall.c
index 3bc19e9c84..b3aa22adc5 100644
--- a/src/core/killall.c
+++ b/src/core/killall.c
@@ -24,6 +24,7 @@
#include "alloc-util.h"
#include "def.h"
+#include "dirent-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "killall.h"
@@ -172,7 +173,7 @@ static int killall(int sig, Set *pids, bool send_sighup) {
if (!dir)
return -errno;
- while ((d = readdir(dir))) {
+ FOREACH_DIRENT_ALL(d, dir, break) {
pid_t pid;
int r;
diff --git a/src/core/manager.c b/src/core/manager.c
index 1f663d3c1d..21cd6062c6 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -17,7 +17,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/kd.h>
@@ -233,6 +232,7 @@ static void manager_print_jobs_in_progress(Manager *m) {
static int have_ask_password(void) {
_cleanup_closedir_ DIR *dir;
+ struct dirent *de;
dir = opendir("/run/systemd/ask-password");
if (!dir) {
@@ -242,19 +242,11 @@ static int have_ask_password(void) {
return -errno;
}
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(dir);
- if (!de && errno > 0)
- return -errno;
- if (!de)
- return false;
-
+ FOREACH_DIRENT_ALL(de, dir, return -errno) {
if (startswith(de->d_name, "ask."))
return true;
}
+ return false;
}
static int manager_dispatch_ask_password_fd(sd_event_source *source,
diff --git a/src/core/service.c b/src/core/service.c
index c68a7122b6..61246d831d 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1714,7 +1714,7 @@ static void service_enter_running(Service *s, ServiceResult f) {
}
} else if (f != SERVICE_SUCCESS)
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
else if (s->remain_after_exit)
service_set_state(s, SERVICE_EXITED);
else
@@ -1851,7 +1851,7 @@ static void service_enter_start(Service *s) {
fail:
log_unit_warning_errno(UNIT(s), r, "Failed to run 'start' task: %m");
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
static void service_enter_start_pre(Service *s) {
@@ -1997,9 +1997,7 @@ static void service_run_next_control(Service *s) {
fail:
log_unit_warning_errno(UNIT(s), r, "Failed to run next control task: %m");
- if (s->state == SERVICE_START_PRE)
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
- else if (s->state == SERVICE_STOP)
+ if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_STOP))
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
else if (s->state == SERVICE_STOP_POST)
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
@@ -2600,7 +2598,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
case SERVICE_START:
if (s->type == SERVICE_NOTIFY) {
/* No chance of getting a ready notification anymore */
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL);
+ service_enter_stop_post(s, SERVICE_FAILURE_PROTOCOL);
break;
}
@@ -2613,7 +2611,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
service_unwatch_pid_file(s);
if (s->state == SERVICE_START)
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL);
+ service_enter_stop_post(s, SERVICE_FAILURE_PROTOCOL);
else
service_enter_stop(s, SERVICE_FAILURE_PROTOCOL);
}
@@ -2747,17 +2745,17 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (f == SERVICE_SUCCESS)
service_enter_start_post(s);
else
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
break;
} else if (s->type == SERVICE_NOTIFY) {
/* Only enter running through a notification, so that the
* SERVICE_START state signifies that no ready notification
* has been received */
if (f != SERVICE_SUCCESS)
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
else if (!s->remain_after_exit)
/* The service has never been active */
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL);
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_PROTOCOL);
break;
}
@@ -2837,7 +2835,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (f == SERVICE_SUCCESS)
service_enter_start(s);
else
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
break;
case SERVICE_START:
@@ -2846,7 +2844,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
if (f != SERVICE_SUCCESS) {
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
break;
}
@@ -2863,7 +2861,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (!has_start_post && r < 0) {
r = service_demand_pid_file(s);
if (r < 0 || !cgroup_good(s))
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_PROTOCOL);
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_PROTOCOL);
break;
}
} else
@@ -2959,7 +2957,7 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
case SERVICE_START_PRE:
case SERVICE_START:
log_unit_warning(UNIT(s), "%s operation timed out. Terminating.", s->state == SERVICE_START ? "Start" : "Start-pre");
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
+ service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_START_POST:
diff --git a/src/core/service.h b/src/core/service.h
index e09722a952..ff9cfaeb88 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -79,6 +79,8 @@ typedef enum NotifyState {
_NOTIFY_STATE_INVALID = -1
} NotifyState;
+/* The values of this enum are referenced in man/systemd.exec.xml and src/shared/bus-unit-util.c.
+ * Update those sources for each change to this enum. */
typedef enum ServiceResult {
SERVICE_SUCCESS,
SERVICE_FAILURE_RESOURCES, /* a bit of a misnomer, just our catch-all error for errnos we didn't expect */
diff --git a/src/delta/delta.c b/src/delta/delta.c
index 107b105fde..9a44b15da7 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -297,6 +297,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const char *path, bool dropins) {
_cleanup_closedir_ DIR *d;
+ struct dirent *de;
assert(top);
assert(bottom);
@@ -313,16 +314,10 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch
return log_error_errno(errno, "Failed to open %s: %m", path);
}
- for (;;) {
- struct dirent *de;
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
int k;
char *p;
- errno = 0;
- de = readdir(d);
- if (!de)
- return -errno;
-
dirent_ensure_type(d, de);
if (dropins && de->d_type == DT_DIR && endswith(de->d_name, ".d"))
@@ -354,6 +349,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch
return k;
}
}
+ return 0;
}
static int should_skip_prefix(const char* p) {
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 9d78b953fc..092a1eabb0 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -86,6 +86,28 @@ int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result
return 0;
}
+static bool net_condition_test_strv(char * const *raw_patterns,
+ const char *string) {
+ if (strv_isempty(raw_patterns))
+ return true;
+
+ /* If the patterns begin with "!", edit it out and negate the test. */
+ if (raw_patterns[0][0] == '!') {
+ char **patterns;
+ unsigned i, length;
+
+ length = strv_length(raw_patterns) + 1; /* Include the NULL. */
+ patterns = newa(char*, length);
+ patterns[0] = raw_patterns[0] + 1; /* Skip the "!". */
+ for (i = 1; i < length; i++)
+ patterns[i] = raw_patterns[i];
+
+ return !string || !strv_fnmatch(patterns, string, 0);
+ }
+
+ return string && strv_fnmatch(raw_patterns, string, 0);
+}
+
bool net_match_config(const struct ether_addr *match_mac,
char * const *match_paths,
char * const *match_drivers,
@@ -117,20 +139,16 @@ bool net_match_config(const struct ether_addr *match_mac,
if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
return false;
- if (!strv_isempty(match_paths) &&
- (!dev_path || !strv_fnmatch(match_paths, dev_path, 0)))
+ if (!net_condition_test_strv(match_paths, dev_path))
return false;
- if (!strv_isempty(match_drivers) &&
- (!dev_driver || !strv_fnmatch(match_drivers, dev_driver, 0)))
+ if (!net_condition_test_strv(match_drivers, dev_driver))
return false;
- if (!strv_isempty(match_types) &&
- (!dev_type || !strv_fnmatch_or_empty(match_types, dev_type, 0)))
+ if (!net_condition_test_strv(match_types, dev_type))
return false;
- if (!strv_isempty(match_names) &&
- (!dev_name || !strv_fnmatch_or_empty(match_names, dev_name, 0)))
+ if (!net_condition_test_strv(match_names, dev_name))
return false;
return true;
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index d48ef6bbe2..46c4dac7d7 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -511,3 +511,8 @@ global:
sd_bus_get_exit_on_disconnect;
sd_id128_get_invocation;
} LIBSYSTEMD_231;
+
+LIBSYSTEMD_233 {
+global:
+ sd_id128_get_machine_app_specific;
+} LIBSYSTEMD_232;
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index 1081979bf9..bc5e92f8fe 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -28,6 +28,7 @@
#include "device-internal.h"
#include "device-private.h"
#include "device-util.h"
+#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
@@ -1627,7 +1628,7 @@ static int device_sysattrs_read_all(sd_device *device) {
if (r < 0)
return r;
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ FOREACH_DIRENT_ALL(dent, dir, return -errno) {
char *path;
struct stat statbuf;
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index d4450c70a0..0d673ba655 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -27,6 +27,7 @@
#include "hexdecoct.h"
#include "id128-util.h"
#include "io-util.h"
+#include "khash.h"
#include "macro.h"
#include "random-util.h"
#include "util.h"
@@ -181,3 +182,34 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
*ret = make_v4_uuid(t);
return 0;
}
+
+_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
+ _cleanup_(khash_unrefp) khash *h = NULL;
+ sd_id128_t m, result;
+ const void *p;
+ int r;
+
+ assert_return(ret, -EINVAL);
+
+ r = sd_id128_get_machine(&m);
+ if (r < 0)
+ return r;
+
+ r = khash_new_with_key(&h, "hmac(sha256)", &m, sizeof(m));
+ if (r < 0)
+ return r;
+
+ r = khash_put(h, &app_id, sizeof(app_id));
+ if (r < 0)
+ return r;
+
+ r = khash_digest_data(h, &p);
+ if (r < 0)
+ return r;
+
+ /* We chop off the trailing 16 bytes */
+ memcpy(&result, p, MIN(khash_get_size(h), sizeof(result)));
+
+ *ret = make_v4_uuid(result);
+ return 0;
+}
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index 42ea0badfc..d2cfbdf5b0 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -793,6 +793,7 @@ _public_ int sd_get_sessions(char ***sessions) {
_public_ int sd_get_uids(uid_t **users) {
_cleanup_closedir_ DIR *d;
+ struct dirent *de;
int r = 0;
unsigned n = 0;
_cleanup_free_ uid_t *l = NULL;
@@ -801,19 +802,10 @@ _public_ int sd_get_uids(uid_t **users) {
if (!d)
return -errno;
- for (;;) {
- struct dirent *de;
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
int k;
uid_t uid;
- errno = 0;
- de = readdir(d);
- if (!de && errno > 0)
- return -errno;
-
- if (!de)
- break;
-
dirent_ensure_type(d, de);
if (!dirent_is_file(de))
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 23ad5d7c6a..3873bf3e96 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -1286,8 +1286,7 @@ static int flush_devices(Manager *m) {
} else {
struct dirent *de;
- while ((de = readdir(d))) {
-
+ FOREACH_DIRENT_ALL(de, d, break) {
if (!dirent_is_file(de))
continue;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index de05b6c5ef..d701f2158d 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -490,7 +490,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nU", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nUE:", options, NULL)) >= 0)
switch (c) {
@@ -1326,6 +1326,8 @@ static int setup_resolv_conf(const char *dest) {
* advantage that the container will be able to follow the host's DNS server configuration changes
* transparently. */
+ (void) touch(where);
+
r = mount_verbose(LOG_WARNING, "/usr/lib/systemd/resolv.conf", where, NULL, MS_BIND, NULL);
if (r >= 0)
return mount_verbose(LOG_ERR, NULL, where, NULL,
diff --git a/src/shared/dropin.c b/src/shared/dropin.c
index 2c1cd84df5..3cbfe13f4c 100644
--- a/src/shared/dropin.c
+++ b/src/shared/dropin.c
@@ -17,7 +17,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <dirent.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
@@ -25,6 +24,7 @@
#include "alloc-util.h"
#include "conf-files.h"
+#include "dirent-util.h"
#include "dropin.h"
#include "escape.h"
#include "fd-util.h"
@@ -124,6 +124,7 @@ static int iterate_dir(
char ***strv) {
_cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
int r;
assert(path);
@@ -148,21 +149,9 @@ static int iterate_dir(
return log_error_errno(errno, "Failed to open directory %s: %m", path);
}
- for (;;) {
- struct dirent *de;
+ FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read directory %s: %m", path)) {
_cleanup_free_ char *f = NULL;
- errno = 0;
- de = readdir(d);
- if (!de && errno > 0)
- return log_error_errno(errno, "Failed to read directory %s: %m", path);
-
- if (!de)
- break;
-
- if (hidden_or_backup_file(de->d_name))
- continue;
-
f = strjoin(path, "/", de->d_name);
if (!f)
return log_oom();
diff --git a/src/shared/fdset.c b/src/shared/fdset.c
index 527f27bc67..090f3fdcdd 100644
--- a/src/shared/fdset.c
+++ b/src/shared/fdset.c
@@ -18,13 +18,13 @@
***/
#include <alloca.h>
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include "sd-daemon.h"
+#include "dirent-util.h"
#include "fd-util.h"
#include "fdset.h"
#include "log.h"
@@ -148,12 +148,9 @@ int fdset_new_fill(FDSet **_s) {
goto finish;
}
- while ((de = readdir(d))) {
+ FOREACH_DIRENT(de, d, return -errno) {
int fd = -1;
- if (hidden_or_backup_file(de->d_name))
- continue;
-
r = safe_atoi(de->d_name, &fd);
if (r < 0)
goto finish;
diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h
index ee011b1861..6cc8e4ac0e 100644
--- a/src/systemd/sd-id128.h
+++ b/src/systemd/sd-id128.h
@@ -39,12 +39,12 @@ union sd_id128 {
#define SD_ID128_STRING_MAX 33
char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]);
-
int sd_id128_from_string(const char *s, sd_id128_t *ret);
int sd_id128_randomize(sd_id128_t *ret);
int sd_id128_get_machine(sd_id128_t *ret);
+int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret);
int sd_id128_get_boot(sd_id128_t *ret);
int sd_id128_get_invocation(sd_id128_t *ret);
diff --git a/src/test/test-hash.c b/src/test/test-hash.c
new file mode 100644
index 0000000000..1972b94cfe
--- /dev/null
+++ b/src/test/test-hash.c
@@ -0,0 +1,82 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "log.h"
+#include "string-util.h"
+#include "khash.h"
+
+int main(int argc, char *argv[]) {
+ _cleanup_(khash_unrefp) khash *h = NULL, *copy = NULL;
+ _cleanup_free_ char *s = NULL;
+
+ log_set_max_level(LOG_DEBUG);
+
+ assert_se(khash_new(&h, NULL) == -EINVAL);
+ assert_se(khash_new(&h, "") == -EINVAL);
+ assert_se(khash_new(&h, "foobar") == -EOPNOTSUPP);
+
+ assert_se(khash_new(&h, "sha256") >= 0);
+ assert_se(khash_get_size(h) == 32);
+ assert_se(streq(khash_get_algorithm(h), "sha256"));
+
+ assert_se(khash_digest_string(h, &s) >= 0);
+ assert_se(streq(s, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"));
+ s = mfree(s);
+
+ assert_se(khash_put(h, "foobar", 6) >= 0);
+ assert_se(khash_digest_string(h, &s) >= 0);
+ assert_se(streq(s, "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"));
+ s = mfree(s);
+
+ assert_se(khash_put(h, "piep", 4) >= 0);
+ assert_se(khash_digest_string(h, &s) >= 0);
+ assert_se(streq(s, "f114d872b5ea075d3be9040d0b7a429514b3f9324a8e8e3dc3fb24c34ee56bea"));
+ s = mfree(s);
+
+ assert_se(khash_put(h, "foo", 3) >= 0);
+ assert_se(khash_dup(h, &copy) >= 0);
+
+ assert_se(khash_put(h, "bar", 3) >= 0);
+ assert_se(khash_put(copy, "bar", 3) >= 0);
+
+ assert_se(khash_digest_string(h, &s) >= 0);
+ assert_se(streq(s, "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"));
+ s = mfree(s);
+
+ assert_se(khash_digest_string(copy, &s) >= 0);
+ assert_se(streq(s, "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2"));
+ s = mfree(s);
+
+ h = khash_unref(h);
+
+ assert_se(khash_new_with_key(&h, "hmac(sha256)", "quux", 4) >= 0);
+ assert_se(khash_get_size(h) == 32);
+ assert_se(streq(khash_get_algorithm(h), "hmac(sha256)"));
+
+ assert_se(khash_digest_string(h, &s) >= 0);
+ assert_se(streq(s, "abed9f8218ab473f77218a6a7d39abf1d21fa46d0700c4898e330ba88309d5ae"));
+ s = mfree(s);
+
+ assert_se(khash_put(h, "foobar", 6) >= 0);
+ assert_se(khash_digest_string(h, &s) >= 0);
+ assert_se(streq(s, "33f6c70a60db66007d5325d5d1dea37c371354e5b83347a59ad339ce9f4ba3dc"));
+
+ return 0;
+}
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index 1c8e5549da..ab5a111ba9 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -153,5 +153,11 @@ int main(int argc, char *argv[]) {
assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0);
assert_se(sd_id128_equal(id, id2));
+ assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id) >= 0);
+ assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id2) >= 0);
+ assert_se(sd_id128_equal(id, id2));
+ assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(51,df,0b,4b,c3,b0,4c,97,80,e2,99,b9,8c,a3,73,b8), &id2) >= 0);
+ assert_se(!sd_id128_equal(id, id2));
+
return 0;
}
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index b881d774a0..79f75e165b 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -18,7 +18,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
@@ -44,6 +43,7 @@
#include "conf-files.h"
#include "copy.h"
#include "def.h"
+#include "dirent-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
@@ -380,7 +380,7 @@ static int dir_cleanup(
bool deleted = false;
int r = 0;
- while ((dent = readdir(d))) {
+ FOREACH_DIRENT_ALL(dent, d, break) {
struct stat s;
usec_t age;
_cleanup_free_ char *sub_path = NULL;
@@ -1053,6 +1053,7 @@ typedef int (*action_t)(Item *, const char *);
static int item_do_children(Item *i, const char *path, action_t action) {
_cleanup_closedir_ DIR *d;
+ struct dirent *de;
int r = 0;
assert(i);
@@ -1065,19 +1066,11 @@ static int item_do_children(Item *i, const char *path, action_t action) {
if (!d)
return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
- for (;;) {
+ FOREACH_DIRENT_ALL(de, d, r = -errno) {
_cleanup_free_ char *p = NULL;
- struct dirent *de;
int q;
errno = 0;
- de = readdir(d);
- if (!de) {
- if (errno > 0 && r == 0)
- r = -errno;
-
- break;
- }
if (STR_IN_SET(de->d_name, ".", ".."))
continue;
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index fe9d6f4482..5be158f527 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -100,6 +100,7 @@
#include <unistd.h>
#include <linux/pci_regs.h>
+#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "stdio-util.h"
@@ -256,7 +257,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
goto out;
}
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ FOREACH_DIRENT_ALL(dent, dir, break) {
int i;
char *rest, *address, str[PATH_MAX];
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index 1825ee75a7..527f0bff2d 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -20,7 +20,6 @@
*/
#include <ctype.h>
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@@ -31,6 +30,7 @@
#include <unistd.h>
#include "alloc-util.h"
+#include "dirent-util.h"
#include "string-util.h"
#include "udev.h"
@@ -405,7 +405,7 @@ static struct udev_device *handle_scsi_default(struct udev_device *parent, char
parent = NULL;
goto out;
}
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ FOREACH_DIRENT_ALL(dent, dir, break) {
char *rest;
int i;
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index e94a814388..53cfd9c053 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -15,7 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
@@ -25,6 +24,7 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "dirent-util.h"
#include "format-util.h"
#include "fs-util.h"
#include "selinux-util.h"
@@ -129,6 +129,7 @@ exit:
static const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize) {
struct udev *udev = udev_device_get_udev(dev);
DIR *dir;
+ struct dirent *dent;
int priority = 0;
const char *target = NULL;
@@ -141,12 +142,10 @@ static const char *link_find_prioritized(struct udev_device *dev, bool add, cons
dir = opendir(stackdir);
if (dir == NULL)
return target;
- for (;;) {
+ FOREACH_DIRENT_ALL(dent, dir, break) {
struct udev_device *dev_db;
- struct dirent *dent;
- dent = readdir(dir);
- if (dent == NULL || dent->d_name[0] == '\0')
+ if (dent->d_name[0] == '\0')
break;
if (dent->d_name[0] == '.')
continue;
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index d88687e9c2..b0238220e4 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -16,7 +16,6 @@
*/
#include <ctype.h>
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
@@ -31,6 +30,7 @@
#include "alloc-util.h"
#include "conf-files.h"
+#include "dirent-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fs-util.h"
@@ -703,7 +703,7 @@ static void attr_subst_subdir(char *attr, size_t len) {
if (dir == NULL)
return;
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir))
+ FOREACH_DIRENT_ALL(dent, dir, break)
if (dent->d_name[0] != '.') {
char n[strlen(dent->d_name) + strlen(tail) + 1];
diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c
index bc9096ed0c..aa432bb90a 100644
--- a/src/udev/udev-watch.c
+++ b/src/udev/udev-watch.c
@@ -17,13 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <dirent.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/inotify.h>
#include <unistd.h>
+#include "dirent-util.h"
#include "stdio-util.h"
#include "udev.h"
@@ -57,7 +57,7 @@ void udev_watch_restore(struct udev *udev) {
return;
}
- for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) {
+ FOREACH_DIRENT_ALL(ent, dir, break) {
char device[UTIL_PATH_SIZE];
ssize_t len;
struct udev_device *dev;
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
index 6753c52005..90cdfa16c7 100644
--- a/src/udev/udevadm-info.c
+++ b/src/udev/udevadm-info.c
@@ -16,7 +16,6 @@
*/
#include <ctype.h>
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
@@ -26,6 +25,7 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "dirent-util.h"
#include "fd-util.h"
#include "string-util.h"
#include "udev-util.h"
@@ -196,7 +196,7 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
if (depth <= 0)
return;
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ FOREACH_DIRENT_ALL(dent, dir, break) {
struct stat stats;
if (dent->d_name[0] == '.')
diff --git a/test/networkd-test.py b/test/networkd-test.py
index a932d32b92..39bd4f5b1b 100755
--- a/test/networkd-test.py
+++ b/test/networkd-test.py
@@ -74,6 +74,14 @@ class NetworkdTestingUtilities:
some required methods.
"""
+ def add_veth_pair(self, veth, peer, veth_options=(), peer_options=()):
+ """Add a veth interface pair, and queue them to be removed."""
+ subprocess.check_call(['ip', 'link', 'add', 'name', veth] +
+ list(veth_options) +
+ ['type', 'veth', 'peer', 'name', peer] +
+ list(peer_options))
+ self.addCleanup(subprocess.call, ['ip', 'link', 'del', 'dev', peer])
+
def write_network(self, unit_name, contents):
"""Write a network unit file, and queue it to be removed."""
unit_path = os.path.join(NETWORK_UNITDIR, unit_name)
@@ -439,9 +447,7 @@ IPv6AcceptRA=False''' % self.iface)
# create second device/dnsmasq for a .company/.lab VPN interface
# static IPs for simplicity
- subprocess.check_call(['ip', 'link', 'add', 'name', 'testvpnclient', 'type',
- 'veth', 'peer', 'name', 'testvpnrouter'])
- self.addCleanup(subprocess.call, ['ip', 'link', 'del', 'dev', 'testvpnrouter'])
+ self.add_veth_pair('testvpnclient', 'testvpnrouter')
subprocess.check_call(['ip', 'a', 'flush', 'dev', 'testvpnrouter'])
subprocess.check_call(['ip', 'a', 'add', '10.241.3.1/24', 'dev', 'testvpnrouter'])
subprocess.check_call(['ip', 'link', 'set', 'testvpnrouter', 'up'])
@@ -768,6 +774,42 @@ DNS=127.0.0.1''')
raise
+class MatchClientTest(unittest.TestCase, NetworkdTestingUtilities):
+ """Test [Match] sections in .network files.
+
+ Be aware that matching the test host's interfaces will wipe their
+ configuration, so as a precaution, all network files should have a
+ restrictive [Match] section to only ever interfere with the
+ temporary veth interfaces created here.
+ """
+
+ def tearDown(self):
+ """Stop networkd."""
+ subprocess.call(['systemctl', 'stop', 'systemd-networkd'])
+
+ def test_basic_matching(self):
+ """Verify the Name= line works throughout this class."""
+ self.add_veth_pair('test_if1', 'fake_if2')
+ self.write_network('test.network', "[Match]\nName=test_*\n[Network]")
+ subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+ self.assert_link_states(test_if1='managed', fake_if2='unmanaged')
+
+ def test_inverted_matching(self):
+ """Verify that a '!'-prefixed value inverts the match."""
+ # Use a MAC address as the interfaces' common matching attribute
+ # to avoid depending on udev, to support testing in containers.
+ mac = '00:01:02:03:98:99'
+ self.add_veth_pair('test_veth', 'test_peer',
+ ['addr', mac], ['addr', mac])
+ self.write_network('no-veth.network', """\
+[Match]
+MACAddress=%s
+Name=!nonexistent *peer*
+[Network]""" % mac)
+ subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+ self.assert_link_states(test_veth='managed', test_peer='unmanaged')
+
+
class UnmanagedClientTest(unittest.TestCase, NetworkdTestingUtilities):
"""Test if networkd manages the correct interfaces."""
@@ -798,11 +840,7 @@ class UnmanagedClientTest(unittest.TestCase, NetworkdTestingUtilities):
def create_iface(self):
"""Create temporary veth pairs for interface matching."""
for veth, peer in self.veths.items():
- subprocess.check_call(['ip', 'link', 'add',
- 'name', veth, 'type', 'veth',
- 'peer', 'name', peer])
- self.addCleanup(subprocess.call,
- ['ip', 'link', 'del', 'dev', peer])
+ self.add_veth_pair(veth, peer)
def test_unmanaged_setting(self):
"""Verify link states with Unmanaged= settings, hot-plug."""