summary refs log tree commit diff
path: root/src/systemd
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemd')
-rw-r--r--src/systemd/sd-adapt/architecture.h (renamed from src/systemd/sd-adapt/process-util.h)0
-rw-r--r--src/systemd/sd-adapt/btrfs-util.h3
-rw-r--r--src/systemd/sd-adapt/ioprio.h3
-rw-r--r--src/systemd/sd-adapt/nm-sd-adapt.h33
-rw-r--r--src/systemd/sd-adapt/raw-clone.h3
-rw-r--r--src/systemd/sd-adapt/udev.h1
-rw-r--r--src/systemd/src/basic/alloc-util.c27
-rw-r--r--src/systemd/src/basic/alloc-util.h10
-rw-r--r--src/systemd/src/basic/escape.c42
-rw-r--r--src/systemd/src/basic/escape.h23
-rw-r--r--src/systemd/src/basic/extract-word.c9
-rw-r--r--src/systemd/src/basic/extract-word.h2
-rw-r--r--src/systemd/src/basic/fd-util.c3
-rw-r--r--src/systemd/src/basic/fileio.c207
-rw-r--r--src/systemd/src/basic/fileio.h22
-rw-r--r--src/systemd/src/basic/fs-util.c19
-rw-r--r--src/systemd/src/basic/fs-util.h1
-rw-r--r--src/systemd/src/basic/hashmap.c26
-rw-r--r--src/systemd/src/basic/hashmap.h4
-rw-r--r--src/systemd/src/basic/hexdecoct.c3
-rw-r--r--src/systemd/src/basic/hostname-util.c13
-rw-r--r--src/systemd/src/basic/in-addr-util.c150
-rw-r--r--src/systemd/src/basic/in-addr-util.h16
-rw-r--r--src/systemd/src/basic/io-util.h13
-rw-r--r--src/systemd/src/basic/log.h133
-rw-r--r--src/systemd/src/basic/macro.h1
-rw-r--r--src/systemd/src/basic/parse-util.c21
-rw-r--r--src/systemd/src/basic/parse-util.h1
-rw-r--r--src/systemd/src/basic/path-util.c29
-rw-r--r--src/systemd/src/basic/path-util.h16
-rw-r--r--src/systemd/src/basic/process-util.c1093
-rw-r--r--src/systemd/src/basic/process-util.h141
-rw-r--r--src/systemd/src/basic/random-util.c147
-rw-r--r--src/systemd/src/basic/random-util.h4
-rw-r--r--src/systemd/src/basic/set.h2
-rw-r--r--src/systemd/src/basic/siphash24.c202
-rw-r--r--src/systemd/src/basic/siphash24.h23
-rw-r--r--src/systemd/src/basic/socket-util.c31
-rw-r--r--src/systemd/src/basic/socket-util.h20
-rw-r--r--src/systemd/src/basic/string-util.c31
-rw-r--r--src/systemd/src/basic/string-util.h13
-rw-r--r--src/systemd/src/basic/strv.c6
-rw-r--r--src/systemd/src/basic/time-util.c267
-rw-r--r--src/systemd/src/basic/time-util.h19
-rw-r--r--src/systemd/src/basic/unaligned.h129
-rw-r--r--src/systemd/src/basic/utf8.c2
-rw-r--r--src/systemd/src/basic/util.c152
-rw-r--r--src/systemd/src/basic/util.h3
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-lease-internal.h2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-network.c16
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-packet.c4
-rw-r--r--src/systemd/src/libsystemd-network/lldp-neighbor.c7
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.c39
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.h7
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-client.c105
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-lease.c151
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-client.c2
-rw-r--r--src/systemd/src/libsystemd-network/sd-ipv4acd.c2
-rw-r--r--src/systemd/src/libsystemd-network/sd-lldp.c2
-rw-r--r--src/systemd/src/libsystemd/sd-event/sd-event.c21
-rw-r--r--src/systemd/src/libsystemd/sd-id128/id128-util.c2
-rw-r--r--src/systemd/src/libsystemd/sd-id128/sd-id128.c4
-rw-r--r--src/systemd/src/shared/dns-domain.c83
-rw-r--r--src/systemd/src/shared/dns-domain.h4
-rw-r--r--src/systemd/src/systemd/sd-dhcp-client.h17
-rw-r--r--src/systemd/src/systemd/sd-dhcp-lease.h1
66 files changed, 2786 insertions, 802 deletions
diff --git a/src/systemd/sd-adapt/process-util.h b/src/systemd/sd-adapt/architecture.h
index 637892c2..637892c2 100644
--- a/src/systemd/sd-adapt/process-util.h
+++ b/src/systemd/sd-adapt/architecture.h
diff --git a/src/systemd/sd-adapt/btrfs-util.h b/src/systemd/sd-adapt/btrfs-util.h
new file mode 100644
index 00000000..637892c2
--- /dev/null
+++ b/src/systemd/sd-adapt/btrfs-util.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/systemd/sd-adapt/ioprio.h b/src/systemd/sd-adapt/ioprio.h
new file mode 100644
index 00000000..637892c2
--- /dev/null
+++ b/src/systemd/sd-adapt/ioprio.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/systemd/sd-adapt/nm-sd-adapt.h b/src/systemd/sd-adapt/nm-sd-adapt.h
index a8ff18bc..0d291e26 100644
--- a/src/systemd/sd-adapt/nm-sd-adapt.h
+++ b/src/systemd/sd-adapt/nm-sd-adapt.h
@@ -32,12 +32,24 @@
 #define CLOCK_BOOTTIME 7
 #endif
 
