summary refs log tree commit diff
path: root/src/libnm-systemd-shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-systemd-shared')
-rw-r--r--src/libnm-systemd-shared/meson.build6
-rw-r--r--src/libnm-systemd-shared/sd-adapt-shared/dns-resolver-internal.h3
-rw-r--r--src/libnm-systemd-shared/sd-adapt-shared/keyring-util.h3
-rw-r--r--src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h5
-rw-r--r--src/libnm-systemd-shared/sd-adapt-shared/syslog-util.h3
-rw-r--r--src/libnm-systemd-shared/src/basic/alloc-util.c11
-rw-r--r--src/libnm-systemd-shared/src/basic/alloc-util.h19
-rw-r--r--src/libnm-systemd-shared/src/basic/arphrd-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/bitfield.h73
-rw-r--r--src/libnm-systemd-shared/src/basic/cgroup-util.h48
-rw-r--r--src/libnm-systemd-shared/src/basic/chase.h8
-rw-r--r--src/libnm-systemd-shared/src/basic/chattr-util.c176
-rw-r--r--src/libnm-systemd-shared/src/basic/chattr-util.h64
-rw-r--r--src/libnm-systemd-shared/src/basic/constants.h14
-rw-r--r--src/libnm-systemd-shared/src/basic/devnum-util.c11
-rw-r--r--src/libnm-systemd-shared/src/basic/env-util.c54
-rw-r--r--src/libnm-systemd-shared/src/basic/env-util.h7
-rw-r--r--src/libnm-systemd-shared/src/basic/errno-util.h11
-rw-r--r--src/libnm-systemd-shared/src/basic/escape.c12
-rw-r--r--src/libnm-systemd-shared/src/basic/ether-addr-util.c2
-rw-r--r--src/libnm-systemd-shared/src/basic/ether-addr-util.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.c192
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.h16
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.c235
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.h42
-rw-r--r--src/libnm-systemd-shared/src/basic/format-ifname.c39
-rw-r--r--src/libnm-systemd-shared/src/basic/format-ifname.h27
-rw-r--r--src/libnm-systemd-shared/src/basic/format-util.c51
-rw-r--r--src/libnm-systemd-shared/src/basic/format-util.h28
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.c363
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.h50
-rw-r--r--src/libnm-systemd-shared/src/basic/glyph-util.c6
-rw-r--r--src/libnm-systemd-shared/src/basic/glyph-util.h10
-rw-r--r--src/libnm-systemd-shared/src/basic/hashmap.c20
-rw-r--r--src/libnm-systemd-shared/src/basic/hashmap.h5
-rw-r--r--src/libnm-systemd-shared/src/basic/hexdecoct.c25
-rw-r--r--src/libnm-systemd-shared/src/basic/hexdecoct.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.c81
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.h21
-rw-r--r--src/libnm-systemd-shared/src/basic/inotify-util.c14
-rw-r--r--src/libnm-systemd-shared/src/basic/iovec-util.h35
-rw-r--r--src/libnm-systemd-shared/src/basic/label.c11
-rw-r--r--src/libnm-systemd-shared/src/basic/label.h6
-rw-r--r--src/libnm-systemd-shared/src/basic/locale-util.c3
-rw-r--r--src/libnm-systemd-shared/src/basic/lock-util.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/log.h59
-rw-r--r--src/libnm-systemd-shared/src/basic/macro.h69
-rw-r--r--src/libnm-systemd-shared/src/basic/memory-util.h11
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_fcntl.h8
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_pidfd.h48
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_random.h16
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_socket.h55
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_syscall.h80
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_threads.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_type.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_wait.h12
-rw-r--r--src/libnm-systemd-shared/src/basic/namespace-util.h51
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.c19
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.c137
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.h60
-rw-r--r--src/libnm-systemd-shared/src/basic/pidfd-util.c279
-rw-r--r--src/libnm-systemd-shared/src/basic/pidfd-util.h21
-rw-r--r--src/libnm-systemd-shared/src/basic/pidref.h78
-rw-r--r--src/libnm-systemd-shared/src/basic/prioq.c25
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.c551
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.h63
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.c114
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/ratelimit.c28
-rw-r--r--src/libnm-systemd-shared/src/basic/ratelimit.h6
-rw-r--r--src/libnm-systemd-shared/src/basic/sha256.c52
-rw-r--r--src/libnm-systemd-shared/src/basic/sha256.h16
-rw-r--r--src/libnm-systemd-shared/src/basic/signal-util.c41
-rw-r--r--src/libnm-systemd-shared/src/basic/signal-util.h21
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.c99
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.h15
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.c138
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.h23
-rw-r--r--src/libnm-systemd-shared/src/basic/stdio-util.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/string-table.h13
-rw-r--r--src/libnm-systemd-shared/src/basic/string-util.c285
-rw-r--r--src/libnm-systemd-shared/src/basic/string-util.h120
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.c286
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.h18
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.c180
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.h18
-rw-r--r--src/libnm-systemd-shared/src/basic/tmpfile-util.c63
-rw-r--r--src/libnm-systemd-shared/src/basic/tmpfile-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/user-util.h34
-rw-r--r--src/libnm-systemd-shared/src/basic/utf8.c79
-rw-r--r--src/libnm-systemd-shared/src/basic/utf8.h23
-rw-r--r--src/libnm-systemd-shared/src/fundamental/iovec-util-fundamental.h37
-rw-r--r--src/libnm-systemd-shared/src/fundamental/macro-fundamental.h85
-rw-r--r--src/libnm-systemd-shared/src/fundamental/sha256-fundamental.c (renamed from src/libnm-systemd-shared/src/fundamental/sha256.c)10
-rw-r--r--src/libnm-systemd-shared/src/fundamental/sha256-fundamental.h (renamed from src/libnm-systemd-shared/src/fundamental/sha256.h)0
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.c158
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.h2
98 files changed, 3696 insertions, 1752 deletions
diff --git a/src/libnm-systemd-shared/meson.build b/src/libnm-systemd-shared/meson.build
index c93930f3..7a88d78d 100644
--- a/src/libnm-systemd-shared/meson.build
+++ b/src/libnm-systemd-shared/meson.build
@@ -5,6 +5,7 @@ libnm_systemd_shared = static_library(
   sources: files(
     'nm-sd-utils-shared.c',
     'src/basic/alloc-util.c',
+    'src/basic/chattr-util.c',
     'src/basic/btrfs.c',
     'src/basic/devnum-util.c',
     'src/basic/env-file.c',
@@ -14,6 +15,7 @@ libnm_systemd_shared = static_library(
     'src/basic/extract-word.c',
     'src/basic/fd-util.c',
     'src/basic/fileio.c',
+    'src/basic/format-ifname.c',
     'src/basic/format-util.c',
     'src/basic/fs-util.c',
     'src/basic/glyph-util.c',
@@ -31,10 +33,12 @@ libnm_systemd_shared = static_library(
     'src/basic/ordered-set.c',
     'src/basic/parse-util.c',
     'src/basic/path-util.c',
+    'src/basic/pidfd-util.c',
     'src/basic/prioq.c',
     'src/basic/process-util.c',
     'src/basic/random-util.c',
     'src/basic/ratelimit.c',
+    'src/basic/sha256.c',
     'src/basic/signal-util.c',
     'src/basic/socket-util.c',
     'src/basic/stat-util.c',
@@ -45,7 +49,7 @@ libnm_systemd_shared = static_library(
     'src/basic/time-util.c',
     'src/basic/tmpfile-util.c',
     'src/basic/utf8.c',
-    'src/fundamental/sha256.c',
+    'src/fundamental/sha256-fundamental.c',
     'src/fundamental/string-util-fundamental.c',
     'src/shared/dns-domain.c',
     'src/shared/web-util.c',
diff --git a/src/libnm-systemd-shared/sd-adapt-shared/dns-resolver-internal.h b/src/libnm-systemd-shared/sd-adapt-shared/dns-resolver-internal.h
new file mode 100644
index 00000000..637892c2
--- /dev/null
+++ b/src/libnm-systemd-shared/sd-adapt-shared/dns-resolver-internal.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/libnm-systemd-shared/sd-adapt-shared/keyring-util.h b/src/libnm-systemd-shared/sd-adapt-shared/keyring-util.h
new file mode 100644
index 00000000..637892c2
--- /dev/null
+++ b/src/libnm-systemd-shared/sd-adapt-shared/keyring-util.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h b/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h
index 83916fb2..e2fd27b8 100644
--- a/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h
+++ b/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h
@@ -116,6 +116,11 @@ raw_getpid(void)
 #define ALTIFNAMSIZ 128
 #endif
 
+/* kernel cb12fd8e0dabb9a1c8aef55a6a41e2c255fcdf4b (6.8) */
+#ifndef PID_FS_MAGIC
+#define PID_FS_MAGIC 0x50494446
+#endif
+
 #define HAVE_LINUX_TIME_TYPES_H 0
 
 #ifndef __COMPAR_FN_T
diff --git a/src/libnm-systemd-shared/sd-adapt-shared/syslog-util.h b/src/libnm-systemd-shared/sd-adapt-shared/syslog-util.h
new file mode 100644
index 00000000..637892c2
--- /dev/null
+++ b/src/libnm-systemd-shared/sd-adapt-shared/syslog-util.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.c b/src/libnm-systemd-shared/src/basic/alloc-util.c
index 243ff521..f9686666 100644
--- a/src/libnm-systemd-shared/src/basic/alloc-util.c
+++ b/src/libnm-systemd-shared/src/basic/alloc-util.c
@@ -45,7 +45,7 @@ void* greedy_realloc(
                 size_t need,
                 size_t size) {
 
-        size_t a, newalloc;
+        size_t newalloc;
         void *q;
 
         assert(p);
@@ -62,14 +62,13 @@ void* greedy_realloc(
                 return NULL;
         newalloc = need * 2;
 
-        if (size_multiply_overflow(newalloc, size))
+        if (!MUL_ASSIGN_SAFE(&newalloc, size))
                 return NULL;
-        a = newalloc * size;
 
-        if (a < 64) /* Allocate at least 64 bytes */
-                a = 64;
+        if (newalloc < 64) /* Allocate at least 64 bytes */
+                newalloc = 64;
 
-        q = realloc(*p, a);
+        q = realloc(*p, newalloc);
         if (!q)
                 return NULL;
 
diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.h b/src/libnm-systemd-shared/src/basic/alloc-util.h
index c215c33f..ba712982 100644
--- a/src/libnm-systemd-shared/src/basic/alloc-util.h
+++ b/src/libnm-systemd-shared/src/basic/alloc-util.h
@@ -26,23 +26,23 @@ typedef void* (*mfree_func_t)(void *p);
 
 #define alloca_safe(n)                                                  \
         ({                                                              \
-                size_t _nn_ = n;                                        \
+                size_t _nn_ = (n);                                      \
                 assert(_nn_ <= ALLOCA_MAX);                             \
                 alloca(_nn_ == 0 ? 1 : _nn_);                           \
         })                                                              \
 
 #define newa(t, n)                                                      \
         ({                                                              \
-                size_t _n_ = n;                                         \
-                assert(!size_multiply_overflow(sizeof(t), _n_));        \
-                (t*) alloca_safe(sizeof(t)*_n_);                        \
+                size_t _n_ = (n);                                       \
+                assert_se(MUL_ASSIGN_SAFE(&_n_, sizeof(t)));            \
+                (t*) alloca_safe(_n_);                                  \
         })
 
 #define newa0(t, n)                                                     \
         ({                                                              \
-                size_t _n_ = n;                                         \
-                assert(!size_multiply_overflow(sizeof(t), _n_));        \
-                (t*) alloca0((sizeof(t)*_n_));                          \
+                size_t _n_ = (n);                                       \
+                assert_se(MUL_ASSIGN_SAFE(&_n_, sizeof(t)));            \
+                (t*) alloca0(_n_);                                      \
         })
 
 #define newdup(t, p, n) ((t*) memdup_multiply(p, n, sizeof(t)))
@@ -155,7 +155,10 @@ void* greedy_realloc_append(void **p, size_t *n_p, const void *from, size_t n_fr
         greedy_realloc0((void**) &(array), (need), sizeof((array)[0]))
 
 #define GREEDY_REALLOC_APPEND(array, n_array, from, n_from)             \
-        greedy_realloc_append((void**) &(array), (size_t*) &(n_array), (from), (n_from), sizeof((array)[0]))
+        ({                                                              \
+                const typeof(*(array)) *_from_ = (from);                \
+                greedy_realloc_append((void**) &(array), &(n_array), _from_, (n_from), sizeof((array)[0])); \
+        })
 
 #define alloca0(n)                                      \
         ({                                              \
diff --git a/src/libnm-systemd-shared/src/basic/arphrd-util.h b/src/libnm-systemd-shared/src/basic/arphrd-util.h
index 33f5694a..0fd75a04 100644
--- a/src/libnm-systemd-shared/src/basic/arphrd-util.h
+++ b/src/libnm-systemd-shared/src/basic/arphrd-util.h
@@ -4,7 +4,7 @@
 #include <inttypes.h>
 #include <stddef.h>
 
-const char *arphrd_to_name(int id);
+const char* arphrd_to_name(int id);
 int arphrd_from_name(const char *name);
 
 size_t arphrd_to_hw_addr_len(uint16_t arphrd);
diff --git a/src/libnm-systemd-shared/src/basic/bitfield.h b/src/libnm-systemd-shared/src/basic/bitfield.h
new file mode 100644
index 00000000..048e08d7
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/bitfield.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "macro.h"
+
+/* Bit index (0-based) to mask of specified type. Assertion failure if index is out of range. */
+#define _INDEX_TO_MASK(type, i, uniq)                                   \
+        ({                                                              \
+                int UNIQ_T(_i, uniq) = (i);                             \
+                assert(UNIQ_T(_i, uniq) < (int)sizeof(type) * 8);       \
+                ((type)1) << UNIQ_T(_i, uniq);                          \
+        })
+#define INDEX_TO_MASK(type, i)                                          \
+        ({                                                              \
+                assert_cc(sizeof(type) <= sizeof(unsigned long long));  \
+                assert_cc(__builtin_choose_expr(__builtin_constant_p(i), i, 0) < (int)(sizeof(type) * 8)); \
+                __builtin_choose_expr(__builtin_constant_p(i),          \
+                                      ((type)1) << (i),                 \
+                                      _INDEX_TO_MASK(type, i, UNIQ));   \
+        })
+
+/* Builds a mask of specified type with multiple bits set. Note the result will not be constant, even if all
+ * indexes are constant. */
+#define INDEXES_TO_MASK(type, ...)                              \
+        UNIQ_INDEXES_TO_MASK(type, UNIQ, ##__VA_ARGS__)
+#define UNIQ_INDEXES_TO_MASK(type, uniq, ...)                           \
+        ({                                                              \
+                typeof(type) UNIQ_T(_mask, uniq) = (type)0;             \
+                int UNIQ_T(_i, uniq);                                   \
+                FOREACH_ARGUMENT(UNIQ_T(_i, uniq), ##__VA_ARGS__)       \
+                        UNIQ_T(_mask, uniq) |= INDEX_TO_MASK(type, UNIQ_T(_i, uniq)); \
+                UNIQ_T(_mask, uniq);                                    \
+        })
+
+/* Same as the FLAG macros, but accept a 0-based bit index instead of a mask. Results in assertion failure if
+ * index is out of range for the type. */
+#define SET_BIT(bits, i) SET_FLAG(bits, INDEX_TO_MASK(typeof(bits), i), true)
+#define CLEAR_BIT(bits, i) SET_FLAG(bits, INDEX_TO_MASK(typeof(bits), i), false)
+#define BIT_SET(bits, i) FLAGS_SET(bits, INDEX_TO_MASK(typeof(bits), i))
+
+/* As above, but accepts multiple indexes. Note the result will not be constant, even if all indexes are
+ * constant. */
+#define SET_BITS(bits, ...) SET_FLAG(bits, INDEXES_TO_MASK(typeof(bits), ##__VA_ARGS__), true)
+#define CLEAR_BITS(bits, ...) SET_FLAG(bits, INDEXES_TO_MASK(typeof(bits), ##__VA_ARGS__), false)
+#define BITS_SET(bits, ...) FLAGS_SET(bits, INDEXES_TO_MASK(typeof(bits), ##__VA_ARGS__))
+
+/* Iterate through each set bit. Index is 0-based and type int. */
+#define BIT_FOREACH(index, bits) _BIT_FOREACH(index, bits, UNIQ)
+#define _BIT_FOREACH(index, bits, uniq)                                 \
+        for (int UNIQ_T(_last, uniq) = -1, index;                       \
+             (index = BIT_NEXT_SET(bits, UNIQ_T(_last, uniq))) >= 0;    \
+             UNIQ_T(_last, uniq) = index)
+
+/* Find the next set bit after 0-based index 'prev'. Result is 0-based index of next set bit, or -1 if no
+ * more bits are set. */
+#define BIT_FIRST_SET(bits) BIT_NEXT_SET(bits, -1)
+#define BIT_NEXT_SET(bits, prev)                        \
+        UNIQ_BIT_NEXT_SET(bits, prev, UNIQ)
+#define UNIQ_BIT_NEXT_SET(bits, prev, uniq)                             \
+        ({                                                              \
+                typeof(bits) UNIQ_T(_bits, uniq) = (bits);              \
+                int UNIQ_T(_prev, uniq) = (prev);                       \
+                int UNIQ_T(_next, uniq);                                \
+                _BIT_NEXT_SET(UNIQ_T(_bits, uniq),                      \
+                              UNIQ_T(_prev, uniq),                      \
+                              UNIQ_T(_next, uniq));                     \
+        })
+#define _BIT_NEXT_SET(bits, prev, next)                                 \
+        ((int)(prev + 1) == (int)sizeof(bits) * 8                       \
+         ? -1 /* Prev index was msb. */                                 \
+         : ((next = __builtin_ffsll(((unsigned long long)(bits)) >> (prev + 1))) == 0 \
+            ? -1 /* No more bits set. */                                \
+            : prev + next))
diff --git a/src/libnm-systemd-shared/src/basic/cgroup-util.h b/src/libnm-systemd-shared/src/basic/cgroup-util.h
index 244f3b65..77294779 100644
--- a/src/libnm-systemd-shared/src/basic/cgroup-util.h
+++ b/src/libnm-systemd-shared/src/basic/cgroup-util.h
@@ -180,20 +180,33 @@ typedef enum CGroupUnified {
  * generate paths with multiple adjacent / removed.
  */
 
+int cg_path_open(const char *controller, const char *path);
+int cg_cgroupid_open(int fsfd, uint64_t id);
+
+int cg_path_from_cgroupid(int cgroupfs_fd, uint64_t id, char **ret);
+int cg_get_cgroupid_at(int dfd, const char *path, uint64_t *ret);
+static inline int cg_path_get_cgroupid(const char *path, uint64_t *ret) {
+        return cg_get_cgroupid_at(AT_FDCWD, path, ret);
+}
+static inline int cg_fd_get_cgroupid(int fd, uint64_t *ret) {
+        return cg_get_cgroupid_at(fd, NULL, ret);
+}
+
+typedef enum CGroupFlags {
+        CGROUP_SIGCONT            = 1 << 0,
+        CGROUP_IGNORE_SELF        = 1 << 1,
+        CGROUP_DONT_SKIP_UNMAPPED = 1 << 2,
+        CGROUP_NO_PIDFD           = 1 << 3,
+} CGroupFlags;
+
 int cg_enumerate_processes(const char *controller, const char *path, FILE **ret);
-int cg_read_pid(FILE *f, pid_t *ret);
-int cg_read_pidref(FILE *f, PidRef *ret);
+int cg_read_pid(FILE *f, pid_t *ret, CGroupFlags flags);
+int cg_read_pidref(FILE *f, PidRef *ret, CGroupFlags flags);
 int cg_read_event(const char *controller, const char *path, const char *event, char **ret);
 
 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **ret);
 int cg_read_subgroup(DIR *d, char **ret);
 
-typedef enum CGroupFlags {
-        CGROUP_SIGCONT     = 1 << 0,
-        CGROUP_IGNORE_SELF = 1 << 1,
-        CGROUP_REMOVE      = 1 << 2,
-} CGroupFlags;
-
 typedef int (*cg_kill_log_func_t)(const PidRef *pid, int sig, void *userdata);
 
 int cg_kill(const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
@@ -209,8 +222,6 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
 int cg_pid_get_path(const char *controller, pid_t pid, char **ret);
 int cg_pidref_get_path(const char *controller, const PidRef *pidref, char **ret);
 
-int cg_rmdir(const char *controller, const char *path);
-
 int cg_is_threaded(const char *path);
 
 int cg_is_delegated(const char *path);
@@ -258,15 +269,11 @@ int cg_get_xattr_malloc(const char *path, const char *name, char **ret);
 int cg_get_xattr_bool(const char *path, const char *name);
 int cg_remove_xattr(const char *path, const char *name);
 
-int cg_install_release_agent(const char *controller, const char *agent);
-int cg_uninstall_release_agent(const char *controller);
-
 int cg_is_empty(const char *controller, const char *path);
 int cg_is_empty_recursive(const char *controller, const char *path);
 
 int cg_get_root_path(char **path);
 
-int cg_path_get_cgroupid(const char *path, uint64_t *ret);
 int cg_path_get_session(const char *path, char **ret_session);
 int cg_path_get_owner_uid(const char *path, uid_t *ret_uid);
 int cg_path_get_unit(const char *path, char **ret_unit);
@@ -280,7 +287,9 @@ int cg_shift_path(const char *cgroup, const char *cached_root, const char **ret_
 int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **ret_cgroup);
 
 int cg_pid_get_session(pid_t pid, char **ret_session);
+int cg_pidref_get_session(const PidRef *pidref, char **ret);
 int cg_pid_get_owner_uid(pid_t pid, uid_t *ret_uid);
+int cg_pidref_get_owner_uid(const PidRef *pidref, uid_t *ret);
 int cg_pid_get_unit(pid_t pid, char **ret_unit);
 int cg_pidref_get_unit(const PidRef *pidref, char **ret);
 int cg_pid_get_user_unit(pid_t pid, char **ret_unit);
@@ -292,14 +301,12 @@ int cg_path_decode_unit(const char *cgroup, char **ret_unit);
 
 bool cg_needs_escape(const char *p);
 int cg_escape(const char *p, char **ret);
-char *cg_unescape(const char *p) _pure_;
+char* cg_unescape(const char *p) _pure_;
 
 bool cg_controller_is_valid(const char *p);
 
 int cg_slice_to_path(const char *unit, char **ret);
 
-typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata);
-
 int cg_mask_supported(CGroupMask *ret);
 int cg_mask_supported_subtree(const char *root, CGroupMask *ret);
 int cg_mask_from_string(const char *s, CGroupMask *ret);
@@ -352,5 +359,10 @@ typedef union {
         uint8_t space[offsetof(struct file_handle, f_handle) + sizeof(uint64_t)];
 } cg_file_handle;
 
-#define CG_FILE_HANDLE_INIT { .file_handle.handle_bytes = sizeof(uint64_t) }
+#define CG_FILE_HANDLE_INIT                                     \
+        (cg_file_handle) {                                      \
+                .file_handle.handle_bytes = sizeof(uint64_t),   \
+                .file_handle.handle_type = FILEID_KERNFS,       \
+        }
+
 #define CG_FILE_HANDLE_CGROUPID(fh) (*(uint64_t*) (fh).file_handle.f_handle)
diff --git a/src/libnm-systemd-shared/src/basic/chase.h b/src/libnm-systemd-shared/src/basic/chase.h
index cfc714b9..eda7cad0 100644
--- a/src/libnm-systemd-shared/src/basic/chase.h
+++ b/src/libnm-systemd-shared/src/basic/chase.h
@@ -27,12 +27,10 @@ typedef enum ChaseFlags {
                                              * also points to the result path even if this flag is set.
                                              * When this specified, chase() will succeed with 1 even if the
                                              * file points to the last path component does not exist. */
-        CHASE_MKDIR_0755         = 1 << 11, /* Create any missing parent directories in the given path. This
-                                             * needs to be set with CHASE_NONEXISTENT and/or CHASE_PARENT.
-                                             * Note, chase_and_open() or friends always add CHASE_PARENT flag
-                                             * when internally call chase(), hence CHASE_MKDIR_0755 can be
-                                             * safely set without CHASE_NONEXISTENT and CHASE_PARENT. */
+        CHASE_MKDIR_0755         = 1 << 11, /* Create any missing directories in the given path. */
         CHASE_EXTRACT_FILENAME   = 1 << 12, /* Only return the last component of the resolved path */
+        CHASE_MUST_BE_DIRECTORY  = 1 << 13, /* Fail if returned inode fd is not a dir */
+        CHASE_MUST_BE_REGULAR    = 1 << 14, /* Fail if returned inode fd is not a regular file */
 } ChaseFlags;
 
 bool unsafe_transition(const struct stat *a, const struct stat *b);
diff --git a/src/libnm-systemd-shared/src/basic/chattr-util.c b/src/libnm-systemd-shared/src/basic/chattr-util.c
new file mode 100644
index 00000000..2a63e46d
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/chattr-util.c
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "nm-sd-adapt-shared.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <linux/fs.h>
+
+#include "bitfield.h"
+#include "chattr-util.h"
+#include "errno-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "macro.h"
+#include "string-util.h"
+
+int chattr_full(
+              int dir_fd,
+              const char *path,
+              unsigned value,
+              unsigned mask,
+              unsigned *ret_previous,
+              unsigned *ret_final,
+              ChattrApplyFlags flags) {
+
+        _cleanup_close_ int fd = -EBADF;
+        unsigned old_attr, new_attr;
+        int set_flags_errno = 0;
+        struct stat st;
+
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+
+        fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+        if (fd < 0)
+                return fd;
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        /* Explicitly check whether this is a regular file or directory. If it is anything else (such
+         * as a device node or fifo), then the ioctl will not hit the file systems but possibly
+         * drivers, where the ioctl might have different effects. Notably, DRM is using the same
+         * ioctl() number. */
+
+        if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+                return -ENOTTY;
+
+        if (mask == 0 && !ret_previous && !ret_final)
+                return 0;
+
+        if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
+                return -errno;
+
+        new_attr = (old_attr & ~mask) | (value & mask);
+        if (new_attr == old_attr) {
+                if (ret_previous)
+                        *ret_previous = old_attr;
+                if (ret_final)
+                        *ret_final = old_attr;
+                return 0;
+        }
+
+        if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) >= 0) {
+                unsigned attr;
+
+                /* Some filesystems (BTRFS) silently fail when a flag cannot be set. Let's make sure our
+                 * changes actually went through by querying the flags again and verifying they're equal to
+                 * the flags we tried to configure. */
+
+                if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
+                        return -errno;
+
+                if (new_attr == attr) {
+                        if (ret_previous)
+                                *ret_previous = old_attr;
+                        if (ret_final)
+                                *ret_final = new_attr;
+                        return 1;
+                }
+
+                /* Trigger the fallback logic. */
+                errno = EINVAL;
+        }
+
+        if ((errno != EINVAL && !ERRNO_IS_NOT_SUPPORTED(errno)) ||
+            !FLAGS_SET(flags, CHATTR_FALLBACK_BITWISE))
+                return -errno;
+
+        /* When -EINVAL is returned, we assume that incompatible attributes are simultaneously
+         * specified. E.g., compress(c) and nocow(C) attributes cannot be set to files on btrfs.
+         * As a fallback, let's try to set attributes one by one.
+         *
+         * Also, when we get EOPNOTSUPP (or a similar error code) we assume a flag might just not be
+         * supported, and we can ignore it too */
+
+        unsigned current_attr = old_attr;
+
+        BIT_FOREACH(i, mask) {
+                unsigned new_one, mask_one = 1u << i;
+
+                new_one = UPDATE_FLAG(current_attr, mask_one, FLAGS_SET(value, mask_one));
+                if (new_one == current_attr)
+                        continue;
+
+                if (ioctl(fd, FS_IOC_SETFLAGS, &new_one) < 0) {
+                        if (!ERRNO_IS_IOCTL_NOT_SUPPORTED(errno))
+                                return -errno;
+
+                        log_full_errno(FLAGS_SET(flags, CHATTR_WARN_UNSUPPORTED_FLAGS) ? LOG_WARNING : LOG_DEBUG,
+                                       errno,
+                                       "Unable to set file attribute 0x%x on %s, ignoring: %m", mask_one, strna(path));
+
+                        /* Ensures that we record whether only EOPNOTSUPP&friends are encountered, or if a more serious
+                         * error (thus worth logging at a different level, etc) was seen too. */
+                        if (set_flags_errno == 0 || !ERRNO_IS_NOT_SUPPORTED(errno))
+                                set_flags_errno = -errno;
+
+                        continue;
+                }
+
+                if (ioctl(fd, FS_IOC_GETFLAGS, &current_attr) < 0)
+                        return -errno;
+        }
+
+        if (ret_previous)
+                *ret_previous = old_attr;
+        if (ret_final)
+                *ret_final = current_attr;
+
+        /* -ENOANO indicates that some attributes cannot be set. ERRNO_IS_NOT_SUPPORTED indicates that all
+         * encountered failures were due to flags not supported by the FS, so return a specific error in
+         * that case, so callers can handle it properly (e.g.: tmpfiles.d can use debug level logging). */
+        return current_attr == new_attr ? 1 : ERRNO_IS_NOT_SUPPORTED(set_flags_errno) ? set_flags_errno : -ENOANO;
+}
+
+int read_attr_fd(int fd, unsigned *ret) {
+        struct stat st;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+                return -ENOTTY;
+
+        _cleanup_close_ int fd_close = -EBADF;
+        fd = fd_reopen_condition(fd, O_RDONLY|O_CLOEXEC|O_NOCTTY, O_PATH, &fd_close); /* drop O_PATH if it is set */
+        if (fd < 0)
+                return fd;
+
+        return RET_NERRNO(ioctl(fd, FS_IOC_GETFLAGS, ret));
+}
+
+int read_attr_at(int dir_fd, const char *path, unsigned *ret) {
+        _cleanup_close_ int fd_close = -EBADF;
+        int fd;
+
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+        assert(ret);
+
+        if (isempty(path) && dir_fd != AT_FDCWD)
+                fd = dir_fd;
+        else {
+                fd_close = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+                if (fd_close < 0)
+                        return fd_close;
+
+                fd = fd_close;
+        }
+
+        return read_attr_fd(fd, ret);
+}
diff --git a/src/libnm-systemd-shared/src/basic/chattr-util.h b/src/libnm-systemd-shared/src/basic/chattr-util.h
new file mode 100644
index 00000000..1fe38e32
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/chattr-util.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <fcntl.h>
+#include <linux/fs.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "missing_fs.h"
+
+/* The chattr() flags to apply when creating a new file *before* writing to it. In particular, flags such as
+ * FS_NOCOW_FL don't work if applied a-posteriori. All other flags are fine (or even necessary, think
+ * FS_IMMUTABLE_FL!) to apply after writing to the files. */
+#define CHATTR_EARLY_FL                         \
+        (FS_NOATIME_FL |                        \
+         FS_COMPR_FL   |                        \
+         FS_NOCOW_FL   |                        \
+         FS_NOCOMP_FL  |                        \
+         FS_PROJINHERIT_FL)
+
+#define CHATTR_ALL_FL                           \
+        (FS_NOATIME_FL      |                   \
+         FS_SYNC_FL         |                   \
+         FS_DIRSYNC_FL      |                   \
+         FS_APPEND_FL       |                   \
+         FS_COMPR_FL        |                   \
+         FS_NODUMP_FL       |                   \
+         FS_EXTENT_FL       |                   \
+         FS_IMMUTABLE_FL    |                   \
+         FS_JOURNAL_DATA_FL |                   \
+         FS_SECRM_FL        |                   \
+         FS_UNRM_FL         |                   \
+         FS_NOTAIL_FL       |                   \
+         FS_TOPDIR_FL       |                   \
+         FS_NOCOW_FL        |                   \
+         FS_PROJINHERIT_FL)
+
+typedef enum ChattrApplyFlags {
+        CHATTR_FALLBACK_BITWISE       = 1 << 0,
+        CHATTR_WARN_UNSUPPORTED_FLAGS = 1 << 1,
+} ChattrApplyFlags;
+
+int chattr_full(int dir_fd, const char *path, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, ChattrApplyFlags flags);
+static inline int chattr_at(int dir_fd, const char *path, unsigned value, unsigned mask, unsigned *previous) {
+        return chattr_full(dir_fd, path, value, mask, previous, NULL, 0);
+}
+static inline int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) {
+        return chattr_full(fd, NULL, value, mask, previous, NULL, 0);
+}
+static inline int chattr_path(const char *path, unsigned value, unsigned mask, unsigned *previous) {
+        return chattr_full(AT_FDCWD, path, value, mask, previous, NULL, 0);
+}
+
+int read_attr_fd(int fd, unsigned *ret);
+int read_attr_at(int dir_fd, const char *path, unsigned *ret);
+
+/* Combination of chattr flags, that should be appropriate for secrets stored on disk: Secure Remove +
+ * Exclusion from Dumping + Synchronous Writing (i.e. not caching in memory) + In-Place Updating (i.e. not
+ * spurious copies). */
+#define CHATTR_SECRET_FLAGS (FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL)
+
+static inline int chattr_secret(int fd, ChattrApplyFlags flags) {
+        return chattr_full(fd, NULL, CHATTR_SECRET_FLAGS, CHATTR_SECRET_FLAGS, NULL, NULL, flags|CHATTR_FALLBACK_BITWISE);
+}
diff --git a/src/libnm-systemd-shared/src/basic/constants.h b/src/libnm-systemd-shared/src/basic/constants.h
index 6bb5f3c2..93e6efbd 100644
--- a/src/libnm-systemd-shared/src/basic/constants.h
+++ b/src/libnm-systemd-shared/src/basic/constants.h
@@ -42,9 +42,6 @@
 #define DEFAULT_START_LIMIT_INTERVAL (10*USEC_PER_SEC)
 #define DEFAULT_START_LIMIT_BURST 5
 
-/* Wait for 1.5 seconds at maximum for freeze operation */
-#define FREEZE_TIMEOUT (1500 * USEC_PER_MSEC)
-
 /* The default time after which exit-on-idle services exit. This
  * should be kept lower than the watchdog timeout, because otherwise
  * the watchdog pings will keep the loop busy. */
@@ -67,18 +64,12 @@
         "/usr/local/lib/" n "\0"                \
         "/usr/lib/" n "\0"
 
-#define CONF_PATHS_USR(n)                       \
+#define CONF_PATHS(n)                           \
         "/etc/" n,                              \
         "/run/" n,                              \
         "/usr/local/lib/" n,                    \
         "/usr/lib/" n
 
-#define CONF_PATHS(n)                           \
-        CONF_PATHS_USR(n)
-
-#define CONF_PATHS_USR_STRV(n)                  \
-        STRV_MAKE(CONF_PATHS_USR(n))
-
 #define CONF_PATHS_STRV(n)                      \
         STRV_MAKE(CONF_PATHS(n))
 
@@ -94,4 +85,5 @@
 /* Path where systemd-oomd listens for varlink connections from user managers to report changes in ManagedOOM settings. */
 #define VARLINK_ADDR_PATH_MANAGED_OOM_USER "/run/systemd/oom/io.systemd.ManagedOOM"
 
-#define KERNEL_BASELINE_VERSION "4.15"
+/* Recommended baseline - see README for details */
+#define KERNEL_BASELINE_VERSION "5.7"
diff --git a/src/libnm-systemd-shared/src/basic/devnum-util.c b/src/libnm-systemd-shared/src/basic/devnum-util.c
index b13c9fc6..f2c7c2d9 100644
--- a/src/libnm-systemd-shared/src/basic/devnum-util.c
+++ b/src/libnm-systemd-shared/src/basic/devnum-util.c
@@ -60,21 +60,18 @@ int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret) {
 }
 
 int device_path_make_inaccessible(mode_t mode, char **ret) {
-        char *s;
+        const char *s;
 
         assert(ret);
 
         if (S_ISCHR(mode))
-                s = strdup("/run/systemd/inaccessible/chr");
+                s = "/run/systemd/inaccessible/chr";
         else if (S_ISBLK(mode))
-                s = strdup("/run/systemd/inaccessible/blk");
+                s = "/run/systemd/inaccessible/blk";
         else
                 return -ENODEV;
-        if (!s)
-                return -ENOMEM;
 
-        *ret = s;
-        return 0;
+        return strdup_to(ret, s);
 }
 
 #if 0 /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/env-util.c b/src/libnm-systemd-shared/src/basic/env-util.c
index 54509a55..2fe7332c 100644
--- a/src/libnm-systemd-shared/src/basic/env-util.c
+++ b/src/libnm-systemd-shared/src/basic/env-util.c
@@ -20,6 +20,7 @@
 #include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "syslog-util.h"
 #include "utf8.h"
 
 #if 0 /* NM_IGNORED */
@@ -268,7 +269,7 @@ static bool env_entry_has_name(const char *entry, const char *name) {
         return *t == '=';
 }
 
-char **strv_env_delete(char **x, size_t n_lists, ...) {
+char** strv_env_delete(char **x, size_t n_lists, ...) {
         size_t n, i = 0;
         _cleanup_strv_free_ char **t = NULL;
         va_list ap;
@@ -555,7 +556,7 @@ char* strv_env_get_n(char * const *l, const char *name, size_t k, ReplaceEnvFlag
 }
 #endif /* NM_IGNORED */
 
-char *strv_env_pairs_get(char **l, const char *name) {
+char* strv_env_pairs_get(char **l, const char *name) {
         char *result = NULL;
 
         assert(name);
@@ -568,7 +569,35 @@ char *strv_env_pairs_get(char **l, const char *name) {
 }
 
 #if 0 /* NM_IGNORED */
-char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
+int strv_env_get_merged(char **l, char ***ret) {
+        _cleanup_strv_free_ char **v = NULL;
+        size_t n = 0;
+        int r;
+
+        assert(ret);
+
+        /* This converts a strv with pairs of environment variable name + value into a strv of name and
+         * value concatenated with a "=" separator. E.g.
+         * input  : { "NAME", "value", "FOO", "var" }
+         * output : { "NAME=value", "FOO=var" } */
+
+        STRV_FOREACH_PAIR(key, value, l) {
+                char *s;
+
+                s = strjoin(*key, "=", *value);
+                if (!s)
+                        return -ENOMEM;
+
+                r = strv_consume_with_size(&v, &n, s);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = TAKE_PTR(v);
+        return 0;
+}
+
+char** strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
         int k = 0;
 
         STRV_FOREACH(p, e) {
@@ -800,10 +829,10 @@ int replace_env_full(
                                         t = v;
                                 }
 
-                                r = strv_extend_strv(&unset_variables, u, /* filter_duplicates= */ true);
+                                r = strv_extend_strv_consume(&unset_variables, TAKE_PTR(u), /* filter_duplicates= */ true);
                                 if (r < 0)
                                         return r;
-                                r = strv_extend_strv(&bad_variables, b, /* filter_duplicates= */ true);
+                                r = strv_extend_strv_consume(&bad_variables, TAKE_PTR(b), /* filter_duplicates= */ true);
                                 if (r < 0)
                                         return r;
 
@@ -935,21 +964,21 @@ int replace_env_argv(
                         return r;
                 n[++k] = NULL;
 
-                r = strv_extend_strv(&unset_variables, u, /* filter_duplicates= */ true);
+                r = strv_extend_strv_consume(&unset_variables, TAKE_PTR(u), /* filter_duplicates= */ true);
                 if (r < 0)
                         return r;
 
-                r = strv_extend_strv(&bad_variables, b, /*filter_duplicates= */ true);
+                r = strv_extend_strv_consume(&bad_variables, TAKE_PTR(b), /* filter_duplicates= */ true);
                 if (r < 0)
                         return r;
         }
 
         if (ret_unset_variables) {
-                strv_uniq(strv_sort(unset_variables));
+                strv_sort_uniq(unset_variables);
                 *ret_unset_variables = TAKE_PTR(unset_variables);
         }
         if (ret_bad_variables) {
-                strv_uniq(strv_sort(bad_variables));
+                strv_sort_uniq(bad_variables);
                 *ret_bad_variables = TAKE_PTR(bad_variables);
         }
 
@@ -1146,14 +1175,17 @@ int setenvf(const char *name, bool overwrite, const char *valuef, ...) {
                 return RET_NERRNO(unsetenv(name));
 
         va_start(ap, valuef);
-        DISABLE_WARNING_FORMAT_NONLITERAL;
         r = vasprintf(&value, valuef, ap);
-        REENABLE_WARNING;
         va_end(ap);
 
         if (r < 0)
                 return -ENOMEM;
 
+        /* Try to suppress writes if the value is already set correctly (simply because memory management of
+         * environment variables sucks a bit. */
+        if (streq_ptr(getenv(name), value))
+                return 0;
+
         return RET_NERRNO(setenv(name, value, overwrite));
 }
 #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 6610ca8c..203ed65b 100644
--- a/src/libnm-systemd-shared/src/basic/env-util.h
+++ b/src/libnm-systemd-shared/src/basic/env-util.h
@@ -34,14 +34,14 @@ int replace_env_argv(char **argv, char **env, char ***ret, char ***ret_unset_var
 
 bool strv_env_is_valid(char **e);
 #define strv_env_clean(l) strv_env_clean_with_callback(l, NULL, NULL)
-char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata);
+char** strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata);
 
 bool strv_env_name_is_valid(char **l);
 bool strv_env_name_or_assignment_is_valid(char **l);
 
 char** _strv_env_merge(char **first, ...);
 #define strv_env_merge(first, ...) _strv_env_merge(first, __VA_ARGS__, POINTER_MAX)
-char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
+char** strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
 
 char** strv_env_unset(char **l, const char *p); /* In place ... */
 char** strv_env_unset_many_internal(char **l, ...) _sentinel_;
@@ -59,7 +59,8 @@ static inline char* strv_env_get(char * const *x, const char *n) {
         return strv_env_get_n(x, n, SIZE_MAX, 0);
 }
 
-char *strv_env_pairs_get(char **l, const char *name) _pure_;
+char* strv_env_pairs_get(char **l, const char *name) _pure_;
+int strv_env_get_merged(char **l, char ***ret);
 
 int getenv_bool(const char *p);
 int secure_getenv_bool(const char *p);
diff --git a/src/libnm-systemd-shared/src/basic/errno-util.h b/src/libnm-systemd-shared/src/basic/errno-util.h
index 27804e63..02572e3b 100644
--- a/src/libnm-systemd-shared/src/basic/errno-util.h
+++ b/src/libnm-systemd-shared/src/basic/errno-util.h
@@ -158,7 +158,7 @@ static inline bool ERRNO_IS_NEG_RESOURCE(intmax_t r) {
 }
 _DEFINE_ABS_WRAPPER(RESOURCE);
 
-/* Seven different errors for "operation/system call/ioctl/socket feature not supported" */
+/* Seven different errors for "operation/system call/socket feature not supported" */
 static inline bool ERRNO_IS_NEG_NOT_SUPPORTED(intmax_t r) {
         return IN_SET(r,
                       -EOPNOTSUPP,
@@ -167,10 +167,17 @@ static inline bool ERRNO_IS_NEG_NOT_SUPPORTED(intmax_t r) {
                       -EAFNOSUPPORT,
                       -EPFNOSUPPORT,
                       -EPROTONOSUPPORT,
-                      -ESOCKTNOSUPPORT);
+                      -ESOCKTNOSUPPORT,
+                      -ENOPROTOOPT);
 }
 _DEFINE_ABS_WRAPPER(NOT_SUPPORTED);
 
+/* ioctl() with unsupported command/arg might additionally return EINVAL */
+static inline bool ERRNO_IS_NEG_IOCTL_NOT_SUPPORTED(intmax_t r) {
+        return ERRNO_IS_NEG_NOT_SUPPORTED(r) || r == -EINVAL;
+}
+_DEFINE_ABS_WRAPPER(IOCTL_NOT_SUPPORTED);
+
 /* Two different errors for access problems */
 static inline bool ERRNO_IS_NEG_PRIVILEGE(intmax_t r) {
         return IN_SET(r,
diff --git a/src/libnm-systemd-shared/src/basic/escape.c b/src/libnm-systemd-shared/src/basic/escape.c
index 29f8b9cd..e882aced 100644
--- a/src/libnm-systemd-shared/src/basic/escape.c
+++ b/src/libnm-systemd-shared/src/basic/escape.c
@@ -368,6 +368,8 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, XEscape
         char *ans, *t, *prev, *prev2;
         const char *f;
 
+        assert(s);
+
         /* Escapes all chars in bad, in addition to \ and all special chars, in \xFF style escaping. May be
          * reversed with cunescape(). If XESCAPE_8_BIT is specified, characters >= 127 are let through
          * unchanged. This corresponds to non-ASCII printable characters in pre-unicode encodings.
@@ -400,7 +402,7 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, XEscape
 
                 if ((unsigned char) *f < ' ' ||
                     (!FLAGS_SET(flags, XESCAPE_8_BIT) && (unsigned char) *f >= 127) ||
-                    *f == '\\' || strchr(bad, *f)) {
+                    *f == '\\' || (bad && strchr(bad, *f))) {
                         if ((size_t) (t - ans) + 4 + 3 * force_ellipsis > console_width)
                                 break;
 
@@ -440,7 +442,7 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, XEscape
 
 char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFlags flags) {
         if (FLAGS_SET(flags, XESCAPE_8_BIT))
-                return xescape_full(str, "", console_width, flags);
+                return xescape_full(str, /* bad= */ NULL, console_width, flags);
         else
                 return utf8_escape_non_printable_full(str,
                                                       console_width,
@@ -454,6 +456,12 @@ char* octescape(const char *s, size_t len) {
 
         assert(s || len == 0);
 
+        if (len == SIZE_MAX)
+                len = strlen(s);
+
+        if (len > (SIZE_MAX - 1) / 4)
+                return NULL;
+
         t = buf = new(char, len * 4 + 1);
         if (!buf)
                 return NULL;
diff --git a/src/libnm-systemd-shared/src/basic/ether-addr-util.c b/src/libnm-systemd-shared/src/basic/ether-addr-util.c
index 1eb2e700..2643c974 100644
--- a/src/libnm-systemd-shared/src/basic/ether-addr-util.c
+++ b/src/libnm-systemd-shared/src/basic/ether-addr-util.c
@@ -13,7 +13,7 @@
 #include "macro.h"
 #include "string-util.h"
 
-char *hw_addr_to_string_full(
+char* hw_addr_to_string_full(
                 const struct hw_addr_data *addr,
                 HardwareAddressToStringFlags flags,
                 char buffer[static HW_ADDR_TO_STRING_MAX]) {
diff --git a/src/libnm-systemd-shared/src/basic/ether-addr-util.h b/src/libnm-systemd-shared/src/basic/ether-addr-util.h
index 187e4ef5..8ebf9c03 100644
--- a/src/libnm-systemd-shared/src/basic/ether-addr-util.h
+++ b/src/libnm-systemd-shared/src/basic/ether-addr-util.h
@@ -36,11 +36,11 @@ typedef enum HardwareAddressToStringFlags {
 } HardwareAddressToStringFlags;
 
 #define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE)
-char *hw_addr_to_string_full(
+char* hw_addr_to_string_full(
                 const struct hw_addr_data *addr,
                 HardwareAddressToStringFlags flags,
                 char buffer[static HW_ADDR_TO_STRING_MAX]);
-static inline char *hw_addr_to_string(const struct hw_addr_data *addr, char buffer[static HW_ADDR_TO_STRING_MAX]) {
+static inline char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[static HW_ADDR_TO_STRING_MAX]) {
         return hw_addr_to_string_full(addr, 0, buffer);
 }
 
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.c b/src/libnm-systemd-shared/src/basic/fd-util.c
index 584d02f0..e052a6a2 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.c
+++ b/src/libnm-systemd-shared/src/basic/fd-util.c
@@ -169,7 +169,10 @@ int fd_nonblock(int fd, bool nonblock) {
         if (nflags == flags)
                 return 0;
 
-        return RET_NERRNO(fcntl(fd, F_SETFL, nflags));
+        if (fcntl(fd, F_SETFL, nflags) < 0)
+                return -errno;
+
+        return 1;
 }
 
 int stdio_disable_nonblock(void) {
@@ -212,9 +215,6 @@ int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec) {
                         continue;
 
                 RET_GATHER(r, fd_cloexec(*fd, cloexec));
-
-                if (r >= 0)
-                        r = 1; /* report if we did anything */
         }
 
         return r;
@@ -514,6 +514,16 @@ int pack_fds(int fds[], size_t n_fds) {
         return 0;
 }
 
+int fd_validate(int fd) {
+        if (fd < 0)
+                return -EBADF;
+
+        if (fcntl(fd, F_GETFD) < 0)
+                return -errno;
+
+        return 0;
+}
+
 int same_fd(int a, int b) {
         struct stat sta, stb;
         pid_t pid;
@@ -523,25 +533,57 @@ int same_fd(int a, int b) {
         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. */
+         * have F_DUPFD_QUERY/kcmp() or we don't. If we have F_DUPFD_QUERY/kcmp() this will only return true
+         * for dup()ed file descriptors, but not otherwise. If we don't have F_DUPFD_QUERY/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.
+         *
+         * Guarantees that if either of the passed fds is not allocated we'll return -EBADF. */
+
+        if (a == b) {
+                /* Let's validate that the fd is valid */
+                r = fd_validate(a);
+                if (r < 0)
+                        return r;
 
-        if (a == b)
                 return true;
+        }
+
+        /* Try to use F_DUPFD_QUERY if we have it first, as it is the nicest API */
+        r = fcntl(a, F_DUPFD_QUERY, b);
+        if (r > 0)
+                return true;
+        if (r == 0) {
+                /* The kernel will return 0 in case the first fd is allocated, but the 2nd is not. (Which is different in the kcmp() case) Explicitly validate it hence. */
+                r = fd_validate(b);
+                if (r < 0)
+                        return r;
+
+                return false;
+        }
+        /* On old kernels (< 6.10) that do not support F_DUPFD_QUERY this will return EINVAL for regular fds, and EBADF on O_PATH fds. Confusing. */
+        if (errno == EBADF) {
+                /* EBADF could mean two things: the first fd is not valid, or it is valid and is O_PATH and
+                 * F_DUPFD_QUERY is not supported. Let's validate the fd explicitly, to distinguish this
+                 * case. */
+                r = fd_validate(a);
+                if (r < 0)
+                        return r;
+
+                /* If the fd is valid, but we got EBADF, then let's try kcmp(). */
+        } else if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
+                return -errno;
 
         /* Try to use kcmp() if we have it. */
         pid = getpid_cached();
         r = kcmp(pid, pid, KCMP_FILE, a, b);
-        if (r == 0)
-                return true;
-        if (r > 0)
-                return false;
+        if (r >= 0)
+                return !r;
         if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
                 return -errno;
 
-        /* We don't have kcmp(), use fstat() instead. */
+        /* We have neither F_DUPFD_QUERY nor kcmp(), use fstat() instead. */
         if (fstat(a, &sta) < 0)
                 return -errno;
 
@@ -572,14 +614,21 @@ int same_fd(int a, int b) {
 #endif /* NM_IGNORED */
 
 void cmsg_close_all(struct msghdr *mh) {
-        struct cmsghdr *cmsg;
-
         assert(mh);
 
-        CMSG_FOREACH(cmsg, mh)
-                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+        struct cmsghdr *cmsg;
+        CMSG_FOREACH(cmsg, mh) {
+                if (cmsg->cmsg_level != SOL_SOCKET)
+                        continue;
+
+                if (cmsg->cmsg_type == SCM_RIGHTS)
                         close_many(CMSG_TYPED_DATA(cmsg, int),
                                    (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
+                else if (cmsg->cmsg_type == SCM_PIDFD) {
+                        assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
+                        safe_close(*CMSG_TYPED_DATA(cmsg, int));
+                }
+        }
 }
 
 bool fdname_is_valid(const char *s) {
@@ -609,7 +658,6 @@ bool fdname_is_valid(const char *s) {
         return p - s <= FDNAME_MAX;
 }
 
-#if 0 /* NM_IGNORED */
 int fd_get_path(int fd, char **ret) {
         int r;
 
@@ -619,19 +667,12 @@ int fd_get_path(int fd, char **ret) {
                 return safe_getcwd(ret);
 
         r = readlink_malloc(FORMAT_PROC_FD_PATH(fd), ret);
-        if (r == -ENOENT) {
-                /* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make
-                 * things debuggable and distinguish the two. */
-
-                if (proc_mounted() == 0)
-                        return -ENOSYS;  /* /proc is not available or not set up properly, we're most likely in some chroot
-                                          * environment. */
-                return -EBADF; /* The directory exists, hence it's the fd that doesn't. */
-        }
-
+        if (r == -ENOENT)
+                return proc_fd_enoent_errno();
         return r;
 }
 
+#if 0 /* NM_IGNORED */
 int move_fd(int from, int to, int cloexec) {
         int r;
 
@@ -768,8 +809,7 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_
         }
 
         /* Let's assemble fd[] with the fds to install in place of stdin/stdout/stderr */
-        for (int i = 0; i < 3; i++) {
-
+        for (int i = 0; i < 3; i++)
                 if (fd[i] < 0)
                         fd[i] = null_fd;        /* A negative parameter means: connect this one to /dev/null */
                 else if (fd[i] != i && fd[i] < 3) {
@@ -782,20 +822,16 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_
 
                         fd[i] = copy_fd[i];
                 }
-        }
 
         /* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that
          * we have freedom to move them around. If the fds already were at the right places then the specific
          * fds are -EBADF. Let's now move them to the right places. This is the point of no return. */
-        for (int i = 0; i < 3; i++) {
-
+        for (int i = 0; i < 3; i++)
                 if (fd[i] == i) {
-
                         /* fd is already in place, but let's make sure O_CLOEXEC is off */
                         r = fd_cloexec(i, false);
                         if (r < 0)
                                 goto finish;
-
                 } else {
                         assert(fd[i] > 2);
 
@@ -804,7 +840,6 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_
                                 goto finish;
                         }
                 }
-        }
 
         r = 0;
 
@@ -828,8 +863,6 @@ finish:
 #endif /* NM_IGNORED */
 
 int fd_reopen(int fd, int flags) {
-        int r;
-
         assert(fd >= 0 || fd == AT_FDCWD);
         assert(!FLAGS_SET(flags, O_CREAT));
 
@@ -865,13 +898,47 @@ int fd_reopen(int fd, int flags) {
                 if (errno != ENOENT)
                         return -errno;
 
-                r = proc_mounted();
-                if (r == 0)
-                        return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
+                return proc_fd_enoent_errno();
+        }
 
-                return r > 0 ? -EBADF : -ENOENT; /* If /proc/ is definitely around then this means the fd is
-                                                  * not valid, otherwise let's propagate the original
-                                                  * error */
+        return new_fd;
+}
+
+int fd_reopen_propagate_append_and_position(int fd, int flags) {
+        /* Invokes fd_reopen(fd, flags), but propagates O_APPEND if set on original fd, and also tries to
+         * keep current file position.
+         *
+         * You should use this if the original fd potentially is O_APPEND, otherwise we get rather
+         * "unexpected" behavior. Unless you intentionally want to overwrite pre-existing data, and have
+         * your output overwritten by the next user.
+         *
+         * Use case: "systemd-run --pty >> some-log".
+         *
+         * The "keep position" part is obviously nonsense for the O_APPEND case, but should reduce surprises
+         * if someone carefully pre-positioned the passed in original input or non-append output FDs. */
+
+        assert(fd >= 0);
+        assert(!(flags & (O_APPEND|O_DIRECTORY)));
+
+        int existing_flags = fcntl(fd, F_GETFL);
+        if (existing_flags < 0)
+                return -errno;
+
+        int new_fd = fd_reopen(fd, flags | (existing_flags & O_APPEND));
+        if (new_fd < 0)
+                return new_fd;
+
+        /* Try to adjust the offset, but ignore errors. */
+        off_t p = lseek(fd, 0, SEEK_CUR);
+        if (p > 0) {
+                off_t new_p = lseek(new_fd, p, SEEK_SET);
+                if (new_p < 0)
+                        log_debug_errno(errno,
+                                        "Failed to propagate file position for re-opened fd %d, ignoring: %m",
+                                        fd);
+                else if (new_p != p)
+                        log_debug("Failed to propagate file position for re-opened fd %d (%lld != %lld), ignoring.",
+                                  fd, (long long) new_p, (long long) p);
         }
 
         return new_fd;
@@ -922,21 +989,21 @@ int fd_is_opath(int fd) {
         return FLAGS_SET(r, O_PATH);
 }
 
-int fd_verify_safe_flags(int fd) {
+int fd_verify_safe_flags_full(int fd, int extra_flags) {
         int flags, unexpected_flags;
 
         /* Check if an extrinsic fd is safe to work on (by a privileged service). This ensures that clients
          * can't trick a privileged service into giving access to a file the client doesn't already have
          * access to (especially via something like O_PATH).
          *
-         * O_NOFOLLOW: For some reason the kernel will return this flag from fcntl; it doesn't go away
+         * O_NOFOLLOW: For some reason the kernel will return this flag from fcntl(); it doesn't go away
          *             immediately after open(). It should have no effect whatsoever to an already-opened FD,
          *             and since we refuse O_PATH it should be safe.
          *
          * RAW_O_LARGEFILE: glibc secretly sets this and neglects to hide it from us if we call fcntl.
          *                  See comment in missing_fcntl.h for more details about this.
          *
-         * O_DIRECTORY: this is set for directories, which are totally fine
+         * If 'extra_flags' is specified as non-zero the included flags are also allowed.
          */
 
         assert(fd >= 0);
@@ -945,13 +1012,13 @@ int fd_verify_safe_flags(int fd) {
         if (flags < 0)
                 return -errno;
 
-        unexpected_flags = flags & ~(O_ACCMODE|O_NOFOLLOW|RAW_O_LARGEFILE|O_DIRECTORY);
+        unexpected_flags = flags & ~(O_ACCMODE|O_NOFOLLOW|RAW_O_LARGEFILE|extra_flags);
         if (unexpected_flags != 0)
                 return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
                                        "Unexpected flags set for extrinsic fd: 0%o",
                                        (unsigned) unexpected_flags);
 
-        return 0;
+        return flags & (O_ACCMODE | extra_flags); /* return the flags variable, but remove the noise */
 }
 
 int read_nr_open(void) {
@@ -1055,8 +1122,6 @@ int fds_are_same_mount(int fd1, int fd2) {
                 int mntid;
 
                 r = path_get_mnt_id_at_fallback(fd1, "", &mntid);
-                if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
-                        return true; /* skip the mount ID check */
                 if (r < 0)
                         return r;
                 assert(mntid >= 0);
@@ -1069,8 +1134,6 @@ int fds_are_same_mount(int fd1, int fd2) {
                 int mntid;
 
                 r = path_get_mnt_id_at_fallback(fd2, "", &mntid);
-                if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
-                        return true; /* skip the mount ID check */
                 if (r < 0)
                         return r;
                 assert(mntid >= 0);
@@ -1082,7 +1145,7 @@ int fds_are_same_mount(int fd1, int fd2) {
         return statx_mount_same(&st1.nsx, &st2.nsx);
 }
 
-const char *accmode_to_string(int flags) {
+const char* accmode_to_string(int flags) {
         switch (flags & O_ACCMODE) {
         case O_RDONLY:
                 return "ro";
@@ -1095,7 +1158,7 @@ const char *accmode_to_string(int flags) {
         }
 }
 
-char *format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid, int fd) {
+char* format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid, int fd) {
         assert(buf);
         assert(fd >= 0);
         assert(pid >= 0);
@@ -1103,3 +1166,20 @@ char *format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid,
         return buf;
 }
 #endif /* NM_IGNORED */
+
+int proc_fd_enoent_errno(void) {
+        int r;
+
+        /* When ENOENT is returned during the use of FORMAT_PROC_FD_PATH, it can mean two things:
+         * that the fd does not exist or that /proc/ is not mounted.
+         * Let's make things debuggable and figure out the most appropriate errno. */
+
+        r = proc_mounted();
+        if (r == 0)
+                return -ENOSYS;  /* /proc/ is not available or not set up properly, we're most likely
+                                    in some chroot environment. */
+        if (r > 0)
+                return -EBADF;   /* If /proc/ is definitely around then this means the fd is not valid. */
+
+        return -ENOENT;          /* Otherwise let's propagate the original ENOENT. */
+}
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.h b/src/libnm-systemd-shared/src/basic/fd-util.h
index f5498310..93b254c6 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.h
+++ b/src/libnm-systemd-shared/src/basic/fd-util.h
@@ -80,6 +80,7 @@ int close_all_fds_without_malloc(const int except[], size_t n_except);
 
 int pack_fds(int fds[], size_t n);
 
+int fd_validate(int fd);
 int same_fd(int a, int b);
 
 void cmsg_close_all(struct msghdr *mh);
@@ -111,10 +112,15 @@ static inline int make_null_stdio(void) {
         })
 
 int fd_reopen(int fd, int flags);
+int fd_reopen_propagate_append_and_position(int fd, int flags);
 int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
 
 int fd_is_opath(int fd);
-int fd_verify_safe_flags(int fd);
+
+int fd_verify_safe_flags_full(int fd, int extra_flags);
+static inline int fd_verify_safe_flags(int fd) {
+        return fd_verify_safe_flags_full(fd, 0);
+}
 
 int read_nr_open(void);
 int fd_get_diskseq(int fd, uint64_t *ret);
@@ -136,7 +142,7 @@ int fds_are_same_mount(int fd1, int fd2);
 #define PROC_FD_PATH_MAX \
         (STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int))
 
-static inline char *format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int fd) {
+static inline char* format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int fd) {
         assert(buf);
         assert(fd >= 0);
         assert_se(snprintf_ok(buf, PROC_FD_PATH_MAX, "/proc/self/fd/%i", fd));
@@ -150,13 +156,15 @@ static inline char *format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int f
 #define PROC_PID_FD_PATH_MAX \
         (STRLEN("/proc//fd/") + DECIMAL_STR_MAX(pid_t) + DECIMAL_STR_MAX(int))
 
-char *format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid, int fd);
+char* format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid, int fd);
 
 /* Kinda the same as FORMAT_PROC_FD_PATH(), but goes by PID rather than "self" symlink */
 #define FORMAT_PROC_PID_FD_PATH(pid, fd)                                \
         format_proc_pid_fd_path((char[PROC_PID_FD_PATH_MAX]) {}, (pid), (fd))
 
-const char *accmode_to_string(int flags);
+int proc_fd_enoent_errno(void);
+
+const char* accmode_to_string(int flags);
 
 /* Like ASSERT_PTR, but for fds */
 #define ASSERT_FD(fd)                           \
diff --git a/src/libnm-systemd-shared/src/basic/fileio.c b/src/libnm-systemd-shared/src/basic/fileio.c
index 7ab29816..78231228 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.c
+++ b/src/libnm-systemd-shared/src/basic/fileio.c
@@ -16,10 +16,12 @@
 
 #include "alloc-util.h"
 #include "chase.h"
+#include "extract-word.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
 #include "hexdecoct.h"
+#include "label.h"
 #include "log.h"
 #include "macro.h"
 #include "mkdir.h"
@@ -34,7 +36,7 @@
 #include "tmpfile-util.h"
 
 /* The maximum size of the file we'll read in one go in read_full_file() (64M). */
-#define READ_FULL_BYTES_MAX (64U*1024U*1024U - 1U)
+#define READ_FULL_BYTES_MAX (64U * U64_MB - UINT64_C(1))
 /* Used when a size is specified for read_full_file() with READ_FULL_FILE_UNBASE64 or _UNHEX */
 #define READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY 3
 
@@ -47,7 +49,7 @@
  * exponentially in a loop. We use a size limit of 4M-2 because 4M-1 is the maximum buffer that /proc/sys/
  * allows us to read() (larger reads will fail with ENOMEM), and we want to read one extra byte so that we
  * can detect EOFs. */
-#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 2U)
+#define READ_VIRTUAL_BYTES_MAX (4U * U64_MB - UINT64_C(2))
 
 int fdopen_unlocked(int fd, const char *options, FILE **ret) {
         assert(ret);
@@ -121,7 +123,7 @@ FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode) {
 }
 
 #if 0 /* NM_IGNORED */
-int write_string_stream_ts(
+int write_string_stream_full(
                 FILE *f,
                 const char *line,
                 WriteStringFileFlags flags,
@@ -233,22 +235,40 @@ static int write_string_file_atomic_at(
         /* Note that we'd really like to use O_TMPFILE here, but can't really, since we want replacement
          * semantics here, and O_TMPFILE can't offer that. i.e. rename() replaces but linkat() doesn't. */
 
+        mode_t mode = write_string_file_flags_to_mode(flags);
+
+        bool call_label_ops_post = false;
+        if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL)) {
+                r = label_ops_pre(dir_fd, fn, mode);
+                if (r < 0)
+                        return r;
+
+                call_label_ops_post = true;
+        }
+
         r = fopen_temporary_at(dir_fd, fn, &f, &p);
         if (r < 0)
-                return r;
+                goto fail;
+
+        if (call_label_ops_post) {
+                call_label_ops_post = false;
 
-        r = write_string_stream_ts(f, line, flags, ts);
+                r = label_ops_post(fileno(f), /* path= */ NULL, /* created= */ true);
+                if (r < 0)
+                        goto fail;
+        }
+
+        r = write_string_stream_full(f, line, flags, ts);
         if (r < 0)
                 goto fail;
 
-        r = fchmod_umask(fileno(f), write_string_file_flags_to_mode(flags));
+        r = fchmod_umask(fileno(f), mode);
         if (r < 0)
                 goto fail;
 
-        if (renameat(dir_fd, p, dir_fd, fn) < 0) {
-                r = -errno;
+        r = RET_NERRNO(renameat(dir_fd, p, dir_fd, fn));
+        if (r < 0)
                 goto fail;
-        }
 
         if (FLAGS_SET(flags, WRITE_STRING_FILE_SYNC)) {
                 /* Sync the rename, too */
@@ -260,20 +280,26 @@ static int write_string_file_atomic_at(
         return 0;
 
 fail:
-        (void) unlinkat(dir_fd, p, 0);
+        if (call_label_ops_post)
+                (void) label_ops_post(f ? fileno(f) : dir_fd, f ? NULL : fn, /* created= */ !!f);
+
+        if (f)
+                (void) unlinkat(dir_fd, p, 0);
         return r;
 }
 
-int write_string_file_ts_at(
+int write_string_file_full(
                 int dir_fd,
                 const char *fn,
                 const char *line,
                 WriteStringFileFlags flags,
-                const struct timespec *ts) {
+                const struct timespec *ts,
+                const char *label_fn) {
 
+        bool call_label_ops_post = false, made_file = false;
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_close_ int fd = -EBADF;
-        int q, r;
+        int r;
 
         assert(fn);
         assert(line);
@@ -295,21 +321,40 @@ int write_string_file_ts_at(
                         goto fail;
 
                 return r;
-        } else
-                assert(!ts);
+        }
+
+        mode_t mode = write_string_file_flags_to_mode(flags);
+
+        if (FLAGS_SET(flags, WRITE_STRING_FILE_LABEL|WRITE_STRING_FILE_CREATE)) {
+                r = label_ops_pre(dir_fd, label_fn ?: fn, mode);
+                if (r < 0)
+                        goto fail;
+
+                call_label_ops_post = true;
+        }
 
         /* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */
-        fd = openat(dir_fd, fn, O_CLOEXEC|O_NOCTTY |
-                    (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
-                    (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
-                    (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
-                    (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY),
-                    write_string_file_flags_to_mode(flags));
+        fd = openat_report_new(
+                        dir_fd, fn, O_CLOEXEC | O_NOCTTY |
+                        (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
+                        (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
+                        (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
+                        (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY),
+                        mode,
+                        &made_file);
         if (fd < 0) {
-                r = -errno;
+                r = fd;
                 goto fail;
         }
 
+        if (call_label_ops_post) {
+                call_label_ops_post = false;
+
+                r = label_ops_post(fd, /* path= */ NULL, made_file);
+                if (r < 0)
+                        goto fail;
+        }
+
         r = take_fdopen_unlocked(&fd, "w", &f);
         if (r < 0)
                 goto fail;
@@ -317,26 +362,31 @@ int write_string_file_ts_at(
         if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
                 setvbuf(f, NULL, _IONBF, 0);
 
-        r = write_string_stream_ts(f, line, flags, ts);
+        r = write_string_stream_full(f, line, flags, ts);
         if (r < 0)
                 goto fail;
 
         return 0;
 
 fail:
+        if (call_label_ops_post)
+                (void) label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : fn, made_file);
+
+        if (made_file)
+                (void) unlinkat(dir_fd, fn, 0);
+
         if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
                 return r;
 
         f = safe_fclose(f);
+        fd = safe_close(fd);
 
-        /* OK, the operation failed, but let's see if the right
-         * contents in place already. If so, eat up the error. */
-
-        q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) || (flags & WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE));
-        if (q <= 0)
-                return r;
+        /* OK, the operation failed, but let's see if the right contents in place already. If so, eat up the
+         * error. */
+        if (verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) || (flags & WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE)) > 0)
+                return 0;
 
-        return 0;
+        return r;
 }
 
 int write_string_filef(
@@ -358,6 +408,22 @@ int write_string_filef(
         return write_string_file(fn, p, flags);
 }
 
+int write_base64_file_at(
+                int dir_fd,
+                const char *fn,
+                const struct iovec *data,
+                WriteStringFileFlags flags) {
+
+        _cleanup_free_ char *encoded = NULL;
+        ssize_t n;
+
+        n = base64mem_full(data ? data->iov_base : NULL, data ? data->iov_len : 0, 79, &encoded);
+        if (n < 0)
+                return n;
+
+        return write_string_file_at(dir_fd, fn, encoded, flags);
+}
+
 int read_one_line_file_at(int dir_fd, const char *filename, char **ret) {
         _cleanup_fclose_ FILE *f = NULL;
         int r;
@@ -796,35 +862,49 @@ int read_full_file_full(
 }
 
 #if 0 /* NM_IGNORED */
-int executable_is_script(const char *path, char **interpreter) {
-        _cleanup_free_ char *line = NULL;
-        size_t len;
-        char *ans;
+int script_get_shebang_interpreter(const char *path, char **ret) {
+        _cleanup_fclose_ FILE *f = NULL;
         int r;
 
         assert(path);
 
-        r = read_one_line_file(path, &line);
-        if (r == -ENOBUFS) /* First line overly long? if so, then it's not a script */
-                return 0;
+        f = fopen(path, "re");
+        if (!f)
+                return -errno;
+
+        char c;
+        r = safe_fgetc(f, &c);
         if (r < 0)
                 return r;
+        if (r == 0)
+                return -EBADMSG;
+        if (c != '#')
+                return -EMEDIUMTYPE;
+        r = safe_fgetc(f, &c);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EBADMSG;
+        if (c != '!')
+                return -EMEDIUMTYPE;
 
-        if (!startswith(line, "#!"))
-                return 0;
-
-        ans = strstrip(line + 2);
-        len = strcspn(ans, " \t");
+        _cleanup_free_ char *line = NULL;
+        r = read_line(f, LONG_LINE_MAX, &line);
+        if (r < 0)
+                return r;
 
-        if (len == 0)
-                return 0;
+        _cleanup_free_ char *p = NULL;
+        const char *s = line;
 
-        ans = strndup(ans, len);
-        if (!ans)
-                return -ENOMEM;
+        r = extract_first_word(&s, &p, /* separators = */ NULL, /* flags = */ 0);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -ENOEXEC;
 
-        *interpreter = ans;
-        return 1;
+        if (ret)
+                *ret = TAKE_PTR(p);
+        return 0;
 }
 
 /**
@@ -897,19 +977,21 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
         return 0;
 }
 
-DIR *xopendirat(int fd, const char *name, int flags) {
-        _cleanup_close_ int nfd = -EBADF;
+DIR* xopendirat(int dir_fd, const char *name, int flags) {
+        _cleanup_close_ int fd = -EBADF;
 
-        assert(!(flags & O_CREAT));
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+        assert(name);
+        assert(!(flags & (O_CREAT|O_TMPFILE)));
 
-        if (fd == AT_FDCWD && flags == 0)
+        if (dir_fd == AT_FDCWD && flags == 0)
                 return opendir(name);
 
-        nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
-        if (nfd < 0)
+        fd = openat(dir_fd, name, O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags);
+        if (fd < 0)
                 return NULL;
 
-        return take_fdopendir(&nfd);
+        return take_fdopendir(&fd);
 }
 #endif /* NM_IGNORED */
 
@@ -1364,6 +1446,29 @@ int fputs_with_separator(FILE *f, const char *s, const char *separator, bool *sp
         return 0;
 }
 
+int fputs_with_newline(FILE *f, const char *s) {
+
+        /* This is like fputs() but outputs a trailing newline char, but only if the string isn't empty
+         * and doesn't end in a newline already. Returns 0 in case we didn't append a newline, > 0 otherwise. */
+
+        if (isempty(s))
+                return 0;
+
+        if (!f)
+                f = stdout;
+
+        if (fputs(s, f) < 0)
+                return -EIO;
+
+        if (endswith(s, "\n"))
+                return 0;
+
+        if (fputc('\n', f) < 0)
+                return -EIO;
+
+        return 1;
+}
+
 #if 0 /* NM_IGNORED */
 /* A bitmask of the EOL markers we know */
 typedef enum EndOfLineMarker {
@@ -1515,7 +1620,7 @@ int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
 
 int read_stripped_line(FILE *f, size_t limit, char **ret) {
         _cleanup_free_ char *s = NULL;
-        int r;
+        int r, k;
 
         assert(f);
 
@@ -1524,23 +1629,17 @@ int read_stripped_line(FILE *f, size_t limit, char **ret) {
                 return r;
 
         if (ret) {
-                const char *p;
-
-                p = strstrip(s);
+                const char *p = strstrip(s);
                 if (p == s)
                         *ret = TAKE_PTR(s);
                 else {
-                        char *copy;
-
-                        copy = strdup(p);
-                        if (!copy)
-                                return -ENOMEM;
-
-                        *ret = copy;
+                        k = strdup_to(ret, p);
+                        if (k < 0)
+                                return k;
                 }
         }
 
-        return r;
+        return r > 0;          /* Return 1 if something was read. */
 }
 
 int safe_fgetc(FILE *f, char *ret) {
diff --git a/src/libnm-systemd-shared/src/basic/fileio.h b/src/libnm-systemd-shared/src/basic/fileio.h
index 03c3f3ff..bd053050 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.h
+++ b/src/libnm-systemd-shared/src/basic/fileio.h
@@ -28,11 +28,7 @@ typedef enum {
         WRITE_STRING_FILE_MODE_0600                  = 1 << 10,
         WRITE_STRING_FILE_MODE_0444                  = 1 << 11,
         WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL = 1 << 12,
-
-        /* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one
-           more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file()
-           and friends. */
-
+        WRITE_STRING_FILE_LABEL                      = 1 << 13,
 } WriteStringFileFlags;
 
 typedef enum {
@@ -51,23 +47,22 @@ DIR* take_fdopendir(int *dfd);
 FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc);
 FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode);
 
-int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
+int write_string_stream_full(FILE *f, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
 static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
-        return write_string_stream_ts(f, line, flags, NULL);
-}
-int write_string_file_ts_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
-static inline int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts) {
-        return write_string_file_ts_at(AT_FDCWD, fn, line, flags, ts);
+        return write_string_stream_full(f, line, flags, NULL);
 }
+
+int write_string_file_full(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts, const char *label_fn);
 static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) {
-        return write_string_file_ts_at(dir_fd, fn, line, flags, NULL);
+        return write_string_file_full(dir_fd, fn, line, flags, NULL, NULL);
 }
 static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
-        return write_string_file_ts(fn, line, flags, NULL);
+        return write_string_file_at(AT_FDCWD, fn, line, flags);
 }
-
 int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
 
+int write_base64_file_at(int dir_fd, const char *fn, const struct iovec *data, WriteStringFileFlags flags);
+
 int read_one_line_file_at(int dir_fd, const char *filename, char **ret);
 static inline int read_one_line_file(const char *filename, char **ret) {
         return read_one_line_file_at(AT_FDCWD, filename, ret);
@@ -99,11 +94,11 @@ static inline int verify_file(const char *fn, const char *blob, bool accept_extr
         return verify_file_at(AT_FDCWD, fn, blob, accept_extra_nl);
 }
 
-int executable_is_script(const char *path, char **interpreter);
+int script_get_shebang_interpreter(const char *path, char **ret);
 
 int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
 
-DIR *xopendirat(int dirfd, const char *name, int flags);
+DIR* xopendirat(int dir_fd, const char *name, int flags);
 
 typedef enum XfopenFlags {
         XFOPEN_UNLOCKED = 1 << 0, /* call __fsetlocking(FSETLOCKING_BYCALLER) after opened */
@@ -144,6 +139,7 @@ int write_timestamp_file_atomic(const char *fn, usec_t n);
 int read_timestamp_file(const char *fn, usec_t *ret);
 
 int fputs_with_separator(FILE *f, const char *s, const char *separator, bool *space);
+int fputs_with_newline(FILE *f, const char *s);
 
 typedef enum ReadLineFlags {
         READ_LINE_ONLY_NUL  = 1 << 0,
@@ -152,23 +148,21 @@ typedef enum ReadLineFlags {
 } 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);
 }
-
 static inline int read_nul_string(FILE *f, size_t limit, char **ret) {
         return read_line_full(f, limit, READ_LINE_ONLY_NUL, ret);
 }
 
 int read_stripped_line(FILE *f, size_t limit, 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;
+}
+
 int safe_fgetc(FILE *f, char *ret);
 
 int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line);
diff --git a/src/libnm-systemd-shared/src/basic/format-ifname.c b/src/libnm-systemd-shared/src/basic/format-ifname.c
new file mode 100644
index 00000000..81592998
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/format-ifname.c
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "nm-sd-adapt-shared.h"
+
+#include "format-ifname.h"
+#include "string-util.h"
+
+assert_cc(STRLEN("%") + DECIMAL_STR_MAX(int) <= IF_NAMESIZE);
+
+int format_ifname_full(int ifindex, FormatIfnameFlag flag, char buf[static IF_NAMESIZE]) {
+        if (ifindex <= 0)
+                return -EINVAL;
+
+        if (if_indextoname(ifindex, buf))
+                return 0;
+
+        if (!FLAGS_SET(flag, FORMAT_IFNAME_IFINDEX))
+                return -errno;
+
+        if (FLAGS_SET(flag, FORMAT_IFNAME_IFINDEX_WITH_PERCENT))
+                assert_se(snprintf_ok(buf, IF_NAMESIZE, "%%%d", ifindex));
+        else
+                assert_se(snprintf_ok(buf, IF_NAMESIZE, "%d", ifindex));
+
+        return 0;
+}
+
+int format_ifname_full_alloc(int ifindex, FormatIfnameFlag flag, char **ret) {
+        char buf[IF_NAMESIZE];
+        int r;
+
+        assert(ret);
+
+        r = format_ifname_full(ifindex, flag, buf);
+        if (r < 0)
+                return r;
+
+        return strdup_to(ret, buf);
+}
diff --git a/src/libnm-systemd-shared/src/basic/format-ifname.h b/src/libnm-systemd-shared/src/basic/format-ifname.h
new file mode 100644
index 00000000..84415b13
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/format-ifname.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <net/if.h>
+
+typedef enum {
+        FORMAT_IFNAME_IFINDEX              = 1 << 0,
+        FORMAT_IFNAME_IFINDEX_WITH_PERCENT = (1 << 1) | FORMAT_IFNAME_IFINDEX,
+} FormatIfnameFlag;
+
+int format_ifname_full(int ifindex, FormatIfnameFlag flag, char buf[static IF_NAMESIZE]);
+int format_ifname_full_alloc(int ifindex, FormatIfnameFlag flag, char **ret);
+
+static inline int format_ifname(int ifindex, char buf[static IF_NAMESIZE]) {
+        return format_ifname_full(ifindex, 0, buf);
+}
+static inline int format_ifname_alloc(int ifindex, char **ret) {
+        return format_ifname_full_alloc(ifindex, 0, ret);
+}
+
+static inline char* _format_ifname_full(int ifindex, FormatIfnameFlag flag, char buf[static IF_NAMESIZE]) {
+        (void) format_ifname_full(ifindex, flag, buf);
+        return buf;
+}
+
+#define FORMAT_IFNAME_FULL(index, flag) _format_ifname_full(index, flag, (char[IF_NAMESIZE]){})
+#define FORMAT_IFNAME(index) _format_ifname_full(index, 0, (char[IF_NAMESIZE]){})
diff --git a/src/libnm-systemd-shared/src/basic/format-util.c b/src/libnm-systemd-shared/src/basic/format-util.c
index ebe52713..b2a5d2d0 100644
--- a/src/libnm-systemd-shared/src/basic/format-util.c
+++ b/src/libnm-systemd-shared/src/basic/format-util.c
@@ -7,44 +7,7 @@
 #include "stdio-util.h"
 #include "strxcpyx.h"
 
-assert_cc(STRLEN("%") + DECIMAL_STR_MAX(int) <= IF_NAMESIZE);
-int format_ifname_full(int ifindex, FormatIfnameFlag flag, char buf[static IF_NAMESIZE]) {
-        if (ifindex <= 0)
-                return -EINVAL;
-
-        if (if_indextoname(ifindex, buf))
-                return 0;
-
-        if (!FLAGS_SET(flag, FORMAT_IFNAME_IFINDEX))
-                return -errno;
-
-        if (FLAGS_SET(flag, FORMAT_IFNAME_IFINDEX_WITH_PERCENT))
-                assert(snprintf_ok(buf, IF_NAMESIZE, "%%%d", ifindex));
-        else
-                assert(snprintf_ok(buf, IF_NAMESIZE, "%d", ifindex));
-
-        return 0;
-}
-
-int format_ifname_full_alloc(int ifindex, FormatIfnameFlag flag, char **ret) {
-        char buf[IF_NAMESIZE], *copy;
-        int r;
-
-        assert(ret);
-
-        r = format_ifname_full(ifindex, flag, buf);
-        if (r < 0)
-                return r;
-
-        copy = strdup(buf);
-        if (!copy)
-                return -ENOMEM;
-
-        *ret = copy;
-        return 0;
-}
-
-char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {
+char* format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {
         typedef struct {
                 const char *suffix;
                 uint64_t factor;
@@ -77,15 +40,17 @@ char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {
 
         for (size_t i = 0; i < n; i++)
                 if (t >= table[i].factor) {
-                        if (flag & FORMAT_BYTES_BELOW_POINT) {
+                        uint64_t remainder = i != n - 1 ?
+                                (t / table[i + 1].factor * 10 / table[n - 1].factor) % 10 :
+                                (t * 10 / table[i].factor) % 10;
+
+                        if (FLAGS_SET(flag, FORMAT_BYTES_BELOW_POINT) && remainder > 0)
                                 (void) snprintf(buf, l,
                                                 "%" PRIu64 ".%" PRIu64 "%s",
                                                 t / table[i].factor,
-                                                i != n - 1 ?
-                                                (t / table[i + 1].factor * UINT64_C(10) / table[n - 1].factor) % UINT64_C(10):
-                                                (t * UINT64_C(10) / table[i].factor) % UINT64_C(10),
+                                                remainder,
                                                 table[i].suffix);
-                        } else
+                        else
                                 (void) snprintf(buf, l,
                                                 "%" PRIu64 "%s",
                                                 t / table[i].factor,
diff --git a/src/libnm-systemd-shared/src/basic/format-util.h b/src/libnm-systemd-shared/src/basic/format-util.h
index 8a80eb33..1939ee18 100644
--- a/src/libnm-systemd-shared/src/basic/format-util.h
+++ b/src/libnm-systemd-shared/src/basic/format-util.h
@@ -2,7 +2,6 @@
 #pragma once
 
 #include <inttypes.h>
-#include <net/if.h>
 #include <stdbool.h>
 
 #include "cgroup-util.h"
@@ -69,29 +68,6 @@ assert_cc(sizeof(gid_t) == sizeof(uint32_t));
 #endif
 
 typedef enum {
-        FORMAT_IFNAME_IFINDEX              = 1 << 0,
-        FORMAT_IFNAME_IFINDEX_WITH_PERCENT = (1 << 1) | FORMAT_IFNAME_IFINDEX,
-} FormatIfnameFlag;
-
-int format_ifname_full(int ifindex, FormatIfnameFlag flag, char buf[static IF_NAMESIZE]);
-int format_ifname_full_alloc(int ifindex, FormatIfnameFlag flag, char **ret);
-
-static inline int format_ifname(int ifindex, char buf[static IF_NAMESIZE]) {
-        return format_ifname_full(ifindex, 0, buf);
-}
-static inline int format_ifname_alloc(int ifindex, char **ret) {
-        return format_ifname_full_alloc(ifindex, 0, ret);
-}
-
-static inline char *_format_ifname_full(int ifindex, FormatIfnameFlag flag, char buf[static IF_NAMESIZE]) {
-        (void) format_ifname_full(ifindex, flag, buf);
-        return buf;
-}
-
-#define FORMAT_IFNAME_FULL(index, flag) _format_ifname_full(index, flag, (char[IF_NAMESIZE]){})
-#define FORMAT_IFNAME(index) _format_ifname_full(index, 0, (char[IF_NAMESIZE]){})
-
-typedef enum {
         FORMAT_BYTES_USE_IEC     = 1 << 0,
         FORMAT_BYTES_BELOW_POINT = 1 << 1,
         FORMAT_BYTES_TRAILING_B  = 1 << 2,
@@ -99,10 +75,10 @@ typedef enum {
 
 #define FORMAT_BYTES_MAX 16U
 
-char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) _warn_unused_result_;
+char* format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) _warn_unused_result_;
 
 _warn_unused_result_
-static inline char *format_bytes(char *buf, size_t l, uint64_t t) {
+static inline char* format_bytes(char *buf, size_t l, uint64_t t) {
         return format_bytes_full(buf, l, t, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | FORMAT_BYTES_TRAILING_B);
 }
 
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c
index 3f414794..0202933d 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.c
+++ b/src/libnm-systemd-shared/src/basic/fs-util.c
@@ -12,6 +12,7 @@
 
 #include "alloc-util.h"
 #include "btrfs.h"
+#include "chattr-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -156,10 +157,6 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
         }
 }
 
-int readlink_malloc(const char *p, char **ret) {
-        return readlinkat_malloc(AT_FDCWD, p, ret);
-}
-
 int readlink_value(const char *p, char **ret) {
         _cleanup_free_ char *link = NULL, *name = NULL;
         int r;
@@ -318,10 +315,7 @@ int fchmod_opath(int fd, mode_t m) {
                 if (errno != ENOENT)
                         return -errno;
 
-                if (proc_mounted() == 0)
-                        return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
-
-                return -ENOENT;
+                return proc_fd_enoent_errno();
         }
 
         return 0;
@@ -330,14 +324,21 @@ int fchmod_opath(int fd, mode_t m) {
 int futimens_opath(int fd, const struct timespec ts[2]) {
         /* Similar to fchmod_opath() but for futimens() */
 
-        if (utimensat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), ts, 0) < 0) {
+        assert(fd >= 0);
+
+        if (utimensat(fd, "", ts, AT_EMPTY_PATH) >= 0)
+                return 0;
+        if (errno != EINVAL)
+                return -errno;
+
+        /* Support for AT_EMPTY_PATH is added rather late (kernel 5.8), so fall back to going through /proc/
+         * if unavailable. */
+
+        if (utimensat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), ts, /* flags = */ 0) < 0) {
                 if (errno != ENOENT)
                         return -errno;
 
-                if (proc_mounted() == 0)
-                        return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
-
-                return -ENOENT;
+                return proc_fd_enoent_errno();
         }
 
         return 0;
@@ -375,9 +376,21 @@ int fd_warn_permissions(const char *path, int fd) {
         return stat_warn_permissions(path, &st);
 }
 
+int touch_fd(int fd, usec_t stamp) {
+        assert(fd >= 0);
+
+        if (stamp == USEC_INFINITY)
+                return futimens_opath(fd, /* ts= */ NULL);
+
+        struct timespec ts[2];
+        timespec_store(ts + 0, stamp);
+        ts[1] = ts[0];
+        return futimens_opath(fd, ts);
+}
+
 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
         _cleanup_close_ int fd = -EBADF;
-        int r, ret;
+        int ret;
 
         assert(path);
 
@@ -409,21 +422,10 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
          * something fchown(), fchmod(), futimensat() don't allow. */
         ret = fchmod_and_chown(fd, mode, uid, gid);
 
-        if (stamp != USEC_INFINITY) {
-                struct timespec ts[2];
-
-                timespec_store(&ts[0], stamp);
-                ts[1] = ts[0];
-                r = futimens_opath(fd, ts);
-        } else
-                r = futimens_opath(fd, NULL);
-        if (r < 0 && ret >= 0)
-                return r;
-
-        return ret;
+        return RET_GATHER(ret, touch_fd(fd, stamp));
 }
 
-int symlink_idempotent(const char *from, const char *to, bool make_relative) {
+int symlinkat_idempotent(const char *from, int atfd, const char *to, bool make_relative) {
         _cleanup_free_ char *relpath = NULL;
         int r;
 
@@ -438,13 +440,13 @@ int symlink_idempotent(const char *from, const char *to, bool make_relative) {
                 from = relpath;
         }
 
-        if (symlink(from, to) < 0) {
+        if (symlinkat(from, atfd, to) < 0) {
                 _cleanup_free_ char *p = NULL;
 
                 if (errno != EEXIST)
                         return -errno;
 
-                r = readlink_malloc(to, &p);
+                r = readlinkat_malloc(atfd, to, &p);
                 if (r == -EINVAL) /* Not a symlink? In that case return the original error we encountered: -EEXIST */
                         return -EEXIST;
                 if (r < 0) /* Any other error? In that case propagate it as is */
@@ -632,11 +634,11 @@ static int tmp_dir_internal(const char *def, const char **ret) {
                 return 0;
         }
 
-        k = is_dir(def, true);
+        k = is_dir(def, /* follow = */ true);
         if (k == 0)
                 k = -ENOTDIR;
         if (k < 0)
-                return r < 0 ? r : k;
+                return RET_GATHER(r, k);
 
         *ret = def;
         return 0;
@@ -644,6 +646,7 @@ static int tmp_dir_internal(const char *def, const char **ret) {
 
 #if 0 /* NM_IGNORED */
 int var_tmp_dir(const char **ret) {
+        assert(ret);
 
         /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
          * even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
@@ -655,6 +658,7 @@ int var_tmp_dir(const char **ret) {
 #endif /* NM_IGNORED */
 
 int tmp_dir(const char **ret) {
+        assert(ret);
 
         /* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
          * backed by an in-memory file system: /tmp. */
@@ -664,6 +668,8 @@ int tmp_dir(const char **ret) {
 
 #if 0 /* NM_IGNORED */
 int unlink_or_warn(const char *filename) {
+        assert(filename);
+
         if (unlink(filename) < 0 && errno != ENOENT)
                 /* If the file doesn't exist and the fs simply was read-only (in which
                  * case unlink() returns EROFS even if the file doesn't exist), don't
@@ -675,39 +681,35 @@ int unlink_or_warn(const char *filename) {
 }
 
 int access_fd(int fd, int mode) {
+        assert(fd >= 0);
+
         /* Like access() but operates on an already open fd */
 
+        if (faccessat(fd, "", mode, AT_EMPTY_PATH) >= 0)
+                return 0;
+        if (errno != EINVAL)
+                return -errno;
+
+        /* Support for AT_EMPTY_PATH is added rather late (kernel 5.8), so fall back to going through /proc/
+         * if unavailable. */
+
         if (access(FORMAT_PROC_FD_PATH(fd), mode) < 0) {
                 if (errno != ENOENT)
                         return -errno;
 
-                /* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's
-                 * make things debuggable and distinguish the two. */
-
-                if (proc_mounted() == 0)
-                        return -ENOSYS;  /* /proc is not available or not set up properly, we're most likely in some chroot
-                                          * environment. */
-
-                return -EBADF; /* The directory exists, hence it's the fd that doesn't. */
+                return proc_fd_enoent_errno();
         }
 
         return 0;
 }
 
-void unlink_tempfilep(char (*p)[]) {
-        /* If the file is created with mkstemp(), it will (almost always)
-         * change the suffix. Treat this as a sign that the file was
-         * successfully created. We ignore both the rare case where the
-         * original suffix is used and unlink failures. */
-        if (!endswith(*p, ".XXXXXX"))
-                (void) unlink(*p);
-}
-
 int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
         _cleanup_close_ int truncate_fd = -EBADF;
         struct stat st;
         off_t l, bs;
 
+        assert(fd >= 0 || fd == AT_FDCWD);
+        assert(name);
         assert((flags & ~(UNLINK_REMOVEDIR|UNLINK_ERASE)) == 0);
 
         /* Operates like unlinkat() but also deallocates the file contents if it is a regular file and there's no other
@@ -1028,7 +1030,7 @@ int parse_cifs_service(
         return 0;
 }
 
-int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
+int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode) {
         _cleanup_close_ int fd = -EBADF, parent_fd = -EBADF;
         _cleanup_free_ char *fname = NULL, *parent = NULL;
         int r;
@@ -1064,7 +1066,7 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
                 path = fname;
         }
 
-        fd = xopenat_full(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, /* xopen_flags = */ 0, mode);
+        fd = xopenat_full(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, xopen_flags, mode);
         if (IN_SET(fd, -ELOOP, -ENOTDIR))
                 return -EEXIST;
         if (fd < 0)
@@ -1074,46 +1076,50 @@ 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) {
-        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));
+         * shortcut to openat() otherwise.
+         *
+         * Note that this routine is a bit more strict with symlinks than regular openat() is. If O_NOFOLLOW
+         * is not specified, then we'll follow the symlink when opening an existing file but we will *not*
+         * follow it when creating a new one (because that's a terrible UNIX misfeature and generally a
+         * security hole). */
 
         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);
+                if (ret_newly_created)
+                        *ret_newly_created = FLAGS_SET(flags, O_CREAT);
                 return fd;
         }
 
-        for (;;) {
+        for (unsigned attempts = 7;;) {
                 /* 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;
+                        if (ret_newly_created)
+                                *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);
+                /* So the file didn't exist yet, hence create it with O_CREAT/O_EXCL/O_NOFOLLOW. */
+                fd = openat(dirfd, pathname, flags | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
                 if (fd >= 0) {
-                        *ret_newly_created = true;
+                        if (ret_newly_created)
+                                *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 */
+                /* Hmm, so now we got EEXIST? Then someone might have created the file between the first and
+                 * second call to openat(). Let's try again but with a limit so we don't spin forever. */
 
                 if (--attempts == 0) /* Give up eventually, somebody is playing with us */
                         return -EEXIST;
@@ -1122,11 +1128,14 @@ int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, b
 
 int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
         _cleanup_close_ int fd = -EBADF;
-        bool made = false;
+        bool made_dir = false, made_file = false;
         int r;
 
         assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
 
+        /* An inode cannot be both a directory and a regular file at the same time. */
+        assert(!(FLAGS_SET(open_flags, O_DIRECTORY) && FLAGS_SET(xopen_flags, XO_REGULAR)));
+
         /* This is like openat(), but has a few tricks up its sleeves, extending behaviour:
          *
          *   • O_DIRECTORY|O_CREAT is supported, which causes a directory to be created, and immediately
@@ -1135,17 +1144,37 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
          *   • If O_CREAT is used with XO_LABEL, any created file will be immediately relabelled.
          *
          *   • If the path is specified NULL or empty, behaves like fd_reopen().
+         *
+         *   • If XO_NOCOW is specified will turn on the NOCOW btrfs flag on the file, if available.
+         *
+         *   • if XO_REGULAR is specified will return an error if inode is not a regular file.
+         *
+         *   • If mode is specified as MODE_INVALID, we'll use 0755 for dirs, and 0644 for regular files.
          */
 
+        if (mode == MODE_INVALID)
+                mode = (open_flags & O_DIRECTORY) ? 0755 : 0644;
+
         if (isempty(path)) {
                 assert(!FLAGS_SET(open_flags, O_CREAT|O_EXCL));
+
+                if (FLAGS_SET(xopen_flags, XO_REGULAR)) {
+                        r = fd_verify_regular(dir_fd);
+                        if (r < 0)
+                                return r;
+                }
+
                 return fd_reopen(dir_fd, open_flags & ~O_NOFOLLOW);
         }
 
+        bool call_label_ops_post = false;
+
         if (FLAGS_SET(open_flags, O_CREAT) && FLAGS_SET(xopen_flags, XO_LABEL)) {
                 r = label_ops_pre(dir_fd, path, FLAGS_SET(open_flags, O_DIRECTORY) ? S_IFDIR : S_IFREG);
                 if (r < 0)
                         return r;
+
+                call_label_ops_post = true;
         }
 
         if (FLAGS_SET(open_flags, O_DIRECTORY|O_CREAT)) {
@@ -1156,49 +1185,100 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
                 if (r == -EEXIST) {
                         if (FLAGS_SET(open_flags, O_EXCL))
                                 return -EEXIST;
-
-                        made = false;
                 } else if (r < 0)
                         return r;
                 else
-                        made = true;
-
-                if (FLAGS_SET(xopen_flags, XO_LABEL)) {
-                        r = label_ops_post(dir_fd, path);
-                        if (r < 0)
-                                return r;
-                }
+                        made_dir = true;
 
                 open_flags &= ~(O_EXCL|O_CREAT);
-                xopen_flags &= ~XO_LABEL;
         }
 
-        fd = RET_NERRNO(openat(dir_fd, path, open_flags, mode));
-        if (fd < 0) {
-                if (IN_SET(fd,
-                           /* We got ENOENT? then someone else immediately removed it after we
-                           * created it. In that case let's return immediately without unlinking
-                           * anything, because there simply isn't anything to unlink anymore. */
-                           -ENOENT,
-                           /* is a symlink? exists already → created by someone else, don't unlink */
-                           -ELOOP,
-                           /* not a directory? exists already → created by someone else, don't unlink */
-                           -ENOTDIR))
-                        return fd;
+        if (FLAGS_SET(xopen_flags, XO_REGULAR)) {
+                /* Guarantee we return a regular fd only, and don't open the file unless we verified it
+                 * first */
 
-                if (made)
-                        (void) unlinkat(dir_fd, path, AT_REMOVEDIR);
+                if (FLAGS_SET(open_flags, O_PATH)) {
+                        fd = openat(dir_fd, path, open_flags, mode);
+                        if (fd < 0) {
+                                r = -errno;
+                                goto error;
+                        }
 
-                return fd;
+                        r = fd_verify_regular(fd);
+                        if (r < 0)
+                                goto error;
+
+                } else if (FLAGS_SET(open_flags, O_CREAT|O_EXCL)) {
+                        /* In O_EXCL mode we can just create the thing, everything is dealt with for us */
+                        fd = openat(dir_fd, path, open_flags, mode);
+                        if (fd < 0) {
+                                r = -errno;
+                                goto error;
+                        }
+
+                        made_file = true;
+                } else {
+                        /* Otherwise pin the inode first via O_PATH */
+                        _cleanup_close_ int inode_fd = openat(dir_fd, path, O_PATH|O_CLOEXEC|(open_flags & O_NOFOLLOW));
+                        if (inode_fd < 0) {
+                                if (errno != ENOENT || !FLAGS_SET(open_flags, O_CREAT)) {
+                                        r = -errno;
+                                        goto error;
+                                }
+
+                                /* Doesn't exist yet, then try to create it */
+                                fd = openat(dir_fd, path, open_flags|O_CREAT|O_EXCL, mode);
+                                if (fd < 0) {
+                                        r = -errno;
+                                        goto error;
+                                }
+
+                                made_file = true;
+                        } else {
+                                /* OK, we pinned it. Now verify it's actually a regular file, and then reopen it */
+                                r = fd_verify_regular(inode_fd);
+                                if (r < 0)
+                                        goto error;
+
+                                fd = fd_reopen(inode_fd, open_flags & ~(O_NOFOLLOW|O_CREAT));
+                                if (fd < 0) {
+                                        r = fd;
+                                        goto error;
+                                }
+                        }
+                }
+        } else {
+                fd = openat_report_new(dir_fd, path, open_flags, mode, &made_file);
+                if (fd < 0) {
+                        r = fd;
+                        goto error;
+                }
         }
 
-        if (FLAGS_SET(open_flags, O_CREAT) && FLAGS_SET(xopen_flags, XO_LABEL)) {
-                r = label_ops_post(dir_fd, path);
+        if (call_label_ops_post) {
+                call_label_ops_post = false;
+
+                r = label_ops_post(fd, /* path= */ NULL, made_file || made_dir);
                 if (r < 0)
-                        return r;
+                        goto error;
+        }
+
+        if (FLAGS_SET(xopen_flags, XO_NOCOW)) {
+                r = chattr_fd(fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
+                if (r < 0 && !ERRNO_IS_NOT_SUPPORTED(r))
+                        goto error;
         }
 
         return TAKE_FD(fd);
+
+error:
+        if (call_label_ops_post)
+                (void) label_ops_post(fd >= 0 ? fd : dir_fd, fd >= 0 ? NULL : path, made_dir || made_file);
+
+        if (made_dir || made_file)
+                (void) unlinkat(dir_fd, path, made_dir ? AT_REMOVEDIR : 0);
+
+        return r;
 }
 
 #if 0 /* NM_IGNORED */
@@ -1247,4 +1327,103 @@ int xopenat_lock_full(
 
         return TAKE_FD(fd);
 }
+
+int link_fd(int fd, int newdirfd, const char *newpath) {
+        int r, k;
+
+        assert(fd >= 0);
+        assert(newdirfd >= 0 || newdirfd == AT_FDCWD);
+        assert(newpath);
+
+        /* Try linking via /proc/self/fd/ first. */
+        r = RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), newdirfd, newpath, AT_SYMLINK_FOLLOW));
+        if (r != -ENOENT)
+                return r;
+
+        /* Fall back to symlinking via AT_EMPTY_PATH as fallback (this requires CAP_DAC_READ_SEARCH and a
+         * more recent kernel, but does not require /proc/ mounted) */
+        k = proc_mounted();
+        if (k < 0)
+                return r;
+        if (k > 0)
+                return -EBADF;
+
+        return RET_NERRNO(linkat(fd, "", newdirfd, newpath, AT_EMPTY_PATH));
+}
+
+int linkat_replace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
+        _cleanup_close_ int old_fd = -EBADF;
+        int r;
+
+        assert(olddirfd >= 0 || olddirfd == AT_FDCWD);
+        assert(newdirfd >= 0 || newdirfd == AT_FDCWD);
+        assert(!isempty(newpath)); /* source path is optional, but the target path is not */
+
+        /* Like linkat() but replaces the target if needed. Is a NOP if source and target already share the
+         * same inode. */
+
+        if (olddirfd == AT_FDCWD && isempty(oldpath)) /* Refuse operating on the cwd (which is a dir, and dirs can't be hardlinked) */
+                return -EISDIR;
+
+        if (path_implies_directory(oldpath)) /* Refuse these definite directories early */
+                return -EISDIR;
+
+        if (path_implies_directory(newpath))
+                return -EISDIR;
+
+        /* First, try to link this directly */
+        if (oldpath)
+                r = RET_NERRNO(linkat(olddirfd, oldpath, newdirfd, newpath, 0));
+        else
+                r = link_fd(olddirfd, newdirfd, newpath);
+        if (r >= 0)
+                return 0;
+        if (r != -EEXIST)
+                return r;
+
+        old_fd = xopenat(olddirfd, oldpath, O_PATH|O_CLOEXEC);
+        if (old_fd < 0)
+                return old_fd;
+
+        struct stat old_st;
+        if (fstat(old_fd, &old_st) < 0)
+                return -errno;
+
+        if (S_ISDIR(old_st.st_mode)) /* Don't bother if we are operating on a directory */
+                return -EISDIR;
+
+        struct stat new_st;
+        if (fstatat(newdirfd, newpath, &new_st, AT_SYMLINK_NOFOLLOW) < 0)
+                return -errno;
+
+        if (S_ISDIR(new_st.st_mode)) /* Refuse replacing directories */
+                return -EEXIST;
+
+        if (stat_inode_same(&old_st, &new_st)) /* Already the same inode? Then shortcut this */
+                return 0;
+
+        _cleanup_free_ char *tmp_path = NULL;
+        r = tempfn_random(newpath, /* extra= */ NULL, &tmp_path);
+        if (r < 0)
+                return r;
+
+        r = link_fd(old_fd, newdirfd, tmp_path);
+        if (r < 0) {
+                if (!ERRNO_IS_PRIVILEGE(r))
+                        return r;
+
+                /* If that didn't work due to permissions then go via the path of the dentry */
+                r = RET_NERRNO(linkat(olddirfd, oldpath, newdirfd, tmp_path, 0));
+                if (r < 0)
+                        return r;
+        }
+
+        r = RET_NERRNO(renameat(newdirfd, tmp_path, newdirfd, newpath));
+        if (r < 0) {
+                (void) unlinkat(newdirfd, tmp_path, /* flags= */ 0);
+                return r;
+        }
+
+        return 0;
+}
 #endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.h b/src/libnm-systemd-shared/src/basic/fs-util.h
index 6a1e2e76..eb031a0c 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.h
+++ b/src/libnm-systemd-shared/src/basic/fs-util.h
@@ -28,9 +28,11 @@ int rmdir_parents(const char *path, const char *stop);
 int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
 
 int readlinkat_malloc(int fd, const char *p, char **ret);
-int readlink_malloc(const char *p, char **r);
+static inline int readlink_malloc(const char *p, char **ret) {
+        return readlinkat_malloc(AT_FDCWD, p, ret);
+}
 int readlink_value(const char *p, char **ret);
-int readlink_and_make_absolute(const char *p, char **r);
+int readlink_and_make_absolute(const char *p, char **ret);
 
 int chmod_and_chown_at(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid);
 static inline int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
@@ -49,16 +51,21 @@ int futimens_opath(int fd, const struct timespec ts[2]);
 int fd_warn_permissions(const char *path, int fd);
 int stat_warn_permissions(const char *path, const struct stat *st);
 
-#define laccess(path, mode)                                             \
+#define access_nofollow(path, mode)                                             \
         RET_NERRNO(faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW))
 
+int touch_fd(int fd, usec_t stamp);
+
 int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
 
 static inline int touch(const char *path) {
         return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
 }
 
-int symlink_idempotent(const char *from, const char *to, bool make_relative);
+int symlinkat_idempotent(const char *from, int atfd, const char *to, bool make_relative);
+static inline int symlink_idempotent(const char *from, const char *to, bool make_relative) {
+        return symlinkat_idempotent(from, AT_FDCWD, to, make_relative);
+}
 
 int symlinkat_atomic_full(const char *from, int atfd, const char *to, bool make_relative);
 static inline int symlink_atomic(const char *from, const char *to) {
@@ -105,8 +112,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free);
 
 int access_fd(int fd, int mode);
 
-void unlink_tempfilep(char (*p)[]);
-
 typedef enum UnlinkDeallocateFlags {
         UNLINK_REMOVEDIR = 1 << 0,
         UNLINK_ERASE     = 1 << 1,
@@ -128,15 +133,23 @@ 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);
-
 typedef enum XOpenFlags {
-        XO_LABEL     = 1 << 0,
-        XO_SUBVOLUME = 1 << 1,
+        XO_LABEL     = 1 << 0, /* When creating: relabel */
+        XO_SUBVOLUME = 1 << 1, /* When creating as directory: make it a subvolume */
+        XO_NOCOW     = 1 << 2, /* Enable NOCOW mode after opening */
+        XO_REGULAR   = 1 << 3, /* Fail if the inode is not a regular file */
 } XOpenFlags;
 
+int open_mkdir_at_full(int dirfd, const char *path, int flags, XOpenFlags xopen_flags, mode_t mode);
+static inline int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
+        return open_mkdir_at_full(dirfd, path, flags, 0, mode);
+}
+static inline int open_mkdir(const char *path, int flags, mode_t mode) {
+        return open_mkdir_at_full(AT_FDCWD, path, flags, 0, mode);
+}
+
+int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created);
+
 int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
 static inline int xopenat(int dir_fd, const char *path, int open_flags) {
         return xopenat_full(dir_fd, path, open_flags, 0, 0);
@@ -146,3 +159,16 @@ int xopenat_lock_full(int dir_fd, const char *path, int open_flags, XOpenFlags x
 static inline int xopenat_lock(int dir_fd, const char *path, int open_flags, LockType locktype, int operation) {
         return xopenat_lock_full(dir_fd, path, open_flags, 0, 0, locktype, operation);
 }
+
+int link_fd(int fd, int newdirfd, const char *newpath);
+
+int linkat_replace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
+
+static inline int at_flags_normalize_nofollow(int flags) {
+        if (FLAGS_SET(flags, AT_SYMLINK_FOLLOW)) {
+                assert(!FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW));
+                flags &= ~AT_SYMLINK_FOLLOW;
+        } else
+                flags |= AT_SYMLINK_NOFOLLOW;
+        return flags;
+}
diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.c b/src/libnm-systemd-shared/src/basic/glyph-util.c
index 58d64a03..d38698b6 100644
--- a/src/libnm-systemd-shared/src/basic/glyph-util.c
+++ b/src/libnm-systemd-shared/src/basic/glyph-util.c
@@ -25,7 +25,7 @@ bool emoji_enabled(void) {
         return cached_emoji_enabled;
 }
 
-const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
+const char* special_glyph_full(SpecialGlyph code, bool force_utf) {
 
         /* A list of a number of interesting unicode glyphs we can use to decorate our output. It's probably wise to be
          * conservative here, and primarily stick to the glyphs defined in the eurlatgr font, so that display still
@@ -82,6 +82,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
                         [SPECIAL_GLYPH_YELLOW_CIRCLE]           = "o",
                         [SPECIAL_GLYPH_BLUE_CIRCLE]             = "o",
                         [SPECIAL_GLYPH_GREEN_CIRCLE]            = "o",
+                        [SPECIAL_GLYPH_SUPERHERO]               = "S",
+                        [SPECIAL_GLYPH_IDCARD]                  = "@",
                 },
 
                 /* UTF-8 */
@@ -151,6 +153,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
                         [SPECIAL_GLYPH_YELLOW_CIRCLE]           = u8"🟡",
                         [SPECIAL_GLYPH_BLUE_CIRCLE]             = u8"🔵",
                         [SPECIAL_GLYPH_GREEN_CIRCLE]            = u8"🟢",
+                        [SPECIAL_GLYPH_SUPERHERO]               = u8"🦸",
+                        [SPECIAL_GLYPH_IDCARD]                  = u8"🪪",
                 },
         };
 
diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.h b/src/libnm-systemd-shared/src/basic/glyph-util.h
index db8dbbff..ca4d4eda 100644
--- a/src/libnm-systemd-shared/src/basic/glyph-util.h
+++ b/src/libnm-systemd-shared/src/basic/glyph-util.h
@@ -55,22 +55,24 @@ typedef enum SpecialGlyph {
         SPECIAL_GLYPH_YELLOW_CIRCLE,
         SPECIAL_GLYPH_BLUE_CIRCLE,
         SPECIAL_GLYPH_GREEN_CIRCLE,
+        SPECIAL_GLYPH_SUPERHERO,
+        SPECIAL_GLYPH_IDCARD,
         _SPECIAL_GLYPH_MAX,
         _SPECIAL_GLYPH_INVALID = -EINVAL,
 } SpecialGlyph;
 
 bool emoji_enabled(void);
 
-const char *special_glyph_full(SpecialGlyph code, bool force_utf) _const_;
+const char* special_glyph_full(SpecialGlyph code, bool force_utf) _const_;
 
-static inline const char *special_glyph(SpecialGlyph code) {
+static inline const char* special_glyph(SpecialGlyph code) {
         return special_glyph_full(code, false);
 }
 
-static inline const char *special_glyph_check_mark(bool b) {
+static inline const char* special_glyph_check_mark(bool b) {
         return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK);
 }
 
-static inline const char *special_glyph_check_mark_space(bool b) {
+static inline const char* special_glyph_check_mark_space(bool b) {
         return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : " ";
 }
diff --git a/src/libnm-systemd-shared/src/basic/hashmap.c b/src/libnm-systemd-shared/src/basic/hashmap.c
index 9686af0d..6b0247c3 100644
--- a/src/libnm-systemd-shared/src/basic/hashmap.c
+++ b/src/libnm-systemd-shared/src/basic/hashmap.c
@@ -878,6 +878,26 @@ int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_
         return ordered_hashmap_put(*h, key, value);
 }
 
+int _ordered_hashmap_ensure_replace(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value  HASHMAP_DEBUG_PARAMS) {
+        int r;
+
+        r = _ordered_hashmap_ensure_allocated(h, hash_ops  HASHMAP_DEBUG_PASS_ARGS);
+        if (r < 0)
+                return r;
+
+        return ordered_hashmap_replace(*h, key, value);
+}
+
+int _hashmap_ensure_replace(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value  HASHMAP_DEBUG_PARAMS) {
+        int r;
+
+        r = _hashmap_ensure_allocated(h, hash_ops  HASHMAP_DEBUG_PASS_ARGS);
+        if (r < 0)
+                return r;
+
+        return hashmap_replace(*h, key, value);
+}
+
 static void hashmap_free_no_clear(HashmapBase *h) {
         assert(!h->has_indirect);
         assert(h->n_direct_entries == 0);
diff --git a/src/libnm-systemd-shared/src/basic/hashmap.h b/src/libnm-systemd-shared/src/basic/hashmap.h
index 49d9d118..01a4fb32 100644
--- a/src/libnm-systemd-shared/src/basic/hashmap.h
+++ b/src/libnm-systemd-shared/src/basic/hashmap.h
@@ -130,14 +130,19 @@ HashmapBase* _hashmap_copy(HashmapBase *h  HASHMAP_DEBUG_PARAMS);
 int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
 int _hashmap_ensure_put(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value  HASHMAP_DEBUG_PARAMS);
 int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
+int _hashmap_ensure_replace(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value  HASHMAP_DEBUG_PARAMS);
 
 #define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops  HASHMAP_DEBUG_SRC_ARGS)
 #define hashmap_ensure_put(s, ops, key, value) _hashmap_ensure_put(s, ops, key, value  HASHMAP_DEBUG_SRC_ARGS)
 #define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops  HASHMAP_DEBUG_SRC_ARGS)
+#define hashmap_ensure_replace(s, ops, key, value) _hashmap_ensure_replace(s, ops, key, value  HASHMAP_DEBUG_SRC_ARGS)
 
 int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value  HASHMAP_DEBUG_PARAMS);
 #define ordered_hashmap_ensure_put(s, ops, key, value) _ordered_hashmap_ensure_put(s, ops, key, value  HASHMAP_DEBUG_SRC_ARGS)
 
+int _ordered_hashmap_ensure_replace(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value  HASHMAP_DEBUG_PARAMS);
+#define ordered_hashmap_ensure_replace(s, ops, key, value) _ordered_hashmap_ensure_replace(s, ops, key, value  HASHMAP_DEBUG_SRC_ARGS)
+
 IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h);
 static inline IteratedCache* hashmap_iterated_cache_new(Hashmap *h) {
         return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
diff --git a/src/libnm-systemd-shared/src/basic/hexdecoct.c b/src/libnm-systemd-shared/src/basic/hexdecoct.c
index 41228520..1acff812 100644
--- a/src/libnm-systemd-shared/src/basic/hexdecoct.c
+++ b/src/libnm-systemd-shared/src/basic/hexdecoct.c
@@ -38,7 +38,7 @@ int undecchar(char c) {
 }
 
 char hexchar(int x) {
-        static const char table[16] = "0123456789abcdef";
+        static const char table[] = "0123456789abcdef";
 
         return table[x & 15];
 }
@@ -57,7 +57,7 @@ int unhexchar(char c) {
         return -EINVAL;
 }
 
-char *hexmem(const void *p, size_t l) {
+char* hexmem(const void *p, size_t l) {
         const uint8_t *x;
         char *r, *z;
 
@@ -171,8 +171,8 @@ int unhexmem_full(
  * useful when representing NSEC3 hashes, as one can then verify the
  * order of hashes directly from their representation. */
 char base32hexchar(int x) {
-        static const char table[32] = "0123456789"
-                                      "ABCDEFGHIJKLMNOPQRSTUV";
+        static const char table[] = "0123456789"
+                                    "ABCDEFGHIJKLMNOPQRSTUV";
 
         return table[x & 31];
 }
@@ -191,7 +191,7 @@ int unbase32hexchar(char c) {
         return -EINVAL;
 }
 
-char *base32hexmem(const void *p, size_t l, bool padding) {
+char* base32hexmem(const void *p, size_t l, bool padding) {
         char *r, *z;
         const uint8_t *x;
         size_t len;
@@ -522,9 +522,9 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l
 
 /* https://tools.ietf.org/html/rfc4648#section-4 */
 char base64char(int x) {
-        static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                                      "abcdefghijklmnopqrstuvwxyz"
-                                      "0123456789+/";
+        static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                    "abcdefghijklmnopqrstuvwxyz"
+                                    "0123456789+/";
         return table[x & 63];
 }
 #endif /* NM_IGNORED */
@@ -533,9 +533,9 @@ char base64char(int x) {
  * since we don't want "/" appear in interface names (since interfaces appear in sysfs as filenames).
  * See section #5 of RFC 4648. */
 char urlsafe_base64char(int x) {
-        static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                                      "abcdefghijklmnopqrstuvwxyz"
-                                      "0123456789-_";
+        static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                    "abcdefghijklmnopqrstuvwxyz"
+                                    "0123456789-_";
         return table[x & 63];
 }
 
@@ -873,6 +873,9 @@ void hexdump(FILE *f, const void *p, size_t s) {
 
         assert(b || s == 0);
 
+        if (s == SIZE_MAX)
+                s = strlen(p);
+
         if (!f)
                 f = stdout;
 
diff --git a/src/libnm-systemd-shared/src/basic/hexdecoct.h b/src/libnm-systemd-shared/src/basic/hexdecoct.h
index 0a10af3e..d160ca28 100644
--- a/src/libnm-systemd-shared/src/basic/hexdecoct.h
+++ b/src/libnm-systemd-shared/src/basic/hexdecoct.h
@@ -17,7 +17,7 @@ int undecchar(char c) _const_;
 char hexchar(int x) _const_;
 int unhexchar(char c) _const_;
 
-char *hexmem(const void *p, size_t l);
+char* hexmem(const void *p, size_t l);
 int unhexmem_full(const char *p, size_t l, bool secure, void **ret_data, size_t *ret_size);
 static inline int unhexmem(const char *p, void **ret_data, size_t *ret_size) {
         return unhexmem_full(p, SIZE_MAX, false, ret_data, ret_size);
@@ -30,7 +30,7 @@ char base64char(int x) _const_;
 char urlsafe_base64char(int x) _const_;
 int unbase64char(char c) _const_;
 
-char *base32hexmem(const void *p, size_t l, bool padding);
+char* base32hexmem(const void *p, size_t l, bool padding);
 int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
 
 ssize_t base64mem_full(const void *p, size_t l, size_t line_break, 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 310e057a..44445f1e 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.c
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c
@@ -197,58 +197,69 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_
 }
 
 #if 0 /* NM_IGNORED */
-int in_addr_prefix_intersect(
-                int family,
-                const union in_addr_union *a,
+bool in4_addr_prefix_intersect(
+                const struct in_addr *a,
                 unsigned aprefixlen,
-                const union in_addr_union *b,
+                const struct in_addr *b,
                 unsigned bprefixlen) {
 
-        unsigned m;
-
         assert(a);
         assert(b);
 
-        /* Checks whether there are any addresses that are in both networks */
+        unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in_addr) * 8));
+        if (m == 0)
+                return true; /* Let's return earlier, to avoid shift by 32. */
 
-        m = MIN(aprefixlen, bprefixlen);
+        uint32_t x = be32toh(a->s_addr ^ b->s_addr);
+        uint32_t n = 0xFFFFFFFFUL << (32 - m);
+        return (x & n) == 0;
+}
 
-        if (family == AF_INET) {
-                uint32_t x, nm;
+bool in6_addr_prefix_intersect(
+                const struct in6_addr *a,
+                unsigned aprefixlen,
+                const struct in6_addr *b,
+                unsigned bprefixlen) {
 
-                x = be32toh(a->in.s_addr ^ b->in.s_addr);
-                nm = m == 0 ? 0 : 0xFFFFFFFFUL << (32 - m);
+        assert(a);
+        assert(b);
 
-                return (x & nm) == 0;
-        }
+        unsigned m = MIN3(aprefixlen, bprefixlen, (unsigned) (sizeof(struct in6_addr) * 8));
+        if (m == 0)
+                return true;
 
-        if (family == AF_INET6) {
-                unsigned i;
+        for (size_t i = 0; i < sizeof(struct in6_addr); i++) {
+                uint8_t x = a->s6_addr[i] ^ b->s6_addr[i];
+                uint8_t n = m < 8 ? (0xFF << (8 - m)) : 0xFF;
+                if ((x & n) != 0)
+                        return false;
 
-                if (m > 128)
-                        m = 128;
+                if (m <= 8)
+                        break;
 
-                for (i = 0; i < 16; i++) {
-                        uint8_t x, nm;
+                m -= 8;
+        }
 
-                        x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
+        return true;
+}
 
-                        if (m < 8)
-                                nm = 0xFF << (8 - m);
-                        else
-                                nm = 0xFF;
+int in_addr_prefix_intersect(
+                int family,
+                const union in_addr_union *a,
+                unsigned aprefixlen,
+                const union in_addr_union *b,
+                unsigned bprefixlen) {
+
+        assert(a);
+        assert(b);
 
-                        if ((x & nm) != 0)
-                                return 0;
+        /* Checks whether there are any addresses that are in both networks. */
 
-                        if (m > 8)
-                                m -= 8;
-                        else
-                                m = 0;
-                }
+        if (family == AF_INET)
+                return in4_addr_prefix_intersect(&a->in, aprefixlen, &b->in, bprefixlen);
 
-                return 1;
-        }
+        if (family == AF_INET6)
+                return in6_addr_prefix_intersect(&a->in6, aprefixlen, &b->in6, bprefixlen);
 
         return -EAFNOSUPPORT;
 }
@@ -888,7 +899,7 @@ int in_addr_prefix_from_string(
         return 0;
 }
 
-int in_addr_prefix_from_string_auto_internal(
+int in_addr_prefix_from_string_auto_full(
                 const char *p,
                 InAddrPrefixLenMode mode,
                 int *ret_family,
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 5c820c6e..2efe9aec 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.h
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h
@@ -61,7 +61,22 @@ bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a);
 bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b);
 bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b);
 int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
-int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
+bool in4_addr_prefix_intersect(
+                const struct in_addr *a,
+                unsigned aprefixlen,
+                const struct in_addr *b,
+                unsigned bprefixlen);
+bool in6_addr_prefix_intersect(
+                const struct in6_addr *a,
+                unsigned aprefixlen,
+                const struct in6_addr *b,
+                unsigned bprefixlen);
+int in_addr_prefix_intersect(
+                int family,
+                const union in_addr_union *a,
+                unsigned aprefixlen,
+                const union in_addr_union *b,
+                unsigned bprefixlen);
 int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
 int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth);
 int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen);
@@ -166,9 +181,9 @@ typedef enum InAddrPrefixLenMode {
         PREFIXLEN_REFUSE, /* Fail with -ENOANO if prefixlen is not specified. */
 } InAddrPrefixLenMode;
 
-int in_addr_prefix_from_string_auto_internal(const char *p, InAddrPrefixLenMode mode, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
+int in_addr_prefix_from_string_auto_full(const char *p, InAddrPrefixLenMode mode, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
 static inline int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) {
-        return in_addr_prefix_from_string_auto_internal(p, PREFIXLEN_FULL, ret_family, ret_prefix, ret_prefixlen);
+        return in_addr_prefix_from_string_auto_full(p, PREFIXLEN_FULL, ret_family, ret_prefix, ret_prefixlen);
 }
 
 static inline size_t FAMILY_ADDRESS_SIZE(int family) {
diff --git a/src/libnm-systemd-shared/src/basic/inotify-util.c b/src/libnm-systemd-shared/src/basic/inotify-util.c
index c748bf1b..14e012ab 100644
--- a/src/libnm-systemd-shared/src/basic/inotify-util.c
+++ b/src/libnm-systemd-shared/src/basic/inotify-util.c
@@ -44,7 +44,10 @@ bool inotify_event_next(
 }
 
 int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
-        int wd, r;
+        int wd;
+
+        assert(fd >= 0);
+        assert(what >= 0);
 
         /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
         wd = inotify_add_watch(fd, FORMAT_PROC_FD_PATH(what), mask);
@@ -52,14 +55,7 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
                 if (errno != ENOENT)
                         return -errno;
 
-                /* Didn't work with ENOENT? If so, then either /proc/ isn't mounted, or the fd is bad */
-                r = proc_mounted();
-                if (r == 0)
-                        return -ENOSYS;
-                if (r > 0)
-                        return -EBADF;
-
-                return -ENOENT; /* OK, no clue, let's propagate the original error */
+                return proc_fd_enoent_errno();
         }
 
         return wd;
diff --git a/src/libnm-systemd-shared/src/basic/iovec-util.h b/src/libnm-systemd-shared/src/basic/iovec-util.h
index 8cfa5717..86845404 100644
--- a/src/libnm-systemd-shared/src/basic/iovec-util.h
+++ b/src/libnm-systemd-shared/src/basic/iovec-util.h
@@ -6,25 +6,16 @@
 #include <sys/uio.h>
 
 #include "alloc-util.h"
+#include "iovec-util-fundamental.h"
 #include "macro.h"
 
-/* An iovec pointing to a single NUL byte */
-#define IOVEC_NUL_BYTE (const struct iovec) {                   \
-                .iov_base = (void*) (const uint8_t[1]) { 0 },   \
-                .iov_len = 1,                                   \
-        }
+extern const struct iovec iovec_nul_byte; /* Points to a single NUL byte */
+extern const struct iovec iovec_empty;    /* Points to an empty, but valid (i.e. non-NULL) pointer */
 
 size_t iovec_total_size(const struct iovec *iovec, size_t n);
 
 bool iovec_increment(struct iovec *iovec, size_t n, size_t k);
 
-/* This accepts both const and non-const pointers */
-#define IOVEC_MAKE(base, len)                                           \
-        (struct iovec) {                                                \
-                .iov_base = (void*) (base),                             \
-                .iov_len = (len),                                       \
-        }
-
 static inline struct iovec* iovec_make_string(struct iovec *iovec, const char *s) {
         assert(iovec);
         /* We don't use strlen_ptr() here, because we don't want to include string-util.h for now */
@@ -41,14 +32,6 @@ static inline struct iovec* iovec_make_string(struct iovec *iovec, const char *s
                 .iov_len = STRLEN(s),           \
         }
 
-static inline void iovec_done(struct iovec *iovec) {
-        /* A _cleanup_() helper that frees the iov_base in the iovec */
-        assert(iovec);
-
-        iovec->iov_base = mfree(iovec->iov_base);
-        iovec->iov_len = 0;
-}
-
 static inline void iovec_done_erase(struct iovec *iovec) {
         assert(iovec);
 
@@ -56,16 +39,6 @@ static inline void iovec_done_erase(struct iovec *iovec) {
         iovec->iov_len = 0;
 }
 
-static inline bool iovec_is_set(const struct iovec *iovec) {
-        /* Checks if the iovec points to a non-empty chunk of memory */
-        return iovec && iovec->iov_len > 0 && iovec->iov_base;
-}
-
-static inline bool iovec_is_valid(const struct iovec *iovec) {
-        /* Checks if the iovec is either NULL, empty or points to a valid bit of memory */
-        return !iovec || (iovec->iov_base || iovec->iov_len == 0);
-}
-
 char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
 char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value);
 
@@ -97,3 +70,5 @@ static inline struct iovec *iovec_memdup(const struct iovec *source, struct iove
 
         return ret;
 }
+
+struct iovec* iovec_append(struct iovec *iovec, const struct iovec *append);
diff --git a/src/libnm-systemd-shared/src/basic/label.c b/src/libnm-systemd-shared/src/basic/label.c
index a08a238f..ab78f85d 100644
--- a/src/libnm-systemd-shared/src/basic/label.c
+++ b/src/libnm-systemd-shared/src/basic/label.c
@@ -6,10 +6,13 @@
 #include <stddef.h>
 
 #include "label.h"
+#include "macro.h"
 
 static const LabelOps *label_ops = NULL;
 
 int label_ops_set(const LabelOps *ops) {
+        assert(ops);
+
         if (label_ops)
                 return -EBUSY;
 
@@ -17,6 +20,10 @@ int label_ops_set(const LabelOps *ops) {
         return 0;
 }
 
+void label_ops_reset(void) {
+        label_ops = NULL;
+}
+
 int label_ops_pre(int dir_fd, const char *path, mode_t mode) {
         if (!label_ops || !label_ops->pre)
                 return 0;
@@ -24,9 +31,9 @@ int label_ops_pre(int dir_fd, const char *path, mode_t mode) {
         return label_ops->pre(dir_fd, path, mode);
 }
 
-int label_ops_post(int dir_fd, const char *path) {
+int label_ops_post(int dir_fd, const char *path, bool created) {
         if (!label_ops || !label_ops->post)
                 return 0;
 
-        return label_ops->post(dir_fd, path);
+        return label_ops->post(dir_fd, path, created);
 }
diff --git a/src/libnm-systemd-shared/src/basic/label.h b/src/libnm-systemd-shared/src/basic/label.h
index 9644e435..d001307a 100644
--- a/src/libnm-systemd-shared/src/basic/label.h
+++ b/src/libnm-systemd-shared/src/basic/label.h
@@ -1,14 +1,16 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <stdbool.h>
 #include <sys/types.h>
 
 typedef struct LabelOps {
         int (*pre)(int dir_fd, const char *path, mode_t mode);
-        int (*post)(int dir_fd, const char *path);
+        int (*post)(int dir_fd, const char *path, bool created);
 } LabelOps;
 
 int label_ops_set(const LabelOps *label_ops);
+void label_ops_reset(void);
 
 int label_ops_pre(int dir_fd, const char *path, mode_t mode);
-int label_ops_post(int dir_fd, const char *path);
+int label_ops_post(int dir_fd, const char *path, bool created);
diff --git a/src/libnm-systemd-shared/src/basic/locale-util.c b/src/libnm-systemd-shared/src/basic/locale-util.c
index 95648775..0654fde8 100644
--- a/src/libnm-systemd-shared/src/basic/locale-util.c
+++ b/src/libnm-systemd-shared/src/basic/locale-util.c
@@ -279,8 +279,7 @@ int locale_is_installed(const char *name) {
         if (STR_IN_SET(name, "C", "POSIX")) /* These ones are always OK */
                 return true;
 
-        _cleanup_(freelocalep) locale_t loc =
-                newlocale(LC_ALL_MASK, name, 0);
+        _cleanup_(freelocalep) locale_t loc = newlocale(LC_ALL_MASK, name, (locale_t) 0);
         if (loc == (locale_t) 0)
                 return errno == ENOMEM ? -ENOMEM : false;
 
diff --git a/src/libnm-systemd-shared/src/basic/lock-util.h b/src/libnm-systemd-shared/src/basic/lock-util.h
index 91b332f8..a67d8b2c 100644
--- a/src/libnm-systemd-shared/src/basic/lock-util.h
+++ b/src/libnm-systemd-shared/src/basic/lock-util.h
@@ -2,6 +2,8 @@
 #pragma once
 
 #include <fcntl.h>
+/* Include here so consumers have LOCK_{EX,SH,NB} available. */
+#include <sys/file.h>
 
 typedef struct LockFile {
         int dir_fd;
@@ -17,7 +19,7 @@ static inline int make_lock_file(const char *p, int operation, LockFile *ret) {
 int make_lock_file_for(const char *p, int operation, LockFile *ret);
 void release_lock_file(LockFile *f);
 
-#define LOCK_FILE_INIT { .dir_fd = -EBADF, .fd = -EBADF }
+#define LOCK_FILE_INIT (LockFile) { .dir_fd = -EBADF, .fd = -EBADF }
 
 /* POSIX locks with the same interface as flock(). */
 int posix_lock(int fd, int operation);
diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h
index 1b5bc655..6477bff4 100644
--- a/src/libnm-systemd-shared/src/basic/log.h
+++ b/src/libnm-systemd-shared/src/basic/log.h
@@ -18,25 +18,26 @@ struct signalfd_siginfo;
 
 typedef enum LogTarget{
         LOG_TARGET_CONSOLE,
-        LOG_TARGET_CONSOLE_PREFIXED,
         LOG_TARGET_KMSG,
         LOG_TARGET_JOURNAL,
-        LOG_TARGET_JOURNAL_OR_KMSG,
         LOG_TARGET_SYSLOG,
+        LOG_TARGET_CONSOLE_PREFIXED,
+        LOG_TARGET_JOURNAL_OR_KMSG,
         LOG_TARGET_SYSLOG_OR_KMSG,
         LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */
         LOG_TARGET_NULL,
-        _LOG_TARGET_MAX,
+        _LOG_TARGET_SINGLE_MAX = LOG_TARGET_SYSLOG + 1,
+        _LOG_TARGET_MAX = LOG_TARGET_NULL + 1,
         _LOG_TARGET_INVALID = -EINVAL,
 } LogTarget;
 
 /* This log level disables logging completely. It can only be passed to log_set_max_level() and cannot be
- * used a regular log level. */
+ * used as a regular log level. */
 #define LOG_NULL (LOG_EMERG - 1)
+assert_cc(LOG_NULL == -1);
 
-/* Note to readers: << and >> have lower precedence (are evaluated earlier) than & and | */
-#define SYNTHETIC_ERRNO(num)                (1 << 30 | (num))
-#define IS_SYNTHETIC_ERRNO(val)             ((val) >> 30 & 1)
+#define SYNTHETIC_ERRNO(num)                (abs(num) | (1 << 30))
+#define IS_SYNTHETIC_ERRNO(val)             (((val) >> 30) == 1)
 #define ERRNO_VALUE(val)                    (abs(val) & ~(1 << 30))
 
 /* The callback function to be invoked when syntax warnings are seen
@@ -48,7 +49,7 @@ static inline void clear_log_syntax_callback(dummy_t *dummy) {
           set_log_syntax_callback(/* cb= */ NULL, /* userdata= */ NULL);
 }
 
-const char *log_target_to_string(LogTarget target) _const_;
+const char* log_target_to_string(LogTarget target) _const_;
 LogTarget log_target_from_string(const char *s) _pure_;
 void log_set_target(LogTarget target);
 void log_set_target_and_open(LogTarget target);
@@ -56,7 +57,7 @@ int log_set_target_from_string(const char *e);
 LogTarget log_get_target(void) _pure_;
 void log_settle_target(void);
 
-void log_set_max_level(int level);
+int log_set_max_level(int level);
 int log_set_max_level_from_string(const char *e);
 #if 0 /* NM_IGNORED */
 int log_get_max_level(void) _pure_;
@@ -67,6 +68,7 @@ log_get_max_level(void)
         return 7 /* LOG_DEBUG */;
 }
 #endif /* NM_IGNORED */
+int log_max_levels_to_string(int level, char **ret);
 
 void log_set_facility(int facility);
 
@@ -95,6 +97,7 @@ assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1);
 #define PROJECT_FILE __FILE__
 #endif /* NM_IGNORED */
 
+bool stderr_is_journal(void);
 int log_open(void);
 void log_close(void);
 void log_forget_fds(void);
@@ -434,9 +437,10 @@ int log_emergency_level(void);
 #define log_dump(level, buffer)                                         \
         log_dump_internal(level, 0, PROJECT_FILE, __LINE__, __func__, buffer)
 
-#define log_oom() log_oom_internal(LOG_ERR, PROJECT_FILE, __LINE__, __func__)
-#define log_oom_debug() log_oom_internal(LOG_DEBUG, PROJECT_FILE, __LINE__, __func__)
-#define log_oom_warning() log_oom_internal(LOG_WARNING, PROJECT_FILE, __LINE__, __func__)
+#define log_oom_full(level) log_oom_internal(level, PROJECT_FILE, __LINE__, __func__)
+#define log_oom()           log_oom_full(LOG_ERR)
+#define log_oom_debug()     log_oom_full(LOG_DEBUG)
+#define log_oom_warning()   log_oom_full(LOG_WARNING)
 
 bool log_on_console(void) _pure_;
 
@@ -498,6 +502,18 @@ int log_syntax_invalid_utf8_internal(
                 const char *func,
                 const char *rvalue);
 
+int log_syntax_parse_error_internal(
+                const char *unit,
+                const char *config_file,
+                unsigned config_line,
+                int error,
+                bool critical, /* When true, propagate the passed error, otherwise this always returns 0. */
+                const char *file,
+                int line,
+                const char *func,
+                const char *lvalue,
+                const char *rvalue);
+
 #define log_syntax(unit, level, config_file, config_line, error, ...)   \
         ({                                                              \
                 int _level = (level), _e = (error);                     \
@@ -514,6 +530,12 @@ int log_syntax_invalid_utf8_internal(
                         : -EINVAL;                                      \
         })
 
+#define log_syntax_parse_error_full(unit, config_file, config_line, error, critical, lvalue, rvalue) \
+        log_syntax_parse_error_internal(unit, config_file, config_line, error, critical, PROJECT_FILE, __LINE__, __func__, lvalue, rvalue)
+
+#define log_syntax_parse_error(unit, config_file, config_line, error, lvalue, rvalue) \
+        log_syntax_parse_error_full(unit, config_file, config_line, error, /* critical = */ false, lvalue, rvalue)
+
 #define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
 
 void log_setup(void);
@@ -570,8 +592,8 @@ typedef struct LogRateLimit {
 #define log_ratelimit_error_errno(error, ...)     log_ratelimit_full_errno(LOG_ERR,     error, __VA_ARGS__)
 #define log_ratelimit_emergency_errno(error, ...) log_ratelimit_full_errno(log_emergency_level(), error, __VA_ARGS__)
 
-const char *_log_set_prefix(const char *prefix, bool force);
-static inline const char *_log_unset_prefixp(const char **p) {
+const char* _log_set_prefix(const char *prefix, bool force);
+static inline const char* _log_unset_prefixp(const char **p) {
         assert(p);
         _log_set_prefix(*p, true);
         return NULL;
@@ -630,6 +652,15 @@ size_t log_context_num_contexts(void);
 /* Returns the number of fields in all attached log contexts. */
 size_t log_context_num_fields(void);
 
+static inline void _reset_log_level(int *saved_log_level) {
+        assert(saved_log_level);
+
+        log_set_max_level(*saved_log_level);
+}
+
+#define LOG_CONTEXT_SET_LOG_LEVEL(level) \
+        _cleanup_(_reset_log_level) _unused_ int _saved_log_level_ = log_set_max_level(level);
+
 #define LOG_CONTEXT_PUSH(...) \
         LOG_CONTEXT_PUSH_STRV(STRV_MAKE(__VA_ARGS__))
 
diff --git a/src/libnm-systemd-shared/src/basic/macro.h b/src/libnm-systemd-shared/src/basic/macro.h
index eec8cba6..026ec136 100644
--- a/src/libnm-systemd-shared/src/basic/macro.h
+++ b/src/libnm-systemd-shared/src/basic/macro.h
@@ -30,60 +30,6 @@
 #define _function_no_sanitize_float_cast_overflow_
 #endif
 
-#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined (__clang__)
-/* Temporarily disable some warnings */
-#define DISABLE_WARNING_DEPRECATED_DECLARATIONS                         \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
-
-#define DISABLE_WARNING_FORMAT_NONLITERAL                               \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
-
-#define DISABLE_WARNING_MISSING_PROTOTYPES                              \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"")
-
-#define DISABLE_WARNING_NONNULL                                         \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wnonnull\"")
-
-#define DISABLE_WARNING_SHADOW                                          \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wshadow\"")
-
-#define DISABLE_WARNING_INCOMPATIBLE_POINTER_TYPES                      \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"")
-
-#if HAVE_WSTRINGOP_TRUNCATION
-#  define DISABLE_WARNING_STRINGOP_TRUNCATION                           \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wstringop-truncation\"")
-#else
-#  define DISABLE_WARNING_STRINGOP_TRUNCATION                           \
-        _Pragma("GCC diagnostic push")
-#endif
-
-#define DISABLE_WARNING_TYPE_LIMITS                                     \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
-
-#define DISABLE_WARNING_ADDRESS                                         \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Waddress\"")
-
-#define REENABLE_WARNING                                                \
-        _Pragma("GCC diagnostic pop")
-#else
-#define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT
-#define DISABLE_WARNING_FORMAT_NONLITERAL
-#define DISABLE_WARNING_MISSING_PROTOTYPES
-#define DISABLE_WARNING_NONNULL
-#define DISABLE_WARNING_SHADOW
-#define REENABLE_WARNING
-#endif
-
 /* test harness */
 #define EXIT_TEST_SKIP 77
 
@@ -256,16 +202,10 @@ static inline int __coverity_check_and_return__(int condition) {
 #define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p)))
 #define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u)))
 
-#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p)))
-#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u)))
-
 #define CHAR_TO_STR(x) ((char[2]) { x, 0 })
 
 #define char_array_0(x) x[sizeof(x)-1] = 0;
 
-#define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member)
-#define endoffsetof_field(struct_type, member) (offsetof(struct_type, member) + sizeof_field(struct_type, member))
-
 /* Maximum buffer size needed for formatting an unsigned integer type as hex, including space for '0x'
  * prefix and trailing NUL suffix. */
 #define HEXADECIMAL_STR_MAX(type) (2 + sizeof(type) * 2 + 1)
@@ -311,15 +251,6 @@ static inline int __coverity_check_and_return__(int condition) {
 /* Pointers range from NULL to POINTER_MAX */
 #define POINTER_MAX ((void*) UINTPTR_MAX)
 
-#define _FOREACH_ARRAY(i, array, num, m, end)                           \
-        for (typeof(array[0]) *i = (array), *end = ({                   \
-                                typeof(num) m = (num);                  \
-                                (i && m > 0) ? i + m : NULL;            \
-                        }); end && i < end; i++)
-
-#define FOREACH_ARRAY(i, array, num)                                    \
-        _FOREACH_ARRAY(i, array, num, UNIQ_T(m, UNIQ), UNIQ_T(end, UNIQ))
-
 #define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope)             \
         scope type *name##_ref(type *p) {                       \
                 if (!p)                                         \
diff --git a/src/libnm-systemd-shared/src/basic/memory-util.h b/src/libnm-systemd-shared/src/basic/memory-util.h
index 294aed67..1f604cc4 100644
--- a/src/libnm-systemd-shared/src/basic/memory-util.h
+++ b/src/libnm-systemd-shared/src/basic/memory-util.h
@@ -20,7 +20,7 @@ size_t page_size(void) _pure_;
 #define PAGE_OFFSET_U64(l)     ALIGN_OFFSET_U64(l, page_size())
 
 /* 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) {
+static inline void* memcpy_safe(void *dst, const void *src, size_t n) {
         if (n == 0)
                 return dst;
         assert(src);
@@ -28,13 +28,20 @@ static inline void *memcpy_safe(void *dst, const void *src, size_t n) {
 }
 
 /* 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) {
+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);
 }
 
+#define mempcpy_typesafe(dst, src, n)                                   \
+        ({                                                              \
+                size_t _sz_;                                            \
+                assert_se(MUL_SAFE(&_sz_, sizeof((dst)[0]), n));        \
+                (typeof((dst)[0])*) mempcpy_safe(dst, src, _sz_);       \
+        })
+
 /* 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)
diff --git a/src/libnm-systemd-shared/src/basic/missing_fcntl.h b/src/libnm-systemd-shared/src/basic/missing_fcntl.h
index 3c85befd..a6188879 100644
--- a/src/libnm-systemd-shared/src/basic/missing_fcntl.h
+++ b/src/libnm-systemd-shared/src/basic/missing_fcntl.h
@@ -7,6 +7,10 @@
 #define F_LINUX_SPECIFIC_BASE 1024
 #endif
 
+#ifndef F_DUPFD_QUERY
+#define F_DUPFD_QUERY (F_LINUX_SPECIFIC_BASE + 3)
+#endif
+
 #ifndef F_SETPIPE_SZ
 #define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
 #endif
@@ -92,3 +96,7 @@
 #define RAW_O_LARGEFILE 00100000
 #endif
 #endif
+
+#ifndef AT_HANDLE_FID
+#define AT_HANDLE_FID AT_REMOVEDIR
+#endif
diff --git a/src/libnm-systemd-shared/src/basic/missing_pidfd.h b/src/libnm-systemd-shared/src/basic/missing_pidfd.h
new file mode 100644
index 00000000..4c815142
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/missing_pidfd.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <linux/types.h>
+#if HAVE_PIDFD_OPEN
+#include <sys/pidfd.h>
+#endif
+
+#ifndef PIDFS_IOCTL_MAGIC
+#  define PIDFS_IOCTL_MAGIC 0xFF
+#endif
+
+#ifndef PIDFD_GET_CGROUP_NAMESPACE
+#  define PIDFD_GET_CGROUP_NAMESPACE              _IO(PIDFS_IOCTL_MAGIC, 1)
+#  define PIDFD_GET_IPC_NAMESPACE                 _IO(PIDFS_IOCTL_MAGIC, 2)
+#  define PIDFD_GET_MNT_NAMESPACE                 _IO(PIDFS_IOCTL_MAGIC, 3)
+#  define PIDFD_GET_NET_NAMESPACE                 _IO(PIDFS_IOCTL_MAGIC, 4)
+#  define PIDFD_GET_PID_NAMESPACE                 _IO(PIDFS_IOCTL_MAGIC, 5)
+#  define PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE    _IO(PIDFS_IOCTL_MAGIC, 6)
+#  define PIDFD_GET_TIME_NAMESPACE                _IO(PIDFS_IOCTL_MAGIC, 7)
+#  define PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE   _IO(PIDFS_IOCTL_MAGIC, 8)
+#  define PIDFD_GET_USER_NAMESPACE                _IO(PIDFS_IOCTL_MAGIC, 9)
+#  define PIDFD_GET_UTS_NAMESPACE                 _IO(PIDFS_IOCTL_MAGIC, 10)
+#endif
+
+#ifndef PIDFD_GET_INFO
+struct pidfd_info {
+        __u64 mask;
+        __u64 cgroupid;
+        __u32 pid;
+        __u32 tgid;
+        __u32 ppid;
+        __u32 ruid;
+        __u32 rgid;
+        __u32 euid;
+        __u32 egid;
+        __u32 suid;
+        __u32 sgid;
+        __u32 fsuid;
+        __u32 fsgid;
+        __u32 spare0[1];
+};
+
+#define PIDFD_GET_INFO          _IOWR(PIDFS_IOCTL_MAGIC, 11, struct pidfd_info)
+#define PIDFD_INFO_PID          (1UL << 0)
+#define PIDFD_INFO_CREDS        (1UL << 1)
+#define PIDFD_INFO_CGROUPID     (1UL << 2)
+#endif
diff --git a/src/libnm-systemd-shared/src/basic/missing_random.h b/src/libnm-systemd-shared/src/basic/missing_random.h
index 443b9136..5f40c4e5 100644
--- a/src/libnm-systemd-shared/src/basic/missing_random.h
+++ b/src/libnm-systemd-shared/src/basic/missing_random.h
@@ -1,20 +1,28 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
-#if USE_SYS_RANDOM_H
+#include "macro.h"
+
+#if HAVE_GETRANDOM
 #  include <sys/random.h>
 #else
 #  include <linux/random.h>
 #endif
 
 #ifndef GRND_NONBLOCK
-#define GRND_NONBLOCK 0x0001
+#  define GRND_NONBLOCK 0x0001
+#else
+assert_cc(GRND_NONBLOCK == 0x0001);
 #endif
 
 #ifndef GRND_RANDOM
-#define GRND_RANDOM 0x0002
+#  define GRND_RANDOM 0x0002
+#else
+assert_cc(GRND_RANDOM == 0x0002);
 #endif
 
 #ifndef GRND_INSECURE
-#define GRND_INSECURE 0x0004
+#  define GRND_INSECURE 0x0004
+#else
+assert_cc(GRND_INSECURE == 0x0004);
 #endif
diff --git a/src/libnm-systemd-shared/src/basic/missing_socket.h b/src/libnm-systemd-shared/src/basic/missing_socket.h
index ffda7cc6..8460ce13 100644
--- a/src/libnm-systemd-shared/src/basic/missing_socket.h
+++ b/src/libnm-systemd-shared/src/basic/missing_socket.h
@@ -3,44 +3,6 @@
 
 #include <sys/socket.h>
 
-#if 0 /* NM_IGNORED */
-#if HAVE_LINUX_VM_SOCKETS_H
-#include <linux/vm_sockets.h>
-#else
-struct sockaddr_vm {
-        unsigned short svm_family;
-        unsigned short svm_reserved1;
-        unsigned int svm_port;
-        unsigned int svm_cid;
-        unsigned char svm_zero[sizeof(struct sockaddr) -
-                               sizeof(unsigned short) -
-                               sizeof(unsigned short) -
-                               sizeof(unsigned int) -
-                               sizeof(unsigned int)];
-};
-#endif /* !HAVE_LINUX_VM_SOCKETS_H */
-#endif /* NM_IGNORED */
-
-#ifndef VMADDR_CID_ANY
-#define VMADDR_CID_ANY -1U
-#endif
-
-#ifndef VMADDR_CID_HYPERVISOR
-#define VMADDR_CID_HYPERVISOR 0U
-#endif
-
-#ifndef VMADDR_CID_LOCAL
-#define VMADDR_CID_LOCAL 1U
-#endif
-
-#ifndef VMADDR_CID_HOST
-#define VMADDR_CID_HOST 2U
-#endif
-
-#ifndef VMADDR_PORT_ANY
-#define VMADDR_PORT_ANY -1U
-#endif
-
 #ifndef AF_VSOCK
 #define AF_VSOCK 40
 #endif
@@ -53,6 +15,10 @@ struct sockaddr_vm {
 #define SO_PEERGROUPS 59
 #endif
 
+#ifndef SO_PASSPIDFD
+#define SO_PASSPIDFD 76
+#endif
+
 #ifndef SO_PEERPIDFD
 #define SO_PEERPIDFD 77
 #endif
@@ -74,11 +40,14 @@ struct sockaddr_vm {
 #define SOL_SCTP 132
 #endif
 
-/* Not exposed yet. Defined in include/linux/socket.h */
 #ifndef SCM_SECURITY
 #define SCM_SECURITY 0x03
 #endif
 
+#ifndef SCM_PIDFD
+#define SCM_PIDFD 0x04
+#endif
+
 /* netinet/in.h */
 #ifndef IP_FREEBIND
 #define IP_FREEBIND 15
@@ -100,7 +69,9 @@ struct sockaddr_vm {
 #define IPV6_RECVFRAGSIZE 77
 #endif
 
-/* linux/sockios.h */
-#ifndef SIOCGSKNS
-#define SIOCGSKNS 0x894C
+/* The maximum number of fds that SCM_RIGHTS accepts. This is an internal kernel constant, but very much
+ * useful for userspace too. It's documented in unix(7) these days, hence should be fairly reliable to define
+ * here. */
+#ifndef SCM_MAX_FD
+#define SCM_MAX_FD 253U
 #endif
diff --git a/src/libnm-systemd-shared/src/basic/missing_syscall.h b/src/libnm-systemd-shared/src/basic/missing_syscall.h
index 149c5b48..da6f9827 100644
--- a/src/libnm-systemd-shared/src/basic/missing_syscall.h
+++ b/src/libnm-systemd-shared/src/basic/missing_syscall.h
@@ -22,6 +22,7 @@
 
 #include "macro.h"
 #include "missing_keyctl.h"
+#include "missing_sched.h"
 #include "missing_stat.h"
 #include "missing_syscall_def.h"
 
@@ -81,12 +82,7 @@ static inline int missing_ioprio_set(int which, int who, int ioprio) {
 
 #if !HAVE_MEMFD_CREATE
 static inline int missing_memfd_create(const char *name, unsigned int flags) {
-#  ifdef __NR_memfd_create
         return syscall(__NR_memfd_create, name, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
 }
 
 #  define memfd_create missing_memfd_create
@@ -98,12 +94,7 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) {
 #if !HAVE_GETRANDOM
 /* glibc says getrandom() returns ssize_t */
 static inline ssize_t missing_getrandom(void *buffer, size_t count, unsigned flags) {
-#  ifdef __NR_getrandom
         return syscall(__NR_getrandom, buffer, count, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
 }
 
 #  define getrandom missing_getrandom
@@ -150,12 +141,7 @@ static inline int missing_name_to_handle_at(int fd, const char *name, struct fil
 
 #if !HAVE_SETNS
 static inline int missing_setns(int fd, int nstype) {
-#  ifdef __NR_setns
         return syscall(__NR_setns, fd, nstype);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
 }
 
 #  define setns missing_setns
@@ -175,12 +161,7 @@ static inline pid_t raw_getpid(void) {
 
 #if !HAVE_RENAMEAT2
 static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) {
-#  ifdef __NR_renameat2
         return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
 }
 
 #  define renameat2 missing_renameat2
@@ -190,12 +171,7 @@ static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, c
 
 #if !HAVE_KCMP
 static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
-#  if defined __NR_kcmp && __NR_kcmp >= 0
         return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
 }
 
 #  define kcmp missing_kcmp
@@ -205,34 +181,19 @@ static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long i
 
 #if !HAVE_KEYCTL
 static inline long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) {
-#  if defined __NR_keyctl && __NR_keyctl >= 0
         return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
 
 #  define keyctl missing_keyctl
 }
 
 static inline key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) {
-#  if defined __NR_add_key && __NR_add_key >= 0
         return syscall(__NR_add_key, type, description, payload, plen, ringid);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
 
 #  define add_key missing_add_key
 }
 
 static inline key_serial_t missing_request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) {
-#  if defined __NR_request_key && __NR_request_key >= 0
         return syscall(__NR_request_key, type, description, callout_info, destringid);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
 
 #  define request_key missing_request_key
 }
@@ -344,12 +305,7 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask,
 
 #if !HAVE_PIDFD_SEND_SIGNAL
 static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) {
-#  ifdef __NR_pidfd_send_signal
         return syscall(__NR_pidfd_send_signal, fd, sig, info, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
 }
 
 #  define pidfd_send_signal missing_pidfd_send_signal
@@ -357,12 +313,7 @@ static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, un
 
 #if !HAVE_PIDFD_OPEN
 static inline int missing_pidfd_open(pid_t pid, unsigned flags) {
-#  ifdef __NR_pidfd_open
         return syscall(__NR_pidfd_open, pid, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
 }
 
 #  define pidfd_open missing_pidfd_open
@@ -671,6 +622,17 @@ static inline ssize_t missing_getdents64(int fd, void *buffer, size_t length) {
 
 #  define getdents64 missing_getdents64
 #endif
+
+/* ======================================================================= */
+
+#if !HAVE_SCHED_SETATTR
+
+static inline ssize_t missing_sched_setattr(pid_t pid, struct sched_attr *attr, unsigned int flags) {
+        return syscall(__NR_sched_setattr, pid, attr, flags);
+}
+
+#  define sched_setattr missing_sched_setattr
+#endif
 #endif /* NM_IGNORED */
 
 /* ======================================================================= */
@@ -686,3 +648,21 @@ int __clone2(int (*fn)(void *), void *stack_base, size_t stack_size, int flags,
  * at build time) and just define it. Once the kernel drops ia64 support, we can drop this too. */
 #define HAVE_CLONE 1
 #endif
+
+/* ======================================================================= */
+
+#if 0 /* NM_IGNORED */
+#if !HAVE_QUOTACTL_FD
+
+static inline int missing_quotactl_fd(int fd, int cmd, int id, void *addr) {
+#if defined __NR_quotactl_fd
+        return syscall(__NR_quotactl_fd, fd, cmd, id, addr);
+#else
+        errno = ENOSYS;
+        return -1;
+#endif
+}
+
+#  define quotactl_fd missing_quotactl_fd
+#endif
+#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/missing_threads.h b/src/libnm-systemd-shared/src/basic/missing_threads.h
index fb3b7224..c7da1dbd 100644
--- a/src/libnm-systemd-shared/src/basic/missing_threads.h
+++ b/src/libnm-systemd-shared/src/basic/missing_threads.h
@@ -5,9 +5,7 @@
 #if HAVE_THREADS_H
 #  include <threads.h>
 #elif !(defined(thread_local))
-/* Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
- * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 */
-#  if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
+#  ifndef __STDC_NO_THREADS__
 #    define thread_local _Thread_local
 #  else
 #    define thread_local __thread
diff --git a/src/libnm-systemd-shared/src/basic/missing_type.h b/src/libnm-systemd-shared/src/basic/missing_type.h
index f6233090..1d17705c 100644
--- a/src/libnm-systemd-shared/src/basic/missing_type.h
+++ b/src/libnm-systemd-shared/src/basic/missing_type.h
@@ -4,9 +4,9 @@
 #include <uchar.h>
 
 #if !HAVE_CHAR32_T
-#define char32_t uint32_t
+#  define char32_t uint32_t
 #endif
 
 #if !HAVE_CHAR16_T
-#define char16_t uint16_t
+#  define char16_t uint16_t
 #endif
diff --git a/src/libnm-systemd-shared/src/basic/missing_wait.h b/src/libnm-systemd-shared/src/basic/missing_wait.h
new file mode 100644
index 00000000..3965b5bd
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/missing_wait.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <sys/wait.h>
+
+#include "macro.h"
+
+#ifndef P_PIDFD
+#  define P_PIDFD 3
+#else
+assert_cc(P_PIDFD == 3);
+#endif
diff --git a/src/libnm-systemd-shared/src/basic/namespace-util.h b/src/libnm-systemd-shared/src/basic/namespace-util.h
index 34cbec3f..3d40a515 100644
--- a/src/libnm-systemd-shared/src/basic/namespace-util.h
+++ b/src/libnm-systemd-shared/src/basic/namespace-util.h
@@ -3,6 +3,8 @@
 
 #include <sys/types.h>
 
+#include "pidref.h"
+
 typedef enum NamespaceType {
         NAMESPACE_CGROUP,
         NAMESPACE_IPC,
@@ -19,9 +21,23 @@ typedef enum NamespaceType {
 extern const struct namespace_info {
         const char *proc_name;
         const char *proc_path;
-        unsigned int clone_flag;
+        unsigned long clone_flag;
+        unsigned long pidfd_get_ns_ioctl_cmd;
+        ino_t root_inode;
 } namespace_info[_NAMESPACE_TYPE_MAX + 1];
 
+NamespaceType clone_flag_to_namespace_type(unsigned long clone_flag);
+
+int pidref_namespace_open_by_type(const PidRef *pidref, NamespaceType type);
+int namespace_open_by_type(NamespaceType type);
+
+int pidref_namespace_open(
+                const PidRef *pidref,
+                int *ret_pidns_fd,
+                int *ret_mntns_fd,
+                int *ret_netns_fd,
+                int *ret_userns_fd,
+                int *ret_root_fd);
 int namespace_open(
                 pid_t pid,
                 int *ret_pidns_fd,
@@ -29,11 +45,28 @@ int namespace_open(
                 int *ret_netns_fd,
                 int *ret_userns_fd,
                 int *ret_root_fd);
+
 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
 
-int fd_is_ns(int fd, unsigned long nsflag);
+int fd_is_namespace(int fd, NamespaceType type);
+int is_our_namespace(int fd, NamespaceType type);
+
+int namespace_is_init(NamespaceType type);
+
+int pidref_in_same_namespace(PidRef *pid1, PidRef *pid2, NamespaceType type);
+static inline int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type) {
+        assert(pid1 >= 0);
+        assert(pid2 >= 0);
+        return pidref_in_same_namespace(pid1 == 0 ? NULL : &PIDREF_MAKE_FROM_PID(pid1),
+                                        pid2 == 0 ? NULL : &PIDREF_MAKE_FROM_PID(pid2),
+                                        type);
+}
+
+int namespace_get_leader(PidRef *pidref, NamespaceType type, PidRef *ret);
 
 int detach_mount_namespace(void);
+int detach_mount_namespace_harder(uid_t target_uid, gid_t target_gid);
+int detach_mount_namespace_userns(int userns_fd);
 
 static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
         /* Checks that the specified userns range makes sense, i.e. contains at least one UID, and the end
@@ -50,8 +83,16 @@ static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
         return true;
 }
 
+int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_range);
+
+int userns_acquire_empty(void);
 int userns_acquire(const char *uid_map, const char *gid_map);
-int netns_acquire(void);
-int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type);
+int userns_enter_and_pin(int userns_fd, pid_t *ret_pid);
 
-int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_range);
+int userns_get_base_uid(int userns_fd, uid_t *ret_uid, gid_t *ret_gid);
+
+int process_is_owned_by_uid(const PidRef *pidref, uid_t uid);
+
+int is_idmapping_supported(const char *path);
+
+int netns_acquire(void);
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.c b/src/libnm-systemd-shared/src/basic/parse-util.c
index 34a5375f..bff09b74 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.c
+++ b/src/libnm-systemd-shared/src/basic/parse-util.c
@@ -4,6 +4,7 @@
 
 #include <errno.h>
 #include <inttypes.h>
+#include <linux/ipv6.h>
 #include <net/if.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -640,7 +641,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
         s = *p;
 
         /* accept any number of digits, strtoull is limited to 19 */
-        for (size_t i = 0; i < digits; i++,s++) {
+        for (size_t i = 0; i < digits; i++, s++) {
                 if (!ascii_isdigit(*s)) {
                         if (i == 0)
                                 return -EINVAL;
@@ -721,22 +722,6 @@ int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high, bool allow
         return 0;
 }
 
-int parse_ip_prefix_length(const char *s, int *ret) {
-        unsigned l;
-        int r;
-
-        r = safe_atou(s, &l);
-        if (r < 0)
-                return r;
-
-        if (l > 128)
-                return -ERANGE;
-
-        *ret = (int) l;
-
-        return 0;
-}
-
 int parse_oom_score_adjust(const char *s, int *ret) {
         int r, v;
 
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.h b/src/libnm-systemd-shared/src/basic/parse-util.h
index c12988ef..a47c8c79 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.h
+++ b/src/libnm-systemd-shared/src/basic/parse-util.h
@@ -141,8 +141,6 @@ int parse_nice(const char *p, int *ret);
 int parse_ip_port(const char *s, uint16_t *ret);
 int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high, bool allow_zero);
 
-int parse_ip_prefix_length(const char *s, int *ret);
-
 int parse_oom_score_adjust(const char *s, int *ret);
 
 /* Implement floating point using fixed integers, to improve performance when
diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c
index 0e0f53d9..1de055d5 100644
--- a/src/libnm-systemd-shared/src/basic/path-util.c
+++ b/src/libnm-systemd-shared/src/basic/path-util.c
@@ -54,6 +54,7 @@ char* path_make_absolute(const char *p, const char *prefix) {
 
         return path_join(prefix, p);
 }
+#endif /* NM_IGNORED */
 
 int safe_getcwd(char **ret) {
         _cleanup_free_ char *cwd = NULL;
@@ -73,6 +74,7 @@ int safe_getcwd(char **ret) {
         return 0;
 }
 
+#if 0 /* NM_IGNORED */
 int path_make_absolute_cwd(const char *p, char **ret) {
         char *c;
         int r;
@@ -221,8 +223,10 @@ int path_make_relative_parent(const char *from_child, const char *to, char **ret
 }
 #endif /* NM_IGNORED */
 
-char* path_startswith_strv(const char *p, char **set) {
-        STRV_FOREACH(s, set) {
+char* path_startswith_strv(const char *p, char * const *strv) {
+        assert(p);
+
+        STRV_FOREACH(s, strv) {
                 char *t;
 
                 t = path_startswith(p, *s);
@@ -531,6 +535,20 @@ int path_compare_filename(const char *a, const char *b) {
         return strcmp(fa, fb);
 }
 
+#if 0 /* NM_IGNORED */
+int path_equal_or_inode_same_full(const char *a, const char *b, int flags) {
+        /* Returns true if paths are of the same entry, false if not, <0 on error. */
+
+        if (path_equal(a, b))
+                return 1;
+
+        if (!a || !b)
+                return 0;
+
+        return inode_same(a, b, flags);
+}
+#endif /* NM_IGNORED */
+
 char* path_extend_internal(char **x, ...) {
         size_t sz, old_sz;
         char *q, *nx;
@@ -646,7 +664,7 @@ static int find_executable_impl(const char *name, const char *root, char **ret_f
          * /usr/bin/sleep when find_executables is called. Hence, this function should be invoked when
          * needed to avoid unforeseen regression or other complicated changes. */
         if (root) {
-                 /* prefix root to name in case full paths are not specified */
+                /* prefix root to name in case full paths are not specified */
                 r = chase(name, root, CHASE_PREFIX_ROOT, &path_name, /* ret_fd= */ NULL);
                 if (r < 0)
                         return r;
@@ -662,6 +680,8 @@ static int find_executable_impl(const char *name, const char *root, char **ret_f
                 r = path_make_absolute_cwd(name, ret_filename);
                 if (r < 0)
                         return r;
+
+                path_simplify(*ret_filename);
         }
 
         if (ret_fd)
@@ -673,48 +693,49 @@ static int find_executable_impl(const char *name, const char *root, char **ret_f
 int find_executable_full(
                 const char *name,
                 const char *root,
-                char **exec_search_path,
+                char * const *exec_search_path,
                 bool use_path_envvar,
                 char **ret_filename,
                 int *ret_fd) {
 
         int last_error = -ENOENT, r = 0;
-        const char *p = NULL;
 
         assert(name);
 
         if (is_path(name))
                 return find_executable_impl(name, root, ret_filename, ret_fd);
 
-        if (use_path_envvar)
-                /* Plain getenv, not secure_getenv, because we want to actually allow the user to pick the
-                 * binary. */
-                p = getenv("PATH");
-        if (!p)
-                p = DEFAULT_PATH;
-
         if (exec_search_path) {
                 STRV_FOREACH(element, exec_search_path) {
                         _cleanup_free_ char *full_path = NULL;
 
-                        if (!path_is_absolute(*element))
+                        if (!path_is_absolute(*element)) {
+                                log_debug("Exec search path '%s' isn't absolute, ignoring.", *element);
                                 continue;
+                        }
 
                         full_path = path_join(*element, name);
                         if (!full_path)
                                 return -ENOMEM;
 
                         r = find_executable_impl(full_path, root, ret_filename, ret_fd);
-                        if (r < 0) {
-                                if (r != -EACCES)
-                                        last_error = r;
-                                continue;
-                        }
-                        return 0;
+                        if (r >= 0)
+                                return 0;
+                        if (r != -EACCES)
+                                last_error = r;
                 }
                 return last_error;
         }
 
+        const char *p = NULL;
+
+        if (use_path_envvar)
+                /* Plain getenv, not secure_getenv, because we want to actually allow the user to pick the
+                 * binary. */
+                p = getenv("PATH");
+        if (!p)
+                p = default_PATH();
+
         /* Resolve a single-component name to a full path */
         for (;;) {
                 _cleanup_free_ char *element = NULL;
@@ -725,22 +746,20 @@ int find_executable_full(
                 if (r == 0)
                         break;
 
-                if (!path_is_absolute(element))
+                if (!path_is_absolute(element)) {
+                        log_debug("Exec search path '%s' isn't absolute, ignoring.", element);
                         continue;
+                }
 
                 if (!path_extend(&element, name))
                         return -ENOMEM;
 
                 r = find_executable_impl(element, root, ret_filename, ret_fd);
-                if (r < 0) {
-                        /* PATH entries which we don't have access to are ignored, as per tradition. */
-                        if (r != -EACCES)
-                                last_error = r;
-                        continue;
-                }
-
-                /* Found it! */
-                return 0;
+                if (r >= 0) /* Found it! */
+                        return 0;
+                /* PATH entries which we don't have access to are ignored, as per tradition. */
+                if (r != -EACCES)
+                        last_error = r;
         }
 
         return last_error;
@@ -1102,7 +1121,6 @@ int path_extract_filename(const char *path, char **ret) {
 }
 
 int path_extract_directory(const char *path, char **ret) {
-        _cleanup_free_ char *a = NULL;
         const char *c, *next = NULL;
         int r;
 
@@ -1126,14 +1144,10 @@ int path_extract_directory(const char *path, char **ret) {
                 if (*path != '/') /* filename only */
                         return -EDESTADDRREQ;
 
-                a = strdup("/");
-                if (!a)
-                        return -ENOMEM;
-                *ret = TAKE_PTR(a);
-                return 0;
+                return strdup_to(ret, "/");
         }
 
-        a = strndup(path, next - path);
+        _cleanup_free_ char *a = strndup(path, next - path);
         if (!a)
                 return -ENOMEM;
 
@@ -1347,6 +1361,20 @@ bool dot_or_dot_dot(const char *path) {
 }
 
 #if 0 /* NM_IGNORED */
+bool path_implies_directory(const char *path) {
+
+        /* Sometimes, if we look at a path we already know it must refer to a directory, because it is
+         * suffixed with a slash, or its last component is "." or ".." */
+
+        if (!path)
+                return false;
+
+        if (dot_or_dot_dot(path))
+                return true;
+
+        return ENDSWITH_SET(path, "/", "/.", "/..");
+}
+
 bool empty_or_root(const char *path) {
 
         /* For operations relative to some root directory, returns true if the specified root directory is
@@ -1358,7 +1386,9 @@ bool empty_or_root(const char *path) {
         return path_equal(path, "/");
 }
 
-bool path_strv_contains(char **l, const char *path) {
+bool path_strv_contains(char * const *l, const char *path) {
+        assert(path);
+
         STRV_FOREACH(i, l)
                 if (path_equal(*i, path))
                         return true;
@@ -1366,7 +1396,9 @@ bool path_strv_contains(char **l, const char *path) {
         return false;
 }
 
-bool prefixed_path_strv_contains(char **l, const char *path) {
+bool prefixed_path_strv_contains(char * const *l, const char *path) {
+        assert(path);
+
         STRV_FOREACH(i, l) {
                 const char *j = *i;
 
@@ -1374,6 +1406,7 @@ bool prefixed_path_strv_contains(char **l, const char *path) {
                         j++;
                 if (*j == '+')
                         j++;
+
                 if (path_equal(j, path))
                         return true;
         }
@@ -1443,4 +1476,32 @@ int path_glob_can_match(const char *pattern, const char *prefix, char **ret) {
                 *ret = NULL;
         return false;
 }
+
+const char* default_PATH(void) {
+#if HAVE_SPLIT_BIN
+        static int split = -1;
+        int r;
+
+        /* Check whether /usr/sbin is not a symlink and return the appropriate $PATH.
+         * On error fall back to the safe value with both directories as configured… */
+
+        if (split < 0)
+                STRV_FOREACH_PAIR(bin, sbin, STRV_MAKE("/usr/bin", "/usr/sbin",
+                                                       "/usr/local/bin", "/usr/local/sbin")) {
+                        r = inode_same(*bin, *sbin, AT_NO_AUTOMOUNT);
+                        if (r > 0 || r == -ENOENT)
+                                continue;
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to compare \"%s\" and \"%s\", using compat $PATH: %m",
+                                                *bin, *sbin);
+                        split = true;
+                        break;
+                }
+        if (split < 0)
+                split = false;
+        if (split)
+                return DEFAULT_PATH_WITH_SBIN;
+#endif
+        return DEFAULT_PATH_WITHOUT_SBIN;
+}
 #endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/path-util.h b/src/libnm-systemd-shared/src/basic/path-util.h
index 5bb51ff5..9b13d958 100644
--- a/src/libnm-systemd-shared/src/basic/path-util.h
+++ b/src/libnm-systemd-shared/src/basic/path-util.h
@@ -12,27 +12,26 @@
 #include "time-util.h"
 
 #if 0 /* NM_IGNORED */
-#define PATH_SPLIT_SBIN_BIN(x) x "sbin:" x "bin"
-#define PATH_SPLIT_SBIN_BIN_NULSTR(x) x "sbin\0" x "bin\0"
+#define PATH_SPLIT_BIN(x) x "sbin:" x "bin"
+#define PATH_SPLIT_BIN_NULSTR(x) x "sbin\0" x "bin\0"
 
-#define PATH_NORMAL_SBIN_BIN(x) x "bin"
-#define PATH_NORMAL_SBIN_BIN_NULSTR(x) x "bin\0"
+#define PATH_MERGED_BIN(x) x "bin"
+#define PATH_MERGED_BIN_NULSTR(x) x "bin\0"
 
-#if HAVE_SPLIT_BIN
-#  define PATH_SBIN_BIN(x) PATH_SPLIT_SBIN_BIN(x)
-#  define PATH_SBIN_BIN_NULSTR(x) PATH_SPLIT_SBIN_BIN_NULSTR(x)
-#else
-#  define PATH_SBIN_BIN(x) PATH_NORMAL_SBIN_BIN(x)
-#  define PATH_SBIN_BIN_NULSTR(x) PATH_NORMAL_SBIN_BIN_NULSTR(x)
-#endif
+#define DEFAULT_PATH_WITH_SBIN PATH_SPLIT_BIN("/usr/local/") ":" PATH_SPLIT_BIN("/usr/")
+#define DEFAULT_PATH_WITHOUT_SBIN PATH_MERGED_BIN("/usr/local/") ":" PATH_MERGED_BIN("/usr/")
+
+#define DEFAULT_PATH_COMPAT PATH_SPLIT_BIN("/usr/local/") ":" PATH_SPLIT_BIN("/usr/") ":" PATH_SPLIT_BIN("/")
 
-#define DEFAULT_PATH PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/")
-#define DEFAULT_PATH_NULSTR PATH_SBIN_BIN_NULSTR("/usr/local/") PATH_SBIN_BIN_NULSTR("/usr/")
-#define DEFAULT_PATH_COMPAT PATH_SPLIT_SBIN_BIN("/usr/local/") ":" PATH_SPLIT_SBIN_BIN("/usr/") ":" PATH_SPLIT_SBIN_BIN("/")
+const char* default_PATH(void);
 
-#ifndef DEFAULT_USER_PATH
-#  define DEFAULT_USER_PATH DEFAULT_PATH
+static inline const char* default_user_PATH(void) {
+#ifdef DEFAULT_USER_PATH
+        return DEFAULT_USER_PATH;
+#else
+        return default_PATH();
 #endif
+}
 #endif /* NM_IGNORED */
 
 static inline bool is_path(const char *p) {
@@ -70,14 +69,19 @@ static inline bool path_equal_filename(const char *a, const char *b) {
         return path_compare_filename(a, b) == 0;
 }
 
+int path_equal_or_inode_same_full(const char *a, const char *b, int flags);
 static inline bool path_equal_or_inode_same(const char *a, const char *b, int flags) {
-        return path_equal(a, b) || inode_same(a, b, flags) > 0;
+        return path_equal_or_inode_same_full(a, b, flags) > 0;
 }
 
 char* path_extend_internal(char **x, ...);
 #define path_extend(x, ...) path_extend_internal(x, __VA_ARGS__, POINTER_MAX)
 #define path_join(...) path_extend_internal(NULL, __VA_ARGS__, POINTER_MAX)
 
+static inline char* skip_leading_slash(const char *p) {
+        return skip_leading_chars(p, "/");
+}
+
 typedef enum PathSimplifyFlags {
         PATH_SIMPLIFY_KEEP_TRAILING_SLASH = 1 << 0,
 } PathSimplifyFlags;
@@ -103,21 +107,23 @@ static inline int path_simplify_alloc(const char *path, char **ret) {
         return 0;
 }
 
-static inline bool path_equal_ptr(const char *a, const char *b) {
-        return !!a == !!b && (!a || path_equal(a, b));
-}
-
 /* Note: the search terminates on the first NULL item. */
 #define PATH_IN_SET(p, ...) path_strv_contains(STRV_MAKE(__VA_ARGS__), p)
 
-char* path_startswith_strv(const char *p, char **set);
+char* path_startswith_strv(const char *p, char * const *strv);
 #define PATH_STARTSWITH_SET(p, ...) path_startswith_strv(p, STRV_MAKE(__VA_ARGS__))
 
 int path_strv_make_absolute_cwd(char **l);
 char** path_strv_resolve(char **l, const char *root);
 char** path_strv_resolve_uniq(char **l, const char *root);
 
-int find_executable_full(const char *name, const char *root, char **exec_search_path, bool use_path_envvar, char **ret_filename, int *ret_fd);
+int find_executable_full(
+                const char *name,
+                const char *root,
+                char * const *exec_search_path,
+                bool use_path_envvar,
+                char **ret_filename,
+                int *ret_fd);
 static inline int find_executable(const char *name, char **ret_filename) {
         return find_executable_full(name, /* root= */ NULL, NULL, true, ret_filename, NULL);
 }
@@ -203,7 +209,9 @@ bool valid_device_allow_pattern(const char *path);
 
 bool dot_or_dot_dot(const char *path);
 
-static inline const char *skip_dev_prefix(const char *p) {
+bool path_implies_directory(const char *path);
+
+static inline const char* skip_dev_prefix(const char *p) {
         const char *e;
 
         /* Drop any /dev prefix if there is any */
@@ -218,7 +226,7 @@ static inline const char* empty_to_root(const char *path) {
         return isempty(path) ? "/" : path;
 }
 
-bool path_strv_contains(char **l, const char *path);
-bool prefixed_path_strv_contains(char **l, const char *path);
+bool path_strv_contains(char * const *l, const char *path);
+bool prefixed_path_strv_contains(char * const *l, const char *path);
 
 int path_glob_can_match(const char *pattern, const char *prefix, char **ret);
diff --git a/src/libnm-systemd-shared/src/basic/pidfd-util.c b/src/libnm-systemd-shared/src/basic/pidfd-util.c
new file mode 100644
index 00000000..d6bd5517
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/pidfd-util.c
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "nm-sd-adapt-shared.h"
+
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "errno-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "macro.h"
+#include "memory-util.h"
+#include "missing_magic.h"
+#include "missing_threads.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "pidfd-util.h"
+#include "process-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+
+static int have_pidfs = -1;
+
+static int pidfd_check_pidfs(int pid_fd) {
+
+        /* NB: the passed fd *must* be acquired via pidfd_open(), i.e. must be a true pidfd! */
+
+        if (have_pidfs >= 0)
+                return have_pidfs;
+
+        return (have_pidfs = fd_is_fs_type(pid_fd, PID_FS_MAGIC));
+}
+
+int pidfd_get_namespace(int fd, unsigned long ns_type_cmd) {
+        static bool cached_supported = true;
+
+        /* Obtain the namespace fd from pidfd directly through ioctl(PIDFD_GET_*_NAMESPACE).
+         *
+         * Returns -EOPNOTSUPP if ioctl on pidfds are not supported, -ENOPKG if the requested namespace
+         * is disabled in kernel. (The errno used are different from what kernel returns via ioctl(),
+         * see below) */
+
+        assert(fd >= 0);
+
+        /* If we know ahead of time that pidfs is unavailable, shortcut things. But otherwise we don't
+         * call pidfd_check_pidfs() here, which is kinda extraneous and our own cache is required
+         * anyways (pidfs is introduced in kernel 6.9 while ioctl support there is added in 6.11). */
+        if (have_pidfs == 0 || !cached_supported)
+                return -EOPNOTSUPP;
+
+        int nsfd = ioctl(fd, ns_type_cmd);
+        if (nsfd < 0) {
+                /* Kernel returns EOPNOTSUPP if the ns type in question is disabled. Hence we need to look
+                 * at precise errno instead of generic ERRNO_IS_(IOCTL_)NOT_SUPPORTED. */
+                if (IN_SET(errno, ENOTTY, EINVAL)) {
+                        cached_supported = false;
+                        return -EOPNOTSUPP;
+                }
+                if (errno == EOPNOTSUPP) /* Translate to something more recognizable */
+                        return -ENOPKG;
+
+                return -errno;
+        }
+
+        return nsfd;
+}
+
+#if 0 /* NM_IGNORED */
+static int pidfd_get_info(int fd, struct pidfd_info *info) {
+        static bool cached_supported = true;
+
+        assert(fd >= 0);
+        assert(info);
+
+        if (have_pidfs == 0 || !cached_supported)
+                return -EOPNOTSUPP;
+
+        if (ioctl(fd, PIDFD_GET_INFO, info) < 0) {
+                if (ERRNO_IS_IOCTL_NOT_SUPPORTED(errno)) {
+                        cached_supported = false;
+                        return -EOPNOTSUPP;
+                }
+
+                return -errno;
+        }
+
+        return 0;
+}
+
+static int pidfd_get_pid_fdinfo(int fd, pid_t *ret) {
+        char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
+        _cleanup_free_ char *fdinfo = NULL;
+        int r;
+
+        assert(fd >= 0);
+
+        xsprintf(path, "/proc/self/fdinfo/%i", fd);
+
+        r = read_full_virtual_file(path, &fdinfo, NULL);
+        if (r == -ENOENT)
+                return proc_fd_enoent_errno();
+        if (r < 0)
+                return r;
+
+        char *p = find_line_startswith(fdinfo, "Pid:");
+        if (!p)
+                return -ENOTTY; /* not a pidfd? */
+
+        p = skip_leading_chars(p, /* bad = */ NULL);
+        p[strcspn(p, WHITESPACE)] = 0;
+
+        if (streq(p, "0"))
+                return -EREMOTE; /* PID is in foreign PID namespace? */
+        if (streq(p, "-1"))
+                return -ESRCH;   /* refers to reaped process? */
+
+        return parse_pid(p, ret);
+}
+
+static int pidfd_get_pid_ioctl(int fd, pid_t *ret) {
+        struct pidfd_info info = { .mask = PIDFD_INFO_PID };
+        int r;
+
+        assert(fd >= 0);
+
+        r = pidfd_get_info(fd, &info);
+        if (r < 0)
+                return r;
+
+        assert(FLAGS_SET(info.mask, PIDFD_INFO_PID));
+
+        if (ret)
+                *ret = info.pid;
+        return 0;
+}
+
+int pidfd_get_pid(int fd, pid_t *ret) {
+        int r;
+
+        /* Converts a pidfd into a pid. We try ioctl(PIDFD_GET_INFO) (kernel 6.13+) first,
+         * /proc/self/fdinfo/ as fallback. Well known errors:
+         *
+         *    -EBADF   → fd invalid
+         *    -ESRCH   → fd valid, but process is already reaped
+         *
+         * pidfd_get_pid_fdinfo() might additionally fail for other reasons:
+         *
+         *    -ENOSYS  → /proc/ not mounted
+         *    -ENOTTY  → fd valid, but not a pidfd
+         *    -EREMOTE → fd valid, but pid is in another namespace we cannot translate to the local one
+         *               (when using PIDFD_GET_INFO this is indistinguishable from -ESRCH)
+         */
+
+        assert(fd >= 0);
+
+        r = pidfd_get_pid_ioctl(fd, ret);
+        if (r != -EOPNOTSUPP)
+                return r;
+
+        return pidfd_get_pid_fdinfo(fd, ret);
+}
+
+int pidfd_verify_pid(int pidfd, pid_t pid) {
+        pid_t current_pid;
+        int r;
+
+        assert(pidfd >= 0);
+        assert(pid > 0);
+
+        r = pidfd_get_pid(pidfd, &current_pid);
+        if (r < 0)
+                return r;
+
+        return current_pid != pid ? -ESRCH : 0;
+}
+
+int pidfd_get_ppid(int fd, pid_t *ret) {
+        struct pidfd_info info = { .mask = PIDFD_INFO_PID };
+        int r;
+
+        assert(fd >= 0);
+
+        r = pidfd_get_info(fd, &info);
+        if (r < 0)
+                return r;
+
+        assert(FLAGS_SET(info.mask, PIDFD_INFO_PID));
+
+        if (info.ppid == 0) /* See comments in pid_get_ppid() */
+                return -EADDRNOTAVAIL;
+
+        if (ret)
+                *ret = info.ppid;
+        return 0;
+}
+
+int pidfd_get_uid(int fd, uid_t *ret) {
+        struct pidfd_info info = { .mask = PIDFD_INFO_CREDS };
+        int r;
+
+        assert(fd >= 0);
+
+        r = pidfd_get_info(fd, &info);
+        if (r < 0)
+                return r;
+
+        assert(FLAGS_SET(info.mask, PIDFD_INFO_CREDS));
+
+        if (ret)
+                *ret = info.ruid;
+        return 0;
+}
+
+int pidfd_get_cgroupid(int fd, uint64_t *ret) {
+        struct pidfd_info info = { .mask = PIDFD_INFO_CGROUPID };
+        int r;
+
+        assert(fd >= 0);
+
+        r = pidfd_get_info(fd, &info);
+        if (r < 0)
+                return r;
+
+        assert(FLAGS_SET(info.mask, PIDFD_INFO_CGROUPID));
+
+        if (ret)
+                *ret = info.cgroupid;
+        return 0;
+}
+#endif /* NM_IGNORED */
+
+int pidfd_get_inode_id(int fd, uint64_t *ret) {
+        int r;
+
+        assert(fd >= 0);
+
+        r = pidfd_check_pidfs(fd);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EOPNOTSUPP;
+
+        struct stat st;
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (ret)
+                *ret = (uint64_t) st.st_ino;
+        return 0;
+}
+
+int pidfd_get_inode_id_self_cached(uint64_t *ret) {
+        static thread_local uint64_t cached = 0;
+        static thread_local pid_t initialized = 0; /* < 0: cached error; == 0: invalid; > 0: valid and pid that was current */
+        int r;
+
+        assert(ret);
+
+        if (initialized == getpid_cached()) {
+                *ret = cached;
+                return 0;
+        }
+        if (initialized < 0)
+                return initialized;
+
+        _cleanup_close_ int fd = pidfd_open(getpid_cached(), 0);
+        if (fd < 0)
+                return -errno;
+
+        r = pidfd_get_inode_id(fd, &cached);
+        if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
+                return (initialized = -EOPNOTSUPP);
+        if (r < 0)
+                return r;
+
+        *ret = cached;
+        initialized = getpid_cached();
+        return 0;
+}
diff --git a/src/libnm-systemd-shared/src/basic/pidfd-util.h b/src/libnm-systemd-shared/src/basic/pidfd-util.h
new file mode 100644
index 00000000..c20de6df
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/pidfd-util.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "missing_pidfd.h"
+#include "missing_syscall.h"
+
+int pidfd_get_namespace(int fd, unsigned long ns_type_cmd);
+
+int pidfd_get_pid(int fd, pid_t *ret);
+int pidfd_verify_pid(int pidfd, pid_t pid);
+
+int pidfd_get_ppid(int fd, pid_t *ret);
+int pidfd_get_uid(int fd, uid_t *ret);
+int pidfd_get_cgroupid(int fd, uint64_t *ret);
+
+int pidfd_get_inode_id(int fd, uint64_t *ret);
+
+int pidfd_get_inode_id_self_cached(uint64_t *ret);
diff --git a/src/libnm-systemd-shared/src/basic/pidref.h b/src/libnm-systemd-shared/src/basic/pidref.h
index c440c8b0..9e8a39ec 100644
--- a/src/libnm-systemd-shared/src/basic/pidref.h
+++ b/src/libnm-systemd-shared/src/basic/pidref.h
@@ -1,15 +1,50 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
-#include "macro.h"
-
-/* An embeddable structure carrying a reference to a process. Supposed to be used when tracking processes continuously. */
-typedef struct PidRef {
-        pid_t pid; /* always valid */
-        int fd;    /* only valid if pidfd are available in the kernel, and we manage to get an fd */
-} PidRef;
+typedef struct PidRef PidRef;
 
-#define PIDREF_NULL (const PidRef) { .fd = -EBADF }
+#include "macro.h"
+#include "process-util.h"
+
+/* An embeddable structure carrying a reference to a process. Supposed to be used when tracking processes
+ * continuously. This combines a PID, a modern Linux pidfd and the 64bit inode number of the pidfd into one
+ * structure. Note that depending on kernel support the pidfd might not be initialized, and if it is
+ * initialized then fd_id might still not be initialized (because the concept was added to the kernel much
+ * later than pidfds themselves).
+ *
+ * There are three special states a PidRef can be in:
+ *
+ * 1. It can be *unset*. Use pidref_is_set() to detect this case. Most operations attempted on such a PidRef
+ *    will fail with -ESRCH. Use PIDREF_NULL for initializing a PidRef in this state.
+ *
+ * 2. It can be marked as *automatic*. This is a special state indicating that a process reference is
+ *    supposed to be derived automatically from the current context. This is used by the Varlink/JSON
+ *    dispatcher as indication that a PidRef shall be derived from the connection peer, but might be
+ *    otherwise used too. When marked *automatic* the PidRef will also be considered *unset*, hence most
+ *    operations will fail with -ESRCH, as above.
+ *
+ * 3. It can be marked as *remote*. This is useful when deserializing a PidRef structure from an IPC message
+ *    or similar, and it has been determined that the given PID definitely doesn't refer to a local
+ *    process. In this case the PidRef logic will refrain from trying to acquire a pidfd for the
+ *    process. Moreover, most operations will fail with -EREMOTE. Only PidRef structures that are not marked
+ *    *unset* can be marked *remote*.
+ */
+struct PidRef {
+        pid_t pid;      /* > 0 if the PidRef is set, otherwise set to PID_AUTOMATIC if automatic mode is
+                         * desired, or 0 otherwise. */
+        int fd;         /* only valid if pidfd are available in the kernel, and we manage to get an fd. If we
+                         * know that the PID is not from the local machine we set this to -EREMOTE, otherwise
+                         * we use -EBADF as indicator the fd is invalid. */
+        uint64_t fd_id; /* the inode number of pidfd. only useful in kernel 6.9+ where pidfds live in
+                           their own pidfs and each process comes with a unique inode number */
+};
+
+#define PIDREF_NULL (PidRef) { .fd = -EBADF }
+
+/* A special pidref value that we are using when a PID shall be automatically acquired from some surrounding
+ * context, for example connection peer. Much like PIDREF_NULL it will be considered unset by
+ * pidref_is_set().*/
+#define PIDREF_AUTOMATIC (const PidRef) { .pid = PID_AUTOMATIC, .fd = -EBADF }
 
 /* Turns a pid_t into a PidRef structure on-the-fly *without* acquiring a pidfd for it. (As opposed to
  * pidref_set_pid() which does so *with* acquiring one, see below) */
@@ -19,18 +54,17 @@ static inline bool pidref_is_set(const PidRef *pidref) {
         return pidref && pidref->pid > 0;
 }
 
-static inline bool pidref_equal(const PidRef *a, const PidRef *b) {
+bool pidref_is_automatic(const PidRef *pidref);
 
-        if (pidref_is_set(a)) {
-                if (!pidref_is_set(b))
-                        return false;
-
-                return a->pid == b->pid;
-        }
-
-        return !pidref_is_set(b);
+static inline bool pidref_is_remote(const PidRef *pidref) {
+        /* If the fd is set to -EREMOTE we assume PidRef does not refer to a local PID, but on another
+         * machine (and we just got the PidRef initialized due to deserialization of some RPC message) */
+        return pidref_is_set(pidref) && pidref->fd == -EREMOTE;
 }
 
+int pidref_acquire_pidfd_id(PidRef *pidref);
+bool pidref_equal(PidRef *a, PidRef *b);
+
 /* This turns a pid_t into a PidRef structure, and acquires a pidfd for it, if possible. (As opposed to
  * PIDREF_MAKE_FROM_PID() above, which does not acquire a pidfd.) */
 int pidref_set_pid(PidRef *pidref, pid_t pid);
@@ -43,13 +77,13 @@ static inline int pidref_set_self(PidRef *pidref) {
         return pidref_set_pid(pidref, 0);
 }
 
-bool pidref_is_self(const PidRef *pidref);
+bool pidref_is_self(PidRef *pidref);
 
 void pidref_done(PidRef *pidref);
-PidRef *pidref_free(PidRef *pidref);
+PidRef* pidref_free(PidRef *pidref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(PidRef*, pidref_free);
 
-int pidref_copy(const PidRef *pidref, PidRef *dest);
+int pidref_copy(const PidRef *pidref, PidRef *ret);
 int pidref_dup(const PidRef *pidref, PidRef **ret);
 
 int pidref_new_from_pid(pid_t pid, PidRef **ret);
@@ -58,8 +92,8 @@ int pidref_kill(const PidRef *pidref, int sig);
 int pidref_kill_and_sigcont(const PidRef *pidref, int sig);
 int pidref_sigqueue(const PidRef *pidref, int sig, int value);
 
-int pidref_wait(const PidRef *pidref, siginfo_t *siginfo, int options);
-int pidref_wait_for_terminate(const PidRef *pidref, siginfo_t *ret);
+int pidref_wait(PidRef *pidref, siginfo_t *siginfo, int options);
+int pidref_wait_for_terminate(PidRef *pidref, siginfo_t *ret);
 
 static inline void pidref_done_sigkill_wait(PidRef *pidref) {
         if (!pidref_is_set(pidref))
diff --git a/src/libnm-systemd-shared/src/basic/prioq.c b/src/libnm-systemd-shared/src/basic/prioq.c
index b05b08da..c36d0ddd 100644
--- a/src/libnm-systemd-shared/src/basic/prioq.c
+++ b/src/libnm-systemd-shared/src/basic/prioq.c
@@ -26,8 +26,7 @@ struct prioq_item {
 
 struct Prioq {
         compare_func_t compare_func;
-        unsigned n_items, n_allocated;
-
+        unsigned n_items;
         struct prioq_item *items;
 };
 
@@ -144,28 +143,18 @@ static unsigned shuffle_down(Prioq *q, unsigned idx) {
 }
 
 int prioq_put(Prioq *q, void *data, unsigned *idx) {
-        struct prioq_item *i;
         unsigned k;
 
         assert(q);
 
-        if (q->n_items >= q->n_allocated) {
-                unsigned n;
-                struct prioq_item *j;
-
-                n = MAX((q->n_items+1) * 2, 16u);
-                j = reallocarray(q->items, n, sizeof(struct prioq_item));
-                if (!j)
-                        return -ENOMEM;
-
-                q->items = j;
-                q->n_allocated = n;
-        }
+        if (!GREEDY_REALLOC(q->items, MAX(q->n_items + 1, 16u)))
+                return -ENOMEM;
 
         k = q->n_items++;
-        i = q->items + k;
-        i->data = data;
-        i->idx = idx;
+        q->items[k] = (struct prioq_item) {
+                .data = data,
+                .idx = idx,
+        };
 
         if (idx)
                 *idx = k;
diff --git a/src/libnm-systemd-shared/src/basic/process-util.c b/src/libnm-systemd-shared/src/basic/process-util.c
index 5dd9003d..85187562 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.c
+++ b/src/libnm-systemd-shared/src/basic/process-util.c
@@ -27,6 +27,7 @@
 #include "alloc-util.h"
 #include "architecture.h"
 #include "argv-util.h"
+#include "cgroup-util.h"
 #include "dirent-util.h"
 #include "env-file.h"
 #include "env-util.h"
@@ -36,6 +37,7 @@
 #include "fileio.h"
 #include "fs-util.h"
 #include "hostname-util.h"
+#include "io-util.h"
 #include "locale-util.h"
 #include "log.h"
 #include "macro.h"
@@ -48,6 +50,7 @@
 #include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "pidfd-util.h"
 #include "process-util.h"
 #include "raw-clone.h"
 #include "rlimit-util.h"
@@ -57,6 +60,7 @@
 #include "string-table.h"
 #include "string-util.h"
 #include "terminal-util.h"
+#include "time-util.h"
 #include "user-util.h"
 #include "utf8.h"
 
@@ -103,8 +107,8 @@ int pid_get_comm(pid_t pid, char **ret) {
         _cleanup_free_ char *escaped = NULL, *comm = NULL;
         int r;
 
-        assert(ret);
         assert(pid >= 0);
+        assert(ret);
 
         if (pid == 0 || pid == getpid_cached()) {
                 comm = new0(char, TASK_COMM_LEN + 1); /* Must fit in 16 byte according to prctl(2) */
@@ -144,6 +148,9 @@ int pidref_get_comm(const PidRef *pid, char **ret) {
         if (!pidref_is_set(pid))
                 return -ESRCH;
 
+        if (pidref_is_remote(pid))
+                return -EREMOTE;
+
         r = pid_get_comm(pid->pid, &comm);
         if (r < 0)
                 return r;
@@ -290,6 +297,9 @@ int pidref_get_cmdline(const PidRef *pid, size_t max_columns, ProcessCmdlineFlag
         if (!pidref_is_set(pid))
                 return -ESRCH;
 
+        if (pidref_is_remote(pid))
+                return -EREMOTE;
+
         r = pid_get_cmdline(pid->pid, max_columns, flags, &s);
         if (r < 0)
                 return r;
@@ -332,6 +342,9 @@ int pidref_get_cmdline_strv(const PidRef *pid, ProcessCmdlineFlags flags, char *
         if (!pidref_is_set(pid))
                 return -ESRCH;
 
+        if (pidref_is_remote(pid))
+                return -EREMOTE;
+
         r = pid_get_cmdline_strv(pid->pid, flags, &args);
         if (r < 0)
                 return r;
@@ -387,33 +400,6 @@ int container_get_leader(const char *machine, pid_t *pid) {
         return 0;
 }
 
-int namespace_get_leader(pid_t pid, NamespaceType type, pid_t *ret) {
-        int r;
-
-        assert(ret);
-
-        for (;;) {
-                pid_t ppid;
-
-                r = get_process_ppid(pid, &ppid);
-                if (r < 0)
-                        return r;
-
-                r = in_same_namespace(pid, ppid, type);
-                if (r < 0)
-                        return r;
-                if (r == 0) {
-                        /* If the parent and the child are not in the same
-                         * namespace, then the child is the leader we are
-                         * looking for. */
-                        *ret = pid;
-                        return 0;
-                }
-
-                pid = ppid;
-        }
-}
-
 int pid_is_kernel_thread(pid_t pid) {
         _cleanup_free_ char *line = NULL;
         unsigned long long flags;
@@ -478,6 +464,9 @@ int pidref_is_kernel_thread(const PidRef *pid) {
         if (!pidref_is_set(pid))
                 return -ESRCH;
 
+        if (pidref_is_remote(pid))
+                return -EREMOTE;
+
         result = pid_is_kernel_thread(pid->pid);
         if (result < 0)
                 return result;
@@ -489,22 +478,6 @@ int pidref_is_kernel_thread(const PidRef *pid) {
         return result;
 }
 
-int get_process_capeff(pid_t pid, char **ret) {
-        const char *p;
-        int r;
-
-        assert(pid >= 0);
-        assert(ret);
-
-        p = procfs_file_alloca(pid, "status");
-
-        r = get_proc_field(p, "CapEff", WHITESPACE, ret);
-        if (r == -ENOENT)
-                return -ESRCH;
-
-        return r;
-}
-
 static int get_process_link_contents(pid_t pid, const char *proc_file, char **ret) {
         const char *p;
         int r;
@@ -589,12 +562,21 @@ int pid_get_uid(pid_t pid, uid_t *ret) {
 }
 
 int pidref_get_uid(const PidRef *pid, uid_t *ret) {
-        uid_t uid;
         int r;
 
         if (!pidref_is_set(pid))
                 return -ESRCH;
 
+        if (pidref_is_remote(pid))
+                return -EREMOTE;
+
+        if (pid->fd >= 0) {
+                r = pidfd_get_uid(pid->fd, ret);
+                if (!ERRNO_IS_NEG_NOT_SUPPORTED(r))
+                        return r;
+        }
+
+        uid_t uid;
         r = pid_get_uid(pid->pid, &uid);
         if (r < 0)
                 return r;
@@ -680,7 +662,7 @@ int get_process_environ(pid_t pid, char **ret) {
         return 0;
 }
 
-int get_process_ppid(pid_t pid, pid_t *ret) {
+int pid_get_ppid(pid_t pid, pid_t *ret) {
         _cleanup_free_ char *line = NULL;
         unsigned long ppid;
         const char *p;
@@ -688,15 +670,17 @@ int get_process_ppid(pid_t pid, pid_t *ret) {
 
         assert(pid >= 0);
 
-        if (pid == 0 || pid == getpid_cached()) {
+        if (pid == 0)
+                pid = getpid_cached();
+        if (pid == 1) /* PID 1 has no parent, shortcut this case */
+                return -EADDRNOTAVAIL;
+
+        if (pid == getpid_cached()) {
                 if (ret)
                         *ret = getppid();
                 return 0;
         }
 
-        if (pid == 1) /* PID 1 has no parent, shortcut this case */
-                return -EADDRNOTAVAIL;
-
         p = procfs_file_alloca(pid, "stat");
         r = read_one_line_file(p, &line);
         if (r == -ENOENT)
@@ -710,7 +694,6 @@ int get_process_ppid(pid_t pid, pid_t *ret) {
         p = strrchr(line, ')');
         if (!p)
                 return -EIO;
-
         p++;
 
         if (sscanf(p, " "
@@ -719,9 +702,9 @@ int get_process_ppid(pid_t pid, pid_t *ret) {
                    &ppid) != 1)
                 return -EIO;
 
-        /* If ppid is zero the process has no parent. Which might be the case for PID 1 but also for
-         * processes originating in other namespaces that are inserted into a pidns. Return a recognizable
-         * error in this case. */
+        /* If ppid is zero the process has no parent. Which might be the case for PID 1 (caught above)
+         * but also for processes originating in other namespaces that are inserted into a pidns.
+         * Return a recognizable error in this case. */
         if (ppid == 0)
                 return -EADDRNOTAVAIL;
 
@@ -734,7 +717,74 @@ int get_process_ppid(pid_t pid, pid_t *ret) {
         return 0;
 }
 
-int pid_get_start_time(pid_t pid, uint64_t *ret) {
+int pidref_get_ppid(const PidRef *pidref, pid_t *ret) {
+        int r;
+
+        if (!pidref_is_set(pidref))
+                return -ESRCH;
+
+        if (pidref_is_remote(pidref))
+                return -EREMOTE;
+
+        if (pidref->fd >= 0) {
+                r = pidfd_get_ppid(pidref->fd, ret);
+                if (!ERRNO_IS_NEG_NOT_SUPPORTED(r))
+                        return r;
+        }
+
+        pid_t ppid;
+        r = pid_get_ppid(pidref->pid, ret ? &ppid : NULL);
+        if (r < 0)
+                return r;
+
+        r = pidref_verify(pidref);
+        if (r < 0)
+                return r;
+
+        if (ret)
+                *ret = ppid;
+        return 0;
+}
+
+int pidref_get_ppid_as_pidref(const PidRef *pidref, PidRef *ret) {
+        pid_t ppid;
+        int r;
+
+        assert(ret);
+
+        r = pidref_get_ppid(pidref, &ppid);
+        if (r < 0)
+                return r;
+
+        for (unsigned attempt = 0; attempt < 16; attempt++) {
+                _cleanup_(pidref_done) PidRef parent = PIDREF_NULL;
+
+                r = pidref_set_pid(&parent, ppid);
+                if (r < 0)
+                        return r;
+
+                /* If we have a pidfd of the original PID, let's verify that the process we acquired really
+                 * is the parent still */
+                if (pidref->fd >= 0) {
+                        r = pidref_get_ppid(pidref, &ppid);
+                        if (r < 0)
+                                return r;
+
+                        /* Did the PPID change since we queried it? if so we might have pinned the wrong
+                         * process, if its PID got reused by now. Let's try again */
+                        if (parent.pid != ppid)
+                                continue;
+                }
+
+                *ret = TAKE_PIDREF(parent);
+                return 0;
+        }
+
+        /* Give up after 16 tries */
+        return -ENOTRECOVERABLE;
+}
+
+int pid_get_start_time(pid_t pid, usec_t *ret) {
         _cleanup_free_ char *line = NULL;
         const char *p;
         int r;
@@ -754,13 +804,12 @@ int pid_get_start_time(pid_t pid, uint64_t *ret) {
         p = strrchr(line, ')');
         if (!p)
                 return -EIO;
-
         p++;
 
         unsigned long llu;
 
         if (sscanf(p, " "
-                   "%*c "  /* state */
+                   "%*c " /* state */
                    "%*u " /* ppid */
                    "%*u " /* pgrp */
                    "%*u " /* session */
@@ -784,18 +833,21 @@ int pid_get_start_time(pid_t pid, uint64_t *ret) {
                 return -EIO;
 
         if (ret)
-                *ret = llu;
+                *ret = jiffies_to_usec(llu); /* CLOCK_BOOTTIME */
 
         return 0;
 }
 
-int pidref_get_start_time(const PidRef *pid, uint64_t *ret) {
-        uint64_t t;
+int pidref_get_start_time(const PidRef *pid, usec_t *ret) {
+        usec_t t;
         int r;
 
         if (!pidref_is_set(pid))
                 return -ESRCH;
 
+        if (pidref_is_remote(pid))
+                return -EREMOTE;
+
         r = pid_get_start_time(pid->pid, ret ? &t : NULL);
         if (r < 0)
                 return r;
@@ -1026,7 +1078,6 @@ int kill_and_sigcont(pid_t pid, int sig) {
 
 int getenv_for_pid(pid_t pid, const char *field, char **ret) {
         _cleanup_fclose_ FILE *f = NULL;
-        char *value = NULL;
         const char *path;
         size_t sum = 0;
         int r;
@@ -1035,22 +1086,8 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) {
         assert(field);
         assert(ret);
 
-        if (pid == 0 || pid == getpid_cached()) {
-                const char *e;
-
-                e = getenv(field);
-                if (!e) {
-                        *ret = NULL;
-                        return 0;
-                }
-
-                value = strdup(e);
-                if (!value)
-                        return -ENOMEM;
-
-                *ret = value;
-                return 1;
-        }
+        if (pid == 0 || pid == getpid_cached())
+                return strdup_to_full(ret, getenv(field));
 
         if (!pid_is_valid(pid))
                 return -EINVAL;
@@ -1079,78 +1116,55 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) {
                 sum += r;
 
                 match = startswith(line, field);
-                if (match && *match == '=') {
-                        value = strdup(match + 1);
-                        if (!value)
-                                return -ENOMEM;
-
-                        *ret = value;
-                        return 1;
-                }
+                if (match && *match == '=')
+                        return strdup_to_full(ret, match + 1);
         }
 
         *ret = NULL;
         return 0;
 }
 
-int pid_is_my_child(pid_t pid) {
-        pid_t ppid;
+int pidref_is_my_child(PidRef *pid) {
         int r;
 
-        if (pid < 0)
+        if (!pidref_is_set(pid))
                 return -ESRCH;
 
-        if (pid <= 1)
+        if (pidref_is_remote(pid))
+                return -EREMOTE;
+
+        if (pid->pid == 1 || pidref_is_self(pid))
                 return false;
 
-        r = get_process_ppid(pid, &ppid);
+        pid_t ppid;
+        r = pidref_get_ppid(pid, &ppid);
+        if (r == -EADDRNOTAVAIL) /* if this process is outside of our pidns, it is definitely not our child */
+                return false;
         if (r < 0)
                 return r;
 
         return ppid == getpid_cached();
 }
 
-int pidref_is_my_child(const PidRef *pid) {
-        int r, result;
-
-        if (!pidref_is_set(pid))
-                return -ESRCH;
-
-        result = pid_is_my_child(pid->pid);
-        if (result < 0)
-                return result;
-
-        r = pidref_verify(pid);
-        if (r < 0)
-                return r;
-
-        return result;
-}
-
-int pid_is_unwaited(pid_t pid) {
-        /* Checks whether a PID is still valid at all, including a zombie */
-
-        if (pid < 0)
-                return -ESRCH;
-
-        if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */
-                return true;
-
-        if (pid == getpid_cached())
-                return true;
+int pid_is_my_child(pid_t pid) {
 
-        if (kill(pid, 0) >= 0)
-                return true;
+        if (pid == 0)
+                return false;
 
-        return errno != ESRCH;
+        return pidref_is_my_child(&PIDREF_MAKE_FROM_PID(pid));
 }
 
-int pidref_is_unwaited(const PidRef *pid) {
+int pidref_is_unwaited(PidRef *pid) {
         int r;
 
+        /* Checks whether a PID is still valid at all, including a zombie */
+
         if (!pidref_is_set(pid))
                 return -ESRCH;
 
+        if (pidref_is_remote(pid))
+                return -EREMOTE;
+
         if (pid->pid == 1 || pidref_is_self(pid))
                 return true;
 
@@ -1163,6 +1177,14 @@ int pidref_is_unwaited(const PidRef *pid) {
         return true;
 }
 
+int pid_is_unwaited(pid_t pid) {
+
+        if (pid == 0)
+                return true;
+
+        return pidref_is_unwaited(&PIDREF_MAKE_FROM_PID(pid));
+}
+
 int pid_is_alive(pid_t pid) {
         int r;
 
@@ -1192,6 +1214,9 @@ int pidref_is_alive(const PidRef *pidref) {
         if (!pidref_is_set(pidref))
                 return -ESRCH;
 
+        if (pidref_is_remote(pidref))
+                return -EREMOTE;
+
         result = pid_is_alive(pidref->pid);
         if (result < 0) {
                 assert(result != -ESRCH);
@@ -1207,28 +1232,63 @@ int pidref_is_alive(const PidRef *pidref) {
         return result;
 }
 
-int pid_from_same_root_fs(pid_t pid) {
-        const char *root;
+int pidref_from_same_root_fs(PidRef *a, PidRef *b) {
+        _cleanup_(pidref_done) PidRef self = PIDREF_NULL;
+        int r;
 
-        if (pid < 0)
+        /* Checks if the two specified processes have the same root fs. Either can be specified as NULL in
+         * which case we'll check against ourselves. */
+
+        if (!a || !b) {
+                r = pidref_set_self(&self);
+                if (r < 0)
+                        return r;
+                if (!a)
+                        a = &self;
+                if (!b)
+                        b = &self;
+        }
+
+        if (!pidref_is_set(a) || !pidref_is_set(b))
+                return -ESRCH;
+
+        /* If one of the two processes have the same root they cannot have the same root fs, but if both of
+         * them do we don't know */
+        if (pidref_is_remote(a) && pidref_is_remote(b))
+                return -EREMOTE;
+        if (pidref_is_remote(a) || pidref_is_remote(b))
                 return false;
 
-        if (pid == 0 || pid == getpid_cached())
+        if (pidref_equal(a, b))
                 return true;
 
-        root = procfs_file_alloca(pid, "root");
+        const char *roota = procfs_file_alloca(a->pid, "root");
+        const char *rootb = procfs_file_alloca(b->pid, "root");
+
+        int result = inode_same(roota, rootb, 0);
+        if (result == -ENOENT)
+                return proc_mounted() == 0 ? -ENOSYS : -ESRCH;
+        if (result < 0)
+                return result;
 
-        return inode_same(root, "/proc/1/root", 0);
+        r = pidref_verify(a);
+        if (r < 0)
+                return r;
+        r = pidref_verify(b);
+        if (r < 0)
+                return r;
+
+        return result;
 }
 #endif /* NM_IGNORED */
 
 bool is_main_thread(void) {
-        static thread_local int cached = 0;
+        static thread_local int cached = -1;
 
-        if (_unlikely_(cached == 0))
-                cached = getpid_cached() == gettid() ? 1 : -1;
+        if (cached < 0)
+                cached = getpid_cached() == gettid();
 
-        return cached > 0;
+        return cached;
 }
 
 #if 0 /* NM_IGNORED */
@@ -1423,11 +1483,6 @@ int must_be_root(void) {
         return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be root.");
 }
 
-static void restore_sigsetp(sigset_t **ssp) {
-        if (*ssp)
-                (void) sigprocmask(SIG_SETMASK, *ssp, NULL);
-}
-
 pid_t clone_with_nested_stack(int (*fn)(void *), int flags, void *userdata) {
         size_t ps;
         pid_t pid;
@@ -1467,6 +1522,11 @@ pid_t clone_with_nested_stack(int (*fn)(void *), int flags, void *userdata) {
         return pid;
 }
 
+static void restore_sigsetp(sigset_t **ssp) {
+        if (*ssp)
+                (void) sigprocmask(SIG_SETMASK, *ssp, NULL);
+}
+
 static int fork_flags_to_signal(ForkFlags flags) {
         return (flags & FORK_DEATHSIG_SIGTERM) ? SIGTERM :
                 (flags & FORK_DEATHSIG_SIGINT) ? SIGINT :
@@ -1487,8 +1547,8 @@ int safe_fork_full(
         bool block_signals = false, block_all = false, intermediary = false;
         int prio, r;
 
-        assert(!FLAGS_SET(flags, FORK_DETACH) || !ret_pid);
-        assert(!FLAGS_SET(flags, FORK_DETACH|FORK_WAIT));
+        assert(!FLAGS_SET(flags, FORK_DETACH) ||
+               (!ret_pid && (flags & (FORK_WAIT|FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT|FORK_DEATHSIG_SIGKILL)) == 0));
 
         /* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always
          * returns the child's PID in *ret_pid. Returns == 0 in the child, and > 0 in the parent. */
@@ -1519,15 +1579,12 @@ int safe_fork_full(
         }
 
         if (block_signals) {
-                if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0)
-                        return log_full_errno(prio, errno, "Failed to set signal mask: %m");
+                if (sigprocmask(SIG_BLOCK, &ss, &saved_ss) < 0)
+                        return log_full_errno(prio, errno, "Failed to block signal mask: %m");
                 saved_ssp = &saved_ss;
         }
 
         if (FLAGS_SET(flags, FORK_DETACH)) {
-                assert(!FLAGS_SET(flags, FORK_WAIT));
-                assert(!ret_pid);
-
                 /* Fork off intermediary child if needed */
 
                 r = is_reaper_process();
@@ -1549,11 +1606,12 @@ int safe_fork_full(
                 }
         }
 
-        if ((flags & (FORK_NEW_MOUNTNS|FORK_NEW_USERNS|FORK_NEW_NETNS)) != 0)
+        if ((flags & (FORK_NEW_MOUNTNS|FORK_NEW_USERNS|FORK_NEW_NETNS|FORK_NEW_PIDNS)) != 0)
                 pid = raw_clone(SIGCHLD|
                                 (FLAGS_SET(flags, FORK_NEW_MOUNTNS) ? CLONE_NEWNS : 0) |
                                 (FLAGS_SET(flags, FORK_NEW_USERNS) ? CLONE_NEWUSER : 0) |
-                                (FLAGS_SET(flags, FORK_NEW_NETNS) ? CLONE_NEWNET : 0));
+                                (FLAGS_SET(flags, FORK_NEW_NETNS) ? CLONE_NEWNET : 0) |
+                                (FLAGS_SET(flags, FORK_NEW_PIDNS) ? CLONE_NEWPID : 0));
         else
                 pid = fork();
         if (pid < 0)
@@ -1748,6 +1806,9 @@ int safe_fork_full(
                 }
         }
 
+        if (FLAGS_SET(flags, FORK_FREEZE))
+                freeze();
+
         if (ret_pid)
                 *ret_pid = getpid_cached();
 
@@ -1765,12 +1826,16 @@ int pidref_safe_fork_full(
         pid_t pid;
         int r, q;
 
-        assert(!FLAGS_SET(flags, FORK_WAIT));
-
         r = safe_fork_full(name, stdio_fds, except_fds, n_except_fds, flags, &pid);
-        if (r < 0)
+        if (r < 0 || !ret_pid)
                 return r;
 
+        if (r > 0 && FLAGS_SET(flags, FORK_WAIT)) {
+                /* If we are in the parent and successfully waited, then the process doesn't exist anymore */
+                *ret_pid = PIDREF_NULL;
+                return r;
+        }
+
         q = pidref_set_pid(ret_pid, pid);
         if (q < 0) /* Let's not fail for this, no matter what, the process exists after all, and that's key */
                 *ret_pid = PIDREF_MAKE_FROM_PID(pid);
@@ -1841,6 +1906,9 @@ int namespace_fork(
 int set_oom_score_adjust(int value) {
         char t[DECIMAL_STR_MAX(int)];
 
+        if (!oom_score_adjust_is_valid(value))
+                return -EINVAL;
+
         xsprintf(t, "%i", value);
 
         return write_string_file("/proc/self/oom_score_adj", t,
@@ -1857,67 +1925,17 @@ int get_oom_score_adjust(int *ret) {
 
         delete_trailing_chars(t, WHITESPACE);
 
-        assert_se(safe_atoi(t, &a) >= 0);
-        assert_se(oom_score_adjust_is_valid(a));
-
-        if (ret)
-                *ret = a;
-        return 0;
-}
-
-int pidfd_get_pid(int fd, pid_t *ret) {
-        char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
-        _cleanup_free_ char *fdinfo = NULL;
-        char *p;
-        int r;
-
-        /* Converts a pidfd into a pid. Well known errors:
-         *
-         *    -EBADF   → fd invalid
-         *    -ENOSYS  → /proc/ not mounted
-         *    -ENOTTY  → fd valid, but not a pidfd
-         *    -EREMOTE → fd valid, but pid is in another namespace we cannot translate to the local one
-         *    -ESRCH   → fd valid, but process is already reaped
-         */
-
-        if (fd < 0)
-                return -EBADF;
-
-        xsprintf(path, "/proc/self/fdinfo/%i", fd);
-
-        r = read_full_virtual_file(path, &fdinfo, NULL);
-        if (r == -ENOENT) /* if fdinfo doesn't exist we assume the process does not exist */
-                return proc_mounted() > 0 ? -EBADF : -ENOSYS;
+        r = safe_atoi(t, &a);
         if (r < 0)
                 return r;
 
-        p = find_line_startswith(fdinfo, "Pid:");
-        if (!p)
-                return -ENOTTY; /* not a pidfd? */
-
-        p += strspn(p, WHITESPACE);
-        p[strcspn(p, WHITESPACE)] = 0;
-
-        if (streq(p, "0"))
-                return -EREMOTE; /* PID is in foreign PID namespace? */
-        if (streq(p, "-1"))
-                return -ESRCH;   /* refers to reaped process? */
-
-        return parse_pid(p, ret);
-}
-
-int pidfd_verify_pid(int pidfd, pid_t pid) {
-        pid_t current_pid;
-        int r;
-
-        assert(pidfd >= 0);
-        assert(pid > 0);
+        if (!oom_score_adjust_is_valid(a))
+                return -ENODATA;
 
-        r = pidfd_get_pid(pidfd, &current_pid);
-        if (r < 0)
-                return r;
+        if (ret)
+                *ret = a;
 
-        return current_pid != pid ? -ESRCH : 0;
+        return 0;
 }
 
 static int rlimit_to_nice(rlim_t limit) {
@@ -1931,17 +1949,15 @@ static int rlimit_to_nice(rlim_t limit) {
 }
 
 int setpriority_closest(int priority) {
-        int current, limit, saved_errno;
         struct rlimit highest;
+        int r, current, limit;
 
         /* Try to set requested nice level */
-        if (setpriority(PRIO_PROCESS, 0, priority) >= 0)
+        r = RET_NERRNO(setpriority(PRIO_PROCESS, 0, priority));
+        if (r >= 0)
                 return 1;
-
-        /* Permission failed */
-        saved_errno = -errno;
-        if (!ERRNO_IS_PRIVILEGE(saved_errno))
-                return saved_errno;
+        if (!ERRNO_IS_NEG_PRIVILEGE(r))
+                return r;
 
         errno = 0;
         current = getpriority(PRIO_PROCESS, 0);
@@ -1955,24 +1971,21 @@ int setpriority_closest(int priority) {
         * then the whole setpriority() system call is blocked to us, hence let's propagate the error
         * right-away */
         if (priority > current)
-                return saved_errno;
+                return r;
 
         if (getrlimit(RLIMIT_NICE, &highest) < 0)
                 return -errno;
 
         limit = rlimit_to_nice(highest.rlim_cur);
 
-        /* We are already less nice than limit allows us */
-        if (current < limit) {
-                log_debug("Cannot raise nice level, permissions and the resource limit do not allow it.");
-                return 0;
-        }
-
-        /* Push to the allowed limit */
-        if (setpriority(PRIO_PROCESS, 0, limit) < 0)
-                return -errno;
+        /* Push to the allowed limit if we're higher than that. Note that we could also be less nice than
+         * limit allows us, but still higher than what's requested. In that case our current value is
+         * the best choice. */
+        if (current > limit)
+                if (setpriority(PRIO_PROCESS, 0, limit) < 0)
+                        return -errno;
 
-        log_debug("Cannot set requested nice level (%i), used next best (%i).", priority, limit);
+        log_debug("Cannot set requested nice level (%i), using next best (%i).", priority, MIN(current, limit));
         return 0;
 }
 
@@ -1992,7 +2005,8 @@ _noreturn_ void freeze(void) {
                         break;
         }
 
-        /* waitid() failed with an unexpected error, things are really borked. Freeze now! */
+        /* waitid() failed with an ECHLD error (because there are no left-over child processes) or any other
+         * (unexpected) error. Freeze for good now! */
         for (;;)
                 pause();
 }
@@ -2064,7 +2078,7 @@ int posix_spawn_wrapper(
                 const char *cgroup,
                 PidRef *ret_pidref) {
 
-        short flags = POSIX_SPAWN_SETSIGMASK|POSIX_SPAWN_SETSIGDEF;
+        short flags = POSIX_SPAWN_SETSIGMASK;
         posix_spawnattr_t attr;
         sigset_t mask;
         int r;
@@ -2075,7 +2089,7 @@ int posix_spawn_wrapper(
          * issues.
          *
          * Also, move the newly-created process into 'cgroup' through POSIX_SPAWN_SETCGROUP (clone3())
-         * if available. Note that CLONE_INTO_CGROUP is only supported on cgroup v2.
+         * if available.
          * returns 1: We're already in the right cgroup
          *         0: 'cgroup' not specified or POSIX_SPAWN_SETCGROUP is not supported. The caller
          *            needs to call 'cg_attach' on their own */
@@ -2094,9 +2108,10 @@ int posix_spawn_wrapper(
         _unused_ _cleanup_(posix_spawnattr_destroyp) posix_spawnattr_t *attr_destructor = &attr;
 
 #if HAVE_PIDFD_SPAWN
+        static bool have_clone_into_cgroup = true; /* kernel 5.7+ */
         _cleanup_close_ int cgroup_fd = -EBADF;
 
-        if (cgroup) {
+        if (cgroup && have_clone_into_cgroup) {
                 _cleanup_free_ char *resolved_cgroup = NULL;
 
                 r = cg_get_path_and_check(
@@ -2130,25 +2145,38 @@ int posix_spawn_wrapper(
         _cleanup_close_ int pidfd = -EBADF;
 
         r = pidfd_spawn(&pidfd, path, NULL, &attr, argv, envp);
-        if (r == 0) {
-                r = pidref_set_pidfd_consume(ret_pidref, TAKE_FD(pidfd));
-                if (r < 0)
-                        return r;
+        if (ERRNO_IS_NOT_SUPPORTED(r) && FLAGS_SET(flags, POSIX_SPAWN_SETCGROUP) && cg_is_threaded(cgroup) > 0)
+                return -EUCLEAN; /* clone3() could also return EOPNOTSUPP if the target cgroup is in threaded mode,
+                                    turn that into something recognizable */
+        if ((ERRNO_IS_NOT_SUPPORTED(r) || ERRNO_IS_PRIVILEGE(r) || r == E2BIG) &&
+            FLAGS_SET(flags, POSIX_SPAWN_SETCGROUP)) {
+                /* Compiled on a newer host, or seccomp&friends blocking clone3()? Fallback, but
+                 * need to disable POSIX_SPAWN_SETCGROUP, which is what redirects to clone3().
+                 * Note that we might get E2BIG here since some kernels (e.g. 5.4) support clone3()
+                 * but not CLONE_INTO_CGROUP. */
+
+                /* CLONE_INTO_CGROUP definitely won't work, hence remember the fact so that we don't
+                 * retry every time. */
+                have_clone_into_cgroup = false;
+
+                flags &= ~POSIX_SPAWN_SETCGROUP;
+                r = posix_spawnattr_setflags(&attr, flags);
+                if (r != 0)
+                        return -r;
 
-                return FLAGS_SET(flags, POSIX_SPAWN_SETCGROUP);
+                r = pidfd_spawn(&pidfd, path, NULL, &attr, argv, envp);
         }
-        if (!(ERRNO_IS_NOT_SUPPORTED(r) || ERRNO_IS_PRIVILEGE(r)))
-                return -r;
-
-        /* Compiled on a newer host, or seccomp&friends blocking clone3()? Fallback, but need to change the
-         * flags to remove the cgroup one, which is what redirects to clone3() */
-        flags &= ~POSIX_SPAWN_SETCGROUP;
-        r = posix_spawnattr_setflags(&attr, flags);
         if (r != 0)
                 return -r;
-#endif
 
+        r = pidref_set_pidfd_consume(ret_pidref, TAKE_FD(pidfd));
+        if (r < 0)
+                return r;
+
+        return FLAGS_SET(flags, POSIX_SPAWN_SETCGROUP);
+#else
         pid_t pid;
+
         r = posix_spawn(&pid, path, NULL, &attr, argv, envp);
         if (r != 0)
                 return -r;
@@ -2158,6 +2186,7 @@ int posix_spawn_wrapper(
                 return r;
 
         return 0; /* We did not use CLONE_INTO_CGROUP so return 0, the caller will have to move the child */
+#endif
 }
 
 int proc_dir_open(DIR **ret) {
@@ -2248,4 +2277,46 @@ static const char* const sched_policy_table[] = {
 };
 
 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
+
+_noreturn_ void report_errno_and_exit(int errno_fd, int error) {
+        int r;
+
+        if (error >= 0)
+                _exit(EXIT_SUCCESS);
+
+        assert(errno_fd >= 0);
+
+        r = loop_write(errno_fd, &error, sizeof(error));
+        if (r < 0)
+                log_debug_errno(r, "Failed to write errno to errno_fd=%d: %m", errno_fd);
+
+        _exit(EXIT_FAILURE);
+}
+
+int read_errno(int errno_fd) {
+        int r;
+
+        assert(errno_fd >= 0);
+
+        /* The issue here is that it's impossible to distinguish between an error code returned by child and
+         * IO error arose when reading it. So, the function logs errors and return EIO for the later case. */
+
+        ssize_t n = loop_read(errno_fd, &r, sizeof(r), /* do_poll = */ false);
+        if (n < 0) {
+                log_debug_errno(n, "Failed to read errno: %m");
+                return -EIO;
+        }
+        if (n == sizeof(r)) {
+                if (r == 0)
+                        return 0;
+                if (r < 0) /* child process reported an error, return it */
+                        return log_debug_errno(r, "Child process failed with errno: %m");
+                return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Received an errno, but it's a positive value.");
+        }
+        if (n != 0)
+                return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Received unexpected amount of bytes while reading errno.");
+
+        /* the process exited without reporting an error, assuming success */
+        return 0;
+}
 #endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/process-util.h b/src/libnm-systemd-shared/src/basic/process-util.h
index 49350065..19ac55dd 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.h
+++ b/src/libnm-systemd-shared/src/basic/process-util.h
@@ -14,7 +14,7 @@
 #include "alloc-util.h"
 #include "format-util.h"
 #include "macro.h"
-#include "namespace-util.h"
+#include "pidref.h"
 #include "time-util.h"
 
 #define procfs_file_alloca(pid, field)                                  \
@@ -49,19 +49,18 @@ int get_process_exe(pid_t pid, char **ret);
 int pid_get_uid(pid_t pid, uid_t *ret);
 int pidref_get_uid(const PidRef *pid, uid_t *ret);
 int get_process_gid(pid_t pid, gid_t *ret);
-int get_process_capeff(pid_t pid, char **ret);
 int get_process_cwd(pid_t pid, char **ret);
 int get_process_root(pid_t pid, char **ret);
 int get_process_environ(pid_t pid, char **ret);
-int get_process_ppid(pid_t pid, pid_t *ret);
-int pid_get_start_time(pid_t pid, uint64_t *ret);
-int pidref_get_start_time(const PidRef* pid, uint64_t *ret);
+int pid_get_ppid(pid_t pid, pid_t *ret);
+int pidref_get_ppid(const PidRef *pidref, pid_t *ret);
+int pidref_get_ppid_as_pidref(const PidRef *pidref, PidRef *ret);
+int pid_get_start_time(pid_t pid, usec_t *ret);
+int pidref_get_start_time(const PidRef *pid, usec_t *ret);
 int get_process_umask(pid_t pid, mode_t *ret);
 
 int container_get_leader(const char *machine, pid_t *pid);
 
-int namespace_get_leader(pid_t pid, NamespaceType type, pid_t *ret);
-
 int wait_for_terminate(pid_t pid, siginfo_t *status);
 
 typedef enum WaitFlags {
@@ -91,10 +90,10 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value);
 int pid_is_alive(pid_t pid);
 int pidref_is_alive(const PidRef *pidref);
 int pid_is_unwaited(pid_t pid);
-int pidref_is_unwaited(const PidRef *pidref);
+int pidref_is_unwaited(PidRef *pidref);
 int pid_is_my_child(pid_t pid);
-int pidref_is_my_child(const PidRef *pidref);
-int pid_from_same_root_fs(pid_t pid);
+int pidref_is_my_child(PidRef *pidref);
+int pidref_from_same_root_fs(PidRef *a, PidRef *b);
 
 bool is_main_thread(void);
 
@@ -113,12 +112,12 @@ bool oom_score_adjust_is_valid(int oa);
 #define OPINIONATED_PERSONALITY_MASK 0xFFUL
 
 unsigned long personality_from_string(const char *p);
-const char *personality_to_string(unsigned long);
+const char* personality_to_string(unsigned long);
 
 int safe_personality(unsigned long p);
 int opinionated_personality(unsigned long *ret);
 
-const char *sigchld_code_to_string(int i) _const_;
+const char* sigchld_code_to_string(int i) _const_;
 int sigchld_code_from_string(const char *s) _pure_;
 
 int sched_policy_to_string_alloc(int i, char **s);
@@ -149,9 +148,15 @@ static inline bool sched_priority_is_valid(int i) {
         return i >= 0 && i <= sched_get_priority_max(SCHED_RR);
 }
 
+#define PID_AUTOMATIC ((pid_t) INT_MIN) /* special value indicating "acquire pid from connection peer" */
+
 static inline bool pid_is_valid(pid_t p) {
         return p > 0;
 }
+
+static inline bool pid_is_automatic(pid_t p) {
+        return p == PID_AUTOMATIC;
+}
 #endif /* NM_IGNORED */
 
 pid_t getpid_cached(void);
@@ -161,7 +166,7 @@ int must_be_root(void);
 
 pid_t clone_with_nested_stack(int (*fn)(void *), int flags, void *userdata);
 
-/* 💣 Note that FORK_NEW_USERNS, FORK_NEW_MOUNTNS, or FORK_NEW_NETNS should not be called in threaded
+/* 💣 Note that FORK_NEW_USERNS, FORK_NEW_MOUNTNS, FORK_NEW_NETNS or FORK_NEW_PIDNS should not be called in threaded
  * programs, because they cause us to use raw_clone() which does not synchronize the glibc malloc() locks,
  * and thus will cause deadlocks if the parent uses threads and the child does memory allocations. Hence: if
  * the parent is threaded these flags may not be used. These flags cannot be used if the parent uses threads
@@ -176,18 +181,20 @@ typedef enum ForkFlags {
         FORK_REOPEN_LOG         = 1 <<  6, /* Reopen log connection */
         FORK_LOG                = 1 <<  7, /* Log above LOG_DEBUG log level about failures */
         FORK_WAIT               = 1 <<  8, /* Wait until child exited */
-        FORK_NEW_MOUNTNS        = 1 <<  9, /* Run child in its own mount namespace                               💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
-        FORK_MOUNTNS_SLAVE      = 1 << 10, /* Make child's mount namespace MS_SLAVE */
-        FORK_PRIVATE_TMP        = 1 << 11, /* Mount new /tmp/ in the child (combine with FORK_NEW_MOUNTNS!) */
-        FORK_RLIMIT_NOFILE_SAFE = 1 << 12, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
-        FORK_STDOUT_TO_STDERR   = 1 << 13, /* Make stdout a copy of stderr */
-        FORK_FLUSH_STDIO        = 1 << 14, /* fflush() stdout (and stderr) before forking */
-        FORK_NEW_USERNS         = 1 << 15, /* Run child in its own user namespace                                💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
-        FORK_CLOEXEC_OFF        = 1 << 16, /* In the child: turn off O_CLOEXEC on all fds in except_fds[] */
-        FORK_KEEP_NOTIFY_SOCKET = 1 << 17, /* Unless this specified, $NOTIFY_SOCKET will be unset. */
-        FORK_DETACH             = 1 << 18, /* Double fork if needed to ensure PID1/subreaper is parent */
-        FORK_NEW_NETNS          = 1 << 19, /* Run child in its own network namespace                             💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
-        FORK_PACK_FDS           = 1 << 20, /* Rearrange the passed FDs to be FD 3,4,5,etc. Updates the array in place (combine with FORK_CLOSE_ALL_FDS!) */
+        FORK_MOUNTNS_SLAVE      = 1 <<  9, /* Make child's mount namespace MS_SLAVE */
+        FORK_PRIVATE_TMP        = 1 << 10, /* Mount new /tmp/ in the child (combine with FORK_NEW_MOUNTNS!) */
+        FORK_RLIMIT_NOFILE_SAFE = 1 << 11, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
+        FORK_STDOUT_TO_STDERR   = 1 << 12, /* Make stdout a copy of stderr */
+        FORK_FLUSH_STDIO        = 1 << 13, /* fflush() stdout (and stderr) before forking */
+        FORK_CLOEXEC_OFF        = 1 << 14, /* In the child: turn off O_CLOEXEC on all fds in except_fds[] */
+        FORK_KEEP_NOTIFY_SOCKET = 1 << 15, /* Unless this specified, $NOTIFY_SOCKET will be unset. */
+        FORK_DETACH             = 1 << 16, /* Double fork if needed to ensure PID1/subreaper is parent */
+        FORK_PACK_FDS           = 1 << 17, /* Rearrange the passed FDs to be FD 3,4,5,etc. Updates the array in place (combine with FORK_CLOSE_ALL_FDS!) */
+        FORK_NEW_MOUNTNS        = 1 << 18, /* Run child in its own mount namespace                               💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
+        FORK_NEW_USERNS         = 1 << 19, /* Run child in its own user namespace                                💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
+        FORK_NEW_NETNS          = 1 << 20, /* Run child in its own network namespace                             💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
+        FORK_NEW_PIDNS          = 1 << 21, /* Run child in its own PID namespace                                 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
+        FORK_FREEZE             = 1 << 22, /* Don't return in child, just call freeze() instead */
 } ForkFlags;
 
 int safe_fork_full(
@@ -245,9 +252,6 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
 /* Like TAKE_PTR() but for pid_t, resetting them to 0 */
 #define TAKE_PID(pid) TAKE_GENERIC(pid, pid_t, 0)
 
-int pidfd_get_pid(int fd, pid_t *ret);
-int pidfd_verify_pid(int pidfd, pid_t pid);
-
 int setpriority_closest(int priority);
 
 _noreturn_ void freeze(void);
@@ -267,3 +271,6 @@ int posix_spawn_wrapper(
 int proc_dir_open(DIR **ret);
 int proc_dir_read(DIR *d, pid_t *ret);
 int proc_dir_read_pidref(DIR *d, PidRef *ret);
+
+_noreturn_ void report_errno_and_exit(int errno_fd, int error);
+int read_errno(int errno_fd);
diff --git a/src/libnm-systemd-shared/src/basic/random-util.c b/src/libnm-systemd-shared/src/basic/random-util.c
index c7b95516..1e1a24bd 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.c
+++ b/src/libnm-systemd-shared/src/basic/random-util.c
@@ -10,29 +10,28 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/auxv.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
 
-#if HAVE_SYS_AUXV_H
-#  include <sys/auxv.h>
-#endif
-
 #include "alloc-util.h"
 #include "env-util.h"
 #include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "io-util.h"
+#include "iovec-util.h"
 #include "missing_random.h"
 #include "missing_syscall.h"
 #include "missing_threads.h"
 #include "parse-util.h"
+#include "pidfd-util.h"
 #include "process-util.h"
 #include "random-util.h"
 #include "sha256.h"
 #include "time-util.h"
 
-/* This is a "best effort" kind of thing, but has no real security value.  So, this should only be used by
+/* This is a "best effort" kind of thing, but has no real security value. So, this should only be used by
  * random_bytes(), which is not meant for crypto. This could be made better, but we're *not* trying to roll a
  * userspace prng here, or even have forward secrecy, but rather just do the shortest thing that is at least
  * better than libc rand(). */
@@ -43,10 +42,10 @@ static void fallback_random_bytes(void *p, size_t n) {
                 uint64_t call_id, block_id;
                 usec_t stamp_mono, stamp_real;
                 pid_t pid, tid;
+                uint64_t pidfdid;
                 uint8_t auxval[16];
         } state = {
                 /* Arbitrary domain separation to prevent other usage of AT_RANDOM from clashing. */
-                .label = "systemd fallback random bytes v1",
                 .call_id = fallback_counter++,
                 .stamp_mono = now(CLOCK_MONOTONIC),
                 .stamp_real = now(CLOCK_REALTIME),
@@ -54,9 +53,9 @@ static void fallback_random_bytes(void *p, size_t n) {
                 .tid = gettid(),
         };
 
-#if HAVE_SYS_AUXV_H
+        memcpy(state.label, "systemd fallback random bytes v1", sizeof(state.label));
         memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval));
-#endif
+        (void) pidfd_get_inode_id_self_cached(&state.pidfdid);
 
         while (n > 0) {
                 struct sha256_ctx ctx;
@@ -77,8 +76,9 @@ static void fallback_random_bytes(void *p, size_t n) {
 }
 
 void random_bytes(void *p, size_t n) {
-        static bool have_getrandom = true, have_grndinsecure = true;
-        _cleanup_close_ int fd = -EBADF;
+        static bool have_grndinsecure = true;
+
+        assert(p || n == 0);
 
         if (n == 0)
                 return;
@@ -86,32 +86,26 @@ void random_bytes(void *p, size_t n) {
         for (;;) {
                 ssize_t l;
 
-                if (!have_getrandom)
-                        break;
-
                 l = getrandom(p, n, have_grndinsecure ? GRND_INSECURE : GRND_NONBLOCK);
-                if (l > 0) {
-                        if ((size_t) l == n)
-                                return; /* Done reading, success. */
-                        p = (uint8_t *) p + l;
-                        n -= l;
-                        continue; /* Interrupted by a signal; keep going. */
-                } else if (l == 0)
-                        break; /* Weird, so fallback to /dev/urandom. */
-                else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
-                        have_getrandom = false;
-                        break; /* No syscall, so fallback to /dev/urandom. */
-                } else if (errno == EINVAL && have_grndinsecure) {
+                if (l < 0 && errno == EINVAL && have_grndinsecure) {
+                        /* No GRND_INSECURE; fallback to GRND_NONBLOCK. */
                         have_grndinsecure = false;
-                        continue; /* No GRND_INSECURE; fallback to GRND_NONBLOCK. */
-                } else if (errno == EAGAIN && !have_grndinsecure)
-                        break; /* Will block, but no GRND_INSECURE, so fallback to /dev/urandom. */
+                        continue;
+                }
+                if (l <= 0)
+                        break; /* Will block (with GRND_NONBLOCK), or unexpected error. Give up and fallback
+                                  to /dev/urandom. */
+
+                if ((size_t) l == n)
+                        return; /* Done reading, success. */
 
-                break; /* Unexpected, so just give up and fallback to /dev/urandom. */
+                p = (uint8_t *) p + l;
+                n -= l;
+                /* Interrupted by a signal; keep going. */
         }
 
-        fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-        if (fd >= 0 && loop_read_exact(fd, p, n, false) == 0)
+        _cleanup_close_ int fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+        if (fd >= 0 && loop_read_exact(fd, p, n, false) >= 0)
                 return;
 
         /* This is a terrible fallback. Oh well. */
@@ -119,8 +113,7 @@ void random_bytes(void *p, size_t n) {
 }
 
 int crypto_random_bytes(void *p, size_t n) {
-        static bool have_getrandom = true, seen_initialized = false;
-        _cleanup_close_ int fd = -EBADF;
+        assert(p || n == 0);
 
         if (n == 0)
                 return 0;
@@ -128,42 +121,37 @@ int crypto_random_bytes(void *p, size_t n) {
         for (;;) {
                 ssize_t l;
 
-                if (!have_getrandom)
-                        break;
-
                 l = getrandom(p, n, 0);
-                if (l > 0) {
-                        if ((size_t) l == n)
-                                return 0; /* Done reading, success. */
-                        p = (uint8_t *) p + l;
-                        n -= l;
-                        continue; /* Interrupted by a signal; keep going. */
-                } else if (l == 0)
+                if (l < 0)
+                        return -errno;
+                if (l == 0)
                         return -EIO; /* Weird, should never happen. */
-                else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
-                        have_getrandom = false;
-                        break; /* No syscall, so fallback to /dev/urandom. */
-                }
-                return -errno;
-        }
 
-        if (!seen_initialized) {
-                _cleanup_close_ int ready_fd = -EBADF;
-                int r;
+                if ((size_t) l == n)
+                        return 0; /* Done reading, success. */
 
-                ready_fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (ready_fd < 0)
-                        return -errno;
-                r = fd_wait_for_event(ready_fd, POLLIN, USEC_INFINITY);
-                if (r < 0)
-                        return r;
-                seen_initialized = true;
+                p = (uint8_t *) p + l;
+                n -= l;
+                /* Interrupted by a signal; keep going. */
         }
+}
+
+int crypto_random_bytes_allocate_iovec(size_t n, struct iovec *ret) {
+        _cleanup_free_ void *p = NULL;
+        int r;
+
+        assert(ret);
+
+        p = malloc(MAX(n, 1U));
+        if (!p)
+                return -ENOMEM;
+
+        r = crypto_random_bytes(p, n);
+        if (r < 0)
+                return r;
 
-        fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-        if (fd < 0)
-                return -errno;
-        return loop_read_exact(fd, p, n, false);
+        *ret = IOVEC_MAKE(TAKE_PTR(p), n);
+        return 0;
 }
 
 #if 0 /* 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 b1a4d109..0b5ba771 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.h
+++ b/src/libnm-systemd-shared/src/basic/random-util.h
@@ -4,9 +4,11 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <sys/uio.h>
 
 void random_bytes(void *p, size_t n); /* Returns random bytes suitable for most uses, but may be insecure sometimes. */
 int crypto_random_bytes(void *p, size_t n); /* Returns secure random bytes after waiting for the RNG to initialize. */
+int crypto_random_bytes_allocate_iovec(size_t n, struct iovec *ret);
 
 static inline uint64_t random_u64(void) {
         uint64_t u;
diff --git a/src/libnm-systemd-shared/src/basic/ratelimit.c b/src/libnm-systemd-shared/src/basic/ratelimit.c
index a28c8122..8036f66c 100644
--- a/src/libnm-systemd-shared/src/basic/ratelimit.c
+++ b/src/libnm-systemd-shared/src/basic/ratelimit.c
@@ -10,37 +10,37 @@
 /* Modelled after Linux' lib/ratelimit.c by Dave Young
  * <hidave.darkstar@gmail.com>, which is licensed GPLv2. */
 
-bool ratelimit_below(RateLimit *r) {
+bool ratelimit_below(RateLimit *rl) {
         usec_t ts;
 
-        assert(r);
+        assert(rl);
 
-        if (!ratelimit_configured(r))
+        if (!ratelimit_configured(rl))
                 return true;
 
         ts = now(CLOCK_MONOTONIC);
 
-        if (r->begin <= 0 ||
-            usec_sub_unsigned(ts, r->begin) > r->interval) {
-                r->begin = ts;  /* Start a new time window */
-                r->num = 1;     /* Reset counter */
+        if (rl->begin <= 0 ||
+            usec_sub_unsigned(ts, rl->begin) > rl->interval) {
+                rl->begin = ts;  /* Start a new time window */
+                rl->num = 1;     /* Reset counter */
                 return true;
         }
 
-        if (_unlikely_(r->num == UINT_MAX))
+        if (_unlikely_(rl->num == UINT_MAX))
                 return false;
 
-        r->num++;
-        return r->num <= r->burst;
+        rl->num++;
+        return rl->num <= rl->burst;
 }
 
-unsigned ratelimit_num_dropped(RateLimit *r) {
-        assert(r);
+unsigned ratelimit_num_dropped(const RateLimit *rl) {
+        assert(rl);
 
-        if (r->num == UINT_MAX) /* overflow, return as special case */
+        if (rl->num == UINT_MAX) /* overflow, return as special case */
                 return UINT_MAX;
 
-        return LESS_BY(r->num, r->burst);
+        return LESS_BY(rl->num, rl->burst);
 }
 
 usec_t ratelimit_end(const RateLimit *rl) {
diff --git a/src/libnm-systemd-shared/src/basic/ratelimit.h b/src/libnm-systemd-shared/src/basic/ratelimit.h
index 492ea3b4..7801ef42 100644
--- a/src/libnm-systemd-shared/src/basic/ratelimit.h
+++ b/src/libnm-systemd-shared/src/basic/ratelimit.h
@@ -18,13 +18,13 @@ static inline void ratelimit_reset(RateLimit *rl) {
         rl->num = rl->begin = 0;
 }
 
-static inline bool ratelimit_configured(RateLimit *rl) {
+static inline bool ratelimit_configured(const RateLimit *rl) {
         return rl->interval > 0 && rl->burst > 0;
 }
 
-bool ratelimit_below(RateLimit *r);
+bool ratelimit_below(RateLimit *rl);
 
-unsigned ratelimit_num_dropped(RateLimit *r);
+unsigned ratelimit_num_dropped(const RateLimit *rl);
 
 usec_t ratelimit_end(const RateLimit *rl);
 usec_t ratelimit_left(const RateLimit *rl);
diff --git a/src/libnm-systemd-shared/src/basic/sha256.c b/src/libnm-systemd-shared/src/basic/sha256.c
new file mode 100644
index 00000000..88871a6b
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/sha256.c
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "nm-sd-adapt-shared.h"
+
+#include <unistd.h>
+
+#include "hexdecoct.h"
+#include "macro.h"
+#include "sha256.h"
+
+int sha256_fd(int fd, uint64_t max_size, uint8_t ret[static SHA256_DIGEST_SIZE]) {
+        struct sha256_ctx ctx;
+        uint64_t total_size = 0;
+
+        sha256_init_ctx(&ctx);
+
+        for (;;) {
+                uint8_t buffer[64 * 1024];
+                ssize_t n;
+
+                n = read(fd, buffer, sizeof(buffer));
+                if (n < 0)
+                        return -errno;
+                if (n == 0)
+                        break;
+
+                if (!INC_SAFE(&total_size, n) || total_size > max_size)
+                        return -EFBIG;
+
+                sha256_process_bytes(buffer, n, &ctx);
+        }
+
+        sha256_finish_ctx(&ctx, ret);
+        return 0;
+}
+
+int parse_sha256(const char *s, uint8_t ret[static SHA256_DIGEST_SIZE]) {
+        _cleanup_free_ uint8_t *data = NULL;
+        size_t size = 0;
+        int r;
+
+        if (!sha256_is_valid(s))
+                return -EINVAL;
+
+        r = unhexmem_full(s, SHA256_DIGEST_SIZE * 2, false, (void**) &data, &size);
+        if (r < 0)
+                return r;
+        assert(size == SHA256_DIGEST_SIZE);
+
+        memcpy(ret, data, size);
+        return 0;
+}
diff --git a/src/libnm-systemd-shared/src/basic/sha256.h b/src/libnm-systemd-shared/src/basic/sha256.h
new file mode 100644
index 00000000..95bac1bc
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/sha256.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#pragma once
+
+#include <stdint.h>
+
+#include "sha256-fundamental.h"
+#include "string-util.h"
+
+int sha256_fd(int fd, uint64_t max_size, uint8_t ret[static SHA256_DIGEST_SIZE]);
+
+int parse_sha256(const char *s, uint8_t res[static SHA256_DIGEST_SIZE]);
+
+static inline bool sha256_is_valid(const char *s) {
+        return s && in_charset(s, HEXDIGITS) && (strlen(s) == SHA256_DIGEST_SIZE * 2);
+}
diff --git a/src/libnm-systemd-shared/src/basic/signal-util.c b/src/libnm-systemd-shared/src/basic/signal-util.c
index 95c86584..05b2b50d 100644
--- a/src/libnm-systemd-shared/src/basic/signal-util.c
+++ b/src/libnm-systemd-shared/src/basic/signal-util.c
@@ -17,10 +17,6 @@
 
 #if 0 /* NM_IGNORED */
 int reset_all_signal_handlers(void) {
-        static const struct sigaction sa = {
-                .sa_handler = SIG_DFL,
-                .sa_flags = SA_RESTART,
-        };
         int ret = 0, r;
 
         for (int sig = 1; sig < _NSIG; sig++) {
@@ -31,7 +27,7 @@ int reset_all_signal_handlers(void) {
 
                 /* On Linux the first two RT signals are reserved by glibc, and sigaction() will return
                  * EINVAL for them. */
-                r = RET_NERRNO(sigaction(sig, &sa, NULL));
+                r = RET_NERRNO(sigaction(sig, &sigaction_default, NULL));
                 if (r != -EINVAL)
                         RET_GATHER(ret, r);
         }
@@ -154,7 +150,7 @@ static const char *const static_signal_table[] = {
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(static_signal, int);
 
-const char *signal_to_string(int signo) {
+const char* signal_to_string(int signo) {
         static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int)];
         const char *name;
 
@@ -271,7 +267,7 @@ int pop_pending_signal_internal(int sig, ...) {
         if (r < 0)
                 return r;
 
-        r = sigtimedwait(&ss, NULL, &(struct timespec) { 0, 0 });
+        r = sigtimedwait(&ss, NULL, &(const struct timespec) {});
         if (r < 0) {
                 if (errno == EAGAIN)
                         return 0;
@@ -298,4 +294,35 @@ void propagate_signal(int sig, siginfo_t *siginfo) {
         if (rt_tgsigqueueinfo(p, gettid(), sig, siginfo) < 0)
                 assert_se(kill(p, sig) >= 0);
 }
+
+const struct sigaction sigaction_ignore = {
+        .sa_handler = SIG_IGN,
+        .sa_flags = SA_RESTART,
+};
+
+const struct sigaction sigaction_default = {
+        .sa_handler = SIG_DFL,
+        .sa_flags = SA_RESTART,
+};
+
+const struct sigaction sigaction_nop_nocldstop = {
+        .sa_handler = nop_signal_handler,
+        .sa_flags = SA_NOCLDSTOP|SA_RESTART,
+};
+
+int parse_signo(const char *s, int *ret) {
+        int sig, r;
+
+        r = safe_atoi(s, &sig);
+        if (r < 0)
+                return r;
+
+        if (!SIGNAL_VALID(sig))
+                return -EINVAL;
+
+        if (ret)
+                *ret = sig;
+
+        return 0;
+}
 #endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/signal-util.h b/src/libnm-systemd-shared/src/basic/signal-util.h
index 8826fbeb..dc2b9de1 100644
--- a/src/libnm-systemd-shared/src/basic/signal-util.h
+++ b/src/libnm-systemd-shared/src/basic/signal-util.h
@@ -12,19 +12,13 @@ int sigaction_many_internal(const struct sigaction *sa, ...);
 
 #define ignore_signals(...)                                             \
         sigaction_many_internal(                                        \
-                        &(const struct sigaction) {                     \
-                                .sa_handler = SIG_IGN,                  \
-                                .sa_flags = SA_RESTART                  \
-                        },                                              \
+                        &sigaction_ignore,                              \
                         __VA_ARGS__,                                    \
                         -1)
 
 #define default_signals(...)                                            \
         sigaction_many_internal(                                        \
-                        &(const struct sigaction) {                     \
-                                .sa_handler = SIG_DFL,                  \
-                                .sa_flags = SA_RESTART                  \
-                        },                                              \
+                        &sigaction_default,                             \
                         __VA_ARGS__,                                    \
                         -1)
 
@@ -34,10 +28,10 @@ int sigaction_many_internal(const struct sigaction *sa, ...);
 int sigset_add_many_internal(sigset_t *ss, ...);
 #define sigset_add_many(...) sigset_add_many_internal(__VA_ARGS__, -1)
 
-int sigprocmask_many_internal(int how, sigset_t *old, ...);
+int sigprocmask_many_internal(int how, sigset_t *ret_old_mask, ...);
 #define sigprocmask_many(...) sigprocmask_many_internal(__VA_ARGS__, -1)
 
-const char *signal_to_string(int i) _const_;
+const char* signal_to_string(int i) _const_;
 int signal_from_string(const char *s) _pure_;
 
 void nop_signal_handler(int sig);
@@ -52,6 +46,7 @@ static inline void block_signals_reset(sigset_t *ss) {
                 assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__) >= 0);     \
                 _t;                                                                \
         })
+#define SIGNO_INVALID (-EINVAL)
 
 static inline bool SIGNAL_VALID(int signo) {
         return signo > 0 && signo < _NSIG;
@@ -70,3 +65,9 @@ int pop_pending_signal_internal(int sig, ...);
 #define pop_pending_signal(...) pop_pending_signal_internal(__VA_ARGS__, -1)
 
 void propagate_signal(int sig, siginfo_t *siginfo);
+
+extern const struct sigaction sigaction_ignore;
+extern const struct sigaction sigaction_default;
+extern const struct sigaction sigaction_nop_nocldstop;
+
+int parse_signo(const char *s, int *ret);
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.c b/src/libnm-systemd-shared/src/basic/socket-util.c
index df3e2c17..9cb0d7f4 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.c
+++ b/src/libnm-systemd-shared/src/basic/socket-util.c
@@ -2,10 +2,11 @@
 
 #include "nm-sd-adapt-shared.h"
 
+/* Make sure the net/if.h header is included before any linux/ one */
+#include <net/if.h>
 #include <arpa/inet.h>
 #include <errno.h>
 #include <limits.h>
-#include <net/if.h>
 #include <netdb.h>
 #include <netinet/ip.h>
 #include <poll.h>
@@ -24,7 +25,7 @@
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
-#include "format-util.h"
+#include "format-ifname.h"
 #include "io-util.h"
 #include "log.h"
 #include "memory-util.h"
@@ -458,6 +459,7 @@ int sockaddr_pretty(
 
         assert(sa);
         assert(salen >= sizeof(sa->sa.sa_family));
+        assert(ret);
 
         switch (sa->sa.sa_family) {
 
@@ -638,7 +640,8 @@ int socknameinfo_pretty(const struct sockaddr *sa, socklen_t salen, char **ret)
         int r;
 
         assert(sa);
-        assert(salen > sizeof(sa_family_t));
+        assert(salen >= sizeof(sa_family_t));
+        assert(ret);
 
         r = getnameinfo(sa, salen, host, sizeof(host), /* service= */ NULL, /* service_len= */ 0, IDN_FLAGS);
         if (r != 0) {
@@ -652,15 +655,7 @@ int socknameinfo_pretty(const struct sockaddr *sa, socklen_t salen, char **ret)
                 return sockaddr_pretty(sa, salen, /* translate_ipv6= */ true, /* include_port= */ true, ret);
         }
 
-        if (ret) {
-                char *copy = strdup(host);
-                if (!copy)
-                        return -ENOMEM;
-
-                *ret = copy;
-        }
-
-        return 0;
+        return strdup_to(ret, host);
 }
 
 static const char* const netlink_family_table[] = {
@@ -987,6 +982,28 @@ int getpeerpidfd(int fd) {
         return pidfd;
 }
 
+int getpeerpidref(int fd, PidRef *ret) {
+        int r;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        int pidfd = getpeerpidfd(fd);
+        if (pidfd < 0) {
+                if (!ERRNO_IS_NEG_NOT_SUPPORTED(pidfd))
+                        return pidfd;
+
+                struct ucred ucred;
+                r = getpeercred(fd, &ucred);
+                if (r < 0)
+                        return r;
+
+                return pidref_set_pid(ret, ucred.pid);
+        }
+
+        return pidref_set_pidfd_consume(ret, pidfd);
+}
+
 ssize_t send_many_fds_iov_sa(
                 int transport_fd,
                 int *fds_array, size_t n_fds_array,
@@ -1124,14 +1141,10 @@ ssize_t receive_many_fds_iov(
                 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
                         size_t n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
 
-                        fds_array = GREEDY_REALLOC(fds_array, n_fds_array + n);
-                        if (!fds_array) {
+                        if (!GREEDY_REALLOC_APPEND(fds_array, n_fds_array, CMSG_TYPED_DATA(cmsg, int), n)) {
                                 cmsg_close_all(&mh);
                                 return -ENOMEM;
                         }
-
-                        memcpy(fds_array + n_fds_array, CMSG_TYPED_DATA(cmsg, int), sizeof(int) * n);
-                        n_fds_array += n;
                 }
 
         if (n_fds_array == 0) {
@@ -1468,18 +1481,22 @@ int socket_bind_to_ifindex(int fd, int ifindex) {
 ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) {
         ssize_t n;
 
-        /* A wrapper around recvmsg() that checks for MSG_CTRUNC, and turns it into an error, in a reasonably
-         * safe way, closing any SCM_RIGHTS fds in the error path.
+        /* A wrapper around recvmsg() that checks for MSG_CTRUNC and MSG_TRUNC, and turns them into an error,
+         * in a reasonably safe way, closing any received fds in the error path.
          *
          * Note that unlike our usual coding style this might modify *msg on failure. */
 
+        assert(sockfd >= 0);
+        assert(msg);
+
         n = recvmsg(sockfd, msg, flags);
         if (n < 0)
                 return -errno;
 
-        if (FLAGS_SET(msg->msg_flags, MSG_CTRUNC)) {
+        if (FLAGS_SET(msg->msg_flags, MSG_CTRUNC) ||
+            (!FLAGS_SET(flags, MSG_PEEK) && FLAGS_SET(msg->msg_flags, MSG_TRUNC))) {
                 cmsg_close_all(msg);
-                return -EXFULL; /* a recognizable error code */
+                return FLAGS_SET(msg->msg_flags, MSG_CTRUNC) ? -ECHRNG : -EXFULL;
         }
 
         return n;
@@ -1781,15 +1798,49 @@ int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
 int vsock_get_local_cid(unsigned *ret) {
         _cleanup_close_ int vsock_fd = -EBADF;
 
-        assert(ret);
-
         vsock_fd = open("/dev/vsock", O_RDONLY|O_CLOEXEC);
         if (vsock_fd < 0)
                 return log_debug_errno(errno, "Failed to open /dev/vsock: %m");
 
-        if (ioctl(vsock_fd, IOCTL_VM_SOCKETS_GET_LOCAL_CID, ret) < 0)
+        unsigned tmp;
+        if (ioctl(vsock_fd, IOCTL_VM_SOCKETS_GET_LOCAL_CID, ret ?: &tmp) < 0)
                 return log_debug_errno(errno, "Failed to query local AF_VSOCK CID: %m");
 
         return 0;
 }
+
+int netlink_socket_get_multicast_groups(int fd, size_t *ret_len, uint32_t **ret_groups) {
+        _cleanup_free_ uint32_t *groups = NULL;
+        socklen_t len = 0, old_len;
+
+        assert(fd >= 0);
+
+        /* This returns ENOPROTOOPT if the kernel is older than 4.2. */
+
+        if (getsockopt(fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len) < 0)
+                return -errno;
+
+        if (len == 0)
+                goto finalize;
+
+        groups = new0(uint32_t, len);
+        if (!groups)
+                return -ENOMEM;
+
+        old_len = len;
+
+        if (getsockopt(fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len) < 0)
+                return -errno;
+
+        if (old_len != len)
+                return -EIO;
+
+finalize:
+        if (ret_len)
+                *ret_len = len;
+        if (ret_groups)
+                *ret_groups = TAKE_PTR(groups);
+
+        return 0;
+}
 #endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.h b/src/libnm-systemd-shared/src/basic/socket-util.h
index 15c7d1c5..b6c38725 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.h
+++ b/src/libnm-systemd-shared/src/basic/socket-util.h
@@ -2,15 +2,16 @@
 #pragma once
 
 #include <inttypes.h>
-#include <linux/netlink.h>
 #include <linux/if_ether.h>
 #include <linux/if_infiniband.h>
 #include <linux/if_packet.h>
+#include <linux/netlink.h>
+#include <sys/socket.h> /* linux/vms_sockets.h requires 'struct sockaddr' */
+#include <linux/vm_sockets.h>
 #include <netinet/in.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <string.h>
-#include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
 
@@ -19,6 +20,7 @@
 #include "macro.h"
 #include "missing_network.h"
 #include "missing_socket.h"
+#include "pidref.h"
 #include "sparse-endian.h"
 
 union sockaddr_union {
@@ -28,7 +30,7 @@ union sockaddr_union {
         /* The libc provided version that allocates "enough room" for every protocol */
         struct sockaddr_storage storage;
 
-        /* Protoctol-specific implementations */
+        /* Protocol-specific implementations */
         struct sockaddr_in in;
         struct sockaddr_in6 in6;
         struct sockaddr_un un;
@@ -155,6 +157,7 @@ int getpeercred(int fd, struct ucred *ucred);
 int getpeersec(int fd, char **ret);
 int getpeergroups(int fd, gid_t **ret);
 int getpeerpidfd(int fd);
+int getpeerpidref(int fd, PidRef *ret);
 
 ssize_t send_many_fds_iov_sa(
                 int transport_fd,
@@ -331,7 +334,7 @@ struct timespec_large {
 
 /* glibc duplicates timespec/timeval on certain 32-bit arches, once in 32-bit and once in 64-bit.
  * See __convert_scm_timestamps() in glibc source code. Hence, we need additional buffer space for them
- * to prevent from recvmsg_safe() returning -EXFULL. */
+ * to prevent truncating control msg (recvmsg() MSG_CTRUNC). */
 #define CMSG_SPACE_TIMEVAL                                              \
         ((sizeof(struct timeval) == sizeof(struct timeval_large)) ?     \
          CMSG_SPACE(sizeof(struct timeval)) :                           \
@@ -393,10 +396,12 @@ int socket_address_parse_unix(SocketAddress *ret_address, const char *s);
 int socket_address_parse_vsock(SocketAddress *ret_address, const char *s);
 
 /* libc's SOMAXCONN is defined to 128 or 4096 (at least on glibc). But actually, the value can be much
- * larger. In our codebase we want to set it to the max usually, since noawadays socket memory is properly
+ * larger. In our codebase we want to set it to the max usually, since nowadays socket memory is properly
  * tracked by memcg, and hence we don't need to enforce extra limits here. Moreover, the kernel caps it to
  * /proc/sys/net/core/somaxconn anyway, thus by setting this to unbounded we just make that sysctl file
  * authoritative. */
 #define SOMAXCONN_DELUXE INT_MAX
 
 int vsock_get_local_cid(unsigned *ret);
+
+int netlink_socket_get_multicast_groups(int fd, size_t *ret_len, uint32_t **ret_groups);
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c
index 4da3845b..ef813e19 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.c
+++ b/src/libnm-systemd-shared/src/basic/stat-util.c
@@ -22,6 +22,7 @@
 #include "missing_fs.h"
 #include "missing_magic.h"
 #include "missing_syscall.h"
+#include "mountpoint-util.h"
 #include "nulstr-util.h"
 #include "parse-util.h"
 #include "stat-util.h"
@@ -33,6 +34,7 @@ static int verify_stat_at(
                 bool follow,
                 int (*verify_func)(const struct stat *st),
                 bool verify) {
+
         struct stat st;
         int r;
 
@@ -158,25 +160,9 @@ int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup)
         struct dirent *buf;
         size_t m;
 
-        if (path) {
-                assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
-
-                fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
-                if (fd < 0)
-                        return -errno;
-        } else if (dir_fd == AT_FDCWD) {
-                fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
-                if (fd < 0)
-                        return -errno;
-        } else {
-                /* Note that DUPing is not enough, as the internal pointer would still be shared and moved
-                 * getedents64(). */
-                assert(dir_fd >= 0);
-
-                fd = fd_reopen(dir_fd, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
-                if (fd < 0)
-                        return fd;
-        }
+        fd = xopenat(dir_fd, path, O_DIRECTORY|O_CLOEXEC);
+        if (fd < 0)
+                return fd;
 
         /* Allocate space for at least 3 full dirents, since every dir has at least two entries ("."  +
          * ".."), and only once we have seen if there's a third we know whether the dir is empty or not. If
@@ -231,7 +217,7 @@ int null_or_empty_path_with_root(const char *fn, const char *root) {
          * 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"))
+        if (path_equal(path_startswith(fn, root ?: "/"), "dev/null"))
                 return true;
 
         r = chase_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st);
@@ -241,7 +227,7 @@ int null_or_empty_path_with_root(const char *fn, const char *root) {
         return null_or_empty(&st);
 }
 
-static int fd_is_read_only_fs(int fd) {
+int fd_is_read_only_fs(int fd) {
         struct statvfs st;
 
         assert(fd >= 0);
@@ -271,22 +257,108 @@ int path_is_read_only_fs(const char *path) {
 
         return fd_is_read_only_fs(fd);
 }
-#endif /* NM_IGNORED */
 
 int inode_same_at(int fda, const char *filea, int fdb, const char *fileb, int flags) {
-        struct stat a, b;
+        struct stat sta, stb;
+        int r;
 
         assert(fda >= 0 || fda == AT_FDCWD);
         assert(fdb >= 0 || fdb == AT_FDCWD);
+        assert((flags & ~(AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT)) == 0);
+
+        /* Refuse an unset filea or fileb early unless AT_EMPTY_PATH is set */
+        if ((isempty(filea) || isempty(fileb)) && !FLAGS_SET(flags, AT_EMPTY_PATH))
+                return -EINVAL;
+
+        /* Shortcut: comparing the same fd with itself means we can return true */
+        if (fda >= 0 && fda == fdb && isempty(filea) && isempty(fileb) && FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW))
+                return true;
 
-        if (fstatat(fda, strempty(filea), &a, flags) < 0)
-                return log_debug_errno(errno, "Cannot stat %s: %m", filea);
+        _cleanup_close_ int pin_a = -EBADF, pin_b = -EBADF;
+        if (!FLAGS_SET(flags, AT_NO_AUTOMOUNT)) {
+                /* Let's try to use the name_to_handle_at() AT_HANDLE_FID API to identify identical
+                 * inodes. We have to issue multiple calls on the same file for that (first, to acquire the
+                 * FID, and then to check if .st_dev is actually the same). Hence let's pin the inode in
+                 * between via O_PATH, unless we already have an fd for it. */
+
+                if (!isempty(filea)) {
+                        pin_a = openat(fda, filea, O_PATH|O_CLOEXEC|(FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW) ? O_NOFOLLOW : 0));
+                        if (pin_a < 0)
+                                return -errno;
+
+                        fda = pin_a;
+                        filea = NULL;
+                        flags |= AT_EMPTY_PATH;
+                }
+
+                if (!isempty(fileb)) {
+                        pin_b = openat(fdb, fileb, O_PATH|O_CLOEXEC|(FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW) ? O_NOFOLLOW : 0));
+                        if (pin_b < 0)
+                                return -errno;
+
+                        fdb = pin_b;
+                        fileb = NULL;
+                        flags |= AT_EMPTY_PATH;
+                }
+
+                int ntha_flags = (flags & AT_EMPTY_PATH) | (FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW) ? 0 : AT_SYMLINK_FOLLOW);
+                _cleanup_free_ struct file_handle *ha = NULL, *hb = NULL;
+                int mntida = -1, mntidb = -1;
+
+                r = name_to_handle_at_try_fid(
+                                fda,
+                                filea,
+                                &ha,
+                                &mntida,
+                                ntha_flags);
+                if (r < 0) {
+                        if (is_name_to_handle_at_fatal_error(r))
+                                return r;
+
+                        goto fallback;
+                }
+
+                r = name_to_handle_at_try_fid(
+                                fdb,
+                                fileb,
+                                &hb,
+                                &mntidb,
+                                ntha_flags);
+                if (r < 0) {
+                        if (is_name_to_handle_at_fatal_error(r))
+                                return r;
+
+                        goto fallback;
+                }
+
+                /* Now compare the two file handles */
+                if (!file_handle_equal(ha, hb))
+                        return false;
+
+                /* If the file handles are the same and they come from the same mount ID? Great, then we are
+                 * good, they are definitely the same */
+                if (mntida == mntidb)
+                        return true;
+
+                /* File handles are the same, they are not on the same mount id. This might either be because
+                 * they are on two entirely different file systems, that just happen to have the same FIDs
+                 * (because they originally where created off the same disk images), or it could be because
+                 * they are located on two distinct bind mounts of the same fs. To check that, let's look at
+                 * .st_rdev of the inode. We simply reuse the fallback codepath for that, since it checks
+                 * exactly that (it checks slightly more, but we don't care.) */
+        }
+
+fallback:
+        if (fstatat(fda, strempty(filea), &sta, flags) < 0)
+                return log_debug_errno(errno, "Cannot stat %s: %m", strna(filea));
 
-        if (fstatat(fdb, strempty(fileb), &b, flags) < 0)
-                return log_debug_errno(errno, "Cannot stat %s: %m", fileb);
+        if (fstatat(fdb, strempty(fileb), &stb, flags) < 0)
+                return log_debug_errno(errno, "Cannot stat %s: %m", strna(fileb));
 
-        return stat_inode_same(&a, &b);
+        return stat_inode_same(&sta, &stb);
 }
+#endif /* NM_IGNORED */
+
 
 bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
         assert(s);
@@ -369,8 +441,7 @@ 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 */
+        return stat_is_set(a) && stat_is_set(b) &&
                 ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 &&  /* same inode type */
                 a->st_dev == b->st_dev &&
                 a->st_ino == b->st_ino;
@@ -399,9 +470,8 @@ bool statx_inode_same(const struct statx *a, const struct statx *b) {
 
         /* Same as stat_inode_same() but for struct statx */
 
-        return a && b &&
+        return statx_is_set(a) && statx_is_set(b) &&
                 FLAGS_SET(a->stx_mask, STATX_TYPE|STATX_INO) && FLAGS_SET(b->stx_mask, STATX_TYPE|STATX_INO) &&
-                (a->stx_mode & S_IFMT) != 0 &&
                 ((a->stx_mode ^ b->stx_mode) & S_IFMT) == 0 &&
                 a->stx_dev_major == b->stx_dev_major &&
                 a->stx_dev_minor == b->stx_dev_minor &&
@@ -409,7 +479,7 @@ bool statx_inode_same(const struct statx *a, const struct statx *b) {
 }
 
 bool statx_mount_same(const struct new_statx *a, const struct new_statx *b) {
-        if (!a || !b)
+        if (!new_statx_is_set(a) || !new_statx_is_set(b))
                 return false;
 
         /* if we have the mount ID, that's all we need */
@@ -545,6 +615,8 @@ const char* inode_type_to_string(mode_t m) {
                 return "sock";
         }
 
+        /* Note anonymous inodes in the kernel will have a zero type. Hence fstat() of an eventfd() will
+         * return an .st_mode where we'll return NULL here! */
         return NULL;
 }
 
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.h b/src/libnm-systemd-shared/src/basic/stat-util.h
index 7eb951a7..17fb520f 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.h
+++ b/src/libnm-systemd-shared/src/basic/stat-util.h
@@ -9,6 +9,7 @@
 #include <sys/types.h>
 #include <sys/vfs.h>
 
+#include "fs-util.h"
 #include "macro.h"
 #include "missing_stat.h"
 #include "siphash24.h"
@@ -44,13 +45,16 @@ static inline int null_or_empty_path(const char *fn) {
         return null_or_empty_path_with_root(fn, NULL);
 }
 
+int fd_is_read_only_fs(int fd);
 int path_is_read_only_fs(const char *path);
 
 int inode_same_at(int fda, const char *filea, int fdb, const char *fileb, int flags);
-
 static inline int inode_same(const char *filea, const char *fileb, int flags) {
         return inode_same_at(AT_FDCWD, filea, AT_FDCWD, fileb, flags);
 }
+static inline int fd_inode_same(int fda, int fdb) {
+        return inode_same_at(fda, NULL, fdb, NULL, AT_EMPTY_PATH);
+}
 
 /* The .f_type field of struct statfs is really weird defined on
  * different archs. Let's give its type a name. */
@@ -126,3 +130,20 @@ extern const struct hash_ops inode_hash_ops;
 
 const char* inode_type_to_string(mode_t m);
 mode_t inode_type_from_string(const char *s);
+
+/* Macros that check whether the stat/statx structures have been initialized already. For "struct stat" we
+ * use a check for .st_dev being non-zero, since the kernel unconditionally fills that in, mapping the file
+ * to its originating superblock, regardless if the fs is block based or virtual (we also check for .st_mode
+ * being MODE_INVALID, since we use that as an invalid marker for separate mode_t fields). For "struct statx"
+ * we use the .stx_mask field, which must be non-zero if any of the fields have already been initialized. */
+static inline bool stat_is_set(const struct stat *st) {
+        return st && st->st_dev != 0 && st->st_mode != MODE_INVALID;
+}
+#if 0 /* NM_IGNORED */
+static inline bool statx_is_set(const struct statx *sx) {
+        return sx && sx->stx_mask != 0;
+}
+static inline bool new_statx_is_set(const struct new_statx *sx) {
+        return sx && sx->stx_mask != 0;
+}
+#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/stdio-util.h b/src/libnm-systemd-shared/src/basic/stdio-util.h
index d0b25fdf..c35e6655 100644
--- a/src/libnm-systemd-shared/src/basic/stdio-util.h
+++ b/src/libnm-systemd-shared/src/basic/stdio-util.h
@@ -11,14 +11,12 @@
 #include "macro.h"
 
 _printf_(3, 4)
-static inline char *snprintf_ok(char *buf, size_t len, const char *format, ...) {
+static inline char* snprintf_ok(char *buf, size_t len, const char *format, ...) {
         va_list ap;
         int r;
 
         va_start(ap, format);
-        DISABLE_WARNING_FORMAT_NONLITERAL;
         r = vsnprintf(buf, len, format, ap);
-        REENABLE_WARNING;
         va_end(ap);
 
         return r >= 0 && (size_t) r < len ? buf : NULL;
diff --git a/src/libnm-systemd-shared/src/basic/string-table.h b/src/libnm-systemd-shared/src/basic/string-table.h
index 3be70dfa..83891eeb 100644
--- a/src/libnm-systemd-shared/src/basic/string-table.h
+++ b/src/libnm-systemd-shared/src/basic/string-table.h
@@ -15,7 +15,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
 
 /* For basic lookup tables with strictly enumerated entries */
 #define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
-        scope const char *name##_to_string(type i) {                    \
+        scope const char* name##_to_string(type i) {                    \
                 if (i < 0 || i >= (type) ELEMENTSOF(name##_table))      \
                         return NULL;                                    \
                 return name##_table[i];                                 \
@@ -47,10 +47,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
                         s = strdup(name##_table[i]);                    \
                         if (!s)                                         \
                                 return -ENOMEM;                         \
-                } else {                                                \
-                        if (asprintf(&s, "%i", i) < 0)                  \
-                                return -ENOMEM;                         \
-                }                                                       \
+                } else if (asprintf(&s, "%i", i) < 0)                   \
+                        return -ENOMEM;                                 \
                 *str = s;                                               \
                 return 0;                                               \
         }
@@ -103,7 +101,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
         _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static)
 
 #define DUMP_STRING_TABLE(name,type,max)                                \
-        do {                                                            \
+        ({                                                              \
                 flockfile(stdout);                                      \
                 for (type _k = 0; _k < (max); _k++) {                   \
                         const char *_t;                                 \
@@ -114,4 +112,5 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
                         fputc_unlocked('\n', stdout);                   \
                 }                                                       \
                 funlockfile(stdout);                                    \
-        } while (false)
+                0;                                                      \
+        })
diff --git a/src/libnm-systemd-shared/src/basic/string-util.c b/src/libnm-systemd-shared/src/basic/string-util.c
index 59e65918..6a06594a 100644
--- a/src/libnm-systemd-shared/src/basic/string-util.c
+++ b/src/libnm-systemd-shared/src/basic/string-util.c
@@ -13,6 +13,7 @@
 #include "extract-word.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "glyph-util.h"
 #include "gunicode.h"
 #include "locale-util.h"
 #include "macro.h"
@@ -25,40 +26,29 @@
 #include "utf8.h"
 
 char* first_word(const char *s, const char *word) {
-        size_t sl, wl;
-        const char *p;
-
         assert(s);
         assert(word);
 
-        /* Checks if the string starts with the specified word, either
-         * followed by NUL or by whitespace. Returns a pointer to the
-         * NUL or the first character after the whitespace. */
-
-        sl = strlen(s);
-        wl = strlen(word);
-
-        if (sl < wl)
-                return NULL;
+        /* Checks if the string starts with the specified word, either followed by NUL or by whitespace.
+         * Returns a pointer to the NUL or the first character after the whitespace. */
 
-        if (wl == 0)
+        if (isempty(word))
                 return (char*) s;
 
-        if (memcmp(s, word, wl) != 0)
+        const char *p = startswith(s, word);
+        if (!p)
                 return NULL;
-
-        p = s + wl;
-        if (*p == 0)
+        if (*p == '\0')
                 return (char*) p;
 
-        if (!strchr(WHITESPACE, *p))
+        const char *nw = skip_leading_chars(p, WHITESPACE);
+        if (p == nw)
                 return NULL;
 
-        p += strspn(p, WHITESPACE);
-        return (char*) p;
+        return (char*) nw;
 }
 
-char *strnappend(const char *s, const char *suffix, size_t b) {
+char* strnappend(const char *s, const char *suffix, size_t b) {
         size_t a;
         char *r;
 
@@ -89,40 +79,8 @@ char *strnappend(const char *s, const char *suffix, size_t b) {
         return r;
 }
 
-char *strjoin_real(const char *x, ...) {
-        va_list ap;
-        size_t l = 1;
-        char *r, *p;
-
-        va_start(ap, x);
-        for (const char *t = x; t; t = va_arg(ap, const char *)) {
-                size_t n;
-
-                n = strlen(t);
-                if (n > SIZE_MAX - l) {
-                        va_end(ap);
-                        return NULL;
-                }
-                l += n;
-        }
-        va_end(ap);
-
-        p = r = new(char, l);
-        if (!r)
-                return NULL;
-
-        va_start(ap, x);
-        for (const char *t = x; t; t = va_arg(ap, const char *))
-                p = stpcpy(p, t);
-        va_end(ap);
-
-        *p = 0;
-
-        return r;
-}
-
 #if 0 /* NM_IGNORED */
-char *strstrip(char *s) {
+char* strstrip(char *s) {
         if (!s)
                 return NULL;
 
@@ -131,7 +89,7 @@ char *strstrip(char *s) {
         return delete_trailing_chars(skip_leading_chars(s, WHITESPACE), WHITESPACE);
 }
 
-char *delete_chars(char *s, const char *bad) {
+char* delete_chars(char *s, const char *bad) {
         char *f, *t;
 
         /* Drops all specified bad characters, regardless where in the string */
@@ -154,7 +112,7 @@ char *delete_chars(char *s, const char *bad) {
         return s;
 }
 
-char *delete_trailing_chars(char *s, const char *bad) {
+char* delete_trailing_chars(char *s, const char *bad) {
         char *c = s;
 
         /* Drops all specified bad characters, at the end of the string */
@@ -175,7 +133,7 @@ char *delete_trailing_chars(char *s, const char *bad) {
 }
 #endif /* NM_IGNORED */
 
-char *truncate_nl_full(char *s, size_t *ret_len) {
+char* truncate_nl_full(char *s, size_t *ret_len) {
         size_t n;
 
         assert(s);
@@ -203,7 +161,7 @@ char ascii_toupper(char x) {
         return x;
 }
 
-char *ascii_strlower(char *t) {
+char* ascii_strlower(char *t) {
         assert(t);
 
         for (char *p = t; *p; p++)
@@ -212,7 +170,7 @@ char *ascii_strlower(char *t) {
         return t;
 }
 
-char *ascii_strupper(char *t) {
+char* ascii_strupper(char *t) {
         assert(t);
 
         for (char *p = t; *p; p++)
@@ -221,7 +179,7 @@ char *ascii_strupper(char *t) {
         return t;
 }
 
-char *ascii_strlower_n(char *t, size_t n) {
+char* ascii_strlower_n(char *t, size_t n) {
         if (n <= 0)
                 return t;
 
@@ -287,16 +245,9 @@ bool string_has_cc(const char *p, const char *ok) {
 
 #if 0 /* NM_IGNORED */
 static int write_ellipsis(char *buf, bool unicode) {
-        if (unicode || is_locale_utf8()) {
-                buf[0] = 0xe2; /* tri-dot ellipsis: … */
-                buf[1] = 0x80;
-                buf[2] = 0xa6;
-        } else {
-                buf[0] = '.';
-                buf[1] = '.';
-                buf[2] = '.';
-        }
-
+        const char *s = special_glyph_full(SPECIAL_GLYPH_ELLIPSIS, unicode);
+        assert(strlen(s) == 3);
+        memcpy(buf, s, 3);
         return 3;
 }
 
@@ -403,8 +354,7 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le
         x = ((new_length - need_space) * percent + 50) / 100;
         assert(x <= new_length - need_space);
 
-        memcpy(t, s, x);
-        write_ellipsis(t + x, false);
+        write_ellipsis(mempcpy(t, s, x), /* unicode = */ false);
         suffix_len = new_length - x - need_space;
         memcpy(t + x + 3, s + old_length - suffix_len, suffix_len);
         *(t + x + 3 + suffix_len) = '\0';
@@ -412,7 +362,7 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le
         return t;
 }
 
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
+char* ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
         size_t x, k, len, len2;
         const char *i, *j;
         int r;
@@ -525,13 +475,8 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
         if (!e)
                 return NULL;
 
-        /*
-        printf("old_length=%zu new_length=%zu x=%zu len=%zu len2=%zu k=%zu\n",
-               old_length, new_length, x, len, len2, k);
-        */
-
         memcpy_safe(e, s, len);
-        write_ellipsis(e + len, true);
+        write_ellipsis(e + len, /* unicode = */ true);
 
         char *dst = e + len + 3;
 
@@ -552,7 +497,7 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
         return e;
 }
 
-char *cellescape(char *buf, size_t len, const char *s) {
+char* cellescape(char *buf, size_t len, const char *s) {
         /* Escape and ellipsize s into buffer buf of size len. Only non-control ASCII
          * characters are copied as they are, everything else is escaped. The result
          * is different then if escaping and ellipsization was performed in two
@@ -567,7 +512,9 @@ char *cellescape(char *buf, size_t len, const char *s) {
 
         size_t i = 0, last_char_width[4] = {}, k = 0;
 
+        assert(buf);
         assert(len > 0); /* at least a terminating NUL */
+        assert(s);
 
         for (;;) {
                 char four[4];
@@ -608,7 +555,7 @@ char *cellescape(char *buf, size_t len, const char *s) {
         }
 
         if (i + 4 <= len) /* yay, enough space */
-                i += write_ellipsis(buf + i, false);
+                i += write_ellipsis(buf + i, /* unicode = */ false);
         else if (i + 3 <= len) { /* only space for ".." */
                 buf[i++] = '.';
                 buf[i++] = '.';
@@ -617,7 +564,7 @@ char *cellescape(char *buf, size_t len, const char *s) {
         else
                 assert(i + 1 <= len);
 
- done:
+done:
         buf[i] = '\0';
         return buf;
 }
@@ -657,7 +604,7 @@ int strgrowpad0(char **s, size_t l) {
 }
 #endif /* NM_IGNORED */
 
-char *strreplace(const char *text, const char *old_string, const char *new_string) {
+char* strreplace(const char *text, const char *old_string, const char *new_string) {
         size_t l, old_len, new_len;
         char *t, *ret = NULL;
         const char *f;
@@ -720,13 +667,14 @@ static void advance_offsets(
                 shift[1] += size;
 }
 
-char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
+char* strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
         const char *begin = NULL;
         enum {
                 STATE_OTHER,
                 STATE_ESCAPE,
                 STATE_CSI,
-                STATE_CSO,
+                STATE_OSC,
+                STATE_OSC_CLOSING,
         } state = STATE_OTHER;
         _cleanup_(memstream_done) MemStream m = {};
         size_t isz, shift[2] = {}, n_carriage_returns = 0;
@@ -739,7 +687,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
          *
          * 1. Replaces TABs by 8 spaces
          * 2. Strips ANSI color sequences (a subset of CSI), i.e. ESC '[' … 'm' sequences
-         * 3. Strips ANSI operating system sequences (CSO), i.e. ESC ']' … BEL sequences
+         * 3. Strips ANSI operating system sequences (OSC), i.e. ESC ']' … ST sequences
          * 4. Strip trailing \r characters (since they would "move the cursor", but have no
          *    other effect).
          *
@@ -747,7 +695,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
          * are any other special characters. Truncated ANSI sequences are left-as is too. This call is
          * supposed to suppress the most basic formatting noise, but nothing else.
          *
-         * Why care for CSO sequences? Well, to undo what terminal_urlify() and friends generate. */
+         * Why care for OSC sequences? Well, to undo what terminal_urlify() and friends generate. */
 
         isz = _isz ? *_isz : strlen(*ibuf);
 
@@ -759,10 +707,12 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
 
         for (const char *i = *ibuf; i < *ibuf + isz + 1; i++) {
 
+                bool eot = i >= *ibuf + isz;
+
                 switch (state) {
 
                 case STATE_OTHER:
-                        if (i >= *ibuf + isz) /* EOT */
+                        if (eot)
                                 break;
 
                         if (*i == '\r') {
@@ -787,15 +737,15 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
                 case STATE_ESCAPE:
                         assert(n_carriage_returns == 0);
 
-                        if (i >= *ibuf + isz) { /* EOT */
+                        if (eot) {
                                 fputc('\x1B', f);
                                 advance_offsets(i - *ibuf, highlight, shift, 1);
                                 break;
                         } else if (*i == '[') { /* ANSI CSI */
                                 state = STATE_CSI;
                                 begin = i + 1;
-                        } else if (*i == ']') { /* ANSI CSO */
-                                state = STATE_CSO;
+                        } else if (*i == ']') { /* ANSI OSC */
+                                state = STATE_OSC;
                                 begin = i + 1;
                         } else {
                                 fputc('\x1B', f);
@@ -809,8 +759,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
                 case STATE_CSI:
                         assert(n_carriage_returns == 0);
 
-                        if (i >= *ibuf + isz || /* EOT … */
-                            !strchr("01234567890;m", *i)) { /* … or invalid chars in sequence */
+                        if (eot || !strchr("01234567890;m", *i)) { /* EOT or invalid chars in sequence */
                                 fputc('\x1B', f);
                                 fputc('[', f);
                                 advance_offsets(i - *ibuf, highlight, shift, 2);
@@ -821,17 +770,33 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
 
                         break;
 
-                case STATE_CSO:
+                case STATE_OSC:
                         assert(n_carriage_returns == 0);
 
-                        if (i >= *ibuf + isz || /* EOT … */
-                            (*i != '\a' && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */
+                        /* There are three kinds of OSC terminators: \x07, \x1b\x5c or \x9c. We only support
+                         * the first two, because the last one is a valid UTF-8 codepoint and hence creates
+                         * an ambiguity (many Terminal emulators refuse to support it as well). */
+                        if (eot || (!IN_SET(*i, '\x07', '\x1b') && !osc_char_is_valid(*i))) { /* EOT or invalid chars in sequence */
                                 fputc('\x1B', f);
                                 fputc(']', f);
                                 advance_offsets(i - *ibuf, highlight, shift, 2);
                                 state = STATE_OTHER;
                                 i = begin-1;
-                        } else if (*i == '\a')
+                        } else if (*i == '\x07') /* Single character ST */
+                                state = STATE_OTHER;
+                        else if (*i == '\x1B')
+                                state = STATE_OSC_CLOSING;
+
+                        break;
+
+                case STATE_OSC_CLOSING:
+                        if (eot || *i != '\x5c') { /* EOT or incomplete two-byte ST in sequence */
+                                fputc('\x1B', f);
+                                fputc(']', f);
+                                advance_offsets(i - *ibuf, highlight, shift, 2);
+                                state = STATE_OTHER;
+                                i = begin-1;
+                        } else if (*i == '\x5c')
                                 state = STATE_OTHER;
 
                         break;
@@ -853,13 +818,15 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
 }
 #endif /* NM_IGNORED */
 
-char *strextend_with_separator_internal(char **x, const char *separator, ...) {
+char* strextend_with_separator_internal(char **x, const char *separator, ...) {
+        _cleanup_free_ char *buffer = NULL;
         size_t f, l, l_separator;
         bool need_separator;
         char *nr, *p;
         va_list ap;
 
-        assert(x);
+        if (!x)
+                x = &buffer;
 
         l = f = strlen_ptr(*x);
 
@@ -867,13 +834,14 @@ char *strextend_with_separator_internal(char **x, const char *separator, ...) {
         l_separator = strlen_ptr(separator);
 
         va_start(ap, separator);
-        for (;;) {
-                const char *t;
+        for (const char *t;;) {
                 size_t n;
 
                 t = va_arg(ap, const char *);
                 if (!t)
                         break;
+                if (t == POINTER_MAX)
+                        continue;
 
                 n = strlen(t);
 
@@ -906,6 +874,8 @@ char *strextend_with_separator_internal(char **x, const char *separator, ...) {
                 t = va_arg(ap, const char *);
                 if (!t)
                         break;
+                if (t == POINTER_MAX)
+                        continue;
 
                 if (need_separator && separator)
                         p = stpcpy(p, separator);
@@ -917,9 +887,13 @@ char *strextend_with_separator_internal(char **x, const char *separator, ...) {
         va_end(ap);
 
         assert(p == nr + l);
-
         *p = 0;
 
+        /* If no buffer to extend was passed in return the start of the buffer */
+        if (buffer)
+                return TAKE_PTR(buffer);
+
+        /* Otherwise we extended the buffer: return the end */
         return p;
 }
 
@@ -1004,12 +978,12 @@ int strextendf_with_separator(char **x, const char *separator, const char *forma
         return 0;
 
 oom:
-        /* truncate the bytes added after the first vsnprintf() attempt again */
+        /* truncate the bytes added after memcpy_safe() again */
         (*x)[m] = 0;
         return -ENOMEM;
 }
 
-char *strextendn(char **x, const char *s, size_t l) {
+char* strextendn(char **x, const char *s, size_t l) {
         assert(x);
         assert(s || l == 0);
 
@@ -1036,7 +1010,7 @@ char *strextendn(char **x, const char *s, size_t l) {
         return *x;
 }
 
-char *strrep(const char *s, unsigned n) {
+char* strrep(const char *s, unsigned n) {
         char *r, *p;
         size_t l;
 
@@ -1054,34 +1028,26 @@ char *strrep(const char *s, unsigned n) {
         return r;
 }
 
-int split_pair(const char *s, const char *sep, char **l, char **r) {
-        char *x, *a, *b;
-
+int split_pair(const char *s, const char *sep, char **ret_first, char **ret_second) {
         assert(s);
-        assert(sep);
-        assert(l);
-        assert(r);
+        assert(!isempty(sep));
+        assert(ret_first);
+        assert(ret_second);
 
-        if (isempty(sep))
-                return -EINVAL;
-
-        x = strstr(s, sep);
+        const char *x = strstr(s, sep);
         if (!x)
                 return -EINVAL;
 
-        a = strndup(s, x - s);
+        _cleanup_free_ char *a = strndup(s, x - s);
         if (!a)
                 return -ENOMEM;
 
-        b = strdup(x + strlen(sep));
-        if (!b) {
-                free(a);
+        _cleanup_free_ char *b = strdup(x + strlen(sep));
+        if (!b)
                 return -ENOMEM;
-        }
-
-        *l = a;
-        *r = b;
 
+        *ret_first = TAKE_PTR(a);
+        *ret_second = TAKE_PTR(b);
         return 0;
 }
 
@@ -1134,6 +1100,24 @@ int free_and_strndup(char **p, const char *s, size_t l) {
         return 1;
 }
 
+int strdup_to_full(char **ret, const char *src) {
+        if (!src) {
+                if (ret)
+                        *ret = NULL;
+
+                return 0;
+        } else {
+                if (ret) {
+                        char *t = strdup(src);
+                        if (!t)
+                                return -ENOMEM;
+                        *ret = t;
+                }
+
+                return 1;
+        }
+};
+
 bool string_is_safe(const char *p) {
         if (!p)
                 return false;
@@ -1244,54 +1228,31 @@ int string_extract_line(const char *s, size_t i, char **ret) {
                                         return -ENOMEM;
 
                                 *ret = m;
-                                return !isempty(q + 1); /* more coming? */
-                        } else {
-                                if (p == s)
-                                        *ret = NULL; /* Just use the input string */
-                                else {
-                                        char *m;
-
-                                        m = strdup(p);
-                                        if (!m)
-                                                return -ENOMEM;
-
-                                        *ret = m;
-                                }
-
-                                return 0; /* The end */
-                        }
+                                return !isempty(q + 1); /* More coming? */
+                        } else
+                                /* Tell the caller to use the input string if equal */
+                                return strdup_to(ret, p != s ? p : NULL);
                 }
 
-                if (!q) {
-                        char *m;
-
+                if (!q)
                         /* No more lines, return empty line */
-
-                        m = strdup("");
-                        if (!m)
-                                return -ENOMEM;
-
-                        *ret = m;
-                        return 0; /* The end */
-                }
+                        return strdup_to(ret, "");
 
                 p = q + 1;
                 c++;
         }
 }
 
-int string_contains_word_strv(const char *string, const char *separators, char **words, const char **ret_word) {
-        /* In the default mode with no separators specified, we split on whitespace and
-         * don't coalesce separators. */
+int string_contains_word_strv(const char *string, const char *separators, char * const *words, const char **ret_word) {
+        /* In the default mode with no separators specified, we split on whitespace and coalesce separators. */
         const ExtractFlags flags = separators ? EXTRACT_DONT_COALESCE_SEPARATORS : 0;
-
         const char *found = NULL;
+        int r;
 
-        for (const char *p = string;;) {
+        for (;;) {
                 _cleanup_free_ char *w = NULL;
-                int r;
 
-                r = extract_first_word(&p, &w, separators, flags);
+                r = extract_first_word(&string, &w, separators, flags);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -1324,7 +1285,7 @@ bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok) {
 }
 #endif /* NM_IGNORED */
 
-char *string_replace_char(char *str, char old_char, char new_char) {
+char* string_replace_char(char *str, char old_char, char new_char) {
         assert(str);
         assert(old_char != '\0');
         assert(new_char != '\0');
@@ -1395,14 +1356,14 @@ size_t strspn_from_end(const char *str, const char *accept) {
 }
 
 #if 0 /* NM_IGNORED */
-char *strdupspn(const char *a, const char *accept) {
+char* strdupspn(const char *a, const char *accept) {
         if (isempty(a) || isempty(accept))
                 return strdup("");
 
         return strndup(a, strspn(a, accept));
 }
 
-char *strdupcspn(const char *a, const char *reject) {
+char* strdupcspn(const char *a, const char *reject) {
         if (isempty(a))
                 return strdup("");
         if (isempty(reject))
@@ -1411,7 +1372,7 @@ char *strdupcspn(const char *a, const char *reject) {
         return strndup(a, strcspn(a, reject));
 }
 
-char *find_line_startswith(const char *haystack, const char *needle) {
+char* find_line_startswith(const char *haystack, const char *needle) {
         char *p;
 
         assert(haystack);
@@ -1523,7 +1484,7 @@ ssize_t strlevenshtein(const char *x, const char *y) {
         return t1[yl];
 }
 
-char *strrstr(const char *haystack, const char *needle) {
+char* strrstr(const char *haystack, const char *needle) {
         /* Like strstr() but returns the last rather than the first occurrence of "needle" in "haystack". */
 
         if (!haystack || !needle)
diff --git a/src/libnm-systemd-shared/src/basic/string-util.h b/src/libnm-systemd-shared/src/basic/string-util.h
index e162765a..1bcb1c40 100644
--- a/src/libnm-systemd-shared/src/basic/string-util.h
+++ b/src/libnm-systemd-shared/src/basic/string-util.h
@@ -8,6 +8,7 @@
 #include "alloc-util.h"
 #include "macro.h"
 #include "string-util-fundamental.h"
+#include "utf8.h"
 
 /* What is interpreted as whitespace? */
 #define WHITESPACE          " \t\n\r"
@@ -32,7 +33,7 @@ static inline char* strstr_ptr(const char *haystack, const char *needle) {
         return strstr(haystack, needle);
 }
 
-static inline char *strstrafter(const char *haystack, const char *needle) {
+static inline char* strstrafter(const char *haystack, const char *needle) {
         char *p;
 
         /* Returns NULL if not found, or pointer to first character after needle if found */
@@ -48,7 +49,7 @@ static inline const char* strnull(const char *s) {
         return s ?: "(null)";
 }
 
-static inline const char *strna(const char *s) {
+static inline const char* strna(const char *s) {
         return s ?: "n/a";
 }
 
@@ -80,11 +81,11 @@ static inline const char* enabled_disabled(bool b) {
                 (typeof(p)) (isempty(_p) ? NULL : _p);  \
         })
 
-static inline const char *empty_to_na(const char *p) {
+static inline const char* empty_to_na(const char *p) {
         return isempty(p) ? "n/a" : p;
 }
 
-static inline const char *empty_to_dash(const char *str) {
+static inline const char* empty_to_dash(const char *str) {
         return isempty(str) ? "-" : str;
 }
 
@@ -94,7 +95,7 @@ static inline bool empty_or_dash(const char *str) {
                 (str[0] == '-' && str[1] == 0);
 }
 
-static inline const char *empty_or_dash_to_null(const char *p) {
+static inline const char* empty_or_dash_to_null(const char *p) {
         return empty_or_dash(p) ? NULL : p;
 }
 #define empty_or_dash_to_null(p)                                \
@@ -103,12 +104,11 @@ static inline const char *empty_or_dash_to_null(const char *p) {
                 (typeof(p)) (empty_or_dash(_p) ? NULL : _p);    \
         })
 
-char *first_word(const char *s, const char *word) _pure_;
+char* first_word(const char *s, const char *word) _pure_;
 
-char *strnappend(const char *s, const char *suffix, size_t length);
+char* strnappend(const char *s, const char *suffix, size_t length);
 
-char *strjoin_real(const char *x, ...) _sentinel_;
-#define strjoin(a, ...) strjoin_real((a), __VA_ARGS__, NULL)
+#define strjoin(a, ...) strextend_with_separator_internal(NULL, NULL, a, __VA_ARGS__, NULL)
 
 #define strjoina(a, ...)                                                \
         ({                                                              \
@@ -125,15 +125,15 @@ char *strjoin_real(const char *x, ...) _sentinel_;
                 _d_;                                                    \
         })
 
-char *strstrip(char *s);
-char *delete_chars(char *s, const char *bad);
-char *delete_trailing_chars(char *s, const char *bad);
-char *truncate_nl_full(char *s, size_t *ret_len);
-static inline char *truncate_nl(char *s) {
+char* strstrip(char *s);
+char* delete_chars(char *s, const char *bad);
+char* delete_trailing_chars(char *s, const char *bad);
+char* truncate_nl_full(char *s, size_t *ret_len);
+static inline char* truncate_nl(char *s) {
         return truncate_nl_full(s, NULL);
 }
 
-static inline char *skip_leading_chars(const char *s, const char *bad) {
+static inline char* skip_leading_chars(const char *s, const char *bad) {
         if (!s)
                 return NULL;
 
@@ -144,18 +144,18 @@ static inline char *skip_leading_chars(const char *s, const char *bad) {
 }
 
 char ascii_tolower(char x);
-char *ascii_strlower(char *s);
-char *ascii_strlower_n(char *s, size_t n);
+char* ascii_strlower(char *s);
+char* ascii_strlower_n(char *s, size_t n);
 
 char ascii_toupper(char x);
-char *ascii_strupper(char *s);
+char* ascii_strupper(char *s);
 
 int ascii_strcasecmp_n(const char *a, const char *b, size_t n);
 int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m);
 
 bool chars_intersect(const char *a, const char *b) _pure_;
 
-static inline bool _pure_ in_charset(const char *s, const char* charset) {
+static inline bool _pure_ in_charset(const char *s, const char *charset) {
         assert(s);
         assert(charset);
         return s[strspn(s, charset)] == '\0';
@@ -171,12 +171,12 @@ static inline bool char_is_cc(char p) {
 }
 bool string_has_cc(const char *p, const char *ok) _pure_;
 
-char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
-static inline char *ellipsize(const char *s, size_t length, unsigned percent) {
+char* ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
+static inline char* ellipsize(const char *s, size_t length, unsigned percent) {
         return ellipsize_mem(s, strlen(s), length, percent);
 }
 
-char *cellescape(char *buf, size_t len, const char *s);
+char* cellescape(char *buf, size_t len, const char *s);
 
 /* This limit is arbitrary, enough to give some idea what the string contains */
 #define CELLESCAPE_DEFAULT_LENGTH 64
@@ -185,33 +185,35 @@ char* strshorten(char *s, size_t l);
 
 int strgrowpad0(char **s, size_t l);
 
-char *strreplace(const char *text, const char *old_string, const char *new_string);
+char* strreplace(const char *text, const char *old_string, const char *new_string);
 
-char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]);
+char* strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]);
 
-char *strextend_with_separator_internal(char **x, const char *separator, ...) _sentinel_;
+char* strextend_with_separator_internal(char **x, const char *separator, ...) _sentinel_;
 #define strextend_with_separator(x, separator, ...) strextend_with_separator_internal(x, separator, __VA_ARGS__, NULL)
 #define strextend(x, ...) strextend_with_separator_internal(x, NULL, __VA_ARGS__, NULL)
 
-char *strextendn(char **x, const char *s, size_t l);
+char* strextendn(char **x, const char *s, size_t l);
 
 int strextendf_with_separator(char **x, const char *separator, const char *format, ...) _printf_(3,4);
 #define strextendf(x, ...) strextendf_with_separator(x, NULL, __VA_ARGS__)
 
-char *strrep(const char *s, unsigned n);
+char* strrep(const char *s, unsigned n);
 
-#define strrepa(s, n)                                           \
-        ({                                                      \
-                char *_d_, *_p_;                                \
-                size_t _len_ = strlen(s) * n;                   \
-                _p_ = _d_ = newa(char, _len_ + 1);              \
-                for (unsigned _i_ = 0; _i_ < n; _i_++)          \
-                        _p_ = stpcpy(_p_, s);                   \
-                *_p_ = 0;                                       \
-                _d_;                                            \
+#define strrepa(s, n)                                                   \
+        ({                                                              \
+                const char *_sss_ = (s);                                \
+                size_t _nnn_ = (n), _len_ = strlen(_sss_);              \
+                assert_se(MUL_ASSIGN_SAFE(&_len_, _nnn_));              \
+                char *_d_, *_p_;                                        \
+                _p_ = _d_ = newa(char, _len_ + 1);                      \
+                for (size_t _i_ = 0; _i_ < _nnn_; _i_++)                \
+                        _p_ = stpcpy(_p_, _sss_);                       \
+                *_p_ = 0;                                               \
+                _d_;                                                    \
         })
 
-int split_pair(const char *s, const char *sep, char **l, char **r);
+int split_pair(const char *s, const char *sep, char **ret_first, char **ret_second);
 
 int free_and_strdup(char **p, const char *s);
 static inline int free_and_strdup_warn(char **p, const char *s) {
@@ -224,7 +226,16 @@ static inline int free_and_strdup_warn(char **p, const char *s) {
 }
 int free_and_strndup(char **p, const char *s, size_t l);
 
+int strdup_to_full(char **ret, const char *src);
+static inline int strdup_to(char **ret, const char *src) {
+        int r = strdup_to_full(ASSERT_PTR(ret), src);
+        return r < 0 ? r : 0;  /* Suppress return value of 1. */
+}
+
 bool string_is_safe(const char *p) _pure_;
+static inline bool string_is_safe_ascii(const char *p) {
+        return ascii_is_valid(p) && string_is_safe(p);
+}
 
 DISABLE_WARNING_STRINGOP_TRUNCATION;
 static inline void strncpy_exact(char *buf, const char *src, size_t buf_len) {
@@ -235,7 +246,7 @@ REENABLE_WARNING;
 /* Like startswith_no_case(), but operates on arbitrary memory blocks.
  * It works only for ASCII strings.
  */
-static inline void *memory_startswith_no_case(const void *p, size_t sz, const char *token) {
+static inline void* memory_startswith_no_case(const void *p, size_t sz, const char *token) {
         assert(token);
 
         size_t n = strlen(token);
@@ -265,14 +276,14 @@ char* string_erase(char *x);
 int string_truncate_lines(const char *s, size_t n_lines, char **ret);
 int string_extract_line(const char *s, size_t i, char **ret);
 
-int string_contains_word_strv(const char *string, const char *separators, char **words, const char **ret_word);
+int string_contains_word_strv(const char *string, const char *separators, char * const *words, const char **ret_word);
 static inline int string_contains_word(const char *string, const char *separators, const char *word) {
         return string_contains_word_strv(string, separators, STRV_MAKE(word), NULL);
 }
 
 bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok);
 
-char *string_replace_char(char *str, char old_char, char new_char);
+char* string_replace_char(char *str, char old_char, char new_char);
 
 typedef enum MakeCStringMode {
         MAKE_CSTRING_REFUSE_TRAILING_NUL,
@@ -286,10 +297,10 @@ int make_cstring(const char *s, size_t n, MakeCStringMode mode, char **ret);
 
 size_t strspn_from_end(const char *str, const char *accept);
 
-char *strdupspn(const char *a, const char *accept);
-char *strdupcspn(const char *a, const char *reject);
+char* strdupspn(const char *a, const char *accept);
+char* strdupcspn(const char *a, const char *reject);
 
-char *find_line_startswith(const char *haystack, const char *needle);
+char* find_line_startswith(const char *haystack, const char *needle);
 
 bool version_is_valid(const char *s);
 
@@ -297,25 +308,4 @@ bool version_is_valid_versionspec(const char *s);
 
 ssize_t strlevenshtein(const char *x, const char *y);
 
-static inline int strdup_or_null(const char *s, char **ret) {
-        char *c;
-
-        assert(ret);
-
-        /* This is a lot like strdup(), but is happy with NULL strings, and does not treat that as error, but
-         * copies the NULL value. */
-
-        if (!s) {
-                *ret = NULL;
-                return 0;
-        }
-
-        c = strdup(s);
-        if (!c)
-                return -ENOMEM;
-
-        *ret = c;
-        return 1;
-}
-
-char *strrstr(const char *haystack, const char *needle);
+char* strrstr(const char *haystack, const char *needle);
diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c
index ed02b481..38466696 100644
--- a/src/libnm-systemd-shared/src/basic/strv.c
+++ b/src/libnm-systemd-shared/src/basic/strv.c
@@ -13,11 +13,13 @@
 #include "escape.h"
 #include "extract-word.h"
 #include "fileio.h"
+#include "gunicode.h"
 #include "memory-util.h"
 #include "nulstr-util.h"
 #include "sort-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "utf8.h"
 
 char* strv_find(char * const *l, const char *name) {
         assert(name);
@@ -66,6 +68,68 @@ char* strv_find_startswith(char * const *l, const char *name) {
         return NULL;
 }
 
+static char* strv_find_closest_prefix(char * const *l, const char *name) {
+        size_t best_distance = SIZE_MAX;
+        char *best = NULL;
+
+        assert(name);
+
+        STRV_FOREACH(s, l) {
+                char *e = startswith(*s, name);
+                if (!e)
+                        continue;
+
+                size_t n = strlen(e);
+                if (n < best_distance) {
+                        best_distance = n;
+                        best = *s;
+                }
+        }
+
+        return best;
+}
+
+static char* strv_find_closest_by_levenshtein(char * const *l, const char *name) {
+        ssize_t best_distance = SSIZE_MAX;
+        char *best = NULL;
+
+        assert(name);
+
+        STRV_FOREACH(i, l) {
+                ssize_t distance;
+
+                distance = strlevenshtein(*i, name);
+                if (distance < 0) {
+                        log_debug_errno(distance, "Failed to determine Levenshtein distance between %s and %s: %m", *i, name);
+                        return NULL;
+                }
+
+                if (distance > 5) /* If the distance is just too far off, don't make a bad suggestion */
+                        continue;
+
+                if (distance < best_distance) {
+                        best_distance = distance;
+                        best = *i;
+                }
+        }
+
+        return best;
+}
+
+char* strv_find_closest(char * const *l, const char *name) {
+        assert(name);
+
+        /* Be more helpful to the user, and give a hint what the user might have wanted to type. We search
+         * with two mechanisms: a simple prefix match and – if that didn't yield results –, a Levenshtein
+         * word distance based match. */
+
+        char *found = strv_find_closest_prefix(l, name);
+        if (found)
+                return found;
+
+        return strv_find_closest_by_levenshtein(l, name);
+}
+
 char* strv_find_first_field(char * const *needles, char * const *haystack) {
         STRV_FOREACH(k, needles) {
                 char *value = strv_env_pairs_get((char **)haystack, *k);
@@ -202,20 +266,18 @@ char** strv_new_internal(const char *x, ...) {
 
 int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
         size_t p, q, i = 0;
-        char **t;
 
         assert(a);
 
-        if (strv_isempty(b))
+        q = strv_length(b);
+        if (q == 0)
                 return 0;
 
         p = strv_length(*a);
-        q = strv_length(b);
-
         if (p >= SIZE_MAX - q)
                 return -ENOMEM;
 
-        t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
+        char **t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
         if (!t)
                 return -ENOMEM;
 
@@ -244,22 +306,78 @@ rollback:
         return -ENOMEM;
 }
 
+int strv_extend_strv_consume(char ***a, char **b, bool filter_duplicates) {
+        _cleanup_strv_free_ char **b_consume = b;
+        size_t p, q, i;
+
+        assert(a);
+
+        q = strv_length(b);
+        if (q == 0)
+                return 0;
+
+        p = strv_length(*a);
+        if (p == 0) {
+                strv_free_and_replace(*a, b_consume);
+
+                if (filter_duplicates)
+                        strv_uniq(*a);
+
+                return strv_length(*a);
+        }
+
+        if (p >= SIZE_MAX - q)
+                return -ENOMEM;
+
+        char **t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
+        if (!t)
+                return -ENOMEM;
+
+        t[p] = NULL;
+        *a = t;
+
+        if (!filter_duplicates) {
+                *mempcpy_typesafe(t + p, b, q) = NULL;
+                i = q;
+        } else {
+                i = 0;
+
+                STRV_FOREACH(s, b) {
+                        if (strv_contains(t, *s)) {
+                                free(*s);
+                                continue;
+                        }
+
+                        t[p+i] = *s;
+
+                        i++;
+                        t[p+i] = NULL;
+                }
+        }
+
+        assert(i <= q);
+
+        b_consume = mfree(b_consume);
+
+        return (int) i;
+}
+
 #if 0 /* NM_IGNORED */
-int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) {
+int strv_extend_strv_biconcat(char ***a, const char *prefix, const char* const *b, const char *suffix) {
         int r;
 
+        assert(a);
+
         STRV_FOREACH(s, b) {
                 char *v;
 
-                v = strjoin(*s, suffix);
+                v = strjoin(strempty(prefix), *s, suffix);
                 if (!v)
                         return -ENOMEM;
 
-                r = strv_push(a, v);
-                if (r < 0) {
-                        free(v);
+                r = strv_consume(a, v);
+                if (r < 0)
                         return r;
-                }
         }
 
         return 0;
@@ -327,7 +445,7 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla
 
 #if 0 /* NM_IGNORED */
 int strv_split_and_extend_full(char ***t, const char *s, const char *separators, bool filter_duplicates, ExtractFlags flags) {
-        _cleanup_strv_free_ char **l = NULL;
+        char **l;
         int r;
 
         assert(t);
@@ -337,7 +455,7 @@ int strv_split_and_extend_full(char ***t, const char *s, const char *separators,
         if (r < 0)
                 return r;
 
-        r = strv_extend_strv(t, l, filter_duplicates);
+        r = strv_extend_strv_consume(t, l, filter_duplicates);
         if (r < 0)
                 return r;
 
@@ -712,7 +830,21 @@ char** strv_sort(char **l) {
         typesafe_qsort(l, strv_length(l), str_compare);
         return l;
 }
-#endif /* NM_IGNORED */
+
+char** strv_sort_uniq(char **l) {
+        if (strv_isempty(l))
+                return l;
+
+        char **tail = strv_sort(l), *prev = NULL;
+        STRV_FOREACH(i, l)
+                if (streq_ptr(*i, prev))
+                        free(*i);
+                else
+                        *(tail++) = prev = *i;
+
+        *tail = NULL;
+        return l;
+}
 
 int strv_compare(char * const *a, char * const *b) {
         int r;
@@ -736,6 +868,26 @@ int strv_compare(char * const *a, char * const *b) {
         return 0;
 }
 
+bool strv_equal_ignore_order(char **a, char **b) {
+
+        /* Just like strv_equal(), but doesn't care about the order of elements or about redundant entries
+         * (i.e. it's even ok if the number of entries in the array differ, as long as the difference just
+         * consists of repititions) */
+
+        if (a == b)
+                return true;
+
+        STRV_FOREACH(i, a)
+                if (!strv_contains(b, *i))
+                        return false;
+
+        STRV_FOREACH(i, b)
+                if (!strv_contains(a, *i))
+                        return false;
+
+        return true;
+}
+
 void strv_print_full(char * const *l, const char *prefix) {
         STRV_FOREACH(s, l)
                 printf("%s%s\n", strempty(prefix), *s);
@@ -755,6 +907,7 @@ int strv_extendf(char ***l, const char *format, ...) {
 
         return strv_consume(l, x);
 }
+#endif /* NM_IGNORED */
 
 char* startswith_strv(const char *s, char * const *l) {
         STRV_FOREACH(i, l) {
@@ -920,10 +1073,17 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
         return 0;
 }
 
+#if 0 /* NM_IGNORED */
+DEFINE_PRIVATE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
+
 static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
         char **l;
         int r;
 
+        assert(h);
+        assert(key);
+        assert(value);
+
         l = hashmap_get(h, key);
         if (l) {
                 /* A list for this key already exists, let's append to it if it is not listed yet */
@@ -951,6 +1111,7 @@ static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const c
                 r = hashmap_put(h, t, l2);
                 if (r < 0)
                         return r;
+
                 TAKE_PTR(t);
                 TAKE_PTR(l2);
         }
@@ -961,6 +1122,10 @@ static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const c
 int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS) {
         int r;
 
+        assert(h);
+        assert(key);
+        assert(value);
+
         r = _hashmap_ensure_allocated(h, &string_strv_hash_ops  HASHMAP_DEBUG_PASS_ARGS);
         if (r < 0)
                 return r;
@@ -971,6 +1136,10 @@ int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value  HA
 int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS) {
         int r;
 
+        assert(h);
+        assert(key);
+        assert(value);
+
         r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops  HASHMAP_DEBUG_PASS_ARGS);
         if (r < 0)
                 return r;
@@ -978,4 +1147,91 @@ int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const
         return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
 }
 
-DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
+int strv_rebreak_lines(char **l, size_t width, char ***ret) {
+        _cleanup_strv_free_ char **broken = NULL;
+        int r;
+
+        assert(ret);
+
+        /* Implements a simple UTF-8 line breaking algorithm
+         *
+         * Goes through all entries in *l, and line-breaks each line that is longer than the specified
+         * character width. Breaks at the end of words/beginning of whitespace. Lines that do not contain whitespace are not
+         * broken. Retains whitespace at beginning of lines, removes it at end of lines. */
+
+        if (width == SIZE_MAX) { /* NOP? */
+                broken = strv_copy(l);
+                if (!broken)
+                        return -ENOMEM;
+
+                *ret = TAKE_PTR(broken);
+                return 0;
+        }
+
+        STRV_FOREACH(i, l) {
+                const char *start = *i, *whitespace_begin = NULL, *whitespace_end = NULL;
+                bool in_prefix = true; /* still in the whitespace in the beginning of the line? */
+                size_t w = 0;
+
+                for (const char *p = start; *p != 0; p = utf8_next_char(p)) {
+                        if (strchr(NEWLINE, *p)) {
+                                in_prefix = true;
+                                whitespace_begin = whitespace_end = NULL;
+                                w = 0;
+                        } else if (strchr(WHITESPACE, *p)) {
+                                if (!in_prefix && (!whitespace_begin || whitespace_end)) {
+                                        whitespace_begin = p;
+                                        whitespace_end = NULL;
+                                }
+                        } else {
+                                if (whitespace_begin && !whitespace_end)
+                                        whitespace_end = p;
+
+                                in_prefix = false;
+                        }
+
+                        int cw = utf8_char_console_width(p);
+                        if (cw < 0) {
+                                log_debug_errno(cw, "Comment to line break contains invalid UTF-8, ignoring.");
+                                cw = 1;
+                        }
+
+                        w += cw;
+
+                        if (w > width && whitespace_begin && whitespace_end) {
+                                _cleanup_free_ char *truncated = NULL;
+
+                                truncated = strndup(start, whitespace_begin - start);
+                                if (!truncated)
+                                        return -ENOMEM;
+
+                                r = strv_consume(&broken, TAKE_PTR(truncated));
+                                if (r < 0)
+                                        return r;
+
+                                p = start = whitespace_end;
+                                whitespace_begin = whitespace_end = NULL;
+                                w = cw;
+                        }
+                }
+
+                /* Process rest of the line */
+                assert(start);
+                if (in_prefix) /* Never seen anything non-whitespace? Generate empty line! */
+                        r = strv_extend(&broken, "");
+                else if (whitespace_begin && !whitespace_end) { /* Ends in whitespace? Chop it off! */
+                        _cleanup_free_ char *truncated = strndup(start, whitespace_begin - start);
+                        if (!truncated)
+                                return -ENOMEM;
+
+                        r = strv_consume(&broken, TAKE_PTR(truncated));
+                } else /* Otherwise use line as is */
+                        r = strv_extend(&broken, start);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = TAKE_PTR(broken);
+        return 0;
+}
+#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h
index 91337b92..86ba06f8 100644
--- a/src/libnm-systemd-shared/src/basic/strv.h
+++ b/src/libnm-systemd-shared/src/basic/strv.h
@@ -17,6 +17,7 @@ char* strv_find(char * const *l, const char *name) _pure_;
 char* strv_find_case(char * const *l, const char *name) _pure_;
 char* strv_find_prefix(char * const *l, const char *name) _pure_;
 char* strv_find_startswith(char * const *l, const char *name) _pure_;
+char* strv_find_closest(char * const *l, const char *name) _pure_;
 /* Given two vectors, the first a list of keys and the second a list of key-value pairs, returns the value
  * of the first key from the first vector that is found in the second vector. */
 char* strv_find_first_field(char * const *needles, char * const *haystack) _pure_;
@@ -43,7 +44,13 @@ int strv_copy_unless_empty(char * const *l, char ***ret);
 size_t strv_length(char * const *l) _pure_;
 
 int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
-int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix);
+int strv_extend_strv_consume(char ***a, char **b, bool filter_duplicates);
+
+int strv_extend_strv_biconcat(char ***a, const char *prefix, const char* const *b, const char *suffix);
+static inline int strv_extend_strv_concat(char ***a, const char* const *b, const char *suffix) {
+        return strv_extend_strv_biconcat(a, NULL, b, suffix);
+}
+
 int strv_prepend(char ***l, const char *value);
 
 /* _with_size() are lower-level functions where the size can be provided externally,
@@ -89,6 +96,8 @@ static inline bool strv_equal(char * const *a, char * const *b) {
         return strv_compare(a, b) == 0;
 }
 
+bool strv_equal_ignore_order(char **a, char **b);
+
 char** strv_new_internal(const char *x, ...) _sentinel_;
 char** strv_new_ap(const char *x, va_list ap);
 #define strv_new(...) strv_new_internal(__VA_ARGS__, NULL)
@@ -150,7 +159,7 @@ bool strv_overlap(char * const *a, char * const *b) _pure_;
         _STRV_FOREACH_BACKWARDS(s, l, UNIQ_T(h, UNIQ), UNIQ_T(i, UNIQ))
 
 #define _STRV_FOREACH_PAIR(x, y, l, i)                          \
-        for (typeof(*l) *x, *y, *i = (l);                       \
+        for (typeof(*(l)) *x, *y, *i = (l);                     \
              i && *(x = i) && *(y = i + 1);                     \
              i += 2)
 
@@ -158,6 +167,7 @@ bool strv_overlap(char * const *a, char * const *b) _pure_;
         _STRV_FOREACH_PAIR(x, y, l, UNIQ_T(i, UNIQ))
 
 char** strv_sort(char **l);
+char** strv_sort_uniq(char **l);
 void strv_print_full(char * const *l, const char *prefix);
 static inline void strv_print(char * const *l) {
         strv_print_full(l, NULL);
@@ -231,7 +241,6 @@ bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *
 static inline bool strv_fnmatch(char* const* patterns, const char *s) {
         return strv_fnmatch_full(patterns, s, 0, NULL);
 }
-
 static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) {
         assert(s);
         return strv_isempty(patterns) ||
@@ -249,8 +258,9 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
 #define strv_free_and_replace(a, b)             \
         free_and_replace_full(a, b, strv_free)
 
-extern const struct hash_ops string_strv_hash_ops;
 int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS);
 int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS);
 #define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v  HASHMAP_DEBUG_SRC_ARGS)
 #define string_strv_ordered_hashmap_put(h, k, v) _string_strv_ordered_hashmap_put(h, k, v  HASHMAP_DEBUG_SRC_ARGS)
+
+int strv_rebreak_lines(char **l, size_t width, char ***ret);
diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c
index 47f5bb5a..594d5315 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.c
+++ b/src/libnm-systemd-shared/src/basic/time-util.c
@@ -85,7 +85,7 @@ triple_timestamp* triple_timestamp_now(triple_timestamp *ts) {
         return ts;
 }
 
-static usec_t map_clock_usec_internal(usec_t from, usec_t from_base, usec_t to_base) {
+usec_t map_clock_usec_raw(usec_t from, usec_t from_base, usec_t to_base) {
 
         /* Maps the time 'from' between two clocks, based on a common reference point where the first clock
          * is at 'from_base' and the second clock at 'to_base'. Basically calculates:
@@ -123,7 +123,7 @@ usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock) {
         if (from == USEC_INFINITY)
                 return from;
 
-        return map_clock_usec_internal(from, now(from_clock), now(to_clock));
+        return map_clock_usec_raw(from, now(from_clock), now(to_clock));
 }
 
 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
@@ -152,8 +152,8 @@ triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u)
         nowr = now(CLOCK_REALTIME);
 
         ts->realtime = u;
-        ts->monotonic = map_clock_usec_internal(u, nowr, now(CLOCK_MONOTONIC));
-        ts->boottime = map_clock_usec_internal(u, nowr, now(CLOCK_BOOTTIME));
+        ts->monotonic = map_clock_usec_raw(u, nowr, now(CLOCK_MONOTONIC));
+        ts->boottime = map_clock_usec_raw(u, nowr, now(CLOCK_BOOTTIME));
 
         return ts;
 }
@@ -171,8 +171,8 @@ triple_timestamp* triple_timestamp_from_boottime(triple_timestamp *ts, usec_t u)
         nowb = now(CLOCK_BOOTTIME);
 
         ts->boottime = u;
-        ts->monotonic = map_clock_usec_internal(u, nowb, now(CLOCK_MONOTONIC));
-        ts->realtime = map_clock_usec_internal(u, nowb, now(CLOCK_REALTIME));
+        ts->monotonic = map_clock_usec_raw(u, nowb, now(CLOCK_MONOTONIC));
+        ts->realtime = map_clock_usec_raw(u, nowb, now(CLOCK_REALTIME));
 
         return ts;
 }
@@ -201,8 +201,8 @@ dual_timestamp* dual_timestamp_from_boottime(dual_timestamp *ts, usec_t u) {
         }
 
         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));
+        ts->monotonic = map_clock_usec_raw(u, nowm, now(CLOCK_MONOTONIC));
+        ts->realtime = map_clock_usec_raw(u, nowm, now(CLOCK_REALTIME));
         return ts;
 }
 
@@ -315,7 +315,7 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) {
         return tv;
 }
 
-char *format_timestamp_style(
+char* format_timestamp_style(
                 char *buf,
                 size_t l,
                 usec_t t,
@@ -335,7 +335,6 @@ char *format_timestamp_style(
 
         struct tm tm;
         bool utc, us;
-        time_t sec;
         size_t n;
 
         assert(buf);
@@ -378,9 +377,7 @@ char *format_timestamp_style(
                 return strcpy(buf, xxx[style]);
         }
 
-        sec = (time_t) (t / USEC_PER_SEC); /* Round down */
-
-        if (!localtime_or_gmtime_r(&sec, &tm, utc))
+        if (localtime_or_gmtime_usec(t, utc, &tm) < 0)
                 return NULL;
 
         /* Start with the week day */
@@ -563,7 +560,7 @@ char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
 
         /* The result of this function can be parsed with parse_sec */
 
-        for (size_t i = 0; i < ELEMENTSOF(table); i++) {
+        FOREACH_ELEMENT(i, table) {
                 int k = 0;
                 size_t n;
                 bool done = false;
@@ -575,20 +572,20 @@ char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
                 if (t < accuracy && something)
                         break;
 
-                if (t < table[i].usec)
+                if (t < i->usec)
                         continue;
 
                 if (l <= 1)
                         break;
 
-                a = t / table[i].usec;
-                b = t % table[i].usec;
+                a = t / i->usec;
+                b = t % i->usec;
 
                 /* Let's see if we should shows this in dot notation */
                 if (t < USEC_PER_MINUTE && b > 0) {
                         signed char j = 0;
 
-                        for (usec_t cc = table[i].usec; cc > 1; cc /= 10)
+                        for (usec_t cc = i->usec; cc > 1; cc /= 10)
                                 j++;
 
                         for (usec_t cc = accuracy; cc > 1; cc /= 10) {
@@ -603,7 +600,7 @@ char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
                                              a,
                                              j,
                                              b,
-                                             table[i].suffix);
+                                             i->suffix);
 
                                 t = 0;
                                 done = true;
@@ -616,7 +613,7 @@ char* format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
                                      "%s"USEC_FMT"%s",
                                      p > buf ? " " : "",
                                      a,
-                                     table[i].suffix);
+                                     i->suffix);
 
                         t = b;
                 }
@@ -670,7 +667,6 @@ static int parse_timestamp_impl(
         unsigned fractional = 0;
         const char *k;
         struct tm tm, copy;
-        time_t sec;
 
         /* Allowed syntaxes:
          *
@@ -783,10 +779,9 @@ static int parse_timestamp_impl(
                 }
         }
 
-        sec = (time_t) (usec / USEC_PER_SEC);
-
-        if (!localtime_or_gmtime_r(&sec, &tm, utc))
-                return -EINVAL;
+        r = localtime_or_gmtime_usec(usec, utc, &tm);
+        if (r < 0)
+                return r;
 
         tm.tm_isdst = isdst;
 
@@ -805,12 +800,12 @@ static int parse_timestamp_impl(
                 goto from_tm;
         }
 
-        for (size_t i = 0; i < ELEMENTSOF(day_nr); i++) {
-                k = startswith_no_case(t, day_nr[i].name);
+        FOREACH_ELEMENT(day, day_nr) {
+                k = startswith_no_case(t, day->name);
                 if (!k || *k != ' ')
                         continue;
 
-                weekday = day_nr[i].nr;
+                weekday = day->nr;
                 t = k + 1;
                 break;
         }
@@ -944,11 +939,11 @@ from_tm:
         } else
                 minus = gmtoff * USEC_PER_SEC;
 
-        sec = mktime_or_timegm(&tm, utc);
-        if (sec < 0)
-                return -EINVAL;
+        r = mktime_or_timegm_usec(&tm, utc, &usec);
+        if (r < 0)
+                return r;
 
-        usec = usec_add(sec * USEC_PER_SEC, fractional);
+        usec = usec_add(usec, fractional);
 
 finish:
         usec = usec_add(usec, plus);
@@ -1004,8 +999,12 @@ int parse_timestamp(const char *t, usec_t *ret) {
         assert(t);
 
         t_len = strlen(t);
-        if (t_len > 2 && t[t_len - 1] == 'Z' && t[t_len - 2] != ' ')  /* RFC3339-style welded UTC: "1985-04-12T23:20:50.52Z" */
-                return parse_timestamp_impl(t, t_len - 1, /* utc = */ true, /* isdst = */ -1, /* gmtoff = */ 0, ret);
+        if (t_len > 2 && t[t_len - 1] == 'Z') {
+                /* Try to parse as RFC3339-style welded UTC: "1985-04-12T23:20:50.52Z" */
+                r = parse_timestamp_impl(t, t_len - 1, /* utc = */ true, /* isdst = */ -1, /* gmtoff = */ 0, ret);
+                if (r >= 0)
+                        return r;
+        }
 
         if (t_len > 7 && IN_SET(t[t_len - 6], '+', '-') && t[t_len - 7] != ' ') {  /* RFC3339-style welded offset: "1990-12-31T15:59:60-08:00" */
                 k = strptime(&t[t_len - 6], "%z", &tm);
@@ -1049,6 +1048,14 @@ int parse_timestamp(const char *t, usec_t *ret) {
         if (shared == MAP_FAILED)
                 return negative_errno();
 
+        /* The input string may be in argv. Let's copy it. */
+        _cleanup_free_ char *t_copy = strdup(t);
+        if (!t_copy)
+                return -ENOMEM;
+
+        t = t_copy;
+        assert_se(tz = endswith(t_copy, tz));
+
         r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL|FORK_WAIT, NULL);
         if (r < 0) {
                 (void) munmap(shared, sizeof *shared);
@@ -1120,12 +1127,12 @@ static const char* extract_multiplier(const char *p, usec_t *ret) {
         assert(p);
         assert(ret);
 
-        for (size_t i = 0; i < ELEMENTSOF(table); i++) {
+        FOREACH_ELEMENT(i, table) {
                 char *e;
 
-                e = startswith(p, table[i].suffix);
+                e = startswith(p, i->suffix);
                 if (e) {
-                        *ret = table[i].usec;
+                        *ret = i->usec;
                         return e;
                 }
         }
@@ -1135,19 +1142,14 @@ static const char* extract_multiplier(const char *p, usec_t *ret) {
 
 int parse_time(const char *t, usec_t *ret, usec_t default_unit) {
         const char *p, *s;
-        usec_t usec = 0;
-        bool something = false;
 
         assert(t);
         assert(default_unit > 0);
 
-        p = t;
-
-        p += strspn(p, WHITESPACE);
+        p = skip_leading_chars(t, /* bad = */ NULL);
         s = startswith(p, "infinity");
         if (s) {
-                s += strspn(s, WHITESPACE);
-                if (*s != 0)
+                if (!in_charset(s, WHITESPACE))
                         return -EINVAL;
 
                 if (ret)
@@ -1155,13 +1157,14 @@ int parse_time(const char *t, usec_t *ret, usec_t default_unit) {
                 return 0;
         }
 
-        for (;;) {
+        usec_t usec = 0;
+
+        for (bool something = false;;) {
                 usec_t multiplier = default_unit, k;
                 long long l;
                 char *e;
 
-                p += strspn(p, WHITESPACE);
-
+                p = skip_leading_chars(p, /* bad = */ NULL);
                 if (*p == 0) {
                         if (!something)
                                 return -EINVAL;
@@ -1298,17 +1301,16 @@ static const char* extract_nsec_multiplier(const char *p, nsec_t *ret) {
                 { "ns",      1ULL            },
                 { "",        1ULL            }, /* default is nsec */
         };
-        size_t i;
 
         assert(p);
         assert(ret);
 
-        for (i = 0; i < ELEMENTSOF(table); i++) {
+        FOREACH_ELEMENT(i, table) {
                 char *e;
 
-                e = startswith(p, table[i].suffix);
+                e = startswith(p, i->suffix);
                 if (e) {
-                        *ret = table[i].nsec;
+                        *ret = i->nsec;
                         return e;
                 }
         }
@@ -1524,8 +1526,7 @@ int get_timezones(char ***ret) {
         if (r < 0)
                 return r;
 
-        strv_sort(zones);
-        strv_uniq(zones);
+        strv_sort_uniq(zones);
 
         *ret = TAKE_PTR(zones);
         return 0;
@@ -1613,51 +1614,74 @@ bool clock_supported(clockid_t clock) {
 #if 0 /* NM_IGNORED */
 int get_timezone(char **ret) {
         _cleanup_free_ char *t = NULL;
-        const char *e;
-        char *z;
         int r;
 
         assert(ret);
 
         r = readlink_malloc("/etc/localtime", &t);
-        if (r == -ENOENT) {
+        if (r == -ENOENT)
                 /* If the symlink does not exist, assume "UTC", like glibc does */
-                z = strdup("UTC");
-                if (!z)
-                        return -ENOMEM;
-
-                *ret = z;
-                return 0;
-        }
+                return strdup_to(ret, "UTC");
         if (r < 0)
-                return r; /* returns EINVAL if not a symlink */
+                return r; /* Return EINVAL if not a symlink */
 
-        e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
+        const char *e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
         if (!e)
                 return -EINVAL;
-
         if (!timezone_is_valid(e, LOG_DEBUG))
                 return -EINVAL;
 
-        z = strdup(e);
-        if (!z)
-                return -ENOMEM;
-
-        *ret = z;
-        return 0;
+        return strdup_to(ret, e);
 }
 
-time_t mktime_or_timegm(struct tm *tm, bool utc) {
+int mktime_or_timegm_usec(
+                struct tm *tm, /* input + normalized output */
+                bool utc,
+                usec_t *ret) {
+
+        time_t t;
+
         assert(tm);
 
-        return utc ? timegm(tm) : mktime(tm);
+        if (tm->tm_year < 69) /* early check for negative (i.e. before 1970) time_t (Note that in some timezones the epoch is in the year 1969!)*/
+                return -ERANGE;
+        if ((usec_t) tm->tm_year > CONST_MIN(USEC_INFINITY / USEC_PER_YEAR, (usec_t) TIME_T_MAX / (365U * 24U * 60U * 60U)) - 1900) /* early check for possible overrun of usec_t or time_t */
+                return -ERANGE;
+
+        /* timegm()/mktime() is a bit weird to use, since it returns -1 in two cases: on error as well as a
+         * valid time indicating one second before the UNIX epoch. Let's treat both cases the same here, and
+         * return -ERANGE for anything negative, since usec_t is unsigned, and we can thus not express
+         * negative times anyway. */
+
+        t = utc ? timegm(tm) : mktime(tm);
+        if (t < 0) /* Refuse negative times and errors */
+                return -ERANGE;
+        if ((usec_t) t >= USEC_INFINITY / USEC_PER_SEC) /* Never return USEC_INFINITY by accident (or overflow) */
+                return -ERANGE;
+
+        if (ret)
+                *ret = (usec_t) t * USEC_PER_SEC;
+        return 0;
 }
 
-struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
-        assert(t);
-        assert(tm);
+int localtime_or_gmtime_usec(
+                usec_t t,
+                bool utc,
+                struct tm *ret) {
 
-        return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
+        t /= USEC_PER_SEC; /* Round down */
+        if (t > (usec_t) TIME_T_MAX)
+                return -ERANGE;
+        time_t sec = (time_t) t;
+
+        struct tm buf = {};
+        if (!(utc ? gmtime_r(&sec, &buf) : localtime_r(&sec, &buf)))
+                return -EINVAL;
+
+        if (ret)
+                *ret = buf;
+
+        return 0;
 }
 
 static uint32_t sysconf_clock_ticks_cached(void) {
diff --git a/src/libnm-systemd-shared/src/basic/time-util.h b/src/libnm-systemd-shared/src/basic/time-util.h
index 29373477..14d660ee 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.h
+++ b/src/libnm-systemd-shared/src/basic/time-util.h
@@ -71,12 +71,16 @@ typedef enum TimestampStyle {
 
 #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
 
-#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) {})
-#define TRIPLE_TIMESTAMP_NULL ((struct triple_timestamp) {})
+#define DUAL_TIMESTAMP_NULL ((dual_timestamp) {})
+#define DUAL_TIMESTAMP_INFINITY ((dual_timestamp) { USEC_INFINITY, USEC_INFINITY })
+#define TRIPLE_TIMESTAMP_NULL ((triple_timestamp) {})
+
+#define TIMESPEC_OMIT ((const struct timespec) { .tv_nsec = UTIME_OMIT })
 
 usec_t now(clockid_t clock);
 nsec_t now_nsec(clockid_t clock);
 
+usec_t map_clock_usec_raw(usec_t from, usec_t from_base, usec_t to_base);
 usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock);
 
 dual_timestamp* dual_timestamp_now(dual_timestamp *ts);
@@ -173,8 +177,8 @@ usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to);
 
 int get_timezone(char **ret);
 
-time_t mktime_or_timegm(struct tm *tm, bool utc);
-struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
+int mktime_or_timegm_usec(struct tm *tm, bool utc, usec_t *ret);
+int localtime_or_gmtime_usec(usec_t t, bool utc, struct tm *ret);
 
 uint32_t usec_to_jiffies(usec_t usec);
 usec_t jiffies_to_usec(uint32_t jiffies);
@@ -184,11 +188,7 @@ bool in_utc_timezone(void);
 static inline usec_t usec_add(usec_t a, usec_t b) {
         /* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output,
          * and doesn't overflow. */
-
-        if (a > USEC_INFINITY - b) /* overflow check */
-                return USEC_INFINITY;
-
-        return a + b;
+        return saturate_add(a, b, USEC_INFINITY);
 }
 
 static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) {
diff --git a/src/libnm-systemd-shared/src/basic/tmpfile-util.c b/src/libnm-systemd-shared/src/basic/tmpfile-util.c
index a66ee82d..3d1b8d04 100644
--- a/src/libnm-systemd-shared/src/basic/tmpfile-util.c
+++ b/src/libnm-systemd-shared/src/basic/tmpfile-util.c
@@ -122,6 +122,17 @@ int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
 }
 #endif /* NM_IGNORED */
 
+void unlink_tempfilep(char (*p)[]) {
+        assert(p);
+
+        /* If the file is created with mkstemp(), it will (almost always) change the suffix.
+         * Treat this as a sign that the file was successfully created. We ignore both the rare case
+         * where the original suffix is used and unlink failures. */
+
+        if (!endswith(*p, ".XXXXXX"))
+                (void) unlink(*p);
+}
+
 static int tempfn_build(const char *p, const char *pre, const char *post, bool child, char **ret) {
         _cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL, *result = NULL;
         size_t len_pre, len_post, len_add;
@@ -335,28 +346,7 @@ int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE
         return 0;
 }
 
-static int link_fd(int fd, int newdirfd, const char *newpath) {
-        int r;
-
-        assert(fd >= 0);
-        assert(newdirfd >= 0 || newdirfd == AT_FDCWD);
-        assert(newpath);
-
-        /* Try symlinking via /proc/fd/ first. */
-        r = RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), newdirfd, newpath, AT_SYMLINK_FOLLOW));
-        if (r != -ENOENT)
-                return r;
-
-        /* Fall back to symlinking via AT_EMPTY_PATH as fallback (this requires CAP_DAC_READ_SEARCH and a
-         * more recent kernel, but does not require /proc/ mounted) */
-        if (proc_mounted() != 0)
-                return r;
-
-        return RET_NERRNO(linkat(fd, "", newdirfd, newpath, AT_EMPTY_PATH));
-}
-
 int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, LinkTmpfileFlags flags) {
-        _cleanup_free_ char *tmp = NULL;
         int r;
 
         assert(fd >= 0);
@@ -375,33 +365,14 @@ int link_tmpfile_at(int fd, int dir_fd, const char *path, const char *target, Li
                         r = RET_NERRNO(renameat(dir_fd, path, dir_fd, target));
                 else
                         r = rename_noreplace(dir_fd, path, dir_fd, target);
-                if (r < 0)
-                        return r;
         } else {
-
-                r = link_fd(fd, dir_fd, target);
-                if (r != -EEXIST || !FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
-                        return r;
-
-                /* So the target already exists and we were asked to replace it. That sucks a bit, since the kernel's
-                 * linkat() logic does not allow that. We work-around this by linking the file to a random name
-                 * first, and then renaming that to the final name. This reintroduces the race O_TMPFILE kinda is
-                 * trying to fix, but at least the vulnerability window (i.e. where the file is linked into the file
-                 * system under a temporary name) is very short. */
-
-                r = tempfn_random(target, NULL, &tmp);
-                if (r < 0)
-                        return r;
-
-                if (link_fd(fd, dir_fd, tmp) < 0)
-                        return -EEXIST; /* propagate original error */
-
-                r = RET_NERRNO(renameat(dir_fd, tmp, dir_fd, target));
-                if (r < 0) {
-                        (void) unlinkat(dir_fd, tmp, 0);
-                        return r;
-                }
+                if (FLAGS_SET(flags, LINK_TMPFILE_REPLACE))
+                        r = linkat_replace(fd, /* oldpath= */ NULL, dir_fd, target);
+                else
+                        r = link_fd(fd, dir_fd, target);
         }
+        if (r < 0)
+                return r;
 
         if (FLAGS_SET(flags, LINK_TMPFILE_SYNC)) {
                 r = fsync_full(fd);
diff --git a/src/libnm-systemd-shared/src/basic/tmpfile-util.h b/src/libnm-systemd-shared/src/basic/tmpfile-util.h
index 8c917c06..408f80e1 100644
--- a/src/libnm-systemd-shared/src/basic/tmpfile-util.h
+++ b/src/libnm-systemd-shared/src/basic/tmpfile-util.h
@@ -18,6 +18,8 @@ static inline int fopen_temporary_child(const char *path, FILE **ret_file, char
 int mkostemp_safe(char *pattern);
 int fmkostemp_safe(char *pattern, const char *mode, FILE**_f);
 
+void unlink_tempfilep(char (*p)[]);
+
 int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
 int tempfn_random(const char *p, const char *extra, char **ret);
 int tempfn_random_child(const char *p, const char *extra, char **ret);
diff --git a/src/libnm-systemd-shared/src/basic/user-util.h b/src/libnm-systemd-shared/src/basic/user-util.h
index 9d07ef31..653f1425 100644
--- a/src/libnm-systemd-shared/src/basic/user-util.h
+++ b/src/libnm-systemd-shared/src/basic/user-util.h
@@ -12,6 +12,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "string-util.h"
+
 /* Users managed by systemd-homed. See https://systemd.io/UIDS-GIDS for details how this range fits into the rest of the world */
 #define HOME_UID_MIN ((uid_t) 60001)
 #define HOME_UID_MAX ((uid_t) 60513)
@@ -36,10 +38,20 @@ static inline int parse_gid(const char *s, gid_t *ret_gid) {
 char* getlogname_malloc(void);
 char* getusername_malloc(void);
 
+const char* default_root_shell_at(int rfd);
+const char* default_root_shell(const char *root);
+
+bool is_nologin_shell(const char *shell);
+
+static inline bool shell_is_placeholder(const char *shell) {
+        return isempty(shell) || is_nologin_shell(shell);
+}
+
 typedef enum UserCredsFlags {
-        USER_CREDS_PREFER_NSS    = 1 << 0,  /* if set, only synthesize user records if database lacks them. Normally we bypass the userdb entirely for the records we can synthesize */
-        USER_CREDS_ALLOW_MISSING = 1 << 1,  /* if a numeric UID string is resolved, be OK if there's no record for it */
-        USER_CREDS_CLEAN         = 1 << 2,  /* try to clean up shell and home fields with invalid data */
+        USER_CREDS_PREFER_NSS           = 1 << 0,  /* if set, only synthesize user records if database lacks them. Normally we bypass the userdb entirely for the records we can synthesize */
+        USER_CREDS_ALLOW_MISSING        = 1 << 1,  /* if a numeric UID string is resolved, be OK if there's no record for it */
+        USER_CREDS_CLEAN                = 1 << 2,  /* try to clean up shell and home fields with invalid data */
+        USER_CREDS_SUPPRESS_PLACEHOLDER = 1 << 3,  /* suppress home and/or shell fields if value is placeholder (root/empty/nologin) */
 } UserCredsFlags;
 
 int get_user_creds(const char **username, uid_t *ret_uid, gid_t *ret_gid, const char **ret_home, const char **ret_shell, UserCredsFlags flags);
@@ -52,7 +64,7 @@ int in_gid(gid_t gid);
 int in_group(const char *name);
 
 int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t size2, gid_t **result);
-int getgroups_alloc(gid_t** gids);
+int getgroups_alloc(gid_t **ret);
 
 int get_home_dir(char **ret);
 int get_shell(char **ret);
@@ -108,15 +120,7 @@ bool valid_user_group_name(const char *u, ValidUserFlags flags);
 bool valid_gecos(const char *d);
 char* mangle_gecos(const char *d);
 bool valid_home(const char *p);
-
-static inline bool valid_shell(const char *p) {
-        /* We have the same requirements, so just piggy-back on the home check.
-         *
-         * Let's ignore /etc/shells because this is only applicable to real and
-         * not system users. It is also incompatible with the idea of empty /etc.
-         */
-        return valid_home(p);
-}
+bool valid_shell(const char *p);
 
 int maybe_setgroups(size_t size, const gid_t *list);
 
@@ -133,10 +137,6 @@ int fgetsgent_sane(FILE *stream, struct sgrp **sg);
 int putsgent_sane(const struct sgrp *sg, FILE *stream);
 #endif
 
-bool is_nologin_shell(const char *shell);
-const char* default_root_shell_at(int rfd);
-const char* default_root_shell(const char *root);
-
 int is_this_me(const char *username);
 
 const char* get_home_root(void);
diff --git a/src/libnm-systemd-shared/src/basic/utf8.c b/src/libnm-systemd-shared/src/basic/utf8.c
index cf24e82f..33fdd96e 100644
--- a/src/libnm-systemd-shared/src/basic/utf8.c
+++ b/src/libnm-systemd-shared/src/basic/utf8.c
@@ -1,26 +1,10 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/* SPDX-License-Identifier: LGPL-2.0-or-later */
 
-/* Parts of this file are based on the GLIB utf8 validation functions. The
- * original license text follows. */
-
-/* gutf8.c - Operations on UTF-8 strings.
+/* Parts of this file are based on the GLIB utf8 validation functions. The original copyright follows.
  *
+ * gutf8.c - Operations on UTF-8 strings.
  * Copyright (C) 1999 Tom Tromey
  * Copyright (C) 2000 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include "nm-sd-adapt-shared.h"
@@ -148,30 +132,30 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newlin
         return true;
 }
 
-char *utf8_is_valid_n(const char *str, size_t len_bytes) {
+char* utf8_is_valid_n(const char *str, size_t len_bytes) {
         /* Check if the string is composed of valid utf8 characters. If length len_bytes is given, stop after
          * len_bytes. Otherwise, stop at NUL. */
 
         assert(str);
 
-        for (const char *p = str; len_bytes != SIZE_MAX ? (size_t) (p - str) < len_bytes : *p != '\0'; ) {
+        for (size_t i = 0; len_bytes != SIZE_MAX ? i < len_bytes : str[i] != '\0'; ) {
                 int len;
 
-                if (_unlikely_(*p == '\0') && len_bytes != SIZE_MAX)
+                if (_unlikely_(str[i] == '\0'))
                         return NULL; /* embedded NUL */
 
-                len = utf8_encoded_valid_unichar(p,
-                                                 len_bytes != SIZE_MAX ? len_bytes - (p - str) : SIZE_MAX);
+                len = utf8_encoded_valid_unichar(str + i,
+                                                 len_bytes != SIZE_MAX ? len_bytes - i : SIZE_MAX);
                 if (_unlikely_(len < 0))
                         return NULL; /* invalid character */
 
-                p += len;
+                i += len;
         }
 
         return (char*) str;
 }
 
-char *utf8_escape_invalid(const char *str) {
+char* utf8_escape_invalid(const char *str) {
         char *p, *s;
 
         assert(str);
@@ -198,7 +182,7 @@ char *utf8_escape_invalid(const char *str) {
 }
 
 #if 0 /* NM_IGNORED */
-static int utf8_char_console_width(const char *str) {
+int utf8_char_console_width(const char *str) {
         char32_t c;
         int r;
 
@@ -206,12 +190,15 @@ static int utf8_char_console_width(const char *str) {
         if (r < 0)
                 return r;
 
+        if (c == '\t')
+                return 8; /* Assume a tab width of 8 */
+
         /* TODO: we should detect combining characters */
 
         return unichar_iswide(c) ? 2 : 1;
 }
 
-char *utf8_escape_non_printable_full(const char *str, size_t console_width, bool force_ellipsis) {
+char* utf8_escape_non_printable_full(const char *str, size_t console_width, bool force_ellipsis) {
         char *p, *s, *prev_s;
         size_t n = 0; /* estimated print width */
 
@@ -288,33 +275,18 @@ char *utf8_escape_non_printable_full(const char *str, size_t console_width, bool
 }
 #endif /* NM_IGNORED */
 
-char *ascii_is_valid(const char *str) {
-        /* Check whether the string consists of valid ASCII bytes,
-         * i.e values between 0 and 127, inclusive. */
-
-        assert(str);
-
-        for (const char *p = str; *p; p++)
-                if ((unsigned char) *p >= 128)
-                        return NULL;
-
-        return (char*) str;
-}
-
-#if 0 /* NM_IGNORED */
-char *ascii_is_valid_n(const char *str, size_t len) {
-        /* Very similar to ascii_is_valid(), but checks exactly len
-         * bytes and rejects any NULs in that range. */
+char* ascii_is_valid_n(const char *str, size_t len) {
+        /* Check whether the string consists of valid ASCII bytes, i.e values between 1 and 127, inclusive.
+         * Stops at len, or NUL byte if len is SIZE_MAX. */
 
         assert(str);
 
-        for (size_t i = 0; i < len; i++)
-                if ((unsigned char) str[i] >= 128 || str[i] == 0)
+        for (size_t i = 0; len != SIZE_MAX ? i < len : str[i] != '\0'; i++)
+                if ((unsigned char) str[i] >= 128 || str[i] == '\0')
                         return NULL;
 
         return (char*) str;
 }
-#endif /* NM_IGNORED */
 
 int utf8_to_ascii(const char *str, char replacement_char, char **ret) {
         /* Convert to a string that has only ASCII chars, replacing anything that is not ASCII
@@ -392,7 +364,7 @@ size_t utf8_encode_unichar(char *out_utf8, char32_t g) {
 }
 
 #if 0 /* NM_IGNORED */
-char *utf16_to_utf8(const char16_t *s, size_t length /* bytes! */) {
+char* utf16_to_utf8(const char16_t *s, size_t length /* bytes! */) {
         const uint8_t *f;
         char *r, *t;
 
@@ -536,6 +508,10 @@ size_t char16_strlen(const char16_t *s) {
 
         return n;
 }
+
+size_t char16_strsize(const char16_t *s) {
+        return s ? (char16_strlen(s) + 1) * sizeof(*s) : 0;
+}
 #endif /* NM_IGNORED */
 
 /* expected size used to encode one unicode char */
@@ -619,11 +595,14 @@ size_t utf8_n_codepoints(const char *str) {
 }
 
 size_t utf8_console_width(const char *str) {
-        size_t n = 0;
+
+        if (isempty(str))
+                return 0;
 
         /* Returns the approximate width a string will take on screen when printed on a character cell
          * terminal/console. */
 
+        size_t n = 0;
         while (*str) {
                 int w;
 
diff --git a/src/libnm-systemd-shared/src/basic/utf8.h b/src/libnm-systemd-shared/src/basic/utf8.h
index 962312c5..221bc46a 100644
--- a/src/libnm-systemd-shared/src/basic/utf8.h
+++ b/src/libnm-systemd-shared/src/basic/utf8.h
@@ -14,31 +14,35 @@
 
 bool unichar_is_valid(char32_t c);
 
-char *utf8_is_valid_n(const char *str, size_t len_bytes) _pure_;
-static inline char *utf8_is_valid(const char *s) {
-        return utf8_is_valid_n(s, SIZE_MAX);
+char* utf8_is_valid_n(const char *str, size_t len_bytes) _pure_;
+static inline char* utf8_is_valid(const char *str) {
+        return utf8_is_valid_n(str, SIZE_MAX);
+}
+
+char* ascii_is_valid_n(const char *str, size_t len) _pure_;
+static inline char* ascii_is_valid(const char *str) {
+        return ascii_is_valid_n(str, SIZE_MAX);
 }
-char *ascii_is_valid(const char *s) _pure_;
-char *ascii_is_valid_n(const char *str, size_t len);
 
 int utf8_to_ascii(const char *str, char replacement_char, char **ret);
 
 bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) _pure_;
 #define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
 
-char *utf8_escape_invalid(const char *s);
-char *utf8_escape_non_printable_full(const char *str, size_t console_width, bool force_ellipsis);
-static inline char *utf8_escape_non_printable(const char *str) {
+char* utf8_escape_invalid(const char *s);
+char* utf8_escape_non_printable_full(const char *str, size_t console_width, bool force_ellipsis);
+static inline char* utf8_escape_non_printable(const char *str) {
         return utf8_escape_non_printable_full(str, SIZE_MAX, false);
 }
 
 size_t utf8_encode_unichar(char *out_utf8, char32_t g);
 size_t utf16_encode_unichar(char16_t *out, char32_t c);
 
-char *utf16_to_utf8(const char16_t *s, size_t length /* bytes! */);
+char* utf16_to_utf8(const char16_t *s, size_t length /* bytes! */);
 char16_t *utf8_to_utf16(const char *s, size_t length);
 
 size_t char16_strlen(const char16_t *s); /* returns the number of 16-bit words in the string (not bytes!) */
+size_t char16_strsize(const char16_t *s);
 
 int utf8_encoded_valid_unichar(const char *str, size_t length);
 int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar);
@@ -56,4 +60,5 @@ static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t t
 }
 
 size_t utf8_n_codepoints(const char *str);
+int utf8_char_console_width(const char *str);
 size_t utf8_console_width(const char *str);
diff --git a/src/libnm-systemd-shared/src/fundamental/iovec-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/iovec-util-fundamental.h
new file mode 100644
index 00000000..68d5bf4e
--- /dev/null
+++ b/src/libnm-systemd-shared/src/fundamental/iovec-util-fundamental.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#if SD_BOOT
+/* struct iovec is a POSIX userspace construct. Let's introduce it also in EFI mode, it's just so useful */
+struct iovec {
+        void *iov_base;
+        size_t iov_len;
+};
+
+static inline void free(void *p);
+#endif
+
+/* This accepts both const and non-const pointers */
+#define IOVEC_MAKE(base, len)                                           \
+        (struct iovec) {                                                \
+                .iov_base = (void*) (base),                             \
+                .iov_len = (len),                                       \
+        }
+
+static inline void iovec_done(struct iovec *iovec) {
+        /* A _cleanup_() helper that frees the iov_base in the iovec */
+        assert(iovec);
+
+        iovec->iov_base = mfree(iovec->iov_base);
+        iovec->iov_len = 0;
+}
+
+static inline bool iovec_is_set(const struct iovec *iovec) {
+        /* Checks if the iovec points to a non-empty chunk of memory */
+        return iovec && iovec->iov_len > 0 && iovec->iov_base;
+}
+
+static inline bool iovec_is_valid(const struct iovec *iovec) {
+        /* Checks if the iovec is either NULL, empty or points to a valid bit of memory */
+        return !iovec || (iovec->iov_base || iovec->iov_len == 0);
+}
diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
index 00f2a2b9..418ea55f 100644
--- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
+++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
@@ -32,6 +32,10 @@
         _Pragma("GCC diagnostic push");                                 \
         _Pragma("GCC diagnostic ignored \"-Wshadow\"")
 
+#define DISABLE_WARNING_STRINGOP_OVERREAD                               \
+        _Pragma("GCC diagnostic push");                                 \
+        _Pragma("GCC diagnostic ignored \"-Wstringop-overread\"")
+
 #define DISABLE_WARNING_INCOMPATIBLE_POINTER_TYPES                      \
         _Pragma("GCC diagnostic push");                                 \
         _Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"")
@@ -44,6 +48,32 @@
         _Pragma("GCC diagnostic push");                                 \
         _Pragma("GCC diagnostic ignored \"-Waddress\"")
 
+#define DISABLE_WARNING_STRINGOP_TRUNCATION                             \
+        _Pragma("GCC diagnostic push");                                 \
+        _Pragma("GCC diagnostic ignored \"-Wstringop-truncation\"")
+
+#if 0 /* NM_IGNORED */
+
+#if HAVE_WARNING_ZERO_LENGTH_BOUNDS
+#  define DISABLE_WARNING_ZERO_LENGTH_BOUNDS                            \
+        _Pragma("GCC diagnostic push");                                 \
+        _Pragma("GCC diagnostic ignored \"-Wzero-length-bounds\"")
+#else
+#  define DISABLE_WARNING_ZERO_LENGTH_BOUNDS                            \
+        _Pragma("GCC diagnostic push")
+#endif
+
+#if HAVE_WARNING_ZERO_AS_NULL_POINTER_CONSTANT
+#  define DISABLE_WARNING_ZERO_AS_NULL_POINTER_CONSTANT                 \
+        _Pragma("GCC diagnostic push");                                 \
+        _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"")
+#else
+#  define DISABLE_WARNING_ZERO_AS_NULL_POINTER_CONSTANT                 \
+        _Pragma("GCC diagnostic push")
+#endif
+
+#endif /* NM_IGNORED */
+
 #define REENABLE_WARNING                                                \
         _Pragma("GCC diagnostic pop")
 
@@ -87,10 +117,10 @@
 #  define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
 #endif
 
-#if __GNUC__ >= 7 || (defined(__clang__) && __clang_major__ >= 10)
-#  define _fallthrough_ __attribute__((__fallthrough__))
-#else
+#if defined(__clang__) && __clang_major__ < 10
 #  define _fallthrough_
+#else
+#  define _fallthrough_ __attribute__((__fallthrough__))
 #endif
 
 #define XSTRINGIFY(x) #x
@@ -288,6 +318,30 @@
                 MUL_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b);       \
         })
 
+#define ADD_SAFE(ret, a, b) (!__builtin_add_overflow(a, b, ret))
+#define INC_SAFE(a, b) __INC_SAFE(UNIQ, a, b)
+#define __INC_SAFE(q, a, b)                                     \
+        ({                                                      \
+                const typeof(a) UNIQ_T(A, q) = (a);             \
+                ADD_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b);       \
+        })
+
+#define SUB_SAFE(ret, a, b) (!__builtin_sub_overflow(a, b, ret))
+#define DEC_SAFE(a, b) __DEC_SAFE(UNIQ, a, b)
+#define __DEC_SAFE(q, a, b)                                     \
+        ({                                                      \
+                const typeof(a) UNIQ_T(A, q) = (a);             \
+                SUB_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b);       \
+        })
+
+#define MUL_SAFE(ret, a, b) (!__builtin_mul_overflow(a, b, ret))
+#define MUL_ASSIGN_SAFE(a, b) __MUL_ASSIGN_SAFE(UNIQ, a, b)
+#define __MUL_ASSIGN_SAFE(q, a, b)                              \
+        ({                                                      \
+                const typeof(a) UNIQ_T(A, q) = (a);             \
+                MUL_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b);       \
+        })
+
 #define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
 #define __LESS_BY(aq, a, bq, b)                         \
         ({                                              \
@@ -532,6 +586,10 @@ static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) {
                 }                                                       \
         }
 
+/* Restriction/bug (see below) was fixed in GCC 15 and clang 19. */
+#if __GNUC__ >= 15 || (defined(__clang__) && __clang_major__ >= 19)
+#define DECLARE_FLEX_ARRAY(type, name) type name[]
+#else
 /* Declare a flexible array usable in a union.
  * This is essentially a work-around for a pointless constraint in C99
  * and might go away in some future version of the standard.
@@ -543,12 +601,12 @@ static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) {
                 dummy_t __empty__ ## name;             \
                 type name[];                           \
         }
+#endif
 
 /* Declares an ELF read-only string section that does not occupy memory at runtime. */
 #define DECLARE_NOALLOC_SECTION(name, text)   \
         asm(".pushsection " name ",\"S\"\n\t" \
             ".ascii " STRINGIFY(text) "\n\t"  \
-            ".zero 1\n\t"                     \
             ".popsection\n")
 
 #ifdef SBAT_DISTRO
@@ -556,3 +614,22 @@ static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) {
 #else
         #define DECLARE_SBAT(text)
 #endif
+
+#define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member)
+#define endoffsetof_field(struct_type, member) (offsetof(struct_type, member) + sizeof_field(struct_type, member))
+#define voffsetof(v, member) offsetof(typeof(v), member)
+
+#define _FOREACH_ARRAY(i, array, num, m, end)                           \
+        for (typeof(array[0]) *i = (array), *end = ({                   \
+                                typeof(num) m = (num);                  \
+                                (i && m > 0) ? i + m : NULL;            \
+                        }); end && i < end; i++)
+
+#define FOREACH_ARRAY(i, array, num)                                    \
+        _FOREACH_ARRAY(i, array, num, UNIQ_T(m, UNIQ), UNIQ_T(end, UNIQ))
+
+#define FOREACH_ELEMENT(i, array)                                 \
+        FOREACH_ARRAY(i, array, ELEMENTSOF(array))
+
+#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p)))
+#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u)))
diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.c b/src/libnm-systemd-shared/src/fundamental/sha256-fundamental.c
index 84113aed..6682bc87 100644
--- a/src/libnm-systemd-shared/src/fundamental/sha256.c
+++ b/src/libnm-systemd-shared/src/fundamental/sha256-fundamental.c
@@ -23,15 +23,9 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdbool.h>
-#if SD_BOOT
-#  include "efi-string.h"
-#else
-#  include <string.h>
-#endif
-
 #include "macro-fundamental.h"
-#include "sha256.h"
+#include "memory-util-fundamental.h"
+#include "sha256-fundamental.h"
 #include "unaligned-fundamental.h"
 
 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.h b/src/libnm-systemd-shared/src/fundamental/sha256-fundamental.h
index dbb08e35..dbb08e35 100644
--- a/src/libnm-systemd-shared/src/fundamental/sha256.h
+++ b/src/libnm-systemd-shared/src/fundamental/sha256-fundamental.h
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.c b/src/libnm-systemd-shared/src/shared/dns-domain.c
index a07eaa33..42efd04a 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.c
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.c
@@ -401,9 +401,9 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
 #endif
 #endif /* NM_IGNORED */
 
-int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_ret) {
-        _cleanup_free_ char *ret = NULL;
-        size_t n = 0;
+int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **ret) {
+        _cleanup_free_ char *result = NULL;
+        size_t n_result = 0, n_unescaped = 0;
         const char *p;
         bool first = true;
         int r;
@@ -433,17 +433,18 @@ int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_r
 
                         break;
                 }
+                n_unescaped += r + !first; /* Count unescaped length to make max length determination below */
 
-                if (_ret) {
-                        if (!GREEDY_REALLOC(ret, n + !first + DNS_LABEL_ESCAPED_MAX))
+                if (ret) {
+                        if (!GREEDY_REALLOC(result, n_result + !first + DNS_LABEL_ESCAPED_MAX))
                                 return -ENOMEM;
 
-                        r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
+                        r = dns_label_escape(label, r, result + n_result + !first, DNS_LABEL_ESCAPED_MAX);
                         if (r < 0)
                                 return r;
 
                         if (!first)
-                                ret[n] = '.';
+                                result[n_result] = '.';
                 } else {
                         char escaped[DNS_LABEL_ESCAPED_MAX];
 
@@ -452,45 +453,51 @@ int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_r
                                 return r;
                 }
 
-                n += r + !first;
+                n_result += r + !first;
                 first = false;
         }
 
 finish:
-        if (n > DNS_HOSTNAME_MAX)
-                return -EINVAL;
+        if (n_unescaped == 0) {
+                /* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
 
-        if (_ret) {
-                if (n == 0) {
-                        /* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
-                        if (!GREEDY_REALLOC(ret, 2))
+                if (ret) {
+                        if (!GREEDY_REALLOC(result, 2)) /* Room for dot, and already pre-allocate space for the trailing NUL byte at the same time */
                                 return -ENOMEM;
 
-                        ret[n++] = '.';
-                } else {
-                        if (!GREEDY_REALLOC(ret, n + 1))
-                                return -ENOMEM;
+                        result[n_result++] = '.';
                 }
 
-                ret[n] = 0;
-                *_ret = TAKE_PTR(ret);
+                n_unescaped++;
+        }
+
+        if (n_unescaped > DNS_HOSTNAME_MAX) /* Enforce max length check on unescaped length */
+                return -EINVAL;
+
+        if (ret) {
+                /* Suffix with a NUL byte */
+                if (!GREEDY_REALLOC(result, n_result + 1))
+                        return -ENOMEM;
+
+                result[n_result] = 0;
+                *ret = TAKE_PTR(result);
         }
 
         return 0;
 }
 
 #if 0 /* NM_IGNORED */
-void dns_name_hash_func(const char *p, struct siphash *state) {
+void dns_name_hash_func(const char *name, struct siphash *state) {
         int r;
 
-        assert(p);
+        assert(name);
 
-        for (;;) {
+        for (const char *p = name;;) {
                 char label[DNS_LABEL_MAX+1];
 
                 r = dns_label_unescape(&p, label, sizeof label, 0);
                 if (r < 0)
-                        break;
+                        return string_hash_func(p, state); /* fallback for invalid DNS names */
                 if (r == 0)
                         break;
 
@@ -516,13 +523,13 @@ int dns_name_compare_func(const char *a, const char *b) {
         for (;;) {
                 char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
 
-                if (x == NULL && y == NULL)
+                if (!x && !y)
                         return 0;
 
                 r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
                 q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
                 if (r < 0 || q < 0)
-                        return CMP(r, q);
+                        return strcmp(a, b); /* if not valid DNS labels, then let's compare the whole strings as is */
 
                 r = ascii_strcasecmp_nn(la, r, lb, q);
                 if (r != 0)
@@ -760,7 +767,7 @@ int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_ad
         if (r > 0) {
                 uint8_t a[4];
 
-                for (size_t i = 0; i < ELEMENTSOF(a); i++) {
+                FOREACH_ELEMENT(i, a) {
                         char label[DNS_LABEL_MAX+1];
 
                         r = dns_label_unescape(&p, label, sizeof label, 0);
@@ -771,7 +778,7 @@ int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_ad
                         if (r > 3)
                                 return -EINVAL;
 
-                        r = safe_atou8(label, &a[i]);
+                        r = safe_atou8(label, i);
                         if (r < 0)
                                 return r;
                 }
@@ -906,6 +913,78 @@ int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, boo
         return out - buffer;
 }
 
+/* Decode a domain name according to RFC 1035 Section 3.1, without compression */
+int dns_name_from_wire_format(const uint8_t **data, size_t *len, char **ret) {
+        _cleanup_free_ char *domain = NULL;
+        const uint8_t *optval;
+        size_t optlen, n = 0;
+        int r;
+
+        assert(data);
+        assert(len);
+        assert(*data || *len == 0);
+        assert(ret);
+
+        optval = *data;
+        optlen = *len;
+
+        for (;;) {
+                const char *label;
+                uint8_t c;
+
+                /* RFC 4704 § 4: fully qualified domain names include the terminating
+                 * zero-length label, partial names don't. According to the RFC, DHCPv6
+                 * servers should always send the fully qualified name, but that's not
+                 * true in practice. Also accept partial names. */
+                if (optlen == 0)
+                        break;
+
+                /* RFC 1035 § 3.1 total length of encoded name is limited to 255 octets */
+                if (*len - optlen > 255)
+                        return -EMSGSIZE;
+
+                c = *optval;
+                optval++;
+                optlen--;
+
+                if (c == 0)
+                        /* End label */
+                        break;
+                if (c > DNS_LABEL_MAX)
+                        return -EBADMSG;
+                if (c > optlen)
+                        return -EMSGSIZE;
+
+                /* Literal label */
+                label = (const char*) optval;
+                optval += c;
+                optlen -= c;
+
+                if (!GREEDY_REALLOC(domain, n + (n != 0) + DNS_LABEL_ESCAPED_MAX))
+                        return -ENOMEM;
+
+                if (n != 0)
+                        domain[n++] = '.';
+
+                r = dns_label_escape(label, c, domain + n, DNS_LABEL_ESCAPED_MAX);
+                if (r < 0)
+                        return r;
+
+                n += r;
+        }
+
+        if (!GREEDY_REALLOC(domain, n + 1))
+                return -ENOMEM;
+
+        domain[n] = '\0';
+
+        *ret = TAKE_PTR(domain);
+        *data = optval;
+        *len = optlen;
+
+        return n;
+}
+
 #if 0 /* NM_IGNORED */
 static bool srv_type_label_is_valid(const char *label, size_t n) {
         assert(label);
@@ -989,6 +1068,29 @@ bool dns_service_name_is_valid(const char *name) {
         return true;
 }
 
+bool dns_subtype_name_is_valid(const char *name) {
+        size_t l;
+
+        /* This more or less implements RFC 6763, Section 7.2 */
+
+        if (!name)
+                return false;
+
+        if (!utf8_is_valid(name))
+                return false;
+
+        if (string_has_cc(name, NULL))
+                return false;
+
+        l = strlen(name);
+        if (l <= 0)
+                return false;
+        if (l > DNS_LABEL_MAX)
+                return false;
+
+        return true;
+}
+
 int dns_service_join(const char *name, const char *type, const char *domain, char **ret) {
         char escaped[DNS_LABEL_ESCAPED_MAX];
         _cleanup_free_ char *n = NULL;
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.h b/src/libnm-systemd-shared/src/shared/dns-domain.h
index a9449410..1cd3c7a5 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.h
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.h
@@ -81,10 +81,12 @@ bool dns_name_is_root(const char *name);
 bool dns_name_is_single_label(const char *name);
 
 int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical);
+int dns_name_from_wire_format(const uint8_t **data, size_t *len, char **ret);
 
 bool dns_srv_type_is_valid(const char *name);
 bool dnssd_srv_type_is_valid(const char *name);
 bool dns_service_name_is_valid(const char *name);
+bool dns_subtype_name_is_valid(const char *name);
 
 int dns_service_join(const char *name, const char *type, const char *domain, char **ret);
 int dns_service_split(const char *joined, char **ret_name, char **ret_type, char **ret_domain);