summary refs log tree commit diff
path: root/shared/systemd
diff options
context:
space:
mode:
Diffstat (limited to 'shared/systemd')
-rw-r--r--shared/systemd/nm-default-systemd-shared.h18
-rw-r--r--shared/systemd/nm-logging-stub.c4
-rw-r--r--shared/systemd/nm-sd-utils-shared.c26
-rw-r--r--shared/systemd/nm-sd-utils-shared.h4
-rw-r--r--shared/systemd/sd-adapt-shared/idn-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h23
-rw-r--r--shared/systemd/src/basic/alloc-util.c2
-rw-r--r--shared/systemd/src/basic/alloc-util.h14
-rw-r--r--shared/systemd/src/basic/async.h8
-rw-r--r--shared/systemd/src/basic/cgroup-util.h15
-rw-r--r--shared/systemd/src/basic/env-file.c2
-rw-r--r--shared/systemd/src/basic/env-file.h2
-rw-r--r--shared/systemd/src/basic/env-util.c30
-rw-r--r--shared/systemd/src/basic/env-util.h5
-rw-r--r--shared/systemd/src/basic/errno-util.h10
-rw-r--r--shared/systemd/src/basic/escape.c2
-rw-r--r--shared/systemd/src/basic/escape.h4
-rw-r--r--shared/systemd/src/basic/ether-addr-util.c17
-rw-r--r--shared/systemd/src/basic/ether-addr-util.h26
-rw-r--r--shared/systemd/src/basic/extract-word.c2
-rw-r--r--shared/systemd/src/basic/extract-word.h2
-rw-r--r--shared/systemd/src/basic/fd-util.c88
-rw-r--r--shared/systemd/src/basic/fd-util.h2
-rw-r--r--shared/systemd/src/basic/fileio.c93
-rw-r--r--shared/systemd/src/basic/fileio.h39
-rw-r--r--shared/systemd/src/basic/format-util.c2
-rw-r--r--shared/systemd/src/basic/format-util.h7
-rw-r--r--shared/systemd/src/basic/fs-util.c87
-rw-r--r--shared/systemd/src/basic/fs-util.h4
-rw-r--r--shared/systemd/src/basic/hash-funcs.c15
-rw-r--r--shared/systemd/src/basic/hash-funcs.h4
-rw-r--r--shared/systemd/src/basic/hashmap.c64
-rw-r--r--shared/systemd/src/basic/hashmap.h7
-rw-r--r--shared/systemd/src/basic/hexdecoct.c2
-rw-r--r--shared/systemd/src/basic/hexdecoct.h2
-rw-r--r--shared/systemd/src/basic/hostname-util.c173
-rw-r--r--shared/systemd/src/basic/hostname-util.h26
-rw-r--r--shared/systemd/src/basic/in-addr-util.c2
-rw-r--r--shared/systemd/src/basic/in-addr-util.h2
-rw-r--r--shared/systemd/src/basic/io-util.c6
-rw-r--r--shared/systemd/src/basic/io-util.h2
-rw-r--r--shared/systemd/src/basic/list.h2
-rw-r--r--shared/systemd/src/basic/log.h39
-rw-r--r--shared/systemd/src/basic/macro.h30
-rw-r--r--shared/systemd/src/basic/memory-util.c2
-rw-r--r--shared/systemd/src/basic/memory-util.h2
-rw-r--r--shared/systemd/src/basic/mempool.c2
-rw-r--r--shared/systemd/src/basic/mempool.h2
-rw-r--r--shared/systemd/src/basic/missing_fcntl.h2
-rw-r--r--shared/systemd/src/basic/missing_random.h2
-rw-r--r--shared/systemd/src/basic/missing_socket.h10
-rw-r--r--shared/systemd/src/basic/missing_stat.h2
-rw-r--r--shared/systemd/src/basic/missing_syscall.h495
-rw-r--r--shared/systemd/src/basic/missing_type.h2
-rw-r--r--shared/systemd/src/basic/parse-util.c44
-rw-r--r--shared/systemd/src/basic/parse-util.h24
-rw-r--r--shared/systemd/src/basic/path-util.c58
-rw-r--r--shared/systemd/src/basic/path-util.h10
-rw-r--r--shared/systemd/src/basic/prioq.c2
-rw-r--r--shared/systemd/src/basic/prioq.h2
-rw-r--r--shared/systemd/src/basic/process-util.c2
-rw-r--r--shared/systemd/src/basic/process-util.h2
-rw-r--r--shared/systemd/src/basic/random-util.c19
-rw-r--r--shared/systemd/src/basic/random-util.h2
-rw-r--r--shared/systemd/src/basic/ratelimit.c40
-rw-r--r--shared/systemd/src/basic/ratelimit.h24
-rw-r--r--shared/systemd/src/basic/set.h14
-rw-r--r--shared/systemd/src/basic/signal-util.c13
-rw-r--r--shared/systemd/src/basic/signal-util.h2
-rw-r--r--shared/systemd/src/basic/siphash24.h14
-rw-r--r--shared/systemd/src/basic/socket-util.c117
-rw-r--r--shared/systemd/src/basic/socket-util.h46
-rw-r--r--shared/systemd/src/basic/sort-util.h6
-rw-r--r--shared/systemd/src/basic/stat-util.c12
-rw-r--r--shared/systemd/src/basic/stat-util.h2
-rw-r--r--shared/systemd/src/basic/stdio-util.h4
-rw-r--r--shared/systemd/src/basic/string-table.c2
-rw-r--r--shared/systemd/src/basic/string-table.h9
-rw-r--r--shared/systemd/src/basic/string-util.c77
-rw-r--r--shared/systemd/src/basic/string-util.h17
-rw-r--r--shared/systemd/src/basic/strv.c57
-rw-r--r--shared/systemd/src/basic/strv.h5
-rw-r--r--shared/systemd/src/basic/strxcpyx.c2
-rw-r--r--shared/systemd/src/basic/strxcpyx.h2
-rw-r--r--shared/systemd/src/basic/time-util.c4
-rw-r--r--shared/systemd/src/basic/time-util.h10
-rw-r--r--shared/systemd/src/basic/tmpfile-util.c2
-rw-r--r--shared/systemd/src/basic/tmpfile-util.h2
-rw-r--r--shared/systemd/src/basic/umask-util.h2
-rw-r--r--shared/systemd/src/basic/utf8.c2
-rw-r--r--shared/systemd/src/basic/utf8.h2
-rw-r--r--shared/systemd/src/basic/util.c8
-rw-r--r--shared/systemd/src/basic/util.h2
-rw-r--r--shared/systemd/src/shared/dns-domain.c90
-rw-r--r--shared/systemd/src/shared/dns-domain.h2
-rw-r--r--shared/systemd/src/shared/log-link.h45
-rw-r--r--shared/systemd/src/shared/web-util.c2
-rw-r--r--shared/systemd/src/shared/web-util.h2
98 files changed, 1487 insertions, 756 deletions
diff --git a/shared/systemd/nm-default-systemd-shared.h b/shared/systemd/nm-default-systemd-shared.h
new file mode 100644
index 00000000..bc0e6c4c
--- /dev/null
+++ b/shared/systemd/nm-default-systemd-shared.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ */
+
+#ifndef __NM_DEFAULT_SYSTEMD_SHARED_H__
+#define __NM_DEFAULT_SYSTEMD_SHARED_H__
+
+/*****************************************************************************/
+
+#include "nm-glib-aux/nm-default-glib.h"
+
+#undef NETWORKMANAGER_COMPILATION
+#define NETWORKMANAGER_COMPILATION NM_NETWORKMANAGER_COMPILATION_SYSTEMD_SHARED
+
+/*****************************************************************************/
+
+#endif /* __NM_DEFAULT_SYSTEMD_SHARED_H__ */
diff --git a/shared/systemd/nm-logging-stub.c b/shared/systemd/nm-logging-stub.c
index fa2328f3..8db90cd9 100644
--- a/shared/systemd/nm-logging-stub.c
+++ b/shared/systemd/nm-logging-stub.c
@@ -1,9 +1,9 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 /*
  * Copyright (C) 2018 Red Hat, Inc.
  */
 
-#include "nm-default.h"
+#include "shared/systemd/nm-default-systemd-shared.h"
 
 #include "nm-glib-aux/nm-logging-fwd.h"
 
diff --git a/shared/systemd/nm-sd-utils-shared.c b/shared/systemd/nm-sd-utils-shared.c
index 83c91af7..f0504aa9 100644
--- a/shared/systemd/nm-sd-utils-shared.c
+++ b/shared/systemd/nm-sd-utils-shared.c
@@ -1,9 +1,9 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 /*
  * Copyright (C) 2018 Red Hat, Inc.
  */
 
-#include "nm-default.h"
+#include "shared/systemd/nm-default-systemd-shared.h"
 
 #include "nm-sd-utils-shared.h"
 
@@ -88,7 +88,27 @@ nm_sd_dns_name_is_valid(const char *s)
 gboolean
 nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot)
 {
-    return hostname_is_valid(s, allow_trailing_dot);
+    return hostname_is_valid(s,
+                             allow_trailing_dot ? VALID_HOSTNAME_TRAILING_DOT
+                                                : (ValidHostnameFlags) 0);
+}
+
+char *
+nm_sd_dns_name_normalize(const char *s)
+{
+    nm_auto_free char *n = NULL;
+    int                r;
+
+    r = dns_name_normalize(s, 0, &n);
+    if (r < 0)
+        return NULL;
+
+    nm_assert(n);
+
+    /* usually we try not to mix malloc/g_malloc and free/g_free. In practice,
+     * they are the same. So here we return a buffer allocated with malloc(),
+     * and the caller should free it with g_free(). */
+    return g_steal_pointer(&n);
 }
 
 /*****************************************************************************/
diff --git a/shared/systemd/nm-sd-utils-shared.h b/shared/systemd/nm-sd-utils-shared.h
index b871fc29..45089c07 100644
--- a/shared/systemd/nm-sd-utils-shared.h
+++ b/shared/systemd/nm-sd-utils-shared.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 /*
  * Copyright (C) 2018 Red Hat, Inc.
  */
@@ -28,6 +28,8 @@ nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gb
 int      nm_sd_dns_name_is_valid(const char *s);
 gboolean nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot);
 
+char *nm_sd_dns_name_normalize(const char *s);
+
 /*****************************************************************************/
 
 gboolean nm_sd_http_url_is_valid_https(const char *url);
diff --git a/shared/systemd/sd-adapt-shared/idn-util.h b/shared/systemd/sd-adapt-shared/idn-util.h
new file mode 100644
index 00000000..637892c2
--- /dev/null
+++ b/shared/systemd/sd-adapt-shared/idn-util.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h
index 0160284d..b094ce40 100644
--- a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h
+++ b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 /*
  * Copyright (C) 2014 - 2018 Red Hat, Inc.
  */
@@ -6,7 +6,7 @@
 #ifndef __NM_SD_ADAPT_SHARED_H__
 #define __NM_SD_ADAPT_SHARED_H__
 
-#include "nm-default.h"
+#include "shared/systemd/nm-default-systemd-shared.h"
 
 #include "nm-glib-aux/nm-logging-fwd.h"
 
@@ -127,6 +127,7 @@ _nm_log_get_max_level_realm(void)
 
     #include <sys/syscall.h>
     #include <sys/ioctl.h>
+    #include <pthread.h>
 
     #define ENABLE_GSHADOW FALSE
 
@@ -195,6 +196,24 @@ _nm_gettid(void)
         #define HAVE_RT_SIGQUEUEINFO 0
     #endif
 
+    #ifndef __COMPAR_FN_T
+        #define __COMPAR_FN_T
+typedef int (*__compar_fn_t)(const void *, const void *);
+typedef __compar_fn_t comparison_fn_t;
+typedef int (*__compar_d_fn_t)(const void *, const void *, void *);
+    #endif
+
+    #ifndef __GLIBC__
+static inline int
+__register_atfork(void (*prepare)(void),
+                  void (*parent)(void),
+                  void (*child)(void),
+                  void *dso_handle)
+{
+    return pthread_atfork(prepare, parent, child);
+}
+    #endif
+
 #endif /* (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD */
 
 /*****************************************************************************/
diff --git a/shared/systemd/src/basic/alloc-util.c b/shared/systemd/src/basic/alloc-util.c
index e355b60f..7f7eb433 100644
--- a/shared/systemd/src/basic/alloc-util.c
+++ b/shared/systemd/src/basic/alloc-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/alloc-util.h b/shared/systemd/src/basic/alloc-util.h
index 64d9e003..f3e192dd 100644
--- a/shared/systemd/src/basic/alloc-util.h
+++ b/shared/systemd/src/basic/alloc-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <alloca.h>
@@ -27,7 +27,7 @@ typedef void (*free_func_t)(void *p);
                 size_t _n_ = n;                                         \
                 assert(!size_multiply_overflow(sizeof(t), _n_));        \
                 assert(sizeof(t)*_n_ <= ALLOCA_MAX);                    \
-                (t*) alloca(sizeof(t)*_n_);                             \
+                (t*) alloca((sizeof(t)*_n_) ?: 1);                      \
         })
 
 #define newa0(t, n)                                                     \
@@ -35,14 +35,14 @@ typedef void (*free_func_t)(void *p);
                 size_t _n_ = n;                                         \
                 assert(!size_multiply_overflow(sizeof(t), _n_));        \
                 assert(sizeof(t)*_n_ <= ALLOCA_MAX);                    \
-                (t*) alloca0(sizeof(t)*_n_);                            \
+                (t*) alloca0((sizeof(t)*_n_) ?: 1);                     \
         })
 
 #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
 
 #define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
 
-#define malloc0(n) (calloc(1, (n)))
+#define malloc0(n) (calloc(1, (n) ?: 1))
 
 static inline void *mfree(void *memory) {
         free(memory);
@@ -65,7 +65,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
                 void *_q_;                      \
                 size_t _l_ = l;                 \
                 assert(_l_ <= ALLOCA_MAX);      \
-                _q_ = alloca(_l_);              \
+                _q_ = alloca(_l_ ?: 1);         \
                 memcpy(_q_, p, _l_);            \
         })
 
@@ -135,7 +135,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
                 char *_new_;                            \
                 size_t _len_ = n;                       \
                 assert(_len_ <= ALLOCA_MAX);            \
-                _new_ = alloca(_len_);                  \
+                _new_ = alloca(_len_ ?: 1);             \
                 (void *) memset(_new_, 0, _len_);       \
         })
 
@@ -146,7 +146,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
                 size_t _mask_ = (align) - 1;                            \
                 size_t _size_ = size;                                   \
                 assert(_size_ <= ALLOCA_MAX);                           \
-                _ptr_ = alloca(_size_ + _mask_);                        \
+                _ptr_ = alloca((_size_ + _mask_) ?: 1);                 \
                 (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_);         \
         })
 
diff --git a/shared/systemd/src/basic/async.h b/shared/systemd/src/basic/async.h
index 31606131..e0bbaa56 100644
--- a/shared/systemd/src/basic/async.h
+++ b/shared/systemd/src/basic/async.h
@@ -1,7 +1,13 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <sys/types.h>
+
+#include "macro.h"
+
 int asynchronous_job(void* (*func)(void *p), void *arg);
 
 int asynchronous_sync(pid_t *ret_pid);
 int asynchronous_close(int fd);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(int, asynchronous_close);
diff --git a/shared/systemd/src/basic/cgroup-util.h b/shared/systemd/src/basic/cgroup-util.h
index 2b88571b..bdc0d0d0 100644
--- a/shared/systemd/src/basic/cgroup-util.h
+++ b/shared/systemd/src/basic/cgroup-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <dirent.h>
@@ -208,6 +208,9 @@ static inline int cg_get_keyed_attribute_graceful(
 
 int cg_get_attribute_as_uint64(const char *controller, const char *path, const char *attribute, uint64_t *ret);
 
+/* Does a parse_boolean() on the attribute contents and sets ret accordingly */
+int cg_get_attribute_as_bool(const char *controller, const char *path, const char *attribute, bool *ret);
+
 int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid);
 
 int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags);
@@ -275,3 +278,13 @@ CGroupController cgroup_controller_from_string(const char *s) _pure_;
 
 bool is_cgroup_fs(const struct statfs *s);
 bool fd_is_cgroup_fs(int fd);
+
+typedef enum ManagedOOMMode {
+        MANAGED_OOM_AUTO,
+        MANAGED_OOM_KILL,
+        _MANAGED_OOM_MODE_MAX,
+        _MANAGED_OOM_MODE_INVALID = -1,
+} ManagedOOMMode;
+
+const char* managed_oom_mode_to_string(ManagedOOMMode m) _const_;
+ManagedOOMMode managed_oom_mode_from_string(const char *s) _pure_;
diff --git a/shared/systemd/src/basic/env-file.c b/shared/systemd/src/basic/env-file.c
index 1e93f18e..568b742f 100644
--- a/shared/systemd/src/basic/env-file.c
+++ b/shared/systemd/src/basic/env-file.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/env-file.h b/shared/systemd/src/basic/env-file.h
index e1ca195f..de475885 100644
--- a/shared/systemd/src/basic/env-file.h
+++ b/shared/systemd/src/basic/env-file.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdarg.h>
diff --git a/shared/systemd/src/basic/env-util.c b/shared/systemd/src/basic/env-util.c
index 11f4b29b..a311ee00 100644
--- a/shared/systemd/src/basic/env-util.c
+++ b/shared/systemd/src/basic/env-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -19,7 +19,8 @@
 #include "utf8.h"
 
 #if 0 /* NM_IGNORED */
-#define VALID_CHARS_ENV_NAME                    \
+/* We follow bash for the character set. Different shells have different rules. */
+#define VALID_BASH_ENV_NAME_CHARS               \
         DIGITS LETTERS                          \
         "_"
 