+#if defined(HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO == 1
+#define HAVE_EXPLICIT_BZERO 1
+#else
+#define HAVE_EXPLICIT_BZERO 0
+#endif
+
+#define ENABLE_DEBUG_HASHMAP 0
+
+#ifndef HAVE_SYS_AUXV_H
+#define HAVE_SYS_AUXV_H 0
+#endif
+
 /*****************************************************************************/
 
 static inline NMLogLevel
 _slog_level_to_nm (int slevel)
 {
-    switch (slevel) {
+    switch (LOG_PRI (slevel)) {
     case LOG_DEBUG:   return LOGL_DEBUG;
 	case LOG_WARNING: return LOGL_WARN;
 	case LOG_CRIT:
@@ -48,7 +60,15 @@ _slog_level_to_nm (int slevel)
 	}
 }
 
-#define log_internal(level, error, file, line, func, format, ...) \
+static inline int
+_nm_log_get_max_level_realm (void)
+{
+	/* inline function, to avoid coverity warning about constant expression. */
+	return LOG_DEBUG;
+}
+#define log_get_max_level_realm(realm) _nm_log_get_max_level_realm ()
+
+#define log_internal_realm(level, error, file, line, func, format, ...) \
 ({ \
 	const int _nm_e = (error); \
 	const NMLogLevel _nm_l = _slog_level_to_nm ((level)); \
@@ -61,11 +81,6 @@ _slog_level_to_nm (int slevel)
 	(_nm_e > 0 ? -_nm_e : _nm_e); \
 })
 
-#define log_full_errno(level, error, ...) \
-({ \
-	log_internal(level, error, __FILE__, __LINE__, __func__, __VA_ARGS__); \
-})
-
 #define log_assert_failed(text, file, line, func) \
 G_STMT_START { \
 	log_internal (LOG_CRIT, 0, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.", text, file, line, func); \
@@ -171,10 +186,6 @@ static inline pid_t gettid(void) {
         return (pid_t) syscall(SYS_gettid);
 }
 
-static inline bool is_main_thread(void) {
-        return TRUE;
-}
-
 #endif /* (NETWORKMANAGER_COMPILATION) == NM_NETWORKMANAGER_COMPILATION_SYSTEMD */
 
 #endif /* NM_SD_ADAPT_H */
diff --git a/src/systemd/sd-adapt/raw-clone.h b/src/systemd/sd-adapt/raw-clone.h
new file mode 100644
index 00000000..637892c2
--- /dev/null
+++ b/src/systemd/sd-adapt/raw-clone.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/systemd/sd-adapt/udev.h b/src/systemd/sd-adapt/udev.h
index 00f60f92..419abcbf 100644
--- a/src/systemd/sd-adapt/udev.h
+++ b/src/systemd/sd-adapt/udev.h
@@ -3,3 +3,4 @@
 /* dummy header */
 
 #include "libudev.h"
+#include "strv.h"
diff --git a/src/systemd/src/basic/alloc-util.c b/src/systemd/src/basic/alloc-util.c
index 5fae60c9..97588312 100644
--- a/src/systemd/src/basic/alloc-util.c
+++ b/src/systemd/src/basic/alloc-util.c
@@ -27,16 +27,31 @@
 #include "util.h"
 
 void* memdup(const void *p, size_t l) {
-        void *r;
+        void *ret;
 
-        assert(p);
+        assert(l == 0 || p);
+
+        ret = malloc(l);
+        if (!ret)
+                return NULL;
+
+        memcpy(ret, p, l);
+        return ret;
+}
+
+void* memdup_suffix0(const void*p, size_t l) {
+        void *ret;
+
+        assert(l == 0 || p);
+
+        /* The same as memdup() but place a safety NUL byte after the allocated memory */
 
-        r = malloc(l);
-        if (!r)
+        ret = malloc(l + 1);
+        if (!ret)
                 return NULL;
 
-        memcpy(r, p, l);
-        return r;
+        *((uint8_t*) mempcpy(ret, p, l)) = 0;
+        return ret;
 }
 
 void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
diff --git a/src/systemd/src/basic/alloc-util.h b/src/systemd/src/basic/alloc-util.h
index a44dd473..0a89691b 100644
--- a/src/systemd/src/basic/alloc-util.h
+++ b/src/systemd/src/basic/alloc-util.h
@@ -36,6 +36,8 @@
 
 #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
 
+#define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
+
 #define malloc0(n) (calloc(1, (n)))
 
 static inline void *mfree(void *memory) {
@@ -52,6 +54,7 @@ static inline void *mfree(void *memory) {
         })
 
 void* memdup(const void *p, size_t l) _alloc_(2);
+void* memdup_suffix0(const void*p, size_t l) _alloc_(2);
 
 static inline void freep(void *p) {
         free(*(void**) p);
@@ -84,6 +87,13 @@ _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, si
         return memdup(p, size * need);
 }
 
+_alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
+        if (size_multiply_overflow(size, need))
+                return NULL;
+
+        return memdup_suffix0(p, size * need);
+}
+
 void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
 void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
 
diff --git a/src/systemd/src/basic/escape.c b/src/systemd/src/basic/escape.c
index ac96f0ee..27a20702 100644
--- a/src/systemd/src/basic/escape.c
+++ b/src/systemd/src/basic/escape.c
@@ -316,7 +316,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
 
         /* Undoes C style string escaping, and optionally prefixes it. */
 
-        pl = prefix ? strlen(prefix) : 0;
+        pl = strlen_ptr(prefix);
 
         r = new(char, pl+length+1);
         if (!r)
@@ -428,7 +428,7 @@ char *octescape(const char *s, size_t len) {
 
         for (f = s, t = r; f < s + len; f++) {
 
-                if (*f < ' ' || *f >= 127 || *f == '\\' || *f == '"') {
+                if (*f < ' ' || *f >= 127 || IN_SET(*f, '\\', '"')) {
                         *(t++) = '\\';
                         *(t++) = '0' + (*f >> 6);
                         *(t++) = '0' + ((*f >> 3) & 8);
@@ -443,10 +443,16 @@ char *octescape(const char *s, size_t len) {
 
 }
 
-static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
+static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad, bool escape_tab_nl) {
         assert(bad);
 
         for (; *s; s++) {
+                if (escape_tab_nl && IN_SET(*s, '\n', '\t')) {
+                        *(t++) = '\\';
+                        *(t++) = *s == '\n' ? 'n' : 't';
+                        continue;
+                }
+
                 if (*s == '\\' || strchr(bad, *s))
                         *(t++) = '\\';
 
@@ -463,20 +469,21 @@ char *shell_escape(const char *s, const char *bad) {
         if (!r)
                 return NULL;
 
-        t = strcpy_backslash_escaped(r, s, bad);
+        t = strcpy_backslash_escaped(r, s, bad, false);
         *t = 0;
 
         return r;
 }
 
-char *shell_maybe_quote(const char *s) {
+char* shell_maybe_quote(const char *s, EscapeStyle style) {
         const char *p;
         char *r, *t;
 
         assert(s);
 
-        /* Encloses a string in double quotes if necessary to make it
-         * OK as shell string. */
+        /* Encloses a string in quotes if necessary to make it OK as a shell
+         * string. Note that we treat benign UTF-8 characters as needing
+         * escaping too, but that should be OK. */
 
         for (p = s; *p; p++)
                 if (*p <= ' ' ||
@@ -487,17 +494,30 @@ char *shell_maybe_quote(const char *s) {
         if (!*p)
                 return strdup(s);
 
-        r = new(char, 1+strlen(s)*2+1+1);
+        r = new(char, (style == ESCAPE_POSIX) + 1 + strlen(s)*2 + 1 + 1);
         if (!r)
                 return NULL;
 
         t = r;
-        *(t++) = '"';
+        if (style == ESCAPE_BACKSLASH)
+                *(t++) = '"';
+        else if (style == ESCAPE_POSIX) {
+                *(t++) = '$';
+                *(t++) = '\'';
+        } else
+                assert_not_reached("Bad EscapeStyle");
+
         t = mempcpy(t, s, p - s);
 
-        t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
+        if (style == ESCAPE_BACKSLASH)
+                t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE, false);
+        else
+                t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE_POSIX, true);
 
-        *(t++)= '"';
+        if (style == ESCAPE_BACKSLASH)
+                *(t++) = '"';
+        else
+                *(t++) = '\'';
         *t = 0;
 
         return r;
diff --git a/src/systemd/src/basic/escape.h b/src/systemd/src/basic/escape.h
index 24729dc1..e62347af 100644
--- a/src/systemd/src/basic/escape.h
+++ b/src/systemd/src/basic/escape.h
@@ -33,13 +33,30 @@
 /* What characters are special in the shell? */
 /* must be escaped outside and inside double-quotes */
 #define SHELL_NEED_ESCAPE "\"\\`$"
-/* can be escaped or double-quoted */
-#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;"
+
+/* Those that can be escaped or double-quoted.
+ *
+ * Stricly speaking, ! does not need to be escaped, except in interactive
+ * mode, but let's be extra nice to the user and quote ! in case this
+ * output is ever used in interactive mode. */
+#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;!"
+
+/* Note that we assume control characters would need to be escaped too in
+ * addition to the "special" characters listed here, if they appear in the
+ * string. Current users disallow control characters. Also '"' shall not
+ * be escaped.
+ */
+#define SHELL_NEED_ESCAPE_POSIX "\\\'"
 
 typedef enum UnescapeFlags {
         UNESCAPE_RELAX = 1,
 } UnescapeFlags;
 
+typedef enum EscapeStyle {
+        ESCAPE_BACKSLASH = 1,
+        ESCAPE_POSIX = 2,
+} EscapeStyle;
+
 char *cescape(const char *s);
 char *cescape_length(const char *s, size_t n);
 size_t cescape_char(char c, char *buf);
@@ -53,4 +70,4 @@ char *xescape(const char *s, const char *bad);
 char *octescape(const char *s, size_t len);
 
 char *shell_escape(const char *s, const char *bad);
-char *shell_maybe_quote(const char *s);
+char* shell_maybe_quote(const char *s, EscapeStyle style);
diff --git a/src/systemd/src/basic/extract-word.c b/src/systemd/src/basic/extract-word.c
index 734712dc..69d8c48d 100644
--- a/src/systemd/src/basic/extract-word.c
+++ b/src/systemd/src/basic/extract-word.c
@@ -154,7 +154,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
                         for (;; (*p)++, c = **p) {
                                 if (c == 0)
                                         goto finish_force_terminate;
-                                else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) {
+                                else if (IN_SET(c, '\'', '"') && (flags & EXTRACT_QUOTES)) {
                                         quote = c;
                                         break;
                                 } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
@@ -244,7 +244,12 @@ int extract_first_word_and_warn(
         return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue);
 }
 
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
+/* We pass ExtractFlags as unsigned int (to avoid undefined behaviour when passing
+ * an object that undergoes default argument promotion as an argument to va_start).
+ * Let's make sure that ExtractFlags fits into an unsigned int. */
+assert_cc(sizeof(enum ExtractFlags) <= sizeof(unsigned));
+
+int extract_many_words(const char **p, const char *separators, unsigned flags, ...) {
         va_list ap;
         char **l;
         int n = 0, i, c, r;
diff --git a/src/systemd/src/basic/extract-word.h b/src/systemd/src/basic/extract-word.h
index 21db5ef3..04746c6d 100644
--- a/src/systemd/src/basic/extract-word.h
+++ b/src/systemd/src/basic/extract-word.h
@@ -32,4 +32,4 @@ typedef enum ExtractFlags {
 
 int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
 int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
+int extract_many_words(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c
index d1c988e1..1c327d83 100644
--- a/src/systemd/src/basic/fd-util.c
+++ b/src/systemd/src/basic/fd-util.c
@@ -33,6 +33,7 @@
 #include "missing.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "process-util.h"
 #include "socket-util.h"
 #include "stdio-util.h"
 #include "util.h"
@@ -285,7 +286,7 @@ int same_fd(int a, int b) {
                 return true;
 
         /* Try to use kcmp() if we have it. */
-        pid = getpid();
+        pid = getpid_cached();
         r = kcmp(pid, pid, KCMP_FILE, a, b);
         if (r == 0)
                 return true;
diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c
index 711580a4..51d1c052 100644
--- a/src/systemd/src/basic/fileio.c
+++ b/src/systemd/src/basic/fileio.c
@@ -32,6 +32,7 @@
 
 #include "alloc-util.h"
 #include "ctype.h"
+#include "def.h"
 #include "env-util.h"
 #include "escape.h"
 #include "fd-util.h"
@@ -43,6 +44,7 @@
 #include "missing.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "process-util.h"
 #include "random-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
@@ -53,19 +55,39 @@
 
 #define READ_FULL_BYTES_MAX (4U*1024U*1024U)
 
-int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
+#if 0 /* NM_IGNORED */
+int write_string_stream_ts(
+                FILE *f,
+                const char *line,
+                WriteStringFileFlags flags,
+                struct timespec *ts) {
 
         assert(f);
         assert(line);
 
         fputs(line, f);
-        if (enforce_newline && !endswith(line, "\n"))
+        if (!(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n"))
                 fputc('\n', f);
 
-        return fflush_and_check(f);
+        if (ts) {
+                struct timespec twice[2] = {*ts, *ts};
+
+                if (futimens(fileno(f), twice) < 0)
+                        return -errno;
+        }
+
+        if (flags & WRITE_STRING_FILE_SYNC)
+                return fflush_sync_and_check(f);
+        else
+                return fflush_and_check(f);
 }
 
-static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) {
+static int write_string_file_atomic(
+                const char *fn,
+                const char *line,
+                WriteStringFileFlags flags,
+                struct timespec *ts) {
+
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_free_ char *p = NULL;
         int r;
@@ -79,34 +101,47 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
 
         (void) fchmod_umask(fileno(f), 0644);
 
-        r = write_string_stream(f, line, enforce_newline);
-        if (r >= 0) {
-                if (rename(p, fn) < 0)
-                        r = -errno;
+        r = write_string_stream_ts(f, line, flags, ts);
+        if (r < 0)
+                goto fail;
+
+        if (rename(p, fn) < 0) {
+                r = -errno;
+                goto fail;
         }
 
-        if (r < 0)
-                (void) unlink(p);
+        return 0;
 
+fail:
+        (void) unlink(p);
         return r;
 }
 
-int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
+int write_string_file_ts(
+                const char *fn,
+                const char *line,
+                WriteStringFileFlags flags,
+                struct timespec *ts) {
+
         _cleanup_fclose_ FILE *f = NULL;
         int q, r;
 
         assert(fn);
         assert(line);
 
+        /* We don't know how to verify whether the file contents was already on-disk. */
+        assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
+
         if (flags & WRITE_STRING_FILE_ATOMIC) {
                 assert(flags & WRITE_STRING_FILE_CREATE);
 
-                r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+                r = write_string_file_atomic(fn, line, flags, ts);
                 if (r < 0)
                         goto fail;
 
                 return r;
-        }
+        } else
+                assert(ts == NULL);
 
         if (flags & WRITE_STRING_FILE_CREATE) {
                 f = fopen(fn, "we");
@@ -133,7 +168,7 @@ int write_string_file(const char *fn, const char *line, WriteStringFileFlags fla
                 }
         }
 
-        r = write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+        r = write_string_stream_ts(f, line, flags, ts);
         if (r < 0)
                 goto fail;
 
@@ -157,7 +192,7 @@ fail:
 
 int read_one_line_file(const char *fn, char **line) {
         _cleanup_fclose_ FILE *f = NULL;
-        char t[LINE_MAX], *c;
+        int r;
 
         assert(fn);
         assert(line);
@@ -166,22 +201,10 @@ int read_one_line_file(const char *fn, char **line) {
         if (!f)
                 return -errno;
 
-        if (!fgets(t, sizeof(t), f)) {
-
-                if (ferror(f))
-                        return errno > 0 ? -errno : -EIO;
-
-                t[0] = 0;
-        }
-
-        c = strdup(t);
-        if (!c)
-                return -ENOMEM;
-        truncate_nl(c);
-
-        *line = c;
-        return 0;
+        r = read_line(f, LONG_LINE_MAX, line);
+        return r < 0 ? r : 0;
 }
+#endif /* NM_IGNORED */
 
 int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
         _cleanup_fclose_ FILE *f = NULL;
@@ -239,11 +262,11 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
                 if (st.st_size > READ_FULL_BYTES_MAX)
                         return -E2BIG;
 
-                /* Start with the right file size, but be prepared for
-                 * files from /proc which generally report a file size
-                 * of 0 */
+                /* Start with the right file size, but be prepared for files from /proc which generally report a file
+                 * size of 0. Note that we increase the size to read here by one, so that the first read attempt
+                 * already makes us notice the EOF. */
                 if (st.st_size > 0)
-                        n = st.st_size;
+                        n = st.st_size + 1;
         }
 
         l = 0;
@@ -256,12 +279,13 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
                         return -ENOMEM;
 
                 buf = t;
+                errno = 0;
                 k = fread(buf + l, 1, n - l, f);
                 if (k > 0)
                         l += k;
 
                 if (ferror(f))
-                        return -errno;
+                        return errno > 0 ? -errno : -EIO;
 
                 if (feof(f))
                         break;
@@ -818,29 +842,29 @@ static void write_env_var(FILE *f, const char *v) {
         p = strchr(v, '=');
         if (!p) {
                 /* Fallback */
-                fputs(v, f);
-                fputc('\n', f);
+                fputs_unlocked(v, f);
+                fputc_unlocked('\n', f);
                 return;
         }
 
         p++;
-        fwrite(v, 1, p-v, f);
+        fwrite_unlocked(v, 1, p-v, f);
 
         if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
-                fputc('\"', f);
+                fputc_unlocked('\"', f);
 
                 for (; *p; p++) {
                         if (strchr(SHELL_NEED_ESCAPE, *p))
-                                fputc('\\', f);
+                                fputc_unlocked('\\', f);
 
-                        fputc(*p, f);
+                        fputc_unlocked(*p, f);
                 }
 
-                fputc('\"', f);
+                fputc_unlocked('\"', f);
         } else
-                fputs(p, f);
+                fputs_unlocked(p, f);
 
-        fputc('\n', f);
+        fputc_unlocked('\n', f);
 }
 
 int write_env_file(const char *fname, char **l) {
@@ -871,7 +895,6 @@ int write_env_file(const char *fname, char **l) {
         unlink(p);
         return r;
 }
-#endif /* NM_IGNORED */
 
 int executable_is_script(const char *path, char **interpreter) {
         int r;
@@ -901,6 +924,7 @@ int executable_is_script(const char *path, char **interpreter) {
         *interpreter = ans;
         return 1;
 }
+#endif /* NM_IGNORED */
 
 /**
  * Retrieve one field from a file like /proc/self/status.  pattern
@@ -1123,6 +1147,21 @@ int fflush_and_check(FILE *f) {
         return 0;
 }
 
+int fflush_sync_and_check(FILE *f) {
+        int r;
+
+        assert(f);
+
+        r = fflush_and_check(f);
+        if (r < 0)
+                return r;
+
+        if (fsync(fileno(f)) < 0)
+                return -errno;
+
+        return 0;
+}
+
 /* This is much like mkostemp() but is subject to umask(). */
 int mkostemp_safe(char *pattern) {
         _cleanup_umask_ mode_t u = 0;
@@ -1171,6 +1210,7 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
         return 0;
 }
 
+#if 0 /* NM_IGNORED */
 int tempfn_random(const char *p, const char *extra, char **ret) {
         const char *fn;
         char *t, *x;
@@ -1213,7 +1253,6 @@ int tempfn_random(const char *p, const char *extra, char **ret) {
         return 0;
 }
 
-#if 0 /* NM_IGNORED */
 int tempfn_random_child(const char *p, const char *extra, char **ret) {
         char *t, *x;
         uint64_t u;
@@ -1400,7 +1439,7 @@ int open_serialization_fd(const char *ident) {
         if (fd < 0) {
                 const char *path;
 
-                path = getpid() == 1 ? "/run/systemd" : "/tmp";
+                path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
                 fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
                 if (fd < 0)
                         return fd;
@@ -1498,4 +1537,78 @@ int mkdtemp_malloc(const char *template, char **ret) {
         *ret = p;
         return 0;
 }
+
+static inline void funlockfilep(FILE **f) {
+        funlockfile(*f);
+}
+
+int read_line(FILE *f, size_t limit, char **ret) {
+        _cleanup_free_ char *buffer = NULL;
+        size_t n = 0, allocated = 0, count = 0;
+
+        assert(f);
+
+        /* Something like a bounded version of getline().
+         *
+         * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string
+         * returned.
+         *
+         * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
+         * the number of characters in the returned string). When EOF is hit, 0 is returned.
+         *
+         * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
+         * delimiters. If the limit is hit we fail and return -ENOBUFS.
+         *
+         * If a line shall be skipped ret may be initialized as NULL. */
+
+        if (ret) {
+                if (!GREEDY_REALLOC(buffer, allocated, 1))
+                        return -ENOMEM;
+        }
+
+        {
+                _cleanup_(funlockfilep) FILE *flocked = f;
+                flockfile(f);
+
+                for (;;) {
+                        int c;
+
+                        if (n >= limit)
+                                return -ENOBUFS;
+
+                        errno = 0;
+                        c = fgetc_unlocked(f);
+                        if (c == EOF) {
+                                /* if we read an error, and have no data to return, then propagate the error */
+                                if (ferror_unlocked(f) && n == 0)
+                                        return errno > 0 ? -errno : -EIO;
+
+                                break;
+                        }
+
+                        count++;
+
+                        if (IN_SET(c, '\n', 0)) /* Reached a delimiter */
+                                break;
+
+                        if (ret) {
+                                if (!GREEDY_REALLOC(buffer, allocated, n + 2))
+                                        return -ENOMEM;
+
+                                buffer[n] = (char) c;
+                        }
+
+                        n++;
+                }
+        }
+
+        if (ret) {
+                buffer[n] = 0;
+
+                *ret = buffer;
+                buffer = NULL;
+        }
+
+        return (int) count;
+}
 #endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/fileio.h b/src/systemd/src/basic/fileio.h
index e547614c..eba05be2 100644
--- a/src/systemd/src/basic/fileio.h
+++ b/src/systemd/src/basic/fileio.h
@@ -29,14 +29,21 @@
 #include "time-util.h"
 
 typedef enum {
-        WRITE_STRING_FILE_CREATE = 1,
-        WRITE_STRING_FILE_ATOMIC = 2,
-        WRITE_STRING_FILE_AVOID_NEWLINE = 4,
-        WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8,
+        WRITE_STRING_FILE_CREATE = 1<<0,
+        WRITE_STRING_FILE_ATOMIC = 1<<1,
+        WRITE_STRING_FILE_AVOID_NEWLINE = 1<<2,
+        WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1<<3,
+        WRITE_STRING_FILE_SYNC = 1<<4,
 } WriteStringFileFlags;
 
-int write_string_stream(FILE *f, const char *line, bool enforce_newline);
-int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags);
+int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts);
+static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
+        return write_string_stream_ts(f, line, flags, NULL);
+}
+int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, struct timespec *ts);
+static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
+        return write_string_file_ts(fn, line, flags, NULL);
+}
 
 int read_one_line_file(const char *fn, char **line);
 int read_full_file(const char *fn, char **contents, size_t *size);
@@ -71,6 +78,7 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
                 } else
 
 int fflush_and_check(FILE *f);
+int fflush_sync_and_check(FILE *f);
 
 int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
 int mkostemp_safe(char *pattern);
@@ -93,3 +101,5 @@ int link_tmpfile(int fd, const char *path, const char *target);
 int read_nul_string(FILE *f, char **ret);
 
 int mkdtemp_malloc(const char *template, char **ret);
+
+int read_line(FILE *f, size_t limit, char **ret);
diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c
index 5e980329..ff4ad5ab 100644
--- a/src/systemd/src/basic/fs-util.c
+++ b/src/systemd/src/basic/fs-util.c
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <linux/magic.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -314,7 +315,7 @@ int fd_warn_permissions(const char *path, int fd) {
         if (st.st_mode & 0002)
                 log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
 
-        if (getpid() == 1 && (st.st_mode & 0044) != 0044)
+        if (getpid_cached() == 1 && (st.st_mode & 0044) != 0044)
                 log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
 
         return 0;
@@ -330,7 +331,7 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
                 mkdir_parents(path, 0755);
 
         fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY,
-                        (mode == 0 || mode == MODE_INVALID) ? 0644 : mode);
+                  IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode);
         if (fd < 0)
                 return -errno;
 
@@ -365,22 +366,25 @@ int touch(const char *path) {
 }
 
 int symlink_idempotent(const char *from, const char *to) {
-        _cleanup_free_ char *p = NULL;
         int r;
 
         assert(from);
         assert(to);
 
         if (symlink(from, to) < 0) {
+                _cleanup_free_ char *p = NULL;
+
                 if (errno != EEXIST)
                         return -errno;
 
                 r = readlink_malloc(to, &p);
-                if (r < 0)
+                if (r == -EINVAL) /* Not a symlink? In that case return the original error we encountered: -EEXIST */
+                        return -EEXIST;
+                if (r < 0) /* Any other error? In that case propagate it as is */
                         return r;
 
-                if (!streq(p, from))
-                        return -EINVAL;
+                if (!streq(p, from)) /* Not the symlink we want it to be? In that case, propagate the original -EEXIST */
+                        return -EEXIST;
         }
 
         return 0;
@@ -728,6 +732,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
 
                 if (fstat(child, &st) < 0)
                         return -errno;
+                if ((flags & CHASE_NO_AUTOFS) &&
+                    fd_check_fstype(child, AUTOFS_SUPER_MAGIC) > 0)
+                        return -EREMOTE;
 
                 if (S_ISLNK(st.st_mode)) {
                         char *joined;
diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h
index 094acf17..d3342d5c 100644
--- a/src/systemd/src/basic/fs-util.h
+++ b/src/systemd/src/basic/fs-util.h
@@ -81,6 +81,7 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask);
 enum {
         CHASE_PREFIX_ROOT = 1,   /* If set, the specified path will be prefixed by the specified root before beginning the iteration */
         CHASE_NONEXISTENT = 2,   /* If set, it's OK if the path doesn't actually exist. */
+        CHASE_NO_AUTOFS = 4,     /* If set, return -EREMOTE if autofs mount point found */
 };
 
 int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret);
diff --git a/src/systemd/src/basic/hashmap.c b/src/systemd/src/basic/hashmap.c
index dc6bcab0..c95d4991 100644
--- a/src/systemd/src/basic/hashmap.c
+++ b/src/systemd/src/basic/hashmap.c
@@ -36,7 +36,7 @@
 #include "strv.h"
 #include "util.h"
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
 #include <pthread.h>
 #include "list.h"
 #endif
@@ -144,7 +144,7 @@ typedef uint8_t dib_raw_t;
 
 #define DIB_FREE UINT_MAX
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
 struct hashmap_debug_info {
         LIST_FIELDS(struct hashmap_debug_info, debug_list);
         unsigned max_entries;  /* high watermark of n_entries */
@@ -501,7 +501,7 @@ static void base_remove_entry(HashmapBase *h, unsigned idx) {
         dibs = dib_raw_ptr(h);
         assert(dibs[idx] != DIB_RAW_FREE);
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         h->debug.rem_count++;
         h->debug.last_rem_idx = idx;
 #endif
@@ -510,7 +510,7 @@ static void base_remove_entry(HashmapBase *h, unsigned idx) {
         /* Find the stop bucket ("right"). It is either free or has DIB == 0. */
         for (right = next_idx(h, left); ; right = next_idx(h, right)) {
                 raw_dib = dibs[right];
-                if (raw_dib == 0 || raw_dib == DIB_RAW_FREE)
+                if (IN_SET(raw_dib, 0, DIB_RAW_FREE))
                         break;
 
                 /* The buckets are not supposed to be all occupied and with DIB > 0.
@@ -580,7 +580,7 @@ static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *
                 assert(e->p.b.key == i->next_key);
         }
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         i->prev_idx = idx;
 #endif
 
@@ -637,7 +637,7 @@ static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
         }
 
         idx = i->idx;
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         i->prev_idx = idx;
 #endif
 
@@ -660,7 +660,7 @@ static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
                 return IDX_NIL;
         }
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         if (i->idx == IDX_FIRST) {
                 i->put_count = h->debug.put_count;
                 i->rem_count = h->debug.rem_count;
@@ -752,7 +752,7 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
                 shared_hash_key_initialized= true;
         }
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         h->debug.func = func;
         h->debug.file = file;
         h->debug.line = line;
@@ -809,7 +809,7 @@ static void hashmap_free_no_clear(HashmapBase *h) {
         assert(!h->has_indirect);
         assert(!h->n_direct_entries);
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
         LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug);
         assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
@@ -921,7 +921,7 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
         dib_raw_t raw_dib, *dibs;
         unsigned dib, distance;
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         h->debug.put_count++;
 #endif
 
@@ -929,7 +929,7 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
 
         for (distance = 0; ; distance++) {
                 raw_dib = dibs[idx];
-                if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) {
+                if (IN_SET(raw_dib, DIB_RAW_FREE, DIB_RAW_REHASH)) {
                         if (raw_dib == DIB_RAW_REHASH)
                                 bucket_move_entry(h, swap, idx, IDX_TMP);
 
@@ -1014,7 +1014,7 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
         assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
 
         n_entries_inc(h);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h));
 #endif
 
@@ -1242,7 +1242,7 @@ int hashmap_replace(Hashmap *h, const void *key, void *value) {
         idx = bucket_scan(h, hash, key);
         if (idx != IDX_NIL) {
                 e = plain_bucket_at(h, idx);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
                 /* Although the key is equal, the key pointer may have changed,
                  * and this would break our assumption for iterating. So count
                  * this operation as incompatible with iteration. */
diff --git a/src/systemd/src/basic/hashmap.h b/src/systemd/src/basic/hashmap.h
index 6d1ae48b..c1089652 100644
--- a/src/systemd/src/basic/hashmap.h
+++ b/src/systemd/src/basic/hashmap.h
@@ -58,7 +58,7 @@ typedef struct Set Set;                       /* Stores just keys */
 typedef struct {
         unsigned idx;         /* index of an entry to be iterated next */
         const void *next_key; /* expected value of that entry's key pointer */
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
         unsigned put_count;   /* hashmap's put_count recorded at start of iteration */
         unsigned rem_count;   /* hashmap's rem_count in previous iteration */
         unsigned prev_idx;    /* idx in previous iteration */
@@ -89,7 +89,7 @@ typedef struct {
                 (Hashmap*)(h), \
                 (void)0)
 
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
 # define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line
 # define HASHMAP_DEBUG_SRC_ARGS   , __func__, __FILE__, __LINE__
 # define HASHMAP_DEBUG_PASS_ARGS   , func, file, line
diff --git a/src/systemd/src/basic/hexdecoct.c b/src/systemd/src/basic/hexdecoct.c
index 2da8f8a2..e0ae83c1 100644
--- a/src/systemd/src/basic/hexdecoct.c
+++ b/src/systemd/src/basic/hexdecoct.c
@@ -27,6 +27,7 @@
 #include "alloc-util.h"
 #include "hexdecoct.h"
 #include "macro.h"
+#include "string-util.h"
 #include "util.h"
 
 char octchar(int x) {
@@ -571,7 +572,7 @@ static int base64_append_width(char **prefix, int plen,
 
         lines = (len + width - 1) / width;
 
-        slen = sep ? strlen(sep) : 0;
+        slen = strlen_ptr(sep);
         t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
         if (!t)
                 return -ENOMEM;
diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c
index 823aa26a..be6e9e58 100644
--- a/src/systemd/src/basic/hostname-util.c
+++ b/src/systemd/src/basic/hostname-util.c
@@ -94,9 +94,7 @@ static bool hostname_valid_char(char c) {
                 (c >= 'a' && c <= 'z') ||
                 (c >= 'A' && c <= 'Z') ||
                 (c >= '0' && c <= '9') ||
-                c == '-' ||
-                c == '_' ||
-                c == '.';
+                IN_SET(c, '-', '_', '.');
 }
 
 /**
@@ -201,8 +199,11 @@ bool is_gateway_hostname(const char *hostname) {
          * synthetic "gateway" host. */
 
         return
-                strcaseeq(hostname, "gateway") ||
-                strcaseeq(hostname, "gateway.");
+                strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.")
+#if ENABLE_COMPAT_GATEWAY_HOSTNAME
+                || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.")
+#endif
+                ;
 }
 
 int sethostname_idempotent(const char *s) {
@@ -237,7 +238,7 @@ int read_hostname_config(const char *path, char **hostname) {
         /* may have comments, ignore them */
         FOREACH_LINE(l, f, return -errno) {
                 truncate_nl(l);
-                if (l[0] != '\0' && l[0] != '#') {
+                if (!IN_SET(l[0], '\0', '#')) {
                         /* found line with value */
                         name = hostname_cleanup(l);
                         name = strdup(name);
diff --git a/src/systemd/src/basic/in-addr-util.c b/src/systemd/src/basic/in-addr-util.c
index 1140ca76..2a02d90b 100644
--- a/src/systemd/src/basic/in-addr-util.c
+++ b/src/systemd/src/basic/in-addr-util.c
@@ -310,22 +310,22 @@ int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
         return 0;
 }
 
-int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret) {
+int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
         int r;
 
         assert(s);
 
         r = in_addr_from_string(AF_INET, s, ret);
         if (r >= 0) {
-                if (family)
-                        *family = AF_INET;
+                if (ret_family)
+                        *ret_family = AF_INET;
                 return 0;
         }
 
         r = in_addr_from_string(AF_INET6, s, ret);
         if (r >= 0) {
-                if (family)
-                        *family = AF_INET6;
+                if (ret_family)
+                        *ret_family = AF_INET6;
                 return 0;
         }
 
@@ -373,13 +373,13 @@ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_u
         return r;
 }
 
-unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
+unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
         assert(addr);
 
         return 32 - u32ctz(be32toh(addr->s_addr));
 }
 
-struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
+struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
         assert(addr);
         assert(prefixlen <= 32);
 
@@ -392,7 +392,7 @@ struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char
         return addr;
 }
 
-int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
+int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
         uint8_t msb_octet = *(uint8_t*) addr;
 
         /* addr may not be aligned, so make sure we only access it byte-wise */
@@ -416,28 +416,29 @@ int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixl
         return 0;
 }
 
-int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
+int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
         unsigned char prefixlen;
         int r;
 
         assert(addr);
         assert(mask);
 
-        r = in_addr_default_prefixlen(addr, &prefixlen);
+        r = in4_addr_default_prefixlen(addr, &prefixlen);
         if (r < 0)
                 return r;
 
-        in_addr_prefixlen_to_netmask(mask, prefixlen);
+        in4_addr_prefixlen_to_netmask(mask, prefixlen);
         return 0;
 }
 
+#if 0 /* NM_IGNORED */
 int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
         assert(addr);
 
         if (family == AF_INET) {
                 struct in_addr mask;
 
-                if (!in_addr_prefixlen_to_netmask(&mask, prefixlen))
+                if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
                         return -EINVAL;
 
                 addr->in.s_addr &= mask.s_addr;
@@ -466,3 +467,128 @@ int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen)
 
         return -EAFNOSUPPORT;
 }
+
+int in_addr_prefix_covers(int family,
+                          const union in_addr_union *prefix,
+                          unsigned char prefixlen,
+                          const union in_addr_union *address) {
+
+        union in_addr_union masked_prefix, masked_address;
+        int r;
+
+        assert(prefix);
+        assert(address);
+
+        masked_prefix = *prefix;
+        r = in_addr_mask(family, &masked_prefix, prefixlen);
+        if (r < 0)
+                return r;
+
+        masked_address = *address;
+        r = in_addr_mask(family, &masked_address, prefixlen);
+        if (r < 0)
+                return r;
+
+        return in_addr_equal(family, &masked_prefix, &masked_address);
+}
+
+int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
+        uint8_t u;
+        int r;
+
+        if (!IN_SET(family, AF_INET, AF_INET6))
+                return -EAFNOSUPPORT;
+
+        r = safe_atou8(p, &u);
+        if (r < 0)
+                return r;
+
+        if (u > FAMILY_ADDRESS_SIZE(family) * 8)
+                return -ERANGE;
+
+        *ret = u;
+        return 0;
+}
+
+int in_addr_prefix_from_string(
+                const char *p,
+                int family,
+                union in_addr_union *ret_prefix,
+                unsigned char *ret_prefixlen) {
+
+        union in_addr_union buffer;
+        const char *e, *l;
+        unsigned char k;
+        int r;
+
+        assert(p);
+
+        if (!IN_SET(family, AF_INET, AF_INET6))
+                return -EAFNOSUPPORT;
+
+        e = strchr(p, '/');
+        if (e)
+                l = strndupa(p, e - p);
+        else
+                l = p;
+
+        r = in_addr_from_string(family, l, &buffer);
+        if (r < 0)
+                return r;
+
+        if (e) {
+                r = in_addr_parse_prefixlen(family, e+1, &k);
+                if (r < 0)
+                        return r;
+        } else
+                k = FAMILY_ADDRESS_SIZE(family) * 8;
+
+        if (ret_prefix)
+                *ret_prefix = buffer;
+        if (ret_prefixlen)
+                *ret_prefixlen = k;
+
+        return 0;
+}
+
+int in_addr_prefix_from_string_auto(
+                const char *p,
+                int *ret_family,
+                union in_addr_union *ret_prefix,
+                unsigned char *ret_prefixlen) {
+
+        union in_addr_union buffer;
+        const char *e, *l;
+        unsigned char k;
+        int family, r;
+
+        assert(p);
+
+        e = strchr(p, '/');
+        if (e)
+                l = strndupa(p, e - p);
+        else
+                l = p;
+
+        r = in_addr_from_string_auto(l, &family, &buffer);
+        if (r < 0)
+                return r;
+
+        if (e) {
+                r = in_addr_parse_prefixlen(family, e+1, &k);
+                if (r < 0)
+                        return r;
+        } else
+                k = FAMILY_ADDRESS_SIZE(family) * 8;
+
+        if (ret_family)
+                *ret_family = family;
+        if (ret_prefix)
+                *ret_prefix = buffer;
+        if (ret_prefixlen)
+                *ret_prefixlen = k;
+
+        return 0;
+
+}
+#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/in-addr-util.h b/src/systemd/src/basic/in-addr-util.h
index 51a5aa67..59f8eb7e 100644
--- a/src/systemd/src/basic/in-addr-util.h
+++ b/src/systemd/src/basic/in-addr-util.h
@@ -53,16 +53,20 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
 int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
 int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
 int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
-int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret);
+int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
 int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
-unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr);
-struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
-int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
-int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
+unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
+struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
+int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
+int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
 int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
+int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address);
+int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret);
+int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
+int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
 
 static inline size_t FAMILY_ADDRESS_SIZE(int family) {
-        assert(family == AF_INET || family == AF_INET6);
+        assert(IN_SET(family, AF_INET, AF_INET6));
         return family == AF_INET6 ? 16 : 4;
 }
 
diff --git a/src/systemd/src/basic/io-util.h b/src/systemd/src/basic/io-util.h
index 4684ed3b..d9b69add 100644
--- a/src/systemd/src/basic/io-util.h
+++ b/src/systemd/src/basic/io-util.h
@@ -40,14 +40,6 @@ int fd_wait_for_event(int fd, int event, usec_t timeout);
 
 ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
 
-#define IOVEC_SET_STRING(i, s)                  \
-        do {                                    \
-                struct iovec *_i = &(i);        \
-                char *_s = (char *)(s);         \
-                _i->iov_base = _s;              \
-                _i->iov_len = strlen(_s);       \
-        } while (false)
-
 static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
         unsigned j;
         size_t r = 0;
@@ -93,3 +85,8 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
         return FILE_SIZE_VALID(l);
 
 }
+
+#define IOVEC_INIT(base, len) { .iov_base = (base), .iov_len = (len) }
+#define IOVEC_MAKE(base, len) (struct iovec) IOVEC_INIT(base, len)
+#define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string))
+#define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string)
diff --git a/src/systemd/src/basic/log.h b/src/systemd/src/basic/log.h
index d8335d12..67fda3f9 100644
--- a/src/systemd/src/basic/log.h
+++ b/src/systemd/src/basic/log.h
@@ -30,6 +30,17 @@
 #include "sd-id128.h"
 
 #include "macro.h"
+#include "process-util.h"
+
+typedef enum LogRealm {
+        LOG_REALM_SYSTEMD,
+        LOG_REALM_UDEV,
+        _LOG_REALM_MAX,
+} LogRealm;
+
+#ifndef LOG_REALM
+#  define LOG_REALM LOG_REALM_SYSTEMD
+#endif
 
 typedef enum LogTarget{
         LOG_TARGET_CONSOLE,
@@ -44,14 +55,24 @@ typedef enum LogTarget{
         LOG_TARGET_NULL,
         _LOG_TARGET_MAX,
         _LOG_TARGET_INVALID = -1
-}  LogTarget;
+} LogTarget;
+
+#define LOG_REALM_PLUS_LEVEL(realm, level)      \
+        ((realm) << 10 | (level))
+#define LOG_REALM_REMOVE_LEVEL(realm_level)     \
+        ((realm_level >> 10))
 
 void log_set_target(LogTarget target);
-void log_set_max_level(int level);
+void log_set_max_level_realm(LogRealm realm, int level);
+#define log_set_max_level(level)                \
+        log_set_max_level_realm(LOG_REALM, (level))
+
 void log_set_facility(int facility);
 
 int log_set_target_from_string(const char *e);
-int log_set_max_level_from_string(const char *e);
+int log_set_max_level_from_string_realm(LogRealm realm, const char *e);
+#define log_set_max_level_from_string(e)        \
+        log_set_max_level_from_string_realm(LOG_REALM, (e))
 
 void log_show_color(bool b);
 bool log_get_show_color(void) _pure_;
@@ -62,7 +83,16 @@ int log_show_color_from_string(const char *e);
 int log_show_location_from_string(const char *e);
 
 LogTarget log_get_target(void) _pure_;
-int log_get_max_level(void) _pure_;
+#if 0 /* NM_IGNORED */
+int log_get_max_level_realm(LogRealm realm) _pure_;
+#endif /* NM_IGNORED */
+#define log_get_max_level()                     \
+        log_get_max_level_realm(LOG_REALM)
+
+/* Functions below that open and close logs or configure logging based on the
+ * environment should not be called from library code — this is always a job
+ * for the application itself.
+ */
 
 int log_open(void);
 void log_close(void);
@@ -73,18 +103,36 @@ void log_close_journal(void);
 void log_close_kmsg(void);
 void log_close_console(void);
 
-void log_parse_environment(void);
+void log_parse_environment_realm(LogRealm realm);
+#define log_parse_environment() \
+        log_parse_environment_realm(LOG_REALM)
 
 #if 0 /* NM_IGNORED */
-int log_internal(
+int log_dispatch_internal(
+                int level,
+                int error,
+                const char *file,
+                int line,
+                const char *func,
+                const char *object_field,
+                const char *object,
+                const char *extra,
+                const char *extra_field,
+                char *buffer);
+
+int log_internal_realm(
                 int level,
                 int error,
                 const char *file,
                 int line,
                 const char *func,
                 const char *format, ...) _printf_(6,7);
+#endif /* NM_IGNORED */
+#define log_internal(level, ...) \
+        log_internal_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__)
 
-int log_internalv(
+#if 0 /* NM_IGNORED */
+int log_internalv_realm(
                 int level,
                 int error,
                 const char *file,
@@ -92,7 +140,10 @@ int log_internalv(
                 const char *func,
                 const char *format,
                 va_list ap) _printf_(6,0);
+#define log_internalv(level, ...) \
+        log_internalv_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__)
 
+/* Realm is fixed to LOG_REALM_SYSTEMD for those */
 int log_object_internal(
                 int level,
                 int error,
@@ -116,7 +167,7 @@ int log_object_internalv(
                 const char *extra_field,
                 const char *extra,
                 const char *format,
-                va_list ap) _printf_(9,0);
+                va_list ap) _printf_(10,0);
 
 int log_struct_internal(
                 int level,
@@ -127,6 +178,7 @@ int log_struct_internal(
                 const char *format, ...) _printf_(6,0) _sentinel_;
 
 int log_oom_internal(
+                LogRealm realm,
                 const char *file,
                 int line,
                 const char *func);
@@ -138,7 +190,16 @@ int log_format_iovec(
                 bool newline_separator,
                 int error,
                 const char *format,
-                va_list ap);
+                va_list ap) _printf_(6, 0);
+
+int log_struct_iovec_internal(
+                int level,
+                int error,
+                const char *file,
+                int line,
+                const char *func,
+                const struct iovec input_iovec[],
+                size_t n_input_iovec);
 
 /* This modifies the buffer passed! */
 int log_dump_internal(
@@ -150,35 +211,51 @@ int log_dump_internal(
                 char *buffer);
 
 /* Logging for various assertions */
-noreturn void log_assert_failed(
+noreturn void log_assert_failed_realm(
+                LogRealm realm,
                 const char *text,
                 const char *file,
                 int line,
                 const char *func);
+#define log_assert_failed(text, ...) \
+        log_assert_failed_realm(LOG_REALM, (text), __VA_ARGS__)
 
-noreturn void log_assert_failed_unreachable(
+noreturn void log_assert_failed_unreachable_realm(
+                LogRealm realm,
                 const char *text,
                 const char *file,
                 int line,
                 const char *func);
+#define log_assert_failed_unreachable(text, ...) \
+        log_assert_failed_unreachable_realm(LOG_REALM, (text), __VA_ARGS__)
 
-void log_assert_failed_return(
+void log_assert_failed_return_realm(
+                LogRealm realm,
                 const char *text,
                 const char *file,
                 int line,
                 const char *func);
+#define log_assert_failed_return(text, ...) \
+        log_assert_failed_return_realm(LOG_REALM, (text), __VA_ARGS__)
+
+#define log_dispatch(level, error, buffer)                              \
+        log_dispatch_internal(level, error, __FILE__, __LINE__, __func__, NULL, NULL, NULL, NULL, buffer)
+#endif /* NM_IGNORED */
 
 /* Logging with level */
-#define log_full_errno(level, error, ...)                               \
+#define log_full_errno_realm(realm, level, error, ...)                  \
         ({                                                              \
                 int _level = (level), _e = (error);                     \
-                (log_get_max_level() >= LOG_PRI(_level))                \
-                        ? log_internal(_level, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
+                (log_get_max_level_realm((realm)) >= LOG_PRI(_level))   \
+                        ? log_internal_realm(LOG_REALM_PLUS_LEVEL((realm), _level), _e, \
+                                             __FILE__, __LINE__, __func__, __VA_ARGS__) \
                         : -abs(_e);                                     \
         })
-#endif /* NM_IGNORED */
 
-#define log_full(level, ...) log_full_errno(level, 0, __VA_ARGS__)
+#define log_full_errno(level, error, ...)                               \
+        log_full_errno_realm(LOG_REALM, (level), (error), __VA_ARGS__)
+
+#define log_full(level, ...) log_full_errno((level), 0, __VA_ARGS__)
 
 /* Normal logging */
 #define log_debug(...)     log_full(LOG_DEBUG,   __VA_ARGS__)
@@ -186,7 +263,7 @@ void log_assert_failed_return(
 #define log_notice(...)    log_full(LOG_NOTICE,  __VA_ARGS__)
 #define log_warning(...)   log_full(LOG_WARNING, __VA_ARGS__)
 #define log_error(...)     log_full(LOG_ERR,     __VA_ARGS__)
-#define log_emergency(...) log_full(getpid() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
+#define log_emergency(...) log_full(getpid_cached() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
 
 /* Logging triggered by an errno-like error */
 #define log_debug_errno(error, ...)     log_full_errno(LOG_DEBUG,   error, __VA_ARGS__)
@@ -194,7 +271,7 @@ void log_assert_failed_return(
 #define log_notice_errno(error, ...)    log_full_errno(LOG_NOTICE,  error, __VA_ARGS__)
 #define log_warning_errno(error, ...)   log_full_errno(LOG_WARNING, error, __VA_ARGS__)
 #define log_error_errno(error, ...)     log_full_errno(LOG_ERR,     error, __VA_ARGS__)
-#define log_emergency_errno(error, ...) log_full_errno(getpid() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
+#define log_emergency_errno(error, ...) log_full_errno(getpid_cached() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
 
 #ifdef LOG_TRACE
 #  define log_trace(...) log_debug(__VA_ARGS__)
@@ -203,13 +280,22 @@ void log_assert_failed_return(
 #endif
 
 /* Structured logging */
-#define log_struct(level, ...) log_struct_internal(level, 0, __FILE__, __LINE__, __func__, __VA_ARGS__)
-#define log_struct_errno(level, error, ...) log_struct_internal(level, error, __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define log_struct_errno(level, error, ...) \
+        log_struct_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
+                            error, __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__)
+
+#define log_struct_iovec_errno(level, error, iovec, n_iovec)            \
+        log_struct_iovec_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
+                                  error, __FILE__, __LINE__, __func__, iovec, n_iovec)
+#define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec)
 
 /* This modifies the buffer passed! */
-#define log_dump(level, buffer) log_dump_internal(level, 0, __FILE__, __LINE__, __func__, buffer)
+#define log_dump(level, buffer) \
+        log_dump_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
+                          0, __FILE__, __LINE__, __func__, buffer)
 
-#define log_oom() log_oom_internal(__FILE__, __LINE__, __func__)
+#define log_oom() log_oom_internal(LOG_REALM, __FILE__, __LINE__, __func__)
 
 bool log_on_console(void) _pure_;
 
@@ -223,6 +309,7 @@ void log_received_signal(int level, const struct signalfd_siginfo *si);
 
 void log_set_upgrade_syslog_to_journal(bool b);
 void log_set_always_reopen_console(bool b);
+void log_set_open_when_needed(bool b);
 
 int log_syntax_internal(
                 const char *unit,
diff --git a/src/systemd/src/basic/macro.h b/src/systemd/src/basic/macro.h
index 7db87b49..afcde459 100644
--- a/src/systemd/src/basic/macro.h
+++ b/src/systemd/src/basic/macro.h
@@ -19,7 +19,6 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <assert.h>
 #include <inttypes.h>
 #include <stdbool.h>
 #include <sys/param.h>
diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c
index 8ffd9464..6d978e93 100644
--- a/src/systemd/src/basic/parse-util.c
+++ b/src/systemd/src/basic/parse-util.c
@@ -44,6 +44,7 @@ int parse_boolean(const char *v) {
         return -EINVAL;
 }
 
+#if 0 /* NM_IGNORED */
 int parse_pid(const char *s, pid_t* ret_pid) {
         unsigned long ul = 0;
         pid_t pid;
@@ -61,12 +62,13 @@ int parse_pid(const char *s, pid_t* ret_pid) {
         if ((unsigned long) pid != ul)
                 return -ERANGE;
 
-        if (pid <= 0)
+        if (!pid_is_valid(pid))
                 return -ERANGE;
 
         *ret_pid = pid;
         return 0;
 }
+#endif /* NM_IGNORED */
 
 int parse_mode(const char *s, mode_t *ret) {
         char *x;
@@ -154,7 +156,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
         unsigned n_entries, start_pos = 0;
 
         assert(t);
-        assert(base == 1000 || base == 1024);
+        assert(IN_SET(base, 1000, 1024));
         assert(size);
 
         if (base == 1000) {
@@ -594,4 +596,19 @@ int parse_ip_port(const char *s, uint16_t *ret) {
 
         return 0;
 }
+
+int parse_dev(const char *s, dev_t *ret) {
+        unsigned x, y;
+        dev_t d;
+
+        if (sscanf(s, "%u:%u", &x, &y) != 2)
+                return -EINVAL;
+
+        d = makedev(x, y);
+        if ((unsigned) major(d) != x || (unsigned) minor(d) != y)
+                return -EINVAL;
+
+        *ret = d;
+        return 0;
+}
 #endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h
index 4d132f0d..dc09782c 100644
--- a/src/systemd/src/basic/parse-util.h
+++ b/src/systemd/src/basic/parse-util.h
@@ -30,6 +30,7 @@
 #define MODE_INVALID ((mode_t) -1)
 
 int parse_boolean(const char *v) _pure_;
+int parse_dev(const char *s, dev_t *ret);
 int parse_pid(const char *s, pid_t* ret_pid);
 int parse_mode(const char *s, mode_t *ret);
 int parse_ifindex(const char *s, int *ret);
diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c
index 12ba6ae7..1bdcc653 100644
--- a/src/systemd/src/basic/path-util.c
+++ b/src/systemd/src/basic/path-util.c
@@ -134,8 +134,7 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
 
         /* Skip the common part. */
         for (;;) {
-                size_t a;
-                size_t b;
+                size_t a, b;
 
                 from_dir += strspn(from_dir, "/");
                 to_path += strspn(to_path, "/");
@@ -147,7 +146,6 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
                         else
                                 /* from_dir is a parent directory of to_path. */
                                 r = strdup(to_path);
-
                         if (!r)
                                 return -ENOMEM;
 
@@ -178,21 +176,32 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
 
         /* Count the number of necessary ".." elements. */
         for (n_parents = 0;;) {
+                size_t w;
+
                 from_dir += strspn(from_dir, "/");
 
                 if (!*from_dir)
                         break;
 
-                from_dir += strcspn(from_dir, "/");
-                n_parents++;
+                w = strcspn(from_dir, "/");
+
+                /* If this includes ".." we can't do a simple series of "..", refuse */
+                if (w == 2 && from_dir[0] == '.' && from_dir[1] == '.')
+                        return -EINVAL;
+
+                /* Count number of elements, except if they are "." */
+                if (w != 1 || from_dir[0] != '.')
+                        n_parents++;
+
+                from_dir += w;
         }
 
-        r = malloc(n_parents * 3 + strlen(to_path) + 1);
+        r = new(char, n_parents * 3 + strlen(to_path) + 1);
         if (!r)
                 return -ENOMEM;
 
-        for (p = r; n_parents > 0; n_parents--, p += 3)
-                memcpy(p, "../", 3);
+        for (p = r; n_parents > 0; n_parents--)
+                p = mempcpy(p, "../", 3);
 
         strcpy(p, to_path);
         path_kill_slashes(r);
@@ -447,8 +456,8 @@ bool path_equal(const char *a, const char *b) {
         return path_compare(a, b) == 0;
 }
 
-bool path_equal_or_files_same(const char *a, const char *b) {
-        return path_equal(a, b) || files_same(a, b) > 0;
+bool path_equal_or_files_same(const char *a, const char *b, int flags) {
+        return path_equal(a, b) || files_same(a, b, flags) > 0;
 }
 
 char* path_join(const char *root, const char *path, const char *rest) {
diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h
index 35aef3ad..399ed5f9 100644
--- a/src/systemd/src/basic/path-util.h
+++ b/src/systemd/src/basic/path-util.h
@@ -27,14 +27,16 @@
 #include "string-util.h"
 #include "time-util.h"
 
+#if 0 /* NM_IGNORED */
 #define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
 #define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin"
 
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
 #  define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR
 #else
 #  define DEFAULT_PATH DEFAULT_PATH_NORMAL
 #endif
+#endif /* NM_IGNORED */
 
 bool is_path(const char *p) _pure_;
 int path_split_and_make_absolute(const char *p, char ***ret);
@@ -46,7 +48,7 @@ char* path_kill_slashes(char *path);
 char* path_startswith(const char *path, const char *prefix) _pure_;
 int path_compare(const char *a, const char *b) _pure_;
 bool path_equal(const char *a, const char *b) _pure_;
-bool path_equal_or_files_same(const char *a, const char *b);
+bool path_equal_or_files_same(const char *a, const char *b, int flags);
 char* path_join(const char *root, const char *path, const char *rest);
 
 static inline bool path_equal_ptr(const char *a, const char *b) {
@@ -143,3 +145,13 @@ bool is_deviceallow_pattern(const char *path);
 int systemd_installation_has_version(const char *root, unsigned minimal_version);
 
 bool dot_or_dot_dot(const char *path);
+
+static inline const char *skip_dev_prefix(const char *p) {
+        const char *e;
+
+        /* Drop any /dev prefix if there is any */
+
+        e = path_startswith(p, "/dev/");
+
+        return e ?: p;
+}
diff --git a/src/systemd/src/basic/process-util.c b/src/systemd/src/basic/process-util.c
new file mode 100644
index 00000000..272030d1
--- /dev/null
+++ b/src/systemd/src/basic/process-util.c
@@ -0,0 +1,1093 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "nm-sd-adapt.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <linux/oom.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/personality.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <syslog.h>
+#include <unistd.h>
+#if 0 /* NM_IGNORED */
+#if HAVE_VALGRIND_VALGRIND_H
+#include <valgrind/valgrind.h>
+#endif
+#endif /* NM_IGNORED */
+
+#include "alloc-util.h"
+#include "architecture.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "ioprio.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "process-util.h"
+#include "raw-clone.h"
+#include "signal-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
+
+#if 0 /* NM_IGNORED */
+int get_process_state(pid_t pid) {
+        const char *p;
+        char state;
+        int r;
+        _cleanup_free_ char *line = NULL;
+
+        assert(pid >= 0);
+
+        p = procfs_file_alloca(pid, "stat");
+
+        r = read_one_line_file(p, &line);
+        if (r == -ENOENT)
+                return -ESRCH;
+        if (r < 0)
+                return r;
+
+        p = strrchr(line, ')');
+        if (!p)
+                return -EIO;
+
+        p++;
+
+        if (sscanf(p, " %c", &state) != 1)
+                return -EIO;
+
+        return (unsigned char) state;
+}
+
+int get_process_comm(pid_t pid, char **name) {
+        const char *p;
+        int r;
+
+        assert(name);
+        assert(pid >= 0);
+
+        p = procfs_file_alloca(pid, "comm");
+
+        r = read_one_line_file(p, name);
+        if (r == -ENOENT)
+                return -ESRCH;
+
+        return r;
+}
+
+int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
+        _cleanup_fclose_ FILE *f = NULL;
+        bool space = false;
+        char *k, *ans = NULL;
+        const char *p;
+        int c;
+
+        assert(line);
+        assert(pid >= 0);
+
+        /* Retrieves a process' command line. Replaces unprintable characters while doing so by whitespace (coalescing
+         * multiple sequential ones into one). If max_length is != 0 will return a string of the specified size at most
+         * (the trailing NUL byte does count towards the length here!), abbreviated with a "..." ellipsis. If
+         * comm_fallback is true and the process has no command line set (the case for kernel threads), or has a
+         * command line that resolves to the empty string will return the "comm" name of the process instead.
+         *
+         * Returns -ESRCH if the process doesn't exist, and -ENOENT if the process has no command line (and
+         * comm_fallback is false). Returns 0 and sets *line otherwise. */
+
+        p = procfs_file_alloca(pid, "cmdline");
+
+        f = fopen(p, "re");
+        if (!f) {
+                if (errno == ENOENT)
+                        return -ESRCH;
+                return -errno;
+        }
+
+        if (max_length == 1) {
+
+                /* If there's only room for one byte, return the empty string */
+                ans = new0(char, 1);
+                if (!ans)
+                        return -ENOMEM;
+
+                *line = ans;
+                return 0;
+
+        } else if (max_length == 0) {
+                size_t len = 0, allocated = 0;
+
+                while ((c = getc(f)) != EOF) {
+
+                        if (!GREEDY_REALLOC(ans, allocated, len+3)) {
+                                free(ans);
+                                return -ENOMEM;
+                        }
+
+                        if (isprint(c)) {
+                                if (space) {
+                                        ans[len++] = ' ';
+                                        space = false;
+                                }
+
+                                ans[len++] = c;
+                        } else if (len > 0)
+                                space = true;
+               }
+
+                if (len > 0)
+                        ans[len] = '\0';
+                else
+                        ans = mfree(ans);
+
+        } else {
+                bool dotdotdot = false;
+                size_t left;
+
+                ans = new(char, max_length);
+                if (!ans)
+                        return -ENOMEM;
+
+                k = ans;
+                left = max_length;
+                while ((c = getc(f)) != EOF) {
+
+                        if (isprint(c)) {
+
+                                if (space) {
+                                        if (left <= 2) {
+                                                dotdotdot = true;
+                                                break;
+                                        }
+
+                                        *(k++) = ' ';
+                                        left--;
+                                        space = false;
+                                }
+
+                                if (left <= 1) {
+                                        dotdotdot = true;
+                                        break;
+                                }
+
+                                *(k++) = (char) c;
+                                left--;
+                        } else if (k > ans)
+                                space = true;
+                }
+
+                if (dotdotdot) {
+                        if (max_length <= 4) {
+                                k = ans;
+                                left = max_length;
+                        } else {
+                                k = ans + max_length - 4;
+                                left = 4;
+
+                                /* Eat up final spaces */
+                                while (k > ans && isspace(k[-1])) {
+                                        k--;
+                                        left++;
+                                }
+                        }
+
+                        strncpy(k, "...", left-1);
+                        k[left-1] = 0;
+                } else
+                        *k = 0;
+        }
+
+        /* Kernel threads have no argv[] */
+        if (isempty(ans)) {
+                _cleanup_free_ char *t = NULL;
+                int h;
+
+                free(ans);
+
+                if (!comm_fallback)
+                        return -ENOENT;
+
+                h = get_process_comm(pid, &t);
+                if (h < 0)
+                        return h;
+
+                if (max_length == 0)
+                        ans = strjoin("[", t, "]");
+                else {
+                        size_t l;
+
+                        l = strlen(t);
+
+                        if (l + 3 <= max_length)
+                                ans = strjoin("[", t, "]");
+                        else if (max_length <= 6) {
+
+                                ans = new(char, max_length);
+                                if (!ans)
+                                        return -ENOMEM;
+
+                                memcpy(ans, "[...]", max_length-1);
+                                ans[max_length-1] = 0;
+                        } else {
+                                char *e;
+
+                                t[max_length - 6] = 0;
+
+                                /* Chop off final spaces */
+                                e = strchr(t, 0);
+                                while (e > t && isspace(e[-1]))
+                                        e--;
+                                *e = 0;
+
+                                ans = strjoin("[", t, "...]");
+                        }
+                }
+                if (!ans)
+                        return -ENOMEM;
+        }
+
+        *line = ans;
+        return 0;
+}
+
+int rename_process(const char name[]) {
+        static size_t mm_size = 0;
+        static char *mm = NULL;
+        bool truncated = false;
+        size_t l;
+
+        /* This is a like a poor man's setproctitle(). It changes the comm field, argv[0], and also the glibc's
+         * internally used name of the process. For the first one a limit of 16 chars applies; to the second one in
+         * many cases one of 10 (i.e. length of "/sbin/init") — however if we have CAP_SYS_RESOURCES it is unbounded;
+         * to the third one 7 (i.e. the length of "systemd". If you pass a longer string it will likely be
+         * truncated.
+         *
+         * Returns 0 if a name was set but truncated, > 0 if it was set but not truncated. */
+
+        if (isempty(name))
+                return -EINVAL; /* let's not confuse users unnecessarily with an empty name */
+
+        l = strlen(name);
+
+        /* First step, change the comm field. */
+        (void) prctl(PR_SET_NAME, name);
+        if (l > 15) /* Linux process names can be 15 chars at max */
+                truncated = true;
+
+        /* Second step, change glibc's ID of the process name. */
+        if (program_invocation_name) {
+                size_t k;
+
+                k = strlen(program_invocation_name);
+                strncpy(program_invocation_name, name, k);
+                if (l > k)
+                        truncated = true;
+        }
+
+        /* Third step, completely replace the argv[] array the kernel maintains for us. This requires privileges, but
+         * has the advantage that the argv[] array is exactly what we want it to be, and not filled up with zeros at
+         * the end. This is the best option for changing /proc/self/cmdline. */
+
+        /* Let's not bother with this if we don't have euid == 0. Strictly speaking we should check for the
+         * CAP_SYS_RESOURCE capability which is independent of the euid. In our own code the capability generally is
+         * present only for euid == 0, hence let's use this as quick bypass check, to avoid calling mmap() if
+         * PR_SET_MM_ARG_{START,END} fails with EPERM later on anyway. After all geteuid() is dead cheap to call, but
+         * mmap() is not. */
+        if (geteuid() != 0)
+                log_debug("Skipping PR_SET_MM, as we don't have privileges.");
+        else if (mm_size < l+1) {
+                size_t nn_size;
+                char *nn;
+
+                nn_size = PAGE_ALIGN(l+1);
+                nn = mmap(NULL, nn_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+                if (nn == MAP_FAILED) {
+                        log_debug_errno(errno, "mmap() failed: %m");
+                        goto use_saved_argv;
+                }
+
+                strncpy(nn, name, nn_size);
+
+                /* Now, let's tell the kernel about this new memory */
+                if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
+                        log_debug_errno(errno, "PR_SET_MM_ARG_START failed, proceeding without: %m");
+                        (void) munmap(nn, nn_size);
+                        goto use_saved_argv;
+                }
+
+                /* And update the end pointer to the new end, too. If this fails, we don't really know what to do, it's
+                 * pretty unlikely that we can rollback, hence we'll just accept the failure, and continue. */
+                if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0)
+                        log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
+
+                if (mm)
+                        (void) munmap(mm, mm_size);
+
+                mm = nn;
+                mm_size = nn_size;
+        } else {
+                strncpy(mm, name, mm_size);
+
+                /* Update the end pointer, continuing regardless of any failure. */
+                if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) mm + l + 1, 0, 0) < 0)
+                        log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
+        }
+
+use_saved_argv:
+        /* Fourth step: in all cases we'll also update the original argv[], so that our own code gets it right too if
+         * it still looks here */
+
+        if (saved_argc > 0) {
+                int i;
+
+                if (saved_argv[0]) {
+                        size_t k;
+
+                        k = strlen(saved_argv[0]);
+                        strncpy(saved_argv[0], name, k);
+                        if (l > k)
+                                truncated = true;
+                }
+
+                for (i = 1; i < saved_argc; i++) {
+                        if (!saved_argv[i])
+                                break;
+
+                        memzero(saved_argv[i], strlen(saved_argv[i]));
+                }
+        }
+
+        return !truncated;
+}
+
+int is_kernel_thread(pid_t pid) {
+        const char *p;
+        size_t count;
+        char c;
+        bool eof;
+        FILE *f;
+
+        if (IN_SET(pid, 0, 1) || pid == getpid_cached()) /* pid 1, and we ourselves certainly aren't a kernel thread */
+                return 0;
+
+        assert(pid > 1);
+
+        p = procfs_file_alloca(pid, "cmdline");
+        f = fopen(p, "re");
+        if (!f) {
+                if (errno == ENOENT)
+                        return -ESRCH;
+                return -errno;
+        }
+
+        count = fread(&c, 1, 1, f);
+        eof = feof(f);
+        fclose(f);
+
+        /* Kernel threads have an empty cmdline */
+
+        if (count <= 0)
+                return eof ? 1 : -errno;
+
+        return 0;
+}
+
+int get_process_capeff(pid_t pid, char **capeff) {
+        const char *p;
+        int r;
+
+        assert(capeff);
+        assert(pid >= 0);
+
+        p = procfs_file_alloca(pid, "status");
+
+        r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
+        if (r == -ENOENT)
+                return -ESRCH;
+
+        return r;
+}
+
+static int get_process_link_contents(const char *proc_file, char **name) {
+        int r;
+
+        assert(proc_file);
+        assert(name);
+
+        r = readlink_malloc(proc_file, name);
+        if (r == -ENOENT)
+                return -ESRCH;
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+int get_process_exe(pid_t pid, char **name) {
+        const char *p;
+        char *d;
+        int r;
+
+        assert(pid >= 0);
+
+        p = procfs_file_alloca(pid, "exe");
+        r = get_process_link_contents(p, name);
+        if (r < 0)
+                return r;
+
+        d = endswith(*name, " (deleted)");
+        if (d)
+                *d = '\0';
+
+        return 0;
+}
+
+static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
+        _cleanup_fclose_ FILE *f = NULL;
+        char line[LINE_MAX];
+        const char *p;
+
+        assert(field);
+        assert(uid);
+
+        if (pid < 0)
+                return -EINVAL;
+
+        p = procfs_file_alloca(pid, "status");
+        f = fopen(p, "re");
+        if (!f) {
+                if (errno == ENOENT)
+                        return -ESRCH;
+                return -errno;
+        }
+
+        FOREACH_LINE(line, f, return -errno) {
+                char *l;
+
+                l = strstrip(line);
+
+                if (startswith(l, field)) {
+                        l += strlen(field);
+                        l += strspn(l, WHITESPACE);
+
+                        l[strcspn(l, WHITESPACE)] = 0;
+
+                        return parse_uid(l, uid);
+                }
+        }
+
+        return -EIO;
+}
+
+int get_process_uid(pid_t pid, uid_t *uid) {
+
+        if (pid == 0 || pid == getpid_cached()) {
+                *uid = getuid();
+                return 0;
+        }
+
+        return get_process_id(pid, "Uid:", uid);
+}
+
+int get_process_gid(pid_t pid, gid_t *gid) {
+
+        if (pid == 0 || pid == getpid_cached()) {
+                *gid = getgid();
+                return 0;
+        }
+
+        assert_cc(sizeof(uid_t) == sizeof(gid_t));
+        return get_process_id(pid, "Gid:", gid);
+}
+
+int get_process_cwd(pid_t pid, char **cwd) {
+        const char *p;
+
+        assert(pid >= 0);
+
+        p = procfs_file_alloca(pid, "cwd");
+
+        return get_process_link_contents(p, cwd);
+}
+
+int get_process_root(pid_t pid, char **root) {
+        const char *p;
+
+        assert(pid >= 0);
+
+        p = procfs_file_alloca(pid, "root");
+
+        return get_process_link_contents(p, root);
+}
+
+int get_process_environ(pid_t pid, char **env) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *outcome = NULL;
+        int c;
+        const char *p;
+        size_t allocated = 0, sz = 0;
+
+        assert(pid >= 0);
+        assert(env);
+
+        p = procfs_file_alloca(pid, "environ");
+
+        f = fopen(p, "re");
+        if (!f) {
+                if (errno == ENOENT)
+                        return -ESRCH;
+                return -errno;
+        }
+
+        while ((c = fgetc(f)) != EOF) {
+                if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
+                        return -ENOMEM;
+
+                if (c == '\0')
+                        outcome[sz++] = '\n';
+                else
+                        sz += cescape_char(c, outcome + sz);
+        }
+
+        if (!outcome) {
+                outcome = strdup("");
+                if (!outcome)
+                        return -ENOMEM;
+        } else
+                outcome[sz] = '\0';
+
+        *env = outcome;
+        outcome = NULL;
+
+        return 0;
+}
+
+int get_process_ppid(pid_t pid, pid_t *_ppid) {
+        int r;
+        _cleanup_free_ char *line = NULL;
+        long unsigned ppid;
+        const char *p;
+
+        assert(pid >= 0);
+        assert(_ppid);
+
+        if (pid == 0 || pid == getpid_cached()) {
+                *_ppid = getppid();
+                return 0;
+        }
+
+        p = procfs_file_alloca(pid, "stat");
+        r = read_one_line_file(p, &line);
+        if (r == -ENOENT)
+                return -ESRCH;
+        if (r < 0)
+                return r;
+
+        /* Let's skip the pid and comm fields. The latter is enclosed
+         * in () but does not escape any () in its value, so let's
+         * skip over it manually */
+
+        p = strrchr(line, ')');
+        if (!p)
+                return -EIO;
+
+        p++;
+
+        if (sscanf(p, " "
+                   "%*c "  /* state */
+                   "%lu ", /* ppid */
+                   &ppid) != 1)
+                return -EIO;
+
+        if ((long unsigned) (pid_t) ppid != ppid)
+                return -ERANGE;
+
+        *_ppid = (pid_t) ppid;
+
+        return 0;
+}
+
+int wait_for_terminate(pid_t pid, siginfo_t *status) {
+        siginfo_t dummy;
+
+        assert(pid >= 1);
+
+        if (!status)
+                status = &dummy;
+
+        for (;;) {
+                zero(*status);
+
+                if (waitid(P_PID, pid, status, WEXITED) < 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        return negative_errno();
+                }
+
+                return 0;
+        }
+}
+
+/*
+ * Return values:
+ * < 0 : wait_for_terminate() failed to get the state of the
+ *       process, the process was terminated by a signal, or
+ *       failed for an unknown reason.
+ * >=0 : The process terminated normally, and its exit code is
+ *       returned.
+ *
+ * That is, success is indicated by a return value of zero, and an
+ * error is indicated by a non-zero value.
+ *
+ * A warning is emitted if the process terminates abnormally,
+ * and also if it returns non-zero unless check_exit_code is true.
+ */
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
+        int r;
+        siginfo_t status;
+
+        assert(name);
+        assert(pid > 1);
+
+        r = wait_for_terminate(pid, &status);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to wait for %s: %m", name);
+
+        if (status.si_code == CLD_EXITED) {
+                if (status.si_status != 0)
+                        log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
+                                 "%s failed with error code %i.", name, status.si_status);
+                else
+                        log_debug("%s succeeded.", name);
+
+                return status.si_status;
+        } else if (IN_SET(status.si_code, CLD_KILLED, CLD_DUMPED)) {
+
+                log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
+                return -EPROTO;
+        }
+
+        log_warning("%s failed due to unknown reason.", name);
+        return -EPROTO;
+}
+
+void sigkill_wait(pid_t pid) {
+        assert(pid > 1);
+
+        if (kill(pid, SIGKILL) > 0)
+                (void) wait_for_terminate(pid, NULL);
+}
+
+void sigkill_waitp(pid_t *pid) {
+        if (!pid)
+                return;
+        if (*pid <= 1)
+                return;
+
+        sigkill_wait(*pid);
+}
+
+int kill_and_sigcont(pid_t pid, int sig) {
+        int r;
+
+        r = kill(pid, sig) < 0 ? -errno : 0;
+
+        /* If this worked, also send SIGCONT, unless we already just sent a SIGCONT, or SIGKILL was sent which isn't
+         * affected by a process being suspended anyway. */
+        if (r >= 0 && !IN_SET(sig, SIGCONT, SIGKILL))
+                (void) kill(pid, SIGCONT);
+
+        return r;
+}
+
+int getenv_for_pid(pid_t pid, const char *field, char **_value) {
+        _cleanup_fclose_ FILE *f = NULL;
+        char *value = NULL;
+        int r;
+        bool done = false;
+        size_t l;
+        const char *path;
+
+        assert(pid >= 0);
+        assert(field);
+        assert(_value);
+
+        path = procfs_file_alloca(pid, "environ");
+
+        f = fopen(path, "re");
+        if (!f) {
+                if (errno == ENOENT)
+                        return -ESRCH;
+                return -errno;
+        }
+
+        l = strlen(field);
+        r = 0;
+
+        do {
+                char line[LINE_MAX];
+                unsigned i;
+
+                for (i = 0; i < sizeof(line)-1; i++) {
+                        int c;
+
+                        c = getc(f);
+                        if (_unlikely_(c == EOF)) {
+                                done = true;
+                                break;
+                        } else if (c == 0)
+                                break;
+
+                        line[i] = c;
+                }
+                line[i] = 0;
+
+                if (strneq(line, field, l) && line[l] == '=') {
+                        value = strdup(line + l + 1);
+                        if (!value)
+                                return -ENOMEM;
+
+                        r = 1;
+                        break;
+                }
+
+        } while (!done);
+
+        *_value = value;
+        return r;
+}
+
+bool pid_is_unwaited(pid_t pid) {
+        /* Checks whether a PID is still valid at all, including a zombie */
+
+        if (pid < 0)
+                return false;
+
+        if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */
+                return true;
+
+        if (pid == getpid_cached())
+                return true;
+
+        if (kill(pid, 0) >= 0)
+                return true;
+
+        return errno != ESRCH;
+}
+
+bool pid_is_alive(pid_t pid) {
+        int r;
+
+        /* Checks whether a PID is still valid and not a zombie */
+
+        if (pid < 0)
+                return false;
+
+        if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */
+                return true;
+
+        if (pid == getpid_cached())
+                return true;
+
+        r = get_process_state(pid);
+        if (IN_SET(r, -ESRCH, 'Z'))
+                return false;
+
+        return true;
+}
+
+int pid_from_same_root_fs(pid_t pid) {
+        const char *root;
+
+        if (pid < 0)
+                return false;
+
+        if (pid == 0 || pid == getpid_cached())
+                return true;
+
+        root = procfs_file_alloca(pid, "root");
+
+        return files_same(root, "/proc/1/root", 0);
+}
+#endif /* NM_IGNORED */
+
+bool is_main_thread(void) {
+        static thread_local int cached = 0;
+
+        if (_unlikely_(cached == 0))
+                cached = getpid_cached() == gettid() ? 1 : -1;
+
+        return cached > 0;
+}
+
+#if 0 /* NM_IGNORED */
+noreturn void freeze(void) {
+
+        log_close();
+
+        /* Make sure nobody waits for us on a socket anymore */
+        close_all_fds(NULL, 0);
+
+        sync();
+
+        for (;;)
+                pause();
+}
+
+bool oom_score_adjust_is_valid(int oa) {
+        return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
+}
+
+unsigned long personality_from_string(const char *p) {
+        int architecture;
+
+        if (!p)
+                return PERSONALITY_INVALID;
+
+        /* Parse a personality specifier. We use our own identifiers that indicate specific ABIs, rather than just
+         * hints regarding the register size, since we want to keep things open for multiple locally supported ABIs for
+         * the same register size. */
+
+        architecture = architecture_from_string(p);
+        if (architecture < 0)
+                return PERSONALITY_INVALID;
+
+        if (architecture == native_architecture())
+                return PER_LINUX;
+#ifdef SECONDARY_ARCHITECTURE
+        if (architecture == SECONDARY_ARCHITECTURE)
+                return PER_LINUX32;
+#endif
+
+        return PERSONALITY_INVALID;
+}
+
+const char* personality_to_string(unsigned long p) {
+        int architecture = _ARCHITECTURE_INVALID;
+
+        if (p == PER_LINUX)
+                architecture = native_architecture();
+#ifdef SECONDARY_ARCHITECTURE
+        else if (p == PER_LINUX32)
+                architecture = SECONDARY_ARCHITECTURE;
+#endif
+
+        if (architecture < 0)
+                return NULL;
+
+        return architecture_to_string(architecture);
+}
+
+int safe_personality(unsigned long p) {
+        int ret;
+
+        /* So here's the deal, personality() is weirdly defined by glibc. In some cases it returns a failure via errno,
+         * and in others as negative return value containing an errno-like value. Let's work around this: this is a
+         * wrapper that uses errno if it is set, and uses the return value otherwise. And then it sets both errno and
+         * the return value indicating the same issue, so that we are definitely on the safe side.
+         *
+         * See https://github.com/systemd/systemd/issues/6737 */
+
+        errno = 0;
+        ret = personality(p);
+        if (ret < 0) {
+                if (errno != 0)
+                        return -errno;
+
+                errno = -ret;
+        }
+
+        return ret;
+}
+
+int opinionated_personality(unsigned long *ret) {
+        int current;
+
+        /* Returns the current personality, or PERSONALITY_INVALID if we can't determine it. This function is a bit
+         * opinionated though, and ignores all the finer-grained bits and exotic personalities, only distinguishing the
+         * two most relevant personalities: PER_LINUX and PER_LINUX32. */
+
+        current = safe_personality(PERSONALITY_INVALID);
+        if (current < 0)
+                return current;
+
+        if (((unsigned long) current & 0xffff) == PER_LINUX32)
+                *ret = PER_LINUX32;
+        else
+                *ret = PER_LINUX;
+
+        return 0;
+}
+
+void valgrind_summary_hack(void) {
+#if HAVE_VALGRIND_VALGRIND_H
+        if (getpid_cached() == 1 && RUNNING_ON_VALGRIND) {
+                pid_t pid;
+                pid = raw_clone(SIGCHLD);
+                if (pid < 0)
+                        log_emergency_errno(errno, "Failed to fork off valgrind helper: %m");
+                else if (pid == 0)
+                        exit(EXIT_SUCCESS);
+                else {
+                        log_info("Spawned valgrind helper as PID "PID_FMT".", pid);
+                        (void) wait_for_terminate(pid, NULL);
+                }
+        }
+#endif
+}
+
+int pid_compare_func(const void *a, const void *b) {
+        const pid_t *p = a, *q = b;
+
+        /* Suitable for usage in qsort() */
+
+        if (*p < *q)
+                return -1;
+        if (*p > *q)
+                return 1;
+        return 0;
+}
+
+int ioprio_parse_priority(const char *s, int *ret) {
+        int i, r;
+
+        assert(s);
+        assert(ret);
+
+        r = safe_atoi(s, &i);
+        if (r < 0)
+                return r;
+
+        if (!ioprio_priority_is_valid(i))
+                return -EINVAL;
+
+        *ret = i;
+        return 0;
+}
+#endif /* NM_IGNORED */
+
+/* The cached PID, possible values:
+ *
+ *     == UNSET [0]  → cache not initialized yet
+ *     == BUSY [-1]  → some thread is initializing it at the moment
+ *     any other     → the cached PID
+ */
+
+#define CACHED_PID_UNSET ((pid_t) 0)
+#define CACHED_PID_BUSY ((pid_t) -1)
+
+static pid_t cached_pid = CACHED_PID_UNSET;
+
+static void reset_cached_pid(void) {
+        /* Invoked in the child after a fork(), i.e. at the first moment the PID changed */
+        cached_pid = CACHED_PID_UNSET;
+}
+
+/* We use glibc __register_atfork() + __dso_handle directly here, as they are not included in the glibc
+ * headers. __register_atfork() is mostly equivalent to pthread_atfork(), but doesn't require us to link against
+ * libpthread, as it is part of glibc anyway. */
+extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void (*child) (void), void * __dso_handle);
+extern void* __dso_handle __attribute__ ((__weak__));
+
+pid_t getpid_cached(void) {
+        pid_t current_value;
+
+        /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a
+         * system call each time. This restores glibc behaviour from before 2.24, when getpid() was unconditionally
+         * cached. Starting with 2.24 getpid() started to become prohibitively expensive when used for detecting when
+         * objects were used across fork()s. With this caching the old behaviour is somewhat restored.
+         *
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1443976
+         * https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=c579f48edba88380635ab98cb612030e3ed8691e
+         */
+
+        current_value = __sync_val_compare_and_swap(&cached_pid, CACHED_PID_UNSET, CACHED_PID_BUSY);
+
+        switch (current_value) {
+
+        case CACHED_PID_UNSET: { /* Not initialized yet, then do so now */
+                pid_t new_pid;
+
+                new_pid = getpid();
+
+                if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) {
+                        /* OOM? Let's try again later */
+                        cached_pid = CACHED_PID_UNSET;
+                        return new_pid;
+                }
+
+                cached_pid = new_pid;
+                return new_pid;
+        }
+
+        case CACHED_PID_BUSY: /* Somebody else is currently initializing */
+                return getpid();
+
+        default: /* Properly initialized */
+                return current_value;
+        }
+}
+
+#if 0 /* NM_IGNORED */
+static const char *const ioprio_class_table[] = {
+        [IOPRIO_CLASS_NONE] = "none",
+        [IOPRIO_CLASS_RT] = "realtime",
+        [IOPRIO_CLASS_BE] = "best-effort",
+        [IOPRIO_CLASS_IDLE] = "idle"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
+
+static const char *const sigchld_code_table[] = {
+        [CLD_EXITED] = "exited",
+        [CLD_KILLED] = "killed",
+        [CLD_DUMPED] = "dumped",
+        [CLD_TRAPPED] = "trapped",
+        [CLD_STOPPED] = "stopped",
+        [CLD_CONTINUED] = "continued",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
+
+static const char* const sched_policy_table[] = {
+        [SCHED_OTHER] = "other",
+        [SCHED_BATCH] = "batch",
+        [SCHED_IDLE] = "idle",
+        [SCHED_FIFO] = "fifo",
+        [SCHED_RR] = "rr"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
+#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/process-util.h b/src/systemd/src/basic/process-util.h
new file mode 100644
index 00000000..e1bd2c5b
--- /dev/null
+++ b/src/systemd/src/basic/process-util.h
@@ -0,0 +1,141 @@
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <alloca.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+
+#include "format-util.h"
+#include "ioprio.h"
+#include "macro.h"
+
+#define procfs_file_alloca(pid, field)                                  \
+        ({                                                              \
+                pid_t _pid_ = (pid);                                    \
+                const char *_r_;                                        \
+                if (_pid_ == 0) {                                       \
+                        _r_ = ("/proc/self/" field);                    \
+                } else {                                                \
+                        _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \
+                        sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_);                       \
+                }                                                       \
+                _r_;                                                    \
+        })
+
+int get_process_state(pid_t pid);
+int get_process_comm(pid_t pid, char **name);
+int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line);
+int get_process_exe(pid_t pid, char **name);
+int get_process_uid(pid_t pid, uid_t *uid);
+int get_process_gid(pid_t pid, gid_t *gid);
+int get_process_capeff(pid_t pid, char **capeff);
+int get_process_cwd(pid_t pid, char **cwd);
+int get_process_root(pid_t pid, char **root);
+int get_process_environ(pid_t pid, char **environ);
+int get_process_ppid(pid_t pid, pid_t *ppid);
+
+int wait_for_terminate(pid_t pid, siginfo_t *status);
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
+
+void sigkill_wait(pid_t pid);
+void sigkill_waitp(pid_t *pid);
+
+int kill_and_sigcont(pid_t pid, int sig);
+
+int rename_process(const char name[]);
+int is_kernel_thread(pid_t pid);
+
+int getenv_for_pid(pid_t pid, const char *field, char **_value);
+
+bool pid_is_alive(pid_t pid);
+bool pid_is_unwaited(pid_t pid);
+int pid_from_same_root_fs(pid_t pid);
+
+bool is_main_thread(void);
+
+noreturn void freeze(void);
+
+bool oom_score_adjust_is_valid(int oa);
+
+#ifndef PERSONALITY_INVALID
+/* personality(7) documents that 0xffffffffUL is used for querying the
+ * current personality, hence let's use that here as error
+ * indicator. */
+#define PERSONALITY_INVALID 0xffffffffLU
+#endif
+
+unsigned long personality_from_string(const char *p);
+const char *personality_to_string(unsigned long);
+
+int safe_personality(unsigned long p);
+int opinionated_personality(unsigned long *ret);
+
+int ioprio_class_to_string_alloc(int i, char **s);
+int ioprio_class_from_string(const char *s);
+
+const char *sigchld_code_to_string(int i) _const_;
+int sigchld_code_from_string(const char *s) _pure_;
+
+int sched_policy_to_string_alloc(int i, char **s);
+int sched_policy_from_string(const char *s);
+
+#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
+#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
+
+void valgrind_summary_hack(void);
+
+int pid_compare_func(const void *a, const void *b);
+
+#if 0 /* NM_IGNORED */
+static inline bool nice_is_valid(int n) {
+        return n >= PRIO_MIN && n < PRIO_MAX;
+}
+
+static inline bool sched_policy_is_valid(int i) {
+        return IN_SET(i, SCHED_OTHER, SCHED_BATCH, SCHED_IDLE, SCHED_FIFO, SCHED_RR);
+}
+
+static inline bool sched_priority_is_valid(int i) {
+        return i >= 0 && i <= sched_get_priority_max(SCHED_RR);
+}
+
+static inline bool ioprio_class_is_valid(int i) {
+        return IN_SET(i, IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE);
+}
+
+static inline bool ioprio_priority_is_valid(int i) {
+        return i >= 0 && i < IOPRIO_BE_NR;
+}
+
+static inline bool pid_is_valid(pid_t p) {
+        return p > 0;
+}
+#endif /* NM_IGNORED */
+
+int ioprio_parse_priority(const char *s, int *ret);
+
+pid_t getpid_cached(void);
diff --git a/src/systemd/src/basic/random-util.c b/src/systemd/src/basic/random-util.c
index 1d8ca882..3b6ddb7d 100644
--- a/src/systemd/src/basic/random-util.c
+++ b/src/systemd/src/basic/random-util.c
@@ -28,8 +28,14 @@
 #include <linux/random.h>
 #include <stdint.h>
 
-#ifdef HAVE_SYS_AUXV_H
-#include <sys/auxv.h>
+#if HAVE_SYS_AUXV_H
+#  include <sys/auxv.h>
+#endif
+
+#if USE_SYS_RANDOM_H
+#  include <sys/random.h>
+#else
+#  include <linux/random.h>
 #endif
 
 #include "fd-util.h"
@@ -38,76 +44,86 @@
 #include "random-util.h"
 #include "time-util.h"
 
-int dev_urandom(void *p, size_t n) {
-#if 0 /* NM_IGNORED */
+int acquire_random_bytes(void *p, size_t n, bool high_quality_required) {
         static int have_syscall = -1;
 
         _cleanup_close_ int fd = -1;
+        unsigned already_done = 0;
         int r;
 
-        /* Gathers some randomness from the kernel. This call will
-         * never block, and will always return some data from the
-         * kernel, regardless if the random pool is fully initialized
-         * or not. It thus makes no guarantee for the quality of the
-         * returned entropy, but is good enough for our usual usecases
-         * of seeding the hash functions for hashtable */
-
-        /* Use the getrandom() syscall unless we know we don't have
-         * it, or when the requested size is too large for it. */
-        if (have_syscall != 0 || (size_t) (int) n != n) {
+        /* Gathers some randomness from the kernel. This call will never block. If
+         * high_quality_required, it will always return some data from the kernel,
+         * regardless of whether the random pool is fully initialized or not.
+         * Otherwise, it will return success if at least some random bytes were
+         * successfully acquired, and an error if the kernel has no entropy whatsover
+         * for us. */
+
+        /* Use the getrandom() syscall unless we know we don't have it. */
+        if (have_syscall != 0) {
+#if !HAVE_GETRANDOM
+                /* XXX: NM: systemd calls the syscall directly in this case. Don't add that workaround.
+                 * If you don't compile against a libc that provides getrandom(), you don't get it. */
+                r = -1;
+                errno = ENOSYS;
+#else
                 r = getrandom(p, n, GRND_NONBLOCK);
-                if (r == (int) n) {
+#endif
+                if (r > 0) {
+                        have_syscall = true;
+                        if ((size_t) r == n)
+                                return 0;
+                        if (!high_quality_required) {
+                                /* Fill in the remaining bytes using pseudorandom values */
+                                pseudorandom_bytes((uint8_t*) p + r, n - r);
+                                return 0;
+                        }
+
+                        already_done = r;
+                } else if (errno == ENOSYS)
+                          /* We lack the syscall, continue with reading from /dev/urandom. */
+                          have_syscall = false;
+                else if (errno == EAGAIN) {
+                        /* The kernel has no entropy whatsoever. Let's remember to
+                         * use the syscall the next time again though.
+                         *
+                         * If high_quality_required is false, return an error so that
+                         * random_bytes() can produce some pseudorandom
+                         * bytes. Otherwise, fall back to /dev/urandom, which we know
+                         * is empty, but the kernel will produce some bytes for us on
+                         * a best-effort basis. */
                         have_syscall = true;
-                        return 0;
-                }
-
-                if (r < 0) {
-                        if (errno == ENOSYS)
-                                /* we lack the syscall, continue with
-                                 * reading from /dev/urandom */
-                                have_syscall = false;
-                        else if (errno == EAGAIN)
-                                /* not enough entropy for now. Let's
-                                 * remember to use the syscall the
-                                 * next time, again, but also read
-                                 * from /dev/urandom for now, which
-                                 * doesn't care about the current
-                                 * amount of entropy.  */
-                                have_syscall = true;
-                        else
-                                return -errno;
+
+                        if (!high_quality_required)
+                                return -ENODATA;
                 } else
-                        /* too short read? */
-                        return -ENODATA;
+                        return -errno;
         }
-#else /* NM_IGNORED */
-        _cleanup_close_ int fd = -1;
-#endif /* NM_IGNORED */
 
         fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
         if (fd < 0)
                 return errno == ENOENT ? -ENOSYS : -errno;
 
-        return loop_read_exact(fd, p, n, true);
+        return loop_read_exact(fd, (uint8_t*) p + already_done, n - already_done, true);
 }
 
 void initialize_srand(void) {
         static bool srand_called = false;
         unsigned x;
-#ifdef HAVE_SYS_AUXV_H
+#if HAVE_SYS_AUXV_H
         void *auxv;
 #endif
 
         if (srand_called)
                 return;
 
-#ifdef HAVE_SYS_AUXV_H
-        /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed the
-         * pseudo-random generator. It's better than nothing... */
+#if HAVE_SYS_AUXV_H
+        /* The kernel provides us with 16 bytes of entropy in auxv, so let's
+         * try to make use of that to seed the pseudo-random generator. It's
+         * better than nothing... */
 
         auxv = (void*) getauxval(AT_RANDOM);
         if (auxv) {
-                assert_cc(sizeof(x) < 16);
+                assert_cc(sizeof(x) <= 16);
                 memcpy(&x, auxv, sizeof(x));
         } else
 #endif
@@ -121,19 +137,44 @@ void initialize_srand(void) {
         srand_called = true;
 }
 
-void random_bytes(void *p, size_t n) {
+/* INT_MAX gives us only 31 bits, so use 24 out of that. */
+#if RAND_MAX >= INT_MAX
+#  define RAND_STEP 3
+#else
+/* SHORT_INT_MAX or lower gives at most 15 bits, we just just 8 out of that. */
+#  define RAND_STEP 1
+#endif
+
+void pseudorandom_bytes(void *p, size_t n) {
         uint8_t *q;
+
+        initialize_srand();
+
+        for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) {
+                unsigned rr;
+
+                rr = (unsigned) rand();
+
+#if RAND_STEP >= 3
+                if ((size_t) (q - (uint8_t*) p + 2) < n)
+                        q[2] = rr >> 16;
+#endif
+#if RAND_STEP >= 2
+                if ((size_t) (q - (uint8_t*) p + 1) < n)
+                        q[1] = rr >> 8;
+#endif
+                q[0] = rr;
+        }
+}
+
+void random_bytes(void *p, size_t n) {
         int r;
 
-        r = dev_urandom(p, n);
+        r = acquire_random_bytes(p, n, false);
         if (r >= 0)
                 return;
 
-        /* If some idiot made /dev/urandom unavailable to us, he'll
-         * get a PRNG instead. */
-
-        initialize_srand();
-
-        for (q = p; q < (uint8_t*) p + n; q ++)
-                *q = rand();
+        /* If some idiot made /dev/urandom unavailable to us, or the
+         * kernel has no entropy, use a PRNG instead. */
+        return pseudorandom_bytes(p, n);
 }
diff --git a/src/systemd/src/basic/random-util.h b/src/systemd/src/basic/random-util.h
index 3cee4c50..804e225f 100644
--- a/src/systemd/src/basic/random-util.h
+++ b/src/systemd/src/basic/random-util.h
@@ -19,10 +19,12 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 
-int dev_urandom(void *p, size_t n);
+int acquire_random_bytes(void *p, size_t n, bool high_quality_required);
+void pseudorandom_bytes(void *p, size_t n);
 void random_bytes(void *p, size_t n);
 void initialize_srand(void);
 
diff --git a/src/systemd/src/basic/set.h b/src/systemd/src/basic/set.h
index a5f8beb0..12d0fda1 100644
--- a/src/systemd/src/basic/set.h
+++ b/src/systemd/src/basic/set.h
@@ -136,3 +136,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
 
 #define _cleanup_set_free_ _cleanup_(set_freep)
 #define _cleanup_set_free_free_ _cleanup_(set_free_freep)
+
+int set_make(Set **ret, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS, void *add, ...);
diff --git a/src/systemd/src/basic/siphash24.c b/src/systemd/src/basic/siphash24.c
deleted file mode 100644
index e4b1cb10..00000000
--- a/src/systemd/src/basic/siphash24.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
-   SipHash reference C implementation
-
-   Written in 2012 by
-   Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
-   Daniel J. Bernstein <djb@cr.yp.to>
-
-   To the extent possible under law, the author(s) have dedicated all copyright
-   and related and neighboring rights to this software to the public domain
-   worldwide. This software is distributed without any warranty.
-
-   You should have received a copy of the CC0 Public Domain Dedication along with
-   this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
-
-   (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd)
-   (Refactored by Tom Gundersen to split up in several functions and follow systemd
-    coding style)
-*/
-
-#include "nm-sd-adapt.h"
-
-#include <stdio.h>
-
-#include "macro.h"
-#include "siphash24.h"
-#include "unaligned.h"
-
-static inline uint64_t rotate_left(uint64_t x, uint8_t b) {
-        assert(b < 64);
-
-        return (x << b) | (x >> (64 - b));
-}
-
-static inline void sipround(struct siphash *state) {
-        assert(state);
-
-        state->v0 += state->v1;
-        state->v1 = rotate_left(state->v1, 13);
-        state->v1 ^= state->v0;
-        state->v0 = rotate_left(state->v0, 32);
-        state->v2 += state->v3;
-        state->v3 = rotate_left(state->v3, 16);
-        state->v3 ^= state->v2;
-        state->v0 += state->v3;
-        state->v3 = rotate_left(state->v3, 21);
-        state->v3 ^= state->v0;
-        state->v2 += state->v1;
-        state->v1 = rotate_left(state->v1, 17);
-        state->v1 ^= state->v2;
-        state->v2 = rotate_left(state->v2, 32);
-}
-
-void siphash24_init(struct siphash *state, const uint8_t k[16]) {
-        uint64_t k0, k1;
-
-        assert(state);
-        assert(k);
-
-        k0 = unaligned_read_le64(k);
-        k1 = unaligned_read_le64(k + 8);
-
-        *state = (struct siphash) {
-                /* "somepseudorandomlygeneratedbytes" */
-                .v0 = 0x736f6d6570736575ULL ^ k0,
-                .v1 = 0x646f72616e646f6dULL ^ k1,
-                .v2 = 0x6c7967656e657261ULL ^ k0,
-                .v3 = 0x7465646279746573ULL ^ k1,
-                .padding = 0,
-                .inlen = 0,
-        };
-}
-
-void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
-
-        const uint8_t *in = _in;
-        const uint8_t *end = in + inlen;
-        size_t left = state->inlen & 7;
-        uint64_t m;
-
-        assert(in);
-        assert(state);
-
-        /* Update total length */
-        state->inlen += inlen;
-
-        /* If padding exists, fill it out */
-        if (left > 0) {
-                for ( ; in < end && left < 8; in ++, left ++)
-                        state->padding |= ((uint64_t) *in) << (left * 8);
-
-                if (in == end && left < 8)
-                        /* We did not have enough input to fill out the padding completely */
-                        return;
-
-#ifdef DEBUG
-                printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
-                printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
-                printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
-                printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
-                printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
-#endif
-
-                state->v3 ^= state->padding;
-                sipround(state);
-                sipround(state);
-                state->v0 ^= state->padding;
-
-                state->padding = 0;
-        }
-
-        end -= (state->inlen % sizeof(uint64_t));
-
-        for ( ; in < end; in += 8) {
-                m = unaligned_read_le64(in);
-#ifdef DEBUG
-                printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
-                printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
-                printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
-                printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
-                printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m);
-#endif
-                state->v3 ^= m;
-                sipround(state);
-                sipround(state);
-                state->v0 ^= m;
-        }
-
-        left = state->inlen & 7;
-        switch (left) {
-                case 7:
-                        state->padding |= ((uint64_t) in[6]) << 48;
-                        /* fall through */
-                case 6:
-                        state->padding |= ((uint64_t) in[5]) << 40;
-                        /* fall through */
-                case 5:
-                        state->padding |= ((uint64_t) in[4]) << 32;
-                        /* fall through */
-                case 4:
-                        state->padding |= ((uint64_t) in[3]) << 24;
-                        /* fall through */
-                case 3:
-                        state->padding |= ((uint64_t) in[2]) << 16;
-                        /* fall through */
-                case 2:
-                        state->padding |= ((uint64_t) in[1]) <<  8;
-                        /* fall through */
-                case 1:
-                        state->padding |= ((uint64_t) in[0]);
-                        /* fall through */
-                case 0:
-                        break;
-        }
-}
-
-uint64_t siphash24_finalize(struct siphash *state) {
-        uint64_t b;
-
-        assert(state);
-
-        b = state->padding | (((uint64_t) state->inlen) << 56);
-
-#ifdef DEBUG
-        printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
-        printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
-        printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
-        printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
-        printf("(%3zu) padding   %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding);
-#endif
-
-        state->v3 ^= b;
-        sipround(state);
-        sipround(state);
-        state->v0 ^= b;
-
-#ifdef DEBUG
-        printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
-        printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
-        printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
-        printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
-#endif
-        state->v2 ^= 0xff;
-
-        sipround(state);
-        sipround(state);
-        sipround(state);
-        sipround(state);
-
-        return state->v0 ^ state->v1 ^ state->v2  ^ state->v3;
-}
-
-uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]) {
-        struct siphash state;
-
-        assert(in);
-        assert(k);
-
-        siphash24_init(&state, k);
-        siphash24_compress(in, inlen, &state);
-
-        return siphash24_finalize(&state);
-}
diff --git a/src/systemd/src/basic/siphash24.h b/src/systemd/src/basic/siphash24.h
deleted file mode 100644
index 54e2420c..00000000
--- a/src/systemd/src/basic/siphash24.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-struct siphash {
-        uint64_t v0;
-        uint64_t v1;
-        uint64_t v2;
-        uint64_t v3;
-        uint64_t padding;
-        size_t inlen;
-};
-
-void siphash24_init(struct siphash *state, const uint8_t k[16]);
-void siphash24_compress(const void *in, size_t inlen, struct siphash *state);
-#define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state))
-
-uint64_t siphash24_finalize(struct siphash *state);
-
-uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]);
diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c
index e63dd0db..798ab16e 100644
--- a/src/systemd/src/basic/socket-util.c
+++ b/src/systemd/src/basic/socket-util.c
@@ -51,6 +51,12 @@
 #include "util.h"
 
 #if 0 /* NM_IGNORED */
+#if ENABLE_IDN
+#  define IDN_FLAGS (NI_IDN|NI_IDN_USE_STD3_ASCII_RULES)
+#else
+#  define IDN_FLAGS 0
+#endif
+
 int socket_address_parse(SocketAddress *a, const char *s) {
         char *e, *n;
         unsigned u;
@@ -265,7 +271,7 @@ int socket_address_verify(const SocketAddress *a) {
                 if (a->sockaddr.in.sin_port == 0)
                         return -EINVAL;
 
-                if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
+                if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
                         return -EINVAL;
 
                 return 0;
@@ -277,7 +283,7 @@ int socket_address_verify(const SocketAddress *a) {
                 if (a->sockaddr.in6.sin6_port == 0)
                         return -EINVAL;
 
-                if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
+                if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
                         return -EINVAL;
 
                 return 0;
@@ -301,7 +307,7 @@ int socket_address_verify(const SocketAddress *a) {
                         }
                 }
 
-                if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
+                if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
                         return -EINVAL;
 
                 return 0;
@@ -311,7 +317,7 @@ int socket_address_verify(const SocketAddress *a) {
                 if (a->size != sizeof(struct sockaddr_nl))
                         return -EINVAL;
 
-                if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
+                if (!IN_SET(a->type, SOCK_RAW, SOCK_DGRAM))
                         return -EINVAL;
 
                 return 0;
@@ -320,7 +326,7 @@ int socket_address_verify(const SocketAddress *a) {
                 if (a->size != sizeof(struct sockaddr_vm))
                         return -EINVAL;
 
-                if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
+                if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
                         return -EINVAL;
 
                 return 0;
@@ -361,8 +367,7 @@ bool socket_address_can_accept(const SocketAddress *a) {
         assert(a);
 
         return
-                a->type == SOCK_STREAM ||
-                a->type == SOCK_SEQPACKET;
+                IN_SET(a->type, SOCK_STREAM, SOCK_SEQPACKET);
 }
 
 bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
@@ -409,7 +414,7 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
                         return false;
 
                 if (a->sockaddr.un.sun_path[0]) {
-                        if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path))
+                        if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, 0))
                                 return false;
                 } else {
                         if (a->size != b->size)
@@ -726,8 +731,7 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret)
 
         assert(_ret);
 
-        r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0,
-                        NI_IDN|NI_IDN_USE_STD3_ASCII_RULES);
+        r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0, IDN_FLAGS);
         if (r != 0) {
                 int saved_errno = errno;
 
@@ -791,7 +795,8 @@ static const char* const netlink_family_table[] = {
         [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
         [NETLINK_GENERIC] = "generic",
         [NETLINK_SCSITRANSPORT] = "scsitransport",
-        [NETLINK_ECRYPTFS] = "ecryptfs"
+        [NETLINK_ECRYPTFS] = "ecryptfs",
+        [NETLINK_RDMA] = "rdma",
 };
 
 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
@@ -890,7 +895,7 @@ bool ifname_valid(const char *p) {
                 if ((unsigned char) *p <= 32U)
                         return false;
 
-                if (*p == ':' || *p == '/')
+                if (IN_SET(*p, ':', '/'))
                         return false;
 
                 numeric = numeric && (*p >= '0' && *p <= '9');
@@ -1079,7 +1084,7 @@ ssize_t next_datagram_size_fd(int fd) {
 
         l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC);
         if (l < 0) {
-                if (errno == EOPNOTSUPP || errno == EFAULT)
+                if (IN_SET(errno, EOPNOTSUPP, EFAULT))
                         goto fallback;
 
                 return -errno;
diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h
index 19a9ddb2..d7e2d85f 100644
--- a/src/systemd/src/basic/socket-util.h
+++ b/src/systemd/src/basic/socket-util.h
@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include <sys/un.h>
 #include <linux/netlink.h>
+#include <linux/if_infiniband.h>
 #include <linux/if_packet.h>
 
 #include "macro.h"
@@ -44,6 +45,8 @@ union sockaddr_union {
 #if 0 /* NM_IGNORED */
         struct sockaddr_vm vm;
 #endif /* NM_IGNORED */
+        /* Ensure there is enough space to store Infiniband addresses */
+        uint8_t ll_buffer[offsetof(struct sockaddr_ll, sll_addr) + CONST_MAX(ETH_ALEN, INFINIBAND_ALEN)];
 };
 
 typedef struct SocketAddress {
@@ -149,6 +152,23 @@ int flush_accept(int fd);
 
 struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
 
+/*
+ * Certain hardware address types (e.g Infiniband) do not fit into sll_addr
+ * (8 bytes) and run over the structure. This macro returns the correct size that
+ * must be passed to kernel.
+ */
+#define SOCKADDR_LL_LEN(sa)                                             \
+        ({                                                              \
+                const struct sockaddr_ll *_sa = &(sa);                  \
+                size_t _mac_len = sizeof(_sa->sll_addr);                \
+                assert(_sa->sll_family == AF_PACKET);                   \
+                if (be16toh(_sa->sll_hatype) == ARPHRD_ETHER)           \
+                        _mac_len = MAX(_mac_len, (size_t) ETH_ALEN);    \
+                if (be16toh(_sa->sll_hatype) == ARPHRD_INFINIBAND)      \
+                        _mac_len = MAX(_mac_len, (size_t) INFINIBAND_ALEN); \
+                offsetof(struct sockaddr_ll, sll_addr) + _mac_len;      \
+        })
+
 /* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
 #define SOCKADDR_UN_LEN(sa)                                             \
         ({                                                              \
diff --git a/src/systemd/src/basic/string-util.c b/src/systemd/src/basic/string-util.c
index 406d6d3c..047eb162 100644
--- a/src/systemd/src/basic/string-util.c
+++ b/src/systemd/src/basic/string-util.c
@@ -217,7 +217,7 @@ char *strnappend(const char *s, const char *suffix, size_t b) {
 }
 
 char *strappend(const char *s, const char *suffix) {
-        return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+        return strnappend(s, suffix, strlen_ptr(suffix));
 }
 
 char *strjoin_real(const char *x, ...) {
@@ -546,7 +546,7 @@ char *ellipsize(const char *s, size_t length, unsigned percent) {
 }
 #endif /* NM_IGNORED */
 
-bool nulstr_contains(const char*nulstr, const char *needle) {
+bool nulstr_contains(const char *nulstr, const char *needle) {
         const char *i;
 
         if (!nulstr)
@@ -562,7 +562,7 @@ bool nulstr_contains(const char*nulstr, const char *needle) {
 char* strshorten(char *s, size_t l) {
         assert(s);
 
-        if (l < strlen(s))
+        if (strnlen(s, l+1) > l)
                 s[l] = 0;
 
         return s;
@@ -639,6 +639,11 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
         if (!f)
                 return NULL;
 
+        /* Note we use the _unlocked() stdio variants on f for performance
+         * reasons.  It's safe to do so since we created f here and it
+         * doesn't leave our scope.
+         */
+
         for (i = *ibuf; i < *ibuf + isz + 1; i++) {
 
                 switch (state) {
@@ -649,21 +654,21 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
                         else if (*i == '\x1B')
                                 state = STATE_ESCAPE;
                         else if (*i == '\t')
-                                fputs("        ", f);
+                                fputs_unlocked("        ", f);
                         else
-                                fputc(*i, f);
+                                fputc_unlocked(*i, f);
                         break;
 
                 case STATE_ESCAPE:
                         if (i >= *ibuf + isz) { /* EOT */
-                                fputc('\x1B', f);
+                                fputc_unlocked('\x1B', f);
                                 break;
                         } else if (*i == '[') {
                                 state = STATE_BRACKET;
                                 begin = i + 1;
                         } else {
-                                fputc('\x1B', f);
-                                fputc(*i, f);
+                                fputc_unlocked('\x1B', f);
+                                fputc_unlocked(*i, f);
                                 state = STATE_OTHER;
                         }
 
@@ -672,9 +677,9 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
                 case STATE_BRACKET:
 
                         if (i >= *ibuf + isz || /* EOT */
-                            (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
-                                fputc('\x1B', f);
-                                fputc('[', f);
+                            (!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) {
+                                fputc_unlocked('\x1B', f);
+                                fputc_unlocked('[', f);
                                 state = STATE_OTHER;
                                 i = begin-1;
                         } else if (*i == 'm')
@@ -706,7 +711,7 @@ char *strextend(char **x, ...) {
 
         assert(x);
 
-        l = f = *x ? strlen(*x) : 0;
+        l = f = strlen_ptr(*x);
 
         va_start(ap, x);
         for (;;) {
@@ -825,7 +830,7 @@ int free_and_strdup(char **p, const char *s) {
         return 1;
 }
 
-#if !HAVE_DECL_EXPLICIT_BZERO
+#if !HAVE_EXPLICIT_BZERO
 /*
  * Pointer to memset is volatile so that compiler must de-reference
  * the pointer and can't assume that it points to any function in
diff --git a/src/systemd/src/basic/string-util.h b/src/systemd/src/basic/string-util.h
index be44dedf..4c94b182 100644
--- a/src/systemd/src/basic/string-util.h
+++ b/src/systemd/src/basic/string-util.h
@@ -120,7 +120,7 @@ char *strjoin_real(const char *x, ...) _sentinel_;
         ({                                                              \
                 const char *_appendees_[] = { a, __VA_ARGS__ };         \
                 char *_d_, *_p_;                                        \
-                int _len_ = 0;                                          \
+                size_t _len_ = 0;                                          \
                 unsigned _i_;                                           \
                 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
                         _len_ += strlen(_appendees_[_i_]);              \
@@ -158,7 +158,7 @@ bool string_has_cc(const char *p, const char *ok) _pure_;
 char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
 char *ellipsize(const char *s, size_t length, unsigned percent);
 
-bool nulstr_contains(const char*nulstr, const char *needle);
+bool nulstr_contains(const char *nulstr, const char *needle);
 
 char* strshorten(char *s, size_t l);
 
@@ -189,7 +189,7 @@ static inline void *memmem_safe(const void *haystack, size_t haystacklen, const
         return memmem(haystack, haystacklen, needle, needlelen);
 }
 
-#if !HAVE_DECL_EXPLICIT_BZERO
+#if !HAVE_EXPLICIT_BZERO
 void explicit_bzero(void *p, size_t l);
 #endif
 
@@ -200,3 +200,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
 #define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)
 
 bool string_is_safe(const char *p) _pure_;
+
+static inline size_t strlen_ptr(const char *s) {
+        if (!s)
+                return 0;
+
+        return strlen(s);
+}
diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c
index a3660f08..08bcff6e 100644
--- a/src/systemd/src/basic/strv.c
+++ b/src/systemd/src/basic/strv.c
@@ -774,11 +774,7 @@ static int str_compare(const void *_a, const void *_b) {
 }
 
 char **strv_sort(char **l) {
-
-        if (strv_isempty(l))
-                return l;
-
-        qsort(l, strv_length(l), sizeof(char*), str_compare);
+        qsort_safe(l, strv_length(l), sizeof(char*), str_compare);
         return l;
 }
 
diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c
index e8158d55..7f1c3f7c 100644
--- a/src/systemd/src/basic/time-util.c
+++ b/src/systemd/src/basic/time-util.c
@@ -23,6 +23,7 @@
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/timerfd.h>
@@ -109,7 +110,7 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
         ts->realtime = u;
 
         delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
-        ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta);
+        ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
 
         return ts;
 }
@@ -126,8 +127,8 @@ triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u)
 
         ts->realtime = u;
         delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
-        ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta);
-        ts->boottime = clock_boottime_supported() ? usec_sub(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
+        ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
+        ts->boottime = clock_boottime_supported() ? usec_sub_signed(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
 
         return ts;
 }
@@ -143,7 +144,7 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
 
         ts->monotonic = u;
         delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
-        ts->realtime = usec_sub(now(CLOCK_REALTIME), delta);
+        ts->realtime = usec_sub_signed(now(CLOCK_REALTIME), delta);
 
         return ts;
 }
@@ -158,8 +159,8 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us
 
         dual_timestamp_get(ts);
         delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
-        ts->realtime = usec_sub(ts->realtime, delta);
-        ts->monotonic = usec_sub(ts->monotonic, delta);
+        ts->realtime = usec_sub_signed(ts->realtime, delta);
+        ts->monotonic = usec_sub_signed(ts->monotonic, delta);
 
         return ts;
 }
@@ -244,7 +245,7 @@ usec_t timeval_load(const struct timeval *tv) {
 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
         assert(tv);
 
-        if (u == USEC_INFINITY||
+        if (u == USEC_INFINITY ||
             u / USEC_PER_SEC > TIME_T_MAX) {
                 tv->tv_sec = (time_t) -1;
                 tv->tv_usec = (suseconds_t) -1;
@@ -560,15 +561,29 @@ void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
 
 int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
         uint64_t a, b;
+        int r, pos;
 
         assert(value);
         assert(t);
 
-        if (sscanf(value, "%" PRIu64 "%" PRIu64, &a, &b) != 2) {
-                log_debug("Failed to parse dual timestamp value \"%s\": %m", value);
+        pos = strspn(value, WHITESPACE);
+        if (value[pos] == '-')
+                return -EINVAL;
+        pos += strspn(value + pos, DIGITS);
+        pos += strspn(value + pos, WHITESPACE);
+        if (value[pos] == '-')
+                return -EINVAL;
+
+        r = sscanf(value, "%" PRIu64 "%" PRIu64 "%n", &a, &b, &pos);
+        if (r != 2) {
+                log_debug("Failed to parse dual timestamp value \"%s\".", value);
                 return -EINVAL;
         }
 
+        if (value[pos] != '\0')
+                /* trailing garbage */
+                return -EINVAL;
+
         t->realtime = a;
         t->monotonic = b;
 
@@ -587,7 +602,7 @@ int timestamp_deserialize(const char *value, usec_t *timestamp) {
         return r;
 }
 
-int parse_timestamp(const char *t, usec_t *usec) {
+static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
         static const struct {
                 const char *name;
                 const int nr;
@@ -608,7 +623,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
                 { "Sat",       6 },
         };
 
-        const char *k, *utc, *tzn = NULL;
+        const char *k, *utc = NULL, *tzn = NULL;
         struct tm tm, copy;
         time_t x;
         usec_t x_usec, plus = 0, minus = 0, ret;
@@ -636,84 +651,86 @@ int parse_timestamp(const char *t, usec_t *usec) {
         assert(t);
         assert(usec);
 
-        if (t[0] == '@')
+        if (t[0] == '@' && !with_tz)
                 return parse_sec(t + 1, usec);
 
         ret = now(CLOCK_REALTIME);
 
-        if (streq(t, "now"))
-                goto finish;
+        if (!with_tz) {
+                if (streq(t, "now"))
+                        goto finish;
 
-        else if (t[0] == '+') {
-                r = parse_sec(t+1, &plus);
-                if (r < 0)
-                        return r;
+                else if (t[0] == '+') {
+                        r = parse_sec(t+1, &plus);
+                        if (r < 0)
+                                return r;
 
-                goto finish;
+                        goto finish;
 
-        } else if (t[0] == '-') {
-                r = parse_sec(t+1, &minus);
-                if (r < 0)
-                        return r;
+                } else if (t[0] == '-') {
+                        r = parse_sec(t+1, &minus);
+                        if (r < 0)
+                                return r;
 
-                goto finish;
+                        goto finish;
 
-        } else if ((k = endswith(t, " ago"))) {
-                t = strndupa(t, k - t);
+                } else if ((k = endswith(t, " ago"))) {
+                        t = strndupa(t, k - t);
 
-                r = parse_sec(t, &minus);
-                if (r < 0)
-                        return r;
+                        r = parse_sec(t, &minus);
+                        if (r < 0)
+                                return r;
 
-                goto finish;
+                        goto finish;
 
-        } else if ((k = endswith(t, " left"))) {
-                t = strndupa(t, k - t);
+                } else if ((k = endswith(t, " left"))) {
+                        t = strndupa(t, k - t);
 
-                r = parse_sec(t, &plus);
-                if (r < 0)
-                        return r;
+                        r = parse_sec(t, &plus);
+                        if (r < 0)
+                                return r;
 
-                goto finish;
-        }
+                        goto finish;
+                }
 
-        /* See if the timestamp is suffixed with UTC */
-        utc = endswith_no_case(t, " UTC");
-        if (utc)
-                t = strndupa(t, utc - t);
-        else {
-                const char *e = NULL;
-                int j;
+                /* See if the timestamp is suffixed with UTC */
+                utc = endswith_no_case(t, " UTC");
+                if (utc)
+                        t = strndupa(t, utc - t);
+                else {
+                        const char *e = NULL;
+                        int j;
 
-                tzset();
+                        tzset();
 
-                /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
-                 * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
-                 * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
-                 * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
-                 * support arbitrary timezone specifications.  */
+                        /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
+                        * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
+                        * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
+                        * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
+                        * support arbitrary timezone specifications.  */
 
-                for (j = 0; j <= 1; j++) {
+                        for (j = 0; j <= 1; j++) {
 
-                        if (isempty(tzname[j]))
-                                continue;
+                                if (isempty(tzname[j]))
+                                        continue;
 
-                        e = endswith_no_case(t, tzname[j]);
-                        if (!e)
-                                continue;
-                        if (e == t)
-                                continue;
-                        if (e[-1] != ' ')
-                                continue;
+                                e = endswith_no_case(t, tzname[j]);
+                                if (!e)
+                                        continue;
+                                if (e == t)
+                                        continue;
+                                if (e[-1] != ' ')
+                                        continue;
 
-                        break;
-                }
+                                break;
+                        }
 
-                if (IN_SET(j, 0, 1)) {
-                        /* Found one of the two timezones specified. */
-                        t = strndupa(t, e - t - 1);
-                        dst = j;
-                        tzn = tzname[j];
+                        if (IN_SET(j, 0, 1)) {
+                                /* Found one of the two timezones specified. */
+                                t = strndupa(t, e - t - 1);
+                                dst = j;
+                                tzn = tzname[j];
+                        }
                 }
         }
 
@@ -724,7 +741,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
                 return -EINVAL;
 
         tm.tm_isdst = dst;
-        if (tzn)
+        if (!with_tz && tzn)
                 tm.tm_zone = tzn;
 
         if (streq(t, "today")) {
@@ -837,11 +854,11 @@ parse_usec:
         }
 
 from_tm:
-        x = mktime_or_timegm(&tm, utc);
-        if (x < 0)
+        if (weekday >= 0 && tm.tm_wday != weekday)
                 return -EINVAL;
 
-        if (weekday >= 0 && tm.tm_wday != weekday)
+        x = mktime_or_timegm(&tm, utc);
+        if (x < 0)
                 return -EINVAL;
 
         ret = (usec_t) x * USEC_PER_SEC + x_usec;
@@ -855,16 +872,85 @@ finish:
         if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
                 return -EINVAL;
 
-        if (ret > minus)
+        if (ret >= minus)
                 ret -= minus;
         else
-                ret = 0;
+                return -EINVAL;
 
         *usec = ret;
 
         return 0;
 }
 
+typedef struct ParseTimestampResult {
+        usec_t usec;
+        int return_value;
+} ParseTimestampResult;
+
+int parse_timestamp(const char *t, usec_t *usec) {
+        char *last_space, *tz = NULL;
+        ParseTimestampResult *shared, tmp;
+        int r;
+        pid_t pid;
+
+        last_space = strrchr(t, ' ');
+        if (last_space != NULL && timezone_is_valid(last_space + 1))
+                tz = last_space + 1;
+
+        if (tz == NULL || endswith_no_case(t, " UTC"))
+                return parse_timestamp_impl(t, usec, false);
+
+        shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+        if (shared == MAP_FAILED)
+                return negative_errno();
+
+        pid = fork();
+
+        if (pid == -1) {
+                int fork_errno = errno;
+                (void) munmap(shared, sizeof *shared);
+                return -fork_errno;
+        }
+
+        if (pid == 0) {
+                bool with_tz = true;
+
+                if (setenv("TZ", tz, 1) != 0) {
+                        shared->return_value = negative_errno();
+                        _exit(EXIT_FAILURE);
+                }
+
+                tzset();
+
+                /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
+                 * Otherwise just cut it off */
+                with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
+
+                /*cut off the timezone if we dont need it*/
+                if (with_tz)
+                        t = strndupa(t, last_space - t);
+
+                shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
+
+                _exit(EXIT_SUCCESS);
+        }
+
+        r = wait_for_terminate(pid, NULL);
+        if (r < 0) {
+                (void) munmap(shared, sizeof *shared);
+                return r;
+        }
+
+        tmp = *shared;
+        if (munmap(shared, sizeof *shared) != 0)
+                return negative_errno();
+
+        if (tmp.return_value == 0)
+                *usec = tmp.usec;
+
+        return tmp.return_value;
+}
+
 static char* extract_multiplier(char *p, usec_t *multiplier) {
         static const struct {
                 const char *suffix;
@@ -1000,6 +1086,20 @@ int parse_sec(const char *t, usec_t *usec) {
         return parse_time(t, usec, USEC_PER_SEC);
 }
 
+int parse_sec_fix_0(const char *t, usec_t *usec) {
+        assert(t);
+        assert(usec);
+
+        t += strspn(t, WHITESPACE);
+
+        if (streq(t, "0")) {
+                *usec = USEC_INFINITY;
+                return 0;
+        }
+
+        return parse_sec(t, usec);
+}
+
 int parse_nsec(const char *t, nsec_t *nsec) {
         static const struct {
                 const char *suffix;
@@ -1218,7 +1318,7 @@ bool timezone_is_valid(const char *name) {
                 if (!(*p >= '0' && *p <= '9') &&
                     !(*p >= 'a' && *p <= 'z') &&
                     !(*p >= 'A' && *p <= 'Z') &&
-                    !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
+                    !IN_SET(*p, '-', '_', '+', '/'))
                         return false;
 
                 if (*p == '/') {
@@ -1344,4 +1444,23 @@ unsigned long usec_to_jiffies(usec_t u) {
 
         return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
 }
+
+usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
+        usec_t a, b;
+
+        if (x == USEC_INFINITY)
+                return USEC_INFINITY;
+        if (map_clock_id(from) == map_clock_id(to))
+                return x;
+
+        a = now(from);
+        b = now(to);
+
+        if (x > a)
+                /* x lies in the future */
+                return usec_add(b, usec_sub_unsigned(x, a));
+        else
+                /* x lies in the past */
+                return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
+}
 #endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h
index 7463507f..73f7e400 100644
--- a/src/systemd/src/basic/time-util.h
+++ b/src/systemd/src/basic/time-util.h
@@ -133,6 +133,7 @@ int timestamp_deserialize(const char *value, usec_t *timestamp);
 int parse_timestamp(const char *t, usec_t *usec);
 
 int parse_sec(const char *t, usec_t *usec);
+int parse_sec_fix_0(const char *t, usec_t *usec);
 int parse_time(const char *t, usec_t *usec, usec_t default_unit);
 int parse_nsec(const char *t, nsec_t *nsec);
 
@@ -145,9 +146,7 @@ bool clock_boottime_supported(void);
 bool clock_supported(clockid_t clock);
 clockid_t clock_boottime_or_monotonic(void);
 
-#define xstrftime(buf, fmt, tm) \
-        assert_message_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0, \
-                          "xstrftime: " #buf "[] must be big enough")
+usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to);
 
 int get_timezone(char **timezone);
 
@@ -169,19 +168,23 @@ static inline usec_t usec_add(usec_t a, usec_t b) {
         return c;
 }
 
-static inline usec_t usec_sub(usec_t timestamp, int64_t delta) {
-        if (delta < 0)
-                return usec_add(timestamp, (usec_t) (-delta));
+static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) {
 
         if (timestamp == USEC_INFINITY) /* Make sure infinity doesn't degrade */
                 return USEC_INFINITY;
-
-        if (timestamp < (usec_t) delta)
+        if (timestamp < delta)
                 return 0;
 
         return timestamp - delta;
 }
 
+static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
+        if (delta < 0)
+                return usec_add(timestamp, (usec_t) (-delta));
+        else
+                return usec_sub_unsigned(timestamp, (usec_t) delta);
+}
+
 #if SIZEOF_TIME_T == 8
 /* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit year
  * territory. However, since we want to stay away from this in all timezones we take one day off. */
diff --git a/src/systemd/src/basic/unaligned.h b/src/systemd/src/basic/unaligned.h
deleted file mode 100644
index 7c847a3c..00000000
--- a/src/systemd/src/basic/unaligned.h
+++ /dev/null
@@ -1,129 +0,0 @@
-#pragma once
-
-/***
-  This file is part of systemd.
-
-  Copyright 2014 Tom Gundersen
-
-  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 <endian.h>
-#include <stdint.h>
-
-/* BE */
-
-static inline uint16_t unaligned_read_be16(const void *_u) {
-        const uint8_t *u = _u;
-
-        return (((uint16_t) u[0]) << 8) |
-                ((uint16_t) u[1]);
-}
-
-static inline uint32_t unaligned_read_be32(const void *_u) {
-        const uint8_t *u = _u;
-
-        return (((uint32_t) unaligned_read_be16(u)) << 16) |
-                ((uint32_t) unaligned_read_be16(u + 2));
-}
-
-static inline uint64_t unaligned_read_be64(const void *_u) {
-        const uint8_t *u = _u;
-
-        return (((uint64_t) unaligned_read_be32(u)) << 32) |
-                ((uint64_t) unaligned_read_be32(u + 4));
-}
-
-static inline void unaligned_write_be16(void *_u, uint16_t a) {
-        uint8_t *u = _u;
-
-        u[0] = (uint8_t) (a >> 8);
-        u[1] = (uint8_t) a;
-}
-
-static inline void unaligned_write_be32(void *_u, uint32_t a) {
-        uint8_t *u = _u;
-
-        unaligned_write_be16(u, (uint16_t) (a >> 16));
-        unaligned_write_be16(u + 2, (uint16_t) a);
-}
-
-static inline void unaligned_write_be64(void *_u, uint64_t a) {
-        uint8_t *u = _u;
-
-        unaligned_write_be32(u, (uint32_t) (a >> 32));
-        unaligned_write_be32(u + 4, (uint32_t) a);
-}
-
-/* LE */
-
-static inline uint16_t unaligned_read_le16(const void *_u) {
-        const uint8_t *u = _u;
-
-        return (((uint16_t) u[1]) << 8) |
-                ((uint16_t) u[0]);
-}
-
-static inline uint32_t unaligned_read_le32(const void *_u) {
-        const uint8_t *u = _u;
-
-        return (((uint32_t) unaligned_read_le16(u + 2)) << 16) |
-                ((uint32_t) unaligned_read_le16(u));
-}
-
-static inline uint64_t unaligned_read_le64(const void *_u) {
-        const uint8_t *u = _u;
-
-        return (((uint64_t) unaligned_read_le32(u + 4)) << 32) |
-                ((uint64_t) unaligned_read_le32(u));
-}
-
-static inline void unaligned_write_le16(void *_u, uint16_t a) {
-        uint8_t *u = _u;
-
-        u[0] = (uint8_t) a;
-        u[1] = (uint8_t) (a >> 8);
-}
-
-static inline void unaligned_write_le32(void *_u, uint32_t a) {
-        uint8_t *u = _u;
-
-        unaligned_write_le16(u, (uint16_t) a);
-        unaligned_write_le16(u + 2, (uint16_t) (a >> 16));
-}
-
-static inline void unaligned_write_le64(void *_u, uint64_t a) {
-        uint8_t *u = _u;
-
-        unaligned_write_le32(u, (uint32_t) a);
-        unaligned_write_le32(u + 4, (uint32_t) (a >> 32));
-}
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define unaligned_read_ne16 unaligned_read_be16
-#define unaligned_read_ne32 unaligned_read_be32
-#define unaligned_read_ne64 unaligned_read_be64
-
-#define unaligned_write_ne16 unaligned_write_be16
-#define unaligned_write_ne32 unaligned_write_be32
-#define unaligned_write_ne64 unaligned_write_be64
-#else
-#define unaligned_read_ne16 unaligned_read_le16
-#define unaligned_read_ne32 unaligned_read_le32
-#define unaligned_read_ne64 unaligned_read_le64
-
-#define unaligned_write_ne16 unaligned_write_le16
-#define unaligned_write_ne32 unaligned_write_le32
-#define unaligned_write_ne64 unaligned_write_le64
-#endif
diff --git a/src/systemd/src/basic/utf8.c b/src/systemd/src/basic/utf8.c
index a6bdda6e..ff281e43 100644
--- a/src/systemd/src/basic/utf8.c
+++ b/src/systemd/src/basic/utf8.c
@@ -75,7 +75,7 @@ static bool unichar_is_control(char32_t ch) {
           '\t' is in C0 range, but more or less harmless and commonly used.
         */
 
-        return (ch < ' ' && ch != '\t' && ch != '\n') ||
+        return (ch < ' ' && !IN_SET(ch, '\t', '\n')) ||
                 (0x7F <= ch && ch <= 0x9F);
 }
 
diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c
index 563ee87e..c8a22d68 100644
--- a/src/systemd/src/basic/util.c
+++ b/src/systemd/src/basic/util.c
@@ -36,6 +36,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "btrfs-util.h"
 #include "build.h"
 #include "cgroup-util.h"
 #include "def.h"
@@ -181,15 +182,12 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
 }
 
 bool kexec_loaded(void) {
-       bool loaded = false;
-       char *s;
-
-       if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
-               if (s[0] == '1')
-                       loaded = true;
-               free(s);
-       }
-       return loaded;
+       _cleanup_free_ char *s = NULL;
+
+       if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
+               return false;
+
+       return s[0] == '1';
 }
 
 int prot_from_flags(int flags) {
@@ -224,7 +222,7 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
         /* Spawns a temporary TTY agent, making sure it goes away when
          * we go away */
 
-        parent_pid = getpid();
+        parent_pid = getpid_cached();
 
         /* First we temporarily block all signals, so that the new
          * child has them blocked initially. This way, we can be sure
@@ -382,7 +380,7 @@ int on_ac_power(void) {
 
                 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
                 if (device < 0) {
-                        if (errno == ENOENT || errno == ENOTDIR)
+                        if (IN_SET(errno, ENOENT, ENOTDIR))
                                 continue;
 
                         return -errno;
@@ -546,7 +544,7 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
                 if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
                         return -ENOMEM;
 
-                r = files_same(userns_fd_path, "/proc/self/ns/user");
+                r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
                 if (r < 0)
                         return r;
                 if (r)
@@ -724,4 +722,134 @@ int version(void) {
              SYSTEMD_FEATURES);
         return 0;
 }
+
+int get_block_device(const char *path, dev_t *dev) {
+        struct stat st;
+        struct statfs sfs;
+
+        assert(path);
+        assert(dev);
+
+        /* Get's the block device directly backing a file system. If
+         * the block device is encrypted, returns the device mapper
+         * block device. */
+
+        if (lstat(path, &st))
+                return -errno;
+
+        if (major(st.st_dev) != 0) {
+                *dev = st.st_dev;
+                return 1;
+        }
+
+        if (statfs(path, &sfs) < 0)
+                return -errno;
+
+        if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
+                return btrfs_get_block_device(path, dev);
+
+        return 0;
+}
+
+int get_block_device_harder(const char *path, dev_t *dev) {
+        _cleanup_closedir_ DIR *d = NULL;
+        _cleanup_free_ char *p = NULL, *t = NULL;
+        struct dirent *de, *found = NULL;
+        const char *q;
+        unsigned maj, min;
+        dev_t dt;
+        int r;
+
+        assert(path);
+        assert(dev);
+
+        /* Gets the backing block device for a file system, and
+         * handles LUKS encrypted file systems, looking for its
+         * immediate parent, if there is one. */
+
+        r = get_block_device(path, &dt);
+        if (r <= 0)
+                return r;
+
+        if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
+                return -ENOMEM;
+
+        d = opendir(p);
+        if (!d) {
+                if (errno == ENOENT)
+                        goto fallback;
+
+                return -errno;
+        }
+
+        FOREACH_DIRENT_ALL(de, d, return -errno) {
+
+                if (dot_or_dot_dot(de->d_name))
+                        continue;
+
+                if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
+                        continue;
+
+                if (found) {
+                        _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL;
+
+                        /* We found a device backed by multiple other devices. We don't really support automatic
+                         * discovery on such setups, with the exception of dm-verity partitions. In this case there are
+                         * two backing devices: the data partition and the hash partition. We are fine with such
+                         * setups, however, only if both partitions are on the same physical device. Hence, let's
+                         * verify this. */
+
+                        u = strjoin(p, "/", de->d_name, "/../dev");
+                        if (!u)
+                                return -ENOMEM;
+
+                        v = strjoin(p, "/", found->d_name, "/../dev");
+                        if (!v)
+                                return -ENOMEM;
+
+                        r = read_one_line_file(u, &a);
+                        if (r < 0) {
+                                log_debug_errno(r, "Failed to read %s: %m", u);
+                                goto fallback;
+                        }
+
+                        r = read_one_line_file(v, &b);
+                        if (r < 0) {
+                                log_debug_errno(r, "Failed to read %s: %m", v);
+                                goto fallback;
+                        }
+
+                        /* Check if the parent device is the same. If not, then the two backing devices are on
+                         * different physical devices, and we don't support that. */
+                        if (!streq(a, b))
+                                goto fallback;
+                }
+
+                found = de;
+        }
+
+        if (!found)
+                goto fallback;
+
+        q = strjoina(p, "/", found->d_name, "/dev");
+
+        r = read_one_line_file(q, &t);
+        if (r == -ENOENT)
+                goto fallback;
+        if (r < 0)
+                return r;
+
+        if (sscanf(t, "%u:%u", &maj, &min) != 2)
+                return -EINVAL;
+
+        if (maj == 0)
+                goto fallback;
+
+        *dev = makedev(maj, min);
+        return 1;
+
+fallback:
+        *dev = dt;
+        return 1;
+}
 #endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h
index c7da6c39..b31dfd1c 100644
--- a/src/systemd/src/basic/util.h
+++ b/src/systemd/src/basic/util.h
@@ -192,3 +192,6 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
 int update_reboot_parameter_and_warn(const char *param);
 
 int version(void);
+
+int get_block_device(const char *path, dev_t *dev);
+int get_block_device_harder(const char *path, dev_t *dev);
diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
index 82cae230..7847ce07 100644
--- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
@@ -75,6 +75,7 @@ struct sd_dhcp_lease {
         uint16_t mtu; /* 0 if unset */
 
         char *domainname;
+        char **search_domains;
         char *hostname;
         char *root_path;
 
@@ -92,6 +93,7 @@ struct sd_dhcp_lease {
 int dhcp_lease_new(sd_dhcp_lease **ret);
 
 int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata);
+int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains);
 int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len);
 
 int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);
diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c
index 7ad0ec37..f01b2cfe 100644
--- a/src/systemd/src/libsystemd-network/dhcp-network.c
+++ b/src/systemd/src/libsystemd-network/dhcp-network.c
@@ -110,14 +110,16 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
         if (r < 0)
                 return -errno;
 
-        link->ll.sll_family = AF_PACKET;
-        link->ll.sll_protocol = htobe16(ETH_P_IP);
-        link->ll.sll_ifindex = ifindex;
-        link->ll.sll_hatype = htobe16(arp_type);
-        link->ll.sll_halen = mac_addr_len;
+        link->ll = (struct sockaddr_ll) {
+                .sll_family = AF_PACKET,
+                .sll_protocol = htobe16(ETH_P_IP),
+                .sll_ifindex = ifindex,
+                .sll_hatype = htobe16(arp_type),
+                .sll_halen = mac_addr_len,
+        };
         memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
 
-        r = bind(s, &link->sa, sizeof(link->ll));
+        r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
         if (r < 0)
                 return -errno;
 
@@ -223,7 +225,7 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
         assert(packet);
         assert(len);
 
-        r = sendto(s, packet, len, 0, &link->sa, sizeof(link->ll));
+        r = sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll));
         if (r < 0)
                 return -errno;
 
diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c
index 27410520..1bb1bfcf 100644
--- a/src/systemd/src/libsystemd-network/dhcp-packet.c
+++ b/src/systemd/src/libsystemd-network/dhcp-packet.c
@@ -36,8 +36,8 @@ int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
         size_t offset = 0;
         int r;
 
-        assert(op == BOOTREQUEST || op == BOOTREPLY);
-        assert(arp_type == ARPHRD_ETHER || arp_type == ARPHRD_INFINIBAND);
+        assert(IN_SET(op, BOOTREQUEST, BOOTREPLY));
+        assert(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND));
 
         message->op = op;
         message->htype = arp_type;
diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c
index afede1e7..c560a864 100644
--- a/src/systemd/src/libsystemd-network/lldp-neighbor.c
+++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c
@@ -251,10 +251,9 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) {
                                 log_lldp("End marker TLV not zero-sized, ignoring datagram.");
                                 return -EBADMSG;
                         }
-                        if (left != 0) {
-                                log_lldp("Trailing garbage in datagram, ignoring datagram.");
-                                return -EBADMSG;
-                        }
+
+                        /* Note that after processing the SD_LLDP_TYPE_END left could still be > 0
+                         * as the message may contain padding (see IEEE 802.1AB-2016, sec. 8.5.12) */
 
                         goto end_marker;
 
diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c
index 285a73e3..de37b9f0 100644
--- a/src/systemd/src/libsystemd-network/network-internal.c
+++ b/src/systemd/src/libsystemd-network/network-internal.c
@@ -351,8 +351,47 @@ int config_parse_iaid(const char *unit,
 
         return 0;
 }
+
+int config_parse_bridge_port_priority(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        uint16_t i;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = safe_atou16(rvalue, &i);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse bridge port priority, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue);
+                return 0;
+        }
+
+        *((uint16_t *)data) = i;
+
+        return 0;
+}
 #endif /* NM_IGNORED */
 
+
 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
         unsigned i;
 
diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h
index 5bcd5771..4666f174 100644
--- a/src/systemd/src/libsystemd-network/network-internal.h
+++ b/src/systemd/src/libsystemd-network/network-internal.h
@@ -26,6 +26,9 @@
 #include "condition.h"
 #include "udev.h"
 
+#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128
+#define LINK_BRIDGE_PORT_PRIORITY_MAX 63
+
 bool net_match_config(const struct ether_addr *match_mac,
                       char * const *match_path,
                       char * const *match_driver,
@@ -62,6 +65,10 @@ int config_parse_iaid(const char *unit, const char *filename, unsigned line,
                       const char *section, unsigned section_line, const char *lvalue,
                       int ltype, const char *rvalue, void *data, void *userdata);
 
+int config_parse_bridge_port_priority(const char *unit, const char *filename, unsigned line,
+                      const char *section, unsigned section_line, const char *lvalue,
+                      int ltype, const char *rvalue, void *data, void *userdata);
+
 int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result);
 const char *net_get_name(struct udev_device *device);
 
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
index 17393e20..fc6ad422 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
@@ -64,6 +64,7 @@ struct sd_dhcp_client {
         uint8_t *req_opts;
         size_t req_opts_allocated;
         size_t req_opts_size;
+        bool anonymize;
         be32_t last_addr;
         uint8_t mac_addr[MAX_MAC_ADDR_LEN];
         size_t mac_addr_len;
@@ -118,6 +119,32 @@ static const uint8_t default_req_opts[] = {
         SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
 };
 
+/* RFC7844 section 3:
+   MAY contain the Parameter Request List option.
+   RFC7844 section 3.6:
+   The client intending to protect its privacy SHOULD only request a
+   minimal number of options in the PRL and SHOULD also randomly shuffle
+   the ordering of option codes in the PRL.  If this random ordering
+   cannot be implemented, the client MAY order the option codes in the
+   PRL by option code number (lowest to highest).
+*/
+/* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */
+static const uint8_t default_req_opts_anonymize[] = {
+       SD_DHCP_OPTION_SUBNET_MASK,                     /* 1 */
+       SD_DHCP_OPTION_ROUTER,                          /* 3 */
+       SD_DHCP_OPTION_DOMAIN_NAME_SERVER,              /* 6 */
+       SD_DHCP_OPTION_DOMAIN_NAME,                     /* 15 */
+       SD_DHCP_OPTION_ROUTER_DISCOVER,                 /* 31 */
+       SD_DHCP_OPTION_STATIC_ROUTE,                    /* 33 */
+       SD_DHCP_OPTION_VENDOR_SPECIFIC,                 /* 43 */
+       SD_DHCP_OPTION_NETBIOS_NAMESERVER,              /* 44 */
+       SD_DHCP_OPTION_NETBIOS_NODETYPE,                /* 46 */
+       SD_DHCP_OPTION_NETBIOS_SCOPE,                   /* 47 */
+       SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE,          /* 121 */
+       SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE,  /* 249 */
+       SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY,     /* 252 */
+};
+
 static int client_receive_message_raw(
                 sd_event_source *s,
                 int fd,
@@ -432,9 +459,7 @@ int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
         assert_return(client, -EINVAL);
 
-        if (client->state != DHCP_STATE_BOUND &&
-            client->state != DHCP_STATE_RENEWING &&
-            client->state != DHCP_STATE_REBINDING)
+        if (!IN_SET(client->state, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING))
                 return -EADDRNOTAVAIL;
 
         if (ret)
@@ -507,7 +532,7 @@ static int client_message_init(
         assert(ret);
         assert(_optlen);
         assert(_optoffset);
-        assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
+        assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST));
 
         optlen = DHCP_MIN_OPTIONS_SIZE;
         size = sizeof(DHCPPacket) + optlen;
@@ -592,11 +617,18 @@ static int client_message_init(
            it MUST include that list in any subsequent DHCPREQUEST
            messages.
          */
-        r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
-                               SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
-                               client->req_opts_size, client->req_opts);
-        if (r < 0)
-                return r;
+
+        /* RFC7844 section 3:
+           MAY contain the Parameter Request List option. */
+        /* NOTE: in case that there would be an option to do not send
+         * any PRL at all, the size should be checked before sending */
+        if (client->req_opts_size > 0) {
+                r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
+                                       SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
+                                       client->req_opts_size, client->req_opts);
+                if (r < 0)
+                        return r;
+        }
 
         /* RFC2131 section 3.5:
            The client SHOULD include the ’maximum DHCP message size’ option to
@@ -620,12 +652,16 @@ static int client_message_init(
            Maximum DHCP Message Size option is the total maximum packet size,
            including IP and UDP headers.)
          */
-        max_size = htobe16(size);
-        r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
-                               SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
-                               2, &max_size);
-        if (r < 0)
-                return r;
+        /* RFC7844 section 3:
+           SHOULD NOT contain any other option. */
+        if (!client->anonymize) {
+                max_size = htobe16(size);
+                r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
+                                       SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
+                                       2, &max_size);
+                if (r < 0)
+                        return r;
+        }
 
         *_optlen = optlen;
         *_optoffset = optoffset;
@@ -675,8 +711,7 @@ static int client_send_discover(sd_dhcp_client *client) {
         int r;
 
         assert(client);
-        assert(client->state == DHCP_STATE_INIT ||
-               client->state == DHCP_STATE_SELECTING);
+        assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
 
         r = client_message_init(client, &discover, DHCP_DISCOVER,
                                 &optlen, &optoffset);
@@ -1130,7 +1165,7 @@ static int client_start_delayed(sd_dhcp_client *client) {
         }
         client->fd = r;
 
-        if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT)
+        if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT))
                 client->start_time = now(clock_boottime_or_monotonic());
 
         return client_initialize_events(client, client_receive_message_raw);
@@ -1656,10 +1691,11 @@ static int client_receive_message_udp(
 
         len = recv(fd, message, buflen, 0);
         if (len < 0) {
-                if (errno == EAGAIN || errno == EINTR)
+                if (IN_SET(errno, EAGAIN, EINTR))
                         return 0;
 
-                return log_dhcp_client_errno(client, errno, "Could not receive message from UDP socket: %m");
+                return log_dhcp_client_errno(client, errno,
+                                             "Could not receive message from UDP socket: %m");
         }
         if ((size_t) len < sizeof(DHCPMessage)) {
                 log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
@@ -1749,12 +1785,11 @@ static int client_receive_message_raw(
 
         len = recvmsg(fd, &msg, 0);
         if (len < 0) {
-                if (errno == EAGAIN || errno == EINTR)
+                if (IN_SET(errno, EAGAIN, EINTR))
                         return 0;
 
-                log_dhcp_client(client, "Could not receive message from raw socket: %m");
-
-                return -errno;
+                return log_dhcp_client_errno(client, errno,
+                                             "Could not receive message from raw socket: %m");
         } else if ((size_t)len < sizeof(DHCPPacket))
                 return 0;
 
@@ -1787,7 +1822,14 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
         if (r < 0)
                 return r;
 
-        if (client->last_addr)
+        /* RFC7844 section 3.3:
+           SHOULD perform a complete four-way handshake, starting with a
+           DHCPDISCOVER, to obtain a new address lease.  If the client can
+           ascertain that this is exactly the same network to which it was
+           previously connected, and if the link-layer address did not change,
+           the client MAY issue a DHCPREQUEST to try to reclaim the current
+           address. */
+        if (client->last_addr && !client->anonymize)
                 client->state = DHCP_STATE_INIT_REBOOT;
 
         r = client_start(client);
@@ -1879,7 +1921,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
         return mfree(client);
 }
 
-int sd_dhcp_client_new(sd_dhcp_client **ret) {
+int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
         _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
 
         assert_return(ret, -EINVAL);
@@ -1896,8 +1938,15 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) {
         client->mtu = DHCP_DEFAULT_MIN_SIZE;
         client->port = DHCP_PORT_CLIENT;
 
-        client->req_opts_size = ELEMENTSOF(default_req_opts);
-        client->req_opts = memdup(default_req_opts, client->req_opts_size);
+        client->anonymize = !!anonymize;
+        /* NOTE: this could be moved to a function. */
+        if (anonymize) {
+                client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
+                client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
+        } else {
+                client->req_opts_size = ELEMENTSOF(default_req_opts);
+                client->req_opts = memdup(default_req_opts, client->req_opts_size);
+        }
         if (!client->req_opts)
                 return -ENOMEM;
 
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
index 5a3bff2f..c00190b5 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
@@ -233,6 +233,21 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
         return (int) lease->static_route_size;
 }
 
+int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
+        unsigned r;
+
+        assert_return(lease, -EINVAL);
+        assert_return(domains, -EINVAL);
+
+        r = strv_length(lease->search_domains);
+        if (r > 0) {
+                *domains = lease->search_domains;
+                return (int) r;
+        }
+
+        return -ENODATA;
+}
+
 int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
         assert_return(lease, -EINVAL);
         assert_return(data, -EINVAL);
@@ -284,6 +299,7 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
         free(lease->static_route);
         free(lease->client_id);
         free(lease->vendor_specific);
+        strv_free(lease->search_domains);
         return mfree(lease);
 }
 
@@ -457,7 +473,7 @@ static int lease_parse_routes(
                 struct sd_dhcp_route *route = *routes + *routes_size;
                 int r;
 
-                r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
+                r = in4_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
                 if (r < 0) {
                         log_debug("Failed to determine destination prefix length from class based IP, ignoring");
                         continue;
@@ -596,6 +612,11 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
                 r = lease_parse_u16(option, len, &lease->mtu, 68);
                 if (r < 0)
                         log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
+                if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) {
+                        log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE);
+                        lease->mtu = DHCP_DEFAULT_MIN_SIZE;
+                }
+
                 break;
 
         case SD_DHCP_OPTION_DOMAIN_NAME:
@@ -607,6 +628,12 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
 
                 break;
 
+        case SD_DHCP_OPTION_DOMAIN_SEARCH_LIST:
+                r = dhcp_lease_parse_search_domains(option, len, &lease->search_domains);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to parse Domain Search List, ignoring: %m");
+                break;
+
         case SD_DHCP_OPTION_HOST_NAME:
                 r = lease_parse_domain(option, len, &lease->hostname);
                 if (r < 0) {
@@ -698,6 +725,96 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
         return 0;
 }
 
+/* Parses compressed domain names. */
+int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains) {
+        _cleanup_strv_free_ char **names = NULL;
+        size_t pos = 0, cnt = 0;
+        int r;
+
+        assert(domains);
+        assert_return(option && len > 0, -ENODATA);
+
+        while (pos < len) {
+                _cleanup_free_ char *name = NULL;
+                size_t n = 0, allocated = 0;
+                size_t jump_barrier = pos, next_chunk = 0;
+                bool first = true;
+
+                for (;;) {
+                        uint8_t c;
+                        c = option[pos++];
+
+                        if (c == 0) {
+                                /* End of name */
+                                break;
+                        } else if (c <= 63) {
+                                const char *label;
+
+                                /* Literal label */
+                                label = (const char*) (option + pos);
+                                pos += c;
+                                if (pos >= len)
+                                        return -EBADMSG;
+
+                                if (!GREEDY_REALLOC(name, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
+                                        return -ENOMEM;
+
+                                if (first)
+                                        first = false;
+                                else
+                                        name[n++] = '.';
+
+                                r = dns_label_escape(label, c, name + n, DNS_LABEL_ESCAPED_MAX);
+                                if (r < 0)
+                                        return r;
+
+                                n += r;
+                        } else if ((c & 0xc0) == 0xc0) {
+                                /* Pointer */
+
+                                uint8_t d;
+                                uint16_t ptr;
+
+                                if (pos >= len)
+                                        return -EBADMSG;
+
+                                d = option[pos++];
+                                ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
+
+                                /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
+                                if (ptr >= jump_barrier)
+                                        return -EBADMSG;
+                                jump_barrier = ptr;
+
+                                /* Save current location so we don't end up re-parsing what's parsed so far. */
+                                if (next_chunk == 0)
+                                        next_chunk = pos;
+
+                                pos = ptr;
+                        } else
+                                return -EBADMSG;
+                }
+
+                if (!GREEDY_REALLOC(name, allocated, n + 1))
+                        return -ENOMEM;
+                name[n] = 0;
+
+                r = strv_extend(&names, name);
+                if (r < 0)
+                        return r;
+
+                cnt++;
+
+                if (next_chunk != 0)
+                      pos = next_chunk;
+        }
+
+        *domains = names;
+        names = NULL;
+
+        return cnt;
+}
+
 int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) {
         struct sd_dhcp_raw_option *cur, *option;
 
@@ -753,6 +870,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
         const char *string;
         uint16_t mtu;
         _cleanup_free_ sd_dhcp_route **routes = NULL;
+        char **search_domains = NULL;
         uint32_t t1, t2, lifetime;
         int r;
 
@@ -810,22 +928,29 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
 
         r = sd_dhcp_lease_get_dns(lease, &addresses);
         if (r > 0) {
-                fputs("DNS=", f);
+                fputs_unlocked("DNS=", f);
                 serialize_in_addrs(f, addresses, r);
-                fputs("\n", f);
+                fputs_unlocked("\n", f);
         }
 
         r = sd_dhcp_lease_get_ntp(lease, &addresses);
         if (r > 0) {
-                fputs("NTP=", f);
+                fputs_unlocked("NTP=", f);
                 serialize_in_addrs(f, addresses, r);
-                fputs("\n", f);
+                fputs_unlocked("\n", f);
         }
 
         r = sd_dhcp_lease_get_domainname(lease, &string);
         if (r >= 0)
                 fprintf(f, "DOMAINNAME=%s\n", string);
 
+        r = sd_dhcp_lease_get_search_domains(lease, &search_domains);
+        if (r > 0) {
+                fputs_unlocked("DOMAIN_SEARCH_LIST=", f);
+                fputstrv(f, search_domains, NULL, NULL);
+                fputs_unlocked("\n", f);
+        }
+
         r = sd_dhcp_lease_get_hostname(lease, &string);
         if (r >= 0)
                 fprintf(f, "HOSTNAME=%s\n", string);
@@ -907,6 +1032,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                 *ntp = NULL,
                 *mtu = NULL,
                 *routes = NULL,
+                *domains = NULL,
                 *client_id_hex = NULL,
                 *vendor_specific_hex = NULL,
                 *lifetime = NULL,
@@ -935,6 +1061,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                            "MTU", &mtu,
                            "DOMAINNAME", &lease->domainname,
                            "HOSTNAME", &lease->hostname,
+                           "DOMAIN_SEARCH_LIST", &domains,
                            "ROOT_PATH", &lease->root_path,
                            "ROUTES", &routes,
                            "CLIENTID", &client_id_hex,
@@ -1040,6 +1167,18 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                         log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu);
         }
 
+        if (domains) {
+                _cleanup_strv_free_ char **a = NULL;
+                a = strv_split(domains, " ");
+                if (!a)
+                        return -ENOMEM;
+
+                if (!strv_isempty(a)) {
+                        lease->search_domains = a;
+                        a = NULL;
+                }
+        }
+
         if (routes) {
                 r = deserialize_dhcp_routes(
                                 &lease->static_route,
@@ -1116,7 +1255,7 @@ int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
         address.s_addr = lease->address;
 
         /* fall back to the default subnet masks based on address class */
-        r = in_addr_default_subnet_mask(&address, &mask);
+        r = in4_addr_default_subnet_mask(&address, &mask);
         if (r < 0)
                 return r;
 
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
index fa508d68..f512b65b 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
@@ -944,7 +944,7 @@ static int client_receive_message(
 
         len = recv(fd, message, buflen, 0);
         if (len < 0) {
-                if (errno == EAGAIN || errno == EINTR)
+                if (IN_SET(errno, EAGAIN, EINTR))
                         return 0;
 
                 return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c
index 3976768b..694384b5 100644
--- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c
@@ -356,7 +356,7 @@ static int ipv4acd_on_packet(
 
         n = recv(fd, &packet, sizeof(struct ether_arp), 0);
         if (n < 0) {
-                if (errno == EAGAIN || errno == EINTR)
+                if (IN_SET(errno, EAGAIN, EINTR))
                         return 0;
 
                 log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m");
diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c
index 2a64a99b..31e24486 100644
--- a/src/systemd/src/libsystemd-network/sd-lldp.c
+++ b/src/systemd/src/libsystemd-network/sd-lldp.c
@@ -220,7 +220,7 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
 
         length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
         if (length < 0) {
-                if (errno == EAGAIN || errno == EINTR)
+                if (IN_SET(errno, EAGAIN, EINTR))
                         return 0;
 
                 return log_lldp_errno(errno, "Failed to read LLDP datagram: %m");
diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c
index 3f7b703e..9dfe6847 100644
--- a/src/systemd/src/libsystemd/sd-event/sd-event.c
+++ b/src/systemd/src/libsystemd/sd-event/sd-event.c
@@ -438,7 +438,7 @@ _public_ int sd_event_new(sd_event** ret) {
         e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->boottime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1;
         e->realtime.next = e->boottime.next = e->monotonic.next = e->realtime_alarm.next = e->boottime_alarm.next = USEC_INFINITY;
         e->realtime.wakeup = e->boottime.wakeup = e->monotonic.wakeup = e->realtime_alarm.wakeup = e->boottime_alarm.wakeup = WAKEUP_CLOCK_DATA;
-        e->original_pid = getpid();
+        e->original_pid = getpid_cached();
         e->perturb = USEC_INFINITY;
 
         r = prioq_ensure_allocated(&e->pending, pending_prioq_compare);
@@ -495,7 +495,7 @@ static bool event_pid_changed(sd_event *e) {
         /* We don't support people creating an event loop and keeping
          * it around over a fork(). Let's complain. */
 
-        return e->original_pid != getpid();
+        return e->original_pid != getpid_cached();
 }
 
 static void source_io_unregister(sd_event_source *s) {
@@ -1601,7 +1601,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
         int r;
 
         assert_return(s, -EINVAL);
-        assert_return(m == SD_EVENT_OFF || m == SD_EVENT_ON || m == SD_EVENT_ONESHOT, -EINVAL);
+        assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL);
         assert_return(!event_pid_changed(s->event), -ECHILD);
 
         /* If we are dead anyway, we are fine with turning off
@@ -2054,7 +2054,7 @@ static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) {
 
         ss = read(fd, &x, sizeof(x));
         if (ss < 0) {
-                if (errno == EAGAIN || errno == EINTR)
+                if (IN_SET(errno, EAGAIN, EINTR))
                         return 0;
 
                 return -errno;
@@ -2143,10 +2143,7 @@ static int process_child(sd_event *e) {
                         return -errno;
 
                 if (s->child.siginfo.si_pid != 0) {
-                        bool zombie =
-                                s->child.siginfo.si_code == CLD_EXITED ||
-                                s->child.siginfo.si_code == CLD_KILLED ||
-                                s->child.siginfo.si_code == CLD_DUMPED;
+                        bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED);
 
                         if (!zombie && (s->child.options & WEXITED)) {
                                 /* If the child isn't dead then let's
@@ -2197,7 +2194,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
 
                 n = read(d->fd, &si, sizeof(si));
                 if (n < 0) {
-                        if (errno == EAGAIN || errno == EINTR)
+                        if (IN_SET(errno, EAGAIN, EINTR))
                                 return read_one;
 
                         return -errno;
@@ -2239,7 +2236,7 @@ static int source_dispatch(sd_event_source *s) {
          * the event. */
         saved_type = s->type;
 
-        if (s->type != SOURCE_DEFER && s->type != SOURCE_EXIT) {
+        if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
                 r = source_set_pending(s, false);
                 if (r < 0)
                         return r;
@@ -2291,9 +2288,7 @@ static int source_dispatch(sd_event_source *s) {
         case SOURCE_CHILD: {
                 bool zombie;
 
-                zombie = s->child.siginfo.si_code == CLD_EXITED ||
-                         s->child.siginfo.si_code == CLD_KILLED ||
-                         s->child.siginfo.si_code == CLD_DUMPED;
+                zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED);
 
                 r = s->child.callback(s, &s->child.siginfo, s->userdata);
 
diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c
index 57525ddb..19277021 100644
--- a/src/systemd/src/libsystemd/sd-id128/id128-util.c
+++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c
@@ -78,7 +78,7 @@ bool id128_is_valid(const char *s) {
                 for (i = 0; i < l; i++) {
                         char c = s[i];
 
-                        if ((i == 8 || i == 13 || i == 18 || i == 23)) {
+                        if (IN_SET(i, 8, 13, 18, 23)) {
                                 if (c != '-')
                                         return false;
                         } else {
diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
index 9920bfdf..052110d5 100644
--- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
@@ -70,7 +70,7 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
 
                         if (i == 8)
                                 is_guid = true;
-                        else if (i == 13 || i == 18 || i == 23) {
+                        else if (IN_SET(i, 13, 18, 23)) {
                                 if (!is_guid)
                                         return -EINVAL;
                         } else
@@ -294,7 +294,7 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
 
         assert_return(ret, -EINVAL);
 
-        r = dev_urandom(&t, sizeof(t));
+        r = acquire_random_bytes(&t, sizeof t, true);
         if (r < 0)
                 return r;
 
diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c
index 5ed27191..c313a033 100644
--- a/src/systemd/src/shared/dns-domain.c
+++ b/src/systemd/src/shared/dns-domain.c
@@ -19,9 +19,13 @@
 
 #include "nm-sd-adapt.h"
 
-#ifdef HAVE_LIBIDN
-#include <idna.h>
-#include <stringprep.h>
+#if 0 /* NM_IGNORED */
+#if HAVE_LIBIDN2
+#  include <idn2.h>
+#elif HAVE_LIBIDN
+#  include <idna.h>
+#  include <stringprep.h>
+#endif
 #endif
 
 #include <endian.h>
@@ -76,7 +80,7 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
                                 /* Ending NUL */
                                 return -EINVAL;
 
-                        else if (*n == '\\' || *n == '.') {
+                        else if (IN_SET(*n, '\\', '.')) {
                                 /* Escaped backslash or dot */
 
                                 if (d)
@@ -144,6 +148,7 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
         return r;
 }
 
+#if 0 /* NM_IGNORED */
 /* @label_terminal: terminal character of a label, updated to point to the terminal character of
  *                  the previous label (always skipping one dot) or to NULL if there are no more
  *                  labels. */
@@ -164,7 +169,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
         }
 
         terminal = *label_terminal;
-        assert(*terminal == '.' || *terminal == 0);
+        assert(IN_SET(*terminal, 0, '.'));
 
         /* Skip current terminal character (and accept domain names ending it ".") */
         if (*terminal == 0)
@@ -209,6 +214,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
 
         return r;
 }
+#endif /* NM_IGNORED */
 
 int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
         char *q;
@@ -228,7 +234,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
         q = dest;
         while (l > 0) {
 
-                if (*p == '.' || *p == '\\') {
+                if (IN_SET(*p, '.', '\\')) {
 
                         /* Dot or backslash */
 
@@ -240,8 +246,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
 
                         sz -= 2;
 
-                } else if (*p == '_' ||
-                           *p == '-' ||
+                } else if (IN_SET(*p, '_', '-') ||
                            (*p >= '0' && *p <= '9') ||
                            (*p >= 'a' && *p <= 'z') ||
                            (*p >= 'A' && *p <= 'Z')) {
@@ -277,6 +282,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
         return (int) (q - dest);
 }
 
+#if 0 /* NM_IGNORED */
 int dns_label_escape_new(const char *p, size_t l, char **ret) {
         _cleanup_free_ char *s = NULL;
         int r;
@@ -301,8 +307,8 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) {
         return r;
 }
 
+#if HAVE_LIBIDN
 int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
-#ifdef HAVE_LIBIDN
         _cleanup_free_ uint32_t *input = NULL;
         size_t input_size, l;
         const char *p;
@@ -350,13 +356,9 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
                 decoded[l] = 0;
 
         return (int) l;
-#else
-        return 0;
-#endif
 }
 
 int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
-#ifdef HAVE_LIBIDN
         size_t input_size, output_size;
         _cleanup_free_ uint32_t *input = NULL;
         _cleanup_free_ char *result = NULL;
@@ -401,10 +403,9 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
                 decoded[w] = 0;
 
         return w;
-#else
-        return 0;
-#endif
 }
+#endif
+#endif /* NM_IGNORED */
 
 int dns_name_concat(const char *a, const char *b, char **_ret) {
         _cleanup_free_ char *ret = NULL;
@@ -1279,6 +1280,49 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
 }
 
 int dns_name_apply_idna(const char *name, char **ret) {
+        /* Return negative on error, 0 if not implemented, positive on success. */
+
+#if HAVE_LIBIDN2
+        int r;
+        _cleanup_free_ char *t = NULL;
+
+        assert(name);
+        assert(ret);
+
+        r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
+                           IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
+        log_debug("idn2_lookup_u8: %s → %s", name, t);
+        if (r == IDN2_OK) {
+                if (!startswith(name, "xn--")) {
+                        _cleanup_free_ char *s = NULL;
+
+                        r = idn2_to_unicode_8z8z(t, &s, 0);
+                        if (r != IDN2_OK) {
+                                log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
+                                          t, r, idn2_strerror(r));
+                                return 0;
+                        }
+
+                        if (!streq_ptr(name, s)) {
+                                log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.",
+                                          name, t, s);
+                                return 0;
+                        }
+                }
+
+                *ret = t;
+                t = NULL;
+                return 1; /* *ret has been written */
+        }
+
+        log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r));
+        if (r == IDN2_2HYPHEN)
+                /* The name has two hypens — forbidden by IDNA2008 in some cases */
+                return 0;
+        if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL))
+                return -ENOSPC;
+        return -EINVAL;
+#elif HAVE_LIBIDN
         _cleanup_free_ char *buf = NULL;
         size_t n = 0, allocated = 0;
         bool first = true;
@@ -1314,7 +1358,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
                 else
                         buf[n++] = '.';
 
-                n +=r;
+                n += r;
         }
 
         if (n > DNS_HOSTNAME_MAX)
@@ -1327,7 +1371,10 @@ int dns_name_apply_idna(const char *name, char **ret) {
         *ret = buf;
         buf = NULL;
 
-        return (int) n;
+        return 1;
+#else
+        return 0;
+#endif
 }
 
 int dns_name_is_valid_or_address(const char *name) {
diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h
index 03f16036..d1a99be7 100644
--- a/src/systemd/src/shared/dns-domain.h
+++ b/src/systemd/src/shared/dns-domain.h
@@ -51,8 +51,12 @@ static inline int dns_name_parent(const char **name) {
         return dns_label_unescape(name, NULL, DNS_LABEL_MAX);
 }
 
+#if 0 /* NM_IGNORED */
+#if HAVE_LIBIDN
 int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
 int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
+#endif
+#endif /* NM_IGNORED */
 
 int dns_name_concat(const char *a, const char *b, char **ret);
 
diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h
index ffe7f836..5e46d8d0 100644
--- a/src/systemd/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/src/systemd/sd-dhcp-client.h
@@ -58,9 +58,17 @@ enum {
         SD_DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24,
         SD_DHCP_OPTION_INTERFACE_MTU               = 26,
         SD_DHCP_OPTION_BROADCAST                   = 28,
+       /* Windows 10 option to send when Anonymize=true */
+        SD_DHCP_OPTION_ROUTER_DISCOVER             = 31,
         SD_DHCP_OPTION_STATIC_ROUTE                = 33,
         SD_DHCP_OPTION_NTP_SERVER                  = 42,
         SD_DHCP_OPTION_VENDOR_SPECIFIC             = 43,
+       /* Windows 10 option to send when Anonymize=true */
+        SD_DHCP_OPTION_NETBIOS_NAMESERVER          = 44,
+       /* Windows 10 option to send when Anonymize=true */
+        SD_DHCP_OPTION_NETBIOS_NODETYPE            = 46,
+       /* Windows 10 option to send when Anonymize=true */
+        SD_DHCP_OPTION_NETBIOS_SCOPE               = 47,
         SD_DHCP_OPTION_REQUESTED_IP_ADDRESS        = 50,
         SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME       = 51,
         SD_DHCP_OPTION_OVERLOAD                    = 52,
@@ -76,8 +84,13 @@ enum {
         SD_DHCP_OPTION_FQDN                        = 81,
         SD_DHCP_OPTION_NEW_POSIX_TIMEZONE          = 100,
         SD_DHCP_OPTION_NEW_TZDB_TIMEZONE           = 101,
+        SD_DHCP_OPTION_DOMAIN_SEARCH_LIST          = 119,
         SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE      = 121,
         SD_DHCP_OPTION_PRIVATE_BASE                = 224,
+       /* Windows 10 option to send when Anonymize=true */
+        SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249,
+       /* Windows 10 option to send when Anonymize=true */
+        SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY = 252,
         SD_DHCP_OPTION_PRIVATE_LAST                = 254,
         SD_DHCP_OPTION_END                         = 255,
 };
@@ -145,7 +158,9 @@ int sd_dhcp_client_start(sd_dhcp_client *client);
 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);
 sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client);
 
-int sd_dhcp_client_new(sd_dhcp_client **ret);
+/* NOTE: anonymize parameter is used to initialize PRL memory with different
+ * options when using RFC7844 Anonymity Profiles */
+int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize);
 
 int sd_dhcp_client_attach_event(
                 sd_dhcp_client *client,
diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h
index 2f565ca8..7ab99ccc 100644
--- a/src/systemd/src/systemd/sd-dhcp-lease.h
+++ b/src/systemd/src/systemd/sd-dhcp-lease.h
@@ -49,6 +49,7 @@ int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr);
 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu);
 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
+int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains);
 int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
 int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
 int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes);