summary refs log tree commit diff
path: root/src/libnm-systemd-shared
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2022-05-04 15:35:24 +0200
committerMichael Biebl <biebl@debian.org>2022-05-04 15:35:24 +0200
commit9959fdb2e8ddd06f2161798ca0a39c77d67c652d (patch)
tree2ce24a336d2b1c5fd5dec3090db312eded6c78ba /src/libnm-systemd-shared
parent8c623dddbdebe354cb94bfc559a5371a14865317 (diff)
New upstream version 1.37.92 upstream/1.37.92
Diffstat (limited to 'src/libnm-systemd-shared')
-rw-r--r--src/libnm-systemd-shared/src/basic/alloc-util.h17
-rw-r--r--src/libnm-systemd-shared/src/basic/cgroup-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/env-file.c98
-rw-r--r--src/libnm-systemd-shared/src/basic/env-util.c46
-rw-r--r--src/libnm-systemd-shared/src/basic/env-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/errno-util.h10
-rw-r--r--src/libnm-systemd-shared/src/basic/escape.c1
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.c54
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.h1
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.c6
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.h6
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.c57
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/hashmap.c3
-rw-r--r--src/libnm-systemd-shared/src/basic/hexdecoct.c3
-rw-r--r--src/libnm-systemd-shared/src/basic/hostname-util.c18
-rw-r--r--src/libnm-systemd-shared/src/basic/hostname-util.h5
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.c13
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.h1
-rw-r--r--src/libnm-systemd-shared/src/basic/inotify-util.h24
-rw-r--r--src/libnm-systemd-shared/src/basic/io-util.c3
-rw-r--r--src/libnm-systemd-shared/src/basic/list.h46
-rw-r--r--src/libnm-systemd-shared/src/basic/log.h6
-rw-r--r--src/libnm-systemd-shared/src/basic/macro.h53
-rw-r--r--src/libnm-systemd-shared/src/basic/memory-util.h12
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_syscall.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/ordered-set.c1
-rw-r--r--src/libnm-systemd-shared/src/basic/ordered-set.h8
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.c2
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.h12
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.c53
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.c82
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.c259
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.h10
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/sort-util.h12
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.c49
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.h14
-rw-r--r--src/libnm-systemd-shared/src/basic/string-table.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.c64
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.h37
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.c85
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.h9
-rw-r--r--src/libnm-systemd-shared/src/basic/tmpfile-util.c39
-rw-r--r--src/libnm-systemd-shared/src/basic/tmpfile-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/util.h6
-rw-r--r--src/libnm-systemd-shared/src/fundamental/macro-fundamental.h35
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.c31
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.h2
50 files changed, 659 insertions, 652 deletions
diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.h b/src/libnm-systemd-shared/src/basic/alloc-util.h
index 65d51756..9dde770d 100644
--- a/src/libnm-systemd-shared/src/basic/alloc-util.h
+++ b/src/libnm-systemd-shared/src/basic/alloc-util.h
@@ -13,6 +13,7 @@
 #endif
 
 typedef void (*free_func_t)(void *p);
+typedef void* (*mfree_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. */
@@ -173,13 +174,23 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
  * is compatible with _FORTIFY_SOURCES. If _FORTIFY_SOURCES is used many memory operations will take the
  * object size as returned by __builtin_object_size() into account. Hence, let's return the smaller size of
  * malloc_usable_size() and __builtin_object_size() here, so that we definitely operate in safe territory by
- * both the compiler's and libc's standards. Note that __builtin_object_size() evaluates to SIZE_MAX if the
- * size cannot be determined, hence the MIN() expression should be safe with dynamically sized memory,
- * too. Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and
+ * both the compiler's and libc's standards. Note that _FORTIFY_SOURCES=3 handles also dynamically allocated
+ * objects and thus it's safer using __builtin_dynamic_object_size if _FORTIFY_SOURCES=3 is used (#22801).
+ * Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and
  * __builtin_object_size() returns SIZE_MAX too, hence we also return a sensible value of 0 in this corner
  * case. */
+
+#if defined __has_builtin
+#  if __has_builtin(__builtin_dynamic_object_size)
+#    define MALLOC_SIZEOF_SAFE(x) \
+        MIN(malloc_usable_size(x), __builtin_dynamic_object_size(x, 0))
+#  endif
+#endif
+
+#ifndef MALLOC_SIZEOF_SAFE
 #define MALLOC_SIZEOF_SAFE(x) \
         MIN(malloc_usable_size(x), __builtin_object_size(x, 0))
+#endif
 
 /* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items
  * that fit into the specified memory block */
diff --git a/src/libnm-systemd-shared/src/basic/cgroup-util.h b/src/libnm-systemd-shared/src/basic/cgroup-util.h
index 461c01b3..4c413a8d 100644
--- a/src/libnm-systemd-shared/src/basic/cgroup-util.h
+++ b/src/libnm-systemd-shared/src/basic/cgroup-util.h
@@ -205,6 +205,8 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path);
 
 int cg_rmdir(const char *controller, const char *path);
 
+int cg_is_threaded(const char *controller, const char *path);
+
 typedef enum  {
         CG_KEY_MODE_GRACEFUL = 1 << 0,
 } CGroupKeyMode;