@@ -44,17 +45,14 @@ static bool env_name_is_valid_n(const char *e, size_t n) {
                 return false;
 
         for (p = e; p < e + n; p++)
-                if (!strchr(VALID_CHARS_ENV_NAME, *p))
+                if (!strchr(VALID_BASH_ENV_NAME_CHARS, *p))
                         return false;
 
         return true;
 }
 
 bool env_name_is_valid(const char *e) {
-        if (!e)
-                return false;
-
-        return env_name_is_valid_n(e, strlen(e));
+        return env_name_is_valid_n(e, strlen_ptr(e));
 }
 
 bool env_value_is_valid(const char *e) {
@@ -549,7 +547,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
                                 word = e+1;
                                 state = WORD;
 
-                        } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) {
+                        } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
                                 k = strnappend(r, word, e-word-1);
                                 if (!k)
                                         return NULL;
@@ -639,7 +637,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
                 case VARIABLE_RAW:
                         assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
 
-                        if (!strchr(VALID_CHARS_ENV_NAME, *e)) {
+                        if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
                                 const char *t;
 
                                 t = strv_env_get_n(env, word+1, e-word-1, flags);
@@ -753,3 +751,17 @@ int getenv_bool_secure(const char *p) {
 
         return parse_boolean(e);
 }
+
+#if 0 /* NM_IGNORED */
+int set_unset_env(const char *name, const char *value, bool overwrite) {
+        int r;
+
+        if (value)
+                r = setenv(name, value, overwrite);
+        else
+                r = unsetenv(name);
+        if (r < 0)
+                return -errno;
+        return 0;
+}
+#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/env-util.h b/shared/systemd/src/basic/env-util.h
index 92802ed7..6684b335 100644
--- a/shared/systemd/src/basic/env-util.h
+++ b/shared/systemd/src/basic/env-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>
@@ -52,3 +52,6 @@ char *strv_env_get(char **x, const char *n) _pure_;
 
 int getenv_bool(const char *p);
 int getenv_bool_secure(const char *p);
+
+/* Like setenv, but calls unsetenv if value == NULL. */
+int set_unset_env(const char *name, const char *value, bool overwrite);
diff --git a/shared/systemd/src/basic/errno-util.h b/shared/systemd/src/basic/errno-util.h
index 0ca650f4..5609820b 100644
--- a/shared/systemd/src/basic/errno-util.h
+++ b/shared/systemd/src/basic/errno-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdlib.h>
@@ -50,7 +50,10 @@ static inline int errno_or_else(int fallback) {
 /* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5.
  *
  * Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases.  See the
- *          icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */
+ *          icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources.
+ *
+ * Hint #3: When asynchronous connect() on TCP fails because the host never acknowledges a single packet,
+ *          kernel tells us that with ETIMEDOUT, see tcp(7). */
 static inline bool ERRNO_IS_DISCONNECT(int r) {
         return IN_SET(abs(r),
                       ECONNABORTED,
@@ -66,7 +69,8 @@ static inline bool ERRNO_IS_DISCONNECT(int r) {
                       ENOTCONN,
                       EPIPE,
                       EPROTO,
-                      ESHUTDOWN);
+                      ESHUTDOWN,
+                      ETIMEDOUT);
 }
 
 /* Transient errors we might get on accept() that we should ignore. As per error handling comment in
diff --git a/shared/systemd/src/basic/escape.c b/shared/systemd/src/basic/escape.c
index 1261fd48..094b5c5f 100644
--- a/shared/systemd/src/basic/escape.c
+++ b/shared/systemd/src/basic/escape.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/escape.h b/shared/systemd/src/basic/escape.h
index fa267813..691b6d80 100644
--- a/shared/systemd/src/basic/escape.h
+++ b/shared/systemd/src/basic/escape.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <inttypes.h>
@@ -16,7 +16,7 @@
 
 /* Those that can be escaped or double-quoted.
  *
- * Stricly speaking, ! does not need to be escaped, except in interactive
+ * Strictly speaking, ! does not need to be escaped, except in interactive
  * mode, but let's be extra nice to the user and quote ! in case this
  * output is ever used in interactive mode. */
 #define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;!"
diff --git a/shared/systemd/src/basic/ether-addr-util.c b/shared/systemd/src/basic/ether-addr-util.c
index 4878a3d2..ae83eade 100644
--- a/shared/systemd/src/basic/ether-addr-util.c
+++ b/shared/systemd/src/basic/ether-addr-util.c
@@ -1,8 +1,9 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
 #include <errno.h>
+#include <inttypes.h>
 #include <net/ethernet.h>
 #include <stdio.h>
 #include <sys/types.h>
@@ -11,6 +12,20 @@
 #include "macro.h"
 #include "string-util.h"
 
+char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) {
+        assert(addr);
+        assert(buffer);
+        assert(addr->length <= HW_ADDR_MAX_SIZE);
+
+        for (size_t i = 0; i < addr->length; i++) {
+                sprintf(&buffer[3*i], "%02"PRIx8, addr->addr.bytes[i]);
+                if (i < addr->length - 1)
+                        buffer[3*i + 2] = ':';
+        }
+
+        return buffer;
+}
+
 char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
         assert(addr);
         assert(buffer);
diff --git a/shared/systemd/src/basic/ether-addr-util.h b/shared/systemd/src/basic/ether-addr-util.h
index 4e44b30b..942ce556 100644
--- a/shared/systemd/src/basic/ether-addr-util.h
+++ b/shared/systemd/src/basic/ether-addr-util.h
@@ -1,11 +1,35 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <linux/if_infiniband.h>
 #include <net/ethernet.h>
 #include <stdbool.h>
 
 #include "hash-funcs.h"
 
+/* This is MAX_ADDR_LEN as defined in linux/netdevice.h, but net/if_arp.h
+ * defines a macro of the same name with a much lower size. */
+#define HW_ADDR_MAX_SIZE 32
+
+union hw_addr_union {
+        struct ether_addr ether;
+        uint8_t infiniband[INFINIBAND_ALEN];
+        uint8_t bytes[HW_ADDR_MAX_SIZE];
+};
+
+typedef struct hw_addr_data {
+        union hw_addr_union addr;
+        size_t length;
+} hw_addr_data;
+
+#define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE)
+char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]);
+
+/* Use only as function argument, never stand-alone! */
+#define HW_ADDR_TO_STR(hw_addr) hw_addr_to_string((hw_addr), (char[HW_ADDR_TO_STRING_MAX]){})
+
+#define HW_ADDR_NULL ((const hw_addr_data){})
+
 #define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
 #define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
 
diff --git a/shared/systemd/src/basic/extract-word.c b/shared/systemd/src/basic/extract-word.c
index e32b4c7f..1d86033f 100644
--- a/shared/systemd/src/basic/extract-word.c
+++ b/shared/systemd/src/basic/extract-word.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/extract-word.h b/shared/systemd/src/basic/extract-word.h
index f028577c..d1de32e5 100644
--- a/shared/systemd/src/basic/extract-word.h
+++ b/shared/systemd/src/basic/extract-word.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include "macro.h"
diff --git a/shared/systemd/src/basic/fd-util.c b/shared/systemd/src/basic/fd-util.c
index 525d3828..e53cf18d 100644
--- a/shared/systemd/src/basic/fd-util.c
+++ b/shared/systemd/src/basic/fd-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -23,6 +23,7 @@
 #include "path-util.h"
 #include "process-util.h"
 #include "socket-util.h"
+#include "sort-util.h"
 #include "stat-util.h"
 #include "stdio-util.h"
 #include "tmpfile-util.h"
