]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #4795 from poettering/dissect
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 10 Dec 2016 06:08:13 +0000 (01:08 -0500)
committerGitHub <noreply@github.com>
Sat, 10 Dec 2016 06:08:13 +0000 (01:08 -0500)
Generalize image dissection logic of nspawn, and make it useful for other tools.

40 files changed:
.gitignore
Makefile-man.am
Makefile.am
TODO
man/machine-id.xml
man/sd_id128_get_machine.xml
man/systemd.exec.xml
man/systemd.network.xml
src/basic/fd-util.c
src/basic/fs-util.c
src/basic/khash.c [new file with mode: 0644]
src/basic/khash.h [new file with mode: 0644]
src/basic/missing.h
src/basic/rm-rf.c
src/basic/util.c
src/core/killall.c
src/core/manager.c
src/core/service.c
src/core/service.h
src/delta/delta.c
src/libsystemd-network/network-internal.c
src/libsystemd/libsystemd.sym
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-id128/sd-id128.c
src/libsystemd/sd-login/sd-login.c
src/login/logind-dbus.c
src/nspawn/nspawn.c
src/shared/dropin.c
src/shared/fdset.c
src/systemd/sd-id128.h
src/test/test-hash.c [new file with mode: 0644]
src/test/test-id128.c
src/tmpfiles/tmpfiles.c
src/udev/udev-builtin-net_id.c
src/udev/udev-builtin-path_id.c
src/udev/udev-node.c
src/udev/udev-rules.c
src/udev/udev-watch.c
src/udev/udevadm-info.c
test/networkd-test.py

index baa975d813d29043cfa552864723d1ac5ff4506b..016ba625e36f58fc7db18945c719f1627dda532a 100644 (file)
 /test-fs-util
 /test-fstab-util
 /test-glob-util
+/test-hash
 /test-hashmap
 /test-hexdecoct
 /test-hostname
index 013e0d796711be2d369b9189713cc0571f43d114..228e29fc4f4ef035e5353a4d563c34a178cff75f 100644 (file)
@@ -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)
 
index 1895e33e05c18214457fbf21789aae111a6669e4..9bc18d39d6c391bf06b0cb631e5b649d3a572a05 100644 (file)
@@ -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 \
@@ -4081,6 +4083,16 @@ test_id128_LDADD = \
 tests += \
        test-id128
 
+# ------------------------------------------------------------------------------
+test_hash_SOURCES = \
+       src/test/test-hash.c
+
+test_hash_LDADD = \
+       libsystemd-shared.la
+
+tests += \
+       test-hash
+
 # ------------------------------------------------------------------------------
 
 bin_PROGRAMS += \
diff --git a/TODO b/TODO
index 74183b5f47ee6b68cf80bda81ae0bb2f07696922..00d1cd01fa78c347e3bf7d4e50479e64a67f58b0 100644 (file)
--- 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:
index a722649de4e27135a5e5e77259b270a700a90d0b..3c261bffcc3856d585d41c3fe6ba3f0f6e844f1f 100644 (file)
     <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>
index 9a86c24aed1b5d824d6c6810c17717b9010fe3d0..3938c6d836c199633b84423489d5e1a3697bfb62 100644 (file)
@@ -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>
         <paramdef>sd_id128_t *<parameter>ret</parameter></paramdef>
       </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>
   <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
     <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>
   <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>
 
index ab83876eba5fd277844463fea97843f3830db1aa..f27e4a5c04cc17a3f332e966f5783bd0ceea788c 100644 (file)
           <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
index 53c49f817fd79771add7afcae5e9c257f546e575..0fa68b7623f9ca5da06a0ba468a7ae5af88aa29c 100644 (file)
           <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>
             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>
           <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>
           <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>
index 5c820332a5dd1417663c31a4f269a3d5c440b796..19ad20789b7cb9d8e2f558f16d4768576b8510e5 100644 (file)
@@ -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;
index b30cec4f925154ae96d7142441b12d1a5887226c..5b232691090acbb405d7ba137d56d6652af05a32 100644 (file)
@@ -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 (file)
index 0000000..9a2a3ed
--- /dev/null
@@ -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 (file)
index 0000000..f404a68
--- /dev/null
@@ -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);
index 8833617dc6c9079c4370b2713c67803fe9026d6c..1502b3f4f43f3876222db252c0397c10208c3a9d 100644 (file)
@@ -1109,4 +1109,8 @@ struct ethtool_link_settings {
 
 #endif
 
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
 #include "missing_syscall.h"
index baa70c2c8d136a0de6cc3f04d0f13346856aa2fa..07d42f78dd20926b22123acb08b024f3af3560f1 100644 (file)
@@ -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) {
index c1b5ca1ef7b7d6f9c0b0717be62746edb2787a34..8a630049d7c26ac313c802be93e0972bd4953d30 100644 (file)
@@ -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)
index 3bc19e9c842ba802f83d9acbb9dde998f9461d8a..b3aa22adc55d7af5a5d882e9fc1240d65f066fc8 100644 (file)
@@ -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;
 
