about summary refs log tree commit diff
path: root/shared/systemd/src/basic
diff options
context:
space:
mode:
authorSebastien Bacher <seb128@ubuntu.com>2019-03-12 15:16:42 +0100
committerSebastien Bacher <seb128@ubuntu.com>2019-03-12 15:16:42 +0100
commitcc4ab276f923ded9f415c1c2bf192994367ab0bb (patch)
treeac3a7775665992b27d07eb44186d38ff961a8cd7 /shared/systemd/src/basic
parentbb1cf58350bb34463e9ffc5f96ac4f9b6bf46d28 (diff)
parentdd428301eb6f02542015121d7b08d9997f137e50 (diff)
Update upstream source from tag 'upstream/1.15.91'
Update to upstream version '1.15.91'
with Debian dir 74de38245314cab529c6c94cd9d0b874ce0c2994
Diffstat (limited to 'shared/systemd/src/basic')
-rw-r--r--shared/systemd/src/basic/alloc-util.h49
-rw-r--r--shared/systemd/src/basic/env-file.c32
-rw-r--r--shared/systemd/src/basic/env-util.c2
-rw-r--r--shared/systemd/src/basic/env-util.h6
-rw-r--r--shared/systemd/src/basic/extract-word.h12
-rw-r--r--shared/systemd/src/basic/fd-util.c39
-rw-r--r--shared/systemd/src/basic/fileio.c4
-rw-r--r--shared/systemd/src/basic/hashmap.c10
-rw-r--r--shared/systemd/src/basic/hashmap.h1
-rw-r--r--shared/systemd/src/basic/hexdecoct.c7
-rw-r--r--shared/systemd/src/basic/in-addr-util.c45
-rw-r--r--shared/systemd/src/basic/in-addr-util.h24
-rw-r--r--shared/systemd/src/basic/io-util.c16
-rw-r--r--shared/systemd/src/basic/io-util.h2
-rw-r--r--shared/systemd/src/basic/missing_fcntl.h60
-rw-r--r--shared/systemd/src/basic/path-util.h2
-rw-r--r--shared/systemd/src/basic/prioq.c7
-rw-r--r--shared/systemd/src/basic/prioq.h8
-rw-r--r--shared/systemd/src/basic/process-util.c91
-rw-r--r--shared/systemd/src/basic/process-util.h4
-rw-r--r--shared/systemd/src/basic/stat-util.c16
-rw-r--r--shared/systemd/src/basic/stat-util.h5
-rw-r--r--shared/systemd/src/basic/string-util.h3
-rw-r--r--shared/systemd/src/basic/strv.h15
-rw-r--r--shared/systemd/src/basic/time-util.c9
-rw-r--r--shared/systemd/src/basic/time-util.h1
-rw-r--r--shared/systemd/src/basic/tmpfile-util.c1
-rw-r--r--shared/systemd/src/basic/util.h9
28 files changed, 302 insertions, 178 deletions
diff --git a/shared/systemd/src/basic/alloc-util.h b/shared/systemd/src/basic/alloc-util.h
index ff7a4679..893a1238 100644
--- a/shared/systemd/src/basic/alloc-util.h
+++ b/shared/systemd/src/basic/alloc-util.h
@@ -10,20 +10,28 @@
 
 typedef void (*free_func_t)(void *p);
 
+/* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than
+ * proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */
+#define ALLOCA_MAX (4U*1024U*1024U)
+
 #define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
 
 #define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t)))
 