@@ -214,12 +215,97 @@ static int get_max_fd(void) {
 }
 
 int close_all_fds(const int except[], size_t n_except) {
+        static bool have_close_range = true; /* Assume we live in the future */
         _cleanup_closedir_ DIR *d = NULL;
         struct dirent *de;
         int r = 0;
 
         assert(n_except == 0 || except);
 
+        if (have_close_range) {
+                /* In the best case we have close_range() to close all fds between a start and an end fd,
+                 * which we can use on the "inverted" exception array, i.e. all intervals between all
+                 * adjacent pairs from the sorted exception array. This changes loop complexity from O(n)
+                 * where n is number of open fds to O(m⋅log(m)) where m is the number of fds to keep
+                 * open. Given that we assume n ≫ m that's preferable to us. */
+
+                if (n_except == 0) {
+                        /* Close everything. Yay! */
+
+                        if (close_range(3, -1, 0) >= 0)
+                                return 1;
+
+                        if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+                                return -errno;
+
+                        have_close_range = false;
+                } else {
+                        _cleanup_free_ int *sorted_malloc = NULL;
+                        size_t n_sorted;
+                        int *sorted;
+
+                        assert(n_except < SIZE_MAX);
+                        n_sorted = n_except + 1;
+
+                        if (n_sorted > 64) /* Use heap for large numbers of fds, stack otherwise */
+                                sorted = sorted_malloc = new(int, n_sorted);
+                        else
+                                sorted = newa(int, n_sorted);
+
+                        if (sorted) {
+                                int c = 0;
+
+                                memcpy(sorted, except, n_except * sizeof(int));
+
+                                /* Let's add fd 2 to the list of fds, to simplify the loop below, as this
+                                 * allows us to cover the head of the array the same way as the body */
+                                sorted[n_sorted-1] = 2;
+
+                                typesafe_qsort(sorted, n_sorted, cmp_int);
+
+                                for (size_t i = 0; i < n_sorted-1; i++) {
+                                        int start, end;
+
+                                        start = MAX(sorted[i], 2); /* The first three fds shall always remain open */
+                                        end = MAX(sorted[i+1], 2);
+
+                                        assert(end >= start);
+
+                                        if (end - start <= 1)
+                                                continue;
+
+                                        /* Close everything between the start and end fds (both of which shall stay open) */
+                                        if (close_range(start + 1, end - 1, 0) < 0) {
+                                                if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+                                                        return -errno;
+
+                                                have_close_range = false;
+                                                break;
+                                        }
+
+                                        c += end - start - 1;
+                                }
+
+                                if (have_close_range) {
+                                        /* The loop succeeded. Let's now close everything beyond the end */
+
+                                        if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
+                                                return c;
+
+                                        if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
+                                                return c + 1;
+
+                                        if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+                                                return -errno;
+
+                                        have_close_range = false;
+                                }
+                        }
+                }
+
+                /* Fallback on OOM or if close_range() is not supported */
+        }
+
         d = opendir("/proc/self/fd");
         if (!d) {
                 int fd, max_fd;
diff --git a/shared/systemd/src/basic/fd-util.h b/shared/systemd/src/basic/fd-util.h
index 93ce95cd..2162537b 100644
--- a/shared/systemd/src/basic/fd-util.h
+++ b/shared/systemd/src/basic/fd-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <dirent.h>
diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c
index 664b894a..ea90614a 100644
--- a/shared/systemd/src/basic/fileio.c
+++ b/shared/systemd/src/basic/fileio.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -120,7 +120,7 @@ int write_string_stream_ts(
                 FILE *f,
                 const char *line,
                 WriteStringFileFlags flags,
-                struct timespec *ts) {
+                const struct timespec *ts) {
 
         bool needs_nl;
         int r, fd;
@@ -164,7 +164,7 @@ int write_string_stream_ts(
                 return r;
 
         if (ts) {
-                struct timespec twice[2] = {*ts, *ts};
+                const struct timespec twice[2] = {*ts, *ts};
 
                 if (futimens(fd, twice) < 0)
                         return -errno;
@@ -177,7 +177,7 @@ static int write_string_file_atomic(
                 const char *fn,
                 const char *line,
                 WriteStringFileFlags flags,
-                struct timespec *ts) {
+                const struct timespec *ts) {
 
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_free_ char *p = NULL;
@@ -224,7 +224,7 @@ int write_string_file_ts(
                 const char *fn,
                 const char *line,
                 WriteStringFileFlags flags,
-                struct timespec *ts) {
+                const struct timespec *ts) {
 
         _cleanup_fclose_ FILE *f = NULL;
         int q, r, fd;
@@ -255,7 +255,8 @@ int write_string_file_ts(
         /* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */
         fd = open(fn, O_WRONLY|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_CREATE) ? O_CREAT : 0) |
+                  (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0),
                   (FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
         if (fd < 0) {
                 r = -errno;
@@ -475,12 +476,13 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
 int read_full_stream_full(
                 FILE *f,
                 const char *filename,
+                uint64_t offset,
+                size_t size,
                 ReadFullFileFlags flags,
                 char **ret_contents,
                 size_t *ret_size) {
 
         _cleanup_free_ char *buf = NULL;
-        struct stat st;
         size_t n, n_next, l;
         int fd, r;
 
@@ -488,32 +490,45 @@ int read_full_stream_full(
         assert(ret_contents);
         assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
 
-        n_next = LINE_MAX; /* Start size */
+        if (offset != UINT64_MAX && offset > LONG_MAX)
+                return -ERANGE;
+
+        n_next = size != SIZE_MAX ? size : LINE_MAX; /* Start size */
 
         fd = fileno(f);
-        if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's
-                        * optimize our buffering */
+        if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see
+                        * fmemopen()), let's optimize our buffering */
+                struct stat st;
 
                 if (fstat(fd, &st) < 0)
                         return -errno;
 
                 if (S_ISREG(st.st_mode)) {
-
-                        /* Safety check */
-                        if (st.st_size > READ_FULL_BYTES_MAX)
-                                return -E2BIG;
-
-                        /* Start with the right file size. Note that we increase the size
-                         * to read here by one, so that the first read attempt already
-                         * makes us notice the EOF. */
-                        if (st.st_size > 0)
-                                n_next = st.st_size + 1;
+                        if (size == SIZE_MAX) {
+                                uint64_t rsize =
+                                        LESS_BY((uint64_t) st.st_size, offset == UINT64_MAX ? 0 : offset);
+
+                                /* Safety check */
+                                if (rsize > READ_FULL_BYTES_MAX)
+                                        return -E2BIG;
+
+                                /* Start with the right file size. Note that we increase the size to read
+                                 * here by one, so that the first read attempt already makes us notice the
+                                 * EOF. If the reported size of the file is zero, we avoid this logic
+                                 * however, since quite likely it might be a virtual file in procfs that all
+                                 * report a zero file size. */
+                                if (st.st_size > 0)
+                                        n_next = rsize + 1;
+                        }
 
                         if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
                                 (void) warn_file_is_world_accessible(filename, &st, NULL, 0);
                 }
         }
 
+        if (offset != UINT64_MAX && fseek(f, offset, SEEK_SET) < 0)
+                return -errno;
+
         n = l = 0;
         for (;;) {
                 char *t;
@@ -550,6 +565,11 @@ int read_full_stream_full(
                 if (feof(f))
                         break;
 
+                if (size != SIZE_MAX) { /* If we got asked to read some specific size, we already sized the buffer right, hence leave */
+                        assert(l == size);
+                        break;
+                }
+
                 assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
 
                 /* Safety check */
@@ -605,12 +625,21 @@ finalize:
         return r;
 }
 
-int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
+int read_full_file_full(
+                int dir_fd,
+                const char *filename,
+                uint64_t offset,
+                size_t size,
+                ReadFullFileFlags flags,
+                const char *bind_name,
+                char **ret_contents,
+                size_t *ret_size) {
+
         _cleanup_fclose_ FILE *f = NULL;
         int r;
 
         assert(filename);
-        assert(contents);
+        assert(ret_contents);
 
         r = xfopenat(dir_fd, filename, "re", 0, &f);
         if (r < 0) {
@@ -625,6 +654,10 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag
                 if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
                         return -ENXIO;
 
+                /* Seeking is not supported on AF_UNIX sockets */
+                if (offset != UINT64_MAX)
+                        return -ESPIPE;
+
                 if (dir_fd == AT_FDCWD)
                         r = sockaddr_un_set_path(&sa.un, filename);
                 else {
@@ -648,6 +681,20 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag
                 if (sk < 0)
                         return -errno;
 
+                if (bind_name) {
+                        /* If the caller specified a socket name to bind to, do so before connecting. This is
+                         * useful to communicate some minor, short meta-information token from the client to
+                         * the server. */
+                        union sockaddr_union bsa;
+
+                        r = sockaddr_un_set_path(&bsa.un, bind_name);
+                        if (r < 0)
+                                return r;
+
+                        if (bind(sk, &bsa.sa, r) < 0)
+                                return r;
+                }
+
                 if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
                         return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is
                                                                      * not a socket after all */
@@ -664,7 +711,7 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag
 
         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
 
-        return read_full_stream_full(f, filename, flags, contents, size);
+        return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
 }
 
 #if 0 /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/fileio.h b/shared/systemd/src/basic/fileio.h
index 9cba5a90..5a028561 100644
--- a/shared/systemd/src/basic/fileio.h
+++ b/shared/systemd/src/basic/fileio.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <dirent.h>
@@ -6,7 +6,11 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <sys/stat.h>
+#if 0 /* NM_IGNORED */
 #include <sys/fcntl.h>
+#else /* NM_IGNORED */
+#include <fcntl.h>
+#endif /* NM_IGNORED */
 #include <sys/types.h>
 
 #include "macro.h"
@@ -16,14 +20,15 @@
 
 typedef enum {
         WRITE_STRING_FILE_CREATE            = 1 << 0,
-        WRITE_STRING_FILE_ATOMIC            = 1 << 1,
-        WRITE_STRING_FILE_AVOID_NEWLINE     = 1 << 2,
-        WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 3,
-        WRITE_STRING_FILE_SYNC              = 1 << 4,
-        WRITE_STRING_FILE_DISABLE_BUFFER    = 1 << 5,
-        WRITE_STRING_FILE_NOFOLLOW          = 1 << 6,
-        WRITE_STRING_FILE_MKDIR_0755        = 1 << 7,
-        WRITE_STRING_FILE_MODE_0600         = 1 << 8,
+        WRITE_STRING_FILE_TRUNCATE          = 1 << 1,
+        WRITE_STRING_FILE_ATOMIC            = 1 << 2,
+        WRITE_STRING_FILE_AVOID_NEWLINE     = 1 << 3,
+        WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 4,
+        WRITE_STRING_FILE_SYNC              = 1 << 5,
+        WRITE_STRING_FILE_DISABLE_BUFFER    = 1 << 6,
+        WRITE_STRING_FILE_NOFOLLOW          = 1 << 7,
+        WRITE_STRING_FILE_MKDIR_0755        = 1 << 8,
+        WRITE_STRING_FILE_MODE_0600         = 1 << 9,
 
         /* 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()
@@ -47,11 +52,11 @@ 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, struct timespec *ts);
+int write_string_stream_ts(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(const char *fn, const char *line, WriteStringFileFlags flags, struct timespec *ts);
+int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
 static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
         return write_string_file_ts(fn, line, flags, NULL);
 }
@@ -59,14 +64,14 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
 int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
 
 int read_one_line_file(const char *filename, char **line);
-int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
-static inline int read_full_file(const char *filename, char **contents, size_t *size) {
-        return read_full_file_full(AT_FDCWD, filename, 0, contents, size);
+int read_full_file_full(int dir_fd, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, const char *bind_name, char **ret_contents, size_t *ret_size);
+static inline int read_full_file(const char *filename, char **ret_contents, size_t *ret_size) {
+        return read_full_file_full(AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size);
 }
 int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size);
-int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
-static inline int read_full_stream(FILE *f, char **contents, size_t *size) {
-        return read_full_stream_full(f, NULL, 0, contents, size);
+int read_full_stream_full(FILE *f, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, char **ret_contents, size_t *ret_size);
+static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_size) {
+        return read_full_stream_full(f, NULL, UINT64_MAX, SIZE_MAX, 0, ret_contents, ret_size);
 }
 
 int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
diff --git a/shared/systemd/src/basic/format-util.c b/shared/systemd/src/basic/format-util.c
index 62477f53..42224b6f 100644
--- a/shared/systemd/src/basic/format-util.c
+++ b/shared/systemd/src/basic/format-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/format-util.h b/shared/systemd/src/basic/format-util.h
index c47fa76e..b7e18768 100644
--- a/shared/systemd/src/basic/format-util.h
+++ b/shared/systemd/src/basic/format-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <inttypes.h>
@@ -72,11 +72,14 @@ typedef enum {
         FORMAT_BYTES_TRAILING_B  = 1 << 2,
 } FormatBytesFlag;
 
-#define FORMAT_BYTES_MAX 16
+#define FORMAT_BYTES_MAX 16U
+
 char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag);
+
 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);
 }
+
 static inline char *format_bytes_cgroup_protection(char *buf, size_t l, uint64_t t) {
         if (t == CGROUP_LIMIT_MAX) {
                 (void) snprintf(buf, l, "%s", "infinity");
diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c
index e50252cb..2ed9ee0e 100644
--- a/shared/systemd/src/basic/fs-util.c
+++ b/shared/systemd/src/basic/fs-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -821,7 +821,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
          *
          * 3. With CHASE_STEP: in this case only a single step of the normalization is executed, i.e. only the first
          *    symlink or ".." component of the path is resolved, and the resulting path is returned. This is useful if
-         *    a caller wants to trace the a path through the file system verbosely. Returns < 0 on error, > 0 if the
+         *    a caller wants to trace the path through the file system verbosely. Returns < 0 on error, > 0 if the
          *    path is fully normalized, and == 0 for each normalization step. This may be combined with
          *    CHASE_NONEXISTENT, in which case 1 is returned when a component is not found.
          *
@@ -945,7 +945,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                         /* Preserve the trailing slash */
 
                         if (flags & CHASE_TRAIL_SLASH)
-                                if (!strextend(&done, "/", NULL))
+                                if (!strextend(&done, "/"))
                                         return -ENOMEM;
 
                         break;
@@ -1016,7 +1016,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                                 if (streq_ptr(done, "/"))
                                         *done = '\0';
 
-                                if (!strextend(&done, first, todo, NULL))
+                                if (!strextend(&done, first, todo))
                                         return -ENOMEM;
 
                                 exists = false;
@@ -1109,7 +1109,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                         if (streq(done, "/"))
                                 *done = '\0';
 
-                        if (!strextend(&done, first, NULL))
+                        if (!strextend(&done, first))
                                 return -ENOMEM;
                 }
 
@@ -1626,4 +1626,81 @@ int path_is_encrypted(const char *path) {
 
         return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
 }
+
+int conservative_rename(
+                int olddirfd, const char *oldpath,
+                int newdirfd, const char *newpath) {
+
+        _cleanup_close_ int old_fd = -1, new_fd = -1;
+        struct stat old_stat, new_stat;
+
+        /* Renames the old path to thew new path, much like renameat() — except if both are regular files and
+         * have the exact same contents and basic file attributes already. In that case remove the new file
+         * instead. This call is useful for reducing inotify wakeups on files that are updated but don't
+         * actually change. This function is written in a style that we rather rename too often than suppress
+         * too much. i.e. whenever we are in doubt we rather rename than fail. After all reducing inotify
+         * events is an optimization only, not more. */
+
+        old_fd = openat(olddirfd, oldpath, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_NOFOLLOW);
+        if (old_fd < 0)
+                goto do_rename;
+
+        new_fd = openat(newdirfd, newpath, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_NOFOLLOW);
+        if (new_fd < 0)
+                goto do_rename;
+
+        if (fstat(old_fd, &old_stat) < 0)
+                goto do_rename;
+
+        if (!S_ISREG(old_stat.st_mode))
+                goto do_rename;
+
+        if (fstat(new_fd, &new_stat) < 0)
+                goto do_rename;
+
+        if (new_stat.st_ino == old_stat.st_ino &&
+            new_stat.st_dev == old_stat.st_dev)
+                goto is_same;
+
+        if (old_stat.st_mode != new_stat.st_mode ||
+            old_stat.st_size != new_stat.st_size ||
+            old_stat.st_uid != new_stat.st_uid ||
+            old_stat.st_gid != new_stat.st_gid)
+                goto do_rename;
+
+        for (;;) {
+                char buf1[16*1024];
+                char buf2[sizeof(buf1) + 1];
+                ssize_t l1, l2;
+
+                l1 = read(old_fd, buf1, sizeof(buf1));
+                if (l1 < 0)
+                        goto do_rename;
+
+                l2 = read(new_fd, buf2, l1 + 1);
+                if (l1 != l2)
+                        goto do_rename;
+
+                if (l1 == 0) /* EOF on both! And everything's the same so far, yay! */
+                        break;
+
+                if (memcmp(buf1, buf2, l1) != 0)
+                        goto do_rename;
+        }
+
+is_same:
+        /* Everything matches? Then don't rename, instead remove the source file, and leave the existing
+         * destination in place */
+
+        if (unlinkat(olddirfd, oldpath, 0) < 0)
+                goto do_rename;
+
+        return 0;
+
+do_rename:
+        if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
+                return -errno;
+
+        return 1;
+}
 #endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/fs-util.h b/shared/systemd/src/basic/fs-util.h
index 241cc6ef..9a394735 100644
--- a/shared/systemd/src/basic/fs-util.h
+++ b/shared/systemd/src/basic/fs-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <dirent.h>
@@ -132,3 +132,5 @@ int syncfs_path(int atfd, const char *path);
 int open_parent(const char *path, int flags, mode_t mode);
 
 int path_is_encrypted(const char *path);
+
+int conservative_rename(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
diff --git a/shared/systemd/src/basic/hash-funcs.c b/shared/systemd/src/basic/hash-funcs.c
index b1c19c95..6f540b29 100644
--- a/shared/systemd/src/basic/hash-funcs.c
+++ b/shared/systemd/src/basic/hash-funcs.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -75,6 +75,19 @@ const struct hash_ops trivial_hash_ops = {
         .compare = trivial_compare_func,
 };
 
+const struct hash_ops trivial_hash_ops_free = {
+        .hash = trivial_hash_func,
+        .compare = trivial_compare_func,
+        .free_key = free,
+};
+
+const struct hash_ops trivial_hash_ops_free_free = {
+        .hash = trivial_hash_func,
+        .compare = trivial_compare_func,
+        .free_key = free,
+        .free_value = free,
+};
+
 void uint64_hash_func(const uint64_t *p, struct siphash *state) {
         siphash24_compress(p, sizeof(uint64_t), state);
 }
diff --git a/shared/systemd/src/basic/hash-funcs.h b/shared/systemd/src/basic/hash-funcs.h
index 005d1b21..5672df1d 100644
--- a/shared/systemd/src/basic/hash-funcs.h
+++ b/shared/systemd/src/basic/hash-funcs.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include "alloc-util.h"
@@ -88,6 +88,8 @@ extern const struct hash_ops path_hash_ops_free;
 void trivial_hash_func(const void *p, struct siphash *state);
 int trivial_compare_func(const void *a, const void *b) _const_;
 extern const struct hash_ops trivial_hash_ops;
+extern const struct hash_ops trivial_hash_ops_free;
+extern const struct hash_ops trivial_hash_ops_free_free;
 
 /* 32bit values we can always just embed in the pointer itself, but in order to support 32bit archs we need store 64bit
  * values indirectly, since they don't fit in a pointer. */
diff --git a/shared/systemd/src/basic/hashmap.c b/shared/systemd/src/basic/hashmap.c
index b57814e6..0a5deabf 100644
--- a/shared/systemd/src/basic/hashmap.c
+++ b/shared/systemd/src/basic/hashmap.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -1797,10 +1797,10 @@ int set_consume(Set *s, void *value) {
 }
 
 #if 0 /* NM_IGNORED */
-int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v  HASHMAP_DEBUG_PARAMS) {
+int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v  HASHMAP_DEBUG_PARAMS) {
         int r;
 
-        r = _hashmap_ensure_allocated(h, &string_hash_ops_free_free  HASHMAP_DEBUG_PASS_ARGS);
+        r = _hashmap_ensure_allocated(h, hash_ops  HASHMAP_DEBUG_PASS_ARGS);
         if (r < 0)
                 return r;
 
@@ -1832,14 +1832,14 @@ int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v  HASHMAP_DEBUG
 }
 #endif /* NM_IGNORED */
 
-int _set_put_strdup(Set **s, const char *p  HASHMAP_DEBUG_PARAMS) {
+int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p  HASHMAP_DEBUG_PARAMS) {
         char *c;
         int r;
 
         assert(s);
         assert(p);
 
-        r = _set_ensure_allocated(s, &string_hash_ops_free  HASHMAP_DEBUG_PASS_ARGS);
+        r = _set_ensure_allocated(s, hash_ops  HASHMAP_DEBUG_PASS_ARGS);
         if (r < 0)
                 return r;
 
@@ -1853,14 +1853,14 @@ int _set_put_strdup(Set **s, const char *p  HASHMAP_DEBUG_PARAMS) {
         return set_consume(*s, c);
 }
 
-int _set_put_strdupv(Set **s, char **l  HASHMAP_DEBUG_PARAMS) {
+int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l  HASHMAP_DEBUG_PARAMS) {
         int n = 0, r;
         char **i;
 
         assert(s);
 
         STRV_FOREACH(i, l) {
-                r = _set_put_strdup(s, *i  HASHMAP_DEBUG_PASS_ARGS);
+                r = _set_put_strdup_full(s, hash_ops, *i  HASHMAP_DEBUG_PASS_ARGS);
                 if (r < 0)
                         return r;
 
@@ -1980,3 +1980,53 @@ IteratedCache* iterated_cache_free(IteratedCache *cache) {
 
         return mfree(cache);
 }
+
+int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret) {
+        size_t separator_len, allocated = 0, len = 0;
+        _cleanup_free_ char *str = NULL;
+        const char *value;
+        bool first;
+
+        assert(ret);
+
+        if (set_isempty(s)) {
+                *ret = NULL;
+                return 0;
+        }
+
+        separator_len = strlen_ptr(separator);
+
+        if (separator_len == 0)
+                wrap_with_separator = false;
+
+        first = !wrap_with_separator;
+
+        SET_FOREACH(value, s) {
+                size_t l = strlen_ptr(value);
+
+                if (l == 0)
+                        continue;
+
+                if (!GREEDY_REALLOC(str, allocated, len + l + (first ? 0 : separator_len) + (wrap_with_separator ? separator_len : 0) + 1))
+                        return -ENOMEM;
+
+                if (separator_len > 0 && !first) {
+                        memcpy(str + len, separator, separator_len);
+                        len += separator_len;
+                }
+
+                memcpy(str + len, value, l);
+                len += l;
+                first = false;
+        }
+
+        if (wrap_with_separator) {
+                memcpy(str + len, separator, separator_len);
+                len += separator_len;
+        }
+
+        str[len] = '\0';
+
+        *ret = TAKE_PTR(str);
+        return 0;
+}
diff --git a/shared/systemd/src/basic/hashmap.h b/shared/systemd/src/basic/hashmap.h
index 890f90a9..e9944837 100644
--- a/shared/systemd/src/basic/hashmap.h
+++ b/shared/systemd/src/basic/hashmap.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <limits.h>
@@ -153,8 +153,9 @@ static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *
         return hashmap_put(PLAIN_HASHMAP(h), key, value);
 }
 
-int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v  HASHMAP_DEBUG_PARAMS);
-#define hashmap_put_strdup(h, k, v) _hashmap_put_strdup(h, k, v  HASHMAP_DEBUG_SRC_ARGS)
+int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v  HASHMAP_DEBUG_PARAMS);
+#define hashmap_put_strdup_full(h, hash_ops, k, v) _hashmap_put_strdup_full(h, hash_ops, k, v  HASHMAP_DEBUG_SRC_ARGS)
+#define hashmap_put_strdup(h, k, v) hashmap_put_strdup_full(h, &string_hash_ops_free_free, k, v)
 
 int hashmap_update(Hashmap *h, const void *key, void *value);
 static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
diff --git a/shared/systemd/src/basic/hexdecoct.c b/shared/systemd/src/basic/hexdecoct.c
index 1fb52305..78930b32 100644
--- a/shared/systemd/src/basic/hexdecoct.c
+++ b/shared/systemd/src/basic/hexdecoct.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/hexdecoct.h b/shared/systemd/src/basic/hexdecoct.h
index dfdff1e9..7e2a6892 100644
--- a/shared/systemd/src/basic/hexdecoct.h
+++ b/shared/systemd/src/basic/hexdecoct.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>
diff --git a/shared/systemd/src/basic/hostname-util.c b/shared/systemd/src/basic/hostname-util.c
index 82fc56db..a3cdc62e 100644
--- a/shared/systemd/src/basic/hostname-util.c
+++ b/shared/systemd/src/basic/hostname-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -9,29 +9,11 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
-#include "fd-util.h"
-#include "fileio.h"
 #include "hostname-util.h"
-#include "macro.h"
 #include "string-util.h"
 #include "strv.h"
 
 #if 0 /* NM_IGNORED */
-bool hostname_is_set(void) {
-        struct utsname u;
-
-        assert_se(uname(&u) >= 0);
-
-        if (isempty(u.nodename))
-                return false;
-
-        /* This is the built-in kernel default hostname */
-        if (streq(u.nodename, "(none)"))
-                return false;
-
-        return true;
-}
-
 char* gethostname_malloc(void) {
         struct utsname u;
         const char *s;
@@ -93,6 +75,8 @@ int gethostname_strict(char **ret) {
 }
 
 bool valid_ldh_char(char c) {
+        /* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */
+
         return
                 (c >= 'a' && c <= 'z') ||
                 (c >= 'A' && c <= 'Z') ||
@@ -100,28 +84,24 @@ bool valid_ldh_char(char c) {
                 c == '-';
 }
 
-/**
- * Check if s looks like a valid hostname or FQDN. This does not do
- * full DNS validation, but only checks if the name is composed of
- * allowed characters and the length is not above the maximum allowed
- * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
- * allow_trailing_dot is true and at least two components are present
- * in the name. Note that due to the restricted charset and length
- * this call is substantially more conservative than
- * dns_name_is_valid().
- */
-bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
+bool hostname_is_valid(const char *s, ValidHostnameFlags flags) {
         unsigned n_dots = 0;
         const char *p;
         bool dot, hyphen;
 
+        /* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only
+         * checks if the name is composed of allowed characters and the length is not above the maximum
+         * allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if
+         * VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note
+         * that due to the restricted charset and length this call is substantially more conservative than
+         * dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames
+         * with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */
+
         if (isempty(s))
                 return false;
 
-        /* Doesn't accept empty hostnames, hostnames with
-         * leading dots, and hostnames with multiple dots in a
-         * sequence. Also ensures that the length stays below
-         * HOST_NAME_MAX. */
+        if (streq(s, ".host")) /* Used by the container logic to denote the "root container" */
+                return FLAGS_SET(flags, VALID_HOSTNAME_DOT_HOST);
 
         for (p = s, dot = hyphen = true; *p; p++)
                 if (*p == '.') {
@@ -147,14 +127,13 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
                         hyphen = false;
                 }
 
-        if (dot && (n_dots < 2 || !allow_trailing_dot))
+        if (dot && (n_dots < 2 || !FLAGS_SET(flags, VALID_HOSTNAME_TRAILING_DOT)))
                 return false;
         if (hyphen)
                 return false;
 
-        if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
-                                  * Linux, but DNS allows domain names
-                                  * up to 255 characters */
+        if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to
+                                  * 255 characters */
                 return false;
 
         return true;
@@ -215,121 +194,3 @@ bool is_localhost(const char *hostname) {
                 endswith_no_case(hostname, ".localhost.localdomain") ||
                 endswith_no_case(hostname, ".localhost.localdomain.");
 }
-
-#if 0 /* NM_IGNORED */
-bool is_gateway_hostname(const char *hostname) {
-        assert(hostname);
-
-        /* This tries to identify the valid syntaxes for the our
-         * synthetic "gateway" host. */
-
-        return
-                strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.")
-#if ENABLE_COMPAT_GATEWAY_HOSTNAME
-                || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.")
-#endif
-                ;
-}
-
-int sethostname_idempotent(const char *s) {
-        char buf[HOST_NAME_MAX + 1] = {};
-
-        assert(s);
-
-        if (gethostname(buf, sizeof(buf)) < 0)
-                return -errno;
-
-        if (streq(buf, s))
-                return 0;
-
-        if (sethostname(s, strlen(s)) < 0)
-                return -errno;
-
-        return 1;
-}
-
-int shorten_overlong(const char *s, char **ret) {
-        char *h, *p;
-
-        /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
-         * whatever comes earlier. */
-
-        assert(s);
-
-        h = strdup(s);
-        if (!h)
-                return -ENOMEM;
-
-        if (hostname_is_valid(h, false)) {
-                *ret = h;
-                return 0;
-        }
-
-        p = strchr(h, '.');
-        if (p)
-                *p = 0;
-
-        strshorten(h, HOST_NAME_MAX);
-
-        if (!hostname_is_valid(h, false)) {
-                free(h);
-                return -EDOM;
-        }
-
-        *ret = h;
-        return 1;
-}
-
-int read_etc_hostname_stream(FILE *f, char **ret) {
-        int r;
-
-        assert(f);
-        assert(ret);
-
-        for (;;) {
-                _cleanup_free_ char *line = NULL;
-                char *p;
-
-                r = read_line(f, LONG_LINE_MAX, &line);
-                if (r < 0)
-                        return r;
-                if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
-                        return -ENOENT;
-
-                p = strstrip(line);
-
-                /* File may have empty lines or comments, ignore them */
-                if (!IN_SET(*p, '\0', '#')) {
-                        char *copy;
-
-                        hostname_cleanup(p); /* normalize the hostname */
-
-                        if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */
-                                return -EBADMSG;
-
-                        copy = strdup(p);
-                        if (!copy)
-                                return -ENOMEM;
-
-                        *ret = copy;
-                        return 0;
-                }
-        }
-}
-
-int read_etc_hostname(const char *path, char **ret) {
-        _cleanup_fclose_ FILE *f = NULL;
-
-        assert(ret);
-
-        if (!path)
-                path = "/etc/hostname";
-
-        f = fopen(path, "re");
-        if (!f)
-                return -errno;
-
-        return read_etc_hostname_stream(f, ret);
-
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/hostname-util.h b/shared/systemd/src/basic/hostname-util.h
index cafd6f02..6cff9c1d 100644
--- a/shared/systemd/src/basic/hostname-util.h
+++ b/shared/systemd/src/basic/hostname-util.h
@@ -1,29 +1,29 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>
 #include <stdio.h>
 
 #include "macro.h"
-
-bool hostname_is_set(void);
+#include "strv.h"
 
 char* gethostname_malloc(void);
 char* gethostname_short_malloc(void);
 int gethostname_strict(char **ret);
 
 bool valid_ldh_char(char c) _const_;
-bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_;
-char* hostname_cleanup(char *s);
-
-#define machine_name_is_valid(s) hostname_is_valid(s, false)
 
-bool is_localhost(const char *hostname);
-bool is_gateway_hostname(const char *hostname);
+typedef enum ValidHostnameFlags {
+        VALID_HOSTNAME_TRAILING_DOT = 1 << 0,   /* Accept trailing dot on multi-label names */
+        VALID_HOSTNAME_DOT_HOST     = 1 << 1,   /* Accept ".host" as valid hostname */
+} ValidHostnameFlags;
 
-int sethostname_idempotent(const char *s);
+bool hostname_is_valid(const char *s, ValidHostnameFlags flags) _pure_;
+char* hostname_cleanup(char *s);
 
-int shorten_overlong(const char *s, char **ret);
+bool is_localhost(const char *hostname);
 
-int read_etc_hostname_stream(FILE *f, char **ret);
-int read_etc_hostname(const char *path, char **ret);
+static inline bool is_gateway_hostname(const char *hostname) {
+        /* This tries to identify the valid syntaxes for the our synthetic "gateway" host. */
+        return STRCASE_IN_SET(hostname, "_gateway", "_gateway.");
+}
diff --git a/shared/systemd/src/basic/in-addr-util.c b/shared/systemd/src/basic/in-addr-util.c
index 1ea3e7ff..c315dcbb 100644
--- a/shared/systemd/src/basic/in-addr-util.c
+++ b/shared/systemd/src/basic/in-addr-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/in-addr-util.h b/shared/systemd/src/basic/in-addr-util.h
index 45c93a00..24308b70 100644
--- a/shared/systemd/src/basic/in-addr-util.h
+++ b/shared/systemd/src/basic/in-addr-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <netinet/in.h>
diff --git a/shared/systemd/src/basic/io-util.c b/shared/systemd/src/basic/io-util.c
index 8b0e354a..f09c7fdd 100644
--- a/shared/systemd/src/basic/io-util.c
+++ b/shared/systemd/src/basic/io-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -298,7 +298,7 @@ int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len) {
                 return -E2BIG;
 
         if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
-                return log_oom();
+                return -ENOMEM;
 
         iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len);
         return 0;
@@ -310,7 +310,7 @@ int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const c
 
         x = strjoin(field, value);
         if (!x)
-                return log_oom();
+                return -ENOMEM;
 
         r = iovw_put(iovw, x, strlen(x));
         if (r >= 0)
diff --git a/shared/systemd/src/basic/io-util.h b/shared/systemd/src/basic/io-util.h
index 719e19e8..d817714b 100644
--- a/shared/systemd/src/basic/io-util.h
+++ b/shared/systemd/src/basic/io-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>
diff --git a/shared/systemd/src/basic/list.h b/shared/systemd/src/basic/list.h
index b62c3749..256b7187 100644
--- a/shared/systemd/src/basic/list.h
+++ b/shared/systemd/src/basic/list.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include "macro.h"
diff --git a/shared/systemd/src/basic/log.h b/shared/systemd/src/basic/log.h
index c2ffbb5d..ee2e4839 100644
--- a/shared/systemd/src/basic/log.h
+++ b/shared/systemd/src/basic/log.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdarg.h>
@@ -44,10 +44,17 @@ typedef enum LogTarget{
 #define ERRNO_VALUE(val)                    (abs(val) & 255)
 
 void log_set_target(LogTarget target);
+
 void log_set_max_level_realm(LogRealm realm, int level);
+
 #define log_set_max_level(level)                \
         log_set_max_level_realm(LOG_REALM, (level))
 
+static inline void log_set_max_level_all_realms(int level) {
+        for (LogRealm realm = 0; realm < _LOG_REALM_MAX; realm++)
+                log_set_max_level_realm(realm, level);
+}
+
 void log_set_facility(int facility);
 
 int log_set_target_from_string(const char *e);
@@ -122,6 +129,31 @@ int log_internal_realm(
 #define log_internal(level, ...) \
         log_internal_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__)
 
+#define log_object_internal(level,              \
+                            error,              \
+                            file,               \
+                            line,               \
+                            func,               \
+                            object_field,       \
+                            object,             \
+                            extra_field,        \
+                            extra,              \
+                            format,             \
+                            ...)                \
+    ({                                          \
+        const char *const _object = (object);   \
+                                                \
+        log_internal_realm((level),             \
+                           (error),             \
+                           file,                \
+                           (line),              \
+                           (func),              \
+                           "%s%s" format,       \
+                           _object ?: "",       \
+                           _object ? ": " : "", \
+                           ##__VA_ARGS__);        \
+    })
+
 #if 0 /* NM_IGNORED */
 int log_internalv_realm(
                 int level,
@@ -169,7 +201,7 @@ int log_struct_internal(
                 const char *format, ...) _printf_(6,0) _sentinel_;
 
 int log_oom_internal(
-                LogRealm realm,
+                int level,
                 const char *file,
                 int line,
                 const char *func);
@@ -293,7 +325,8 @@ int log_emergency_level(void);
         log_dump_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
                           0, PROJECT_FILE, __LINE__, __func__, buffer)
 
-#define log_oom() log_oom_internal(LOG_REALM, PROJECT_FILE, __LINE__, __func__)
+#define log_oom() log_oom_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, LOG_ERR), PROJECT_FILE, __LINE__, __func__)
+#define log_oom_debug() log_oom_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, LOG_DEBUG), PROJECT_FILE, __LINE__, __func__)
 
 bool log_on_console(void) _pure_;
 
diff --git a/shared/systemd/src/basic/macro.h b/shared/systemd/src/basic/macro.h
index f872d41f..34416b3d 100644
--- a/shared/systemd/src/basic/macro.h
+++ b/shared/systemd/src/basic/macro.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <assert.h>
@@ -94,6 +94,10 @@
 
 #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\"")
@@ -286,6 +290,12 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
                 MAX(_c, z);                             \
         })
 
+#define MAX4(x, y, z, a)                                \
+        ({                                              \
+                const typeof(x) _d = MAX3(x, y, z);     \
+                MAX(_d, a);                             \
+        })
+
 #undef MIN
 #define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
 #define __MIN(aq, a, bq, b)                             \
@@ -449,6 +459,9 @@ static inline int __coverity_check_and_return__(int condition) {
 #define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p)))
 #define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u)))
 
+#define PTR_TO_UINT8(p) ((uint8_t) ((uintptr_t) (p)))
+#define UINT8_TO_PTR(u) ((void *) ((uintptr_t) (u)))
+
 #define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p)))
 #define INT32_TO_PTR(u) ((void *) ((intptr_t) (u)))
 #define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
@@ -550,10 +563,13 @@ static inline int __coverity_check_and_return__(int condition) {
 #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
 #define STRV_MAKE_EMPTY ((char*[1]) { NULL })
 
-/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses (void*) -1 as internal marker for EOL. */
-#define FOREACH_POINTER(p, x, ...)                                                      \
-        for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, (void*) -1 }; \
-             p != (typeof(p)) (void*) -1;                                               \
+/* Pointers range from NULL to POINTER_MAX */
+#define POINTER_MAX ((void*) UINTPTR_MAX)
+
+/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses POINTER_MAX as internal marker for EOL. */
+#define FOREACH_POINTER(p, x, ...)                                                       \
+        for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, POINTER_MAX }; \
+             p != (typeof(p)) POINTER_MAX;                                               \
              p = *(++_l))
 
 /* Define C11 thread_local attribute even on older gcc compiler
@@ -643,4 +659,8 @@ static inline int __coverity_check_and_return__(int condition) {
                 _copy;                                                  \
         })
 
+static inline size_t size_add(size_t x, size_t y) {
+        return y >= SIZE_MAX - x ? SIZE_MAX : x + y;
+}
+
 #include "log.h"
diff --git a/shared/systemd/src/basic/memory-util.c b/shared/systemd/src/basic/memory-util.c
index bd1f5d73..7ee7c94e 100644
--- a/shared/systemd/src/basic/memory-util.c
+++ b/shared/systemd/src/basic/memory-util.c
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
 #include "nm-sd-adapt-shared.h"
 
 #include <unistd.h>
diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h
index 4f596cff..179edd24 100644
--- a/shared/systemd/src/basic/memory-util.h
+++ b/shared/systemd/src/basic/memory-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <inttypes.h>
diff --git a/shared/systemd/src/basic/mempool.c b/shared/systemd/src/basic/mempool.c
index 8b8337db..46c44914 100644
--- a/shared/systemd/src/basic/mempool.c
+++ b/shared/systemd/src/basic/mempool.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/mempool.h b/shared/systemd/src/basic/mempool.h
index 0eecca0f..0fe2f278 100644
--- a/shared/systemd/src/basic/mempool.h
+++ b/shared/systemd/src/basic/mempool.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>
diff --git a/shared/systemd/src/basic/missing_fcntl.h b/shared/systemd/src/basic/missing_fcntl.h
index 5d1c6352..00937d2a 100644
--- a/shared/systemd/src/basic/missing_fcntl.h
+++ b/shared/systemd/src/basic/missing_fcntl.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <fcntl.h>
diff --git a/shared/systemd/src/basic/missing_random.h b/shared/systemd/src/basic/missing_random.h
index 17af87a3..443b9136 100644
--- a/shared/systemd/src/basic/missing_random.h
+++ b/shared/systemd/src/basic/missing_random.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #if USE_SYS_RANDOM_H
diff --git a/shared/systemd/src/basic/missing_socket.h b/shared/systemd/src/basic/missing_socket.h
index fe4d35bd..a4f6836f 100644
--- a/shared/systemd/src/basic/missing_socket.h
+++ b/shared/systemd/src/basic/missing_socket.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <sys/socket.h>
@@ -69,6 +69,14 @@ struct sockaddr_vm {
 #define IPV6_FREEBIND 78
 #endif
 
+#ifndef IP_RECVFRAGSIZE
+#define IP_RECVFRAGSIZE 25
+#endif
+
+#ifndef IPV6_RECVFRAGSIZE
+#define IPV6_RECVFRAGSIZE 77
+#endif
+
 /* linux/sockios.h */
 #ifndef SIOCGSKNS
 #define SIOCGSKNS 0x894C
diff --git a/shared/systemd/src/basic/missing_stat.h b/shared/systemd/src/basic/missing_stat.h
index 5d59a214..9c1df698 100644
--- a/shared/systemd/src/basic/missing_stat.h
+++ b/shared/systemd/src/basic/missing_stat.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <linux/types.h>
diff --git a/shared/systemd/src/basic/missing_syscall.h b/shared/systemd/src/basic/missing_syscall.h
index d11a77d5..42d64753 100644
--- a/shared/systemd/src/basic/missing_syscall.h
+++ b/shared/systemd/src/basic/missing_syscall.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 /* Missing glibc definitions to access certain kernel APIs */
@@ -15,6 +15,26 @@
 #include <asm/sgidefs.h>
 #endif
 
+#if defined(__alpha__)
+#  define systemd_SC_arch_bias(x) (110 + (x))
+#elif defined(__ia64__)
+#  define systemd_SC_arch_bias(x) (1024 + (x))
+#elif defined(_MIPS_SIM)
+#  if _MIPS_SIM == _MIPS_SIM_ABI32
+#    define systemd_SC_arch_bias(x) (4000 + (x))
+#  elif _MIPS_SIM == _MIPS_SIM_NABI32
+#    define systemd_SC_arch_bias(x) (6000 + (x))
+#  elif _MIPS_SIM == _MIPS_SIM_ABI64
+#    define systemd_SC_arch_bias(x) (5000 + (x))
+#  else
+#    error "Unknown MIPS ABI"
+#  endif
+#elif defined(__x86_64__) && defined(__ILP32__)
+#  define systemd_SC_arch_bias(x) ((x) | /* __X32_SYSCALL_BIT */ 0x40000000)
+#else
+#  define systemd_SC_arch_bias(x) (x)
+#endif
+
 #include "missing_keyctl.h"
 #include "missing_stat.h"
 
@@ -35,32 +55,38 @@ static inline int missing_pivot_root(const char *new_root, const char *put_old)
 
 /* ======================================================================= */
 
-#if defined __x86_64__
-#  define systemd_NR_memfd_create 319
-#elif defined __arm__
-#  define systemd_NR_memfd_create 385
-#elif defined __aarch64__
+#if defined(__aarch64__)
 #  define systemd_NR_memfd_create 279
+#elif defined(__alpha__)
+#  define systemd_NR_memfd_create 512
+#elif defined(__arc__) || defined(__tilegx__)
+#  define systemd_NR_memfd_create 279
+#elif defined(__arm__)
+#  define systemd_NR_memfd_create 385
+#elif defined(__i386__)
+#  define systemd_NR_memfd_create 356
+#elif defined(__ia64__)
+#  define systemd_NR_memfd_create systemd_SC_arch_bias(316)
+#elif defined(__m68k__)
+#  define systemd_NR_memfd_create 353
+#elif defined(_MIPS_SIM)
+#  if _MIPS_SIM == _MIPS_SIM_ABI32
+#    define systemd_NR_memfd_create systemd_SC_arch_bias(354)
+#  elif _MIPS_SIM == _MIPS_SIM_NABI32
+#    define systemd_NR_memfd_create systemd_SC_arch_bias(318)
+#  elif _MIPS_SIM == _MIPS_SIM_ABI64
+#    define systemd_NR_memfd_create systemd_SC_arch_bias(314)
+#  endif
 #elif defined(__powerpc__)
 #  define systemd_NR_memfd_create 360
-#elif defined __s390__
+#elif defined(__s390__)
 #  define systemd_NR_memfd_create 350
-#elif defined _MIPS_SIM
-#  if _MIPS_SIM == _MIPS_SIM_ABI32
-#    define systemd_NR_memfd_create 4354
-#  endif
-#  if _MIPS_SIM == _MIPS_SIM_NABI32
-#    define systemd_NR_memfd_create 6318
-#  endif
-#  if _MIPS_SIM == _MIPS_SIM_ABI64
-#    define systemd_NR_memfd_create 5314
-#  endif
-#elif defined __i386__
-#  define systemd_NR_memfd_create 356
-#elif defined __arc__
-#  define systemd_NR_memfd_create 279
+#elif defined(__sparc__)
+#  define systemd_NR_memfd_create 348
+#elif defined(__x86_64__)
+#  define systemd_NR_memfd_create systemd_SC_arch_bias(319)
 #else
-#  warning "memfd_create() syscall number unknown for your architecture"
+#  warning "memfd_create() syscall number is unknown for your architecture"
 #endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -92,36 +118,38 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) {
 
 /* ======================================================================= */
 
-#if defined __x86_64__
-#  define systemd_NR_getrandom 318
-#elif defined(__i386__)
-#  define systemd_NR_getrandom 355
+#if defined(__aarch64__)
+#  define systemd_NR_getrandom 278
+#elif defined(__alpha__)
+#  define systemd_NR_getrandom 511
+#elif defined(__arc__) || defined(__tilegx__)
+#  define systemd_NR_getrandom 278
 #elif defined(__arm__)
 #  define systemd_NR_getrandom 384
-#elif defined(__aarch64__)
-#  define systemd_NR_getrandom 278
+#elif defined(__i386__)
+#  define systemd_NR_getrandom 355
 #elif defined(__ia64__)
-#  define systemd_NR_getrandom 1339
+#  define systemd_NR_getrandom systemd_SC_arch_bias(318)
 #elif defined(__m68k__)
 #  define systemd_NR_getrandom 352
-#elif defined(__s390x__)
-#  define systemd_NR_getrandom 349
-#elif defined(__powerpc__)
-#  define systemd_NR_getrandom 359
-#elif defined _MIPS_SIM
+#elif defined(_MIPS_SIM)
 #  if _MIPS_SIM == _MIPS_SIM_ABI32
-#    define systemd_NR_getrandom 4353
-#  endif
-#  if _MIPS_SIM == _MIPS_SIM_NABI32
-#    define systemd_NR_getrandom 6317
+#    define systemd_NR_getrandom systemd_SC_arch_bias(353)
+#  elif _MIPS_SIM == _MIPS_SIM_NABI32
+#    define systemd_NR_getrandom systemd_SC_arch_bias(317)
+#  elif _MIPS_SIM == _MIPS_SIM_ABI64
+#    define systemd_NR_getrandom systemd_SC_arch_bias(313)
 #  endif
-#  if _MIPS_SIM == _MIPS_SIM_ABI64
-#    define systemd_NR_getrandom 5313
-#  endif
-#elif defined(__arc__)
-#  define systemd_NR_getrandom 278
+#elif defined(__powerpc__)
+#  define systemd_NR_getrandom 359
+#elif defined(__s390__)
+#  define systemd_NR_getrandom 349
+#elif defined(__sparc__)
+#  define systemd_NR_getrandom 347
+#elif defined(__x86_64__)
+#  define systemd_NR_getrandom systemd_SC_arch_bias(318)
 #else
-#  warning "getrandom() syscall number unknown for your architecture"
+#  warning "getrandom() syscall number is unknown for your architecture"
 #endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -168,22 +196,38 @@ static inline pid_t missing_gettid(void) {
 
 /* ======================================================================= */
 
-#if defined(__x86_64__)
-#  define systemd_NR_name_to_handle_at 303
-#elif defined(__i386__)
-#  define systemd_NR_name_to_handle_at 341
+#if defined(__aarch64__)
+#  define systemd_NR_name_to_handle_at 264
+#elif defined(__alpha__)
+#  define systemd_NR_name_to_handle_at 497
+#elif defined(__arc__) || defined(__tilegx__)
+#  define systemd_NR_name_to_handle_at 264
 #elif defined(__arm__)
 #  define systemd_NR_name_to_handle_at 370
-#elif defined __aarch64__
-#  define systemd_NR_name_to_handle_at 264
+#elif defined(__i386__)
+#  define systemd_NR_name_to_handle_at 341
+#elif defined(__ia64__)
+#  define systemd_NR_name_to_handle_at systemd_SC_arch_bias(302)
+#elif defined(__m68k__)
+#  define systemd_NR_name_to_handle_at 340
+#elif defined(_MIPS_SIM)
+#  if _MIPS_SIM == _MIPS_SIM_ABI32
+#    define systemd_NR_name_to_handle_at systemd_SC_arch_bias(339)
+#  elif _MIPS_SIM == _MIPS_SIM_NABI32
+#    define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303)
+#  elif _MIPS_SIM == _MIPS_SIM_ABI64
+#    define systemd_NR_name_to_handle_at systemd_SC_arch_bias(298)
+#  endif
 #elif defined(__powerpc__)
 #  define systemd_NR_name_to_handle_at 345
-#elif defined __s390__ || defined __s390x__
+#elif defined(__s390__)
 #  define systemd_NR_name_to_handle_at 335
-#elif defined(__arc__)
-#  define systemd_NR_name_to_handle_at 264
+#elif defined(__sparc__)
+#  define systemd_NR_name_to_handle_at 332
+#elif defined(__x86_64__)
+#  define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303)
 #else
-#  warning "name_to_handle_at number is not defined"
+#  warning "name_to_handle_at() syscall number is unknown for your architecture"
 #endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -221,22 +265,38 @@ static inline int missing_name_to_handle_at(int fd, const char *name, struct fil
 
 /* ======================================================================= */
 
-#if defined __aarch64__
+#if defined(__aarch64__)
 #  define systemd_NR_setns 268
-#elif defined __arm__
+#elif defined(__alpha__)
+#  define systemd_NR_setns 501
+#elif defined(__arc__) || defined(__tilegx__)
+#  define systemd_NR_setns 268
+#elif defined(__arm__)
 #  define systemd_NR_setns 375
-#elif defined(__x86_64__)
-#  define systemd_NR_setns 308
 #elif defined(__i386__)
 #  define systemd_NR_setns 346
+#elif defined(__ia64__)
+#  define systemd_NR_setns systemd_SC_arch_bias(306)
+#elif defined(__m68k__)
+#  define systemd_NR_setns 344
+#elif defined(_MIPS_SIM)
+#  if _MIPS_SIM == _MIPS_SIM_ABI32
+#    define systemd_NR_setns systemd_SC_arch_bias(344)
+#  elif _MIPS_SIM == _MIPS_SIM_NABI32
+#    define systemd_NR_setns systemd_SC_arch_bias(308)
+#  elif _MIPS_SIM == _MIPS_SIM_ABI64
+#    define systemd_NR_setns systemd_SC_arch_bias(303)
+#  endif
 #elif defined(__powerpc__)
 #  define systemd_NR_setns 350
-#elif defined __s390__ || defined __s390x__
+#elif defined(__s390__)
 #  define systemd_NR_setns 339
-#elif defined(__arc__)
-#  define systemd_NR_setns 268
+#elif defined(__sparc__)
+#  define systemd_NR_setns 337
+#elif defined(__x86_64__)
+#  define systemd_NR_setns systemd_SC_arch_bias(308)
 #else
-#  warning "setns() syscall number unknown for your architecture"
+#  warning "setns() syscall number is unknown for your architecture"
 #endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -278,32 +338,38 @@ static inline pid_t raw_getpid(void) {
 
 /* ======================================================================= */
 
-#if defined __x86_64__
-#  define systemd_NR_renameat2 316
-#elif defined __arm__
-#  define systemd_NR_renameat2 382
-#elif defined __aarch64__
+#if defined(__aarch64__)
 #  define systemd_NR_renameat2 276
-#elif defined _MIPS_SIM
+#elif defined(__alpha__)
+#  define systemd_NR_renameat2 510
+#elif defined(__arc__) || defined(__tilegx__)
+#  define systemd_NR_renameat2 276
+#elif defined(__arm__)
+#  define systemd_NR_renameat2 382
+#elif defined(__i386__)
+#  define systemd_NR_renameat2 353
+#elif defined(__ia64__)
+#  define systemd_NR_renameat2 systemd_SC_arch_bias(314)
+#elif defined(__m68k__)
+#  define systemd_NR_renameat2 351
+#elif defined(_MIPS_SIM)
 #  if _MIPS_SIM == _MIPS_SIM_ABI32
-#    define systemd_NR_renameat2 4351
+#    define systemd_NR_renameat2 systemd_SC_arch_bias(351)
+#  elif _MIPS_SIM == _MIPS_SIM_NABI32
+#    define systemd_NR_renameat2 systemd_SC_arch_bias(315)
+#  elif _MIPS_SIM == _MIPS_SIM_ABI64
+#    define systemd_NR_renameat2 systemd_SC_arch_bias(311)
 #  endif
-#  if _MIPS_SIM == _MIPS_SIM_NABI32
-#    define systemd_NR_renameat2 6315
-#  endif
-#  if _MIPS_SIM == _MIPS_SIM_ABI64
-#    define systemd_NR_renameat2 5311
-#  endif
-#elif defined __i386__
-#  define systemd_NR_renameat2 353
-#elif defined __powerpc64__
+#elif defined(__powerpc__)
 #  define systemd_NR_renameat2 357
-#elif defined __s390__ || defined __s390x__
+#elif defined(__s390__)
 #  define systemd_NR_renameat2 347
-#elif defined __arc__
-#  define systemd_NR_renameat2 276
+#elif defined(__sparc__)
+#  define systemd_NR_renameat2 345
+#elif defined(__x86_64__)
+#  define systemd_NR_renameat2 systemd_SC_arch_bias(316)
 #else
-#  warning "renameat2() syscall number unknown for your architecture"
+#  warning "renameat2() syscall number is unknown for your architecture"
 #endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -387,22 +453,38 @@ static inline key_serial_t missing_request_key(const char *type, const char *des
 
 /* ======================================================================= */
 
-#if defined(__x86_64__)
-#  define systemd_NR_copy_file_range 326
+#if defined(__aarch64__)
+#  define systemd_NR_copy_file_range 285
+#elif defined(__alpha__)
+#  define systemd_NR_copy_file_range 519
+#elif defined(__arc__) || defined(__tilegx__)
+#  define systemd_NR_copy_file_range 285
+#elif defined(__arm__)
+#  define systemd_NR_copy_file_range 391
 #elif defined(__i386__)
 #  define systemd_NR_copy_file_range 377
-#elif defined __s390__
-#  define systemd_NR_copy_file_range 375
-#elif defined __arm__
-#  define systemd_NR_copy_file_range 391
-#elif defined __aarch64__
-#  define systemd_NR_copy_file_range 285
-#elif defined __powerpc__
+#elif defined(__ia64__)
+#  define systemd_NR_copy_file_range systemd_SC_arch_bias(323)
+#elif defined(__m68k__)
+#  define systemd_NR_copy_file_range 376
+#elif defined(_MIPS_SIM)
+#  if _MIPS_SIM == _MIPS_SIM_ABI32
+#    define systemd_NR_copy_file_range systemd_SC_arch_bias(360)
+#  elif _MIPS_SIM == _MIPS_SIM_NABI32
+#    define systemd_NR_copy_file_range systemd_SC_arch_bias(324)
+#  elif _MIPS_SIM == _MIPS_SIM_ABI64
+#    define systemd_NR_copy_file_range systemd_SC_arch_bias(320)
+#  endif
+#elif defined(__powerpc__)
 #  define systemd_NR_copy_file_range 379
-#elif defined __arc__
-#  define systemd_NR_copy_file_range 285
+#elif defined(__s390__)
+#  define systemd_NR_copy_file_range 375
+#elif defined(__sparc__)
+#  define systemd_NR_copy_file_range 357
+#elif defined(__x86_64__)
+#  define systemd_NR_copy_file_range systemd_SC_arch_bias(326)
 #else
-#  warning "copy_file_range() syscall number unknown for your architecture"
+#  warning "copy_file_range() syscall number is unknown for your architecture"
 #endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -437,24 +519,38 @@ static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in,
 
 /* ======================================================================= */
 
-#if defined __i386__
-#  define systemd_NR_bpf 357
-#elif defined __x86_64__
-#  define systemd_NR_bpf 321
-#elif defined __aarch64__
+#if defined(__aarch64__)
+#  define systemd_NR_bpf 280
+#elif defined(__alpha__)
+#  define systemd_NR_bpf 515
+#elif defined(__arc__) || defined(__tilegx__)
 #  define systemd_NR_bpf 280
-#elif defined __arm__
+#elif defined(__arm__)
 #  define systemd_NR_bpf 386
+#elif defined(__i386__)
+#  define systemd_NR_bpf 357
+#elif defined(__ia64__)
+#  define systemd_NR_bpf systemd_SC_arch_bias(317)
+#elif defined(__m68k__)
+#  define systemd_NR_bpf 354
+#elif defined(_MIPS_SIM)
+#  if _MIPS_SIM == _MIPS_SIM_ABI32
+#    define systemd_NR_bpf systemd_SC_arch_bias(355)
+#  elif _MIPS_SIM == _MIPS_SIM_NABI32
+#    define systemd_NR_bpf systemd_SC_arch_bias(319)
+#  elif _MIPS_SIM == _MIPS_SIM_ABI64
+#    define systemd_NR_bpf systemd_SC_arch_bias(315)
+#  endif
 #elif defined(__powerpc__)
 #  define systemd_NR_bpf 361
-#elif defined __sparc__
-#  define systemd_NR_bpf 349
-#elif defined __s390__
+#elif defined(__s390__)
 #  define systemd_NR_bpf 351
-#elif defined __tilegx__
-#  define systemd_NR_bpf 280
+#elif defined(__sparc__)
+#  define systemd_NR_bpf 349
+#elif defined(__x86_64__)
+#  define systemd_NR_bpf systemd_SC_arch_bias(321)
 #else
-#  warning "bpf() syscall number unknown for your architecture"
+#  warning "bpf() syscall number is unknown for your architecture"
 #endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -489,30 +585,38 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) {
 /* ======================================================================= */
 
 #ifndef __IGNORE_pkey_mprotect
-#  if defined __i386__
-#    define systemd_NR_pkey_mprotect 380
-#  elif defined __x86_64__
-#    define systemd_NR_pkey_mprotect 329
-#  elif defined __aarch64__
+#  if defined(__aarch64__)
 #    define systemd_NR_pkey_mprotect 288
-#  elif defined __arm__
+#  elif defined(__alpha__)
+#    define systemd_NR_pkey_mprotect 524
+#  elif defined(__arc__) || defined(__tilegx__)
+#    define systemd_NR_pkey_mprotect 226
+#  elif defined(__arm__)
 #    define systemd_NR_pkey_mprotect 394
-#  elif defined __powerpc__
-#    define systemd_NR_pkey_mprotect 386
-#  elif defined __s390__
-#    define systemd_NR_pkey_mprotect 384
-#  elif defined _MIPS_SIM
+#  elif defined(__i386__)
+#    define systemd_NR_pkey_mprotect 380
+#  elif defined(__ia64__)
+#    define systemd_NR_pkey_mprotect systemd_SC_arch_bias(330)
+#  elif defined(__m68k__)
+#    define systemd_NR_pkey_mprotect 381
+#  elif defined(_MIPS_SIM)
 #    if _MIPS_SIM == _MIPS_SIM_ABI32
-#      define systemd_NR_pkey_mprotect 4363
-#    endif
-#    if _MIPS_SIM == _MIPS_SIM_NABI32
-#      define systemd_NR_pkey_mprotect 6327
-#    endif
-#    if _MIPS_SIM == _MIPS_SIM_ABI64
-#      define systemd_NR_pkey_mprotect 5323
+#      define systemd_NR_pkey_mprotect systemd_SC_arch_bias(363)
+#    elif _MIPS_SIM == _MIPS_SIM_NABI32
+#      define systemd_NR_pkey_mprotect systemd_SC_arch_bias(327)
+#    elif _MIPS_SIM == _MIPS_SIM_ABI64
+#      define systemd_NR_pkey_mprotect systemd_SC_arch_bias(323)
 #    endif
+#  elif defined(__powerpc__)
+#    define systemd_NR_pkey_mprotect 386
+#  elif defined(__s390__)
+#    define systemd_NR_pkey_mprotect 384
+#  elif defined(__sparc__)
+#    define systemd_NR_pkey_mprotect 362
+#  elif defined(__x86_64__)
+#    define systemd_NR_pkey_mprotect systemd_SC_arch_bias(329)
 #  else
-#    warning "pkey_mprotect() syscall number unknown for your architecture"
+#    warning "pkey_mprotect() syscall number is unknown for your architecture"
 #  endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -532,22 +636,38 @@ assert_cc(__NR_pkey_mprotect == systemd_NR_pkey_mprotect);
 
 /* ======================================================================= */
 
-#if defined __aarch64__
+#if defined(__aarch64__)
 #  define systemd_NR_statx 291
-#elif defined __arm__
-#  define systemd_NR_statx 397
-#elif defined __alpha__
+#elif defined(__alpha__)
 #  define systemd_NR_statx 522
-#elif defined __i386__ || defined __powerpc64__
+#elif defined(__arc__) || defined(__tilegx__)
+#  define systemd_NR_statx 291
+#elif defined(__arm__)
+#  define systemd_NR_statx 397
+#elif defined(__i386__)
+#  define systemd_NR_statx 383
+#elif defined(__ia64__)
+#  define systemd_NR_statx systemd_SC_arch_bias(326)
+#elif defined(__m68k__)
+#  define systemd_NR_statx 379
+#elif defined(_MIPS_SIM)
+#  if _MIPS_SIM == _MIPS_SIM_ABI32
+#    define systemd_NR_statx systemd_SC_arch_bias(366)
+#  elif _MIPS_SIM == _MIPS_SIM_NABI32
+#    define systemd_NR_statx systemd_SC_arch_bias(330)
+#  elif _MIPS_SIM == _MIPS_SIM_ABI64
+#    define systemd_NR_statx systemd_SC_arch_bias(326)
+#  endif
+#elif defined(__powerpc__)
 #  define systemd_NR_statx 383
-#elif defined __s390__ || defined __s390x__
+#elif defined(__s390__)
 #  define systemd_NR_statx 379
-#elif defined __sparc__
+#elif defined(__sparc__)
 #  define systemd_NR_statx 360
-#elif defined __x86_64__
-#  define systemd_NR_statx 332
+#elif defined(__x86_64__)
+#  define systemd_NR_statx systemd_SC_arch_bias(332)
 #else
-#  warning "statx() syscall number unknown for your architecture"
+#  warning "statx() syscall number is unknown for your architecture"
 #endif
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -632,23 +752,7 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask,
 /* ======================================================================= */
 
 /* should be always defined, see kernel 39036cd2727395c3369b1051005da74059a85317 */
-#if defined __alpha__
-#  define systemd_NR_pidfd_send_signal 534
-#elif defined _MIPS_SIM
-#  if _MIPS_SIM == _MIPS_SIM_ABI32	/* o32 */
-#    define systemd_NR_pidfd_send_signal (424 + 4000)
-#  endif
-#  if _MIPS_SIM == _MIPS_SIM_NABI32	/* n32 */
-#    define systemd_NR_pidfd_send_signal (424 + 6000)
-#  endif
-#  if _MIPS_SIM == _MIPS_SIM_ABI64	/* n64 */
-#    define systemd_NR_pidfd_send_signal (424 + 5000)
-#  endif
-#elif defined __ia64__
-#  define systemd_NR_pidfd_send_signal (424 + 1024)
-#else
-#  define systemd_NR_pidfd_send_signal 424
-#endif
+#define systemd_NR_pidfd_send_signal systemd_SC_arch_bias(424)
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
 #if defined __NR_pidfd_send_signal && __NR_pidfd_send_signal >= 0
@@ -664,7 +768,7 @@ assert_cc(__NR_pidfd_send_signal == systemd_NR_pidfd_send_signal);
 
 #if !HAVE_PIDFD_SEND_SIGNAL
 static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) {
-#  ifdef __NR_pidfd_open
+#  ifdef __NR_pidfd_send_signal
         return syscall(__NR_pidfd_send_signal, fd, sig, info, flags);
 #  else
         errno = ENOSYS;
@@ -676,23 +780,7 @@ static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, un
 #endif
 
 /* should be always defined, see kernel 7615d9e1780e26e0178c93c55b73309a5dc093d7 */
-#if defined __alpha__
-#  define systemd_NR_pidfd_open 544
-#elif defined _MIPS_SIM
-#  if _MIPS_SIM == _MIPS_SIM_ABI32	/* o32 */
-#    define systemd_NR_pidfd_open (434 + 4000)
-#  endif
-#  if _MIPS_SIM == _MIPS_SIM_NABI32	/* n32 */
-#    define systemd_NR_pidfd_open (434 + 6000)
-#  endif
-#  if _MIPS_SIM == _MIPS_SIM_ABI64	/* n64 */
-#    define systemd_NR_pidfd_open (434 + 5000)
-#  endif
-#elif defined __ia64__
-#  define systemd_NR_pidfd_open (434 + 1024)
-#else
-#  define systemd_NR_pidfd_open 434
-#endif
+#define systemd_NR_pidfd_open systemd_SC_arch_bias(434)
 
 /* may be (invalid) negative number due to libseccomp, see PR 13319 */
 #if defined __NR_pidfd_open && __NR_pidfd_open >= 0
@@ -732,3 +820,70 @@ static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info)
 
 #  define rt_sigqueueinfo missing_rt_sigqueueinfo
 #endif
+
+/* ======================================================================= */
+
+#if 0 /* NM_IGNORED */
+#if !HAVE_EXECVEAT
+static inline int missing_execveat(int dirfd, const char *pathname,
+                                   char *const argv[], char *const envp[],
+                                   int flags) {
+#  if defined __NR_execveat && __NR_execveat >= 0
+        return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags);
+#  else
+        errno = ENOSYS;
+        return -1;
+#  endif
+}
+
+#  undef AT_EMPTY_PATH
+#  define AT_EMPTY_PATH 0x1000
+#  define execveat missing_execveat
+#endif
+
+/* ======================================================================= */
+
+#define systemd_NR_close_range systemd_SC_arch_bias(436)
+
+/* may be (invalid) negative number due to libseccomp, see PR 13319 */
+#if defined __NR_close_range && __NR_close_range >= 0
+#  if defined systemd_NR_close_range
+assert_cc(__NR_close_range == systemd_NR_close_range);
+#  endif
+#else
+#  if defined __NR_close_range
+#    undef __NR_close_range
+#  endif
+#  if defined systemd_NR_close_range
+#    define __NR_close_range systemd_NR_close_range
+#  endif
+#endif
+
+#if !HAVE_CLOSE_RANGE
+static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) {
+#  ifdef __NR_close_range
+        /* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
+         * userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to
+         * wrap this syscall, but let's assume it's going to be similar to what they do for close(),
+         * i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the
+         * userspace wrapper. There's only one caveat for this: unlike for close() there's the special
+         * UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse
+         * any other negative values. */
+        if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) {
+                errno = -EBADF;
+                return -1;
+        }
+
+        return syscall(__NR_close_range,
+                       (unsigned) first_fd,
+                       end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */
+                       flags);
+#  else
+        errno = ENOSYS;
+        return -1;
+#  endif
+}
+
+#  define close_range missing_close_range
+#endif
+#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/missing_type.h b/shared/systemd/src/basic/missing_type.h
index bf8a6caa..f6233090 100644
--- a/shared/systemd/src/basic/missing_type.h
+++ b/shared/systemd/src/basic/missing_type.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <uchar.h>
diff --git a/shared/systemd/src/basic/parse-util.c b/shared/systemd/src/basic/parse-util.c
index 6b47317a..d53bf620 100644
--- a/shared/systemd/src/basic/parse-util.c
+++ b/shared/systemd/src/basic/parse-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -867,4 +867,46 @@ int parse_oom_score_adjust(const char *s, int *ret) {
         *ret = v;
         return 0;
 }
+
+int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret) {
+        assert(ret);
+
+        if (i >= (~0UL << FSHIFT))
+                return -ERANGE;
+
+        i = i << FSHIFT;
+        f = DIV_ROUND_UP((f << FSHIFT), 100);
+
+        if (f >= FIXED_1)
+                return -ERANGE;
+
+        *ret = i | f;
+        return 0;
+}
+
+int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) {
+        const char *d, *f_str, *i_str;
+        unsigned long i, f;
+        int r;
+
+        assert(s);
+        assert(ret);
+
+        d = strchr(s, '.');
+        if (!d)
+                return -EINVAL;
+
+        i_str = strndupa(s, d - s);
+        f_str = d + 1;
+
+        r = safe_atolu_full(i_str, 10, &i);
+        if (r < 0)
+                return r;
+
+        r = safe_atolu_full(f_str, 10, &f);
+        if (r < 0)
+                return r;
+
+        return store_loadavg_fixed_point(i, f, ret);
+}
 #endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/parse-util.h b/shared/systemd/src/basic/parse-util.h
index 2cee65c4..ba4e727e 100644
--- a/shared/systemd/src/basic/parse-util.h
+++ b/shared/systemd/src/basic/parse-util.h
@@ -1,14 +1,19 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <inttypes.h>
 #include <limits.h>
+#if 0 /* NM_IGNORED */
+#include <linux/loadavg.h>
+#endif /* NM_IGNORED */
 #include <stddef.h>
 #include <stdint.h>
 #include <sys/types.h>
 
 #include "macro.h"
 
+typedef unsigned long loadavg_t;
+
 int parse_boolean(const char *v) _pure_;
 int parse_dev(const char *s, dev_t *ret);
 int parse_pid(const char *s, pid_t* ret_pid);
@@ -88,18 +93,18 @@ static inline int safe_atoux64(const char *s, uint64_t *ret) {
 }
 
 #if LONG_MAX == INT_MAX
-static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+static inline int safe_atolu_full(const char *s, unsigned base, long unsigned *ret_u) {
         assert_cc(sizeof(unsigned long) == sizeof(unsigned));
-        return safe_atou(s, (unsigned*) ret_u);
+        return safe_atou_full(s, base, (unsigned*) ret_u);
 }
 static inline int safe_atoli(const char *s, long int *ret_u) {
         assert_cc(sizeof(long int) == sizeof(int));
         return safe_atoi(s, (int*) ret_u);
 }
 #else
-static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+static inline int safe_atolu_full(const char *s, unsigned base, unsigned long *ret_u) {
         assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
-        return safe_atollu(s, (unsigned long long*) ret_u);
+        return safe_atollu_full(s, base, (unsigned long long*) ret_u);
 }
 static inline int safe_atoli(const char *s, long int *ret_u) {
         assert_cc(sizeof(long int) == sizeof(long long int));
@@ -107,6 +112,10 @@ static inline int safe_atoli(const char *s, long int *ret_u) {
 }
 #endif
 
+static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+        return safe_atolu_full(s, 0, ret_u);
+}
+
 #if SIZE_MAX == UINT_MAX
 static inline int safe_atozu(const char *s, size_t *ret_u) {
         assert_cc(sizeof(size_t) == sizeof(unsigned));
@@ -137,3 +146,8 @@ int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high);
 int parse_ip_prefix_length(const char *s, int *ret);
 
 int parse_oom_score_adjust(const char *s, int *ret);
+
+/* Given a Linux load average (e.g. decimal number 34.89 where 34 is passed as i and 89 is passed as f), convert it
+ * to a loadavg_t. */
+int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret);
+int parse_loadavg_fixed_point(const char *s, loadavg_t *ret);
diff --git a/shared/systemd/src/basic/path-util.c b/shared/systemd/src/basic/path-util.c
index 644829b2..ea44c32b 100644
--- a/shared/systemd/src/basic/path-util.c
+++ b/shared/systemd/src/basic/path-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -558,7 +558,7 @@ char* path_join_internal(const char *first, ...) {
 
         sz = strlen_ptr(first);
         va_start(ap, first);
-        while ((p = va_arg(ap, char*)) != (const char*) -1)
+        while ((p = va_arg(ap, char*)) != POINTER_MAX)
                 if (!isempty(p))
                         sz += 1 + strlen(p);
         va_end(ap);
@@ -578,7 +578,7 @@ char* path_join_internal(const char *first, ...) {
         }
 
         va_start(ap, first);
-        while ((p = va_arg(ap, char*)) != (const char*) -1) {
+        while ((p = va_arg(ap, char*)) != POINTER_MAX) {
                 if (isempty(p))
                         continue;
 
@@ -594,22 +594,53 @@ char* path_join_internal(const char *first, ...) {
 }
 
 #if 0 /* NM_IGNORED */
-int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
+static int check_x_access(const char *path, int *ret_fd) {
+        if (ret_fd) {
+                _cleanup_close_ int fd = -1;
+                int r;
+
+                /* We need to use O_PATH because there may be executables for which we have only exec
+                 * permissions, but not read (usually suid executables). */
+                fd = open(path, O_PATH|O_CLOEXEC);
+                if (fd < 0)
+                        return -errno;
+
+                r = access_fd(fd, X_OK);
+                if (r < 0)
+                        return r;
+
+                *ret_fd = TAKE_FD(fd);
+        } else {
+                /* Let's optimize things a bit by not opening the file if we don't need the fd. */
+                if (access(path, X_OK) < 0)
+                        return -errno;
+        }
+
+        return 0;
+}
+
+int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd) {
         int last_error, r;
         const char *p = NULL;
 
         assert(name);
 
         if (is_path(name)) {
-                if (access(name, X_OK) < 0)
-                        return -errno;
+                _cleanup_close_ int fd = -1;
 
-                if (ret) {
-                        r = path_make_absolute_cwd(name, ret);
+                r = check_x_access(name, ret_fd ? &fd : NULL);
+                if (r < 0)
+                        return r;
+
+                if (ret_filename) {
+                        r = path_make_absolute_cwd(name, ret_filename);
                         if (r < 0)
                                 return r;
                 }
 
+                if (ret_fd)
+                        *ret_fd = TAKE_FD(fd);
+
                 return 0;
         }
 
@@ -622,8 +653,10 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
 
         last_error = -ENOENT;
 
+        /* Resolve a single-component name to a full path */
         for (;;) {
                 _cleanup_free_ char *j = NULL, *element = NULL;
+                _cleanup_close_ int fd = -1;
 
                 r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
                 if (r < 0)
@@ -638,7 +671,8 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
                 if (!j)
                         return -ENOMEM;
 
-                if (access(j, X_OK) >= 0) {
+                r = check_x_access(j, ret_fd ? &fd : NULL);
+                if (r >= 0) {
                         _cleanup_free_ char *with_dash;
 
                         with_dash = strjoin(j, "/");
@@ -652,8 +686,10 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
                         /* We can't just `continue` inverting this case, since we need to update last_error. */
                         if (errno == ENOTDIR) {
                                 /* Found it! */
-                                if (ret)
-                                        *ret = path_simplify(TAKE_PTR(j), false);
+                                if (ret_filename)
+                                        *ret_filename = path_simplify(TAKE_PTR(j), false);
+                                if (ret_fd)
+                                        *ret_fd = TAKE_FD(fd);
 
                                 return 0;
                         }
diff --git a/shared/systemd/src/basic/path-util.h b/shared/systemd/src/basic/path-util.h
index 6c265519..988f058b 100644
--- a/shared/systemd/src/basic/path-util.h
+++ b/shared/systemd/src/basic/path-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <alloca.h>
@@ -64,7 +64,7 @@ int path_compare(const char *a, const char *b) _pure_;
 bool path_equal(const char *a, const char *b) _pure_;
 bool path_equal_or_files_same(const char *a, const char *b, int flags);
 char* path_join_internal(const char *first, ...);
-#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, (const char*) -1)
+#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, POINTER_MAX)
 
 char* path_simplify(char *path, bool kill_dots);
 
@@ -90,9 +90,9 @@ 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, bool use_path_envvar, char **ret);
-static inline int find_executable(const char *name, char **ret) {
-        return find_executable_full(name, true, ret);
+int find_executable_full(const char *name, 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, true, ret_filename, NULL);
 }
 
 bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
diff --git a/shared/systemd/src/basic/prioq.c b/shared/systemd/src/basic/prioq.c
index dc048cc7..19a9bc57 100644
--- a/shared/systemd/src/basic/prioq.c
+++ b/shared/systemd/src/basic/prioq.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 /*
  * Priority Queue
diff --git a/shared/systemd/src/basic/prioq.h b/shared/systemd/src/basic/prioq.h
index 1fb57bfa..951576c0 100644
--- a/shared/systemd/src/basic/prioq.h
+++ b/shared/systemd/src/basic/prioq.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>
diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c
index 03ca04e1..0e25b020 100644
--- a/shared/systemd/src/basic/process-util.c
+++ b/shared/systemd/src/basic/process-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/process-util.h b/shared/systemd/src/basic/process-util.h
index 314a8de1..aab2c7a1 100644
--- a/shared/systemd/src/basic/process-util.h
+++ b/shared/systemd/src/basic/process-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <errno.h>
diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c
index 9551e762..4f67d9af 100644
--- a/shared/systemd/src/basic/random-util.c
+++ b/shared/systemd/src/basic/random-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -462,10 +462,21 @@ size_t random_pool_size(void) {
 }
 
 int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
+        _cleanup_close_ int opened_fd = -1;
         int r;
 
-        assert(fd >= 0);
-        assert(seed && size > 0);
+        assert(seed || size == 0);
+
+        if (size == 0)
+                return 0;
+
+        if (fd < 0) {
+                opened_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
+                if (opened_fd < 0)
+                        return -errno;
+
+                fd = opened_fd;
+        }
 
         if (credit) {
                 _cleanup_free_ struct rand_pool_info *info = NULL;
@@ -491,6 +502,6 @@ int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
                         return r;
         }
 
-        return 0;
+        return 1;
 }
 #endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/random-util.h b/shared/systemd/src/basic/random-util.h
index 7824ffac..f661fc09 100644
--- a/shared/systemd/src/basic/random-util.h
+++ b/shared/systemd/src/basic/random-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>
diff --git a/shared/systemd/src/basic/ratelimit.c b/shared/systemd/src/basic/ratelimit.c
new file mode 100644
index 00000000..12c8324d
--- /dev/null
+++ b/shared/systemd/src/basic/ratelimit.c
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "nm-sd-adapt-shared.h"
+
+#include <sys/time.h>
+
+#include "macro.h"
+#include "ratelimit.h"
+
+/* Modelled after Linux' lib/ratelimit.c by Dave Young
+ * <hidave.darkstar@gmail.com>, which is licensed GPLv2. */
+
+bool ratelimit_below(RateLimit *r) {
+        usec_t ts;
+
+        assert(r);
+
+        if (!ratelimit_configured(r))
+                return true;
+
+        ts = now(CLOCK_MONOTONIC);
+
+        if (r->begin <= 0 ||
+            ts - r->begin > r->interval) {
+                r->begin = ts;
+
+                /* Reset counter */
+                r->num = 0;
+                goto good;
+        }
+
+        if (r->num < r->burst)
+                goto good;
+
+        return false;
+
+good:
+        r->num++;
+        return true;
+}
diff --git a/shared/systemd/src/basic/ratelimit.h b/shared/systemd/src/basic/ratelimit.h
new file mode 100644
index 00000000..ee1d17c0
--- /dev/null
+++ b/shared/systemd/src/basic/ratelimit.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdbool.h>
+
+#include "time-util.h"
+#include "util.h"
+
+typedef struct RateLimit {
+        usec_t interval; /* Keep those two fields first so they can be initialized easily: */
+        unsigned burst;  /*   RateLimit rl = { INTERVAL, BURST }; */
+        unsigned num;
+        usec_t begin;
+} RateLimit;
+
+static inline void ratelimit_reset(RateLimit *rl) {
+        rl->num = rl->begin = 0;
+}
+
+static inline bool ratelimit_configured(RateLimit *rl) {
+        return rl->interval > 0 && rl->burst > 0;
+}
+
+bool ratelimit_below(RateLimit *r);
diff --git a/shared/systemd/src/basic/set.h b/shared/systemd/src/basic/set.h
index 7170eea8..57ff7130 100644
--- a/shared/systemd/src/basic/set.h
+++ b/shared/systemd/src/basic/set.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include "extract-word.h"
@@ -128,10 +128,12 @@ int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key  HAS
 
 int set_consume(Set *s, void *value);
 
-int _set_put_strdup(Set **s, const char *p  HASHMAP_DEBUG_PARAMS);
-#define set_put_strdup(s, p) _set_put_strdup(s, p  HASHMAP_DEBUG_SRC_ARGS)
-int _set_put_strdupv(Set **s, char **l  HASHMAP_DEBUG_PARAMS);
-#define set_put_strdupv(s, l) _set_put_strdupv(s, l  HASHMAP_DEBUG_SRC_ARGS)
+int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p  HASHMAP_DEBUG_PARAMS);
+#define set_put_strdup_full(s, hash_ops, p) _set_put_strdup_full(s, hash_ops, p  HASHMAP_DEBUG_SRC_ARGS)
+#define set_put_strdup(s, p) set_put_strdup_full(s, &string_hash_ops_free, p)
+int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l  HASHMAP_DEBUG_PARAMS);
+#define set_put_strdupv_full(s, hash_ops, l) _set_put_strdupv_full(s, hash_ops, l  HASHMAP_DEBUG_SRC_ARGS)
+#define set_put_strdupv(s, l) set_put_strdupv_full(s, &string_hash_ops_free, l)
 
 int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags);
 
@@ -148,3 +150,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
 
 #define _cleanup_set_free_ _cleanup_(set_freep)
 #define _cleanup_set_free_free_ _cleanup_(set_free_freep)
+
+int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret);
diff --git a/shared/systemd/src/basic/signal-util.c b/shared/systemd/src/basic/signal-util.c
index a4b8163c..0c6f5818 100644
--- a/shared/systemd/src/basic/signal-util.c
+++ b/shared/systemd/src/basic/signal-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -52,16 +52,7 @@ static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
         int r = 0;
 
         /* negative signal ends the list. 0 signal is skipped. */
-
-        if (sig < 0)
-                return 0;
-
-        if (sig > 0) {
-                if (sigaction(sig, sa, NULL) < 0)
-                        r = -errno;
-        }
-
-        while ((sig = va_arg(ap, int)) >= 0) {
+        for (; sig >= 0; sig = va_arg(ap, int)) {
 
                 if (sig == 0)
                         continue;
diff --git a/shared/systemd/src/basic/signal-util.h b/shared/systemd/src/basic/signal-util.h
index 3909ee34..bdd39d42 100644
--- a/shared/systemd/src/basic/signal-util.h
+++ b/shared/systemd/src/basic/signal-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <signal.h>
diff --git a/shared/systemd/src/basic/siphash24.h b/shared/systemd/src/basic/siphash24.h
index 474d9c9d..e46f3cc5 100644
--- a/shared/systemd/src/basic/siphash24.h
+++ b/shared/systemd/src/basic/siphash24.h
@@ -1,11 +1,13 @@
+/* SPDX-License-Identifier: CC0-1.0 */
+
 #pragma once
 
 #include <inttypes.h>
 #include <stddef.h>
 #include <stdint.h>
-#include <string.h>
 #include <sys/types.h>
 
+#include "string-util.h"
 #include "time-util.h"
 
 #if 0 /* NM_IGNORED */
@@ -61,11 +63,15 @@ static inline void siphash24_compress_usec_t(usec_t in, struct siphash *state) {
         siphash24_compress(&in, sizeof in, state);
 }
 
-static inline void siphash24_compress_string(const char *in, struct siphash *state) {
-        if (!in)
+static inline void siphash24_compress_safe(const void *in, size_t inlen, struct siphash *state) {
+        if (inlen == 0)
                 return;
 
-        siphash24_compress(in, strlen(in), state);
+        siphash24_compress(in, inlen, state);
+}
+
+static inline void siphash24_compress_string(const char *in, struct siphash *state) {
+        siphash24_compress_safe(in, strlen_ptr(in), state);
 }
 
 uint64_t siphash24_finalize(struct siphash *state);
diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c
index 4d889e56..e224091d 100644
--- a/shared/systemd/src/basic/socket-util.c
+++ b/shared/systemd/src/basic/socket-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -27,10 +27,7 @@
 #include "format-util.h"
 #include "io-util.h"
 #include "log.h"
-#include "macro.h"
 #include "memory-util.h"
-#include "missing_socket.h"
-#include "missing_network.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -325,7 +322,7 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) {
 }
 
 int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
-        union sockaddr_union *sa = (union sockaddr_union*) _sa;
+        const union sockaddr_union *sa = (const union sockaddr_union*) _sa;
 
         /* Note, this returns the port as 'unsigned' rather than 'uint16_t', as AF_VSOCK knows larger ports */
 
@@ -350,6 +347,25 @@ int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
         }
 }
 
+const union in_addr_union *sockaddr_in_addr(const struct sockaddr *_sa) {
+        const union sockaddr_union *sa = (const union sockaddr_union*) _sa;
+
+        if (!sa)
+                return NULL;
+
+        switch (sa->sa.sa_family) {
+
+        case AF_INET:
+                return (const union in_addr_union*) &sa->in.sin_addr;
+
+        case AF_INET6:
+                return (const union in_addr_union*) &sa->in6.sin6_addr;
+
+        default:
+                return NULL;
+        }
+}
+
 int sockaddr_pretty(
                 const struct sockaddr *_sa,
                 socklen_t salen,
@@ -1251,71 +1267,8 @@ int socket_set_recvpktinfo(int fd, int af, bool b) {
         case AF_NETLINK:
                 return setsockopt_int(fd, SOL_NETLINK, NETLINK_PKTINFO, b);
 
-        default:
-                return -EAFNOSUPPORT;
-        }
-}
-
-int socket_set_recverr(int fd, int af, bool b) {
-        int r;
-
-        if (af == AF_UNSPEC) {
-                r = socket_get_family(fd, &af);
-                if (r < 0)
-                        return r;
-        }
-
-        switch (af) {
-
-        case AF_INET:
-                return setsockopt_int(fd, IPPROTO_IP, IP_RECVERR, b);
-
-        case AF_INET6:
-                return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVERR, b);
-
-        default:
-                return -EAFNOSUPPORT;
-        }
-}
-
-int socket_set_recvttl(int fd, int af, bool b) {
-        int r;
-
-        if (af == AF_UNSPEC) {
-                r = socket_get_family(fd, &af);
-                if (r < 0)
-                        return r;
-        }
-
-        switch (af) {
-
-        case AF_INET:
-                return setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, b);
-
-        case AF_INET6:
-                return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, b);
-
-        default:
-                return -EAFNOSUPPORT;
-        }
-}
-
-int socket_set_ttl(int fd, int af, int ttl) {
-        int r;
-
-        if (af == AF_UNSPEC) {
-                r = socket_get_family(fd, &af);
-                if (r < 0)
-                        return r;
-        }
-
-        switch (af) {
-
-        case AF_INET:
-                return setsockopt_int(fd, IPPROTO_IP, IP_TTL, ttl);
-
-        case AF_INET6:
-                return setsockopt_int(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, ttl);
+        case AF_PACKET:
+                return setsockopt_int(fd, SOL_PACKET, PACKET_AUXDATA, b);
 
         default:
                 return -EAFNOSUPPORT;
@@ -1351,7 +1304,7 @@ int socket_set_unicast_if(int fd, int af, int ifi) {
         }
 }
 
-int socket_set_freebind(int fd, int af, bool b) {
+int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val) {
         int r;
 
         if (af == AF_UNSPEC) {
@@ -1363,18 +1316,18 @@ int socket_set_freebind(int fd, int af, bool b) {
         switch (af) {
 
         case AF_INET:
-                return setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, b);
+                return setsockopt_int(fd, IPPROTO_IP, opt_ipv4, val);
 
         case AF_INET6:
-                return setsockopt_int(fd, IPPROTO_IPV6, IPV6_FREEBIND, b);
+                return setsockopt_int(fd, IPPROTO_IPV6, opt_ipv6, val);
 
         default:
                 return -EAFNOSUPPORT;
         }
 }
 
-int socket_set_transparent(int fd, int af, bool b) {
-        int r;
+int socket_get_mtu(int fd, int af, size_t *ret) {
+        int mtu, r;
 
         if (af == AF_UNSPEC) {
                 r = socket_get_family(fd, &af);
@@ -1385,13 +1338,23 @@ int socket_set_transparent(int fd, int af, bool b) {
         switch (af) {
 
         case AF_INET:
-                return setsockopt_int(fd, IPPROTO_IP, IP_TRANSPARENT, b);
+                r = getsockopt_int(fd, IPPROTO_IP, IP_MTU, &mtu);
+                break;
 
         case AF_INET6:
-                return setsockopt_int(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, b);
+                r = getsockopt_int(fd, IPPROTO_IPV6, IPV6_MTU, &mtu);
+                break;
 
         default:
                 return -EAFNOSUPPORT;
         }
+
+        if (r < 0)
+                return r;
+        if (mtu <= 0)
+                return -EINVAL;
+
+        *ret = (size_t) mtu;
+        return 0;
 }
 #endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/socket-util.h b/shared/systemd/src/basic/socket-util.h
index 1ece9118..1de06947 100644
--- a/shared/systemd/src/basic/socket-util.h
+++ b/shared/systemd/src/basic/socket-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <inttypes.h>
@@ -15,6 +15,7 @@
 #include <sys/un.h>
 
 #include "macro.h"
+#include "missing_network.h"
 #include "missing_socket.h"
 #include "sparse-endian.h"
 
@@ -104,6 +105,7 @@ const char* socket_address_get_path(const SocketAddress *a);
 bool socket_ipv6_is_supported(void);
 
 int sockaddr_port(const struct sockaddr *_sa, unsigned *port);
+const union in_addr_union *sockaddr_in_addr(const struct sockaddr *sa);
 
 int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret);
 int getpeername_pretty(int fd, bool include_port, char **ret);
@@ -258,6 +260,19 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) {
         return 0;
 }
 
+static inline int getsockopt_int(int fd, int level, int optname, int *ret) {
+        int v;
+        socklen_t sl = sizeof(v);
+
+        if (getsockopt(fd, level, optname, &v, &sl) < 0)
+                return -errno;
+        if (sl != sizeof(v))
+                return -EIO;
+
+        *ret = v;
+        return 0;
+}
+
 int socket_bind_to_ifname(int fd, const char *ifname);
 int socket_bind_to_ifindex(int fd, int ifindex);
 
@@ -265,9 +280,28 @@ ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags);
 
 int socket_get_family(int fd, int *ret);
 int socket_set_recvpktinfo(int fd, int af, bool b);
-int socket_set_recverr(int fd, int af, bool b);
-int socket_set_recvttl(int fd, int af, bool b);
-int socket_set_ttl(int fd, int af, int ttl);
 int socket_set_unicast_if(int fd, int af, int ifi);
-int socket_set_freebind(int fd, int af, bool b);
-int socket_set_transparent(int fd, int af, bool b);
+
+int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val);
+#if 0 /* NM_IGNORED */
+static inline int socket_set_recverr(int fd, int af, bool b) {
+        return socket_set_option(fd, af, IP_RECVERR, IPV6_RECVERR, b);
+}
+static inline int socket_set_recvttl(int fd, int af, bool b) {
+        return socket_set_option(fd, af, IP_RECVTTL, IPV6_RECVHOPLIMIT, b);
+}
+static inline int socket_set_ttl(int fd, int af, int ttl) {
+        return socket_set_option(fd, af, IP_TTL, IPV6_UNICAST_HOPS, ttl);
+}
+static inline int socket_set_freebind(int fd, int af, bool b) {
+        return socket_set_option(fd, af, IP_FREEBIND, IPV6_FREEBIND, b);
+}
+static inline int socket_set_transparent(int fd, int af, bool b) {
+        return socket_set_option(fd, af, IP_TRANSPARENT, IPV6_TRANSPARENT, b);
+}
+static inline int socket_set_recvfragsize(int fd, int af, bool b) {
+        return socket_set_option(fd, af, IP_RECVFRAGSIZE, IPV6_RECVFRAGSIZE, b);
+}
+#endif /* NM_IGNORED */
+
+int socket_get_mtu(int fd, int af, size_t *ret);
diff --git a/shared/systemd/src/basic/sort-util.h b/shared/systemd/src/basic/sort-util.h
index a8dc3bb6..a8984fc1 100644
--- a/shared/systemd/src/basic/sort-util.h
+++ b/shared/systemd/src/basic/sort-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdlib.h>
@@ -55,6 +55,7 @@ static inline void _qsort_safe(void *base, size_t nmemb, size_t size, __compar_f
                 _qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
         })
 
+#if 0 /* NM_IGNORED */
 static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
         if (nmemb <= 1)
                 return;
@@ -68,3 +69,6 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_
                 int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
                 qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
         })
+#endif /* NM_IGNORED */
+
+int cmp_int(const int *a, const int *b);
diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c
index 6d393041..a9880096 100644
--- a/shared/systemd/src/basic/stat-util.c
+++ b/shared/systemd/src/basic/stat-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -231,13 +231,12 @@ int fd_is_network_fs(int fd) {
 }
 
 int path_is_temporary_fs(const char *path) {
-        _cleanup_close_ int fd = -1;
+        struct statfs s;
 
-        fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
-        if (fd < 0)
+        if (statfs(path, &s) < 0)
                 return -errno;
 
-        return fd_is_temporary_fs(fd);
+        return is_temporary_fs(&s);
 }
 #endif /* NM_IGNORED */
 
@@ -415,7 +414,8 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
         return a && b &&
                 (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
                 ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 &&  /* same inode type */
-                a->st_mtime == b->st_mtime &&
+                a->st_mtim.tv_sec == b->st_mtim.tv_sec &&
+                a->st_mtim.tv_nsec == b->st_mtim.tv_nsec &&
                 (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
                 a->st_dev == b->st_dev &&
                 a->st_ino == b->st_ino &&
diff --git a/shared/systemd/src/basic/stat-util.h b/shared/systemd/src/basic/stat-util.h
index 26ecd635..a566114f 100644
--- a/shared/systemd/src/basic/stat-util.h
+++ b/shared/systemd/src/basic/stat-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <fcntl.h>
diff --git a/shared/systemd/src/basic/stdio-util.h b/shared/systemd/src/basic/stdio-util.h
index c3b9448d..d45d3c1a 100644
--- a/shared/systemd/src/basic/stdio-util.h
+++ b/shared/systemd/src/basic/stdio-util.h
@@ -1,7 +1,9 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#if 0 /* NM_IGNORED */
 #include <printf.h>
+#endif /* NM_IGNORED */
 #include <stdarg.h>
 #include <stdio.h>
 #include <sys/types.h>
diff --git a/shared/systemd/src/basic/string-table.c b/shared/systemd/src/basic/string-table.c
index 46014b18..bd8047e6 100644
--- a/shared/systemd/src/basic/string-table.c
+++ b/shared/systemd/src/basic/string-table.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/string-table.h b/shared/systemd/src/basic/string-table.h
index 96924778..ae4ea145 100644
--- a/shared/systemd/src/basic/string-table.h
+++ b/shared/systemd/src/basic/string-table.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #pragma once
 
@@ -28,13 +28,12 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
 
 #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
         scope type name##_from_string(const char *s) {                  \
-                int b;                                                  \
                 if (!s)                                                 \
                         return -1;                                      \
-                b = parse_boolean(s);                                   \
+                int b = parse_boolean(s);                               \
                 if (b == 0)                                             \
                         return (type) 0;                                \
-                else if (b > 0)                                         \
+                if (b > 0)                                              \
                         return yes;                                     \
                 return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
         }
@@ -79,11 +78,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
         _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope)
 
 #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
+#define DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,)
 #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
 #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
 #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
 
 #define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,static)
 
 /* For string conversions where numbers are also acceptable */
 #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max)         \
diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c
index aea13dcb..744a3606 100644
--- a/shared/systemd/src/basic/string-util.c
+++ b/shared/systemd/src/basic/string-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -147,57 +147,32 @@ char *strnappend(const char *s, const char *suffix, size_t b) {
 
 char *strjoin_real(const char *x, ...) {
         va_list ap;
-        size_t l;
+        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;
 
-        if (x) {
-                l = strlen(x);
-
-                for (;;) {
-                        const char *t;
-                        size_t n;
-
-                        t = va_arg(ap, const char *);
-                        if (!t)
-                                break;
-
-                        n = strlen(t);
-                        if (n > ((size_t) -1) - l) {
-                                va_end(ap);
-                                return NULL;
-                        }
-
-                        l += n;
+                n = strlen(t);
+                if (n > SIZE_MAX - l) {
+                        va_end(ap);
+                        return NULL;
                 }
-        } else
-                l = 0;
-
+                l += n;
+        }
         va_end(ap);
 
-        r = new(char, l+1);
+        p = r = new(char, l);
         if (!r)
                 return NULL;
 
-        if (x) {
-                p = stpcpy(r, x);
-
-                va_start(ap, x);
-
-                for (;;) {
-                        const char *t;
-
-                        t = va_arg(ap, const char *);
-                        if (!t)
-                                break;
-
-                        p = stpcpy(p, t);
-                }
+        va_start(ap, x);
+        for (const char *t = x; t; t = va_arg(ap, const char *))
+                p = stpcpy(p, t);
+        va_end(ap);
 
-                va_end(ap);
-        } else
-                r[0] = 0;
+        *p = 0;
 
         return r;
 }
@@ -823,10 +798,10 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
         return *ibuf;
 }
 
-char *strextend_with_separator(char **x, const char *separator, ...) {
-        bool need_separator;
+char *strextend_with_separator_internal(char **x, const char *separator, ...) {
         size_t f, l, l_separator;
-        char *r, *p;
+        bool need_separator;
+        char *nr, *p;
         va_list ap;
 
         assert(x);
@@ -850,7 +825,7 @@ char *strextend_with_separator(char **x, const char *separator, ...) {
                 if (need_separator)
                         n += l_separator;
 
-                if (n > ((size_t) -1) - l) {
+                if (n >= SIZE_MAX - l) {
                         va_end(ap);
                         return NULL;
                 }
@@ -862,11 +837,12 @@ char *strextend_with_separator(char **x, const char *separator, ...) {
 
         need_separator = !isempty(*x);
 
-        r = realloc(*x, l+1);
-        if (!r)
+        nr = realloc(*x, GREEDY_ALLOC_ROUND_UP(l+1));
+        if (!nr)
                 return NULL;
 
-        p = r + f;
+        *x = nr;
+        p = nr + f;
 
         va_start(ap, separator);
         for (;;) {
@@ -885,12 +861,11 @@ char *strextend_with_separator(char **x, const char *separator, ...) {
         }
         va_end(ap);
 
-        assert(p == r + l);
+        assert(p == nr + l);
 
         *p = 0;
-        *x = r;
 
-        return r + l;
+        return p;
 }
 #endif /* NM_IGNORED */
 
diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h
index cefbda35..593cf04a 100644
--- a/shared/systemd/src/basic/string-util.h
+++ b/shared/systemd/src/basic/string-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>
@@ -33,6 +33,12 @@ static inline bool streq_ptr(const char *a, const char *b) {
         return strcmp_ptr(a, b) == 0;
 }
 
+static inline char* strstr_ptr(const char *haystack, const char *needle) {
+        if (!haystack || !needle)
+                return NULL;
+        return strstr(haystack, needle);
+}
+
 static inline const char* strempty(const char *s) {
         return s ?: "";
 }
@@ -53,6 +59,10 @@ static inline const char* true_false(bool b) {
         return b ? "true" : "false";
 }
 
+static inline const char* plus_minus(bool b) {
+        return b ? "+" : "-";
+}
+
 static inline const char* one_zero(bool b) {
         return b ? "1" : "0";
 }
@@ -179,9 +189,10 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin
 
 char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]);
 
-char *strextend_with_separator(char **x, const char *separator, ...) _sentinel_;
+char *strextend_with_separator_internal(char **x, const char *separator, ...) _sentinel_;
 
-#define strextend(x, ...) strextend_with_separator(x, NULL, __VA_ARGS__)
+#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 *strrep(const char *s, unsigned n);
 
diff --git a/shared/systemd/src/basic/strv.c b/shared/systemd/src/basic/strv.c
index 30d3af46..7d3e3fc7 100644
--- a/shared/systemd/src/basic/strv.c
+++ b/shared/systemd/src/basic/strv.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -125,7 +125,6 @@ size_t strv_length(char * const *l) {
 }
 
 char **strv_new_ap(const char *x, va_list ap) {
-        const char *s;
         _cleanup_strv_free_ char **a = NULL;
         size_t n = 0, i = 0;
         va_list aq;
@@ -135,43 +134,28 @@ char **strv_new_ap(const char *x, va_list ap) {
          * STRV_IFNOTNULL() macro to include possibly NULL strings in
          * the string list. */
 
-        if (x) {
-                n = x == STRV_IGNORE ? 0 : 1;
-
-                va_copy(aq, ap);
-                while ((s = va_arg(aq, const char*))) {
-                        if (s == STRV_IGNORE)
-                                continue;
-
-                        n++;
-                }
+        va_copy(aq, ap);
+        for (const char *s = x; s; s = va_arg(aq, const char*)) {
+                if (s == STRV_IGNORE)
+                        continue;
 
-                va_end(aq);
+                n++;
         }
+        va_end(aq);
 
         a = new(char*, n+1);
         if (!a)
                 return NULL;
 
-        if (x) {
-                if (x != STRV_IGNORE) {
-                        a[i] = strdup(x);
-                        if (!a[i])
-                                return NULL;
-                        i++;
-                }
-
-                while ((s = va_arg(ap, const char*))) {
-
-                        if (s == STRV_IGNORE)
-                                continue;
+        for (const char *s = x; s; s = va_arg(ap, const char*)) {
+                if (s == STRV_IGNORE)
+                        continue;
 
-                        a[i] = strdup(s);
-                        if (!a[i])
-                                return NULL;
+                a[i] = strdup(s);
+                if (!a[i])
+                        return NULL;
 
-                        i++;
-                }
+                i++;
         }
 
         a[i] = NULL;
@@ -543,6 +527,19 @@ int strv_consume_prepend(char ***l, char *value) {
         return r;
 }
 
+int strv_prepend(char ***l, const char *value) {
+        char *v;
+
+        if (!value)
+                return 0;
+
+        v = strdup(value);
+        if (!v)
+                return -ENOMEM;
+
+        return strv_consume_prepend(l, v);
+}
+
 int strv_extend(char ***l, const char *value) {
         char *v;
 
diff --git a/shared/systemd/src/basic/strv.h b/shared/systemd/src/basic/strv.h
index 919fabf7..6b3e8e7f 100644
--- a/shared/systemd/src/basic/strv.h
+++ b/shared/systemd/src/basic/strv.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <fnmatch.h>
@@ -34,6 +34,7 @@ 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_prepend(char ***l, const char *value);
 int strv_extend(char ***l, const char *value);
 int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
 int strv_extend_front(char ***l, const char *value);
@@ -62,7 +63,7 @@ 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)
 
-#define STRV_IGNORE ((const char *) -1)
+#define STRV_IGNORE ((const char *) POINTER_MAX)
 
 static inline const char* STRV_IFNOTNULL(const char *x) {
         return x ? x : STRV_IGNORE;
diff --git a/shared/systemd/src/basic/strxcpyx.c b/shared/systemd/src/basic/strxcpyx.c
index 301e6899..39aebb88 100644
--- a/shared/systemd/src/basic/strxcpyx.c
+++ b/shared/systemd/src/basic/strxcpyx.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 /*
  * Concatenates/copies strings. In any case, terminates in all cases
diff --git a/shared/systemd/src/basic/strxcpyx.h b/shared/systemd/src/basic/strxcpyx.h
index 9b668412..cdef492d 100644
--- a/shared/systemd/src/basic/strxcpyx.h
+++ b/shared/systemd/src/basic/strxcpyx.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stddef.h>
diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c
index 0fac79a7..e5faa334 100644
--- a/shared/systemd/src/basic/time-util.c
+++ b/shared/systemd/src/basic/time-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -1613,7 +1613,7 @@ TimestampStyle timestamp_style_from_string(const char *s) {
                 return t;
         if (streq_ptr(s, "µs"))
                 return TIMESTAMP_US;
-        if (streq_ptr(s, "µs+uts"))
+        if (streq_ptr(s, "µs+utc"))
                 return TIMESTAMP_US_UTC;
         return t;
 }
diff --git a/shared/systemd/src/basic/time-util.h b/shared/systemd/src/basic/time-util.h
index cecd5efa..89ee8b4a 100644
--- a/shared/systemd/src/basic/time-util.h
+++ b/shared/systemd/src/basic/time-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <inttypes.h>
@@ -63,10 +63,10 @@ typedef enum TimestampStyle {
 
 /* We assume a maximum timezone length of 6. TZNAME_MAX is not defined on Linux, but glibc internally initializes this
  * to 6. Let's rely on that. */
-#define FORMAT_TIMESTAMP_MAX (3+1+10+1+8+1+6+1+6+1)
-#define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */
-#define FORMAT_TIMESTAMP_RELATIVE_MAX 256
-#define FORMAT_TIMESPAN_MAX 64
+#define FORMAT_TIMESTAMP_MAX (3U+1U+10U+1U+8U+1U+6U+1U+6U+1U)
+#define FORMAT_TIMESTAMP_WIDTH 28U /* when outputting, assume this width */
+#define FORMAT_TIMESTAMP_RELATIVE_MAX 256U
+#define FORMAT_TIMESPAN_MAX 64U
 
 #define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
 
diff --git a/shared/systemd/src/basic/tmpfile-util.c b/shared/systemd/src/basic/tmpfile-util.c
index 9b3621ba..bbd6a1ed 100644
--- a/shared/systemd/src/basic/tmpfile-util.c
+++ b/shared/systemd/src/basic/tmpfile-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/basic/tmpfile-util.h b/shared/systemd/src/basic/tmpfile-util.h
index 802c85d6..45255fc0 100644
--- a/shared/systemd/src/basic/tmpfile-util.h
+++ b/shared/systemd/src/basic/tmpfile-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdio.h>
diff --git a/shared/systemd/src/basic/umask-util.h b/shared/systemd/src/basic/umask-util.h
index cad74517..bd7c2bdb 100644
--- a/shared/systemd/src/basic/umask-util.h
+++ b/shared/systemd/src/basic/umask-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>
diff --git a/shared/systemd/src/basic/utf8.c b/shared/systemd/src/basic/utf8.c
index 8159b187..a7679bfa 100644
--- a/shared/systemd/src/basic/utf8.c
+++ b/shared/systemd/src/basic/utf8.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 /* Parts of this file are based on the GLIB utf8 validation functions. The
  * original license text follows. */
diff --git a/shared/systemd/src/basic/utf8.h b/shared/systemd/src/basic/utf8.h
index f315ea0f..a6ea942c 100644
--- a/shared/systemd/src/basic/utf8.h
+++ b/shared/systemd/src/basic/utf8.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>
diff --git a/shared/systemd/src/basic/util.c b/shared/systemd/src/basic/util.c
index 8a3f95dc..10a5bcff 100644
--- a/shared/systemd/src/basic/util.c
+++ b/shared/systemd/src/basic/util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
@@ -168,7 +168,7 @@ int container_get_leader(const char *machine, pid_t *pid) {
                 return 0;
         }
 
-        if (!machine_name_is_valid(machine))
+        if (!hostname_is_valid(machine, 0))
                 return -EINVAL;
 
         p = strjoina("/run/systemd/machines/", machine);
@@ -196,8 +196,8 @@ int container_get_leader(const char *machine, pid_t *pid) {
 }
 
 int version(void) {
-        puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n"
-             SYSTEMD_FEATURES);
+        printf("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n%s\n",
+               systemd_features);
         return 0;
 }
 
diff --git a/shared/systemd/src/basic/util.h b/shared/systemd/src/basic/util.h
index 6fc7480f..942d773f 100644
--- a/shared/systemd/src/basic/util.h
+++ b/shared/systemd/src/basic/util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdint.h>
diff --git a/shared/systemd/src/shared/dns-domain.c b/shared/systemd/src/shared/dns-domain.c
index 6d60eb58..95e4a93a 100644
--- a/shared/systemd/src/shared/dns-domain.c
+++ b/shared/systemd/src/shared/dns-domain.c
@@ -1,16 +1,7 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
-#if 0 /* NM_IGNORED */
-#if HAVE_LIBIDN2
-#  include <idn2.h>
-#elif HAVE_LIBIDN
-#  include <idna.h>
-#  include <stringprep.h>
-#endif
-#endif
-
 #include <endian.h>
 #include <netinet/in.h>
 #include <stdio.h>
@@ -21,6 +12,7 @@
 #include "hashmap.h"
 #include "hexdecoct.h"
 #include "hostname-util.h"
+#include "idn-util.h"
 #include "in-addr-util.h"
 #include "macro.h"
 #include "parse-util.h"
@@ -319,12 +311,17 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
         const char *p;
         bool contains_8bit = false;
         char buffer[DNS_LABEL_MAX+1];
+        int r;
 
         assert(encoded);
         assert(decoded);
 
         /* Converts an U-label into an A-label */
 
+        r = dlopen_idn();
+        if (r < 0)
+                return r;
+
         if (encoded_size <= 0)
                 return -EINVAL;
 
@@ -339,11 +336,11 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
                 return 0;
         }
 
-        input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
+        input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
         if (!input)
                 return -ENOMEM;
 
-        if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
+        if (sym_idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
                 return -EINVAL;
 
         l = strlen(buffer);
@@ -369,28 +366,33 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
         _cleanup_free_ char *result = NULL;
         uint32_t *output = NULL;
         size_t w;
+        int r;
 
         /* To be invoked after unescaping. Converts an A-label into an U-label. */
 
         assert(encoded);
         assert(decoded);
 
+        r = dlopen_idn();
+        if (r < 0)
+                return r;
+
         if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX)
                 return -EINVAL;
 
         if (!memory_startswith(encoded, encoded_size, IDNA_ACE_PREFIX))
                 return 0;
 
-        input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
+        input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
         if (!input)
                 return -ENOMEM;
 
         output_size = input_size;
         output = newa(uint32_t, output_size);
 
-        idna_to_unicode_44i(input, input_size, output, &output_size, 0);
+        sym_idna_to_unicode_44i(input, input_size, output, &output_size, 0);
 
-        result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
+        result = sym_stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
         if (!result)
                 return -ENOMEM;
         if (w <= 0)
@@ -748,12 +750,12 @@ int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
         return 0;
 }
 
-int dns_name_address(const char *p, int *family, union in_addr_union *address) {
+int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_address) {
         int r;
 
         assert(p);
-        assert(family);
-        assert(address);
+        assert(ret_family);
+        assert(ret_address);
 
         r = dns_name_endswith(p, "in-addr.arpa");
         if (r < 0)
@@ -782,11 +784,11 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
                 if (r <= 0)
                         return r;
 
-                *family = AF_INET;
-                address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
-                                             ((uint32_t) a[2] << 16) |
-                                             ((uint32_t) a[1] << 8) |
-                                              (uint32_t) a[0]);
+                *ret_family = AF_INET;
+                ret_address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
+                                                 ((uint32_t) a[2] << 16) |
+                                                 ((uint32_t) a[1] << 8) |
+                                                 (uint32_t) a[0]);
 
                 return 1;
         }
@@ -827,11 +829,14 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
                 if (r <= 0)
                         return r;
 
-                *family = AF_INET6;
-                address->in6 = a;
+                *ret_family = AF_INET6;
+                ret_address->in6 = a;
                 return 1;
         }
 
+        *ret_family = AF_UNSPEC;
+        *ret_address = IN_ADDR_NULL;
+
         return 0;
 }
 #endif /* NM_IGNORED */
@@ -1277,47 +1282,67 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
 }
 
 int dns_name_apply_idna(const char *name, char **ret) {
+
         /* Return negative on error, 0 if not implemented, positive on success. */
 
-#if HAVE_LIBIDN2
+#if HAVE_LIBIDN2 || HAVE_LIBIDN2
         int r;
+
+        r = dlopen_idn();
+        if (r == -EOPNOTSUPP) {
+                *ret = NULL;
+                return 0;
+        }
+        if (r < 0)
+                return r;
+#endif
+
+#if HAVE_LIBIDN2
         _cleanup_free_ char *t = NULL;
 
         assert(name);
         assert(ret);
 
-        r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
-                           IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
+        /* First, try non-transitional mode (i.e. IDN2008 rules) */
+        r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
+                               IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
+        if (r == IDN2_DISALLOWED) /* If that failed, because of disallowed characters, try transitional mode.
+                                   * (i.e. IDN2003 rules which supports some unicode chars IDN2008 doesn't allow). */
+                r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
+                                       IDN2_NFC_INPUT | IDN2_TRANSITIONAL);
+
         log_debug("idn2_lookup_u8: %s → %s", name, t);
         if (r == IDN2_OK) {
                 if (!startswith(name, "xn--")) {
                         _cleanup_free_ char *s = NULL;
 
-                        r = idn2_to_unicode_8z8z(t, &s, 0);
+                        r = sym_idn2_to_unicode_8z8z(t, &s, 0);
                         if (r != IDN2_OK) {
                                 log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
-                                          t, r, idn2_strerror(r));
+                                          t, r, sym_idn2_strerror(r));
+                                *ret = NULL;
                                 return 0;
                         }
 
                         if (!streq_ptr(name, s)) {
                                 log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.",
                                           name, t, s);
+                                *ret = NULL;
                                 return 0;
                         }
                 }
 
                 *ret = TAKE_PTR(t);