diff --git a/src/libnm-systemd-shared/src/basic/env-file.c b/src/libnm-systemd-shared/src/basic/env-file.c
index baab9bd2..61a9cd60 100644
--- a/src/libnm-systemd-shared/src/basic/env-file.c
+++ b/src/libnm-systemd-shared/src/basic/env-file.c
@@ -18,14 +18,12 @@ static int parse_env_file_internal(
                 FILE *f,
                 const char *fname,
                 int (*push) (const char *filename, unsigned line,
-                             const char *key, char *value, void *userdata, int *n_pushed),
-                void *userdata,
-                int *n_pushed) {
+                             const char *key, char *value, void *userdata),
+                void *userdata) {
 
         size_t n_key = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX;
         _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
         unsigned line = 1;
-        char *p;
         int r;
 
         enum {
@@ -48,7 +46,7 @@ static int parse_env_file_internal(
         if (r < 0)
                 return r;
 
-        for (p = contents; *p; p++) {
+        for (char *p = contents; *p; p++) {
                 char c = *p;
 
                 switch (state) {
@@ -102,7 +100,7 @@ static int parse_env_file_internal(
                                 if (last_key_whitespace != SIZE_MAX)
                                         key[last_key_whitespace] = 0;
 
-                                r = push(fname, line, key, value, userdata, n_pushed);
+                                r = push(fname, line, key, value, userdata);
                                 if (r < 0)
                                         return r;
 
@@ -145,7 +143,7 @@ static int parse_env_file_internal(
                                 if (last_key_whitespace != SIZE_MAX)
                                         key[last_key_whitespace] = 0;
 
-                                r = push(fname, line, key, value, userdata, n_pushed);
+                                r = push(fname, line, key, value, userdata);
                                 if (r < 0)
                                         return r;
 
@@ -264,7 +262,7 @@ static int parse_env_file_internal(
                 if (last_key_whitespace != SIZE_MAX)
                         key[last_key_whitespace] = 0;
 
-                r = push(fname, line, key, value, userdata, n_pushed);
+                r = push(fname, line, key, value, userdata);
                 if (r < 0)
                         return r;
 
@@ -302,8 +300,7 @@ static int check_utf8ness_and_warn(
 static int parse_env_file_push(
                 const char *filename, unsigned line,
                 const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
+                void *userdata) {
 
         const char *k;
         va_list aq, *ap = userdata;
@@ -325,9 +322,6 @@ static int parse_env_file_push(
                         free(*v);
                         *v = value;
 
-                        if (n_pushed)
-                                (*n_pushed)++;
-
                         return 1;
                 }
         }
@@ -343,16 +337,13 @@ int parse_env_filev(
                 const char *fname,
                 va_list ap) {
 
-        int r, n_pushed = 0;
+        int r;
         va_list aq;
 
         va_copy(aq, ap);
-        r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed);
+        r = parse_env_file_internal(f, fname, parse_env_file_push, &aq);
         va_end(aq);
-        if (r < 0)
-                return r;
-
-        return n_pushed;
+        return r;
 }
 
 int parse_env_file_sentinel(
@@ -374,8 +365,7 @@ int parse_env_file_sentinel(
 static int load_env_file_push(
                 const char *filename, unsigned line,
                 const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
+                void *userdata) {
         char ***m = userdata;
         char *p;
         int r;
@@ -392,78 +382,69 @@ static int load_env_file_push(
         if (r < 0)
                 return r;
 
-        if (n_pushed)
-                (*n_pushed)++;
-
         free(value);
         return 0;
 }
 
 int load_env_file(FILE *f, const char *fname, char ***rl) {
-        char **m = NULL;
+        _cleanup_strv_free_ char **m = NULL;
         int r;
 
-        r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL);
-        if (r < 0) {
-                strv_free(m);
+        r = parse_env_file_internal(f, fname, load_env_file_push, &m);
+        if (r < 0)
                 return r;
-        }
 
-        *rl = m;
+        *rl = TAKE_PTR(m);
         return 0;
 }
 
 static int load_env_file_push_pairs(
                 const char *filename, unsigned line,
                 const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
-        char ***m = userdata;
+                void *userdata) {
+
+        char ***m = ASSERT_PTR(userdata);
         int r;
 
         r = check_utf8ness_and_warn(filename, line, key, value);
         if (r < 0)
                 return r;
 
+        /* Check if the key is present */
+        for (char **t = *m; t && *t; t += 2)
+                if (streq(t[0], key)) {
+                        if (value)
+                                return free_and_replace(t[1], value);
+                        else
+                                return free_and_strdup(t+1, "");
+                }
+
         r = strv_extend(m, key);
         if (r < 0)
-                return -ENOMEM;
-
-        if (!value) {
-                r = strv_extend(m, "");
-                if (r < 0)
-                        return -ENOMEM;
-        } else {
-                r = strv_push(m, value);
-                if (r < 0)
-                        return r;
-        }
-
-        if (n_pushed)
-                (*n_pushed)++;
+                return r;
 
-        return 0;
+        if (value)
+                return strv_push(m, value);
+        else
+                return strv_extend(m, "");
 }
 
 int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
-        char **m = NULL;
+        _cleanup_strv_free_ char **m = NULL;
         int r;
 
-        r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL);
-        if (r < 0) {
-                strv_free(m);
+        r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m);
+        if (r < 0)
                 return r;
-        }
 
-        *rl = m;
+        *rl = TAKE_PTR(m);
         return 0;
 }
 
 static int merge_env_file_push(
                 const char *filename, unsigned line,
                 const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
+                void *userdata) {
 
         char ***env = userdata;
         char *expanded_value;
@@ -492,7 +473,7 @@ static int merge_env_file_push(
 
         log_debug("%s:%u: setting %s=%s", filename, line, key, value);
 
-        return load_env_file_push(filename, line, key, value, env, n_pushed);
+        return load_env_file_push(filename, line, key, value, env);
 }
 
 int merge_env_file(
@@ -504,7 +485,7 @@ int merge_env_file(
          * plus "extended" substitutions, unlike other exported parsing functions.
          */
 
-        return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL);
+        return parse_env_file_internal(f, fname, merge_env_file_push, env);
 }
 
 static void write_env_var(FILE *f, const char *v) {
@@ -541,7 +522,6 @@ static void write_env_var(FILE *f, const char *v) {
 int write_env_file(const char *fname, char **l) {
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_free_ char *p = NULL;
-        char **i;
         int r;
 
         assert(fname);
diff --git a/src/libnm-systemd-shared/src/basic/env-util.c b/src/libnm-systemd-shared/src/basic/env-util.c
index f47ddefe..b4ac6811 100644
--- a/src/libnm-systemd-shared/src/basic/env-util.c
+++ b/src/libnm-systemd-shared/src/basic/env-util.c
@@ -99,8 +99,6 @@ bool env_assignment_is_valid(const char *e) {
 }
 
 bool strv_env_is_valid(char **e) {
-        char **p, **q;
-
         STRV_FOREACH(p, e) {
                 size_t k;
 
@@ -118,8 +116,6 @@ bool strv_env_is_valid(char **e) {
 }
 
 bool strv_env_name_is_valid(char **l) {
-        char **p;
-
         STRV_FOREACH(p, l) {
                 if (!env_name_is_valid(*p))
                         return false;
@@ -132,8 +128,6 @@ bool strv_env_name_is_valid(char **l) {
 }
 
 bool strv_env_name_or_assignment_is_valid(char **l) {
-        char **p;
-
         STRV_FOREACH(p, l) {
                 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
                         return false;
@@ -275,7 +269,7 @@ static bool env_entry_has_name(const char *entry, const char *name) {
 
 char **strv_env_delete(char **x, size_t n_lists, ...) {
         size_t n, i = 0;
-        char **k, **r;
+        char **r;
         va_list ap;
 
         /* Deletes every entry from x that is mentioned in the other
@@ -290,7 +284,7 @@ char **strv_env_delete(char **x, size_t n_lists, ...) {
         STRV_FOREACH(k, x) {
                 va_start(ap, n_lists);
                 for (size_t v = 0; v < n_lists; v++) {
-                        char **l, **j;
+                        char **l;
 
                         l = va_arg(ap, char**);
                         STRV_FOREACH(j, l)
@@ -382,7 +376,6 @@ char **strv_env_unset_many(char **l, ...) {
 
 int strv_env_replace_consume(char ***l, char *p) {
         const char *t, *name;
-        char **f;
         int r;
 
         assert(p);
@@ -470,8 +463,6 @@ int strv_env_assign(char ***l, const char *key, const char *value) {
 }
 
 char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
-        char **i;
-
         assert(name);
 
         if (k <= 0)
@@ -499,7 +490,7 @@ char *strv_env_get(char **l, const char *name) {
 }
 
 char *strv_env_pairs_get(char **l, const char *name) {
-        char **key, **value, *result = NULL;
+        char *result = NULL;
 
         assert(name);
 
@@ -511,7 +502,6 @@ char *strv_env_pairs_get(char **l, const char *name) {
 }
 
 char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
-        char **p, **q;
         int k = 0;
 
         STRV_FOREACH(p, e) {
@@ -705,7 +695,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
 }
 
 char **replace_env_argv(char **argv, char **env) {
-        char **ret, **i;
+        char **ret;
         size_t k = 0, l = 0;
 
         l = strv_length(argv);
@@ -837,7 +827,6 @@ int setenv_systemd_exec_pid(bool update_only) {
 int getenv_path_list(const char *name, char ***ret_paths) {
         _cleanup_strv_free_ char **l = NULL;
         const char *e;
-        char **p;
         int r;
 
         assert(name);
@@ -873,20 +862,37 @@ int getenv_path_list(const char *name, char ***ret_paths) {
         return 1;
 }
 
-int unsetenv_erase(const char *name) {
-        char *p;
+int getenv_steal_erase(const char *name, char **ret) {
+        _cleanup_(erase_and_freep) char *a = NULL;
+        char *e;
 
         assert(name);
 
-        p = getenv(name);
-        if (!p)
+        /* Reads an environment variable, makes a copy of it, erases its memory in the environment block and removes
+         * it from there. Usecase: reading passwords from the env block (which is a bad idea, but useful for
+         * testing, and given that people are likely going to misuse this, be thorough) */
+
+        e = getenv(name);
+        if (!e) {
+                if (ret)
+                        *ret = NULL;
                 return 0;
+        }
+
+        if (ret) {
+                a = strdup(e);
+                if (!a)
+                        return -ENOMEM;
+        }
 
-        string_erase(p);
+        string_erase(e);
 
         if (unsetenv(name) < 0)
                 return -errno;
 
+        if (ret)
+                *ret = TAKE_PTR(a);
+
         return 1;
 }
 #endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/env-util.h b/src/libnm-systemd-shared/src/basic/env-util.h
index 38bfc8a3..2bf0603f 100644
--- a/src/libnm-systemd-shared/src/basic/env-util.h
+++ b/src/libnm-systemd-shared/src/basic/env-util.h
@@ -69,4 +69,4 @@ int setenv_systemd_exec_pid(bool update_only);
  * PATH-like colon-separated absolute paths */
 int getenv_path_list(const char *name, char ***ret_paths);
 
-int unsetenv_erase(const char *name);
+int getenv_steal_erase(const char *name, char **ret);
diff --git a/src/libnm-systemd-shared/src/basic/errno-util.h b/src/libnm-systemd-shared/src/basic/errno-util.h
index 09abf0b7..648de50e 100644
--- a/src/libnm-systemd-shared/src/basic/errno-util.h
+++ b/src/libnm-systemd-shared/src/basic/errno-util.h
@@ -138,10 +138,18 @@ static inline bool ERRNO_IS_PRIVILEGE(int r) {
                       EPERM);
 }
 
-/* Three difference errors for "not enough disk space" */
+/* Three different errors for "not enough disk space" */
 static inline bool ERRNO_IS_DISK_SPACE(int r) {
         return IN_SET(abs(r),
                       ENOSPC,
                       EDQUOT,
                       EFBIG);
 }
+
+/* Three different errors for "this device does not quite exist" */
+static inline bool ERRNO_IS_DEVICE_ABSENT(int r) {
+        return IN_SET(abs(r),
+                      ENODEV,
+                      ENXIO,
+                      ENOENT);
+}
diff --git a/src/libnm-systemd-shared/src/basic/escape.c b/src/libnm-systemd-shared/src/basic/escape.c
index 4dfb9a16..cc317dfb 100644
--- a/src/libnm-systemd-shared/src/basic/escape.c
+++ b/src/libnm-systemd-shared/src/basic/escape.c
@@ -552,7 +552,6 @@ char* quote_command_line(char **argv, ShellEscapeFlags flags) {
 
         assert(argv);
 
-        char **a;
         STRV_FOREACH(a, argv) {
                 _cleanup_free_ char *t = NULL;
 
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.c b/src/libnm-systemd-shared/src/basic/fd-util.c
index c3df68de..53efeb40 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.c
+++ b/src/libnm-systemd-shared/src/basic/fd-util.c
@@ -5,6 +5,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/btrfs.h>
+#include <linux/fs.h>
 #include <linux/magic.h>
 #include <sys/ioctl.h>
 #include <sys/resource.h>
@@ -19,6 +20,7 @@
 #include "io-util.h"
 #include "macro.h"
 #include "missing_fcntl.h"
+#include "missing_fs.h"
 #include "missing_syscall.h"
 #include "parse-util.h"
 #include "path-util.h"
@@ -420,14 +422,11 @@ int same_fd(int a, int b) {
         assert(a >= 0);
         assert(b >= 0);
 
-        /* Compares two file descriptors. Note that semantics are
-         * quite different depending on whether we have kcmp() or we
-         * don't. If we have kcmp() this will only return true for
-         * dup()ed file descriptors, but not otherwise. If we don't
-         * have kcmp() this will also return true for two fds of the same
-         * file, created by separate open() calls. Since we use this
-         * call mostly for filtering out duplicates in the fd store
-         * this difference hopefully doesn't matter too much. */
+        /* Compares two file descriptors. Note that semantics are quite different depending on whether we
+         * have kcmp() or we don't. If we have kcmp() this will only return true for dup()ed file
+         * descriptors, but not otherwise. If we don't have kcmp() this will also return true for two fds of
+         * the same file, created by separate open() calls. Since we use this call mostly for filtering out
+         * duplicates in the fd store this difference hopefully doesn't matter too much. */
 
         if (a == b)
                 return true;
@@ -439,7 +438,7 @@ int same_fd(int a, int b) {
                 return true;
         if (r > 0)
                 return false;
-        if (!IN_SET(errno, ENOSYS, EACCES, EPERM))
+        if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
                 return -errno;
 
         /* We don't have kcmp(), use fstat() instead. */
@@ -449,23 +448,17 @@ int same_fd(int a, int b) {
         if (fstat(b, &stb) < 0)
                 return -errno;
 
-        if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
+        if (!stat_inode_same(&sta, &stb))
                 return false;
 
-        /* We consider all device fds different, since two device fds
-         * might refer to quite different device contexts even though
-         * they share the same inode and backing dev_t. */
+        /* We consider all device fds different, since two device fds might refer to quite different device
+         * contexts even though they share the same inode and backing dev_t. */
 
         if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
                 return false;
 
-        if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
-                return false;
-
-        /* The fds refer to the same inode on disk, let's also check
-         * if they have the same fd flags. This is useful to
-         * distinguish the read and write side of a pipe created with
-         * pipe(). */
+        /* The fds refer to the same inode on disk, let's also check if they have the same fd flags. This is
+         * useful to distinguish the read and write side of a pipe created with pipe(). */
         fa = fcntl(a, F_GETFL);
         if (fa < 0)
                 return -errno;
@@ -804,4 +797,25 @@ int btrfs_defrag_fd(int fd) {
 
         return RET_NERRNO(ioctl(fd, BTRFS_IOC_DEFRAG, NULL));
 }
+
+int fd_get_diskseq(int fd, uint64_t *ret) {
+        uint64_t diskseq;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        if (ioctl(fd, BLKGETDISKSEQ, &diskseq) < 0) {
+                /* Note that the kernel is weird: non-existing ioctls currently return EINVAL
+                 * rather than ENOTTY on loopback block devices. They should fix that in the kernel,
+                 * but in the meantime we accept both here. */
+                if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL)
+                        return -errno;
+
+                return -EOPNOTSUPP;
+        }
+
+        *ret = diskseq;
+
+        return 0;
+}
 #endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.h b/src/libnm-systemd-shared/src/basic/fd-util.h
index f5cfcb4e..808cac4d 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.h
+++ b/src/libnm-systemd-shared/src/basic/fd-util.h
@@ -109,6 +109,7 @@ static inline int make_null_stdio(void) {
 int fd_reopen(int fd, int flags);
 int read_nr_open(void);
 int btrfs_defrag_fd(int fd);
+int fd_get_diskseq(int fd, uint64_t *ret);
 
 /* The maximum length a buffer for a /proc/self/fd/<fd> path needs */
 #define PROC_FD_PATH_MAX \
diff --git a/src/libnm-systemd-shared/src/basic/fileio.c b/src/libnm-systemd-shared/src/basic/fileio.c
index c66bc67b..0ad8ae03 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.c
+++ b/src/libnm-systemd-shared/src/basic/fileio.c
@@ -1049,8 +1049,6 @@ static int search_and_fopen_internal(
                 FILE **ret,
                 char **ret_path) {
 
-        char **i;
-
         assert(path);
         assert(mode);
         assert(ret);
@@ -1204,7 +1202,7 @@ int write_timestamp_file_atomic(const char *fn, usec_t n) {
         /* Creates a "timestamp" file, that contains nothing but a
          * usec_t timestamp, formatted in ASCII. */
 
-        if (n <= 0 || n >= USEC_INFINITY)
+        if (!timestamp_is_set(n))
                 return -ERANGE;
 
         xsprintf(ln, USEC_FMT "\n", n);
@@ -1225,7 +1223,7 @@ int read_timestamp_file(const char *fn, usec_t *ret) {
         if (r < 0)
                 return r;
 
-        if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
+        if (!timestamp_is_set(t))
                 return -ERANGE;
 
         *ret = (usec_t) t;
diff --git a/src/libnm-systemd-shared/src/basic/fileio.h b/src/libnm-systemd-shared/src/basic/fileio.h
index cea3dd89..9151d823 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.h
+++ b/src/libnm-systemd-shared/src/basic/fileio.h
@@ -110,6 +110,12 @@ typedef enum ReadLineFlags {
 
 int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret);
 
+static inline bool file_offset_beyond_memory_size(off_t x) {
+        if (x < 0) /* off_t is signed, filter that out */
+                return false;
+        return (uint64_t) x > (uint64_t) SIZE_MAX;
+}
+
 static inline int read_line(FILE *f, size_t limit, char **ret) {
         return read_line_full(f, limit, 0, ret);
 }
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c
index b524a6fd..dccfb27b 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.c
+++ b/src/libnm-systemd-shared/src/basic/fs-util.c
@@ -123,7 +123,6 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
         size_t l = PATH_MAX;
 
         assert(p);
-        assert(ret);
 
         for (;;) {
                 _cleanup_free_ char *c = NULL;
@@ -139,7 +138,10 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
 
                 if ((size_t) n < l) {
                         c[n] = 0;
-                        *ret = TAKE_PTR(c);
+
+                        if (ret)
+                                *ret = TAKE_PTR(c);
+
                         return 0;
                 }
 
@@ -576,7 +578,6 @@ int get_files_in_directory(const char *path, char ***list) {
 #endif /* NM_IGNORED */
 
 static int getenv_tmp_dir(const char **ret_path) {
-        const char *n;
         int r, ret = 0;
 
         assert(ret_path);
@@ -866,8 +867,7 @@ int conservative_renameat(
         if (fstat(new_fd, &new_stat) < 0)
                 goto do_rename;
 
-        if (new_stat.st_ino == old_stat.st_ino &&
-            new_stat.st_dev == old_stat.st_dev)
+        if (stat_inode_same(&new_stat, &old_stat))
                 goto is_same;
 
         if (old_stat.st_mode != new_stat.st_mode ||
@@ -1094,3 +1094,50 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
 
         return TAKE_FD(fd);
 }
+
+int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created) {
+        unsigned attempts = 7;
+        int fd;
+
+        /* Just like openat(), but adds one thing: optionally returns whether we created the file anew or if
+         * it already existed before. This is only relevant if O_CREAT is set without O_EXCL, and thus will
+         * shortcut to openat() otherwise */
+
+        if (!ret_newly_created)
+                return RET_NERRNO(openat(dirfd, pathname, flags, mode));
+
+        if (!FLAGS_SET(flags, O_CREAT) || FLAGS_SET(flags, O_EXCL)) {
+                fd = openat(dirfd, pathname, flags, mode);
+                if (fd < 0)
+                        return -errno;
+
+                *ret_newly_created = FLAGS_SET(flags, O_CREAT);
+                return fd;
+        }
+
+        for (;;) {
+                /* First, attempt to open without O_CREAT/O_EXCL, i.e. open existing file */
+                fd = openat(dirfd, pathname, flags & ~(O_CREAT | O_EXCL), mode);
+                if (fd >= 0) {
+                        *ret_newly_created = false;
+                        return fd;
+                }
+                if (errno != ENOENT)
+                        return -errno;
+
+                /* So the file didn't exist yet, hence create it with O_CREAT/O_EXCL. */
+                fd = openat(dirfd, pathname, flags | O_CREAT | O_EXCL, mode);
+                if (fd >= 0) {
+                        *ret_newly_created = true;
+                        return fd;
+                }
+                if (errno != EEXIST)
+                        return -errno;
+
+                /* Hmm, so now we got EEXIST? So it apparently exists now? If so, let's try to open again
+                 * without the two flags. But let's not spin forever, hence put a limit on things */
+
+                if (--attempts == 0) /* Give up eventually, somebody is playing with us */
+                        return -EEXIST;
+        }
+}
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.h b/src/libnm-systemd-shared/src/basic/fs-util.h
index 0bbb3f62..e48cf680 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.h
+++ b/src/libnm-systemd-shared/src/basic/fs-util.h
@@ -110,3 +110,5 @@ int posix_fallocate_loop(int fd, uint64_t offset, uint64_t size);
 int parse_cifs_service(const char *s, char **ret_host, char **ret_service, char **ret_path);
 
 int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode);
+
+int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created);
diff --git a/src/libnm-systemd-shared/src/basic/hashmap.c b/src/libnm-systemd-shared/src/basic/hashmap.c
index ee2a12e8..e7dedc6d 100644
--- a/src/libnm-systemd-shared/src/basic/hashmap.c
+++ b/src/libnm-systemd-shared/src/basic/hashmap.c
@@ -164,7 +164,7 @@ struct _packed_ indirect_storage {
         unsigned n_buckets;                /* number of buckets */
 
         unsigned idx_lowest_entry;         /* Index below which all buckets are free.
-                                              Makes "while(hashmap_steal_first())" loops
+                                              Makes "while (hashmap_steal_first())" loops
                                               O(n) instead of O(n^2) for unordered hashmaps. */
         uint8_t  _pad[3];                  /* padding for the whole HashmapBase */
         /* The bitfields in HashmapBase complete the alignment of the whole thing. */
@@ -1868,7 +1868,6 @@ int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p
 
 int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l  HASHMAP_DEBUG_PARAMS) {
         int n = 0, r;
-        char **i;
 
         assert(s);
 
diff --git a/src/libnm-systemd-shared/src/basic/hexdecoct.c b/src/libnm-systemd-shared/src/basic/hexdecoct.c
index 381e79ba..570da688 100644
--- a/src/libnm-systemd-shared/src/basic/hexdecoct.c
+++ b/src/libnm-systemd-shared/src/basic/hexdecoct.c
@@ -688,8 +688,7 @@ static int base64_append_width(
                         s += indent;
                 }
 
-                memcpy(s, x + width * line, act);
-                s += act;
+                s = mempcpy(s, x + width * line, act);
                 *(s++) = line < lines - 1 ? '\n' : '\0';
                 avail -= act;
         }
diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.c b/src/libnm-systemd-shared/src/basic/hostname-util.c
index 1d1c2f51..692733ac 100644
--- a/src/libnm-systemd-shared/src/basic/hostname-util.c
+++ b/src/libnm-systemd-shared/src/basic/hostname-util.c
@@ -10,6 +10,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "env-file.h"
 #include "hostname-util.h"
 #include "os-util.h"
 #include "string-util.h"
@@ -197,3 +198,20 @@ bool is_localhost(const char *hostname) {
                 endswith_no_case(hostname, ".localhost.localdomain") ||
                 endswith_no_case(hostname, ".localhost.localdomain.");
 }
+
+int get_pretty_hostname(char **ret) {
+        _cleanup_free_ char *n = NULL;
+        int r;
+
+        assert(ret);
+
+        r = parse_env_file(NULL, "/etc/machine-info", "PRETTY_HOSTNAME", &n);
+        if (r < 0)
+                return r;
+
+        if (isempty(n))
+                return -ENXIO;
+
+        *ret = TAKE_PTR(n);
+        return 0;
+}
diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.h b/src/libnm-systemd-shared/src/basic/hostname-util.h
index d435bed5..a00b8523 100644
--- a/src/libnm-systemd-shared/src/basic/hostname-util.h
+++ b/src/libnm-systemd-shared/src/basic/hostname-util.h
@@ -4,7 +4,6 @@
 #include <stdbool.h>
 #include <stdio.h>
 
-#include "env-file.h"
 #include "macro.h"
 #include "strv.h"
 
@@ -61,6 +60,4 @@ static inline bool is_outbound_hostname(const char *hostname) {
         return STRCASE_IN_SET(hostname, "_outbound", "_outbound.");
 }
 
-static inline int get_pretty_hostname(char **ret) {
-        return parse_env_file(NULL, "/etc/machine-info", "PRETTY_HOSTNAME", ret);
-}
+int get_pretty_hostname(char **ret);
diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.c b/src/libnm-systemd-shared/src/basic/in-addr-util.c
index 1bf0764d..51a6b165 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.c
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c
@@ -123,6 +123,19 @@ int in_addr_is_localhost(int family, const union in_addr_union *u) {
         return -EAFNOSUPPORT;
 }
 
+int in_addr_is_localhost_one(int family, const union in_addr_union *u) {
+        assert(u);
+
+        if (family == AF_INET)
+                /* 127.0.0.1 */
+                return be32toh(u->in.s_addr) == UINT32_C(0x7F000001);
+
+        if (family == AF_INET6)
+                return IN6_IS_ADDR_LOOPBACK(&u->in6); /* lgtm [cpp/potentially-dangerous-function] */
+
+        return -EAFNOSUPPORT;
+}
+
 bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) {
         return a->s6_addr32[0] == 0 &&
                 a->s6_addr32[1] == 0 &&
diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.h b/src/libnm-systemd-shared/src/basic/in-addr-util.h
index 0178391e..5de87a95 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.h
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h
@@ -49,6 +49,7 @@ bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a);
 
 bool in4_addr_is_localhost(const struct in_addr *a);
 int in_addr_is_localhost(int family, const union in_addr_union *u);
+int in_addr_is_localhost_one(int family, const union in_addr_union *u);
 
 bool in4_addr_is_local_multicast(const struct in_addr *a);
 bool in4_addr_is_non_local(const struct in_addr *a);
diff --git a/src/libnm-systemd-shared/src/basic/inotify-util.h b/src/libnm-systemd-shared/src/basic/inotify-util.h
index 88af0868..61951ff3 100644
--- a/src/libnm-systemd-shared/src/basic/inotify-util.h
+++ b/src/libnm-systemd-shared/src/basic/inotify-util.h
@@ -6,12 +6,28 @@
 #include <stddef.h>
 #include <sys/inotify.h>
 
+#include "log.h"
+
 #define INOTIFY_EVENT_MAX (offsetof(struct inotify_event, name) + NAME_MAX + 1)
 
-#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
-        for ((e) = &buffer.ev;                                \
-             (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \
-             (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
+#define _FOREACH_INOTIFY_EVENT(e, buffer, sz, log_level, start, end)    \
+        for (struct inotify_event                                       \
+                     *start = &((buffer).ev),                           \
+                     *end = (struct inotify_event*) ((uint8_t*) start + (sz)), \
+                     *e = start;                                        \
+             (size_t) ((uint8_t*) end - (uint8_t*) e) >= sizeof(struct inotify_event) && \
+             ((size_t) ((uint8_t*) end - (uint8_t*) e) >= sizeof(struct inotify_event) + e->len || \
+              (log_full(log_level, "Received invalid inotify event, ignoring."), false)); \
+             e = (struct inotify_event*) ((uint8_t*) e + sizeof(struct inotify_event) + e->len))
+
+#define _FOREACH_INOTIFY_EVENT_FULL(e, buffer, sz, log_level)           \
+        _FOREACH_INOTIFY_EVENT(e, buffer, sz, log_level, UNIQ_T(start, UNIQ), UNIQ_T(end, UNIQ))
+
+#define FOREACH_INOTIFY_EVENT(e, buffer, sz)                    \
+        _FOREACH_INOTIFY_EVENT_FULL(e, buffer, sz, LOG_DEBUG)
+
+#define FOREACH_INOTIFY_EVENT_WARN(e, buffer, sz)               \
+        _FOREACH_INOTIFY_EVENT_FULL(e, buffer, sz, LOG_WARNING)
 
 union inotify_event_buffer {
         struct inotify_event ev;
diff --git a/src/libnm-systemd-shared/src/basic/io-util.c b/src/libnm-systemd-shared/src/basic/io-util.c
index d5cbb899..8a2b9c2f 100644
--- a/src/libnm-systemd-shared/src/basic/io-util.c
+++ b/src/libnm-systemd-shared/src/basic/io-util.c
@@ -165,7 +165,6 @@ int pipe_eof(int fd) {
 #endif /* NM_IGNORED */
 
 int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) {
-        struct timespec ts;
         int r;
 
         assert(fds || nfds == 0);
@@ -173,7 +172,7 @@ int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) {
         if (nfds == 0)
                 return 0;
 
-        r = ppoll(fds, nfds, timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL);
+        r = ppoll(fds, nfds, timeout == USEC_INFINITY ? NULL : TIMESPEC_STORE(timeout), NULL);
         if (r < 0)
                 return -errno;
         if (r == 0)
diff --git a/src/libnm-systemd-shared/src/basic/list.h b/src/libnm-systemd-shared/src/basic/list.h
index f827e721..58e83a6c 100644
--- a/src/libnm-systemd-shared/src/basic/list.h
+++ b/src/libnm-systemd-shared/src/basic/list.h
@@ -136,33 +136,39 @@
 #define LIST_JUST_US(name,item)                                         \
         (!(item)->name##_prev && !(item)->name##_next)
 
+/* The type of the iterator 'i' is automatically determined by the type of 'head', and declared in the
+ * loop. Hence, do not declare the same variable in the outer scope. Sometimes, we set 'head' through
+ * hashmap_get(). In that case, you need to explicitly cast the result. */
+#define LIST_FOREACH_WITH_NEXT(name,i,n,head)                           \
+        for (typeof(*(head)) *n, *i = (head); i && (n = i->name##_next, true); i = n)
+
 #define LIST_FOREACH(name,i,head)                                       \
-        for ((i) = (head); (i); (i) = (i)->name##_next)
+        LIST_FOREACH_WITH_NEXT(name, i, UNIQ_T(n, UNIQ), head)
 
-#define LIST_FOREACH_SAFE(name,i,n,head)                                \
-        for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
+#define _LIST_FOREACH_WITH_PREV(name,i,p,start)                         \
+        for (typeof(*(start)) *p, *i = (start); i && (p = i->name##_prev, true); i = p)
 
-#define LIST_FOREACH_BACKWARDS(name,i,p)                                \
-        for ((i) = (p); (i); (i) = (i)->name##_prev)
+#define LIST_FOREACH_BACKWARDS(name,i,start)                            \
+        _LIST_FOREACH_WITH_PREV(name, i, UNIQ_T(p, UNIQ), start)
 
 /* Iterate through all the members of the list p is included in, but skip over p */
 #define LIST_FOREACH_OTHERS(name,i,p)                                   \
-        for (({                                                         \
-                (i) = (p);                                              \
-                while ((i) && (i)->name##_prev)                         \
-                        (i) = (i)->name##_prev;                         \
-                if ((i) == (p))                                         \
-                        (i) = (p)->name##_next;                         \
-             });                                                        \
-             (i);                                                       \
-             (i) = (i)->name##_next == (p) ? (p)->name##_next : (i)->name##_next)
-
-/* Loop starting from p->next until p->prev.
-   p can be adjusted meanwhile. */
+        for (typeof(*(p)) *_p = (p), *i = ({                            \
+                                typeof(*_p) *_j = _p;                   \
+                                while (_j && _j->name##_prev)           \
+                                        _j = _j->name##_prev;           \
+                                if (_j == _p)                           \
+                                        _j = _p->name##_next;           \
+                                _j;                                     \
+                        });                                             \
+             i;                                                         \
+             i = i->name##_next == _p ? _p->name##_next : i->name##_next)
+
+/* Loop starting from p->next until p->prev. p can be adjusted meanwhile. */
 #define LIST_LOOP_BUT_ONE(name,i,head,p)                                \
-        for ((i) = (p)->name##_next ? (p)->name##_next : (head);        \
-             (i) != (p);                                                \
-             (i) = (i)->name##_next ? (i)->name##_next : (head))
+        for (typeof(*(p)) *i = (p)->name##_next ? (p)->name##_next : (head); \
+             i != (p);                                                  \
+             i = i->name##_next ? i->name##_next : (head))
 
 #define LIST_IS_EMPTY(head)                                             \
         (!(head))
diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h
index 88d278fd..6361eb0f 100644
--- a/src/libnm-systemd-shared/src/basic/log.h
+++ b/src/libnm-systemd-shared/src/basic/log.h
@@ -409,9 +409,11 @@ int log_emergency_level(void);
         })
 
 #if LOG_TRACE
-#  define log_trace(...) log_debug(__VA_ARGS__)
+#  define log_trace(...)          log_debug(__VA_ARGS__)
+#  define log_trace_errno(...)    log_debug_errno(__VA_ARGS__)
 #else
-#  define log_trace(...) do {} while (0)
+#  define log_trace(...)          do {} while (0)
+#  define log_trace_errno(e, ...) (-ERRNO_VALUE(e))
 #endif
 
 /* Structured logging */
diff --git a/src/libnm-systemd-shared/src/basic/macro.h b/src/libnm-systemd-shared/src/basic/macro.h
index 79437775..41d83b3e 100644
--- a/src/libnm-systemd-shared/src/basic/macro.h
+++ b/src/libnm-systemd-shared/src/basic/macro.h
@@ -318,23 +318,32 @@ static inline int __coverity_check_and_return__(int condition) {
 
 #define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member)
 
-/* Returns the number of chars needed to format variables of the
- * specified type as a decimal string. Adds in extra space for a
- * negative '-' prefix (hence works correctly on signed
- * types). Includes space for the trailing NUL. */
+/* Returns the number of chars needed to format variables of the specified type as a decimal string. Adds in
+ * extra space for a negative '-' prefix for signed types. Includes space for the trailing NUL. */
 #define DECIMAL_STR_MAX(type)                                           \
-        (2U+(sizeof(type) <= 1 ? 3U :                                   \
+        ((size_t) IS_SIGNED_INTEGER_TYPE(type) + 1U +                   \
+            (sizeof(type) <= 1 ? 3U :                                   \
              sizeof(type) <= 2 ? 5U :                                   \
              sizeof(type) <= 4 ? 10U :                                  \
-             sizeof(type) <= 8 ? 20U : sizeof(int[-2*(sizeof(type) > 8)])))
-
-#define DECIMAL_STR_WIDTH(x)                            \
-        ({                                              \
-                typeof(x) _x_ = (x);                    \
-                size_t ans = 1;                         \
-                while ((_x_ /= 10) != 0)                \
-                        ans++;                          \
-                ans;                                    \
+             sizeof(type) <= 8 ? (IS_SIGNED_INTEGER_TYPE(type) ? 19U : 20U) : sizeof(int[-2*(sizeof(type) > 8)])))
+
+/* Returns the number of chars needed to format the specified integer value. It's hence more specific than
+ * DECIMAL_STR_MAX() which answers the same question for all possible values of the specified type. Does
+ * *not* include space for a trailing NUL. (If you wonder why we special case _x_ == 0 here: it's to trick
+ * out gcc's -Wtype-limits, which would complain on comparing an unsigned type with < 0, otherwise. By
+ * special-casing == 0 here first, we can use <= 0 instead of < 0 to trick out gcc.) */
+#define DECIMAL_STR_WIDTH(x)                                      \
+        ({                                                        \
+                typeof(x) _x_ = (x);                              \
+                size_t ans;                                       \
+                if (_x_ == 0)                                     \
+                        ans = 1;                                  \
+                else {                                            \
+                        ans = _x_ <= 0 ? 2 : 1;                   \
+                        while ((_x_ /= 10) != 0)                  \
+                                ans++;                            \
+                }                                                 \
+                ans;                                              \
         })
 
 #define SWAP_TWO(x, y) do {                        \
@@ -463,4 +472,20 @@ typedef struct {
 
 assert_cc(sizeof(dummy_t) == 0);
 
+/* A little helper for subtracting 1 off a pointer in a safe UB-free way. This is intended to be used for for
+ * loops that count down from a high pointer until some base. A naive loop would implement this like this:
+ *
+ * for (p = end-1; p >= base; p--) …
+ *
+ * But this is not safe because p before the base is UB in C. With this macro the loop becomes this instead:
+ *
+ * for (p = PTR_SUB1(end, base); p; p = PTR_SUB1(p, base)) …
+ *
+ * And is free from UB! */
+#define PTR_SUB1(p, base)                                \
+        ({                                               \
+                typeof(p) _q = (p);                      \
+                _q && _q > (base) ? &_q[-1] : NULL;      \
+        })
+
 #include "log.h"
diff --git a/src/libnm-systemd-shared/src/basic/memory-util.h b/src/libnm-systemd-shared/src/basic/memory-util.h
index 9f37431f..6e3280b9 100644
--- a/src/libnm-systemd-shared/src/basic/memory-util.h
+++ b/src/libnm-systemd-shared/src/basic/memory-util.h
@@ -15,7 +15,7 @@ size_t page_size(void) _pure_;
 #define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1))
 #define PAGE_OFFSET(l) ((l) & (page_size() - 1))
 
-/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
+/* Normal memcpy() requires src to be nonnull. We do nothing if n is 0. */
 static inline void *memcpy_safe(void *dst, const void *src, size_t n) {
         if (n == 0)
                 return dst;
@@ -23,7 +23,15 @@ static inline void *memcpy_safe(void *dst, const void *src, size_t n) {
         return memcpy(dst, src, n);
 }
 
-/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */
+/* Normal mempcpy() requires src to be nonnull. We do nothing if n is 0. */
+static inline void *mempcpy_safe(void *dst, const void *src, size_t n) {
+        if (n == 0)
+                return dst;
+        assert(src);
+        return mempcpy(dst, src, n);
+}
+
+/* Normal memcmp() requires s1 and s2 to be nonnull. We do nothing if n is 0. */
 static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
         if (n == 0)
                 return 0;
diff --git a/src/libnm-systemd-shared/src/basic/missing_syscall.h b/src/libnm-systemd-shared/src/basic/missing_syscall.h
index 41c83ec5..e5bdc0e1 100644
--- a/src/libnm-systemd-shared/src/basic/missing_syscall.h
+++ b/src/libnm-systemd-shared/src/basic/missing_syscall.h
@@ -574,6 +574,10 @@ static inline int missing_open_tree(
 #define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */
 #endif
 
+#ifndef MOVE_MOUNT_T_EMPTY_PATH
+#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */
+#endif
+
 static inline int missing_move_mount(
                 int from_dfd,
                 const char *from_pathname,
diff --git a/src/libnm-systemd-shared/src/basic/ordered-set.c b/src/libnm-systemd-shared/src/basic/ordered-set.c
index 62a36b5d..f402bb5b 100644
--- a/src/libnm-systemd-shared/src/basic/ordered-set.c
+++ b/src/libnm-systemd-shared/src/basic/ordered-set.c
@@ -60,7 +60,6 @@ int _ordered_set_put_strdup(OrderedSet **s, const char *p  HASHMAP_DEBUG_PARAMS)
 
 int _ordered_set_put_strdupv(OrderedSet **s, char **l  HASHMAP_DEBUG_PARAMS) {
         int n = 0, r;
-        char **i;
 
         STRV_FOREACH(i, l) {
                 r = _ordered_set_put_strdup(s, *i  HASHMAP_DEBUG_PASS_ARGS);
diff --git a/src/libnm-systemd-shared/src/basic/ordered-set.h b/src/libnm-systemd-shared/src/basic/ordered-set.h
index 3ee47350..c0650e01 100644
--- a/src/libnm-systemd-shared/src/basic/ordered-set.h
+++ b/src/libnm-systemd-shared/src/basic/ordered-set.h
@@ -18,6 +18,14 @@ int _ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops  HA
 int _ordered_set_ensure_put(OrderedSet **s, const struct hash_ops *ops, void *p  HASHMAP_DEBUG_PARAMS);
 #define ordered_set_ensure_put(s, hash_ops, key) _ordered_set_ensure_put(s, hash_ops, key  HASHMAP_DEBUG_SRC_ARGS)
 
+static inline void ordered_set_clear(OrderedSet *s) {
+        return ordered_hashmap_clear((OrderedHashmap*) s);
+}
+
+static inline void ordered_set_clear_free(OrderedSet *s) {
+        return ordered_hashmap_clear_free((OrderedHashmap*) s);
+}
+
 static inline OrderedSet* ordered_set_free(OrderedSet *s) {
         return (OrderedSet*) ordered_hashmap_free((OrderedHashmap*) s);
 }
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.c b/src/libnm-systemd-shared/src/basic/parse-util.c
index 4ba2657c..0a623c51 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.c
+++ b/src/libnm-systemd-shared/src/basic/parse-util.c
@@ -421,7 +421,7 @@ int safe_atoi(const char *s, int *ret_i) {
         return 0;
 }
 
-int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu) {
+int safe_atollu_full(const char *s, unsigned base, unsigned long long *ret_llu) {
         char *x = NULL;
         unsigned long long l;
 
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.h b/src/libnm-systemd-shared/src/basic/parse-util.h
index 3dc5e140..82731246 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.h
+++ b/src/libnm-systemd-shared/src/basic/parse-util.h
@@ -65,9 +65,9 @@ static inline int safe_atoi32(const char *s, int32_t *ret_i) {
         return safe_atoi(s, (int*) ret_i);
 }
 
-int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu);
+int safe_atollu_full(const char *s, unsigned base, unsigned long long *ret_llu);
 
-static inline int safe_atollu(const char *s, long long unsigned *ret_llu) {
+static inline int safe_atollu(const char *s, unsigned long long *ret_llu) {
         return safe_atollu_full(s, 0, ret_llu);
 }
 
@@ -82,12 +82,12 @@ static inline int safe_atoi64(const char *s, int64_t *ret_i) {
 }
 
 static inline int safe_atoux64(const char *s, uint64_t *ret) {
-        assert_cc(sizeof(int64_t) == sizeof(long long unsigned));
-        return safe_atollu_full(s, 16, (long long unsigned*) ret);
+        assert_cc(sizeof(int64_t) == sizeof(unsigned long long));
+        return safe_atollu_full(s, 16, (unsigned long long*) ret);
 }
 
 #if LONG_MAX == INT_MAX
-static inline int safe_atolu_full(const char *s, unsigned base, long unsigned *ret_u) {
+static inline int safe_atolu_full(const char *s, unsigned base, unsigned long *ret_u) {
         assert_cc(sizeof(unsigned long) == sizeof(unsigned));
         return safe_atou_full(s, base, (unsigned*) ret_u);
 }
@@ -117,7 +117,7 @@ static inline int safe_atozu(const char *s, size_t *ret_u) {
 }
 #else
 static inline int safe_atozu(const char *s, size_t *ret_u) {
-        assert_cc(sizeof(size_t) == sizeof(long unsigned));
+        assert_cc(sizeof(size_t) == sizeof(unsigned long));
         return safe_atolu(s, ret_u);
 }
 #endif
diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c
index f391848f..f6088458 100644
--- a/src/libnm-systemd-shared/src/basic/path-util.c
+++ b/src/libnm-systemd-shared/src/basic/path-util.c
@@ -66,7 +66,7 @@ char *path_make_absolute(const char *p, const char *prefix) {
 }
 
 int safe_getcwd(char **ret) {
-        char *cwd;
+        _cleanup_free_ char *cwd = NULL;
 
         cwd = get_current_dir_name();
         if (!cwd)
@@ -74,12 +74,12 @@ int safe_getcwd(char **ret) {
 
         /* Let's make sure the directory is really absolute, to protect us from the logic behind
          * CVE-2018-1000001 */
-        if (cwd[0] != '/') {
-                free(cwd);
+        if (cwd[0] != '/')
                 return -ENOMEDIUM;
-        }
 
-        *ret = cwd;
+        if (ret)
+                *ret = TAKE_PTR(cwd);
+
         return 0;
 }
 
@@ -205,9 +205,9 @@ int path_make_relative(const char *from, const char *to, char **ret) {
 }
 
 char* path_startswith_strv(const char *p, char **set) {
-        char **s, *t;
-
         STRV_FOREACH(s, set) {
+                char *t;
+
                 t = path_startswith(p, *s);
                 if (t)
                         return t;
@@ -217,7 +217,6 @@ char* path_startswith_strv(const char *p, char **set) {
 }
 
 int path_strv_make_absolute_cwd(char **l) {
-        char **s;
         int r;
 
         /* Goes through every item in the string list and makes it
@@ -239,7 +238,6 @@ int path_strv_make_absolute_cwd(char **l) {
 }
 
 char **path_strv_resolve(char **l, const char *root) {
-        char **s;
         unsigned k = 0;
         bool enomem = false;
         int r;
@@ -707,12 +705,12 @@ int find_executable_full(const char *name, const char *root, char **exec_search_
                 p = DEFAULT_PATH;
 
         if (exec_search_path) {
-                char **element;
-
                 STRV_FOREACH(element, exec_search_path) {
                         _cleanup_free_ char *full_path = NULL;
+
                         if (!path_is_absolute(*element))
                                 continue;
+
                         full_path = path_join(*element, name);
                         if (!full_path)
                                 return -ENOMEM;
@@ -761,7 +759,6 @@ int find_executable_full(const char *name, const char *root, char **exec_search_
 
 bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
         bool changed = false, originally_unset;
-        const char* const* i;
 
         assert(timestamp);
 
@@ -940,8 +937,9 @@ int path_find_first_component(const char **p, bool accept_dot_dot, const char **
 
 static const char *skip_slash_or_dot_backward(const char *path, const char *q) {
         assert(path);
+        assert(!q || q >= path);
 
-        for (; q >= path; q--) {
+        for (; q; q = PTR_SUB1(q, path)) {
                 if (*q == '/')
                         continue;
                 if (q > path && strneq(q - 1, "/.", 2))
@@ -1006,7 +1004,7 @@ int path_find_last_component(const char *path, bool accept_dot_dot, const char *
                 q = path + strlen(path) - 1;
 
         q = skip_slash_or_dot_backward(path, q);
-        if ((q < path) || /* the root directory */
+        if (!q || /* the root directory */
             (q == path && *q == '.')) { /* path is "." or "./" */
                 if (next)
                         *next = path;
@@ -1017,10 +1015,10 @@ int path_find_last_component(const char *path, bool accept_dot_dot, const char *
 
         last_end = q + 1;
 
-        while (q >= path && *q != '/')
-                q--;
+        while (q && *q != '/')
+                q = PTR_SUB1(q, path);
 
-        last_begin = q + 1;
+        last_begin = q ? q + 1 : path;
         len = last_end - last_begin;
 
         if (len > NAME_MAX)
@@ -1030,10 +1028,7 @@ int path_find_last_component(const char *path, bool accept_dot_dot, const char *
 
         if (next) {
                 q = skip_slash_or_dot_backward(path, q);
-                if (q < path)
-                        *next = path;
-                else
-                        *next = q + 1;
+                *next = q ? q + 1 : path;
         }
 
         if (ret)
@@ -1249,9 +1244,10 @@ bool hidden_or_backup_file(const char *filename) {
         assert(filename);
 
         if (filename[0] == '.' ||
-            streq(filename, "lost+found") ||
-            streq(filename, "aquota.user") ||
-            streq(filename, "aquota.group") ||
+            STR_IN_SET(filename,
+                       "lost+found",
+                       "aquota.user",
+                       "aquota.group") ||
             endswith(filename, "~"))
                 return true;
 
@@ -1348,7 +1344,7 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version)
 
                 _cleanup_strv_free_ char **names = NULL;
                 _cleanup_free_ char *path = NULL;
-                char *c, **name;
+                char *c;
 
                 path = path_join(root, pattern);
                 if (!path)
@@ -1422,8 +1418,6 @@ bool empty_or_root(const char *path) {
 }
 
 bool path_strv_contains(char **l, const char *path) {
-        char **i;
-
         STRV_FOREACH(i, l)
                 if (path_equal(*i, path))
                         return true;
@@ -1432,10 +1426,9 @@ bool path_strv_contains(char **l, const char *path) {
 }
 
 bool prefixed_path_strv_contains(char **l, const char *path) {
-        char **i, *j;
-
         STRV_FOREACH(i, l) {
-                j = *i;
+                const char *j = *i;
+
                 if (*j == '-')
                         j++;
                 if (*j == '+')
diff --git a/src/libnm-systemd-shared/src/basic/process-util.c b/src/libnm-systemd-shared/src/basic/process-util.c
index 70564bd3..83e3a71e 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.c
+++ b/src/libnm-systemd-shared/src/basic/process-util.c
@@ -6,6 +6,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <linux/oom.h>
+#include <pthread.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -220,7 +221,6 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
                 assert(!(flags & PROCESS_CMDLINE_USE_LOCALE));
 
                 _cleanup_strv_free_ char **args = NULL;
-                char **p;
 
                 args = strv_parse_nulstr(t, k);
                 if (!args)
@@ -478,37 +478,33 @@ int get_process_capeff(pid_t pid, char **ret) {
         return r;
 }
 
-static int get_process_link_contents(const char *proc_file, char **ret) {
+static int get_process_link_contents(pid_t pid, const char *proc_file, char **ret) {
+        const char *p;
         int r;
 
         assert(proc_file);
-        assert(ret);
 
-        r = readlink_malloc(proc_file, ret);
-        if (r == -ENOENT)
-                return -ESRCH;
-        if (r < 0)
-                return r;
+        p = procfs_file_alloca(pid, proc_file);
 
-        return 0;
+        r = readlink_malloc(p, ret);
+        return r == -ENOENT ? -ESRCH : r;
 }
 
 int get_process_exe(pid_t pid, char **ret) {
-        const char *p;
         char *d;
         int r;
 
         assert(pid >= 0);
-        assert(ret);
 
-        p = procfs_file_alloca(pid, "exe");
-        r = get_process_link_contents(p, ret);
+        r = get_process_link_contents(pid, "exe", ret);
         if (r < 0)
                 return r;
 
-        d = endswith(*ret, " (deleted)");
-        if (d)
-                *d = '\0';
+        if (ret) {
+                d = endswith(*ret, " (deleted)");
+                if (d)
+                        *d = '\0';
+        }
 
         return 0;
 }
@@ -578,28 +574,17 @@ int get_process_gid(pid_t pid, gid_t *ret) {
 }
 
 int get_process_cwd(pid_t pid, char **ret) {
-        const char *p;
-
         assert(pid >= 0);
-        assert(ret);
 
         if (pid == 0 || pid == getpid_cached())
                 return safe_getcwd(ret);
 
-        p = procfs_file_alloca(pid, "cwd");
-
-        return get_process_link_contents(p, ret);
+        return get_process_link_contents(pid, "cwd", ret);
 }
 
 int get_process_root(pid_t pid, char **ret) {
-        const char *p;
-
         assert(pid >= 0);
-        assert(ret);
-
-        p = procfs_file_alloca(pid, "root");
-
-        return get_process_link_contents(p, ret);
+        return get_process_link_contents(pid, "root", ret);
 }
 
 #define ENVIRONMENT_BLOCK_MAX (5U*1024U*1024U)
@@ -651,7 +636,7 @@ int get_process_environ(pid_t pid, char **ret) {
 
 int get_process_ppid(pid_t pid, pid_t *ret) {
         _cleanup_free_ char *line = NULL;
-        long unsigned ppid;
+        unsigned long ppid;
         const char *p;
         int r;
 
@@ -694,7 +679,7 @@ int get_process_ppid(pid_t pid, pid_t *ret) {
         if (ppid == 0)
                 return -EADDRNOTAVAIL;
 
-        if ((pid_t) ppid < 0 || (long unsigned) (pid_t) ppid != ppid)
+        if ((pid_t) ppid < 0 || (unsigned long) (pid_t) ppid != ppid)
                 return -ERANGE;
 
         if (ret)
@@ -825,13 +810,12 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
         for (;;) {
                 usec_t n;
                 siginfo_t status = {};
-                struct timespec ts;
 
                 n = now(CLOCK_MONOTONIC);
                 if (n >= until)
                         break;
 
-                r = RET_NERRNO(sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)));
+                r = RET_NERRNO(sigtimedwait(&mask, NULL, TIMESPEC_STORE(until - n)));
                 /* Assuming we woke due to the child exiting. */
                 if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) {
                         if (status.si_pid == pid) {
@@ -1170,12 +1154,6 @@ void reset_cached_pid(void) {
         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 _weak_;
-
 pid_t getpid_cached(void) {
         static bool installed = false;
         pid_t current_value;
@@ -1203,7 +1181,7 @@ pid_t getpid_cached(void) {
                          * only half-documented (glibc doesn't document it but LSB does — though only superficially)
                          * we'll check for errors only in the most generic fashion possible. */
 
-                        if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) {
+                        if (pthread_atfork(NULL, NULL, reset_cached_pid) != 0) {
                                 /* OOM? Let's try again later */
                                 cached_pid = CACHED_PID_UNSET;
                                 return new_pid;
@@ -1632,6 +1610,30 @@ _noreturn_ void freeze(void) {
                 pause();
 }
 
+bool argv_looks_like_help(int argc, char **argv) {
+        char **l;
+
+        /* Scans the command line for indications the user asks for help. This is supposed to be called by
+         * tools that do not implement getopt() style command line parsing because they are not primarily
+         * user-facing. Detects four ways of asking for help:
+         *
+         * 1. Passing zero arguments
+         * 2. Passing "help" as first argument
+         * 3. Passing --help as any argument
+         * 4. Passing -h as any argument
+         */
+
+        if (argc <= 1)
+                return true;
+
+        if (streq_ptr(argv[1], "help"))
+                return true;
+
+        l = strv_skip(argv, 1);
+
+        return strv_contains(l, "--help") ||
+                strv_contains(l, "-h");
+}
 
 static const char *const sigchld_code_table[] = {
         [CLD_EXITED] = "exited",
diff --git a/src/libnm-systemd-shared/src/basic/process-util.h b/src/libnm-systemd-shared/src/basic/process-util.h
index a957cab2..c488c6a8 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.h
+++ b/src/libnm-systemd-shared/src/basic/process-util.h
@@ -193,3 +193,5 @@ int setpriority_closest(int priority);
 bool invoked_as(char *argv[], const char *token);
 
 _noreturn_ void freeze(void);
+
+bool argv_looks_like_help(int argc, char **argv);
diff --git a/src/libnm-systemd-shared/src/basic/random-util.c b/src/libnm-systemd-shared/src/basic/random-util.c
index 9832f8ef..e3f4ee72 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.c
+++ b/src/libnm-systemd-shared/src/basic/random-util.c
@@ -37,225 +37,41 @@
 
 static bool srand_called = false;
 
-int rdrand(unsigned long *ret) {
-
-        /* So, you are a "security researcher", and you wonder why we bother with using raw RDRAND here,
-         * instead of sticking to /dev/urandom or getrandom()?
-         *
-         * Here's why: early boot. On Linux, during early boot the random pool that backs /dev/urandom and
-         * getrandom() is generally not initialized yet. It is very common that initialization of the random
-         * pool takes a longer time (up to many minutes), in particular on embedded devices that have no
-         * explicit hardware random generator, as well as in virtualized environments such as major cloud
-         * installations that do not provide virtio-rng or a similar mechanism.
-         *
-         * In such an environment using getrandom() synchronously means we'd block the entire system boot-up
-         * until the pool is initialized, i.e. *very* long. Using getrandom() asynchronously (GRND_NONBLOCK)
-         * would mean acquiring randomness during early boot would simply fail. Using /dev/urandom would mean
-         * generating many kmsg log messages about our use of it before the random pool is properly
-         * initialized. Neither of these outcomes is desirable.
-         *
-         * Thus, for very specific purposes we use RDRAND instead of either of these three options. RDRAND
-         * provides us quickly and relatively reliably with random values, without having to delay boot,
-         * without triggering warning messages in kmsg.
-         *
-         * Note that we use RDRAND only under very specific circumstances, when the requirements on the
-         * quality of the returned entropy permit it. Specifically, here are some cases where we *do* use
-         * RDRAND:
-         *
-         *         • UUID generation: UUIDs are supposed to be universally unique but are not cryptographic
-         *           key material. The quality and trust level of RDRAND should hence be OK: UUIDs should be
-         *           generated in a way that is reliably unique, but they do not require ultimate trust into
-         *           the entropy generator. systemd generates a number of UUIDs during early boot, including
-         *           'invocation IDs' for every unit spawned that identify the specific invocation of the
-         *           service globally, and a number of others. Other alternatives for generating these UUIDs
-         *           have been considered, but don't really work: for example, hashing uuids from a local
-         *           system identifier combined with a counter falls flat because during early boot disk
-         *           storage is not yet available (think: initrd) and thus a system-specific ID cannot be
-         *           stored or retrieved yet.
-         *
-         *         • Hash table seed generation: systemd uses many hash tables internally. Hash tables are
-         *           generally assumed to have O(1) access complexity, but can deteriorate to prohibitive
-         *           O(n) access complexity if an attacker manages to trigger a large number of hash
-         *           collisions. Thus, systemd (as any software employing hash tables should) uses seeded
-         *           hash functions for its hash tables, with a seed generated randomly. The hash tables
-         *           systemd employs watch the fill level closely and reseed if necessary. This allows use of
-         *           a low quality RNG initially, as long as it improves should a hash table be under attack:
-         *           the attacker after all needs to trigger many collisions to exploit it for the purpose
-         *           of DoS, but if doing so improves the seed the attack surface is reduced as the attack
-         *           takes place.
-         *
-         * Some cases where we do NOT use RDRAND are:
-         *
-         *         • Generation of cryptographic key material 🔑
-         *
-         *         • Generation of cryptographic salt values 🧂
-         *
-         * This function returns:
-         *
-         *         -EOPNOTSUPP → RDRAND is not available on this system 😔
-         *         -EAGAIN     → The operation failed this time, but is likely to work if you try again a few
-         *                       times ♻
-         *         -EUCLEAN    → We got some random value, but it looked strange, so we refused using it.
-         *                       This failure might or might not be temporary. 😕
-         */
-
-#if defined(__i386__) || defined(__x86_64__)
-        static int have_rdrand = -1;
-        unsigned long v;
-        uint8_t success;
-
-        if (have_rdrand < 0) {
-                uint32_t eax, ebx, ecx, edx;
-
-                /* Check if RDRAND is supported by the CPU */
-                if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0) {
-                        have_rdrand = false;
-                        return -EOPNOTSUPP;
-                }
-
-/* Compat with old gcc where bit_RDRND didn't exist yet */
-#ifndef bit_RDRND
-#define bit_RDRND (1U << 30)
-#endif
-
-                have_rdrand = !!(ecx & bit_RDRND);
-
-                if (have_rdrand > 0) {
-                        /* Allow disabling use of RDRAND with SYSTEMD_RDRAND=0
-                           If it is unset getenv_bool_secure will return a negative value. */
-                        if (getenv_bool_secure("SYSTEMD_RDRAND") == 0) {
-                                have_rdrand = false;
-                                return -EOPNOTSUPP;
-                        }
-                }
-        }
-
-        if (have_rdrand == 0)
-                return -EOPNOTSUPP;
-
-        asm volatile("rdrand %0;"
-                     "setc %1"
-                     : "=r" (v),
-                       "=qm" (success));
-        msan_unpoison(&success, sizeof(success));
-        if (!success)
-                return -EAGAIN;
-
-        /* Apparently on some AMD CPUs RDRAND will sometimes (after a suspend/resume cycle?) report success
-         * via the carry flag but nonetheless return the same fixed value -1 in all cases. This appears to be
-         * a bad bug in the CPU or firmware. Let's deal with that and work-around this by explicitly checking
-         * for this special value (and also 0, just to be sure) and filtering it out. This is a work-around
-         * only however and something AMD really should fix properly. The Linux kernel should probably work
-         * around this issue by turning off RDRAND altogether on those CPUs. See:
-         * https://github.com/systemd/systemd/issues/11810 */
-        if (v == 0 || v == ULONG_MAX)
-                return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
-                                       "RDRAND returned suspicious value %lx, assuming bad hardware RNG, not using value.", v);
-
-        *ret = v;
-        return 0;
-#else
-        return -EOPNOTSUPP;
-#endif
-}
-
 int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
         static int have_syscall = -1;
         _cleanup_close_ int fd = -1;
-        bool got_some = false;
-
-        /* Gathers some high-quality randomness from the kernel (or potentially mid-quality randomness from
-         * the CPU if the RANDOM_ALLOW_RDRAND flag is set). This call won't block, unless the RANDOM_BLOCK
-         * flag is set. If RANDOM_MAY_FAIL is set, an error is returned if the random pool is not
-         * initialized. Otherwise it will always return some data from the kernel, regardless of whether the
-         * random pool is fully initialized or not. If RANDOM_EXTEND_WITH_PSEUDO is set, and some but not
-         * enough better quality randomness could be acquired, the rest is filled up with low quality
-         * randomness.
-         *
-         * Of course, when creating cryptographic key material you really shouldn't use RANDOM_ALLOW_DRDRAND
-         * or even RANDOM_EXTEND_WITH_PSEUDO.
-         *
-         * When generating UUIDs it's fine to use RANDOM_ALLOW_RDRAND but not OK to use
-         * RANDOM_EXTEND_WITH_PSEUDO. In fact RANDOM_EXTEND_WITH_PSEUDO is only really fine when invoked via
-         * an "all bets are off" wrapper, such as random_bytes(), see below. */
+
+        /* Gathers some high-quality randomness from the kernel. This call won't block, unless the RANDOM_BLOCK
+         * flag is set. If it doesn't block, it will still always return some data from the kernel, regardless
+         * of whether the random pool is fully initialized or not. When creating cryptographic key material you
+         * should always use RANDOM_BLOCK. */
 
         if (n == 0)
                 return 0;
 
-        if (FLAGS_SET(flags, RANDOM_ALLOW_RDRAND))
-                /* Try x86-64' RDRAND intrinsic if we have it. We only use it if high quality randomness is
-                 * not required, as we don't trust it (who does?). Note that we only do a single iteration of
-                 * RDRAND here, even though the Intel docs suggest calling this in a tight loop of 10
-                 * invocations or so. That's because we don't really care about the quality here. We
-                 * generally prefer using RDRAND if the caller allows us to, since this way we won't upset
-                 * the kernel's random subsystem by accessing it before the pool is initialized (after all it
-                 * will kmsg log about every attempt to do so). */
-                for (;;) {
-                        unsigned long u;
-                        size_t m;
-
-                        if (rdrand(&u) < 0) {
-                                if (got_some && FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
-                                        /* Fill in the remaining bytes using pseudo-random values */
-                                        pseudo_random_bytes(p, n);
-                                        return 0;
-                                }
-
-                                /* OK, this didn't work, let's go to getrandom() + /dev/urandom instead */
-                                break;
-                        }
-
-                        m = MIN(sizeof(u), n);
-                        memcpy(p, &u, m);
-
-                        p = (uint8_t*) p + m;
-                        n -= m;
-
-                        if (n == 0)
-                                return 0; /* Yay, success! */
-
-                        got_some = true;
-                }
-
         /* Use the getrandom() syscall unless we know we don't have it. */
         if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
-
                 for (;;) {
-                        ssize_t l;
-#if !HAVE_GETRANDOM
+#if HAVE_GETRANDOM
+                        ssize_t l = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_INSECURE);
+#else
                         /* NetworkManager Note: 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. */
-                        l = -1;
+                        ssize_t l = -1;
                         errno = ENOSYS;
-#else
-                        l = getrandom(p, n,
-                                      (FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK) |
-                                      (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE) ? GRND_INSECURE : 0));
 #endif
+
                         if (l > 0) {
                                 have_syscall = true;
 
                                 if ((size_t) l == n)
                                         return 0; /* Yay, success! */
 
+                                /* We didn't get enough data, so try again */
                                 assert((size_t) l < n);
                                 p = (uint8_t*) p + l;
                                 n -= l;
-
-                                if (FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
-                                        /* Fill in the remaining bytes using pseudo-random values */
-                                        pseudo_random_bytes(p, n);
-                                        return 0;
-                                }
-
-                                got_some = true;
-
-                                /* Hmm, we didn't get enough good data but the caller insists on good data? Then try again */
-                                if (FLAGS_SET(flags, RANDOM_BLOCK))
-                                        continue;
-
-                                /* Fill in the rest with /dev/urandom */
-                                break;
+                                continue;
 
                         } else if (l == 0) {
                                 have_syscall = true;
@@ -266,37 +82,12 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
                                 have_syscall = false;
                                 break;
 
-                        } else if (errno == EAGAIN) {
-                                /* The kernel has no entropy whatsoever. Let's remember to use the syscall
-                                 * the next time again though.
-                                 *
-                                 * If RANDOM_MAY_FAIL is set, return an error so that random_bytes() can
-                                 * produce some pseudo-random bytes instead. 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;
-
-                                if (got_some && FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
-                                        /* Fill in the remaining bytes using pseudorandom values */
-                                        pseudo_random_bytes(p, n);
-                                        return 0;
-                                }
-
-                                if (FLAGS_SET(flags, RANDOM_MAY_FAIL))
-                                        return -ENODATA;
-
-                                /* Use /dev/urandom instead */
-                                break;
-
                         } else if (errno == EINVAL) {
-
-                                /* Most likely: unknown flag. We know that GRND_INSECURE might cause this,
-                                 * hence try without. */
-
-                                if (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE)) {
-                                        flags = flags &~ RANDOM_ALLOW_INSECURE;
-                                        continue;
-                                }
+                                /* If we previously passed GRND_INSECURE, and this flag isn't known, then
+                                 * we're likely running an old kernel which has getrandom() but not
+                                 * GRND_INSECURE. In this case, fall back to /dev/urandom. */
+                                if (!FLAGS_SET(flags, RANDOM_BLOCK))
+                                        break;
 
                                 return -errno;
                         } else
@@ -321,8 +112,6 @@ void initialize_srand(void) {
 #if HAVE_SYS_AUXV_H
         const void *auxv;
 #endif
-        unsigned long k;
-
         if (srand_called)
                 return;
 
@@ -347,9 +136,6 @@ void initialize_srand(void) {
         x ^= (unsigned) now(CLOCK_REALTIME);
         x ^= (unsigned) gettid();
 
-        if (rdrand(&k) >= 0)
-                x ^= (unsigned) k;
-
         srand(x);
         srand_called = true;
 
@@ -403,11 +189,8 @@ void random_bytes(void *p, size_t n) {
          *
          * What this function will do:
          *
-         *         • This function will preferably use the CPU's RDRAND operation, if it is available, in
-         *           order to return "mid-quality" random values cheaply.
-         *
-         *         • Use getrandom() with GRND_NONBLOCK, to return high-quality random values if they are
-         *           cheaply available.
+         *         • Use getrandom(GRND_INSECURE) or /dev/urandom, to return high-quality random values if
+         *           they are cheaply available, or less high-quality random values if they are not.
          *
          *         • This function will return pseudo-random data, generated via libc rand() if nothing
          *           better is available.
@@ -430,7 +213,7 @@ void random_bytes(void *p, size_t n) {
          * This function is hence not useful for generating UUIDs or cryptographic key material.
          */
 
-        if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND|RANDOM_ALLOW_INSECURE) >= 0)
+        if (genuine_random_bytes(p, n, 0) >= 0)
                 return;
 
         /* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
@@ -504,6 +287,7 @@ int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
 
         return 1;
 }
+#endif /* NM_IGNORED */
 
 uint64_t random_u64_range(uint64_t m) {
         uint64_t x, remainder;
@@ -523,4 +307,3 @@ uint64_t random_u64_range(uint64_t m) {
 
         return x % m;
 }
-#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/random-util.h b/src/libnm-systemd-shared/src/basic/random-util.h
index e6528ddc..ccee3279 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.h
+++ b/src/libnm-systemd-shared/src/basic/random-util.h
@@ -6,11 +6,7 @@
 #include <stdint.h>
 
 typedef enum RandomFlags {
-        RANDOM_EXTEND_WITH_PSEUDO = 1 << 0, /* If we can't get enough genuine randomness, but some, fill up the rest with pseudo-randomness */
-        RANDOM_BLOCK              = 1 << 1, /* Rather block than return crap randomness (only if the kernel supports that) */
-        RANDOM_MAY_FAIL           = 1 << 2, /* If we can't get any randomness at all, return early with -ENODATA */
-        RANDOM_ALLOW_RDRAND       = 1 << 3, /* Allow usage of the CPU RNG */
-        RANDOM_ALLOW_INSECURE     = 1 << 4, /* Allow usage of GRND_INSECURE flag to kernel's getrandom() API */
+        RANDOM_BLOCK              = 1 << 0, /* Rather block than return crap randomness (only if the kernel supports that) */
 } RandomFlags;
 
 int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */
@@ -31,10 +27,8 @@ static inline uint32_t random_u32(void) {
         return u;
 }
 
-int rdrand(unsigned long *ret);
-
 /* Some limits on the pool sizes when we deal with the kernel random pool */
-#define RANDOM_POOL_SIZE_MIN 512U
+#define RANDOM_POOL_SIZE_MIN 32U
 #define RANDOM_POOL_SIZE_MAX (10U*1024U*1024U)
 
 size_t random_pool_size(void);
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.h b/src/libnm-systemd-shared/src/basic/socket-util.h
index ddea5350..709da206 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.h
+++ b/src/libnm-systemd-shared/src/basic/socket-util.h
@@ -230,7 +230,7 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng
         ({                                                              \
                 const union sockaddr_union *__sa = &(sa);               \
                 size_t _len;                                            \
-                switch(__sa->sa.sa_family) {                            \
+                switch (__sa->sa.sa_family) {                           \
                 case AF_INET:                                           \
                         _len = sizeof(struct sockaddr_in);              \
                         break;                                          \
diff --git a/src/libnm-systemd-shared/src/basic/sort-util.h b/src/libnm-systemd-shared/src/basic/sort-util.h
index 28c06c40..52d611b8 100644
--- a/src/libnm-systemd-shared/src/basic/sort-util.h
+++ b/src/libnm-systemd-shared/src/basic/sort-util.h
@@ -16,8 +16,8 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
 
 #define typesafe_bsearch_r(k, b, n, func, userdata)                     \
         ({                                                              \
-                const typeof(b[0]) *_k = k;                             \
-                int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
+                const typeof((b)[0]) *_k = k;                           \
+                int (*_func_)(const typeof((b)[0])*, const typeof((b)[0])*, typeof(userdata)) = func; \
                 xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (comparison_userdata_fn_t) _func_, userdata); \
         })
 
@@ -36,8 +36,8 @@ static inline void* bsearch_safe(const void *key, const void *base,
 
 #define typesafe_bsearch(k, b, n, func)                                 \
         ({                                                              \
-                const typeof(b[0]) *_k = k;                             \
-                int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
+                const typeof((b)[0]) *_k = k;                           \
+                int (*_func_)(const typeof((b)[0])*, const typeof((b)[0])*) = func; \
                 bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (comparison_fn_t) _func_); \
         })
 
@@ -57,7 +57,7 @@ static inline void _qsort_safe(void *base, size_t nmemb, size_t size, comparison
  * is the prototype for the comparison function */
 #define typesafe_qsort(p, n, func)                                      \
         ({                                                              \
-                int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
+                int (*_func_)(const typeof((p)[0])*, const typeof((p)[0])*) = func; \
                 _qsort_safe((p), (n), sizeof((p)[0]), (comparison_fn_t) _func_); \
         })
 
@@ -72,7 +72,7 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, compariso
 
 #define typesafe_qsort_r(p, n, func, userdata)                          \
         ({                                                              \
-                int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
+                int (*_func_)(const typeof((p)[0])*, const typeof((p)[0])*, typeof(userdata)) = func; \
                 qsort_r_safe((p), (n), sizeof((p)[0]), (comparison_userdata_fn_t) _func_, userdata); \
         })
 #endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c
index 8126ce08..fd32f25d 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.c
+++ b/src/libnm-systemd-shared/src/basic/stat-util.c
@@ -132,17 +132,22 @@ bool null_or_empty(struct stat *st) {
         return false;
 }
 
-int null_or_empty_path(const char *fn) {
+int null_or_empty_path_with_root(const char *fn, const char *root) {
         struct stat st;
+        int r;
 
         assert(fn);
 
-        /* If we have the path, let's do an easy text comparison first. */
-        if (path_equal(fn, "/dev/null"))
+        /* A symlink to /dev/null or an empty file?
+         * When looking under root_dir, we can't expect /dev/ to be mounted,
+         * so let's see if the path is a (possibly dangling) symlink to /dev/null. */
+
+        if (path_equal_ptr(path_startswith(fn, root ?: "/"), "dev/null"))
                 return true;
 
-        if (stat(fn, &st) < 0)
-                return -errno;
+        r = chase_symlinks_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st, NULL);
+        if (r < 0)
+                return r;
 
         return null_or_empty(&st);
 }
@@ -191,8 +196,7 @@ int files_same(const char *filea, const char *fileb, int flags) {
         if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
                 return -errno;
 
-        return a.st_dev == b.st_dev &&
-               a.st_ino == b.st_ino;
+        return stat_inode_same(&a, &b);
 }
 
 bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
@@ -211,7 +215,7 @@ int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
 
         return is_fs_type(&s, magic_value);
 }
-#endif /* NM_IGNORE */
+#endif /* NM_IGNORED */
 
 int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
         struct statfs s;
@@ -222,7 +226,7 @@ int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
         return is_fs_type(&s, magic_value);
 }
 
-#if 0 /* NM_IGNORE */
+#if 0 /* NM_IGNORED */
 bool is_temporary_fs(const struct statfs *s) {
         return fs_in_group(s, FILESYSTEM_SET_TEMPORARY);
 }
@@ -257,6 +261,15 @@ int path_is_temporary_fs(const char *path) {
 
         return is_temporary_fs(&s);
 }
+
+int path_is_network_fs(const char *path) {
+        struct statfs s;
+
+        if (statfs(path, &s) < 0)
+                return -errno;
+
+        return is_network_fs(&s);
+}
 #endif /* NM_IGNORED */
 
 int stat_verify_regular(const struct stat *st) {
@@ -420,6 +433,18 @@ int proc_mounted(void) {
         return r;
 }
 
+bool stat_inode_same(const struct stat *a, const struct stat *b) {
+
+        /* Returns if the specified stat structure references the same (though possibly modified) inode. Does
+         * a thorough check, comparing inode nr, backing device and if the inode is still of the same type. */
+
+        return a && b &&
+                (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
+                ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 &&  /* same inode type */
+                a->st_dev == b->st_dev &&
+                a->st_ino == b->st_ino;
+}
+
 #if 0 /* NM_IGNORED */
 bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
 
@@ -432,14 +457,10 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
          * about contents of the file. The purpose here is to detect file contents changes, and nothing
          * else. */
 
-        return a && b &&
-                (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
-                ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 &&  /* same inode type */
+        return stat_inode_same(a, b) &&
                 a->st_mtim.tv_sec == b->st_mtim.tv_sec &&
                 a->st_mtim.tv_nsec == b->st_mtim.tv_nsec &&
                 (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
-                a->st_dev == b->st_dev &&
-                a->st_ino == b->st_ino &&
                 (!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
 }
 
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.h b/src/libnm-systemd-shared/src/basic/stat-util.h
index a566114f..37513a43 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.h
+++ b/src/libnm-systemd-shared/src/basic/stat-util.h
@@ -31,9 +31,13 @@ static inline int dir_is_populated(const char *path) {
 }
 
 bool null_or_empty(struct stat *st) _pure_;
-int null_or_empty_path(const char *fn);
+int null_or_empty_path_with_root(const char *fn, const char *root);
 int null_or_empty_fd(int fd);
 
+static inline int null_or_empty_path(const char *fn) {
+        return null_or_empty_path_with_root(fn, NULL);
+}
+
 int path_is_read_only_fs(const char *path);
 
 int files_same(const char *filea, const char *fileb, int flags);
@@ -53,6 +57,7 @@ int fd_is_temporary_fs(int fd);
 int fd_is_network_fs(int fd);
 
 int path_is_temporary_fs(const char *path);
+int path_is_network_fs(const char *path);
 
 /* Because statfs.t_type can be int on some architectures, we have to cast
  * the const magic to the type, otherwise the compiler warns about
@@ -91,6 +96,7 @@ int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret
 
 int proc_mounted(void);
 
+bool stat_inode_same(const struct stat *a, const struct stat *b);
 bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
 
 int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx);
@@ -113,3 +119,9 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
                 struct new_statx nsx;           \
         } var
 #endif
+
+static inline bool devid_set_and_equal(dev_t a, dev_t b) {
+        /* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't
+         * know" and we'll return false */
+        return a == b && a != 0;
+}
diff --git a/src/libnm-systemd-shared/src/basic/string-table.h b/src/libnm-systemd-shared/src/basic/string-table.h
index 97c1adc0..e3a26a62 100644
--- a/src/libnm-systemd-shared/src/basic/string-table.h
+++ b/src/libnm-systemd-shared/src/basic/string-table.h
@@ -113,4 +113,4 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
                         fputc_unlocked('\n', stdout);                   \
                 }                                                       \
                 funlockfile(stdout);                                    \
-        } while(false)
+        } while (false)
diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c
index 3e0faf95..f2cb80fe 100644
--- a/src/libnm-systemd-shared/src/basic/strv.c
+++ b/src/libnm-systemd-shared/src/basic/strv.c
@@ -19,8 +19,6 @@
 #include "strv.h"
 
 char* strv_find(char * const *l, const char *name) {
-        char * const *i;
-
         assert(name);
 
         STRV_FOREACH(i, l)
@@ -31,8 +29,6 @@ char* strv_find(char * const *l, const char *name) {
 }
 
 char* strv_find_case(char * const *l, const char *name) {
-        char * const *i;
-
         assert(name);
 
         STRV_FOREACH(i, l)
@@ -43,8 +39,6 @@ char* strv_find_case(char * const *l, const char *name) {
 }
 
 char* strv_find_prefix(char * const *l, const char *name) {
-        char * const *i;
-
         assert(name);
 
         STRV_FOREACH(i, l)
@@ -55,14 +49,14 @@ char* strv_find_prefix(char * const *l, const char *name) {
 }
 
 char* strv_find_startswith(char * const *l, const char *name) {
-        char * const *i, *e;
-
         assert(name);
 
         /* Like strv_find_prefix, but actually returns only the
          * suffix, not the whole item */
 
         STRV_FOREACH(i, l) {
+                char *e;
+
                 e = startswith(*i, name);
                 if (e)
                         return e;
@@ -72,18 +66,13 @@ char* strv_find_startswith(char * const *l, const char *name) {
 }
 
 char** strv_free(char **l) {
-        if (!l)
-                return NULL;
-
-        for (char **k = l; *k; k++)
+        STRV_FOREACH(k, l)
                 free(*k);
 
         return mfree(l);
 }
 
 char** strv_free_erase(char **l) {
-        char **i;
-
         STRV_FOREACH(i, l)
                 erase_and_freep(i);
 
@@ -91,32 +80,29 @@ char** strv_free_erase(char **l) {
 }
 
 char** strv_copy(char * const *l) {
-        char **r, **k;
+        _cleanup_strv_free_ char **result = NULL;
+        char **k;
 
-        k = r = new(char*, strv_length(l) + 1);
-        if (!r)
+        result = new(char*, strv_length(l) + 1);
+        if (!result)
                 return NULL;
 
-        if (l)
-                for (; *l; k++, l++) {
-                        *k = strdup(*l);
-                        if (!*k) {
-                                strv_free(r);
-                                return NULL;
-                        }
-                }
+        k = result;
+        STRV_FOREACH(i, l) {
+                *k = strdup(*i);
+                if (!*k)
+                        return NULL;
+                k++;
+        }
 
         *k = NULL;
-        return r;
+        return TAKE_PTR(result);
 }
 
 size_t strv_length(char * const *l) {
         size_t n = 0;
 
-        if (!l)
-                return 0;
-
-        for (; *l; l++)
+        STRV_FOREACH(i, l)
                 n++;
 
         return n;
@@ -173,8 +159,8 @@ char** strv_new_internal(const char *x, ...) {
 }
 
 int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
-        char * const *s, **t;
         size_t p, q, i = 0;
+        char **t;
 
         assert(a);
 
@@ -220,7 +206,6 @@ rollback:
 
 #if 0 /* NM_IGNORED */
 int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) {
-        char * const *s;
         int r;
 
         STRV_FOREACH(s, b) {
@@ -373,7 +358,6 @@ int strv_split_colon_pairs(char ***t, const char *s) {
 #endif /* NM_IGNORED */
 
 char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) {
-        char * const *s;
         char *r, *e;
         size_t n, k, m;
 
@@ -601,8 +585,6 @@ int strv_extend_front(char ***l, const char *value) {
 }
 
 char** strv_uniq(char **l) {
-        char **i;
-
         /* Drops duplicate entries. The first identical string will be
          * kept, the others dropped */
 
@@ -613,10 +595,8 @@ char** strv_uniq(char **l) {
 }
 
 bool strv_is_uniq(char * const *l) {
-        char * const *i;
-
         STRV_FOREACH(i, l)
-                if (strv_find(i+1, *i))
+                if (strv_contains(i+1, *i))
                         return false;
 
         return true;
@@ -725,7 +705,6 @@ int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
          */
 
         _cleanup_free_ char *m = NULL;
-        char * const *i;
         size_t n = 0;
 
         assert(ret);
@@ -762,8 +741,6 @@ int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
 }
 
 bool strv_overlap(char * const *a, char * const *b) {
-        char * const *i;
-
         STRV_FOREACH(i, a)
                 if (strv_contains(b, *i))
                         return true;
@@ -805,8 +782,6 @@ int strv_compare(char * const *a, char * const *b) {
 }
 
 void strv_print(char * const *l) {
-        char * const *s;
-
         STRV_FOREACH(s, l)
                 puts(*s);
 }
@@ -841,8 +816,6 @@ char** strv_reverse(char **l) {
 
 #if 0 /* NM_IGNORED */
 char** strv_shell_escape(char **l, const char *bad) {
-        char **s;
-
         /* Escapes every character in every string in l that is in bad,
          * edits in-place, does not roll-back on error. */
 
@@ -926,7 +899,6 @@ rollback:
 
 int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
         bool b = false;
-        char * const *s;
         int r;
 
         /* Like fputs(), but for strv, and with a less stupid argument order */
diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h
index 092d40c8..2a858326 100644
--- a/src/libnm-systemd-shared/src/basic/strv.h
+++ b/src/libnm-systemd-shared/src/basic/strv.h
@@ -122,19 +122,30 @@ static inline int strv_from_nulstr(char ***a, const char *nulstr) {
 
 bool strv_overlap(char * const *a, char * const *b) _pure_;
 
+#define _STRV_FOREACH(s, l, i)                                          \
+        for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++)
+
 #define STRV_FOREACH(s, l)                      \
-        for ((s) = (l); (s) && *(s); (s)++)
+        _STRV_FOREACH(s, l, UNIQ_T(i, UNIQ))
+
+#define _STRV_FOREACH_BACKWARDS(s, l, h, i)                             \
+        for (typeof(*(l)) *s, *h = (l), *i = ({                         \
+                                size_t _len = strv_length(h);           \
+                                _len > 0 ? h + _len - 1 : NULL;         \
+                        });                                             \
+             (s = i);                                                   \
+             i = PTR_SUB1(i, h))
+
+#define STRV_FOREACH_BACKWARDS(s, l)                                    \
+        _STRV_FOREACH_BACKWARDS(s, l, UNIQ_T(h, UNIQ), UNIQ_T(i, UNIQ))
 
-#define STRV_FOREACH_BACKWARDS(s, l)                                \
-        for (s = ({                                                 \
-                        typeof(l) _l = l;                           \
-                        _l ? _l + strv_length(_l) - 1U : NULL;      \
-                        });                                         \
-             (l) && ((s) >= (l));                                   \
-             (s)--)
+#define _STRV_FOREACH_PAIR(x, y, l, i)                          \
+        for (typeof(*l) *x, *y, *i = (l);                       \
+             i && *(x = i) && *(y = i + 1);                     \
+             i += 2)
 
-#define STRV_FOREACH_PAIR(x, y, l)               \
-        for ((x) = (l), (y) = (x) ? (x+1) : NULL; (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
+#define STRV_FOREACH_PAIR(x, y, l)                      \
+        _STRV_FOREACH_PAIR(x, y, l, UNIQ_T(i, UNIQ))
 
 char** strv_sort(char **l);
 void strv_print(char * const *l);
@@ -185,7 +196,7 @@ void strv_print(char * const *l);
 #define STARTSWITH_SET(p, ...)                                  \
         ({                                                      \
                 const char *_p = (p);                           \
-                char  *_found = NULL, **_i;                     \
+                char *_found = NULL;                            \
                 STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) {      \
                         _found = startswith(_p, *_i);           \
                         if (_found)                             \
@@ -197,7 +208,7 @@ void strv_print(char * const *l);
 #define ENDSWITH_SET(p, ...)                                    \
         ({                                                      \
                 const char *_p = (p);                           \
-                char  *_found = NULL, **_i;                     \
+                char *_found = NULL;                            \
                 STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) {      \
                         _found = endswith(_p, *_i);             \
                         if (_found)                             \
@@ -207,7 +218,7 @@ void strv_print(char * const *l);
         })
 
 #define _FOREACH_STRING(uniq, x, y, ...)                                \
-        for (char **UNIQ_T(l, uniq) = STRV_MAKE(({ x = y; }), ##__VA_ARGS__); \
+        for (const char *x, * const*UNIQ_T(l, uniq) = STRV_MAKE_CONST(({ x = y; }), ##__VA_ARGS__); \
              x;                                                         \
              x = *(++UNIQ_T(l, uniq)))
 
diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c
index d7ea2b38..8476a650 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.c
+++ b/src/libnm-systemd-shared/src/basic/time-util.c
@@ -79,7 +79,7 @@ triple_timestamp* triple_timestamp_get(triple_timestamp *ts) {
 
         ts->realtime = now(CLOCK_REALTIME);
         ts->monotonic = now(CLOCK_MONOTONIC);
-        ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY;
+        ts->boottime = now(CLOCK_BOOTTIME);
 
         return ts;
 }
@@ -128,7 +128,7 @@ usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock) {
 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
         assert(ts);
 
-        if (u == USEC_INFINITY || u == 0) {
+        if (!timestamp_is_set(u)) {
                 ts->realtime = ts->monotonic = u;
                 return ts;
         }
@@ -143,7 +143,7 @@ triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u)
 
         assert(ts);
 
-        if (u == USEC_INFINITY || u == 0) {
+        if (!timestamp_is_set(u)) {
                 ts->realtime = ts->monotonic = ts->boottime = u;
                 return ts;
         }
@@ -152,9 +152,7 @@ triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u)
 
         ts->realtime = u;
         ts->monotonic = map_clock_usec_internal(u, nowr, now(CLOCK_MONOTONIC));
-        ts->boottime = clock_boottime_supported() ?
-                map_clock_usec_internal(u, nowr, now(CLOCK_BOOTTIME)) :
-                USEC_INFINITY;
+        ts->boottime = map_clock_usec_internal(u, nowr, now(CLOCK_BOOTTIME));
 
         return ts;
 }
@@ -172,8 +170,7 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
         return ts;
 }
 
-dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
-        clockid_t cid;
+dual_timestamp* dual_timestamp_from_boottime(dual_timestamp *ts, usec_t u) {
         usec_t nowm;
 
         if (u == USEC_INFINITY) {
@@ -181,14 +178,8 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us
                 return ts;
         }
 
-        cid = clock_boottime_or_monotonic();
-        nowm = now(cid);
-
-        if (cid == CLOCK_MONOTONIC)
-                ts->monotonic = u;
-        else
-                ts->monotonic = map_clock_usec_internal(u, nowm, now(CLOCK_MONOTONIC));
-
+        nowm = now(CLOCK_BOOTTIME);
+        ts->monotonic = map_clock_usec_internal(u, nowm, now(CLOCK_MONOTONIC));
         ts->realtime = map_clock_usec_internal(u, nowm, now(CLOCK_REALTIME));
         return ts;
 }
@@ -323,11 +314,13 @@ char *format_timestamp_style(
         time_t sec;
         size_t n;
         bool utc = false, us = false;
+        int r;
 
         assert(buf);
 
         switch (style) {
                 case TIMESTAMP_PRETTY:
+                case TIMESTAMP_UNIX:
                         break;
                 case TIMESTAMP_US:
                         us = true;
@@ -350,9 +343,17 @@ char *format_timestamp_style(
                           1 + 1 +              /* space and shortest possible zone */
                           1))
                 return NULL; /* Not enough space even for the shortest form. */
-        if (t <= 0 || t == USEC_INFINITY)
+        if (!timestamp_is_set(t))
                 return NULL; /* Timestamp is unset */
 
+        if (style == TIMESTAMP_UNIX) {
+                r = snprintf(buf, l, "@" USEC_FMT, t / USEC_PER_SEC);  /* round down µs → s */
+                if (r < 0 || (size_t) r >= l)
+                        return NULL; /* Doesn't fit */
+
+                return buf;
+        }
+
         /* Let's not format times with years > 9999 */
         if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) {
                 assert(l >= STRLEN("--- XXXX-XX-XX XX:XX:XX") + 1);
@@ -420,7 +421,7 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
         const char *s;
         usec_t n, d;
 
-        if (t <= 0 || t == USEC_INFINITY)
+        if (!timestamp_is_set(t))
                 return NULL;
 
         n = now(CLOCK_REALTIME);
@@ -793,6 +794,16 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
                         goto from_tm;
         }
 
+        /* Support OUTPUT_SHORT and OUTPUT_SHORT_PRECISE formats */
+        tm = copy;
+        k = strptime(t, "%b %d %H:%M:%S", &tm);
+        if (k) {
+                if (*k == '.')
+                        goto parse_usec;
+                else if (*k == 0)
+                        goto from_tm;
+        }
+
         tm = copy;
         k = strptime(t, "%y-%m-%d %H:%M", &tm);
         if (k && *k == 0) {
@@ -1447,33 +1458,6 @@ int verify_timezone(const char *name, int log_level) {
         return 0;
 }
 
-bool clock_boottime_supported(void) {
-        static int supported = -1;
-
-        /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
-
-        if (supported < 0) {
-                int fd;
-
-                fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
-                if (fd < 0)
-                        supported = false;
-                else {
-                        safe_close(fd);
-                        supported = true;
-                }
-        }
-
-        return supported;
-}
-
-clockid_t clock_boottime_or_monotonic(void) {
-        if (clock_boottime_supported())
-                return CLOCK_BOOTTIME;
-        else
-                return CLOCK_MONOTONIC;
-}
-
 bool clock_supported(clockid_t clock) {
         struct timespec ts;
 
@@ -1481,16 +1465,10 @@ bool clock_supported(clockid_t clock) {
 
         case CLOCK_MONOTONIC:
         case CLOCK_REALTIME:
-                return true;
-
         case CLOCK_BOOTTIME:
-                return clock_boottime_supported();
-
-        case CLOCK_BOOTTIME_ALARM:
-                if (!clock_boottime_supported())
-                        return false;
+                /* These three are always available in our baseline, and work in timerfd, as of kernel 3.15 */
+                return true;
 
-                _fallthrough_;
         default:
                 /* For everything else, check properly */
                 return clock_gettime(clock, &ts) >= 0;
@@ -1639,6 +1617,7 @@ static const char* const timestamp_style_table[_TIMESTAMP_STYLE_MAX] = {
         [TIMESTAMP_US] = "us",
         [TIMESTAMP_UTC] = "utc",
         [TIMESTAMP_US_UTC] = "us+utc",
+        [TIMESTAMP_UNIX] = "unix",
 };
 
 /* Use the macro for enum → string to allow for aliases */
diff --git a/src/libnm-systemd-shared/src/basic/time-util.h b/src/libnm-systemd-shared/src/basic/time-util.h
index 895af882..bf312442 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.h
+++ b/src/libnm-systemd-shared/src/basic/time-util.h
@@ -34,6 +34,7 @@ typedef enum TimestampStyle {
         TIMESTAMP_US,
         TIMESTAMP_UTC,
         TIMESTAMP_US_UTC,
+        TIMESTAMP_UNIX,
         _TIMESTAMP_STYLE_MAX,
         _TIMESTAMP_STYLE_INVALID = -EINVAL,
 } TimestampStyle;
@@ -81,7 +82,7 @@ usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock);
 dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u);
-dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u);
+dual_timestamp* dual_timestamp_from_boottime(dual_timestamp *ts, usec_t u);
 
 triple_timestamp* triple_timestamp_get(triple_timestamp *ts);
 triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u);
@@ -114,9 +115,13 @@ nsec_t timespec_load_nsec(const struct timespec *ts) _pure_;
 struct timespec* timespec_store(struct timespec *ts, usec_t u);
 struct timespec* timespec_store_nsec(struct timespec *ts, nsec_t n);
 
+#define TIMESPEC_STORE(u) timespec_store(&(struct timespec) {}, (u))
+
 usec_t timeval_load(const struct timeval *tv) _pure_;
 struct timeval* timeval_store(struct timeval *tv, usec_t u);
 
+#define TIMEVAL_STORE(u) timeval_store(&(struct timeval) {}, (u))
+
 char* format_timestamp_style(char *buf, size_t l, usec_t t, TimestampStyle style) _warn_unused_result_;
 char* format_timestamp_relative(char *buf, size_t l, usec_t t) _warn_unused_result_;
 char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) _warn_unused_result_;
@@ -150,9 +155,7 @@ static inline bool timezone_is_valid(const char *name, int log_level) {
         return verify_timezone(name, log_level) >= 0;
 }
 
-bool clock_boottime_supported(void);
 bool clock_supported(clockid_t clock);
-clockid_t clock_boottime_or_monotonic(void);
 
 usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to);
 
diff --git a/src/libnm-systemd-shared/src/basic/tmpfile-util.c b/src/libnm-systemd-shared/src/basic/tmpfile-util.c
index dc5a49e2..57447a42 100644
--- a/src/libnm-systemd-shared/src/basic/tmpfile-util.c
+++ b/src/libnm-systemd-shared/src/basic/tmpfile-util.c
@@ -280,6 +280,28 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
         return fd;
 }
 
+int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE **ret_file) {
+        _cleanup_free_ char *path = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_close_ int fd = -1;
+
+        assert(target);
+        assert(ret_file);
+        assert(ret_path);
+
+        fd = open_tmpfile_linkable(target, flags, &path);
+        if (fd < 0)
+                return fd;
+
+        f = take_fdopen(&fd, "w");
+        if (!f)
+                return -ENOMEM;
+
+        *ret_path = TAKE_PTR(path);
+        *ret_file = TAKE_PTR(f);
+        return 0;
+}
+
 int link_tmpfile(int fd, const char *path, const char *target) {
         assert(fd >= 0);
         assert(target);
@@ -297,6 +319,23 @@ int link_tmpfile(int fd, const char *path, const char *target) {
         return RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), AT_FDCWD, target, AT_SYMLINK_FOLLOW));
 }
 
+int flink_tmpfile(FILE *f, const char *path, const char *target) {
+        int fd, r;
+
+        assert(f);
+        assert(target);
+
+        fd = fileno(f);
+        if (fd < 0) /* Not all FILE* objects encapsulate fds */
+                return -EBADF;
+
+        r = fflush_sync_and_check(f);
+        if (r < 0)
+                return r;
+
+        return link_tmpfile(fd, path, target);
+}
+
 int mkdtemp_malloc(const char *template, char **ret) {
         _cleanup_free_ char *p = NULL;
         int r;
diff --git a/src/libnm-systemd-shared/src/basic/tmpfile-util.h b/src/libnm-systemd-shared/src/basic/tmpfile-util.h
index 45255fc0..610cbaf8 100644
--- a/src/libnm-systemd-shared/src/basic/tmpfile-util.h
+++ b/src/libnm-systemd-shared/src/basic/tmpfile-util.h
@@ -13,7 +13,9 @@ int tempfn_random_child(const char *p, const char *extra, char **ret);
 
 int open_tmpfile_unlinkable(const char *directory, int flags);
 int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
+int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE **ret_file);
 
 int link_tmpfile(int fd, const char *path, const char *target);
+int flink_tmpfile(FILE *f, const char *path, const char *target);
 
 int mkdtemp_malloc(const char *template, char **ret);
diff --git a/src/libnm-systemd-shared/src/basic/util.h b/src/libnm-systemd-shared/src/basic/util.h
index dd1cb4f3..368e3e4f 100644
--- a/src/libnm-systemd-shared/src/basic/util.h
+++ b/src/libnm-systemd-shared/src/basic/util.h
@@ -9,6 +9,12 @@ extern int saved_argc;
 extern char **saved_argv;
 
 static inline void save_argc_argv(int argc, char **argv) {
+
+        /* Protect against CVE-2021-4034 style attacks */
+        assert_se(argc > 0);
+        assert_se(argv);
+        assert_se(argv[0]);
+
         saved_argc = argc;
         saved_argv = argv;
 }
diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
index d597c743..1c198f6a 100644
--- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
+++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
@@ -53,14 +53,16 @@
 #define CONCATENATE(x, y) XCONCATENATE(x, y)
 
 #ifdef SD_BOOT
+        void efi_assert(const char *expr, const char *file, unsigned line, const char *function) _noreturn_;
+
         #ifdef NDEBUG
                 #define assert(expr)
                 #define assert_not_reached() __builtin_unreachable()
         #else
-                void efi_assert(const char *expr, const char *file, unsigned line, const char *function) _noreturn_;
                 #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
                 #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__)
         #endif
+        #define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
 
         #define memcpy(a, b, c) CopyMem((a), (b), (c))
         #define free(a) FreePool(a)
@@ -74,6 +76,13 @@
                 _expr_;                         \
         })
 
+#define ASSERT_SE_PTR(expr)                     \
+        ({                                      \
+                typeof(expr) _expr_ = (expr);   \
+                assert_se(_expr_);              \
+                _expr_;                         \
+        })
+
 #if defined(static_assert)
 #define assert_cc(expr)                                                 \
         static_assert(expr, #expr)
@@ -243,23 +252,23 @@
                                CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
                    (CASE_F,__VA_ARGS__)
 
-#define IN_SET(x, ...)                          \
-        ({                                      \
-                sd_bool _found = sd_false;      \
+#define IN_SET(x, ...)                                                  \
+        ({                                                              \
+                sd_bool _found = sd_false;                              \
                 /* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as  \
                  * type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
                  * the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that  \
                  * doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */         \
                 static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \
-                assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
-                switch(x) {                     \
-                FOR_EACH_MAKE_CASE(__VA_ARGS__) \
-                        _found = sd_true;       \
-                        break;                  \
-                default:                        \
-                        break;                  \
-                }                               \
-                _found;                         \
+                assert_cc(ELEMENTSOF(__assert_in_set) <= 20);           \
+                switch (x) {                                            \
+                FOR_EACH_MAKE_CASE(__VA_ARGS__)                         \
+                        _found = sd_true;                               \
+                       break;                                           \
+                default:                                                \
+                        break;                                          \
+                }                                                       \
+                _found;                                                 \
         })
 
 /* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.c b/src/libnm-systemd-shared/src/shared/dns-domain.c
index b82a9a1c..e932b693 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.c
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.c
@@ -171,24 +171,18 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
 
         /* Skip current terminal character (and accept domain names ending it ".") */
         if (*terminal == 0)
-                terminal--;
+                terminal = PTR_SUB1(terminal, name);
         if (terminal >= name && *terminal == '.')
-                terminal--;
+                terminal = PTR_SUB1(terminal, name);
 
         /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
-        for (;;) {
-                if (terminal < name) {
-                        /* Reached the first label, so indicate that there are no more */
-                        terminal = NULL;
-                        break;
-                }
-
+        while (terminal) {
                 /* Find the start of the last label */
                 if (*terminal == '.') {
                         const char *y;
                         unsigned slashes = 0;
 
-                        for (y = terminal - 1; y >= name && *y == '\\'; y--)
+                        for (y = PTR_SUB1(terminal, name); y && *y == '\\'; y = PTR_SUB1(y, name))
                                 slashes++;
 
                         if (slashes % 2 == 0) {
@@ -201,7 +195,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
                         }
                 }
 
-                terminal--;
+                terminal = PTR_SUB1(terminal, name);
         }
 
         r = dns_label_unescape(&name, dest, sz, 0);
@@ -1424,4 +1418,19 @@ int dns_name_dot_suffixed(const char *name) {
                         return false;
         }
 }
+
+bool dns_name_dont_resolve(const char *name) {
+
+        /* Never respond to some of the domains listed in RFC6303 */
+        if (dns_name_endswith(name, "0.in-addr.arpa") > 0 ||
+            dns_name_equal(name, "255.255.255.255.in-addr.arpa") > 0 ||
+            dns_name_equal(name, "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0)
+                return true;
+
+        /* Never respond to some of the domains listed in RFC6761 */
+        if (dns_name_endswith(name, "invalid") > 0)
+                return true;
+
+        return false;
+}
 #endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.h b/src/libnm-systemd-shared/src/shared/dns-domain.h
index c237f761..ec174c0e 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.h
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.h
@@ -105,3 +105,5 @@ int dns_name_apply_idna(const char *name, char **ret);
 int dns_name_is_valid_or_address(const char *name);
 
 int dns_name_dot_suffixed(const char *name);
+
+bool dns_name_dont_resolve(const char *name);