-#define newa(t, n)                                              \
-        ({                                                      \
-                assert(!size_multiply_overflow(sizeof(t), n));  \
-                (t*) alloca(sizeof(t)*(n));                     \
+#define newa(t, n)                                                      \
+        ({                                                              \
+                size_t _n_ = n;                                         \
+                assert(!size_multiply_overflow(sizeof(t), _n_));        \
+                assert(sizeof(t)*_n_ <= ALLOCA_MAX);                    \
+                (t*) alloca(sizeof(t)*_n_);                             \
         })
 
-#define newa0(t, n)                                             \
-        ({                                                      \
-                assert(!size_multiply_overflow(sizeof(t), n));  \
-                (t*) alloca0(sizeof(t)*(n));                    \
+#define newa0(t, n)                                                     \
+        ({                                                              \
+                size_t _n_ = n;                                         \
+                assert(!size_multiply_overflow(sizeof(t), _n_));        \
+                assert(sizeof(t)*_n_ <= ALLOCA_MAX);                    \
+                (t*) alloca0(sizeof(t)*_n_);                            \
         })
 
 #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
@@ -51,16 +59,20 @@ void* memdup_suffix0(const void *p, size_t l) _alloc_(2);
 #define memdupa(p, l)                           \
         ({                                      \
                 void *_q_;                      \
-                _q_ = alloca(l);                \
-                memcpy(_q_, p, l);              \
+                size_t _l_ = l;                 \
+                assert(_l_ <= ALLOCA_MAX);      \
+                _q_ = alloca(_l_);              \
+                memcpy(_q_, p, _l_);            \
         })
 
 #define memdupa_suffix0(p, l)                   \
         ({                                      \
                 void *_q_;                      \
-                _q_ = alloca(l + 1);            \
-                ((uint8_t*) _q_)[l] = 0;        \
-                memcpy(_q_, p, l);              \
+                size_t _l_ = l;                 \
+                assert(_l_ <= ALLOCA_MAX);      \
+                _q_ = alloca(_l_ + 1);          \
+                ((uint8_t*) _q_)[_l_] = 0;      \
+                memcpy(_q_, p, _l_);            \
         })
 
 static inline void freep(void *p) {
@@ -116,6 +128,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
         ({                                              \
                 char *_new_;                            \
                 size_t _len_ = n;                       \
+                assert(_len_ <= ALLOCA_MAX);            \
                 _new_ = alloca(_len_);                  \
                 (void *) memset(_new_, 0, _len_);       \
         })
@@ -125,16 +138,18 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
         ({                                                              \
                 void *_ptr_;                                            \
                 size_t _mask_ = (align) - 1;                            \
-                _ptr_ = alloca((size) + _mask_);                        \
+                size_t _size_ = size;                                   \
+                assert(_size_ <= ALLOCA_MAX);                           \
+                _ptr_ = alloca(_size_ + _mask_);                        \
                 (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_);         \
         })
 
 #define alloca0_align(size, align)                                      \
         ({                                                              \
                 void *_new_;                                            \
-                size_t _size_ = (size);                                 \
-                _new_ = alloca_align(_size_, (align));                  \
-                (void*)memset(_new_, 0, _size_);                        \
+                size_t _xsize_ = (size);                                \
+                _new_ = alloca_align(_xsize_, (align));                 \
+                (void*)memset(_new_, 0, _xsize_);                       \
         })
 
 /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to
diff --git a/shared/systemd/src/basic/env-file.c b/shared/systemd/src/basic/env-file.c
index beafd8c2..4babe753 100644
--- a/shared/systemd/src/basic/env-file.c
+++ b/shared/systemd/src/basic/env-file.c
@@ -37,7 +37,6 @@ static int parse_env_file_internal(
                 VALUE,
                 VALUE_ESCAPE,
                 SINGLE_QUOTE_VALUE,
-                SINGLE_QUOTE_VALUE_ESCAPE,
                 DOUBLE_QUOTE_VALUE,
                 DOUBLE_QUOTE_VALUE_ESCAPE,
                 COMMENT,
@@ -115,7 +114,7 @@ static int parse_env_file_internal(
 
                         } else if (c == '\'')
                                 state = SINGLE_QUOTE_VALUE;
-                        else if (c == '\"')
+                        else if (c == '"')
                                 state = DOUBLE_QUOTE_VALUE;
                         else if (c == '\\')
                                 state = VALUE_ESCAPE;
@@ -188,8 +187,6 @@ static int parse_env_file_internal(
                 case SINGLE_QUOTE_VALUE:
                         if (c == '\'')
                                 state = PRE_VALUE;
-                        else if (c == '\\')
-                                state = SINGLE_QUOTE_VALUE_ESCAPE;
                         else {
                                 if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
                                         return -ENOMEM;
@@ -199,19 +196,8 @@ static int parse_env_file_internal(
 
                         break;
 
-                case SINGLE_QUOTE_VALUE_ESCAPE:
-                        state = SINGLE_QUOTE_VALUE;
-
-                        if (!strchr(NEWLINE, c)) {
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-                        break;
-
                 case DOUBLE_QUOTE_VALUE:
-                        if (c == '\"')
+                        if (c == '"')
                                 state = PRE_VALUE;
                         else if (c == '\\')
                                 state = DOUBLE_QUOTE_VALUE_ESCAPE;
@@ -227,12 +213,17 @@ static int parse_env_file_internal(
                 case DOUBLE_QUOTE_VALUE_ESCAPE:
                         state = DOUBLE_QUOTE_VALUE;
 
-                        if (!strchr(NEWLINE, c)) {
+                        if (c == '"') {
                                 if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
                                         return -ENOMEM;
-
+                                value[n_value++] = '"';
+                        } else if (!strchr(NEWLINE, c)) {
+                                if (!GREEDY_REALLOC(value, value_alloc, n_value+3))
+                                        return -ENOMEM;
+                                value[n_value++] = '\\';
                                 value[n_value++] = c;
                         }
+
                         break;
 
                 case COMMENT:
@@ -255,7 +246,6 @@ static int parse_env_file_internal(
                    VALUE,
                    VALUE_ESCAPE,
                    SINGLE_QUOTE_VALUE,
-                   SINGLE_QUOTE_VALUE_ESCAPE,
                    DOUBLE_QUOTE_VALUE,
                    DOUBLE_QUOTE_VALUE_ESCAPE)) {
 
@@ -530,7 +520,7 @@ static void write_env_var(FILE *f, const char *v) {
         fwrite_unlocked(v, 1, p-v, f);
 
         if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
-                fputc_unlocked('\"', f);
+                fputc_unlocked('"', f);
 
                 for (; *p; p++) {
                         if (strchr(SHELL_NEED_ESCAPE, *p))
@@ -539,7 +529,7 @@ static void write_env_var(FILE *f, const char *v) {
                         fputc_unlocked(*p, f);
                 }
 
-                fputc_unlocked('\"', f);
+                fputc_unlocked('"', f);
         } else
                 fputs_unlocked(p, f);
 
diff --git a/shared/systemd/src/basic/env-util.c b/shared/systemd/src/basic/env-util.c
index fd9eedc5..dc10362d 100644
--- a/shared/systemd/src/basic/env-util.c
+++ b/shared/systemd/src/basic/env-util.c
@@ -342,7 +342,6 @@ char **strv_env_unset(char **l, const char *p) {
 }
 
 char **strv_env_unset_many(char **l, ...) {
-
         char **f, **t;
 
         if (!l)
@@ -411,7 +410,6 @@ int strv_env_replace(char ***l, char *p) {
 }
 
 char **strv_env_set(char **x, const char *p) {
-
         _cleanup_strv_free_ char **ret = NULL;
         size_t n, m;
         char **k;
diff --git a/shared/systemd/src/basic/env-util.h b/shared/systemd/src/basic/env-util.h
index 4d21ea6b..d54f9965 100644
--- a/shared/systemd/src/basic/env-util.h
+++ b/shared/systemd/src/basic/env-util.h
@@ -13,9 +13,9 @@ bool env_value_is_valid(const char *e);
 bool env_assignment_is_valid(const char *e);
 
 enum {
-        REPLACE_ENV_USE_ENVIRONMENT = 1u,
-        REPLACE_ENV_ALLOW_BRACELESS = 2u,
-        REPLACE_ENV_ALLOW_EXTENDED  = 4u,
+        REPLACE_ENV_USE_ENVIRONMENT = 1 << 0,
+        REPLACE_ENV_ALLOW_BRACELESS = 1 << 1,
+        REPLACE_ENV_ALLOW_EXTENDED  = 1 << 2,
 };
 
 char *replace_env_n(const char *format, size_t n, char **env, unsigned flags);
diff --git a/shared/systemd/src/basic/extract-word.h b/shared/systemd/src/basic/extract-word.h
index 8c63b7c3..705ebbe9 100644
--- a/shared/systemd/src/basic/extract-word.h
+++ b/shared/systemd/src/basic/extract-word.h
@@ -4,12 +4,12 @@
 #include "macro.h"
 
 typedef enum ExtractFlags {
-        EXTRACT_RELAX                    = 1,
-        EXTRACT_CUNESCAPE                = 2,
-        EXTRACT_CUNESCAPE_RELAX          = 4,
-        EXTRACT_QUOTES                   = 8,
-        EXTRACT_DONT_COALESCE_SEPARATORS = 16,
-        EXTRACT_RETAIN_ESCAPE            = 32,
+        EXTRACT_RELAX                    = 1 << 0,
+        EXTRACT_CUNESCAPE                = 1 << 1,
+        EXTRACT_CUNESCAPE_RELAX          = 1 << 2,
+        EXTRACT_QUOTES                   = 1 << 3,
+        EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 4,
+        EXTRACT_RETAIN_ESCAPE            = 1 << 5,
 } ExtractFlags;
 
 int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
diff --git a/shared/systemd/src/basic/fd-util.c b/shared/systemd/src/basic/fd-util.c
index 8ca1711b..0cc0c6b5 100644
--- a/shared/systemd/src/basic/fd-util.c
+++ b/shared/systemd/src/basic/fd-util.c
@@ -192,6 +192,27 @@ _pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {
         return false;
 }
 
+static int get_max_fd(void) {
+        struct rlimit rl;
+        rlim_t m;
+
+        /* Return the highest possible fd, based RLIMIT_NOFILE, but enforcing FD_SETSIZE-1 as lower boundary
+         * and INT_MAX as upper boundary. */
+
+        if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
+                return -errno;
+
+        m = MAX(rl.rlim_cur, rl.rlim_max);
+        if (m < FD_SETSIZE) /* Let's always cover at least 1024 fds */
+                return FD_SETSIZE-1;
+
+        if (m == RLIM_INFINITY || m > INT_MAX) /* Saturate on overflow. After all fds are "int", hence can
+                                                * never be above INT_MAX */
+                return INT_MAX;
+
+        return (int) (m - 1);
+}
+
 int close_all_fds(const int except[], size_t n_except) {
         _cleanup_closedir_ DIR *d = NULL;
         struct dirent *de;
@@ -201,20 +222,14 @@ int close_all_fds(const int except[], size_t n_except) {
 
         d = opendir("/proc/self/fd");
         if (!d) {
-                struct rlimit rl;
                 int fd, max_fd;
 
-                /* When /proc isn't available (for example in chroots) the fallback is brute forcing through the fd
-                 * table */
-
-                assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
-
-                if (rl.rlim_max == 0)
-                        return -EINVAL;
+                /* When /proc isn't available (for example in chroots) the fallback is brute forcing through
+                 * the fd table */
 
-                /* Let's take special care if the resource limit is set to unlimited, or actually larger than the range
-                 * of 'int'. Let's avoid implicit overflows. */
-                max_fd = (rl.rlim_max == RLIM_INFINITY || rl.rlim_max > INT_MAX) ? INT_MAX : (int) (rl.rlim_max - 1);
+                max_fd = get_max_fd();
+                if (max_fd < 0)
+                        return max_fd;
 
                 for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
                         int q;
@@ -365,7 +380,7 @@ int fd_get_path(int fd, char **ret) {
         r = readlink_malloc(procfs_path, ret);
         if (r == -ENOENT) {
                 /* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make
-                 * things debuggable and distuingish the two. */
+                 * things debuggable and distinguish the two. */
 
                 if (access("/proc/self/fd/", F_OK) < 0)
                         /* /proc is not available or not set up properly, we're most likely in some chroot
diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c
index b172507b..ee66190f 100644
--- a/shared/systemd/src/basic/fileio.c
+++ b/shared/systemd/src/basic/fileio.c
@@ -215,7 +215,6 @@ int write_string_filef(
 
 int read_one_line_file(const char *fn, char **line) {
         _cleanup_fclose_ FILE *f = NULL;
-        int r;
 
         assert(fn);
         assert(line);
@@ -226,8 +225,7 @@ int read_one_line_file(const char *fn, char **line) {
 
         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
 
-        r = read_line(f, LONG_LINE_MAX, line);
-        return r < 0 ? r : 0;
+        return read_line(f, LONG_LINE_MAX, line);
 }
 
 int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
diff --git a/shared/systemd/src/basic/hashmap.c b/shared/systemd/src/basic/hashmap.c
index 09303c6f..c0655831 100644
--- a/shared/systemd/src/basic/hashmap.c
+++ b/shared/systemd/src/basic/hashmap.c
@@ -347,7 +347,7 @@ static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
 }
 #define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p)
 
-static inline void base_set_dirty(HashmapBase *h) {
+static void base_set_dirty(HashmapBase *h) {
         h->dirty = true;
 }
 #define hashmap_set_dirty(h) base_set_dirty(HASHMAP_BASE(h))
@@ -890,7 +890,8 @@ void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_f
                  * themselves from our hash table a second time, the entry is already gone. */
 
                 while (internal_hashmap_size(h) > 0) {
-                        void *v, *k;
+                        void *k = NULL;
+                        void *v;
 
                         v = internal_hashmap_first_key_and_value(h, true, &k);
 
@@ -1517,8 +1518,11 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r
         unsigned idx;
 
         idx = find_first_entry(h);
-        if (idx == IDX_NIL)
+        if (idx == IDX_NIL) {
+                if (ret_key)
+                        *ret_key = NULL;
                 return NULL;
+        }
 
         e = bucket_at(h, idx);
         key = (void*) e->key;
diff --git a/shared/systemd/src/basic/hashmap.h b/shared/systemd/src/basic/hashmap.h
index 5bf807a7..e16a9f9e 100644
--- a/shared/systemd/src/basic/hashmap.h
+++ b/shared/systemd/src/basic/hashmap.h
@@ -326,7 +326,6 @@ static inline void *ordered_hashmap_first_key_and_value(OrderedHashmap *h, void
         return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
 }
 
-
 static inline void *hashmap_steal_first(Hashmap *h) {
         return internal_hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
 }
diff --git a/shared/systemd/src/basic/hexdecoct.c b/shared/systemd/src/basic/hexdecoct.c
index ffd9a8f6..7c66cc62 100644
--- a/shared/systemd/src/basic/hexdecoct.c
+++ b/shared/systemd/src/basic/hexdecoct.c
@@ -606,10 +606,11 @@ static int base64_append_width(
         lines = DIV_ROUND_UP(len, width);
 
         slen = strlen_ptr(sep);
-        if (lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1))
+        if (plen >= SSIZE_MAX - 1 - slen ||
+            lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1))
                 return -ENOMEM;
 
-        t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
+        t = realloc(*prefix, (ssize_t) plen + 1 + slen + (indent + width + 1) * lines);
         if (!t)
                 return -ENOMEM;
 
@@ -644,7 +645,7 @@ int base64_append(
                 return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
         else
                 /* leave plen on the left, keep last column free */
-                return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
+                return base64_append_width(prefix, plen, " ", plen, p, l, width - plen - 1);
 }
 #endif /* NM_IGNORED */
 
diff --git a/shared/systemd/src/basic/in-addr-util.c b/shared/systemd/src/basic/in-addr-util.c
index d2cc5606..5ced3501 100644
--- a/shared/systemd/src/basic/in-addr-util.c
+++ b/shared/systemd/src/basic/in-addr-util.c
@@ -70,6 +70,14 @@ bool in4_addr_is_localhost(const struct in_addr *a) {
         return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
 }
 
+bool in4_addr_is_non_local(const struct in_addr *a) {
+        /* Whether the address is not null and not localhost.
+         *
+         * As such, it is suitable to configure as DNS/NTP server from DHCP. */
+        return !in4_addr_is_null(a) &&
+               !in4_addr_is_localhost(a);
+}
+
 int in_addr_is_localhost(int family, const union in_addr_union *u) {
         assert(u);
 
@@ -500,9 +508,8 @@ int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
         return 0;
 }
 
-int in_addr_prefix_from_string_internal(
+int in_addr_prefix_from_string(
                 const char *p,
-                bool use_default_prefixlen,
                 int family,
                 union in_addr_union *ret_prefix,
                 unsigned char *ret_prefixlen) {
@@ -536,13 +543,6 @@ int in_addr_prefix_from_string_internal(
                 r = in_addr_parse_prefixlen(family, e+1, &k);
                 if (r < 0)
                         return r;
-        } else if (use_default_prefixlen) {
-                if (family == AF_INET) {
-                        r = in4_addr_default_prefixlen(&buffer.in, &k);
-                        if (r < 0)
-                                return r;
-                } else
-                        k = 0;
         } else
                 k = FAMILY_ADDRESS_SIZE(family) * 8;
 
@@ -556,7 +556,7 @@ int in_addr_prefix_from_string_internal(
 
 int in_addr_prefix_from_string_auto_internal(
                 const char *p,
-                bool use_default_prefixlen,
+                InAddrPrefixLenMode mode,
                 int *ret_family,
                 union in_addr_union *ret_prefix,
                 unsigned char *ret_prefixlen) {
@@ -587,15 +587,24 @@ int in_addr_prefix_from_string_auto_internal(
                 r = in_addr_parse_prefixlen(family, e+1, &k);
                 if (r < 0)
                         return r;
-        } else if (use_default_prefixlen) {
-                if (family == AF_INET) {
-                        r = in4_addr_default_prefixlen(&buffer.in, &k);
-                        if (r < 0)
-                                return r;
-                } else
-                        k = 0;
         } else
-                k = FAMILY_ADDRESS_SIZE(family) * 8;
+                switch (mode) {
+                case PREFIXLEN_FULL:
+                        k = FAMILY_ADDRESS_SIZE(family) * 8;
+                        break;
+                case PREFIXLEN_REFUSE:
+                        return -ENOANO; /* To distinguish this error from others. */
+                case PREFIXLEN_LEGACY:
+                        if (family == AF_INET) {
+                                r = in4_addr_default_prefixlen(&buffer.in, &k);
+                                if (r < 0)
+                                        return r;
+                        } else
+                                k = 0;
+                        break;
+                default:
+                        assert_not_reached("Invalid prefixlen mode");
+                }
 
         if (ret_family)
                 *ret_family = family;
diff --git a/shared/systemd/src/basic/in-addr-util.h b/shared/systemd/src/basic/in-addr-util.h
index 5de85cc4..c2156712 100644
--- a/shared/systemd/src/basic/in-addr-util.h
+++ b/shared/systemd/src/basic/in-addr-util.h
@@ -30,6 +30,8 @@ int in_addr_is_link_local(int family, const union in_addr_union *u);
 bool in4_addr_is_localhost(const struct in_addr *a);
 int in_addr_is_localhost(int family, const union in_addr_union *u);
 
+bool in4_addr_is_non_local(const struct in_addr *a);
+
 int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
 int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
 int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
@@ -45,19 +47,17 @@ int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mas
 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_internal(const char *p, bool use_default_prefixlen, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
-int in_addr_prefix_from_string_auto_internal(const char *p, bool use_default_prefixlen, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
-static inline int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) {
-        return in_addr_prefix_from_string_internal(p, false, family, ret_prefix, ret_prefixlen);
-}
+int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
+
+typedef enum InAddrPrefixLenMode {
+        PREFIXLEN_FULL,   /* Default to prefixlen of address size, 32 for IPv4 or 128 for IPv6, if not specified. */
+        PREFIXLEN_REFUSE, /* Fail with -ENOANO if prefixlen is not specified. */
+        PREFIXLEN_LEGACY, /* Default to legacy default prefixlen calculation from address if not specified. */
+} InAddrPrefixLenMode;
+
+int in_addr_prefix_from_string_auto_internal(const char *p, InAddrPrefixLenMode mode, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
 static inline int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) {
-        return in_addr_prefix_from_string_auto_internal(p, false, ret_family, ret_prefix, ret_prefixlen);
-}
-static inline int in_addr_default_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) {
-        return in_addr_prefix_from_string_internal(p, true, family, ret_prefix, ret_prefixlen);
-}
-static inline int in_addr_default_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) {
-        return in_addr_prefix_from_string_auto_internal(p, true, ret_family, ret_prefix, ret_prefixlen);
+        return in_addr_prefix_from_string_auto_internal(p, PREFIXLEN_FULL, ret_family, ret_prefix, ret_prefixlen);
 }
 
 static inline size_t FAMILY_ADDRESS_SIZE(int family) {
diff --git a/shared/systemd/src/basic/io-util.c b/shared/systemd/src/basic/io-util.c
index f7c25915..3f47eff5 100644
--- a/shared/systemd/src/basic/io-util.c
+++ b/shared/systemd/src/basic/io-util.c
@@ -10,8 +10,10 @@
 #include <unistd.h>
 
 #include "io-util.h"
+#include "string-util.h"
 #include "time-util.h"
 
+#if 0 /* NM_IGNORED */
 int flush_fd(int fd) {
         struct pollfd pollfd = {
                 .fd = fd,
@@ -55,6 +57,7 @@ int flush_fd(int fd) {
                 count += (int) l;
         }
 }
+#endif /* NM_IGNORED */
 
 ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
         uint8_t *p = buf;
@@ -115,6 +118,7 @@ int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
         return 0;
 }
 
+#if 0 /* NM_IGNORED */
 int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
         const uint8_t *p = buf;
 
@@ -173,6 +177,7 @@ int pipe_eof(int fd) {
 
         return pollfd.revents & POLLHUP;
 }
+#endif /* NM_IGNORED */
 
 int fd_wait_for_event(int fd, int event, usec_t t) {
 
@@ -193,6 +198,7 @@ int fd_wait_for_event(int fd, int event, usec_t t) {
         return pollfd.revents;
 }
 
+#if 0 /* NM_IGNORED */
 static size_t nul_length(const uint8_t *p, size_t sz) {
         size_t n = 0;
 
@@ -254,3 +260,13 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
 
         return q - (const uint8_t*) p;
 }
+
+char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) {
+        char *x;
+
+        x = strappend(field, value);
+        if (x)
+                iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
+        return x;
+}
+#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/io-util.h b/shared/systemd/src/basic/io-util.h
index ed189b58..792a64ad 100644
--- a/shared/systemd/src/basic/io-util.h
+++ b/shared/systemd/src/basic/io-util.h
@@ -71,3 +71,5 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
 #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)
+
+char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
diff --git a/shared/systemd/src/basic/missing_fcntl.h b/shared/systemd/src/basic/missing_fcntl.h
new file mode 100644
index 00000000..5d1c6352
--- /dev/null
+++ b/shared/systemd/src/basic/missing_fcntl.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <fcntl.h>
+
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_SETPIPE_SZ
+#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
+#endif
+
+#ifndef F_GETPIPE_SZ
+#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
+#endif
+
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
+
+#define F_SEAL_SEAL     0x0001  /* prevent further seals from being set */
+#define F_SEAL_SHRINK   0x0002  /* prevent file from shrinking */
+#define F_SEAL_GROW     0x0004  /* prevent file from growing */
+#define F_SEAL_WRITE    0x0008  /* prevent writes */
+#endif
+
+#ifndef F_OFD_GETLK
+#define F_OFD_GETLK     36
+#define F_OFD_SETLK     37
+#define F_OFD_SETLKW    38
+#endif
+
+#ifndef MAX_HANDLE_SZ
+#define MAX_HANDLE_SZ 128
+#endif
+
+/* The precise definition of __O_TMPFILE is arch specific; use the
+ * values defined by the kernel (note: some are hexa, some are octal,
+ * duplicated as-is from the kernel definitions):
+ * - alpha, parisc, sparc: each has a specific value;
+ * - others: they use the "generic" value.
+ */
+
+#ifndef __O_TMPFILE
+#if defined(__alpha__)
+#define __O_TMPFILE     0100000000
+#elif defined(__parisc__) || defined(__hppa__)
+#define __O_TMPFILE     0400000000
+#elif defined(__sparc__) || defined(__sparc64__)
+#define __O_TMPFILE     0x2000000
+#else
+#define __O_TMPFILE     020000000
+#endif
+#endif
+
+/* a horrid kludge trying to make sure that this will fail on old kernels */
+#ifndef O_TMPFILE
+#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
+#endif
diff --git a/shared/systemd/src/basic/path-util.h b/shared/systemd/src/basic/path-util.h
index 56ebd59c..5204adaa 100644
--- a/shared/systemd/src/basic/path-util.h
+++ b/shared/systemd/src/basic/path-util.h
@@ -133,7 +133,7 @@ char *prefix_root(const char *root, const char *path);
                         _ret = _path;                                   \
                 else {                                                  \
                         _l = strlen(_root) + 1 + strlen(_path) + 1;     \
-                        _n = alloca(_l);                                \
+                        _n = newa(char, _l);                            \
                         _p = stpcpy(_n, _root);                         \
                         while (_p > _n && _p[-1] == '/')                \
                                 _p--;                                   \
diff --git a/shared/systemd/src/basic/prioq.c b/shared/systemd/src/basic/prioq.c
index b218f37d..dc048cc7 100644
--- a/shared/systemd/src/basic/prioq.c
+++ b/shared/systemd/src/basic/prioq.c
@@ -261,15 +261,14 @@ int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
         return 1;
 }
 
-void *prioq_peek(Prioq *q) {
-
+void *prioq_peek_by_index(Prioq *q, unsigned idx) {
         if (!q)
                 return NULL;
 
-        if (q->n_items <= 0)
+        if (idx >= q->n_items)
                 return NULL;
 
-        return q->items[0].data;
+        return q->items[idx].data;
 }
 
 void *prioq_pop(Prioq *q) {
diff --git a/shared/systemd/src/basic/prioq.h b/shared/systemd/src/basic/prioq.h
index bba5c7ca..1fb57bfa 100644
--- a/shared/systemd/src/basic/prioq.h
+++ b/shared/systemd/src/basic/prioq.h
@@ -19,8 +19,14 @@ int prioq_put(Prioq *q, void *data, unsigned *idx);
 int prioq_remove(Prioq *q, void *data, unsigned *idx);
 int prioq_reshuffle(Prioq *q, void *data, unsigned *idx);
 
-void *prioq_peek(Prioq *q) _pure_;
+void *prioq_peek_by_index(Prioq *q, unsigned idx) _pure_;
+static inline void *prioq_peek(Prioq *q) {
+        return prioq_peek_by_index(q, 0);
+}
 void *prioq_pop(Prioq *q);
 
+#define PRIOQ_FOREACH_ITEM(q, p)                                \
+        for (unsigned _i = 0; (p = prioq_peek_by_index(q, _i)); _i++)
+
 unsigned prioq_size(Prioq *q) _pure_;
 bool prioq_isempty(Prioq *q) _pure_;
diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c
index be7911a3..b0afb5c8 100644
--- a/shared/systemd/src/basic/process-util.c
+++ b/shared/systemd/src/basic/process-util.c
@@ -107,7 +107,8 @@ int get_process_comm(pid_t pid, char **ret) {
 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;
+        char *k;
+        _cleanup_free_ char *ans = NULL;
         const char *p;
         int c;
 
@@ -134,6 +135,13 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
 
         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
 
+        if (max_length == 0) {
+                /* This is supposed to be a safety guard against runaway command lines. */
+                long l = sysconf(_SC_ARG_MAX);
+                assert(l > 0);
+                max_length = l;
+        }
+
         if (max_length == 1) {
 
                 /* If there's only room for one byte, return the empty string */
@@ -141,35 +149,9 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
                 if (!ans)
                         return -ENOMEM;
 
-                *line = ans;
+                *line = TAKE_PTR(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;
@@ -232,7 +214,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
                 _cleanup_free_ char *t = NULL;
                 int h;
 
-                free(ans);
+                ans = mfree(ans);
 
                 if (!comm_fallback)
                         return -ENOENT;
@@ -241,37 +223,42 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
                 if (h < 0)
                         return h;
 
-                if (max_length == 0)
-                        ans = strjoin("[", t, "]");
-                else {
-                        size_t l;
-
-                        l = strlen(t);
+                size_t l = strlen(t);
 
-                        if (l + 3 <= max_length)
-                                ans = strjoin("[", t, "]");
-                        else if (max_length <= 6) {
+                if (l + 3 <= max_length) {
+                        ans = strjoin("[", t, "]");
+                        if (!ans)
+                                return -ENOMEM;
 
-                                ans = new(char, max_length);
-                                if (!ans)
-                                        return -ENOMEM;
+                } 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 {
-                                t[max_length - 6] = 0;
+                        memcpy(ans, "[...]", max_length-1);
+                        ans[max_length-1] = 0;
+                } else {
+                        t[max_length - 6] = 0;
 
-                                /* Chop off final spaces */
-                                delete_trailing_chars(t, WHITESPACE);
+                        /* Chop off final spaces */
+                        delete_trailing_chars(t, WHITESPACE);
 
-                                ans = strjoin("[", t, "...]");
-                        }
+                        ans = strjoin("[", t, "...]");
+                        if (!ans)
+                                return -ENOMEM;
                 }
-                if (!ans)
-                        return -ENOMEM;
+
+                *line = TAKE_PTR(ans);
+                return 0;
         }
 
-        *line = ans;
+        k = realloc(ans, strlen(ans) + 1);
+        if (!k)
+                return -ENOMEM;
+
+        ans = NULL;
+        *line = k;
+
         return 0;
 }
 
diff --git a/shared/systemd/src/basic/process-util.h b/shared/systemd/src/basic/process-util.h
index 0fad4e1e..0425042f 100644
--- a/shared/systemd/src/basic/process-util.h
+++ b/shared/systemd/src/basic/process-util.h
@@ -24,8 +24,8 @@
                 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_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \
+                        sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \
                 }                                                       \
                 _r_;                                                    \
         })
diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c
index 8843aba8..686adaf1 100644
--- a/shared/systemd/src/basic/stat-util.c
+++ b/shared/systemd/src/basic/stat-util.c
@@ -70,13 +70,22 @@ int is_device_node(const char *path) {
         return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
 }
 
-int dir_is_empty(const char *path) {
-        _cleanup_closedir_ DIR *d;
+int dir_is_empty_at(int dir_fd, const char *path) {
+        _cleanup_close_ int fd = -1;
+        _cleanup_closedir_ DIR *d = NULL;
         struct dirent *de;
 
-        d = opendir(path);
+        if (path)
+                fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+        else
+                fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+        if (fd < 0)
+                return -errno;
+
+        d = fdopendir(fd);
         if (!d)
                 return -errno;
+        fd = -1;
 
         FOREACH_DIRENT(de, d, return -errno)
                 return 0;
@@ -343,7 +352,6 @@ int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) {
                 return -ENOMEM;
 
         return 0;
-
 }
 
 int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) {
diff --git a/shared/systemd/src/basic/stat-util.h b/shared/systemd/src/basic/stat-util.h
index 0a08e642..74fb7251 100644
--- a/shared/systemd/src/basic/stat-util.h
+++ b/shared/systemd/src/basic/stat-util.h
@@ -15,7 +15,10 @@ int is_dir(const char *path, bool follow);
 int is_dir_fd(int fd);
 int is_device_node(const char *path);
 
-int dir_is_empty(const char *path);
+int dir_is_empty_at(int dir_fd, const char *path);
+static inline int dir_is_empty(const char *path) {
+        return dir_is_empty_at(AT_FDCWD, path);
+}
 
 static inline int dir_is_populated(const char *path) {
         int r;
diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h
index a5b5a16a..38070abb 100644
--- a/shared/systemd/src/basic/string-util.h
+++ b/shared/systemd/src/basic/string-util.h
@@ -6,6 +6,7 @@
 #include <stddef.h>
 #include <string.h>
 
+#include "alloc-util.h"
 #include "macro.h"
 
 /* What is interpreted as whitespace? */
@@ -111,7 +112,7 @@ char *strjoin_real(const char *x, ...) _sentinel_;
                 size_t _i_;                                           \
                 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
                         _len_ += strlen(_appendees_[_i_]);              \
-                _p_ = _d_ = alloca(_len_ + 1);                          \
+                _p_ = _d_ = newa(char, _len_ + 1);                      \
                 for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
                         _p_ = stpcpy(_p_, _appendees_[_i_]);            \
                 *_p_ = 0;                                               \
diff --git a/shared/systemd/src/basic/strv.h b/shared/systemd/src/basic/strv.h
index aa4cd4aa..392cab65 100644
--- a/shared/systemd/src/basic/strv.h
+++ b/shared/systemd/src/basic/strv.h
@@ -156,17 +156,10 @@ void strv_print(char **l);
                 _found;                                         \
         })
 
-#define FOREACH_STRING(x, ...)                               \
-        for (char **_l = ({                                  \
-                char **_ll = STRV_MAKE(__VA_ARGS__);         \
-                x = _ll ? _ll[0] : NULL;                     \
-                _ll;                                         \
-        });                                                  \
-        _l && *_l;                                           \
-        x = ({                                               \
-                _l ++;                                       \
-                _l[0];                                       \
-        }))
+#define FOREACH_STRING(x, y, ...)                                       \
+        for (char **_l = STRV_MAKE(({ x = y; }), ##__VA_ARGS__);        \
+             x;                                                         \
+             x = *(++_l))
 
 char **strv_reverse(char **l);
 char **strv_shell_escape(char **l, const char *bad);
diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c
index 4e609a64..9ea0380a 100644
--- a/shared/systemd/src/basic/time-util.c
+++ b/shared/systemd/src/basic/time-util.c
@@ -1036,6 +1036,15 @@ int parse_sec_fix_0(const char *t, usec_t *ret) {
         return r;
 }
 
+int parse_sec_def_infinity(const char *t, usec_t *ret) {
+        t += strspn(t, WHITESPACE);
+        if (isempty(t)) {
+                *ret = USEC_INFINITY;
+                return 0;
+        }
+        return parse_sec(t, ret);
+}
+
 static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
         static const struct {
                 const char *suffix;
diff --git a/shared/systemd/src/basic/time-util.h b/shared/systemd/src/basic/time-util.h
index 53163050..a238f691 100644
--- a/shared/systemd/src/basic/time-util.h
+++ b/shared/systemd/src/basic/time-util.h
@@ -112,6 +112,7 @@ 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_sec_def_infinity(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);
 
diff --git a/shared/systemd/src/basic/tmpfile-util.c b/shared/systemd/src/basic/tmpfile-util.c
index 06e325f0..019121cb 100644
--- a/shared/systemd/src/basic/tmpfile-util.c
+++ b/shared/systemd/src/basic/tmpfile-util.c
@@ -10,6 +10,7 @@
 #include "hexdecoct.h"
 #include "macro.h"
 #include "memfd-util.h"
+#include "missing_fcntl.h"
 #include "missing_syscall.h"
 #include "path-util.h"
 #include "process-util.h"
diff --git a/shared/systemd/src/basic/util.h b/shared/systemd/src/basic/util.h
index f009d37d..dc33d660 100644
--- a/shared/systemd/src/basic/util.h
+++ b/shared/systemd/src/basic/util.h
@@ -174,12 +174,21 @@ static inline void *mempset(void *s, int c, size_t n) {
 }
 
 static inline void _reset_errno_(int *saved_errno) {
+        if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
+                return;
+
         errno = *saved_errno;
 }
 
 #define PROTECT_ERRNO                                                   \
         _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
 
+#define UNPROTECT_ERRNO                         \
+        do {                                    \
+                errno = _saved_errno_;          \
+                _saved_errno_ = -1;             \
+        } while (false)
+
 static inline int negative_errno(void) {
         /* This helper should be used to shut up gcc if you know 'errno' is
          * negative. Instead of "return -errno;", use "return negative_errno();"