-
                 return 1; /* *ret has been written */
         }
 
-        log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r));
+        log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, sym_idn2_strerror(r));
         if (r == IDN2_2HYPHEN)
                 /* The name has two hyphens — forbidden by IDNA2008 in some cases */
                 return 0;
         if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL))
                 return -ENOSPC;
+
         return -EINVAL;
 #elif HAVE_LIBIDN
         _cleanup_free_ char *buf = NULL;
@@ -1369,6 +1394,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
 
         return 1;
 #else
+        *ret = NULL;
         return 0;
 #endif
 }
diff --git a/shared/systemd/src/shared/dns-domain.h b/shared/systemd/src/shared/dns-domain.h
index e4e5b1b9..984f4840 100644
--- a/shared/systemd/src/shared/dns-domain.h
+++ b/shared/systemd/src/shared/dns-domain.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <errno.h>
diff --git a/shared/systemd/src/shared/log-link.h b/shared/systemd/src/shared/log-link.h
new file mode 100644
index 00000000..3a4dcaa2
--- /dev/null
+++ b/shared/systemd/src/shared/log-link.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "log.h"
+
+#define log_interface_full_errno(ifname, level, error, ...)             \
+        ({                                                              \
+                const char *_ifname = (ifname);                         \
+                _ifname ? log_object_internal(level, error, PROJECT_FILE, __LINE__, __func__, "INTERFACE=", _ifname, NULL, NULL, ##__VA_ARGS__) : \
+                        log_internal(level, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \
+        })
+
+/*
+ * The following macros append INTERFACE= to the message.
+ * The macros require a struct named 'Link' which contains 'char *ifname':
+ *
+ *         typedef struct Link {
+ *                 char *ifname;
+ *         } Link;
+ *
+ * See, network/networkd-link.h for example.
+ */
+
+#define log_link_full_errno(link, level, error, ...)                    \
+        ({                                                              \
+                const Link *_l = (link);                                \
+                log_interface_full_errno(_l ? _l->ifname : NULL, level, error, ##__VA_ARGS__); \
+        })
+
+#define log_link_full(link, level, ...) (void) log_link_full_errno(link, level, 0, __VA_ARGS__)
+
+#define log_link_debug(link, ...)   log_link_full_errno(link, LOG_DEBUG, 0, __VA_ARGS__)
+#define log_link_info(link, ...)    log_link_full(link, LOG_INFO, __VA_ARGS__)
+#define log_link_notice(link, ...)  log_link_full(link, LOG_NOTICE, __VA_ARGS__)
+#define log_link_warning(link, ...) log_link_full(link, LOG_WARNING, __VA_ARGS__)
+#define log_link_error(link, ...)   log_link_full(link, LOG_ERR, __VA_ARGS__)
+
+#define log_link_debug_errno(link, error, ...)   log_link_full_errno(link, LOG_DEBUG, error, __VA_ARGS__)
+#define log_link_info_errno(link, error, ...)    log_link_full_errno(link, LOG_INFO, error, __VA_ARGS__)
+#define log_link_notice_errno(link, error, ...)  log_link_full_errno(link, LOG_NOTICE, error, __VA_ARGS__)
+#define log_link_warning_errno(link, error, ...) log_link_full_errno(link, LOG_WARNING, error, __VA_ARGS__)
+#define log_link_error_errno(link, error, ...)   log_link_full_errno(link, LOG_ERR, error, __VA_ARGS__)
+
+#define LOG_LINK_MESSAGE(link, fmt, ...) "MESSAGE=%s: " fmt, (link)->ifname, ##__VA_ARGS__
+#define LOG_LINK_INTERFACE(link) "INTERFACE=%s", (link)->ifname
diff --git a/shared/systemd/src/shared/web-util.c b/shared/systemd/src/shared/web-util.c
index 4cff5e27..35ba1a2e 100644
--- a/shared/systemd/src/shared/web-util.c
+++ b/shared/systemd/src/shared/web-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "nm-sd-adapt-shared.h"
 
diff --git a/shared/systemd/src/shared/web-util.h b/shared/systemd/src/shared/web-util.h
index c9e67e5c..ec54669f 100644
--- a/shared/systemd/src/shared/web-util.h
+++ b/shared/systemd/src/shared/web-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
 #include <stdbool.h>