index 1f663d3c1df3a1a73b332d7fbacfa7ea8eb02634..21cd6062c66fef2056d389d8fdb23b0c020a5f87 100644 (file)
@@ -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,
index c68a7122b629573667a18dac55a363f4839f724b..61246d831dc4843812b9fbafe8e36a06296563e2 100644 (file)
@@ -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:
index e09722a952fd7da5148efb0c86049eef53afc504..ff9cfaeb88e7498808c6e3f32409578387bca61b 100644 (file)
@@ -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 */
index 107b105fde8f99288df129c737124e6607f3dd45..9a44b15da71d238ebbf49ffa9a91f77829cbbb41 100644 (file)
@@ -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) {
index 9d78b953fc11841a3efce69800b650578e79961c..092a1eabb07dd5eb79a6bdecc22b0dba4bc95161 100644 (file)
@@ -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;
index d48ef6bbe2ab7e9061cf6e79fb931ae6994461c8..46c4dac7d71128b5f685eac11150d640f2253b9f 100644 (file)
@@ -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;
index 1081979bf931b47850bb737d29ba54633efeeb8a..bc5e92f8fe62c28e3abc9785f05a061b4dbb6f43 100644 (file)
@@ -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;
 
index d4450c70a003c357b0dafce92a542e2f67f87459..0d673ba655e18905b4ea1742b98ef9b81ba25d0e 100644 (file)
@@ -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;
+}
index 42ea0badfc6a0d6dc269a8cea7ac7a2fa744c3fe..d2cfbdf5b0aa8f5a74dbcee047efbcde56a2f182 100644 (file)
@@ -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))
index 23ad5d7c6a1d0299d5c482bba1116b60f0949487..3873bf3e96cfe64c319dd519891b4ddb0f25e6df 100644 (file)
@@ -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;
 
index de05b6c5efd8195763c638ddf8879f8e64edc81f..d701f2158d9a99ee6d6bed99422507ce35ffa341 100644 (file)
@@ -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,
index 2c1cd84df5cdc70229b917ceeb63422d0ad404bf..3cbfe13f4c49248e5c2423caa13777923bc93786 100644 (file)
@@ -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();
index 527f27bc67a730a5ef596ca20facb079cf46b8c1..090f3fdcdd70d8d6ebcee5c4300149d6a2c0c521 100644 (file)
 ***/
 
 #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;
index ee011b1861b7531d83d67486cb74865a2dd5fbd8..6cc8e4ac0e9f2968b4630d251a1dfa4b1c3b7395 100644 (file)
@@ -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 (file)
index 0000000..1972b94
--- /dev/null
@@ -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;
+}
index 1c8e5549daf983bbc10d25c10511e1e6e6bcc320..ab5a111ba94d5756dfb4af36aa45a4d72cbd1d12 100644 (file)
@@ -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;
 }
index b881d774a0ece70e23755d2449d8250720634762..79f75e165b46c1133ac967e66e60ff04d86e11ca 100644 (file)
@@ -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;
index fe9d6f44829745d2fae911c9a6426d2d043b1a5b..5be158f5272d3999f9a95bf9a104b410e7fbc97d 100644 (file)
 #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];
 
index 1825ee75a7367903ef8ad860f8852652138c54e2..527f0bff2dcbb57663faeb111b557e8ccaa08e0a 100644 (file)
@@ -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;
 
index e94a8143887092d86e5fbf0db97bc2f2231ffe3e..53cfd9c053f9c90956586d2aca43d15b796deb3d 100644 (file)
@@ -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;
index d88687e9c2b83b720f7e908ef9e93dba5609b226..b0238220e47065ae30e307e8a3f4185cb855db89 100644 (file)
@@ -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];
 
index bc9096ed0c170e087c1aed1e48e94ec90b274a89..aa432bb90a80e8aa5bd8ea60e7e54ee9c701fac6 100644 (file)
  * 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;
index 6753c52005ad1c4d8b3f5a1a7d2e86bc1426b6c5..90cdfa16c7630a58a9ac84e66237e61e707b904a 100644 (file)
@@ -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] == '.')
index a932d32b92a42ef52f73734444e74db93ad486f2..39bd4f5b1b3c291ded470f06fdd8444fae468387 100755 (executable)
@@ -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."""