about summary refs log tree commit diff
path: root/shared
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2021-10-01 23:05:04 +0200
committerMichael Biebl <biebl@debian.org>2021-10-01 23:05:04 +0200
commite74c568b07b50b97873fb4ee1d776dedefbd54d6 (patch)
tree3469f17ea9af91f7ff169b890633bda68b0cf76e /shared
parentbfe522304da217296e2a61040f58e35ec5d6f3f2 (diff)
New upstream version 1.32.12 upstream/1.32.12
Diffstat (limited to 'shared')
-rw-r--r--shared/README.md108
-rw-r--r--shared/c-list/src/c-list.h443
-rw-r--r--shared/c-rbtree/src/c-rbtree-private.h35
-rw-r--r--shared/c-rbtree/src/c-rbtree.c1120
-rw-r--r--shared/c-rbtree/src/c-rbtree.h437
-rw-r--r--shared/c-siphash/src/c-siphash.c245
-rw-r--r--shared/c-siphash/src/c-siphash.h60
-rw-r--r--shared/c-stdaux/src/c-stdaux.h550
-rw-r--r--shared/meson.build298
-rw-r--r--shared/n-acd/src/n-acd-bpf-fallback.c30
-rw-r--r--shared/n-acd/src/n-acd-bpf.c317
-rw-r--r--shared/n-acd/src/n-acd-private.h154
-rw-r--r--shared/n-acd/src/n-acd-probe.c712
-rw-r--r--shared/n-acd/src/n-acd.c1027
-rw-r--r--shared/n-acd/src/n-acd.h150
-rw-r--r--shared/n-acd/src/util/timer.c189
-rw-r--r--shared/n-acd/src/util/timer.h54
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-connection.c1256
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-lease.c405
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-c-probe.c1294
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-client.c990
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-incoming.c428
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-outgoing.c373
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-private.h759
-rw-r--r--shared/n-dhcp4/src/n-dhcp4-socket.c661
-rw-r--r--shared/n-dhcp4/src/n-dhcp4.h300
-rw-r--r--shared/n-dhcp4/src/util/packet.c448
-rw-r--r--shared/n-dhcp4/src/util/packet.h61
-rw-r--r--shared/n-dhcp4/src/util/socket.c121
-rw-r--r--shared/n-dhcp4/src/util/socket.h11
-rw-r--r--shared/nm-base/nm-base.h210
-rw-r--r--shared/nm-base/nm-ethtool-base.c288
-rw-r--r--shared/nm-base/nm-ethtool-base.h37
-rw-r--r--shared/nm-base/nm-ethtool-utils-base.h107
-rw-r--r--shared/nm-glib-aux/nm-c-list.h180
-rw-r--r--shared/nm-glib-aux/nm-dbus-aux.c405
-rw-r--r--shared/nm-glib-aux/nm-dbus-aux.h218
-rw-r--r--shared/nm-glib-aux/nm-dedup-multi.c1065
-rw-r--r--shared/nm-glib-aux/nm-dedup-multi.h407
-rw-r--r--shared/nm-glib-aux/nm-default-glib-i18n-lib.h21
-rw-r--r--shared/nm-glib-aux/nm-default-glib-i18n-prog.h21
-rw-r--r--shared/nm-glib-aux/nm-default-glib.h75
-rw-r--r--shared/nm-glib-aux/nm-enum-utils.c368
-rw-r--r--shared/nm-glib-aux/nm-enum-utils.h32
-rw-r--r--shared/nm-glib-aux/nm-errno.c169
-rw-r--r--shared/nm-glib-aux/nm-errno.h171
-rw-r--r--shared/nm-glib-aux/nm-gassert-patch.h76
-rw-r--r--shared/nm-glib-aux/nm-glib.h707
-rw-r--r--shared/nm-glib-aux/nm-hash-utils.c286
-rw-r--r--shared/nm-glib-aux/nm-hash-utils.h442
-rw-r--r--shared/nm-glib-aux/nm-io-utils.c480
-rw-r--r--shared/nm-glib-aux/nm-io-utils.h58
-rw-r--r--shared/nm-glib-aux/nm-jansson.h30
-rw-r--r--shared/nm-glib-aux/nm-json-aux.c286
-rw-r--r--shared/nm-glib-aux/nm-json-aux.h312
-rw-r--r--shared/nm-glib-aux/nm-keyfile-aux.c373
-rw-r--r--shared/nm-glib-aux/nm-keyfile-aux.h55
-rw-r--r--shared/nm-glib-aux/nm-logging-base.c79
-rw-r--r--shared/nm-glib-aux/nm-logging-base.h28
-rw-r--r--shared/nm-glib-aux/nm-logging-fwd.h308
-rw-r--r--shared/nm-glib-aux/nm-macros-internal.h1824
-rw-r--r--shared/nm-glib-aux/nm-obj.h66
-rw-r--r--shared/nm-glib-aux/nm-random-utils.c150
-rw-r--r--shared/nm-glib-aux/nm-random-utils.h11
-rw-r--r--shared/nm-glib-aux/nm-ref-string.c203
-rw-r--r--shared/nm-glib-aux/nm-ref-string.h79
-rw-r--r--shared/nm-glib-aux/nm-secret-utils.c178
-rw-r--r--shared/nm-glib-aux/nm-secret-utils.h273
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.c5789
-rw-r--r--shared/nm-glib-aux/nm-shared-utils.h2484
-rw-r--r--shared/nm-glib-aux/nm-str-buf.h488
-rw-r--r--shared/nm-glib-aux/nm-time-utils.c328
-rw-r--r--shared/nm-glib-aux/nm-time-utils.h47
-rw-r--r--shared/nm-glib-aux/nm-value-type.h209
-rw-r--r--shared/nm-glib-aux/tests/meson.build41
-rw-r--r--shared/nm-glib-aux/tests/test-json-aux.c165
-rw-r--r--shared/nm-glib-aux/tests/test-shared-general.c1289
-rw-r--r--shared/nm-log-core/nm-logging.c1035
-rw-r--r--shared/nm-log-core/nm-logging.h189
-rw-r--r--shared/nm-platform/nm-netlink.c1518
-rw-r--r--shared/nm-platform/nm-netlink.h616
-rw-r--r--shared/nm-platform/nm-platform-utils.c1807
-rw-r--r--shared/nm-platform/nm-platform-utils.h73
-rw-r--r--shared/nm-platform/nmp-base.h94
-rw-r--r--shared/nm-platform/nmp-netns.c759
-rw-r--r--shared/nm-platform/nmp-netns.h56
-rw-r--r--shared/nm-platform/tests/meson.build20
-rw-r--r--shared/nm-platform/tests/test-nm-platform.c116
-rw-r--r--shared/nm-std-aux/c-list-util.c184
-rw-r--r--shared/nm-std-aux/c-list-util.h56
-rw-r--r--shared/nm-std-aux/nm-dbus-compat.h25
-rw-r--r--shared/nm-std-aux/nm-default-std.h102
-rw-r--r--shared/nm-std-aux/nm-networkmanager-compilation.h54
-rw-r--r--shared/nm-std-aux/nm-std-aux.h985
-rw-r--r--shared/nm-std-aux/nm-std-utils.c90
-rw-r--r--shared/nm-std-aux/nm-std-utils.h36
-rw-r--r--shared/nm-std-aux/unaligned.h99
-rw-r--r--shared/nm-test-libnm-utils.h90
-rw-r--r--shared/nm-test-utils-impl.c644
-rw-r--r--shared/nm-udev-aux/nm-udev-utils.c265
-rw-r--r--shared/nm-udev-aux/nm-udev-utils.h33
-rw-r--r--shared/nm-utils/nm-compat.c76
-rw-r--r--shared/nm-utils/nm-compat.h35
-rw-r--r--shared/nm-utils/nm-test-utils.h2824
-rw-r--r--shared/nm-utils/nm-vpn-editor-plugin-call.h167
-rw-r--r--shared/nm-utils/nm-vpn-plugin-macros.h76
-rw-r--r--shared/nm-utils/nm-vpn-plugin-utils.c138
-rw-r--r--shared/nm-utils/nm-vpn-plugin-utils.h25
-rw-r--r--shared/systemd/nm-default-systemd-shared.h18
-rw-r--r--shared/systemd/nm-logging-stub.c36
-rw-r--r--shared/systemd/nm-sd-utils-shared.c192
-rw-r--r--shared/systemd/nm-sd-utils-shared.h41
-rw-r--r--shared/systemd/sd-adapt-shared/architecture.h3
-rw-r--r--shared/systemd/sd-adapt-shared/arphrd-list.h3
-rw-r--r--shared/systemd/sd-adapt-shared/blockdev-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/build.h3
-rw-r--r--shared/systemd/sd-adapt-shared/copy.h3
-rw-r--r--shared/systemd/sd-adapt-shared/def.h3
-rw-r--r--shared/systemd/sd-adapt-shared/dhcp-server-internal.h3
-rw-r--r--shared/systemd/sd-adapt-shared/dirent-util.h5
-rw-r--r--shared/systemd/sd-adapt-shared/errno-list.h3
-rw-r--r--shared/systemd/sd-adapt-shared/glob-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/gunicode.h3
-rw-r--r--shared/systemd/sd-adapt-shared/idn-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/ioprio.h3
-rw-r--r--shared/systemd/sd-adapt-shared/locale-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/memfd-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/missing_fs.h3
-rw-r--r--shared/systemd/sd-adapt-shared/missing_keyctl.h3
-rw-r--r--shared/systemd/sd-adapt-shared/missing_magic.h3
-rw-r--r--shared/systemd/sd-adapt-shared/missing_network.h3
-rw-r--r--shared/systemd/sd-adapt-shared/missing_sched.h3
-rw-r--r--shared/systemd/sd-adapt-shared/missing_timerfd.h3
-rw-r--r--shared/systemd/sd-adapt-shared/mkdir.h3
-rw-r--r--shared/systemd/sd-adapt-shared/namespace-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h221
-rw-r--r--shared/systemd/sd-adapt-shared/nulstr-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/raw-clone.h3
-rw-r--r--shared/systemd/sd-adapt-shared/rlimit-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/terminal-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/unaligned.h3
-rw-r--r--shared/systemd/sd-adapt-shared/user-util.h3
-rw-r--r--shared/systemd/sd-adapt-shared/virt.h3
-rw-r--r--shared/systemd/src/basic/alloc-util.c114
-rw-r--r--shared/systemd/src/basic/alloc-util.h174
-rw-r--r--shared/systemd/src/basic/async.h13
-rw-r--r--shared/systemd/src/basic/cgroup-util.h290
-rw-r--r--shared/systemd/src/basic/env-file.c571
-rw-r--r--shared/systemd/src/basic/env-file.h17
-rw-r--r--shared/systemd/src/basic/env-util.c767
-rw-r--r--shared/systemd/src/basic/env-util.h57
-rw-r--r--shared/systemd/src/basic/errno-util.h119
-rw-r--r--shared/systemd/src/basic/escape.c553
-rw-r--r--shared/systemd/src/basic/escape.h67
-rw-r--r--shared/systemd/src/basic/ether-addr-util.c128
-rw-r--r--shared/systemd/src/basic/ether-addr-util.h52
-rw-r--r--shared/systemd/src/basic/extract-word.c294
-rw-r--r--shared/systemd/src/basic/extract-word.h18
-rw-r--r--shared/systemd/src/basic/fd-util.c1071
-rw-r--r--shared/systemd/src/basic/fd-util.h108
-rw-r--r--shared/systemd/src/basic/fileio.c1360
-rw-r--r--shared/systemd/src/basic/fileio.h127
-rw-r--r--shared/systemd/src/basic/format-util.c83
-rw-r--r--shared/systemd/src/basic/format-util.h89
-rw-r--r--shared/systemd/src/basic/fs-util.c1706
-rw-r--r--shared/systemd/src/basic/fs-util.h136
-rw-r--r--shared/systemd/src/basic/hash-funcs.c113
-rw-r--r--shared/systemd/src/basic/hash-funcs.h110
-rw-r--r--shared/systemd/src/basic/hashmap.c2032
-rw-r--r--shared/systemd/src/basic/hashmap.h449
-rw-r--r--shared/systemd/src/basic/hexdecoct.c869
-rw-r--r--shared/systemd/src/basic/hexdecoct.h44
-rw-r--r--shared/systemd/src/basic/hostname-util.c196
-rw-r--r--shared/systemd/src/basic/hostname-util.h29
-rw-r--r--shared/systemd/src/basic/in-addr-util.c792
-rw-r--r--shared/systemd/src/basic/in-addr-util.h89
-rw-r--r--shared/systemd/src/basic/io-util.c343
-rw-r--r--shared/systemd/src/basic/io-util.h92
-rw-r--r--shared/systemd/src/basic/list.h186
-rw-r--r--shared/systemd/src/basic/log.h401
-rw-r--r--shared/systemd/src/basic/macro.h666
-rw-r--r--shared/systemd/src/basic/memory-util.c61
-rw-r--r--shared/systemd/src/basic/memory-util.h103
-rw-r--r--shared/systemd/src/basic/mempool.c102
-rw-r--r--shared/systemd/src/basic/mempool.h31
-rw-r--r--shared/systemd/src/basic/missing_fcntl.h60
-rw-r--r--shared/systemd/src/basic/missing_random.h20
-rw-r--r--shared/systemd/src/basic/missing_socket.h83
-rw-r--r--shared/systemd/src/basic/missing_stat.h137
-rw-r--r--shared/systemd/src/basic/missing_syscall.h889
-rw-r--r--shared/systemd/src/basic/missing_type.h12
-rw-r--r--shared/systemd/src/basic/parse-util.c912
-rw-r--r--shared/systemd/src/basic/parse-util.h153
-rw-r--r--shared/systemd/src/basic/path-util.c1188
-rw-r--r--shared/systemd/src/basic/path-util.h190
-rw-r--r--shared/systemd/src/basic/prioq.c302
-rw-r--r--shared/systemd/src/basic/prioq.h32
-rw-r--r--shared/systemd/src/basic/process-util.c1662
-rw-r--r--shared/systemd/src/basic/process-util.h203
-rw-r--r--shared/systemd/src/basic/random-util.c507
-rw-r--r--shared/systemd/src/basic/random-util.h42
-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.h154
-rw-r--r--shared/systemd/src/basic/signal-util.c299
-rw-r--r--shared/systemd/src/basic/signal-util.h45
-rw-r--r--shared/systemd/src/basic/siphash24.h83
-rw-r--r--shared/systemd/src/basic/socket-util.c1360
-rw-r--r--shared/systemd/src/basic/socket-util.h307
-rw-r--r--shared/systemd/src/basic/sort-util.h74
-rw-r--r--shared/systemd/src/basic/sparse-endian.h90
-rw-r--r--shared/systemd/src/basic/stat-util.c480
-rw-r--r--shared/systemd/src/basic/stat-util.h115
-rw-r--r--shared/systemd/src/basic/stdio-util.h66
-rw-r--r--shared/systemd/src/basic/string-table.c17
-rw-r--r--shared/systemd/src/basic/string-table.h112
-rw-r--r--shared/systemd/src/basic/string-util.c1146
-rw-r--r--shared/systemd/src/basic/string-util.h280
-rw-r--r--shared/systemd/src/basic/strv.c1005
-rw-r--r--shared/systemd/src/basic/strv.h240
-rw-r--r--shared/systemd/src/basic/strxcpyx.c118
-rw-r--r--shared/systemd/src/basic/strxcpyx.h14
-rw-r--r--shared/systemd/src/basic/time-util.c1620
-rw-r--r--shared/systemd/src/basic/time-util.h201
-rw-r--r--shared/systemd/src/basic/tmpfile-util.c344
-rw-r--r--shared/systemd/src/basic/tmpfile-util.h19
-rw-r--r--shared/systemd/src/basic/umask-util.h26
-rw-r--r--shared/systemd/src/basic/utf8.c595
-rw-r--r--shared/systemd/src/basic/utf8.h57
-rw-r--r--shared/systemd/src/basic/util.c277
-rw-r--r--shared/systemd/src/basic/util.h68
-rw-r--r--shared/systemd/src/shared/dns-domain.c1429
-rw-r--r--shared/systemd/src/shared/dns-domain.h117
-rw-r--r--shared/systemd/src/shared/log-link.h45
-rw-r--r--shared/systemd/src/shared/web-util.c63
-rw-r--r--shared/systemd/src/shared/web-util.h12
236 files changed, 0 insertions, 78797 deletions
diff --git a/shared/README.md b/shared/README.md
deleted file mode 100644
index ed950fce..00000000
--- a/shared/README.md
+++ /dev/null
@@ -1,108 +0,0 @@
-The "shared/" Directory
-=======================
-
-For NetworkManager we place helper/utility code under "shared/"
-in static libraries. The idea is to avoid code duplication but also
-provide high quality helper functions that simplify the higher layers.
-In NetworkManager there are complicated parts, for example "src/nm-manager.c"
-is huge. On the other hand, this helper code should be simple and easy
-to understand, so that we can build more complex code on top of it.
-
-As we statically link them into our binaries, they are all inherently
-internal API, that means they cannot be part of libnm's (libnm-core's) public API.
-It also means that their API/ABI is not stable.
-
-We don't care these libraries to be minimal and contain only symbols that are
-used by all users. Instead, we expect the linker to throw away unused symbols.
-We achieve this by having a symbol versioning file to hide internal symbols
-(which gives the linker a possibility to remove them if they are unused) and
-compiling with LTO or `"-Wl,--gc-sections"`. Let the tool solve this and not
-manual organization.
-
-Hence these libraries (and their content) are structured this way to satisfy
-the following questions:
-
-1) which dependencies (libraries) do they have? That determines which
-   other libraries can use it. For example:
-
-   - "shared/nm-std-aux" and "shared/nm-glib-aux" both provide general
-     purpose helpers, the difference is that the former has no dependency
-     on glib2 library. Both these libraries are a basic dependency for
-     many other parts of the code.
-
-   - "shared/nm-udev-aux" has a dependency on libudev, it thus cannot
-     be in "shared/nm-glib-aux".
-
-   - client code also has a glib2 dependency. That means it can link with
-     "shared/nm-std-aux" and "shared/nm-glib-aux", but must not link
-     with "shared/nm-udev-aux" (as it has no direct udev dependenct --
-     although clients get it indirectly because libnm already requires
-     it).
-
-2) what is their overall purpose? As said, we rely on the linker to
-   prune unused symbols. But in a few cases we avoid to merge different
-   code in the same library. For example:
-
-   - "shared/nm-glib-aux" and "shared/nm-base" both only have a
-     glib2 dependency. Hence, they could be merged. However we
-     don't do that because "shared/nm-base" is more about NetworkManager
-     specific code, while "shared/nm-glib-aux" is about general
-     purpose helpers.
-
-3) some of these libraries are forked from an upstream. They are kept
-   separate so that we can re-import future upstream versions.
-
-Detail
-======
-
-- `shared/c-list`
-- `shared/c-rbtree`
-- `shared/c-siphash`
-- `shared/c-stdoux`
-- `shared/n-acd`
-- `shared/n-dhcp4`
-
-   These are forked from upstream and imported with git-subtree. They
-   in general only have a libc dependency (or dependencies between each
-   other).
-
-- `shared/nm-std-aux`
-
-   This contains helper code with only a libc dependency.
-   Almost all C code depends on this library.
-
-- `shared/nm-glib-aux`
-
-   Like "shared/nm-std-aux" but also has a glib2 dependency.
-   Almost all glib2 code depends on this library.
-
-- `shared/nm-udev/aux`
-
-   Like "shared/nm-glib-aux" but also has a libudev dependency. It
-   has code related to libudev.
-
-- `shared/systemd`
-
-   These are forked from upstream systemd and imported with a script.
-   Under "shared/systemd/src" we try to keep the sources as close to
-   the original as possible. There is also some adapter code to make
-   it useable for us. It has a dependency on "shared/nm-glib-aux"
-   and will need a logging implementation for "shared/nm-glib-aux/nm-logging-fwd.h".
-
-- `shared/nm-base`
-
-   Depends on "shared/nm-glib-aux" and glib2 but it provides helper code
-   that more about NetworkManager specifc things.
-
-- `shared/nm-log-core`
-
-   This is the logging implementation as used by NetworkManager core ("src/").
-   It is also a dependency for "shared/nm-platform".
-
-- `shared/nm-platform`
-
-   Platform implementation. It depends on "shared/nm-log-core", "shared/nm-base"
-   and "shared/nm-glib-aux".
-
-- Other than that, there are still a few unorganized files/directories here.
-  These should be cleaned up.
diff --git a/shared/c-list/src/c-list.h b/shared/c-list/src/c-list.h
deleted file mode 100644
index c92aa6f3..00000000
--- a/shared/c-list/src/c-list.h
+++ /dev/null
@@ -1,443 +0,0 @@
-#pragma once
-
-/*
- * Circular Intrusive Double Linked List Collection in ISO-C11
- *
- * This implements a generic circular double linked list. List entries must
- * embed the CList object, which provides pointers to the next and previous
- * element. Insertion and removal can be done in O(1) due to the double links.
- * Furthermore, the list is circular, thus allows access to front/tail in O(1)
- * as well, even if you only have a single head pointer (which is not how the
- * list is usually operated, though).
- *
- * Note that you are free to use the list implementation without a head
- * pointer. However, usual operation uses a single CList object as head, which
- * is itself linked in the list and as such must be identified as list head.
- * This allows very simply list operations and avoids a lot of special cases.
- * Most importantly, you can unlink entries without requiring a head pointer.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stddef.h>
-
-typedef struct CList CList;
-
-/**
- * struct CList - Entry of a circular double linked list
- * @next:               next entry
- * @prev:               previous entry
- *
- * Each entry in a list must embed a CList object. This object contains
- * pointers to its next and previous elements, which can be freely accessed by
- * the API user at any time. Note that the list is circular, and the list head
- * is linked in the list as well.
- *
- * The list head must be initialized via C_LIST_INIT before use. There is no
- * reason to initialize entry objects before linking them. However, if you need
- * a boolean state that tells you whether the entry is linked or not, you should
- * initialize the entry via C_LIST_INIT as well.
- */
-struct CList {
-        CList *next;
-        CList *prev;
-};
-
-#define C_LIST_INIT(_var) { .next = &(_var), .prev = &(_var) }
-
-/**
- * c_list_init() - initialize list entry
- * @what:               list entry to initialize
- */
-static inline void c_list_init(CList *what) {
-        *what = (CList)C_LIST_INIT(*what);
-}
-
-/**
- * c_list_entry() - get parent container of list entry
- * @_what:              list entry, or NULL
- * @_t:                 type of parent container
- * @_m:                 member name of list entry in @_t
- *
- * If the list entry @_what is embedded into a surrounding structure, this will
- * turn the list entry pointer @_what into a pointer to the parent container
- * (using offsetof(3), or sometimes called container_of(3)).
- *
- * If @_what is NULL, this will also return NULL.
- *
- * Return: Pointer to parent container, or NULL.
- */
-#define c_list_entry(_what, _t, _m) \
-        ((_t *)(void *)(((unsigned long)(void *)(_what) ?: \
-                         offsetof(_t, _m)) - offsetof(_t, _m)))
-
-/**
- * c_list_is_linked() - check whether an entry is linked
- * @what:               entry to check, or NULL
- *
- * Return: True if @what is linked in a list, false if not.
- */
-static inline _Bool c_list_is_linked(const CList *what) {
-        return what && what->next != what;
-}
-
-/**
- * c_list_is_empty() - check whether a list is empty
- * @list:               list to check, or NULL
- *
- * This is the same as !c_list_is_linked().
- *
- * Return: True if @list is empty, false if not.
- */
-static inline _Bool c_list_is_empty(const CList *list) {
-        return !c_list_is_linked(list);
-}
-
-/**
- * c_list_link_before() - link entry into list
- * @where:              linked list entry used as anchor
- * @what:               entry to link
- *
- * This links @what directly in front of @where. @where can either be a list
- * head or any entry in the list.
- *
- * If @where points to the list head, this effectively links @what as new tail
- * element. Hence, the macro c_list_link_tail() is an alias to this.
- *
- * @what is not inspected prior to being linked. Hence, it better not be linked
- * into another list, or the other list will be corrupted.
- */
-static inline void c_list_link_before(CList *where, CList *what) {
-        CList *prev = where->prev, *next = where;
-
-        next->prev = what;
-        what->next = next;
-        what->prev = prev;
-        prev->next = what;
-}
-#define c_list_link_tail(_list, _what) c_list_link_before((_list), (_what))
-
-/**
- * c_list_link_after() - link entry into list
- * @where:              linked list entry used as anchor
- * @what:               entry to link
- *
- * This links @what directly after @where. @where can either be a list head or
- * any entry in the list.
- *
- * If @where points to the list head, this effectively links @what as new front
- * element. Hence, the macro c_list_link_front() is an alias to this.
- *
- * @what is not inspected prior to being linked. Hence, it better not be linked
- * into another list, or the other list will be corrupted.
- */
-static inline void c_list_link_after(CList *where, CList *what) {
-        CList *prev = where, *next = where->next;
-
-        next->prev = what;
-        what->next = next;
-        what->prev = prev;
-        prev->next = what;
-}
-#define c_list_link_front(_list, _what) c_list_link_after((_list), (_what))
-
-/**
- * c_list_unlink_stale() - unlink element from list
- * @what:               element to unlink
- *
- * This unlinks @what. If @what was initialized via C_LIST_INIT(), it has no
- * effect. If @what was never linked, nor initialized, behavior is undefined.
- *
- * Note that this does not modify @what. It just modifies the previous and next
- * elements in the list to no longer reference @what. If you want to make sure
- * @what is re-initialized after removal, use c_list_unlink().
- */
-static inline void c_list_unlink_stale(CList *what) {
-        CList *prev = what->prev, *next = what->next;
-
-        next->prev = prev;
-        prev->next = next;
-}
-
-/**
- * c_list_unlink() - unlink element from list and re-initialize
- * @what:               element to unlink
- *
- * This is like c_list_unlink_stale() but re-initializes @what after removal.
- */
-static inline void c_list_unlink(CList *what) {
-        /* condition is not needed, but avoids STOREs in fast-path */
-        if (c_list_is_linked(what)) {
-                c_list_unlink_stale(what);
-                *what = (CList)C_LIST_INIT(*what);
-        }
-}
-
-/**
- * c_list_swap() - exchange the contents of two lists
- * @list1:      the list to operate on
- * @list2:      the list to operate on
- *
- * This replaces the contents of the list @list1 with the contents
- * of @list2, and vice versa.
- */
-static inline void c_list_swap(CList *list1, CList *list2) {
-        CList t;
-
-        /* make neighbors of list1 point to list2, and vice versa */
-        t = *list1;
-        t.next->prev = list2;
-        t.prev->next = list2;
-        t = *list2;
-        t.next->prev = list1;
-        t.prev->next = list1;
-
-        /* swap list1 and list2 now that their neighbors were fixed up */
-        t = *list1;
-        *list1 = *list2;
-        *list2 = t;
-}
-
-/**
- * c_list_splice() - splice one list into another
- * @target:     the list to splice into
- * @source:     the list to splice
- *
- * This removes all the entries from @source and splice them into @target.
- * The order of the two lists is preserved and the source is appended
- * to the end of target.
- *
- * On return, the source list will be empty.
- */
-static inline void c_list_splice(CList *target, CList *source) {
-        if (!c_list_is_empty(source)) {
-                /* attach the front of @source to the tail of @target */
-                source->next->prev = target->prev;
-                target->prev->next = source->next;
-
-                /* attach the tail of @source to the front of @target */
-                source->prev->next = target;
-                target->prev = source->prev;
-
-                /* clear source */
-                *source = (CList)C_LIST_INIT(*source);
-        }
-}
-
-/**
- * c_list_first() - return pointer to first element, or NULL if empty
- * @list:               list to operate on, or NULL
- *
- * This returns a pointer to the first element, or NULL if empty. This never
- * returns a pointer to the list head.
- *
- * Return: Pointer to first list element, or NULL if empty.
- */
-static inline CList *c_list_first(CList *list) {
-        return c_list_is_empty(list) ? NULL : list->next;
-}
-
-/**
- * c_list_last() - return pointer to last element, or NULL if empty
- * @list:               list to operate on, or NULL
- *
- * This returns a pointer to the last element, or NULL if empty. This never
- * returns a pointer to the list head.
- *
- * Return: Pointer to last list element, or NULL if empty.
- */
-static inline CList *c_list_last(CList *list) {
-        return c_list_is_empty(list) ? NULL : list->prev;
-}
-
-/**
- * c_list_first_entry() - return pointer to first entry, or NULL if empty
- * @_list:              list to operate on, or NULL
- * @_t:                 type of list entries
- * @_m:                 name of CList member in @_t
- *
- * This is like c_list_first(), but also applies c_list_entry() on the result.
- *
- * Return: Pointer to first list entry, or NULL if empty.
- */
-#define c_list_first_entry(_list, _t, _m) \
-        c_list_entry(c_list_first(_list), _t, _m)
-
-/**
- * c_list_last_entry() - return pointer to last entry, or NULL if empty
- * @_list:              list to operate on, or NULL
- * @_t:                 type of list entries
- * @_m:                 name of CList member in @_t
- *
- * This is like c_list_last(), but also applies c_list_entry() on the result.
- *
- * Return: Pointer to last list entry, or NULL if empty.
- */
-#define c_list_last_entry(_list, _t, _m) \
-        c_list_entry(c_list_last(_list), _t, _m)
-
-/**
- * c_list_for_each*() - iterators
- *
- * The c_list_for_each*() macros provide simple for-loop wrappers to iterate
- * a linked list. They come in a set of flavours:
- *
- *   - "entry": This combines c_list_entry() with the loop iterator, so the
- *              iterator always has the type of the surrounding object, rather
- *              than CList.
- *
- *   - "safe": The loop iterator always keeps track of the next element to
- *             visit. This means, you can safely modify the current element,
- *             while retaining loop-integrity.
- *             You still must not touch any other entry of the list. Otherwise,
- *             the loop-iterator will be corrupted.
- *
- *   - "continue": Rather than starting the iteration at the front of the list,
- *                 use the current value of the iterator as starting position.
- *                 Note that the first loop iteration will be the following
- *                 element, not the given element.
- *
- *   - "unlink": This unlinks the current element from the list before the loop
- *               code is run. Note that this only does a partial unlink, since
- *               it assumes the entire list will be unlinked. You must not
- *               break out of the loop, or the list will be in an inconsistent
- *               state.
- */
-
-#define c_list_for_each(_iter, _list)                                           \
-        for (_iter = (_list)->next;                                             \
-             (_iter) != (_list);                                                \
-             _iter = (_iter)->next)
-
-#define c_list_for_each_entry(_iter, _list, _m)                                 \
-        for (_iter = c_list_entry((_list)->next, __typeof__(*_iter), _m);       \
-             &(_iter)->_m != (_list);                                           \
-             _iter = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m))
-
-#define c_list_for_each_safe(_iter, _safe, _list)                               \
-        for (_iter = (_list)->next, _safe = (_iter)->next;                      \
-             (_iter) != (_list);                                                \
-             _iter = (_safe), _safe = (_safe)->next)
-
-#define c_list_for_each_entry_safe(_iter, _safe, _list, _m)                     \
-        for (_iter = c_list_entry((_list)->next, __typeof__(*_iter), _m),       \
-             _safe = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m);    \
-             &(_iter)->_m != (_list);                                           \
-             _iter = (_safe),                                                   \
-             _safe = c_list_entry((_safe)->_m.next, __typeof__(*_iter), _m))    \
-
-#define c_list_for_each_continue(_iter, _list)                                  \
-        for (_iter = (_iter) ? (_iter)->next : (_list)->next;                   \
-             (_iter) != (_list);                                                \
-             _iter = (_iter)->next)
-
-#define c_list_for_each_entry_continue(_iter, _list, _m)                        \
-        for (_iter = c_list_entry((_iter) ? (_iter)->_m.next : (_list)->next,   \
-                                  __typeof__(*_iter),                           \
-                                  _m);                                          \
-             &(_iter)->_m != (_list);                                           \
-             _iter = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m))
-
-#define c_list_for_each_safe_continue(_iter, _safe, _list)                      \
-        for (_iter = (_iter) ? (_iter)->next : (_list)->next,                   \
-             _safe = (_iter)->next;                                             \
-             (_iter) != (_list);                                                \
-             _iter = (_safe), _safe = (_safe)->next)
-
-#define c_list_for_each_entry_safe_continue(_iter, _safe, _list, _m)            \
-        for (_iter = c_list_entry((_iter) ? (_iter)->_m.next : (_list)->next,   \
-                                  __typeof__(*_iter),                           \
-                                  _m),                                          \
-             _safe = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m);    \
-             &(_iter)->_m != (_list);                                           \
-             _iter = (_safe),                                                   \
-             _safe = c_list_entry((_safe)->_m.next, __typeof__(*_iter), _m))    \
-
-#define c_list_for_each_safe_unlink(_iter, _safe, _list)                        \
-        for (_iter = (_list)->next, _safe = (_iter)->next;                      \
-             ((*_iter = (CList)C_LIST_INIT(*_iter)), (_iter) != (_list));       \
-             _iter = (_safe), _safe = (_safe)->next)
-
-#define c_list_for_each_entry_safe_unlink(_iter, _safe, _list, _m)              \
-        for (_iter = c_list_entry((_list)->next, __typeof__(*_iter), _m),       \
-             _safe = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m);    \
-             (((_iter)->_m = (CList)C_LIST_INIT((_iter)->_m)),                  \
-              &(_iter)->_m != (_list));                                         \
-             _iter = (_safe),                                                   \
-             _safe = c_list_entry((_safe)->_m.next, __typeof__(*_iter), _m))    \
-
-/**
- * c_list_flush() - flush all entries from a list
- * @list:               list to flush
- *
- * This unlinks all entries from the given list @list and reinitializes their
- * link-nodes via C_LIST_INIT().
- *
- * Note that the entries are not modified in any other way, nor is their memory
- * released. This function just unlinks them and resets all the list nodes. It
- * is particularly useful with temporary lists on the stack in combination with
- * the GCC-extension __attribute__((__cleanup__(arg))).
- */
-static inline void c_list_flush(CList *list) {
-        CList *iter, *safe;
-
-        c_list_for_each_safe_unlink(iter, safe, list)
-                /* empty */ ;
-}
-
-/**
- * c_list_length() - return number of linked entries, excluding the head
- * @list:               list to operate on
- *
- * Returns the number of entries in the list, excluding the list head @list.
- * That is, for a list that is empty according to c_list_is_empty(), the
- * returned length is 0. This requires to iterate the list and has thus O(n)
- * runtime.
- *
- * Note that this function is meant for debugging purposes only. If you need
- * the list size during normal operation, you should maintain a counter
- * separately.
- *
- * Return: Number of items in @list.
- */
-static inline unsigned long c_list_length(const CList *list) {
-        unsigned long n = 0;
-        const CList *iter;
-
-        c_list_for_each(iter, list)
-                ++n;
-
-        return n;
-}
-
-/**
- * c_list_contains() - check whether an entry is linked in a certain list
- * @list:               list to operate on
- * @what:               entry to look for
- *
- * This checks whether @what is linked into @list. This requires a linear
- * search through the list, as such runs in O(n). Note that the list-head is
- * considered part of the list, and hence this returns true if @what equals
- * @list.
- *
- * Note that this function is meant for debugging purposes, and consistency
- * checks. You should always be aware whether your objects are linked in a
- * specific list.
- *
- * Return: True if @what is in @list, false otherwise.
- */
-static inline _Bool c_list_contains(const CList *list, const CList *what) {
-        const CList *iter;
-
-        c_list_for_each(iter, list)
-                if (what == iter)
-                        return 1;
-
-        return what == list;
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/shared/c-rbtree/src/c-rbtree-private.h b/shared/c-rbtree/src/c-rbtree-private.h
deleted file mode 100644
index c9befbf3..00000000
--- a/shared/c-rbtree/src/c-rbtree-private.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#pragma once
-
-/*
- * Private definitions
- * This file contains private definitions for the RB-Tree implementation, but
- * which are used by our test-suite.
- */
-
-#include <c-stdaux.h>
-#include <stddef.h>
-#include "c-rbtree.h"
-
-/*
- * Nodes
- */
-
-static inline void *c_rbnode_raw(CRBNode *n) {
-        return (void *)(n->__parent_and_flags & ~C_RBNODE_FLAG_MASK);
-}
-
-static inline unsigned long c_rbnode_flags(CRBNode *n) {
-        return n->__parent_and_flags & C_RBNODE_FLAG_MASK;
-}
-
-static inline _Bool c_rbnode_is_red(CRBNode *n) {
-        return c_rbnode_flags(n) & C_RBNODE_RED;
-}
-
-static inline _Bool c_rbnode_is_black(CRBNode *n) {
-        return !(c_rbnode_flags(n) & C_RBNODE_RED);
-}
-
-static inline _Bool c_rbnode_is_root(CRBNode *n) {
-        return c_rbnode_flags(n) & C_RBNODE_ROOT;
-}
diff --git a/shared/c-rbtree/src/c-rbtree.c b/shared/c-rbtree/src/c-rbtree.c
deleted file mode 100644
index 2f0e608f..00000000
--- a/shared/c-rbtree/src/c-rbtree.c
+++ /dev/null
@@ -1,1120 +0,0 @@
-/*
- * RB-Tree Implementation
- * This implements the insertion/removal of elements in RB-Trees. You're highly
- * recommended to have an RB-Tree documentation at hand when reading this. Both
- * insertion and removal can be split into a handful of situations that can
- * occur. Those situations are enumerated as "Case 1" to "Case n" here, and
- * follow closely the cases described in most RB-Tree documentations. This file
- * does not explain why it is enough to handle just those cases, nor does it
- * provide a proof of correctness. Dig out your algorithm 101 handbook if
- * you're interested.
- *
- * This implementation is *not* straightforward. Usually, a handful of
- * rotation, reparent, swap and link helpers can be used to implement the
- * rebalance operations. However, those often perform unnecessary writes.
- * Therefore, this implementation hard-codes all the operations. You're highly
- * recommended to look at the two basic helpers before reading the code:
- *     c_rbnode_swap_child()
- *     c_rbnode_set_parent_and_flags()
- * Those are the only helpers used, hence, you should really know what they do
- * before digging into the code.
- *
- * For a highlevel documentation of the API, see the header file and docbook
- * comments.
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <stdalign.h>
-#include <stddef.h>
-#include "c-rbtree.h"
-#include "c-rbtree-private.h"
-
-/*
- * We use the lower 2 bits of CRBNode pointers to store flags. Make sure
- * CRBNode is 4-byte aligned, so the lower 2 bits are actually unused. We also
- * sometimes store a pointer to the root-node, so make sure this one is also 4
- * byte aligned.
- * Note that there are actually some architectures where `max_align_t` is 4, so
- * we do not have much wiggle-room to extend this flag-set.
- */
-static_assert(alignof(CRBNode) <= alignof(max_align_t), "Invalid RBNode alignment");
-static_assert(alignof(CRBNode) >= 4, "Invalid CRBNode alignment");
-static_assert(alignof(CRBTree) <= alignof(max_align_t), "Invalid RBTree alignment");
-static_assert(alignof(CRBTree) >= 4, "Invalid CRBTree alignment");
-
-/**
- * c_rbnode_leftmost() - return leftmost child
- * @n:          current node, or NULL
- *
- * This returns the leftmost child of @n. If @n is NULL, this will return NULL.
- * In all other cases, this function returns a valid pointer. That is, if @n
- * does not have any left children, this returns @n.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to leftmost child, or NULL.
- */
-_c_public_ CRBNode *c_rbnode_leftmost(CRBNode *n) {
-        if (n)
-                while (n->left)
-                        n = n->left;
-        return n;
-}
-
-/**
- * c_rbnode_rightmost() - return rightmost child
- * @n:          current node, or NULL
- *
- * This returns the rightmost child of @n. If @n is NULL, this will return
- * NULL. In all other cases, this function returns a valid pointer. That is, if
- * @n does not have any right children, this returns @n.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to rightmost child, or NULL.
- */
-_c_public_ CRBNode *c_rbnode_rightmost(CRBNode *n) {
-        if (n)
-                while (n->right)
-                        n = n->right;
-        return n;
-}
-
-/**
- * c_rbnode_leftdeepest() - return left-deepest child
- * @n:          current node, or NULL
- *
- * This returns the left-deepest child of @n. If @n is NULL, this will return
- * NULL. In all other cases, this function returns a valid pointer. That is, if
- * @n does not have any children, this returns @n.
- *
- * The left-deepest child is defined as the deepest child without any left
- * (grand-...)siblings.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to left-deepest child, or NULL.
- */
-_c_public_ CRBNode *c_rbnode_leftdeepest(CRBNode *n) {
-        if (n) {
-                for (;;) {
-                        if (n->left)
-                                n = n->left;
-                        else if (n->right)
-                                n = n->right;
-                        else
-                                break;
-                }
-        }
-        return n;
-}
-
-/**
- * c_rbnode_rightdeepest() - return right-deepest child
- * @n:          current node, or NULL
- *
- * This returns the right-deepest child of @n. If @n is NULL, this will return
- * NULL. In all other cases, this function returns a valid pointer. That is, if
- * @n does not have any children, this returns @n.
- *
- * The right-deepest child is defined as the deepest child without any right
- * (grand-...)siblings.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to right-deepest child, or NULL.
- */
-_c_public_ CRBNode *c_rbnode_rightdeepest(CRBNode *n) {
-        if (n) {
-                for (;;) {
-                        if (n->right)
-                                n = n->right;
-                        else if (n->left)
-                                n = n->left;
-                        else
-                                break;
-                }
-        }
-        return n;
-}
-
-/**
- * c_rbnode_next() - return next node
- * @n:          current node, or NULL
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically next node to @n. If @n is NULL, the last node or
- * unlinked, this returns NULL.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to next node, or NULL.
- */
-_c_public_ CRBNode *c_rbnode_next(CRBNode *n) {
-        CRBNode *p;
-
-        if (!c_rbnode_is_linked(n))
-                return NULL;
-        if (n->right)
-                return c_rbnode_leftmost(n->right);
-
-        while ((p = c_rbnode_parent(n)) && n == p->right)
-                n = p;
-
-        return p;
-}
-
-/**
- * c_rbnode_prev() - return previous node
- * @n:          current node, or NULL
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically previous node to @n. If @n is NULL, the first node or
- * unlinked, this returns NULL.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to previous node, or NULL.
- */
-_c_public_ CRBNode *c_rbnode_prev(CRBNode *n) {
-        CRBNode *p;
-
-        if (!c_rbnode_is_linked(n))
-                return NULL;
-        if (n->left)
-                return c_rbnode_rightmost(n->left);
-
-        while ((p = c_rbnode_parent(n)) && n == p->left)
-                n = p;
-
-        return p;
-}
-
-/**
- * c_rbnode_next_postorder() - return next node in post-order
- * @n:          current node, or NULL
- *
- * This returns the next node to @n, based on a left-to-right post-order
- * traversal. If @n is NULL, the root node, or unlinked, this returns NULL.
- *
- * This implements a left-to-right post-order traversal: First visit the left
- * child of a node, then the right, and lastly the node itself. Children are
- * traversed recursively.
- *
- * This function can be used to implement a left-to-right post-order traversal:
- *
- *     for (n = c_rbtree_first_postorder(t); n; n = c_rbnode_next_postorder(n))
- *             visit(n);
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to next node, or NULL.
- */
-_c_public_ CRBNode *c_rbnode_next_postorder(CRBNode *n) {
-        CRBNode *p;
-
-        if (!c_rbnode_is_linked(n))
-                return NULL;
-
-        p = c_rbnode_parent(n);
-        if (p && n == p->left && p->right)
-                return c_rbnode_leftdeepest(p->right);
-
-        return p;
-}
-
-/**
- * c_rbnode_prev_postorder() - return previous node in post-order
- * @n:          current node, or NULL
- *
- * This returns the previous node to @n, based on a left-to-right post-order
- * traversal. That is, it is the inverse operation to c_rbnode_next_postorder().
- * If @n is NULL, the left-deepest node, or unlinked, this returns NULL.
- *
- * This function returns the logical previous node in a directed post-order
- * traversal. That is, it effectively does a pre-order traversal (since a
- * reverse post-order traversal is a pre-order traversal). This function does
- * NOT do a right-to-left post-order traversal! In other words, the following
- * invariant is guaranteed, if c_rbnode_next_postorder(n) is non-NULL:
- *
- *     n == c_rbnode_prev_postorder(c_rbnode_next_postorder(n))
- *
- * This function can be used to implement a right-to-left pre-order traversal,
- * using the fact that a reverse post-order traversal is also a valid pre-order
- * traversal:
- *
- *     for (n = c_rbtree_last_postorder(t); n; n = c_rbnode_prev_postorder(n))
- *             visit(n);
- *
- * This would effectively perform a right-to-left pre-order traversal: first
- * visit a parent, then its right child, then its left child. Both children are
- * traversed recursively.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to previous node in post-order, or NULL.
- */
-_c_public_ CRBNode *c_rbnode_prev_postorder(CRBNode *n) {
-        CRBNode *p;
-
-        if (!c_rbnode_is_linked(n))
-                return NULL;
-        if (n->right)
-                return n->right;
-        if (n->left)
-                return n->left;
-
-        while ((p = c_rbnode_parent(n))) {
-                if (p->left && n != p->left)
-                        return p->left;
-                n = p;
-        }
-
-        return NULL;
-}
-
-/**
- * c_rbtree_first() - return first node
- * @t:          tree to operate on
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically first node in @t. If @t is empty, NULL is returned.
- *
- * Fixed runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to first node, or NULL.
- */
-_c_public_ CRBNode *c_rbtree_first(CRBTree *t) {
-        c_assert(t);
-        return c_rbnode_leftmost(t->root);
-}
-
-/**
- * c_rbtree_last() - return last node
- * @t:          tree to operate on
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically last node in @t. If @t is empty, NULL is returned.
- *
- * Fixed runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to last node, or NULL.
- */
-_c_public_ CRBNode *c_rbtree_last(CRBTree *t) {
-        c_assert(t);
-        return c_rbnode_rightmost(t->root);
-}
-
-/**
- * c_rbtree_first_postorder() - return first node in post-order
- * @t:          tree to operate on
- *
- * This returns the first node of a left-to-right post-order traversal. That
- * is, it returns the left-deepest leaf. If the tree is empty, this returns
- * NULL.
- *
- * This can also be interpreted as the last node of a right-to-left pre-order
- * traversal.
- *
- * Fixed runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to first node in post-order, or NULL.
- */
-_c_public_ CRBNode *c_rbtree_first_postorder(CRBTree *t) {
-        c_assert(t);
-        return c_rbnode_leftdeepest(t->root);
-}
-
-/**
- * c_rbtree_last_postorder() - return last node in post-order
- * @t:          tree to operate on
- *
- * This returns the last node of a left-to-right post-order traversal. That is,
- * it always returns the root node, or NULL if the tree is empty.
- *
- * This can also be interpreted as the first node of a right-to-left pre-order
- * traversal.
- *
- * Fixed runtime (n: number of elements in tree): O(1)
- *
- * Return: Pointer to last node in post-order, or NULL.
- */
-_c_public_ CRBNode *c_rbtree_last_postorder(CRBTree *t) {
-        c_assert(t);
-        return t->root;
-}
-
-static inline void c_rbtree_store(CRBNode **ptr, CRBNode *addr) {
-        /*
-         * We use volatile accesses whenever we STORE @left or @right members
-         * of a node. This guarantees that any parallel, lockless lookup gets
-         * to see those stores in the correct order, which itself guarantees
-         * that there're no temporary loops during tree rotation.
-         * Note that you still need to properly synchronize your accesses via
-         * seqlocks, rcu, whatever. We just guarantee that you get *some*
-         * result on a lockless traversal and never run into endless loops, or
-         * undefined behavior.
-         */
-        *(volatile CRBNode **)ptr = addr;
-}
-
-/*
- * Set the flags and parent of a node. This should be treated as a simple
- * assignment of the 'flags' and 'parent' fields of the node. No other magic is
- * applied. But since both fields share its backing memory, this helper
- * function is provided.
- */
-static inline void c_rbnode_set_parent_and_flags(CRBNode *n, CRBNode *p, unsigned long flags) {
-        n->__parent_and_flags = (unsigned long)p | flags;
-}
-
-/*
- * Nodes in the tree do not separately store a point to the tree root. That is,
- * there is no way to access the tree-root in O(1) given an arbitrary node.
- * Fortunately, this is usually not required. The only situation where this is
- * needed is when rotating the root-node itself.
- *
- * In case of the root node, c_rbnode_parent() returns NULL. We use this fact
- * to re-use the parent-pointer storage of the root node to point to the
- * CRBTree root. This way, we can rotate the root-node (or add/remove it)
- * without requiring a separate tree-root pointer.
- *
- * However, to keep the tree-modification functions simple, we hide this detail
- * whenever possible. This means, c_rbnode_parent() will continue to return
- * NULL, and tree modifications will boldly reset the pointer to NULL on
- * rotation. Hence, the only way to retain this pointer is to call
- * c_rbnode_pop_root() on a possible root-node before rotating. This returns
- * NULL if the node in question is not the root node. Otherwise, it returns the
- * tree-root, and clears the pointer/flag from the node in question. This way,
- * you can perform tree operations as usual. Afterwards, use
- * c_rbnode_push_root() to restore the root-pointer on any possible new root.
- */
-static inline CRBTree *c_rbnode_pop_root(CRBNode *n) {
-        CRBTree *t = NULL;
-
-        if (c_rbnode_is_root(n)) {
-                t = c_rbnode_raw(n);
-                n->__parent_and_flags = c_rbnode_flags(n) & ~C_RBNODE_ROOT;
-        }
-
-        return t;
-}
-
-/* counter-part to c_rbnode_pop_root() */
-static inline CRBTree *c_rbnode_push_root(CRBNode *n, CRBTree *t) {
-        if (t) {
-                if (n)
-                        n->__parent_and_flags = (unsigned long)t
-                                                | c_rbnode_flags(n)
-                                                | C_RBNODE_ROOT;
-                c_rbtree_store(&t->root, n);
-        }
-
-        return NULL;
-}
-
-/*
- * This function partially swaps a child node with another one. That is, this
- * function changes the parent of @old to point to @new. That is, you use it
- * when swapping @old with @new, to update the parent's left/right pointer.
- * This function does *NOT* perform a full swap, nor does it touch any 'parent'
- * pointer.
- *
- * The sole purpose of this function is to shortcut left/right conditionals
- * like this:
- *
- *     if (old == old->parent->left)
- *             old->parent->left = new;
- *     else
- *             old->parent->right = new;
- *
- * That's it! If @old is the root node, this will do nothing. The caller must
- * employ c_rbnode_pop_root() and c_rbnode_push_root().
- */
-static inline void c_rbnode_swap_child(CRBNode *old, CRBNode *new) {
-        CRBNode *p = c_rbnode_parent(old);
-
-        if (p) {
-                if (p->left == old)
-                        c_rbtree_store(&p->left, new);
-                else
-                        c_rbtree_store(&p->right, new);
-        }
-}
-
-/**
- * c_rbtree_move() - move tree
- * @to:         destination tree
- * @from:       source tree
- *
- * This imports the entire tree from @from into @to. @to must be empty! @from
- * will be empty afterwards.
- *
- * Note that this operates in O(1) time. Only the root-entry is updated to
- * point to the new tree-root.
- */
-_c_public_ void c_rbtree_move(CRBTree *to, CRBTree *from) {
-        CRBTree *t;
-
-        c_assert(!to->root);
-
-        if (from->root) {
-                t = c_rbnode_pop_root(from->root);
-                c_assert(t == from);
-
-                to->root = from->root;
-                from->root = NULL;
-
-                c_rbnode_push_root(to->root, to);
-        }
-}
-
-static inline void c_rbtree_paint_terminal(CRBNode *n) {
-        CRBNode *p, *g, *gg, *x;
-        CRBTree *t;
-
-        /*
-         * Case 4:
-         * This path assumes @n is red, @p is red, but the uncle is unset or
-         * black. This implies @g exists and is black.
-         *
-         * This case requires up to 2 rotations to restore the tree invariants.
-         * That is, it runs in O(1) time and fully restores the RB-Tree
-         * invariants, all at the cost of performing at mots 2 rotations.
-         */
-
-        p = c_rbnode_parent(n);
-        g = c_rbnode_parent(p);
-        gg = c_rbnode_parent(g);
-
-        c_assert(c_rbnode_is_red(p));
-        c_assert(c_rbnode_is_black(g));
-        c_assert(p == g->left || !g->left || c_rbnode_is_black(g->left));
-        c_assert(p == g->right || !g->right || c_rbnode_is_black(g->right));
-
-        if (p == g->left) {
-                if (n == p->right) {
-                        /*
-                         * We're the right red child of a red parent, which is
-                         * a left child. Rotate on parent and consider us to be
-                         * the old parent and the old parent to be us, making us
-                         * the left child instead of the right child so we can
-                         * handle it the same as below. Rotating two red nodes
-                         * changes none of the invariants.
-                         */
-                        x = n->left;
-                        c_rbtree_store(&p->right, x);
-                        c_rbtree_store(&n->left, p);
-                        if (x)
-                                c_rbnode_set_parent_and_flags(x, p, c_rbnode_flags(x));
-                        c_rbnode_set_parent_and_flags(p, n, c_rbnode_flags(p));
-                        p = n;
-                }
-
-                /* 'n' is invalid from here on! */
-
-                /*
-                 * We're the red left child of a red parent, black grandparent
-                 * and uncle. Rotate parent on grandparent and switch their
-                 * colors, making the parent black and the grandparent red. The
-                 * root of this subtree was changed from the grandparent to the
-                 * parent, but the color remained black, so the number of black
-                 * nodes on each path stays the same. However, we got rid of
-                 * the double red path as we are still the (red) child of the
-                 * parent, which has now turned black. Note that had we been
-                 * the right child, rather than the left child, we would now be
-                 * the left child of the old grandparent, and we would still
-                 * have a double red path. As the new grandparent remains
-                 * black, we're done.
-                 */
-                x = p->right;
-                t = c_rbnode_pop_root(g);
-                c_rbtree_store(&g->left, x);
-                c_rbtree_store(&p->right, g);
-                c_rbnode_swap_child(g, p);
-                if (x)
-                        c_rbnode_set_parent_and_flags(x, g, c_rbnode_flags(x) & ~C_RBNODE_RED);
-                c_rbnode_set_parent_and_flags(p, gg, c_rbnode_flags(p) & ~C_RBNODE_RED);
-                c_rbnode_set_parent_and_flags(g, p, c_rbnode_flags(g) | C_RBNODE_RED);
-                c_rbnode_push_root(p, t);
-        } else /* if (p == g->right) */ { /* same as above, but mirrored */
-                if (n == p->left) {
-                        x = n->right;
-                        c_rbtree_store(&p->left, n->right);
-                        c_rbtree_store(&n->right, p);
-                        if (x)
-                                c_rbnode_set_parent_and_flags(x, p, c_rbnode_flags(x));
-                        c_rbnode_set_parent_and_flags(p, n, c_rbnode_flags(p));
-                        p = n;
-                }
-
-                x = p->left;
-                t = c_rbnode_pop_root(g);
-                c_rbtree_store(&g->right, x);
-                c_rbtree_store(&p->left, g);
-                c_rbnode_swap_child(g, p);
-                if (x)
-                        c_rbnode_set_parent_and_flags(x, g, c_rbnode_flags(x) & ~C_RBNODE_RED);
-                c_rbnode_set_parent_and_flags(p, gg, c_rbnode_flags(p) & ~C_RBNODE_RED);
-                c_rbnode_set_parent_and_flags(g, p, c_rbnode_flags(g) | C_RBNODE_RED);
-                c_rbnode_push_root(p, t);
-        }
-}
-
-static inline CRBNode *c_rbtree_paint_path(CRBNode *n) {
-        CRBNode *p, *g, *u;
-
-        for (;;) {
-                p = c_rbnode_parent(n);
-                if (!p) {
-                        /*
-                         * Case 1:
-                         * We reached the root. Mark it black and be done. As
-                         * all leaf-paths share the root, the ratio of black
-                         * nodes on each path stays the same.
-                         */
-                        c_rbnode_set_parent_and_flags(n, c_rbnode_raw(n), c_rbnode_flags(n) & ~C_RBNODE_RED);
-                        return NULL;
-                } else if (c_rbnode_is_black(p)) {
-                        /*
-                         * Case 2:
-                         * The parent is already black. As our node is red, we
-                         * did not change the number of black nodes on any
-                         * path, nor do we have multiple consecutive red nodes.
-                         * There is nothing to be done.
-                         */
-                        return NULL;
-                }
-
-                g = c_rbnode_parent(p);
-                u = (p == g->left) ? g->right : g->left;
-                if (!u || !c_rbnode_is_red(u)) {
-                        /*
-                         * Case 4:
-                         * The parent is red, but its uncle is black. By
-                         * rotating the parent above the uncle, we distribute
-                         * the red nodes and thus restore the tree invariants.
-                         * No recursive fixup will be needed afterwards. Hence,
-                         * just let the caller know about @n and make them do
-                         * the rotations.
-                         */
-                        return n;
-                }
-
-                /*
-                 * Case 3:
-                 * Parent and uncle are both red, and grandparent is black.
-                 * Repaint parent and uncle black, the grandparent red and
-                 * recurse into the grandparent. Note that this is the only
-                 * recursive case. That is, this step restores the tree
-                 * invariants for the sub-tree below @p (including @n), but
-                 * needs to continue the re-coloring two levels up.
-                 */
-                c_rbnode_set_parent_and_flags(p, g, c_rbnode_flags(p) & ~C_RBNODE_RED);
-                c_rbnode_set_parent_and_flags(u, g, c_rbnode_flags(u) & ~C_RBNODE_RED);
-                c_rbnode_set_parent_and_flags(g, c_rbnode_raw(g), c_rbnode_flags(g) | C_RBNODE_RED);
-                n = g;
-        }
-}
-
-static inline void c_rbtree_paint(CRBNode *n) {
-        /*
-         * When a new node is inserted into an RB-Tree, we always link it as a
-         * tail-node and paint it red. This way, the node will not violate the
-         * rb-tree invariants regarding the number of black nodes on all paths.
-         *
-         * However, a red node must never have another bordering red-node (ie.,
-         * child or parent). Since the node is newly linked, it does not have
-         * any children. Therefore, all we need to do is fix the path upwards
-         * through all parents until we hit a black parent or can otherwise fix
-         * the coloring.
-         *
-         * This function first walks up the path from @n towards the tree root
-         * (done in c_rbtree_paint_path()). This recolors its parent/uncle, if
-         * possible, until it hits a sub-tree that cannot be fixed via
-         * re-coloring. After c_rbtree_paint_path() returns, there are two
-         * possible outcomes:
-         *
-         *         1) @n is NULL, in which case the tree invariants were
-         *            restored by mere recoloring. Nothing is to be done.
-         *
-         *         2) @n is non-NULL, but points to a red ancestor of the
-         *            original node. In this case we need to restore the tree
-         *            invariants via a simple left or right rotation. This will
-         *            be done by c_rbtree_paint_terminal().
-         *
-         * As a summary, this function runs O(log(n)) re-coloring operations in
-         * the worst case, followed by O(1) rotations as final restoration. The
-         * amortized cost, however, is O(1), since re-coloring only recurses
-         * upwards if it hits a red uncle (which can only happen if a previous
-         * operation terminated its operation on that layer).
-         * While amortized painting of inserted nodes is O(1), finding the
-         * correct spot to link the node (before painting it) still requires a
-         * search in the binary tree in O(log(n)).
-         */
-        n = c_rbtree_paint_path(n);
-        if (n)
-                c_rbtree_paint_terminal(n);
-}
-
-/**
- * c_rbnode_link() - link node into tree
- * @p:          parent node to link under
- * @l:          left/right slot of @p to link at
- * @n:          node to add
- *
- * This links @n into an tree underneath another node. The caller must provide
- * the exact spot where to link the node. That is, the caller must traverse the
- * tree based on their search order. Once they hit a leaf where to insert the
- * node, call this function to link it and rebalance the tree.
- *
- * For this to work, the caller must provide a pointer to the parent node. If
- * the tree might be empty, you must resort to c_rbtree_add().
- *
- * In most cases you are better off using c_rbtree_add(). See there for details
- * how tree-insertion works.
- */
-_c_public_ void c_rbnode_link(CRBNode *p, CRBNode **l, CRBNode *n) {
-        c_assert(p);
-        c_assert(l);
-        c_assert(n);
-        c_assert(l == &p->left || l == &p->right);
-
-        c_rbnode_set_parent_and_flags(n, p, C_RBNODE_RED);
-        c_rbtree_store(&n->left, NULL);
-        c_rbtree_store(&n->right, NULL);
-        c_rbtree_store(l, n);
-
-        c_rbtree_paint(n);
-}
-
-/**
- * c_rbtree_add() - add node to tree
- * @t:          tree to operate one
- * @p:          parent node to link under, or NULL
- * @l:          left/right slot of @p (or root) to link at
- * @n:          node to add
- *
- * This links @n into the tree given as @t. The caller must provide the exact
- * spot where to link the node. That is, the caller must traverse the tree
- * based on their search order. Once they hit a leaf where to insert the node,
- * call this function to link it and rebalance the tree.
- *
- * A typical insertion would look like this (@t is your tree, @n is your node):
- *
- *        CRBNode **i, *p;
- *
- *        i = &t->root;
- *        p = NULL;
- *        while (*i) {
- *                p = *i;
- *                if (compare(n, *i) < 0)
- *                        i = &(*i)->left;
- *                else
- *                        i = &(*i)->right;
- *        }
- *
- *        c_rbtree_add(t, p, i, n);
- *
- * Once the node is linked into the tree, a simple lookup on the same tree can
- * be coded like this:
- *
- *        CRBNode *i;
- *
- *        i = t->root;
- *        while (i) {
- *                int v = compare(n, i);
- *                if (v < 0)
- *                        i = (*i)->left;
- *                else if (v > 0)
- *                        i = (*i)->right;
- *                else
- *                        break;
- *        }
- *
- * When you add nodes to a tree, the memory contents of the node do not matter.
- * That is, there is no need to initialize the node via c_rbnode_init().
- * However, if you relink nodes multiple times during their lifetime, it is
- * usually very convenient to use c_rbnode_init() and c_rbnode_unlink() (rather
- * than c_rbnode_unlink_stale()). In those cases, you should validate that a
- * node is unlinked before you call c_rbtree_add().
- */
-_c_public_ void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n) {
-        c_assert(t);
-        c_assert(l);
-        c_assert(n);
-        c_assert(!p || l == &p->left || l == &p->right);
-        c_assert(p || l == &t->root);
-
-        c_rbnode_set_parent_and_flags(n, p, C_RBNODE_RED);
-        c_rbtree_store(&n->left, NULL);
-        c_rbtree_store(&n->right, NULL);
-
-        if (p)
-                c_rbtree_store(l, n);
-        else
-                c_rbnode_push_root(n, t);
-
-        c_rbtree_paint(n);
-}
-
-static inline void c_rbnode_rebalance_terminal(CRBNode *p, CRBNode *previous) {
-        CRBNode *s, *x, *y, *g;
-        CRBTree *t;
-
-        if (previous == p->left) {
-                s = p->right;
-                if (c_rbnode_is_red(s)) {
-                        /*
-                         * Case 2:
-                         * We have a red node as sibling. Rotate it onto our
-                         * side so we can later on turn it black. This way, we
-                         * gain the additional black node in our path.
-                         */
-                        t = c_rbnode_pop_root(p);
-                        g = c_rbnode_parent(p);
-                        x = s->left;
-                        c_rbtree_store(&p->right, x);
-                        c_rbtree_store(&s->left, p);
-                        c_rbnode_swap_child(p, s);
-                        c_rbnode_set_parent_and_flags(x, p, c_rbnode_flags(x) & ~C_RBNODE_RED);
-                        c_rbnode_set_parent_and_flags(s, g, c_rbnode_flags(s) & ~C_RBNODE_RED);
-                        c_rbnode_set_parent_and_flags(p, s, c_rbnode_flags(p) | C_RBNODE_RED);
-                        c_rbnode_push_root(s, t);
-                        s = x;
-                }
-
-                x = s->right;
-                if (!x || c_rbnode_is_black(x)) {
-                        y = s->left;
-                        if (!y || c_rbnode_is_black(y)) {
-                                /*
-                                 * Case 3+4:
-                                 * Our sibling is black and has only black
-                                 * children. Flip it red and turn parent black.
-                                 * This way we gained a black node in our path.
-                                 * Note that the parent must be red, otherwise
-                                 * it must have been handled by our caller.
-                                 */
-                                c_assert(c_rbnode_is_red(p));
-                                c_rbnode_set_parent_and_flags(s, p, c_rbnode_flags(s) | C_RBNODE_RED);
-                                c_rbnode_set_parent_and_flags(p, c_rbnode_parent(p), c_rbnode_flags(p) & ~C_RBNODE_RED);
-                                return;
-                        }
-
-                        /*
-                         * Case 5:
-                         * Left child of our sibling is red, right one is black.
-                         * Rotate on parent so the right child of our sibling is
-                         * now red, and we can fall through to case 6.
-                         */
-                        x = y->right;
-                        c_rbtree_store(&s->left, y->right);
-                        c_rbtree_store(&y->right, s);
-                        c_rbtree_store(&p->right, y);
-                        if (x)
-                                c_rbnode_set_parent_and_flags(x, s, c_rbnode_flags(x) & ~C_RBNODE_RED);
-                        x = s;
-                        s = y;
-                }
-
-                /*
-                 * Case 6:
-                 * The right child of our sibling is red. Rotate left and flip
-                 * colors, which gains us an additional black node in our path,
-                 * that was previously on our sibling.
-                 */
-                t = c_rbnode_pop_root(p);
-                g = c_rbnode_parent(p);
-                y = s->left;
-                c_rbtree_store(&p->right, y);
-                c_rbtree_store(&s->left, p);
-                c_rbnode_swap_child(p, s);
-                c_rbnode_set_parent_and_flags(x, s, c_rbnode_flags(x) & ~C_RBNODE_RED);
-                if (y)
-                        c_rbnode_set_parent_and_flags(y, p, c_rbnode_flags(y));
-                c_rbnode_set_parent_and_flags(s, g, c_rbnode_flags(p));
-                c_rbnode_set_parent_and_flags(p, s, c_rbnode_flags(p) & ~C_RBNODE_RED);
-                c_rbnode_push_root(s, t);
-        } else /* if (previous == p->right) */ { /* same as above, but mirrored */
-                s = p->left;
-                if (c_rbnode_is_red(s)) {
-                        t = c_rbnode_pop_root(p);
-                        g = c_rbnode_parent(p);
-                        x = s->right;
-                        c_rbtree_store(&p->left, x);
-                        c_rbtree_store(&s->right, p);
-                        c_rbnode_swap_child(p, s);
-                        c_rbnode_set_parent_and_flags(x, p, c_rbnode_flags(x) & ~C_RBNODE_RED);
-                        c_rbnode_set_parent_and_flags(s, g, c_rbnode_flags(s) & ~C_RBNODE_RED);
-                        c_rbnode_set_parent_and_flags(p, s, c_rbnode_flags(p) | C_RBNODE_RED);
-                        c_rbnode_push_root(s, t);
-                        s = x;
-                }
-
-                x = s->left;
-                if (!x || c_rbnode_is_black(x)) {
-                        y = s->right;
-                        if (!y || c_rbnode_is_black(y)) {
-                                c_assert(c_rbnode_is_red(p));
-                                c_rbnode_set_parent_and_flags(s, p, c_rbnode_flags(s) | C_RBNODE_RED);
-                                c_rbnode_set_parent_and_flags(p, c_rbnode_parent(p), c_rbnode_flags(p) & ~C_RBNODE_RED);
-                                return;
-                        }
-
-                        x = y->left;
-                        c_rbtree_store(&s->right, y->left);
-                        c_rbtree_store(&y->left, s);
-                        c_rbtree_store(&p->left, y);
-                        if (x)
-                                c_rbnode_set_parent_and_flags(x, s, c_rbnode_flags(x) & ~C_RBNODE_RED);
-                        x = s;
-                        s = y;
-                }
-
-                t = c_rbnode_pop_root(p);
-                g = c_rbnode_parent(p);
-                y = s->right;
-                c_rbtree_store(&p->left, y);
-                c_rbtree_store(&s->right, p);
-                c_rbnode_swap_child(p, s);
-                c_rbnode_set_parent_and_flags(x, s, c_rbnode_flags(x) & ~C_RBNODE_RED);
-                if (y)
-                        c_rbnode_set_parent_and_flags(y, p, c_rbnode_flags(y));
-                c_rbnode_set_parent_and_flags(s, g, c_rbnode_flags(p));
-                c_rbnode_set_parent_and_flags(p, s, c_rbnode_flags(p) & ~C_RBNODE_RED);
-                c_rbnode_push_root(s, t);
-        }
-}
-
-static inline CRBNode *c_rbnode_rebalance_path(CRBNode *p, CRBNode **previous) {
-        CRBNode *s, *nl, *nr;
-
-        while (p) {
-                s = (*previous == p->left) ? p->right : p->left;
-                nl = s->left;
-                nr = s->right;
-
-                /*
-                 * If the sibling under @p is black and exclusively has black
-                 * children itself (i.e., nephews/nieces in @nl/@nr), then we
-                 * can easily re-color to fix this sub-tree, and continue one
-                 * layer up. However, if that's not the case, we have tree
-                 * rotations at our hands to move one of the black nodes into
-                 * our path, then turning the red node black to fully restore
-                 * the RB-Tree invariants again. This fixup will be done by the
-                 * caller, so we just let them know where to do that.
-                 */
-                if (c_rbnode_is_red(s) ||
-                    (nl && c_rbnode_is_red(nl)) ||
-                    (nr && c_rbnode_is_red(nr)))
-                        return p;
-
-                /*
-                 * Case 3+4:
-                 * Sibling is black, and all nephews/nieces are black. Flip
-                 * sibling red. This way the sibling lost a black node in its
-                 * path, thus getting even with our path. However, paths not
-                 * going through @p haven't been fixed up, hence we proceed
-                 * recursively one layer up.
-                 * Before we continue one layer up, there are two possible
-                 * terminations: If the parent is red, we can turn it black.
-                 * This terminates the rebalancing, since the entire point of
-                 * rebalancing is that everything below @p has one black node
-                 * less than everything else. Lastly, if there is no layer
-                 * above, we hit the tree root and nothing is left to be done.
-                 */
-                c_rbnode_set_parent_and_flags(s, p, c_rbnode_flags(s) | C_RBNODE_RED);
-                if (c_rbnode_is_red(p)) {
-                        c_rbnode_set_parent_and_flags(p, c_rbnode_parent(p), c_rbnode_flags(p) & ~C_RBNODE_RED);
-                        return NULL;
-                }
-
-                *previous = p;
-                p = c_rbnode_parent(p);
-        }
-
-        return NULL;
-}
-
-static inline void c_rbnode_rebalance(CRBNode *n) {
-        CRBNode *previous = NULL;
-
-        /*
-         * Rebalance a tree after a node was removed. This function must be
-         * called on the parent of the leaf that was removed. It will first
-         * perform a recursive re-coloring on the parents of @n, until it
-         * either hits the tree-root, or a condition where a tree-rotation is
-         * needed to restore the RB-Tree invariants.
-         */
-
-        n = c_rbnode_rebalance_path(n, &previous);
-        if (n)
-                c_rbnode_rebalance_terminal(n, previous);
-}
-
-/**
- * c_rbnode_unlink_stale() - remove node from tree
- * @n:          node to remove
- *
- * This removes the given node from its tree. Once unlinked, the tree is
- * rebalanced.
- *
- * This does *NOT* reset @n to being unlinked. If you need this, use
- * c_rbtree_unlink().
- */
-_c_public_ void c_rbnode_unlink_stale(CRBNode *n) {
-        CRBTree *t;
-
-        c_assert(n);
-        c_assert(c_rbnode_is_linked(n));
-
-        /*
-         * There are three distinct cases during node removal of a tree:
-         *  * The node has no children, in which case it can simply be removed.
-         *  * The node has exactly one child, in which case the child displaces
-         *    its parent.
-         *  * The node has two children, in which case there is guaranteed to
-         *    be a successor to the node (successor being the node ordered
-         *    directly after it). This successor is the leftmost descendant of
-         *    the node's right child, so it cannot have a left child of its own.
-         *    Therefore, we can simply swap the node with its successor (including
-         *    color) and remove the node from its new place, which will be one of
-         *    the first two cases.
-         *
-         * Whenever the node we removed was black, we have to rebalance the
-         * tree. Note that this affects the actual node we _remove_, not @n (in
-         * case we swap it).
-         */
-
-        if (!n->left && !n->right) {
-                /*
-                 * Case 1.0
-                 * The node has no children, it is a leaf-node and we
-                 * can simply unlink it. If it was also black, we have
-                 * to rebalance.
-                 */
-                t = c_rbnode_pop_root(n);
-                c_rbnode_swap_child(n, NULL);
-                c_rbnode_push_root(NULL, t);
-
-                if (c_rbnode_is_black(n))
-                        c_rbnode_rebalance(c_rbnode_parent(n));
-        } else if (!n->left && n->right) {
-                /*
-                 * Case 1.1:
-                 * The node has exactly one child, and it is on the
-                 * right. The child *must* be red (otherwise, the right
-                 * path has more black nodes than the non-existing left
-                 * path), and the node to be removed must hence be
-                 * black. We simply replace the node with its child,
-                 * turning the red child black, and thus no rebalancing
-                 * is required.
-                 */
-                t = c_rbnode_pop_root(n);
-                c_rbnode_swap_child(n, n->right);
-                c_rbnode_set_parent_and_flags(n->right, c_rbnode_parent(n), c_rbnode_flags(n->right) & ~C_RBNODE_RED);
-                c_rbnode_push_root(n->right, t);
-        } else if (n->left && !n->right) {
-                /*
-                 * Case 1.2:
-                 * The node has exactly one child, and it is on the left. Treat
-                 * it as mirrored case of Case 1.1 (i.e., replace the node by
-                 * its child).
-                 */
-                t = c_rbnode_pop_root(n);
-                c_rbnode_swap_child(n, n->left);
-                c_rbnode_set_parent_and_flags(n->left, c_rbnode_parent(n), c_rbnode_flags(n->left) & ~C_RBNODE_RED);
-                c_rbnode_push_root(n->left, t);
-        } else /* if (n->left && n->right) */ {
-                CRBNode *s, *p, *c, *next = NULL;
-
-                /* Cache possible tree-root during tree-rotations. */
-                t = c_rbnode_pop_root(n);
-
-                /*
-                 * Case 1.3:
-                 * We are dealing with a full interior node with a child on
-                 * both sides. We want to find its successor and swap it,
-                 * then remove the node similar to Case 1. For performance
-                 * reasons we don't perform the full swap, but skip links
-                 * that are about to be removed, anyway.
-                 *
-                 * First locate the successor, remember its child and the
-                 * parent the original node should have been linked on,
-                 * before being removed. Then link up both the successor's
-                 * new children and old child.
-                 *
-                 *      s: successor
-                 *      p: parent
-                 *      c: right (and only potential) child of successor
-                 *      next: next node to rebalance on
-                 */
-                s = n->right;
-                if (!s->left) {
-                        /*
-                         * The immediate right child is the successor,
-                         * the successor's right child remains linked
-                         * as before.
-                         */
-                        p = s;
-                        c = s->right;
-                } else {
-                        s = c_rbnode_leftmost(s);
-                        p = c_rbnode_parent(s);
-                        c = s->right;
-
-                        /*
-                         * The new parent pointer of the successor's
-                         * child is set below.
-                         */
-                        c_rbtree_store(&p->left, c);
-
-                        c_rbtree_store(&s->right, n->right);
-                        c_rbnode_set_parent_and_flags(n->right, s, c_rbnode_flags(n->right));
-                }
-
-                /*
-                 * In both the above cases, the successor's left child
-                 * needs to be replaced with the left child of the node
-                 * that is being removed.
-                 */
-                c_rbtree_store(&s->left, n->left);
-                c_rbnode_set_parent_and_flags(n->left, s, c_rbnode_flags(n->left));
-
-                /*
-                 * As in cases 1.1 and 1.0 above, if successor was a
-                 * black leaf, we need to rebalance the tree, otherwise
-                 * it must have a red child, so simply recolor that black
-                 * and continue. Note that @next must be stored here, as
-                 * the original color of the successor is forgotten below.
-                 */
-                if (c)
-                        c_rbnode_set_parent_and_flags(c, p, c_rbnode_flags(c) & ~C_RBNODE_RED);
-                else
-                        next = c_rbnode_is_black(s) ? p : NULL;
-
-                /*
-                 * Update the successor, to inherit the parent and color
-                 * from the node being removed.
-                 */
-                if (c_rbnode_is_red(n))
-                        c_rbnode_set_parent_and_flags(s, c_rbnode_parent(n), c_rbnode_flags(s) | C_RBNODE_RED);
-                else
-                        c_rbnode_set_parent_and_flags(s, c_rbnode_parent(n), c_rbnode_flags(s) & ~C_RBNODE_RED);
-
-                /*
-                 * Update the parent of the node being removed. Note that this
-                 * needs to happen after the parent of the successor is set
-                 * above, as that call would clear the root pointer, if set.
-                 */
-                c_rbnode_swap_child(n, s);
-
-                /* Possibly restore saved tree-root. */
-                c_rbnode_push_root(s, t);
-
-                if (next)
-                        c_rbnode_rebalance(next);
-        }
-}
diff --git a/shared/c-rbtree/src/c-rbtree.h b/shared/c-rbtree/src/c-rbtree.h
deleted file mode 100644
index d4d0fe45..00000000
--- a/shared/c-rbtree/src/c-rbtree.h
+++ /dev/null
@@ -1,437 +0,0 @@
-#pragma once
-
-/**
- * Standalone Red-Black-Tree Implementation in Standard ISO-C11
- *
- * This library provides an RB-Tree API, that is fully implemented in ISO-C11
- * and has no external dependencies. Furthermore, tree traversal, memory
- * allocations, and key comparisons are completely controlled by the API user.
- * The implementation only provides the RB-Tree specific rebalancing and
- * coloring.
- *
- * A tree is represented by the "CRBTree" structure. It contains a *single*
- * field, which is a pointer to the root node. If NULL, the tree is empty. If
- * non-NULL, there is at least a single element in the tree.
- *
- * Each node of the tree is represented by the "CRBNode" structure. It has
- * three fields. The @left and @right members can be accessed by the API user
- * directly to traverse the tree. The third member is a combination of the
- * parent pointer and a set of flags.
- * API users are required to embed the CRBNode object into their own objects
- * and then use offsetof() (i.e., container_of() and friends) to turn CRBNode
- * pointers into pointers to their own structure.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <assert.h>
-#include <stdalign.h>
-#include <stddef.h>
-
-typedef struct CRBNode CRBNode;
-typedef struct CRBTree CRBTree;
-
-/* implementation detail */
-#define C_RBNODE_RED                    (0x1UL)
-#define C_RBNODE_ROOT                   (0x2UL)
-#define C_RBNODE_FLAG_MASK              (0x3UL)
-
-/**
- * struct CRBNode - Node of a Red-Black Tree
- * @__parent_and_flags:         internal state
- * @left:                       left child, or NULL
- * @right:                      right child, or NULL
- *
- * Each node in an RB-Tree must embed a CRBNode object. This object contains
- * pointers to its left and right child, which can be freely accessed by the
- * API user at any time. They are NULL, if the node does not have a left/right
- * child.
- *
- * The @__parent_and_flags field must never be accessed directly. It encodes
- * the pointer to the parent node, and the color of the node. Use the accessor
- * functions instead.
- *
- * There is no reason to initialize a CRBNode object before linking it.
- * However, if you need a boolean state that tells you whether the node is
- * linked or not, you should initialize the node via c_rbnode_init() or
- * C_RBNODE_INIT.
- */
-struct CRBNode {
-        union {
-                unsigned long __parent_and_flags;
-                /* enforce >=4-byte alignment for @__parent_and_flags */
-                alignas(4) unsigned char __align_dummy;
-        };
-        CRBNode *left;
-        CRBNode *right;
-};
-
-#define C_RBNODE_INIT(_var) { .__parent_and_flags = (unsigned long)&(_var) }
-
-CRBNode *c_rbnode_leftmost(CRBNode *n);
-CRBNode *c_rbnode_rightmost(CRBNode *n);
-CRBNode *c_rbnode_leftdeepest(CRBNode *n);
-CRBNode *c_rbnode_rightdeepest(CRBNode *n);
-CRBNode *c_rbnode_next(CRBNode *n);
-CRBNode *c_rbnode_prev(CRBNode *n);
-CRBNode *c_rbnode_next_postorder(CRBNode *n);
-CRBNode *c_rbnode_prev_postorder(CRBNode *n);
-
-void c_rbnode_link(CRBNode *p, CRBNode **l, CRBNode *n);
-void c_rbnode_unlink_stale(CRBNode *n);
-
-/**
- * struct CRBTree - Red-Black Tree
- * @root:       pointer to the root node, or NULL
- *
- * Each Red-Black Tree is rooted in an CRBTree object. This object contains a
- * pointer to the root node of the tree. The API user is free to access the
- * @root member at any time, and use it to traverse the tree.
- *
- * To initialize an RB-Tree, set it to NULL / all zero.
- */
-struct CRBTree {
-        union {
-                CRBNode *root;
-                /* enforce >=4-byte alignment for @root */
-                alignas(4) unsigned char __align_dummy;
-        };
-};
-
-#define C_RBTREE_INIT {}
-
-CRBNode *c_rbtree_first(CRBTree *t);
-CRBNode *c_rbtree_last(CRBTree *t);
-CRBNode *c_rbtree_first_postorder(CRBTree *t);
-CRBNode *c_rbtree_last_postorder(CRBTree *t);
-
-void c_rbtree_move(CRBTree *to, CRBTree *from);
-void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n);
-
-/**
- * c_rbnode_init() - mark a node as unlinked
- * @n:          node to operate on
- *
- * This marks the node @n as unlinked. The node will be set to a valid state
- * that can never happen if the node is linked in a tree. Furthermore, this
- * state is fully known to the implementation, and as such handled gracefully
- * in all cases.
- *
- * You are *NOT* required to call this on your node. c_rbtree_add() can handle
- * uninitialized nodes just fine. However, calling this allows to use
- * c_rbnode_is_linked() to check for the state of a node. Furthermore,
- * iterators and accessors can be called on initialized (yet unlinked) nodes.
- *
- * Use the C_RBNODE_INIT macro if you want to initialize static variables.
- */
-static inline void c_rbnode_init(CRBNode *n) {
-        *n = (CRBNode)C_RBNODE_INIT(*n);
-}
-
-/**
- * c_rbnode_entry() - get parent container of tree node
- * @_what:              tree node, or NULL
- * @_t:                 type of parent container
- * @_m:                 member name of tree node in @_t
- *
- * If the tree node @_what is embedded into a surrounding structure, this will
- * turn the tree node pointer @_what into a pointer to the parent container
- * (using offsetof(3), or sometimes called container_of(3)).
- *
- * If @_what is NULL, this will also return NULL.
- *
- * Return: Pointer to parent container, or NULL.
- */
-#define c_rbnode_entry(_what, _t, _m) \
-        ((_t *)(void *)(((unsigned long)(void *)(_what) ?: \
-                         offsetof(_t, _m)) - offsetof(_t, _m)))
-
-/**
- * c_rbnode_parent() - return parent pointer
- * @n           node to access
- *
- * This returns a pointer to the parent of the given node @n. If @n does not
- * have a parent, NULL is returned. If @n is not linked, @n itself is returned.
- *
- * You should not call this on unlinked or uninitialized nodes! If you do, you
- * better know its semantics.
- *
- * Return: Pointer to parent.
- */
-static inline CRBNode *c_rbnode_parent(CRBNode *n) {
-        return (n->__parent_and_flags & C_RBNODE_ROOT) ?
-                        NULL :
-                        (void *)(n->__parent_and_flags & ~C_RBNODE_FLAG_MASK);
-}
-
-/**
- * c_rbnode_is_linked() - check whether a node is linked
- * @n:          node to check, or NULL
- *
- * This checks whether the passed node is linked. If you pass NULL, or if the
- * node is not linked into a tree, this will return false. Otherwise, this
- * returns true.
- *
- * Note that you must have either linked the node or initialized it, before
- * calling this function. Never call this function on uninitialized nodes.
- * Furthermore, removing a node via c_rbnode_unlink_stale() does *NOT* mark the
- * node as unlinked. You have to call c_rbnode_init() yourself after removal, or
- * use the c_rbnode_unlink() helper.
- *
- * Return: true if the node is linked, false if not.
- */
-static inline _Bool c_rbnode_is_linked(CRBNode *n) {
-        return n && c_rbnode_parent(n) != n;
-}
-
-/**
- * c_rbnode_unlink() - safely remove node from tree and reinitialize it
- * @n:          node to remove, or NULL
- *
- * This is almost the same as c_rbnode_unlink_stale(), but extends it slightly, to be
- * more convenient to use in many cases:
- *  - if @n is unlinked or NULL, this is a no-op
- *  - @n is reinitialized after being removed
- */
-static inline void c_rbnode_unlink(CRBNode *n) {
-        if (c_rbnode_is_linked(n)) {
-                c_rbnode_unlink_stale(n);
-                c_rbnode_init(n);
-        }
-}
-
-/**
- * c_rbtree_init() - initialize a new RB-Tree
- * @t:          tree to operate on
- *
- * This initializes a new, empty RB-Tree. An RB-Tree must be initialized before
- * any other functions are called on it. Alternatively, you can zero its memory
- * or assign C_RBTREE_INIT.
- */
-static inline void c_rbtree_init(CRBTree *t) {
-        *t = (CRBTree)C_RBTREE_INIT;
-}
-
-/**
- * c_rbtree_is_empty() - check whether an RB-tree is empty
- * @t:          tree to operate on
- *
- * This checks whether the passed RB-Tree is empty.
- *
- * Return: True if tree is empty, false otherwise.
- */
-static inline _Bool c_rbtree_is_empty(CRBTree *t) {
-        return !t->root;
-}
-
-/**
- * CRBCompareFunc - compare a node to a key
- * @t:          tree where the node is linked to
- * @k:          key to compare
- * @n:          node to compare
- *
- * If you use the tree-traversal helpers (which are optional), you need to
- * provide this callback so they can compare nodes in a tree to the key you
- * look for.
- *
- * The tree @t is provided as optional context to this callback. The key you
- * look for is provided as @k, the current node that should be compared to is
- * provided as @n. This function should work like strcmp(), that is, return <0
- * if @key orders before @n, 0 if both compare equal, and >0 if it orders after
- * @n.
- */
-typedef int (*CRBCompareFunc) (CRBTree *t, void *k, CRBNode *n);
-
-/**
- * c_rbtree_find_node() - find node
- * @t:          tree to search through
- * @f:          comparison function
- * @k:          key to search for
- *
- * This searches through @t for a node that compares equal to @k. The function
- * @f must be provided by the caller, which is used to compare nodes to @k. See
- * the documentation of CRBCompareFunc for details.
- *
- * If there are multiple entries that compare equal to @k, this will return a
- * pseudo-randomly picked node. If you need stable lookup functions for trees
- * where duplicate entries are allowed, you better code your own lookup.
- *
- * Return: Pointer to matching node, or NULL.
- */
-static inline CRBNode *c_rbtree_find_node(CRBTree *t, CRBCompareFunc f, const void *k) {
-        CRBNode *i;
-
-        assert(t);
-        assert(f);
-
-        i = t->root;
-        while (i) {
-                int v = f(t, (void *)k, i);
-                if (v < 0)
-                        i = i->left;
-                else if (v > 0)
-                        i = i->right;
-                else
-                        return i;
-        }
-
-        return NULL;
-}
-
-/**
- * c_rbtree_find_entry() - find entry
- * @_t:         tree to search through
- * @_f:         comparison function
- * @_k:         key to search for
- * @_s:         type of the structure that embeds the nodes
- * @_m:         name of the node-member in type @_t
- *
- * This is very similar to c_rbtree_find_node(), but instead of returning a
- * pointer to the CRBNode, it returns a pointer to the surrounding object. This
- * object must embed the CRBNode object. The type of the surrounding object
- * must be given as @_s, and the name of the embedded CRBNode member as @_m.
- *
- * See c_rbtree_find_node() and c_rbnode_entry() for more details.
- *
- * Return: Pointer to found entry, NULL if not found.
- */
-#define c_rbtree_find_entry(_t, _f, _k, _s, _m) \
-        c_rbnode_entry(c_rbtree_find_node((_t), (_f), (_k)), _s, _m)
-
-/**
- * c_rbtree_find_slot() - find slot to insert new node
- * @t:          tree to search through
- * @f:          comparison function
- * @k:          key to search for
- * @p:          output storage for parent pointer
- *
- * This searches through @t just like c_rbtree_find_node() does. However,
- * instead of returning a pointer to a node that compares equal to @k, this
- * searches for a slot to insert a node with key @k. A pointer to the slot is
- * returned, and a pointer to the parent of the slot is stored in @p. Both
- * can be passed directly to c_rbtree_add(), together with your node to insert.
- *
- * If there already is a node in the tree, that compares equal to @k, this will
- * return NULL and store the conflicting node in @p. In all other cases,
- * this will return a pointer (non-NULL) to the empty slot to insert the node
- * at. @p will point to the parent node of that slot.
- *
- * If you want trees that allow duplicate nodes, you better code your own
- * insertion function.
- *
- * Return: Pointer to slot to insert node, or NULL on conflicts.
- */
-static inline CRBNode **c_rbtree_find_slot(CRBTree *t, CRBCompareFunc f, const void *k, CRBNode **p) {
-        CRBNode **i;
-
-        assert(t);
-        assert(f);
-        assert(p);
-
-        i = &t->root;
-        *p = NULL;
-        while (*i) {
-                int v = f(t, (void *)k, *i);
-                *p = *i;
-                if (v < 0)
-                        i = &(*i)->left;
-                else if (v > 0)
-                        i = &(*i)->right;
-                else
-                        return NULL;
-        }
-
-        return i;
-}
-
-/**
- * c_rbtree_for_each*() - iterators
- *
- * The c_rbtree_for_each*() macros provide simple for-loop wrappers to iterate
- * an RB-Tree. They come in a set of flavours:
- *
- *   - "entry": This combines c_rbnode_entry() with the loop iterator, so the
- *              iterator always has the type of the surrounding object, rather
- *              than CRBNode.
- *
- *   - "safe": The loop iterator always keeps track of the next element to
- *             visit. This means, you can safely modify the current element,
- *             while retaining loop-integrity.
- *             You still must not touch any other entry of the tree. Otherwise,
- *             the loop-iterator will be corrupted. Also remember to only
- *             modify the tree in a way compatible with your iterator-order.
- *             That is, if you use in-order iteration (default), you can unlink
- *             your current object, including re-balancing the tree. However,
- *             if you use post-order, you must not trigger a tree rebalance
- *             operation, since it is not an invariant of post-order iteration.
- *
- *   - "postorder": Rather than the default in-order iteration, this iterates
- *                  the tree in post-order.
- *
- *   - "unlink": This unlinks the current element from the tree before the loop
- *               code is run. Note that the tree is not rebalanced. That is,
- *               you must never break out of the loop. If you do so, the tree
- *               is corrupted.
- */
-
-#define c_rbtree_for_each(_iter, _tree)                                                                 \
-        for (_iter = c_rbtree_first(_tree);                                                             \
-             _iter;                                                                                     \
-             _iter = c_rbnode_next(_iter))
-
-#define c_rbtree_for_each_entry(_iter, _tree, _m)                                                       \
-        for (_iter = c_rbnode_entry(c_rbtree_first(_tree), __typeof__(*_iter), _m);                     \
-             _iter;                                                                                     \
-             _iter = c_rbnode_entry(c_rbnode_next(&_iter->_m), __typeof__(*_iter), _m))
-
-#define c_rbtree_for_each_safe(_iter, _safe, _tree)                                                     \
-        for (_iter = c_rbtree_first(_tree), _safe = c_rbnode_next(_iter);                               \
-             _iter;                                                                                     \
-             _iter = _safe, _safe = c_rbnode_next(_safe))
-
-#define c_rbtree_for_each_entry_safe(_iter, _safe, _tree, _m)                                           \
-        for (_iter = c_rbnode_entry(c_rbtree_first(_tree), __typeof__(*_iter), _m),                     \
-             _safe = _iter ? c_rbnode_entry(c_rbnode_next(&_iter->_m), __typeof__(*_iter), _m) : NULL;  \
-             _iter;                                                                                     \
-             _iter = _safe,                                                                             \
-             _safe = _safe ? c_rbnode_entry(c_rbnode_next(&_safe->_m), __typeof__(*_iter), _m) : NULL)
-
-#define c_rbtree_for_each_postorder(_iter, _tree)                                                       \
-        for (_iter = c_rbtree_first_postorder(_tree);                                                   \
-             _iter;                                                                                     \
-             _iter = c_rbnode_next_postorder(_iter))                                                    \
-
-#define c_rbtree_for_each_entry_postorder(_iter, _tree, _m)                                             \
-        for (_iter = c_rbnode_entry(c_rbtree_first_postorder(_tree), __typeof__(*_iter), _m);           \
-             _iter;                                                                                     \
-             _iter = c_rbnode_entry(c_rbnode_next_postorder(&_iter->_m), __typeof__(*_iter), _m))
-
-#define c_rbtree_for_each_safe_postorder(_iter, _safe, _tree)                                           \
-        for (_iter = c_rbtree_first_postorder(_tree), _safe = c_rbnode_next_postorder(_iter);           \
-             _iter;                                                                                     \
-             _iter = _safe, _safe = c_rbnode_next_postorder(_safe))
-
-#define c_rbtree_for_each_entry_safe_postorder(_iter, _safe, _tree, _m)                                                 \
-        for (_iter = c_rbnode_entry(c_rbtree_first_postorder(_tree), __typeof__(*_iter), _m),                           \
-             _safe = _iter ? c_rbnode_entry(c_rbnode_next_postorder(&_iter->_m), __typeof__(*_iter), _m) : NULL;        \
-             _iter;                                                                                                     \
-             _iter = _safe,                                                                                             \
-             _safe = _safe ? c_rbnode_entry(c_rbnode_next_postorder(&_safe->_m), __typeof__(*_iter), _m) : NULL)
-
-#define c_rbtree_for_each_safe_postorder_unlink(_iter, _safe, _tree)                                    \
-        for (_iter = c_rbtree_first_postorder(_tree), _safe = c_rbnode_next_postorder(_iter);           \
-             _iter ? ((*_iter = (CRBNode)C_RBNODE_INIT(*_iter)), 1) : (((_tree)->root = NULL), 0);      \
-             _iter = _safe, _safe = c_rbnode_next_postorder(_safe))                                     \
-
-#define c_rbtree_for_each_entry_safe_postorder_unlink(_iter, _safe, _tree, _m)                                          \
-        for (_iter = c_rbnode_entry(c_rbtree_first_postorder(_tree), __typeof__(*_iter), _m),                           \
-             _safe = _iter ? c_rbnode_entry(c_rbnode_next_postorder(&_iter->_m), __typeof__(*_iter), _m) : NULL;        \
-             _iter ? ((_iter->_m = (CRBNode)C_RBNODE_INIT(_iter->_m)), 1) : (((_tree)->root = NULL), 0);                \
-             _iter = _safe,                                                                                             \
-             _safe = _safe ? c_rbnode_entry(c_rbnode_next_postorder(&_safe->_m), __typeof__(*_iter), _m) : NULL)
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/shared/c-siphash/src/c-siphash.c b/shared/c-siphash/src/c-siphash.c
deleted file mode 100644
index 720e403a..00000000
--- a/shared/c-siphash/src/c-siphash.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * SipHash Implementation
- *
- * For highlevel documentation of the API see the header file and the docbook
- * comments. This implementation is based on the reference implementation of
- * SipHash, written by Jean-Philippe Aumasson and Daniel J. Bernstein, and
- * released to the Public Domain.
- *
- * So far, only SipHash24 is implemented, since there was no need for other
- * parameters. However, adjusted c_siphash_append_X() and
- * C_siphash_finalize_Y() can be easily provided, if required.
- */
-
-#include <c-stdaux.h>
-#include <stddef.h>
-#include <stdint.h>
-#include "c-siphash.h"
-
-static inline uint64_t c_siphash_read_le64(const uint8_t bytes[8]) {
-        return  ((uint64_t) bytes[0]) |
-               (((uint64_t) bytes[1]) <<  8) |
-               (((uint64_t) bytes[2]) << 16) |
-               (((uint64_t) bytes[3]) << 24) |
-               (((uint64_t) bytes[4]) << 32) |
-               (((uint64_t) bytes[5]) << 40) |
-               (((uint64_t) bytes[6]) << 48) |
-               (((uint64_t) bytes[7]) << 56);
-}
-
-static inline uint64_t c_siphash_rotate_left(uint64_t x, uint8_t b) {
-        return (x << b) | (x >> (64 - b));
-}
-
-static inline void c_siphash_sipround(CSipHash *state) {
-        state->v0 += state->v1;
-        state->v1 = c_siphash_rotate_left(state->v1, 13);
-        state->v1 ^= state->v0;
-        state->v0 = c_siphash_rotate_left(state->v0, 32);
-        state->v2 += state->v3;
-        state->v3 = c_siphash_rotate_left(state->v3, 16);
-        state->v3 ^= state->v2;
-        state->v0 += state->v3;
-        state->v3 = c_siphash_rotate_left(state->v3, 21);
-        state->v3 ^= state->v0;
-        state->v2 += state->v1;
-        state->v1 = c_siphash_rotate_left(state->v1, 17);
-        state->v1 ^= state->v2;
-        state->v2 = c_siphash_rotate_left(state->v2, 32);
-}
-
-/**
- * c_siphash_init() - initialize siphash context
- * @state:              context object
- * @seed:               128bit seed
- *
- * This initializes the siphash state context. Once initialized, it can be used
- * to hash arbitrary input. To feed data into it, use c_siphash_append(). To get
- * the final hash, use c_siphash_finalize().
- *
- * Note that the siphash context does not allocate state. There is no need to
- * deserialize it before releasing its backing memory.
- *
- * The hashes generated by this context change depending on the seed. Every
- * user is highly inclined to provide their unique seed. If no stable hashes
- * are needed, a random seed will do fine.
- *
- * Right now, only SipHash24 is supported. Other SipHash parameters can be
- * easily added if required.
- */
-_c_public_ void c_siphash_init(CSipHash *state, const uint8_t seed[16]) {
-        uint64_t k0, k1;
-
-        k0 = c_siphash_read_le64(seed);
-        k1 = c_siphash_read_le64(seed + 8);
-
-        *state = (CSipHash) {
-                /*
-                 * Default seed is taken from the reference implementation
-                 * of SipHash24 ("somepseudorandomlygeneratedbytes"). Callers
-                 * are still recommended to provide proper seeds themselves.
-                 */
-                .v0 = 0x736f6d6570736575ULL ^ k0,
-                .v1 = 0x646f72616e646f6dULL ^ k1,
-                .v2 = 0x6c7967656e657261ULL ^ k0,
-                .v3 = 0x7465646279746573ULL ^ k1,
-                .padding = 0,
-                .n_bytes = 0,
-        };
-}
-
-/**
- * c_siphash_append() - hash stream of data
- * @state:              context object
- * @bytes:              array of input bytes
- * @n_bytes:            number of input bytes
- *
- * This feeds an array of bytes into the SipHash state machine. This is a
- * streaming-capable API. That is, the resulting hash is the same, regardless
- * of the way you chunk the input.
- * This function simply feeds the given bytes into the SipHash state machine.
- * It does not produce a final hash. You can call this function many times to
- * append more data. To retrieve the final hash, call c_siphash_finalize().
- *
- * Note that this implementation works best when used with chunk-sizes of
- * multiples of 64bit (8-bytes). This is not a requirement, though.
- */
-_c_public_ void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n_bytes) {
-        const uint8_t *end = bytes + n_bytes;
-        size_t left = state->n_bytes & 7;
-        uint64_t m;
-
-        state->n_bytes += n_bytes;
-
-        /*
-         * SipHash operates on 64bit chunks. If the previous blob was not a
-         * multiple of 64bit in length, we must operate on single bytes.
-         */
-        if (left > 0) {
-                for ( ; bytes < end && left < 8; ++bytes, ++left)
-                        state->padding |= ((uint64_t) *bytes) << (left * 8);
-
-                if (bytes == end && left < 8)
-                        return;
-
-                state->v3 ^= state->padding;
-                c_siphash_sipround(state);
-                c_siphash_sipround(state);
-                state->v0 ^= state->padding;
-
-                state->padding = 0;
-        }
-
-        end -= (state->n_bytes % sizeof(uint64_t));
-
-        /*
-         * We are now guaranteed to be at a 64bit state boundary. Hence, we can
-         * operate in 64bit chunks on all input. This is much faster than the
-         * one-byte-at-a-time loop.
-         */
-        for ( ; bytes < end; bytes += 8) {
-                m = c_siphash_read_le64(bytes);
-
-                state->v3 ^= m;
-                c_siphash_sipround(state);
-                c_siphash_sipround(state);
-                state->v0 ^= m;
-        }
-
-        /*
-         * Now that we hashed as much 64bit chunks as possible, we need to
-         * remember the remaining trailing bytes. Keep them in @padding so the
-         * next round (or the finalizer) get access to them.
-         */
-        left = state->n_bytes & 7;
-        switch (left) {
-                case 7:
-                        state->padding |= ((uint64_t) bytes[6]) << 48;
-                        /* fallthrough */
-                case 6:
-                        state->padding |= ((uint64_t) bytes[5]) << 40;
-                        /* fallthrough */
-                case 5:
-                        state->padding |= ((uint64_t) bytes[4]) << 32;
-                        /* fallthrough */
-                case 4:
-                        state->padding |= ((uint64_t) bytes[3]) << 24;
-                        /* fallthrough */
-                case 3:
-                        state->padding |= ((uint64_t) bytes[2]) << 16;
-                        /* fallthrough */
-                case 2:
-                        state->padding |= ((uint64_t) bytes[1]) <<  8;
-                        /* fallthrough */
-                case 1:
-                        state->padding |= ((uint64_t) bytes[0]);
-                        /* fallthrough */
-                case 0:
-                        break;
-        }
-}
-
-/**
- * c_siphash_finalize() - finalize hash
- * @state:              context object
- *
- * This produces the final SipHash24 hash value for the given SipHash state.
- * That is, it produces a hash value corresponding to the SipHash24 hash value
- * of the concatenated byte-array passed into @state via c_siphash_append().
- *
- * Note that @state has an invalid state after this function returns. To reuse
- * it for another hash, you must call c_siphash_init() again. If you don't need
- * the object, anymore, you can release it any time. There is no need to
- * destroy the object explicitly.
- *
- * Return: 64bit hash value
- */
-_c_public_ uint64_t c_siphash_finalize(CSipHash *state) {
-        uint64_t b;
-
-        b = state->padding | (((uint64_t) state->n_bytes) << 56);
-
-        state->v3 ^= b;
-        c_siphash_sipround(state);
-        c_siphash_sipround(state);
-        state->v0 ^= b;
-
-        state->v2 ^= 0xff;
-
-        c_siphash_sipround(state);
-        c_siphash_sipround(state);
-        c_siphash_sipround(state);
-        c_siphash_sipround(state);
-
-        return state->v0 ^ state->v1 ^ state->v2  ^ state->v3;
-}
-
-/**
- * c_siphash_hash() - hash data blob
- * @seed:               128bit seed
- * @bytes:              byte array to hash
- * @n_bytes:            number of bytes to hash
- *
- * This produces the SipHash24 hash value for the input @bytes / @n_bytes,
- * using the seed provided as @seed.
- *
- * This is functionally equivalent to:
- *
- *         CSipHash state;
- *         c_siphash_init(&state, seed);
- *         c_siphash_append(&state, bytes, n_bytes);
- *         return c_siphash_finalize(&state);
- *
- * Unlike the streaming API, this is a one-shot call suitable for any data that
- * is available in-memory at the same time.
- *
- * Return: 64bit hash value
- */
-_c_public_ uint64_t c_siphash_hash(const uint8_t seed[16], const uint8_t *bytes, size_t n_bytes) {
-        CSipHash state;
-
-        c_siphash_init(&state, seed);
-        c_siphash_append(&state, bytes, n_bytes);
-
-        return c_siphash_finalize(&state);
-}
diff --git a/shared/c-siphash/src/c-siphash.h b/shared/c-siphash/src/c-siphash.h
deleted file mode 100644
index c0cfc1e0..00000000
--- a/shared/c-siphash/src/c-siphash.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#pragma once
-
-/**
- * Streaming-capable SipHash Implementation
- *
- * This library provides a SipHash API, that is fully implemented in ISO-C11
- * and has no external dependencies. The library performs no memory allocation,
- * and provides a streaming API where data to be hashed can be appended
- * piecemeal.
- *
- * A streaming-capable hash state is represented by the "CSipHash" structure,
- * which should be initialized with a unique seed before use. If streaming
- * capabilities are not required, c_siphash_hash() provides a simple one-shot
- * API.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stddef.h>
-#include <stdint.h>
-
-typedef struct CSipHash CSipHash;
-
-/**
- * struct CSipHash - SipHash state object
- * @v0-@v3:             internal state
- * @padding:            pending bytes that were not a multiple of 8
- * @n_bytes:            number of hashed bytes
- *
- * The state of an inflight hash is represenetd by a CSipHash object. Before
- * hashing, it must be initialized with c_siphash_init(), providing a unique
- * random hash seed. Data is hashed by appending it to the state object, using
- * c_siphash_append(). Finally, the hash is read out by calling
- * c_siphash_finalize().
- *
- * This state object has no allocated resources. It is safe to release its
- * backing memory without any further action.
- */
-struct CSipHash {
-        uint64_t v0;
-        uint64_t v1;
-        uint64_t v2;
-        uint64_t v3;
-        uint64_t padding;
-        size_t n_bytes;
-};
-
-#define C_SIPHASH_NULL {}
-
-void c_siphash_init(CSipHash *state, const uint8_t seed[16]);
-void c_siphash_append(CSipHash *state, const uint8_t *bytes, size_t n_bytes);
-uint64_t c_siphash_finalize(CSipHash *state);
-
-uint64_t c_siphash_hash(const uint8_t seed[16], const uint8_t *bytes, size_t n_bytes);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/shared/c-stdaux/src/c-stdaux.h b/shared/c-stdaux/src/c-stdaux.h
deleted file mode 100644
index 1cdbbbcf..00000000
--- a/shared/c-stdaux/src/c-stdaux.h
+++ /dev/null
@@ -1,550 +0,0 @@
-#pragma once
-
-/*
- * Auxiliary macros and functions for the C standard library
- *
- * The `c-stdaux.h` header contains a collection of auxiliary macros and helper
- * functions around the functionality provided by the different C standard
- * library implementations, as well as other specifications implemented by
- * them.
- *
- * Most of the helpers provided here provide aliases for common library and
- * compiler features. Furthermore, several helpers simply provide other calling
- * conventions than their standard counterparts (e.g., they allow for NULL to
- * be passed with an object length of 0 where it makes sense to accept empty
- * input).
- *
- * The namespace used by this project is:
- *
- *  * `c_*` for all common C symbols or definitions that behave like proper C
- *    entities (e.g., macros that protect against double-evaluation would use
- *    lower-case names)
- *
- *  * `C_*` for all constants, as well as macros that may not be safe against
- *    double evaluation.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <assert.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdalign.h>
-#include <stdarg.h>
-#if 0 /* NM_IGNORED */
-#include <stdatomic.h>
-#endif /* NM_IGNORED */
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdnoreturn.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-/*
- * Shortcuts for gcc attributes. See GCC manual for details. They're 1-to-1
- * mappings to the GCC equivalents. No additional magic here. They are
- * supported by other compilers as well.
- */
-#define _c_cleanup_(_x) __attribute__((__cleanup__(_x)))
-#define _c_const_ __attribute__((__const__))
-#define _c_deprecated_ __attribute__((__deprecated__))
-#define _c_hidden_ __attribute__((__visibility__("hidden")))
-#define _c_likely_(_x) (__builtin_expect(!!(_x), 1))
-#define _c_packed_ __attribute__((__packed__))
-#define _c_printf_(_a, _b) __attribute__((__format__(printf, _a, _b)))
-#define _c_public_ __attribute__((__visibility__("default")))
-#define _c_pure_ __attribute__((__pure__))
-#define _c_sentinel_ __attribute__((__sentinel__))
-#define _c_unlikely_(_x) (__builtin_expect(!!(_x), 0))
-#define _c_unused_ __attribute__((__unused__))
-
-/**
- * C_EXPR_ASSERT() - create expression with assertion
- * @_expr:              expression to evaluate to
- * @_assertion:         arbitrary assertion
- * @_message:           message associated with the assertion
- *
- * This macro simply evaluates to @_expr. That is, it can be used in any
- * context that expects an expression like @_expr. Additionally, it takes an
- * assertion as @_assertion and evaluates it through _Static_assert(), using
- * @_message as debug message.
- *
- * The _Static_assert() builtin of C11 is defined as statement and thus cannot
- * be used in expressions. This macro circumvents this restriction.
- *
- * Return: Evaluates to @_expr.
- */
-#if defined(__COVERITY__) // Coverity cannot const-fold __builtin_choose_expr()
-#  define C_EXPR_ASSERT(_expr, _assertion, _message) (_expr)
-#else
-#  define C_EXPR_ASSERT(_expr, _assertion, _message)                    \
-        /* indentation and line-split to get better diagnostics */      \
-        (__builtin_choose_expr(                                         \
-                !!(1 + 0 * sizeof(                                      \
-                        struct {                                        \
-_Static_assert(_assertion, _message); \
-                        }                                               \
-                )),                                                     \
-                (_expr),                                                \
-                ((void)0)                                               \
-        ))
-#endif
-
-/**
- * C_STRINGIFY() - stringify a token, but evaluate it first
- * @_x:         token to evaluate and stringify
- *
- * Return: Evaluates to a constant string literal
- */
-#define C_STRINGIFY(_x) C_INTERNAL_STRINGIFY(_x)
-#define C_INTERNAL_STRINGIFY(_x) #_x
-
-/**
- * C_CONCATENATE() - concatenate two tokens, but evaluate them first
- * @_x:         first token
- * @_y:         second token
- *
- * Return: Evaluates to a constant identifier
- */
-#define C_CONCATENATE(_x, _y) C_INTERNAL_CONCATENATE(_x, _y)
-#define C_INTERNAL_CONCATENATE(_x, _y) _x ## _y
-
-/**
- * C_EXPAND() - expand a tuple to a series of its values
- * @_x:         tuple to expand
- *
- * Return: Evaluates to the expanded tuple
- */
-#define C_EXPAND(_x) C_INTERNAL_EXPAND _x
-#define C_INTERNAL_EXPAND(...) __VA_ARGS__
-
-/**
- * C_VAR() - generate unique variable name
- * @_x:         name of variable, optional
- * @_uniq:      unique prefix, usually provided by __COUNTER__, optional
- *
- * This macro shall be used to generate unique variable names, that will not be
- * shadowed by recursive macro invocations. It is effectively a
- * C_CONCATENATE of both arguments, but also provides a globally separated
- * prefix and makes the code better readable.
- *
- * The second argument is optional. If not given, __LINE__ is implied, and as
- * such the macro will generate the same identifier if used multiple times on
- * the same code-line (or within a macro). This should be used if recursive
- * calls into the macro are not expected. In fact, no argument is necessary in
- * this case, as a mere `C_VAR` will evaluate to a valid variable name.
- *
- * This helper may be used by macro implementations that might reasonable well
- * be called in a stacked fasion, like:
- *
- *     c_max(foo, c_max(bar, baz))
- *
- * Such a stacked call of c_max() might cause compiler warnings of shadowed
- * variables in the definition of c_max(). By using C_VAR(), such warnings
- * can be silenced as each evaluation of c_max() uses unique variable names.
- *
- * Return: This evaluates to a constant identifier.
- */
-#define C_VAR(...) C_INTERNAL_VAR(__VA_ARGS__, 2, 1)
-#define C_INTERNAL_VAR(_x, _uniq, _num, ...) C_VAR ## _num (_x, _uniq)
-#define C_VAR1(_x, _unused) C_VAR2(_x, C_CONCATENATE(line, __LINE__))
-#define C_VAR2(_x, _uniq) C_CONCATENATE(c_internal_var_unique_, C_CONCATENATE(_uniq, _x))
-
-/**
- * C_CC_MACRO1() - provide safe environment to a macro
- * @_call:      macro to call
- * @_x1:        first argument
- * @...:        further arguments to forward unmodified to @_call
- *
- * This function simplifies the implementation of macros. Whenever you
- * implement a macro, provide the internal macro name as @_call and its
- * argument as @_x1. Inside of your internal macro, you...
- *
- *  - ...are safe against multiple evaluation errors, since C_CC_MACRO1 will
- *       store the initial parameters in temporary variables.
- *
- *  - ...support constant folding, as C_CC_MACRO1 takes care to invoke your
- *       macro with the original values, if they are compile-time constant.
- *
- *  - ...have unique variable names for recursive callers and will not run into
- *       variable-shadowing-warnings accidentally.
- *
- *  - ...have properly typed arguments as C_CC_MACRO1 stores the original
- *       arguments in an `__auto_type` temporary variable.
- *
- * Return: Result of @_call is returned.
- */
-#define C_CC_MACRO1(_call, _x1, ...) C_INTERNAL_CC_MACRO1(_call, __COUNTER__, (_x1), ## __VA_ARGS__)
-#define C_INTERNAL_CC_MACRO1(_call, _x1q, _x1, ...)                     \
-        __builtin_choose_expr(                                          \
-                __builtin_constant_p(_x1),                              \
-                _call(_x1, ## __VA_ARGS__),                             \
-                __extension__ ({                                        \
-                        const __auto_type C_VAR(X1, _x1q) = (_x1);      \
-                        _call(C_VAR(X1, _x1q), ## __VA_ARGS__);         \
-                }))
-
-/**
- * C_CC_MACRO2() - provide safe environment to a macro
- * @_call:      macro to call
- * @_x1:        first argument
- * @_x2:        second argument
- * @...:        further arguments to forward unmodified to @_call
- *
- * This is the 2-argument equivalent of C_CC_MACRO1().
- *
- * Return: Result of @_call is returned.
- */
-#define C_CC_MACRO2(_call, _x1, _x2, ...) C_INTERNAL_CC_MACRO2(_call, __COUNTER__, (_x1), __COUNTER__, (_x2), ## __VA_ARGS__)
-#define C_INTERNAL_CC_MACRO2(_call, _x1q, _x1, _x2q, _x2, ...)                          \
-        __builtin_choose_expr(                                                          \
-                (__builtin_constant_p(_x1) && __builtin_constant_p(_x2)),               \
-                _call((_x1), (_x2), ## __VA_ARGS__),                                    \
-                __extension__ ({                                                        \
-                        const __auto_type C_VAR(X1, _x1q) = (_x1);                      \
-                        const __auto_type C_VAR(X2, _x2q) = (_x2);                      \
-                        _call(C_VAR(X1, _x1q), C_VAR(X2, _x2q), ## __VA_ARGS__);        \
-                }))
-
-/**
- * C_CC_MACRO3() - provide safe environment to a macro
- * @_call:      macro to call
- * @_x1:        first argument
- * @_x2:        second argument
- * @_x3:        third argument
- * @...:        further arguments to forward unmodified to @_call
- *
- * This is the 3-argument equivalent of C_CC_MACRO1().
- *
- * Return: Result of @_call is returned.
- */
-#define C_CC_MACRO3(_call, _x1, _x2, _x3, ...) C_INTERNAL_CC_MACRO3(_call, __COUNTER__, (_x1), __COUNTER__, (_x2), __COUNTER__, (_x3), ## __VA_ARGS__)
-#define C_INTERNAL_CC_MACRO3(_call, _x1q, _x1, _x2q, _x2, _x3q, _x3, ...)                               \
-        __builtin_choose_expr(                                                                          \
-                (__builtin_constant_p(_x1) && __builtin_constant_p(_x2) && __builtin_constant_p(_x3)),  \
-                _call((_x1), (_x2), (_x3), ## __VA_ARGS__),                                             \
-                __extension__ ({                                                                        \
-                        const __auto_type C_VAR(X1, _x1q) = (_x1);                                      \
-                        const __auto_type C_VAR(X2, _x2q) = (_x2);                                      \
-                        const __auto_type C_VAR(X3, _x3q) = (_x3);                                      \
-                        _call(C_VAR(X1, _x1q), C_VAR(X2, _x2q), C_VAR(X3, _x3q), ## __VA_ARGS__);       \
-                }))
-
-/**
- * C_ARRAY_SIZE() - calculate number of array elements at compile time
- * @_x:         array to calculate size of
- *
- * Return: Evaluates to a constant integer expression.
- */
-#define C_ARRAY_SIZE(_x)                                                \
-        C_EXPR_ASSERT(sizeof(_x) / sizeof((_x)[0]),                     \
-               /*                                                       \
-                * Verify that `_x' is an array, not a pointer. Rely on  \
-                * `&_x[0]' degrading arrays to pointers.                \
-                */                                                      \
-                !__builtin_types_compatible_p(                          \
-                        __typeof__(_x),                                 \
-                        __typeof__(&(*(__typeof__(_x)*)0)[0])           \
-                ),                                                      \
-                "C_ARRAY_SIZE() called with non-array argument"         \
-        )
-
-/**
- * C_DECIMAL_MAX() - calculate maximum length of the decimal
- *                   representation of an integer
- * @_type: integer variable/type
- *
- * This calculates the bytes required for the decimal representation of an
- * integer of the given type. It accounts for a possible +/- prefix, but it
- * does *NOT* include the trailing terminating zero byte.
- *
- * Return: Evaluates to a constant integer expression
- */
-#define C_DECIMAL_MAX(_arg)                                                             \
-        (_Generic((__typeof__(_arg)){ 0 },                                              \
-                        char: C_INTERNAL_DECIMAL_MAX(sizeof(char)),                     \
-                 signed char: C_INTERNAL_DECIMAL_MAX(sizeof(signed char)),              \
-               unsigned char: C_INTERNAL_DECIMAL_MAX(sizeof(unsigned char)),            \
-                signed short: C_INTERNAL_DECIMAL_MAX(sizeof(signed short)),             \
-              unsigned short: C_INTERNAL_DECIMAL_MAX(sizeof(unsigned short)),           \
-                  signed int: C_INTERNAL_DECIMAL_MAX(sizeof(signed int)),               \
-                unsigned int: C_INTERNAL_DECIMAL_MAX(sizeof(unsigned int)),             \
-                 signed long: C_INTERNAL_DECIMAL_MAX(sizeof(signed long)),              \
-               unsigned long: C_INTERNAL_DECIMAL_MAX(sizeof(unsigned long)),            \
-            signed long long: C_INTERNAL_DECIMAL_MAX(sizeof(signed long long)),         \
-          unsigned long long: C_INTERNAL_DECIMAL_MAX(sizeof(unsigned long long))))
-#define C_INTERNAL_DECIMAL_MAX(_bytes)                                          \
-        C_EXPR_ASSERT(                                                          \
-                1 + ((_bytes) <= 1 ?  3 :                                       \
-                     (_bytes) <= 2 ?  5 :                                       \
-                     (_bytes) <= 4 ? 10 :                                       \
-                                     20),                                       \
-                (_bytes) <= 8,                                                  \
-                "Invalid use of C_INTERNAL_DECIMAL_MAX()"                       \
-        )
-
-/**
- * c_container_of() - cast a member of a structure out to the containing structure
- * @_ptr:       pointer to the member or NULL
- * @_type:      type of the container struct this is embedded in
- * @_member:    name of the member within the struct
- *
- * This uses `offsetof(3)` to turn a pointer to a structure-member into a
- * pointer to the surrounding structure.
- *
- * Return: Pointer to the surrounding object.
- */
-#define c_container_of(_ptr, _type, _member) C_CC_MACRO1(C_CONTAINER_OF, (_ptr), _type, _member)
-#define C_CONTAINER_OF(_ptr, _type, _member)                                            \
-        __extension__ ({                                                                \
-                /* trigger warning if types do not match */                             \
-                (void)(&((_type *)0)->_member == (_ptr));                               \
-                _ptr ? (_type*)( (char*)_ptr - offsetof(_type, _member) ) : NULL;       \
-        })
-
-/**
- * c_max() - compute maximum of two values
- * @_a:         value A
- * @_b:         value B
- *
- * Calculate the maximum of both passed values. Both arguments are evaluated
- * exactly once, under all circumstances. Furthermore, if both values are
- * constant expressions, the result will be constant as well.
- *
- * The comparison of their values is performed with the types given by the
- * caller. It is the caller's responsibility to convert them to suitable types
- * if necessary.
- *
- * Return: Maximum of both values is returned.
- */
-#define c_max(_a, _b) C_CC_MACRO2(C_MAX, (_a), (_b))
-#define C_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
-
-/**
- * c_min() - compute minimum of two values
- * @_a:         value A
- * @_b:         value B
- *
- * Calculate the minimum of both passed values. Both arguments are evaluated
- * exactly once, under all circumstances. Furthermore, if both values are
- * constant expressions, the result will be constant as well.
- *
- * The comparison of their values is performed with the types given by the
- * caller. It is the caller's responsibility to convert them to suitable types
- * if necessary.
- *
- * Return: Minimum of both values is returned.
- */
-#define c_min(_a, _b) C_CC_MACRO2(C_MIN, (_a), (_b))
-#define C_MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
-
-/**
- * c_less_by() - calculate clamped difference of two values
- * @_a:         minuend
- * @_b:         subtrahend
- *
- * Calculate [_a - _b], but clamp the result to 0. Both arguments are evaluated
- * exactly once, under all circumstances. Furthermore, if both values are
- * constant expressions, the result will be constant as well.
- *
- * The comparison of their values is performed with the types given by the
- * caller. It is the caller's responsibility to convert them to suitable types
- * if necessary.
- *
- * Return: This computes [_a - _b], if [_a > _b]. Otherwise, 0 is returned.
- */
-#define c_less_by(_a, _b) C_CC_MACRO2(C_LESS_BY, (_a), (_b))
-#define C_LESS_BY(_a, _b) ((_a) > (_b) ? (_a) - (_b) : 0)
-
-/**
- * c_clamp() - clamp value to lower and upper boundary
- * @_x:         value to clamp
- * @_low:       lower boundary
- * @_high:      higher boundary
- *
- * This clamps @_x to the lower and higher bounds given as @_low and @_high.
- * All arguments are evaluated exactly once, and yield a constant expression if
- * all arguments are constant as well.
- *
- * The comparison of their values is performed with the types given by the
- * caller. It is the caller's responsibility to convert them to suitable types
- * if necessary.
- *
- * Return: Clamped integer value.
- */
-#define c_clamp(_x, _low, _high) C_CC_MACRO3(C_CLAMP, (_x), (_low), (_high))
-#define C_CLAMP(_x, _low, _high) ((_x) > (_high) ? (_high) : (_x) < (_low) ? (_low) : (_x))
-
-/**
- * c_div_round_up() - calculate integer quotient but round up
- * @_x:         dividend
- * @_y:         divisor
- *
- * Calculates [x / y] but rounds up the result to the next integer. All
- * arguments are evaluated exactly once, and yield a constant expression if all
- * arguments are constant.
- *
- * Note:
- * [(x + y - 1) / y] suffers from an integer overflow, even though the
- * computation should be possible in the given type. Therefore, we use
- * [x / y + !!(x % y)]. Note that on most CPUs a division returns both the
- * quotient and the remainder, so both should be equally fast. Furthermore, if
- * the divisor is a power of two, the compiler will optimize it, anyway.
- *
- * The operationsare performed with the types given by the caller. It is the
- * caller's responsibility to convert the arguments to suitable types if
- * necessary.
- *
- * Return: The quotient is returned.
- */
-#define c_div_round_up(_x, _y) C_CC_MACRO2(C_DIV_ROUND_UP, (_x), (_y))
-#define C_DIV_ROUND_UP(_x, _y) ((_x) / (_y) + !!((_x) % (_y)))
-
-/**
- * c_align_to() - align value to a multiple
- * @_val:       value to align
- * @_to:        align to multiple of this
- *
- * This aligns @_val to a multiple of @_to. If @_val is already a multiple of
- * @_to, @_val is returned unchanged. This function operates within the
- * boundaries of the type of @_val and @_to. Make sure to cast them if needed.
- *
- * The arguments of this macro are evaluated exactly once. If both arguments
- * are a constant expression, this also yields a constant return value.
- *
- * Note that @_to must be a power of 2, otherwise the behavior will not match
- * expectations.
- *
- * Return: @_val aligned to a multiple of @_to
- */
-#define c_align_to(_val, _to) C_CC_MACRO2(C_ALIGN_TO, (_val), (_to))
-#define C_ALIGN_TO(_val, _to) (((_val) + (_to) - 1) & ~((_to) - 1))
-
-/**
- * c_assert() - runtime assertions
- * @expr_result:                result of an expression
- *
- * This function behaves like the standard `assert(3)` macro. That is, if
- * `NDEBUG` is defined, it is a no-op. In all other cases it will assert that
- * the result of the passed expression is true.
- *
- * Unlike the standard `assert(3)` macro, this function always evaluates its
- * argument. This means side-effects will always be evaluated! However, if the
- * macro is used with constant expressions, the compiler will be able to
- * optimize it away.
- */
-#define c_assert(_x) ({                                                         \
-                const _c_unused_ bool c_assert_result = (_x);                   \
-                assert(c_assert_result && #_x);                                 \
-        })
-
-/**
- * c_errno() - return valid errno
- *
- * This helper should be used to shut up gcc if you know 'errno' is valid (ie.,
- * errno is > 0). Instead of "return -errno;", use
- * "return -c_errno();" It will suppress bogus gcc warnings in case it assumes
- * 'errno' might be 0 (or <0) and thus the caller's error-handling might not be
- * triggered.
- *
- * This helper should be avoided whenever possible. However, occasionally we
- * really want to shut up gcc (especially with static/inline functions). In
- * those cases, gcc usually cannot deduce that some error paths are guaranteed
- * to be taken. Hence, making the return value explicit allows gcc to better
- * optimize the code.
- *
- * Note that you really should never use this helper to work around broken libc
- * calls or syscalls, not setting 'errno' correctly.
- *
- * Return: Positive error code is returned.
- */
-static inline int c_errno(void) {
-        return _c_likely_(errno > 0) ? errno : ENOTRECOVERABLE;
-}
-
-/*
- * Common Destructors
- *
- * Followingly, there're a bunch of common 'static inline' destructors, which
- * simply call the function that they're named after, but return "INVALID"
- * instead of "void". This allows direct assignment to any member-field and/or
- * variable they're defined in, like:
- *
- *   foo = c_free(foo);
- *
- * or
- *
- *   foo->bar = c_close(foo->bar);
- *
- * Furthermore, all those destructors can be safely called with the "INVALID"
- * value as argument, and they will be a no-op.
- */
-
-static inline void *c_free(void *p) {
-        free(p);
-        return NULL;
-}
-
-static inline int c_close(int fd) {
-        if (fd >= 0)
-                close(fd);
-        return -1;
-}
-
-static inline FILE *c_fclose(FILE *f) {
-        if (f)
-                fclose(f);
-        return NULL;
-}
-
-static inline DIR *c_closedir(DIR *d) {
-        if (d)
-                closedir(d);
-        return NULL;
-}
-
-/*
- * Common Cleanup Helpers
- *
- * A bunch of _c_cleanup_(foobarp) helpers that are used all over the place.
- * Note that all of those have the "if (IS_INVALID(foobar))" check inline, so
- * compilers can optimize most of the cleanup-paths in a function. However, if
- * the function they call already does this _inline_, then it might be skipped.
- */
-
-#define C_DEFINE_CLEANUP(_type, _func)                                          \
-        static inline void _func ## p(_type *p) {                               \
-                if (*p)                                                         \
-                        _func(*p);                                              \
-        } struct c_internal_trailing_semicolon
-
-#define C_DEFINE_DIRECT_CLEANUP(_type, _func)                                   \
-        static inline void _func ## p(_type *p) {                               \
-                _func(*p);                                                      \
-        } struct c_internal_trailing_semicolon
-
-static inline void c_freep(void *p) {
-        /*
-         * `foobar **` does not coerce to `void **`, so we need `void *` as
-         * argument type, and then we dereference manually.
-         */
-        c_free(*(void **)p);
-}
-
-C_DEFINE_DIRECT_CLEANUP(int, c_close);
-C_DEFINE_CLEANUP(FILE *, c_fclose);
-C_DEFINE_CLEANUP(DIR *, c_closedir);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/shared/meson.build b/shared/meson.build
deleted file mode 100644
index 52eb6b9b..00000000
--- a/shared/meson.build
+++ /dev/null
@@ -1,298 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-
-shared_inc = include_directories('.')
-
-glib_nm_default_dep = declare_dependency(
-  include_directories: [
-    top_inc,
-    shared_inc,
-  ],
-  dependencies: [
-    glib_dep,
-  ],
-)
-
-libc_siphash = static_library(
-  'c-siphash',
-  sources: 'c-siphash/src/c-siphash.c',
-  include_directories: include_directories('c-stdaux/src'),
-)
-
-libc_rbtree = static_library(
-  'c-rbtree',
-  sources: 'c-rbtree/src/c-rbtree.c',
-  include_directories: include_directories('c-stdaux/src'),
-  c_args: '-std=c11',
-)
-
-if enable_ebpf
-  n_acd_bpf_source = 'n-acd/src/n-acd-bpf.c'
-else
-  n_acd_bpf_source = 'n-acd/src/n-acd-bpf-fallback.c'
-endif
-
-libn_acd = static_library(
-  'n-acd',
-  sources: files(
-    'n-acd/src/n-acd.c',
-    'n-acd/src/n-acd-probe.c',
-    'n-acd/src/util/timer.c',
-    n_acd_bpf_source,
-  ),
-  include_directories: include_directories(
-    'c-list/src',
-    'c-rbtree/src',
-    'c-siphash/src',
-    'c-stdaux/src',
-  ),
-  c_args: [
-    '-D_GNU_SOURCE',
-    '-DSO_ATTACH_BPF=50',
-    '-std=c11',
-    '-Wno-pointer-arith',
-    '-Wno-vla',
-  ],
-  link_with: [
-    libc_rbtree,
-    libc_siphash,
-  ],
-)
-
-libn_acd_dep = declare_dependency(
-  include_directories: shared_inc,
-  link_with: libn_acd,
-)
-
-libn_dhcp4 = static_library(
-  'n-dhcp4',
-  sources: files(
-    'n-dhcp4/src/n-dhcp4-c-connection.c',
-    'n-dhcp4/src/n-dhcp4-c-lease.c',
-    'n-dhcp4/src/n-dhcp4-client.c',
-    'n-dhcp4/src/n-dhcp4-c-probe.c',
-    'n-dhcp4/src/n-dhcp4-incoming.c',
-    'n-dhcp4/src/n-dhcp4-outgoing.c',
-    'n-dhcp4/src/n-dhcp4-socket.c',
-    'n-dhcp4/src/util/packet.c',
-    'n-dhcp4/src/util/socket.c',
-  ),
-  c_args: [
-    '-D_GNU_SOURCE',
-    '-Wno-declaration-after-statement',
-    '-Wno-pointer-arith',
-  ],
-  include_directories: include_directories(
-    'c-list/src',
-    'c-siphash/src',
-    'c-stdaux/src',
-  ),
-  link_with: libc_siphash,
-)
-
-libn_dhcp4_dep = declare_dependency(
-  include_directories: shared_inc,
-  link_with: libn_dhcp4,
-)
-
-nm_test_utils_impl_source = files('nm-test-utils-impl.c')
-
-nm_vpn_plugin_utils_source = files('nm-utils/nm-vpn-plugin-utils.c')
-
-libnm_std_aux = static_library(
-  'nm-std-aux',
-  sources: [
-    'nm-std-aux/c-list-util.c',
-    'nm-std-aux/nm-std-utils.c',
-  ],
-  include_directories: top_inc,
-  c_args: [
-    '-DG_LOG_DOMAIN="libnm"',
-  ],
-)
-
-libnm_glib_aux = static_library(
-  'nm-glib-aux',
-  sources: files(
-    'nm-glib-aux/nm-dbus-aux.c',
-    'nm-glib-aux/nm-dedup-multi.c',
-    'nm-glib-aux/nm-enum-utils.c',
-    'nm-glib-aux/nm-errno.c',
-    'nm-glib-aux/nm-hash-utils.c',
-    'nm-glib-aux/nm-io-utils.c',
-    'nm-glib-aux/nm-json-aux.c',
-    'nm-glib-aux/nm-keyfile-aux.c',
-    'nm-glib-aux/nm-logging-base.c',
-    'nm-glib-aux/nm-random-utils.c',
-    'nm-glib-aux/nm-ref-string.c',
-    'nm-glib-aux/nm-secret-utils.c',
-    'nm-glib-aux/nm-shared-utils.c',
-    'nm-glib-aux/nm-time-utils.c',
-  ),
-  dependencies: glib_nm_default_dep,
-  c_args: [
-    '-DG_LOG_DOMAIN="libnm"',
-  ],
-  link_with: [
-    libc_siphash,
-    libnm_std_aux,
-  ],
-)
-
-libnm_glib_aux_dep = declare_dependency(
-  dependencies: glib_nm_default_dep,
-  link_with: libnm_glib_aux,
-)
-
-libnm_udev_aux = static_library(
-  'nm-udev-aux',
-  sources: 'nm-udev-aux/nm-udev-utils.c',
-  dependencies: [
-    glib_nm_default_dep,
-    libudev_dep,
-  ],
-  c_args: [
-    '-DG_LOG_DOMAIN="libnm"',
-  ],
-)
-
-libnm_udev_aux_dep = declare_dependency(
-  include_directories: shared_inc,
-  link_with: libnm_udev_aux,
-)
-
-libnm_base = static_library(
-  'nm-base',
-  sources: files(
-    'nm-base/nm-ethtool-base.c',
-  ),
-  dependencies: libnm_glib_aux_dep,
-  c_args: [
-    '-DG_LOG_DOMAIN="libnm"',
-  ],
-)
-
-libnm_base_dep = declare_dependency(
-  include_directories: shared_inc,
-  dependencies: libnm_glib_aux_dep,
-  link_with: libnm_base,
-)
-
-libnm_log_core = static_library(
-  'nm-log-core',
-  sources: 'nm-log-core/nm-logging.c',
-  dependencies: [
-    glib_nm_default_dep,
-    libsystemd_dep,
-  ],
-  c_args: [
-    '-DG_LOG_DOMAIN="NetworkManager"',
-  ],
-)
-
-libnm_log_core_dep = declare_dependency(
-  include_directories: shared_inc,
-  dependencies: [
-    libnm_glib_aux_dep,
-  ],
-  link_with: libnm_log_core,
-)
-
-libnm_platform = static_library(
-  'nm-platform',
-  sources: [
-    'nm-platform/nm-netlink.c',
-    'nm-platform/nm-platform-utils.c',
-    'nm-platform/nmp-netns.c',
-  ],
-  dependencies: [
-    glib_nm_default_dep,
-  ],
-  c_args: [
-    '-DG_LOG_DOMAIN="NetworkManager"',
-  ],
-)
-
-libnm_platform_dep = declare_dependency(
-  include_directories: shared_inc,
-  dependencies: [
-    libnm_glib_aux_dep,
-  ],
-  link_with: libnm_platform,
-)
-
-libnm_systemd_shared = static_library(
-  'nm-systemd-shared',
-  sources: files(
-    'systemd/nm-sd-utils-shared.c',
-    'systemd/src/basic/alloc-util.c',
-    'systemd/src/basic/env-file.c',
-    'systemd/src/basic/env-util.c',
-    'systemd/src/basic/escape.c',
-    'systemd/src/basic/ether-addr-util.c',
-    'systemd/src/basic/extract-word.c',
-    'systemd/src/basic/fd-util.c',
-    'systemd/src/basic/fileio.c',
-    'systemd/src/basic/format-util.c',
-    'systemd/src/basic/fs-util.c',
-    'systemd/src/basic/hash-funcs.c',
-    'systemd/src/basic/hashmap.c',
-    'systemd/src/basic/hexdecoct.c',
-    'systemd/src/basic/hostname-util.c',
-    'systemd/src/basic/in-addr-util.c',
-    'systemd/src/basic/io-util.c',
-    'systemd/src/basic/memory-util.c',
-    'systemd/src/basic/mempool.c',
-    'systemd/src/basic/parse-util.c',
-    'systemd/src/basic/path-util.c',
-    'systemd/src/basic/prioq.c',
-    'systemd/src/basic/process-util.c',
-    'systemd/src/basic/random-util.c',
-    'systemd/src/basic/ratelimit.c',
-    'systemd/src/basic/signal-util.c',
-    'systemd/src/basic/socket-util.c',
-    'systemd/src/basic/stat-util.c',
-    'systemd/src/basic/string-table.c',
-    'systemd/src/basic/string-util.c',
-    'systemd/src/basic/strv.c',
-    'systemd/src/basic/strxcpyx.c',
-    'systemd/src/basic/time-util.c',
-    'systemd/src/basic/tmpfile-util.c',
-    'systemd/src/basic/utf8.c',
-    'systemd/src/basic/util.c',
-    'systemd/src/shared/dns-domain.c',
-    'systemd/src/shared/web-util.c',
-  ),
-  include_directories: include_directories(
-    'systemd/sd-adapt-shared',
-    'systemd/src/basic',
-    'systemd/src/shared',
-  ),
-  dependencies: glib_nm_default_dep,
-  c_args: [
-    '-DG_LOG_DOMAIN="libnm"',
-  ],
-)
-
-libnm_systemd_shared_dep = declare_dependency(
-  include_directories: include_directories(
-    'systemd/sd-adapt-shared',
-    'systemd/src/basic',
-    'systemd/src/shared',
-  ),
-  dependencies: glib_dep,
-  link_with: libnm_systemd_shared,
-)
-
-libnm_systemd_logging_stub = static_library(
-  'nm-systemd-logging-stub',
-  sources: 'systemd/nm-logging-stub.c',
-  dependencies: glib_nm_default_dep,
-  c_args: [
-    '-DG_LOG_DOMAIN="libnm"',
-  ],
-)
-
-if enable_tests
-  subdir('nm-glib-aux/tests')
-  subdir('nm-platform/tests')
-endif
diff --git a/shared/n-acd/src/n-acd-bpf-fallback.c b/shared/n-acd/src/n-acd-bpf-fallback.c
deleted file mode 100644
index 3cf4eb06..00000000
--- a/shared/n-acd/src/n-acd-bpf-fallback.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * A noop implementation of eBPF filter for IPv4 Address Conflict Detection
- *
- * These are a collection of dummy functions that have no effect, but allows
- * n-acd to compile without eBPF support.
- *
- * See n-acd-bpf.c for documentation.
- */
-
-#include <c-stdaux.h>
-#include <stddef.h>
-#include "n-acd-private.h"
-
-int n_acd_bpf_map_create(int *mapfdp, size_t max_entries) {
-        *mapfdp = -1;
-        return 0;
-}
-
-int n_acd_bpf_map_add(int mapfd, struct in_addr *addrp) {
-        return 0;
-}
-
-int n_acd_bpf_map_remove(int mapfd, struct in_addr *addrp) {
-        return 0;
-}
-
-int n_acd_bpf_compile(int *progfdp, int mapfd, struct ether_addr *macp) {
-        *progfdp = -1;
-        return 0;
-}
diff --git a/shared/n-acd/src/n-acd-bpf.c b/shared/n-acd/src/n-acd-bpf.c
deleted file mode 100644
index 57b29ddf..00000000
--- a/shared/n-acd/src/n-acd-bpf.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * eBPF filter for IPv4 Address Conflict Detection
- *
- * An eBPF map and an eBPF program are provided. The map contains all the
- * addresses address conflict detection is performed on, and the program
- * filters out all packets except exactly the packets relevant to the ACD
- * protocol on the addresses currently in the map.
- *
- * Note that userspace still has to filter the incoming packets, as filter
- * are applied when packets are queued on the socket, not when userspace
- * receives them. It is therefore possible to receive packets about addresses
- * that have already been removed.
- */
-
-#include <c-stdaux.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <linux/bpf.h>
-#include <netinet/if_ether.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-#include "n-acd-private.h"
-
-#define BPF_LD_ABS(SIZE, IMM)                                                   \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS,            \
-                .dst_reg        = 0,                                            \
-                .src_reg        = 0,                                            \
-                .off            = 0,                                            \
-                .imm            = IMM,                                          \
-        })
-
-#define BPF_LDX_MEM(SIZE, DST, SRC, OFF)                                        \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM,           \
-                .dst_reg        = DST,                                          \
-                .src_reg        = SRC,                                          \
-                .off            = OFF,                                          \
-                .imm            = 0,                                            \
-        })
-
-#define BPF_LD_MAP_FD(DST, MAP_FD)                                              \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_LD | BPF_DW | BPF_IMM,                    \
-                .dst_reg        = DST,                                          \
-                .src_reg        = BPF_PSEUDO_MAP_FD,                            \
-                .off            = 0,                                            \
-                .imm            = (__u32) (MAP_FD),                             \
-        }),                                                                     \
-        ((struct bpf_insn) {                                                    \
-                .code           = 0, /* zero is reserved opcode */              \
-                .dst_reg        = 0,                                            \
-                .src_reg        = 0,                                            \
-                .off            = 0,                                            \
-                .imm            = ((__u64) (MAP_FD)) >> 32,                     \
-        })
-
-#define BPF_ALU_REG(OP, DST, SRC)                                               \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_ALU64 | BPF_OP(OP) | BPF_X,               \
-                .dst_reg        = DST,                                          \
-                .src_reg        = SRC,                                          \
-                .off            = 0,                                            \
-                .imm            = 0,                                            \
-        })
-
-#define BPF_ALU_IMM(OP, DST, IMM)                                               \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_ALU64 | BPF_OP(OP) | BPF_K,               \
-                .dst_reg        = DST,                                          \
-                .src_reg        = 0,                                            \
-                .off            = 0,                                            \
-                .imm            = IMM,                                          \
-        })
-
-#define BPF_MOV_REG(DST, SRC)                                                   \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_ALU64 | BPF_MOV | BPF_X,                  \
-                .dst_reg        = DST,                                          \
-                .src_reg        = SRC,                                          \
-                .off            = 0,                                            \
-                .imm            = 0,                                            \
-        })
-
-#define BPF_MOV_IMM(DST, IMM)                                                   \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_ALU64 | BPF_MOV | BPF_K,                  \
-                .dst_reg        = DST,                                          \
-                .src_reg        = 0,                                            \
-                .off            = 0,                                            \
-                .imm            = IMM,                                          \
-        })
-
-#define BPF_STX_MEM(SIZE, DST, SRC, OFF)                                        \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM,           \
-                .dst_reg        = DST,                                          \
-                .src_reg        = SRC,                                          \
-                .off            = OFF,                                          \
-                .imm            = 0,                                            \
-        })
-
-#define BPF_JMP_REG(OP, DST, SRC, OFF)                                          \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_JMP | BPF_OP(OP) | BPF_X,                 \
-                .dst_reg        = DST,                                          \
-                .src_reg        = SRC,                                          \
-                .off            = OFF,                                          \
-                .imm            = 0,                                            \
-        })
-
-#define BPF_JMP_IMM(OP, DST, IMM, OFF)                                          \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_JMP | BPF_OP(OP) | BPF_K,                 \
-                .dst_reg        = DST,                                          \
-                .src_reg        = 0,                                            \
-                .off            = OFF,                                          \
-                .imm            = IMM,                                          \
-        })
-
-#define BPF_EMIT_CALL(FUNC)                                                     \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_JMP | BPF_CALL,                           \
-                .dst_reg        = 0,                                            \
-                .src_reg        = 0,                                            \
-                .off            = 0,                                            \
-                .imm            = FUNC,                                         \
-        })
-
-#define BPF_EXIT_INSN()                                                         \
-        ((struct bpf_insn) {                                                    \
-                .code           = BPF_JMP | BPF_EXIT,                           \
-                .dst_reg        = 0,                                            \
-                .src_reg        = 0,                                            \
-                .off            = 0,                                            \
-                .imm            = 0,                                            \
-        })
-
-static int n_acd_syscall_bpf(int cmd, union bpf_attr *attr, unsigned int size) {
-        return (int)syscall(__NR_bpf, cmd, attr, size);
-}
-
-int n_acd_bpf_map_create(int *mapfdp, size_t max_entries) {
-        union bpf_attr attr;
-        int mapfd;
-
-        memset(&attr, 0, sizeof(attr));
-        attr = (union bpf_attr){
-                .map_type    = BPF_MAP_TYPE_HASH,
-                .key_size    = sizeof(uint32_t),
-                .value_size  = sizeof(uint8_t), /* values are never used, but must be set */
-                .max_entries = max_entries,
-        };
-
-        mapfd = n_acd_syscall_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
-        if (mapfd < 0)
-                return -errno;
-
-        *mapfdp = mapfd;
-        return 0;
-}
-
-int n_acd_bpf_map_add(int mapfd, struct in_addr *addrp) {
-        union bpf_attr attr;
-        uint32_t addr = be32toh(addrp->s_addr);
-        uint8_t _dummy = 0;
-        int r;
-
-        memset(&attr, 0, sizeof(attr));
-        attr = (union bpf_attr){
-                .map_fd = mapfd,
-                .key    = (uint64_t)(unsigned long)&addr,
-                .value  = (uint64_t)(unsigned long)&_dummy,
-                .flags  = BPF_NOEXIST,
-        };
-
-        r = n_acd_syscall_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-int n_acd_bpf_map_remove(int mapfd, struct in_addr *addrp) {
-        uint32_t addr = be32toh(addrp->s_addr);
-        union bpf_attr attr;
-        int r;
-
-        memset(&attr, 0, sizeof(attr));
-        attr = (union bpf_attr){
-                .map_fd = mapfd,
-                .key    = (uint64_t)(unsigned long)&addr,
-        };
-
-        r = n_acd_syscall_bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-int n_acd_bpf_compile(int *progfdp, int mapfd, struct ether_addr *macp) {
-        const union {
-                uint8_t u8[6];
-                uint16_t u16[3];
-                uint32_t u32[1];
-        } mac = {
-                .u8 = {
-                        macp->ether_addr_octet[0],
-                        macp->ether_addr_octet[1],
-                        macp->ether_addr_octet[2],
-                        macp->ether_addr_octet[3],
-                        macp->ether_addr_octet[4],
-                        macp->ether_addr_octet[5],
-                },
-        };
-        struct bpf_insn prog[] = {
-                /* for using BPF_LD_ABS r6 must point to the skb, currently in r1 */
-                BPF_MOV_REG(6, 1),                                              /* r6 = r1 */
-
-                /* drop the packet if it is too short */
-                BPF_LDX_MEM(BPF_W, 0, 6, offsetof(struct __sk_buff, len)),      /* r0 = skb->len */
-                BPF_JMP_IMM(BPF_JGE, 0, sizeof(struct ether_arp), 2),           /* if (r0 >= sizeof(ether_arp)) skip 2 */
-                BPF_MOV_IMM(0, 0),                                              /* r0 = 0 */
-                BPF_EXIT_INSN(),                                                /* return */
-
-                /* drop the packet if the header is not as expected */
-                BPF_LD_ABS(BPF_H, offsetof(struct ether_arp, arp_hrd)),         /* r0 = header type */
-                BPF_JMP_IMM(BPF_JEQ, 0, ARPHRD_ETHER, 2),                       /* if (r0 == ethernet) skip 2 */
-                BPF_MOV_IMM(0, 0),                                              /* r0 = 0 */
-                BPF_EXIT_INSN(),                                                /* return */
-
-                BPF_LD_ABS(BPF_H, offsetof(struct ether_arp, arp_pro)),         /* r0 = protocol */
-                BPF_JMP_IMM(BPF_JEQ, 0, ETHERTYPE_IP, 2),                       /* if (r0 == IP) skip 2 */
-                BPF_MOV_IMM(0, 0),                                              /* r0 = 0 */
-                BPF_EXIT_INSN(),                                                /* return */
-
-                BPF_LD_ABS(BPF_B, offsetof(struct ether_arp, arp_hln)),         /* r0 = hw addr length */
-                BPF_JMP_IMM(BPF_JEQ, 0, sizeof(struct ether_addr), 2),          /* if (r0 == sizeof(ether_addr)) skip 2 */
-                BPF_MOV_IMM(0, 0),                                              /* r0 = 0 */
-                BPF_EXIT_INSN(),                                                /* return */
-
-                BPF_LD_ABS(BPF_B, offsetof(struct ether_arp, arp_pln)),         /* r0 = protocol addr length */
-                BPF_JMP_IMM(BPF_JEQ, 0, sizeof(struct in_addr), 2),             /* if (r0 == sizeof(in_addr)) skip 2 */
-                BPF_MOV_IMM(0, 0),                                              /* r0 = 0 */
-                BPF_EXIT_INSN(),                                                /* return */
-
-                /* drop packets from our own mac address */
-                BPF_LD_ABS(BPF_W, offsetof(struct ether_arp, arp_sha)),         /* r0 = first four bytes of packet mac address */
-                BPF_JMP_IMM(BPF_JNE, 0, be32toh(mac.u32[0]), 4),                /* if (r0 != first four bytes of our mac address) skip 4 */
-                BPF_LD_ABS(BPF_H, offsetof(struct ether_arp, arp_sha) + 4),     /* r0 = last two bytes of packet mac address */
-                BPF_JMP_IMM(BPF_JNE, 0, be16toh(mac.u16[2]), 2),                /* if (r0 != last two bytes of our mac address) skip 2 */
-                BPF_MOV_IMM(0, 0),                                              /* r0 = 0 */
-                BPF_EXIT_INSN(),                                                /* return */
-
-                /*
-                 * We listen for two kinds of packets:
-                 *  Conflicts)
-                 *    These are requests or replies with the sender address not set to INADDR_ANY. The
-                 *    conflicted address is the sender address, remember this in r7.
-                 *  Probes)
-                 *    These are requests with the sender address set to INADDR_ANY. The probed address
-                 *    is the target address, remember this in r7.
-                 *  Any other packets are dropped.
-                 */
-                BPF_LD_ABS(BPF_W, offsetof(struct ether_arp, arp_spa)),         /* r0 = sender ip address */
-                BPF_JMP_IMM(BPF_JEQ, 0, 0, 7),                                  /* if (r0 == 0) skip 7 */
-                BPF_MOV_REG(7, 0),                                              /* r7 = r0 */
-                BPF_LD_ABS(BPF_H, offsetof(struct ether_arp, arp_op)),          /* r0 = operation */
-                BPF_JMP_IMM(BPF_JEQ, 0, ARPOP_REQUEST, 3),                      /* if (r0 == request) skip 3 */
-                BPF_JMP_IMM(BPF_JEQ, 0, ARPOP_REPLY, 2),                        /* if (r0 == reply) skip 2 */
-                BPF_MOV_IMM(0, 0),                                              /* r0 = 0 */
-                BPF_EXIT_INSN(),                                                /* return */
-                BPF_JMP_IMM(BPF_JA, 0, 0, 6),                                   /* skip 6 */
-                BPF_LD_ABS(BPF_W, offsetof(struct ether_arp, arp_tpa)),         /* r0 = target ip address */
-                BPF_MOV_REG(7, 0),                                              /* r7 = r0 */
-                BPF_LD_ABS(BPF_H, offsetof(struct ether_arp, arp_op)),          /* r0 = operation */
-                BPF_JMP_IMM(BPF_JEQ, 0, ARPOP_REQUEST, 2),                      /* if (r0 == request) skip 2 */
-                BPF_MOV_IMM(0, 0),                                              /* r0 = 0 */
-                BPF_EXIT_INSN(),                                                /* return */
-
-                /* check if the probe or conflict is for an address we are monitoring */
-                BPF_STX_MEM(BPF_W, 10, 7, -4),                                  /* *(uint32_t*)fp - 4 = r7 */
-                BPF_MOV_REG(2, 10),                                             /* r2 = fp */
-                BPF_ALU_IMM(BPF_ADD, 2, -4),                                    /* r2 -= 4 */
-                BPF_LD_MAP_FD(1, mapfd),                                        /* r1 = mapfd */
-                BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),                        /* r0 = map_lookup_elem(r1, r2) */
-                BPF_JMP_IMM(BPF_JNE, 0, 0, 2),                                  /* if (r0 != NULL) skip 2 */
-                BPF_MOV_IMM(0, 0),                                              /* r0 = 0 */
-                BPF_EXIT_INSN(),                                                /* return */
-
-                /* return exactly the packet length*/
-                BPF_MOV_IMM(0, sizeof(struct ether_arp)),                       /* r0 = sizeof(struct ether_arp) */
-                BPF_EXIT_INSN(),                                                /* return */
-        };
-        union bpf_attr attr;
-        int progfd;
-
-        memset(&attr, 0, sizeof(attr));
-        attr = (union bpf_attr){
-                .prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
-                .insns     = (uint64_t)(unsigned long)prog,
-                .insn_cnt  = sizeof(prog) / sizeof(*prog),
-                .license   = (uint64_t)(unsigned long)"ASL",
-        };
-
-        progfd = n_acd_syscall_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
-        if (progfd < 0)
-                return -errno;
-
-        *progfdp = progfd;
-        return 0;
-}
diff --git a/shared/n-acd/src/n-acd-private.h b/shared/n-acd/src/n-acd-private.h
deleted file mode 100644
index 4583c018..00000000
--- a/shared/n-acd/src/n-acd-private.h
+++ /dev/null
@@ -1,154 +0,0 @@
-#pragma once
-
-#include <c-list.h>
-#include <c-rbtree.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <netinet/if_ether.h>
-#include <netinet/in.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include "util/timer.h"
-#include "n-acd.h"
-
-typedef struct NAcdEventNode NAcdEventNode;
-
-/* This augments the error-codes with internal ones that are never exposed. */
-enum {
-        _N_ACD_INTERNAL = _N_ACD_E_N,
-
-        N_ACD_E_DROPPED,
-};
-
-enum {
-        N_ACD_PROBE_STATE_PROBING,
-        N_ACD_PROBE_STATE_CONFIGURING,
-        N_ACD_PROBE_STATE_ANNOUNCING,
-        N_ACD_PROBE_STATE_FAILED,
-};
-
-struct NAcdConfig {
-        int ifindex;
-        unsigned int transport;
-        uint8_t mac[ETH_ALEN];
-        size_t n_mac;
-};
-
-#define N_ACD_CONFIG_NULL(_x) {                                                 \
-                .transport = _N_ACD_TRANSPORT_N,                                \
-        }
-
-struct NAcdProbeConfig {
-        struct in_addr ip;
-        uint64_t timeout_msecs;
-};
-
-#define N_ACD_PROBE_CONFIG_NULL(_x) {                                           \
-                .timeout_msecs = N_ACD_TIMEOUT_RFC5227,                         \
-        }
-
-struct NAcdEventNode {
-        CList acd_link;
-        CList probe_link;
-        NAcdEvent event;
-        uint8_t sender[ETH_ALEN];
-        bool is_public : 1;
-};
-
-#define N_ACD_EVENT_NODE_NULL(_x) {                                             \
-                .acd_link = C_LIST_INIT((_x).acd_link),                         \
-                .probe_link = C_LIST_INIT((_x).probe_link),                     \
-        }
-
-struct NAcd {
-        unsigned long n_refs;
-        unsigned int seed;
-        int fd_epoll;
-        int fd_socket;
-        CRBTree ip_tree;
-        CList event_list;
-        Timer timer;
-
-        /* BPF map */
-        int fd_bpf_map;
-        size_t n_bpf_map;
-        size_t max_bpf_map;
-
-        /* configuration */
-        int ifindex;
-        uint8_t mac[ETH_ALEN];
-
-        /* flags */
-        bool preempted : 1;
-};
-
-#define N_ACD_NULL(_x) {                                                        \
-                .n_refs = 1,                                                    \
-                .fd_epoll = -1,                                                 \
-                .fd_socket = -1,                                                \
-                .ip_tree = C_RBTREE_INIT,                                       \
-                .event_list = C_LIST_INIT((_x).event_list),                     \
-                .timer = TIMER_NULL((_x).timer),                                \
-                .fd_bpf_map = -1,                                               \
-        }
-
-struct NAcdProbe {
-        NAcd *acd;
-        CRBNode ip_node;
-        CList event_list;
-        Timeout timeout;
-
-        /* configuration */
-        struct in_addr ip;
-        uint64_t timeout_multiplier;
-        void *userdata;
-
-        /* state */
-        unsigned int state;
-        unsigned int n_iteration;
-        unsigned int defend;
-        uint64_t last_defend;
-};
-
-#define N_ACD_PROBE_NULL(_x) {                                                  \
-                .ip_node = C_RBNODE_INIT((_x).ip_node),                         \
-                .event_list = C_LIST_INIT((_x).event_list),                     \
-                .timeout = TIMEOUT_INIT((_x).timeout),                          \
-                .state = N_ACD_PROBE_STATE_PROBING,                             \
-                .defend = N_ACD_DEFEND_NEVER,                                   \
-        }
-
-/* events */
-
-int n_acd_event_node_new(NAcdEventNode **nodep);
-NAcdEventNode *n_acd_event_node_free(NAcdEventNode *node);
-
-/* contexts */
-
-void n_acd_remember(NAcd *acd, uint64_t now, bool success);
-int n_acd_raise(NAcd *acd, NAcdEventNode **nodep, unsigned int event);
-int n_acd_send(NAcd *acd, const struct in_addr *tpa, const struct in_addr *spa);
-int n_acd_ensure_bpf_map_space(NAcd *acd);
-
-/* probes */
-
-int n_acd_probe_new(NAcdProbe **probep, NAcd *acd, NAcdProbeConfig *config);
-int n_acd_probe_raise(NAcdProbe *probe, NAcdEventNode **nodep, unsigned int event);
-int n_acd_probe_handle_timeout(NAcdProbe *probe);
-int n_acd_probe_handle_packet(NAcdProbe *probe, struct ether_arp *packet, bool hard_conflict);
-
-/* eBPF */
-
-int n_acd_bpf_map_create(int *mapfdp, size_t max_elements);
-int n_acd_bpf_map_add(int mapfd, struct in_addr *addr);
-int n_acd_bpf_map_remove(int mapfd, struct in_addr *addr);
-
-int n_acd_bpf_compile(int *progfdp, int mapfd, struct ether_addr *mac);
-
-/* inline helpers */
-
-static inline void n_acd_event_node_freep(NAcdEventNode **node) {
-        if (*node)
-                n_acd_event_node_free(*node);
-}
diff --git a/shared/n-acd/src/n-acd-probe.c b/shared/n-acd/src/n-acd-probe.c
deleted file mode 100644
index 2a5c6451..00000000
--- a/shared/n-acd/src/n-acd-probe.c
+++ /dev/null
@@ -1,712 +0,0 @@
-/*
- * IPv4 Address Conflict Detection
- *
- * This file implements the probe object. A probe is basically the
- * state-machine of a single ACD run. It takes an address to probe for, checks
- * for conflicts and then defends it once configured.
- */
-
-#include <assert.h>
-#include <c-rbtree.h>
-#include <c-stdaux.h>
-#include <endian.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <netinet/if_ether.h>
-#include <netinet/in.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "n-acd.h"
-#include "n-acd-private.h"
-
-/*
- * These parameters and timing intervals are specified in RFC-5227. The
- * original values are:
- *
- *     PROBE_NUM                                3
- *     PROBE_WAIT                               1s
- *     PROBE_MIN                                1s
- *     PROBE_MAX                                3s
- *     ANNOUNCE_NUM                             3
- *     ANNOUNCE_WAIT                            2s
- *     ANNOUNCE_INTERVAL                        2s
- *     MAX_CONFLICTS                            10
- *     RATE_LIMIT_INTERVAL                      60s
- *     DEFEND_INTERVAL                          10s
- *
- * If we assume a best-case and worst-case scenario for non-conflicted runs, we
- * end up with a runtime between 4s and 9s to finish the probe. Then it still
- * takes a fixed 4s to finish the announcements.
- *
- * RFC 5227 section 1.1:
- *     [...] (Note that the values listed here are fixed constants; they are
- *     not intended to be modifiable by implementers, operators, or end users.
- *     These constants are given symbolic names here to facilitate the writing
- *     of future standards that may want to reference this document with
- *     different values for these named constants; however, at the present time
- *     no such future standards exist.) [...]
- *
- * Unfortunately, no-one ever stepped up to write a "future standard" to revise
- * the timings. A 9s timeout for successful link setups is not acceptable today.
- * Hence, we will just go forward and ignore the proposed values. On both
- * wired and wireless local links round-trip latencies of below 3ms are common.
- * We require the caller to set a timeout multiplier, where 1 corresponds to a
- * total probe time between 0.5 ms and 1.0 ms. On modern networks a multiplier
- * of about 100 should be a reasonable default. To comply with the RFC select a
- * multiplier of 9000.
- */
-#define N_ACD_RFC_PROBE_NUM                     (3)
-#define N_ACD_RFC_PROBE_WAIT_NSEC               (UINT64_C(111111)) /* 1/9 ms */
-#define N_ACD_RFC_PROBE_MIN_NSEC                (UINT64_C(111111)) /* 1/9 ms */
-#define N_ACD_RFC_PROBE_MAX_NSEC                (UINT64_C(333333)) /* 3/9 ms */
-#define N_ACD_RFC_ANNOUNCE_NUM                  (3)
-#define N_ACD_RFC_ANNOUNCE_WAIT_NSEC            (UINT64_C(222222)) /* 2/9 ms */
-#define N_ACD_RFC_ANNOUNCE_INTERVAL_NSEC        (UINT64_C(222222)) /* 2/9 ms */
-#define N_ACD_RFC_MAX_CONFLICTS                 (10)
-#define N_ACD_RFC_RATE_LIMIT_INTERVAL_NSEC      (UINT64_C(60000000000)) /* 60s */
-#define N_ACD_RFC_DEFEND_INTERVAL_NSEC          (UINT64_C(10000000000)) /* 10s */
-
-/**
- * n_acd_probe_config_new() - create probe configuration
- * @configp:                    output argument for new probe configuration
- *
- * This creates a new probe configuration. It will be returned in @configp to
- * the caller, which upon return fully owns the object.
- *
- * A probe configuration collects parameters for probes. It never validates the
- * input, but this is left to the consumer of the configuration to do.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_acd_probe_config_new(NAcdProbeConfig **configp) {
-        _c_cleanup_(n_acd_probe_config_freep) NAcdProbeConfig *config = NULL;
-
-        config = malloc(sizeof(*config));
-        if (!config)
-                return -ENOMEM;
-
-        *config = (NAcdProbeConfig)N_ACD_PROBE_CONFIG_NULL(*config);
-
-        *configp = config;
-        config = NULL;
-        return 0;
-}
-
-/**
- * n_acd_probe_config_free() - destroy probe configuration
- * @config:                     configuration to operate on, or NULL
- *
- * This destroys the probe configuration and all associated objects. If @config
- * is NULL, this is a no-op.
- *
- * Return: NULL is returned.
- */
-_c_public_ NAcdProbeConfig *n_acd_probe_config_free(NAcdProbeConfig *config) {
-        if (!config)
-                return NULL;
-
-        free(config);
-
-        return NULL;
-}
-
-/**
- * n_acd_probe_config_set_ip() - set ip property
- * @config:                     configuration to operate on
- * @ip:                         ip to set
- *
- * This sets the IP property to the value `ip`. The address is copied into the
- * configuration object. No validation is performed.
- *
- * The IP property selects the IP address that a probe checks for. It is the
- * caller's responsibility to guarantee the address is valid and can be used.
- */
-_c_public_ void n_acd_probe_config_set_ip(NAcdProbeConfig *config, struct in_addr ip) {
-        config->ip = ip;
-}
-
-/**
- * n_acd_probe_config_set_timeout() - set timeout property
- * @config:                     configuration to operate on
- * @msecs:                      timeout to set, in milliseconds
- *
- * This sets the timeout to use for a conflict detection probe. The
- * specification default is provided as `N_ACD_TIMEOUT_RFC5227` and corresponds
- * to 9 seconds.
- *
- * If set to 0, conflict detection is skipped and the address is immediately
- * advertised and defended.
- *
- * Depending on the transport used, the API user should select a suitable
- * timeout. Since `ACD` only operates on the link layer, timeouts in the
- * hundreds of milliseconds range should be more than enough for any modern
- * network. Note that increasing this value directly affects the time it takes
- * to connect to a network, since an address should not be used unless conflict
- * detection finishes.
- *
- * Using the specification default is **discouraged**. It is way too slow and
- * not appropriate for modern networks.
- *
- * Default value is `N_ACD_TIMEOUT_RFC5227`.
- */
-_c_public_ void n_acd_probe_config_set_timeout(NAcdProbeConfig *config, uint64_t msecs) {
-        config->timeout_msecs = msecs;
-}
-
-static void n_acd_probe_schedule(NAcdProbe *probe, uint64_t n_timeout, unsigned int n_jitter) {
-        uint64_t n_time;
-
-        timer_now(&probe->acd->timer, &n_time);
-        n_time += n_timeout;
-
-        /*
-         * ACD specifies jitter values to reduce packet storms on the local
-         * link. This call accepts the maximum relative jitter value in
-         * nanoseconds as @n_jitter. We then use rand_r(3p) to get a
-         * pseudo-random jitter on top of the real timeout given as @n_timeout.
-         */
-        if (n_jitter) {
-                uint64_t random;
-
-                random = ((uint64_t)rand_r(&probe->acd->seed) << 32) | (uint64_t)rand_r(&probe->acd->seed);
-                n_time += random % n_jitter;
-        }
-
-        timeout_schedule(&probe->timeout, &probe->acd->timer, n_time);
-}
-
-static void n_acd_probe_unschedule(NAcdProbe *probe) {
-        timeout_unschedule(&probe->timeout);
-}
-
-static bool n_acd_probe_is_unique(NAcdProbe *probe) {
-        NAcdProbe *sibling;
-
-        if (!c_rbnode_is_linked(&probe->ip_node))
-                return false;
-
-        sibling = c_rbnode_entry(c_rbnode_next(&probe->ip_node), NAcdProbe, ip_node);
-        if (sibling && sibling->ip.s_addr == probe->ip.s_addr)
-                return false;
-
-        sibling = c_rbnode_entry(c_rbnode_prev(&probe->ip_node), NAcdProbe, ip_node);
-        if (sibling && sibling->ip.s_addr == probe->ip.s_addr)
-                return false;
-
-        return true;
-}
-
-static int n_acd_probe_link(NAcdProbe *probe) {
-        int r;
-
-        /*
-         * Make sure the kernel bpf map has space for at least one more
-         * entry.
-         */
-        r = n_acd_ensure_bpf_map_space(probe->acd);
-        if (r)
-                return r;
-
-        /*
-         * Link entry into context, indexed by its IP. Note that we allow
-         * duplicates just fine. It is up to you to decide whether to avoid
-         * duplicates, if you don't want them. Duplicates on the same context
-         * do not conflict with each other, though.
-         */
-        {
-                CRBNode **slot, *parent;
-                NAcdProbe *other;
-
-                slot = &probe->acd->ip_tree.root;
-                parent = NULL;
-                while (*slot) {
-                        other = c_rbnode_entry(*slot, NAcdProbe, ip_node);
-                        parent = *slot;
-                        if (probe->ip.s_addr < other->ip.s_addr)
-                                slot = &(*slot)->left;
-                        else
-                                slot = &(*slot)->right;
-                }
-
-                c_rbtree_add(&probe->acd->ip_tree, parent, slot, &probe->ip_node);
-        }
-
-        /*
-         * Add the ip address to the map, if it is not already there.
-         */
-        if (n_acd_probe_is_unique(probe)) {
-                r = n_acd_bpf_map_add(probe->acd->fd_bpf_map, &probe->ip);
-                if (r) {
-                        /*
-                         * Make sure the IP address is linked in userspace iff
-                         * it is linked in the kernel.
-                         */
-                        c_rbnode_unlink(&probe->ip_node);
-                        return r;
-                }
-                ++probe->acd->n_bpf_map;
-        }
-
-        return 0;
-}
-
-static void n_acd_probe_unlink(NAcdProbe *probe) {
-        int r;
-
-        /*
-         * If this is the only probe for a given IP, remove the IP from the
-         * kernel BPF map.
-         */
-        if (n_acd_probe_is_unique(probe)) {
-                r = n_acd_bpf_map_remove(probe->acd->fd_bpf_map, &probe->ip);
-                c_assert(r >= 0);
-                --probe->acd->n_bpf_map;
-        }
-        c_rbnode_unlink(&probe->ip_node);
-}
-
-int n_acd_probe_new(NAcdProbe **probep, NAcd *acd, NAcdProbeConfig *config) {
-        _c_cleanup_(n_acd_probe_freep) NAcdProbe *probe = NULL;
-        int r;
-
-        if (!config->ip.s_addr)
-                return N_ACD_E_INVALID_ARGUMENT;
-
-        probe = malloc(sizeof(*probe));
-        if (!probe)
-                return -ENOMEM;
-
-        *probe = (NAcdProbe)N_ACD_PROBE_NULL(*probe);
-        probe->acd = n_acd_ref(acd);
-        probe->ip = config->ip;
-
-        /*
-         * We use the provided timeout-length as multiplier for all our
-         * timeouts. The provided timeout defines the maximum length of an
-         * entire probe-interval until the first announcement. Given the
-         * spec-provided parameters, this ends up as:
-         *
-         *     PROBE_WAIT + PROBE_MAX + PROBE_MAX + ANNOUNCE_WAIT
-         *   =         1s +        3s +        3s +            2s
-         *   = 9s
-         *
-         * Hence, the default value for this timeout is 9000ms, which just
-         * ends up matching the spec-provided values.
-         *
-         * What we now semantically do is divide this timeout by 1ns/1000000.
-         * This first turns it into nanoseconds, then strips the unit by
-         * turning it into a multiplier. However, rather than performing the
-         * division here, we multiplier all our timeouts by 1000000 statically
-         * at compile time. Therefore, we can use the user-provided timeout as
-         * unmodified multiplier. No conversion necessary.
-         */
-        probe->timeout_multiplier = config->timeout_msecs;
-
-        r = n_acd_probe_link(probe);
-        if (r)
-                return r;
-
-        /*
-         * Now that everything is set up, we have to send the first probe. This
-         * is done after ~PROBE_WAIT seconds, hence we schedule our timer.
-         * In case no timeout-multiplier is set, we pretend we already sent all
-         * probes successfully and schedule the timer so we proceed with the
-         * announcements. We must schedule a fake timer there, since we are not
-         * allowed to advance the state machine outside of n_acd_dispatch().
-         */
-        if (probe->timeout_multiplier) {
-                probe->n_iteration = 0;
-                n_acd_probe_schedule(probe,
-                                     0,
-                                     probe->timeout_multiplier * N_ACD_RFC_PROBE_WAIT_NSEC);
-        } else {
-                probe->n_iteration = N_ACD_RFC_PROBE_NUM;
-                n_acd_probe_schedule(probe, 0, 0);
-        }
-
-        *probep = probe;
-        probe = NULL;
-        return 0;
-}
-
-/**
- * n_acd_probe_free() - destroy a probe
- * @probe:                      probe to operate on, or NULL
- *
- * This destroys the probe specified by @probe. All operations are immediately
- * ceded and all associated objects are released.
- *
- * If @probe is NULL, this is a no-op.
- *
- * This function will flush all events associated with @probe from the event
- * queue. That is, no events will be returned for this @probe anymore.
- *
- * Return: NULL is returned.
- */
-_c_public_ NAcdProbe *n_acd_probe_free(NAcdProbe *probe) {
-        NAcdEventNode *node, *t_node;
-
-        if (!probe)
-                return NULL;
-
-        c_list_for_each_entry_safe(node, t_node, &probe->event_list, probe_link)
-                n_acd_event_node_free(node);
-
-        n_acd_probe_unschedule(probe);
-        n_acd_probe_unlink(probe);
-        probe->acd = n_acd_unref(probe->acd);
-        free(probe);
-
-        return NULL;
-}
-
-int n_acd_probe_raise(NAcdProbe *probe, NAcdEventNode **nodep, unsigned int event) {
-        _c_cleanup_(n_acd_event_node_freep) NAcdEventNode *node = NULL;
-        int r;
-
-        r = n_acd_raise(probe->acd, &node, event);
-        if (r)
-                return r;
-
-        switch (event) {
-        case N_ACD_EVENT_READY:
-                node->event.ready.probe = probe;
-                break;
-        case N_ACD_EVENT_USED:
-                node->event.used.probe = probe;
-                break;
-        case N_ACD_EVENT_DEFENDED:
-                node->event.defended.probe = probe;
-                break;
-        case N_ACD_EVENT_CONFLICT:
-                node->event.conflict.probe = probe;
-                break;
-        default:
-                c_assert(0);
-                return -ENOTRECOVERABLE;
-        }
-
-        c_list_link_tail(&probe->event_list, &node->probe_link);
-
-        if (nodep)
-                *nodep = node;
-        node = NULL;
-        return 0;
-}
-
-int n_acd_probe_handle_timeout(NAcdProbe *probe) {
-        int r;
-
-        switch (probe->state) {
-        case N_ACD_PROBE_STATE_PROBING:
-                /*
-                 * We are still PROBING. We send 3 probes with a random timeout
-                 * scheduled between each. If, after a fixed timeout, we did
-                 * not receive any conflict we consider the probing successful.
-                 */
-                if (probe->n_iteration < N_ACD_RFC_PROBE_NUM) {
-                        /*
-                         * We have not sent all 3 probes, yet. A timer fired,
-                         * so we are ready to send the next probe. If this is
-                         * the third probe, schedule a timer for ANNOUNCE_WAIT
-                         * to give other peers a chance to answer. If this is
-                         * not the third probe, wait between PROBE_MIN and
-                         * PROBE_MAX for the next probe.
-                         */
-
-                        r = n_acd_send(probe->acd, &probe->ip, NULL);
-                        if (r) {
-                                if (r != -N_ACD_E_DROPPED)
-                                        return r;
-
-                                /*
-                                 * Packet was dropped, and we know about it. It
-                                 * never reached the network. Reasons are
-                                 * manifold, and n_acd_send() raises events if
-                                 * necessary.
-                                 * From a probe-perspective, we simply pretend
-                                 * we never sent the probe and schedule a
-                                 * timeout for the next probe, effectively
-                                 * doubling a single probe-interval.
-                                 */
-                        } else {
-                                /* Successfully sent, so advance counter. */
-                                ++probe->n_iteration;
-                        }
-
-                        if (probe->n_iteration < N_ACD_RFC_PROBE_NUM)
-                                n_acd_probe_schedule(probe,
-                                                     probe->timeout_multiplier * N_ACD_RFC_PROBE_MIN_NSEC,
-                                                     probe->timeout_multiplier * (N_ACD_RFC_PROBE_MAX_NSEC - N_ACD_RFC_PROBE_MIN_NSEC));
-                        else
-                                n_acd_probe_schedule(probe,
-                                                     probe->timeout_multiplier * N_ACD_RFC_ANNOUNCE_WAIT_NSEC,
-                                                     0);
-                } else {
-                        /*
-                         * All 3 probes succeeded and we waited enough to
-                         * consider this address usable by now. Do not announce
-                         * the address, yet. We must first give the caller a
-                         * chance to configure the address (so they can answer
-                         * ARP requests), before announcing it.
-                         */
-                        r = n_acd_probe_raise(probe, NULL, N_ACD_EVENT_READY);
-                        if (r)
-                                return r;
-
-                        probe->state = N_ACD_PROBE_STATE_CONFIGURING;
-                }
-
-                break;
-
-        case N_ACD_PROBE_STATE_ANNOUNCING:
-                /*
-                 * We are ANNOUNCING, meaning the caller configured the address
-                 * on the interface and is actively using it. We send 3
-                 * announcements out, in a short interval, and then just
-                 * perform passive conflict detection.
-                 * Note that once all 3 announcements are sent, we no longer
-                 * schedule a timer, so this part should not trigger, anymore.
-                 */
-
-                r = n_acd_send(probe->acd, &probe->ip, &probe->ip);
-                if (r) {
-                        if (r != -N_ACD_E_DROPPED)
-                                return r;
-
-                        /*
-                         * See above in STATE_PROBING for details. We know the
-                         * packet was never sent, so we simply try again after
-                         * extending the timer.
-                         */
-                } else {
-                        /* Successfully sent, so advance counter. */
-                        ++probe->n_iteration;
-                }
-
-                if (probe->n_iteration < N_ACD_RFC_ANNOUNCE_NUM) {
-                        /*
-                         * Announcements are always scheduled according to the
-                         * time-intervals specified in the spec. We always use
-                         * the RFC5227-mandated multiplier.
-                         * If you reconsider this, note that timeout_multiplier
-                         * might be 0 here.
-                         */
-                        n_acd_probe_schedule(probe,
-                                             N_ACD_TIMEOUT_RFC5227 * N_ACD_RFC_ANNOUNCE_INTERVAL_NSEC,
-                                             0);
-                }
-
-                break;
-
-        case N_ACD_PROBE_STATE_CONFIGURING:
-        case N_ACD_PROBE_STATE_FAILED:
-        default:
-                /*
-                 * There are no timeouts in these states. If we trigger one,
-                 * something is fishy.
-                 */
-                c_assert(0);
-                return -ENOTRECOVERABLE;
-        }
-
-        return 0;
-}
-
-int n_acd_probe_handle_packet(NAcdProbe *probe, struct ether_arp *packet, bool hard_conflict) {
-        NAcdEventNode *node;
-        uint64_t now;
-        int r;
-
-        timer_now(&probe->acd->timer, &now);
-
-        switch (probe->state) {
-        case N_ACD_PROBE_STATE_PROBING:
-                /*
-                 * Regardless whether this is a hard or soft conflict, we must
-                 * treat this as a probe failure. That is, notify the caller of
-                 * the conflict and wait for further instructions. We do not
-                 * react to this, until the caller tells us what to do, but we
-                 * do stop sending further probes.
-                 */
-                r = n_acd_probe_raise(probe, &node, N_ACD_EVENT_USED);
-                if (r)
-                        return r;
-
-                node->event.used.sender = node->sender;
-                node->event.used.n_sender = ETH_ALEN;
-                memcpy(node->sender, packet->arp_sha, ETH_ALEN);
-
-                n_acd_probe_unschedule(probe);
-                n_acd_probe_unlink(probe);
-                probe->state = N_ACD_PROBE_STATE_FAILED;
-
-                break;
-
-        case N_ACD_PROBE_STATE_CONFIGURING:
-                /*
-                 * We are waiting for the caller to configure the interface and
-                 * start ANNOUNCING. In this state, we cannot defend the
-                 * address as that would indicate that it is ready to be used,
-                 * and we cannot signal CONFLICT or USED as the caller may
-                 * already have started to use the address (and may have
-                 * configured the engine to always defend it, which means they
-                 * should be able to rely on never losing it after READY).
-                 * Simply drop the event, and rely on the anticipated ANNOUNCE
-                 * to trigger it again.
-                 */
-
-                break;
-
-        case N_ACD_PROBE_STATE_ANNOUNCING: {
-                /*
-                 * We were already instructed to announce the address, which
-                 * means the address is configured and in use. Hence, the
-                 * caller is responsible to serve regular ARP queries. Meaning,
-                 * we can ignore any soft conflicts (other peers doing ACD).
-                 *
-                 * But if we see a hard-conflict, we either defend the address
-                 * according to the caller's instructions, or we report the
-                 * conflict and bail out.
-                 */
-                bool conflict = false, rate_limited = false;
-
-                if (!hard_conflict)
-                        break;
-
-                rate_limited = now < probe->last_defend + N_ACD_RFC_DEFEND_INTERVAL_NSEC;
-
-                switch (probe->defend) {
-                case N_ACD_DEFEND_NEVER:
-                        conflict = true;
-                        break;
-                case N_ACD_DEFEND_ONCE:
-                        if (rate_limited) {
-                                conflict = true;
-                                break;
-                        }
-
-                        /* fallthrough */
-                case N_ACD_DEFEND_ALWAYS:
-                        if (!rate_limited) {
-                                r = n_acd_send(probe->acd, &probe->ip, &probe->ip);
-                                if (r) {
-                                        if (r != -N_ACD_E_DROPPED)
-                                                return r;
-
-                                        if (probe->defend == N_ACD_DEFEND_ONCE) {
-                                                conflict = true;
-                                                break;
-                                        }
-                                }
-
-                                if (r != -N_ACD_E_DROPPED)
-                                        probe->last_defend = now;
-                        }
-
-                        r = n_acd_probe_raise(probe, &node, N_ACD_EVENT_DEFENDED);
-                        if (r)
-                                return r;
-
-                        node->event.defended.sender = node->sender;
-                        node->event.defended.n_sender = ETH_ALEN;
-                        memcpy(node->sender, packet->arp_sha, ETH_ALEN);
-
-                        break;
-                }
-
-                if (conflict) {
-                        r = n_acd_probe_raise(probe, &node, N_ACD_EVENT_CONFLICT);
-                        if (r)
-                                return r;
-
-                        node->event.conflict.sender = node->sender;
-                        node->event.conflict.n_sender = ETH_ALEN;
-                        memcpy(node->sender, packet->arp_sha, ETH_ALEN);
-
-                        n_acd_probe_unschedule(probe);
-                        n_acd_probe_unlink(probe);
-                        probe->state = N_ACD_PROBE_STATE_FAILED;
-                }
-
-                break;
-        }
-
-        case N_ACD_PROBE_STATE_FAILED:
-        default:
-                /*
-                 * We are not listening for packets in these states. If we receive one,
-                 * something is fishy.
-                 */
-                c_assert(0);
-                return -ENOTRECOVERABLE;
-        }
-
-        return 0;
-}
-
-/**
- * n_acd_probe_set_userdata - set userdata
- * @probe:                      probe to operate on
- * @userdata:                   userdata pointer
- *
- * This can be used to set a caller-controlled user-data pointer on @probe. The
- * value of the pointer is never inspected or used by `n-acd` and is fully
- * under control of the caller.
- *
- * The default value is NULL.
- */
-_c_public_ void n_acd_probe_set_userdata(NAcdProbe *probe, void *userdata) {
-        probe->userdata = userdata;
-}
-
-/**
- * n_acd_probe_get_userdata - get userdata
- * @probe:                      probe to operate on
- *
- * This queries the userdata pointer that was previously set through
- * n_acd_probe_set_userdata().
- *
- * The default value is NULL.
- *
- * Return: The stored userdata pointer is returned.
- */
-_c_public_ void n_acd_probe_get_userdata(NAcdProbe *probe, void **userdatap) {
-        *userdatap = probe->userdata;
-}
-
-/**
- * n_acd_probe_announce() - announce the configured IP address
- * @probe:                      probe to operate on
- * @defend:                     defense policy
- *
- * Announce the IP address on the local link, and start defending it according
- * to the given policy, which mut be one of N_ACD_DEFEND_ONCE,
- * N_ACD_DEFEND_NEVER, or N_ACD_DEFEND_ALWAYS.
- *
- * This must be called in response to an N_ACD_EVENT_READY event, and only
- * after the given address has been configured on the given network interface.
- *
- * Return: 0 on success, N_ACD_E_INVALID_ARGUMENT in case the defense policy
- *         is invalid, negative error code on failure.
- */
-_c_public_ int n_acd_probe_announce(NAcdProbe *probe, unsigned int defend) {
-        if (defend >= _N_ACD_DEFEND_N)
-                return N_ACD_E_INVALID_ARGUMENT;
-
-        probe->state = N_ACD_PROBE_STATE_ANNOUNCING;
-        probe->defend = defend;
-        probe->n_iteration = 0;
-
-        /*
-         * We must schedule a fake-timeout, since we are not allowed to
-         * advance the state-machine outside of n_acd_dispatch().
-         */
-        n_acd_probe_schedule(probe, 0, 0);
-
-        return 0;
-}
diff --git a/shared/n-acd/src/n-acd.c b/shared/n-acd/src/n-acd.c
deleted file mode 100644
index c1d92865..00000000
--- a/shared/n-acd/src/n-acd.c
+++ /dev/null
@@ -1,1027 +0,0 @@
-/*
- * IPv4 Address Conflict Detection
- *
- * This file contains the main context initialization and management functions,
- * as well as a bunch of utilities used through the n-acd modules.
- */
-
-/**
- * DOC: IPv4 Address Conflict Detection
- *
- * The `n-acd` project implements the IPv4 Address Conflict Detection protocol
- * as defined in RFC-5227. The protocol originates in the IPv4 Link Local
- * Address selection but was later on generalized and resulted in `ACD`. The
- * idea is to use `ARP` to query a link for an address to see whether it
- * already exists on the network, as well as defending an address that is in
- * use on a network interface. Furthermore, `ACD` provides passive diagnostics
- * for administrators, as it will detect address conflicts automatically, which
- * then can be logged or shown to a user.
- *
- * The main context object of `n-acd` is the `NAcd` structure. It is a passive
- * ref-counted context object which drives `ACD` probes running on it. A
- * context is specific to a linux network device and transport. If multiple
- * network devices are used, then separate `NAcd` contexts must be deployed.
- *
- * The `NAcdProbe` object drives a single `ACD` state-machine. A probe is
- * created on an `NAcd` context by providing an address to probe for. The probe
- * will then raise notifications whether the address conflict detection found
- * something, or whether the address is ready to be used. Optionally, the probe
- * will then enter into passive mode and defend the address as long as it is
- * kept active.
- *
- * Note that the `n-acd` project only implements the networking protocol. It
- * never queries or modifies network interfaces. It completely relies on the
- * API user to react to notifications and update network interfaces
- * respectively. `n-acd` uses an event-mechanism on every context object. All
- * events raise by any probe or operation on a given context will queue all
- * events on that context object. The event-queue can then be drained by the
- * API user. All events are properly asynchronous and designed in a way that no
- * synchronous reaction to any event is required. That is, the events are
- * carefully designed to allow forwarding via IPC (or even networks) to a
- * controller that handles them and specifies how to react. Furthermore, none
- * of the function calls of `n-acd` require synchronous error handling.
- * Instead, functions only ever return values on fatal errors. Everything else
- * is queued as events, thus guaranteeing that synchronous handling of return
- * values is not required. Exceptions are functions that do not affect internal
- * state or do not have an associated context object.
- */
-
-#include <assert.h>
-#include <c-list.h>
-#include <c-rbtree.h>
-#include <c-siphash.h>
-#include <c-stdaux.h>
-#include <endian.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <linux/if_packet.h>
-#include <netinet/if_ether.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/auxv.h>
-#include <sys/epoll.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "n-acd.h"
-#include "n-acd-private.h"
-
-enum {
-        N_ACD_EPOLL_TIMER,
-        N_ACD_EPOLL_SOCKET,
-};
-
-static int n_acd_get_random(unsigned int *random) {
-        uint8_t hash_seed[] = {
-                0x3a, 0x0c, 0xa6, 0xdd, 0x44, 0xef, 0x5f, 0x7a,
-                0x5e, 0xd7, 0x25, 0x37, 0xbf, 0x4e, 0x80, 0xa1,
-        };
-        CSipHash hash = C_SIPHASH_NULL;
-        struct timespec ts;
-        const uint8_t *p;
-        int r;
-
-        /*
-         * We need random jitter for all timeouts when handling ARP probes. Use
-         * AT_RANDOM to get a seed for rand_r(3p), if available (should always
-         * be available on linux). See the time-out scheduler for details.
-         * Additionally, we include the current time in the seed. This avoids
-         * using the same jitter in case you run multiple ACD engines in the
-         * same process. Lastly, the seed is hashed with SipHash24 to avoid
-         * exposing the value of AT_RANDOM on the network.
-         */
-        c_siphash_init(&hash, hash_seed);
-
-        p = (const uint8_t *)getauxval(AT_RANDOM);
-        if (p)
-                c_siphash_append(&hash, p, 16);
-
-        r = clock_gettime(CLOCK_MONOTONIC, &ts);
-        if (r < 0)
-                return -c_errno();
-
-        c_siphash_append(&hash, (const uint8_t *)&ts.tv_sec, sizeof(ts.tv_sec));
-        c_siphash_append(&hash, (const uint8_t *)&ts.tv_nsec, sizeof(ts.tv_nsec));
-
-        *random = c_siphash_finalize(&hash);
-        return 0;
-}
-
-static int n_acd_socket_new(int *fdp, int fd_bpf_prog, NAcdConfig *config) {
-        const struct sockaddr_ll address = {
-                .sll_family = AF_PACKET,
-                .sll_protocol = htobe16(ETH_P_ARP),
-                .sll_ifindex = config->ifindex,
-                .sll_halen = ETH_ALEN,
-                .sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
-        };
-        int r, s = -1;
-
-        s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-        if (s < 0) {
-                r = -c_errno();
-                goto error;
-        }
-
-        if (fd_bpf_prog >= 0) {
-                r = setsockopt(s, SOL_SOCKET, SO_ATTACH_BPF, &fd_bpf_prog, sizeof(fd_bpf_prog));
-                if (r < 0) {
-                        r = -c_errno();
-                        goto error;
-                }
-        }
-
-        r = bind(s, (struct sockaddr *)&address, sizeof(address));
-        if (r < 0) {
-                r = -c_errno();
-                goto error;
-        }
-
-        *fdp = s;
-        s = -1;
-        return 0;
-
-error:
-        if (s >= 0)
-                close(s);
-        return r;
-}
-
-/**
- * n_acd_config_new() - create configuration object
- * @configp:                    output argument for new configuration
- *
- * This creates a new configuration object and provides it to the caller. The
- * object is fully owned by the caller upon function return.
- *
- * A configuration object is a passive structure that is used to collect
- * information that is then passed to a constructor or other function. A
- * configuration never validates the data, but it is up to the consumer of a
- * configuration to do that.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_acd_config_new(NAcdConfig **configp) {
-        _c_cleanup_(n_acd_config_freep) NAcdConfig *config = NULL;
-
-        config = malloc(sizeof(*config));
-        if (!config)
-                return -ENOMEM;
-
-        *config = (NAcdConfig)N_ACD_CONFIG_NULL(*config);
-
-        *configp = config;
-        config = NULL;
-        return 0;
-}
-
-/**
- * n_acd_config_free() - destroy configuration object
- * @config:                     configuration to operate on, or NULL
- *
- * This destroys the configuration object @config. If @config is NULL, this is
- * a no-op.
- *
- * Return: NULL is returned.
- */
-_c_public_ NAcdConfig *n_acd_config_free(NAcdConfig *config) {
-        if (!config)
-                return NULL;
-
-        free(config);
-
-        return NULL;
-}
-
-/**
- * n_acd_config_set_ifindex() - set ifindex property
- * @config:                     configuration to operate on
- * @ifindex:                    ifindex to set
- *
- * This sets the @ifindex property of the configuration object. Any previous
- * value is overwritten.
- *
- * A valid ifindex is a 32bit integer greater than 0. Any other value is
- * treated as unspecified.
- *
- * The ifindex corresponds to the interface index provided by the linux kernel.
- * It specifies the network device to be used.
- */
-_c_public_ void n_acd_config_set_ifindex(NAcdConfig *config, int ifindex) {
-        config->ifindex = ifindex;
-}
-
-/**
- * n_acd_config_set_transport() - set transport property
- * @config:                     configuration to operate on
- * @transport:                  transport to set
- *
- * This specifies the transport to use. A transport must be one of the
- * `N_ACD_TRANSPORT_*` identifiers. It selects which transport protocol `n-acd`
- * will run on.
- */
-_c_public_ void n_acd_config_set_transport(NAcdConfig *config, unsigned int transport) {
-        config->transport = transport;
-}
-
-/**
- * n_acd_config_set_mac() - set mac property
- * @config:                     configuration to operate on
- * @mac:                        mac to set
- *
- * This specifies the hardware address (also referred to as `MAC Address`) to
- * use. Any hardware address can be specified. It is the caller's
- * responsibility to make sure the address can actually be used.
- *
- * The address in @mac is copied into @config. It does not have to be retained
- * by the caller.
- */
-_c_public_ void n_acd_config_set_mac(NAcdConfig *config, const uint8_t *mac, size_t n_mac) {
-        /*
-         * We truncate the address at the maximum we support. We still remember
-         * the original length, so any consumer of this configuration can then
-         * complain about an unsupported address length. This allows us to
-         * avoid a memory allocation here and having to return `int`.
-         */
-        config->n_mac = n_mac;
-        memcpy(config->mac, mac, n_mac > ETH_ALEN ? ETH_ALEN : n_mac);
-}
-
-int n_acd_event_node_new(NAcdEventNode **nodep) {
-        NAcdEventNode *node;
-
-        node = malloc(sizeof(*node));
-        if (!node)
-                return -ENOMEM;
-
-        *node = (NAcdEventNode)N_ACD_EVENT_NODE_NULL(*node);
-
-        *nodep = node;
-        return 0;
-}
-
-NAcdEventNode *n_acd_event_node_free(NAcdEventNode *node) {
-        if (!node)
-                return NULL;
-
-        c_list_unlink(&node->probe_link);
-        c_list_unlink(&node->acd_link);
-        free(node);
-
-        return NULL;
-}
-
-int n_acd_ensure_bpf_map_space(NAcd *acd) {
-        NAcdProbe *probe;
-        _c_cleanup_(c_closep) int fd_map = -1, fd_prog = -1;
-        size_t  max_map;
-        int r;
-
-        if (acd->n_bpf_map < acd->max_bpf_map)
-                return 0;
-
-        max_map = 2 * acd->max_bpf_map;
-
-        r = n_acd_bpf_map_create(&fd_map, max_map);
-        if (r)
-                return r;
-
-        c_rbtree_for_each_entry(probe, &acd->ip_tree, ip_node) {
-                r = n_acd_bpf_map_add(fd_map, &probe->ip);
-                if (r)
-                        return r;
-        }
-
-        r = n_acd_bpf_compile(&fd_prog, fd_map, (struct ether_addr*) acd->mac);
-        if (r)
-                return r;
-
-        if (fd_prog >= 0) {
-                r = setsockopt(acd->fd_socket, SOL_SOCKET, SO_ATTACH_BPF, &fd_prog, sizeof(fd_prog));
-                if (r)
-                        return -c_errno();
-        }
-
-        if (acd->fd_bpf_map >= 0)
-                close(acd->fd_bpf_map);
-        acd->fd_bpf_map = fd_map;
-        fd_map = -1;
-        acd->max_bpf_map = max_map;
-        return 0;
-}
-
-/**
- * n_acd_new() - create a new ACD context
- * @acdp:                       output argument for new context object
- * @config:                     configuration parameters
- *
- * Create a new ACD context and return it in @acdp. The configuration @config
- * must be initialized by the caller and must specify a valid network
- * interface, transport mechanism, as well as hardware address compatible with
- * the selected transport. The configuration is copied into the context. The
- * @config object thus does not have to be retained by the caller.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_acd_new(NAcd **acdp, NAcdConfig *config) {
-        _c_cleanup_(n_acd_unrefp) NAcd *acd = NULL;
-        _c_cleanup_(c_closep) int fd_bpf_prog = -1;
-        struct epoll_event eevent;
-        int r;
-
-        if (config->ifindex <= 0 ||
-            config->transport != N_ACD_TRANSPORT_ETHERNET ||
-            config->n_mac != ETH_ALEN ||
-            !memcmp(config->mac, (uint8_t[ETH_ALEN]){ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ETH_ALEN))
-                return N_ACD_E_INVALID_ARGUMENT;
-
-        acd = malloc(sizeof(*acd));
-        if (!acd)
-                return -ENOMEM;
-
-        *acd = (NAcd)N_ACD_NULL(*acd);
-        acd->ifindex = config->ifindex;
-        memcpy(acd->mac, config->mac, ETH_ALEN);
-
-        r = n_acd_get_random(&acd->seed);
-        if (r)
-                return r;
-
-        acd->fd_epoll = epoll_create1(EPOLL_CLOEXEC);
-        if (acd->fd_epoll < 0)
-                return -c_errno();
-
-        r = timer_init(&acd->timer);
-        if (r < 0)
-                return r;
-
-        acd->max_bpf_map = 8;
-
-        r = n_acd_bpf_map_create(&acd->fd_bpf_map, acd->max_bpf_map);
-        if (r)
-                return r;
-
-        r = n_acd_bpf_compile(&fd_bpf_prog, acd->fd_bpf_map, (struct ether_addr*) acd->mac);
-        if (r)
-                return r;
-
-        r = n_acd_socket_new(&acd->fd_socket, fd_bpf_prog, config);
-        if (r)
-                return r;
-
-        eevent = (struct epoll_event){
-                .events = EPOLLIN,
-                .data.u32 = N_ACD_EPOLL_TIMER,
-        };
-        r = epoll_ctl(acd->fd_epoll, EPOLL_CTL_ADD, acd->timer.fd, &eevent);
-        if (r < 0)
-                return -c_errno();
-
-        eevent = (struct epoll_event){
-                .events = EPOLLIN,
-                .data.u32 = N_ACD_EPOLL_SOCKET,
-        };
-        r = epoll_ctl(acd->fd_epoll, EPOLL_CTL_ADD, acd->fd_socket, &eevent);
-        if (r < 0)
-                return -c_errno();
-
-        *acdp = acd;
-        acd = NULL;
-        return 0;
-}
-
-static void n_acd_free_internal(NAcd *acd) {
-        NAcdEventNode *node, *t_node;
-
-        if (!acd)
-                return;
-
-        c_list_for_each_entry_safe(node, t_node, &acd->event_list, acd_link)
-                n_acd_event_node_free(node);
-
-        c_assert(c_rbtree_is_empty(&acd->ip_tree));
-
-        if (acd->fd_socket >= 0) {
-                c_assert(acd->fd_epoll >= 0);
-                epoll_ctl(acd->fd_epoll, EPOLL_CTL_DEL, acd->fd_socket, NULL);
-                close(acd->fd_socket);
-                acd->fd_socket = -1;
-        }
-
-        if (acd->fd_bpf_map >= 0) {
-                close(acd->fd_bpf_map);
-                acd->fd_bpf_map = -1;
-        }
-
-        if (acd->timer.fd >= 0) {
-                c_assert(acd->fd_epoll >= 0);
-                epoll_ctl(acd->fd_epoll, EPOLL_CTL_DEL, acd->timer.fd, NULL);
-                timer_deinit(&acd->timer);
-        }
-
-        if (acd->fd_epoll >= 0) {
-                close(acd->fd_epoll);
-                acd->fd_epoll = -1;
-        }
-
-        free(acd);
-}
-
-/**
- * n_acd_ref() - acquire reference
- * @acd:                        context to operate on, or NULL
- *
- * This acquires a single reference to the context specified as @acd. If @acd
- * is NULL, this is a no-op.
- *
- * Return: @acd is returned.
- */
-_c_public_ NAcd *n_acd_ref(NAcd *acd) {
-        if (acd)
-                ++acd->n_refs;
-        return acd;
-}
-
-/**
- * n_acd_unref() - release reference
- * @acd:                        context to operate on, or NULL
- *
- * This releases a single reference to the context @acd. If this is the last
- * reference, the context is torn down and deallocated.
- *
- * Return: NULL is returned.
- */
-_c_public_ NAcd *n_acd_unref(NAcd *acd) {
-        if (acd && !--acd->n_refs)
-                n_acd_free_internal(acd);
-        return NULL;
-}
-
-int n_acd_raise(NAcd *acd, NAcdEventNode **nodep, unsigned int event) {
-        NAcdEventNode *node;
-        int r;
-
-        r = n_acd_event_node_new(&node);
-        if (r)
-                return r;
-
-        node->event.event = event;
-        c_list_link_tail(&acd->event_list, &node->acd_link);
-
-        if (nodep)
-                *nodep = node;
-        return 0;
-}
-
-int n_acd_send(NAcd *acd, const struct in_addr *tpa, const struct in_addr *spa) {
-        struct sockaddr_ll address = {
-                .sll_family = AF_PACKET,
-                .sll_protocol = htobe16(ETH_P_ARP),
-                .sll_ifindex = acd->ifindex,
-                .sll_halen = ETH_ALEN,
-                .sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
-        };
-        struct ether_arp arp = {
-                .ea_hdr = {
-                        .ar_hrd = htobe16(ARPHRD_ETHER),
-                        .ar_pro = htobe16(ETHERTYPE_IP),
-                        .ar_hln = sizeof(acd->mac),
-                        .ar_pln = sizeof(uint32_t),
-                        .ar_op = htobe16(ARPOP_REQUEST),
-                },
-        };
-        ssize_t l;
-        int r;
-
-        memcpy(arp.arp_sha, acd->mac, sizeof(acd->mac));
-        memcpy(arp.arp_tpa, &tpa->s_addr, sizeof(uint32_t));
-
-        if (spa)
-                memcpy(arp.arp_spa, &spa->s_addr, sizeof(spa->s_addr));
-
-        l = sendto(acd->fd_socket,
-                   &arp,
-                   sizeof(arp),
-                   MSG_NOSIGNAL,
-                   (struct sockaddr *)&address,
-                   sizeof(address));
-        if (l < 0) {
-                if (errno == EAGAIN || errno == ENOBUFS) {
-                        /*
-                         * We never maintain outgoing queues. We rely on the
-                         * network device to do that for us. In case the queues
-                         * are full, or the kernel refuses to queue the packet
-                         * for other reasons, we must tell our caller that the
-                         * packet was dropped.
-                         */
-                        return N_ACD_E_DROPPED;
-                } else if (errno == ENETDOWN || errno == ENXIO) {
-                        /*
-                         * These errors happen if the network device went down
-                         * or was actually removed. We always propagate this as
-                         * event, so the user can react accordingly (similarly
-                         * to the recvmmsg(2) handler). In case the user does
-                         * not immediately react, we also tell our caller that
-                         * the packet was dropped, so we don't erroneously
-                         * treat this as success.
-                         */
-
-                        r = n_acd_raise(acd, NULL, N_ACD_EVENT_DOWN);
-                        if (r)
-                                return r;
-
-                        return N_ACD_E_DROPPED;
-                }
-
-                /*
-                 * Random network error. We treat this as fatal and propagate
-                 * the error, so it is noticed and can be investigated.
-                 */
-                return -c_errno();
-        } else if (l != (ssize_t)sizeof(arp)) {
-                /*
-                 * Ugh, the kernel modified the packet. This is unexpected. We
-                 * consider the packet lost.
-                 */
-                return N_ACD_E_DROPPED;
-        }
-
-        return 0;
-}
-
-/**
- * n_acd_get_fd() - get pollable file descriptor
- * @acd:                        context object to operate on
- * @fdp:                        output argument for file descriptor
- *
- * This returns the backing file-descriptor of the context object @acd. The
- * file-descriptor is owned by @acd and valid as long as @acd is. The
- * file-descriptor never changes, so it can be cached by the caller as long as
- * they hold a reference to @acd.
- *
- * The file-descriptor is internal to the @acd context and should not be
- * modified by the caller. It is only exposed to allow the caller to poll on
- * it. Whenever the file-descriptor polls readable, n_acd_dispatch() should be
- * called.
- *
- * Currently, the file-descriptor is an epoll-fd.
- */
-_c_public_ void n_acd_get_fd(NAcd *acd, int *fdp) {
-        *fdp = acd->fd_epoll;
-}
-
-static int n_acd_handle_timeout(NAcd *acd) {
-        NAcdProbe *probe;
-        uint64_t now;
-        int r;
-
-        /*
-         * Read the current time once, and handle all timeouts that triggered
-         * before the current time. Rereading the current time in each loop
-         * might risk creating a live-lock, and the fact that we read the
-         * time after reading the timer guarantees that the timeout which
-         * woke us up is handled.
-         *
-         * When there are no more timeouts to handle at the given time, we
-         * rearm the timer to potentially wake us up again in the future.
-         */
-        timer_now(&acd->timer, &now);
-
-        for (;;) {
-                Timeout *timeout;
-
-                r = timer_pop_timeout(&acd->timer, now, &timeout);
-                if (r < 0) {
-                        return r;
-                } else if (!timeout) {
-                        /*
-                         * There are no more timeouts pending before @now. Rearm
-                         * the timer to fire again at the next timeout.
-                         */
-                        timer_rearm(&acd->timer);
-                        break;
-                }
-
-                probe = (void *)timeout - offsetof(NAcdProbe, timeout);
-                r = n_acd_probe_handle_timeout(probe);
-                if (r)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int n_acd_handle_packet(NAcd *acd, struct ether_arp *packet) {
-        bool hard_conflict;
-        NAcdProbe *probe;
-        uint32_t addr;
-        CRBNode *node;
-        int r;
-
-        /*
-         * We are interested in 2 kinds of ARP messages:
-         *
-         *  1) Someone who is *NOT* us sends *ANY* ARP message with our IP
-         *     address as sender. This is never good, because it implies an
-         *     address conflict.
-         *     We call this a hard-conflict.
-         *
-         *  2) Someone who is *NOT* us sends an ARP REQUEST without any sender
-         *     IP, but our IP as target. This implies someone else performs an
-         *     ARP Probe with our address. This also implies a conflict, but
-         *     one that can be resolved by responding to the probe.
-         *     We call this a soft-conflict.
-         *
-         * We are never interested in any other ARP message. The kernel already
-         * deals with everything else, hence, we can silently ignore those.
-         *
-         * Now, we simply check whether a sender-address is set. This allows us
-         * to distinguish both cases. We then check further conditions, so we
-         * can bail out early if neither is the case.
-         *
-         * Lastly, we perform a lookup in our probe-set to check whether the
-         * address actually matches, so we can let these probes dispatch the
-         * message. Note that we allow duplicate probes, so we need to dispatch
-         * each matching probe, not just one.
-         */
-
-        if (memcmp(packet->arp_spa, (uint8_t[4]){ }, sizeof(packet->arp_spa))) {
-                memcpy(&addr, packet->arp_spa, sizeof(addr));
-                hard_conflict = true;
-        } else if (packet->ea_hdr.ar_op == htobe16(ARPOP_REQUEST)) {
-                memcpy(&addr, packet->arp_tpa, sizeof(addr));
-                hard_conflict = false;
-        } else {
-                /*
-                 * The BPF filter will not let through any other packet.
-                 */
-                return -EIO;
-        }
-
-        /* Find top-most node that matches @addr. */
-        node = acd->ip_tree.root;
-        while (node) {
-                probe = c_rbnode_entry(node, NAcdProbe, ip_node);
-                if (addr < probe->ip.s_addr)
-                        node = node->left;
-                else if (addr > probe->ip.s_addr)
-                        node = node->right;
-                else
-                        break;
-        }
-
-        /*
-         * If the address is unknown, we drop the package. This might happen if
-         * the kernel queued the packet and passed the BPF filter, but we
-         * modified the set before dequeuing the message.
-         */
-        if (!node)
-                return 0;
-
-        /* Forward to left-most child that still matches @addr. */
-        while (node->left && addr == c_rbnode_entry(node->left,
-                                                    NAcdProbe,
-                                                    ip_node)->ip.s_addr)
-                node = node->left;
-
-        /* Iterate all matching entries in-order. */
-        do {
-                probe = c_rbnode_entry(node, NAcdProbe, ip_node);
-
-                r = n_acd_probe_handle_packet(probe, packet, hard_conflict);
-                if (r)
-                        return r;
-
-                node = c_rbnode_next(node);
-        } while (node && addr == c_rbnode_entry(node,
-                                                NAcdProbe,
-                                                ip_node)->ip.s_addr);
-
-        return 0;
-}
-
-static int n_acd_dispatch_timer(NAcd *acd, struct epoll_event *event) {
-        int r;
-
-        if (event->events & (EPOLLHUP | EPOLLERR)) {
-                /*
-                 * There is no way to handle either gracefully. If we ignored
-                 * them, we would busy-loop, so lets rather forward the error
-                 * to the caller.
-                 */
-                return -EIO;
-        }
-
-        if (event->events & EPOLLIN) {
-                r = timer_read(&acd->timer);
-                if (r <= 0)
-                        return r;
-
-                c_assert(r == TIMER_E_TRIGGERED);
-
-                /*
-                 * A timer triggered, handle all pending timeouts at a given
-                 * point in time. There can only be a finite number of pending
-                 * timeouts, any new ones will be in the future, so not handled
-                 * now, but guaranteed to wake us up again when they do trigger.
-                 */
-                r = n_acd_handle_timeout(acd);
-                if (r)
-                        return r;
-        }
-
-        return 0;
-}
-
-static bool n_acd_packet_is_valid(NAcd *acd, void *packet, size_t n_packet) {
-        struct ether_arp *arp;
-
-        /*
-         * The eBPF filter will ensure that this function always returns true, however,
-         * this allows the eBPF filter to be an optional optimization which is necessary
-         * on older kernels.
-         *
-         * See comments in n-acd-bpf.c for details.
-         */
-
-        if (n_packet != sizeof(*arp))
-                return false;
-
-        arp = packet;
-
-        if (arp->arp_hrd != htobe16(ARPHRD_ETHER))
-                return false;
-
-        if (arp->arp_pro != htobe16(ETHERTYPE_IP))
-                return false;
-
-        if (arp->arp_hln != sizeof(struct ether_addr))
-                return false;
-
-        if (arp->arp_pln != sizeof(struct in_addr))
-                return false;
-
-        if (!memcmp(arp->arp_sha, acd->mac, sizeof(struct ether_addr)))
-                return false;
-
-        if (memcmp(arp->arp_spa, &((struct in_addr) { INADDR_ANY }), sizeof(struct in_addr))) {
-                if (arp->arp_op != htobe16(ARPOP_REQUEST) && arp->arp_op != htobe16(ARPOP_REPLY))
-                        return false;
-        } else if (arp->arp_op != htobe16(ARPOP_REQUEST)) {
-                return false;
-        }
-
-        return true;
-}
-
-static int n_acd_dispatch_socket(NAcd *acd, struct epoll_event *event) {
-        const size_t n_batch = 8;
-        struct mmsghdr msgs[n_batch];
-        struct iovec iovecs[n_batch];
-        struct ether_arp data[n_batch];
-        size_t i;
-        int r, n;
-
-        for (i = 0; i < n_batch; ++i) {
-                iovecs[i].iov_base = data + i;
-                iovecs[i].iov_len = sizeof(data[i]);
-                msgs[i].msg_hdr = (struct msghdr){
-                        .msg_iov = iovecs + i,
-                        .msg_iovlen = 1,
-                };
-        }
-
-        /*
-         * We always directly call into recvmmsg(2), regardless which EPOLL*
-         * event is signalled. On sockets, the recv(2)-family of syscalls does
-         * a suitable job of handling all possible scenarios and telling us
-         * about it. Hence, lets take the easy route and always ask the kernel
-         * about the current state.
-         */
-        n = recvmmsg(acd->fd_socket, msgs, n_batch, 0, NULL);
-        if (n < 0) {
-                if (errno == ENETDOWN) {
-                        /*
-                         * We get ENETDOWN if the network-device goes down or
-                         * is removed. This error is temporary and only queued
-                         * once. Subsequent reads will simply return EAGAIN
-                         * until the device is up again and has data queued.
-                         * Usually, the caller should tear down all probes when
-                         * an interface goes down, but we leave it up to the
-                         * caller to decide what to do. We propagate the code
-                         * and continue.
-                         */
-                        return n_acd_raise(acd, NULL, N_ACD_EVENT_DOWN);
-                } else if (errno == EAGAIN) {
-                        /*
-                         * There is no more data queued and we did not get
-                         * preempted. Everything is good to go.
-                         * As a safety-net against busy-looping, we do check
-                         * for HUP/ERR. Neither should be set, since they imply
-                         * error-dequeue behavior on all socket calls. Lets
-                         * fail hard if we trigger it, so we can investigate.
-                         */
-                        if (event->events & (EPOLLHUP | EPOLLERR))
-                                return -EIO;
-
-                        return 0;
-                } else {
-                        /*
-                         * Something went wrong. Propagate the error-code, so
-                         * this can be investigated.
-                         */
-                        return -c_errno();
-                }
-        } else if (n >= (ssize_t)n_batch) {
-                /*
-                 * If all buffers were filled with data, we cannot be sure that
-                 * there is nothing left to read. But to avoid starvation, we
-                 * cannot loop on this condition. Instead, we mark the context
-                 * as preempted so the caller can call us again.
-                 * Note that in level-triggered event-loops this condition can
-                 * be neglected, but in edge-triggered event-loops it is
-                 * crucial to forward this information.
-                 *
-                 * On the other hand, there are several conditions where the
-                 * kernel might return less batches than requested, but was
-                 * still preempted. However, all of those cases require the
-                 * preemption to have triggered a wakeup *after* we entered
-                 * recvmmsg(). Hence, even if we did not recognize the
-                 * preemption, an edge must have triggered and as such we will
-                 * handle the event on the next turn.
-                 */
-                acd->preempted = true;
-        }
-
-        for (i = 0; (ssize_t)i < n; ++i) {
-                if (!n_acd_packet_is_valid(acd, data + i, msgs[i].msg_len))
-                        continue;
-                /*
-                 * Handle the packet. Bail out if something went wrong. Note
-                 * that this must be fatal errors, since we discard all other
-                 * packets that follow.
-                 */
-                r = n_acd_handle_packet(acd, data + i);
-                if (r)
-                        return r;
-        }
-
-        return 0;
-}
-
-/**
- * n_acd_dispatch() - dispatch context
- * @acd:                        context object to operate on
- *
- * This dispatches the internal state-machine of all probes and operations
- * running on the context @acd.
- *
- * Any outside effect or event triggered by this dispatcher will be queued on
- * the event-queue of @acd. Whenever the dispatcher returns, the caller is
- * required to drain the event-queue via n_acd_pop_event() until it is empty.
- *
- * This function dispatches as many events as possible up to a static limit to
- * prevent stalling execution. If the static limit is reached, this function
- * will return with N_ACD_E_PREEMPTED, otherwise 0 is returned. In most cases
- * preemption can be ignored, because level-triggered event notification
- * handles it automatically. However, in case of edge-triggered event
- * mechanisms, the caller must make sure to call the dispatcher again.
- *
- * Return: 0 on success, N_ACD_E_PREEMPTED on preemption, negative error code
- *         on failure.
- */
-_c_public_ int n_acd_dispatch(NAcd *acd) {
-        struct epoll_event events[2];
-        int n, i, r = 0;
-
-        n = epoll_wait(acd->fd_epoll, events, sizeof(events) / sizeof(*events), 0);
-        if (n < 0) {
-                /* Linux never returns EINTR if `timeout == 0'. */
-                return -c_errno();
-        }
-
-        acd->preempted = false;
-
-        for (i = 0; i < n; ++i) {
-                switch (events[i].data.u32) {
-                case N_ACD_EPOLL_TIMER:
-                        r = n_acd_dispatch_timer(acd, events + i);
-                        break;
-                case N_ACD_EPOLL_SOCKET:
-                        r = n_acd_dispatch_socket(acd, events + i);
-                        break;
-                default:
-                        c_assert(0);
-                        r = 0;
-                        break;
-                }
-
-                if (r)
-                        return r;
-        }
-
-        return acd->preempted ? N_ACD_E_PREEMPTED : 0;
-}
-
-/**
- * n_acd_pop_event() - get the next pending event
- * @acd:                        context object to operate on
- * @eventp:                     output argument for the event
- *
- * Returns a pointer to the next pending event. The event is still owend by
- * the context, and is only valid until the next call to n_acd_pop_event()
- * or until the owning object is freed (either the ACD context or the indicated
- * probe object).
- *
- * An event either originates on the ACD context, or one of the configured
- * probes. If the event-type has a 'probe' pointer, it originated on the
- * indicated probe (which is *never* NULL), otherwise it originated on the
- * context.
- *
- * Users must call this function repeatedly until either an error is returned,
- * or the event-pointer is NULL. Wakeups on the epoll-fd are only guaranteed
- * for each batch of events. Hence, it is the callers responsibility to drain
- * the event-queue somehow after each call to n_acd_dispatch(). Note that
- * events can only be added by n_acd_dispatch(), hence, you cannot live-lock
- * when draining the event queue.
- *
- * The possible events are:
- *  * N_ACD_EVENT_READY:    A configured IP address was probed successfully
- *                          and is ready to be used. Once configured on the
- *                          interface, the caller must call n_acd_announce()
- *                          to announce and start defending the address.
- *  * N_ACD_EVENT_USED:     Someone is already using the IP address being
- *                          probed. The probe is put into stopped state and
- *                          should be freed by the caller.
- *  * N_ACD_EVENT_DEFENDED: A conflict was detected for an announced IP
- *                          address, and the engine attempted to defend it.
- *                          This is purely informational, and no action is
- *                          required by the caller.
- *  * N_ACD_EVENT_CONFLICT: A conflict was detected for an announced IP
- *                          address, and the probe was not able to defend
- *                          it (according to the configured policy). The
- *                          probe halted, the caller must stop using
- *                          the address immediately, and should free the probe.
- *  * N_ACD_EVENT_DOWN:     The specified network interface was put down. The
- *                          user is recommended to free *ALL* probes and
- *                          recreate them as soon as the interface is up again.
- *                          Note that this event is purely informational. The
- *                          probes will continue running, but all packets will
- *                          be blackholed, and no network packets are received,
- *                          until the network is back up again. Hence, from an
- *                          operational perspective, the legitimacy of the ACD
- *                          probes is lost and the user better re-probes all
- *                          addresses.
- *
- * Returns: 0 on success, negative error code on failure. The popped event is
- *          returned in @eventp. If no event is pending, NULL is placed in
- *          @eventp and 0 is returned. If an error is returned, @eventp is left
- *          untouched.
- */
-_c_public_ int n_acd_pop_event(NAcd *acd, NAcdEvent **eventp) {
-        NAcdEventNode *node, *t_node;
-
-        c_list_for_each_entry_safe(node, t_node, &acd->event_list, acd_link) {
-                if (node->is_public) {
-                        n_acd_event_node_free(node);
-                        continue;
-                }
-
-                node->is_public = true;
-                *eventp = &node->event;
-                return 0;
-        }
-
-        *eventp = NULL;
-        return 0;
-}
-
-/**
- * n_acd_probe() - start new probe
- * @acd:                        context object to operate on
- * @probep:                     output argument for new probe
- * @config:                     probe configuration
- *
- * This creates a new probe on the context @acd and returns the probe in
- * @probep. The configuration @config must provide valid probe parameters. At
- * least a valid IP address must be provided through the configuration.
- *
- * This function does not reject duplicate probes for the same address. It is
- * the caller's decision whether duplicates are allowed or not. But note that
- * duplicate probes on the same context will not conflict each other. That is,
- * running a probe for the same address twice on the same context will not
- * cause them to consider each other a duplicate.
- *
- * Probes are rather lightweight objects. They do not create any
- * file-descriptors or other kernel objects. Probes always re-use the
- * infrastructure provided by the context object @acd. This allows running many
- * probes simultaneously without exhausting resources.
- *
- * Return: 0 on success, N_ACD_E_INVALID_ARGUMENT on invalid configuration
- *         parameters, negative error code on failure.
- */
-_c_public_ int n_acd_probe(NAcd *acd, NAcdProbe **probep, NAcdProbeConfig *config) {
-        return n_acd_probe_new(probep, acd, config);
-}
diff --git a/shared/n-acd/src/n-acd.h b/shared/n-acd/src/n-acd.h
deleted file mode 100644
index e2b01270..00000000
--- a/shared/n-acd/src/n-acd.h
+++ /dev/null
@@ -1,150 +0,0 @@
-#pragma once
-
-/*
- * IPv4 Address Conflict Detection
- *
- * This is the public header of the n-acd library, implementing IPv4 Address
- * Conflict Detection as described in RFC-5227. This header defines the public
- * API and all entry points of n-acd.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <netinet/in.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-typedef struct NAcd NAcd;
-typedef struct NAcdConfig NAcdConfig;
-typedef struct NAcdEvent NAcdEvent;
-typedef struct NAcdProbe NAcdProbe;
-typedef struct NAcdProbeConfig NAcdProbeConfig;
-
-#define N_ACD_TIMEOUT_RFC5227 (UINT64_C(9000))
-
-enum {
-        _N_ACD_E_SUCCESS,
-
-        N_ACD_E_PREEMPTED,
-        N_ACD_E_INVALID_ARGUMENT,
-
-        _N_ACD_E_N,
-};
-
-enum {
-        N_ACD_TRANSPORT_ETHERNET,
-        _N_ACD_TRANSPORT_N,
-};
-
-enum {
-        N_ACD_EVENT_READY,
-        N_ACD_EVENT_USED,
-        N_ACD_EVENT_DEFENDED,
-        N_ACD_EVENT_CONFLICT,
-        N_ACD_EVENT_DOWN,
-        _N_ACD_EVENT_N,
-};
-
-enum {
-        N_ACD_DEFEND_NEVER,
-        N_ACD_DEFEND_ONCE,
-        N_ACD_DEFEND_ALWAYS,
-        _N_ACD_DEFEND_N,
-};
-
-struct NAcdEvent {
-        unsigned int event;
-        union {
-                struct {
-                        NAcdProbe *probe;
-                } ready;
-                struct {
-                } down;
-                struct {
-                        NAcdProbe *probe;
-                        uint8_t *sender;
-                        size_t n_sender;
-                } used, defended, conflict;
-        };
-};
-
-/* configs */
-
-int n_acd_config_new(NAcdConfig **configp);
-NAcdConfig *n_acd_config_free(NAcdConfig *config);
-
-void n_acd_config_set_ifindex(NAcdConfig *config, int ifindex);
-void n_acd_config_set_transport(NAcdConfig *config, unsigned int transport);
-void n_acd_config_set_mac(NAcdConfig *config, const uint8_t *mac, size_t n_mac);
-
-int n_acd_probe_config_new(NAcdProbeConfig **configp);
-NAcdProbeConfig *n_acd_probe_config_free(NAcdProbeConfig *config);
-
-void n_acd_probe_config_set_ip(NAcdProbeConfig *config, struct in_addr ip);
-void n_acd_probe_config_set_timeout(NAcdProbeConfig *config, uint64_t msecs);
-
-/* contexts */
-
-int n_acd_new(NAcd **acdp, NAcdConfig *config);
-NAcd *n_acd_ref(NAcd *acd);
-NAcd *n_acd_unref(NAcd *acd);
-
-void n_acd_get_fd(NAcd *acd, int *fdp);
-int n_acd_dispatch(NAcd *acd);
-int n_acd_pop_event(NAcd *acd, NAcdEvent **eventp);
-
-int n_acd_probe(NAcd *acd, NAcdProbe **probep, NAcdProbeConfig *config);
-
-/* probes */
-
-NAcdProbe *n_acd_probe_free(NAcdProbe *probe);
-
-void n_acd_probe_set_userdata(NAcdProbe *probe, void *userdata);
-void n_acd_probe_get_userdata(NAcdProbe *probe, void **userdatap);
-
-int n_acd_probe_announce(NAcdProbe *probe, unsigned int defend);
-
-/* inline helpers */
-
-static inline void n_acd_config_freep(NAcdConfig **config) {
-        if (*config)
-                n_acd_config_free(*config);
-}
-
-static inline void n_acd_config_freev(NAcdConfig *config) {
-        n_acd_config_free(config);
-}
-
-static inline void n_acd_probe_config_freep(NAcdProbeConfig **config) {
-        if (*config)
-                n_acd_probe_config_free(*config);
-}
-
-static inline void n_acd_probe_config_freev(NAcdProbeConfig *config) {
-        n_acd_probe_config_free(config);
-}
-
-static inline void n_acd_unrefp(NAcd **acd) {
-        if (*acd)
-                n_acd_unref(*acd);
-}
-
-static inline void n_acd_unrefv(NAcd *acd) {
-        n_acd_unref(acd);
-}
-
-static inline void n_acd_probe_freep(NAcdProbe **probe) {
-        if (*probe)
-                n_acd_probe_free(*probe);
-}
-
-static inline void n_acd_probe_freev(NAcdProbe *probe) {
-        n_acd_probe_free(probe);
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/shared/n-acd/src/util/timer.c b/shared/n-acd/src/util/timer.c
deleted file mode 100644
index af2a887c..00000000
--- a/shared/n-acd/src/util/timer.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Timer Utility Library
- */
-
-#include <assert.h>
-#include <c-rbtree.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/timerfd.h>
-#include <time.h>
-#include "timer.h"
-
-int timer_init(Timer *timer) {
-        clockid_t clock = CLOCK_BOOTTIME;
-        int r;
-
-        r = timerfd_create(clock, TFD_CLOEXEC | TFD_NONBLOCK);
-        if (r < 0 && errno == EINVAL) {
-                clock = CLOCK_MONOTONIC;
-                r = timerfd_create(clock, TFD_CLOEXEC | TFD_NONBLOCK);
-        }
-        if (r < 0)
-                return -errno;
-
-        *timer = (Timer)TIMER_NULL(*timer);
-        timer->fd = r;
-        timer->clock = clock;
-
-        return 0;
-}
-
-void timer_deinit(Timer *timer) {
-        c_assert(c_rbtree_is_empty(&timer->tree));
-
-        if (timer->fd >= 0) {
-                close(timer->fd);
-                timer->fd = -1;
-        }
-}
-
-void timer_now(Timer *timer, uint64_t *nowp) {
-        struct timespec ts;
-        int r;
-
-        r = clock_gettime(timer->clock, &ts);
-        c_assert(r >= 0);
-
-        *nowp = ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec;
-}
-
-void timer_rearm(Timer *timer) {
-        uint64_t time;
-        Timeout *timeout;
-        int r;
-
-        /*
-         * A timeout value of 0 clears the timer, we should only set that if
-         * no timeout exists in the tree.
-         */
-
-        timeout = c_rbnode_entry(c_rbtree_first(&timer->tree), Timeout, node);
-        c_assert(!timeout || timeout->timeout);
-
-        time = timeout ? timeout->timeout : 0;
-
-        if (time != timer->scheduled_timeout) {
-                r = timerfd_settime(timer->fd,
-                                    TFD_TIMER_ABSTIME,
-                                    &(struct itimerspec){
-                                            .it_value = {
-                                                    .tv_sec = time / UINT64_C(1000000000),
-                                                    .tv_nsec = time % UINT64_C(1000000000),
-                                            },
-                                    },
-                                    NULL);
-                c_assert(r >= 0);
-
-                timer->scheduled_timeout = time;
-        }
-}
-
-int timer_read(Timer *timer) {
-        uint64_t v;
-        int r;
-
-        r = read(timer->fd, &v, sizeof(v));
-        if (r < 0) {
-                if (errno == EAGAIN) {
-                        /*
-                         * No more pending events.
-                         */
-                        return 0;
-                } else {
-                        /*
-                         * Something failed. We use CLOCK_BOOTTIME/MONOTONIC,
-                         * so ECANCELED cannot happen. Hence, there is no
-                         * error that we could gracefully handle. Fail hard
-                         * and let the caller deal with it.
-                         */
-                        return -errno;
-                }
-        } else if (r != sizeof(v) || v == 0) {
-                /*
-                 * Kernel guarantees 8-byte reads, and only to return
-                 * data if at least one timer triggered; fail hard if
-                 * it suddenly starts doing weird shit.
-                 */
-                return -EIO;
-        }
-
-        return TIMER_E_TRIGGERED;
-}
-
-
-int timer_pop_timeout(Timer *timer, uint64_t until, Timeout **timeoutp) {
-        Timeout *timeout;
-
-        /*
-         * If the first timeout is scheduled before @until, then unlink
-         * it and return it. Otherwise, return NULL.
-         */
-        timeout = c_rbnode_entry(c_rbtree_first(&timer->tree), Timeout, node);
-        if (timeout && timeout->timeout <= until) {
-                c_rbnode_unlink(&timeout->node);
-                timeout->timeout = 0;
-                *timeoutp = timeout;
-        } else {
-                *timeoutp = NULL;
-        }
-
-        return 0;
-}
-
-void timeout_schedule(Timeout *timeout, Timer *timer, uint64_t time) {
-        c_assert(time);
-
-        /*
-         * In case @timeout was already scheduled, remove it from the
-         * tree. If we are moving it to a new timer, rearm the old one.
-         */
-        if (timeout->timer) {
-                c_rbnode_unlink(&timeout->node);
-                if (timeout->timer != timer)
-                        timer_rearm(timeout->timer);
-        }
-        timeout->timer = timer;
-        timeout->timeout = time;
-
-        /*
-         * Now insert it back into the tree in the correct new position.
-         * We allow duplicates in the tree, so this insertion is open-coded.
-         */
-        {
-                Timeout *other;
-                CRBNode **slot, *parent;
-
-                slot = &timer->tree.root;
-                parent = NULL;
-                while (*slot) {
-                        other = c_rbnode_entry(*slot, Timeout, node);
-                        parent = *slot;
-                        if (timeout->timeout < other->timeout)
-                                slot = &(*slot)->left;
-                        else
-                                slot = &(*slot)->right;
-                }
-
-                c_rbtree_add(&timer->tree, parent, slot, &timeout->node);
-        }
-
-        /*
-         * Rearm the timer as we updated the timeout tree.
-         */
-        timer_rearm(timer);
-}
-
-void timeout_unschedule(Timeout *timeout) {
-        Timer *timer = timeout->timer;
-
-        if (!timer)
-                return;
-
-        c_rbnode_unlink(&timeout->node);
-        timeout->timeout = 0;
-        timeout->timer = NULL;
-
-        timer_rearm(timer);
-}
diff --git a/shared/n-acd/src/util/timer.h b/shared/n-acd/src/util/timer.h
deleted file mode 100644
index d01b2741..00000000
--- a/shared/n-acd/src/util/timer.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#pragma once
-
-#include <c-rbtree.h>
-#include <c-stdaux.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-
-typedef struct Timer Timer;
-typedef struct Timeout Timeout;
-
-enum {
-        _TIMER_E_SUCCESS,
-
-        TIMER_E_TRIGGERED,
-
-        _TIMER_E_N,
-};
-
-struct Timer {
-        int fd;
-        clockid_t clock;
-        CRBTree tree;
-        uint64_t scheduled_timeout;
-};
-
-#define TIMER_NULL(_x) {                                                        \
-                .fd = -1,                                                       \
-                .tree = C_RBTREE_INIT,                                          \
-        }
-
-struct Timeout {
-        Timer *timer;
-        CRBNode node;
-        uint64_t timeout;
-};
-
-#define TIMEOUT_INIT(_x) {                                                      \
-                .node = C_RBNODE_INIT((_x).node),                               \
-        }
-
-int timer_init(Timer *timer);
-void timer_deinit(Timer *timer);
-
-void timer_now(Timer *timer, uint64_t *nowp);
-
-int timer_pop_timeout(Timer *timer, uint64_t now, Timeout **timerp);
-void timer_rearm(Timer *timer);
-int timer_read(Timer *timer);
-
-void timeout_schedule(Timeout *timeout, Timer *timer, uint64_t time);
-void timeout_unschedule(Timeout *timeout);
-
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-connection.c b/shared/n-dhcp4/src/n-dhcp4-c-connection.c
deleted file mode 100644
index 31235253..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-c-connection.c
+++ /dev/null
@@ -1,1256 +0,0 @@
-/*
- * DHCPv4 Client Connection
- *
- * XXX
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/socket.h> /* needed by linux/netdevice.h */
-#include <linux/netdevice.h>
-#include <net/if_arp.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include "n-dhcp4-private.h"
-#include "util/packet.h"
-
-/**
- * n_dhcp4_c_connection_init() - initialize client connection
- * @connection:                 connection to operate on
- * @client_config:              client configuration to use
- * @probe_config:               client probe configuration to use
- * @log_queue:                  the log queue for logging events
- * @fd_epoll:                   epoll context to attach to, or -1
- *
- * This initializes a new client connection using the configuration given in
- * @client_config and @probe_config.
- *
- * The client-configuration given as @client_config must survive the lifetime
- * of @connection. It is pinned in the connection and used all over the place.
- * The caller must guarantee that the configuration is not deallocated in the
- * meantime. Same is true for @probe_config.
- *
- * The new connection automatically attaches to the epoll context given as
- * @fd_epoll. The epoll FD is retained in the connection and the caller must
- * guarantee that it lives as long as the connection.
- * The caller is explicitly allowed to pass -1 as @fd_epoll, in which case the
- * connection will initialize correctly, but will not be in a usable state.
- * That is, any call to n_dhcp4_c_connection_listen() will fail, since it will
- * be unable to attach to the epoll context. Such a connection can be used to
- * get a detached object that behaves sound, but provides no runtime.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_c_connection_init(NDhcp4CConnection *connection,
-                              NDhcp4ClientConfig *client_config,
-                              NDhcp4ClientProbeConfig *probe_config,
-                              NDhcp4LogQueue *log_queue,
-                              int fd_epoll) {
-        *connection = (NDhcp4CConnection)N_DHCP4_C_CONNECTION_NULL(*connection);
-        connection->client_config = client_config;
-        connection->probe_config = probe_config;
-        connection->fd_epoll = fd_epoll;
-        connection->log_queue = log_queue;
-
-        /*
-         * We explicitly allow initializing connections with an invalid
-         * epoll-fd. The resulting connection immediately transitions into the
-         * CLOSED state. This allows the caller to create dummy connections
-         * useful to provide asynchronous constructor-feedback in the API.
-         *
-         * The effect of this is as if you immediately call
-         * n_dhcp4_c_connection_close() on the new connection. However, by
-         * directly passing -1 in the constructor, you are guaranteed not even
-         * the constructor can ever mess with your epoll-set.
-         */
-        if (connection->fd_epoll < 0)
-                connection->state = N_DHCP4_C_CONNECTION_STATE_CLOSED;
-
-        return 0;
-}
-
-/**
- * n_dhcp4_c_connection_deinit() - deinitialize client connection
- * @connection:                 connection to operate on
- *
- * This deinitializes a connection that was previously initialized via
- * n_dhcp4_c_connection_init(). It will tear down all allocated state and
- * release it.
- *
- * Once this function returns, @connection is re-initialized to
- * N_DHCP4_C_CONNECTION_NULL. If this function is called on a deinitialized
- * connection, it is a no-op.
- */
-void n_dhcp4_c_connection_deinit(NDhcp4CConnection *connection) {
-        n_dhcp4_c_connection_close(connection);
-        n_dhcp4_outgoing_free(connection->request);
-        *connection = (NDhcp4CConnection)N_DHCP4_C_CONNECTION_NULL(*connection);
-}
-
-static void n_dhcp4_c_connection_outgoing_set_secs(NDhcp4Outgoing *message) {
-        uint64_t secs;
-
-        /*
-         * This function sets the `secs` field for outgoing messages. It
-         * expects the base-time and start-time to be already set by the
-         * caller.
-         * For a given outgoing message, its `secs` field describes the time
-         * (in seconds) between the start of the transaction this message is
-         * part of and the start of the operational process (also called the
-         * base time here).
-         *
-         * The operational process in the DHCP sense describes the entire
-         * process of requesting a lease and acquiring it. That is, it starts
-         * with the caller's intent to request a lease, and it ends when we
-         * got granted a lease. The act of refreshing a lease is, in itself, a
-         * new operational process. The base-time describes the start-time
-         * recorded when such a process as initiated.
-         *
-         * A transaction in the DHCP sense describes a request+reply
-         * combination, in most cases. That is, the time a request is sent is
-         * the start-time of a transaction. In the ideal case, the start-time
-         * of the first transaction in an operational process matches the
-         * base-time. However, transactions are often delayed with a randomized
-         * offset to reduce traffic during network bursts.
-         * In some cases, however, transactions are composed out of multiple
-         * requests+reply combinations. This includes, for instance, the SELECT
-         * message following an OFFER. The specification clearly says that
-         * those must be considered a single transaction and thus share the
-         * transaction start-time.
-         *
-         * The `secs` field, thus, describes how long a client has been busy
-         * requesting a lease. DHCP servers and proxies do use it to prioritize
-         * clients.
-         *
-         * Note: Some DHCP relays reject a `secs` value of 0 (which might look
-         *       like it is uninitialized). Hence, we always clamp the value to
-         *       the range `[1, 65535]`.
-         */
-
-        secs = message->userdata.base_time - message->userdata.start_time;
-        secs /= 1000ULL * 1000ULL * 1000ULL; /* nsecs to secs */
-        secs = C_CLAMP(secs, 1, UINT16_MAX);
-
-        n_dhcp4_outgoing_set_secs(message, secs);
-}
-
-int n_dhcp4_c_connection_listen(NDhcp4CConnection *connection) {
-        _c_cleanup_(c_closep) int fd_packet = -1;
-        int r;
-
-        if (connection->state == N_DHCP4_C_CONNECTION_STATE_PACKET)
-                return 0;
-
-        c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_INIT ||
-                 connection->state == N_DHCP4_C_CONNECTION_STATE_DRAINING ||
-                 connection->state == N_DHCP4_C_CONNECTION_STATE_UDP);
-
-        if (connection->fd_packet >= 0) {
-                epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_packet, NULL);
-                connection->fd_packet = c_close(connection->fd_packet);
-        }
-
-        if (connection->fd_udp >= 0) {
-                epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_udp, NULL);
-                connection->fd_udp = c_close(connection->fd_udp);
-        }
-
-        r = n_dhcp4_c_socket_packet_new(&fd_packet, connection->client_config->ifindex);
-        if (r)
-                return r;
-
-        r = epoll_ctl(connection->fd_epoll,
-                      EPOLL_CTL_ADD,
-                      fd_packet,
-                      &(struct epoll_event){
-                              .events = EPOLLIN,
-                              .data = { .u32 = N_DHCP4_CLIENT_EPOLL_IO },
-                      });
-        if (r < 0)
-                return -errno;
-
-        connection->state = N_DHCP4_C_CONNECTION_STATE_PACKET;
-        connection->fd_packet = fd_packet;
-        fd_packet = -1;
-        return 0;
-}
-
-int n_dhcp4_c_connection_connect(NDhcp4CConnection *connection,
-                                 const struct in_addr *client,
-                                 const struct in_addr *server) {
-        _c_cleanup_(c_closep) int fd_udp = -1;
-        int r;
-
-        c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_PACKET);
-
-        r = n_dhcp4_c_socket_udp_new(&fd_udp,
-                                     connection->client_config->ifindex,
-                                     client,
-                                     server);
-        if (r)
-                return r;
-
-        r = epoll_ctl(connection->fd_epoll,
-                      EPOLL_CTL_ADD,
-                      fd_udp,
-                      &(struct epoll_event){
-                              .events = EPOLLIN,
-                              .data = { .u32 = N_DHCP4_CLIENT_EPOLL_IO },
-                      });
-        if (r < 0)
-                return -errno;
-
-        r = packet_shutdown(connection->fd_packet);
-        if (r < 0) {
-                epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, fd_udp, NULL);
-                return r;
-        }
-
-        connection->state = N_DHCP4_C_CONNECTION_STATE_DRAINING;
-        connection->fd_udp = fd_udp;
-        fd_udp = -1;
-        connection->client_ip = client->s_addr;
-        connection->server_ip = server->s_addr;
-        return 0;
-}
-
-void n_dhcp4_c_connection_close(NDhcp4CConnection *connection) {
-        if (connection->fd_udp >= 0) {
-                epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_udp, NULL);
-                connection->fd_udp = c_close(connection->fd_udp);
-        }
-
-        if (connection->fd_packet >= 0) {
-                epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_packet, NULL);
-                connection->fd_packet = c_close(connection->fd_packet);
-        }
-
-        connection->fd_epoll = -1;
-        connection->state = N_DHCP4_C_CONNECTION_STATE_CLOSED;
-}
-
-static int n_dhcp4_c_connection_verify_incoming(NDhcp4CConnection *connection,
-                                                NDhcp4Incoming *message,
-                                                uint8_t *typep) {
-        NDhcp4Header *header = n_dhcp4_incoming_get_header(message);
-        uint8_t type;
-        uint32_t request_xid;
-        uint8_t *id;
-        size_t n_id;
-        int r;
-
-        r = n_dhcp4_incoming_query_message_type(message, &type);
-        if (r) {
-                if (r == N_DHCP4_E_UNSET)
-                        return N_DHCP4_E_MALFORMED;
-                else
-                        return r;
-        }
-
-        switch (type) {
-        case N_DHCP4_MESSAGE_OFFER:
-        case N_DHCP4_MESSAGE_ACK:
-        case N_DHCP4_MESSAGE_NAK:
-                /*
-                 * Only accept replies if there is a pending request, and it
-                 * has a matching transaction id.
-                 */
-                if (!connection->request)
-                        return N_DHCP4_E_UNEXPECTED;
-
-                n_dhcp4_outgoing_get_xid(connection->request, &request_xid);
-                if (header->xid != request_xid)
-                        return N_DHCP4_E_UNEXPECTED;
-
-                break;
-        case N_DHCP4_MESSAGE_FORCERENEW:
-                /*
-                 * Force renew messages are triggered by a server, and do not
-                 * match a pending request.
-                 */
-                break;
-        default:
-                return N_DHCP4_E_UNEXPECTED;
-        }
-
-        /*
-         * In case our transport makes use of the 'chaddr' field, make sure it
-         * matches exactly our address.
-         */
-        switch (connection->client_config->transport) {
-        case N_DHCP4_TRANSPORT_ETHERNET:
-                c_assert(connection->client_config->n_mac == ETH_ALEN);
-
-                if (header->hlen != ETH_ALEN)
-                        return N_DHCP4_E_UNEXPECTED;
-                if (memcmp(header->chaddr, connection->client_config->mac, ETH_ALEN) != 0)
-                        return N_DHCP4_E_UNEXPECTED;
-
-                break;
-        case N_DHCP4_TRANSPORT_INFINIBAND:
-                if (header->hlen != 0)
-                        return N_DHCP4_E_UNEXPECTED;
-
-                break;
-        }
-
-        /*
-         * If a server passes us back a client ID, it must be the one we
-         * provided. We ignore any packets that have mismatching client-ids.
-         */
-        id = NULL;
-        n_id = 0;
-        r = n_dhcp4_incoming_query(message, N_DHCP4_OPTION_CLIENT_IDENTIFIER, &id, &n_id);
-        if (r) {
-                if (r != N_DHCP4_E_UNSET)
-                        return r;
-        } else {
-                if (n_id != connection->client_config->n_client_id)
-                        return N_DHCP4_E_UNEXPECTED;
-                if (memcmp(id, connection->client_config->client_id, n_id) != 0)
-                        return N_DHCP4_E_UNEXPECTED;
-        }
-
-        *typep = type;
-        return 0;
-}
-
-void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
-                                      uint64_t *timeoutp) {
-        uint64_t timeout;
-        size_t n_send;
-
-        if (!connection->request) {
-                *timeoutp = 0;
-                return;
-        }
-
-        switch (connection->request->userdata.type) {
-        case N_DHCP4_C_MESSAGE_DISCOVER:
-        case N_DHCP4_C_MESSAGE_SELECT:
-        case N_DHCP4_C_MESSAGE_INFORM:
-                /*
-                 * Resend with an exponential backoff and a one second random
-                 * slack, from a minimum of two seconds to a maximum of sixty
-                 * four.
-                 *
-                 * Note that the RFC says to start at four rather than two
-                 * seconds, and use [-1,1] slack, rather than [0,1].
-                 */
-                n_send = connection->request->userdata.n_send;
-                if (n_send >= 6)
-                        n_send = 6;
-
-                timeout = connection->request->userdata.send_time + ((1ULL << n_send) * 1000000000ULL) + connection->request->userdata.send_jitter;
-
-                break;
-        case N_DHCP4_C_MESSAGE_REBIND:
-        case N_DHCP4_C_MESSAGE_RENEW:
-        case N_DHCP4_C_MESSAGE_REBOOT:
-                /*
-                 * Resend every sixty seconds with a one second random slack.
-                 *
-                 * Note that the RFC says to do this at most once, but we do
-                 * it until we are cancelled.
-                 */
-                timeout = connection->request->userdata.send_time + (60ULL * 1000000000ULL) + connection->request->userdata.send_jitter;
-
-                break;
-        case N_DHCP4_C_MESSAGE_DECLINE:
-        case N_DHCP4_C_MESSAGE_RELEASE:
-                /* XXX make sure these message types are never pinned? */
-                timeout = 0;
-                break;
-        default:
-                c_assert(0);
-        }
-
-        *timeoutp = timeout;
-}
-
-static int n_dhcp4_c_connection_packet_broadcast(NDhcp4CConnection *connection,
-                                                 NDhcp4Outgoing *message) {
-        int r;
-
-        c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_PACKET);
-
-        r = n_dhcp4_c_socket_packet_send(connection->fd_packet,
-                                         connection->client_config->ifindex,
-                                         connection->client_config->broadcast_mac,
-                                         connection->client_config->n_broadcast_mac,
-                                         message);
-        if (r)
-                return r;
-
-        return 0;
-}
-
-static int n_dhcp4_c_connection_udp_broadcast(NDhcp4CConnection *connection,
-                                              NDhcp4Outgoing *message) {
-        int r;
-
-        c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_DRAINING ||
-               connection->state == N_DHCP4_C_CONNECTION_STATE_UDP);
-
-        r = n_dhcp4_c_socket_udp_broadcast(connection->fd_udp, message);
-        if (r)
-                return r;
-
-        return 0;
-}
-
-static int n_dhcp4_c_connection_udp_send(NDhcp4CConnection *connection,
-                                         NDhcp4Outgoing *message) {
-        int r;
-
-        c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_DRAINING ||
-               connection->state == N_DHCP4_C_CONNECTION_STATE_UDP);
-
-        r = n_dhcp4_c_socket_udp_send(connection->fd_udp, message);
-        if (r)
-                return r;
-
-        return 0;
-}
-
-static void n_dhcp4_c_connection_init_header(NDhcp4CConnection *connection,
-                                             NDhcp4Header *header) {
-        bool broadcast = connection->client_config->request_broadcast;
-
-        header->op = N_DHCP4_OP_BOOTREQUEST;
-
-        switch (connection->client_config->transport) {
-        case N_DHCP4_TRANSPORT_ETHERNET:
-                c_assert(connection->client_config->n_mac == ETH_ALEN);
-
-                header->htype = ARPHRD_ETHER;
-                header->hlen = ETH_ALEN;
-                memcpy(header->chaddr, connection->client_config->mac, ETH_ALEN);
-                break;
-        case N_DHCP4_TRANSPORT_INFINIBAND:
-                header->htype = ARPHRD_INFINIBAND;
-                header->hlen = 0;
-
-                /* infiniband mandates to request broadcasts */
-                broadcast = true;
-                break;
-        default:
-                abort();
-                break;
-        }
-
-        if (connection->client_ip != INADDR_ANY) {
-                header->ciaddr = connection->client_ip;
-        } else {
-                /*
-                 * When the IP stack has not been configured, we may
-                 * not be able to receive unicast packets, depending
-                 * on the hardware. If that is the case we must request
-                 * replies from the server to be broadcast.
-                 *
-                 * Once the IP stack has been configured, receiving
-                 * unicast packets is never a problem, so the broadcast
-                 * flag should not be set.
-                 */
-                if (broadcast)
-                        header->flags |= N_DHCP4_MESSAGE_FLAG_BROADCAST;
-        }
-}
-
-static int n_dhcp4_c_connection_new_message(NDhcp4CConnection *connection,
-                                            NDhcp4Outgoing **messagep,
-                                            uint8_t type) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        NDhcp4Header *header;
-        uint8_t message_type;
-        bool via_packet_socket = false;
-        int r;
-
-        switch (type) {
-        case N_DHCP4_C_MESSAGE_DISCOVER:
-                message_type = N_DHCP4_MESSAGE_DISCOVER;
-                via_packet_socket = true;
-                break;
-        case N_DHCP4_C_MESSAGE_INFORM:
-                message_type = N_DHCP4_MESSAGE_INFORM;
-                break;
-        case N_DHCP4_C_MESSAGE_SELECT:
-                message_type = N_DHCP4_MESSAGE_REQUEST;
-                via_packet_socket = true;
-                break;
-        case N_DHCP4_C_MESSAGE_RENEW:
-                message_type = N_DHCP4_MESSAGE_REQUEST;
-                break;
-        case N_DHCP4_C_MESSAGE_REBIND:
-                message_type = N_DHCP4_MESSAGE_REQUEST;
-                break;
-        case N_DHCP4_C_MESSAGE_REBOOT:
-                message_type = N_DHCP4_MESSAGE_REQUEST;
-                via_packet_socket = true;
-                break;
-        case N_DHCP4_C_MESSAGE_RELEASE:
-                message_type = N_DHCP4_MESSAGE_RELEASE;
-                break;
-        case N_DHCP4_C_MESSAGE_DECLINE:
-                message_type = N_DHCP4_MESSAGE_DECLINE;
-                via_packet_socket = true;
-                break;
-        default:
-                abort();
-                return -ENOTRECOVERABLE;
-        }
-
-        /*
-         * We explicitly pass 0 as maximum message size, which makes
-         * NDhcp4Outgoing use the mandated default value from the spec (see its
-         * implementation). While the transport and like layers might support
-         * bigger MTUs (and we very likely know about them through
-         * n_dhcp4_client_update_mtu()), we cannot assume the target DHCP
-         * server supports parsing packets bigger than the minimum (and it is
-         * allowed to refuse bigger IP packets, even if the network supports
-         * transmission of them).
-         *
-         * We could theoretically increase this for packets other than the
-         * initial discovery. However, clients are unlikely to ever send large
-         * packets, so we just keep the same default for all outgoing packets.
-         */
-        r = n_dhcp4_outgoing_new(&message, 0, N_DHCP4_OVERLOAD_FILE | N_DHCP4_OVERLOAD_SNAME);
-        if (r)
-                return r;
-
-        header = n_dhcp4_outgoing_get_header(message);
-        n_dhcp4_c_connection_init_header(connection, header);
-
-        message->userdata.type = type;
-        message->userdata.message_type = message_type;
-
-        /*
-         * Note that some implementations expect the MESSAGE_TYPE option to be
-         * the first option, and possibly even hard-code access to it. Hence,
-         * we really should make sure to pass it first as well.
-         */
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_MESSAGE_TYPE, &message_type, sizeof(message_type));
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message,
-                                    N_DHCP4_OPTION_CLIENT_IDENTIFIER,
-                                    connection->client_config->client_id,
-                                    connection->client_config->n_client_id);
-        if (r)
-                return r;
-
-        switch (message_type) {
-        case N_DHCP4_MESSAGE_DISCOVER:
-        case N_DHCP4_MESSAGE_REQUEST:
-        case N_DHCP4_MESSAGE_INFORM: {
-                uint16_t mtu;
-
-                if (connection->probe_config->n_request_parameters > 0) {
-                        r = n_dhcp4_outgoing_append(message,
-                                                    N_DHCP4_OPTION_PARAMETER_REQUEST_LIST,
-                                                    connection->probe_config->request_parameters,
-                                                    connection->probe_config->n_request_parameters);
-                        if (r)
-                                return r;
-                }
-
-                if (via_packet_socket) {
-                        /*
-                         * In case of packet sockets, we do not support
-                         * fragmentation. Hence, our maximum message size
-                         * equals the transport MTU. In case no mtu is given,
-                         * we use the minimum size mandated by the IP spec. If
-                         * we omit the field, some implementations will
-                         * interpret this to mean any packet size is supported,
-                         * which we rather not want as default behavior (we can
-                         * always support suppressing this field, if that is
-                         * what the caller wants).
-                         */
-                        mtu = htons(connection->mtu ?: N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE);
-                        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE, &mtu, sizeof(mtu));
-                        if (r)
-                                return r;
-                } else {
-                        /*
-                         * Once we use UDP sockets, we support fragmentation
-                         * through the kernel IP stack. This means, the biggest
-                         * message we can receive is the maximum UDP size plus
-                         * the possible IP header. This would sum up to
-                         * 2^16-1 + 20 (or even 2^16-1 + 60 if pedantic) and
-                         * thus exceed the option field. Hence, we simply set
-                         * the option to the maximum possible value.
-                         */
-                        mtu = htons(UINT16_MAX);
-                        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE, &mtu, sizeof(mtu));
-                        if (r)
-                                return r;
-                }
-
-                break;
-        }
-        default:
-                break;
-        }
-
-        *messagep = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 3.1
- *
- *      The client broadcasts a DHCPDISCOVER message on its local physical
- *      subnet.  The DHCPDISCOVER message MAY include options that suggest
- *      values for the network address and lease duration.  BOOTP relay
- *      agents may pass the message on to DHCP servers not on the same
- *      physical subnet.
- *
- *      RFC2131 3.5
- *
- *      [...] in its initial DHCPDISCOVER or DHCPREQUEST message, a client
- *      may provide the server with a list of specific parameters the
- *      client is interested in.  If the client includes a list of
- *      parameters in a DHCPDISCOVER message, it MUST include that list in
- *      any subsequent DHCPREQUEST messages.
- *
- *      [...]
- *
- *      In addition, the client may suggest values for the network address
- *      and lease time in the DHCPDISCOVER message.  The client may include
- *      the 'requested IP address' option to suggest that a particular IP
- *      address be assigned, and may include the 'IP address lease time'
- *      option to suggest the lease time it would like.  Other options
- *      representing "hints" at configuration parameters are allowed in a
- *      DHCPDISCOVER or DHCPREQUEST message.
- *
- *      RFC2131 4.4.1
- *
- *      The client generates and records a random transaction identifier and
- *      inserts that identifier into the 'xid' field.  The client records its
- *      own local time for later use in computing the lease expiration.  The
- *      client then broadcasts the DHCPDISCOVER on the local hardware
- *      broadcast address to the 0xffffffff IP broadcast address and 'DHCP
- *      server' UDP port.
- *
- *      If the 'xid' of an arriving DHCPOFFER message does not match the
- *      'xid' of the most recent DHCPDISCOVER message, the DHCPOFFER message
- *      must be silently discarded.  Any arriving DHCPACK messages must be
- *      silently discarded.
- */
-int n_dhcp4_c_connection_discover_new(NDhcp4CConnection *connection,
-                                      NDhcp4Outgoing **requestp) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_DISCOVER);
-        if (r)
-                return r;
-
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *
- *      RFC2131 4.1.1
- *
- *      The DHCPREQUEST message contains the same 'xid' as the DHCPOFFER
- *      message.
- *
- *      RFC2131 4.3.2
- *
- *      Client inserts the address of the selected server in 'server
- *      identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
- *      filled in with the yiaddr value from the chosen DHCPOFFER.
- */
-int n_dhcp4_c_connection_select_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **requestp,
-                                    NDhcp4Incoming *offer) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        struct in_addr client;
-        struct in_addr server;
-        uint32_t xid;
-        int r;
-
-        n_dhcp4_incoming_get_yiaddr(offer, &client);
-
-        r = n_dhcp4_incoming_query_server_identifier(offer, &server);
-        if (r)
-                return r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_SELECT);
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, &client, sizeof(client));
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_SERVER_IDENTIFIER, &server, sizeof(server));
-        if (r)
-                return r;
-
-        /*
-         * SELECT continues the transaction started by DISCOVER, and as such
-         * keeps the same start time. We also have to preserve the base time
-         * of the selected lease as well as the transaction ID.
-         */
-        message->userdata.start_time = offer->userdata.start_time;
-        message->userdata.base_time = offer->userdata.base_time;
-        message->userdata.client_addr = client.s_addr;
-        n_dhcp4_incoming_get_xid(offer, &xid);
-        n_dhcp4_outgoing_set_xid(message, xid);
-
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 4.3.2
- *
- *      'server identifier' MUST NOT be filled in, 'requested IP address'
- *      option MUST be filled in with client's notion of its previously
- *      assigned address. 'ciaddr' MUST be zero. The client is seeking to
- *      verify a previously allocated, cached configuration. Server SHOULD
- *      send a DHCPNAK message to the client if the 'requested IP address'
- *      is incorrect, or is on the wrong network.
- */
-int n_dhcp4_c_connection_reboot_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **requestp,
-                                    const struct in_addr *client) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_REBOOT);
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, client, sizeof(*client));
-        if (r)
-                return r;
-
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 4.3.2
- *
- *      'server identifier' MUST NOT be filled in, 'requested IP address'
- *      option MUST NOT be filled in, 'ciaddr' MUST be filled in with
- *      client's IP address. In this situation, the client is completely
- *      configured, and is trying to extend its lease. This message will
- *      be unicast, so no relay agents will be involved in its
- *      transmission.  Because 'giaddr' is therefore not filled in, the
- *      DHCP server will trust the value in 'ciaddr', and use it when
- *      replying to the client.
- *
- *      A client MAY choose to renew or extend its lease prior to T1.  The
- *      server may choose not to extend the lease (as a policy decision by
- *      the network administrator), but should return a DHCPACK message
- *      regardless.
- *
- *      RFC2131 4.4.5
- *
- *      At time T1 the client moves to RENEWING state and sends (via unicast)
- *      a DHCPREQUEST message to the server to extend its lease.  The client
- *      sets the 'ciaddr' field in the DHCPREQUEST to its current network
- *      address. The client records the local time at which the DHCPREQUEST
- *      message is sent for computation of the lease expiration time.  The
- *      client MUST NOT include a 'server identifier' in the DHCPREQUEST
- *      message.
- */
-int n_dhcp4_c_connection_renew_new(NDhcp4CConnection *connection,
-                                   NDhcp4Outgoing **requestp) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_RENEW);
-        if (r)
-                return r;
-
-        message->userdata.client_addr = connection->client_ip;
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 4.3.2
- *
- *      'server identifier' MUST NOT be filled in, 'requested IP address'
- *      option MUST NOT be filled in, 'ciaddr' MUST be filled in with
- *      client's IP address. In this situation, the client is completely
- *      configured, and is trying to extend its lease. This message MUST
- *      be broadcast to the 0xffffffff IP broadcast address.  The DHCP
- *      server SHOULD check 'ciaddr' for correctness before replying to
- *      the DHCPREQUEST.
- *
- *      RFC2131 4.4.5
- *
- *      If no DHCPACK arrives before time T2, the client moves to REBINDING
- *      state and sends (via broadcast) a DHCPREQUEST message to extend its
- *      lease.  The client sets the 'ciaddr' field in the DHCPREQUEST to its
- *      current network address.  The client MUST NOT include a 'server
- *      identifier' in the DHCPREQUEST message.
- */
-int n_dhcp4_c_connection_rebind_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **requestp) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_REBIND);
-        if (r)
-                return r;
-
-        message->userdata.client_addr = connection->client_ip;
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 3.2
- *
- *      If the client detects that the IP address in the DHCPACK message
- *      is already in use, the client MUST send a DHCPDECLINE message to the
- *      server and restarts the configuration process by requesting a
- *      new network address.
- *
- *      RFC2131 4.4.4
- *
- *      Because the client is declining the use of the IP address supplied by
- *      the server, the client broadcasts DHCPDECLINE messages.
- */
-int n_dhcp4_c_connection_decline_new(NDhcp4CConnection *connection,
-                                     NDhcp4Outgoing **requestp,
-                                     NDhcp4Incoming *ack,
-                                     const char *error) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        struct in_addr client;
-        struct in_addr server;
-        int r;
-
-        n_dhcp4_incoming_get_yiaddr(ack, &client);
-
-        r = n_dhcp4_incoming_query_server_identifier(ack, &server);
-        if (r)
-                return r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_DECLINE);
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, &client, sizeof(client));
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_SERVER_IDENTIFIER, &server, sizeof(server));
-        if (r)
-                return r;
-
-        if (error) {
-                r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_ERROR_MESSAGE, error, strlen(error) + 1);
-                if (r)
-                        return r;
-        }
-
-        message->userdata.client_addr = client.s_addr;
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 3.4
- *
- *      If a client has obtained a network address through some other means
- *      (e.g., manual configuration), it may use a DHCPINFORM request message
- *      to obtain other local configuration parameters.
- *
- *      RFC2131 4.4
- *
- *      The DHCPINFORM message is not shown in figure 5.  A client simply
- *      sends the DHCPINFORM and waits for DHCPACK messages.  Once the client
- *      has selected its parameters, it has completed the configuration
- *      process.
- *
- *      RFC2131 4.4.3
- *
- *      The client sends a DHCPINFORM message. The client may request
- *      specific configuration parameters by including the 'parameter request
- *      list' option. The client generates and records a random transaction
- *      identifier and inserts that identifier into the 'xid' field. The
- *      client places its own network address in the 'ciaddr' field. The
- *      client SHOULD NOT request lease time parameters.
- *
- *      The client then unicasts the DHCPINFORM to the DHCP server if it
- *      knows the server's address, otherwise it broadcasts the message to
- *      the limited (all 1s) broadcast address.  DHCPINFORM messages MUST be
- *      directed to the 'DHCP server' UDP port.
- */
-int n_dhcp4_c_connection_inform_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **requestp) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_INFORM);
-        if (r)
-                return r;
-
-        message->userdata.client_addr = connection->client_ip;
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-/*
- *      RFC2131 3.1
- *
- *      The client may choose to relinquish its lease on a network address
- *      by sending a DHCPRELEASE message to the server.  The client
- *      identifies the lease to be released with its 'client identifier',
- *      or 'chaddr' and network address in the DHCPRELEASE message. If the
- *      client used a 'client identifier' when it obtained the lease, it
- *      MUST use the same 'client identifier' in the DHCPRELEASE message.
- *
- *      RFC2131 3.2
- *
- *      The client may choose to relinquish its lease on a network
- *      address by sending a DHCPRELEASE message to the server.  The
- *      client identifies the lease to be released with its
- *      'client identifier', or 'chaddr' and network address in the
- *      DHCPRELEASE message.
- *
- *      Note that in this case, where the client retains its network
- *      address locally, the client will not normally relinquish its
- *      lease during a graceful shutdown.  Only in the case where the
- *      client explicitly needs to relinquish its lease, e.g., the client
- *      is about to be moved to a different subnet, will the client send
- *      a DHCPRELEASE message.
- *
- *      RFC2131 4.4.4
- *
- *      The client unicasts DHCPRELEASE messages to the server.
- *
- *      RFC2131 4.4.6
- *
- *      If the client no longer requires use of its assigned network address
- *      (e.g., the client is gracefully shut down), the client sends a
- *      DHCPRELEASE message to the server.  Note that the correct operation
- *      of DHCP does not depend on the transmission of DHCPRELEASE messages.
- */
-int n_dhcp4_c_connection_release_new(NDhcp4CConnection *connection,
-                                     NDhcp4Outgoing **requestp,
-                                     const char *error) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *message = NULL;
-        int r;
-
-        r = n_dhcp4_c_connection_new_message(connection, &message, N_DHCP4_C_MESSAGE_RELEASE);
-        if (r)
-                return r;
-
-        r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_SERVER_IDENTIFIER, &connection->server_ip, sizeof(connection->server_ip));
-        if (r)
-                return r;
-
-        if (error) {
-                r = n_dhcp4_outgoing_append(message, N_DHCP4_OPTION_ERROR_MESSAGE, error, strlen(error) + 1);
-                if (r)
-                        return r;
-        }
-
-        *requestp = message;
-        message = NULL;
-        return 0;
-}
-
-static const char *message_type_to_str(uint8_t type) {
-        switch (type) {
-        case N_DHCP4_MESSAGE_DISCOVER:
-                return "DISCOVER";
-        case N_DHCP4_MESSAGE_OFFER:
-                return "OFFER";
-        case N_DHCP4_MESSAGE_REQUEST:
-                return "REQUEST";
-        case N_DHCP4_MESSAGE_DECLINE:
-                return "DECLINE";
-        case N_DHCP4_MESSAGE_ACK:
-                return "ACK";
-        case N_DHCP4_MESSAGE_NAK:
-                return "NACK";
-        case N_DHCP4_MESSAGE_RELEASE:
-                return "RELEASE";
-        case N_DHCP4_MESSAGE_INFORM:
-                return "INFORM";
-        case N_DHCP4_MESSAGE_FORCERENEW:
-                return "FORCERENEW";
-        default:
-                return "UNKNOWN";
-        }
-}
-
-static int n_dhcp4_c_connection_send_request(NDhcp4CConnection *connection,
-                                             NDhcp4Outgoing *request,
-                                             uint64_t timestamp) {
-        char server_addr[INET_ADDRSTRLEN];
-        char client_addr[INET_ADDRSTRLEN];
-        char error_msg[128];
-        int r;
-        bool broadcast = false;
-
-        /*
-         * Increment the base time and reset the xid field,
-         * where applicable. We never alter the header on
-         * resends of SELECT, as it must always match the
-         * OFFER message they are in reply to.
-         */
-        switch (request->userdata.type) {
-        case N_DHCP4_C_MESSAGE_DISCOVER:
-        case N_DHCP4_C_MESSAGE_INFORM:
-        case N_DHCP4_C_MESSAGE_REBOOT:
-        case N_DHCP4_C_MESSAGE_REBIND:
-        case N_DHCP4_C_MESSAGE_RENEW:
-                request->userdata.base_time = timestamp;
-                n_dhcp4_outgoing_set_xid(request, n_dhcp4_client_probe_config_get_random(connection->probe_config));
-
-                break;
-        case N_DHCP4_C_MESSAGE_SELECT:
-        case N_DHCP4_C_MESSAGE_DECLINE:
-        case N_DHCP4_C_MESSAGE_RELEASE:
-                break;
-        default:
-                c_assert(0);
-        }
-
-        request->userdata.send_time = timestamp;
-        request->userdata.send_jitter = (n_dhcp4_client_probe_config_get_random(connection->probe_config) % 1000000000ULL);
-        n_dhcp4_c_connection_outgoing_set_secs(request);
-
-        switch (request->userdata.type) {
-        case N_DHCP4_C_MESSAGE_DISCOVER:
-        case N_DHCP4_C_MESSAGE_SELECT:
-        case N_DHCP4_C_MESSAGE_REBOOT:
-        case N_DHCP4_C_MESSAGE_DECLINE:
-        case N_DHCP4_C_MESSAGE_REBIND:
-                broadcast = true;
-                r = n_dhcp4_c_connection_packet_broadcast(connection, request);
-                break;
-        case N_DHCP4_C_MESSAGE_INFORM:
-                broadcast = true;
-                r = n_dhcp4_c_connection_udp_broadcast(connection, request);
-                break;
-        case N_DHCP4_C_MESSAGE_RENEW:
-        case N_DHCP4_C_MESSAGE_RELEASE:
-                r = n_dhcp4_c_connection_udp_send(connection, request);
-                break;
-        default:
-                c_assert(0);
-        }
-
-        if (r) {
-                snprintf(error_msg, sizeof(error_msg), ": error %d", r);
-        } else {
-                error_msg[0] = '\0';
-        }
-
-        if (request->userdata.client_addr == INADDR_ANY) {
-                n_dhcp4_log(connection->log_queue,
-                            LOG_INFO,
-                            "send %s to %s%s",
-                            message_type_to_str(request->userdata.message_type),
-                            broadcast ?
-                            "255.255.255.255" :
-                            inet_ntop(AF_INET, &connection->server_ip,
-                                      server_addr, sizeof(server_addr)),
-                            error_msg);
-        } else {
-                n_dhcp4_log(connection->log_queue,
-                            LOG_INFO,
-                            "send %s of %s to %s%s",
-                            message_type_to_str(request->userdata.message_type),
-                            inet_ntop(AF_INET, &request->userdata.client_addr,
-                                      client_addr, sizeof(client_addr)),
-                            broadcast ?
-                            "255.255.255.255" :
-                            inet_ntop(AF_INET, &connection->server_ip,
-                                      server_addr, sizeof(server_addr)),
-                            error_msg);
-        }
-
-        ++request->userdata.n_send;
-        return 0;
-}
-
-int n_dhcp4_c_connection_start_request(NDhcp4CConnection *connection,
-                                       NDhcp4Outgoing *request,
-                                       uint64_t timestamp) {
-        int r;
-
-        /*
-         * This function starts a request, but in the case of SELECT it
-         * continues a previous transaction, so we do not want to reset
-         * the start time. Only set the start time if it was not already
-         * set.
-         */
-        if (request->userdata.start_time == 0)
-                request->userdata.start_time = timestamp;
-
-        connection->request = n_dhcp4_outgoing_free(connection->request);
-
-        r = n_dhcp4_c_connection_send_request(connection, request, timestamp);
-        if (r)
-                return r;
-
-        connection->request = request;
-
-        return 0;
-}
-
-int n_dhcp4_c_connection_dispatch_timer(NDhcp4CConnection *connection,
-                                        uint64_t timestamp) {
-        uint64_t timeout;
-        int r;
-
-        if (!connection->request)
-                return 0;
-
-        n_dhcp4_c_connection_get_timeout(connection, &timeout);
-
-        if (timeout > timestamp)
-                return 0;
-
-        r = n_dhcp4_c_connection_send_request(connection, connection->request, timestamp);
-        if (r)
-                return r;
-
-        return 0;
-}
-
-/*
- * Returns:
- *  0                     on success
- *  N_DHCP4_E_MALFORMED   if a malformed packet was received
- *  N_DHCP4_E_UNEXPECTED  if the packet received contains unexpected data
- *  N_DHCP4_E_AGAIN       if there was another error (non fatal for the client)
- */
-int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
-                                     NDhcp4Incoming **messagep) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
-        char serv_addr[INET_ADDRSTRLEN];
-        char client_addr[INET_ADDRSTRLEN];
-        uint8_t type;
-        int r;
-
-        switch (connection->state) {
-        case N_DHCP4_C_CONNECTION_STATE_PACKET:
-                r = n_dhcp4_c_socket_packet_recv(connection->fd_packet,
-                                                 connection->scratch_buffer,
-                                                 sizeof(connection->scratch_buffer),
-                                                 &message);
-                if (!r)
-                        break;
-                else if (r == N_DHCP4_E_MALFORMED)
-                        return r;
-                return N_DHCP4_E_AGAIN;
-        case N_DHCP4_C_CONNECTION_STATE_DRAINING:
-                r = n_dhcp4_c_socket_packet_recv(connection->fd_packet,
-                                                 connection->scratch_buffer,
-                                                 sizeof(connection->scratch_buffer),
-                                                 &message);
-                if (!r)
-                        break;
-                else if (r == N_DHCP4_E_MALFORMED)
-                        return r;
-                else if (r != N_DHCP4_E_AGAIN)
-                        return N_DHCP4_E_AGAIN;
-
-                /*
-                 * The UDP socket is open and the packet socket has been shut down
-                 * and drained, clean up the packet socket and fall through to
-                 * dispatching the UDP socket.
-                 */
-                r = epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_packet, NULL);
-                c_assert(!r);
-                connection->fd_packet = c_close(connection->fd_packet);
-                connection->state = N_DHCP4_C_CONNECTION_STATE_UDP;
-
-                /* fall-through */
-        case N_DHCP4_C_CONNECTION_STATE_UDP:
-                r = n_dhcp4_c_socket_udp_recv(connection->fd_udp,
-                                              connection->scratch_buffer,
-                                              sizeof(connection->scratch_buffer),
-                                              &message);
-                if (!r)
-                        break;
-                else if (r == N_DHCP4_E_MALFORMED)
-                        return r;
-                return N_DHCP4_E_AGAIN;
-        default:
-                abort();
-                return -ENOTRECOVERABLE;
-        }
-
-        r = n_dhcp4_c_connection_verify_incoming(connection, message, &type);
-        if (r == N_DHCP4_E_MALFORMED || r == N_DHCP4_E_UNEXPECTED)
-                return r;
-        else if (r != 0)
-                return N_DHCP4_E_AGAIN;
-
-        if (type == N_DHCP4_MESSAGE_OFFER || type == N_DHCP4_MESSAGE_ACK) {
-                n_dhcp4_log(connection->log_queue,
-                            LOG_INFO,
-                            "received %s of %s from %s",
-                            message_type_to_str(type),
-                            inet_ntop(AF_INET, &message->message.header.yiaddr,
-                                      client_addr, sizeof(client_addr)),
-                            inet_ntop(AF_INET, &message->message.header.siaddr,
-                                      serv_addr, sizeof(serv_addr)));
-        } else {
-                n_dhcp4_log(connection->log_queue,
-                            LOG_INFO,
-                            "received %s from %s",
-                            message_type_to_str(type),
-                            inet_ntop(AF_INET, &message->message.header.siaddr,
-                                      serv_addr, sizeof(serv_addr)));
-        }
-
-        switch (type) {
-        case N_DHCP4_MESSAGE_OFFER:
-        case N_DHCP4_MESSAGE_ACK:
-        case N_DHCP4_MESSAGE_NAK:
-                /*
-                 * Remember the start time of the transaction, and the base
-                 * time of any relative timestamps from the pending request.
-                 * The same time applies to the response, and should be
-                 * copied over.
-                 */
-                message->userdata.start_time = connection->request->userdata.start_time;
-                message->userdata.base_time = connection->request->userdata.base_time;
-
-                if (type != N_DHCP4_MESSAGE_OFFER) {
-                        /*
-                         * We only allow one reply to ACK or NAK, but for OFFER we must
-                         * accept several, so we do not free the pinned request.
-                         */
-                        connection->request = n_dhcp4_outgoing_free(connection->request);
-                }
-
-                break;
-        default:
-                break;
-        }
-
-        *messagep = message;
-        message = NULL;
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-lease.c b/shared/n-dhcp4/src/n-dhcp4-c-lease.c
deleted file mode 100644
index 515814d4..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-c-lease.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * DHCP4 Client Leases
- *
- * This implements the public API wrapping DHCP4 client leases. A lease object
- * consists of the information given to us from the server, together with the
- * timestamp recording the start of the validity of the lease.
- *
- * A probe may yield many OFFERS, each of which contains a lease object. One of
- * these offers may be SELECTED, which implicitly rejects all the others.
- * The server may then ACK or NAK the lease which tells us whether or not we
- * are permitted to start using it. Once an ACK has been received, we can
- * configure the address, and only then can we SELECT the lease. If we
- * determine that the offered lease was not appropriate after all we
- * may DECLINE it instead.
- */
-
-#include <assert.h>
-#include <c-list.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include "n-dhcp4.h"
-#include "n-dhcp4-private.h"
-
-/*
- * Compute the absolute timeouts from an incoming message. A message contains relative timeouts and the userdata
- * of the incoming message is set to the offset we must apply to get the absolute values.
- *
- * The special value UINT64_MAX is returned to indicate no or infinite timeouts. In case the given timeouts
- * are invalid relative to each other, we recompute T1 and/or T2 to take their default values. Later timeouts
- * take predecende above earlier ones (T1 is adjusted if it conflicts with T2, etc).
- */
-static int n_dhcp4_incoming_get_timeouts(NDhcp4Incoming *message, uint64_t *t1p, uint64_t *t2p, uint64_t *lifetimep) {
-        uint64_t lifetime, t2, t1;
-        uint32_t u32;
-        int r;
-
-        r = n_dhcp4_incoming_query_lifetime(message, &u32);
-        if (r == N_DHCP4_E_UNSET) {
-                lifetime = UINT64_MAX;
-        } else if (r) {
-                return r;
-        } else if (u32 == UINT32_MAX) {
-                lifetime = UINT64_MAX;
-        } else {
-                lifetime = u32 * (1000000000ULL);
-        }
-
-        r = n_dhcp4_incoming_query_t2(message, &u32);
-        if (r == N_DHCP4_E_UNSET) {
-                if (lifetime == UINT64_MAX)
-                        t2 = UINT64_MAX;
-                else
-                        t2 = (lifetime * 7) / 8;
-        } else if (r) {
-                return r;
-        } else {
-                if (u32 == UINT32_MAX)
-                        t2 = UINT64_MAX;
-                else
-                        t2 = u32 * (1000000000ULL);
-
-                if (t2 > lifetime)
-                        t2 = (lifetime * 7) / 8;
-        }
-
-        r = n_dhcp4_incoming_query_t1(message, &u32);
-        if (r == N_DHCP4_E_UNSET) {
-                if (t2 == UINT64_MAX)
-                        t1 = UINT64_MAX;
-                else
-                        t1 = (t2 * 4) / 7;
-        } else if (r) {
-                return r;
-        } else {
-                if (u32 == UINT32_MAX)
-                        t1 = UINT64_MAX;
-                else
-                        t1 = u32 * (1000000000ULL);
-
-                if (t1 > t2)
-                        t1 = (t2 * 4) / 7;
-        }
-
-        if (lifetime != UINT64_MAX)
-                lifetime += message->userdata.base_time;
-        if (t2 != UINT64_MAX)
-                t2 += message->userdata.base_time;
-        if (t1 != UINT64_MAX)
-                t1 += message->userdata.base_time;
-
-        *lifetimep = lifetime;
-        *t2p = t2;
-        *t1p = t1;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_lease_new() - allocate new client lease object
- * @leasep:                     output argument for new client lease object
- * @message:                    incoming message representing the lease
- *
- * This creates a new client lease object. Client lease objects are simple
- * wrappers around an incoming message representing a lease.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_client_lease_new(NDhcp4ClientLease **leasep, NDhcp4Incoming *message) {
-        _c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
-        int r;
-
-        c_assert(leasep);
-
-        lease = malloc(sizeof(*lease));
-        if (!lease)
-                return -ENOMEM;
-
-        *lease = (NDhcp4ClientLease)N_DHCP4_CLIENT_LEASE_NULL(*lease);
-
-        r = n_dhcp4_incoming_get_timeouts(message, &lease->t1, &lease->t2, &lease->lifetime);
-        if (r)
-                return r;
-
-        lease->message = message;
-        *leasep = lease;
-        lease = NULL;
-        return 0;
-}
-
-static void n_dhcp4_client_lease_free(NDhcp4ClientLease *lease) {
-        n_dhcp4_client_lease_unlink(lease);
-        n_dhcp4_incoming_free(lease->message);
-        free(lease);
-}
-
-/**
- * n_dhcp4_client_lease_ref() - reference client lease
- * @lease:                      the client lease object to reference
- *
- * Take a new reference to a client lease.
- *
- * Return: the lease.
- */
-_c_public_ NDhcp4ClientLease *n_dhcp4_client_lease_ref(NDhcp4ClientLease *lease) {
-        if (lease)
-                ++lease->n_refs;
-        return lease;
-}
-
-/**
- * n_dhcp4_client_lease_unref() - dereference client lease
- * @lease:                      the client lease object to dereference
- *
- * Relase a reference to a client lease.
- *
- * Return: NULL.
- */
-_c_public_ NDhcp4ClientLease *n_dhcp4_client_lease_unref(NDhcp4ClientLease *lease) {
-        if (lease && !--lease->n_refs)
-                n_dhcp4_client_lease_free(lease);
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_lease_link() - link lease into probe
- * @lease:                      the lease to operate on
- * @probe:                      the probe to link the lease into
- *
- * Associate a lease with a probe. The lease may not already be linked.
- */
-void n_dhcp4_client_lease_link(NDhcp4ClientLease *lease, NDhcp4ClientProbe *probe) {
-        c_assert(!lease->probe);
-        c_assert(!c_list_is_linked(&lease->probe_link));
-
-        lease->probe = probe;
-        c_list_link_tail(&probe->lease_list, &lease->probe_link);
-}
-
-/**
- * n_dhcp4_client_lease_unlink() - unlinke lease from its probe
- * @lease:                      the lease to operate on
- *
- * Dissassociate a lease from a probe if it is associated with one. Otherwise,
- * this is a noop.
- */
-void n_dhcp4_client_lease_unlink(NDhcp4ClientLease *lease) {
-        lease->probe = NULL;
-        c_list_unlink(&lease->probe_link);
-}
-
-/**
- * n_dhcp4_client_lease_get_yiaddr() - get the IP address
- * @lease:                      the lease to operate on
- * @yiaddr:                     return argument for the IP address
- *
- * Gets the IP address contained in the lease. Or INADDR_ANY if the lease
- * does not contain an IP address.
- */
-_c_public_ void n_dhcp4_client_lease_get_yiaddr(NDhcp4ClientLease *lease, struct in_addr *yiaddr) {
-        NDhcp4Header *header = n_dhcp4_incoming_get_header(lease->message);
-
-        yiaddr->s_addr = header->yiaddr;
-}
-
-/**
- * n_dhcp4_client_lease_get_siaddr() - get the server IP address
- * @lease:                      the lease to operate on
- * @siaddr:                     return argument for the IP address
- *
- * Gets the server IP address contained in the lease. Or INADDR_ANY if the
- * lease does not contain an IP address.
- */
-_c_public_ void n_dhcp4_client_lease_get_siaddr(NDhcp4ClientLease *lease, struct in_addr *siaddr) {
-        NDhcp4Header *header = n_dhcp4_incoming_get_header(lease->message);
-
-        siaddr->s_addr = header->siaddr;
-}
-
-/**
- * n_dhcp4_client_lease_get_basetime() - get the timestamp when the lease was received.
- * @lease:                      the lease to operate on
- * @ns_basetimep:               return argument for the base time in nano seconds
- *
- * Gets the timestamp when the lease was received in CLOCK_BOOTTIME. This
- * is also the base timestamp for the expiration of the lifetime and t1/t2.
- */
-_c_public_ void n_dhcp4_client_lease_get_basetime(NDhcp4ClientLease *lease, uint64_t *ns_basetimep) {
-        *ns_basetimep = lease->message->userdata.base_time;
-}
-
-/**
- * n_dhcp4_client_lease_get_lifetime() - get the lifetime
- * @lease:                      the lease to operate on
- * @ns_lifetimep:               return argument for the lifetime in nano seconds
- *
- * Gets the end of the lease's lifetime in nanoseconds according to CLOCK_BOOTTIME,
- * or (uint64_t)-1 for permanent leases.
- */
-_c_public_ void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint64_t *ns_lifetimep) {
-        *ns_lifetimep = lease->lifetime;
-}
-
-/**
- * n_dhcp4_client_lease_get_server_identifier() - get the server identifier
- * @lease:                      the lease to operate on
- * @addr:                       return argument for the server identifier
- *
- * Gets the address contained in the server-identifier DHCP option, in network
- * byte order.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_lease_get_server_identifier (NDhcp4ClientLease *lease, struct in_addr *addr) {
-        uint8_t *data;
-        size_t n_data;
-        int r;
-
-        r = n_dhcp4_incoming_query(lease->message, N_DHCP4_OPTION_SERVER_IDENTIFIER, &data, &n_data);
-        if (r)
-                return r;
-        if (n_data < sizeof(struct in_addr))
-                return N_DHCP4_E_MALFORMED;
-
-        memcpy(addr, data, sizeof(struct in_addr));
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_lease_query() - query the lease for an option
- * @lease:                      the lease to operate on
- * @option:                     the DHCP4 option code
- * @datap:                      return argument of the data pointer
- * @n_datap:                    return argument of data length in bytes
- *
- * Query the lease for a given option. Options internal to the DHCP protocol cannot
- * be queried, and only options that were explicitly requested can be queried.
- *
- * Return: 0 on success,
- *         N_DCHP4_E_INTERNAL if an invalid option is queried,
- *         N_DHCP4_E_UNSET if the lease did not contain the option, or
- *         a negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_lease_query(NDhcp4ClientLease *lease, uint8_t option, uint8_t **datap, size_t *n_datap) {
-        switch (option) {
-        case N_DHCP4_OPTION_PAD:
-        case N_DHCP4_OPTION_REQUESTED_IP_ADDRESS:
-        case N_DHCP4_OPTION_IP_ADDRESS_LEASE_TIME:
-        case N_DHCP4_OPTION_OVERLOAD:
-        case N_DHCP4_OPTION_MESSAGE_TYPE:
-        case N_DHCP4_OPTION_SERVER_IDENTIFIER:
-        case N_DHCP4_OPTION_PARAMETER_REQUEST_LIST:
-        case N_DHCP4_OPTION_ERROR_MESSAGE:
-        case N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE:
-        case N_DHCP4_OPTION_RENEWAL_T1_TIME:
-        case N_DHCP4_OPTION_REBINDING_T2_TIME:
-        case N_DHCP4_OPTION_END:
-                return N_DHCP4_E_INTERNAL;
-        }
-
-        /* XXX: refuse to return options that were not requested */
-
-        return n_dhcp4_incoming_query(lease->message, option, datap, n_datap);
-}
-
-/**
- * n_dhcp4_client_lease_select() - select an offered lease
- * @lease:                      lease to operate on
- *
- * Select a lease. This must be a lease that was offered, once
- * one of the leases that were offered in response to a probe was
- * selected none of the others can be.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_lease_select(NDhcp4ClientLease *lease) {
-        NDhcp4ClientLease *l, *t_l;
-        NDhcp4ClientProbe *probe;
-        int r;
-
-        /* XXX error handling, this must be an OFFER */
-
-        if (!lease->probe)
-                return -ENOTRECOVERABLE;
-        if (lease->probe->current_lease)
-                return -ENOTRECOVERABLE;
-
-        r = n_dhcp4_client_probe_transition_select(lease->probe, lease->message, n_dhcp4_gettime(CLOCK_BOOTTIME));
-        if (r)
-                return r;
-
-        /*
-         * Only one of the offered leases can be selected, so flush the list.
-         * All offered lease, including this one are now dead.
-         */
-        probe = lease->probe;
-        c_list_for_each_entry_safe(l, t_l, &probe->lease_list, probe_link)
-                n_dhcp4_client_lease_unlink(l);
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_lease_accept() - accept an ack'ed lease
- * @lease:                      lease to operate on
- *
- * Accept a lease. This must be a lease that was ack'ed by the
- * server.
- *
- * The offered IP address must be fully configured before the lease
- * can be accepted.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_lease_accept(NDhcp4ClientLease *lease) {
-        int r;
-
-        /* XXX error handling, this must be an ACK */
-
-        if (!lease->probe)
-                return -ENOTRECOVERABLE;
-        if (lease->probe->current_lease != lease)
-                return -ENOTRECOVERABLE;
-
-        r = n_dhcp4_client_probe_transition_accept(lease->probe, lease->message);
-        if (r)
-                return r;
-
-        n_dhcp4_client_lease_unlink(lease);
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_lease_decline() - decline an ack'ed lease
- * @lease:                      lease to operate on
- *
- * Decline a lease. This must be a lease that was ack'ed by the
- * server.
- *
- * The offered IP address must not be used once the lease has been
- * decline.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_lease_decline(NDhcp4ClientLease *lease, const char *error) {
-        int r;
-
-        /* XXX: error handling, this must be an ACK */
-
-        if (!lease->probe)
-                return -ENOTRECOVERABLE;
-        if (lease->probe->current_lease != lease)
-                return -ENOTRECOVERABLE;
-
-        r = n_dhcp4_client_probe_transition_decline(lease->probe, lease->message, error, n_dhcp4_gettime(CLOCK_BOOTTIME));
-        if (r)
-                return r;
-
-        lease->probe->current_lease = n_dhcp4_client_lease_unref(lease->probe->current_lease);
-        n_dhcp4_client_lease_unlink(lease);
-
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-probe.c b/shared/n-dhcp4/src/n-dhcp4-c-probe.c
deleted file mode 100644
index 7f20ac05..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-c-probe.c
+++ /dev/null
@@ -1,1294 +0,0 @@
-/*
- * DHCPv4 Client Probes
- *
- * The probe object is used to represent the lifetime of a DHCP client session.
- * A running probe discovers DHCP servers, requests a lease, and maintains that
- * lease.
- */
-
-#include <assert.h>
-#include <c-list.h>
-#include <c-siphash.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/auxv.h>
-#include "n-dhcp4.h"
-#include "n-dhcp4-private.h"
-
-
-static int n_dhcp4_client_probe_option_new(NDhcp4ClientProbeOption **optionp,
-                                    uint8_t option,
-                                    const void *data,
-                                    uint8_t n_data) {
-        NDhcp4ClientProbeOption *op;
-
-        op = malloc(sizeof(*op) + n_data);
-        if (!op)
-                return -ENOMEM;
-
-        op->option = option;
-        op->n_data = n_data;
-        memcpy(op->data, data, n_data);
-
-        *optionp = op;
-        return 0;
-}
-
-static void n_dhcp4_client_probe_option_free(NDhcp4ClientProbeOption *option) {
-        if (option)
-                free(option);
-}
-
-/**
- * n_dhcp4_client_probe_config_new() - create new probe configuration
- * @configp:                    output argument to store new configuration
- *
- * This creates a new probe configuration object. The object is a collection of
- * parameters for probes. No data verification is done by the configuration
- * object. Instead, when passing the configuration to the constructor of a
- * probe, this constructor will perform parameter validation.
- *
- * A probe configuration is an unlinked object only used to pass information to
- * a probe constructor. The caller fully owns the returned configuration object
- * and is responsible to free it when no longer needed.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_probe_config_new(NDhcp4ClientProbeConfig **configp) {
-        _c_cleanup_(n_dhcp4_client_probe_config_freep) NDhcp4ClientProbeConfig *config = NULL;
-
-        config = calloc(1, sizeof(*config));
-        if (!config)
-                return -ENOMEM;
-
-        *config = (NDhcp4ClientProbeConfig)N_DHCP4_CLIENT_PROBE_CONFIG_NULL(*config);
-
-        *configp = config;
-        config = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_config_free() - destroy probe configuration
- * @config:                     configuration to operate on, or NULL
- *
- * This destroys a probe configuration object and deallocates all its
- * resources.
- *
- * If @config is NULL, this is a no-op.
- *
- * Return: NULL is returned.
- */
-_c_public_ NDhcp4ClientProbeConfig *n_dhcp4_client_probe_config_free(NDhcp4ClientProbeConfig *config) {
-        if (!config)
-                return NULL;
-
-        for (unsigned int i = 0; i <= UINT8_MAX; ++i)
-                n_dhcp4_client_probe_option_free(config->options[i]);
-
-        free(config);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_probe_config_dup() - duplicate probe configuration
- * @config:                     configuration to operate on
- * @dupp:                       output argument for duplicate
- *
- * This duplicates the probe configuration given as @config and returns it in
- * @dupp to the caller.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_client_probe_config_dup(NDhcp4ClientProbeConfig *config,
-                                    NDhcp4ClientProbeConfig **dupp) {
-        _c_cleanup_(n_dhcp4_client_probe_config_freep) NDhcp4ClientProbeConfig *dup = NULL;
-        int r;
-
-        r = n_dhcp4_client_probe_config_new(&dup);
-        if (r)
-                return r;
-
-        dup->inform_only = config->inform_only;
-        dup->init_reboot = config->init_reboot;
-        dup->requested_ip = config->requested_ip;
-        dup->ms_start_delay = config->ms_start_delay;
-
-        for (unsigned int i = 0; i < config->n_request_parameters; ++i)
-                dup->request_parameters[dup->n_request_parameters++] = config->request_parameters[i];
-
-        for (unsigned int i = 0; i <= UINT8_MAX; ++i) {
-                if (!config->options[i])
-                        break;
-
-                r = n_dhcp4_client_probe_option_new(&dup->options[i],
-                                                    config->options[i]->option,
-                                                    config->options[i]->data,
-                                                    config->options[i]->n_data);
-                if (r)
-                        return r;
-        }
-
-        *dupp = dup;
-        dup = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_config_set_inform_only() - set inform-only property
- * @config:                     configuration to operate on
- * @inform_only:                value to set
- *
- * This sets the inform-only property of the given configuration object. This
- * property controls whether the client probe should request a full lease, or
- * whether it should just ask for auxiliary information without requesting an
- * address.
- *
- * The default is to request a full lease and address. If inform-only is set to
- * true, only auxiliary information will be requested.
- *
- * XXX: This is currently not implemented, and setting the property has no effect.
- */
-_c_public_ void n_dhcp4_client_probe_config_set_inform_only(NDhcp4ClientProbeConfig *config, bool inform_only) {
-        config->inform_only = inform_only;
-}
-
-/**
- * n_dhcp4_client_probe_config_set_init_reboot() - set init-reboot property
- * @config:                     configuration to operate on
- * @init_reboot:                value to set
- *
- * This sets the init-reboot property of the given configuration object. If this
- * is enabled, a requested IP address must also be set.
- *
- * The default is false. If set to true, a probe will make use of the
- * INIT-REBOOT path, as described by the DHCP specification. In most cases, you
- * do not want this.
- *
- * Background: The INIT-REBOOT path allows a DHCP client to skip
- *             server-discovery when rebooting/resuming their machine. The DHCP
- *             client simply re-requests the lease it had acquired before. This
- *             saves one roundtrip in the success-case, since the DISCOVER step
- *             is skipped. However, there are little to no timeouts involved,
- *             so the roundtrip should be barely noticeable. In contrast, if
- *             the INIT-REBOOT fails (because the lease is no longer valid, or
- *             not valid on this network), the client has to wait for a
- *             possible answer to the request before actually starting the DHCP
- *             process all over. This significantly increases the time needed
- *             to switch networks.
- *             The INIT-REBOOT state might have been a real improvements with
- *             the old resend-timeouts mandated by the DHCP specification.
- *             However, on modern networks with improved timeout values we
- *             recommend against using it.
- */
-_c_public_ void n_dhcp4_client_probe_config_set_init_reboot(NDhcp4ClientProbeConfig *config, bool init_reboot) {
-        config->init_reboot = init_reboot;
-}
-
-/**
- * n_dhcp4_client_probe_config_set_requested_ip() - set requested-ip property
- * @config:                     configuration to operate on
- * @ip:                         value to set
- *
- * This sets the requested-ip property of the given configuration object.
- *
- * The default is all 0. If set to something else, the DHCP discovery will
- * include this IP in its requests to tell DHCP servers which address to pick.
- * Servers are not required to honor this, nor does this have any effect on
- * servers not serving this address.
- *
- * This field should always be set if the caller knows of an address that was
- * previously acquired on this network. It serves as hint to servers and will
- * allow them to provide the same address again.
- */
-_c_public_ void n_dhcp4_client_probe_config_set_requested_ip(NDhcp4ClientProbeConfig *config, struct in_addr ip) {
-        config->requested_ip = ip;
-}
-
-/**
- * n_dhcp4_client_probe_config_set_start_delay() - set start delay
- * @config:                     configuration to operate on
- * @msecs:                      value to set
- *
- * This sets the start delay property of the given configuration object.
- *
- * The default is 9000 ms, which is based on RFC2131. In the RFC the start
- * delay is specified to be a random value in the range 1000 to 10.000 ms.
- * However, there does not appear to be any particular reason to
- * unconditionally wait at least one second, so we move the range down to
- * start at 0 ms. The reason for the random delay is to avoid network-wide
- * events causing too much simultaneous network traffic. However, on modern
- * networks, a more reasonable value may be in the 10 ms range.
- */
-_c_public_ void n_dhcp4_client_probe_config_set_start_delay(NDhcp4ClientProbeConfig *config, uint64_t msecs) {
-        config->ms_start_delay = msecs;
-}
-
-/**
- * n_dhpc4_client_probe_config_request_option() - append option to request from the server
- * @config:                     configuration to operate on
- * @option:                     option to request
- *
- * This adds an option to the list of options to request from the server.
- *
- * A server may send options that we do not request, and it may omit options
- * that we do request. However, to increase the likelyhood of uniform behavior
- * between server implementations, we do not expose options that were not
- * explicitly requested.
- *
- * When called multiple times, the order matters. Earlier requests are
- * considered higher priority than later requests, in case the server must omit
- * some, due to a lack of space. If the same option is requested more than once,
- * only the first call has an effect.
- */
-_c_public_ void n_dhcp4_client_probe_config_request_option(NDhcp4ClientProbeConfig *config, uint8_t option) {
-        for (unsigned int i = 0; i < config->n_request_parameters; ++i) {
-                if (config->request_parameters[i] == option)
-                        return;
-        }
-
-        c_assert(config->n_request_parameters <= UINT8_MAX);
-
-        config->request_parameters[config->n_request_parameters++] = option;
-}
-
-/**
- * n_dhcp4_client_probe_config_append_option() - append option to outgoing messages
- * @config:                     configuration to operate on
- * @option:                     DHCP option number
- * @data:                       payload
- * @n_data:                     number of bytes in payload
- *
- * This sets extra options on a given configuration object.
- *
- * These options are appended verbatim to outgoing messages where
- * that is supported by the specification. The same options are
- * appended to all messages.
- *
- * No option may be appended more than once. Options considered internal
- * to the DHCP protocol may not be appended.
- *
- * Return: 0 on success, N_DHCP4_E_DUPLICATE_OPTION if an option has already been
- *         appended, N_DHCP4_E_INTERNAL if the option is not configurable, or
- *         a negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_probe_config_append_option(NDhcp4ClientProbeConfig *config,
-                                                       uint8_t option,
-                                                       const void *data,
-                                                       uint8_t n_data) {
-        int r;
-
-        /* XXX: filter internal options */
-
-        for (unsigned int i = 0; i <= UINT8_MAX; ++i) {
-                if (config->options[i]) {
-                        if (config->options[i]->option == option)
-                                return N_DHCP4_E_DUPLICATE_OPTION;
-
-                        continue;
-                }
-
-                r = n_dhcp4_client_probe_option_new(&config->options[i],
-                                                    option,
-                                                    data,
-                                                    n_data);
-                if (r)
-                        return r;
-
-                return 0;
-        }
-
-        c_assert(0);
-        return -ENOTRECOVERABLE;
-}
-
-static void n_dhcp4_client_probe_config_initialize_random_seed(NDhcp4ClientProbeConfig *config) {
-        uint8_t hash_seed[] = {
-                0x25, 0x3f, 0x02, 0x75, 0x3a, 0xb8, 0x4f, 0x91,
-                0x9d, 0x0a, 0xd6, 0x15, 0x9d, 0x72, 0x7b, 0xcb,
-        };
-        CSipHash hash = C_SIPHASH_NULL;
-        unsigned short int seed16v[3];
-        const uint8_t *p;
-        uint64_t u64;
-
-        /*
-         * Initialize config's entropy buffer for successive jrand48(3) calls.
-         *
-         * We need random jitter for all timeouts and delays, used to reduce
-         * network traffic during bursts. This is not meant as security measure
-         * but only meant to improve network utilization during bursts. The
-         * random source is thus negligible. However, we want, under all
-         * circumstances, avoid two instances running with the same seed. Thus
-         * we source the seed from AT_RANDOM, which grants us a per-process
-         * unique seed. We then add the current time to make sure consequetive
-         * instances use different seeds (to avoid clashes if processes are
-         * duplicated, or similar), and lastly we add the config memory address
-         * to avoid clashes of multiple parallel instances.
-         *
-         * Again, none of these are meant as security measure, but only to
-         * avoid *ACCIDENTAL* seed clashes. That is, in the case that many
-         * transactions are started in parallel, we delay the individual
-         * messages (as described in the spec), to reduce the traffic on the
-         * network and the chance of packets being dropped (and thus triggering
-         * timeouts and resends).
-         *
-         * We hash everything through SipHash, to avoid exposing AT_RANDOM and
-         * other sources to the network. We use a static salt to distinguish it
-         * from other implementations using the same random source.
-         */
-        c_siphash_init(&hash, hash_seed);
-
-        p = (const uint8_t *)getauxval(AT_RANDOM);
-        if (p)
-                c_siphash_append(&hash, p, 16);
-
-        u64 = n_dhcp4_gettime(CLOCK_MONOTONIC);
-        c_siphash_append(&hash, (const uint8_t *)&u64, sizeof(u64));
-
-        c_siphash_append(&hash, (const uint8_t *)&config, sizeof(config));
-
-        u64 = c_siphash_finalize(&hash);
-
-        seed16v[0] = (u64 >>  0) ^ (u64 >> 48);
-        seed16v[1] = (u64 >> 16) ^ (u64 >>  0);
-        seed16v[2] = (u64 >> 32) ^ (u64 >> 16);
-
-        memcpy(config->entropy, seed16v, sizeof(seed16v));
-}
-
-/**
- * n_dhcp4_client_probe_config_get_random() - get random data
- * @config:                     config object to operate on
- *
- * Fetch the next 32bit random number from the entropy pool in @config.
- * Note that this is in no way suitable for security purposes.
- *
- * Return: the random data.
- */
-uint32_t n_dhcp4_client_probe_config_get_random(NDhcp4ClientProbeConfig *config) {
-        return jrand48(config->entropy);
-};
-
-/**
- * n_dhcp4_client_probe_new() - create new client probe
- * @probep:                     output argument for new client probe
- * @config:                     probe configuration
- * @client:                     client to probe on behalf of
- * @ns_now:                     the current time
- *
- * This creates a new client probe object.
- *
- * If one is already running, the new one will be immediately (but asynchronously)
- * cancelled. Otherwise, a DISCOVER event is scheduled after a randomized delay.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int n_dhcp4_client_probe_new(NDhcp4ClientProbe **probep,
-                             NDhcp4ClientProbeConfig *config,
-                             NDhcp4Client *client,
-                             uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_client_probe_freep) NDhcp4ClientProbe *probe = NULL;
-        bool active;
-        int r;
-
-        /*
-         * If there is already a probe attached, we create the new probe in
-         * detached state. It will not be linked into the epoll context and not
-         * be useful in any way. We immediately raise the CANCELLED event to
-         * notify the caller about it.
-         */
-        active = !client->current_probe;
-
-        probe = calloc(1, sizeof(*probe));
-        if (!probe)
-                return -ENOMEM;
-
-        *probe = (NDhcp4ClientProbe)N_DHCP4_CLIENT_PROBE_NULL(*probe);
-        probe->client = n_dhcp4_client_ref(client);
-
-        r = n_dhcp4_client_probe_config_dup(config, &probe->config);
-        if (r)
-                return r;
-
-        /*
-         * XXX: make seed initialization optional, so the entropy can be reused.
-         */
-        n_dhcp4_client_probe_config_initialize_random_seed(probe->config);
-
-        /* The new probe keeps a reference on @client. So we are sure that &client->log_queue
-         * stays alive as long as we need it. */
-
-        r = n_dhcp4_c_connection_init(&probe->connection,
-                                      client->config,
-                                      probe->config,
-                                      &client->log_queue,
-                                      active ? client->fd_epoll : -1);
-        if (r)
-                return r;
-
-        if (probe->config->requested_ip.s_addr != INADDR_ANY)
-                probe->last_address = probe->config->requested_ip;
-
-        if (probe->config->init_reboot && probe->last_address.s_addr != INADDR_ANY)
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT;
-        else
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
-
-        if (active) {
-                /*
-                 * Defer the sending of DISCOVER by a random amount (by default up to 9 seconds).
-                 */
-                if (probe->state == N_DHCP4_CLIENT_PROBE_STATE_INIT)
-                        probe->ns_deferred = ns_now + (n_dhcp4_client_probe_config_get_random(probe->config) % (probe->config->ms_start_delay * 1000000ULL));
-                probe->client->current_probe = probe;
-        } else {
-                r = n_dhcp4_client_probe_raise(probe,
-                                               NULL,
-                                               N_DHCP4_CLIENT_EVENT_CANCELLED);
-                if (r)
-                        return r;
-        }
-
-        *probep = probe;
-        probe = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_free() - destroy a probe
- * @probe:                      probe to operate on, or NULL
- *
- * This destroys a probe object and deallocates all its resources.
- *
- * If @probe is NULL, this is a no-op.
- *
- * Return: NULL is returned.
- */
-_c_public_ NDhcp4ClientProbe *n_dhcp4_client_probe_free(NDhcp4ClientProbe *probe) {
-        NDhcp4CEventNode *node, *t_node;
-        NDhcp4ClientLease *lease, *t_lease;
-
-        if (!probe)
-                return NULL;
-
-        c_list_for_each_entry_safe(lease, t_lease, &probe->lease_list, probe_link)
-                n_dhcp4_client_lease_unlink(lease);
-
-        c_list_for_each_entry_safe(node, t_node, &probe->event_list, probe_link)
-                n_dhcp4_c_event_node_free(node);
-
-        if (probe == probe->client->current_probe)
-                probe->client->current_probe = NULL;
-
-        n_dhcp4_client_lease_unref(probe->current_lease);
-        n_dhcp4_c_connection_deinit(&probe->connection);
-        n_dhcp4_client_unref(probe->client);
-        n_dhcp4_client_probe_config_free(probe->config);
-
-        c_assert(c_list_is_empty(&probe->lease_list));
-        c_assert(c_list_is_empty(&probe->event_list));
-        free(probe);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_probe_set_userdata() - set userdata pointer
- * @probe:                      the probe to operate on
- * @userdata:                   pointer to userdata
- *
- * Set a userdata pointer. The pointed to data is still owned by the caller, and
- * is completely opaque to the probe.
- */
-_c_public_ void n_dhcp4_client_probe_set_userdata(NDhcp4ClientProbe *probe, void *userdata) {
-        probe->userdata = userdata;
-}
-
-/**
- * n_dhcp4_client_probe_get_userdata() - get userdata pointer
- * @probe:                      the probe to operate on
- * @userdatap:                  return pointer for userdata pointer
- *
- * Get the userdata pointer. The lifetime of the userdata and making sure it is
- * still valid when accessed via the probe is the responsibility of the caller.
- */
-_c_public_ void n_dhcp4_client_probe_get_userdata(NDhcp4ClientProbe *probe, void **userdatap) {
-        *userdatap = probe->userdata;
-}
-
-/**
- * n_dhcp4_client_probe_raise() - XXX
- */
-int n_dhcp4_client_probe_raise(NDhcp4ClientProbe *probe, NDhcp4CEventNode **nodep, unsigned int event) {
-        NDhcp4CEventNode *node;
-        int r;
-
-        r = n_dhcp4_client_raise(probe->client, &node, event);
-        if (r)
-                return r;
-
-        switch (event) {
-        case N_DHCP4_CLIENT_EVENT_OFFER:
-                node->event.offer.probe = probe;
-                break;
-        case N_DHCP4_CLIENT_EVENT_GRANTED:
-                node->event.granted.probe = probe;
-                break;
-        case N_DHCP4_CLIENT_EVENT_RETRACTED:
-                node->event.retracted.probe = probe;
-                break;
-        case N_DHCP4_CLIENT_EVENT_EXTENDED:
-                node->event.extended.probe = probe;
-                break;
-        case N_DHCP4_CLIENT_EVENT_EXPIRED:
-                node->event.expired.probe = probe;
-                break;
-        case N_DHCP4_CLIENT_EVENT_CANCELLED:
-                node->event.cancelled.probe = probe;
-                break;
-        default:
-                c_assert(0);
-                n_dhcp4_c_event_node_free(node);
-                return -ENOTRECOVERABLE;
-        }
-
-        if (nodep)
-                *nodep = node;
-        return 0;
-}
-
-void n_dhcp4_client_probe_get_timeout(NDhcp4ClientProbe *probe, uint64_t *timeoutp) {
-        uint64_t t1 = 0;
-        uint64_t t2 = 0;
-        uint64_t lifetime = 0;
-        uint64_t timeout = 0;
-
-        if (probe->current_lease) {
-                t1 = probe->current_lease->t1;
-                t2 = probe->current_lease->t2;
-                lifetime = probe->current_lease->lifetime;
-        }
-
-        n_dhcp4_c_connection_get_timeout(&probe->connection, &timeout);
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-                /* send DHCP request immediately */
-                timeout = 1;
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-                if (probe->ns_reinit && (!timeout || probe->ns_reinit < timeout))
-                        timeout = probe->ns_reinit;
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-                if (probe->ns_deferred && (!timeout || probe->ns_deferred < timeout))
-                        timeout = probe->ns_deferred;
-
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-                if (t1 && (!timeout || t1 < timeout))
-                        timeout = t1;
-
-                /* fall-through */
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-                if (t2 && (!timeout || t2 < timeout))
-                        timeout = t2;
-
-                /* fall-through */
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-                if (lifetime && (!timeout || lifetime < timeout))
-                        timeout = lifetime;
-                break;
-        default:
-                /* ignore */
-                break;
-        }
-
-        *timeoutp = timeout;
-}
-
-static int n_dhcp4_client_probe_outgoing_append_options(NDhcp4ClientProbe *probe, NDhcp4Outgoing *outgoing) {
-        int r;
-
-        for (unsigned int i = 0; i <= UINT8_MAX; ++i) {
-                if (!probe->config->options[i])
-                        break;
-
-                r = n_dhcp4_outgoing_append(outgoing,
-                                            probe->config->options[i]->option,
-                                            probe->config->options[i]->data,
-                                            probe->config->options[i]->n_data);
-                if (r) {
-                        if (r == N_DHCP4_E_NO_SPACE)
-                                /* XXX */
-                                break;
-
-                        return r;
-                }
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_reboot(NDhcp4ClientProbe *probe, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-                r = n_dhcp4_c_connection_listen(&probe->connection);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_reboot_new(&probe->connection, &request, &probe->last_address);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_REBOOTING;
-                probe->ns_reinit = ns_now + 2000000000ULL;
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                abort();
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-                r = n_dhcp4_c_connection_listen(&probe->connection);
-                if (r)
-                        return r;
-                /* fall-through */
-
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-                r = n_dhcp4_c_connection_discover_new(&probe->connection, &request);
-                if (r)
-                        return r;
-
-                if (probe->last_address.s_addr != INADDR_ANY) {
-                        r = n_dhcp4_outgoing_append_requested_ip(request, probe->last_address);
-                        if (r)
-                                return r;
-                }
-
-                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_SELECTING;
-                probe->ns_deferred = 0;
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                abort();
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_t1(NDhcp4ClientProbe *probe, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-                r = n_dhcp4_c_connection_renew_new(&probe->connection, &request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_RENEWING;
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                abort();
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_t2(NDhcp4ClientProbe *probe, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-                r = n_dhcp4_c_connection_listen(&probe->connection);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_rebind_new(&probe->connection, &request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_REBINDING;
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                abort();
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_lifetime(NDhcp4ClientProbe *probe) {
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-
-                /* XXX */
-
-                r = n_dhcp4_client_probe_raise(probe,
-                                               NULL,
-                                               N_DHCP4_CLIENT_EVENT_EXPIRED);
-                if (r)
-                        return r;
-
-                c_assert(probe->client->current_probe == probe);
-
-                probe->current_lease = n_dhcp4_client_lease_unref(probe->current_lease);
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
-                probe->ns_deferred =  n_dhcp4_gettime(CLOCK_BOOTTIME) + UINT64_C(1);
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                abort();
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_offer(NDhcp4ClientProbe *probe, NDhcp4Incoming *message_take) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = message_take;
-        _c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
-        NDhcp4CEventNode *node;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-
-                r = n_dhcp4_client_probe_raise(probe,
-                                               &node,
-                                               N_DHCP4_CLIENT_EVENT_OFFER);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_lease_new(&lease, message);
-                if (r)
-                        return r;
-
-                message = NULL; /* consumed */
-
-                n_dhcp4_client_lease_link(lease, probe);
-
-                node->event.offer.lease = n_dhcp4_client_lease_ref(lease);
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4Incoming *message_take) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = message_take;
-        _c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
-        NDhcp4CEventNode *node;
-        struct in_addr client = {};
-        struct in_addr server = {};
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-                n_dhcp4_incoming_get_yiaddr(message, &client);
-
-                r = n_dhcp4_incoming_query_server_identifier(message, &server);
-                if (r)
-                        return r;
-                r = n_dhcp4_c_connection_connect(&probe->connection, &client, &server);
-                if (r)
-                        return r;
-                /* fall-through */
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-
-                r = n_dhcp4_client_probe_raise(probe,
-                                               &node,
-                                               N_DHCP4_CLIENT_EVENT_EXTENDED);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_lease_new(&lease, message);
-                if (r)
-                        return r;
-
-                message = NULL; /* consumed */
-
-                n_dhcp4_client_lease_link(lease, probe);
-
-                node->event.extended.lease = n_dhcp4_client_lease_ref(lease);
-                n_dhcp4_client_lease_unref(probe->current_lease);
-                probe->current_lease = n_dhcp4_client_lease_ref(lease);
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_BOUND;
-                n_dhcp4_client_lease_get_yiaddr(lease, &probe->last_address);
-                probe->ns_nak_restart_delay = 0;
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-
-                r = n_dhcp4_client_probe_raise(probe,
-                                               &node,
-                                               N_DHCP4_CLIENT_EVENT_GRANTED);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_lease_new(&lease, message);
-                if (r)
-                        return r;
-
-                message = NULL; /* consumed */
-
-                n_dhcp4_client_lease_link(lease, probe);
-
-                node->event.granted.lease = n_dhcp4_client_lease_ref(lease);
-                probe->current_lease = n_dhcp4_client_lease_ref(lease);
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_GRANTED;
-                probe->ns_nak_restart_delay = 0;
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_probe_transition_nak(NDhcp4ClientProbe *probe) {
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-
-                /* XXX */
-
-                r = n_dhcp4_client_probe_raise(probe,
-                                               NULL,
-                                               N_DHCP4_CLIENT_EVENT_RETRACTED);
-                if (r)
-                        return r;
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
-                probe->ns_deferred = n_dhcp4_gettime(CLOCK_BOOTTIME) + probe->ns_nak_restart_delay;
-                probe->ns_nak_restart_delay = C_CLAMP(probe->ns_nak_restart_delay * 2u,
-                                                      UINT64_C(2)   * UINT64_C(1000000000),
-                                                      UINT64_C(300) * UINT64_C(1000000000));
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-                r = n_dhcp4_c_connection_select_new(&probe->connection, &request, offer);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                /* XXX: ignore other offers */
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_REQUESTING;
-
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_transition_accept() - XXX
- */
-int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incoming *ack) {
-        struct in_addr client = {};
-        struct in_addr server = {};
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-                n_dhcp4_incoming_get_yiaddr(ack, &client);
-
-                r = n_dhcp4_incoming_query_server_identifier(ack, &server);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_connect(&probe->connection, &client, &server);
-                if (r)
-                        return r;
-
-                probe->state = N_DHCP4_CLIENT_PROBE_STATE_BOUND;
-
-                n_dhcp4_client_arm_timer(probe->client);
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-/**
- * n_dhc4_client_probe_transition_decline() - XXX
- */
-int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, const char *error, uint64_t ns_now) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-                r = n_dhcp4_c_connection_decline_new(&probe->connection, &request, offer, error);
-                if (r)
-                        return r;
-
-                r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
-                if (r)
-                        return r;
-                else
-                        request = NULL; /* consumed */
-
-                /* XXX: what state to transition to? */
-
-                break;
-
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-        case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
-        default:
-                /* ignore */
-                break;
-        }
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_dispatch_timer() - XXX
- */
-int n_dhcp4_client_probe_dispatch_timer(NDhcp4ClientProbe *probe, uint64_t ns_now) {
-        int r;
-
-        switch (probe->state) {
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
-                r = n_dhcp4_client_probe_transition_reboot(probe, ns_now);
-                if (r)
-                        return r;
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
-                if (ns_now >= probe->ns_reinit) {
-                        r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
-                        if (r)
-                                return r;
-                }
-
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_INIT:
-                if (ns_now >= probe->ns_deferred) {
-                        r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
-                        if (r)
-                                return r;
-                }
-
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
-                if (ns_now >= probe->current_lease->lifetime) {
-                        r = n_dhcp4_client_probe_transition_lifetime(probe);
-                        if (r)
-                                return r;
-                }
-
-                break;
-        case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
-        case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
-        case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
-                if (ns_now >= probe->current_lease->lifetime) {
-                        r = n_dhcp4_client_probe_transition_lifetime(probe);
-                        if (r)
-                                return r;
-                } else if (ns_now >= probe->current_lease->t2 &&
-                           probe->state != N_DHCP4_CLIENT_PROBE_STATE_REBINDING) {
-                        r = n_dhcp4_client_probe_transition_t2(probe, ns_now);
-                        if (r)
-                                return r;
-                } else if (ns_now >= probe->current_lease->t1 &&
-                           probe->state == N_DHCP4_CLIENT_PROBE_STATE_BOUND) {
-                        r = n_dhcp4_client_probe_transition_t1(probe, ns_now);
-                        if (r)
-                                return r;
-                }
-                break;
-        default:
-                /* ignore */
-                break;
-        }
-
-        r = n_dhcp4_c_connection_dispatch_timer(&probe->connection, ns_now);
-        if (r)
-                return r;
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_dispatch_connection() - XXX
- */
-int n_dhcp4_client_probe_dispatch_io(NDhcp4ClientProbe *probe, uint32_t events) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
-        uint8_t type;
-        int r;
-
-        r = n_dhcp4_c_connection_dispatch_io(&probe->connection, &message);
-        if (r) {
-                if (r == N_DHCP4_E_AGAIN)
-                        return 0;
-                else if (r == N_DHCP4_E_MALFORMED || r == N_DHCP4_E_UNEXPECTED) {
-                        /*
-                         * We fetched something from the sockets, which we
-                         * discarded. We don't know whether there is more data
-                         * to fetch, so we set the preempted flag to notify the
-                         * caller we want to be called again.
-                         */
-                        probe->client->preempted = true;
-                        return 0;
-                }
-
-                abort();
-                return r;
-        }
-
-        /*
-         * We fetched something from the sockets, which we will handle below.
-         * We don't know whether there is more data to fetch, so we set the
-         * preempted flag to notify the caller we want to be called again.
-         */
-        probe->client->preempted = true;
-
-        r = n_dhcp4_incoming_query_message_type(message, &type);
-        if (r == N_DHCP4_E_UNSET || r == N_DHCP4_E_MALFORMED)
-                /*
-                 * XXX: this can never happen as we already queried the message
-                 * type.
-                 */
-                return 0;
-
-        switch (type) {
-        case N_DHCP4_MESSAGE_OFFER:
-                r = n_dhcp4_client_probe_transition_offer(probe, message);
-                message = NULL; /* consumed */
-                if (r)
-                        return r;
-                break;
-        case N_DHCP4_MESSAGE_ACK:
-                r = n_dhcp4_client_probe_transition_ack(probe, message);
-                message = NULL; /* consumed */
-                if (r)
-                        return r;
-                break;
-        case N_DHCP4_MESSAGE_NAK:
-                r = n_dhcp4_client_probe_transition_nak(probe);
-                if (r)
-                        return r;
-                break;
-        default:
-                /*
-                 * We receiveda message type we do not support, simply discard
-                 * it.
-                 */
-                break;
-        }
-
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe_update_mtu() - XXX
- */
-int n_dhcp4_client_probe_update_mtu(NDhcp4ClientProbe *probe, uint16_t mtu) {
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-client.c b/shared/n-dhcp4/src/n-dhcp4-client.c
deleted file mode 100644
index 1dedbf30..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-client.c
+++ /dev/null
@@ -1,990 +0,0 @@
-/*
- * Client Side of the Dynamic Host Configuration Protocol for IPv4
- *
- * This implements the public API around the NDhcp4Client object. The client
- * object is simply a context to track running probes. It manages pending
- * events of all probes, as well as forwards the dispatching requests whenever
- * the dispatcher is run.
- */
-
-#include <assert.h>
-#include <c-list.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <linux/if_ether.h>
-#include <linux/if_infiniband.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/time.h>
-#include <sys/timerfd.h>
-#include <time.h>
-#include <unistd.h>
-#include "n-dhcp4.h"
-#include "n-dhcp4-private.h"
-
-/**
- * n_dhcp4_client_config_new() - allocate new client configuration
- * @configp:                    output argument for new client config
- *
- * This creates a new client configuration object. Client configurations are
- * unlinked objects that merely serve as collection of parameters. They do not
- * perform validity checks.
- *
- * The new client configuration is fully owned by the caller. They are
- * responsible to free the object if no longer needed.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_config_new(NDhcp4ClientConfig **configp) {
-        _c_cleanup_(n_dhcp4_client_config_freep) NDhcp4ClientConfig *config = NULL;
-
-        config = calloc(1, sizeof(*config));
-        if (!config)
-                return -ENOMEM;
-
-        *config = (NDhcp4ClientConfig)N_DHCP4_CLIENT_CONFIG_NULL(*config);
-
-        *configp = config;
-        config = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_config_free() - destroy client configuration
- * @config:                     client configuration to operate on, or NULL
- *
- * This destroys a client configuration and deallocates all its resources. If
- * NULL is passed, this is a no-op.
- *
- * Return: NULL is returned.
- */
-_c_public_ NDhcp4ClientConfig *n_dhcp4_client_config_free(NDhcp4ClientConfig *config) {
-        if (!config)
-                return NULL;
-
-        free(config->client_id);
-        free(config);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_config_dup() - duplicate client configuration
- * @config:                     client configuration to operate on
- * @dupp:                       output argument for duplicate
- *
- * This duplicates the client configuration given as @config and returns it in
- * @dupp to the caller.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_client_config_dup(NDhcp4ClientConfig *config, NDhcp4ClientConfig **dupp) {
-        _c_cleanup_(n_dhcp4_client_config_freep) NDhcp4ClientConfig *dup = NULL;
-        int r;
-
-        r = n_dhcp4_client_config_new(&dup);
-        if (r)
-                return r;
-
-        dup->ifindex = config->ifindex;
-        dup->transport = config->transport;
-        dup->request_broadcast = config->request_broadcast;
-        memcpy(dup->mac, config->mac, sizeof(dup->mac));
-        dup->n_mac = config->n_mac;
-        memcpy(dup->broadcast_mac, config->broadcast_mac, sizeof(dup->broadcast_mac));
-        dup->n_broadcast_mac = config->n_broadcast_mac;
-
-        r = n_dhcp4_client_config_set_client_id(dup,
-                                                config->client_id,
-                                                config->n_client_id);
-        if (r)
-                return r;
-
-        *dupp = dup;
-        dup = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_config_set_ifindex() - set ifindex property
- * @config:                     client configuration to operate on
- * @ifindex:                    ifindex to set
- *
- * This sets the ifindex property of the client configuration. The ifindex
- * specifies the network device that a DHCP client will run on.
- */
-_c_public_ void n_dhcp4_client_config_set_ifindex(NDhcp4ClientConfig *config, int ifindex) {
-        config->ifindex = ifindex;
-}
-
-/**
- * n_dhcp4_client_config_set_transport() - set transport property
- * @config:                     client configuration to operate on
- * @transport:                  transport to set
- *
- * This sets the transport property of the client configuration. The transport
- * defines the hardware transport of the network device that a DHCP client
- * runs on.
- *
- * This takes one of the N_DHCP4_TRANSPORT_* identifiers as argument.
- */
-_c_public_ void n_dhcp4_client_config_set_transport(NDhcp4ClientConfig *config, unsigned int transport) {
-        config->transport = transport;
-}
-
-/**
- * n_dhcp4_client_config_set_request_broadcast() - set request-broadcast property
- * @config:                           configuration to operate on
- * @request_broadcast:                value to set
- *
- * This sets the request_broadcast property of the given configuration object.
- *
- * The default is false. If set to true, a the server will be told to not unicast
- * replies to the client's IP address before it has been configured, but broadcast
- * to INADDR_ANY instead. In most cases, you do not want this.
- *
- * Background: OFFER and ACK messages from DHCP servers to clients are unicast
- *             to the IP address handed out, even before the IP address has
- *             been configured on the target interface. This usually works
- *             because the correct destination hardware address is explicitly
- *             set on the outgoing packets, rather than being resolved (which
- *             would not work). However, some hardware does not accept incoming
- *             IP packets destined for addresses they do not own, even if the
- *             hardware address is correct. In this case, the server must
- *             broadcast the replies in order for the client to receive them.
- *             In general, unnecessary broadcasting is something one wants to
- *             avoid, and some networks will not deliver broadcasts to the
- *             client at all, in which case this flag must not be set.
- */
-_c_public_ void n_dhcp4_client_config_set_request_broadcast(NDhcp4ClientConfig *config, bool request_broadcast) {
-        config->request_broadcast = request_broadcast;
-}
-
-/**
- * n_dhcp4_client_config_set_mac() - set mac property
- * @config:                     client configuration to operate on
- * @mac:                        hardware address to set
- * @n_mac:                      length of the hardware address
- *
- * This sets the mac property of the client configuration. It specifies the
- * hardware address of the local interface that the DHCP client runs on.
- *
- * This function copies the specified hardware address into @config. Any
- * hardware address is supported. It is up to the consumer of the client
- * configuration to verify the validity of the hardware address.
- *
- * Note: This function may truncate the hardware address internally, but
- *       retains the original length. The consumer of this configuration can
- *       thus tell whether the data was truncated and will refuse it.
- *       The internal buffer is big enough to hold any hardware address of all
- *       supported transports. Thus, truncation only happens if you use
- *       unsupported transports, and those will be rejected, anyway.
- */
-_c_public_ void n_dhcp4_client_config_set_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac) {
-        config->n_mac = n_mac;
-
-        if (n_mac > sizeof(config->mac))
-                n_mac = sizeof(config->mac);
-
-        memcpy(config->mac, mac, n_mac);
-}
-
-/**
- * n_dhcp4_client_config_set_broadcast_mac() - set broadcast-mac property
- * @config:                     client configuration to operate on
- * @mac:                        hardware address to set
- * @n_mac:                      length of the hardware address
- *
- * This sets the broadcast-mac property of the client configuration. It
- * specifies the destination hardware address to use for broadcasts on the
- * local interface that the DHCP client runs on.
- *
- * This function copies the specified hardware address into @config. Any
- * hardware address is supported. It is up to the consumer of the client
- * configuration to verify the validity of the hardware address.
- *
- * Note: This function may truncate the hardware address internally, but
- *       retains the original length. The consumer of this configuration can
- *       thus tell whether the data was truncated and will refuse it.
- *       The internal buffer is big enough to hold any hardware address of all
- *       supported transports. Thus, truncation only happens if you use
- *       unsupported transports, and those will be rejected, anyway.
- */
-_c_public_ void n_dhcp4_client_config_set_broadcast_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac) {
-        config->n_broadcast_mac = n_mac;
-
-        if (n_mac > sizeof(config->mac))
-                n_mac = sizeof(config->mac);
-
-        memcpy(config->broadcast_mac, mac, n_mac);
-}
-
-/**
- * n_dhcp4_client_config_set_client_id() - set client-id property
- * @config:                     client configuration to operate on
- * @id:                         client id
- * @n_id:                       length of the client id in bytes. The length
- *                              must be from 2 up to 255 bytes. Set it to 0
- *                              to unset the client-id.
- *
- * This sets the client-id property of @config. It copies the entire client-id
- * buffer into the configuration.
- * See RFC 2132 (section 9.14) for the format of the Client Identifier.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_config_set_client_id(NDhcp4ClientConfig *config, const uint8_t *id, size_t n_id) {
-        uint8_t *t;
-
-        if (n_id == 0) {
-                config->client_id = c_free(config->client_id);
-                config->n_client_id = 0;
-                return 0;
-        }
-
-        if (n_id < 2 || n_id > 255)
-                return -EINVAL;
-
-        t = malloc(n_id + 1);
-        if (!t)
-                return -ENOMEM;
-
-        memcpy(t, id, n_id);
-        t[n_id] = 0; /* safety 0 for debugging */
-
-        free(config->client_id);
-        config->client_id = t;
-        config->n_client_id = n_id;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_set_log_level() - set the logging level of the client
- * @client:                         the client to operate on
- * @level:                          the minimum syslog logging level that is
- *                                  still logged. For example, set to LOG_NOTICE
- *                                  to receive logging events with level LOG_NOTICE
- *                                  and higher. Set to -1 to disable generating
- *                                  logging events (which is also the default).
- *
- * By enabling logging, you can get N_DHCP4_CLIENT_EVENT_LOG events.
- *
- * From the logging event you may steal the message if (and only if) "allow_steal_message"
- * is true. In that case, clear the message field and free the message yourself.
- *
- * If a logging event cannot be logged due to out of memory, one message
- * gets logged that messages are missing. Until the event with that message
- * gets dropped, no further logging events will be queued.
- *
- * You may change the logging level at any time, but it does not affect
- * logging events that are already queued.
-  */
-_c_public_ void n_dhcp4_client_set_log_level(NDhcp4Client *client, int level) {
-        client->log_queue.log_level = level;
-}
-
-/**
- * n_dhcp4_c_event_node_new() - allocate new event
- * @nodep:                      output argument for new event
- *
- * This allocates a new event node and returns it to the caller. The caller
- * fully owns the event-node and is reposonsible to either link it somewhere,
- * or release it.
- *
- * Event nodes can be linked on a client object, as well as optionally on a
- * probe object. As long as an event-node is linked, it will be retrievable by
- * the API user through n_dhcp4_client_pop_event(). Furthermore, destruction of
- * the client, or probe respectively, will clean-up all pending events.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_c_event_node_new(NDhcp4CEventNode **nodep) {
-        NDhcp4CEventNode *node;
-
-        node = calloc(1, sizeof(*node));
-        if (!node)
-                return -ENOMEM;
-
-        *node = (NDhcp4CEventNode)N_DHCP4_C_EVENT_NODE_NULL(*node);
-
-        *nodep = node;
-        return 0;
-}
-
-/**
- * n_dhcp4_c_event_node_free() - deallocate event
- * @node:                       node to operate on, or NULL
- *
- * This deallocates the node given as @node. If the node is linked on a client
- * or probe, it is unlinked automatically.
- *
- * If @probe is NULL, this is a no-op.
- *
- * Return: NULL is returned.
- */
-NDhcp4CEventNode *n_dhcp4_c_event_node_free(NDhcp4CEventNode *node) {
-        if (!node)
-                return NULL;
-
-        switch (node->event.event) {
-        case N_DHCP4_CLIENT_EVENT_OFFER:
-                node->event.offer.lease = n_dhcp4_client_lease_unref(node->event.offer.lease);
-                break;
-        case N_DHCP4_CLIENT_EVENT_GRANTED:
-                node->event.granted.lease = n_dhcp4_client_lease_unref(node->event.granted.lease);
-                break;
-        case N_DHCP4_CLIENT_EVENT_EXTENDED:
-                node->event.extended.lease = n_dhcp4_client_lease_unref(node->event.extended.lease);
-                break;
-        case N_DHCP4_CLIENT_EVENT_LOG:
-                if (_c_unlikely_(!node->event.log.allow_steal_message)) {
-                        /* @node is the static node "nomem_node". It must not be
-                         * freed. */
-                        c_list_unlink(&node->client_link);
-                        node->is_public = false;
-                        return NULL;
-                }
-                node->event.log.message = c_free((char *)node->event.log.message);
-                break;
-        default:
-                break;
-        }
-
-        c_list_unlink(&node->probe_link);
-        c_list_unlink(&node->client_link);
-        free(node);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_new() - allocate new client
- * @clientp:                    output argument for new client
- * @config:                     configuration to use
- *
- * This allocates a new DHCP4 client object and returns it in @clientp to the
- * caller. The caller then owns a single ref-count to the object and is
- * responsible to drop it, when no longer needed.
- *
- * The configuration given as @config is used to initialize the client. The
- * caller is free to destroy the configuration once this function returns.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_new(NDhcp4Client **clientp, NDhcp4ClientConfig *config) {
-        _c_cleanup_(n_dhcp4_client_unrefp) NDhcp4Client *client = NULL;
-        struct epoll_event ev = {
-                .events = EPOLLIN,
-        };
-        int r;
-
-        c_assert(clientp);
-
-        /* verify configuration */
-        {
-                if (config->ifindex < 1)
-                        return N_DHCP4_E_INVALID_IFINDEX;
-
-                switch (config->transport) {
-                case N_DHCP4_TRANSPORT_ETHERNET:
-                        if (config->n_mac != ETH_ALEN ||
-                            config->n_broadcast_mac != ETH_ALEN)
-                                return N_DHCP4_E_INVALID_ADDRESS;
-
-                        break;
-                case N_DHCP4_TRANSPORT_INFINIBAND:
-                        if (config->n_mac != INFINIBAND_ALEN ||
-                            config->n_broadcast_mac != INFINIBAND_ALEN)
-                                return N_DHCP4_E_INVALID_ADDRESS;
-
-                        break;
-                default:
-                        return N_DHCP4_E_INVALID_TRANSPORT;
-                }
-
-                if (config->n_client_id < 1)
-                        return N_DHCP4_E_INVALID_CLIENT_ID;
-        }
-
-        client = malloc(sizeof(*client));
-        if (!client)
-                return -ENOMEM;
-
-        *client = (NDhcp4Client)N_DHCP4_CLIENT_NULL(*client);
-
-        r = n_dhcp4_client_config_dup(config, &client->config);
-        if (r)
-                return r;
-
-        client->fd_epoll = epoll_create1(EPOLL_CLOEXEC);
-        if (client->fd_epoll < 0)
-                return -errno;
-
-        client->fd_timer = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK);
-        if (client->fd_timer < 0 && errno == EINVAL)
-                client->fd_timer = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
-        if (client->fd_timer < 0)
-                return -errno;
-
-        ev.data.u32 = N_DHCP4_CLIENT_EPOLL_TIMER;
-        r = epoll_ctl(client->fd_epoll, EPOLL_CTL_ADD, client->fd_timer, &ev);
-        if (r < 0) {
-                close(client->fd_timer);
-                client->fd_timer = -1;
-                return -errno;
-        }
-
-        *clientp = client;
-        client = NULL;
-        return 0;
-}
-
-static void n_dhcp4_client_free(NDhcp4Client *client) {
-        NDhcp4CEventNode *node, *t_node;
-
-        c_assert(!client->current_probe);
-
-        c_list_for_each_entry_safe(node, t_node, &client->event_list, client_link)
-                n_dhcp4_c_event_node_free(node);
-
-        if (client->fd_timer >= 0) {
-                epoll_ctl(client->fd_epoll, EPOLL_CTL_DEL, client->fd_timer, NULL);
-                close(client->fd_timer);
-        }
-
-        if (client->fd_epoll >= 0)
-                close(client->fd_epoll);
-
-        n_dhcp4_client_config_free(client->config);
-        free(client);
-}
-
-/**
- * n_dhcp4_client_ref() - acquire client reference
- * @client:                     client to operate on, or NULL
- *
- * This acquires a reference to the client given as @client. If @client is
- * NULL, this function is a no-op.
- *
- * Return: @client is returned.
- */
-_c_public_ NDhcp4Client *n_dhcp4_client_ref(NDhcp4Client *client) {
-        if (client)
-                ++client->n_refs;
-        return client;
-}
-
-/**
- * n_dhcp4_client_unref() - release client reference
- * @client:                     client to operate on, or NULL
- *
- * This releases a reference to the client given as @client. If @client is
- * NULL, this is a no-op.
- *
- * Once the last reference is dropped, the client object will get destroyed and
- * deallocated.
- *
- * Return: NULL is returned.
- */
-_c_public_ NDhcp4Client *n_dhcp4_client_unref(NDhcp4Client *client) {
-        if (client && !--client->n_refs)
-                n_dhcp4_client_free(client);
-        return NULL;
-}
-
-/**
- * n_dhcp4_client_raise() - raise event
- * @client:                     client to operate on
- * @nodep:                      output argument for new event, or NULL
- * @event:                      event type to use
- *
- * This creates a new event-node on @client, setting the event-type to @event.
- * The newly created event-node is returned to the caller in @nodep (unless
- * @nodep is NULL).
- *
- * The event-node is automatically linked on @client.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int n_dhcp4_client_raise(NDhcp4Client *client, NDhcp4CEventNode **nodep, unsigned int event) {
-        NDhcp4CEventNode *node;
-        int r;
-
-        r = n_dhcp4_c_event_node_new(&node);
-        if (r)
-                return r;
-
-        node->event.event = event;
-        c_list_link_tail(&client->event_list, &node->client_link);
-
-        if (nodep)
-                *nodep = node;
-        return 0;
-}
-
-/**
- * n_dhcp4_log_queue_fmt() - add a logging event.
- * @client:                  the NDhcp4LogQueue to operate on
- * @level:                   the syslog logging level
- * @fmt:                     the format string for the message
- * @...                      printf arguments for logging
- *
- * Appends a logging event to the event queue if logging is
- * enabled and the logging level sufficiently high.
- *
- * Queuing a logging event might fail with out of memory.
- * In that case, a static event will be queued that informs
- * about lost messages.
- */
-void n_dhcp4_log_queue_fmt(NDhcp4LogQueue *log_queue,
-                           int level,
-                           const char *fmt,
-                           ...) {
-        NDhcp4CEventNode *node;
-        char *message;
-        va_list ap;
-        int r;
-
-        if (level > log_queue->log_level)
-                return;
-
-        /* Currently, the logging queue is only implemented for
-         * the client. Nobody would enable logging except a
-         * client instance. */
-        c_assert(log_queue->is_client);
-
-        if (!c_list_is_empty (&log_queue->nomem_node.client_link)) {
-                /* we have the nomem_node queued after a recent out
-                 * of memory. This disables all logging messages until
-                 * the event gets popped.
-                 *
-                 * The reason is that we can only queue the nomem_node once,
-                 * so if we now try to append another event and succeed, the
-                 * user wouldn't know which messages got dropped. Instead,
-                 * just drop them all!! */
-                return;
-        }
-
-        r = n_dhcp4_c_event_node_new(&node);
-        if (r < 0)
-                goto handle_nomem;
-
-        va_start(ap, fmt);
-        r = vasprintf(&message, fmt, ap);
-        va_end(ap);
-
-        if (r < 0) {
-                n_dhcp4_c_event_node_free(node);
-                goto handle_nomem;
-        }
-
-        node->event = (NDhcp4ClientEvent) {
-                .event = N_DHCP4_CLIENT_EVENT_LOG,
-                .log = {
-                        .level = level,
-                        .message = message,
-                        .allow_steal_message = true,
-                },
-        };
-
-        c_list_link_tail(log_queue->event_list, &node->client_link);
-        return;
-
-handle_nomem:
-        c_list_link_tail(log_queue->event_list, &log_queue->nomem_node.client_link);
-}
-
-/**
- * n_dhcp4_client_arm_timer() - update timer
- * @client:                     client to operate on
- *
- * This updates the timer on @client to fire on the next pending timeout. This
- * must be called whenever a timeout on @client might have changed.
- */
-void n_dhcp4_client_arm_timer(NDhcp4Client *client) {
-        uint64_t now, offset, timeout = 0;
-        int r;
-
-        if (client->current_probe)
-                n_dhcp4_client_probe_get_timeout(client->current_probe, &timeout);
-
-        if (timeout != client->scheduled_timeout) {
-                /*
-                 * Across our codebase, timeouts are specified as absolute
-                 * timestamps on CLOCK_BOOTTIME. Unfortunately, there are
-                 * systems with CLOCK_BOOTTIME support, but timerfd lacks it
-                 * (in particular RHEL). Therefore, our timerfd might be on
-                 * CLOCK_MONOTONIC.
-                 * To account for this, we always schedule a relative timeout.
-                 * We fetch the current time and then calculate the offset
-                 * which we then schedule as relative timeout on the timerfd.
-                 * This works regardless which clock the timerfd runs on.
-                 * Once we no longer support CLOCK_MONOTONIC as fallback, we
-                 * can simply switch to TFD_TIMER_ABSTIME here and specify
-                 * `timeout` directly as value.
-                 */
-                now = n_dhcp4_gettime(CLOCK_BOOTTIME);
-                if (now >= timeout)
-                        offset = 1; /* 0 would disarm the timerfd */
-                else
-                        offset = timeout - now;
-
-                r = timerfd_settime(client->fd_timer,
-                                    0,
-                                    &(struct itimerspec){
-                                        .it_value = {
-                                                .tv_sec = offset / UINT64_C(1000000000),
-                                                .tv_nsec = offset % UINT64_C(1000000000),
-                                        },
-                                    },
-                                    NULL);
-                c_assert(r >= 0);
-
-                client->scheduled_timeout = timeout;
-        }
-}
-
-/**
- * n_dhcp4_client_get_fd() - retrieve event FD
- * @client:                     client to operate on
- * @fdp:                        output argument to store FD
- *
- * This retrieves the FD used by the client object given as @client. The FD is
- * always valid, and returned in @fdp.
- *
- * The caller is expected to poll this FD for readable events and call
- * n_dhcp4_client_dispatch() whenever the FD is readable.
- */
-_c_public_ void n_dhcp4_client_get_fd(NDhcp4Client *client, int *fdp) {
-        *fdp = client->fd_epoll;
-}
-
-static int n_dhcp4_client_dispatch_timer(NDhcp4Client *client, struct epoll_event *event) {
-        uint64_t v, ns_now;
-        int r;
-
-        if (event->events & (EPOLLHUP | EPOLLERR)) {
-                /*
-                 * There is no way to handle either gracefully. If we ignored
-                 * them, we would busy-loop, so lets rather forward the error
-                 * to the caller.
-                 */
-                return -ENOTRECOVERABLE;
-        }
-
-        if (event->events & EPOLLIN) {
-                r = read(client->fd_timer, &v, sizeof(v));
-                if (r < 0) {
-                        if (errno == EAGAIN) {
-                                /*
-                                 * There are no more pending events, so nothing
-                                 * to be done. Return to the caller.
-                                 */
-                                return 0;
-                        }
-
-                        /*
-                         * Something failed. We use CLOCK_BOOTTIME/MONOTONIC,
-                         * so ECANCELED cannot happen. Hence, there is no error
-                         * that we could gracefully handle. Fail hard and let
-                         * the caller deal with it.
-                         */
-                        return -errno;
-                } else if (r != sizeof(v) || v == 0) {
-                        /*
-                         * Kernel guarantees 8-byte reads, and only to return
-                         * data if at least one timer triggered; fail hard if
-                         * it suddenly starts exposing unexpected behavior.
-                         */
-                        return -ENOTRECOVERABLE;
-                }
-
-                /*
-                 * Forward the timer-event to the active probe. Timers should
-                 * not fire if there is no probe running, but lets ignore them
-                 * for now, so probe-internals are not leaked to this generic
-                 * client dispatcher.
-                 */
-                if (client->current_probe) {
-                        /*
-                         * Read the current time *after* dispatching the timer,
-                         * to make sure we do not miss wakeups.
-                         */
-                        ns_now = n_dhcp4_gettime(CLOCK_BOOTTIME);
-
-                        r = n_dhcp4_client_probe_dispatch_timer(client->current_probe,
-                                                                ns_now);
-                        if (r)
-                                return r;
-                }
-        }
-
-        return 0;
-}
-
-static int n_dhcp4_client_dispatch_io(NDhcp4Client *client, struct epoll_event *event) {
-        int r;
-
-        if (client->current_probe)
-                r = n_dhcp4_client_probe_dispatch_io(client->current_probe,
-                                                     event->events);
-        else
-                return -ENOTRECOVERABLE;
-
-        return r;
-}
-
-/**
- * n_dhcp4_client_dispatch() - dispatch client
- * @client:                     client to operate on
- *
- * This dispatches pending operations on @client. It will read incoming
- * messages, write pending data, and handle any timeouts.
- *
- * This function never blocks.
- *
- * If there are more events to dispatch, than would be reasonable to do in a
- * single dispatch, this will return N_DHCP4_E_PREEMPTED. In this case the
- * caller is expected to call into this function again when it is ready to
- * dispatch more events.
- * If your event loop is level-triggered (it very likely is), you can
- * optionally ignore this return code and treat it as success.
- *
- * Return: 0 on success, negative error code on failure, N_DHCP4_E_PREEMPTED if
- *         there is more data to dispatch.
- */
-_c_public_ int n_dhcp4_client_dispatch(NDhcp4Client *client) {
-        struct epoll_event events[2];
-        int n, i, r = 0;
-
-        n = epoll_wait(client->fd_epoll, events, sizeof(events) / sizeof(*events), 0);
-        if (n < 0) {
-                /* Linux never returns EINTR if `timeout == 0'. */
-                return -errno;
-        }
-
-        client->preempted = false;
-
-        for (i = 0; i < n; ++i) {
-                switch (events[i].data.u32) {
-                case N_DHCP4_CLIENT_EPOLL_TIMER:
-                        r = n_dhcp4_client_dispatch_timer(client, events + i);
-                        break;
-                case N_DHCP4_CLIENT_EPOLL_IO:
-                        r = n_dhcp4_client_dispatch_io(client, events + i);
-                        break;
-                default:
-                        c_assert(0);
-                        r = 0;
-                        break;
-                }
-
-                if (r) {
-                        if (r == N_DHCP4_E_DOWN) {
-                                r = n_dhcp4_client_raise(client,
-                                                         NULL,
-                                                         N_DHCP4_CLIENT_EVENT_DOWN);
-                                if (r)
-                                        return r;
-
-                                /* continue normally */
-                        } else if (r) {
-                                if (r >= _N_DHCP4_E_INTERNAL) {
-                                        n_dhcp4_log(&client->log_queue,
-                                                    LOG_ERR,
-                                                    "invalid internal error code %d after dispatch",
-                                                    r);
-                                        return N_DHCP4_E_INTERNAL;
-                                }
-                                return r;
-                        }
-                }
-        }
-
-        n_dhcp4_client_arm_timer(client);
-
-        return client->preempted ? N_DHCP4_E_PREEMPTED : 0;
-}
-
-/**
- * n_dhcp4_client_pop_event() - fetch pending event
- * @client:                     client to operate on
- * @eventp:                     output argument to store next event
- *
- * This fetches the next pending event from the event-queue and returns it to a
- * caller. A pointer to the event is stored in @eventp. If there is no more
- * event queued, NULL is returned.
- *
- * If a valid event is returned, it is accessible until the next call to this
- * function, or the destruction of the context object (this might be either the
- * client object or the probe object, pointed to by the event), whichever
- * happens first.
- * That is, the caller should not pin the returned event object, but copy
- * required information into their own state tracking contexts.
- *
- * The possible events are:
- * * N_DHCP4_CLIENT_EVENT_OFFER:     A lease offered from a server in response
- *                                   to a probe. Several such offers may be
- *                                   received until one of them is selected by
- *                                   the caller. Only one lease may be selected.
- *                                   The attached lease object may be queried
- *                                   for information in order to decide which
- *                                   lease to select, though the information is
- *                                   not guaranteed to stay the same in the
- *                                   final lease.
- * * N_DHCP4_CLIENT_EVENT_GRANTED:   A selected lease was granted by the server.
- *                                   The information in the attached lease
- *                                   object should be used to configure the
- *                                   client. Once the client has been
- *                                   configured, the lease should be accepted.
- * * N_DHCP4_CLIENT_EVENT_RETRACTED: A selected lease offer was retracted by the
- *                                   server. This can happen in case the server
- *                                   offers the same lease to several clients,
- *                                   or the server discovers that the IP address
- *                                   in the lease is already in use.
- * * N_DHCP4_CLIENT_EVENT_EXTENDED:  An active lease is extended, if applicable
- *                                   the kernel should be updated with the new
- *                                   lifetime information for addresses and/or
- *                                   routes.
- * * N_DHCP4_CLIENT_EVENT_EXPIRED:   An active lease failed to be extended by
- *                                   the end of its lifetime. The client should
- *                                   immediately stop using the information
- *                                   contained in the lease.
- * * N_DHCP4_CLIENT_EVENT_DOWN:      The network interface was put down down.
- *                                   The user is recommended to reestablish the
- *                                   lease at the first opportunity when the
- *                                   network comes back up. Note that this is
- *                                   purely informational, the probe will keep
- *                                   running, and if the network topology does
- *                                   not change any lease we have will still be
- *                                   valid.
- * * N_DHCP4_CLIENT_EVENT_CANCELLED: The probe was cancelled. This can happen if
- *                                   the client attempted several incompatible
- *                                   probes in parallel, then the most recent
- *                                   ones will be cancelled asynchronously.
- * * N_DHCP4_CLIENT_EVENT_LOG:       A logging event if n_dhcp4_client_set_log_level()
- *                                   is enabled.
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_pop_event(NDhcp4Client *client, NDhcp4ClientEvent **eventp) {
-        NDhcp4CEventNode *node, *t_node;
-
-        c_list_for_each_entry_safe(node, t_node, &client->event_list, client_link) {
-                if (node->is_public) {
-                        n_dhcp4_c_event_node_free(node);
-                        continue;
-                }
-
-                node->is_public = true;
-                *eventp = &node->event;
-                return 0;
-        }
-
-        *eventp = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_update_mtu() - update link mtu
- * @client:                     client to operate on
- * @mtu:                        new mtu
- *
- * This updates the link MTU used by the client object. By default, the minimum
- * requirement given by the IP specification is assumed, which means 576
- * bytes. The caller is advised to update this to the actual MTU used by the
- * link layer.
- *
- * This value reflects the MTU of the link layer. That is, it is the maximum
- * packet size that you can send on that link, excluding the link-header but
- * including the IP-header. On ethernet-v2 this would be 1500.
- *
- * If unsure, it is safe to leave this unset. However, in this case a DHCP
- * server will be required to omit information if it does not fit into the
- * default MTU.
- *
- * Unless you keep the default MTU, you should update the MTU whenever the link
- * MTU changes. That is, when it is increased *and* when it is decreased.
- * However, you must be aware that decreasing the MTU on a link might cause
- * temporary data loss.
- *
- * Background: Knowing the link MTU guarantees that we can possibly transmit
- *             packets bigger than the IP minimum (i.e., 576 bytes). However,
- *             it does not guarantee that a possible target supports parsing
- *             packets bigger than the IP minimum. Hence, the MTU is used by a
- *             client to send a hint to a server that it can receive replies
- *             bigger than the minimum. As such, a server can reply with more
- *             information than otherwise possible.
- *             Since this DHCP client does not support fragmented packets, we
- *             simply set the allowed packet-size to the local link MTU.
- *             Note that DHCP relays might cause DHCP packets to be routed.
- *             However, such relays are required to always reassemble any
- *             fragments they receive into full DHCP packets, before they
- *             forward them either way. This guarantees that incoming packets
- *             are never fragmented, unless they exceed the local link MTU
- *             (this would otherwise not neccessarily be true, if some other
- *             part of the routed network had a lower MTU).
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_update_mtu(NDhcp4Client *client, uint16_t mtu) {
-        int r;
-
-        if (mtu == client->mtu)
-                return 0;
-
-        if (client->current_probe) {
-                r = n_dhcp4_client_probe_update_mtu(client->current_probe, mtu);
-                if (r)
-                        return r;
-        }
-
-        client->mtu = mtu;
-        return 0;
-}
-
-/**
- * n_dhcp4_client_probe() - create a new probe
- * @client:                     client to operate on
- * @probep:                     output argument to store new probe
- * @config:                     probe configuration to use
- *
- * This creates a new probe on @client. Probes represent DHCP requests and
- * track the state over the entire lifetime of a lease. Once a probe is created
- * it will start looking for DHCP servers, request a lease from them, and renew
- * the lease continuously whenever it expires. Furthermore, if a lease cannot be
- * renewed, a new lease will be requested.
- *
- * The API allows for many probes to be run at the same time. However, the DHCP
- * specification forbids many of those cases (e.g., you must not reuse a client
- * id, otherwise it will be impossible to track who to forward received packets
- * to). Hence, so far only a single probe can run at a time. If you create a
- * new probe, all older probes that conflict with that probe will be canceled
- * (their state machine is halted and a N_DHCP4_CLIENT_EVENT_CANCELLED event is
- * raised.
- * This might change in the future, though. There might be cases where multiple
- * probes can be run in parallel (e.g., with different client-ids, or an INFORM
- * in parallel to a REQUEST, ...).
- *
- * Return: 0 on success, negative error code on failure.
- */
-_c_public_ int n_dhcp4_client_probe(NDhcp4Client *client,
-                                  NDhcp4ClientProbe **probep,
-                                  NDhcp4ClientProbeConfig *config) {
-        _c_cleanup_(n_dhcp4_client_probe_freep) NDhcp4ClientProbe *probe = NULL;
-        uint64_t ns_now;
-        int r;
-
-        ns_now = n_dhcp4_gettime(CLOCK_BOOTTIME);
-
-        r = n_dhcp4_client_probe_new(&probe, config, client, ns_now);
-        if (r)
-                return r;
-
-        n_dhcp4_client_arm_timer(client);
-
-        *probep = probe;
-        probe = NULL;
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-incoming.c b/shared/n-dhcp4/src/n-dhcp4-incoming.c
deleted file mode 100644
index f739413b..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-incoming.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * DHCPv4 Incoming Messages
- *
- * This file implements the message parser object for incoming DHCP4 messages.
- * It takes a linear data blob as input, and provides accessors for the message
- * content.
- *
- * This wrapper mainly deals with the OPTIONs array. That is, in hides the
- * different overload-sections the DHCP4 spec defines, it concatenates
- * duplicate option fields (as described by the spec), and provides a
- * consistent view to the caller.
- *
- * Internally, for every incoming message we linearize its OPTIONs. This means,
- * we create a copy of the contents, and merge all duplicate options into a
- * single option entry. We then provide accessors to the caller to easily get
- * O(1) access to individual fields.
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <endian.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include "n-dhcp4.h"
-#include "n-dhcp4-private.h"
-
-static void n_dhcp4_incoming_prefetch(NDhcp4Incoming *incoming, size_t *offset, uint8_t option, const uint8_t *raw, size_t n_raw) {
-        uint8_t o, l;
-        size_t pos;
-
-        for (pos = 0; pos < n_raw; ) {
-                o = raw[pos++];
-                if (o == N_DHCP4_OPTION_PAD)
-                        continue;
-                if (o == N_DHCP4_OPTION_END)
-                        return;
-
-                /* bail out if no remaining space for length field */
-                if (pos >= n_raw)
-                        return;
-
-                /* bail out if length exceeds the available space */
-                l = raw[pos++];
-                if (l > n_raw || pos > n_raw - l)
-                        return;
-
-                /* prefetch content if it matches @option */
-                if (o == option) {
-                        memcpy((uint8_t *)&incoming->message + *offset, raw + pos, l);
-                        *offset += l;
-                }
-
-                pos += l;
-        }
-}
-
-static void n_dhcp4_incoming_merge(NDhcp4Incoming *incoming, size_t *offset, uint8_t overload, uint8_t option) {
-        uint8_t *m = (uint8_t *)&incoming->message;
-        size_t pos;
-
-        /*
-         * Prefetch all options matching @option from the 3 sections,
-         * concatenating their content. Remember the offset and size of the
-         * option in our message state.
-         */
-
-        pos = *offset;
-
-        /* prefetch option from OPTIONS */
-        n_dhcp4_incoming_prefetch(incoming, offset, option,
-                                  m + offsetof(NDhcp4Message, options),
-                                  incoming->n_message - offsetof(NDhcp4Message, options));
-
-        /* prefetch option from FILE */
-        if (overload & N_DHCP4_OVERLOAD_FILE)
-                n_dhcp4_incoming_prefetch(incoming, offset, option,
-                                          m + offsetof(NDhcp4Message, file),
-                                          sizeof(incoming->message.file));
-
-        /* prefetch option from SNAME */
-        if (overload & N_DHCP4_OVERLOAD_SNAME)
-                n_dhcp4_incoming_prefetch(incoming, offset, option,
-                                          m + offsetof(NDhcp4Message, sname),
-                                          sizeof(incoming->message.sname));
-
-        incoming->options[option].value = m + pos;
-        incoming->options[option].size = *offset - pos;
-}
-
-static void n_dhcp4_incoming_linearize(NDhcp4Incoming *incoming) {
-        uint8_t *m, o, l, overload;
-        size_t i, pos, end, offset;
-
-        /*
-         * Linearize all OPTIONs of the incoming message. We know that
-         * @incoming->message is preallocated to be big enough to hold the
-         * entire linearized message _trailing_ the original copy. All we have
-         * to do is walk the raw message in @incoming->message and for each
-         * option we find, copy it into the trailing space, concatenating all
-         * instances we find.
-         *
-         * Before we can copy the individual options, we must scan for the
-         * OVERLOAD option. This is required so our prefetcher knows which data
-         * arrays to scan for prefetching.
-         *
-         * So far, we require the OVERLOAD option to be present in the
-         * options-array (which is obvious and a given). However, if the option
-         * occurs multiple times outside of the options-array (i.e., SNAME or
-         * FILE), we silently ignore them. The specification does not allow
-         * multiple OVERLOAD options, anyway. Hence, this behavior only defines
-         * what we do when we see broken implementations, and we currently seem
-         * to support all styles we saw in the wild so far.
-         */
-
-        m = (uint8_t *)&incoming->message;
-        offset = incoming->n_message;
-
-        n_dhcp4_incoming_merge(incoming, &offset, 0, N_DHCP4_OPTION_OVERLOAD);
-        if (incoming->options[N_DHCP4_OPTION_OVERLOAD].size >= 1)
-                overload = *incoming->options[N_DHCP4_OPTION_OVERLOAD].value;
-        else
-                overload = 0;
-
-        for (i = 0; i < 3; ++i) {
-                if (i == 0) { /* walk OPTIONS */
-                        pos = offsetof(NDhcp4Message, options);
-                        end = incoming->n_message;
-                } else if (i == 1) { /* walk FILE */
-                        if (!(overload & N_DHCP4_OVERLOAD_FILE))
-                                continue;
-
-                        pos = offsetof(NDhcp4Message, file);
-                        end = pos + sizeof(incoming->message.file);
-                } else { /* walk SNAME */
-                        if (!(overload & N_DHCP4_OVERLOAD_SNAME))
-                                continue;
-
-                        pos = offsetof(NDhcp4Message, sname);
-                        end = pos + sizeof(incoming->message.sname);
-                }
-
-                while (pos < end) {
-                        o = m[pos++];
-                        if (o == N_DHCP4_OPTION_PAD)
-                                continue;
-                        if (o == N_DHCP4_OPTION_END)
-                                break;
-                        if (pos >= end)
-                                break;
-
-                        l = m[pos++];
-                        if (l > end || pos > end - l)
-                                break;
-
-                        if (!incoming->options[o].value)
-                                n_dhcp4_incoming_merge(incoming, &offset, overload, o);
-
-                        pos += l;
-                }
-        }
-}
-
-/**
- * n_dhcp4_incoming_new() - Allocate new incoming message object
- * @incomingp:          output argument for new object
- * @raw:                raw message blob
- * @n_raw:              length of the raw message blob
- *
- * This function allocates a new incoming-message object to wrap a received
- * message blob. It performs basic verification of the message length and
- * header, and then linearizes the DHCP4 options.
- *
- * The incoming-message object mainly provides accessors for the option-array.
- * It handles all the different quirks around parsing and concatenating the
- * options array, and provides the assembled data to the caller. It does not,
- * however, in any way interpret the data of the individual options. This is up
- * to the caller to do.
- *
- * Return: 0 on success, negative error code on failure, N_DHCP4_E_MALFORMED if
- *         the message is not a valid DHCP4 message.
- */
-int n_dhcp4_incoming_new(NDhcp4Incoming **incomingp, const void *raw, size_t n_raw) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *incoming = NULL;
-        size_t size;
-
-        if (n_raw < sizeof(NDhcp4Message) || n_raw > UINT16_MAX)
-                return N_DHCP4_E_MALFORMED;
-
-        /*
-         * Allocate enough space for book-keeping, a copy of @raw and trailing
-         * space for linearized options. The trailing space must be big enough
-         * to hold the entire options array unmodified (linearizing can only
-         * make it smaller). Hence, just allocate enough space to hold the raw
-         * message without the header.
-         */
-        size = sizeof(*incoming) + n_raw - sizeof(NDhcp4Message);
-        size += n_raw - sizeof(NDhcp4Header);
-
-        incoming = calloc(1, size);
-        if (!incoming)
-                return -ENOMEM;
-
-        *incoming = (NDhcp4Incoming)N_DHCP4_INCOMING_NULL(*incoming);
-        incoming->n_message = n_raw;
-        memcpy(&incoming->message, raw, n_raw);
-
-        if (incoming->message.magic != htobe32(N_DHCP4_MESSAGE_MAGIC))
-                return N_DHCP4_E_MALFORMED;
-
-        /* linearize options */
-        n_dhcp4_incoming_linearize(incoming);
-
-        *incomingp = incoming;
-        incoming = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_incoming_free() - Deallocate message object
- * @incoming:           object to operate on, or NULL
- *
- * This deallocates and frees the given incoming-message object. If NULL is
- * passed, this is a no-op.
- *
- * Return: NULL is returned.
- */
-NDhcp4Incoming *n_dhcp4_incoming_free(NDhcp4Incoming *incoming) {
-        if (!incoming)
-                return NULL;
-
-        free(incoming);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_incoming_get_header() - Return message header
- * @incoming:           message to operate on
- *
- * This returns a pointer to the message header. Note that modifications to
- * this header are permanent and will affect the original message.
- *
- * Return: A pointer to the message header is returned.
- */
-NDhcp4Header *n_dhcp4_incoming_get_header(NDhcp4Incoming *incoming) {
-        return &incoming->message.header;
-}
-
-/**
- * n_dhcp4_incoming_get_raw() - Get access to the raw original message
- * @incoming:           message to operate on
- * @rawp:               output argument for the raw blob, or NULL
- *
- * This hands out a pointer to the raw message blob to the caller. This will
- * point to the original message content, rather than the linearized version.
- *
- * Note that if the caller queried the contents of the message before, any
- * modifications done by the caller will not affect the original message. It
- * only affects the linearized content (which is a duplicate trailing the
- * original message). However, modifications to the message header *DO* also
- * appear in the original, since the message header is not duplicated.
- *
- * In either case, it is better to never modify the message, if you intend to
- * forward it further.
- *
- * Return: The length of the raw message blob is returned.
- */
-size_t n_dhcp4_incoming_get_raw(NDhcp4Incoming *incoming, const void **rawp) {
-        if (rawp)
-                *rawp = &incoming->message;
-        return incoming->n_message;
-}
-
-/**
- * n_dhcp4_incoming_query() - Query the contents of a specific option
- * @incoming:           message to query
- * @option:             option to look for
- * @datap:              output argument for the option-data, or NULL
- * @n_datap:            output argument for the length of the option, or NULL
- *
- * This returns a pointer to the requested option blob in the message. It
- * points to a linearized version of all respective option-fields of the same
- * type. Hence, the caller is not required to deal with multiple occurrences of
- * the same option.
- *
- * If an option was not present in the incoming message, N_DHCP4_E_UNSET is
- * returned. Note that this is different from an empty option! And empty option
- * will return a valid pointer and size 0.
- *
- * Note that the pointer to the option-blob does not point to the original
- * message, but a duplicated version. Modifications to the blob will not be
- * reflected in the original message, but they will be permanent regarding
- * further queries through this function.
- *
- * Note that the original message alignment might no longer be reflected in the
- * returned blob. You must not alias the content of the blob, but always copy
- * it out, or consume piecemeal.
- *
- * This function runs in O(1).
- *
- * Return: 0 on success, negative error code on failure, N_DHCP4_E_UNSET if the
- *         option was not found,
- */
-int n_dhcp4_incoming_query(NDhcp4Incoming *incoming, uint8_t option, uint8_t **datap, size_t *n_datap) {
-        if (!incoming->options[option].value)
-                return N_DHCP4_E_UNSET;
-
-        if (datap)
-                *datap = incoming->options[option].value;
-        if (n_datap)
-                *n_datap = incoming->options[option].size;
-        return 0;
-}
-
-static int n_dhcp4_incoming_query_u8(NDhcp4Incoming *message, uint8_t option, uint8_t *u8p) {
-        uint8_t *data;
-        size_t n_data;
-        int r;
-
-        r = n_dhcp4_incoming_query(message, option, &data, &n_data);
-        if (r)
-                return r;
-        else if (n_data < sizeof(*data))
-                return N_DHCP4_E_MALFORMED;
-
-        *u8p = *data;
-        return 0;
-}
-
-static int n_dhcp4_incoming_query_u16(NDhcp4Incoming *message, uint8_t option, uint16_t *u16p) {
-        uint8_t *data;
-        size_t n_data;
-        uint16_t be16;
-        int r;
-
-        r = n_dhcp4_incoming_query(message, option, &data, &n_data);
-        if (r)
-                return r;
-        else if (n_data < sizeof(be16))
-                return N_DHCP4_E_MALFORMED;
-
-        memcpy(&be16, data, sizeof(be16));
-
-        *u16p = ntohs(be16);
-        return 0;
-}
-
-static int n_dhcp4_incoming_query_u32(NDhcp4Incoming *message, uint8_t option, uint32_t *u32p) {
-        uint8_t *data;
-        size_t n_data;
-        uint32_t be32;
-        int r;
-
-        r = n_dhcp4_incoming_query(message, option, &data, &n_data);
-        if (r)
-                return r;
-        else if (n_data < sizeof(be32))
-                return N_DHCP4_E_MALFORMED;
-
-        memcpy(&be32, data, sizeof(be32));
-
-        *u32p = ntohl(be32);
-        return 0;
-}
-
-static int n_dhcp4_incoming_query_in_addr(NDhcp4Incoming *message, uint8_t option, struct in_addr *addrp) {
-        uint8_t *data;
-        size_t n_data;
-        uint32_t be32;
-        int r;
-
-        r = n_dhcp4_incoming_query(message, option, &data, &n_data);
-        if (r)
-                return r;
-        else if (n_data < sizeof(be32))
-                return N_DHCP4_E_MALFORMED;
-
-        memcpy(&be32, data, sizeof(be32));
-
-        addrp->s_addr = be32;
-        return 0;
-}
-
-int n_dhcp4_incoming_query_message_type(NDhcp4Incoming *message, uint8_t *typep) {
-        return n_dhcp4_incoming_query_u8(message, N_DHCP4_OPTION_MESSAGE_TYPE, typep);
-}
-
-int n_dhcp4_incoming_query_lifetime(NDhcp4Incoming *message, uint32_t *lifetimep) {
-        return n_dhcp4_incoming_query_u32(message, N_DHCP4_OPTION_IP_ADDRESS_LEASE_TIME, lifetimep);
-}
-
-int n_dhcp4_incoming_query_t2(NDhcp4Incoming *message, uint32_t *t2p) {
-        return n_dhcp4_incoming_query_u32(message, N_DHCP4_OPTION_REBINDING_T2_TIME, t2p);
-}
-
-int n_dhcp4_incoming_query_t1(NDhcp4Incoming *message, uint32_t *t1p) {
-        return n_dhcp4_incoming_query_u32(message, N_DHCP4_OPTION_RENEWAL_T1_TIME, t1p);
-}
-
-int n_dhcp4_incoming_query_server_identifier(NDhcp4Incoming *message, struct in_addr *idp) {
-        return n_dhcp4_incoming_query_in_addr(message, N_DHCP4_OPTION_SERVER_IDENTIFIER, idp);
-}
-
-int n_dhcp4_incoming_query_max_message_size(NDhcp4Incoming *message, uint16_t *max_message_sizep) {
-        return n_dhcp4_incoming_query_u16(message, N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE, max_message_sizep);
-}
-
-int n_dhcp4_incoming_query_requested_ip(NDhcp4Incoming *message, struct in_addr *requested_ipp) {
-        return n_dhcp4_incoming_query_in_addr(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, requested_ipp);
-}
-
-void n_dhcp4_incoming_get_xid(NDhcp4Incoming *message, uint32_t *xidp) {
-        NDhcp4Header *header = n_dhcp4_incoming_get_header(message);
-
-        *xidp = header->xid;
-}
-
-void n_dhcp4_incoming_get_yiaddr(NDhcp4Incoming *message, struct in_addr *yiaddr) {
-        NDhcp4Header *header = n_dhcp4_incoming_get_header(message);
-
-        yiaddr->s_addr = header->yiaddr;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-outgoing.c b/shared/n-dhcp4/src/n-dhcp4-outgoing.c
deleted file mode 100644
index bcab407f..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-outgoing.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * DHCPv4 Outgoing Messages
- *
- * XXX
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <endian.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include "n-dhcp4.h"
-#include "n-dhcp4-private.h"
-
-/**
- * N_DHCP4_OUTGOING_MAX_PHDR - maximum protocol header size
- *
- * All DHCP4 messages-limits specify the size of the entire packet including
- * the protocol layer (i.e., including the IP headers and UDP headers). To
- * calculate the size we have remaining for the actual DHCP message, we need to
- * substract the maximum possible header-length the linux-kernel might prepend
- * to our messages. This turns out to be the maximum IP-header size (including
- * optional IP headers, hence 60 bytes) plus the UDP header size (i.e., 8
- * bytes).
- */
-#define N_DHCP4_OUTGOING_MAX_PHDR (N_DHCP4_NETWORK_IP_MAXIMUM_HEADER_SIZE + sizeof(struct udphdr))
-
-/**
- * n_dhcp4_outgoing_new() - Allocate new outgoing message
- * @outgoingp:          output argument to return allocate object through
- * @max_size:           maximum transmission size to use
- * @overload:           select sections to overload
- *
- * This allocates a new outgoing message and returns it to the caller. The
- * caller can then append data to it and send it over the wire.
- *
- * The @max_size parameter specifies the transport-layer MTU to consider. If 0,
- * N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE is used. Note that this argument
- * specifies the maximum packet size *INCLUDING* the IP-headers and UDP-header.
- * Internally, the allocator makes sure to never create packets bigger than the
- * specified MTU. The append functions will return an error, if the packet size
- * would exceed the MTU.
- * If you use a full UDP stack that supports packet fragmentation, you can
- * specify the maximum packet size here (e.g., UINT16_MAX).
- *
- * Return: 0 on success, error code on failure.
- */
-int n_dhcp4_outgoing_new(NDhcp4Outgoing **outgoingp, size_t max_size, uint8_t overload) {
-        _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *outgoing = NULL;
-
-        /*
-         * Make sure the minimum limit is bigger than the maximum protocol
-         * header plus the DHCP-message-header plus a single OPTION_END byte.
-         */
-        static_assert(N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE >= N_DHCP4_OUTGOING_MAX_PHDR +
-                                                             sizeof(NDhcp4Message) + 1,
-                      "Invalid minimum IP packet limit");
-
-        c_assert(!(overload & ~(N_DHCP4_OVERLOAD_FILE | N_DHCP4_OVERLOAD_SNAME)));
-
-        outgoing = calloc(1, sizeof(*outgoing));
-        if (!outgoing)
-                return -ENOMEM;
-
-        *outgoing = (NDhcp4Outgoing)N_DHCP4_OUTGOING_NULL(*outgoing);
-        outgoing->n_message = N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE - N_DHCP4_OUTGOING_MAX_PHDR;
-        outgoing->i_message = offsetof(NDhcp4Message, options);
-        outgoing->max_size = outgoing->n_message;
-        outgoing->overload = overload;
-
-        if (max_size > N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE)
-                outgoing->max_size = max_size - N_DHCP4_OUTGOING_MAX_PHDR;
-
-        outgoing->message = calloc(1, outgoing->n_message);
-        if (!outgoing->message)
-                return -ENOMEM;
-
-        outgoing->message->magic = htonl(N_DHCP4_MESSAGE_MAGIC);
-        outgoing->message->options[0] = N_DHCP4_OPTION_END;
-
-        *outgoingp = outgoing;
-        outgoing = NULL;
-        return 0;
-}
-
-/**
- * n_dhcp4_outgoing_free() - Deallocate outgoing message
- * @outgoing:           message to deallocate, or NULL
- *
- * This is the opposite to n_dhcp4_outgoing_new(). It deallocates and frees the
- * passed object. If @outgoing is NULL, this is a no-op.
- *
- * Return: NULL is returned.
- */
-NDhcp4Outgoing *n_dhcp4_outgoing_free(NDhcp4Outgoing *outgoing) {
-        if (!outgoing)
-                return NULL;
-
-        free(outgoing->message);
-        free(outgoing);
-
-        return NULL;
-}
-
-/**
- * n_dhcp4_outgoing_get_header() - Get pointer to the message header
- * @outgoing:           message to operate on
- *
- * This returns a pointer to the DHCP4 message header to the caller. The caller
- * can use this to fill-in the header-fields. Note that all fields are
- * initialized to their default values. Hence, you only need to override the
- * fields where the default is not sufficient.
- *
- * Return: A pointer to the message header is returned.
- */
-NDhcp4Header *n_dhcp4_outgoing_get_header(NDhcp4Outgoing *outgoing) {
-        return &outgoing->message->header;
-}
-
-/**
- * n_dhcp4_outgoing_get_raw() - Get the raw message blob
- * @outgoing:           message to operat on
- * @rawp:               output argument for the message-blob
- *
- * This function gives the caller access to the raw message-blob. That is, once
- * message-marshaling is complete, use this to get the raw blob for sending.
- * Note that this blob is only valid as long as you no longer append any
- * further options to the message, nor modify it in any other way.
- *
- * Return: The size of the raw message blob is returned.
- */
-size_t n_dhcp4_outgoing_get_raw(NDhcp4Outgoing *outgoing, const void **rawp) {
-        if (rawp)
-                *rawp = outgoing->message;
-
-        /*
-         * Return the DHCP message until the END option, excluding any
-         * trailing padding. We overallocate during append, so the
-         * allocated message might be bigger than what we want to
-         * send on the wire.
-         */
-        return outgoing->i_message + 1;
-}
-
-static void n_dhcp4_outgoing_append_option(NDhcp4Outgoing *outgoing,
-                                           uint8_t option,
-                                           const void *data,
-                                           uint8_t n_data) {
-        uint8_t *blob = (void *)outgoing->message;
-
-        blob[outgoing->i_message++] = option;
-        blob[outgoing->i_message++] = n_data;
-        memcpy(blob + outgoing->i_message, data, n_data);
-        outgoing->i_message += n_data;
-        blob[outgoing->i_message] = N_DHCP4_OPTION_END;
-}
-
-/**
- * n_dhcp4_outgoing_append() - Append option to outgoing message
- * @outgoing:           message to operate on
- * @option:             option code to append
- * @data:               data to append in the option
- * @n_data:             length of the data blob
- *
- * This appends another option to the given outgoing message. The data is taken
- * verbatim and copied into the message. Note that no validation is done. If
- * you provide an option multiple times, it will be added multiple times (spec
- * then requires them to be interpreted as concatenated option, in case the
- * option is marked as such).
- *
- * The size of a message is limited, based on the restriction passed to the
- * outgoing-message constructor. If there is not enough free space to copy in
- * the new option, N_DHCP4_E_NO_SPACE is returned.
- *
- * The order in which you append options might matter to some implementations.
- * For example, the message-type is often expected to be the first option. We
- * do not place such restrictions, but for compatibility with external
- * implementations, you should follow these recommendations.
- * Furthermore, we do not implement any kind of smart allocators. That is, all
- * options are simply appended when you call this. But due to the overloading
- * feature, fragmentation might matter. Hence, if you use overloading, overly
- * big options might cause padding, and as such waste space.
- *
- * Return: 0 on success, negative error code on failure, N_DHCP4_E_NO_SPACE
- *         when there is not sufficient free space in the message.
- */
-int n_dhcp4_outgoing_append(NDhcp4Outgoing *outgoing,
-                            uint8_t option,
-                            const void *data,
-                            uint8_t n_data) {
-        NDhcp4Message *m;
-        uint8_t overload;
-        size_t rem, n;
-
-        c_assert(option != N_DHCP4_OPTION_PAD);
-        c_assert(option != N_DHCP4_OPTION_END);
-        c_assert(option != N_DHCP4_OPTION_OVERLOAD);
-
-        /*
-         * If the iterator is on the OPTIONs field, try appending the new blob.
-         * We need 2 header-bytes plus @n_data bytes. Additionally, we always
-         * reserve 3 trailing bytes for a possible OVERLOAD option, and 1 byte
-         * for the END marker.
-         */
-        if (outgoing->i_message >= offsetof(NDhcp4Message, options)) {
-                rem = outgoing->n_message - outgoing->i_message;
-
-                /* try fitting into remaining OPTIONs space */
-                if (rem >= n_data + 2U + 3U + 1U) {
-                        n_dhcp4_outgoing_append_option(outgoing, option, data, n_data);
-                        return 0;
-                }
-
-                /* try fitting into allowed OPTIONs space */
-                if (outgoing->max_size - outgoing->i_message >= n_data + 2U + 3U + 1U) {
-                        /* try over-allocation to reduce allocation pressure */
-                        n = outgoing->n_message + n_data + 128;
-                        if (n > outgoing->max_size)
-                                n = outgoing->max_size;
-                        m = realloc(outgoing->message, n);
-                        if (!m)
-                                return -ENOMEM;
-
-                        memset((void *)m + outgoing->i_message, 0, n - outgoing->i_message);
-                        outgoing->message = m;
-                        outgoing->n_message = n;
-                        n_dhcp4_outgoing_append_option(outgoing, option, data, n_data);
-                        return 0;
-                }
-
-                /* not enough remaining space, try OVERLOAD */
-                if (!outgoing->overload)
-                        return N_DHCP4_E_NO_SPACE;
-
-                /*
-                 * We ran out of space in the OPTIONs array, but overloading
-                 * was enabled. This means, we can insert an OVERLOAD option
-                 * and then use SNAME/FILE to store more options.
-                 * Note that the three different sections cannot overlap and
-                 * all must have an END marker. So as soon as we add the
-                 * OVERLOAD option, we must make sure the other sections have
-                 * the valid END marker. From then on, our *_append_option()
-                 * helper makes sure to move the END marker with every
-                 * insertion.
-                 */
-                overload = outgoing->overload;
-                n_dhcp4_outgoing_append_option(outgoing, N_DHCP4_OPTION_OVERLOAD, &overload, 1);
-
-                if (overload & N_DHCP4_OVERLOAD_FILE)
-                        outgoing->message->file[0] = N_DHCP4_OPTION_END;
-                if (overload & N_DHCP4_OVERLOAD_SNAME)
-                        outgoing->message->sname[0] = N_DHCP4_OPTION_END;
-
-                if (overload & N_DHCP4_OVERLOAD_FILE)
-                        outgoing->i_message = offsetof(NDhcp4Message, file);
-                else if (overload & N_DHCP4_OVERLOAD_SNAME)
-                        outgoing->i_message = offsetof(NDhcp4Message, sname);
-        }
-
-        /*
-         * The OPTIONs section is full and OVERLOAD was enabled. Try writing
-         * into the FILE section. Always reserve 1 byte for the trailing END
-         * marker.
-         */
-        if (outgoing->i_message >= offsetof(NDhcp4Message, file)) {
-                rem = sizeof(outgoing->message->file);
-                rem -= outgoing->i_message - offsetof(NDhcp4Message, file);
-
-                if (rem >= n_data + 2U + 1U) {
-                        n_dhcp4_outgoing_append_option(outgoing, option, data, n_data);
-                        return 0;
-                }
-
-                overload = outgoing->overload;
-                if (overload & N_DHCP4_OVERLOAD_SNAME)
-                        outgoing->i_message = offsetof(NDhcp4Message, sname);
-                else
-                        return N_DHCP4_E_NO_SPACE;
-        }
-
-        /*
-         * OPTIONs and FILE are full, try putting data into the SNAME section
-         * as a last resort.
-         */
-        if (outgoing->i_message >= offsetof(NDhcp4Message, sname)) {
-                rem = sizeof(outgoing->message->sname);
-                rem -= outgoing->i_message - offsetof(NDhcp4Message, sname);
-
-                if (rem >= n_data + 2U + 1U) {
-                        n_dhcp4_outgoing_append_option(outgoing, option, data, n_data);
-                        return 0;
-                }
-        }
-
-        return N_DHCP4_E_NO_SPACE;
-}
-
-static int n_dhcp4_outgoing_append_u32(NDhcp4Outgoing *message, uint8_t option, uint32_t u32) {
-        uint32_t be32 = htonl(u32);
-        int r;
-
-        r = n_dhcp4_outgoing_append(message, option, &be32, sizeof(be32));
-        if (r)
-                return r;
-
-        return 0;
-}
-
-static int n_dhcp4_outgoing_append_in_addr(NDhcp4Outgoing *message, uint8_t option, struct in_addr addr) {
-        int r;
-
-        r = n_dhcp4_outgoing_append(message, option, &addr.s_addr, sizeof(addr.s_addr));
-        if (r)
-                return r;
-
-        return 0;
-}
-
-int n_dhcp4_outgoing_append_t1(NDhcp4Outgoing *message, uint32_t t1) {
-        return n_dhcp4_outgoing_append_u32(message, N_DHCP4_OPTION_RENEWAL_T1_TIME, t1);
-}
-
-int n_dhcp4_outgoing_append_t2(NDhcp4Outgoing *message, uint32_t t2) {
-        return n_dhcp4_outgoing_append_u32(message, N_DHCP4_OPTION_REBINDING_T2_TIME, t2);
-}
-
-int n_dhcp4_outgoing_append_lifetime(NDhcp4Outgoing *message, uint32_t lifetime) {
-        return n_dhcp4_outgoing_append_u32(message, N_DHCP4_OPTION_IP_ADDRESS_LEASE_TIME, lifetime);
-}
-
-int n_dhcp4_outgoing_append_server_identifier(NDhcp4Outgoing *message, struct in_addr addr) {
-        return n_dhcp4_outgoing_append_in_addr(message, N_DHCP4_OPTION_SERVER_IDENTIFIER, addr);
-}
-
-int n_dhcp4_outgoing_append_requested_ip(NDhcp4Outgoing *message, struct in_addr addr) {
-        return n_dhcp4_outgoing_append_in_addr(message, N_DHCP4_OPTION_REQUESTED_IP_ADDRESS, addr);
-}
-
-void n_dhcp4_outgoing_set_secs(NDhcp4Outgoing *message, uint16_t secs) {
-        NDhcp4Header *header = n_dhcp4_outgoing_get_header(message);
-
-        /*
-         * Some DHCP servers will reject DISCOVER or REQUEST messages if 'secs'
-         * is not set (i.e., set to 0), even though the spec allows it.
-         */
-        c_assert(secs);
-
-        header->secs = htons(secs);
-}
-
-void n_dhcp4_outgoing_set_xid(NDhcp4Outgoing *message, uint32_t xid) {
-        NDhcp4Header *header = n_dhcp4_outgoing_get_header(message);
-
-        header->xid = xid;
-}
-
-void n_dhcp4_outgoing_get_xid(NDhcp4Outgoing *message, uint32_t *xidp) {
-        NDhcp4Header *header = n_dhcp4_outgoing_get_header(message);
-
-        *xidp = header->xid;
-}
-
-void n_dhcp4_outgoing_set_yiaddr(NDhcp4Outgoing *message, struct in_addr yiaddr) {
-        NDhcp4Header *header = n_dhcp4_outgoing_get_header(message);
-
-        header->yiaddr = yiaddr.s_addr;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4-private.h b/shared/n-dhcp4/src/n-dhcp4-private.h
deleted file mode 100644
index db7b24ff..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-private.h
+++ /dev/null
@@ -1,759 +0,0 @@
-#pragma once
-
-#include <arpa/inet.h>
-#include <assert.h>
-#include <c-list.h>
-#include <c-stdaux.h>
-#include <endian.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-#include <syslog.h>
-#include "n-dhcp4.h"
-
-typedef struct NDhcp4CConnection NDhcp4CConnection;
-typedef struct NDhcp4CEventNode NDhcp4CEventNode;
-typedef struct NDhcp4ClientProbeOption NDhcp4ClientProbeOption;
-typedef struct NDhcp4Header NDhcp4Header;
-typedef struct NDhcp4Incoming NDhcp4Incoming;
-typedef struct NDhcp4Message NDhcp4Message;
-typedef struct NDhcp4Outgoing NDhcp4Outgoing;
-typedef struct NDhcp4SConnection NDhcp4SConnection;
-typedef struct NDhcp4SConnectionIp NDhcp4SConnectionIp;
-typedef struct NDhcp4SEventNode NDhcp4SEventNode;
-typedef struct NDhcp4LogQueue NDhcp4LogQueue;
-
-/* specs */
-
-#define N_DHCP4_NETWORK_IP_MAXIMUM_HEADER_SIZE (60) /* See RFC791 */
-#define N_DHCP4_NETWORK_IP_MINIMUM_MAX_SIZE (576) /* See RFC791 */
-#define N_DHCP4_NETWORK_SERVER_PORT (67)
-#define N_DHCP4_NETWORK_CLIENT_PORT (68)
-#define N_DHCP4_MESSAGE_MAGIC ((uint32_t)(0x63825363))
-#define N_DHCP4_MESSAGE_FLAG_BROADCAST (htons(0x8000))
-
-enum {
-        N_DHCP4_OP_BOOTREQUEST                          = 1,
-        N_DHCP4_OP_BOOTREPLY                            = 2,
-};
-
-enum {
-        N_DHCP4_OPTION_PAD                              = 0,
-        N_DHCP4_OPTION_SUBNET_MASK                      = 1,
-        N_DHCP4_OPTION_TIME_OFFSET                      = 2,
-        N_DHCP4_OPTION_ROUTER                           = 3,
-        N_DHCP4_OPTION_DOMAIN_NAME_SERVER               = 6,
-        N_DHCP4_OPTION_HOST_NAME                        = 12,
-        N_DHCP4_OPTION_BOOT_FILE_SIZE                   = 13,
-        N_DHCP4_OPTION_DOMAIN_NAME                      = 15,
-        N_DHCP4_OPTION_ROOT_PATH                        = 17,
-        N_DHCP4_OPTION_ENABLE_IP_FORWARDING             = 19,
-        N_DHCP4_OPTION_ENABLE_IP_FORWARDING_NL          = 20,
-        N_DHCP4_OPTION_POLICY_FILTER                    = 21,
-        N_DHCP4_OPTION_INTERFACE_MDR                    = 22,
-        N_DHCP4_OPTION_INTERFACE_TTL                    = 23,
-        N_DHCP4_OPTION_INTERFACE_MTU_AGING_TIMEOUT      = 24,
-        N_DHCP4_OPTION_INTERFACE_MTU                    = 26,
-        N_DHCP4_OPTION_BROADCAST                        = 28,
-        N_DHCP4_OPTION_STATIC_ROUTE                     = 33,
-        N_DHCP4_OPTION_NTP_SERVER                       = 42,
-        N_DHCP4_OPTION_VENDOR_SPECIFIC                  = 43,
-        N_DHCP4_OPTION_REQUESTED_IP_ADDRESS             = 50,
-        N_DHCP4_OPTION_IP_ADDRESS_LEASE_TIME            = 51,
-        N_DHCP4_OPTION_OVERLOAD                         = 52,
-        N_DHCP4_OPTION_MESSAGE_TYPE                     = 53,
-        N_DHCP4_OPTION_SERVER_IDENTIFIER                = 54,
-        N_DHCP4_OPTION_PARAMETER_REQUEST_LIST           = 55,
-        N_DHCP4_OPTION_ERROR_MESSAGE                    = 56,
-        N_DHCP4_OPTION_MAXIMUM_MESSAGE_SIZE             = 57,
-        N_DHCP4_OPTION_RENEWAL_T1_TIME                  = 58,
-        N_DHCP4_OPTION_REBINDING_T2_TIME                = 59,
-        N_DHCP4_OPTION_VENDOR_CLASS_IDENTIFIER          = 60,
-        N_DHCP4_OPTION_CLIENT_IDENTIFIER                = 61,
-        N_DHCP4_OPTION_FQDN                             = 81,
-        N_DHCP4_OPTION_NEW_POSIX_TIMEZONE               = 100,
-        N_DHCP4_OPTION_NEW_TZDB_TIMEZONE                = 101,
-        N_DHCP4_OPTION_CLASSLESS_STATIC_ROUTE           = 121,
-        N_DHCP4_OPTION_PRIVATE_BASE                     = 224,
-        N_DHCP4_OPTION_PRIVATE_LAST                     = 254,
-        N_DHCP4_OPTION_END                              = 255,
-        _N_DHCP4_OPTION_N                               = 256,
-};
-
-enum {
-        N_DHCP4_OVERLOAD_FILE                           = 1,
-        N_DHCP4_OVERLOAD_SNAME                          = 2,
-};
-
-enum {
-        N_DHCP4_MESSAGE_DISCOVER                        = 1,
-        N_DHCP4_MESSAGE_OFFER                           = 2,
-        N_DHCP4_MESSAGE_REQUEST                         = 3,
-        N_DHCP4_MESSAGE_DECLINE                         = 4,
-        N_DHCP4_MESSAGE_ACK                             = 5,
-        N_DHCP4_MESSAGE_NAK                             = 6,
-        N_DHCP4_MESSAGE_RELEASE                         = 7,
-        N_DHCP4_MESSAGE_INFORM                          = 8,
-        N_DHCP4_MESSAGE_FORCERENEW                      = 9,
-};
-
-struct NDhcp4Header {
-        uint8_t op;
-        uint8_t htype;
-        uint8_t hlen;
-        uint8_t hops;
-        uint32_t xid;
-        uint16_t secs;
-        uint16_t flags;
-        uint32_t ciaddr;
-        uint32_t yiaddr;
-        uint32_t siaddr;
-        uint32_t giaddr;
-        uint8_t chaddr[16];
-} _c_packed_;
-
-struct NDhcp4Message {
-        NDhcp4Header header;
-        uint8_t sname[64];
-        uint8_t file[128];
-        uint32_t magic;
-        uint8_t options[];
-} _c_packed_;
-
-/* objects */
-
-enum {
-        _N_DHCP4_E_INTERNAL = _N_DHCP4_E_N,
-
-        N_DHCP4_E_UNEXPECTED,
-
-        N_DHCP4_E_NO_SPACE,
-        N_DHCP4_E_MALFORMED,
-
-        N_DHCP4_E_DROPPED,
-        N_DHCP4_E_DOWN,
-        N_DHCP4_E_AGAIN,
-};
-
-enum {
-        N_DHCP4_C_CONNECTION_STATE_INIT,
-        N_DHCP4_C_CONNECTION_STATE_PACKET,
-        N_DHCP4_C_CONNECTION_STATE_DRAINING,
-        N_DHCP4_C_CONNECTION_STATE_UDP,
-        N_DHCP4_C_CONNECTION_STATE_CLOSED,
-};
-
-enum {
-        N_DHCP4_CLIENT_EPOLL_TIMER,
-        N_DHCP4_CLIENT_EPOLL_IO,
-};
-
-enum {
-        N_DHCP4_CLIENT_PROBE_STATE_INIT,
-        N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT,
-        N_DHCP4_CLIENT_PROBE_STATE_SELECTING,
-        N_DHCP4_CLIENT_PROBE_STATE_REBOOTING,
-        N_DHCP4_CLIENT_PROBE_STATE_REQUESTING,
-        N_DHCP4_CLIENT_PROBE_STATE_GRANTED,
-        N_DHCP4_CLIENT_PROBE_STATE_BOUND,
-        N_DHCP4_CLIENT_PROBE_STATE_RENEWING,
-        N_DHCP4_CLIENT_PROBE_STATE_REBINDING,
-        N_DHCP4_CLIENT_PROBE_STATE_EXPIRED,
-};
-
-enum {
-        N_DHCP4_CLIENT_LEASE_STATE_INIT,
-        N_DHCP4_CLIENT_LEASE_STATE_OFFERED,
-        N_DHCP4_CLIENT_LEASE_STATE_SELECTED,
-        N_DHCP4_CLIENT_LEASE_STATE_DECLINED,
-        N_DHCP4_CLIENT_LEASE_STATE_ACKED,
-};
-
-enum {
-        N_DHCP4_SERVER_EPOLL_TIMER,
-        N_DHCP4_SERVER_EPOLL_IO,
-};
-
-enum {
-        _N_DHCP4_C_MESSAGE_INVALID = 0,
-        N_DHCP4_C_MESSAGE_DISCOVER,
-        N_DHCP4_C_MESSAGE_INFORM,
-        N_DHCP4_C_MESSAGE_SELECT,
-        N_DHCP4_C_MESSAGE_IGNORE,
-        N_DHCP4_C_MESSAGE_RENEW,
-        N_DHCP4_C_MESSAGE_REBIND,
-        N_DHCP4_C_MESSAGE_REBOOT,
-        N_DHCP4_C_MESSAGE_RELEASE,
-        N_DHCP4_C_MESSAGE_DECLINE,
-};
-
-struct NDhcp4Outgoing {
-        NDhcp4Message *message;
-        size_t n_message;
-        size_t i_message;
-        size_t max_size;
-
-        uint8_t overload : 2;
-
-        struct {
-                uint8_t type;
-                uint8_t message_type;
-                uint32_t client_addr;
-                uint64_t start_time;
-                uint64_t base_time;
-                uint64_t send_time;
-                uint64_t send_jitter;
-                size_t n_send;
-        } userdata;
-};
-
-#define N_DHCP4_OUTGOING_NULL(_x) {                                             \
-        }
-
-struct NDhcp4Incoming {
-        struct {
-                uint8_t *value;
-                size_t size;
-        } options[_N_DHCP4_OPTION_N];
-
-        struct {
-                uint8_t type;
-                uint64_t start_time;
-                uint64_t base_time;
-        } userdata;
-
-        size_t n_message;
-        NDhcp4Message message;
-        /* @message must be the last member */
-};
-
-#define N_DHCP4_INCOMING_NULL(_x) {                                             \
-        }
-
-struct NDhcp4ClientConfig {
-        int ifindex;
-        unsigned int transport;
-        bool request_broadcast;
-        uint8_t mac[32]; /* MAX_ADDR_LEN */
-        size_t n_mac;
-        uint8_t broadcast_mac[32]; /* MAX_ADDR_LEN */
-        size_t n_broadcast_mac;
-        uint8_t *client_id;
-        size_t n_client_id;
-};
-
-#define N_DHCP4_CLIENT_CONFIG_NULL(_x) {                                        \
-                .transport = _N_DHCP4_TRANSPORT_N,                              \
-        }
-
-struct NDhcp4ClientProbeOption {
-        uint8_t option;
-        uint8_t n_data;
-        uint8_t data[];
-};
-
-#define N_DHCP4_CLIENT_PROBE_OPTION_NULL(_x) {                                  \
-                .option = N_DHCP4_OPTION_PAD,                                   \
-        }
-
-struct NDhcp4ClientProbeConfig {
-        bool inform_only;
-        bool init_reboot;
-        struct in_addr requested_ip;
-        unsigned short int entropy[3];
-        uint64_t ms_start_delay;        /* max ms to wait before starting probe */
-        NDhcp4ClientProbeOption *options[UINT8_MAX + 1];
-        int8_t request_parameters[UINT8_MAX + 1];
-        size_t n_request_parameters;
-};
-
-#define N_DHCP4_CLIENT_PROBE_CONFIG_NULL(_x) {                                  \
-                .ms_start_delay = N_DHCP4_CLIENT_START_DELAY_RFC2131,           \
-        }
-
-struct NDhcp4CEventNode {
-        CList client_link;
-        CList probe_link;
-        NDhcp4ClientEvent event;
-        bool is_public : 1;
-};
-
-#define N_DHCP4_C_EVENT_NODE_NULL(_x) {                                         \
-                .client_link = C_LIST_INIT((_x).client_link),                   \
-                .probe_link = C_LIST_INIT((_x).probe_link),                     \
-        }
-
-struct NDhcp4LogQueue {
-        CList *event_list;
-        NDhcp4CEventNode nomem_node;
-        int log_level;
-        bool is_client : 1;
-};
-
-#define N_DHCP4_LOG_QUEUE_NULL_DEFUNCT() {                                      \
-                .log_level = -1,                                                \
-                .is_client = false,                                             \
-        }
-
-#define N_DHCP4_LOG_QUEUE_NULL_CLIENT(client) {                                 \
-                .event_list = &((client).event_list),                           \
-                .log_level = -1,                                                \
-                .is_client = true,                                              \
-                .nomem_node = {                                                 \
-                        .client_link = C_LIST_INIT((client).log_queue.nomem_node.client_link), \
-                        .probe_link = C_LIST_INIT((client).log_queue.nomem_node.probe_link), \
-                        .event = {                                              \
-                                .event = N_DHCP4_CLIENT_EVENT_LOG,              \
-                                .log = {                                        \
-                                        .level = LOG_CRIT,                      \
-                                        .message = "one or more logging messages dropped due to out of memory", \
-                                        .allow_steal_message = false,           \
-                                },                                              \
-                        },                                                      \
-                        .is_public = false,                                     \
-                },                                                              \
-        }
-
-struct NDhcp4CConnection {
-        NDhcp4ClientConfig *client_config;
-        NDhcp4ClientProbeConfig *probe_config;
-        NDhcp4LogQueue *log_queue;
-
-        int fd_epoll;
-
-        unsigned int state;             /* current connection state */
-        int fd_packet;                  /* packet socket */
-        int fd_udp;                     /* udp socket */
-
-        NDhcp4Outgoing *request;        /* current request */
-
-        uint32_t client_ip;             /* client IP address, or 0 */
-        uint32_t server_ip;             /* server IP address, or 0 */
-        uint16_t mtu;                   /* client mtu, or 0 */
-
-        /*
-         * When we get DHCP packets from the kernel, we need a buffer to read
-         * the data into. Since UDP packets can be up to 2^16 bytes in size, we
-         * avoid placing it on the stack and instead read into this scratch
-         * buffer. It is purely meant as stack replacement, no data is returned
-         * through this buffer.
-         */
-        uint8_t scratch_buffer[UINT16_MAX];
-};
-
-#define N_DHCP4_C_CONNECTION_NULL(_x) {                                         \
-                .fd_packet = -1,                                                \
-                .fd_udp = -1,                                                   \
-        }
-
-struct NDhcp4Client {
-        unsigned long n_refs;
-        NDhcp4ClientConfig *config;
-        CList event_list;
-
-        NDhcp4LogQueue log_queue;
-
-        int fd_epoll;
-        int fd_timer;
-
-        uint16_t mtu;
-        NDhcp4ClientProbe *current_probe;
-        uint64_t scheduled_timeout;
-
-        bool preempted : 1;
-};
-
-#define N_DHCP4_CLIENT_NULL(_x) {                                               \
-                .n_refs = 1,                                                    \
-                .event_list = C_LIST_INIT((_x).event_list),                     \
-                .fd_epoll = -1,                                                 \
-                .fd_timer = -1,                                                 \
-                .log_queue = N_DHCP4_LOG_QUEUE_NULL_CLIENT(_x),                 \
-        }
-
-struct NDhcp4ClientProbe {
-        NDhcp4ClientProbeConfig *config;
-        NDhcp4Client *client;
-        CList event_list;
-        CList lease_list;
-        void *userdata;
-
-        unsigned int state;                     /* current probe state */
-        struct in_addr last_address;            /* last address obtained */
-        uint64_t ns_deferred;                   /* timeout for deferred action */
-        uint64_t ns_reinit;
-        uint64_t ns_nak_restart_delay;          /* restart delay after a nak */
-        NDhcp4ClientLease *current_lease;       /* current lease */
-
-        NDhcp4CConnection connection;           /* client connection wrapper */
-};
-
-#define N_DHCP4_CLIENT_PROBE_NULL(_x) {                                         \
-                .event_list = C_LIST_INIT((_x).event_list),                     \
-                .lease_list = C_LIST_INIT((_x).lease_list),                     \
-                .connection = N_DHCP4_C_CONNECTION_NULL((_x).connection),       \
-        }
-
-struct NDhcp4ClientLease {
-        unsigned long n_refs;
-
-        NDhcp4ClientProbe *probe;
-        CList probe_link;
-
-        NDhcp4Incoming *message;
-
-        uint64_t t1;
-        uint64_t t2;
-        uint64_t lifetime;
-};
-
-#define N_DHCP4_CLIENT_LEASE_NULL(_x) {                                         \
-                .n_refs = 1,                                                    \
-                .probe_link = C_LIST_INIT((_x).probe_link),                     \
-        }
-
-struct NDhcp4ServerConfig {
-        int ifindex;
-};
-
-#define N_DHCP4_SERVER_CONFIG_NULL(_x) {                                        \
-        }
-
-struct NDhcp4SEventNode {
-        CList server_link;
-        NDhcp4ServerEvent event;
-        bool is_public : 1;
-};
-
-#define N_DHCP4_S_EVENT_NODE_NULL(_x) {                                         \
-                .server_link = C_LIST_INIT((_x).server_link),                   \
-        }
-
-struct NDhcp4SConnection {
-        int ifindex;                    /* interface index */
-        int fd_packet;                  /* packet socket */
-        int fd_udp;                     /* udp socket */
-        uint8_t buf[UINT16_MAX];        /* scratch recevie buffer */
-
-        /* XXX: support a set of server addresses */
-        NDhcp4SConnectionIp *ip;        /* server IP address, or NULL */
-};
-
-#define N_DHCP4_S_CONNECTION_NULL(_x) {                                         \
-                .fd_packet = -1,                                                \
-                .fd_udp = -1,                                                   \
-        }
-
-struct NDhcp4SConnectionIp {
-        NDhcp4SConnection *connection;
-        struct in_addr ip;
-};
-
-#define N_DHCP4_S_CONNECTION_IP_NULL(_x) {                                      \
-}
-
-struct NDhcp4Server {
-        unsigned long n_refs;
-        CList event_list;
-        CList lease_list;
-
-        bool preempted : 1;
-
-        NDhcp4SConnection connection;
-};
-
-#define N_DHCP4_SERVER_NULL(_x) {                                               \
-                .n_refs = 1,                                                    \
-                .event_list = C_LIST_INIT((_x).event_list),                     \
-                .lease_list = C_LIST_INIT((_x).lease_list),                     \
-                .connection = N_DHCP4_S_CONNECTION_NULL((_x).connection),       \
-        }
-
-struct NDhcp4ServerIp {
-                NDhcp4SConnectionIp ip;
-};
-
-#define N_DHCP4_SERVER_IP_NULL(_x) {                                            \
-                .ip = N_DHCP4_S_CONNECTION_IP_NULL((_x).ip),                    \
-        }
-
-struct NDhcp4ServerLease {
-        unsigned long n_refs;
-
-        NDhcp4Server *server;
-        CList server_link;
-
-        NDhcp4Incoming *request;
-        NDhcp4Incoming *reply;
-};
-
-#define N_DHCP4_SERVER_LEASE_NULL(_x) {                                         \
-                .n_refs = 1,                                                    \
-                .server_link = C_LIST_INIT((_x).server_link),                   \
-        }
-
-/* outgoing messages */
-
-int n_dhcp4_outgoing_new(NDhcp4Outgoing **outgoingp, size_t max_size, uint8_t overload);
-NDhcp4Outgoing *n_dhcp4_outgoing_free(NDhcp4Outgoing *outgoing);
-
-NDhcp4Header *n_dhcp4_outgoing_get_header(NDhcp4Outgoing *outgoing);
-size_t n_dhcp4_outgoing_get_raw(NDhcp4Outgoing *outgoing, const void **rawp);
-int n_dhcp4_outgoing_append(NDhcp4Outgoing *outgoing, uint8_t option, const void *data, uint8_t n_data);
-
-int n_dhcp4_outgoing_append_t1(NDhcp4Outgoing *message, uint32_t t1);
-int n_dhcp4_outgoing_append_t2(NDhcp4Outgoing *message, uint32_t t2);
-int n_dhcp4_outgoing_append_lifetime(NDhcp4Outgoing *message, uint32_t lifetime);
-int n_dhcp4_outgoing_append_server_identifier(NDhcp4Outgoing *message, struct in_addr addr);
-int n_dhcp4_outgoing_append_requested_ip(NDhcp4Outgoing *message, struct in_addr addr);
-
-void n_dhcp4_outgoing_set_secs(NDhcp4Outgoing *message, uint16_t secs);
-void n_dhcp4_outgoing_set_xid(NDhcp4Outgoing *message, uint32_t xid);
-void n_dhcp4_outgoing_set_yiaddr(NDhcp4Outgoing *message, struct in_addr yiaddr);
-
-void n_dhcp4_outgoing_get_xid(NDhcp4Outgoing *message, uint32_t *xidp);
-
-/* incoming messages */
-
-int n_dhcp4_incoming_new(NDhcp4Incoming **incomingp, const void *raw, size_t n_raw);
-NDhcp4Incoming *n_dhcp4_incoming_free(NDhcp4Incoming *incoming);
-
-NDhcp4Header *n_dhcp4_incoming_get_header(NDhcp4Incoming *incoming);
-size_t n_dhcp4_incoming_get_raw(NDhcp4Incoming *incoming, const void **rawp);
-int n_dhcp4_incoming_query(NDhcp4Incoming *incoming, uint8_t option, uint8_t **datap, size_t *n_datap);
-
-int n_dhcp4_incoming_query_message_type(NDhcp4Incoming *message, uint8_t *typep);
-int n_dhcp4_incoming_query_lifetime(NDhcp4Incoming *message, uint32_t *lifetimep);
-int n_dhcp4_incoming_query_t2(NDhcp4Incoming *message, uint32_t *t2p);
-int n_dhcp4_incoming_query_t1(NDhcp4Incoming *message, uint32_t *t1p);
-int n_dhcp4_incoming_query_server_identifier(NDhcp4Incoming *message, struct in_addr *idp);
-int n_dhcp4_incoming_query_max_message_size(NDhcp4Incoming *message, uint16_t *max_message_sizep);
-int n_dhcp4_incoming_query_requested_ip(NDhcp4Incoming *message, struct in_addr *requested_ipp);
-
-void n_dhcp4_incoming_get_xid(NDhcp4Incoming *message, uint32_t *xidp);
-void n_dhcp4_incoming_get_yiaddr(NDhcp4Incoming *message, struct in_addr *yiaddr);
-
-/* sockets */
-
-int n_dhcp4_c_socket_packet_new(int *sockfdp, int ifindex);
-int n_dhcp4_c_socket_udp_new(int *sockfdp,
-                             int ifindex,
-                             const struct in_addr *client_addr,
-                             const struct in_addr *server_addr);
-int n_dhcp4_s_socket_packet_new(int *sockfdp);
-int n_dhcp4_s_socket_udp_new(int *sockfdp, int ifindex);
-
-int n_dhcp4_c_socket_packet_send(int sockfd,
-                                 int ifindex,
-                                 const unsigned char *dest_haddr,
-                                 unsigned char halen,
-                                 NDhcp4Outgoing *message);
-int n_dhcp4_c_socket_udp_send(int sockfd, NDhcp4Outgoing *message);
-int n_dhcp4_c_socket_udp_broadcast(int sockfd, NDhcp4Outgoing *message);
-int n_dhcp4_s_socket_packet_send(int sockfd,
-                                 int ifindex,
-                                 const struct in_addr *src_inaddr,
-                                 const unsigned char *dest_haddr,
-                                 unsigned char halen,
-                                 const struct in_addr *dest_inaddr,
-                                 NDhcp4Outgoing *message);
-int n_dhcp4_s_socket_udp_send(int sockfd,
-                              const struct in_addr *inaddr_src,
-                              const struct in_addr *inaddr_dest,
-                              NDhcp4Outgoing *message);
-int n_dhcp4_s_socket_udp_broadcast(int sockfd,
-                                   const struct in_addr *inaddr_src,
-                                   NDhcp4Outgoing *message);
-
-int n_dhcp4_c_socket_packet_recv(int sockfd,
-                                 uint8_t *buf,
-                                 size_t n_buf,
-                                 NDhcp4Incoming **messagep);
-int n_dhcp4_c_socket_udp_recv(int sockfd,
-                              uint8_t *buf,
-                              size_t n_buf,
-                              NDhcp4Incoming **messagep);
-int n_dhcp4_s_socket_udp_recv(int sockfd,
-                              uint8_t *buf,
-                              size_t n_buf,
-                              NDhcp4Incoming **messagep,
-                              struct sockaddr_in *dest);
-
-/* client configs */
-
-int n_dhcp4_client_config_dup(NDhcp4ClientConfig *config,
-                              NDhcp4ClientConfig **dupp);
-
-/* client probe configs */
-
-int n_dhcp4_client_probe_config_dup(NDhcp4ClientProbeConfig *config,
-                                    NDhcp4ClientProbeConfig **dupp);
-uint32_t n_dhcp4_client_probe_config_get_random(NDhcp4ClientProbeConfig *config);
-
-/* client events */
-
-int n_dhcp4_c_event_node_new(NDhcp4CEventNode **nodep);
-NDhcp4CEventNode *n_dhcp4_c_event_node_free(NDhcp4CEventNode *node);
-
-/* client connections */
-
-int n_dhcp4_c_connection_init(NDhcp4CConnection *connection,
-                              NDhcp4ClientConfig *client_config,
-                              NDhcp4ClientProbeConfig *probe_config,
-                              NDhcp4LogQueue *log_queue,
-                              int fd_epoll);
-void n_dhcp4_c_connection_deinit(NDhcp4CConnection *connection);
-
-int n_dhcp4_c_connection_listen(NDhcp4CConnection *connection);
-int n_dhcp4_c_connection_connect(NDhcp4CConnection *connection,
-                                 const struct in_addr *client,
-                                 const struct in_addr *server);
-void n_dhcp4_c_connection_close(NDhcp4CConnection *connection);
-
-void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
-                                      uint64_t *timeoutp);
-
-int n_dhcp4_c_connection_discover_new(NDhcp4CConnection *connection,
-                                      NDhcp4Outgoing **request);
-int n_dhcp4_c_connection_select_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **request,
-                                    NDhcp4Incoming *offer);
-int n_dhcp4_c_connection_reboot_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **request,
-                                    const struct in_addr *client);
-int n_dhcp4_c_connection_renew_new(NDhcp4CConnection *connection,
-                                   NDhcp4Outgoing **request);
-int n_dhcp4_c_connection_rebind_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **request);
-int n_dhcp4_c_connection_decline_new(NDhcp4CConnection *connection,
-                                     NDhcp4Outgoing **request,
-                                     NDhcp4Incoming *ack,
-                                     const char *error);
-int n_dhcp4_c_connection_inform_new(NDhcp4CConnection *connection,
-                                    NDhcp4Outgoing **request);
-int n_dhcp4_c_connection_release_new(NDhcp4CConnection *connection,
-                                     NDhcp4Outgoing **request,
-                                     const char *error);
-
-int n_dhcp4_c_connection_start_request(NDhcp4CConnection *connection,
-                                       NDhcp4Outgoing *request,
-                                       uint64_t timestamp);
-int n_dhcp4_c_connection_dispatch_timer(NDhcp4CConnection *connection,
-                                        uint64_t timestamp);
-int n_dhcp4_c_connection_dispatch_io(NDhcp4CConnection *connection,
-                                     NDhcp4Incoming **messagep);
-
-/* clients */
-
-int n_dhcp4_client_raise(NDhcp4Client *client, NDhcp4CEventNode **nodep, unsigned int event);
-void n_dhcp4_client_arm_timer(NDhcp4Client *client);
-
-/* client probes */
-
-int n_dhcp4_client_probe_new(NDhcp4ClientProbe **probep,
-                             NDhcp4ClientProbeConfig *config,
-                             NDhcp4Client *client,
-                             uint64_t ns_now);
-
-int n_dhcp4_client_probe_raise(NDhcp4ClientProbe *probe, NDhcp4CEventNode **nodep, unsigned int event);
-void n_dhcp4_client_probe_get_timeout(NDhcp4ClientProbe *probe, uint64_t *timeoutp);
-int n_dhcp4_client_probe_dispatch_timer(NDhcp4ClientProbe *probe, uint64_t ns_now);
-int n_dhcp4_client_probe_dispatch_io(NDhcp4ClientProbe *probe, uint32_t events);
-int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, uint64_t ns_now);
-int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incoming *ack);
-int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, const char *error, uint64_t ns_now);
-int n_dhcp4_client_probe_update_mtu(NDhcp4ClientProbe *probe, uint16_t mtu);
-
-/* client leases */
-
-int n_dhcp4_client_lease_new(NDhcp4ClientLease **leasep, NDhcp4Incoming *message);
-void n_dhcp4_client_lease_link(NDhcp4ClientLease *lease, NDhcp4ClientProbe *probe);
-void n_dhcp4_client_lease_unlink(NDhcp4ClientLease *lease);
-
-/* server connections */
-
-int n_dhcp4_s_connection_init(NDhcp4SConnection *connection, int ifindex);
-void n_dhcp4_s_connection_deinit(NDhcp4SConnection *connection);
-
-void n_dhcp4_s_connection_get_fd(NDhcp4SConnection *connection, int *fdp);
-int n_dhcp4_s_connection_dispatch_io(NDhcp4SConnection *connection, NDhcp4Incoming **messagep);
-
-int n_dhcp4_s_connection_offer_new(NDhcp4SConnection *connection,
-                                   NDhcp4Outgoing **replyp,
-                                   NDhcp4Incoming *request,
-                                   const struct in_addr *server_address,
-                                   const struct in_addr *client_address,
-                                   uint32_t lifetime);
-int n_dhcp4_s_connection_ack_new(NDhcp4SConnection *connection,
-                                   NDhcp4Outgoing **replyp,
-                                   NDhcp4Incoming *request,
-                                   const struct in_addr *server_address,
-                                   const struct in_addr *client_address,
-                                   uint32_t lifetime);
-int n_dhcp4_s_connection_nak_new(NDhcp4SConnection *connection,
-                                 NDhcp4Outgoing **replyp,
-                                 NDhcp4Incoming *request,
-                                 const struct in_addr *server_address);
-
-int n_dhcp4_s_connection_send_reply(NDhcp4SConnection *connection,
-                                    const struct in_addr *server_addr,
-                                    NDhcp4Outgoing *reply);
-
-/* server connection ips */
-
-void n_dhcp4_s_connection_ip_init(NDhcp4SConnectionIp *ip, struct in_addr addr);
-void n_dhcp4_s_connection_ip_deinit(NDhcp4SConnectionIp *ip);
-
-void n_dhcp4_s_connection_ip_link(NDhcp4SConnectionIp *ip, NDhcp4SConnection *connection);
-void n_dhcp4_s_connection_ip_unlink(NDhcp4SConnectionIp *ip);
-
-/* inline helpers */
-
-static inline void n_dhcp4_outgoing_freep(NDhcp4Outgoing **outgoing) {
-        if (*outgoing)
-                n_dhcp4_outgoing_free(*outgoing);
-}
-
-static inline void n_dhcp4_incoming_freep(NDhcp4Incoming **incoming) {
-        if (*incoming)
-                n_dhcp4_incoming_free(*incoming);
-}
-
-static inline uint64_t n_dhcp4_gettime(clockid_t clock) {
-        struct timespec ts;
-        int r;
-
-        r = clock_gettime(clock, &ts);
-        c_assert(r >= 0);
-
-        return ts.tv_sec * 1000ULL * 1000ULL * 1000ULL + ts.tv_nsec;
-}
-
-void n_dhcp4_log_queue_fmt(NDhcp4LogQueue *log_queue,
-                           int level,
-                           const char *fmt,
-                           ...) _c_printf_(3, 4);
-
-/**
- * n_dhcp4_log() - append a logging event
- * @x_log_queue:   the logging event queue
- * @x_level:       the syslog logging level for the message.
- * @...:           the format string and arguments.
- *
- * Warning: this macro only evaluates the format arguments if the logging
- * level is enabled.
- */
-#define n_dhcp4_log(x_log_queue, x_level, ...)                                 \
-        do {                                                                   \
-                NDhcp4LogQueue *const _log_queue = (x_log_queue);              \
-                const int _level = (x_level);                                  \
-                                                                               \
-                if (_level <= _log_queue->log_level) {                         \
-                        n_dhcp4_log_queue_fmt(_log_queue,                      \
-                                              _level,                          \
-                                              __VA_ARGS__);                    \
-                }                                                              \
-        } while (0)
diff --git a/shared/n-dhcp4/src/n-dhcp4-socket.c b/shared/n-dhcp4/src/n-dhcp4-socket.c
deleted file mode 100644
index 3e703b4f..00000000
--- a/shared/n-dhcp4/src/n-dhcp4-socket.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * DHCP specific low-level socket helpers
- */
-
-#include <c-stdaux.h>
-#include <errno.h>
-#include <linux/filter.h>
-#include <sys/socket.h> /* needed by linux/if.h */
-#include <linux/if.h>
-#include <linux/if_packet.h>
-#include <linux/netdevice.h>
-#include <linux/udp.h>
-#include <netinet/ip.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/types.h>
-#include "n-dhcp4-private.h"
-#include "util/packet.h"
-#include "util/socket.h"
-
-/**
- * n_dhcp4_c_socket_packet_new() - create a new DHCP4 client packet socket
- * @sockfdp:            return argument for the new socket
- * @ifindex:            interface index to bind to
- *
- * Create a new AF_PACKET/SOCK_DGRAM socket usable to listen to and send DHCP client
- * packets before an IP address has been configured.
- *
- * Only unfragmented DHCP packets from a server to a client destined for the given
- * ifindex is returned.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int n_dhcp4_c_socket_packet_new(int *sockfdp, int ifindex) {
-        _c_cleanup_(c_closep) int sockfd = -1;
-        struct sock_filter filter[] = {
-                /*
-                 * IP
-                 *
-                 * Check
-                 *  - UDP
-                 *  - Unfragmented
-                 *  - Large enough to fit the DHCP header
-                 *
-                 *  Leave X the size of the IP header, for future indirect reads.
-                 */
-                BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct iphdr, protocol)),                           /* A <- IP protocol */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0),                                         /* IP protocol == UDP ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct iphdr, frag_off)),                           /* A <- Flags + Fragment offset */
-                BPF_STMT(BPF_ALU + BPF_AND + BPF_K, IP_MF | IP_OFFMASK),                                        /* A <- A & (IP_MF | IP_OFFMASK) */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                                                   /* fragmented packet ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 0),                                                         /* X <- IP header length */
-                BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0),                                                          /* A <- packet length */
-                BPF_STMT(BPF_ALU + BPF_SUB + BPF_X, 0),                                                         /* A -= X */
-                BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct udphdr) + sizeof(NDhcp4Message), 1, 0),       /* packet >= DHCPPacket ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                /*
-                 * UDP
-                 *
-                 * Check
-                 *  - DHCP client port
-                 *
-                 * Leave X the size of IP and UDP headers, for future indirect reads.
-                 */
-                BPF_STMT(BPF_LD + BPF_H + BPF_IND, offsetof(struct udphdr, dest)),                              /* A <- UDP destination port */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_NETWORK_CLIENT_PORT, 1, 0),                         /* UDP destination port == DHCP client port ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LD + BPF_W + BPF_K, sizeof(struct udphdr)),                                        /* A <- size of UDP header */
-                BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),                                                         /* A += X */
-                BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                                /* X <- A */
-
-                /*
-                 * DHCP
-                 *
-                 * Check
-                 *  - BOOTREPLY (from server to client)
-                 *  - DHCP magic cookie
-                 */
-                BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(NDhcp4Header, op)),                                 /* A <- DHCP op */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_OP_BOOTREPLY, 1, 0),                                /* op == BOOTREPLY ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LD + BPF_W + BPF_IND, offsetof(NDhcp4Message, magic)),                             /* A <- DHCP magic cookie */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_MESSAGE_MAGIC, 1, 0),                               /* cookie == DHCP magic cookie ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_RET + BPF_K, 65535),                                                               /* return all */
-        };
-        struct sock_fprog fprog = {
-                .filter = filter,
-                .len = sizeof(filter) / sizeof(filter[0]),
-        };
-        struct sockaddr_ll addr = {
-                .sll_family = AF_PACKET,
-                .sll_protocol = htons(ETH_P_IP),
-                .sll_ifindex = ifindex,
-        };
-        int r, on = 1;
-
-        sockfd = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-        if (sockfd < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
-        if (r < 0)
-                return -errno;
-
-        /* We need the flag that tells us if the checksum is correct. */
-        r = setsockopt(sockfd, SOL_PACKET, PACKET_AUXDATA, &on, sizeof(on));
-        if (r < 0)
-                return -errno;
-
-        r = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
-        if (r < 0)
-                return -errno;
-
-        *sockfdp = sockfd;
-        sockfd = -1;
-        return 0;
-}
-
-/**
- * n_dhcp4_c_socket_udp_new() - create a new DHCP4 client UDP socket
- * @sockfdp:            return argument for the new socket
- * @ifindex:            interface index to bind to
- * @client_addr:        client address to bind to
- * @server_addr:        server address to connect to
- *
- * Create a new AF_INET/SOCK_DGRAM socket usable to listen to and send DHCP client
- * packets.
- *
- * The client address given in @addr must be configured on the interface @ifindex
- * before the socket is created.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int n_dhcp4_c_socket_udp_new(int *sockfdp,
-                             int ifindex,
-                             const struct in_addr *client_addr,
-                             const struct in_addr *server_addr) {
-        _c_cleanup_(c_closep) int sockfd = -1;
-        struct sock_filter filter[] = {
-                /*
-                 * IP/UDP
-                 *
-                 * Set X to the size of IP and UDP headers, for future indirect reads.
-                 */
-                BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 0),                                                         /* X <- IP header length */
-                BPF_STMT(BPF_LD + BPF_W + BPF_K, sizeof(struct udphdr)),                                        /* A <- size of UDP header */
-                BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),                                                         /* A += X */
-                BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                                /* X <- A */
-
-                /*
-                 * DHCP
-                 *
-                 * Check
-                 *  - BOOTREPLY (from server to client)
-                 *  - DHCP magic cookie
-                 */
-                BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(NDhcp4Header, op)),                                 /* A <- DHCP op */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_OP_BOOTREPLY, 1, 0),                                /* op == BOOTREPLY ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LD + BPF_W + BPF_IND, offsetof(NDhcp4Message, magic)),                             /* A <- DHCP magic cookie */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_MESSAGE_MAGIC, 1, 0),                               /* cookie == DHCP magic cookie ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_RET + BPF_K, 65535),                                                               /* return all */
-        };
-        struct sock_fprog fprog = {
-                .filter = filter,
-                .len = sizeof(filter) / sizeof(filter[0]),
-        };
-        struct sockaddr_in saddr = {
-                .sin_family = AF_INET,
-                .sin_addr = *client_addr,
-                .sin_port = htons(N_DHCP4_NETWORK_CLIENT_PORT),
-        };
-        struct sockaddr_in daddr = {
-                .sin_family = AF_INET,
-                .sin_addr = *server_addr,
-                .sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT),
-        };
-        int r, tos = IPTOS_CLASS_CS6, on = 1;
-
-        sockfd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-        if (sockfd < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
-        if (r < 0)
-                return -errno;
-
-        r = socket_bind_if(sockfd, ifindex);
-        if (r)
-                return r;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
-        if (r < 0)
-                return -errno;
-
-        r = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
-        if (r < 0)
-                return -errno;
-
-        r = connect(sockfd, (struct sockaddr*)&daddr, sizeof(daddr));
-        if (r < 0)
-                return -errno;
-
-        *sockfdp = sockfd;
-        sockfd = -1;
-        return 0;
-}
-
-/**
- * n_dhcp4_s_socket_packet_new() - create a new DHCP4 server packet socket
- * @sockfdp:            return argument for the new socket
- *
- * Create a new AF_PACKET/SOCK_DGRAM socket usable to send DHCP packets to clients
- * before they have an IP address configured, on the given interface.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int n_dhcp4_s_socket_packet_new(int *sockfdp) {
-        _c_cleanup_(c_closep) int sockfd = -1;
-
-        sockfd = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-        if (sockfd < 0)
-                return -errno;
-
-        *sockfdp = sockfd;
-        sockfd = -1;
-        return 0;
-}
-
-/**
- * n_dhcp4_s_socket_udp_new() - create a new DHCP4 server UDP socket
- * @sockfdp:            return argument for the new socket
- * @ifindex:            intercafe index to bind to
- *
- * Create a new AF_INET/SOCK_DGRAM socket usable to listen to DHCP server packets,
- * on the given interface.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int n_dhcp4_s_socket_udp_new(int *sockfdp, int ifindex) {
-        _c_cleanup_(c_closep) int sockfd = -1;
-        struct sock_filter filter[] = {
-                /*
-                 * IP/UDP
-                 *
-                 * Set X to the size of IP and UDP headers, for future indirect reads.
-                 */
-                BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 0),                                                         /* X <- IP header length */
-                BPF_STMT(BPF_LD + BPF_W + BPF_K, sizeof(struct udphdr)),                                        /* A <- size of UDP header */
-                BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),                                                         /* A += X */
-                BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                                /* X <- A */
-
-                /*
-                 * DHCP
-                 *
-                 * Check
-                 *  - BOOTREQUEST (from client to server)
-                 *  - DHCP magic cookie
-                 */
-
-                BPF_STMT(BPF_LD + BPF_B + BPF_IND, offsetof(NDhcp4Header, op)),                                 /* A <- DHCP op */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_OP_BOOTREQUEST, 1, 0),                              /* op == BOOTREQUEST ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_LD + BPF_W + BPF_IND, offsetof(NDhcp4Message, magic)),                             /* A <- DHCP magic cookie */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, N_DHCP4_MESSAGE_MAGIC, 1, 0),                               /* cookie == DHCP magic cookie ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                                                   /* ignore */
-
-                BPF_STMT(BPF_RET + BPF_K, 65535),                                                               /* return all */
-        };
-        struct sock_fprog fprog = {
-                .filter = filter,
-                .len = sizeof(filter) / sizeof(filter[0]),
-        };
-        struct sockaddr_in addr = {
-                .sin_family = AF_INET,
-                .sin_addr = { INADDR_ANY },
-                .sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT),
-        };
-        int r, tos = IPTOS_CLASS_CS6, on = 1;
-
-        sockfd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-        if (sockfd < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
-        if (r < 0)
-                return -errno;
-
-        r = socket_bind_if(sockfd, ifindex);
-        if (r)
-                return r;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
-        if (r < 0)
-                return -errno;
-
-        r = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
-        if (r < 0)
-                return -errno;
-
-        *sockfdp = sockfd;
-        sockfd = -1;
-        return 0;
-}
-
-static int n_dhcp4_socket_packet_send(int sockfd,
-                                      int ifindex,
-                                      const struct sockaddr_in *src_paddr,
-                                      const unsigned char *dest_haddr,
-                                      unsigned char halen,
-                                      const struct sockaddr_in *dest_paddr,
-                                      NDhcp4Outgoing *message) {
-        struct packet_sockaddr_ll haddr = {
-                .sll_family = AF_PACKET,
-                .sll_protocol = htons(ETH_P_IP),
-                .sll_ifindex = ifindex,
-                .sll_halen = halen,
-        };
-        const void *buf;
-        size_t n_buf, len;
-        int r;
-
-        c_assert(halen <= sizeof(haddr.sll_addr));
-
-        memcpy(haddr.sll_addr, dest_haddr, halen);
-
-        n_buf = n_dhcp4_outgoing_get_raw(message, &buf);
-
-        r = packet_sendto_udp(sockfd, buf, n_buf, &len, src_paddr, &haddr, dest_paddr);
-        if (r < 0) {
-                if (r == -EAGAIN || r == -ENOBUFS)
-                        return N_DHCP4_E_DROPPED;
-                else if (r == -ENETDOWN || r == -ENXIO)
-                        return N_DHCP4_E_DOWN;
-                else
-                        return r;
-        } else if (len != n_buf) {
-                return N_DHCP4_E_DROPPED;
-        }
-
-        return 0;
-}
-
-/**
- * n_dhcp4_c_socket_packet_send() - XXX
- */
-int n_dhcp4_c_socket_packet_send(int sockfd,
-                                 int ifindex,
-                                 const unsigned char *dest_haddr,
-                                 unsigned char halen,
-                                 NDhcp4Outgoing *message) {
-        struct sockaddr_in src_paddr = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_CLIENT_PORT),
-                .sin_addr = { INADDR_ANY },
-        };
-        struct sockaddr_in dest_paddr = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT),
-                .sin_addr = { INADDR_BROADCAST }
-        };
-
-        return n_dhcp4_socket_packet_send(sockfd,
-                                          ifindex,
-                                          &src_paddr,
-                                          dest_haddr,
-                                          halen,
-                                          &dest_paddr,
-                                          message);
-}
-
-/**
- * n_dhcp4_c_socket_udp_send() - XXX
- */
-int n_dhcp4_c_socket_udp_send(int sockfd,
-                              NDhcp4Outgoing *message) {
-        const void *buf;
-        size_t n_buf;
-        ssize_t len;
-
-        n_buf = n_dhcp4_outgoing_get_raw(message, &buf);
-
-        len = send(sockfd, buf, n_buf, 0);
-        if (len < 0) {
-                if (errno == EAGAIN || errno == ENOBUFS)
-                        return N_DHCP4_E_DROPPED;
-                else if (errno == ENETDOWN || errno == ENXIO)
-                        return N_DHCP4_E_DOWN;
-                else
-                        return -errno;
-        } else if ((size_t)len != n_buf)
-                return N_DHCP4_E_DROPPED;
-
-        return 0;
-}
-
-/**
- * n_dhcp4_c_socket_udp_broadcast() - XXX
- */
-int n_dhcp4_c_socket_udp_broadcast(int sockfd, NDhcp4Outgoing *message) {
-        struct sockaddr_in sockaddr_dest = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT),
-                .sin_addr = { INADDR_BROADCAST },
-        };
-        const void *buf;
-        size_t n_buf;
-        ssize_t len;
-
-        n_buf = n_dhcp4_outgoing_get_raw(message, &buf);
-
-        len = sendto(sockfd,
-                     buf,
-                     n_buf,
-                     0,
-                     (struct sockaddr*)&sockaddr_dest,
-                     sizeof(sockaddr_dest));
-        if (len < 0) {
-                if (errno == EAGAIN || errno == ENOBUFS)
-                        return N_DHCP4_E_DROPPED;
-                else if (errno == ENETDOWN || errno == ENXIO)
-                        return N_DHCP4_E_DOWN;
-                else
-                        return -errno;
-        } else if ((size_t)len != n_buf)
-                return N_DHCP4_E_DROPPED;
-
-        return 0;
-}
-
-/**
- * n_dhcp4_s_socket_packet_send() - XXX
- */
-int n_dhcp4_s_socket_packet_send(int sockfd,
-                                 int ifindex,
-                                 const struct in_addr *src_inaddr,
-                                 const unsigned char *dest_haddr,
-                                 unsigned char halen,
-                                 const struct in_addr *dest_inaddr,
-                                 NDhcp4Outgoing *message) {
-        struct sockaddr_in src_paddr = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT),
-                .sin_addr = *src_inaddr,
-        };
-        struct sockaddr_in dest_paddr = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_CLIENT_PORT),
-                .sin_addr = *dest_inaddr,
-        };
-
-        return n_dhcp4_socket_packet_send(sockfd,
-                                          ifindex,
-                                          &src_paddr,
-                                          dest_haddr,
-                                          halen,
-                                          &dest_paddr,
-                                          message);
-}
-
-/**
- * n_dhcp4_s_socket_udp_send() - XXX
- */
-int n_dhcp4_s_socket_udp_send(int sockfd,
-                              const struct in_addr *inaddr_src,
-                              const struct in_addr *inaddr_dest,
-                              NDhcp4Outgoing *message) {
-        struct sockaddr_in sockaddr_dest = {
-                .sin_family = AF_INET,
-                .sin_port = htons(N_DHCP4_NETWORK_CLIENT_PORT),
-                .sin_addr = *inaddr_dest,
-        };
-        struct iovec iov = {};
-        union {
-               struct cmsghdr align; /* ensure correct stack alignment */
-               char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
-        } control = {};
-        struct in_pktinfo pktinfo = {
-                .ipi_spec_dst = *inaddr_src,
-        };
-        struct msghdr msg = {
-                .msg_name = (void*)&sockaddr_dest,
-                .msg_namelen = sizeof(sockaddr_dest),
-                .msg_iov = &iov,
-                .msg_iovlen = 1,
-                .msg_control = &control.buf,
-                .msg_controllen = sizeof(control.buf),
-        };
-        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
-        ssize_t len;
-
-        cmsg->cmsg_level = IPPROTO_IP;
-        cmsg->cmsg_type = IP_PKTINFO;
-        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
-        memcpy(CMSG_DATA(cmsg), &pktinfo, sizeof(pktinfo));
-
-        iov.iov_len = n_dhcp4_outgoing_get_raw(message, (const void **)&iov.iov_base);
-
-        len = sendmsg(sockfd, &msg, 0);
-        if (len < 0) {
-                if (errno == EAGAIN || errno == ENOBUFS)
-                        return N_DHCP4_E_DROPPED;
-                else if (errno == ENETDOWN || errno == ENXIO)
-                        return N_DHCP4_E_DOWN;
-                else
-                        return -errno;
-        } else if ((size_t)len != iov.iov_len)
-                return N_DHCP4_E_DROPPED;
-
-        return 0;
-}
-
-int n_dhcp4_s_socket_udp_broadcast(int sockfd,
-                                   const struct in_addr *inaddr_src,
-                                   NDhcp4Outgoing *message) {
-        return n_dhcp4_s_socket_udp_send(sockfd,
-                                         inaddr_src,
-                                         &(const struct in_addr){INADDR_BROADCAST},
-                                         message);
-}
-
-int n_dhcp4_c_socket_packet_recv(int sockfd,
-                                 uint8_t *buf,
-                                 size_t n_buf,
-                                 NDhcp4Incoming **messagep) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
-        size_t len;
-        int r;
-
-        r = packet_recv_udp(sockfd, buf, n_buf, &len);
-        if (r < 0) {
-                if (r == -ENETDOWN)
-                        return N_DHCP4_E_DOWN;
-                else if (r == -EAGAIN)
-                        return N_DHCP4_E_AGAIN;
-                else
-                        return -errno;
-        } else if (len == 0) {
-                return N_DHCP4_E_MALFORMED;
-        }
-
-        r = n_dhcp4_incoming_new(&message, buf, len);
-        if (r)
-                return r;
-
-        *messagep = message;
-        message = NULL;
-        return 0;
-}
-
-static int n_dhcp4_socket_udp_recv(int sockfd,
-                                   uint8_t *buf,
-                                   size_t n_buf,
-                                   NDhcp4Incoming **messagep,
-                                   struct in_pktinfo *pktinfo) {
-        _c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = NULL;
-        struct iovec iov = {
-                .iov_base = buf,
-                .iov_len = n_buf,
-        };
-        uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
-        struct msghdr msg = {
-                .msg_iov = &iov,
-                .msg_iovlen = 1,
-                .msg_control = cmsgbuf,
-                .msg_controllen = sizeof(cmsgbuf),
-        };
-        ssize_t len;
-        int r;
-
-        len = recvmsg(sockfd, &msg, MSG_TRUNC);
-        if (len < 0) {
-                if (errno == ENETDOWN)
-                        return N_DHCP4_E_DOWN;
-                else if (errno == EAGAIN)
-                        return N_DHCP4_E_AGAIN;
-                else
-                        return -errno;
-        } else if (len == 0 || (size_t)len > n_buf) {
-                return N_DHCP4_E_MALFORMED;
-        }
-
-        r = n_dhcp4_incoming_new(&message, buf, len);
-        if (r)
-                return r;
-
-        if (pktinfo) {
-                struct cmsghdr *cmsg;
-
-                cmsg = CMSG_FIRSTHDR(&msg);
-                c_assert(cmsg);
-                c_assert(cmsg->cmsg_level == IPPROTO_IP);
-                c_assert(cmsg->cmsg_type == IP_PKTINFO);
-                c_assert(cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo)));
-
-                memcpy(pktinfo, (void*)CMSG_DATA(cmsg), sizeof(struct in_pktinfo));
-        }
-
-        *messagep = message;
-        message = NULL;
-        return 0;
-}
-
-int n_dhcp4_c_socket_udp_recv(int sockfd,
-                              uint8_t *buf,
-                              size_t n_buf,
-                              NDhcp4Incoming **messagep) {
-        return n_dhcp4_socket_udp_recv(sockfd, buf, n_buf, messagep, NULL);
-}
-
-int n_dhcp4_s_socket_udp_recv(int sockfd,
-                              uint8_t *buf,
-                              size_t n_buf,
-                              NDhcp4Incoming **messagep,
-                              struct sockaddr_in *dest) {
-        struct in_pktinfo pktinfo = {};
-        int r;
-
-        r = n_dhcp4_socket_udp_recv(sockfd, buf, n_buf, messagep, &pktinfo);
-        if (r)
-                return r;
-
-        if (dest) {
-                dest->sin_family = AF_INET;
-                dest->sin_port = htons(N_DHCP4_NETWORK_SERVER_PORT);
-                dest->sin_addr.s_addr = pktinfo.ipi_addr.s_addr;
-        }
-
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/n-dhcp4.h b/shared/n-dhcp4/src/n-dhcp4.h
deleted file mode 100644
index 435c5600..00000000
--- a/shared/n-dhcp4/src/n-dhcp4.h
+++ /dev/null
@@ -1,300 +0,0 @@
-#pragma once
-
-/*
- * Dynamic Host Configuration Protocol for IPv4
- *
- * This is the public header of the n-dhcp4 library, implementing IPv4 Dynamic
- * Host Configuration Protocol as described in RFC-2132. This header defines
- * the public API and all entry points of n-dhcp4.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <inttypes.h>
-#include <netinet/in.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-typedef struct NDhcp4Client NDhcp4Client;
-typedef struct NDhcp4ClientConfig NDhcp4ClientConfig;
-typedef struct NDhcp4ClientEvent NDhcp4ClientEvent;
-typedef struct NDhcp4ClientLease NDhcp4ClientLease;
-typedef struct NDhcp4ClientProbe NDhcp4ClientProbe;
-typedef struct NDhcp4ClientProbeConfig NDhcp4ClientProbeConfig;
-typedef struct NDhcp4Server NDhcp4Server;
-typedef struct NDhcp4ServerConfig NDhcp4ServerConfig;
-typedef struct NDhcp4ServerEvent NDhcp4ServerEvent;
-typedef struct NDhcp4ServerIp NDhcp4ServerIp;
-typedef struct NDhcp4ServerLease NDhcp4ServerLease;
-
-#define N_DHCP4_CLIENT_START_DELAY_RFC2131 (UINT64_C(9000))
-
-enum {
-        _N_DHCP4_E_SUCCESS,
-
-        N_DHCP4_E_PREEMPTED,
-        N_DHCP4_E_INTERNAL,
-
-        N_DHCP4_E_INVALID_IFINDEX,
-        N_DHCP4_E_INVALID_TRANSPORT,
-        N_DHCP4_E_INVALID_ADDRESS,
-        N_DHCP4_E_INVALID_CLIENT_ID,
-        N_DHCP4_E_DUPLICATE_OPTION,
-        N_DHCP4_E_UNSET,
-
-        _N_DHCP4_E_N,
-};
-
-enum {
-        N_DHCP4_TRANSPORT_ETHERNET,
-        N_DHCP4_TRANSPORT_INFINIBAND,
-        _N_DHCP4_TRANSPORT_N,
-};
-
-enum {
-        N_DHCP4_CLIENT_EVENT_DOWN,
-        N_DHCP4_CLIENT_EVENT_OFFER,
-        N_DHCP4_CLIENT_EVENT_GRANTED,
-        N_DHCP4_CLIENT_EVENT_RETRACTED,
-        N_DHCP4_CLIENT_EVENT_EXTENDED,
-        N_DHCP4_CLIENT_EVENT_EXPIRED,
-        N_DHCP4_CLIENT_EVENT_CANCELLED,
-        N_DHCP4_CLIENT_EVENT_LOG,
-        _N_DHCP4_CLIENT_EVENT_N,
-};
-
-enum {
-        N_DHCP4_SERVER_EVENT_DOWN,
-        N_DHCP4_SERVER_EVENT_DISCOVER,
-        N_DHCP4_SERVER_EVENT_REQUEST,
-        N_DHCP4_SERVER_EVENT_RENEW,
-        N_DHCP4_SERVER_EVENT_DECLINE,
-        N_DHCP4_SERVER_EVENT_RELEASE,
-        _N_DHCP4_SERVER_EVENT_N,
-};
-
-struct NDhcp4ClientEvent {
-        unsigned int event;
-        union {
-                struct {
-                } down;
-                struct {
-                        NDhcp4ClientProbe *probe;
-                        NDhcp4ClientLease *lease;
-                } offer, granted, extended;
-                struct {
-                        NDhcp4ClientProbe *probe;
-                } retracted, expired, cancelled;
-                struct {
-                        /* If allow_steal_message is true, then the user may steal the message when handling
-                         * the event. In that case, set the message field to %NULL and free it yourself
-                         * with free(). */
-                        const char *message;
-                        int level;
-                        bool allow_steal_message;
-                } log;
-        };
-};
-
-struct NDhcp4ServerEvent {
-        unsigned int event;
-        union {
-                struct {
-                } down;
-                struct {
-                        NDhcp4ServerLease *lease;
-                } discover, request, decline, release;
-        };
-};
-
-/* client configs */
-
-int n_dhcp4_client_config_new(NDhcp4ClientConfig **configp);
-NDhcp4ClientConfig *n_dhcp4_client_config_free(NDhcp4ClientConfig *config);
-
-void n_dhcp4_client_config_set_ifindex(NDhcp4ClientConfig *config, int ifindex);
-void n_dhcp4_client_config_set_transport(NDhcp4ClientConfig *config, unsigned int transport);
-void n_dhcp4_client_config_set_request_broadcast(NDhcp4ClientConfig *config, bool request_broadcast);
-void n_dhcp4_client_config_set_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac);
-void n_dhcp4_client_config_set_broadcast_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac);
-int n_dhcp4_client_config_set_client_id(NDhcp4ClientConfig *config, const uint8_t *id, size_t n_id);
-
-/* client-probe configs */
-
-int n_dhcp4_client_probe_config_new(NDhcp4ClientProbeConfig **configp);
-NDhcp4ClientProbeConfig *n_dhcp4_client_probe_config_free(NDhcp4ClientProbeConfig *config);
-
-void n_dhcp4_client_probe_config_set_inform_only(NDhcp4ClientProbeConfig *config, bool inform_only);
-void n_dhcp4_client_probe_config_set_init_reboot(NDhcp4ClientProbeConfig *config, bool init_reboot);
-void n_dhcp4_client_probe_config_set_requested_ip(NDhcp4ClientProbeConfig *config, struct in_addr ip);
-void n_dhcp4_client_probe_config_set_start_delay(NDhcp4ClientProbeConfig *config, uint64_t msecs);
-void n_dhcp4_client_probe_config_request_option(NDhcp4ClientProbeConfig *config, uint8_t option);
-int n_dhcp4_client_probe_config_append_option(NDhcp4ClientProbeConfig *config,
-                                              uint8_t option,
-                                              const void *data,
-                                              uint8_t n_data);
-
-/* clients */
-
-int n_dhcp4_client_new(NDhcp4Client **clientp, NDhcp4ClientConfig *config);
-NDhcp4Client *n_dhcp4_client_ref(NDhcp4Client *client);
-NDhcp4Client *n_dhcp4_client_unref(NDhcp4Client *client);
-
-void n_dhcp4_client_get_fd(NDhcp4Client *client, int *fdp);
-int n_dhcp4_client_dispatch(NDhcp4Client *client);
-int n_dhcp4_client_pop_event(NDhcp4Client *client, NDhcp4ClientEvent **eventp);
-
-void n_dhcp4_client_set_log_level(NDhcp4Client *client, int level);
-
-int n_dhcp4_client_update_mtu(NDhcp4Client *client, uint16_t mtu);
-
-int n_dhcp4_client_probe(NDhcp4Client *client,
-                         NDhcp4ClientProbe **probep,
-                         NDhcp4ClientProbeConfig *config);
-
-/* client probes */
-
-NDhcp4ClientProbe *n_dhcp4_client_probe_free(NDhcp4ClientProbe *probe);
-
-void n_dhcp4_client_probe_set_userdata(NDhcp4ClientProbe *probe, void *userdata);
-void n_dhcp4_client_probe_get_userdata(NDhcp4ClientProbe *probe, void **userdatap);
-
-/* client leases */
-
-NDhcp4ClientLease *n_dhcp4_client_lease_ref(NDhcp4ClientLease *lease);
-NDhcp4ClientLease *n_dhcp4_client_lease_unref(NDhcp4ClientLease *lease);
-
-void n_dhcp4_client_lease_get_yiaddr(NDhcp4ClientLease *lease, struct in_addr *yiaddr);
-void n_dhcp4_client_lease_get_siaddr(NDhcp4ClientLease *lease, struct in_addr *siaddr);
-void n_dhcp4_client_lease_get_basetime(NDhcp4ClientLease *lease, uint64_t *ns_basetimep);
-void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint64_t *ns_lifetimep);
-int n_dhcp4_client_lease_query(NDhcp4ClientLease *lease, uint8_t option, uint8_t **datap, size_t *n_datap);
-int n_dhcp4_client_lease_get_server_identifier (NDhcp4ClientLease *lease, struct in_addr *addr);
-
-int n_dhcp4_client_lease_select(NDhcp4ClientLease *lease);
-int n_dhcp4_client_lease_accept(NDhcp4ClientLease *lease);
-int n_dhcp4_client_lease_decline(NDhcp4ClientLease *lease, const char *error);
-
-/* server configs */
-
-int n_dhcp4_server_config_new(NDhcp4ServerConfig **configp);
-NDhcp4ServerConfig *n_dhcp4_server_config_free(NDhcp4ServerConfig *config);
-
-void n_dhcp4_server_config_set_ifindex(NDhcp4ServerConfig *config, int ifindex);
-
-/* servers */
-
-int n_dhcp4_server_new(NDhcp4Server **serverp, NDhcp4ServerConfig *config);
-NDhcp4Server *n_dhcp4_server_ref(NDhcp4Server *server);
-NDhcp4Server *n_dhcp4_server_unref(NDhcp4Server *server);
-
-void n_dhcp4_server_get_fd(NDhcp4Server *server, int *fdp);
-int n_dhcp4_server_dispatch(NDhcp4Server *server);
-int n_dhcp4_server_pop_event(NDhcp4Server *server, NDhcp4ServerEvent **eventp);
-
-int n_dhcp4_server_add_ip(NDhcp4Server *server, NDhcp4ServerIp **ipp, struct in_addr ip);
-
-/* server ip addresses */
-
-NDhcp4ServerIp *n_dhcp4_server_ip_free(NDhcp4ServerIp *ip);
-
-/* server leases */
-
-NDhcp4ServerLease *n_dhcp4_server_lease_ref(NDhcp4ServerLease *lease);
-NDhcp4ServerLease *n_dhcp4_server_lease_unref(NDhcp4ServerLease *lease);
-
-int n_dhcp4_server_lease_query(NDhcp4ServerLease *lease, uint8_t option, uint8_t **datap, size_t *n_datap);
-int n_dhcp4_server_lease_append(NDhcp4ServerLease *lease, uint8_t option, uint8_t *data, size_t n_data);
-
-int n_dhcp4_server_lease_offer(NDhcp4ServerLease *lease);
-int n_dhcp4_server_lease_ack(NDhcp4ServerLease *lease);
-int n_dhcp4_server_lease_nack(NDhcp4ServerLease *lease);
-
-/* inline helpers */
-
-static inline void n_dhcp4_client_config_freep(NDhcp4ClientConfig **p) {
-        if (*p)
-                n_dhcp4_client_config_free(*p);
-}
-
-static inline void n_dhcp4_client_config_freev(NDhcp4ClientConfig *p) {
-        n_dhcp4_client_config_free(p);
-}
-
-static inline void n_dhcp4_client_probe_config_freep(NDhcp4ClientProbeConfig **p) {
-        if (*p)
-                n_dhcp4_client_probe_config_free(*p);
-}
-
-static inline void n_dhcp4_client_probe_config_freev(NDhcp4ClientProbeConfig *p) {
-        n_dhcp4_client_probe_config_free(p);
-}
-
-static inline void n_dhcp4_client_unrefp(NDhcp4Client **p) {
-        if (*p)
-                n_dhcp4_client_unref(*p);
-}
-
-static inline void n_dhcp4_client_unrefv(NDhcp4Client *p) {
-        n_dhcp4_client_unref(p);
-}
-
-static inline void n_dhcp4_client_probe_freep(NDhcp4ClientProbe **p) {
-        if (*p)
-                n_dhcp4_client_probe_free(*p);
-}
-
-static inline void n_dhcp4_client_probe_freev(NDhcp4ClientProbe *p) {
-        n_dhcp4_client_probe_free(p);
-}
-
-static inline void n_dhcp4_client_lease_unrefp(NDhcp4ClientLease **p) {
-        if (*p)
-                n_dhcp4_client_lease_unref(*p);
-}
-
-static inline void n_dhcp4_client_lease_unrefv(NDhcp4ClientLease *p) {
-        n_dhcp4_client_lease_unref(p);
-}
-
-static inline void n_dhcp4_server_config_freep(NDhcp4ServerConfig **p) {
-        if (*p)
-                n_dhcp4_server_config_free(*p);
-}
-
-static inline void n_dhcp4_server_config_freev(NDhcp4ServerConfig *p) {
-        n_dhcp4_server_config_free(p);
-}
-
-static inline void n_dhcp4_server_unrefp(NDhcp4Server **p) {
-        if (*p)
-                n_dhcp4_server_unref(*p);
-}
-
-static inline void n_dhcp4_server_unrefv(NDhcp4Server *p) {
-        n_dhcp4_server_unref(p);
-}
-
-static inline void n_dhcp4_server_ip_freep(NDhcp4ServerIp **p) {
-        if (*p)
-                n_dhcp4_server_ip_free(*p);
-}
-
-static inline void n_dhcp4_server_ip_freev(NDhcp4ServerIp *p) {
-        n_dhcp4_server_ip_free(p);
-}
-
-static inline void n_dhcp4_server_lease_unrefp(NDhcp4ServerLease **p) {
-        if (*p)
-                n_dhcp4_server_lease_unref(*p);
-}
-
-static inline void n_dhcp4_server_lease_unrefv(NDhcp4ServerLease *p) {
-        n_dhcp4_server_lease_unref(p);
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/shared/n-dhcp4/src/util/packet.c b/shared/n-dhcp4/src/util/packet.c
deleted file mode 100644
index 48f2c85e..00000000
--- a/shared/n-dhcp4/src/util/packet.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Packet Sockets
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <endian.h>
-#include <errno.h>
-#include <linux/filter.h>
-#include <linux/if_ether.h>
-#include <linux/if_packet.h>
-#include <linux/udp.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include "packet.h"
-
-/**
- * packet_internet_checksum() - compute the internet checksum
- * @data:               the data to checksum
- * @size:               the length of @data in bytes
- *
- * Computes the internet checksum for a given blob according to RFC1071.
- *
- * The internet checksum is the one's complement of the one's complement sum of
- * the 16-bit words of the data, padded with zero-bytes if the data does not
- * end on a 16-bit boundary.
- *
- * Return: Checksum is returned.
- */
-uint16_t packet_internet_checksum(const uint8_t *data, size_t size) {
-        uint64_t acc = 0;
-        uint32_t local;
-
-        while (size >= sizeof(local)) {
-                memcpy(&local, data, sizeof(local));
-                acc += local;
-
-                data += sizeof(local);
-                size -= sizeof(local);
-        }
-
-        if (size) {
-                local = 0;
-                memcpy(&local, data, size);
-                acc += local;
-        }
-
-        while (acc >> 16)
-                acc = (acc & 0xffff) + (acc >> 16);
-
-        return ~acc;
-}
-
-/**
- * packet_internet_checksum_udp() - compute the internet checkum for UDP packets
- * @src_addr:           source IP address
- * @dst_addr:           destination IP address
- * @src_port:           source port
- * @dst_port:           destination port
- * @data:               payload
- * @size:               length of payload in bytes
- * @checksum:           current checksum, or 0
- *
- * Computes the internet checksum for a UDP packet, given the relevant IP and
- * UDP header fields.
- *
- * Note that since a UDP packet contains the checksum itself, the resulting
- * checksum will always be 0 (this fact is used to verify that a UDP packet is
- * valid).
- * Inversely, when calculating the checksum for outgoing packets, you have to
- * specify 0 as @checksum, and this function will return the checksum for the
- * caller to use for the packet. In this case, though, the caller must check
- * whether the returned checksum might coincidentally be 0, in which case it
- * must be flipped to -1 (0xffff), since 0 is not allowed as checksum in UDP
- * packets, and -1 is arithmetically equivalent in the checksum calculation.
- *
- * Return: Checksum is returned.
- */
-uint16_t packet_internet_checksum_udp(const struct in_addr *src_addr,
-                                      const struct in_addr *dst_addr,
-                                      uint16_t src_port,
-                                      uint16_t dst_port,
-                                      const uint8_t *data,
-                                      size_t size,
-                                      uint16_t checksum) {
-        struct {
-                uint32_t src;
-                uint32_t dst;
-                uint8_t _zeros;
-                uint8_t protocol;
-                uint16_t length;
-                struct udphdr udp;
-        } _c_packed_ udp_phdr = {
-                .src = src_addr->s_addr,
-                .dst = dst_addr->s_addr,
-                .protocol = IPPROTO_UDP,
-                .length = htons(sizeof(struct udphdr) + size),
-                .udp = {
-                        .source = htons(src_port),
-                        .dest = htons(dst_port),
-                        .len = htons(sizeof(struct udphdr) + size),
-                        .check = checksum,
-                },
-        };
-        const uint8_t *iter;
-        uint64_t acc = 0;
-        uint32_t local;
-
-        _Static_assert(!(sizeof(udp_phdr) % sizeof(local)),
-                       "UDP header structure size is not a multiple of 4");
-
-        for (iter = (const uint8_t *)&udp_phdr;
-             iter < (const uint8_t *)(&udp_phdr + 1);
-             iter += sizeof(local)) {
-                memcpy(&local, iter, sizeof(local));
-                acc += local;
-        }
-
-        while (size >= sizeof(local)) {
-                memcpy(&local, data, sizeof(local));
-                acc += local;
-
-                data += sizeof(local);
-                size -= sizeof(local);
-        }
-
-        if (size) {
-                local = 0;
-                memcpy(&local, data, size);
-                acc += local;
-        }
-
-        while (acc >> 16)
-                acc = (acc & 0xffff) + (acc >> 16);
-
-        return ~acc;
-}
-
-/**
- * packet_sendto_udp() - send UDP packet on AF_PACKET socket
- * @sockfd:             AF_PACKET/SOCK_DGRAM socket
- * @buf:                payload
- * @n_buf:              length of payload in bytes
- * @n_transmittedp:     output argument for number of transmitted bytes
- * @src_paddr:          source protocol address, see ip(7)
- * @dest_haddr:         destination hardware address, see packet(7)
- * @dest_paddr:         destination protocol address, see ip(7)
- *
- * Sends an UDP packet on a AF_PACKET socket directly to a hardware
- * address. The difference between this and sendto() on an AF_INET
- * socket is that no routing is performed, so the packet is delivered
- * even if the destination IP is not yet configured on the destination
- * host.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int packet_sendto_udp(int sockfd,
-                      const void *buf,
-                      size_t n_buf,
-                      size_t *n_transmittedp,
-                      const struct sockaddr_in *src_paddr,
-                      const struct packet_sockaddr_ll *dest_haddr,
-                      const struct sockaddr_in *dest_paddr) {
-        struct iphdr ip_hdr = {
-                .version = IPVERSION,
-                .ihl = sizeof(ip_hdr) / 4, /* Length of header in multiples of four bytes */
-                .tos = IPTOS_CLASS_CS6, /* Class Selector for network control */
-                .tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + n_buf),
-                .frag_off = htons(IP_DF), /* Do not fragment */
-                .ttl = IPDEFTTL,
-                .protocol = IPPROTO_UDP,
-                .saddr = src_paddr->sin_addr.s_addr,
-                .daddr = dest_paddr->sin_addr.s_addr,
-        };
-        struct udphdr udp_hdr = {
-                .source = src_paddr->sin_port,
-                .dest = dest_paddr->sin_port,
-                .len = htons(sizeof(udp_hdr) + n_buf),
-        };
-        struct iovec iov[3] = {
-                {
-                        .iov_base = &ip_hdr,
-                        .iov_len = sizeof(ip_hdr),
-                },
-                {
-                        .iov_base = &udp_hdr,
-                        .iov_len = sizeof(udp_hdr),
-                },
-                {
-                        .iov_base = (void *)buf,
-                        .iov_len = n_buf,
-                },
-        };
-        struct msghdr msg = {
-                .msg_name = (void*)dest_haddr,
-                .msg_namelen = sizeof(*dest_haddr),
-                .msg_iov = iov,
-                .msg_iovlen = sizeof(iov) / sizeof(iov[0]),
-        };
-        ssize_t pktlen;
-
-        ip_hdr.check = packet_internet_checksum((void*)&ip_hdr, sizeof(ip_hdr));
-        udp_hdr.check = packet_internet_checksum_udp(&src_paddr->sin_addr,
-                                                     &dest_paddr->sin_addr,
-                                                     ntohs(src_paddr->sin_port),
-                                                     ntohs(dest_paddr->sin_port),
-                                                     buf,
-                                                     n_buf,
-                                                     0);
-
-        /*
-         * 0x0000 and 0xffff are equivalent for computing the UDP checksum,
-         * but 0x0000 is reserved in UDP headers, to mean that the checksum is
-         * not set and should be ignored by the receiver. Hence, flip it to
-         * 0xffff in that case.
-         */
-        udp_hdr.check = udp_hdr.check ?: 0xffff;
-
-        pktlen = sendmsg(sockfd, &msg, 0);
-        if (pktlen < 0)
-                return -c_errno();
-
-        /*
-         * Kernel never truncates. Worst case, we get -EMSGSIZE. Kernel *might*
-         * prepend VNET headers, in which case a bigger length than sent is
-         * returned.
-         * Lets assert on this, and then return to the caller the proportion of
-         * its own buffer that we sent (which is always exactly the requested
-         * size).
-         */
-        c_assert((size_t)pktlen >= sizeof(ip_hdr) + sizeof(udp_hdr) + n_buf);
-        *n_transmittedp = n_buf;
-        return 0;
-}
-
-/**
- * packet_recvfrom_upd() - receive UDP packet from AF_PACKET socket
- * @sockfd:             AF_PACKET/SOCK_DGRAM socket
- * @buf:                buffor for payload
- * @n_buf:              max length of payload in bytes
- * @n_transmittedp:     output argument for number transmitted bytes
- * @src:                return argument for source address, or NULL, see ip(7)
- *
- * Receives an UDP packet on a AF_PACKET socket. The difference between
- * this and recvfrom() on an AF_INET socket is that the packet will be
- * received even if the destination IP address has not been configured
- * on the interface.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int packet_recvfrom_udp(int sockfd,
-                        void *buf,
-                        size_t n_buf,
-                        size_t *n_transmittedp,
-                        struct sockaddr_in *src) {
-        union {
-                struct iphdr hdr;
-                /*
-                 * Maximum IP-header length is 15 * 4, since it is specified in
-                 * the `ihl` field, which is four bits and interpreted as
-                 * factor of 4. So maximum `ihl` value is `(2^4 - 1) * 4`.
-                 */
-                uint8_t data[15 * 4];
-        } ip_hdr;
-        struct udphdr udp_hdr;
-        struct iovec iov[3] = {
-                {
-                        .iov_base = &ip_hdr,
-                },
-                {
-                        .iov_base = &udp_hdr,
-                        .iov_len = sizeof(udp_hdr),
-                },
-                {
-                        .iov_base = buf,
-                        .iov_len = n_buf,
-                },
-        };
-        uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
-        struct msghdr msg = {
-                .msg_iov = iov,
-                .msg_iovlen = sizeof(iov) / sizeof(iov[0]),
-                .msg_control = cmsgbuf,
-                .msg_controllen = sizeof(cmsgbuf),
-        };
-        struct cmsghdr *cmsg;
-        bool checksum = true;
-        ssize_t pktlen;
-        size_t hdrlen;
-
-        *n_transmittedp = 0;
-
-        /* Peek packet to obtain the real IP header length */
-        pktlen = recv(sockfd, &ip_hdr.hdr, sizeof(ip_hdr.hdr), MSG_PEEK);
-        if (pktlen < 0)
-                return -errno;
-
-        if ((size_t)pktlen < sizeof(ip_hdr.hdr)) {
-                /*
-                 * Received packet is smaller than the minimal IP header length,
-                 * discard it.
-                 */
-                recv(sockfd, NULL, 0, 0);
-                return 0;
-        }
-
-        if (ip_hdr.hdr.version != IPVERSION) {
-                /*
-                 * This is not an IPv4 packet, discard it.
-                 */
-                recv(sockfd, NULL, 0, 0);
-                return 0;
-        }
-
-        hdrlen = ip_hdr.hdr.ihl * 4;
-        if (hdrlen < sizeof(ip_hdr.hdr)) {
-                /*
-                 * The length given in the header is smaller than the minimum
-                 * header length, discard the packet.
-                 */
-                recv(sockfd, NULL, 0, 0);
-                return 0;
-        }
-
-        /*
-         * Now that we know the ip-header length, we can prepare the iovec to
-         * read the entire packet into the correct buffers.
-         */
-        iov[0].iov_len = hdrlen;
-        pktlen = recvmsg(sockfd, &msg, 0);
-        if (pktlen < 0)
-                return -errno;
-
-        cmsg = CMSG_FIRSTHDR(&msg);
-        if (cmsg) {
-                if (cmsg->cmsg_level == SOL_PACKET &&
-                    cmsg->cmsg_type == PACKET_AUXDATA &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
-                        struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
-                        checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
-                }
-        }
-
-        if (ntohs(ip_hdr.hdr.tot_len) > pktlen) {
-                /*
-                 * The IP-packet is bigger than the chunk returned by the
-                 * kernel. So either the packet is corrupt, or our caller
-                 * provided too small a buffer. In both cases, we simply drop
-                 * the packet.
-                 */
-                return 0;
-        }
-
-        /* Truncate trailing garbage. */
-        pktlen = ntohs(ip_hdr.hdr.tot_len);
-
-        if ((size_t)pktlen < hdrlen + sizeof(udp_hdr)) {
-                /*
-                 * The packet is too small to even contain an entire UDP
-                 * header, so discard it entirely.
-                 */
-                return 0;
-        } else if ((size_t)pktlen < hdrlen + ntohs(udp_hdr.len)) {
-                /*
-                 * The UDP header specified a longer length than the returned
-                 * packet, so discard it entirely.
-                 */
-                return 0;
-        }
-
-        /*
-         * Make @pktlen the length of the packet payload, without IP/UDP
-         * headers, since that is what the caller is interested in.
-         */
-        pktlen = ntohs(udp_hdr.len) - sizeof(struct udphdr);
-
-        /* IP */
-
-        if (ip_hdr.hdr.protocol != IPPROTO_UDP) {
-                return 0; /* not a UDP packet, discard it */
-        } else if (ip_hdr.hdr.frag_off & htons(IP_MF | IP_OFFMASK)) {
-                return 0; /* fragmented packet, discard it */
-        } else if (checksum && packet_internet_checksum(ip_hdr.data, hdrlen)) {
-                return 0; /* invalid checksum, discard it */
-        }
-
-        /* UDP */
-
-        if (checksum && udp_hdr.check) {
-                /*
-                 * Computing the checksum of a packet that has the checksum set
-                 * must yield 0. If it does not yield 0, the packet is invalid,
-                 * in which case we discard it.
-                 */
-               if (packet_internet_checksum_udp(&(struct in_addr){ ip_hdr.hdr.saddr },
-                                                &(struct in_addr){ ip_hdr.hdr.daddr },
-                                                ntohs(udp_hdr.source),
-                                                ntohs(udp_hdr.dest),
-                                                buf,
-                                                pktlen,
-                                                udp_hdr.check)) {
-                        return 0;
-               }
-        }
-
-        if (src) {
-                src->sin_family = AF_INET;
-                src->sin_addr.s_addr = ip_hdr.hdr.saddr;
-                src->sin_port = udp_hdr.source;
-        }
-
-        /* Return length of UDP payload (i.e., data written to @buf). */
-        *n_transmittedp = pktlen;
-        return 0;
-}
-
-/**
- * packet_shutdown() - shutdown socket for future receive operations
- * @sockfd:     socket
- *
- * Partially emulates `shutdown(sockfd, SHUT_RD)`, in the sense that no
- * further packets may be queued on the socket. All packets that are
- * already queued will still be delivered, but once -EAGAIN is returned
- * we are guaranteed never to be able to read more packets in the future.
- *
- * Return: 0 on success, or a negative error code on failure.
- */
-int packet_shutdown(int sockfd) {
-        struct sock_filter filter[] = {
-                BPF_STMT(BPF_RET + BPF_K, 0), /* discard all packets */
-        };
-        struct sock_fprog fprog = {
-                .filter = filter,
-                .len = sizeof(filter) / sizeof(filter[0]),
-        };
-        int r;
-
-        r = setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/util/packet.h b/shared/n-dhcp4/src/util/packet.h
deleted file mode 100644
index 98dabf7f..00000000
--- a/shared/n-dhcp4/src/util/packet.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#pragma once
-
-/*
- * Packet Sockets
- */
-
-#include <c-stdaux.h>
-#include <inttypes.h>
-#include <linux/if_packet.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-/*
- * `struct sockaddr_ll` is too small to fit the Infiniband hardware address.
- * Introduce `struct packet_sockaddr_ll` which is the same as the original,
- * except the `sl_addr` field is extended to fit all the supported hardware
- * addresses.
- */
-struct packet_sockaddr_ll {
-        unsigned short  sll_family;
-        __be16          sll_protocol;
-        int             sll_ifindex;
-        unsigned short  sll_hatype;
-        unsigned char   sll_pkttype;
-        unsigned char   sll_halen;
-        unsigned char   sll_addr[32]; /* MAX_ADDR_LEN */
-};
-
-uint16_t packet_internet_checksum(const uint8_t *data, size_t len);
-uint16_t packet_internet_checksum_udp(const struct in_addr *src_addr,
-                                      const struct in_addr *dst_addr,
-                                      uint16_t src_port,
-                                      uint16_t dst_port,
-                                      const uint8_t *data,
-                                      size_t size,
-                                      uint16_t checksum);
-
-int packet_sendto_udp(int sockfd,
-                      const void *buf,
-                      size_t n_buf,
-                      size_t *n_transmittedp,
-                      const struct sockaddr_in *src_paddr,
-                      const struct packet_sockaddr_ll *dest_haddr,
-                      const struct sockaddr_in *dest_paddr);
-int packet_recvfrom_udp(int sockfd,
-                        void *buf,
-                        size_t n_buf,
-                        size_t *n_transmittedp,
-                        struct sockaddr_in *src);
-
-int packet_shutdown(int sockfd);
-
-/* inline helpers */
-
-static inline int packet_recv_udp(int sockfd,
-                                  void *buf,
-                                  size_t n_buf,
-                                  size_t *n_transmittedp) {
-        return packet_recvfrom_udp(sockfd, buf, n_buf, n_transmittedp, NULL);
-}
diff --git a/shared/n-dhcp4/src/util/socket.c b/shared/n-dhcp4/src/util/socket.c
deleted file mode 100644
index c25f76fd..00000000
--- a/shared/n-dhcp4/src/util/socket.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Socket Utilities
- */
-
-#include <assert.h>
-#include <c-stdaux.h>
-#include <errno.h>
-#include <net/if.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include "socket.h"
-
-/**
- * socket_SIOCGIFNAME() - resolve an ifindex to an ifname
- * @socket:                     socket to operate on
- * @ifindex:                    index of network interface to resolve
- * @ifname:                     buffer to store resolved name
- *
- * This uses the SIOCGIFNAME ioctl to resolve an ifindex to an ifname. The
- * buffer provided in @ifnamep must be at least IFNAMSIZ bytes in size. The
- * maximum ifname length is IFNAMSIZ-1, and this function always
- * zero-terminates the result.
- *
- * This function is similar to if_indextoname(3) provided by glibc, but it
- * allows to specify the target socket explicitly. This allows the caller to
- * control the target network-namespace, rather than relying on the network
- * namespace of the running process.
- *
- * Return: 0 on success, negative kernel error code on failure.
- */
-int socket_SIOCGIFNAME(int socket, int ifindex, char (*ifnamep)[IFNAMSIZ]) {
-        struct ifreq req = { .ifr_ifindex = ifindex };
-        int r;
-
-        r = ioctl(socket, SIOCGIFNAME, &req);
-        if (r < 0)
-                return -errno;
-
-        /*
-         * The linux kernel guarantees that an interface name is always
-         * zero-terminated, and it always fully fits into IFNAMSIZ bytes,
-         * including the zero-terminator.
-         */
-        memcpy(ifnamep, req.ifr_name, IFNAMSIZ);
-        return 0;
-}
-
-/**
- * socket_bind_if() - bind socket to a network interface
- * @socket:                     socket to operate on
- * @ifindex:                    index of network interface to bind to, or 0
- *
- * This binds the socket given via @socket to the network interface specified
- * via @ifindex. It uses the underlying SO_BINDTODEVICE ioctl of the linux
- * kernel. However, if available, if prefers the newer SO_BINDTOIFINDEX ioctl,
- * which avoids resolving the interface name temporarily, and thus does not
- * suffer from a race-condition.
- *
- * Return: 0 on success, negative error code on failure.
- */
-int socket_bind_if(int socket, int ifindex) {
-        char ifname[IFNAMSIZ] = {};
-        int r;
-
-        c_assert(ifindex >= 0);
-
-        /*
-         * We first try the newer SO_BINDTOIFINDEX. If it is not available on
-         * the running kernel, we fall back to SO_BINDTODEVICE. This, however,
-         * requires us to first resolve the ifindex to an ifname. Note that
-         * this is racy, since the device name might theoretically change
-         * asynchronously.
-         *
-         * Using 0 as ifindex will remove the device-binding. For
-         * SO_BINDTOIFINDEX we simply pass-through the 0 to the kernel, which
-         * recognizes this correctly. For SO_BINDTODEVICE we pass the empty
-         * string, which the kernel recognizes as a request to remove the
-         * binding.
-         *
-         * The commit introducing SO_BINDTOIFINDEX first appeared in linux-5.1:
-         *
-         *     commit f5dd3d0c9638a9d9a02b5964c4ad636f06cf7e2c
-         *     Author: David Herrmann <dh.herrmann@gmail.com>
-         *     Date:   Tue Jan 15 14:42:14 2019 +0100
-         *
-         *         net: introduce SO_BINDTOIFINDEX sockopt
-         *
-         * In older kernels, setsockopt(2) is guaranteed to return ENOPROTOOPT
-         * for this ioctl.
-         */
-
-#ifdef SO_BINDTOIFINDEX
-        r = setsockopt(socket,
-                       SOL_SOCKET,
-                       SO_BINDTOIFINDEX,
-                       &ifindex,
-                       sizeof(ifindex));
-        if (r >= 0)
-                return 0;
-        else if (errno != ENOPROTOOPT)
-                return -errno;
-#endif /* SO_BINDTOIFINDEX */
-
-        if (ifindex > 0) {
-                r = socket_SIOCGIFNAME(socket, ifindex, &ifname);
-                if (r)
-                        return r;
-        }
-
-        r = setsockopt(socket,
-                       SOL_SOCKET,
-                       SO_BINDTODEVICE,
-                       ifname,
-                       strlen(ifname));
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
diff --git a/shared/n-dhcp4/src/util/socket.h b/shared/n-dhcp4/src/util/socket.h
deleted file mode 100644
index b5ecf2c2..00000000
--- a/shared/n-dhcp4/src/util/socket.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-/*
- * Socket Utilities
- */
-
-#include <c-stdaux.h>
-#include <stdlib.h>
-
-int socket_SIOCGIFNAME(int socket, int ifindex, char (*ifnamep)[IFNAMSIZ]);
-int socket_bind_if(int socket, int ifindex);
diff --git a/shared/nm-base/nm-base.h b/shared/nm-base/nm-base.h
deleted file mode 100644
index 105d1783..00000000
--- a/shared/nm-base/nm-base.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_LIBNM_BASE_H__
-#define __NM_LIBNM_BASE_H__
-
-/*****************************************************************************/
-
-/* this must be the same as NM_UTILS_HWADDR_LEN_MAX from libnm. */
-#define _NM_UTILS_HWADDR_LEN_MAX 20
-
-/*****************************************************************************/
-
-typedef enum {
-    NM_ETHTOOL_ID_UNKNOWN = -1,
-
-    _NM_ETHTOOL_ID_FIRST = 0,
-
-    _NM_ETHTOOL_ID_COALESCE_FIRST      = _NM_ETHTOOL_ID_FIRST,
-    NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX = _NM_ETHTOOL_ID_COALESCE_FIRST,
-    NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX,
-    NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH,
-    NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW,
-    NM_ETHTOOL_ID_COALESCE_RX_FRAMES,
-    NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH,
-    NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ,
-    NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW,
-    NM_ETHTOOL_ID_COALESCE_RX_USECS,
-    NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH,
-    NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ,
-    NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW,
-    NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL,
-    NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS,
-    NM_ETHTOOL_ID_COALESCE_TX_FRAMES,
-    NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH,
-    NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ,
-    NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW,
-    NM_ETHTOOL_ID_COALESCE_TX_USECS,
-    NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH,
-    NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ,
-    NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW,
-    _NM_ETHTOOL_ID_COALESCE_LAST = NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW,
-
-    _NM_ETHTOOL_ID_FEATURE_FIRST         = _NM_ETHTOOL_ID_COALESCE_LAST + 1,
-    NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD = _NM_ETHTOOL_ID_FEATURE_FIRST,
-    NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_FCOE_MTU,
-    NM_ETHTOOL_ID_FEATURE_GRO,
-    NM_ETHTOOL_ID_FEATURE_GSO,
-    NM_ETHTOOL_ID_FEATURE_HIGHDMA,
-    NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_LOOPBACK,
-    NM_ETHTOOL_ID_FEATURE_LRO,
-    NM_ETHTOOL_ID_FEATURE_MACSEC_HW_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_NTUPLE,
-    NM_ETHTOOL_ID_FEATURE_RX,
-    NM_ETHTOOL_ID_FEATURE_RXHASH,
-    NM_ETHTOOL_ID_FEATURE_RXVLAN,
-    NM_ETHTOOL_ID_FEATURE_RX_ALL,
-    NM_ETHTOOL_ID_FEATURE_RX_FCS,
-    NM_ETHTOOL_ID_FEATURE_RX_GRO_HW,
-    NM_ETHTOOL_ID_FEATURE_RX_GRO_LIST,
-    NM_ETHTOOL_ID_FEATURE_RX_UDP_GRO_FORWARDING,
-    NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER,
-    NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER,
-    NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE,
-    NM_ETHTOOL_ID_FEATURE_SG,
-    NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD,
-    NM_ETHTOOL_ID_FEATURE_TLS_HW_RX_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_TSO,
-    NM_ETHTOOL_ID_FEATURE_TX,
-    NM_ETHTOOL_ID_FEATURE_TXVLAN,
-    NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC,
-    NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4,
-    NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6,
-    NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC,
-    NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP,
-    NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_GSO_LIST,
-    NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL,
-    NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST,
-    NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY,
-    NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER,
-    NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST,
-    NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_TUNNEL_REMCSUM_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT,
-    _NM_ETHTOOL_ID_FEATURE_LAST = NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT,
-
-    _NM_ETHTOOL_ID_RING_FIRST = _NM_ETHTOOL_ID_FEATURE_LAST + 1,
-    NM_ETHTOOL_ID_RING_RX     = _NM_ETHTOOL_ID_RING_FIRST,
-    NM_ETHTOOL_ID_RING_RX_JUMBO,
-    NM_ETHTOOL_ID_RING_RX_MINI,
-    NM_ETHTOOL_ID_RING_TX,
-    _NM_ETHTOOL_ID_RING_LAST = NM_ETHTOOL_ID_RING_TX,
-
-    _NM_ETHTOOL_ID_LAST = _NM_ETHTOOL_ID_RING_LAST,
-
-    _NM_ETHTOOL_ID_COALESCE_NUM =
-        (_NM_ETHTOOL_ID_COALESCE_LAST - _NM_ETHTOOL_ID_COALESCE_FIRST + 1),
-    _NM_ETHTOOL_ID_FEATURE_NUM = (_NM_ETHTOOL_ID_FEATURE_LAST - _NM_ETHTOOL_ID_FEATURE_FIRST + 1),
-    _NM_ETHTOOL_ID_RING_NUM    = (_NM_ETHTOOL_ID_RING_LAST - _NM_ETHTOOL_ID_RING_FIRST + 1),
-    _NM_ETHTOOL_ID_NUM         = (_NM_ETHTOOL_ID_LAST - _NM_ETHTOOL_ID_FIRST + 1),
-} NMEthtoolID;
-
-#define _NM_ETHTOOL_ID_FEATURE_AS_IDX(ethtool_id)  ((ethtool_id) -_NM_ETHTOOL_ID_FEATURE_FIRST)
-#define _NM_ETHTOOL_ID_COALESCE_AS_IDX(ethtool_id) ((ethtool_id) -_NM_ETHTOOL_ID_COALESCE_FIRST)
-
-typedef enum {
-    NM_ETHTOOL_TYPE_UNKNOWN,
-    NM_ETHTOOL_TYPE_COALESCE,
-    NM_ETHTOOL_TYPE_FEATURE,
-    NM_ETHTOOL_TYPE_RING,
-} NMEthtoolType;
-
-/****************************************************************************/
-
-static inline gboolean
-nm_ethtool_id_is_feature(NMEthtoolID id)
-{
-    return id >= _NM_ETHTOOL_ID_FEATURE_FIRST && id <= _NM_ETHTOOL_ID_FEATURE_LAST;
-}
-
-static inline gboolean
-nm_ethtool_id_is_coalesce(NMEthtoolID id)
-{
-    return id >= _NM_ETHTOOL_ID_COALESCE_FIRST && id <= _NM_ETHTOOL_ID_COALESCE_LAST;
-}
-
-static inline gboolean
-nm_ethtool_id_is_ring(NMEthtoolID id)
-{
-    return id >= _NM_ETHTOOL_ID_RING_FIRST && id <= _NM_ETHTOOL_ID_RING_LAST;
-}
-
-/*****************************************************************************/
-
-typedef enum {
-    _NM_SETTING_WIRED_WAKE_ON_LAN_NONE      = 0,
-    _NM_SETTING_WIRED_WAKE_ON_LAN_PHY       = 0x2,
-    _NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST   = 0x4,
-    _NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST = 0x8,
-    _NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST = 0x10,
-    _NM_SETTING_WIRED_WAKE_ON_LAN_ARP       = 0x20,
-    _NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC     = 0x40,
-
-    _NM_SETTING_WIRED_WAKE_ON_LAN_ALL = 0x7E,
-
-    _NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT         = 0x1,
-    _NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE          = 0x8000,
-    _NM_SETTING_WIRED_WAKE_ON_LAN_EXCLUSIVE_FLAGS = 0x8001,
-} _NMSettingWiredWakeOnLan;
-
-/*****************************************************************************/
-
-typedef enum {
-    /* In priority order; higher number == higher priority */
-
-    NM_IP_CONFIG_SOURCE_UNKNOWN = 0,
-
-    /* for routes, the source is mapped to the uint8 field rtm_protocol.
-     * Reserve the range [1,0x100] for native RTPROT values. */
-
-    NM_IP_CONFIG_SOURCE_RTPROT_UNSPEC   = 1 + 0,
-    NM_IP_CONFIG_SOURCE_RTPROT_REDIRECT = 1 + 1,
-    NM_IP_CONFIG_SOURCE_RTPROT_KERNEL   = 1 + 2,
-    NM_IP_CONFIG_SOURCE_RTPROT_BOOT     = 1 + 3,
-    NM_IP_CONFIG_SOURCE_RTPROT_STATIC   = 1 + 4,
-    NM_IP_CONFIG_SOURCE_RTPROT_RA       = 1 + 9,
-    NM_IP_CONFIG_SOURCE_RTPROT_DHCP     = 1 + 16,
-    _NM_IP_CONFIG_SOURCE_RTPROT_LAST    = 1 + 0xFF,
-
-    NM_IP_CONFIG_SOURCE_KERNEL,
-    NM_IP_CONFIG_SOURCE_SHARED,
-    NM_IP_CONFIG_SOURCE_IP4LL,
-    NM_IP_CONFIG_SOURCE_IP6LL,
-    NM_IP_CONFIG_SOURCE_PPP,
-    NM_IP_CONFIG_SOURCE_WWAN,
-    NM_IP_CONFIG_SOURCE_VPN,
-    NM_IP_CONFIG_SOURCE_DHCP,
-    NM_IP_CONFIG_SOURCE_NDISC,
-    NM_IP_CONFIG_SOURCE_USER,
-} NMIPConfigSource;
-
-static inline gboolean
-NM_IS_IP_CONFIG_SOURCE_RTPROT(NMIPConfigSource source)
-{
-    return source > NM_IP_CONFIG_SOURCE_UNKNOWN && source <= _NM_IP_CONFIG_SOURCE_RTPROT_LAST;
-}
-
-/****************************************************************************/
-
-#endif /* __NM_LIBNM_BASE_H__ */
diff --git a/shared/nm-base/nm-ethtool-base.c b/shared/nm-base/nm-ethtool-base.c
deleted file mode 100644
index 52ff2871..00000000
--- a/shared/nm-base/nm-ethtool-base.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-ethtool-base.h"
-
-#include "nm-ethtool-utils-base.h"
-
-/*****************************************************************************/
-
-#define ETHT_DATA(xname)                                \
-    [NM_ETHTOOL_ID_##xname] = (&((const NMEthtoolData){ \
-        .optname = NM_ETHTOOL_OPTNAME_##xname,          \
-        .id      = NM_ETHTOOL_ID_##xname,               \
-    }))
-
-const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1] = {
-    /* indexed by NMEthtoolID */
-    ETHT_DATA(COALESCE_ADAPTIVE_RX),
-    ETHT_DATA(COALESCE_ADAPTIVE_TX),
-    ETHT_DATA(COALESCE_PKT_RATE_HIGH),
-    ETHT_DATA(COALESCE_PKT_RATE_LOW),
-    ETHT_DATA(COALESCE_RX_FRAMES),
-    ETHT_DATA(COALESCE_RX_FRAMES_HIGH),
-    ETHT_DATA(COALESCE_RX_FRAMES_IRQ),
-    ETHT_DATA(COALESCE_RX_FRAMES_LOW),
-    ETHT_DATA(COALESCE_RX_USECS),
-    ETHT_DATA(COALESCE_RX_USECS_HIGH),
-    ETHT_DATA(COALESCE_RX_USECS_IRQ),
-    ETHT_DATA(COALESCE_RX_USECS_LOW),
-    ETHT_DATA(COALESCE_SAMPLE_INTERVAL),
-    ETHT_DATA(COALESCE_STATS_BLOCK_USECS),
-    ETHT_DATA(COALESCE_TX_FRAMES),
-    ETHT_DATA(COALESCE_TX_FRAMES_HIGH),
-    ETHT_DATA(COALESCE_TX_FRAMES_IRQ),
-    ETHT_DATA(COALESCE_TX_FRAMES_LOW),
-    ETHT_DATA(COALESCE_TX_USECS),
-    ETHT_DATA(COALESCE_TX_USECS_HIGH),
-    ETHT_DATA(COALESCE_TX_USECS_IRQ),
-    ETHT_DATA(COALESCE_TX_USECS_LOW),
-    ETHT_DATA(FEATURE_ESP_HW_OFFLOAD),
-    ETHT_DATA(FEATURE_ESP_TX_CSUM_HW_OFFLOAD),
-    ETHT_DATA(FEATURE_FCOE_MTU),
-    ETHT_DATA(FEATURE_GRO),
-    ETHT_DATA(FEATURE_GSO),
-    ETHT_DATA(FEATURE_HIGHDMA),
-    ETHT_DATA(FEATURE_HW_TC_OFFLOAD),
-    ETHT_DATA(FEATURE_L2_FWD_OFFLOAD),
-    ETHT_DATA(FEATURE_LOOPBACK),
-    ETHT_DATA(FEATURE_LRO),
-    ETHT_DATA(FEATURE_MACSEC_HW_OFFLOAD),
-    ETHT_DATA(FEATURE_NTUPLE),
-    ETHT_DATA(FEATURE_RX),
-    ETHT_DATA(FEATURE_RXHASH),
-    ETHT_DATA(FEATURE_RXVLAN),
-    ETHT_DATA(FEATURE_RX_ALL),
-    ETHT_DATA(FEATURE_RX_FCS),
-    ETHT_DATA(FEATURE_RX_GRO_HW),
-    ETHT_DATA(FEATURE_RX_GRO_LIST),
-    ETHT_DATA(FEATURE_RX_UDP_GRO_FORWARDING),
-    ETHT_DATA(FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD),
-    ETHT_DATA(FEATURE_RX_VLAN_FILTER),
-    ETHT_DATA(FEATURE_RX_VLAN_STAG_FILTER),
-    ETHT_DATA(FEATURE_RX_VLAN_STAG_HW_PARSE),
-    ETHT_DATA(FEATURE_SG),
-    ETHT_DATA(FEATURE_TLS_HW_RECORD),
-    ETHT_DATA(FEATURE_TLS_HW_RX_OFFLOAD),
-    ETHT_DATA(FEATURE_TLS_HW_TX_OFFLOAD),
-    ETHT_DATA(FEATURE_TSO),
-    ETHT_DATA(FEATURE_TX),
-    ETHT_DATA(FEATURE_TXVLAN),
-    ETHT_DATA(FEATURE_TX_CHECKSUM_FCOE_CRC),
-    ETHT_DATA(FEATURE_TX_CHECKSUM_IPV4),
-    ETHT_DATA(FEATURE_TX_CHECKSUM_IPV6),
-    ETHT_DATA(FEATURE_TX_CHECKSUM_IP_GENERIC),
-    ETHT_DATA(FEATURE_TX_CHECKSUM_SCTP),
-    ETHT_DATA(FEATURE_TX_ESP_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_FCOE_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_GRE_CSUM_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_GRE_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_GSO_LIST),
-    ETHT_DATA(FEATURE_TX_GSO_PARTIAL),
-    ETHT_DATA(FEATURE_TX_GSO_ROBUST),
-    ETHT_DATA(FEATURE_TX_IPXIP4_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_IPXIP6_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_NOCACHE_COPY),
-    ETHT_DATA(FEATURE_TX_SCATTER_GATHER),
-    ETHT_DATA(FEATURE_TX_SCATTER_GATHER_FRAGLIST),
-    ETHT_DATA(FEATURE_TX_SCTP_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_TCP6_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_TCP_ECN_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_TCP_MANGLEID_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_TCP_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_TUNNEL_REMCSUM_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_UDP_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_UDP_TNL_SEGMENTATION),
-    ETHT_DATA(FEATURE_TX_VLAN_STAG_HW_INSERT),
-    ETHT_DATA(RING_RX),
-    ETHT_DATA(RING_RX_JUMBO),
-    ETHT_DATA(RING_RX_MINI),
-    ETHT_DATA(RING_TX),
-    [_NM_ETHTOOL_ID_NUM] = NULL,
-};
-
-static const guint8 _by_name[_NM_ETHTOOL_ID_NUM] = {
-    /* sorted by optname. */
-    NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX,
-    NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX,
-    NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH,
-    NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW,
-    NM_ETHTOOL_ID_COALESCE_RX_FRAMES,
-    NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH,
-    NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ,
-    NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW,
-    NM_ETHTOOL_ID_COALESCE_RX_USECS,
-    NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH,
-    NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ,
-    NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW,
-    NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL,
-    NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS,
-    NM_ETHTOOL_ID_COALESCE_TX_FRAMES,
-    NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH,
-    NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ,
-    NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW,
-    NM_ETHTOOL_ID_COALESCE_TX_USECS,
-    NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH,
-    NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ,
-    NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW,
-    NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_FCOE_MTU,
-    NM_ETHTOOL_ID_FEATURE_GRO,
-    NM_ETHTOOL_ID_FEATURE_GSO,
-    NM_ETHTOOL_ID_FEATURE_HIGHDMA,
-    NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_LOOPBACK,
-    NM_ETHTOOL_ID_FEATURE_LRO,
-    NM_ETHTOOL_ID_FEATURE_MACSEC_HW_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_NTUPLE,
-    NM_ETHTOOL_ID_FEATURE_RX,
-    NM_ETHTOOL_ID_FEATURE_RX_ALL,
-    NM_ETHTOOL_ID_FEATURE_RX_FCS,
-    NM_ETHTOOL_ID_FEATURE_RX_GRO_HW,
-    NM_ETHTOOL_ID_FEATURE_RX_GRO_LIST,
-    NM_ETHTOOL_ID_FEATURE_RX_UDP_GRO_FORWARDING,
-    NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER,
-    NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER,
-    NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE,
-    NM_ETHTOOL_ID_FEATURE_RXHASH,
-    NM_ETHTOOL_ID_FEATURE_RXVLAN,
-    NM_ETHTOOL_ID_FEATURE_SG,
-    NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD,
-    NM_ETHTOOL_ID_FEATURE_TLS_HW_RX_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD,
-    NM_ETHTOOL_ID_FEATURE_TSO,
-    NM_ETHTOOL_ID_FEATURE_TX,
-    NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC,
-    NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC,
-    NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4,
-    NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6,
-    NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP,
-    NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_GSO_LIST,
-    NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL,
-    NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST,
-    NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY,
-    NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER,
-    NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST,
-    NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_TUNNEL_REMCSUM_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION,
-    NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT,
-    NM_ETHTOOL_ID_FEATURE_TXVLAN,
-    NM_ETHTOOL_ID_RING_RX,
-    NM_ETHTOOL_ID_RING_RX_JUMBO,
-    NM_ETHTOOL_ID_RING_RX_MINI,
-    NM_ETHTOOL_ID_RING_TX,
-};
-
-/*****************************************************************************/
-
-static void
-_ASSERT_data(void)
-{
-    int i;
-
-    if (!NM_MORE_ASSERT_ONCE(10))
-        return;
-
-    G_STATIC_ASSERT_EXPR(_NM_ETHTOOL_ID_FIRST == 0);
-    G_STATIC_ASSERT_EXPR(_NM_ETHTOOL_ID_LAST == _NM_ETHTOOL_ID_NUM - 1);
-    G_STATIC_ASSERT_EXPR(_NM_ETHTOOL_ID_NUM > 0);
-
-    nm_assert(NM_PTRARRAY_LEN(nm_ethtool_data) == _NM_ETHTOOL_ID_NUM);
-    nm_assert(G_N_ELEMENTS(_by_name) == _NM_ETHTOOL_ID_NUM);
-    nm_assert(G_N_ELEMENTS(nm_ethtool_data) == _NM_ETHTOOL_ID_NUM + 1);
-
-    for (i = 0; i < _NM_ETHTOOL_ID_NUM; i++) {
-        const NMEthtoolData *d = nm_ethtool_data[i];
-
-        nm_assert(d);
-        nm_assert(d->id == (NMEthtoolID) i);
-        nm_assert(d->optname && d->optname[0]);
-    }
-
-    for (i = 0; i < _NM_ETHTOOL_ID_NUM; i++) {
-        NMEthtoolID          id = _by_name[i];
-        const NMEthtoolData *d;
-
-        nm_assert(id >= 0);
-        nm_assert(id < _NM_ETHTOOL_ID_NUM);
-
-        d = nm_ethtool_data[id];
-        if (i > 0) {
-            /* since we assert that all optnames are sorted strictly monotonically increasing,
-             * it also follows that there are no duplicates in the _by_name.
-             * It also follows, that all names in nm_ethtool_data are unique. */
-            if (strcmp(nm_ethtool_data[_by_name[i - 1]]->optname, d->optname) >= 0) {
-                g_error("nm_ethtool_data is not sorted asciibetically: %u/%s should be after %u/%s",
-                        i - 1,
-                        nm_ethtool_data[_by_name[i - 1]]->optname,
-                        i,
-                        d->optname);
-            }
-        }
-    }
-}
-
-static int
-_by_name_cmp(gconstpointer a, gconstpointer b, gpointer user_data)
-{
-    const guint8 *p_id    = a;
-    const char *  optname = b;
-
-    nm_assert(p_id && p_id >= _by_name && p_id <= &_by_name[_NM_ETHTOOL_ID_NUM]);
-    nm_assert(*p_id < _NM_ETHTOOL_ID_NUM);
-
-    return strcmp(nm_ethtool_data[*p_id]->optname, optname);
-}
-
-const NMEthtoolData *
-nm_ethtool_data_get_by_optname(const char *optname)
-{
-    gssize idx;
-
-    if (!optname)
-        return NULL;
-
-    _ASSERT_data();
-
-    idx = nm_utils_array_find_binary_search((gconstpointer *) _by_name,
-                                            sizeof(_by_name[0]),
-                                            _NM_ETHTOOL_ID_NUM,
-                                            optname,
-                                            _by_name_cmp,
-                                            NULL);
-    return (idx < 0) ? NULL : nm_ethtool_data[_by_name[idx]];
-}
-
-NMEthtoolType
-nm_ethtool_id_to_type(NMEthtoolID id)
-{
-    if (nm_ethtool_id_is_coalesce(id))
-        return NM_ETHTOOL_TYPE_COALESCE;
-    if (nm_ethtool_id_is_feature(id))
-        return NM_ETHTOOL_TYPE_FEATURE;
-    if (nm_ethtool_id_is_ring(id))
-        return NM_ETHTOOL_TYPE_RING;
-
-    return NM_ETHTOOL_TYPE_UNKNOWN;
-}
diff --git a/shared/nm-base/nm-ethtool-base.h b/shared/nm-base/nm-ethtool-base.h
deleted file mode 100644
index be90ce75..00000000
--- a/shared/nm-base/nm-ethtool-base.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_ETHTOOL_BASE_H__
-#define __NM_ETHTOOL_BASE_H__
-
-#include "nm-base/nm-base.h"
-
-/*****************************************************************************/
-
-typedef struct {
-    const char *optname;
-    NMEthtoolID id;
-} NMEthtoolData;
-
-extern const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1];
-
-const NMEthtoolData *nm_ethtool_data_get_by_optname(const char *optname);
-
-NMEthtoolType nm_ethtool_id_to_type(NMEthtoolID id);
-
-/****************************************************************************/
-
-static inline NMEthtoolID
-nm_ethtool_id_get_by_name(const char *optname)
-{
-    const NMEthtoolData *d;
-
-    d = nm_ethtool_data_get_by_optname(optname);
-    return d ? d->id : NM_ETHTOOL_ID_UNKNOWN;
-}
-
-/****************************************************************************/
-
-#endif /* __NM_ETHTOOL_BASE_H__ */
diff --git a/shared/nm-base/nm-ethtool-utils-base.h b/shared/nm-base/nm-ethtool-utils-base.h
deleted file mode 100644
index d422724b..00000000
--- a/shared/nm-base/nm-ethtool-utils-base.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_ETHTOOL_UTILS_H__
-#define __NM_ETHTOOL_UTILS_H__
-
-G_BEGIN_DECLS
-
-/*****************************************************************************/
-
-#define NM_ETHTOOL_OPTNAME_FEATURE_ESP_HW_OFFLOAD             "feature-esp-hw-offload"
-#define NM_ETHTOOL_OPTNAME_FEATURE_ESP_TX_CSUM_HW_OFFLOAD     "feature-esp-tx-csum-hw-offload"
-#define NM_ETHTOOL_OPTNAME_FEATURE_FCOE_MTU                   "feature-fcoe-mtu"
-#define NM_ETHTOOL_OPTNAME_FEATURE_GRO                        "feature-gro"
-#define NM_ETHTOOL_OPTNAME_FEATURE_GSO                        "feature-gso"
-#define NM_ETHTOOL_OPTNAME_FEATURE_HIGHDMA                    "feature-highdma"
-#define NM_ETHTOOL_OPTNAME_FEATURE_HW_TC_OFFLOAD              "feature-hw-tc-offload"
-#define NM_ETHTOOL_OPTNAME_FEATURE_L2_FWD_OFFLOAD             "feature-l2-fwd-offload"
-#define NM_ETHTOOL_OPTNAME_FEATURE_LOOPBACK                   "feature-loopback"
-#define NM_ETHTOOL_OPTNAME_FEATURE_LRO                        "feature-lro"
-#define NM_ETHTOOL_OPTNAME_FEATURE_MACSEC_HW_OFFLOAD          "feature-macsec-hw-offload"
-#define NM_ETHTOOL_OPTNAME_FEATURE_NTUPLE                     "feature-ntuple"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RX                         "feature-rx"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RXHASH                     "feature-rxhash"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RXVLAN                     "feature-rxvlan"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RX_ALL                     "feature-rx-all"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RX_FCS                     "feature-rx-fcs"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RX_GRO_HW                  "feature-rx-gro-hw"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RX_GRO_LIST                "feature-rx-gro-list"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RX_UDP_GRO_FORWARDING      "feature-rx-udp-gro-forwarding"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD "feature-rx-udp_tunnel-port-offload"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RX_VLAN_FILTER             "feature-rx-vlan-filter"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RX_VLAN_STAG_FILTER        "feature-rx-vlan-stag-filter"
-#define NM_ETHTOOL_OPTNAME_FEATURE_RX_VLAN_STAG_HW_PARSE      "feature-rx-vlan-stag-hw-parse"
-#define NM_ETHTOOL_OPTNAME_FEATURE_SG                         "feature-sg"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TLS_HW_RECORD              "feature-tls-hw-record"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TLS_HW_RX_OFFLOAD          "feature-tls-hw-rx-offload"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TLS_HW_TX_OFFLOAD          "feature-tls-hw-tx-offload"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TSO                        "feature-tso"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX                         "feature-tx"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TXVLAN                     "feature-txvlan"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_CHECKSUM_FCOE_CRC       "feature-tx-checksum-fcoe-crc"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_CHECKSUM_IPV4           "feature-tx-checksum-ipv4"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_CHECKSUM_IPV6           "feature-tx-checksum-ipv6"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_CHECKSUM_IP_GENERIC     "feature-tx-checksum-ip-generic"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_CHECKSUM_SCTP           "feature-tx-checksum-sctp"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_ESP_SEGMENTATION        "feature-tx-esp-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_FCOE_SEGMENTATION       "feature-tx-fcoe-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_GRE_CSUM_SEGMENTATION   "feature-tx-gre-csum-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_GRE_SEGMENTATION        "feature-tx-gre-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_GSO_LIST                "feature-tx-gso-list"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_GSO_PARTIAL             "feature-tx-gso-partial"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_GSO_ROBUST              "feature-tx-gso-robust"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_IPXIP4_SEGMENTATION     "feature-tx-ipxip4-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_IPXIP6_SEGMENTATION     "feature-tx-ipxip6-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_NOCACHE_COPY            "feature-tx-nocache-copy"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_SCATTER_GATHER          "feature-tx-scatter-gather"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_SCATTER_GATHER_FRAGLIST "feature-tx-scatter-gather-fraglist"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_SCTP_SEGMENTATION       "feature-tx-sctp-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_TCP6_SEGMENTATION       "feature-tx-tcp6-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_TCP_ECN_SEGMENTATION    "feature-tx-tcp-ecn-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_TCP_MANGLEID_SEGMENTATION \
-    "feature-tx-tcp-mangleid-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_TCP_SEGMENTATION "feature-tx-tcp-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_TUNNEL_REMCSUM_SEGMENTATION \
-    "feature-tx-tunnel-remcsum-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_UDP_SEGMENTATION "feature-tx-udp-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION \
-    "feature-tx-udp_tnl-csum-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_UDP_TNL_SEGMENTATION "feature-tx-udp_tnl-segmentation"
-#define NM_ETHTOOL_OPTNAME_FEATURE_TX_VLAN_STAG_HW_INSERT  "feature-tx-vlan-stag-hw-insert"
-
-#define NM_ETHTOOL_OPTNAME_COALESCE_ADAPTIVE_RX       "coalesce-adaptive-rx"
-#define NM_ETHTOOL_OPTNAME_COALESCE_ADAPTIVE_TX       "coalesce-adaptive-tx"
-#define NM_ETHTOOL_OPTNAME_COALESCE_PKT_RATE_HIGH     "coalesce-pkt-rate-high"
-#define NM_ETHTOOL_OPTNAME_COALESCE_PKT_RATE_LOW      "coalesce-pkt-rate-low"
-#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES         "coalesce-rx-frames"
-#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES_HIGH    "coalesce-rx-frames-high"
-#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES_IRQ     "coalesce-rx-frames-irq"
-#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES_LOW     "coalesce-rx-frames-low"
-#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS          "coalesce-rx-usecs"
-#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS_HIGH     "coalesce-rx-usecs-high"
-#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS_IRQ      "coalesce-rx-usecs-irq"
-#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS_LOW      "coalesce-rx-usecs-low"
-#define NM_ETHTOOL_OPTNAME_COALESCE_SAMPLE_INTERVAL   "coalesce-sample-interval"
-#define NM_ETHTOOL_OPTNAME_COALESCE_STATS_BLOCK_USECS "coalesce-stats-block-usecs"
-#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES         "coalesce-tx-frames"
-#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES_HIGH    "coalesce-tx-frames-high"
-#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES_IRQ     "coalesce-tx-frames-irq"
-#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES_LOW     "coalesce-tx-frames-low"
-#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS          "coalesce-tx-usecs"
-#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS_HIGH     "coalesce-tx-usecs-high"
-#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS_IRQ      "coalesce-tx-usecs-irq"
-#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS_LOW      "coalesce-tx-usecs-low"
-
-#define NM_ETHTOOL_OPTNAME_RING_RX       "ring-rx"
-#define NM_ETHTOOL_OPTNAME_RING_RX_JUMBO "ring-rx-jumbo"
-#define NM_ETHTOOL_OPTNAME_RING_RX_MINI  "ring-rx-mini"
-#define NM_ETHTOOL_OPTNAME_RING_TX       "ring-tx"
-
-/*****************************************************************************/
-
-G_END_DECLS
-
-#endif /* __NM_ETHTOOL_UTILS_H__ */
diff --git a/shared/nm-glib-aux/nm-c-list.h b/shared/nm-glib-aux/nm-c-list.h
deleted file mode 100644
index 6dd3ac72..00000000
--- a/shared/nm-glib-aux/nm-c-list.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2014 Red Hat, Inc.
- */
-
-#ifndef __NM_C_LIST_H__
-#define __NM_C_LIST_H__
-
-#include "c-list/src/c-list.h"
-
-/*****************************************************************************/
-
-#define nm_c_list_contains_entry(list, what, member)   \
-    ({                                                 \
-        typeof(what) _what = (what);                   \
-                                                       \
-        _what &&c_list_contains(list, &_what->member); \
-    })
-
-/*****************************************************************************/
-
-typedef struct {
-    CList lst;
-    void *data;
-} NMCListElem;
-
-static inline NMCListElem *
-nm_c_list_elem_new_stale(void *data)
-{
-    NMCListElem *elem;
-
-    elem       = g_slice_new(NMCListElem);
-    elem->data = data;
-    return elem;
-}
-
-static inline gboolean
-nm_c_list_elem_free_full(NMCListElem *elem, GDestroyNotify free_fcn)
-{
-    if (!elem)
-        return FALSE;
-    c_list_unlink_stale(&elem->lst);
-    if (free_fcn)
-        free_fcn(elem->data);
-    g_slice_free(NMCListElem, elem);
-    return TRUE;
-}
-
-static inline gboolean
-nm_c_list_elem_free(NMCListElem *elem)
-{
-    return nm_c_list_elem_free_full(elem, NULL);
-}
-
-static inline void *
-nm_c_list_elem_free_steal(NMCListElem *elem)
-{
-    gpointer data;
-
-    if (!elem)
-        return NULL;
-    data = elem->data;
-    nm_c_list_elem_free_full(elem, NULL);
-    return data;
-}
-
-static inline void
-nm_c_list_elem_free_all(CList *head, GDestroyNotify free_fcn)
-{
-    NMCListElem *elem;
-
-    while ((elem = c_list_first_entry(head, NMCListElem, lst)))
-        nm_c_list_elem_free_full(elem, free_fcn);
-}
-
-#define nm_c_list_elem_find_first(head, arg, predicate) \
-    ({                                                  \
-        CList *const _head   = (head);                  \
-        NMCListElem *_result = NULL;                    \
-        NMCListElem *_elem;                             \
-                                                        \
-        c_list_for_each_entry (_elem, _head, lst) {     \
-            void *const arg = _elem->data;              \
-                                                        \
-            if (predicate) {                            \
-                _result = _elem;                        \
-                break;                                  \
-            }                                           \
-        }                                               \
-        _result;                                        \
-    })
-
-/**
- * nm_c_list_elem_find_first_ptr:
- * @head: the @CList head of a list containing #NMCListElem elements.
- *   Note that the head is not itself part of the list.
- * @needle: the needle pointer.
- *
- * Iterates the list and returns the first #NMCListElem with the matching @needle,
- * using pointer equality.
- *
- * Returns: the found list element or %NULL if not found.
- */
-static inline NMCListElem *
-nm_c_list_elem_find_first_ptr(CList *head, gconstpointer needle)
-{
-    return nm_c_list_elem_find_first(head, x, x == needle);
-}
-
-/*****************************************************************************/
-
-/**
- * nm_c_list_move_before:
- * @lst: the list element to which @elem will be prepended.
- * @elem: the list element to move.
- *
- * This unlinks @elem from the current list and linkes it before
- * @lst. This is like c_list_link_before(), except that @elem must
- * be initialized and linked. Note that @elem may be linked in @lst
- * or in another list. In both cases it gets moved.
- *
- * Returns: %TRUE if there were any changes. %FALSE if elem was already
- *   linked at the right place.
- */
-static inline gboolean
-nm_c_list_move_before(CList *lst, CList *elem)
-{
-    nm_assert(lst);
-    nm_assert(elem);
-
-    if (lst != elem && lst->prev != elem) {
-        c_list_unlink_stale(elem);
-        c_list_link_before(lst, elem);
-        return TRUE;
-    }
-    return FALSE;
-}
-#define nm_c_list_move_tail(lst, elem) nm_c_list_move_before(lst, elem)
-
-/**
- * nm_c_list_move_after:
- * @lst: the list element to which @elem will be prepended.
- * @elem: the list element to move.
- *
- * This unlinks @elem from the current list and linkes it after
- * @lst. This is like c_list_link_after(), except that @elem must
- * be initialized and linked. Note that @elem may be linked in @lst
- * or in another list. In both cases it gets moved.
- *
- * Returns: %TRUE if there were any changes. %FALSE if elem was already
- *   linked at the right place.
- */
-static inline gboolean
-nm_c_list_move_after(CList *lst, CList *elem)
-{
-    nm_assert(lst);
-    nm_assert(elem);
-
-    if (lst != elem && lst->next != elem) {
-        c_list_unlink_stale(elem);
-        c_list_link_after(lst, elem);
-        return TRUE;
-    }
-    return FALSE;
-}
-#define nm_c_list_move_front(lst, elem) nm_c_list_move_after(lst, elem)
-
-#define nm_c_list_free_all(lst, type, member, destroy_fcn)         \
-    G_STMT_START                                                   \
-    {                                                              \
-        CList *const _lst = (lst);                                 \
-        type *       _elem;                                        \
-                                                                   \
-        while ((_elem = c_list_first_entry(_lst, type, member))) { \
-            destroy_fcn(_elem);                                    \
-        }                                                          \
-    }                                                              \
-    G_STMT_END
-
-#endif /* __NM_C_LIST_H__ */
diff --git a/shared/nm-glib-aux/nm-dbus-aux.c b/shared/nm-glib-aux/nm-dbus-aux.c
deleted file mode 100644
index 9fb02a3f..00000000
--- a/shared/nm-glib-aux/nm-dbus-aux.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-dbus-aux.h"
-
-/*****************************************************************************/
-
-static void
-_nm_dbus_connection_call_get_name_owner_cb(GObject *source, GAsyncResult *res, gpointer user_data)
-{
-    gs_unref_variant GVariant *ret           = NULL;
-    gs_free_error GError *             error = NULL;
-    const char *                       owner = NULL;
-    gpointer                           orig_user_data;
-    NMDBusConnectionCallGetNameOwnerCb callback;
-
-    nm_utils_user_data_unpack(user_data, &orig_user_data, &callback);
-
-    ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error);
-    if (ret)
-        g_variant_get(ret, "(&s)", &owner);
-
-    callback(owner, error, orig_user_data);
-}
-
-void
-nm_dbus_connection_call_get_name_owner(GDBusConnection *                  dbus_connection,
-                                       const char *                       service_name,
-                                       int                                timeout_msec,
-                                       GCancellable *                     cancellable,
-                                       NMDBusConnectionCallGetNameOwnerCb callback,
-                                       gpointer                           user_data)
-{
-    nm_assert(callback);
-
-    g_dbus_connection_call(dbus_connection,
-                           DBUS_SERVICE_DBUS,
-                           DBUS_PATH_DBUS,
-                           DBUS_INTERFACE_DBUS,
-                           "GetNameOwner",
-                           g_variant_new("(s)", service_name),
-                           G_VARIANT_TYPE("(s)"),
-                           G_DBUS_CALL_FLAGS_NONE,
-                           timeout_msec,
-                           cancellable,
-                           _nm_dbus_connection_call_get_name_owner_cb,
-                           nm_utils_user_data_pack(user_data, callback));
-}
-
-/*****************************************************************************/
-
-static void
-_nm_dbus_connection_call_default_cb(GObject *source, GAsyncResult *res, gpointer user_data)
-{
-    gs_unref_variant GVariant *ret      = NULL;
-    gs_free_error GError *        error = NULL;
-    gpointer                      orig_user_data;
-    NMDBusConnectionCallDefaultCb callback;
-
-    nm_utils_user_data_unpack(user_data, &orig_user_data, &callback);
-
-    ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error);
-
-    nm_assert((!!ret) != (!!error));
-
-    callback(ret, error, orig_user_data);
-}
-
-void
-nm_dbus_connection_call_get_all(GDBusConnection *             dbus_connection,
-                                const char *                  bus_name,
-                                const char *                  object_path,
-                                const char *                  interface_name,
-                                int                           timeout_msec,
-                                GCancellable *                cancellable,
-                                NMDBusConnectionCallDefaultCb callback,
-                                gpointer                      user_data)
-{
-    nm_assert(callback);
-
-    g_dbus_connection_call(dbus_connection,
-                           bus_name,
-                           object_path,
-                           DBUS_INTERFACE_PROPERTIES,
-                           "GetAll",
-                           g_variant_new("(s)", interface_name),
-                           G_VARIANT_TYPE("(a{sv})"),
-                           G_DBUS_CALL_FLAGS_NONE,
-                           timeout_msec,
-                           cancellable,
-                           _nm_dbus_connection_call_default_cb,
-                           nm_utils_user_data_pack(user_data, callback));
-}
-
-void
-nm_dbus_connection_call_set(GDBusConnection *             dbus_connection,
-                            const char *                  bus_name,
-                            const char *                  object_path,
-                            const char *                  interface_name,
-                            const char *                  property_name,
-                            GVariant *                    value,
-                            int                           timeout_msec,
-                            GCancellable *                cancellable,
-                            NMDBusConnectionCallDefaultCb callback,
-                            gpointer                      user_data)
-{
-    g_dbus_connection_call(dbus_connection,
-                           bus_name,
-                           object_path,
-                           DBUS_INTERFACE_PROPERTIES,
-                           "Set",
-                           g_variant_new("(ssv)", interface_name, property_name, value),
-                           G_VARIANT_TYPE("()"),
-                           G_DBUS_CALL_FLAGS_NONE,
-                           timeout_msec,
-                           cancellable,
-                           callback ? _nm_dbus_connection_call_default_cb : NULL,
-                           callback ? nm_utils_user_data_pack(user_data, callback) : NULL);
-}
-
-/*****************************************************************************/
-
-static void
-_nm_dbus_connection_call_get_managed_objects_cb(GObject *     source,
-                                                GAsyncResult *res,
-                                                gpointer      user_data)
-{
-    gs_unref_variant GVariant *ret      = NULL;
-    gs_unref_variant GVariant *arg      = NULL;
-    gs_free_error GError *        error = NULL;
-    gpointer                      orig_user_data;
-    NMDBusConnectionCallDefaultCb callback;
-
-    nm_utils_user_data_unpack(user_data, &orig_user_data, &callback);
-
-    ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error);
-
-    nm_assert((!!ret) != (!!error));
-
-    if (ret) {
-        nm_assert(g_variant_is_of_type(ret, G_VARIANT_TYPE("(a{oa{sa{sv}}})")));
-        arg = g_variant_get_child_value(ret, 0);
-    }
-
-    callback(arg, error, orig_user_data);
-}
-
-void
-nm_dbus_connection_call_get_managed_objects(GDBusConnection *             dbus_connection,
-                                            const char *                  bus_name,
-                                            const char *                  object_path,
-                                            GDBusCallFlags                flags,
-                                            int                           timeout_msec,
-                                            GCancellable *                cancellable,
-                                            NMDBusConnectionCallDefaultCb callback,
-                                            gpointer                      user_data)
-{
-    nm_assert(callback);
-
-    g_dbus_connection_call(dbus_connection,
-                           bus_name,
-                           object_path,
-                           DBUS_INTERFACE_OBJECT_MANAGER,
-                           "GetManagedObjects",
-                           NULL,
-                           G_VARIANT_TYPE("(a{oa{sa{sv}}})"),
-                           flags,
-                           timeout_msec,
-                           cancellable,
-                           _nm_dbus_connection_call_get_managed_objects_cb,
-                           nm_utils_user_data_pack(user_data, callback));
-}
-
-/*****************************************************************************/
-
-static void
-_call_finish_cb(GObject *     source,
-                GAsyncResult *result,
-                gpointer      user_data,
-                gboolean      return_void,
-                gboolean      strip_dbus_error)
-{
-    gs_unref_object GTask *task      = user_data;
-    gs_unref_variant GVariant *ret   = NULL;
-    GError *                   error = NULL;
-
-    nm_assert(G_IS_DBUS_CONNECTION(source));
-    nm_assert(G_IS_TASK(user_data));
-
-    ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
-    if (!ret) {
-        if (strip_dbus_error)
-            g_dbus_error_strip_remote_error(error);
-        g_task_return_error(task, error);
-        return;
-    }
-
-    if (!return_void)
-        g_task_return_pointer(task, g_steal_pointer(&ret), (GDestroyNotify) g_variant_unref);
-    else {
-        nm_assert(g_variant_is_of_type(ret, G_VARIANT_TYPE("()")));
-        g_task_return_boolean(task, TRUE);
-    }
-}
-
-/**
- * nm_dbus_connection_call_finish_void_cb:
- *
- * A default callback to pass as callback to g_dbus_connection_call().
- *
- * - user_data must be a GTask, whose reference will be consumed by the
- *   callback.
- * - the return GVariant must be a empty tuple "()".
- * - the GTask is returned either with error or TRUE boolean.
- */
-void
-nm_dbus_connection_call_finish_void_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
-    _call_finish_cb(source, result, user_data, TRUE, FALSE);
-}
-
-/**
- * nm_dbus_connection_call_finish_void_strip_dbus_error_cb:
- *
- * Like nm_dbus_connection_call_finish_void_cb(). The difference
- * is that on error this will first call g_dbus_error_strip_remote_error() on the error.
- */
-void
-nm_dbus_connection_call_finish_void_strip_dbus_error_cb(GObject *     source,
-                                                        GAsyncResult *result,
-                                                        gpointer      user_data)
-{
-    _call_finish_cb(source, result, user_data, TRUE, TRUE);
-}
-
-/**
- * nm_dbus_connection_call_finish_variant_cb:
- *
- * A default callback to pass as callback to g_dbus_connection_call().
- *
- * - user_data must be a GTask, whose reference will be consumed by the
- *   callback.
- * - the GTask is returned either with error or with a pointer containing the GVariant.
- */
-void
-nm_dbus_connection_call_finish_variant_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
-    _call_finish_cb(source, result, user_data, FALSE, FALSE);
-}
-
-/**
- * nm_dbus_connection_call_finish_variant_strip_dbus_error_cb:
- *
- * Like nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(). The difference
- * is that on error this will first call g_dbus_error_strip_remote_error() on the error.
- */
-void
-nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(GObject *     source,
-                                                           GAsyncResult *result,
-                                                           gpointer      user_data)
-{
-    _call_finish_cb(source, result, user_data, FALSE, TRUE);
-}
-
-/*****************************************************************************/
-
-typedef struct {
-    char *              bus_name;
-    char *              object_path;
-    char *              interface_name;
-    char *              method_name;
-    GVariant *          parameters;
-    GDBusConnection *   connection;
-    const GVariantType *reply_type;
-    int                 timeout_msec;
-} CallAsyncInfo;
-
-static void
-call_async_info_destroy(CallAsyncInfo *info)
-{
-    g_free(info->bus_name);
-    g_free(info->object_path);
-    g_free(info->interface_name);
-    g_free(info->method_name);
-    g_variant_unref(info->parameters);
-    nm_g_object_unref(info->connection);
-    g_free(info);
-}
-
-static void
-call_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
-    gs_unref_object GTask *task  = user_data;
-    GError *               error = NULL;
-    GVariant *             ret;
-
-    ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
-    if (!ret) {
-        g_task_return_error(task, error);
-        return;
-    }
-
-    g_task_return_pointer(task, ret, (GDestroyNotify) g_variant_unref);
-}
-
-static void
-call_bus_get_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
-    gs_unref_object GTask *task = user_data;
-    GCancellable *         cancellable;
-    CallAsyncInfo *        info;
-    GError *               error = NULL;
-
-    info             = g_task_get_task_data(task);
-    info->connection = g_bus_get_finish(result, &error);
-    cancellable      = g_task_get_cancellable(task);
-
-    if (!info->connection) {
-        g_task_return_error(task, g_steal_pointer(&error));
-        return;
-    }
-
-    g_dbus_connection_call(info->connection,
-                           info->bus_name,
-                           info->object_path,
-                           info->interface_name,
-                           info->method_name,
-                           info->parameters,
-                           info->reply_type,
-                           G_DBUS_CALL_FLAGS_NONE,
-                           info->timeout_msec,
-                           cancellable,
-                           call_cb,
-                           g_steal_pointer(&task));
-}
-
-void
-nm_dbus_call(GBusType            bus_type,
-             const char *        bus_name,
-             const char *        object_path,
-             const char *        interface_name,
-             const char *        method_name,
-             GVariant *          parameters,
-             const GVariantType *reply_type,
-             GCancellable *      cancellable,
-             int                 timeout_msec,
-             GAsyncReadyCallback callback,
-             gpointer            user_data)
-{
-    GTask *        task;
-    CallAsyncInfo *info;
-
-    info  = g_new(CallAsyncInfo, 1);
-    *info = (CallAsyncInfo){
-        .bus_name       = g_strdup(bus_name),
-        .object_path    = g_strdup(object_path),
-        .interface_name = g_strdup(interface_name),
-        .method_name    = g_strdup(method_name),
-        .parameters     = g_variant_ref_sink(parameters),
-        .reply_type     = reply_type,
-        .timeout_msec   = timeout_msec,
-    };
-
-    task = nm_g_task_new(NULL, cancellable, nm_dbus_call, callback, user_data);
-    g_task_set_task_data(task, info, (GDestroyNotify) call_async_info_destroy);
-
-    g_bus_get(bus_type, cancellable, call_bus_get_cb, task);
-}
-
-GVariant *
-nm_dbus_call_finish(GAsyncResult *result, GError **error)
-{
-    nm_assert(nm_g_task_is_valid(result, NULL, nm_dbus_call));
-
-    return g_task_propagate_pointer(G_TASK(result), error);
-}
-
-/*****************************************************************************/
-
-gboolean
-_nm_dbus_error_is(GError *error, ...)
-{
-    gs_free char *dbus_error = NULL;
-    const char *  name;
-    va_list       ap;
-
-    dbus_error = g_dbus_error_get_remote_error(error);
-    if (!dbus_error)
-        return FALSE;
-
-    va_start(ap, error);
-    while ((name = va_arg(ap, const char *))) {
-        if (nm_streq(dbus_error, name)) {
-            va_end(ap);
-            return TRUE;
-        }
-    }
-    va_end(ap);
-
-    return FALSE;
-}
diff --git a/shared/nm-glib-aux/nm-dbus-aux.h b/shared/nm-glib-aux/nm-dbus-aux.h
deleted file mode 100644
index c8107082..00000000
--- a/shared/nm-glib-aux/nm-dbus-aux.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019 Red Hat, Inc.
- */
-
-#ifndef __NM_DBUS_AUX_H__
-#define __NM_DBUS_AUX_H__
-
-#include "nm-std-aux/nm-dbus-compat.h"
-
-/*****************************************************************************/
-
-static inline gboolean
-nm_clear_g_dbus_connection_signal(GDBusConnection *dbus_connection, guint *id)
-{
-    guint v;
-
-    if (id && (v = *id)) {
-        *id = 0;
-        g_dbus_connection_signal_unsubscribe(dbus_connection, v);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/*****************************************************************************/
-
-typedef void (*NMDBusConnectionCallDefaultCb)(GVariant *result, GError *error, gpointer user_data);
-
-/*****************************************************************************/
-
-static inline void
-nm_dbus_connection_call_start_service_by_name(GDBusConnection *   dbus_connection,
-                                              const char *        name,
-                                              int                 timeout_msec,
-                                              GCancellable *      cancellable,
-                                              GAsyncReadyCallback callback,
-                                              gpointer            user_data)
-{
-    g_dbus_connection_call(dbus_connection,
-                           DBUS_SERVICE_DBUS,
-                           DBUS_PATH_DBUS,
-                           DBUS_INTERFACE_DBUS,
-                           "StartServiceByName",
-                           g_variant_new("(su)", name, 0u),
-                           G_VARIANT_TYPE("(u)"),
-                           G_DBUS_CALL_FLAGS_NONE,
-                           timeout_msec,
-                           cancellable,
-                           callback,
-                           user_data);
-}
-
-/*****************************************************************************/
-
-static inline guint
-nm_dbus_connection_signal_subscribe_name_owner_changed(GDBusConnection *   dbus_connection,
-                                                       const char *        service_name,
-                                                       GDBusSignalCallback callback,
-                                                       gpointer            user_data,
-                                                       GDestroyNotify      user_data_free_func)
-
-{
-    return g_dbus_connection_signal_subscribe(dbus_connection,
-                                              DBUS_SERVICE_DBUS,
-                                              DBUS_INTERFACE_DBUS,
-                                              "NameOwnerChanged",
-                                              DBUS_PATH_DBUS,
-                                              service_name,
-                                              G_DBUS_SIGNAL_FLAGS_NONE,
-                                              callback,
-                                              user_data,
-                                              user_data_free_func);
-}
-
-typedef void (*NMDBusConnectionCallGetNameOwnerCb)(const char *name_owner,
-                                                   GError *    error,
-                                                   gpointer    user_data);
-
-void nm_dbus_connection_call_get_name_owner(GDBusConnection *                  dbus_connection,
-                                            const char *                       service_name,
-                                            int                                timeout_msec,
-                                            GCancellable *                     cancellable,
-                                            NMDBusConnectionCallGetNameOwnerCb callback,
-                                            gpointer                           user_data);
-
-static inline guint
-nm_dbus_connection_signal_subscribe_properties_changed(GDBusConnection *   dbus_connection,
-                                                       const char *        bus_name,
-                                                       const char *        object_path,
-                                                       const char *        interface_name,
-                                                       GDBusSignalCallback callback,
-                                                       gpointer            user_data,
-                                                       GDestroyNotify      user_data_free_func)
-
-{
-    nm_assert(bus_name);
-
-    /* it seems that using a non-unique name causes problems that we get signals
-     * also from unrelated senders. Usually, you are anyway monitoring the name-owner,
-     * so you should have the unique name at hand.
-     *
-     * If not, investigate this, ensure that it works, and lift this restriction. */
-    nm_assert(g_dbus_is_unique_name(bus_name));
-
-    return g_dbus_connection_signal_subscribe(dbus_connection,
-                                              bus_name,
-                                              DBUS_INTERFACE_PROPERTIES,
-                                              "PropertiesChanged",
-                                              object_path,
-                                              interface_name,
-                                              G_DBUS_SIGNAL_FLAGS_NONE,
-                                              callback,
-                                              user_data,
-                                              user_data_free_func);
-}
-
-void nm_dbus_connection_call_get_all(GDBusConnection *             dbus_connection,
-                                     const char *                  bus_name,
-                                     const char *                  object_path,
-                                     const char *                  interface_name,
-                                     int                           timeout_msec,
-                                     GCancellable *                cancellable,
-                                     NMDBusConnectionCallDefaultCb callback,
-                                     gpointer                      user_data);
-
-void nm_dbus_connection_call_set(GDBusConnection *             dbus_connection,
-                                 const char *                  bus_name,
-                                 const char *                  object_path,
-                                 const char *                  interface_name,
-                                 const char *                  property_name,
-                                 GVariant *                    value,
-                                 int                           timeout_msec,
-                                 GCancellable *                cancellable,
-                                 NMDBusConnectionCallDefaultCb callback,
-                                 gpointer                      user_data);
-
-/*****************************************************************************/
-
-static inline guint
-nm_dbus_connection_signal_subscribe_object_manager(GDBusConnection *   dbus_connection,
-                                                   const char *        service_name,
-                                                   const char *        object_path,
-                                                   const char *        signal_name,
-                                                   GDBusSignalCallback callback,
-                                                   gpointer            user_data,
-                                                   GDestroyNotify      user_data_free_func)
-{
-    return g_dbus_connection_signal_subscribe(dbus_connection,
-                                              service_name,
-                                              DBUS_INTERFACE_OBJECT_MANAGER,
-                                              signal_name,
-                                              object_path,
-                                              NULL,
-                                              G_DBUS_SIGNAL_FLAGS_NONE,
-                                              callback,
-                                              user_data,
-                                              user_data_free_func);
-}
-
-void nm_dbus_connection_call_get_managed_objects(GDBusConnection *             dbus_connection,
-                                                 const char *                  bus_name,
-                                                 const char *                  object_path,
-                                                 GDBusCallFlags                flags,
-                                                 int                           timeout_msec,
-                                                 GCancellable *                cancellable,
-                                                 NMDBusConnectionCallDefaultCb callback,
-                                                 gpointer                      user_data);
-
-/*****************************************************************************/
-
-void
-nm_dbus_connection_call_finish_void_cb(GObject *source, GAsyncResult *result, gpointer user_data);
-
-void nm_dbus_connection_call_finish_void_strip_dbus_error_cb(GObject *     source,
-                                                             GAsyncResult *result,
-                                                             gpointer      user_data);
-
-void nm_dbus_connection_call_finish_variant_cb(GObject *     source,
-                                               GAsyncResult *result,
-                                               gpointer      user_data);
-
-void nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(GObject *     source,
-                                                                GAsyncResult *result,
-                                                                gpointer      user_data);
-
-/*****************************************************************************/
-
-void nm_dbus_call(GBusType            bus_type,
-                  const char *        bus_name,
-                  const char *        object_path,
-                  const char *        interface_name,
-                  const char *        method_name,
-                  GVariant *          parameters,
-                  const GVariantType *reply_type,
-                  GCancellable *      cancellable,
-                  int                 timeout_msec,
-                  GAsyncReadyCallback callback,
-                  gpointer            user_data);
-
-GVariant *nm_dbus_call_finish(GAsyncResult *result, GError **error);
-
-/*****************************************************************************/
-
-gboolean _nm_dbus_error_is(GError *error, ...) G_GNUC_NULL_TERMINATED;
-
-#define nm_dbus_error_is(error, ...)                           \
-    ({                                                         \
-        GError *const _error = (error);                        \
-                                                               \
-        _error &&_nm_dbus_error_is(_error, __VA_ARGS__, NULL); \
-    })
-
-#define NM_DBUS_ERROR_NAME_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod"
-
-/*****************************************************************************/
-
-#endif /* __NM_DBUS_AUX_H__ */
diff --git a/shared/nm-glib-aux/nm-dedup-multi.c b/shared/nm-glib-aux/nm-dedup-multi.c
deleted file mode 100644
index 99da3b35..00000000
--- a/shared/nm-glib-aux/nm-dedup-multi.c
+++ /dev/null
@@ -1,1065 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-dedup-multi.h"
-
-#include "nm-hash-utils.h"
-#include "nm-c-list.h"
-
-/*****************************************************************************/
-
-typedef struct {
-    /* the stack-allocated lookup entry. It has a compatible
-     * memory layout with NMDedupMultiEntry and NMDedupMultiHeadEntry.
-     *
-     * It is recognizable by having lst_entries_sentinel.next set to NULL.
-     * Contrary to the other entries, which have lst_entries.next
-     * always non-NULL.
-     * */
-    CList                      lst_entries_sentinel;
-    const NMDedupMultiObj *    obj;
-    const NMDedupMultiIdxType *idx_type;
-    bool                       lookup_head;
-} LookupEntry;
-
-struct _NMDedupMultiIndex {
-    int         ref_count;
-    GHashTable *idx_entries;
-    GHashTable *idx_objs;
-};
-
-/*****************************************************************************/
-
-static void
-ASSERT_idx_type(const NMDedupMultiIdxType *idx_type)
-{
-    nm_assert(idx_type);
-#if NM_MORE_ASSERTS > 10
-    nm_assert(idx_type->klass);
-    nm_assert(idx_type->klass->idx_obj_id_hash_update);
-    nm_assert(idx_type->klass->idx_obj_id_equal);
-    nm_assert(!!idx_type->klass->idx_obj_partition_hash_update
-              == !!idx_type->klass->idx_obj_partition_equal);
-    nm_assert(idx_type->lst_idx_head.next);
-#endif
-}
-
-void
-nm_dedup_multi_idx_type_init(NMDedupMultiIdxType *idx_type, const NMDedupMultiIdxTypeClass *klass)
-{
-    nm_assert(idx_type);
-    nm_assert(klass);
-
-    *idx_type = (NMDedupMultiIdxType){
-        .klass        = klass,
-        .lst_idx_head = C_LIST_INIT(idx_type->lst_idx_head),
-    };
-
-    ASSERT_idx_type(idx_type);
-}
-
-/*****************************************************************************/
-
-static NMDedupMultiEntry *
-_entry_lookup_obj(const NMDedupMultiIndex *  self,
-                  const NMDedupMultiIdxType *idx_type,
-                  const NMDedupMultiObj *    obj)
-{
-    const LookupEntry stack_entry = {
-        .obj         = obj,
-        .idx_type    = idx_type,
-        .lookup_head = FALSE,
-    };
-
-    ASSERT_idx_type(idx_type);
-    return g_hash_table_lookup(self->idx_entries, &stack_entry);
-}
-
-static NMDedupMultiHeadEntry *
-_entry_lookup_head(const NMDedupMultiIndex *  self,
-                   const NMDedupMultiIdxType *idx_type,
-                   const NMDedupMultiObj *    obj)
-{
-    NMDedupMultiHeadEntry *head_entry;
-    const LookupEntry      stack_entry = {
-        .obj         = obj,
-        .idx_type    = idx_type,
-        .lookup_head = TRUE,
-    };
-
-    ASSERT_idx_type(idx_type);
-
-    if (!idx_type->klass->idx_obj_partition_equal) {
-        if (c_list_is_empty(&idx_type->lst_idx_head))
-            head_entry = NULL;
-        else {
-            nm_assert(c_list_length(&idx_type->lst_idx_head) == 1);
-            head_entry = c_list_entry(idx_type->lst_idx_head.next, NMDedupMultiHeadEntry, lst_idx);
-        }
-        nm_assert(head_entry == g_hash_table_lookup(self->idx_entries, &stack_entry));
-        return head_entry;
-    }
-
-    return g_hash_table_lookup(self->idx_entries, &stack_entry);
-}
-
-static void
-_entry_unpack(const NMDedupMultiEntry *   entry,
-              const NMDedupMultiIdxType **out_idx_type,
-              const NMDedupMultiObj **    out_obj,
-              gboolean *                  out_lookup_head)
-{
-    const NMDedupMultiHeadEntry *head_entry;
-    const LookupEntry *          lookup_entry;
-
-    nm_assert(entry);
-
-    G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(LookupEntry, lst_entries_sentinel)
-                         == G_STRUCT_OFFSET(NMDedupMultiEntry, lst_entries));
-    G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDedupMultiEntry, lst_entries)
-                         == G_STRUCT_OFFSET(NMDedupMultiHeadEntry, lst_entries_head));
-    G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDedupMultiEntry, obj)
-                         == G_STRUCT_OFFSET(NMDedupMultiHeadEntry, idx_type));
-    G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDedupMultiEntry, is_head)
-                         == G_STRUCT_OFFSET(NMDedupMultiHeadEntry, is_head));
-
-    if (!entry->lst_entries.next) {
-        /* the entry is stack-allocated by _entry_lookup(). */
-        lookup_entry     = (LookupEntry *) entry;
-        *out_obj         = lookup_entry->obj;
-        *out_idx_type    = lookup_entry->idx_type;
-        *out_lookup_head = lookup_entry->lookup_head;
-    } else if (entry->is_head) {
-        head_entry = (NMDedupMultiHeadEntry *) entry;
-        nm_assert(!c_list_is_empty(&head_entry->lst_entries_head));
-        *out_obj =
-            c_list_entry(head_entry->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->obj;
-        *out_idx_type    = head_entry->idx_type;
-        *out_lookup_head = TRUE;
-    } else {
-        *out_obj         = entry->obj;
-        *out_idx_type    = entry->head->idx_type;
-        *out_lookup_head = FALSE;
-    }
-
-    nm_assert(NM_IN_SET(*out_lookup_head, FALSE, TRUE));
-    ASSERT_idx_type(*out_idx_type);
-
-    /* for lookup of the head, we allow to omit object, but only
-     * if the idx_type does not partition the objects. Otherwise, we
-     * require a obj to compare. */
-    nm_assert(!*out_lookup_head || (*out_obj || !(*out_idx_type)->klass->idx_obj_partition_equal));
-
-    /* lookup of the object requires always an object. */
-    nm_assert(*out_lookup_head || *out_obj);
-}
-
-static guint
-_dict_idx_entries_hash(const NMDedupMultiEntry *entry)
-{
-    const NMDedupMultiIdxType *idx_type;
-    const NMDedupMultiObj *    obj;
-    gboolean                   lookup_head;
-    NMHashState                h;
-
-    _entry_unpack(entry, &idx_type, &obj, &lookup_head);
-
-    nm_hash_init(&h, 1914869417u);
-    if (idx_type->klass->idx_obj_partition_hash_update) {
-        nm_assert(obj);
-        idx_type->klass->idx_obj_partition_hash_update(idx_type, obj, &h);
-    }
-
-    if (!lookup_head)
-        idx_type->klass->idx_obj_id_hash_update(idx_type, obj, &h);
-
-    nm_hash_update_val(&h, idx_type);
-    return nm_hash_complete(&h);
-}
-
-static gboolean
-_dict_idx_entries_equal(const NMDedupMultiEntry *entry_a, const NMDedupMultiEntry *entry_b)
-{
-    const NMDedupMultiIdxType *idx_type_a, *idx_type_b;
-    const NMDedupMultiObj *    obj_a, *obj_b;
-    gboolean                   lookup_head_a, lookup_head_b;
-
-    _entry_unpack(entry_a, &idx_type_a, &obj_a, &lookup_head_a);
-    _entry_unpack(entry_b, &idx_type_b, &obj_b, &lookup_head_b);
-
-    if (idx_type_a != idx_type_b || lookup_head_a != lookup_head_b)
-        return FALSE;
-    if (!nm_dedup_multi_idx_type_partition_equal(idx_type_a, obj_a, obj_b))
-        return FALSE;
-    if (!lookup_head_a && !nm_dedup_multi_idx_type_id_equal(idx_type_a, obj_a, obj_b))
-        return FALSE;
-    return TRUE;
-}
-
-/*****************************************************************************/
-
-static gboolean
-_add(NMDedupMultiIndex *       self,
-     NMDedupMultiIdxType *     idx_type,
-     const NMDedupMultiObj *   obj,
-     NMDedupMultiEntry *       entry,
-     NMDedupMultiIdxMode       mode,
-     const NMDedupMultiEntry * entry_order,
-     NMDedupMultiHeadEntry *   head_existing,
-     const NMDedupMultiEntry **out_entry,
-     const NMDedupMultiObj **  out_obj_old)
-{
-    NMDedupMultiHeadEntry *head_entry;
-    const NMDedupMultiObj *obj_new, *obj_old;
-    gboolean               add_head_entry = FALSE;
-
-    nm_assert(self);
-    ASSERT_idx_type(idx_type);
-    nm_assert(obj);
-    nm_assert(NM_IN_SET(mode,
-                        NM_DEDUP_MULTI_IDX_MODE_PREPEND,
-                        NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE,
-                        NM_DEDUP_MULTI_IDX_MODE_APPEND,
-                        NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE));
-    nm_assert(!head_existing || head_existing->idx_type == idx_type);
-    nm_assert(({
-        const NMDedupMultiHeadEntry *_h;
-        gboolean                     _ok = TRUE;
-        if (head_existing) {
-            _h = nm_dedup_multi_index_lookup_head(self, idx_type, obj);
-            if (head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING)
-                _ok = (_h == NULL);
-            else
-                _ok = (_h == head_existing);
-        }
-        _ok;
-    }));
-
-    if (entry) {
-        gboolean changed = FALSE;
-
-        nm_dedup_multi_entry_set_dirty(entry, FALSE);
-
-        nm_assert(!head_existing || entry->head == head_existing);
-        nm_assert(!entry_order || entry_order->head == entry->head);
-        nm_assert(!entry_order || c_list_contains(&entry->lst_entries, &entry_order->lst_entries));
-        nm_assert(!entry_order || c_list_contains(&entry_order->lst_entries, &entry->lst_entries));
-
-        switch (mode) {
-        case NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE:
-            if (entry_order) {
-                if (nm_c_list_move_before((CList *) &entry_order->lst_entries, &entry->lst_entries))
-                    changed = TRUE;
-            } else {
-                if (nm_c_list_move_front((CList *) &entry->head->lst_entries_head,
-                                         &entry->lst_entries))
-                    changed = TRUE;
-            }
-            break;
-        case NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE:
-            if (entry_order) {
-                if (nm_c_list_move_after((CList *) &entry_order->lst_entries, &entry->lst_entries))
-                    changed = TRUE;
-            } else {
-                if (nm_c_list_move_tail((CList *) &entry->head->lst_entries_head,
-                                        &entry->lst_entries))
-                    changed = TRUE;
-            }
-            break;
-        case NM_DEDUP_MULTI_IDX_MODE_PREPEND:
-        case NM_DEDUP_MULTI_IDX_MODE_APPEND:
-            break;
-        };
-
-        nm_assert(obj->klass == ((const NMDedupMultiObj *) entry->obj)->klass);
-        if (obj == entry->obj || obj->klass->obj_full_equal(obj, entry->obj)) {
-            NM_SET_OUT(out_entry, entry);
-            NM_SET_OUT(out_obj_old, nm_dedup_multi_obj_ref(entry->obj));
-            return changed;
-        }
-
-        obj_new = nm_dedup_multi_index_obj_intern(self, obj);
-
-        obj_old    = entry->obj;
-        entry->obj = obj_new;
-
-        NM_SET_OUT(out_entry, entry);
-        if (out_obj_old)
-            *out_obj_old = obj_old;
-        else
-            nm_dedup_multi_obj_unref(obj_old);
-        return TRUE;
-    }
-
-    if (idx_type->klass->idx_obj_partitionable
-        && !idx_type->klass->idx_obj_partitionable(idx_type, obj)) {
-        /* this object cannot be partitioned by this idx_type. */
-        nm_assert(!head_existing || head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING);
-        NM_SET_OUT(out_entry, NULL);
-        NM_SET_OUT(out_obj_old, NULL);
-        return FALSE;
-    }
-
-    obj_new = nm_dedup_multi_index_obj_intern(self, obj);
-
-    if (!head_existing)
-        head_entry = _entry_lookup_head(self, idx_type, obj_new);
-    else if (head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING)
-        head_entry = NULL;
-    else
-        head_entry = head_existing;
-
-    if (!head_entry) {
-        head_entry           = g_slice_new0(NMDedupMultiHeadEntry);
-        head_entry->is_head  = TRUE;
-        head_entry->idx_type = idx_type;
-        c_list_init(&head_entry->lst_entries_head);
-        c_list_link_tail(&idx_type->lst_idx_head, &head_entry->lst_idx);
-        add_head_entry = TRUE;
-    } else
-        nm_assert(c_list_contains(&idx_type->lst_idx_head, &head_entry->lst_idx));
-
-    if (entry_order) {
-        nm_assert(!add_head_entry);
-        nm_assert(entry_order->head == head_entry);
-        nm_assert(c_list_contains(&head_entry->lst_entries_head, &entry_order->lst_entries));
-        nm_assert(c_list_contains(&entry_order->lst_entries, &head_entry->lst_entries_head));
-    }
-
-    entry       = g_slice_new0(NMDedupMultiEntry);
-    entry->obj  = obj_new;
-    entry->head = head_entry;
-
-    switch (mode) {
-    case NM_DEDUP_MULTI_IDX_MODE_PREPEND:
-    case NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE:
-        if (entry_order)
-            c_list_link_before((CList *) &entry_order->lst_entries, &entry->lst_entries);
-        else
-            c_list_link_front(&head_entry->lst_entries_head, &entry->lst_entries);
-        break;
-    default:
-        if (entry_order)
-            c_list_link_after((CList *) &entry_order->lst_entries, &entry->lst_entries);
-        else
-            c_list_link_tail(&head_entry->lst_entries_head, &entry->lst_entries);
-        break;
-    };
-
-    idx_type->len++;
-    head_entry->len++;
-
-    if (add_head_entry && !g_hash_table_add(self->idx_entries, head_entry))
-        nm_assert_not_reached();
-
-    if (!g_hash_table_add(self->idx_entries, entry))
-        nm_assert_not_reached();
-
-    NM_SET_OUT(out_entry, entry);
-    NM_SET_OUT(out_obj_old, NULL);
-    return TRUE;
-}
-
-gboolean
-nm_dedup_multi_index_add(NMDedupMultiIndex *                        self,
-                         NMDedupMultiIdxType *                      idx_type,
-                         /*const NMDedupMultiObj * */ gconstpointer obj,
-                         NMDedupMultiIdxMode                        mode,
-                         const NMDedupMultiEntry **                 out_entry,
-                         /* const NMDedupMultiObj ** */ gpointer    out_obj_old)
-{
-    NMDedupMultiEntry *entry;
-
-    g_return_val_if_fail(self, FALSE);
-    g_return_val_if_fail(idx_type, FALSE);
-    g_return_val_if_fail(obj, FALSE);
-    g_return_val_if_fail(NM_IN_SET(mode,
-                                   NM_DEDUP_MULTI_IDX_MODE_PREPEND,
-                                   NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE,
-                                   NM_DEDUP_MULTI_IDX_MODE_APPEND,
-                                   NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE),
-                         FALSE);
-
-    entry = _entry_lookup_obj(self, idx_type, obj);
-    return _add(self, idx_type, obj, entry, mode, NULL, NULL, out_entry, out_obj_old);
-}
-
-/* nm_dedup_multi_index_add_full:
- * @self: the index instance.
- * @idx_type: the index handle for storing @obj.
- * @obj: the NMDedupMultiObj instance to add.
- * @mode: whether to append or prepend the new item. If @entry_order is given,
- *   the entry will be sorted after/before, instead of appending/prepending to
- *   the entire list. If a comparable object is already tracked, then it may
- *   still be resorted by specifying one of the "FORCE" modes.
- * @entry_order: if not NULL, the new entry will be sorted before or after @entry_order.
- *   If given, @entry_order MUST be tracked by @self, and the object it points to MUST
- *   be in the same partition tracked by @idx_type. That is, they must have the same
- *   head_entry and it means, you must ensure that @entry_order and the created/modified
- *   entry will share the same head.
- * @entry_existing: if not NULL, it safes a hash lookup of the entry where the
- *   object will be placed in. You can omit this, and it will be automatically
- *   detected (at the expense of an additional hash lookup).
- *   Basically, this is the result of nm_dedup_multi_index_lookup_obj(),
- *   with the peculiarity that if you know that @obj is not yet tracked,
- *   you may specify %NM_DEDUP_MULTI_ENTRY_MISSING.
- * @head_existing: an optional argument to safe a lookup for the head. If specified,
- *   it must be identical to nm_dedup_multi_index_lookup_head(), with the peculiarity
- *   that if the head is not yet tracked, you may specify %NM_DEDUP_MULTI_HEAD_ENTRY_MISSING
- * @out_entry: if give, return the added entry. This entry may have already exists (update)
- *   or be newly created. If @obj is not partitionable according to @idx_type, @obj
- *   is not to be added and it returns %NULL.
- * @out_obj_old: if given, return the previously contained object. It only
- *   returns a  object, if a matching entry was tracked previously, not if a
- *   new entry was created. Note that when passing @out_obj_old you obtain a reference
- *   to the boxed object and MUST return it with nm_dedup_multi_obj_unref().
- *
- * Adds and object to the index.
- *
- * Return: %TRUE if anything changed, %FALSE if nothing changed.
- */
-gboolean
-nm_dedup_multi_index_add_full(NMDedupMultiIndex *                        self,
-                              NMDedupMultiIdxType *                      idx_type,
-                              /*const NMDedupMultiObj * */ gconstpointer obj,
-                              NMDedupMultiIdxMode                        mode,
-                              const NMDedupMultiEntry *                  entry_order,
-                              const NMDedupMultiEntry *                  entry_existing,
-                              const NMDedupMultiHeadEntry *              head_existing,
-                              const NMDedupMultiEntry **                 out_entry,
-                              /* const NMDedupMultiObj ** */ gpointer    out_obj_old)
-{
-    NMDedupMultiEntry *entry;
-
-    g_return_val_if_fail(self, FALSE);
-    g_return_val_if_fail(idx_type, FALSE);
-    g_return_val_if_fail(obj, FALSE);
-    g_return_val_if_fail(NM_IN_SET(mode,
-                                   NM_DEDUP_MULTI_IDX_MODE_PREPEND,
-                                   NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE,
-                                   NM_DEDUP_MULTI_IDX_MODE_APPEND,
-                                   NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE),
-                         FALSE);
-
-    if (entry_existing == NULL)
-        entry = _entry_lookup_obj(self, idx_type, obj);
-    else if (entry_existing == NM_DEDUP_MULTI_ENTRY_MISSING) {
-        nm_assert(!_entry_lookup_obj(self, idx_type, obj));
-        entry = NULL;
-    } else {
-        nm_assert(entry_existing == _entry_lookup_obj(self, idx_type, obj));
-        entry = (NMDedupMultiEntry *) entry_existing;
-    }
-    return _add(self,
-                idx_type,
-                obj,
-                entry,
-                mode,
-                entry_order,
-                (NMDedupMultiHeadEntry *) head_existing,
-                out_entry,
-                out_obj_old);
-}
-
-/*****************************************************************************/
-
-static void
-_remove_entry(NMDedupMultiIndex *self, NMDedupMultiEntry *entry, gboolean *out_head_entry_removed)
-{
-    const NMDedupMultiObj *obj;
-    NMDedupMultiHeadEntry *head_entry;
-    NMDedupMultiIdxType *  idx_type;
-
-    nm_assert(self);
-    nm_assert(entry);
-    nm_assert(entry->obj);
-    nm_assert(entry->head);
-    nm_assert(!c_list_is_empty(&entry->lst_entries));
-    nm_assert(g_hash_table_lookup(self->idx_entries, entry) == entry);
-
-    head_entry = (NMDedupMultiHeadEntry *) entry->head;
-    obj        = entry->obj;
-
-    nm_assert(head_entry);
-    nm_assert(head_entry->len > 0);
-    nm_assert(g_hash_table_lookup(self->idx_entries, head_entry) == head_entry);
-
-    idx_type = (NMDedupMultiIdxType *) head_entry->idx_type;
-    ASSERT_idx_type(idx_type);
-
-    nm_assert(idx_type->len >= head_entry->len);
-    if (--head_entry->len > 0) {
-        nm_assert(idx_type->len > 1);
-        idx_type->len--;
-        head_entry = NULL;
-    }
-
-    NM_SET_OUT(out_head_entry_removed, head_entry != NULL);
-
-    if (!g_hash_table_remove(self->idx_entries, entry))
-        nm_assert_not_reached();
-
-    if (head_entry && !g_hash_table_remove(self->idx_entries, head_entry))
-        nm_assert_not_reached();
-
-    c_list_unlink_stale(&entry->lst_entries);
-    g_slice_free(NMDedupMultiEntry, entry);
-
-    if (head_entry) {
-        nm_assert(c_list_is_empty(&head_entry->lst_entries_head));
-        c_list_unlink_stale(&head_entry->lst_idx);
-        g_slice_free(NMDedupMultiHeadEntry, head_entry);
-    }
-
-    nm_dedup_multi_obj_unref(obj);
-}
-
-static guint
-_remove_head(NMDedupMultiIndex *    self,
-             NMDedupMultiHeadEntry *head_entry,
-             gboolean               remove_all /* otherwise just dirty ones */,
-             gboolean               mark_survivors_dirty)
-{
-    guint    n;
-    gboolean head_entry_removed;
-    CList *  iter_entry, *iter_entry_safe;
-
-    nm_assert(self);
-    nm_assert(head_entry);
-    nm_assert(head_entry->len > 0);
-    nm_assert(head_entry->len == c_list_length(&head_entry->lst_entries_head));
-    nm_assert(g_hash_table_lookup(self->idx_entries, head_entry) == head_entry);
-
-    n = 0;
-    c_list_for_each_safe (iter_entry, iter_entry_safe, &head_entry->lst_entries_head) {
-        NMDedupMultiEntry *entry;
-
-        entry = c_list_entry(iter_entry, NMDedupMultiEntry, lst_entries);
-        if (remove_all || entry->dirty) {
-            _remove_entry(self, entry, &head_entry_removed);
-            n++;
-            if (head_entry_removed)
-                break;
-        } else if (mark_survivors_dirty)
-            nm_dedup_multi_entry_set_dirty(entry, TRUE);
-    }
-
-    return n;
-}
-
-static guint
-_remove_idx_entry(NMDedupMultiIndex *  self,
-                  NMDedupMultiIdxType *idx_type,
-                  gboolean             remove_all /* otherwise just dirty ones */,
-                  gboolean             mark_survivors_dirty)
-{
-    guint  n;
-    CList *iter_idx, *iter_idx_safe;
-
-    nm_assert(self);
-    ASSERT_idx_type(idx_type);
-
-    n = 0;
-    c_list_for_each_safe (iter_idx, iter_idx_safe, &idx_type->lst_idx_head) {
-        n += _remove_head(self,
-                          c_list_entry(iter_idx, NMDedupMultiHeadEntry, lst_idx),
-                          remove_all,
-                          mark_survivors_dirty);
-    }
-    return n;
-}
-
-guint
-nm_dedup_multi_index_remove_entry(NMDedupMultiIndex *self, gconstpointer entry)
-{
-    g_return_val_if_fail(self, 0);
-
-    nm_assert(entry);
-
-    if (!((NMDedupMultiEntry *) entry)->is_head) {
-        _remove_entry(self, (NMDedupMultiEntry *) entry, NULL);
-        return 1;
-    }
-    return _remove_head(self, (NMDedupMultiHeadEntry *) entry, TRUE, FALSE);
-}
-
-guint
-nm_dedup_multi_index_remove_obj(NMDedupMultiIndex *                          self,
-                                NMDedupMultiIdxType *                        idx_type,
-                                /*const NMDedupMultiObj * */ gconstpointer   obj,
-                                /*const NMDedupMultiObj ** */ gconstpointer *out_obj)
-{
-    const NMDedupMultiEntry *entry;
-
-    entry = nm_dedup_multi_index_lookup_obj(self, idx_type, obj);
-    if (!entry) {
-        NM_SET_OUT(out_obj, NULL);
-        return 0;
-    }
-
-    /* since we are about to remove the object, we obviously pass
-     * a reference to @out_obj, the caller MUST unref the object,
-     * if he chooses to provide @out_obj. */
-    NM_SET_OUT(out_obj, nm_dedup_multi_obj_ref(entry->obj));
-
-    _remove_entry(self, (NMDedupMultiEntry *) entry, NULL);
-    return 1;
-}
-
-guint
-nm_dedup_multi_index_remove_head(NMDedupMultiIndex *                        self,
-                                 NMDedupMultiIdxType *                      idx_type,
-                                 /*const NMDedupMultiObj * */ gconstpointer obj)
-{
-    const NMDedupMultiHeadEntry *entry;
-
-    entry = nm_dedup_multi_index_lookup_head(self, idx_type, obj);
-    return entry ? _remove_head(self, (NMDedupMultiHeadEntry *) entry, TRUE, FALSE) : 0;
-}
-
-guint
-nm_dedup_multi_index_remove_idx(NMDedupMultiIndex *self, NMDedupMultiIdxType *idx_type)
-{
-    g_return_val_if_fail(self, 0);
-    g_return_val_if_fail(idx_type, 0);
-
-    return _remove_idx_entry(self, idx_type, TRUE, FALSE);
-}
-
-/*****************************************************************************/
-
-/**
- * nm_dedup_multi_index_lookup_obj:
- * @self: the index cache
- * @idx_type: the lookup index type
- * @obj: the object to lookup. This means the match is performed
- *   according to NMDedupMultiIdxTypeClass's idx_obj_id_equal()
- *   of @idx_type.
- *
- * Returns: the cache entry or %NULL if the entry wasn't found.
- */
-const NMDedupMultiEntry *
-nm_dedup_multi_index_lookup_obj(const NMDedupMultiIndex *                  self,
-                                const NMDedupMultiIdxType *                idx_type,
-                                /*const NMDedupMultiObj * */ gconstpointer obj)
-{
-    g_return_val_if_fail(self, FALSE);
-    g_return_val_if_fail(idx_type, FALSE);
-    g_return_val_if_fail(obj, FALSE);
-
-    nm_assert(idx_type && idx_type->klass);
-    return _entry_lookup_obj(self, idx_type, obj);
-}
-
-/**
- * nm_dedup_multi_index_lookup_head:
- * @self: the index cache
- * @idx_type: the lookup index type
- * @obj: the object to lookup, of type "const NMDedupMultiObj *".
- *   Depending on the idx_type, you *must* also provide a selector
- *   object, even when looking up the list head. That is, because
- *   the idx_type implementation may choose to partition the objects
- *   in distinct list, so you need a selector object to know which
- *   list head to lookup.
- *
- * Returns: the cache entry or %NULL if the entry wasn't found.
- */
-const NMDedupMultiHeadEntry *
-nm_dedup_multi_index_lookup_head(const NMDedupMultiIndex *                  self,
-                                 const NMDedupMultiIdxType *                idx_type,
-                                 /*const NMDedupMultiObj * */ gconstpointer obj)
-{
-    g_return_val_if_fail(self, FALSE);
-    g_return_val_if_fail(idx_type, FALSE);
-
-    return _entry_lookup_head(self, idx_type, obj);
-}
-
-/*****************************************************************************/
-
-void
-nm_dedup_multi_index_dirty_set_head(NMDedupMultiIndex *                        self,
-                                    const NMDedupMultiIdxType *                idx_type,
-                                    /*const NMDedupMultiObj * */ gconstpointer obj)
-{
-    NMDedupMultiHeadEntry *head_entry;
-    CList *                iter_entry;
-
-    g_return_if_fail(self);
-    g_return_if_fail(idx_type);
-
-    head_entry = _entry_lookup_head(self, idx_type, obj);
-    if (!head_entry)
-        return;
-
-    c_list_for_each (iter_entry, &head_entry->lst_entries_head) {
-        NMDedupMultiEntry *entry;
-
-        entry = c_list_entry(iter_entry, NMDedupMultiEntry, lst_entries);
-        nm_dedup_multi_entry_set_dirty(entry, TRUE);
-    }
-}
-
-void
-nm_dedup_multi_index_dirty_set_idx(NMDedupMultiIndex *self, const NMDedupMultiIdxType *idx_type)
-{
-    CList *iter_idx, *iter_entry;
-
-    g_return_if_fail(self);
-    g_return_if_fail(idx_type);
-
-    c_list_for_each (iter_idx, &idx_type->lst_idx_head) {
-        NMDedupMultiHeadEntry *head_entry;
-
-        head_entry = c_list_entry(iter_idx, NMDedupMultiHeadEntry, lst_idx);
-        c_list_for_each (iter_entry, &head_entry->lst_entries_head) {
-            NMDedupMultiEntry *entry;
-
-            entry = c_list_entry(iter_entry, NMDedupMultiEntry, lst_entries);
-            nm_dedup_multi_entry_set_dirty(entry, TRUE);
-        }
-    }
-}
-
-/**
- * nm_dedup_multi_index_dirty_remove_idx:
- * @self: the index instance
- * @idx_type: the index-type to select the objects.
- * @mark_survivors_dirty: while the function removes all entries that are
- *   marked as dirty, if @set_dirty is true, the surviving objects
- *   will be marked dirty right away.
- *
- * Deletes all entries for @idx_type that are marked dirty. Only
- * non-dirty objects survive. If @mark_survivors_dirty is set to TRUE, the survivors
- * are marked as dirty right away.
- *
- * Returns: number of deleted entries.
- */
-guint
-nm_dedup_multi_index_dirty_remove_idx(NMDedupMultiIndex *  self,
-                                      NMDedupMultiIdxType *idx_type,
-                                      gboolean             mark_survivors_dirty)
-{
-    g_return_val_if_fail(self, 0);
-    g_return_val_if_fail(idx_type, 0);
-
-    return _remove_idx_entry(self, idx_type, FALSE, mark_survivors_dirty);
-}
-
-/*****************************************************************************/
-
-static guint
-_dict_idx_objs_hash(const NMDedupMultiObj *obj)
-{
-    NMHashState h;
-
-    nm_hash_init(&h, 1748638583u);
-    obj->klass->obj_full_hash_update(obj, &h);
-    return nm_hash_complete(&h);
-}
-
-static gboolean
-_dict_idx_objs_equal(const NMDedupMultiObj *obj_a, const NMDedupMultiObj *obj_b)
-{
-    return obj_a == obj_b
-           || (obj_a->klass == obj_b->klass && obj_a->klass->obj_full_equal(obj_a, obj_b));
-}
-
-void
-nm_dedup_multi_index_obj_release(NMDedupMultiIndex *                         self,
-                                 /* const NMDedupMultiObj * */ gconstpointer obj)
-{
-    nm_assert(self);
-    nm_assert(obj);
-    nm_assert(g_hash_table_lookup(self->idx_objs, obj) == obj);
-    nm_assert(((const NMDedupMultiObj *) obj)->_multi_idx == self);
-
-    ((NMDedupMultiObj *) obj)->_multi_idx = NULL;
-    if (!g_hash_table_remove(self->idx_objs, obj))
-        nm_assert_not_reached();
-}
-
-gconstpointer
-nm_dedup_multi_index_obj_find(NMDedupMultiIndex *                         self,
-                              /* const NMDedupMultiObj * */ gconstpointer obj)
-{
-    g_return_val_if_fail(self, NULL);
-    g_return_val_if_fail(obj, NULL);
-
-    return g_hash_table_lookup(self->idx_objs, obj);
-}
-
-gconstpointer
-nm_dedup_multi_index_obj_intern(NMDedupMultiIndex *                         self,
-                                /* const NMDedupMultiObj * */ gconstpointer obj)
-{
-    const NMDedupMultiObj *obj_new = obj;
-    const NMDedupMultiObj *obj_old;
-
-    nm_assert(self);
-    nm_assert(obj_new);
-
-    if (obj_new->_multi_idx == self) {
-        nm_assert(g_hash_table_lookup(self->idx_objs, obj_new) == obj_new);
-        nm_dedup_multi_obj_ref(obj_new);
-        return obj_new;
-    }
-
-    obj_old = g_hash_table_lookup(self->idx_objs, obj_new);
-    nm_assert(obj_old != obj_new);
-
-    if (obj_old) {
-        nm_assert(obj_old->_multi_idx == self);
-        nm_dedup_multi_obj_ref(obj_old);
-        return obj_old;
-    }
-
-    if (nm_dedup_multi_obj_needs_clone(obj_new))
-        obj_new = nm_dedup_multi_obj_clone(obj_new);
-    else
-        obj_new = nm_dedup_multi_obj_ref(obj_new);
-
-    nm_assert(obj_new);
-    nm_assert(!obj_new->_multi_idx);
-
-    if (!g_hash_table_add(self->idx_objs, (gpointer) obj_new))
-        nm_assert_not_reached();
-
-    ((NMDedupMultiObj *) obj_new)->_multi_idx = self;
-    return obj_new;
-}
-
-void
-nm_dedup_multi_obj_unref(const NMDedupMultiObj *obj)
-{
-    if (obj) {
-        nm_assert(obj->_ref_count > 0);
-        nm_assert(obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT);
-
-again:
-        if (--(((NMDedupMultiObj *) obj)->_ref_count) <= 0) {
-            if (obj->_multi_idx) {
-                /* restore the ref-count to 1 and release the object first
-                 * from the index. Then, retry again to unref. */
-                ((NMDedupMultiObj *) obj)->_ref_count++;
-                nm_dedup_multi_index_obj_release(obj->_multi_idx, obj);
-                nm_assert(obj->_ref_count == 1);
-                nm_assert(!obj->_multi_idx);
-                goto again;
-            }
-
-            obj->klass->obj_destroy((NMDedupMultiObj *) obj);
-        }
-    }
-}
-
-gboolean
-nm_dedup_multi_obj_needs_clone(const NMDedupMultiObj *obj)
-{
-    nm_assert(obj);
-
-    if (obj->_multi_idx || obj->_ref_count == NM_OBJ_REF_COUNT_STACKINIT)
-        return TRUE;
-
-    if (obj->klass->obj_needs_clone && obj->klass->obj_needs_clone(obj))
-        return TRUE;
-
-    return FALSE;
-}
-
-const NMDedupMultiObj *
-nm_dedup_multi_obj_clone(const NMDedupMultiObj *obj)
-{
-    const NMDedupMultiObj *o;
-
-    nm_assert(obj);
-
-    o = obj->klass->obj_clone(obj);
-    nm_assert(o);
-    nm_assert(o->_ref_count == 1);
-    return o;
-}
-
-gconstpointer *
-nm_dedup_multi_objs_to_array_head(const NMDedupMultiHeadEntry *  head_entry,
-                                  NMDedupMultiFcnSelectPredicate predicate,
-                                  gpointer                       user_data,
-                                  guint *                        out_len)
-{
-    gconstpointer *result;
-    CList *        iter;
-    guint          i;
-
-    if (!head_entry) {
-        NM_SET_OUT(out_len, 0);
-        return NULL;
-    }
-
-    result = g_new(gconstpointer, head_entry->len + 1);
-    i      = 0;
-    c_list_for_each (iter, &head_entry->lst_entries_head) {
-        const NMDedupMultiObj *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
-
-        if (!predicate || predicate(obj, user_data)) {
-            nm_assert(i < head_entry->len);
-            result[i++] = obj;
-        }
-    }
-
-    if (i == 0) {
-        g_free(result);
-        NM_SET_OUT(out_len, 0);
-        return NULL;
-    }
-
-    nm_assert(i <= head_entry->len);
-    NM_SET_OUT(out_len, i);
-    result[i++] = NULL;
-    return result;
-}
-
-GPtrArray *
-nm_dedup_multi_objs_to_ptr_array_head(const NMDedupMultiHeadEntry *  head_entry,
-                                      NMDedupMultiFcnSelectPredicate predicate,
-                                      gpointer                       user_data)
-{
-    GPtrArray *result;
-    CList *    iter;
-
-    if (!head_entry)
-        return NULL;
-
-    result = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref);
-    c_list_for_each (iter, &head_entry->lst_entries_head) {
-        const NMDedupMultiObj *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
-
-        if (!predicate || predicate(obj, user_data))
-            g_ptr_array_add(result, (gpointer) nm_dedup_multi_obj_ref(obj));
-    }
-
-    if (result->len == 0) {
-        g_ptr_array_unref(result);
-        return NULL;
-    }
-    return result;
-}
-
-/**
- * nm_dedup_multi_entry_reorder:
- * @entry: the entry to reorder. It must not be NULL (and tracked in an index).
- * @entry_order: (allow-none): an optional other entry. It MUST be in the same
- *   list as entry. If given, @entry will be ordered after/before @entry_order.
- *   If left at %NULL, @entry will be moved to the front/end of the list.
- * @order_after: if @entry_order is given, %TRUE means to move @entry after
- *   @entry_order (otherwise before).
- *   If @entry_order is %NULL, %TRUE means to move @entry to the tail of the list
- *   (otherwise the beginning). Note that "tail of the list" here means that @entry
- *   will be linked before the head of the circular list.
- *
- * Returns: %TRUE, if anything was changed. Otherwise, @entry was already at the
- * right place and nothing was done.
- */
-gboolean
-nm_dedup_multi_entry_reorder(const NMDedupMultiEntry *entry,
-                             const NMDedupMultiEntry *entry_order,
-                             gboolean                 order_after)
-{
-    nm_assert(entry);
-
-    if (!entry_order) {
-        const NMDedupMultiHeadEntry *head_entry = entry->head;
-
-        if (order_after) {
-            if (nm_c_list_move_tail((CList *) &head_entry->lst_entries_head,
-                                    (CList *) &entry->lst_entries))
-                return TRUE;
-        } else {
-            if (nm_c_list_move_front((CList *) &head_entry->lst_entries_head,
-                                     (CList *) &entry->lst_entries))
-                return TRUE;
-        }
-    } else {
-        if (order_after) {
-            if (nm_c_list_move_after((CList *) &entry_order->lst_entries,
-                                     (CList *) &entry->lst_entries))
-                return TRUE;
-        } else {
-            if (nm_c_list_move_before((CList *) &entry_order->lst_entries,
-                                      (CList *) &entry->lst_entries))
-                return TRUE;
-        }
-    }
-
-    return FALSE;
-}
-
-/*****************************************************************************/
-
-NMDedupMultiIndex *
-nm_dedup_multi_index_new(void)
-{
-    NMDedupMultiIndex *self;
-
-    self            = g_slice_new0(NMDedupMultiIndex);
-    self->ref_count = 1;
-    self->idx_entries =
-        g_hash_table_new((GHashFunc) _dict_idx_entries_hash, (GEqualFunc) _dict_idx_entries_equal);
-    self->idx_objs =
-        g_hash_table_new((GHashFunc) _dict_idx_objs_hash, (GEqualFunc) _dict_idx_objs_equal);
-    return self;
-}
-
-NMDedupMultiIndex *
-nm_dedup_multi_index_ref(NMDedupMultiIndex *self)
-{
-    g_return_val_if_fail(self, NULL);
-    g_return_val_if_fail(self->ref_count > 0, NULL);
-
-    self->ref_count++;
-    return self;
-}
-
-NMDedupMultiIndex *
-nm_dedup_multi_index_unref(NMDedupMultiIndex *self)
-{
-    GHashTableIter             iter;
-    const NMDedupMultiIdxType *idx_type;
-    NMDedupMultiEntry *        entry;
-    const NMDedupMultiObj *    obj;
-
-    g_return_val_if_fail(self, NULL);
-    g_return_val_if_fail(self->ref_count > 0, NULL);
-
-    if (--self->ref_count > 0)
-        return NULL;
-
-more:
-    g_hash_table_iter_init(&iter, self->idx_entries);
-    while (g_hash_table_iter_next(&iter, (gpointer *) &entry, NULL)) {
-        if (entry->is_head)
-            idx_type = ((NMDedupMultiHeadEntry *) entry)->idx_type;
-        else
-            idx_type = entry->head->idx_type;
-        _remove_idx_entry(self, (NMDedupMultiIdxType *) idx_type, TRUE, FALSE);
-        goto more;
-    }
-
-    nm_assert(g_hash_table_size(self->idx_entries) == 0);
-
-    g_hash_table_iter_init(&iter, self->idx_objs);
-    while (g_hash_table_iter_next(&iter, (gpointer *) &obj, NULL)) {
-        nm_assert(obj->_multi_idx == self);
-        ((NMDedupMultiObj *) obj)->_multi_idx = NULL;
-    }
-    g_hash_table_remove_all(self->idx_objs);
-
-    g_hash_table_unref(self->idx_entries);
-    g_hash_table_unref(self->idx_objs);
-
-    g_slice_free(NMDedupMultiIndex, self);
-    return NULL;
-}
diff --git a/shared/nm-glib-aux/nm-dedup-multi.h b/shared/nm-glib-aux/nm-dedup-multi.h
deleted file mode 100644
index 1c0761bf..00000000
--- a/shared/nm-glib-aux/nm-dedup-multi.h
+++ /dev/null
@@ -1,407 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#ifndef __NM_DEDUP_MULTI_H__
-#define __NM_DEDUP_MULTI_H__
-
-#include "nm-obj.h"
-#include "nm-std-aux/c-list-util.h"
-
-/*****************************************************************************/
-
-struct _NMHashState;
-
-typedef struct _NMDedupMultiObj          NMDedupMultiObj;
-typedef struct _NMDedupMultiObjClass     NMDedupMultiObjClass;
-typedef struct _NMDedupMultiIdxType      NMDedupMultiIdxType;
-typedef struct _NMDedupMultiIdxTypeClass NMDedupMultiIdxTypeClass;
-typedef struct _NMDedupMultiEntry        NMDedupMultiEntry;
-typedef struct _NMDedupMultiHeadEntry    NMDedupMultiHeadEntry;
-typedef struct _NMDedupMultiIndex        NMDedupMultiIndex;
-
-typedef enum _NMDedupMultiIdxMode {
-    NM_DEDUP_MULTI_IDX_MODE_PREPEND,
-
-    NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE,
-
-    /* append new objects to the end of the list.
-     * If the object is already in the cache, don't move it. */
-    NM_DEDUP_MULTI_IDX_MODE_APPEND,
-
-    /* like NM_DEDUP_MULTI_IDX_MODE_APPEND, but if the object
-     * is already in the cache, move it to the end. */
-    NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE,
-} NMDedupMultiIdxMode;
-
-/*****************************************************************************/
-
-struct _NMDedupMultiObj {
-    union {
-        NMObjBaseInst               parent;
-        const NMDedupMultiObjClass *klass;
-    };
-    NMDedupMultiIndex *_multi_idx;
-    guint              _ref_count;
-};
-
-struct _NMDedupMultiObjClass {
-    NMObjBaseClass parent;
-
-    const NMDedupMultiObj *(*obj_clone)(const NMDedupMultiObj *obj);
-
-    gboolean (*obj_needs_clone)(const NMDedupMultiObj *obj);
-
-    void (*obj_destroy)(NMDedupMultiObj *obj);
-
-    /* the NMDedupMultiObj can be deduplicated. For that the obj_full_hash_update()
-     * and obj_full_equal() compare *all* fields of the object, even minor ones. */
-    void (*obj_full_hash_update)(const NMDedupMultiObj *obj, struct _NMHashState *h);
-    gboolean (*obj_full_equal)(const NMDedupMultiObj *obj_a, const NMDedupMultiObj *obj_b);
-};
-
-/*****************************************************************************/
-
-static inline const NMDedupMultiObj *
-nm_dedup_multi_obj_ref(const NMDedupMultiObj *obj)
-{
-    /* ref and unref accept const pointers. Objects is supposed to be shared
-     * and kept immutable. Disallowing to take/return a reference to a const
-     * NMPObject is cumbersome, because callers are precisely expected to
-     * keep a ref on the otherwise immutable object. */
-
-    nm_assert(obj);
-    nm_assert(obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT);
-    nm_assert(obj->_ref_count > 0);
-
-    ((NMDedupMultiObj *) obj)->_ref_count++;
-    return obj;
-}
-
-void                   nm_dedup_multi_obj_unref(const NMDedupMultiObj *obj);
-const NMDedupMultiObj *nm_dedup_multi_obj_clone(const NMDedupMultiObj *obj);
-gboolean               nm_dedup_multi_obj_needs_clone(const NMDedupMultiObj *obj);
-
-gconstpointer nm_dedup_multi_index_obj_intern(NMDedupMultiIndex *                         self,
-                                              /* const NMDedupMultiObj * */ gconstpointer obj);
-
-void nm_dedup_multi_index_obj_release(NMDedupMultiIndex *                         self,
-                                      /* const NMDedupMultiObj * */ gconstpointer obj);
-
-/* const NMDedupMultiObj * */ gconstpointer
-nm_dedup_multi_index_obj_find(NMDedupMultiIndex *                         self,
-                              /* const NMDedupMultiObj * */ gconstpointer obj);
-
-/*****************************************************************************/
-
-/* the NMDedupMultiIdxType is an access handle under which you can store and
- * retrieve NMDedupMultiObj instances in NMDedupMultiIndex.
- *
- * The NMDedupMultiIdxTypeClass determines its behavior, but you can have
- * multiple instances (of the same class).
- *
- * For example, NMIP4Config can have idx-type to put there all IPv4 Routes.
- * This idx-type instance is private to the NMIP4Config instance. Basically,
- * the NMIP4Config instance uses the idx-type to maintain an ordered list
- * of routes in NMDedupMultiIndex.
- *
- * However, a NMDedupMultiIdxType may also partition the set of objects
- * in multiple distinct lists. NMIP4Config doesn't do that (because instead
- * of creating one idx-type for IPv4 and IPv6 routes, it just cretaes
- * to distinct idx-types, one for each address family.
- * This partitioning is used by NMPlatform to maintain a lookup index for
- * routes by ifindex. As the ifindex is dynamic, it does not create an
- * idx-type instance for each ifindex. Instead, it has one idx-type for
- * all routes. But whenever accessing NMDedupMultiIndex with an NMDedupMultiObj,
- * the partitioning NMDedupMultiIdxType takes into account the NMDedupMultiObj
- * instance to associate it with the right list.
- *
- * Hence, a NMDedupMultiIdxEntry has a list of possibly multiple NMDedupMultiHeadEntry
- * instances, which each is the head for a list of NMDedupMultiEntry instances.
- * In the platform example, the NMDedupMultiHeadEntry partition the indexed objects
- * by their ifindex. */
-struct _NMDedupMultiIdxType {
-    union {
-        NMObjBaseInst                   parent;
-        const NMDedupMultiIdxTypeClass *klass;
-    };
-
-    CList lst_idx_head;
-
-    guint len;
-};
-
-void nm_dedup_multi_idx_type_init(NMDedupMultiIdxType *           idx_type,
-                                  const NMDedupMultiIdxTypeClass *klass);
-
-struct _NMDedupMultiIdxTypeClass {
-    NMObjBaseClass parent;
-
-    void (*idx_obj_id_hash_update)(const NMDedupMultiIdxType *idx_type,
-                                   const NMDedupMultiObj *    obj,
-                                   struct _NMHashState *      h);
-    gboolean (*idx_obj_id_equal)(const NMDedupMultiIdxType *idx_type,
-                                 const NMDedupMultiObj *    obj_a,
-                                 const NMDedupMultiObj *    obj_b);
-
-    /* an NMDedupMultiIdxTypeClass which implements partitioning of the
-     * tracked objects, must implement the idx_obj_partition*() functions.
-     *
-     * idx_obj_partitionable() may return NULL if the object cannot be tracked.
-     * For example, a index for routes by ifindex, may not want to track any
-     * routes that don't have a valid ifindex. If the idx-type says that the
-     * object is not partitionable, it is never added to the NMDedupMultiIndex. */
-    gboolean (*idx_obj_partitionable)(const NMDedupMultiIdxType *idx_type,
-                                      const NMDedupMultiObj *    obj);
-    void (*idx_obj_partition_hash_update)(const NMDedupMultiIdxType *idx_type,
-                                          const NMDedupMultiObj *    obj,
-                                          struct _NMHashState *      h);
-    gboolean (*idx_obj_partition_equal)(const NMDedupMultiIdxType *idx_type,
-                                        const NMDedupMultiObj *    obj_a,
-                                        const NMDedupMultiObj *    obj_b);
-};
-
-static inline gboolean
-nm_dedup_multi_idx_type_id_equal(const NMDedupMultiIdxType *                 idx_type,
-                                 /* const NMDedupMultiObj * */ gconstpointer obj_a,
-                                 /* const NMDedupMultiObj * */ gconstpointer obj_b)
-{
-    nm_assert(idx_type);
-    return obj_a == obj_b || idx_type->klass->idx_obj_id_equal(idx_type, obj_a, obj_b);
-}
-
-static inline gboolean
-nm_dedup_multi_idx_type_partition_equal(const NMDedupMultiIdxType *                 idx_type,
-                                        /* const NMDedupMultiObj * */ gconstpointer obj_a,
-                                        /* const NMDedupMultiObj * */ gconstpointer obj_b)
-{
-    nm_assert(idx_type);
-    if (idx_type->klass->idx_obj_partition_equal) {
-        nm_assert(obj_a);
-        nm_assert(obj_b);
-        return obj_a == obj_b || idx_type->klass->idx_obj_partition_equal(idx_type, obj_a, obj_b);
-    }
-    return TRUE;
-}
-
-/*****************************************************************************/
-
-struct _NMDedupMultiEntry {
-    /* this is the list of all entries that share the same head entry.
-     * All entries compare equal according to idx_obj_partition_equal(). */
-    CList lst_entries;
-
-    /* const NMDedupMultiObj * */ gconstpointer obj;
-
-    bool is_head;
-    bool dirty;
-
-    const NMDedupMultiHeadEntry *head;
-};
-
-struct _NMDedupMultiHeadEntry {
-    /* this is the list of all entries that share the same head entry.
-     * All entries compare equal according to idx_obj_partition_equal(). */
-    CList lst_entries_head;
-
-    const NMDedupMultiIdxType *idx_type;
-
-    bool is_head;
-
-    guint len;
-
-    CList lst_idx;
-};
-
-/*****************************************************************************/
-
-static inline gconstpointer
-nm_dedup_multi_entry_get_obj(const NMDedupMultiEntry *entry)
-{
-    /* convenience method that allows to skip the %NULL check on
-     * @entry. Think of the NULL-conditional operator ?. of C# */
-    return entry ? entry->obj : NULL;
-}
-
-/*****************************************************************************/
-
-static inline void
-nm_dedup_multi_entry_set_dirty(const NMDedupMultiEntry *entry, gboolean dirty)
-{
-    /* NMDedupMultiEntry is always exposed as a const object, because it is not
-     * supposed to be modified outside NMDedupMultiIndex API. Except the "dirty"
-     * flag. In C++ speak, it is a mutable field.
-     *
-     * Add this inline function, to cast-away constness and set the dirty flag. */
-    nm_assert(entry);
-    ((NMDedupMultiEntry *) entry)->dirty = dirty;
-}
-
-/*****************************************************************************/
-
-NMDedupMultiIndex *nm_dedup_multi_index_new(void);
-NMDedupMultiIndex *nm_dedup_multi_index_ref(NMDedupMultiIndex *self);
-NMDedupMultiIndex *nm_dedup_multi_index_unref(NMDedupMultiIndex *self);
-
-static inline void
-_nm_auto_unref_dedup_multi_index(NMDedupMultiIndex **v)
-{
-    if (*v)
-        nm_dedup_multi_index_unref(*v);
-}
-#define nm_auto_unref_dedup_multi_index nm_auto(_nm_auto_unref_dedup_multi_index)
-
-#define NM_DEDUP_MULTI_ENTRY_MISSING      ((const NMDedupMultiEntry *) GUINT_TO_POINTER(1))
-#define NM_DEDUP_MULTI_HEAD_ENTRY_MISSING ((const NMDedupMultiHeadEntry *) GUINT_TO_POINTER(1))
-
-gboolean nm_dedup_multi_index_add_full(NMDedupMultiIndex *                        self,
-                                       NMDedupMultiIdxType *                      idx_type,
-                                       /*const NMDedupMultiObj * */ gconstpointer obj,
-                                       NMDedupMultiIdxMode                        mode,
-                                       const NMDedupMultiEntry *                  entry_order,
-                                       const NMDedupMultiEntry *                  entry_existing,
-                                       const NMDedupMultiHeadEntry *              head_existing,
-                                       const NMDedupMultiEntry **                 out_entry,
-                                       /* const NMDedupMultiObj ** */ gpointer    out_obj_old);
-
-gboolean nm_dedup_multi_index_add(NMDedupMultiIndex *                        self,
-                                  NMDedupMultiIdxType *                      idx_type,
-                                  /*const NMDedupMultiObj * */ gconstpointer obj,
-                                  NMDedupMultiIdxMode                        mode,
-                                  const NMDedupMultiEntry **                 out_entry,
-                                  /* const NMDedupMultiObj ** */ gpointer    out_obj_old);
-
-const NMDedupMultiEntry *
-nm_dedup_multi_index_lookup_obj(const NMDedupMultiIndex *                  self,
-                                const NMDedupMultiIdxType *                idx_type,
-                                /*const NMDedupMultiObj * */ gconstpointer obj);
-
-const NMDedupMultiHeadEntry *
-nm_dedup_multi_index_lookup_head(const NMDedupMultiIndex *                  self,
-                                 const NMDedupMultiIdxType *                idx_type,
-                                 /*const NMDedupMultiObj * */ gconstpointer obj);
-
-guint nm_dedup_multi_index_remove_entry(NMDedupMultiIndex *self, gconstpointer entry);
-
-guint nm_dedup_multi_index_remove_obj(NMDedupMultiIndex *                          self,
-                                      NMDedupMultiIdxType *                        idx_type,
-                                      /*const NMDedupMultiObj * */ gconstpointer   obj,
-                                      /*const NMDedupMultiObj ** */ gconstpointer *out_obj);
-
-guint nm_dedup_multi_index_remove_head(NMDedupMultiIndex *                        self,
-                                       NMDedupMultiIdxType *                      idx_type,
-                                       /*const NMDedupMultiObj * */ gconstpointer obj);
-
-guint nm_dedup_multi_index_remove_idx(NMDedupMultiIndex *self, NMDedupMultiIdxType *idx_type);
-
-void nm_dedup_multi_index_dirty_set_head(NMDedupMultiIndex *                        self,
-                                         const NMDedupMultiIdxType *                idx_type,
-                                         /*const NMDedupMultiObj * */ gconstpointer obj);
-
-void nm_dedup_multi_index_dirty_set_idx(NMDedupMultiIndex *        self,
-                                        const NMDedupMultiIdxType *idx_type);
-
-guint nm_dedup_multi_index_dirty_remove_idx(NMDedupMultiIndex *  self,
-                                            NMDedupMultiIdxType *idx_type,
-                                            gboolean             mark_survivors_dirty);
-
-/*****************************************************************************/
-
-typedef struct _NMDedupMultiIter {
-    const CList *            _head;
-    const CList *            _next;
-    const NMDedupMultiEntry *current;
-} NMDedupMultiIter;
-
-static inline void
-nm_dedup_multi_iter_init(NMDedupMultiIter *iter, const NMDedupMultiHeadEntry *head)
-{
-    g_return_if_fail(iter);
-
-    if (head && !c_list_is_empty(&head->lst_entries_head)) {
-        iter->_head = &head->lst_entries_head;
-        iter->_next = head->lst_entries_head.next;
-    } else {
-        iter->_head = NULL;
-        iter->_next = NULL;
-    }
-    iter->current = NULL;
-}
-
-static inline gboolean
-nm_dedup_multi_iter_next(NMDedupMultiIter *iter)
-{
-    g_return_val_if_fail(iter, FALSE);
-
-    if (!iter->_next)
-        return FALSE;
-
-    /* we always look ahead for the next. This way, the user
-     * may delete the current entry (but no other entries). */
-    iter->current = c_list_entry(iter->_next, NMDedupMultiEntry, lst_entries);
-    if (iter->_next->next == iter->_head)
-        iter->_next = NULL;
-    else
-        iter->_next = iter->_next->next;
-    return TRUE;
-}
-
-#define nm_dedup_multi_iter_for_each(iter, head_entry) \
-    for (nm_dedup_multi_iter_init((iter), (head_entry)); nm_dedup_multi_iter_next((iter));)
-
-/*****************************************************************************/
-
-typedef gboolean (*NMDedupMultiFcnSelectPredicate)(/* const NMDedupMultiObj * */ gconstpointer obj,
-                                                   gpointer user_data);
-
-gconstpointer *nm_dedup_multi_objs_to_array_head(const NMDedupMultiHeadEntry *  head_entry,
-                                                 NMDedupMultiFcnSelectPredicate predicate,
-                                                 gpointer                       user_data,
-                                                 guint *                        out_len);
-GPtrArray *    nm_dedup_multi_objs_to_ptr_array_head(const NMDedupMultiHeadEntry *  head_entry,
-                                                     NMDedupMultiFcnSelectPredicate predicate,
-                                                     gpointer                       user_data);
-
-static inline const NMDedupMultiEntry *
-nm_dedup_multi_head_entry_get_idx(const NMDedupMultiHeadEntry *head_entry, int idx)
-{
-    CList *iter;
-
-    if (head_entry) {
-        if (idx >= 0) {
-            c_list_for_each (iter, &head_entry->lst_entries_head) {
-                if (idx-- == 0)
-                    return c_list_entry(iter, NMDedupMultiEntry, lst_entries);
-            }
-        } else {
-            for (iter = head_entry->lst_entries_head.prev; iter != &head_entry->lst_entries_head;
-                 iter = iter->prev) {
-                if (++idx == 0)
-                    return c_list_entry(iter, NMDedupMultiEntry, lst_entries);
-            }
-        }
-    }
-    return NULL;
-}
-
-static inline void
-nm_dedup_multi_head_entry_sort(const NMDedupMultiHeadEntry *head_entry,
-                               CListSortCmp                 cmp,
-                               gconstpointer                user_data)
-{
-    if (head_entry) {
-        /* the head entry can be sorted directly without messing up the
-         * index to which it belongs. Of course, this does mess up any
-         * NMDedupMultiIter instances. */
-        c_list_sort((CList *) &head_entry->lst_entries_head, cmp, user_data);
-    }
-}
-
-gboolean nm_dedup_multi_entry_reorder(const NMDedupMultiEntry *entry,
-                                      const NMDedupMultiEntry *entry_order,
-                                      gboolean                 order_after);
-
-/*****************************************************************************/
-
-#endif /* __NM_DEDUP_MULTI_H__ */
diff --git a/shared/nm-glib-aux/nm-default-glib-i18n-lib.h b/shared/nm-glib-aux/nm-default-glib-i18n-lib.h
deleted file mode 100644
index 9393d192..00000000
--- a/shared/nm-glib-aux/nm-default-glib-i18n-lib.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#ifndef __NM_DEFAULT_GLIB_I18N_LIB_H__
-#define __NM_DEFAULT_GLIB_I18N_LIB_H__
-
-/*****************************************************************************/
-
-#define _NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB
-
-#include "nm-glib-aux/nm-default-glib.h"
-
-#undef NETWORKMANAGER_COMPILATION
-#define NETWORKMANAGER_COMPILATION \
-    (NM_NETWORKMANAGER_COMPILATION_GLIB | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB)
-
-/*****************************************************************************/
-
-#endif /* __NM_DEFAULT_GLIB_I18N_LIB_H__ */
diff --git a/shared/nm-glib-aux/nm-default-glib-i18n-prog.h b/shared/nm-glib-aux/nm-default-glib-i18n-prog.h
deleted file mode 100644
index 0abe807b..00000000
--- a/shared/nm-glib-aux/nm-default-glib-i18n-prog.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#ifndef __NM_DEFAULT_GLIB_I18N_PROG_H__
-#define __NM_DEFAULT_GLIB_I18N_PROG_H__
-
-/*****************************************************************************/
-
-#define _NETWORKMANAGER_COMPILATION_GLIB_I18N_PROG
-
-#include "nm-glib-aux/nm-default-glib.h"
-
-#undef NETWORKMANAGER_COMPILATION
-#define NETWORKMANAGER_COMPILATION \
-    (NM_NETWORKMANAGER_COMPILATION_GLIB | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)
-
-/*****************************************************************************/
-
-#endif /* __NM_DEFAULT_GLIB_I18N_PROG_H__ */
diff --git a/shared/nm-glib-aux/nm-default-glib.h b/shared/nm-glib-aux/nm-default-glib.h
deleted file mode 100644
index 34b23f77..00000000
--- a/shared/nm-glib-aux/nm-default-glib.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#ifndef __NM_DEFAULT_GLIB_H__
-#define __NM_DEFAULT_GLIB_H__
-
-/*****************************************************************************/
-
-#include "nm-std-aux/nm-default-std.h"
-
-#undef NETWORKMANAGER_COMPILATION
-#define NETWORKMANAGER_COMPILATION NM_NETWORKMANAGER_COMPILATION_WITH_GLIB
-
-/*****************************************************************************/
-
-#include <glib.h>
-
-#if defined(_NETWORKMANAGER_COMPILATION_GLIB_I18N_PROG)
-    #if defined(_NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB)
-        #error Cannot define _NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB and _NETWORKMANAGER_COMPILATION_GLIB_I18N_PROG together
-    #endif
-    #undef _NETWORKMANAGER_COMPILATION_GLIB_I18N_PROG
-    #include <glib/gi18n.h>
-#elif defined(_NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB)
-    #undef _NETWORKMANAGER_COMPILATION_GLIB_I18N_LIB
-    #include <glib/gi18n-lib.h>
-#endif
-
-/*****************************************************************************/
-
-#if NM_MORE_ASSERTS == 0
-    #ifndef G_DISABLE_CAST_CHECKS
-        /* Unless compiling with G_DISABLE_CAST_CHECKS, glib performs type checking
-         * during G_VARIANT_TYPE() via g_variant_type_checked_(). This is not necessary
-         * because commonly this cast is needed during something like
-         *
-         *   g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}"));
-         *
-         * Note that in if the variant type would be invalid, the check still
-         * wouldn't make the buggy code magically work. Instead of passing a
-         * bogus type string (bad), it would pass %NULL to g_variant_builder_init()
-         * (also bad).
-         *
-         * Also, a function like g_variant_builder_init() already validates
-         * the input type via something like
-         *
-         *   g_return_if_fail (g_variant_type_is_container (type));
-         *
-         * So, by having G_VARIANT_TYPE() also validate the type, we validate
-         * twice, whereas the first validation is rather pointless because it
-         * doesn't prevent the function to be called with invalid arguments.
-         *
-         * Just patch G_VARIANT_TYPE() to perform no check.
-         */
-        #undef G_VARIANT_TYPE
-        #define G_VARIANT_TYPE(type_string) ((const GVariantType *) (type_string))
-    #endif
-#endif
-
-/*****************************************************************************/
-
-#include "nm-gassert-patch.h"
-
-#include "nm-std-aux/nm-std-aux.h"
-#include "nm-std-aux/nm-std-utils.h"
-#include "nm-glib-aux/nm-macros-internal.h"
-#include "nm-glib-aux/nm-shared-utils.h"
-#include "nm-glib-aux/nm-errno.h"
-#include "nm-glib-aux/nm-hash-utils.h"
-
-/*****************************************************************************/
-
-#endif /* __NM_DEFAULT_GLIB_H__ */
diff --git a/shared/nm-glib-aux/nm-enum-utils.c b/shared/nm-glib-aux/nm-enum-utils.c
deleted file mode 100644
index b06f2bb2..00000000
--- a/shared/nm-glib-aux/nm-enum-utils.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-enum-utils.h"
-#include "nm-str-buf.h"
-
-/*****************************************************************************/
-
-#define IS_FLAGS_SEPARATOR(ch) (NM_IN_SET((ch), ' ', '\t', ',', '\n', '\r'))
-
-static void
-_ASSERT_enum_values_info(GType type, const NMUtilsEnumValueInfo *value_infos)
-{
-#if NM_MORE_ASSERTS > 5
-    nm_auto_unref_gtypeclass GTypeClass *klass = NULL;
-    gs_unref_hashtable GHashTable *ht          = NULL;
-
-    klass = g_type_class_ref(type);
-
-    g_assert(G_IS_ENUM_CLASS(klass) || G_IS_FLAGS_CLASS(klass));
-
-    if (!value_infos)
-        return;
-
-    ht = g_hash_table_new(g_str_hash, g_str_equal);
-
-    for (; value_infos->nick; value_infos++) {
-        g_assert(value_infos->nick[0]);
-
-        /* duplicate nicks make no sense!! */
-        g_assert(!g_hash_table_contains(ht, value_infos->nick));
-        g_hash_table_add(ht, (gpointer) value_infos->nick);
-
-        if (G_IS_ENUM_CLASS(klass)) {
-            GEnumValue *enum_value;
-
-            enum_value = g_enum_get_value_by_nick(G_ENUM_CLASS(klass), value_infos->nick);
-            if (enum_value) {
-                /* we do allow specifying the same name via @value_infos and @type.
-                 * That might make sense, if @type comes from a library where older versions
-                 * of the library don't yet support the value. In this case, the caller can
-                 * provide the nick via @value_infos, to support the older library version.
-                 * And then, when actually running against a newer library version where
-                 * @type knows the nick, we have this situation.
-                 *
-                 * Another reason for specifying a nick both in @value_infos and @type,
-                 * is to specify an alias which is not used with highest preference. For
-                 * example, if you add an alias "disabled" for "none" (both numerically
-                 * equal), then the first alias in @value_infos will be preferred over
-                 * the name from @type. So, to still use "none" as preferred name, you may
-                 * explicitly specify the "none" alias in @value_infos before "disabled".
-                 *
-                 * However, what never is allowed, is to use a name (nick) to re-number
-                 * the value. That is, if both @value_infos and @type contain a particular
-                 * nick, their numeric values must agree as well.
-                 * Allowing this, would be very confusing, because the name would have a different
-                 * value from the regular GLib GEnum API.
-                 */
-                g_assert(enum_value->value == value_infos->value);
-            }
-        } else {
-            GFlagsValue *flags_value;
-
-            flags_value = g_flags_get_value_by_nick(G_FLAGS_CLASS(klass), value_infos->nick);
-            if (flags_value) {
-                /* see ENUM case above. */
-                g_assert(flags_value->value == (guint) value_infos->value);
-            }
-        }
-    }
-#endif
-}
-
-static gboolean
-_is_hex_string(const char *str, gboolean allow_sign)
-{
-    if (allow_sign && str[0] == '-')
-        str++;
-    return str[0] == '0' && str[1] == 'x' && str[2]
-           && NM_STRCHAR_ALL(&str[2], ch, g_ascii_isxdigit(ch));
-}
-
-static gboolean
-_is_dec_string(const char *str, gboolean allow_sign)
-{
-    if (allow_sign && str[0] == '-')
-        str++;
-    return str[0] && NM_STRCHAR_ALL(&str[0], ch, g_ascii_isdigit(ch));
-}
-
-static gboolean
-_enum_is_valid_enum_nick(const char *str)
-{
-    return str[0] && !NM_STRCHAR_ANY(str, ch, g_ascii_isspace(ch)) && !_is_dec_string(str, TRUE)
-           && !_is_hex_string(str, TRUE);
-}
-
-static gboolean
-_enum_is_valid_flags_nick(const char *str)
-{
-    return str[0] && !NM_STRCHAR_ANY(str, ch, IS_FLAGS_SEPARATOR(ch)) && !_is_dec_string(str, FALSE)
-           && !_is_hex_string(str, FALSE);
-}
-
-char *
-_nm_utils_enum_to_str_full(GType                       type,
-                           int                         value,
-                           const char *                flags_separator,
-                           const NMUtilsEnumValueInfo *value_infos)
-{
-    nm_auto_unref_gtypeclass GTypeClass *klass = NULL;
-
-    _ASSERT_enum_values_info(type, value_infos);
-
-    if (flags_separator
-        && (!flags_separator[0] || NM_STRCHAR_ANY(flags_separator, ch, !IS_FLAGS_SEPARATOR(ch))))
-        g_return_val_if_reached(NULL);
-
-    klass = g_type_class_ref(type);
-
-    if (G_IS_ENUM_CLASS(klass)) {
-        GEnumValue *enum_value;
-
-        for (; value_infos && value_infos->nick; value_infos++) {
-            if (value_infos->value == value)
-                return g_strdup(value_infos->nick);
-        }
-
-        enum_value = g_enum_get_value(G_ENUM_CLASS(klass), value);
-        if (!enum_value || !_enum_is_valid_enum_nick(enum_value->value_nick))
-            return g_strdup_printf("%d", value);
-        else
-            return g_strdup(enum_value->value_nick);
-    } else if (G_IS_FLAGS_CLASS(klass)) {
-        unsigned     uvalue = (unsigned) value;
-        GFlagsValue *flags_value;
-        NMStrBuf     strbuf;
-
-        flags_separator = flags_separator ?: " ";
-
-        nm_str_buf_init(&strbuf, 16, FALSE);
-
-        for (; value_infos && value_infos->nick; value_infos++) {
-            nm_assert(_enum_is_valid_flags_nick(value_infos->nick));
-
-            if (uvalue == 0) {
-                if (value_infos->value != 0)
-                    continue;
-            } else {
-                if (!NM_FLAGS_ALL(uvalue, (unsigned) value_infos->value))
-                    continue;
-            }
-
-            if (strbuf.len)
-                nm_str_buf_append(&strbuf, flags_separator);
-            nm_str_buf_append(&strbuf, value_infos->nick);
-            uvalue &= ~((unsigned) value_infos->value);
-            if (uvalue == 0) {
-                /* we printed all flags. Done. */
-                goto flags_done;
-            }
-        }
-
-        do {
-            flags_value = g_flags_get_first_value(G_FLAGS_CLASS(klass), uvalue);
-            if (strbuf.len)
-                nm_str_buf_append(&strbuf, flags_separator);
-            if (!flags_value || !_enum_is_valid_flags_nick(flags_value->value_nick)) {
-                if (uvalue)
-                    nm_str_buf_append_printf(&strbuf, "0x%x", uvalue);
-                break;
-            }
-            nm_str_buf_append(&strbuf, flags_value->value_nick);
-            uvalue &= ~flags_value->value;
-        } while (uvalue);
-
-flags_done:
-        return nm_str_buf_finalize(&strbuf, NULL);
-    }
-
-    g_return_val_if_reached(NULL);
-}
-
-static const NMUtilsEnumValueInfo *
-_find_value_info(const NMUtilsEnumValueInfo *value_infos, const char *needle)
-{
-    if (value_infos) {
-        for (; value_infos->nick; value_infos++) {
-            if (nm_streq(needle, value_infos->nick))
-                return value_infos;
-        }
-    }
-    return NULL;
-}
-
-gboolean
-_nm_utils_enum_from_str_full(GType                       type,
-                             const char *                str,
-                             int *                       out_value,
-                             char **                     err_token,
-                             const NMUtilsEnumValueInfo *value_infos)
-{
-    nm_auto_unref_gtypeclass GTypeClass *klass     = NULL;
-    gboolean                             ret       = FALSE;
-    int                                  value     = 0;
-    gs_free char *                       str_clone = NULL;
-    char *                               s;
-    gint64                               v64;
-    const NMUtilsEnumValueInfo *         nick;
-
-    g_return_val_if_fail(str, FALSE);
-
-    _ASSERT_enum_values_info(type, value_infos);
-
-    s = nm_strdup_maybe_a(300, nm_str_skip_leading_spaces(str), &str_clone);
-    g_strchomp(s);
-
-    klass = g_type_class_ref(type);
-
-    if (G_IS_ENUM_CLASS(klass)) {
-        GEnumValue *enum_value;
-
-        G_STATIC_ASSERT(G_MAXINT < G_MAXINT64);
-        G_STATIC_ASSERT(G_MININT > G_MININT64);
-
-        if (s[0]) {
-            if (_is_hex_string(s, TRUE)) {
-                if (s[0] == '-') {
-                    v64 = _nm_utils_ascii_str_to_int64(&s[3],
-                                                       16,
-                                                       -((gint64) G_MAXINT),
-                                                       -((gint64) G_MININT),
-                                                       G_MAXINT64);
-                    if (v64 != G_MAXINT64) {
-                        value = (int) (-v64);
-                        ret   = TRUE;
-                    }
-                } else {
-                    v64 = _nm_utils_ascii_str_to_int64(&s[2], 16, G_MININT, G_MAXINT, G_MAXINT64);
-                    if (v64 != G_MAXINT64) {
-                        value = (int) v64;
-                        ret   = TRUE;
-                    }
-                }
-            } else if (_is_dec_string(s, TRUE)) {
-                v64 = _nm_utils_ascii_str_to_int64(s, 10, G_MININT, G_MAXINT, G_MAXINT64);
-                if (v64 != G_MAXINT64) {
-                    value = (int) v64;
-                    ret   = TRUE;
-                }
-            } else if ((nick = _find_value_info(value_infos, s))) {
-                value = nick->value;
-                ret   = TRUE;
-            } else if ((enum_value = g_enum_get_value_by_nick(G_ENUM_CLASS(klass), s))) {
-                value = enum_value->value;
-                ret   = TRUE;
-            }
-        }
-    } else if (G_IS_FLAGS_CLASS(klass)) {
-        GFlagsValue *flags_value;
-        unsigned     uvalue = 0;
-
-        ret = TRUE;
-        while (s[0]) {
-            char *s_end;
-
-            for (s_end = s; s_end[0]; s_end++) {
-                if (IS_FLAGS_SEPARATOR(s_end[0])) {
-                    s_end[0] = '\0';
-                    s_end++;
-                    break;
-                }
-            }
-
-            if (s[0]) {
-                if (_is_hex_string(s, FALSE)) {
-                    v64 = _nm_utils_ascii_str_to_int64(&s[2], 16, 0, G_MAXUINT, -1);
-                    if (v64 == -1) {
-                        ret = FALSE;
-                        break;
-                    }
-                    uvalue |= (unsigned) v64;
-                } else if (_is_dec_string(s, FALSE)) {
-                    v64 = _nm_utils_ascii_str_to_int64(s, 10, 0, G_MAXUINT, -1);
-                    if (v64 == -1) {
-                        ret = FALSE;
-                        break;
-                    }
-                    uvalue |= (unsigned) v64;
-                } else if ((nick = _find_value_info(value_infos, s)))
-                    uvalue |= (unsigned) nick->value;
-                else if ((flags_value = g_flags_get_value_by_nick(G_FLAGS_CLASS(klass), s)))
-                    uvalue |= flags_value->value;
-                else {
-                    ret = FALSE;
-                    break;
-                }
-            }
-
-            s = s_end;
-        }
-
-        value = (int) uvalue;
-    } else
-        g_return_val_if_reached(FALSE);
-
-    NM_SET_OUT(err_token, !ret && s[0] ? g_strdup(s) : NULL);
-    NM_SET_OUT(out_value, ret ? value : 0);
-    return ret;
-}
-
-const char **
-_nm_utils_enum_get_values(GType type, int from, int to)
-{
-    GTypeClass *klass;
-    GPtrArray * array;
-    int         i;
-    char        sbuf[64];
-
-    klass = g_type_class_ref(type);
-    array = g_ptr_array_new();
-
-    if (G_IS_ENUM_CLASS(klass)) {
-        GEnumClass *enum_class = G_ENUM_CLASS(klass);
-        GEnumValue *enum_value;
-
-        for (i = 0; i < enum_class->n_values; i++) {
-            enum_value = &enum_class->values[i];
-            if (enum_value->value >= from && enum_value->value <= to) {
-                if (_enum_is_valid_enum_nick(enum_value->value_nick))
-                    g_ptr_array_add(array, (gpointer) enum_value->value_nick);
-                else
-                    g_ptr_array_add(
-                        array,
-                        (gpointer) g_intern_string(nm_sprintf_buf(sbuf, "%d", enum_value->value)));
-            }
-        }
-    } else if (G_IS_FLAGS_CLASS(klass)) {
-        GFlagsClass *flags_class = G_FLAGS_CLASS(klass);
-        GFlagsValue *flags_value;
-
-        for (i = 0; i < flags_class->n_values; i++) {
-            flags_value = &flags_class->values[i];
-            if (flags_value->value >= (guint) from && flags_value->value <= (guint) to) {
-                if (_enum_is_valid_flags_nick(flags_value->value_nick))
-                    g_ptr_array_add(array, (gpointer) flags_value->value_nick);
-                else
-                    g_ptr_array_add(
-                        array,
-                        (gpointer) g_intern_string(
-                            nm_sprintf_buf(sbuf, "0x%x", (unsigned) flags_value->value)));
-            }
-        }
-    } else {
-        g_type_class_unref(klass);
-        g_ptr_array_free(array, TRUE);
-        g_return_val_if_reached(NULL);
-    }
-
-    g_type_class_unref(klass);
-    g_ptr_array_add(array, NULL);
-
-    return (const char **) g_ptr_array_free(array, FALSE);
-}
diff --git a/shared/nm-glib-aux/nm-enum-utils.h b/shared/nm-glib-aux/nm-enum-utils.h
deleted file mode 100644
index 89be54e7..00000000
--- a/shared/nm-glib-aux/nm-enum-utils.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#ifndef __NM_ENUM_UTILS_H__
-#define __NM_ENUM_UTILS_H__
-
-/*****************************************************************************/
-
-typedef struct _NMUtilsEnumValueInfo {
-    /* currently, this is only used for _nm_utils_enum_from_str_full() to
-     * declare additional aliases for values. */
-    const char *nick;
-    int         value;
-} NMUtilsEnumValueInfo;
-
-char *   _nm_utils_enum_to_str_full(GType                       type,
-                                    int                         value,
-                                    const char *                sep,
-                                    const NMUtilsEnumValueInfo *value_infos);
-gboolean _nm_utils_enum_from_str_full(GType                       type,
-                                      const char *                str,
-                                      int *                       out_value,
-                                      char **                     err_token,
-                                      const NMUtilsEnumValueInfo *value_infos);
-
-const char **_nm_utils_enum_get_values(GType type, int from, int to);
-
-/*****************************************************************************/
-
-#endif /* __NM_ENUM_UTILS_H__ */
diff --git a/shared/nm-glib-aux/nm-errno.c b/shared/nm-glib-aux/nm-errno.c
deleted file mode 100644
index c05379ec..00000000
--- a/shared/nm-glib-aux/nm-errno.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-errno.h"
-
-/*****************************************************************************/
-
-static NM_UTILS_LOOKUP_STR_DEFINE(
-    _geterror,
-#if 0
-    enum _NMErrno,
-#else
-    int,
-#endif
-    NM_UTILS_LOOKUP_DEFAULT(NULL),
-
-    NM_UTILS_LOOKUP_STR_ITEM(NME_ERRNO_SUCCESS, "NME_ERRNO_SUCCESS"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_ERRNO_OUT_OF_RANGE, "NME_ERRNO_OUT_OF_RANGE"),
-
-    NM_UTILS_LOOKUP_STR_ITEM(NME_UNSPEC, "NME_UNSPEC"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_BUG, "NME_BUG"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_NATIVE_ERRNO, "NME_NATIVE_ERRNO"),
-
-    NM_UTILS_LOOKUP_STR_ITEM(NME_NL_ATTRSIZE, "NME_NL_ATTRSIZE"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_NL_BAD_SOCK, "NME_NL_BAD_SOCK"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_NL_DUMP_INTR, "NME_NL_DUMP_INTR"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_OVERFLOW, "NME_NL_MSG_OVERFLOW"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_TOOSHORT, "NME_NL_MSG_TOOSHORT"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_TRUNC, "NME_NL_MSG_TRUNC"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_NL_SEQ_MISMATCH, "NME_NL_SEQ_MISMATCH"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_NL_NOADDR, "NME_NL_NOADDR"),
-
-    NM_UTILS_LOOKUP_STR_ITEM(NME_PL_NOT_FOUND, "not-found"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_PL_EXISTS, "exists"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_PL_WRONG_TYPE, "wrong-type"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_PL_NOT_SLAVE, "not-slave"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_PL_NO_FIRMWARE, "no-firmware"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_PL_OPNOTSUPP, "not-supported"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_PL_NETLINK, "netlink"),
-    NM_UTILS_LOOKUP_STR_ITEM(NME_PL_CANT_SET_MTU, "cant-set-mtu"),
-
-    NM_UTILS_LOOKUP_ITEM_IGNORE(_NM_ERRNO_MININT),
-    NM_UTILS_LOOKUP_ITEM_IGNORE(_NM_ERRNO_RESERVED_LAST_PLUS_1), );
-
-/**
- * nm_strerror():
- * @nmerr: the NetworkManager specific errno to be converted
- *   to string.
- *
- * NetworkManager specific error numbers reserve a range in "errno.h" with
- * our own defines. For numbers that don't fall into this range, the numbers
- * are identical to the common error numbers.
- *
- * Identical to strerror(), g_strerror(), nm_strerror_native() for error numbers
- * that are not in the reserved range of NetworkManager specific errors.
- *
- * Returns: (transfer none): the string representation of the error number.
- */
-const char *
-nm_strerror(int nmerr)
-{
-    const char *s;
-
-    nmerr = nm_errno(nmerr);
-
-    if (nmerr >= _NM_ERRNO_RESERVED_FIRST) {
-        s = _geterror(nmerr);
-        if (s)
-            return s;
-    }
-    return nm_strerror_native(nmerr);
-}
-
-/*****************************************************************************/
-
-/**
- * nm_strerror_native_r:
- * @errsv: the errno to convert to string.
- * @buf: the output buffer where to write the string to.
- * @buf_size: the length of buffer.
- *
- * This is like strerror_r(), with one difference: depending on the
- * locale, the returned string is guaranteed to be valid UTF-8.
- * Also, there is some confusion as to whether to use glibc's
- * strerror_r() or the POXIX/XSI variant. This is abstracted
- * by the function.
- *
- * Note that the returned buffer may also be a statically allocated
- * buffer, and not the input buffer @buf. Consequently, the returned
- * string may be longer than @buf_size.
- *
- * Returns: (transfer none): a NUL terminated error message. This is either a static
- *   string (that is never freed), or the provided @buf argument.
- */
-const char *
-nm_strerror_native_r(int errsv, char *buf, gsize buf_size)
-{
-    char *buf2;
-
-    nm_assert(buf);
-    nm_assert(buf_size > 0);
-
-#if (!defined(__GLIBC__) && !defined(__UCLIBC__)) || ((_POSIX_C_SOURCE >= 200112L) && !_GNU_SOURCE)
-    /* XSI-compliant */
-    {
-        int errno_saved = errno;
-
-        if (strerror_r(errsv, buf, buf_size) != 0) {
-            g_snprintf(buf, buf_size, "Unspecified errno %d", errsv);
-            errno = errno_saved;
-        }
-        buf2 = buf;
-    }
-#else
-    /* GNU-specific */
-    buf2 = strerror_r(errsv, buf, buf_size);
-#endif
-
-    /* like g_strerror(), ensure that the error message is UTF-8. */
-    if (!g_get_charset(NULL) && !g_utf8_validate(buf2, -1, NULL)) {
-        gs_free char *msg = NULL;
-
-        msg = g_locale_to_utf8(buf2, -1, NULL, NULL, NULL);
-        if (msg) {
-            g_strlcpy(buf, msg, buf_size);
-            buf2 = buf;
-        }
-    }
-
-    return buf2;
-}
-
-/**
- * nm_strerror_native:
- * @errsv: the errno integer from <errno.h>
- *
- * Like strerror(), but strerror() is not thread-safe and not guaranteed
- * to be UTF-8.
- *
- * g_strerror() is a thread-safe variant of strerror(), however it caches
- * all returned strings in a dictionary. That means, using this on untrusted
- * error numbers can result in this cache to grow without limits.
- *
- * Instead, return a tread-local buffer. This way, it's thread-safe.
- *
- * There is a downside to this: subsequent calls of nm_strerror_native()
- * overwrite the error message.
- *
- * Returns: (transfer none): the text representation of the error number.
- */
-const char *
-nm_strerror_native(int errsv)
-{
-    static _nm_thread_local char *buf_static = NULL;
-    char *                        buf;
-
-    buf = buf_static;
-    if (G_UNLIKELY(!buf)) {
-        buf        = g_malloc(NM_STRERROR_BUFSIZE);
-        buf_static = buf;
-        nm_utils_thread_local_register_destroy(buf, g_free);
-    }
-
-    return nm_strerror_native_r(errsv, buf, NM_STRERROR_BUFSIZE);
-}
diff --git a/shared/nm-glib-aux/nm-errno.h b/shared/nm-glib-aux/nm-errno.h
deleted file mode 100644
index 62c8379f..00000000
--- a/shared/nm-glib-aux/nm-errno.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_ERRNO_H__
-#define __NM_ERRNO_H__
-
-#include <errno.h>
-
-/*****************************************************************************/
-
-enum _NMErrno {
-    _NM_ERRNO_MININT         = G_MININT,
-    _NM_ERRNO_MAXINT         = G_MAXINT,
-    _NM_ERRNO_RESERVED_FIRST = 100000,
-
-    /* when we cannot represent a number as positive number, we resort to this
-     * number. Basically, the values G_MININT, -NME_ERRNO_SUCCESS, NME_ERRNO_SUCCESS
-     * and G_MAXINT all map to the same value. */
-    NME_ERRNO_OUT_OF_RANGE = G_MAXINT,
-
-    /* Indicate that the original errno was zero. Zero denotes *no error*, but we know something
-     * went wrong and we want to report some error. This is a placeholder to mean, something
-     * was wrong, but errno was zero. */
-    NME_ERRNO_SUCCESS = G_MAXINT - 1,
-
-    /* an unspecified error. */
-    NME_UNSPEC = _NM_ERRNO_RESERVED_FIRST,
-
-    /* A bug, for example when an assertion failed.
-     * Should never happen. */
-    NME_BUG,
-
-    /* a native error number (from <errno.h>) cannot be mapped as
-     * an nm-error, because it is in the range [_NM_ERRNO_RESERVED_FIRST,
-     * _NM_ERRNO_RESERVED_LAST]. */
-    NME_NATIVE_ERRNO,
-
-    /* netlink errors. */
-    NME_NL_SEQ_MISMATCH,
-    NME_NL_MSG_TRUNC,
-    NME_NL_MSG_TOOSHORT,
-    NME_NL_DUMP_INTR,
-    NME_NL_ATTRSIZE,
-    NME_NL_BAD_SOCK,
-    NME_NL_NOADDR,
-    NME_NL_MSG_OVERFLOW,
-
-    /* platform errors. */
-    NME_PL_NOT_FOUND,
-    NME_PL_EXISTS,
-    NME_PL_WRONG_TYPE,
-    NME_PL_NOT_SLAVE,
-    NME_PL_NO_FIRMWARE,
-    NME_PL_OPNOTSUPP,
-    NME_PL_NETLINK,
-    NME_PL_CANT_SET_MTU,
-
-    _NM_ERRNO_RESERVED_LAST_PLUS_1,
-    _NM_ERRNO_RESERVED_LAST = _NM_ERRNO_RESERVED_LAST_PLUS_1 - 1,
-};
-
-/*****************************************************************************/
-
-/* When we receive an errno from a system function, we can safely assume
- * that the error number is not negative. We rely on that, and possibly just
- * "return -errsv;" to signal an error. We also rely on that, because libc
- * is our trusted base: meaning, if it cannot even succeed at setting errno
- * according to specification, all bets are off.
- *
- * This macro returns the input argument, and asserts that the error variable
- * is positive.
- *
- * In a sense, the macro is related to nm_errno_native() function, but the difference
- * is that this macro asserts that @errsv is positive, while nm_errno_native() coerces
- * negative values to be non-negative. */
-#define NM_ERRNO_NATIVE(errsv)        \
-    ({                                \
-        const int _errsv_x = (errsv); \
-                                      \
-        nm_assert(_errsv_x > 0);      \
-        _errsv_x;                     \
-    })
-
-/* Normalize native errno.
- *
- * Our API may return native error codes (<errno.h>) as negative values. This function
- * takes such an errno, and normalizes it to their positive value.
- *
- * The special values G_MININT and zero are coerced to NME_ERRNO_OUT_OF_RANGE and NME_ERRNO_SUCCESS
- * respectively.
- * Other values are coerced to their inverse.
- * Other positive values are returned unchanged.
- *
- * Basically, this normalizes errsv to be positive (taking care of two pathological cases).
- */
-static inline int
-nm_errno_native(int errsv)
-{
-    switch (errsv) {
-    case 0:
-        return NME_ERRNO_SUCCESS;
-    case G_MININT:
-        return NME_ERRNO_OUT_OF_RANGE;
-    default:
-        return errsv >= 0 ? errsv : -errsv;
-    }
-}
-
-/* Normalizes an nm-error to be positive.
- *
- * Various API returns negative error codes, and this function converts the negative
- * value to its positive.
- *
- * Note that @nmerr is on the domain of NetworkManager specific error numbers,
- * which is not the same as the native error numbers (errsv from <errno.h>). But
- * as far as normalizing goes, nm_errno() does exactly the same remapping as
- * nm_errno_native(). */
-static inline int
-nm_errno(int nmerr)
-{
-    return nm_errno_native(nmerr);
-}
-
-/* this maps a native errno to a (always non-negative) nm-error number.
- *
- * Note that nm-error numbers are embedded into the range of regular
- * errno. The only difference is, that nm-error numbers reserve a
- * range (_NM_ERRNO_RESERVED_FIRST, _NM_ERRNO_RESERVED_LAST) for their
- * own purpose.
- *
- * That means, converting an errno to nm-error number means in
- * most cases just returning itself.
- * Only pathological cases need special handling:
- *
- *  - 0 is mapped to NME_ERRNO_SUCCESS;
- *  - G_MININT is mapped to NME_ERRNO_OUT_OF_RANGE;
- *  - values in the range of (+/-) [_NM_ERRNO_RESERVED_FIRST, _NM_ERRNO_RESERVED_LAST]
- *    are mapped to NME_NATIVE_ERRNO
- *  - all other values are their (positive) absolute value.
- */
-static inline int
-nm_errno_from_native(int errsv)
-{
-    switch (errsv) {
-    case 0:
-        return NME_ERRNO_SUCCESS;
-    case G_MININT:
-        return NME_ERRNO_OUT_OF_RANGE;
-    default:
-        if (errsv < 0)
-            errsv = -errsv;
-        return G_UNLIKELY(errsv >= _NM_ERRNO_RESERVED_FIRST && errsv <= _NM_ERRNO_RESERVED_LAST)
-                   ? NME_NATIVE_ERRNO
-                   : errsv;
-    }
-}
-
-const char *nm_strerror(int nmerr);
-
-/*****************************************************************************/
-
-#define NM_STRERROR_BUFSIZE 1024
-
-const char *nm_strerror_native_r(int errsv, char *buf, gsize buf_size);
-const char *nm_strerror_native(int errsv);
-
-/*****************************************************************************/
-
-#endif /* __NM_ERRNO_H__ */
diff --git a/shared/nm-glib-aux/nm-gassert-patch.h b/shared/nm-glib-aux/nm-gassert-patch.h
deleted file mode 100644
index bac8697c..00000000
--- a/shared/nm-glib-aux/nm-gassert-patch.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#ifndef __NM_GASSERT_PATCH_H__
-#define __NM_GASSERT_PATCH_H__
-
-/*****************************************************************************/
-
-#if NM_MORE_ASSERTS == 0
-
-/* glib assertions (g_return_*(), g_assert*()) contain a textual representation
- * of the checked statement. This part of the assertion blows up the size of the
- * binary. Unless we compile a debug-build with NM_MORE_ASSERTS, drop these
- * parts. Note that the failed assertion still prints the file and line where the
- * assertion fails. That shall suffice. */
-
-static inline void
-_nm_g_return_if_fail_warning(const char *log_domain, const char *file, int line)
-{
-    char file_buf[256 + 15];
-
-    g_snprintf(file_buf, sizeof(file_buf), "((%s:%d))", file, line);
-    g_return_if_fail_warning(log_domain, file_buf, "<dropped>");
-}
-
-    #define g_return_if_fail_warning(log_domain, pretty_function, expression) \
-        _nm_g_return_if_fail_warning(log_domain, __FILE__, __LINE__)
-
-    #define g_assertion_message_expr(domain, file, line, func, expr) \
-        g_assertion_message_expr(domain, file, line, "<unknown-fcn>", (expr) ? "<dropped>" : NULL)
-
-    #undef g_return_val_if_reached
-    #define g_return_val_if_reached(val)                          \
-        G_STMT_START                                              \
-        {                                                         \
-            g_log(G_LOG_DOMAIN,                                   \
-                  G_LOG_LEVEL_CRITICAL,                           \
-                  "file %s: line %d (%s): should not be reached", \
-                  __FILE__,                                       \
-                  __LINE__,                                       \
-                  "<dropped>");                                   \
-            return (val);                                         \
-        }                                                         \
-        G_STMT_END
-
-    #undef g_return_if_reached
-    #define g_return_if_reached()                                 \
-        G_STMT_START                                              \
-        {                                                         \
-            g_log(G_LOG_DOMAIN,                                   \
-                  G_LOG_LEVEL_CRITICAL,                           \
-                  "file %s: line %d (%s): should not be reached", \
-                  __FILE__,                                       \
-                  __LINE__,                                       \
-                  "<dropped>");                                   \
-            return;                                               \
-        }                                                         \
-        G_STMT_END
-#endif
-
-/*****************************************************************************/
-
-#if NM_MORE_ASSERTS == 0
-    #define NM_ASSERT_G_RETURN_EXPR(expr) "<dropped>"
-    #define NM_ASSERT_NO_MSG              1
-
-#else
-    #define NM_ASSERT_G_RETURN_EXPR(expr) "" expr ""
-    #define NM_ASSERT_NO_MSG              0
-#endif
-
-/*****************************************************************************/
-
-#endif /* __NM_GASSERT_PATCH_H__ */
diff --git a/shared/nm-glib-aux/nm-glib.h b/shared/nm-glib-aux/nm-glib.h
deleted file mode 100644
index befb8d90..00000000
--- a/shared/nm-glib-aux/nm-glib.h
+++ /dev/null
@@ -1,707 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2008 - 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_GLIB_H__
-#define __NM_GLIB_H__
-
-/*****************************************************************************/
-
-#ifndef __NM_MACROS_INTERNAL_H__
-    #error "nm-glib.h requires nm-macros-internal.h. Do not include this directly"
-#endif
-
-/*****************************************************************************/
-
-#ifdef __clang__
-
-    #undef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-    #undef G_GNUC_END_IGNORE_DEPRECATIONS
-
-    #define G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
-        _Pragma("clang diagnostic push")     \
-            _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
-
-    #define G_GNUC_END_IGNORE_DEPRECATIONS _Pragma("clang diagnostic pop")
-
-#endif
-
-/*****************************************************************************/
-
-static inline void
-__g_type_ensure(GType type)
-{
-#if !GLIB_CHECK_VERSION(2, 34, 0)
-    if (G_UNLIKELY(type == (GType) -1))
-        g_error("can't happen");
-#else
-    G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-    g_type_ensure(type);
-    G_GNUC_END_IGNORE_DEPRECATIONS;
-#endif
-}
-#define g_type_ensure __g_type_ensure
-
-/*****************************************************************************/
-
-#if !GLIB_CHECK_VERSION(2, 34, 0)
-
-    #define g_clear_pointer(pp, destroy)                           \
-        G_STMT_START                                               \
-        {                                                          \
-            G_STATIC_ASSERT(sizeof *(pp) == sizeof(gpointer));     \
-            /* Only one access, please */                          \
-            gpointer *_pp = (gpointer *) (pp);                     \
-            gpointer  _p;                                          \
-            /* This assignment is needed to avoid a gcc warning */ \
-            GDestroyNotify _destroy = (GDestroyNotify)(destroy);   \
-                                                                   \
-            _p = *_pp;                                             \
-            if (_p) {                                              \
-                *_pp = NULL;                                       \
-                _destroy(_p);                                      \
-            }                                                      \
-        }                                                          \
-        G_STMT_END
-
-#endif
-
-/*****************************************************************************/
-
-#if !GLIB_CHECK_VERSION(2, 34, 0)
-
-    /* These are used to clean up the output of test programs; we can just let
- * them no-op in older glib.
- */
-    #define g_test_expect_message(log_domain, log_level, pattern)
-    #define g_test_assert_expected_messages()
-
-#else
-
-    /* We build with -DGLIB_MAX_ALLOWED_VERSION set to 2.32 to make sure we don't
- * accidentally use new API that we shouldn't. But we don't want warnings for
- * the APIs that we emulate above.
- */
-
-    #define g_test_expect_message(domain, level, format...) \
-        G_STMT_START                                        \
-        {                                                   \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                \
-            g_test_expect_message(domain, level, format);   \
-            G_GNUC_END_IGNORE_DEPRECATIONS                  \
-        }                                                   \
-        G_STMT_END
-
-    #define g_test_assert_expected_messages_internal(domain, file, line, func)  \
-        G_STMT_START                                                            \
-        {                                                                       \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                    \
-            g_test_assert_expected_messages_internal(domain, file, line, func); \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                      \
-        }                                                                       \
-        G_STMT_END
-
-#endif
-
-/*****************************************************************************/
-
-#if GLIB_CHECK_VERSION(2, 35, 0)
-    /* For glib >= 2.36, g_type_init() is deprecated.
- * But since 2.35.1 (7c42ab23b55c43ab96d0ac2124b550bf1f49c1ec) this function
- * does nothing. Replace the call with empty statement. */
-    #define nm_g_type_init() \
-        G_STMT_START         \
-        {                    \
-            (void) 0;        \
-        }                    \
-        G_STMT_END
-#else
-    #define nm_g_type_init() \
-        G_STMT_START         \
-        {                    \
-            g_type_init();   \
-        }                    \
-        G_STMT_END
-#endif
-
-/*****************************************************************************/
-
-/* g_test_initialized() is only available since glib 2.36. */
-#if !GLIB_CHECK_VERSION(2, 36, 0)
-    #define g_test_initialized() (g_test_config_vars->test_initialized)
-#endif
-
-/*****************************************************************************/
-
-/* g_assert_cmpmem() is only available since glib 2.46. */
-#if !GLIB_CHECK_VERSION(2, 45, 7)
-    #define g_assert_cmpmem(m1, l1, m2, l2)                                                 \
-        G_STMT_START                                                                        \
-        {                                                                                   \
-            gconstpointer __m1 = m1, __m2 = m2;                                             \
-            int           __l1 = l1, __l2 = l2;                                             \
-            if (__l1 != __l2)                                                               \
-                g_assertion_message_cmpnum(G_LOG_DOMAIN,                                    \
-                                           __FILE__,                                        \
-                                           __LINE__,                                        \
-                                           G_STRFUNC,                                       \
-                                           #l1 " (len(" #m1 ")) == " #l2 " (len(" #m2 "))", \
-                                           __l1,                                            \
-                                           "==",                                            \
-                                           __l2,                                            \
-                                           'i');                                            \
-            else if (memcmp(__m1, __m2, __l1) != 0)                                         \
-                g_assertion_message(G_LOG_DOMAIN,                                           \
-                                    __FILE__,                                               \
-                                    __LINE__,                                               \
-                                    G_STRFUNC,                                              \
-                                    "assertion failed (" #m1 " == " #m2 ")");               \
-        }                                                                                   \
-        G_STMT_END
-#endif
-
-/*****************************************************************************/
-
-/* Rumtime check for glib version. First do a compile time check which
- * (if satisfied) shortcuts the runtime check. */
-static inline gboolean
-nm_glib_check_version(guint major, guint minor, guint micro)
-{
-    return GLIB_CHECK_VERSION(major, minor, micro)
-           || ((glib_major_version > major)
-               || (glib_major_version == major && glib_minor_version > minor)
-               || (glib_major_version == major && glib_minor_version == minor
-                   && glib_micro_version < micro));
-}
-
-/*****************************************************************************/
-
-/* g_test_skip() is only available since glib 2.38. Add a compatibility wrapper. */
-static inline void
-__nmtst_g_test_skip(const char *msg)
-{
-#if GLIB_CHECK_VERSION(2, 38, 0)
-    G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-    g_test_skip(msg);
-    G_GNUC_END_IGNORE_DEPRECATIONS
-#else
-    g_debug("%s", msg);
-#endif
-}
-#define g_test_skip __nmtst_g_test_skip
-
-/*****************************************************************************/
-
-/* g_test_add_data_func_full() is only available since glib 2.34. Add a compatibility wrapper. */
-static inline void
-__g_test_add_data_func_full(const char *   testpath,
-                            gpointer       test_data,
-                            GTestDataFunc  test_func,
-                            GDestroyNotify data_free_func)
-{
-#if GLIB_CHECK_VERSION(2, 34, 0)
-    G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-    g_test_add_data_func_full(testpath, test_data, test_func, data_free_func);
-    G_GNUC_END_IGNORE_DEPRECATIONS
-#else
-    g_return_if_fail(testpath != NULL);
-    g_return_if_fail(testpath[0] == '/');
-    g_return_if_fail(test_func != NULL);
-
-    g_test_add_vtable(testpath,
-                      0,
-                      test_data,
-                      NULL,
-                      (GTestFixtureFunc) test_func,
-                      (GTestFixtureFunc) data_free_func);
-#endif
-}
-#define g_test_add_data_func_full __g_test_add_data_func_full
-
-/*****************************************************************************/
-
-static inline gboolean
-nm_g_hash_table_replace(GHashTable *hash, gpointer key, gpointer value)
-{
-    /* glib 2.40 added a return value indicating whether the key already existed
-     * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */
-#if GLIB_CHECK_VERSION(2, 40, 0)
-    return g_hash_table_replace(hash, key, value);
-#else
-    gboolean contained = g_hash_table_contains(hash, key);
-
-    g_hash_table_replace(hash, key, value);
-    return !contained;
-#endif
-}
-
-static inline gboolean
-nm_g_hash_table_insert(GHashTable *hash, gpointer key, gpointer value)
-{
-    /* glib 2.40 added a return value indicating whether the key already existed
-     * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */
-#if GLIB_CHECK_VERSION(2, 40, 0)
-    return g_hash_table_insert(hash, key, value);
-#else
-    gboolean contained = g_hash_table_contains(hash, key);
-
-    g_hash_table_insert(hash, key, value);
-    return !contained;
-#endif
-}
-
-static inline gboolean
-nm_g_hash_table_add(GHashTable *hash, gpointer key)
-{
-    /* glib 2.40 added a return value indicating whether the key already existed
-     * (910191597a6c2e5d5d460e9ce9efb4f47d9cc63c). */
-#if GLIB_CHECK_VERSION(2, 40, 0)
-    return g_hash_table_add(hash, key);
-#else
-    gboolean contained = g_hash_table_contains(hash, key);
-
-    g_hash_table_add(hash, key);
-    return !contained;
-#endif
-}
-
-/*****************************************************************************/
-
-#if !GLIB_CHECK_VERSION(2, 40, 0) || defined(NM_GLIB_COMPAT_H_TEST)
-static inline void
-_nm_g_ptr_array_insert(GPtrArray *array, int index_, gpointer data)
-{
-    g_return_if_fail(array);
-    g_return_if_fail(index_ >= -1);
-    g_return_if_fail(index_ <= (int) array->len);
-
-    g_ptr_array_add(array, data);
-
-    if (index_ != -1 && index_ != (int) (array->len - 1)) {
-        memmove(&(array->pdata[index_ + 1]),
-                &(array->pdata[index_]),
-                (array->len - index_ - 1) * sizeof(gpointer));
-        array->pdata[index_] = data;
-    }
-}
-#endif
-
-#if !GLIB_CHECK_VERSION(2, 40, 0)
-    #define g_ptr_array_insert(array, index, data)      \
-        G_STMT_START                                    \
-        {                                               \
-            _nm_g_ptr_array_insert(array, index, data); \
-        }                                               \
-        G_STMT_END
-#else
-    #define g_ptr_array_insert(array, index, data)  \
-        G_STMT_START                                \
-        {                                           \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS        \
-            g_ptr_array_insert(array, index, data); \
-            G_GNUC_END_IGNORE_DEPRECATIONS          \
-        }                                           \
-        G_STMT_END
-#endif
-
-/*****************************************************************************/
-
-#if !GLIB_CHECK_VERSION(2, 40, 0)
-static inline gboolean
-_g_key_file_save_to_file(GKeyFile *key_file, const char *filename, GError **error)
-{
-    char *   contents;
-    gboolean success;
-    gsize    length;
-
-    g_return_val_if_fail(key_file != NULL, FALSE);
-    g_return_val_if_fail(filename != NULL, FALSE);
-    g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
-
-    contents = g_key_file_to_data(key_file, &length, NULL);
-    g_assert(contents != NULL);
-
-    success = g_file_set_contents(filename, contents, length, error);
-    g_free(contents);
-
-    return success;
-}
-    #define g_key_file_save_to_file(key_file, filename, error) \
-        _g_key_file_save_to_file(key_file, filename, error)
-#else
-    #define g_key_file_save_to_file(key_file, filename, error)             \
-        ({                                                                 \
-            gboolean _success;                                             \
-                                                                           \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                               \
-            _success = g_key_file_save_to_file(key_file, filename, error); \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                 \
-            _success;                                                      \
-        })
-#endif
-
-/*****************************************************************************/
-
-#if GLIB_CHECK_VERSION(2, 36, 0)
-    #define g_credentials_get_unix_pid(creds, error)                                        \
-        ({                                                                                  \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS(g_credentials_get_unix_pid)((creds), (error)); \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                                  \
-        })
-#else
-    #define g_credentials_get_unix_pid(creds, error)                                          \
-        ({                                                                                    \
-            struct ucred *native_creds;                                                       \
-                                                                                              \
-            native_creds = g_credentials_get_native((creds), G_CREDENTIALS_TYPE_LINUX_UCRED); \
-            g_assert(native_creds);                                                           \
-            native_creds->pid;                                                                \
-        })
-#endif
-
-/*****************************************************************************/
-
-#if !GLIB_CHECK_VERSION(2, 40, 0) || defined(NM_GLIB_COMPAT_H_TEST)
-static inline gpointer *
-_nm_g_hash_table_get_keys_as_array(GHashTable *hash_table, guint *length)
-{
-    GHashTableIter iter;
-    gpointer       key, *ret;
-    guint          i = 0;
-
-    g_return_val_if_fail(hash_table, NULL);
-
-    ret = g_new0(gpointer, g_hash_table_size(hash_table) + 1);
-    g_hash_table_iter_init(&iter, hash_table);
-
-    while (g_hash_table_iter_next(&iter, &key, NULL))
-        ret[i++] = key;
-
-    ret[i] = NULL;
-
-    if (length)
-        *length = i;
-
-    return ret;
-}
-#endif
-#if !GLIB_CHECK_VERSION(2, 40, 0)
-    #define g_hash_table_get_keys_as_array(hash_table, length) \
-        ({ _nm_g_hash_table_get_keys_as_array(hash_table, length); })
-#else
-    #define g_hash_table_get_keys_as_array(hash_table, length)               \
-        ({                                                                   \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS(g_hash_table_get_keys_as_array) \
-            ((hash_table), (length));                                        \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                   \
-        })
-#endif
-
-/*****************************************************************************/
-
-#ifndef g_info
-    /* g_info was only added with 2.39.2 */
-    #define g_info(...) g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, __VA_ARGS__)
-#endif
-
-/*****************************************************************************/
-
-static inline gpointer
-_nm_g_steal_pointer(gpointer pp)
-{
-    gpointer *ptr = (gpointer *) pp;
-    gpointer  ref;
-
-    ref  = *ptr;
-    *ptr = NULL;
-
-    return ref;
-}
-
-#if !GLIB_CHECK_VERSION(2, 44, 0)
-static inline gpointer
-g_steal_pointer(gpointer pp)
-{
-    return _nm_g_steal_pointer(pp);
-}
-#endif
-
-#ifdef g_steal_pointer
-    #undef g_steal_pointer
-#endif
-#define g_steal_pointer(pp) ((typeof(*(pp))) _nm_g_steal_pointer(pp))
-
-/*****************************************************************************/
-
-static inline gboolean
-_nm_g_strv_contains(const char *const *strv, const char *str)
-{
-#if !GLIB_CHECK_VERSION(2, 44, 0)
-    g_return_val_if_fail(strv != NULL, FALSE);
-    g_return_val_if_fail(str != NULL, FALSE);
-
-    for (; *strv != NULL; strv++) {
-        if (g_str_equal(str, *strv))
-            return TRUE;
-    }
-
-    return FALSE;
-#else
-    G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-    return g_strv_contains(strv, str);
-    G_GNUC_END_IGNORE_DEPRECATIONS
-#endif
-}
-#define g_strv_contains _nm_g_strv_contains
-
-/*****************************************************************************/
-
-static inline GVariant *
-_nm_g_variant_new_take_string(char *string)
-{
-#if !GLIB_CHECK_VERSION(2, 36, 0)
-    GVariant *value;
-
-    g_return_val_if_fail(string != NULL, NULL);
-    g_return_val_if_fail(g_utf8_validate(string, -1, NULL), NULL);
-
-    value = g_variant_new_string(string);
-    g_free(string);
-    return value;
-#elif !GLIB_CHECK_VERSION(2, 38, 0)
-    GVariant *value;
-    GBytes *  bytes;
-
-    g_return_val_if_fail(string != NULL, NULL);
-    g_return_val_if_fail(g_utf8_validate(string, -1, NULL), NULL);
-
-    bytes = g_bytes_new_take(string, strlen(string) + 1);
-    value = g_variant_new_from_bytes(G_VARIANT_TYPE_STRING, bytes, TRUE);
-    g_bytes_unref(bytes);
-
-    return value;
-#else
-    G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-    return g_variant_new_take_string(string);
-    G_GNUC_END_IGNORE_DEPRECATIONS
-#endif
-}
-#define g_variant_new_take_string _nm_g_variant_new_take_string
-
-/*****************************************************************************/
-
-#if !GLIB_CHECK_VERSION(2, 38, 0)
-_nm_printf(1, 2) static inline GVariant *_nm_g_variant_new_printf(const char *format_string, ...)
-{
-    char *  string;
-    va_list ap;
-
-    g_return_val_if_fail(format_string, NULL);
-
-    va_start(ap, format_string);
-    string = g_strdup_vprintf(format_string, ap);
-    va_end(ap);
-
-    return g_variant_new_take_string(string);
-}
-    #define g_variant_new_printf(...) _nm_g_variant_new_printf(__VA_ARGS__)
-#else
-    #define g_variant_new_printf(...)               \
-        ({                                          \
-            GVariant *_v;                           \
-                                                    \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS        \
-            _v = g_variant_new_printf(__VA_ARGS__); \
-            G_GNUC_END_IGNORE_DEPRECATIONS          \
-            _v;                                     \
-        })
-#endif
-
-/*****************************************************************************/
-
-/* Recent glib also casts the results to typeof(Obj), but only if
- *
- *  ( defined(g_has_typeof) && GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_56 )
- *
- * Since we build NetworkManager with older GLIB_VERSION_MAX_ALLOWED, it's
- * not taking effect.
- *
- * Override this. */
-#undef g_object_ref
-#undef g_object_ref_sink
-#define g_object_ref(Obj)      ((typeof(Obj)) g_object_ref(Obj))
-#define g_object_ref_sink(Obj) ((typeof(Obj)) g_object_ref_sink(Obj))
-
-/*****************************************************************************/
-
-#ifndef g_autofree
-    /* we still don't rely on recent glib to provide g_autofree. Hence, we continue
- * to use our gs_* free macros that we took from libgsystem.
- *
- * To ease migration towards g_auto*, add a compat define for g_autofree. */
-    #define g_autofree gs_free
-#endif
-
-/*****************************************************************************/
-
-#if !GLIB_CHECK_VERSION(2, 47, 1)
-/* Older versions of g_value_unset() only allowed to unset a GValue which
- * was initialized previously. This was relaxed ([1], [2], [3]).
- *
- * Our nm_auto_unset_gvalue macro requires to be able to call g_value_unset().
- * Also, it is our general practice to allow for that. Add a compat implementation.
- *
- * [1] https://gitlab.gnome.org/GNOME/glib/commit/4b2d92a864f1505f1b08eb639d74293fa32681da
- * [2] commit "Allow passing unset GValues to g_value_unset()"
- * [3] https://bugzilla.gnome.org/show_bug.cgi?id=755766
- */
-static inline void
-_nm_g_value_unset(GValue *value)
-{
-    g_return_if_fail(value);
-
-    if (value->g_type != 0)
-        g_value_unset(value);
-}
-    #define g_value_unset _nm_g_value_unset
-#endif
-
-/* G_PID_FORMAT was added only in 2.53.5. Define it ourself.
- *
- * If this was about "pid_t", we would check SIZEOF_PID_T, and set
- * PRIi32/PRIi16, like systemd does. But it's actually about
- * GPid, which glib typedefs as an "int".
- *
- * There is a test_gpid() that check that GPid is really a typedef
- * for int. */
-#undef G_PID_FORMAT
-#define G_PID_FORMAT "i"
-
-/*****************************************************************************/
-
-/* G_SOURCE_FUNC was added in 2.57.2. */
-#undef G_SOURCE_FUNC
-#define G_SOURCE_FUNC(f) ((GSourceFunc)(void (*)(void))(f))
-
-/*****************************************************************************/
-
-/* g_atomic_pointer_get() is implemented as a macro, and it is also used for
- * (gsize *) arguments. However, that leads to compiler warnings in certain
- * configurations. Work around it, by redefining the macro. */
-static inline gpointer
-_g_atomic_pointer_get(void **atomic)
-{
-    return g_atomic_pointer_get(atomic);
-}
-#undef g_atomic_pointer_get
-#define g_atomic_pointer_get(atomic)                                           \
-    ({                                                                         \
-        typeof(*atomic) *const _atomic = (atomic);                             \
-                                                                               \
-        /* g_atomic_pointer_get() is used by glib also for (gsize *) pointers,
-         * not only pointers to pointers. We thus don't enforce that (*atomic)
-         * is a pointer, but of suitable size/alignment. */ \
-                                                                               \
-        G_STATIC_ASSERT(sizeof(*_atomic) == sizeof(gpointer));                 \
-        G_STATIC_ASSERT(_nm_alignof(*_atomic) == _nm_alignof(gpointer));       \
-        (void) (0 ? (gpointer) * (_atomic) : NULL);                            \
-                                                                               \
-        (typeof(*_atomic)) _g_atomic_pointer_get((void **) _atomic);           \
-    })
-
-/* Reimplement g_atomic_pointer_set() macro too. Our variant does more type
- * checks. */
-static inline void
-_g_atomic_pointer_set(void **atomic, void *newval)
-{
-    return g_atomic_pointer_set(atomic, newval);
-}
-#undef g_atomic_pointer_set
-#define g_atomic_pointer_set(atomic, newval)                        \
-    ({                                                              \
-        typeof(*atomic) *const _atomic                 = (atomic);  \
-        typeof(*_atomic) const _newval                 = (newval);  \
-        _nm_unused gconstpointer const _val_type_check = _newval;   \
-                                                                    \
-        (void) (0 ? (gpointer) * (_atomic) : NULL);                 \
-                                                                    \
-        _g_atomic_pointer_set((void **) _atomic, (void *) _newval); \
-    })
-
-/* Glib implements g_atomic_pointer_compare_and_exchange() as a macro.
- * For one, to inline the atomic operation and also to perform some type checks
- * on the arguments.
- * Depending on compiler and glib version, glib passes the arguments as they
- * are to __atomic_compare_exchange_n(). Some clang version don't accept const
- * pointers there. Reimplement the macro to get that right, but with stronger
- * type checks (as we use typeof()). Had one job. */
-static inline gboolean
-_g_atomic_pointer_compare_and_exchange(void **atomic, void *oldval, void *newval)
-{
-    return g_atomic_pointer_compare_and_exchange(atomic, oldval, newval);
-}
-#undef g_atomic_pointer_compare_and_exchange
-#define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
-    ({                                                                \
-        typeof(*atomic) *const _atomic                 = (atomic);    \
-        typeof(*_atomic) const _oldval                 = (oldval);    \
-        typeof(*_atomic) const _newval                 = (newval);    \
-        _nm_unused gconstpointer const _val_type_check = _oldval;     \
-                                                                      \
-        (void) (0 ? (gpointer) * (_atomic) : NULL);                   \
-                                                                      \
-        _g_atomic_pointer_compare_and_exchange((void **) _atomic,     \
-                                               (void *) _oldval,      \
-                                               (void *) _newval);     \
-    })
-
-/*****************************************************************************/
-
-#if !GLIB_CHECK_VERSION(2, 58, 0)
-static inline gboolean
-g_hash_table_steal_extended(GHashTable *  hash_table,
-                            gconstpointer lookup_key,
-                            gpointer *    stolen_key,
-                            gpointer *    stolen_value)
-{
-    g_assert(stolen_key);
-    g_assert(stolen_value);
-
-    if (g_hash_table_lookup_extended(hash_table, lookup_key, stolen_key, stolen_value)) {
-        g_hash_table_steal(hash_table, lookup_key);
-        return TRUE;
-    }
-    *stolen_key   = NULL;
-    *stolen_value = NULL;
-    return FALSE;
-}
-#else
-    #define g_hash_table_steal_extended(hash_table, lookup_key, stolen_key, stolen_value)    \
-        ({                                                                                   \
-            gpointer *_stolen_key   = (stolen_key);                                          \
-            gpointer *_stolen_value = (stolen_value);                                        \
-                                                                                             \
-            /* we cannot allow NULL arguments, because then we would leak the values in
-             * the compat implementation. */      \
-            g_assert(_stolen_key);                                                           \
-            g_assert(_stolen_value);                                                         \
-                                                                                             \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                                 \
-            g_hash_table_steal_extended(hash_table, lookup_key, _stolen_key, _stolen_value); \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                                   \
-        })
-#endif
-
-/*****************************************************************************/
-
-__attribute__((
-    __deprecated__("Don't use g_cancellable_reset(). Create a new cancellable instead."))) void
-_nm_g_cancellable_reset(GCancellable *cancellable);
-
-#undef g_cancellable_reset
-#define g_cancellable_reset(cancellable) _nm_g_cancellable_reset(cancellable)
-
-/*****************************************************************************/
-
-#endif /* __NM_GLIB_H__ */
diff --git a/shared/nm-glib-aux/nm-hash-utils.c b/shared/nm-glib-aux/nm-hash-utils.c
deleted file mode 100644
index 29349b1d..00000000
--- a/shared/nm-glib-aux/nm-hash-utils.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-hash-utils.h"
-
-#include <stdint.h>
-
-#include "nm-shared-utils.h"
-#include "nm-random-utils.h"
-
-/*****************************************************************************/
-
-#define HASH_KEY_SIZE       16u
-#define HASH_KEY_SIZE_GUINT ((HASH_KEY_SIZE + sizeof(guint) - 1) / sizeof(guint))
-
-G_STATIC_ASSERT(sizeof(guint) * HASH_KEY_SIZE_GUINT >= HASH_KEY_SIZE);
-
-static const guint8 *volatile global_seed = NULL;
-
-static const guint8 *
-_get_hash_key_init(void)
-{
-    /* the returned hash is aligned to guin64, hence, it is safe
-     * to use it as guint* or guint64* pointer. */
-    static union {
-        guint8  v8[HASH_KEY_SIZE];
-        guint   _align_as_uint;
-        guint32 _align_as_uint32;
-        guint64 _align_as_uint64;
-    } g_arr;
-    const guint8 *g;
-
-again:
-    g = g_atomic_pointer_get(&global_seed);
-    if (!G_UNLIKELY(g)) {
-        static gsize g_lock;
-        uint64_t     h;
-        union {
-            guint  vuint;
-            guint8 v8[HASH_KEY_SIZE];
-            guint8 _extra_entropy[3 * HASH_KEY_SIZE];
-        } t_arr;
-
-        nm_utils_random_bytes(&t_arr, sizeof(t_arr));
-
-        /* We only initialize one random hash key. So we can spend some effort
-         * of getting this right. For one, we collect more random bytes than
-         * necessary.
-         *
-         * Then, the first guint of the seed should have all the entropy that we could
-         * obtain in sizeof(t_arr). For that, siphash(t_arr) and xor the first guint
-         * with hash.
-         * The first guint is especially interesting for nm_hash_static() below that
-         * doesn't use siphash itself. */
-        h = c_siphash_hash(t_arr.v8, (const guint8 *) &t_arr, sizeof(t_arr));
-        if (sizeof(h) > sizeof(guint))
-            t_arr.vuint = t_arr.vuint ^ ((guint)(h & G_MAXUINT)) ^ ((guint)(h >> 32));
-        else
-            t_arr.vuint = t_arr.vuint ^ ((guint)(h & G_MAXUINT));
-
-        if (!g_once_init_enter(&g_lock)) {
-            /* lost a race. The random key is already initialized. */
-            goto again;
-        }
-
-        memcpy(g_arr.v8, t_arr.v8, HASH_KEY_SIZE);
-        g = g_arr.v8;
-        g_atomic_pointer_set(&global_seed, g);
-        g_once_init_leave(&g_lock, 1);
-    }
-
-    nm_assert(g == g_arr.v8);
-    return g;
-}
-
-#define _get_hash_key()                          \
-    ({                                           \
-        const guint8 *_g;                        \
-                                                 \
-        _g = g_atomic_pointer_get(&global_seed); \
-        if (G_UNLIKELY(!_g))                     \
-            _g = _get_hash_key_init();           \
-        _g;                                      \
-    })
-
-guint
-nm_hash_static(guint static_seed)
-{
-    /* Note that we only xor the static_seed with the first guint of the key.
-     *
-     * We don't use siphash, which would mix the bits better with _get_hash_key().
-     * Note that nm_hash_static() isn't used to hash the static_seed. Instead, it
-     * is used to get a unique hash value in a static context. That means, every
-     * caller is responsible to choose a static_seed that is sufficiently
-     * distinct from all other callers. In other words, static_seed should be a
-     * unique constant with good entropy.
-     *
-     * Note that _get_hash_key_init() already xored the first guint of the
-     * key with the siphash of the entire static key. That means, even if
-     * we got bad randomness for the first guint, the first guint is also
-     * mixed with the randomness of the entire random key.
-     *
-     * Also, ensure that we don't return zero (like for nm_hash_complete()).
-     */
-    return ((*((const guint *) _get_hash_key())) ^ static_seed) ?: 3679500967u;
-}
-
-void
-nm_hash_siphash42_init(CSipHash *h, guint static_seed)
-{
-    const guint8 *g;
-    union {
-        guint64 _align_as_uint64;
-        guint   arr[HASH_KEY_SIZE_GUINT];
-    } seed;
-
-    nm_assert(h);
-
-    g = _get_hash_key();
-    memcpy(&seed, g, HASH_KEY_SIZE);
-    seed.arr[0] ^= static_seed;
-    c_siphash_init(h, (const guint8 *) &seed);
-}
-
-guint
-nm_hash_str(const char *str)
-{
-    NMHashState h;
-
-    if (!str)
-        return nm_hash_static(1867854211u);
-    nm_hash_init(&h, 1867854211u);
-    nm_hash_update_str(&h, str);
-    return nm_hash_complete(&h);
-}
-
-guint
-nm_str_hash(gconstpointer str)
-{
-    return nm_hash_str(str);
-}
-
-guint
-nm_hash_ptr(gconstpointer ptr)
-{
-    NMHashState h;
-
-    if (!ptr)
-        return nm_hash_static(2907677551u);
-    nm_hash_init(&h, 2907677551u);
-    nm_hash_update(&h, &ptr, sizeof(ptr));
-    return nm_hash_complete(&h);
-}
-
-guint
-nm_direct_hash(gconstpointer ptr)
-{
-    return nm_hash_ptr(ptr);
-}
-
-/*****************************************************************************/
-
-guint
-nm_pstr_hash(gconstpointer p)
-{
-    const char *const *s = p;
-
-    if (!s)
-        return nm_hash_static(101061439u);
-    return nm_hash_str(*s);
-}
-
-gboolean
-nm_pstr_equal(gconstpointer a, gconstpointer b)
-{
-    const char *const *s1 = a;
-    const char *const *s2 = b;
-
-    return (s1 == s2) || (s1 && s2 && nm_streq0(*s1, *s2));
-}
-
-guint
-nm_pint_hash(gconstpointer p)
-{
-    const int *s = p;
-
-    if (!s)
-        return nm_hash_static(298377461u);
-    return nm_hash_val(1208815757u, *s);
-}
-
-gboolean
-nm_pint_equals(gconstpointer a, gconstpointer b)
-{
-    const int *s1 = a;
-    const int *s2 = a;
-
-    return s1 == s2 || (s1 && s2 && *s1 == *s2);
-}
-
-guint
-nm_pdirect_hash(gconstpointer p)
-{
-    const void *const *s = p;
-
-    if (!s)
-        return nm_hash_static(1852748873u);
-    return nm_direct_hash(*s);
-}
-
-gboolean
-nm_pdirect_equal(gconstpointer a, gconstpointer b)
-{
-    const void *const *s1 = a;
-    const void *const *s2 = b;
-
-    return (s1 == s2) || (s1 && s2 && *s1 == *s2);
-}
-
-guint
-nm_ppdirect_hash(gconstpointer p)
-{
-    const void *const *const *s = p;
-
-    if (!s)
-        return nm_hash_static(396534869u);
-    if (!*s)
-        return nm_hash_static(1476102263u);
-    return nm_direct_hash(**s);
-}
-
-gboolean
-nm_ppdirect_equal(gconstpointer a, gconstpointer b)
-{
-    const void *const *const *s1 = a;
-    const void *const *const *s2 = b;
-
-    if (s1 == s2)
-        return TRUE;
-    if (!s1 || !s2)
-        return FALSE;
-
-    if (*s1 == *s2)
-        return TRUE;
-    if (!*s1 || !*s2)
-        return FALSE;
-
-    return **s1 == **s2;
-}
-
-/*****************************************************************************/
-
-guint
-nm_gbytes_hash(gconstpointer p)
-{
-    GBytes *      ptr = (GBytes *) p;
-    gconstpointer arr;
-    gsize         len;
-
-    arr = g_bytes_get_data(ptr, &len);
-    return nm_hash_mem(792701303u, arr, len);
-}
-
-guint
-nm_pgbytes_hash(gconstpointer p)
-{
-    GBytes *const *ptr = p;
-    gconstpointer  arr;
-    gsize          len;
-
-    arr = g_bytes_get_data(*ptr, &len);
-    return nm_hash_mem(1470631313u, arr, len);
-}
-
-gboolean
-nm_pgbytes_equal(gconstpointer a, gconstpointer b)
-{
-    GBytes *const *ptr_a = a;
-    GBytes *const *ptr_b = b;
-
-    return g_bytes_equal(*ptr_a, *ptr_b);
-}
diff --git a/shared/nm-glib-aux/nm-hash-utils.h b/shared/nm-glib-aux/nm-hash-utils.h
deleted file mode 100644
index a7b8677b..00000000
--- a/shared/nm-glib-aux/nm-hash-utils.h
+++ /dev/null
@@ -1,442 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#ifndef __NM_HASH_UTILS_H__
-#define __NM_HASH_UTILS_H__
-
-#include "c-siphash/src/c-siphash.h"
-#include "nm-macros-internal.h"
-
-/*****************************************************************************/
-
-#define NM_HASH_SEED_16(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af) \
-    ((const guint8[16]){a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af})
-
-void nm_hash_siphash42_init(CSipHash *h, guint static_seed);
-
-/* Siphash24 of binary buffer @arr and @len, using the randomized seed from
- * other NMHash functions.
- *
- * Note, that this is guaranteed to use siphash42 under the hood (contrary to
- * all other NMHash API, which leave this undefined). That matters at the point,
- * where the caller needs to be sure that a reasonably strong hashing algorithm
- * is used.  (Yes, NMHash is all about siphash24, but otherwise that is not promised
- * anywhere).
- *
- * Another difference is, that this returns guint64 (not guint like other NMHash functions).
- *
- * Another difference is, that this may also return zero (not like nm_hash_complete()).
- *
- * Then, why not use c_siphash_hash() directly? Because this also uses the randomized,
- * per-run hash-seed like nm_hash_init(). So, you get siphash24 with a random
- * seed (which is cached for the current run of the program).
- */
-static inline guint64
-nm_hash_siphash42(guint static_seed, const void *ptr, gsize n)
-{
-    CSipHash h;
-
-    nm_hash_siphash42_init(&h, static_seed);
-    c_siphash_append(&h, ptr, n);
-    return c_siphash_finalize(&h);
-}
-
-/*****************************************************************************/
-
-struct _NMHashState {
-    CSipHash _state;
-};
-
-typedef struct _NMHashState NMHashState;
-
-guint nm_hash_static(guint static_seed);
-
-static inline void
-nm_hash_init(NMHashState *state, guint static_seed)
-{
-    nm_assert(state);
-
-    nm_hash_siphash42_init(&state->_state, static_seed);
-}
-
-static inline guint64
-nm_hash_complete_u64(NMHashState *state)
-{
-    nm_assert(state);
-
-    /* this returns the native u64 hash value. Note that this differs
-     * from nm_hash_complete() in two ways:
-     *
-     * - the type, guint64 vs. guint.
-     * - nm_hash_complete() never returns zero.
-     *
-     * In practice, nm_hash*() API is implemented via siphash24, so this returns
-     * the siphash24 value. But that is not guaranteed by the API, and if you need
-     * siphash24 directly, use c_siphash_*() and nm_hash_siphash42*() API. */
-    return c_siphash_finalize(&state->_state);
-}
-
-static inline guint
-nm_hash_complete(NMHashState *state)
-{
-    guint64 h;
-
-    h = nm_hash_complete_u64(state);
-
-    /* we don't ever want to return a zero hash.
-     *
-     * NMPObject requires that in _idx_obj_part(), and it's just a good idea. */
-    return (((guint)(h >> 32)) ^ ((guint) h)) ?: 1396707757u;
-}
-
-static inline void
-nm_hash_update(NMHashState *state, const void *ptr, gsize n)
-{
-    nm_assert(state);
-    nm_assert(n == 0 || ptr);
-
-    /* Note: the data passed in here might be sensitive data (secrets),
-     * that we should nm_explicit_bzero() afterwards. However, since
-     * we are using siphash24 with a random key, that is not really
-     * necessary. Something to keep in mind, if we ever move away from
-     * this hash implementation. */
-    c_siphash_append(&state->_state, ptr, n);
-}
-
-#define nm_hash_update_val(state, val)                \
-    G_STMT_START                                      \
-    {                                                 \
-        typeof(val) _val = (val);                     \
-                                                      \
-        nm_hash_update((state), &_val, sizeof(_val)); \
-    }                                                 \
-    G_STMT_END
-
-#define nm_hash_update_valp(state, val) nm_hash_update((state), (val), sizeof(*(val)))
-
-static inline void
-nm_hash_update_bool(NMHashState *state, bool val)
-{
-    nm_hash_update(state, &val, sizeof(val));
-}
-
-#define _NM_HASH_COMBINE_BOOLS_x_1(t, y) ((y) ? ((t)(1ull << 0)) : ((t) 0ull))
-#define _NM_HASH_COMBINE_BOOLS_x_2(t, y, ...) \
-    ((y) ? ((t)(1ull << 1)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_1(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_3(t, y, ...) \
-    ((y) ? ((t)(1ull << 2)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_2(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_4(t, y, ...) \
-    ((y) ? ((t)(1ull << 3)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_3(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_5(t, y, ...) \
-    ((y) ? ((t)(1ull << 4)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_4(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_6(t, y, ...) \
-    ((y) ? ((t)(1ull << 5)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_5(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_7(t, y, ...) \
-    ((y) ? ((t)(1ull << 6)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_6(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_8(t, y, ...) \
-    ((y) ? ((t)(1ull << 7)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_7(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_9(t, y, ...) \
-    ((y) ? ((t)(1ull << 8)) : ((t) 0ull))     \
-        | (G_STATIC_ASSERT_EXPR(sizeof(t) >= 2), (_NM_HASH_COMBINE_BOOLS_x_8(t, __VA_ARGS__)))
-#define _NM_HASH_COMBINE_BOOLS_x_10(t, y, ...) \
-    ((y) ? ((t)(1ull << 9)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_9(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_x_11(t, y, ...) \
-    ((y) ? ((t)(1ull << 10)) : ((t) 0ull)) | _NM_HASH_COMBINE_BOOLS_x_10(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_n2(t, n, ...) _NM_HASH_COMBINE_BOOLS_x_##n(t, __VA_ARGS__)
-#define _NM_HASH_COMBINE_BOOLS_n(t, n, ...)  _NM_HASH_COMBINE_BOOLS_n2(t, n, __VA_ARGS__)
-
-#define NM_HASH_COMBINE_BOOLS(type, ...) \
-    ((type)(_NM_HASH_COMBINE_BOOLS_n(type, NM_NARG(__VA_ARGS__), __VA_ARGS__)))
-
-#define nm_hash_update_bools(state, ...) \
-    nm_hash_update_val(state, NM_HASH_COMBINE_BOOLS(guint8, __VA_ARGS__))
-
-#define _NM_HASH_COMBINE_VALS_typ_x_1(y) typeof(y) _v1;
-#define _NM_HASH_COMBINE_VALS_typ_x_2(y, ...) \
-    typeof(y) _v2;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_1(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_3(y, ...) \
-    typeof(y) _v3;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_2(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_4(y, ...) \
-    typeof(y) _v4;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_3(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_5(y, ...) \
-    typeof(y) _v5;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_4(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_6(y, ...) \
-    typeof(y) _v6;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_5(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_7(y, ...) \
-    typeof(y) _v7;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_6(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_8(y, ...) \
-    typeof(y) _v8;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_7(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_9(y, ...) \
-    typeof(y) _v9;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_8(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_10(y, ...) \
-    typeof(y) _v10;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_9(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_11(y, ...) \
-    typeof(y) _v11;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_10(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_12(y, ...) \
-    typeof(y) _v12;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_11(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_13(y, ...) \
-    typeof(y) _v13;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_12(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_14(y, ...) \
-    typeof(y) _v14;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_13(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_15(y, ...) \
-    typeof(y) _v15;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_14(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_16(y, ...) \
-    typeof(y) _v16;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_15(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_17(y, ...) \
-    typeof(y) _v17;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_16(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_18(y, ...) \
-    typeof(y) _v18;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_17(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_19(y, ...) \
-    typeof(y) _v19;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_18(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_x_20(y, ...) \
-    typeof(y) _v20;                            \
-    _NM_HASH_COMBINE_VALS_typ_x_19(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_n2(n, ...) _NM_HASH_COMBINE_VALS_typ_x_##n(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_typ_n(n, ...)  _NM_HASH_COMBINE_VALS_typ_n2(n, __VA_ARGS__)
-
-#define _NM_HASH_COMBINE_VALS_val_x_1(y)      ._v1 = (y),
-#define _NM_HASH_COMBINE_VALS_val_x_2(y, ...) ._v2 = (y), _NM_HASH_COMBINE_VALS_val_x_1(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_3(y, ...) ._v3 = (y), _NM_HASH_COMBINE_VALS_val_x_2(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_4(y, ...) ._v4 = (y), _NM_HASH_COMBINE_VALS_val_x_3(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_5(y, ...) ._v5 = (y), _NM_HASH_COMBINE_VALS_val_x_4(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_6(y, ...) ._v6 = (y), _NM_HASH_COMBINE_VALS_val_x_5(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_7(y, ...) ._v7 = (y), _NM_HASH_COMBINE_VALS_val_x_6(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_8(y, ...) ._v8 = (y), _NM_HASH_COMBINE_VALS_val_x_7(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_9(y, ...) ._v9 = (y), _NM_HASH_COMBINE_VALS_val_x_8(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_10(y, ...) \
-    ._v10 = (y), _NM_HASH_COMBINE_VALS_val_x_9(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_11(y, ...) \
-    ._v11 = (y), _NM_HASH_COMBINE_VALS_val_x_10(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_12(y, ...) \
-    ._v12 = (y), _NM_HASH_COMBINE_VALS_val_x_11(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_13(y, ...) \
-    ._v13 = (y), _NM_HASH_COMBINE_VALS_val_x_12(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_14(y, ...) \
-    ._v14 = (y), _NM_HASH_COMBINE_VALS_val_x_13(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_15(y, ...) \
-    ._v15 = (y), _NM_HASH_COMBINE_VALS_val_x_14(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_16(y, ...) \
-    ._v16 = (y), _NM_HASH_COMBINE_VALS_val_x_15(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_17(y, ...) \
-    ._v17 = (y), _NM_HASH_COMBINE_VALS_val_x_16(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_18(y, ...) \
-    ._v18 = (y), _NM_HASH_COMBINE_VALS_val_x_17(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_19(y, ...) \
-    ._v19 = (y), _NM_HASH_COMBINE_VALS_val_x_18(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_x_20(y, ...) \
-    ._v20 = (y), _NM_HASH_COMBINE_VALS_val_x_19(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_n2(n, ...) _NM_HASH_COMBINE_VALS_val_x_##n(__VA_ARGS__)
-#define _NM_HASH_COMBINE_VALS_val_n(n, ...)  _NM_HASH_COMBINE_VALS_val_n2(n, __VA_ARGS__)
-
-/* NM_HASH_COMBINE_VALS() is faster then nm_hash_update_val() as it combines multiple
- * calls to nm_hash_update() using a packed structure. */
-#define NM_HASH_COMBINE_VALS(var, ...)                                 \
-    const struct _nm_packed {                                          \
-        _NM_HASH_COMBINE_VALS_typ_n(NM_NARG(__VA_ARGS__), __VA_ARGS__) \
-    } var _nm_alignas(guint64) = {_NM_HASH_COMBINE_VALS_val_n(NM_NARG(__VA_ARGS__), __VA_ARGS__)}
-
-/* nm_hash_update_vals() is faster then nm_hash_update_val() as it combines multiple
- * calls to nm_hash_update() using a packed structure. */
-#define nm_hash_update_vals(state, ...)               \
-    G_STMT_START                                      \
-    {                                                 \
-        NM_HASH_COMBINE_VALS(_val, __VA_ARGS__);      \
-                                                      \
-        nm_hash_update((state), &_val, sizeof(_val)); \
-    }                                                 \
-    G_STMT_END
-
-static inline void
-nm_hash_update_mem(NMHashState *state, const void *ptr, gsize n)
-{
-    /* This also hashes the length of the data. That means,
-     * hashing two consecutive binary fields (of arbitrary
-     * length), will hash differently. That is,
-     * [[1,1], []] differs from [[1],[1]].
-     *
-     * If you have a constant length (sizeof), use nm_hash_update()
-     * instead. */
-    nm_hash_update(state, &n, sizeof(n));
-    if (n > 0)
-        nm_hash_update(state, ptr, n);
-}
-
-static inline void
-nm_hash_update_str0(NMHashState *state, const char *str)
-{
-    if (str)
-        nm_hash_update_mem(state, str, strlen(str));
-    else {
-        gsize n = G_MAXSIZE;
-
-        nm_hash_update(state, &n, sizeof(n));
-    }
-}
-
-static inline void
-nm_hash_update_str(NMHashState *state, const char *str)
-{
-    nm_assert(str);
-    nm_hash_update(state, str, strlen(str) + 1);
-}
-
-#if _NM_CC_SUPPORT_GENERIC
-    /* Like nm_hash_update_str(), but restricted to arrays only. nm_hash_update_str() only works
- * with a @str argument that cannot be NULL. If you have a string pointer, that is never NULL, use
- * nm_hash_update() instead. */
-    #define nm_hash_update_strarr(state, str)                                \
-        (_Generic(&(str), const char(*)[sizeof(str)]                         \
-                  : nm_hash_update_str((state), (str)), char(*)[sizeof(str)] \
-                  : nm_hash_update_str((state), (str))))
-#else
-    #define nm_hash_update_strarr(state, str) nm_hash_update_str((state), (str))
-#endif
-
-guint nm_hash_ptr(gconstpointer ptr);
-guint nm_direct_hash(gconstpointer str);
-
-guint nm_hash_str(const char *str);
-guint nm_str_hash(gconstpointer str);
-
-#define nm_hash_val(static_seed, val)     \
-    ({                                    \
-        NMHashState _h;                   \
-                                          \
-        nm_hash_init(&_h, (static_seed)); \
-        nm_hash_update_val(&_h, (val));   \
-        nm_hash_complete(&_h);            \
-    })
-
-static inline guint
-nm_hash_mem(guint static_seed, const void *ptr, gsize n)
-{
-    NMHashState h;
-
-    if (n == 0)
-        return nm_hash_static(static_seed);
-    nm_hash_init(&h, static_seed);
-    nm_hash_update(&h, ptr, n);
-    return nm_hash_complete(&h);
-}
-
-/*****************************************************************************/
-
-/* nm_pstr_*() are for hashing keys that are pointers to strings,
- * that is, "const char *const*" types, using strcmp(). */
-
-guint nm_pstr_hash(gconstpointer p);
-
-gboolean nm_pstr_equal(gconstpointer a, gconstpointer b);
-
-/*****************************************************************************/
-
-/* nm_pint_*() are for hashing keys that are pointers to int values,
- * that is, "const int *" types. */
-
-guint    nm_pint_hash(gconstpointer p);
-gboolean nm_pint_equals(gconstpointer a, gconstpointer b);
-
-G_STATIC_ASSERT(sizeof(int) == sizeof(guint32));
-#define nm_puint32_hash   nm_pint_hash
-#define nm_puint32_equals nm_pint_equals
-
-/*****************************************************************************/
-
-/* this hashes/compares the pointer value that we point to. Basically,
- * (*((const void *const*) a) == *((const void *const*) b)). */
-
-guint nm_pdirect_hash(gconstpointer p);
-
-gboolean nm_pdirect_equal(gconstpointer a, gconstpointer b);
-
-/* this hashes/compares the direct pointer value by following pointers to
- * pointers 2 times.
- * (**((const void *const*const*) a) == **((const void *const*const*) b)). */
-
-guint nm_ppdirect_hash(gconstpointer p);
-
-gboolean nm_ppdirect_equal(gconstpointer a, gconstpointer b);
-
-/*****************************************************************************/
-
-guint nm_gbytes_hash(gconstpointer p);
-#define nm_gbytes_equal g_bytes_equal
-
-guint    nm_pgbytes_hash(gconstpointer p);
-gboolean nm_pgbytes_equal(gconstpointer a, gconstpointer b);
-
-/*****************************************************************************/
-
-#define NM_HASH_OBFUSCATE_PTR_FMT "%016" G_GINT64_MODIFIER "x"
-
-/* sometimes we want to log a pointer directly, for providing context/information about
- * the message that get logged. Logging pointer values directly defeats ASLR, so we should
- * not do that. This returns a "unsigned long long" value that can be used
- * instead.
- *
- * Note that there is a chance that two different pointer values hash to the same obfuscated
- * value. So beware of that when reviewing logs. However, such a collision is very unlikely. */
-static inline guint64
-nm_hash_obfuscate_ptr(guint static_seed, gconstpointer val)
-{
-    NMHashState h;
-
-    nm_hash_init(&h, static_seed);
-    nm_hash_update_val(&h, val);
-    return nm_hash_complete_u64(&h);
-}
-
-/* if you want to log obfuscated pointer for a certain context (like, NMPRuleManager
- * logging user-tags), then you are advised to use nm_hash_obfuscate_ptr() with your
- * own, unique static-seed.
- *
- * However, for example the singleton constructors log the obfuscated pointer values
- * for all singletons, so they must all be obfuscated with the same seed. So, this
- * macro uses a particular static seed that should be used by when comparing pointer
- * values in a global context. */
-#define NM_HASH_OBFUSCATE_PTR(ptr) (nm_hash_obfuscate_ptr(1678382159u, ptr))
-
-#define NM_HASH_OBFUSCATE_PTR_STR(ptr, buf)                                                        \
-    ({                                                                                             \
-        gconstpointer _ptr = (ptr);                                                                \
-                                                                                                   \
-        _ptr ? nm_sprintf_buf(buf, "[" NM_HASH_OBFUSCATE_PTR_FMT "]", NM_HASH_OBFUSCATE_PTR(_ptr)) \
-             : "(null)";                                                                           \
-    })
-
-static inline const char *
-nm_hash_obfuscated_ptr_str(gconstpointer ptr, char buf[static 17])
-{
-    int l;
-
-    nm_assert(buf);
-    l = g_snprintf(buf, 17, NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(ptr));
-    nm_assert(l < 17);
-    return buf;
-}
-
-#define nm_hash_obfuscated_ptr_str_a(ptr) (nm_hash_obfuscated_ptr_str((ptr), g_alloca(17)))
-
-/*****************************************************************************/
-
-#endif /* __NM_HASH_UTILS_H__ */
diff --git a/shared/nm-glib-aux/nm-io-utils.c b/shared/nm-glib-aux/nm-io-utils.c
deleted file mode 100644
index 429591ad..00000000
--- a/shared/nm-glib-aux/nm-io-utils.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-io-utils.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "nm-str-buf.h"
-#include "nm-shared-utils.h"
-#include "nm-secret-utils.h"
-#include "nm-errno.h"
-
-/*****************************************************************************/
-
-_nm_printf(4, 5) static int _get_contents_error(GError **   error,
-                                                int         errsv,
-                                                int *       out_errsv,
-                                                const char *format,
-                                                ...)
-{
-    nm_assert(NM_ERRNO_NATIVE(errsv));
-
-    if (error) {
-        gs_free char *msg = NULL;
-        va_list       args;
-        char          bstrerr[NM_STRERROR_BUFSIZE];
-
-        va_start(args, format);
-        msg = g_strdup_vprintf(format, args);
-        va_end(args);
-        g_set_error(error,
-                    G_FILE_ERROR,
-                    g_file_error_from_errno(errsv),
-                    "%s: %s",
-                    msg,
-                    nm_strerror_native_r(errsv, bstrerr, sizeof(bstrerr)));
-    }
-
-    nm_assert(errsv > 0);
-    NM_SET_OUT(out_errsv, errsv);
-
-    return FALSE;
-}
-#define _get_contents_error_errno(error, out_errsv, ...)            \
-    ({                                                              \
-        int _errsv = (errno);                                       \
-                                                                    \
-        _get_contents_error(error, _errsv, out_errsv, __VA_ARGS__); \
-    })
-
-/**
- * nm_utils_fd_get_contents:
- * @fd: open file descriptor to read. The fd will not be closed,
- *   but don't rely on its state afterwards.
- * @close_fd: if %TRUE, @fd will be closed by the function.
- *  Passing %TRUE here might safe a syscall for dup().
- * @max_length: allocate at most @max_length bytes. If the
- *   file is larger, reading will fail. Set to zero to use
- *   a very large default.
- *   WARNING: @max_length is here to avoid a crash for huge/unlimited files.
- *   For example, stat(/sys/class/net/enp0s25/ifindex) gives a filesize of
- *   4K, although the actual real is small. @max_length is the memory
- *   allocated in the process of reading the file, thus it must be at least
- *   the size reported by fstat.
- *   If you set it to 1K, read will fail because fstat() claims the
- *   file is larger.
- * @flags: %NMUtilsFileGetContentsFlags for reading the file.
- * @contents: the output buffer with the file read. It is always
- *   NUL terminated. The buffer is at most @max_length long, including
- *  the NUL byte. That is, it reads only files up to a length of
- *  @max_length - 1 bytes.
- * @length: optional output argument of the read file size.
- * @out_errsv: (allow-none) (out): on error, a positive errno. or zero.
- * @error:
- *
- *
- * A reimplementation of g_file_get_contents() with a few differences:
- *   - accepts an open fd, instead of a path name. This allows you to
- *     use openat().
- *   - limits the maximum filesize to max_length.
- *
- * Returns: TRUE on success.
- */
-gboolean
-nm_utils_fd_get_contents(int                         fd,
-                         gboolean                    close_fd,
-                         gsize                       max_length,
-                         NMUtilsFileGetContentsFlags flags,
-                         char **                     contents,
-                         gsize *                     length,
-                         int *                       out_errsv,
-                         GError **                   error)
-{
-    nm_auto_close int fd_keeper = close_fd ? fd : -1;
-    struct stat       stat_buf;
-    gs_free char *    str          = NULL;
-    const bool        do_bzero_mem = NM_FLAGS_HAS(flags, NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET);
-    int               errsv;
-
-    g_return_val_if_fail(fd >= 0, FALSE);
-    g_return_val_if_fail(contents && !*contents, FALSE);
-    g_return_val_if_fail(!error || !*error, FALSE);
-
-    NM_SET_OUT(length, 0);
-
-    if (fstat(fd, &stat_buf) < 0)
-        return _get_contents_error_errno(error, out_errsv, "failure during fstat");
-
-    if (!max_length) {
-        /* default to a very large size, but not extreme */
-        max_length = 2 * 1024 * 1024;
-    }
-
-    if (stat_buf.st_size > 0 && S_ISREG(stat_buf.st_mode)) {
-        const gsize n_stat = stat_buf.st_size;
-        ssize_t     n_read;
-
-        if (n_stat > max_length - 1)
-            return _get_contents_error(error,
-                                       EMSGSIZE,
-                                       out_errsv,
-                                       "file too large (%zu+1 bytes with maximum %zu bytes)",
-                                       n_stat,
-                                       max_length);
-
-        str = g_try_malloc(n_stat + 1);
-        if (!str)
-            return _get_contents_error(error,
-                                       ENOMEM,
-                                       out_errsv,
-                                       "failure to allocate buffer of %zu+1 bytes",
-                                       n_stat);
-
-        n_read = nm_utils_fd_read_loop(fd, str, n_stat, TRUE);
-        if (n_read < 0) {
-            if (do_bzero_mem)
-                nm_explicit_bzero(str, n_stat);
-            return _get_contents_error(error,
-                                       -n_read,
-                                       out_errsv,
-                                       "error reading %zu bytes from file descriptor",
-                                       n_stat);
-        }
-        str[n_read] = '\0';
-
-        if (n_read < n_stat) {
-            if (!(str = nm_secret_mem_try_realloc_take(str, do_bzero_mem, n_stat + 1, n_read + 1)))
-                return _get_contents_error(error,
-                                           ENOMEM,
-                                           out_errsv,
-                                           "failure to reallocate buffer with %zu bytes",
-                                           n_read + 1);
-        }
-        NM_SET_OUT(length, n_read);
-    } else {
-        nm_auto_fclose FILE *f = NULL;
-        char                 buf[4096];
-        gsize                n_have, n_alloc;
-        int                  fd2;
-
-        if (fd_keeper >= 0)
-            fd2 = nm_steal_fd(&fd_keeper);
-        else {
-            fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 0);
-            if (fd2 < 0)
-                return _get_contents_error_errno(error, out_errsv, "error during dup");
-        }
-
-        if (!(f = fdopen(fd2, "r"))) {
-            errsv = errno;
-            nm_close(fd2);
-            return _get_contents_error(error, errsv, out_errsv, "failure during fdopen");
-        }
-
-        n_have  = 0;
-        n_alloc = 0;
-
-        while (!feof(f)) {
-            gsize n_read;
-
-            n_read = fread(buf, 1, sizeof(buf), f);
-            errsv  = errno;
-            if (ferror(f)) {
-                if (do_bzero_mem)
-                    nm_explicit_bzero(buf, sizeof(buf));
-                return _get_contents_error(error, errsv, out_errsv, "error during fread");
-            }
-
-            if (n_have > G_MAXSIZE - 1 - n_read || n_have + n_read + 1 > max_length) {
-                if (do_bzero_mem)
-                    nm_explicit_bzero(buf, sizeof(buf));
-                return _get_contents_error(
-                    error,
-                    EMSGSIZE,
-                    out_errsv,
-                    "file stream too large (%zu+1 bytes with maximum %zu bytes)",
-                    (n_have > G_MAXSIZE - 1 - n_read) ? G_MAXSIZE : n_have + n_read,
-                    max_length);
-            }
-
-            if (n_have + n_read + 1 >= n_alloc) {
-                gsize old_n_alloc = n_alloc;
-
-                if (n_alloc != 0) {
-                    nm_assert(str);
-                    if (n_alloc >= max_length / 2)
-                        n_alloc = max_length;
-                    else
-                        n_alloc *= 2;
-                } else {
-                    nm_assert(!str);
-                    n_alloc = NM_MIN(n_read + 1, sizeof(buf));
-                }
-
-                if (!(str = nm_secret_mem_try_realloc_take(str,
-                                                           do_bzero_mem,
-                                                           old_n_alloc,
-                                                           n_alloc))) {
-                    if (do_bzero_mem)
-                        nm_explicit_bzero(buf, sizeof(buf));
-                    return _get_contents_error(error,
-                                               ENOMEM,
-                                               out_errsv,
-                                               "failure to allocate buffer of %zu bytes",
-                                               n_alloc);
-                }
-            }
-
-            memcpy(str + n_have, buf, n_read);
-            n_have += n_read;
-        }
-
-        if (do_bzero_mem)
-            nm_explicit_bzero(buf, sizeof(buf));
-
-        if (n_alloc == 0)
-            str = g_new0(char, 1);
-        else {
-            str[n_have] = '\0';
-            if (n_have + 1 < n_alloc) {
-                if (!(str = nm_secret_mem_try_realloc_take(str, do_bzero_mem, n_alloc, n_have + 1)))
-                    return _get_contents_error(error,
-                                               ENOMEM,
-                                               out_errsv,
-                                               "failure to truncate buffer to %zu bytes",
-                                               n_have + 1);
-            }
-        }
-
-        NM_SET_OUT(length, n_have);
-    }
-
-    *contents = g_steal_pointer(&str);
-    NM_SET_OUT(out_errsv, 0);
-    return TRUE;
-}
-
-/**
- * nm_utils_file_get_contents:
- * @dirfd: optional file descriptor to use openat(). If negative, use plain open().
- * @filename: the filename to open. Possibly relative to @dirfd.
- * @max_length: allocate at most @max_length bytes.
- *   WARNING: see nm_utils_fd_get_contents() hint about @max_length.
- * @flags: %NMUtilsFileGetContentsFlags for reading the file.
- * @contents: the output buffer with the file read. It is always
- *   NUL terminated. The buffer is at most @max_length long, including
- *   the NUL byte. That is, it reads only files up to a length of
- *   @max_length - 1 bytes.
- * @length: optional output argument of the read file size.
- * @out_errsv: (allow-none) (out): on error, a positive errno. or zero.
- * @error:
- *
- * A reimplementation of g_file_get_contents() with a few differences:
- *   - accepts an @dirfd to open @filename relative to that path via openat().
- *   - limits the maximum filesize to max_length.
- *   - uses O_CLOEXEC on internal file descriptor
- *   - optionally returns the native errno on failure.
- *
- * Returns: TRUE on success.
- */
-gboolean
-nm_utils_file_get_contents(int                         dirfd,
-                           const char *                filename,
-                           gsize                       max_length,
-                           NMUtilsFileGetContentsFlags flags,
-                           char **                     contents,
-                           gsize *                     length,
-                           int *                       out_errsv,
-                           GError **                   error)
-{
-    int fd;
-
-    g_return_val_if_fail(filename && filename[0], FALSE);
-    g_return_val_if_fail(contents && !*contents, FALSE);
-
-    NM_SET_OUT(length, 0);
-
-    if (dirfd >= 0) {
-        fd = openat(dirfd, filename, O_RDONLY | O_CLOEXEC);
-        if (fd < 0) {
-            return _get_contents_error_errno(error,
-                                             out_errsv,
-                                             "Failed to open file \"%s\" with openat",
-                                             filename);
-        }
-    } else {
-        fd = open(filename, O_RDONLY | O_CLOEXEC);
-        if (fd < 0) {
-            return _get_contents_error_errno(error,
-                                             out_errsv,
-                                             "Failed to open file \"%s\"",
-                                             filename);
-        }
-    }
-    return nm_utils_fd_get_contents(fd,
-                                    TRUE,
-                                    max_length,
-                                    flags,
-                                    contents,
-                                    length,
-                                    out_errsv,
-                                    error);
-}
-
-/*****************************************************************************/
-
-/*
- * Copied from GLib's g_file_set_contents() et al., but allows
- * specifying a mode for the new file.
- */
-gboolean
-nm_utils_file_set_contents(const char *filename,
-                           const char *contents,
-                           gssize      length,
-                           mode_t      mode,
-                           int *       out_errsv,
-                           GError **   error)
-{
-    gs_free char *tmp_name = NULL;
-    struct stat   statbuf;
-    int           errsv;
-    gssize        s;
-    int           fd;
-
-    g_return_val_if_fail(filename, FALSE);
-    g_return_val_if_fail(contents || !length, FALSE);
-    g_return_val_if_fail(!error || !*error, FALSE);
-    g_return_val_if_fail(length >= -1, FALSE);
-
-    if (length == -1)
-        length = strlen(contents);
-
-    tmp_name = g_strdup_printf("%s.XXXXXX", filename);
-    fd       = g_mkstemp_full(tmp_name, O_RDWR | O_CLOEXEC, mode);
-    if (fd < 0) {
-        return _get_contents_error_errno(error, out_errsv, "failed to create file %s", tmp_name);
-    }
-
-    while (length > 0) {
-        s = write(fd, contents, length);
-        if (s < 0) {
-            errsv = NM_ERRNO_NATIVE(errno);
-            if (errsv == EINTR)
-                continue;
-
-            nm_close(fd);
-            unlink(tmp_name);
-            return _get_contents_error(error,
-                                       errsv,
-                                       out_errsv,
-                                       "failed to write to file %s",
-                                       tmp_name);
-        }
-
-        g_assert(s <= length);
-
-        contents += s;
-        length -= s;
-    }
-
-    /* If the final destination exists and is > 0 bytes, we want to sync the
-     * newly written file to ensure the data is on disk when we rename over
-     * the destination. Otherwise, if we get a system crash we can lose both
-     * the new and the old file on some filesystems. (I.E. those that don't
-     * guarantee the data is written to the disk before the metadata.)
-     */
-    if (lstat(filename, &statbuf) == 0 && statbuf.st_size > 0) {
-        if (fsync(fd) != 0) {
-            errsv = NM_ERRNO_NATIVE(errno);
-            nm_close(fd);
-            unlink(tmp_name);
-            return _get_contents_error(error, errsv, out_errsv, "failed to fsync %s", tmp_name);
-        }
-    }
-
-    nm_close(fd);
-
-    if (rename(tmp_name, filename)) {
-        errsv = NM_ERRNO_NATIVE(errno);
-        unlink(tmp_name);
-        return _get_contents_error(error,
-                                   errsv,
-                                   out_errsv,
-                                   "failed rename %s to %s",
-                                   tmp_name,
-                                   filename);
-    }
-
-    return TRUE;
-}
-
-/**
- * nm_utils_file_stat:
- * @filename: the filename to stat.
- * @out_st: (allow-none) (out): if given, this will be passed to stat().
- *
- * Just wraps stat() and gives the errno number as function result instead
- * of setting the errno (though, errno is also set). It's only for convenience
- * with
- *
- *    if (nm_utils_file_stat (filename, NULL) == -ENOENT) {
- *    }
- *
- * Returns: 0 on success a negative errno on failure. */
-int
-nm_utils_file_stat(const char *filename, struct stat *out_st)
-{
-    struct stat st;
-
-    if (stat(filename, out_st ?: &st) != 0)
-        return -NM_ERRNO_NATIVE(errno);
-    return 0;
-}
-
-/**
- * nm_utils_fd_read:
- * @fd: the fd to read from.
- * @out_string: (out): output string where read bytes will be stored.
- *
- * Returns: <0 on failure, which is -(errno).
- *          0 on EOF.
- *          >0 on success, which is the number of bytes read.  */
-gssize
-nm_utils_fd_read(int fd, NMStrBuf *out_string)
-{
-    gsize  buf_available;
-    gssize n_read;
-    int    errsv;
-
-    g_return_val_if_fail(fd >= 0, -1);
-    g_return_val_if_fail(out_string, -1);
-
-    /* If the buffer size is 0, we allocate NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 (1000 bytes)
-     * the first time. Afterwards, the buffer grows exponentially.
-     *
-     * Note that with @buf_available, we always would read as much buffer as we actually
-     * have reserved. */
-    nm_str_buf_maybe_expand(out_string, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
-
-    buf_available = out_string->allocated - out_string->len;
-
-    n_read = read(fd, &((nm_str_buf_get_str_unsafe(out_string))[out_string->len]), buf_available);
-    if (n_read < 0) {
-        errsv = errno;
-        return -NM_ERRNO_NATIVE(errsv);
-    }
-
-    if (n_read > 0) {
-        nm_assert((gsize) n_read <= buf_available);
-        nm_str_buf_set_size(out_string, out_string->len + (gsize) n_read, TRUE, FALSE);
-    }
-
-    return n_read;
-}
diff --git a/shared/nm-glib-aux/nm-io-utils.h b/shared/nm-glib-aux/nm-io-utils.h
deleted file mode 100644
index 8182f5cf..00000000
--- a/shared/nm-glib-aux/nm-io-utils.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_IO_UTILS_H__
-#define __NM_IO_UTILS_H__
-
-#include "nm-macros-internal.h"
-
-/*****************************************************************************/
-
-/**
- * NMUtilsFileGetContentsFlags:
- * @NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE: no flag
- * @NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET: if present, ensure that no
- *   data is left in memory. Essentially, it means to call nm_explicit_bzero()
- *   to not leave key material on the heap (when reading secrets).
- */
-typedef enum {
-    NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE   = 0,
-    NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET = (1 << 0),
-} NMUtilsFileGetContentsFlags;
-
-gboolean nm_utils_fd_get_contents(int                         fd,
-                                  gboolean                    close_fd,
-                                  gsize                       max_length,
-                                  NMUtilsFileGetContentsFlags flags,
-                                  char **                     contents,
-                                  gsize *                     length,
-                                  int *                       out_errsv,
-                                  GError **                   error);
-
-gboolean nm_utils_file_get_contents(int                         dirfd,
-                                    const char *                filename,
-                                    gsize                       max_length,
-                                    NMUtilsFileGetContentsFlags flags,
-                                    char **                     contents,
-                                    gsize *                     length,
-                                    int *                       out_errsv,
-                                    GError **                   error);
-
-gboolean nm_utils_file_set_contents(const char *filename,
-                                    const char *contents,
-                                    gssize      length,
-                                    mode_t      mode,
-                                    int *       out_errsv,
-                                    GError **   error);
-
-struct _NMStrBuf;
-
-gssize nm_utils_fd_read(int fd, struct _NMStrBuf *out_string);
-
-struct stat;
-
-int nm_utils_file_stat(const char *filename, struct stat *out_st);
-
-#endif /* __NM_IO_UTILS_H__ */
diff --git a/shared/nm-glib-aux/nm-jansson.h b/shared/nm-glib-aux/nm-jansson.h
deleted file mode 100644
index 6173a7ac..00000000
--- a/shared/nm-glib-aux/nm-jansson.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_JANSSON_H__
-#define __NM_JANSSON_H__
-
-/* you need to include at least "config.h" first, possibly "nm-default.h". */
-
-#if WITH_JANSSON
-
-    #include <jansson.h>
-
-    /* Added in Jansson v2.8 */
-    #ifndef json_object_foreach_safe
-        #define json_object_foreach_safe(object, n, key, value)                         \
-            for (key = json_object_iter_key(json_object_iter(object)),                  \
-                n    = json_object_iter_next(object, json_object_key_to_iter(key));     \
-                 key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
-                 key = json_object_iter_key(n),                                         \
-                n    = json_object_iter_next(object, json_object_key_to_iter(key)))
-    #endif
-
-NM_AUTO_DEFINE_FCN0(json_t *, _nm_auto_decref_json, json_decref);
-    #define nm_auto_decref_json nm_auto(_nm_auto_decref_json)
-
-#endif /* WITH_JANSON */
-
-#endif /* __NM_JANSSON_H__ */
diff --git a/shared/nm-glib-aux/nm-json-aux.c b/shared/nm-glib-aux/nm-json-aux.c
deleted file mode 100644
index 97ee606f..00000000
--- a/shared/nm-glib-aux/nm-json-aux.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 - 2019 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-json-aux.h"
-
-#include <dlfcn.h>
-
-/*****************************************************************************/
-
-/* If RTLD_DEEPBIND isn't available just ignore it. This can cause problems
- * with jansson, json-glib, and cjson symbols clashing (and as such crashing the
- * program). But that needs to be fixed by the json libraries, and it is by adding
- * symbol versioning in recent versions. */
-#ifndef RTLD_DEEPBIND
-    #define RTLD_DEEPBIND 0
-#endif
-
-/*****************************************************************************/
-
-static void
-_gstr_append_string_len(GString *gstr, const char *str, gsize len)
-{
-    g_string_append_c(gstr, '\"');
-
-    while (len > 0) {
-        gsize       n;
-        const char *end;
-        gboolean    valid;
-
-        nm_assert(len > 0);
-
-        valid = g_utf8_validate(str, len, &end);
-
-        nm_assert(end && end >= str && end <= &str[len]);
-
-        if (end > str) {
-            const char *s;
-
-            for (s = str; s < end; s++) {
-                nm_assert(s[0] != '\0');
-
-                if (s[0] < 0x20) {
-                    const char *text;
-
-                    switch (s[0]) {
-                    case '\\':
-                        text = "\\\\";
-                        break;
-                    case '\"':
-                        text = "\\\"";
-                        break;
-                    case '\b':
-                        text = "\\b";
-                        break;
-                    case '\f':
-                        text = "\\f";
-                        break;
-                    case '\n':
-                        text = "\\n";
-                        break;
-                    case '\r':
-                        text = "\\r";
-                        break;
-                    case '\t':
-                        text = "\\t";
-                        break;
-                    default:
-                        g_string_append_printf(gstr, "\\u%04X", (guint) s[0]);
-                        continue;
-                    }
-                    g_string_append(gstr, text);
-                    continue;
-                }
-
-                if (NM_IN_SET(s[0], '\\', '\"'))
-                    g_string_append_c(gstr, '\\');
-                g_string_append_c(gstr, s[0]);
-            }
-        } else
-            nm_assert(!valid);
-
-        if (valid) {
-            nm_assert(end == &str[len]);
-            break;
-        }
-
-        nm_assert(end < &str[len]);
-
-        if (end[0] == '\0') {
-            /* there is a NUL byte in the string. Technically this is valid UTF-8, so we
-             * encode it there. However, this will likely result in a truncated string when
-             * parsing. */
-            g_string_append(gstr, "\\u0000");
-        } else {
-            /* the character is not valid UTF-8. There is nothing we can do about it, because
-             * JSON can only contain UTF-8 and even the escape sequences can only escape Unicode
-             * codepoints (but not binary).
-             *
-             * The argument is not a string (in any known encoding), hence we cannot represent
-             * it as a JSON string (which are unicode strings).
-             *
-             * Print an underscore instead of the invalid char :) */
-            g_string_append_c(gstr, '_');
-        }
-
-        n = str - end;
-        nm_assert(n < len);
-        n++;
-        str += n;
-        len -= n;
-    }
-
-    g_string_append_c(gstr, '\"');
-}
-
-void
-nm_json_gstr_append_string_len(GString *gstr, const char *str, gsize n)
-{
-    g_return_if_fail(gstr);
-
-    _gstr_append_string_len(gstr, str, n);
-}
-
-void
-nm_json_gstr_append_string(GString *gstr, const char *str)
-{
-    g_return_if_fail(gstr);
-
-    if (!str)
-        g_string_append(gstr, "null");
-    else
-        _gstr_append_string_len(gstr, str, strlen(str));
-}
-
-void
-nm_json_gstr_append_obj_name(GString *gstr, const char *key, char start_container)
-{
-    g_return_if_fail(gstr);
-    g_return_if_fail(key);
-
-    nm_json_gstr_append_string(gstr, key);
-
-    if (start_container != '\0') {
-        nm_assert(NM_IN_SET(start_container, '[', '{'));
-        g_string_append_printf(gstr, ": %c ", start_container);
-    } else
-        g_string_append(gstr, ": ");
-}
-
-/*****************************************************************************/
-
-typedef struct {
-    NMJsonVt vt;
-    void *   dl_handle;
-} NMJsonVtInternal;
-
-static NMJsonVtInternal *
-_nm_json_vt_internal_load(void)
-{
-    NMJsonVtInternal *v;
-    const char *      soname;
-    void *            handle;
-
-    v = g_new0(NMJsonVtInternal, 1);
-
-#if WITH_JANSSON && defined(JANSSON_SONAME)
-    G_STATIC_ASSERT_EXPR(NM_STRLEN(JANSSON_SONAME) > 0);
-    nm_assert(strlen(JANSSON_SONAME) > 0);
-    soname = JANSSON_SONAME;
-#elif !WITH_JANSSON && !defined(JANSSON_SONAME)
-    soname = NULL;
-#else
-    #error "WITH_JANSON and JANSSON_SONAME are defined inconsistently."
-#endif
-
-    if (!soname)
-        return v;
-
-    handle = dlopen(soname,
-                    RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE
-#if !defined(ASAN_BUILD)
-                        | RTLD_DEEPBIND
-#endif
-                        | 0);
-    if (!handle)
-        return v;
-
-#define TRY_BIND_SYMBOL(symbol)              \
-    G_STMT_START                             \
-    {                                        \
-        void *_sym = dlsym(handle, #symbol); \
-                                             \
-        if (!_sym)                           \
-            goto fail_symbol;                \
-        v->vt.nm_##symbol = _sym;            \
-    }                                        \
-    G_STMT_END
-
-    TRY_BIND_SYMBOL(json_array);
-    TRY_BIND_SYMBOL(json_array_append_new);
-    TRY_BIND_SYMBOL(json_array_get);
-    TRY_BIND_SYMBOL(json_array_size);
-    TRY_BIND_SYMBOL(json_delete);
-    TRY_BIND_SYMBOL(json_dumps);
-    TRY_BIND_SYMBOL(json_false);
-    TRY_BIND_SYMBOL(json_integer);
-    TRY_BIND_SYMBOL(json_integer_value);
-    TRY_BIND_SYMBOL(json_loads);
-    TRY_BIND_SYMBOL(json_object);
-    TRY_BIND_SYMBOL(json_object_del);
-    TRY_BIND_SYMBOL(json_object_get);
-    TRY_BIND_SYMBOL(json_object_iter);
-    TRY_BIND_SYMBOL(json_object_iter_key);
-    TRY_BIND_SYMBOL(json_object_iter_next);
-    TRY_BIND_SYMBOL(json_object_iter_value);
-    TRY_BIND_SYMBOL(json_object_key_to_iter);
-    TRY_BIND_SYMBOL(json_object_set_new);
-    TRY_BIND_SYMBOL(json_object_size);
-    TRY_BIND_SYMBOL(json_string);
-    TRY_BIND_SYMBOL(json_string_value);
-    TRY_BIND_SYMBOL(json_true);
-
-    v->vt.loaded = TRUE;
-    v->dl_handle = handle;
-    return v;
-
-fail_symbol:
-    dlclose(&handle);
-    *v = (NMJsonVtInternal){};
-    return v;
-}
-
-const NMJsonVt *_nm_json_vt_ptr = NULL;
-
-const NMJsonVt *
-_nm_json_vt_init(void)
-{
-    NMJsonVtInternal *v;
-
-again:
-    v = g_atomic_pointer_get((gpointer *) &_nm_json_vt_ptr);
-    if (G_UNLIKELY(!v)) {
-        v = _nm_json_vt_internal_load();
-        if (!g_atomic_pointer_compare_and_exchange((gpointer *) &_nm_json_vt_ptr, NULL, v)) {
-            if (v->dl_handle)
-                dlclose(v->dl_handle);
-            g_free(v);
-            goto again;
-        }
-
-        /* we transfer ownership. */
-    }
-
-    nm_assert(v && v == g_atomic_pointer_get((gpointer *) &_nm_json_vt_ptr));
-    return &v->vt;
-}
-
-const NMJsonVt *
-nmtst_json_vt_reset(gboolean loaded)
-{
-    NMJsonVtInternal *v_old;
-    NMJsonVtInternal *v;
-
-    v_old = g_atomic_pointer_get((gpointer *) &_nm_json_vt_ptr);
-
-    if (!loaded) {
-        /* load a fake instance for testing. */
-        v = g_new0(NMJsonVtInternal, 1);
-    } else
-        v = _nm_json_vt_internal_load();
-
-    if (!g_atomic_pointer_compare_and_exchange((gpointer *) &_nm_json_vt_ptr, v_old, v))
-        g_assert_not_reached();
-
-    if (v_old) {
-        if (v_old->dl_handle)
-            dlclose(v_old->dl_handle);
-        g_free((gpointer *) v_old);
-    }
-
-    return v->vt.loaded ? &v->vt : NULL;
-}
diff --git a/shared/nm-glib-aux/nm-json-aux.h b/shared/nm-glib-aux/nm-json-aux.h
deleted file mode 100644
index 99759a8d..00000000
--- a/shared/nm-glib-aux/nm-json-aux.h
+++ /dev/null
@@ -1,312 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 - 2019 Red Hat, Inc.
- */
-
-#ifndef __NM_JSON_AUX_H__
-#define __NM_JSON_AUX_H__
-
-#include "nm-value-type.h"
-
-/*****************************************************************************/
-
-static inline GString *
-nm_json_gstr_append_delimiter(GString *gstr)
-{
-    g_string_append(gstr, ", ");
-    return gstr;
-}
-
-void nm_json_gstr_append_string_len(GString *gstr, const char *str, gsize n);
-
-void nm_json_gstr_append_string(GString *gstr, const char *str);
-
-static inline void
-nm_json_gstr_append_bool(GString *gstr, gboolean v)
-{
-    g_string_append(gstr, v ? "true" : "false");
-}
-
-static inline void
-nm_json_gstr_append_int64(GString *gstr, gint64 v)
-{
-    g_string_append_printf(gstr, "%" G_GINT64_FORMAT, v);
-}
-
-void nm_json_gstr_append_obj_name(GString *gstr, const char *key, char start_container);
-
-/*****************************************************************************/
-
-#define NM_JSON_REJECT_DUPLICATES 0x1
-
-typedef enum {
-    NM_JSON_OBJECT,
-    NM_JSON_ARRAY,
-    NM_JSON_STRING,
-    NM_JSON_INTEGER,
-    NM_JSON_REAL,
-    NM_JSON_TRUE,
-    NM_JSON_FALSE,
-    NM_JSON_NULL,
-} nm_json_type;
-
-typedef struct nm_json_t {
-    nm_json_type    type;
-    volatile size_t refcount;
-} nm_json_t;
-
-typedef long long nm_json_int_t;
-
-#define NM_JSON_ERROR_TEXT_LENGTH   160
-#define NM_JSON_ERROR_SOURCE_LENGTH 80
-
-typedef struct nm_json_error_t {
-    int  line;
-    int  column;
-    int  position;
-    char source[NM_JSON_ERROR_SOURCE_LENGTH];
-    char text[NM_JSON_ERROR_TEXT_LENGTH];
-} nm_json_error_t;
-
-typedef struct {
-    gboolean loaded;
-    char *(*nm_json_dumps)(const nm_json_t *json, size_t flags);
-    const char *(*nm_json_object_iter_key)(void *iter);
-    const char *(*nm_json_string_value)(const nm_json_t *json);
-    int (*nm_json_array_append_new)(nm_json_t *json, nm_json_t *value);
-    int (*nm_json_object_del)(nm_json_t *json, const char *key);
-    int (*nm_json_object_set_new)(nm_json_t *json, const char *key, nm_json_t *value);
-    nm_json_int_t (*nm_json_integer_value)(const nm_json_t *json);
-    nm_json_t *(*nm_json_array)(void);
-    nm_json_t *(*nm_json_array_get)(const nm_json_t *json, size_t index);
-    nm_json_t *(*nm_json_false)(void);
-    nm_json_t *(*nm_json_integer)(nm_json_int_t value);
-    nm_json_t *(*nm_json_loads)(const char *string, size_t flags, nm_json_error_t *error);
-    nm_json_t *(*nm_json_object)(void);
-    nm_json_t *(*nm_json_object_get)(const nm_json_t *json, const char *key);
-    nm_json_t *(*nm_json_object_iter_value)(void *);
-    nm_json_t *(*nm_json_string)(const char *value);
-    nm_json_t *(*nm_json_true)(void);
-    size_t (*nm_json_array_size)(const nm_json_t *json);
-    size_t (*nm_json_object_size)(const nm_json_t *json);
-    void (*nm_json_delete)(nm_json_t *json);
-    void *(*nm_json_object_iter)(nm_json_t *json);
-    void *(*nm_json_object_iter_next)(nm_json_t *json, void *iter);
-    void *(*nm_json_object_key_to_iter)(const char *key);
-} NMJsonVt;
-
-extern const NMJsonVt *_nm_json_vt_ptr;
-
-const NMJsonVt *_nm_json_vt_init(void);
-
-static inline const NMJsonVt *
-_nm_json_vt(void)
-{
-    const NMJsonVt *vt;
-
-    vt = g_atomic_pointer_get((gpointer *) &_nm_json_vt_ptr);
-    if (G_UNLIKELY(!vt)) {
-        vt = _nm_json_vt_init();
-        nm_assert(vt);
-    }
-    return vt;
-}
-
-static inline const NMJsonVt *
-nm_json_vt(void)
-{
-    const NMJsonVt *vt;
-
-    vt = _nm_json_vt();
-    return vt->loaded ? vt : NULL;
-}
-
-static inline const NMJsonVt *
-nm_json_vt_assert(void)
-{
-    const NMJsonVt *vt;
-
-    vt = _nm_json_vt();
-    nm_assert(vt->loaded);
-    return vt;
-}
-
-const NMJsonVt *nmtst_json_vt_reset(gboolean loaded);
-
-/*****************************************************************************/
-
-#define nm_json_boolean(vt, val) ((val) ? (vt)->nm_json_true() : (vt)->nm_json_false())
-
-static inline void
-nm_json_decref(const NMJsonVt *vt, nm_json_t *json)
-{
-    /* Our ref-counting is not threadsafe, unlike libjansson's. But we never
-     * share one json_t instance between threads, and if we would, we would very likely
-     * wrap a mutex around it. */
-    if (json && json->refcount != (size_t) -1 && --json->refcount == 0)
-        vt->nm_json_delete(json);
-}
-
-static inline void
-_nm_auto_decref_json(nm_json_t **p_json)
-{
-    if (*p_json && (*p_json)->refcount != (size_t) -1 && --(*p_json)->refcount == 0)
-        nm_json_vt()->nm_json_delete(*p_json);
-}
-
-#define nm_auto_decref_json nm_auto(_nm_auto_decref_json)
-
-/*****************************************************************************/
-
-/* the following are implemented as pure macros in jansson.h.
- * They can be used directly, however, add a nm_json* variant,
- * to make it explict we don't accidentally use jansson ABI. */
-
-#define nm_json_typeof(json)     ((json)->type)
-#define nm_json_is_object(json)  ((json) && nm_json_typeof(json) == NM_JSON_OBJECT)
-#define nm_json_is_array(json)   ((json) && nm_json_typeof(json) == NM_JSON_ARRAY)
-#define nm_json_is_string(json)  ((json) && nm_json_typeof(json) == NM_JSON_STRING)
-#define nm_json_is_integer(json) ((json) && nm_json_typeof(json) == NM_JSON_INTEGER)
-#define nm_json_is_real(json)    ((json) && nm_json_typeof(json) == NM_JSON_REAL)
-#define nm_json_is_number(json)  (nm_json_is_integer(json) || nm_json_is_real(json))
-#define nm_json_is_true(json)    ((json) && nm_json_typeof(json) == NM_JSON_TRUE)
-#define nm_json_is_false(json)   ((json) && nm_json_typeof(json) == NM_JSON_FALSE)
-#define nm_json_boolean_value    nm_json_is_true
-#define nm_json_is_boolean(json) (nm_json_is_true(json) || nm_json_is_false(json))
-#define nm_json_is_null(json)    ((json) && nm_json_typeof(json) == NM_JSON_NULL)
-
-#define nm_json_array_foreach(vt, array, index, value)                                           \
-    for (index = 0;                                                                              \
-         index < vt->nm_json_array_size(array) && (value = vt->nm_json_array_get(array, index)); \
-         index++)
-
-#define nm_json_object_foreach(vt, object, key, value)                                        \
-    for (key = vt->nm_json_object_iter_key(vt->nm_json_object_iter(object));                  \
-         key && (value = vt->nm_json_object_iter_value(vt->nm_json_object_key_to_iter(key))); \
-         key = vt->nm_json_object_iter_key(                                                   \
-             vt->nm_json_object_iter_next(object, vt->nm_json_object_key_to_iter(key))))
-
-/*****************************************************************************/
-
-static inline int
-nm_jansson_json_as_bool(const nm_json_t *elem, bool *out_val)
-{
-    if (!elem)
-        return 0;
-
-    if (!nm_json_is_boolean(elem))
-        return -EINVAL;
-
-    NM_SET_OUT(out_val, nm_json_boolean_value(elem));
-    return 1;
-}
-
-static inline int
-nm_jansson_json_as_int32(const NMJsonVt *vt, const nm_json_t *elem, gint32 *out_val)
-{
-    nm_json_int_t v;
-
-    if (!elem)
-        return 0;
-
-    if (!nm_json_is_integer(elem))
-        return -EINVAL;
-
-    v = vt->nm_json_integer_value(elem);
-    if (v < (gint64) G_MININT32 || v > (gint64) G_MAXINT32)
-        return -ERANGE;
-
-    NM_SET_OUT(out_val, v);
-    return 1;
-}
-
-static inline int
-nm_jansson_json_as_int(const NMJsonVt *vt, const nm_json_t *elem, int *out_val)
-{
-    nm_json_int_t v;
-
-    if (!elem)
-        return 0;
-
-    if (!nm_json_is_integer(elem))
-        return -EINVAL;
-
-    v = vt->nm_json_integer_value(elem);
-    if (v < (gint64) G_MININT || v > (gint64) G_MAXINT)
-        return -ERANGE;
-
-    NM_SET_OUT(out_val, v);
-    return 1;
-}
-
-static inline int
-nm_jansson_json_as_string(const NMJsonVt *vt, const nm_json_t *elem, const char **out_val)
-{
-    if (!elem)
-        return 0;
-
-    if (!nm_json_is_string(elem))
-        return -EINVAL;
-
-    NM_SET_OUT(out_val, vt->nm_json_string_value(elem));
-    return 1;
-}
-
-/*****************************************************************************/
-
-#ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS
-
-static inline void
-nm_value_type_to_json(NMValueType value_type, GString *gstr, gconstpointer p_field)
-{
-    nm_assert(p_field);
-    nm_assert(gstr);
-
-    switch (value_type) {
-    case NM_VALUE_TYPE_BOOL:
-        nm_json_gstr_append_bool(gstr, *((const bool *) p_field));
-        return;
-    case NM_VALUE_TYPE_INT32:
-        nm_json_gstr_append_int64(gstr, *((const gint32 *) p_field));
-        return;
-    case NM_VALUE_TYPE_INT:
-        nm_json_gstr_append_int64(gstr, *((const int *) p_field));
-        return;
-    case NM_VALUE_TYPE_STRING:
-        nm_json_gstr_append_string(gstr, *((const char *const *) p_field));
-        return;
-    case NM_VALUE_TYPE_UNSPEC:
-        break;
-    }
-    nm_assert_not_reached();
-}
-
-static inline gboolean
-nm_value_type_from_json(const NMJsonVt * vt,
-                        NMValueType      value_type,
-                        const nm_json_t *elem,
-                        gpointer         out_val)
-{
-    switch (value_type) {
-    case NM_VALUE_TYPE_BOOL:
-        return (nm_jansson_json_as_bool(elem, out_val) > 0);
-    case NM_VALUE_TYPE_INT32:
-        return (nm_jansson_json_as_int32(vt, elem, out_val) > 0);
-    case NM_VALUE_TYPE_INT:
-        return (nm_jansson_json_as_int(vt, elem, out_val) > 0);
-
-    /* warning: this overwrites/leaks the previous value. You better have *out_val
-     * point to uninitialized memory or NULL. */
-    case NM_VALUE_TYPE_STRING:
-        return (nm_jansson_json_as_string(vt, elem, out_val) > 0);
-
-    case NM_VALUE_TYPE_UNSPEC:
-        break;
-    }
-    nm_assert_not_reached();
-    return FALSE;
-}
-
-#endif /* NM_VALUE_TYPE_DEFINE_FUNCTIONS */
-
-#endif /* __NM_JSON_AUX_H__ */
diff --git a/shared/nm-glib-aux/nm-keyfile-aux.c b/shared/nm-glib-aux/nm-keyfile-aux.c
deleted file mode 100644
index b5962712..00000000
--- a/shared/nm-glib-aux/nm-keyfile-aux.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-keyfile-aux.h"
-
-#include <syslog.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "nm-io-utils.h"
-
-/*****************************************************************************/
-
-struct _NMKeyFileDB {
-    NMKeyFileDBLogFcn      log_fcn;
-    NMKeyFileDBGotDirtyFcn got_dirty_fcn;
-    gpointer               user_data;
-    const char *           group_name;
-    GKeyFile *             kf;
-    guint                  ref_count;
-
-    bool is_started : 1;
-    bool dirty : 1;
-    bool destroyed : 1;
-
-    char filename[];
-};
-
-#define _NMLOG(self, syslog_level, fmt, ...)                                                   \
-    G_STMT_START                                                                               \
-    {                                                                                          \
-        NMKeyFileDB *_self = (self);                                                           \
-                                                                                               \
-        nm_assert(_self);                                                                      \
-        nm_assert(!_self->destroyed);                                                          \
-                                                                                               \
-        if (_self->log_fcn) {                                                                  \
-            _self->log_fcn(_self, (syslog_level), _self->user_data, "" fmt "", ##__VA_ARGS__); \
-        };                                                                                     \
-    }                                                                                          \
-    G_STMT_END
-
-#define _LOGD(...) _NMLOG(self, LOG_DEBUG, __VA_ARGS__)
-
-static gboolean
-_IS_KEY_FILE_DB(NMKeyFileDB *self, gboolean require_is_started, gboolean allow_destroyed)
-{
-    if (self == NULL)
-        return FALSE;
-    if (self->ref_count <= 0) {
-        nm_assert_not_reached();
-        return FALSE;
-    }
-    if (require_is_started && !self->is_started)
-        return FALSE;
-    if (!allow_destroyed && self->destroyed)
-        return FALSE;
-    return TRUE;
-}
-
-/*****************************************************************************/
-
-NMKeyFileDB *
-nm_key_file_db_new(const char *           filename,
-                   const char *           group_name,
-                   NMKeyFileDBLogFcn      log_fcn,
-                   NMKeyFileDBGotDirtyFcn got_dirty_fcn,
-                   gpointer               user_data)
-{
-    NMKeyFileDB *self;
-    gsize        l_filename;
-    gsize        l_group;
-
-    g_return_val_if_fail(filename && filename[0], NULL);
-    g_return_val_if_fail(group_name && group_name[0], NULL);
-
-    l_filename = strlen(filename);
-    l_group    = strlen(group_name);
-
-    self                = g_malloc0(sizeof(NMKeyFileDB) + l_filename + 1 + l_group + 1);
-    self->ref_count     = 1;
-    self->log_fcn       = log_fcn;
-    self->got_dirty_fcn = got_dirty_fcn;
-    self->user_data     = user_data;
-    self->kf            = g_key_file_new();
-    g_key_file_set_list_separator(self->kf, ',');
-    memcpy(self->filename, filename, l_filename + 1);
-    self->group_name = &self->filename[l_filename + 1];
-    memcpy((char *) self->group_name, group_name, l_group + 1);
-
-    return self;
-}
-
-NMKeyFileDB *
-nm_key_file_db_ref(NMKeyFileDB *self)
-{
-    if (!self)
-        return NULL;
-
-    g_return_val_if_fail(_IS_KEY_FILE_DB(self, FALSE, TRUE), NULL);
-
-    nm_assert(self->ref_count < G_MAXUINT);
-    self->ref_count++;
-    return self;
-}
-
-void
-nm_key_file_db_unref(NMKeyFileDB *self)
-{
-    if (!self)
-        return;
-
-    g_return_if_fail(_IS_KEY_FILE_DB(self, FALSE, TRUE));
-
-    if (--self->ref_count > 0)
-        return;
-
-    g_key_file_unref(self->kf);
-
-    g_free(self);
-}
-
-/* destroy() is like unref, but it also makes the instance unusable.
- * All changes afterwards fail with an assertion.
- *
- * The point is that NMKeyFileDB is ref-counted in principle. But there
- * is a primary owner who also provides the log_fcn().
- *
- * When the primary owner goes out of scope and gives up the reference, it does
- * not want to receive any log notifications anymore.
- *
- * The way NMKeyFileDB is intended to be used is in a very strict context:
- * NMSettings owns the NMKeyFileDB instance and receives logging notifications.
- * It's also the last one to persist the data to disk. Afterwards, no other user
- * is supposed to be around and do anything with NMKeyFileDB. But since NMKeyFileDB
- * is ref-counted it's hard to ensure that this is truly honored. So we start
- * asserting at that point.
- */
-void
-nm_key_file_db_destroy(NMKeyFileDB *self)
-{
-    if (!self)
-        return;
-
-    g_return_if_fail(_IS_KEY_FILE_DB(self, FALSE, FALSE));
-    g_return_if_fail(!self->destroyed);
-
-    self->destroyed = TRUE;
-    nm_key_file_db_unref(self);
-}
-
-/*****************************************************************************/
-
-/* nm_key_file_db_start() is supposed to be called right away, after creating the
- * instance.
- *
- * It's not done as separate step after nm_key_file_db_new(), because we want to log,
- * and the log_fcn returns the self pointer (which we should not expose before
- * nm_key_file_db_new() returns. */
-void
-nm_key_file_db_start(NMKeyFileDB *self)
-{
-    gs_free char *contents = NULL;
-    gsize         contents_len;
-    gs_free_error GError *error = NULL;
-
-    g_return_if_fail(_IS_KEY_FILE_DB(self, FALSE, FALSE));
-    g_return_if_fail(!self->is_started);
-
-    self->is_started = TRUE;
-
-    if (!nm_utils_file_get_contents(-1,
-                                    self->filename,
-                                    20 * 1024 * 1024,
-                                    NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
-                                    &contents,
-                                    &contents_len,
-                                    NULL,
-                                    &error)) {
-        _LOGD("failed to read \"%s\": %s", self->filename, error->message);
-        return;
-    }
-
-    if (!g_key_file_load_from_data(self->kf,
-                                   contents,
-                                   contents_len,
-                                   G_KEY_FILE_KEEP_COMMENTS,
-                                   &error)) {
-        _LOGD("failed to load keyfile \"%s\": %s", self->filename, error->message);
-        return;
-    }
-
-    _LOGD("loaded keyfile-db for \"%s\"", self->filename);
-}
-
-/*****************************************************************************/
-
-const char *
-nm_key_file_db_get_filename(NMKeyFileDB *self)
-{
-    g_return_val_if_fail(_IS_KEY_FILE_DB(self, FALSE, TRUE), NULL);
-
-    return self->filename;
-}
-
-gboolean
-nm_key_file_db_is_dirty(NMKeyFileDB *self)
-{
-    g_return_val_if_fail(_IS_KEY_FILE_DB(self, FALSE, TRUE), FALSE);
-
-    return self->dirty;
-}
-
-/*****************************************************************************/
-
-char *
-nm_key_file_db_get_value(NMKeyFileDB *self, const char *key)
-{
-    g_return_val_if_fail(_IS_KEY_FILE_DB(self, TRUE, TRUE), NULL);
-
-    return g_key_file_get_value(self->kf, self->group_name, key, NULL);
-}
-
-char **
-nm_key_file_db_get_string_list(NMKeyFileDB *self, const char *key, gsize *out_len)
-{
-    g_return_val_if_fail(_IS_KEY_FILE_DB(self, TRUE, TRUE), NULL);
-
-    return g_key_file_get_string_list(self->kf, self->group_name, key, out_len, NULL);
-}
-
-/*****************************************************************************/
-
-static void
-_got_dirty(NMKeyFileDB *self, const char *key)
-{
-    nm_assert(_IS_KEY_FILE_DB(self, TRUE, FALSE));
-    nm_assert(!self->dirty);
-
-    _LOGD("updated entry for %s.%s", self->group_name, key);
-
-    self->dirty = TRUE;
-    if (self->got_dirty_fcn)
-        self->got_dirty_fcn(self, self->user_data);
-}
-
-/*****************************************************************************/
-
-void
-nm_key_file_db_remove_key(NMKeyFileDB *self, const char *key)
-{
-    gboolean got_dirty = FALSE;
-
-    g_return_if_fail(_IS_KEY_FILE_DB(self, TRUE, FALSE));
-
-    if (!key)
-        return;
-
-    if (!self->dirty) {
-        gs_free_error GError *error = NULL;
-
-        g_key_file_has_key(self->kf, self->group_name, key, &error);
-        got_dirty = (error != NULL);
-    }
-    g_key_file_remove_key(self->kf, self->group_name, key, NULL);
-
-    if (got_dirty)
-        _got_dirty(self, key);
-}
-
-void
-nm_key_file_db_set_value(NMKeyFileDB *self, const char *key, const char *value)
-{
-    gs_free char *old_value = NULL;
-    gboolean      got_dirty = FALSE;
-
-    g_return_if_fail(_IS_KEY_FILE_DB(self, TRUE, FALSE));
-    g_return_if_fail(key);
-
-    if (!value) {
-        nm_key_file_db_remove_key(self, key);
-        return;
-    }
-
-    if (!self->dirty) {
-        gs_free_error GError *error = NULL;
-
-        old_value = g_key_file_get_value(self->kf, self->group_name, key, &error);
-        if (error)
-            got_dirty = TRUE;
-    }
-
-    g_key_file_set_value(self->kf, self->group_name, key, value);
-
-    if (!self->dirty && !got_dirty) {
-        gs_free_error GError *error     = NULL;
-        gs_free char *        new_value = NULL;
-
-        new_value = g_key_file_get_value(self->kf, self->group_name, key, &error);
-        if (error || !new_value || !nm_streq0(old_value, new_value))
-            got_dirty = TRUE;
-    }
-
-    if (got_dirty)
-        _got_dirty(self, key);
-}
-
-void
-nm_key_file_db_set_string_list(NMKeyFileDB *      self,
-                               const char *       key,
-                               const char *const *value,
-                               gssize             len)
-{
-    gs_free char *old_value = NULL;
-    gboolean      got_dirty = FALSE;
-
-    g_return_if_fail(_IS_KEY_FILE_DB(self, TRUE, FALSE));
-    g_return_if_fail(key);
-
-    if (!value) {
-        nm_key_file_db_remove_key(self, key);
-        return;
-    }
-
-    if (!self->dirty) {
-        gs_free_error GError *error = NULL;
-
-        old_value = g_key_file_get_value(self->kf, self->group_name, key, &error);
-        if (error)
-            got_dirty = TRUE;
-    }
-
-    if (len < 0)
-        len = NM_PTRARRAY_LEN(value);
-
-    g_key_file_set_string_list(self->kf, self->group_name, key, value, len);
-
-    if (!self->dirty && !got_dirty) {
-        gs_free_error GError *error     = NULL;
-        gs_free char *        new_value = NULL;
-
-        new_value = g_key_file_get_value(self->kf, self->group_name, key, &error);
-        if (error || !new_value || !nm_streq0(old_value, new_value))
-            got_dirty = TRUE;
-    }
-
-    if (got_dirty)
-        _got_dirty(self, key);
-}
-
-/*****************************************************************************/
-
-void
-nm_key_file_db_to_file(NMKeyFileDB *self, gboolean force)
-{
-    gs_free_error GError *error = NULL;
-
-    g_return_if_fail(_IS_KEY_FILE_DB(self, TRUE, FALSE));
-
-    if (!force && !self->dirty)
-        return;
-
-    self->dirty = FALSE;
-
-    if (!g_key_file_save_to_file(self->kf, self->filename, &error)) {
-        _LOGD("failure to write keyfile \"%s\": %s", self->filename, error->message);
-    } else
-        _LOGD("write keyfile: \"%s\"", self->filename);
-}
diff --git a/shared/nm-glib-aux/nm-keyfile-aux.h b/shared/nm-glib-aux/nm-keyfile-aux.h
deleted file mode 100644
index 72d2f418..00000000
--- a/shared/nm-glib-aux/nm-keyfile-aux.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019 Red Hat, Inc.
- */
-
-#ifndef __NM_KEYFILE_AUX_H__
-#define __NM_KEYFILE_AUX_H__
-
-/*****************************************************************************/
-
-typedef struct _NMKeyFileDB NMKeyFileDB;
-
-typedef void (*NMKeyFileDBLogFcn)(NMKeyFileDB *self,
-                                  int          syslog_level,
-                                  gpointer     user_data,
-                                  const char * fmt,
-                                  ...) G_GNUC_PRINTF(4, 5);
-
-typedef void (*NMKeyFileDBGotDirtyFcn)(NMKeyFileDB *self, gpointer user_data);
-
-NMKeyFileDB *nm_key_file_db_new(const char *           filename,
-                                const char *           group,
-                                NMKeyFileDBLogFcn      log_fcn,
-                                NMKeyFileDBGotDirtyFcn got_dirty_fcn,
-                                gpointer               user_data);
-
-void nm_key_file_db_start(NMKeyFileDB *self);
-
-NMKeyFileDB *nm_key_file_db_ref(NMKeyFileDB *self);
-void         nm_key_file_db_unref(NMKeyFileDB *self);
-
-void nm_key_file_db_destroy(NMKeyFileDB *self);
-
-const char *nm_key_file_db_get_filename(NMKeyFileDB *self);
-
-gboolean nm_key_file_db_is_dirty(NMKeyFileDB *self);
-
-char *nm_key_file_db_get_value(NMKeyFileDB *self, const char *key);
-
-char **nm_key_file_db_get_string_list(NMKeyFileDB *self, const char *key, gsize *out_len);
-
-void nm_key_file_db_remove_key(NMKeyFileDB *self, const char *key);
-
-void nm_key_file_db_set_value(NMKeyFileDB *self, const char *key, const char *value);
-
-void nm_key_file_db_set_string_list(NMKeyFileDB *      self,
-                                    const char *       key,
-                                    const char *const *value,
-                                    gssize             len);
-
-void nm_key_file_db_to_file(NMKeyFileDB *self, gboolean force);
-
-/*****************************************************************************/
-
-#endif /* __NM_KEYFILE_AUX_H__ */
diff --git a/shared/nm-glib-aux/nm-logging-base.c b/shared/nm-glib-aux/nm-logging-base.c
deleted file mode 100644
index 66b591b2..00000000
--- a/shared/nm-glib-aux/nm-logging-base.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-logging-base.h"
-
-#include <syslog.h>
-
-/*****************************************************************************/
-
-const LogLevelDesc level_desc[_LOGL_N] = {
-    [LOGL_TRACE] =
-        {
-            "TRACE",
-            "<trace>",
-            LOG_DEBUG,
-            G_LOG_LEVEL_DEBUG,
-        },
-    [LOGL_DEBUG] =
-        {
-            "DEBUG",
-            "<debug>",
-            LOG_DEBUG,
-            G_LOG_LEVEL_DEBUG,
-        },
-    [LOGL_INFO] =
-        {
-            "INFO",
-            "<info>",
-            LOG_INFO,
-            G_LOG_LEVEL_INFO,
-        },
-    [LOGL_WARN] =
-        {
-            "WARN",
-            "<warn>",
-            LOG_WARNING,
-            G_LOG_LEVEL_MESSAGE,
-        },
-    [LOGL_ERR] =
-        {
-            "ERR",
-            "<error>",
-            LOG_ERR,
-            G_LOG_LEVEL_MESSAGE,
-        },
-    [_LOGL_OFF] =
-        {
-            "OFF",
-            NULL,
-            0,
-            0,
-        },
-    [_LOGL_KEEP] =
-        {
-            "KEEP",
-            NULL,
-            0,
-            0,
-        },
-};
-
-gboolean
-_nm_log_parse_level(const char *level, NMLogLevel *out_level)
-{
-    int i;
-
-    if (!level)
-        return FALSE;
-
-    for (i = 0; i < (int) G_N_ELEMENTS(level_desc); i++) {
-        if (!g_ascii_strcasecmp(level_desc[i].name, level)) {
-            NM_SET_OUT(out_level, i);
-            return TRUE;
-        }
-    }
-
-    return FALSE;
-}
diff --git a/shared/nm-glib-aux/nm-logging-base.h b/shared/nm-glib-aux/nm-logging-base.h
deleted file mode 100644
index d9ac03c7..00000000
--- a/shared/nm-glib-aux/nm-logging-base.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef __NM_LOGGING_BASE_H__
-#define __NM_LOGGING_BASE_H__
-
-#include "nm-logging-fwd.h"
-
-typedef struct {
-    const char *name;
-    const char *level_str;
-
-    /* nm-logging uses syslog internally. Note that the three most-verbose syslog levels
-     * are LOG_DEBUG, LOG_INFO and LOG_NOTICE. Journal already highlights LOG_NOTICE
-     * as special.
-     *
-     * On the other hand, we have three levels LOGL_TRACE, LOGL_DEBUG and LOGL_INFO,
-     * which are regular messages not to be highlighted. For that reason, we must map
-     * LOGL_TRACE and LOGL_DEBUG both to syslog level LOG_DEBUG. */
-    int syslog_level;
-
-    GLogLevelFlags g_log_level;
-} LogLevelDesc;
-
-extern const LogLevelDesc level_desc[_LOGL_N];
-
-gboolean _nm_log_parse_level(const char *level, NMLogLevel *out_level);
-
-#endif /* __NM_LOGGING_BASE_H__ */
diff --git a/shared/nm-glib-aux/nm-logging-fwd.h b/shared/nm-glib-aux/nm-logging-fwd.h
deleted file mode 100644
index df0bb161..00000000
--- a/shared/nm-glib-aux/nm-logging-fwd.h
+++ /dev/null
@@ -1,308 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2006 - 2018 Red Hat, Inc.
- * Copyright (C) 2006 - 2008 Novell, Inc.
- */
-
-#ifndef __NM_LOGGING_FWD_H__
-#define __NM_LOGGING_FWD_H__
-
-/* Log domains */
-
-typedef enum { /*< skip >*/
-               LOGD_NONE       = 0LL,
-               LOGD_PLATFORM   = (1LL << 0), /* Platform services */
-               LOGD_RFKILL     = (1LL << 1),
-               LOGD_ETHER      = (1LL << 2),
-               LOGD_WIFI       = (1LL << 3),
-               LOGD_BT         = (1LL << 4),
-               LOGD_MB         = (1LL << 5), /* mobile broadband */
-               LOGD_DHCP4      = (1LL << 6),
-               LOGD_DHCP6      = (1LL << 7),
-               LOGD_PPP        = (1LL << 8),
-               LOGD_WIFI_SCAN  = (1LL << 9),
-               LOGD_IP4        = (1LL << 10),
-               LOGD_IP6        = (1LL << 11),
-               LOGD_AUTOIP4    = (1LL << 12),
-               LOGD_DNS        = (1LL << 13),
-               LOGD_VPN        = (1LL << 14),
-               LOGD_SHARING    = (1LL << 15), /* Connection sharing/dnsmasq */
-               LOGD_SUPPLICANT = (1LL << 16), /* Wi-Fi and 802.1x */
-               LOGD_AGENTS     = (1LL << 17), /* Secret agents */
-               LOGD_SETTINGS   = (1LL << 18), /* Settings */
-               LOGD_SUSPEND    = (1LL << 19), /* Suspend/Resume */
-               LOGD_CORE       = (1LL << 20), /* Core daemon and policy stuff */
-               LOGD_DEVICE     = (1LL << 21), /* Device state and activation */
-               LOGD_OLPC       = (1LL << 22),
-               LOGD_INFINIBAND = (1LL << 23),
-               LOGD_FIREWALL   = (1LL << 24),
-               LOGD_ADSL       = (1LL << 25),
-               LOGD_BOND       = (1LL << 26),
-               LOGD_VLAN       = (1LL << 27),
-               LOGD_BRIDGE     = (1LL << 28),
-               LOGD_DBUS_PROPS = (1LL << 29),
-               LOGD_TEAM       = (1LL << 30),
-               LOGD_CONCHECK   = (1LL << 31),
-               LOGD_DCB        = (1LL << 32), /* Data Center Bridging */
-               LOGD_DISPATCH   = (1LL << 33),
-               LOGD_AUDIT      = (1LL << 34),
-               LOGD_SYSTEMD    = (1LL << 35),
-               LOGD_VPN_PLUGIN = (1LL << 36),
-               LOGD_PROXY      = (1LL << 37),
-
-               __LOGD_MAX,
-               LOGD_ALL     = (((__LOGD_MAX - 1LL) << 1) - 1LL),
-               LOGD_DEFAULT = LOGD_ALL & ~(LOGD_DBUS_PROPS | LOGD_WIFI_SCAN | LOGD_VPN_PLUGIN | 0),
-
-               /* aliases: */
-               LOGD_DHCP = LOGD_DHCP4 | LOGD_DHCP6,
-               LOGD_IP   = LOGD_IP4 | LOGD_IP6,
-
-#define LOGD_DHCPX(is_ipv4) ((is_ipv4) ? LOGD_DHCP4 : LOGD_DHCP6)
-#define LOGD_IPX(is_ipv4)   ((is_ipv4) ? LOGD_IP4 : LOGD_IP6)
-
-} NMLogDomain;
-
-/* Log levels */
-typedef enum { /*< skip >*/
-               LOGL_TRACE,
-               LOGL_DEBUG,
-               LOGL_INFO,
-               LOGL_WARN,
-               LOGL_ERR,
-
-               _LOGL_N_REAL, /* the number of actual logging levels */
-
-               _LOGL_OFF = _LOGL_N_REAL, /* special logging level that is always disabled. */
-               _LOGL_KEEP, /* special logging level to indicate that the logging level should not be changed. */
-
-               _LOGL_N, /* the number of logging levels including "OFF" */
-} NMLogLevel;
-
-gboolean _nm_log_enabled_impl(gboolean mt_require_locking, NMLogLevel level, NMLogDomain domain);
-
-void _nm_log_impl(const char *file,
-                  guint       line,
-                  const char *func,
-                  gboolean    mt_require_locking,
-                  NMLogLevel  level,
-                  NMLogDomain domain,
-                  int         error,
-                  const char *ifname,
-                  const char *con_uuid,
-                  const char *fmt,
-                  ...) _nm_printf(10, 11);
-
-static inline NMLogLevel
-nm_log_level_from_syslog(int syslog_level)
-{
-    switch (syslog_level) {
-    case 0 /* LOG_EMERG */:
-        return LOGL_ERR;
-    case 1 /* LOG_ALERT */:
-        return LOGL_ERR;
-    case 2 /* LOG_CRIT */:
-        return LOGL_ERR;
-    case 3 /* LOG_ERR */:
-        return LOGL_ERR;
-    case 4 /* LOG_WARNING */:
-        return LOGL_WARN;
-    case 5 /* LOG_NOTICE */:
-        return LOGL_INFO;
-    case 6 /* LOG_INFO */:
-        return LOGL_DEBUG;
-    case 7 /* LOG_DEBUG */:
-        return LOGL_TRACE;
-    default:
-        return syslog_level >= 0 ? LOGL_TRACE : LOGL_ERR;
-    }
-}
-
-static inline int
-nm_log_level_to_syslog(NMLogLevel nm_level)
-{
-    switch (nm_level) {
-    case LOGL_ERR:
-        return 3; /* LOG_ERR */
-    case LOGL_WARN:
-        return 4; /* LOG_WARN */
-    case LOGL_INFO:
-        return 5; /* LOG_NOTICE */
-    case LOGL_DEBUG:
-        return 6; /* LOG_INFO */
-    case LOGL_TRACE:
-        return 7; /* LOG_DEBUG */
-    default:
-        return 0; /* LOG_EMERG */
-    }
-}
-
-/*****************************************************************************/
-
-struct timespec;
-
-/* this function must be implemented to handle the notification when
- * the first monotonic-timestamp is fetched. */
-extern void _nm_utils_monotonic_timestamp_initialized(const struct timespec *tp,
-                                                      gint64                 offset_sec,
-                                                      gboolean               is_boottime);
-
-/*****************************************************************************/
-
-#define _LOGL_TRACE LOGL_TRACE
-#define _LOGL_DEBUG LOGL_DEBUG
-#define _LOGL_INFO  LOGL_INFO
-#define _LOGL_WARN  LOGL_WARN
-#define _LOGL_ERR   LOGL_ERR
-
-/* This is the default definition of _NMLOG_ENABLED(). Special implementations
- * might want to undef this and redefine it. */
-#define _NMLOG_ENABLED(level) (nm_logging_enabled((level), (_NMLOG_DOMAIN)))
-
-#define _LOGT(...) _NMLOG(_LOGL_TRACE, __VA_ARGS__)
-#define _LOGD(...) _NMLOG(_LOGL_DEBUG, __VA_ARGS__)
-#define _LOGI(...) _NMLOG(_LOGL_INFO, __VA_ARGS__)
-#define _LOGW(...) _NMLOG(_LOGL_WARN, __VA_ARGS__)
-#define _LOGE(...) _NMLOG(_LOGL_ERR, __VA_ARGS__)
-
-#define _LOGT_ENABLED(...) _NMLOG_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
-#define _LOGD_ENABLED(...) _NMLOG_ENABLED(_LOGL_DEBUG, ##__VA_ARGS__)
-#define _LOGI_ENABLED(...) _NMLOG_ENABLED(_LOGL_INFO, ##__VA_ARGS__)
-#define _LOGW_ENABLED(...) _NMLOG_ENABLED(_LOGL_WARN, ##__VA_ARGS__)
-#define _LOGE_ENABLED(...) _NMLOG_ENABLED(_LOGL_ERR, ##__VA_ARGS__)
-
-#define _LOGT_err(errsv, ...) _NMLOG_err(errsv, _LOGL_TRACE, __VA_ARGS__)
-#define _LOGD_err(errsv, ...) _NMLOG_err(errsv, _LOGL_DEBUG, __VA_ARGS__)
-#define _LOGI_err(errsv, ...) _NMLOG_err(errsv, _LOGL_INFO, __VA_ARGS__)
-#define _LOGW_err(errsv, ...) _NMLOG_err(errsv, _LOGL_WARN, __VA_ARGS__)
-#define _LOGE_err(errsv, ...) _NMLOG_err(errsv, _LOGL_ERR, __VA_ARGS__)
-
-/* _LOGT() and _LOGt() both log with level TRACE, but the latter is disabled by default,
- * unless building with --with-more-logging. */
-#if NM_MORE_LOGGING
-    #define _LOGt_ENABLED(...)    _NMLOG_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
-    #define _LOGt(...)            _NMLOG(_LOGL_TRACE, __VA_ARGS__)
-    #define _LOGt_err(errsv, ...) _NMLOG_err(errsv, _LOGL_TRACE, __VA_ARGS__)
-#else
-    /* still call the logging macros to get compile time checks, but they will be optimized out. */
-    #define _LOGt_ENABLED(...) (FALSE && (_NMLOG_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)))
-    #define _LOGt(...)                            \
-        G_STMT_START                              \
-        {                                         \
-            if (FALSE) {                          \
-                _NMLOG(_LOGL_TRACE, __VA_ARGS__); \
-            }                                     \
-        }                                         \
-        G_STMT_END
-    #define _LOGt_err(errsv, ...)                            \
-        G_STMT_START                                         \
-        {                                                    \
-            if (FALSE) {                                     \
-                _NMLOG_err(errsv, _LOGL_TRACE, __VA_ARGS__); \
-            }                                                \
-        }                                                    \
-        G_STMT_END
-#endif
-
-/*****************************************************************************/
-
-/* Some implementation define a second set of logging macros, for a separate
- * use. As with the _LOGD() macro family above, the exact implementation
- * depends on the file that uses them.
- * Still, it encourages a common pattern to have the common set of macros
- * like _LOG2D(), _LOG2I(), etc. and have _LOG2t() which by default
- * is disabled at compile time. */
-
-#define _NMLOG2_ENABLED(level) (nm_logging_enabled((level), (_NMLOG2_DOMAIN)))
-
-#define _LOG2T(...) _NMLOG2(_LOGL_TRACE, __VA_ARGS__)
-#define _LOG2D(...) _NMLOG2(_LOGL_DEBUG, __VA_ARGS__)
-#define _LOG2I(...) _NMLOG2(_LOGL_INFO, __VA_ARGS__)
-#define _LOG2W(...) _NMLOG2(_LOGL_WARN, __VA_ARGS__)
-#define _LOG2E(...) _NMLOG2(_LOGL_ERR, __VA_ARGS__)
-
-#define _LOG2T_ENABLED(...) _NMLOG2_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
-#define _LOG2D_ENABLED(...) _NMLOG2_ENABLED(_LOGL_DEBUG, ##__VA_ARGS__)
-#define _LOG2I_ENABLED(...) _NMLOG2_ENABLED(_LOGL_INFO, ##__VA_ARGS__)
-#define _LOG2W_ENABLED(...) _NMLOG2_ENABLED(_LOGL_WARN, ##__VA_ARGS__)
-#define _LOG2E_ENABLED(...) _NMLOG2_ENABLED(_LOGL_ERR, ##__VA_ARGS__)
-
-#define _LOG2T_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_TRACE, __VA_ARGS__)
-#define _LOG2D_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_DEBUG, __VA_ARGS__)
-#define _LOG2I_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_INFO, __VA_ARGS__)
-#define _LOG2W_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_WARN, __VA_ARGS__)
-#define _LOG2E_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_ERR, __VA_ARGS__)
-
-#if NM_MORE_LOGGING
-    #define _LOG2t_ENABLED(...)    _NMLOG2_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
-    #define _LOG2t(...)            _NMLOG2(_LOGL_TRACE, __VA_ARGS__)
-    #define _LOG2t_err(errsv, ...) _NMLOG2_err(errsv, _LOGL_TRACE, __VA_ARGS__)
-#else
-    /* still call the logging macros to get compile time checks, but they will be optimized out. */
-    #define _LOG2t_ENABLED(...) (FALSE && (_NMLOG2_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)))
-    #define _LOG2t(...)                            \
-        G_STMT_START                               \
-        {                                          \
-            if (FALSE) {                           \
-                _NMLOG2(_LOGL_TRACE, __VA_ARGS__); \
-            }                                      \
-        }                                          \
-        G_STMT_END
-    #define _LOG2t_err(errsv, ...)                            \
-        G_STMT_START                                          \
-        {                                                     \
-            if (FALSE) {                                      \
-                _NMLOG2_err(errsv, _LOGL_TRACE, __VA_ARGS__); \
-            }                                                 \
-        }                                                     \
-        G_STMT_END
-#endif
-
-#define _NMLOG3_ENABLED(level) (nm_logging_enabled((level), (_NMLOG3_DOMAIN)))
-
-#define _LOG3T(...) _NMLOG3(_LOGL_TRACE, __VA_ARGS__)
-#define _LOG3D(...) _NMLOG3(_LOGL_DEBUG, __VA_ARGS__)
-#define _LOG3I(...) _NMLOG3(_LOGL_INFO, __VA_ARGS__)
-#define _LOG3W(...) _NMLOG3(_LOGL_WARN, __VA_ARGS__)
-#define _LOG3E(...) _NMLOG3(_LOGL_ERR, __VA_ARGS__)
-
-#define _LOG3T_ENABLED(...) _NMLOG3_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
-#define _LOG3D_ENABLED(...) _NMLOG3_ENABLED(_LOGL_DEBUG, ##__VA_ARGS__)
-#define _LOG3I_ENABLED(...) _NMLOG3_ENABLED(_LOGL_INFO, ##__VA_ARGS__)
-#define _LOG3W_ENABLED(...) _NMLOG3_ENABLED(_LOGL_WARN, ##__VA_ARGS__)
-#define _LOG3E_ENABLED(...) _NMLOG3_ENABLED(_LOGL_ERR, ##__VA_ARGS__)
-
-#define _LOG3T_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_TRACE, __VA_ARGS__)
-#define _LOG3D_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_DEBUG, __VA_ARGS__)
-#define _LOG3I_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_INFO, __VA_ARGS__)
-#define _LOG3W_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_WARN, __VA_ARGS__)
-#define _LOG3E_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_ERR, __VA_ARGS__)
-
-#if NM_MORE_LOGGING
-    #define _LOG3t_ENABLED(...)    _NMLOG3_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)
-    #define _LOG3t(...)            _NMLOG3(_LOGL_TRACE, __VA_ARGS__)
-    #define _LOG3t_err(errsv, ...) _NMLOG3_err(errsv, _LOGL_TRACE, __VA_ARGS__)
-#else
-    /* still call the logging macros to get compile time checks, but they will be optimized out. */
-    #define _LOG3t_ENABLED(...) (FALSE && (_NMLOG3_ENABLED(_LOGL_TRACE, ##__VA_ARGS__)))
-    #define _LOG3t(...)                            \
-        G_STMT_START                               \
-        {                                          \
-            if (FALSE) {                           \
-                _NMLOG3(_LOGL_TRACE, __VA_ARGS__); \
-            }                                      \
-        }                                          \
-        G_STMT_END
-    #define _LOG3t_err(errsv, ...)                            \
-        G_STMT_START                                          \
-        {                                                     \
-            if (FALSE) {                                      \
-                _NMLOG3_err(errsv, _LOGL_TRACE, __VA_ARGS__); \
-            }                                                 \
-        }                                                     \
-        G_STMT_END
-#endif
-
-/*****************************************************************************/
-
-#endif /* __NM_LOGGING_FWD_H__ */
diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h
deleted file mode 100644
index 6f63f204..00000000
--- a/shared/nm-glib-aux/nm-macros-internal.h
+++ /dev/null
@@ -1,1824 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2012 Colin Walters <walters@verbum.org>.
- * Copyright (C) 2014 Red Hat, Inc.
- */
-
-#ifndef __NM_MACROS_INTERNAL_H__
-#define __NM_MACROS_INTERNAL_H__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-
-#include <gio/gio.h>
-
-/*****************************************************************************/
-
-/* most of our code is single-threaded with a mainloop. Hence, we usually don't need
- * any thread-safety. Sometimes, we do need thread-safety (nm-logging), but we can
- * avoid locking if we are on the main-thread by:
- *
- *   - modifications of shared data is done infrequently and only from the
- *     main-thread (nm_logging_setup())
- *   - read-only access is done frequently (nm_logging_enabled())
- *     - from the main-thread, we can do that without locking (because
- *       all modifications are also done on the main thread.
- *     - from other threads, we need locking. But this is expected to be
- *       done infrequently too. Important is the lock-free fast-path on the
- *       main-thread.
- *
- * By defining NM_THREAD_SAFE_ON_MAIN_THREAD you indicate that this code runs
- * on the main-thread. It is by default defined to "1". If you have code that
- * is also used on another thread, redefine the define to 0 (to opt in into
- * the slow-path).
- */
-#define NM_THREAD_SAFE_ON_MAIN_THREAD 1
-
-/*****************************************************************************/
-
-#include "nm-glib.h"
-
-/*****************************************************************************/
-
-#define nm_offsetofend(t, m) (G_STRUCT_OFFSET(t, m) + sizeof(((t *) NULL)->m))
-
-/*****************************************************************************/
-
-#define gs_free            nm_auto_g_free
-#define gs_unref_object    nm_auto_unref_object
-#define gs_unref_variant   nm_auto_unref_variant
-#define gs_unref_array     nm_auto_unref_array
-#define gs_unref_ptrarray  nm_auto_unref_ptrarray
-#define gs_unref_hashtable nm_auto_unref_hashtable
-#define gs_unref_bytes     nm_auto_unref_bytes
-#define gs_strfreev        nm_auto_strfreev
-#define gs_free_error      nm_auto_free_error
-
-/*****************************************************************************/
-
-NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_g_free, g_free);
-#define nm_auto_g_free nm_auto(_nm_auto_g_free)
-
-NM_AUTO_DEFINE_FCN_VOID0(GObject *, _nm_auto_unref_object, g_object_unref);
-#define nm_auto_unref_object nm_auto(_nm_auto_unref_object)
-
-NM_AUTO_DEFINE_FCN0(GVariant *, _nm_auto_unref_variant, g_variant_unref);
-#define nm_auto_unref_variant nm_auto(_nm_auto_unref_variant)
-
-NM_AUTO_DEFINE_FCN0(GArray *, _nm_auto_unref_array, g_array_unref);
-#define nm_auto_unref_array nm_auto(_nm_auto_unref_array)
-
-NM_AUTO_DEFINE_FCN0(GPtrArray *, _nm_auto_unref_ptrarray, g_ptr_array_unref);
-#define nm_auto_unref_ptrarray nm_auto(_nm_auto_unref_ptrarray)
-
-NM_AUTO_DEFINE_FCN0(GHashTable *, _nm_auto_unref_hashtable, g_hash_table_unref);
-#define nm_auto_unref_hashtable nm_auto(_nm_auto_unref_hashtable)
-
-NM_AUTO_DEFINE_FCN0(GSList *, _nm_auto_free_slist, g_slist_free);
-#define nm_auto_free_slist nm_auto(_nm_auto_free_slist)
-
-NM_AUTO_DEFINE_FCN0(GBytes *, _nm_auto_unref_bytes, g_bytes_unref);
-#define nm_auto_unref_bytes nm_auto(_nm_auto_unref_bytes)
-
-NM_AUTO_DEFINE_FCN0(char **, _nm_auto_strfreev, g_strfreev);
-#define nm_auto_strfreev nm_auto(_nm_auto_strfreev)
-
-NM_AUTO_DEFINE_FCN0(GError *, _nm_auto_free_error, g_error_free);
-#define nm_auto_free_error nm_auto(_nm_auto_free_error)
-
-NM_AUTO_DEFINE_FCN0(GKeyFile *, _nm_auto_unref_keyfile, g_key_file_unref);
-#define nm_auto_unref_keyfile nm_auto(_nm_auto_unref_keyfile)
-
-NM_AUTO_DEFINE_FCN0(GVariantIter *, _nm_auto_free_variant_iter, g_variant_iter_free);
-#define nm_auto_free_variant_iter nm_auto(_nm_auto_free_variant_iter)
-
-NM_AUTO_DEFINE_FCN0(GVariantBuilder *, _nm_auto_unref_variant_builder, g_variant_builder_unref);
-#define nm_auto_unref_variant_builder nm_auto(_nm_auto_unref_variant_builder)
-
-#define nm_auto_clear_variant_builder nm_auto(g_variant_builder_clear)
-
-NM_AUTO_DEFINE_FCN0(GList *, _nm_auto_free_list, g_list_free);
-#define nm_auto_free_list nm_auto(_nm_auto_free_list)
-
-NM_AUTO_DEFINE_FCN0(GChecksum *, _nm_auto_checksum_free, g_checksum_free);
-#define nm_auto_free_checksum nm_auto(_nm_auto_checksum_free)
-
-#define nm_auto_unset_gvalue nm_auto(g_value_unset)
-
-NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_unref_gtypeclass, g_type_class_unref);
-#define nm_auto_unref_gtypeclass nm_auto(_nm_auto_unref_gtypeclass)
-
-NM_AUTO_DEFINE_FCN0(GByteArray *, _nm_auto_unref_bytearray, g_byte_array_unref);
-#define nm_auto_unref_bytearray nm_auto(_nm_auto_unref_bytearray)
-
-static inline void
-_nm_auto_free_gstring(GString **str)
-{
-    if (*str)
-        g_string_free(*str, TRUE);
-}
-#define nm_auto_free_gstring nm_auto(_nm_auto_free_gstring)
-
-NM_AUTO_DEFINE_FCN0(GSource *, _nm_auto_unref_gsource, g_source_unref);
-#define nm_auto_unref_gsource nm_auto(_nm_auto_unref_gsource)
-
-NM_AUTO_DEFINE_FCN0(guint, _nm_auto_remove_source, g_source_remove);
-#define nm_auto_remove_source nm_auto(_nm_auto_remove_source)
-
-NM_AUTO_DEFINE_FCN0(GIOChannel *, _nm_auto_unref_io_channel, g_io_channel_unref);
-#define nm_auto_unref_io_channel nm_auto(_nm_auto_unref_io_channel)
-
-NM_AUTO_DEFINE_FCN0(GMainLoop *, _nm_auto_unref_gmainloop, g_main_loop_unref);
-#define nm_auto_unref_gmainloop nm_auto(_nm_auto_unref_gmainloop)
-
-NM_AUTO_DEFINE_FCN0(GOptionContext *, _nm_auto_free_option_context, g_option_context_free);
-#define nm_auto_free_option_context nm_auto(_nm_auto_free_option_context)
-
-static inline void
-_nm_auto_freev(gpointer ptr)
-{
-    gpointer **p = ptr;
-    gpointer * _ptr;
-
-    if (*p) {
-        for (_ptr = *p; *_ptr; _ptr++)
-            g_free(*_ptr);
-        g_free(*p);
-    }
-}
-/* g_free a NULL terminated array of pointers, with also freeing each
- * pointer with g_free(). It essentially does the same as
- * gs_strfreev / g_strfreev(), but not restricted to strv arrays. */
-#define nm_auto_freev nm_auto(_nm_auto_freev)
-
-/*****************************************************************************/
-
-#define _NM_MACRO_SELECT_ARG_64(_1,  \
-                                _2,  \
-                                _3,  \
-                                _4,  \
-                                _5,  \
-                                _6,  \
-                                _7,  \
-                                _8,  \
-                                _9,  \
-                                _10, \
-                                _11, \
-                                _12, \
-                                _13, \
-                                _14, \
-                                _15, \
-                                _16, \
-                                _17, \
-                                _18, \
-                                _19, \
-                                _20, \
-                                _21, \
-                                _22, \
-                                _23, \
-                                _24, \
-                                _25, \
-                                _26, \
-                                _27, \
-                                _28, \
-                                _29, \
-                                _30, \
-                                _31, \
-                                _32, \
-                                _33, \
-                                _34, \
-                                _35, \
-                                _36, \
-                                _37, \
-                                _38, \
-                                _39, \
-                                _40, \
-                                _41, \
-                                _42, \
-                                _43, \
-                                _44, \
-                                _45, \
-                                _46, \
-                                _47, \
-                                _48, \
-                                _49, \
-                                _50, \
-                                _51, \
-                                _52, \
-                                _53, \
-                                _54, \
-                                _55, \
-                                _56, \
-                                _57, \
-                                _58, \
-                                _59, \
-                                _60, \
-                                _61, \
-                                _62, \
-                                _63, \
-                                N,   \
-                                ...) \
-    N
-
-/* http://stackoverflow.com/a/2124385/354393
- * https://stackoverflow.com/questions/11317474/macro-to-count-number-of-arguments
- */
-
-#define NM_NARG(...)                       \
-    _NM_MACRO_SELECT_ARG_64(,              \
-                            ##__VA_ARGS__, \
-                            62,            \
-                            61,            \
-                            60,            \
-                            59,            \
-                            58,            \
-                            57,            \
-                            56,            \
-                            55,            \
-                            54,            \
-                            53,            \
-                            52,            \
-                            51,            \
-                            50,            \
-                            49,            \
-                            48,            \
-                            47,            \
-                            46,            \
-                            45,            \
-                            44,            \
-                            43,            \
-                            42,            \
-                            41,            \
-                            40,            \
-                            39,            \
-                            38,            \
-                            37,            \
-                            36,            \
-                            35,            \
-                            34,            \
-                            33,            \
-                            32,            \
-                            31,            \
-                            30,            \
-                            29,            \
-                            28,            \
-                            27,            \
-                            26,            \
-                            25,            \
-                            24,            \
-                            23,            \
-                            22,            \
-                            21,            \
-                            20,            \
-                            19,            \
-                            18,            \
-                            17,            \
-                            16,            \
-                            15,            \
-                            14,            \
-                            13,            \
-                            12,            \
-                            11,            \
-                            10,            \
-                            9,             \
-                            8,             \
-                            7,             \
-                            6,             \
-                            5,             \
-                            4,             \
-                            3,             \
-                            2,             \
-                            1,             \
-                            0)
-#define NM_NARG_MAX1(...)                  \
-    _NM_MACRO_SELECT_ARG_64(,              \
-                            ##__VA_ARGS__, \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            1,             \
-                            0)
-#define NM_NARG_MAX2(...)                  \
-    _NM_MACRO_SELECT_ARG_64(,              \
-                            ##__VA_ARGS__, \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            2,             \
-                            1,             \
-                            0)
-
-#define _NM_MACRO_CALL(macro, ...) macro(__VA_ARGS__)
-
-/*****************************************************************************/
-
-#define _NM_MACRO_COMMA_IF_ARGS(...) \
-    _NM_MACRO_CALL(G_PASTE(__NM_MACRO_COMMA_IF_ARGS_, NM_NARG_MAX1(__VA_ARGS__)), __VA_ARGS__)
-#define __NM_MACRO_COMMA_IF_ARGS_0()
-#define __NM_MACRO_COMMA_IF_ARGS_1(...) ,
-
-/*****************************************************************************/
-
-/* http://stackoverflow.com/a/11172679 */
-#define _NM_UTILS_MACRO_FIRST(...)                __NM_UTILS_MACRO_FIRST_HELPER(__VA_ARGS__, throwaway)
-#define __NM_UTILS_MACRO_FIRST_HELPER(first, ...) first
-
-#define _NM_UTILS_MACRO_REST(...) \
-    _NM_MACRO_CALL(G_PASTE(__NM_UTILS_MACRO_REST_, NM_NARG_MAX2(__VA_ARGS__)), __VA_ARGS__)
-#define __NM_UTILS_MACRO_REST_0()
-#define __NM_UTILS_MACRO_REST_1(first)
-#define __NM_UTILS_MACRO_REST_2(first, ...) , __VA_ARGS__
-
-/*****************************************************************************/
-
-#if defined(__GNUC__)
-    #define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(GCC diagnostic ignored warning)
-#elif defined(__clang__)
-    #define _NM_PRAGMA_WARNING_DO(warning) G_STRINGIFY(clang diagnostic ignored warning)
-#endif
-
-/* you can only suppress a specific warning that the compiler
- * understands. Otherwise you will get another compiler warning
- * about invalid pragma option.
- * It's not that bad however, because gcc and clang often have the
- * same name for the same warning. */
-
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-    #define NM_PRAGMA_WARNING_DISABLE(warning) \
-        _Pragma("GCC diagnostic push") _Pragma(_NM_PRAGMA_WARNING_DO(warning))
-#elif defined(__clang__)
-    #define NM_PRAGMA_WARNING_DISABLE(warning)                         \
-        _Pragma("clang diagnostic push")                               \
-            _Pragma(_NM_PRAGMA_WARNING_DO("-Wunknown-warning-option")) \
-                _Pragma(_NM_PRAGMA_WARNING_DO(warning))
-#else
-    #define NM_PRAGMA_WARNING_DISABLE(warning)
-#endif
-
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-    #define NM_PRAGMA_WARNING_REENABLE _Pragma("GCC diagnostic pop")
-#elif defined(__clang__)
-    #define NM_PRAGMA_WARNING_REENABLE _Pragma("clang diagnostic pop")
-#else
-    #define NM_PRAGMA_WARNING_REENABLE
-#endif
-
-/*****************************************************************************/
-
-/**
- * NM_G_ERROR_MSG:
- * @error: (allow-none): the #GError instance
- *
- * All functions must follow the convention that when they
- * return a failure, they must also set the GError to a valid
- * message. For external API however, we want to be extra
- * careful before accessing the error instance. Use NM_G_ERROR_MSG()
- * which is safe to use on NULL.
- *
- * Returns: the error message.
- **/
-static inline const char *
-NM_G_ERROR_MSG(GError *error)
-{
-    return error ? (error->message ?: "(null)") : "(no-error)";
-}
-
-/*****************************************************************************/
-
-#ifndef _NM_CC_SUPPORT_AUTO_TYPE
-    #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)))
-        #define _NM_CC_SUPPORT_AUTO_TYPE 1
-    #else
-        #define _NM_CC_SUPPORT_AUTO_TYPE 0
-    #endif
-#endif
-
-#ifndef _NM_CC_SUPPORT_GENERIC
-    /* In the meantime, NetworkManager requires C11 and _Generic() should always be available.
- * However, shared/nm-utils may also be used in VPN/applet, which possibly did not yet
- * bump the C standard requirement. Leave this for the moment, but eventually we can
- * drop it. */
-    #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))) \
-        || (defined(__clang__))
-        #define _NM_CC_SUPPORT_GENERIC 1
-    #else
-        #define _NM_CC_SUPPORT_GENERIC 0
-    #endif
-#endif
-
-#if _NM_CC_SUPPORT_AUTO_TYPE
-    #define _nm_auto_type __auto_type
-#endif
-
-#if _NM_CC_SUPPORT_GENERIC
-    #define _NM_CONSTCAST_FULL_1(type, obj_expr, obj) \
-        (_Generic ((obj_expr), \
-               const void        *const: ((const type *) (obj)), \
-               const void        *     : ((const type *) (obj)), \
-                     void        *const: ((      type *) (obj)), \
-                     void        *     : ((      type *) (obj)), \
-               const type        *const: ((const type *) (obj)), \
-               const type        *     : ((const type *) (obj)), \
-                     type        *const: ((      type *) (obj)), \
-                     type        *     : ((      type *) (obj))))
-    #define _NM_CONSTCAST_FULL_2(type, obj_expr, obj, alias_type2) \
-        (_Generic ((obj_expr), \
-               const void        *const: ((const type *) (obj)), \
-               const void        *     : ((const type *) (obj)), \
-                     void        *const: ((      type *) (obj)), \
-                     void        *     : ((      type *) (obj)), \
-               const alias_type2 *const: ((const type *) (obj)), \
-               const alias_type2 *     : ((const type *) (obj)), \
-                     alias_type2 *const: ((      type *) (obj)), \
-                     alias_type2 *     : ((      type *) (obj)), \
-               const type        *const: ((const type *) (obj)), \
-               const type        *     : ((const type *) (obj)), \
-                     type        *const: ((      type *) (obj)), \
-                     type        *     : ((      type *) (obj))))
-    #define _NM_CONSTCAST_FULL_3(type, obj_expr, obj, alias_type2, alias_type3) \
-        (_Generic ((obj_expr), \
-               const void        *const: ((const type *) (obj)), \
-               const void        *     : ((const type *) (obj)), \
-                     void        *const: ((      type *) (obj)), \
-                     void        *     : ((      type *) (obj)), \
-               const alias_type2 *const: ((const type *) (obj)), \
-               const alias_type2 *     : ((const type *) (obj)), \
-                     alias_type2 *const: ((      type *) (obj)), \
-                     alias_type2 *     : ((      type *) (obj)), \
-               const alias_type3 *const: ((const type *) (obj)), \
-               const alias_type3 *     : ((const type *) (obj)), \
-                     alias_type3 *const: ((      type *) (obj)), \
-                     alias_type3 *     : ((      type *) (obj)), \
-               const type        *const: ((const type *) (obj)), \
-               const type        *     : ((const type *) (obj)), \
-                     type        *const: ((      type *) (obj)), \
-                     type        *     : ((      type *) (obj))))
-    #define _NM_CONSTCAST_FULL_4(type, obj_expr, obj, alias_type2, alias_type3, alias_type4) \
-        (_Generic ((obj_expr), \
-               const void        *const: ((const type *) (obj)), \
-               const void        *     : ((const type *) (obj)), \
-                     void        *const: ((      type *) (obj)), \
-                     void        *     : ((      type *) (obj)), \
-               const alias_type2 *const: ((const type *) (obj)), \
-               const alias_type2 *     : ((const type *) (obj)), \
-                     alias_type2 *const: ((      type *) (obj)), \
-                     alias_type2 *     : ((      type *) (obj)), \
-               const alias_type3 *const: ((const type *) (obj)), \
-               const alias_type3 *     : ((const type *) (obj)), \
-                     alias_type3 *const: ((      type *) (obj)), \
-                     alias_type3 *     : ((      type *) (obj)), \
-               const alias_type4 *const: ((const type *) (obj)), \
-               const alias_type4 *     : ((const type *) (obj)), \
-                     alias_type4 *const: ((      type *) (obj)), \
-                     alias_type4 *     : ((      type *) (obj)), \
-               const type        *const: ((const type *) (obj)), \
-               const type        *     : ((const type *) (obj)), \
-                     type        *const: ((      type *) (obj)), \
-                     type        *     : ((      type *) (obj))))
-    #define _NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ...) \
-        (_NM_CONSTCAST_FULL_##n(type, obj_expr, obj, ##__VA_ARGS__))
-    #define _NM_CONSTCAST_FULL_y(type, obj_expr, obj, n, ...) \
-        (_NM_CONSTCAST_FULL_x(type, obj_expr, obj, n, ##__VA_ARGS__))
-    #define NM_CONSTCAST_FULL(type, obj_expr, obj, ...) \
-        (_NM_CONSTCAST_FULL_y(type, obj_expr, obj, NM_NARG(dummy, ##__VA_ARGS__), ##__VA_ARGS__))
-#else
-    #define NM_CONSTCAST_FULL(type, obj_expr, obj, ...) ((type *) (obj))
-#endif
-
-#define NM_CONSTCAST(type, obj, ...) NM_CONSTCAST_FULL(type, (obj), (obj), ##__VA_ARGS__)
-
-#if _NM_CC_SUPPORT_GENERIC
-    #define NM_UNCONST_PTR(type, arg) \
-        _Generic((arg), const type * : ((type *) (arg)), type * : ((type *) (arg)))
-#else
-    #define NM_UNCONST_PTR(type, arg) ((type *) (arg))
-#endif
-
-#if _NM_CC_SUPPORT_GENERIC
-    #define NM_UNCONST_PPTR(type, arg) \
-        _Generic ((arg), \
-              const type *     *: ((type **) (arg)), \
-                    type *     *: ((type **) (arg)), \
-              const type *const*: ((type **) (arg)), \
-                    type *const*: ((type **) (arg)))
-#else
-    #define NM_UNCONST_PPTR(type, arg) ((type **) (arg))
-#endif
-
-#define NM_GOBJECT_CAST(type, obj, is_check, ...)                     \
-    ({                                                                \
-        const void *_obj = (obj);                                     \
-                                                                      \
-        nm_assert(_obj || (is_check(_obj)));                          \
-        NM_CONSTCAST_FULL(type, (obj), _obj, GObject, ##__VA_ARGS__); \
-    })
-
-#define NM_GOBJECT_CAST_NON_NULL(type, obj, is_check, ...)            \
-    ({                                                                \
-        const void *_obj = (obj);                                     \
-                                                                      \
-        nm_assert(is_check(_obj));                                    \
-        NM_CONSTCAST_FULL(type, (obj), _obj, GObject, ##__VA_ARGS__); \
-    })
-
-#define NM_ENSURE_NOT_NULL(ptr)   \
-    ({                            \
-        typeof(ptr) _ptr = (ptr); \
-                                  \
-        nm_assert(_ptr != NULL);  \
-        _ptr;                     \
-    })
-
-#if _NM_CC_SUPPORT_GENERIC
-    /* returns @value, if the type of @value matches @type.
-     * This requires support for C11 _Generic(). If no support is
-     * present, this returns @value directly.
-     *
-     * It's useful to check the let the compiler ensure that @value is
-     * of a certain type. */
-    #define _NM_ENSURE_TYPE(type, value) (_Generic((value), type : (value)))
-    #define _NM_ENSURE_TYPE_CONST(type, value)              \
-        (_Generic((value), const type                       \
-                  : ((const type)(value)), const type const \
-                  : ((const type)(value)), type             \
-                  : ((const type)(value)), type const       \
-                  : ((const type)(value))))
-#else
-    #define _NM_ENSURE_TYPE(type, value)       (value)
-    #define _NM_ENSURE_TYPE_CONST(type, value) ((const type)(value))
-#endif
-
-#if _NM_CC_SUPPORT_GENERIC && (!defined(__clang__) || __clang_major__ > 3)
-    #define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) \
-        (_Generic((&(((container *) NULL)->field))[0], type : G_STRUCT_OFFSET(container, field)))
-#else
-    #define NM_STRUCT_OFFSET_ENSURE_TYPE(type, container, field) G_STRUCT_OFFSET(container, field)
-#endif
-
-#if _NM_CC_SUPPORT_GENERIC
-    /* these macros cast (value) to
- *  - "const char **"      (for "MC", mutable-const)
- *  - "const char *const*" (for "CC", const-const)
- * The point is to do this cast, but only accepting pointers
- * that are compatible already.
- *
- * The problem is, if you add a function like g_strdupv(), the input
- * argument is not modified (CC), but you want to make it work also
- * for "char **". C doesn't allow this form of casting (for good reasons),
- * so the function makes a choice like g_strdupv(char**). That means,
- * every time you want to call it with a const argument, you need to
- * explicitly cast it.
- *
- * These macros do the cast, but they only accept a compatible input
- * type, otherwise they will fail compilation.
- */
-    #define NM_CAST_STRV_MC(value) \
-        (_Generic ((value), \
-               const char *     *: (const char *     *) (value), \
-                     char *     *: (const char *     *) (value), \
-                           void *: (const char *     *) (value)))
-    #define NM_CAST_STRV_CC(value) \
-        (_Generic ((value), \
-               const char *const*: (const char *const*) (value), \
-               const char *     *: (const char *const*) (value), \
-                     char *const*: (const char *const*) (value), \
-                     char *     *: (const char *const*) (value), \
-                     const void *: (const char *const*) (value), \
-                           void *: (const char *const*) (value), \
-               const char *const*const: (const char *const*) (value), \
-               const char *     *const: (const char *const*) (value), \
-                     char *const*const: (const char *const*) (value), \
-                     char *     *const: (const char *const*) (value), \
-                     const void *const: (const char *const*) (value), \
-                           void *const: (const char *const*) (value)))
-#else
-    #define NM_CAST_STRV_MC(value) ((const char **) (value))
-    #define NM_CAST_STRV_CC(value) ((const char *const *) (value))
-#endif
-
-#if _NM_CC_SUPPORT_GENERIC
-    #define NM_PROPAGATE_CONST(test_expr, ptr) \
-        (_Generic ((test_expr), \
-               const typeof (*(test_expr)) *: ((const typeof (*(ptr)) *) (ptr)), \
-                                     default: (_Generic ((test_expr), \
-                                                         typeof (*(test_expr)) *: (ptr)))))
-#else
-    #define NM_PROPAGATE_CONST(test_expr, ptr) (ptr)
-#endif
-
-/* with the way it is implemented, the caller may or may not pass a trailing
- * ',' and it will work. However, this makes the macro unsuitable for initializing
- * an array. */
-#define NM_MAKE_STRV(...)                                                                     \
-    ((const char *const[(sizeof(((const char *const[]){__VA_ARGS__})) / sizeof(const char *)) \
-                        + 1]){__VA_ARGS__})
-
-/*****************************************************************************/
-
-/* NM_CACHED_QUARK() returns the GQuark for @string, but caches
- * it in a static variable to speed up future lookups.
- *
- * @string must be a string literal.
- */
-#define NM_CACHED_QUARK(string)                                                \
-    ({                                                                         \
-        static GQuark _nm_cached_quark = 0;                                    \
-                                                                               \
-        (G_LIKELY(_nm_cached_quark != 0)                                       \
-             ? _nm_cached_quark                                                \
-             : (_nm_cached_quark = g_quark_from_static_string("" string ""))); \
-    })
-
-/* NM_CACHED_QUARK_FCN() is essentially the same as G_DEFINE_QUARK
- * with two differences:
- * - @string must be a quoted string-literal
- * - @fcn must be the full function name, while G_DEFINE_QUARK() appends
- *   "_quark" to the function name.
- * Both properties of G_DEFINE_QUARK() are non favorable, because you can no
- * longer grep for string/fcn -- unless you are aware that you are searching
- * for G_DEFINE_QUARK() and omit quotes / append _quark(). With NM_CACHED_QUARK_FCN(),
- * ctags/cscope can locate the use of @fcn (though it doesn't recognize that
- * NM_CACHED_QUARK_FCN() defines it).
- */
-#define NM_CACHED_QUARK_FCN(string, fcn) \
-    GQuark fcn(void)                     \
-    {                                    \
-        return NM_CACHED_QUARK(string);  \
-    }                                    \
-    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
-
-/*****************************************************************************/
-
-static inline GString *
-nm_gstring_prepare(GString **l)
-{
-    if (*l)
-        g_string_set_size(*l, 0);
-    else
-        *l = g_string_sized_new(30);
-    return *l;
-}
-
-static inline GString *
-nm_gstring_add_space_delimiter(GString *str)
-{
-    if (str->len > 0)
-        g_string_append_c(str, ' ');
-    return str;
-}
-
-static inline gboolean
-nm_str_is_empty(const char *str)
-{
-    /* %NULL is also accepted, and also "empty". */
-    return !str || !str[0];
-}
-
-static inline const char *
-nm_str_not_empty(const char *str)
-{
-    return !nm_str_is_empty(str) ? str : NULL;
-}
-
-static inline char *
-nm_strdup_not_empty(const char *str)
-{
-    return !nm_str_is_empty(str) ? g_strdup(str) : NULL;
-}
-
-static inline char *
-nm_str_realloc(char *str)
-{
-    gs_free char *s = str;
-
-    /* Returns a new clone of @str and frees @str. The point is that @str
-     * possibly points to a larger chunck of memory. We want to freshly allocate
-     * a buffer.
-     *
-     * We could use realloc(), but that might not do anything or leave
-     * @str in its memory pool for chunks of a different size (bad for
-     * fragmentation).
-     *
-     * This is only useful when we want to keep the buffer around for a long
-     * time and want to re-allocate a more optimal buffer. */
-
-    return g_strdup(s);
-}
-
-/*****************************************************************************/
-
-#define NM_PRINT_FMT_QUOTED2(cond, prefix, str, str_else) \
-    (cond) ? (prefix) : "", (cond) ? (str) : (str_else)
-#define NM_PRINT_FMT_QUOTED(cond, prefix, str, suffix, str_else) \
-    (cond) ? (prefix) : "", (cond) ? (str) : (str_else), (cond) ? (suffix) : ""
-#define NM_PRINT_FMT_QUOTE_STRING(arg) NM_PRINT_FMT_QUOTED((arg), "\"", (arg), "\"", "(null)")
-#define NM_PRINT_FMT_QUOTE_REF_STRING(arg) \
-    NM_PRINT_FMT_QUOTED((arg), "\"", (arg)->str, "\"", "(null)")
-
-/*****************************************************************************/
-
-/* redefine assertions to use g_assert*() */
-#undef _nm_assert_call
-#undef _nm_assert_call_not_reached
-#define _nm_assert_call(cond)         g_assert(cond)
-#define _nm_assert_call_not_reached() g_assert_not_reached()
-
-/* Usage:
- *
- *   if (NM_MORE_ASSERT_ONCE (5)) { extra_check (); }
- *
- * This will only run the check once, and only if NM_MORE_ASSERT is >= than
- * more_assert_level.
- */
-#define NM_MORE_ASSERT_ONCE(more_assert_level)                                                    \
-    ((NM_MORE_ASSERTS >= (more_assert_level)) && ({                                               \
-         static volatile int _assert_once = 0;                                                    \
-                                                                                                  \
-         G_STATIC_ASSERT_EXPR((more_assert_level) > 0);                                           \
-                                                                                                  \
-         G_UNLIKELY(_assert_once == 0 && g_atomic_int_compare_and_exchange(&_assert_once, 0, 1)); \
-     }))
-
-/*****************************************************************************/
-
-#define NM_GOBJECT_PROPERTIES_DEFINE_BASE_FULL(suffix, ...)                     \
-    typedef enum {                                                              \
-        PROP_0##suffix,                                                         \
-        __VA_ARGS__ _PROPERTY_ENUMS_LAST##suffix,                               \
-    } _PropertyEnums##suffix;                                                   \
-    static GParamSpec *obj_properties##suffix[_PROPERTY_ENUMS_LAST##suffix] = { \
-        NULL,                                                                   \
-    }
-
-#define NM_GOBJECT_PROPERTIES_DEFINE_NOTIFY(suffix, obj_type)                                 \
-    static inline void _nm_gobject_notify_together_impl##suffix(                              \
-        obj_type *                    obj,                                                    \
-        guint                         n,                                                      \
-        const _PropertyEnums##suffix *props)                                                  \
-    {                                                                                         \
-        GObject *const gobj        = (GObject *) obj;                                         \
-        GParamSpec *   pspec_first = NULL;                                                    \
-        gboolean       frozen      = FALSE;                                                   \
-                                                                                              \
-        nm_assert(G_IS_OBJECT(obj));                                                          \
-        nm_assert(n > 0);                                                                     \
-                                                                                              \
-        while (n-- > 0) {                                                                     \
-            const _PropertyEnums##suffix prop = *props++;                                     \
-            GParamSpec *                 pspec;                                               \
-                                                                                              \
-            if (prop == PROP_0##suffix)                                                       \
-                continue;                                                                     \
-                                                                                              \
-            nm_assert((gsize) prop < G_N_ELEMENTS(obj_properties##suffix));                   \
-            pspec = obj_properties##suffix[prop];                                             \
-            nm_assert(pspec);                                                                 \
-                                                                                              \
-            if (!frozen) {                                                                    \
-                if (!pspec_first) {                                                           \
-                    pspec_first = pspec;                                                      \
-                    continue;                                                                 \
-                }                                                                             \
-                frozen = TRUE;                                                                \
-                g_object_freeze_notify(gobj);                                                 \
-                g_object_notify_by_pspec(gobj, pspec_first);                                  \
-            }                                                                                 \
-            g_object_notify_by_pspec(gobj, pspec);                                            \
-        }                                                                                     \
-                                                                                              \
-        if (frozen)                                                                           \
-            g_object_thaw_notify(gobj);                                                       \
-        else if (pspec_first)                                                                 \
-            g_object_notify_by_pspec(gobj, pspec_first);                                      \
-    }                                                                                         \
-                                                                                              \
-    _nm_unused static inline void _notify##suffix(obj_type *obj, _PropertyEnums##suffix prop) \
-    {                                                                                         \
-        _nm_gobject_notify_together_impl##suffix(obj, 1, &prop);                              \
-    }                                                                                         \
-    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
-
-#define NM_GOBJECT_PROPERTIES_DEFINE_BASE(...) \
-    NM_GOBJECT_PROPERTIES_DEFINE_BASE_FULL(, __VA_ARGS__);
-
-#define NM_GOBJECT_PROPERTIES_DEFINE_FULL(suffix, obj_type, ...) \
-    NM_GOBJECT_PROPERTIES_DEFINE_BASE_FULL(suffix, __VA_ARGS__); \
-    NM_GOBJECT_PROPERTIES_DEFINE_NOTIFY(suffix, obj_type)
-
-#define NM_GOBJECT_PROPERTIES_DEFINE(obj_type, ...) \
-    NM_GOBJECT_PROPERTIES_DEFINE_FULL(, obj_type, __VA_ARGS__)
-
-/* invokes _notify() for all arguments (of type _PropertyEnums). Note, that if
- * there are more than one prop arguments, this will involve a freeze/thaw
- * of GObject property notifications. */
-#define nm_gobject_notify_together_full(suffix, obj, ...)          \
-    _nm_gobject_notify_together_impl##suffix(obj,                  \
-                                             NM_NARG(__VA_ARGS__), \
-                                             (const _PropertyEnums##suffix[]){__VA_ARGS__})
-
-#define nm_gobject_notify_together(obj, ...) nm_gobject_notify_together_full(, obj, __VA_ARGS__)
-
-/*****************************************************************************/
-
-#define _NM_GET_PRIVATE(self, type, is_check, ...) \
-    (&(NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__)->_priv))
-#if _NM_CC_SUPPORT_AUTO_TYPE
-    #define _NM_GET_PRIVATE_PTR(self, type, is_check, ...)                       \
-        ({                                                                       \
-            _nm_auto_type _self_get_private =                                    \
-                NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__); \
-                                                                                 \
-            NM_PROPAGATE_CONST(_self_get_private, _self_get_private->_priv);     \
-        })
-#else
-    #define _NM_GET_PRIVATE_PTR(self, type, is_check, ...) \
-        (NM_GOBJECT_CAST_NON_NULL(type, (self), is_check, ##__VA_ARGS__)->_priv)
-#endif
-
-/*****************************************************************************/
-
-static inline gpointer
-nm_g_object_ref(gpointer obj)
-{
-    /* g_object_ref() doesn't accept NULL. */
-    if (obj)
-        g_object_ref(obj);
-    return obj;
-}
-#define nm_g_object_ref(obj) ((typeof(obj)) nm_g_object_ref(obj))
-
-static inline void
-nm_g_object_unref(gpointer obj)
-{
-    /* g_object_unref() doesn't accept NULL. Usually, we workaround that
-     * by using g_clear_object(), but sometimes that is not convenient
-     * (for example as destroy function for a hash table that can contain
-     * NULL values). */
-    if (obj)
-        g_object_unref(obj);
-}
-
-/* Assigns GObject @obj to destination @pp, and takes an additional ref.
- * The previous value of @pp is unrefed.
- *
- * It makes sure to first increase the ref-count of @obj, and handles %NULL
- * @obj correctly.
- * */
-#define nm_g_object_ref_set(pp, obj)                   \
-    ({                                                 \
-        typeof(*(pp)) *const _pp = (pp);               \
-        typeof(*_pp) const _obj  = (obj);              \
-        typeof(*_pp) _p;                               \
-        gboolean _changed = FALSE;                     \
-                                                       \
-        nm_assert(!_pp || !*_pp || G_IS_OBJECT(*_pp)); \
-        nm_assert(!_obj || G_IS_OBJECT(_obj));         \
-                                                       \
-        if (_pp && ((_p = *_pp) != _obj)) {            \
-            nm_g_object_ref(_obj);                     \
-            *_pp = _obj;                               \
-            nm_g_object_unref(_p);                     \
-            _changed = TRUE;                           \
-        }                                              \
-        _changed;                                      \
-    })
-
-#define nm_g_object_ref_set_take(pp, obj)              \
-    ({                                                 \
-        typeof(*(pp)) *const _pp = (pp);               \
-        typeof(*_pp) const _obj  = (obj);              \
-        typeof(*_pp) _p;                               \
-        gboolean _changed = FALSE;                     \
-                                                       \
-        nm_assert(!_pp || !*_pp || G_IS_OBJECT(*_pp)); \
-        nm_assert(!_obj || G_IS_OBJECT(_obj));         \
-                                                       \
-        if (_pp && ((_p = *_pp) != _obj)) {            \
-            *_pp = _obj;                               \
-            nm_g_object_unref(_p);                     \
-            _changed = TRUE;                           \
-        } else                                         \
-            nm_g_object_unref(_obj);                   \
-        _changed;                                      \
-    })
-
-/* basically, replaces
- *   g_clear_pointer (&location, g_free)
- * with
- *   nm_clear_g_free (&location)
- *
- * Another advantage is that by using a macro and typeof(), it is more
- * typesafe and gives you for example a compiler warning when pp is a const
- * pointer or points to a const-pointer.
- */
-#define nm_clear_g_free(pp) nm_clear_pointer(pp, g_free)
-
-/* Our nm_clear_pointer() is more typesafe than g_clear_pointer() and
- * should be preferred.
- *
- * For g_clear_object() that is not the case (because g_object_unref()
- * anyway takes a void pointer). So using g_clear_object() is fine.
- *
- * Still have a nm_clear_g_object() because that returns a boolean
- * indication whether anything was cleared. */
-#define nm_clear_g_object(pp) nm_clear_pointer(pp, g_object_unref)
-
-/**
- * nm_clear_error:
- * @err: a pointer to pointer to a #GError.
- *
- * This is like g_clear_error(). The only difference is
- * that this is an inline function.
- */
-static inline void
-nm_clear_error(GError **err)
-{
-    if (err && *err) {
-        g_error_free(*err);
-        *err = NULL;
-    }
-}
-
-/* Patch g_clear_error() to use nm_clear_error(), which is inlineable
- * and visible to the compiler. For example gs_free_error attribute only
- * frees the error after checking that it's not %NULL. So, in many cases
- * the compiler knows that gs_free_error has no effect and can optimize
- * the call away. By making g_clear_error() inlineable, we give the compiler
- * more chance to detect that the function actually has no effect. */
-#define g_clear_error(ptr) nm_clear_error(ptr)
-
-static inline gboolean
-nm_clear_g_source(guint *id)
-{
-    guint v;
-
-    if (id && (v = *id)) {
-        *id = 0;
-        g_source_remove(v);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-static inline gboolean
-nm_clear_g_signal_handler(gpointer self, gulong *id)
-{
-    gulong v;
-
-    if (id && (v = *id)) {
-        *id = 0;
-        g_signal_handler_disconnect(self, v);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-static inline gboolean
-nm_clear_g_variant(GVariant **variant)
-{
-    GVariant *v;
-
-    if (variant && (v = *variant)) {
-        *variant = NULL;
-        g_variant_unref(v);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-static inline gboolean
-nm_clear_g_string(GString **ptr)
-{
-    GString *s;
-
-    if (ptr && (s = *ptr)) {
-        *ptr = NULL;
-        g_string_free(s, TRUE);
-    };
-    return FALSE;
-}
-
-static inline gboolean
-nm_clear_g_cancellable(GCancellable **cancellable)
-{
-    GCancellable *v;
-
-    if (cancellable && (v = *cancellable)) {
-        *cancellable = NULL;
-        g_cancellable_cancel(v);
-        g_object_unref(v);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/* If @cancellable_id is not 0, clear it and call g_cancellable_disconnect().
- * @cancellable may be %NULL, if there is nothing to disconnect.
- *
- * It's like nm_clear_g_signal_handler(), except that it uses g_cancellable_disconnect()
- * instead of g_signal_handler_disconnect().
- *
- * Note the warning in glib documentation about dead-lock and what g_cancellable_disconnect()
- * actually does. */
-static inline gboolean
-nm_clear_g_cancellable_disconnect(GCancellable *cancellable, gulong *cancellable_id)
-{
-    gulong id;
-
-    if (cancellable_id && (id = *cancellable_id) != 0) {
-        *cancellable_id = 0;
-        g_cancellable_disconnect(cancellable, id);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-/*****************************************************************************/
-
-static inline const char *
-nm_dbus_path_not_empty(const char *str)
-{
-    nm_assert(!str || str[0] == '/');
-    return !str || (str[0] == '/' && str[1] == '\0') ? NULL : str;
-}
-
-/*****************************************************************************/
-
-/* GVariantType is basically a C string. But G_VARIANT_TYPE() is not suitable
- * to initialize a static variable (because it evaluates a function check that
- * the string is valid). Add an alternative macro that does the plain cast.
- *
- * Here you loose the assertion check that G_VARIANT_TYPE() to ensure the
- * string is valid. */
-#define NM_G_VARIANT_TYPE(fmt) ((const GVariantType *) ("" fmt ""))
-
-static inline GVariant *
-nm_g_variant_ref(GVariant *v)
-{
-    if (v)
-        g_variant_ref(v);
-    return v;
-}
-
-static inline GVariant *
-nm_g_variant_ref_sink(GVariant *v)
-{
-    if (v)
-        g_variant_ref_sink(v);
-    return v;
-}
-
-static inline void
-nm_g_variant_unref(GVariant *v)
-{
-    if (v)
-        g_variant_unref(v);
-}
-
-static inline GVariant *
-nm_g_variant_take_ref(GVariant *v)
-{
-    if (v)
-        g_variant_take_ref(v);
-    return v;
-}
-
-/*****************************************************************************/
-
-#define NM_DIV_ROUND_UP(x, y)     \
-    ({                            \
-        const typeof(x) _x = (x); \
-        const typeof(y) _y = (y); \
-                                  \
-        (_x / _y + !!(_x % _y));  \
-    })
-
-/*****************************************************************************/
-
-#define NM_UTILS_LOOKUP_DEFAULT(v)      return (v)
-#define NM_UTILS_LOOKUP_DEFAULT_WARN(v) g_return_val_if_reached(v)
-#define NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(v) \
-    {                                        \
-        nm_assert_not_reached();             \
-        return (v);                          \
-    }
-#define NM_UTILS_LOOKUP_ITEM(v, n) \
-    (void) 0;                      \
-case v:                            \
-    return (n);                    \
-    (void) 0
-#define NM_UTILS_LOOKUP_STR_ITEM(v, n) NM_UTILS_LOOKUP_ITEM(v, "" n "")
-#define NM_UTILS_LOOKUP_ITEM_IGNORE(v) \
-    (void) 0;                          \
-case v:                                \
-    break;                             \
-    (void) 0
-#define NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER() \
-    (void) 0;                               \
-default:                                    \
-    break;                                  \
-    (void) 0
-
-#define NM_UTILS_LOOKUP_DEFINE(fcn_name, lookup_type, result_type, unknown_val, ...) \
-    result_type fcn_name(lookup_type val)                                            \
-    {                                                                                \
-        switch (val) {                                                               \
-            (void) 0, __VA_ARGS__(void) 0;                                           \
-        };                                                                           \
-        {                                                                            \
-            unknown_val;                                                             \
-        }                                                                            \
-    }                                                                                \
-    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
-
-#define NM_UTILS_LOOKUP_STR_DEFINE(fcn_name, lookup_type, unknown_val, ...) \
-    NM_UTILS_LOOKUP_DEFINE(fcn_name, lookup_type, const char *, unknown_val, __VA_ARGS__)
-
-/* Call the string-lookup-table function @fcn_name. If the function returns
- * %NULL, the numeric index is converted to string using a alloca() buffer.
- * Beware: this macro uses alloca(). */
-#define NM_UTILS_LOOKUP_STR_A(fcn_name, idx)                         \
-    ({                                                               \
-        typeof(idx) _idx = (idx);                                    \
-        const char *_s;                                              \
-                                                                     \
-        _s = fcn_name(_idx);                                         \
-        if (!_s) {                                                   \
-            _s = g_alloca(30);                                       \
-                                                                     \
-            g_snprintf((char *) _s, 30, "(%lld)", (long long) _idx); \
-        }                                                            \
-        _s;                                                          \
-    })
-
-/*****************************************************************************/
-
-/* check if @flags has exactly one flag (@check) set. You should call this
- * only with @check being a compile time constant and a power of two. */
-#define NM_FLAGS_HAS(flags, check)                                       \
-    (G_STATIC_ASSERT_EXPR((check) > 0 && ((check) & ((check) -1)) == 0), \
-     NM_FLAGS_ANY((flags), (check)))
-
-#define NM_FLAGS_ANY(flags, check) ((((flags) & (check)) != 0) ? TRUE : FALSE)
-#define NM_FLAGS_ALL(flags, check) ((((flags) & (check)) == (check)) ? TRUE : FALSE)
-
-#define NM_FLAGS_SET(flags, val)              \
-    ({                                        \
-        const typeof(flags) _flags = (flags); \
-        const typeof(flags) _val   = (val);   \
-                                              \
-        _flags | _val;                        \
-    })
-
-#define NM_FLAGS_UNSET(flags, val)            \
-    ({                                        \
-        const typeof(flags) _flags = (flags); \
-        const typeof(flags) _val   = (val);   \
-                                              \
-        _flags &(~_val);                      \
-    })
-
-#define NM_FLAGS_ASSIGN(flags, val, assign)           \
-    ({                                                \
-        const typeof(flags) _flags = (flags);         \
-        const typeof(flags) _val   = (val);           \
-                                                      \
-        (assign) ? _flags | (_val) : _flags &(~_val); \
-    })
-
-#define NM_FLAGS_ASSIGN_MASK(flags, mask, val) \
-    ({                                         \
-        const typeof(flags) _flags = (flags);  \
-        const typeof(flags) _mask  = (mask);   \
-        const typeof(flags) _val   = (val);    \
-                                               \
-        ((_flags & ~_mask) | (_mask & _val));  \
-    })
-
-/*****************************************************************************/
-
-#define _NM_BACKPORT_SYMBOL_IMPL(version,                                                       \
-                                 return_type,                                                   \
-                                 orig_func,                                                     \
-                                 versioned_func,                                                \
-                                 args_typed,                                                    \
-                                 args)                                                          \
-    return_type versioned_func                        args_typed;                               \
-    _nm_externally_visible return_type versioned_func args_typed                                \
-    {                                                                                           \
-        return orig_func args;                                                                  \
-    }                                                                                           \
-    return_type orig_func args_typed;                                                           \
-    __asm__(".symver " G_STRINGIFY(versioned_func) ", " G_STRINGIFY(orig_func) "@" G_STRINGIFY( \
-        version))
-
-#define NM_BACKPORT_SYMBOL(version, return_type, func, args_typed, args) \
-    _NM_BACKPORT_SYMBOL_IMPL(version, return_type, func, _##func##_##version, args_typed, args)
-
-/*****************************************************************************/
-
-/* mirrors g_ascii_isspace() and what we consider spaces in general. */
-#define NM_ASCII_SPACES " \n\t\r\f"
-
-/* Like NM_ASCII_SPACES, but without "\f" (0x0c, Formfeed Page Break).
- * This is what for example systemd calls WHITESPACE and what it uses to tokenize
- * the kernel command line. */
-#define NM_ASCII_WHITESPACES " \n\t\r"
-
-#define nm_str_skip_leading_spaces(str)                          \
-    ({                                                           \
-        typeof(*(str)) *             _str_sls        = (str);    \
-        _nm_unused const char *const _str_type_check = _str_sls; \
-                                                                 \
-        if (_str_sls) {                                          \
-            while (g_ascii_isspace(_str_sls[0]))                 \
-                _str_sls++;                                      \
-        }                                                        \
-        _str_sls;                                                \
-    })
-
-static inline char *
-nm_strstrip(char *str)
-{
-    /* g_strstrip doesn't like NULL. */
-    return str ? g_strstrip(str) : NULL;
-}
-
-static inline const char *
-nm_strstrip_avoid_copy(const char *str, char **str_free)
-{
-    gsize l;
-    char *s;
-
-    nm_assert(str_free && !*str_free);
-
-    if (!str)
-        return NULL;
-
-    str = nm_str_skip_leading_spaces(str);
-    l   = strlen(str);
-    if (l == 0 || !g_ascii_isspace(str[l - 1]))
-        return str;
-    while (l > 0 && g_ascii_isspace(str[l - 1]))
-        l--;
-
-    s = g_new(char, l + 1);
-    memcpy(s, str, l);
-    s[l]      = '\0';
-    *str_free = s;
-    return s;
-}
-
-#define nm_strstrip_avoid_copy_a(alloca_maxlen, str, out_str_free)                                \
-    ({                                                                                            \
-        const char *_str_ssac          = (str);                                                   \
-        char **     _out_str_free_ssac = (out_str_free);                                          \
-                                                                                                  \
-        G_STATIC_ASSERT_EXPR((alloca_maxlen) > 0);                                                \
-                                                                                                  \
-        nm_assert(_out_str_free_ssac || ((alloca_maxlen) > (str ? strlen(str) : 0u)));            \
-        nm_assert(!_out_str_free_ssac || !*_out_str_free_ssac);                                   \
-                                                                                                  \
-        if (_str_ssac) {                                                                          \
-            _str_ssac = nm_str_skip_leading_spaces(_str_ssac);                                    \
-            if (_str_ssac[0] != '\0') {                                                           \
-                gsize _l = strlen(_str_ssac);                                                     \
-                                                                                                  \
-                if (g_ascii_isspace(_str_ssac[--_l])) {                                           \
-                    while (_l > 0 && g_ascii_isspace(_str_ssac[_l - 1])) {                        \
-                        _l--;                                                                     \
-                    }                                                                             \
-                    _str_ssac = nm_strndup_a((alloca_maxlen), _str_ssac, _l, _out_str_free_ssac); \
-                }                                                                                 \
-            }                                                                                     \
-        }                                                                                         \
-                                                                                                  \
-        _str_ssac;                                                                                \
-    })
-
-static inline gboolean
-nm_str_is_stripped(const char *str)
-{
-    if (str && str[0]) {
-        if (g_ascii_isspace(str[0]) || g_ascii_isspace(str[strlen(str) - 1]))
-            return FALSE;
-    }
-    return TRUE;
-}
-
-/* g_ptr_array_sort()'s compare function takes pointers to the
- * value. Thus, you cannot use strcmp directly. You can use
- * nm_strcmp_p().
- *
- * Like strcmp(), this function is not forgiving to accept %NULL. */
-static inline int
-nm_strcmp_p(gconstpointer a, gconstpointer b)
-{
-    const char *s1 = *((const char **) a);
-    const char *s2 = *((const char **) b);
-
-    return strcmp(s1, s2);
-}
-
-/*****************************************************************************/
-
-static inline int
-_NM_IN_STRSET_ASCII_CASE_op_streq(const char *x, const char *s)
-{
-    return s && g_ascii_strcasecmp(x, s) == 0;
-}
-
-#define NM_IN_STRSET_ASCII_CASE(x, ...)                     \
-    _NM_IN_STRSET_EVAL_N(||,                                \
-                         _NM_IN_STRSET_ASCII_CASE_op_streq, \
-                         x,                                 \
-                         NM_NARG(__VA_ARGS__),              \
-                         __VA_ARGS__)
-
-#define NM_STR_HAS_SUFFIX_ASCII_CASE(str, suffix)                                               \
-    ({                                                                                          \
-        const char *const _str_has_suffix = (str);                                              \
-        size_t            _l;                                                                   \
-                                                                                                \
-        nm_assert(strlen(suffix) == NM_STRLEN(suffix));                                         \
-                                                                                                \
-        (_str_has_suffix && ((_l = strlen(_str_has_suffix)) >= NM_STRLEN(suffix))               \
-         && (g_ascii_strcasecmp(&_str_has_suffix[_l - NM_STRLEN(suffix)], "" suffix "") == 0)); \
-    })
-
-#define NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(str, suffix)                                     \
-    ({                                                                                          \
-        const char *const _str_has_suffix = (str);                                              \
-        size_t            _l;                                                                   \
-                                                                                                \
-        nm_assert(strlen(suffix) == NM_STRLEN(suffix));                                         \
-                                                                                                \
-        (_str_has_suffix && ((_l = strlen(_str_has_suffix)) > NM_STRLEN(suffix))                \
-         && (g_ascii_strcasecmp(&_str_has_suffix[_l - NM_STRLEN(suffix)], "" suffix "") == 0)); \
-    })
-
-/*****************************************************************************/
-
-#define nm_g_slice_free(ptr) g_slice_free(typeof(*(ptr)), ptr)
-
-/*****************************************************************************/
-
-/* like g_memdup(). The difference is that the @size argument is of type
- * gsize, while g_memdup() has type guint. Since, the size of container types
- * like GArray is guint as well, this means trying to g_memdup() an
- * array,
- *    g_memdup (array->data, array->len * sizeof (ElementType))
- * will lead to integer overflow, if there are more than G_MAXUINT/sizeof(ElementType)
- * bytes. That seems unnecessarily dangerous to me.
- * nm_memdup() avoids that, because its size argument is always large enough
- * to contain all data that a GArray can hold.
- *
- * Another minor difference to g_memdup() is that the glib version also
- * returns %NULL if @data is %NULL. E.g. g_memdup(NULL, 1)
- * gives %NULL, but nm_memdup(NULL, 1) crashes. I think that
- * is desirable, because @size MUST be correct at all times. @size
- * may be zero, but one must not claim to have non-zero bytes when
- * passing a %NULL @data pointer.
- */
-static inline gpointer
-nm_memdup(gconstpointer data, gsize size)
-{
-    gpointer p;
-
-    if (size == 0)
-        return NULL;
-    p = g_malloc(size);
-    memcpy(p, data, size);
-    return p;
-}
-
-#define nm_malloc_maybe_a(alloca_maxlen, bytes, to_free)  \
-    ({                                                    \
-        const gsize _bytes       = (bytes);               \
-        typeof(to_free) _to_free = (to_free);             \
-        typeof(*_to_free) _ptr;                           \
-                                                          \
-        G_STATIC_ASSERT_EXPR((alloca_maxlen) <= 500u);    \
-        G_STATIC_ASSERT_EXPR((alloca_maxlen) > 0u);       \
-        nm_assert(_to_free && !*_to_free);                \
-                                                          \
-        if (G_LIKELY(_bytes <= (alloca_maxlen))) {        \
-            _ptr = _bytes > 0u ? g_alloca(_bytes) : NULL; \
-        } else {                                          \
-            _ptr      = g_malloc(_bytes);                 \
-            *_to_free = _ptr;                             \
-        };                                                \
-                                                          \
-        _ptr;                                             \
-    })
-
-#define nm_malloc0_maybe_a(alloca_maxlen, bytes, to_free) \
-    ({                                                    \
-        const gsize _bytes       = (bytes);               \
-        typeof(to_free) _to_free = (to_free);             \
-        typeof(*_to_free) _ptr;                           \
-                                                          \
-        G_STATIC_ASSERT_EXPR((alloca_maxlen) <= 500u);    \
-        G_STATIC_ASSERT_EXPR((alloca_maxlen) > 0u);       \
-        nm_assert(_to_free && !*_to_free);                \
-                                                          \
-        if (G_LIKELY(_bytes <= (alloca_maxlen))) {        \
-            if (_bytes > 0u) {                            \
-                _ptr = g_alloca(_bytes);                  \
-                memset(_ptr, 0, _bytes);                  \
-            } else                                        \
-                _ptr = NULL;                              \
-        } else {                                          \
-            _ptr      = g_malloc0(_bytes);                \
-            *_to_free = _ptr;                             \
-        };                                                \
-                                                          \
-        _ptr;                                             \
-    })
-
-#define nm_memdup_maybe_a(alloca_maxlen, data, size, to_free)                 \
-    ({                                                                        \
-        const gsize _size            = (size);                                \
-        typeof(to_free) _to_free_md  = (to_free);                             \
-        typeof(*_to_free_md) _ptr_md = NULL;                                  \
-                                                                              \
-        nm_assert(_to_free_md && !*_to_free_md);                              \
-                                                                              \
-        if (_size > 0u) {                                                     \
-            _ptr_md = nm_malloc_maybe_a((alloca_maxlen), _size, _to_free_md); \
-            memcpy(_ptr_md, (data), _size);                                   \
-        }                                                                     \
-                                                                              \
-        _ptr_md;                                                              \
-    })
-
-static inline char *
-_nm_strndup_a_step(char *s, const char *str, gsize len)
-{
-    NM_PRAGMA_WARNING_DISABLE("-Wstringop-truncation");
-    NM_PRAGMA_WARNING_DISABLE("-Wstringop-overflow");
-    if (len > 0)
-        strncpy(s, str, len);
-    s[len] = '\0';
-    return s;
-    NM_PRAGMA_WARNING_REENABLE;
-    NM_PRAGMA_WARNING_REENABLE;
-}
-
-/* Similar to g_strndup(), however, if the string (including the terminating
- * NUL char) fits into alloca_maxlen, this will alloca() the memory.
- *
- * It's a mix of strndup() and strndupa(), but deciding based on @alloca_maxlen
- * which one to use.
- *
- * In case malloc() is necessary, @out_str_free will be set (this string
- * must be freed afterwards). It is permissible to pass %NULL as @out_str_free,
- * if you ensure that len < alloca_maxlen.
- *
- * Note that just like g_strndup(), this always returns a buffer with @len + 1
- * bytes, even if strlen(@str) is shorter than that (NUL terminated early). We fill
- * the buffer with strncpy(), which means, that @str is copied up to the first
- * NUL character and then filled with NUL characters. */
-#define nm_strndup_a(alloca_maxlen, str, len, out_str_free)        \
-    ({                                                             \
-        const gsize       _alloca_maxlen_snd = (alloca_maxlen);    \
-        const char *const _str_snd           = (str);              \
-        const gsize       _len_snd           = (len);              \
-        char **const      _out_str_free_snd  = (out_str_free);     \
-        char *            _s_snd;                                  \
-                                                                   \
-        G_STATIC_ASSERT_EXPR((alloca_maxlen) <= 300);              \
-                                                                   \
-        if (_out_str_free_snd && _len_snd >= _alloca_maxlen_snd) { \
-            _s_snd             = g_malloc(_len_snd + 1);           \
-            *_out_str_free_snd = _s_snd;                           \
-        } else {                                                   \
-            g_assert(_len_snd < _alloca_maxlen_snd);               \
-            _s_snd = g_alloca(_len_snd + 1);                       \
-        }                                                          \
-        _nm_strndup_a_step(_s_snd, _str_snd, _len_snd);            \
-    })
-
-#define nm_strdup_maybe_a(alloca_maxlen, str, out_str_free)               \
-    ({                                                                    \
-        const char *const _str_snd = (str);                               \
-                                                                          \
-        (char *) nm_memdup_maybe_a(alloca_maxlen,                         \
-                                   _str_snd,                              \
-                                   _str_snd ? strlen(_str_snd) + 1u : 0u, \
-                                   out_str_free);                         \
-    })
-
-/*****************************************************************************/
-
-/* generic macro to convert an int to a (heap allocated) string.
- *
- * Usually, an inline function nm_strdup_int64() would be enough. However,
- * that cannot be used for guint64. So, we would also need nm_strdup_uint64().
- * This causes subtle error potential, because the caller needs to ensure to
- * use the right one (and compiler isn't going to help as it silently casts).
- *
- * Instead, this generic macro is supposed to handle all integers correctly. */
-#if _NM_CC_SUPPORT_GENERIC
-    #define nm_strdup_int(val)                                                       \
-        _Generic((val), char                                                         \
-                 : g_strdup_printf("%d", (int) (val)),                               \
-                                                                                     \
-                   signed char                                                       \
-                 : g_strdup_printf("%d", (signed) (val)), signed short               \
-                 : g_strdup_printf("%d", (signed) (val)), signed                     \
-                 : g_strdup_printf("%d", (signed) (val)), signed long                \
-                 : g_strdup_printf("%ld", (signed long) (val)), signed long long     \
-                 : g_strdup_printf("%lld", (signed long long) (val)),                \
-                                                                                     \
-                   unsigned char                                                     \
-                 : g_strdup_printf("%u", (unsigned) (val)), unsigned short           \
-                 : g_strdup_printf("%u", (unsigned) (val)), unsigned                 \
-                 : g_strdup_printf("%u", (unsigned) (val)), unsigned long            \
-                 : g_strdup_printf("%lu", (unsigned long) (val)), unsigned long long \
-                 : g_strdup_printf("%llu", (unsigned long long) (val)))
-#else
-    #define nm_strdup_int(val)                                       \
-        ((sizeof(val) == sizeof(guint64) && ((typeof(val)) - 1) > 0) \
-             ? g_strdup_printf("%" G_GUINT64_FORMAT, (guint64)(val)) \
-             : g_strdup_printf("%" G_GINT64_FORMAT, (gint64)(val)))
-#endif
-
-/*****************************************************************************/
-
-static inline guint
-nm_encode_version(guint major, guint minor, guint micro)
-{
-    /* analog to the preprocessor macro NM_ENCODE_VERSION(). */
-    return (major << 16) | (minor << 8) | micro;
-}
-
-static inline void
-nm_decode_version(guint version, guint *major, guint *minor, guint *micro)
-{
-    *major = (version & 0xFFFF0000u) >> 16;
-    *minor = (version & 0x0000FF00u) >> 8;
-    *micro = (version & 0x000000FFu);
-}
-
-/*****************************************************************************/
-
-/* taken from systemd's DECIMAL_STR_MAX()
- *
- * Returns the number of chars needed to format variables of the
- * specified type as a decimal string. Adds in extra space for a
- * negative '-' prefix (hence works correctly on signed
- * types). Includes space for the trailing NUL. */
-#define NM_DECIMAL_STR_MAX(type) \
-    (2                           \
-     + (sizeof(type) <= 1   ? 3  \
-        : sizeof(type) <= 2 ? 5  \
-        : sizeof(type) <= 4 ? 10 \
-        : sizeof(type) <= 8 ? 20 \
-                            : sizeof(int[-2 * (sizeof(type) > 8)])))
-
-/*****************************************************************************/
-
-/* if @str is NULL, return "(null)". Otherwise, allocate a buffer using
- * alloca() of and fill it with @str. @str will be quoted with double quote.
- * If @str is longer then @trunc_at, the string is truncated and the closing
- * quote is instead '^' to indicate truncation.
- *
- * Thus, the maximum stack allocated buffer will be @trunc_at+3. The maximum
- * buffer size must be a constant and not larger than 300. */
-#define nm_strquote_a(trunc_at, str)                                     \
-    ({                                                                   \
-        const char *const _str = (str);                                  \
-                                                                         \
-        (_str ? ({                                                       \
-            const gsize _trunc_at     = (trunc_at);                      \
-            const gsize _strlen_trunc = NM_MIN(strlen(_str), _trunc_at); \
-            char *      _buf;                                            \
-                                                                         \
-            G_STATIC_ASSERT_EXPR((trunc_at) <= 300);                     \
-                                                                         \
-            _buf    = g_alloca(_strlen_trunc + 3);                       \
-            _buf[0] = '"';                                               \
-            memcpy(&_buf[1], _str, _strlen_trunc);                       \
-            _buf[_strlen_trunc + 1] = _str[_strlen_trunc] ? '^' : '"';   \
-            _buf[_strlen_trunc + 2] = '\0';                              \
-            _buf;                                                        \
-        })                                                               \
-              : "(null)");                                               \
-    })
-
-#define nm_sprintf_buf(buf, format, ...)                                                    \
-    ({                                                                                      \
-        char *_buf = (buf);                                                                 \
-        int   _buf_len;                                                                     \
-                                                                                            \
-        /* some static assert trying to ensure that the buffer is statically allocated.
-         * It disallows a buffer size of sizeof(gpointer) to catch that. */     \
-        G_STATIC_ASSERT(G_N_ELEMENTS(buf) == sizeof(buf) && sizeof(buf) != sizeof(char *)); \
-        _buf_len = g_snprintf(_buf, sizeof(buf), "" format "", ##__VA_ARGS__);              \
-        nm_assert(_buf_len < sizeof(buf));                                                  \
-        _buf;                                                                               \
-    })
-
-/* it is "unsafe" because @bufsize must not be a constant expression and
- * there is no check at compiletime. Regardless of that, the buffer size
- * must not be larger than 300 bytes, as this gets stack allocated. */
-#define nm_sprintf_buf_unsafe_a(bufsize, format, ...)                       \
-    ({                                                                      \
-        char *_buf;                                                         \
-        int   _buf_len;                                                     \
-        typeof(bufsize) _bufsize = (bufsize);                               \
-                                                                            \
-        nm_assert(_bufsize <= 300);                                         \
-                                                                            \
-        _buf     = g_alloca(_bufsize);                                      \
-        _buf_len = g_snprintf(_buf, _bufsize, "" format "", ##__VA_ARGS__); \
-        nm_assert(_buf_len >= 0 && _buf_len < _bufsize);                    \
-        _buf;                                                               \
-    })
-
-#define nm_sprintf_bufa(bufsize, format, ...)                      \
-    ({                                                             \
-        G_STATIC_ASSERT_EXPR((bufsize) <= 300);                    \
-        nm_sprintf_buf_unsafe_a((bufsize), format, ##__VA_ARGS__); \
-    })
-
-/* aims to alloca() a buffer and fill it with printf(format, name).
- * Note that format must not contain any format specifier except
- * "%s".
- * If the resulting string would be too large for stack allocation,
- * it allocates a buffer with g_malloc() and assigns it to *p_val_to_free. */
-#define nm_construct_name_a(format, name, p_val_to_free)                                   \
-    ({                                                                                     \
-        const char *const _name          = (name);                                         \
-        char **const      _p_val_to_free = (p_val_to_free);                                \
-        const gsize       _name_len      = strlen(_name);                                  \
-        char *            _buf2;                                                           \
-                                                                                           \
-        nm_assert(_p_val_to_free && !*_p_val_to_free);                                     \
-        if (NM_STRLEN(format) <= 290 && _name_len < (gsize)(290 - NM_STRLEN(format)))      \
-            _buf2 = nm_sprintf_buf_unsafe_a(NM_STRLEN(format) + _name_len, format, _name); \
-        else {                                                                             \
-            _buf2           = g_strdup_printf(format, _name);                              \
-            *_p_val_to_free = _buf2;                                                       \
-        }                                                                                  \
-        (const char *) _buf2;                                                              \
-    })
-
-/*****************************************************************************/
-
-#ifdef _G_BOOLEAN_EXPR
-    /* g_assert() uses G_LIKELY(), which in turn uses _G_BOOLEAN_EXPR().
- * As glib's implementation uses a local variable _g_boolean_var_,
- * we cannot do
- *   g_assert (some_macro ());
- * where some_macro() itself expands to ({g_assert(); ...}).
- * In other words, you cannot have a g_assert() inside a g_assert()
- * without getting a -Werror=shadow failure.
- *
- * Workaround that by re-defining _G_BOOLEAN_EXPR()
- **/
-    #undef _G_BOOLEAN_EXPR
-    #define _G_BOOLEAN_EXPR(expr) NM_BOOLEAN_EXPR(expr)
-#endif
-
-/*****************************************************************************/
-
-#define NM_PID_T_INVAL ((pid_t) -1)
-
-/*****************************************************************************/
-
-NM_AUTO_DEFINE_FCN_VOID0(GMutex *, _nm_auto_unlock_g_mutex, g_mutex_unlock);
-
-#define nm_auto_unlock_g_mutex nm_auto(_nm_auto_unlock_g_mutex)
-
-#define _NM_G_MUTEX_LOCKED(lock, uniq)                                      \
-    _nm_unused nm_auto_unlock_g_mutex GMutex *NM_UNIQ_T(nm_lock, uniq) = ({ \
-        GMutex *const _lock = (lock);                                       \
-                                                                            \
-        g_mutex_lock(_lock);                                                \
-        _lock;                                                              \
-    })
-
-#define NM_G_MUTEX_LOCKED(lock) _NM_G_MUTEX_LOCKED(lock, NM_UNIQ)
-
-/*****************************************************************************/
-
-#endif /* __NM_MACROS_INTERNAL_H__ */
diff --git a/shared/nm-glib-aux/nm-obj.h b/shared/nm-glib-aux/nm-obj.h
deleted file mode 100644
index 2062f661..00000000
--- a/shared/nm-glib-aux/nm-obj.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#ifndef __NM_OBJ_H__
-#define __NM_OBJ_H__
-
-/*****************************************************************************/
-
-#define NM_OBJ_REF_COUNT_STACKINIT (G_MAXINT)
-
-typedef struct _NMObjBaseInst  NMObjBaseInst;
-typedef struct _NMObjBaseClass NMObjBaseClass;
-
-struct _NMObjBaseInst {
-    /* The first field of NMObjBaseInst is compatible with GObject.
-     * Basically, NMObjBaseInst is an abstract base type of GTypeInstance.
-     *
-     * If you do it right, you may derive a type of NMObjBaseInst as a proper GTypeInstance.
-     * That involves allocating a GType for it, which can be inconvenient because
-     * a GType is dynamically created (and the class can no longer be immutable
-     * memory).
-     *
-     * Even if your implementation of NMObjBaseInst is not a full fledged GType(Instance),
-     * you still can use GTypeInstances in the same context as you can decide based on the
-     * NMObjBaseClass with what kind of object you are dealing with.
-     *
-     * Basically, the only thing NMObjBaseInst gives you is access to an
-     * NMObjBaseClass instance.
-     */
-    union {
-        const NMObjBaseClass *klass;
-        GTypeInstance         g_type_instance;
-    };
-};
-
-struct _NMObjBaseClass {
-    /* NMObjBaseClass is the base class of all NMObjBaseInst implementations.
-     * Note that it is also an abstract super class of GTypeInstance, that means
-     * you may implement a NMObjBaseClass as a subtype of GTypeClass.
-     *
-     * For that to work, you must properly set the GTypeClass instance (and its
-     * GType).
-     *
-     * Note that to implement a NMObjBaseClass that is *not* a GTypeClass, you wouldn't
-     * set the GType. Hence, this field is only useful for type implementations that actually
-     * extend GTypeClass.
-     *
-     * In a way it is wrong that NMObjBaseClass has the GType member, because it is
-     * a base class of GTypeClass and doesn't necessarily use the GType. However,
-     * it is here so that G_TYPE_CHECK_INSTANCE_TYPE() and friends work correctly
-     * on any NMObjectClass. That means, while not necessary, it is convenient that
-     * a NMObjBaseClass has all members of GTypeClass.
-     * Also note that usually you have only one instance of a certain type, so this
-     * wastes just a few bytes for the unneeded GType.
-     */
-    union {
-        GType      g_type;
-        GTypeClass g_type_class;
-    };
-};
-
-/*****************************************************************************/
-
-#endif /* __NM_OBJ_H__ */
diff --git a/shared/nm-glib-aux/nm-random-utils.c b/shared/nm-glib-aux/nm-random-utils.c
deleted file mode 100644
index 97272ca3..00000000
--- a/shared/nm-glib-aux/nm-random-utils.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-random-utils.h"
-
-#include <fcntl.h>
-
-#if USE_SYS_RANDOM_H
-    #include <sys/random.h>
-#else
-    #include <linux/random.h>
-#endif
-
-#include "nm-shared-utils.h"
-
-/*****************************************************************************/
-
-/**
- * nm_utils_random_bytes:
- * @p: the buffer to fill
- * @n: the number of bytes to write to @p.
- *
- * Uses getrandom() or reads /dev/urandom to fill the buffer
- * with random data. If all fails, as last fallback it uses
- * GRand to fill the buffer with pseudo random numbers.
- * The function always succeeds in writing some random numbers
- * to the buffer. The return value of FALSE indicates that the
- * obtained bytes are probably not of good randomness.
- *
- * Returns: whether the written bytes are good. If you
- * don't require good randomness, you can ignore the return
- * value.
- *
- * Note that if calling getrandom() fails because there is not enough
- * entropy (at early boot), the function will read /dev/urandom.
- * Which of course, still has low entropy, and cause kernel to log
- * a warning.
- */
-gboolean
-nm_utils_random_bytes(void *p, size_t n)
-{
-    int      fd;
-    int      r;
-    gboolean has_high_quality = TRUE;
-    gboolean urandom_success;
-    guint8 * buf           = p;
-    gboolean avoid_urandom = FALSE;
-
-    g_return_val_if_fail(p, FALSE);
-    g_return_val_if_fail(n > 0, FALSE);
-
-#if HAVE_GETRANDOM
-    {
-        static gboolean have_syscall = TRUE;
-
-        if (have_syscall) {
-            r = getrandom(buf, n, GRND_NONBLOCK);
-            if (r > 0) {
-                if ((size_t) r == n)
-                    return TRUE;
-
-                /* no or partial read. There is not enough entropy.
-                 * Fill the rest reading from urandom, and remember that
-                 * some bits are not high quality. */
-                nm_assert(r < n);
-                buf += r;
-                n -= r;
-                has_high_quality = FALSE;
-
-                /* At this point, we don't want to read /dev/urandom, because
-                 * the entropy pool is low (early boot?), and asking for more
-                 * entropy causes kernel messages to be logged.
-                 *
-                 * We use our fallback via GRand. Note that g_rand_new() also
-                 * tries to seed itself with data from /dev/urandom, but since
-                 * we reuse the instance, it shouldn't matter. */
-                avoid_urandom = TRUE;
-            } else {
-                if (errno == ENOSYS) {
-                    /* no support for getrandom(). We don't know whether
-                     * we urandom will give us good quality. Assume yes. */
-                    have_syscall = FALSE;
-                } else {
-                    /* unknown error. We'll read urandom below, but we don't have
-                     * high-quality randomness. */
-                    has_high_quality = FALSE;
-                }
-            }
-        }
-    }
-#endif
-
-    urandom_success = FALSE;
-    if (!avoid_urandom) {
-fd_open:
-        fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY);
-        if (fd < 0) {
-            r = errno;
-            if (r == EINTR)
-                goto fd_open;
-        } else {
-            r = nm_utils_fd_read_loop_exact(fd, buf, n, TRUE);
-            nm_close(fd);
-            if (r >= 0)
-                urandom_success = TRUE;
-        }
-    }
-
-    if (!urandom_success) {
-        static _nm_thread_local GRand *rand = NULL;
-        gsize                          i;
-        int                            j;
-
-        /* we failed to fill the bytes reading from urandom.
-         * Fill the bits using GRand pseudo random numbers.
-         *
-         * We don't have good quality.
-         */
-        has_high_quality = FALSE;
-
-        if (G_UNLIKELY(!rand)) {
-            rand = g_rand_new();
-            nm_utils_thread_local_register_destroy(rand, (GDestroyNotify) g_rand_free);
-        }
-
-        nm_assert(n > 0);
-        i = 0;
-        for (;;) {
-            const union {
-                guint32 v32;
-                guint8  v8[4];
-            } v = {
-                .v32 = g_rand_int(rand),
-            };
-
-            for (j = 0; j < 4;) {
-                buf[i++] = v.v8[j++];
-                if (i >= n)
-                    goto done;
-            }
-        }
-done:;
-    }
-
-    return has_high_quality;
-}
diff --git a/shared/nm-glib-aux/nm-random-utils.h b/shared/nm-glib-aux/nm-random-utils.h
deleted file mode 100644
index d0eae103..00000000
--- a/shared/nm-glib-aux/nm-random-utils.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#ifndef __NM_RANDOM_UTILS_H__
-#define __NM_RANDOM_UTILS_H__
-
-gboolean nm_utils_random_bytes(void *p, size_t n);
-
-#endif /* __NM_RANDOM_UTILS_H__ */
diff --git a/shared/nm-glib-aux/nm-ref-string.c b/shared/nm-glib-aux/nm-ref-string.c
deleted file mode 100644
index 1084c47f..00000000
--- a/shared/nm-glib-aux/nm-ref-string.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-ref-string.h"
-
-/*****************************************************************************/
-
-typedef struct {
-    NMRefString  r;
-    volatile int ref_count;
-    char         str_data[];
-} RefString;
-
-G_LOCK_DEFINE_STATIC(gl_lock);
-static GHashTable *gl_hash;
-
-/* the first field of NMRefString is a pointer to the NUL terminated string.
- * This also allows to compare strings with nm_pstr_equal(), although, pointer
- * equality might be better. */
-G_STATIC_ASSERT(G_STRUCT_OFFSET(NMRefString, str) == 0);
-G_STATIC_ASSERT(G_STRUCT_OFFSET(RefString, r) == 0);
-G_STATIC_ASSERT(G_STRUCT_OFFSET(RefString, r.str) == 0);
-
-/*****************************************************************************/
-
-static guint
-_ref_string_hash(gconstpointer ptr)
-{
-    const RefString *a = ptr;
-    NMHashState      h;
-
-    nm_hash_init(&h, 1463435489u);
-    nm_hash_update(&h, a->r.str, a->r.len);
-    return nm_hash_complete(&h);
-}
-
-static gboolean
-_ref_string_equal(gconstpointer pa, gconstpointer pb)
-{
-    const RefString *a = pa;
-    const RefString *b = pb;
-
-    return a->r.len == b->r.len && memcmp(a->r.str, b->r.str, a->r.len) == 0;
-}
-
-/*****************************************************************************/
-
-static void
-_ASSERT(const RefString *rstr0)
-{
-    int r;
-
-    nm_assert(rstr0);
-
-    if (NM_MORE_ASSERTS > 0) {
-        r = g_atomic_int_get(&rstr0->ref_count);
-        nm_assert(r > 0);
-        nm_assert(r < G_MAXINT);
-    }
-
-    nm_assert(rstr0->r.str == rstr0->str_data);
-    nm_assert(rstr0->r.str[rstr0->r.len] == '\0');
-
-    if (NM_MORE_ASSERTS > 10) {
-        G_LOCK(gl_lock);
-        r = g_atomic_int_get(&rstr0->ref_count);
-        nm_assert(r > 0);
-        nm_assert(r < G_MAXINT);
-
-        nm_assert(rstr0 == g_hash_table_lookup(gl_hash, rstr0));
-        G_UNLOCK(gl_lock);
-    }
-}
-
-/**
- * nm_ref_string_new_len:
- * @cstr: the string to intern. Must contain @len bytes.
- *   If @len is zero, @cstr may be %NULL. Note that it is
- *   acceptable that the string contains a NUL character
- *   within the first @len bytes. That is, the string is
- *   not treated as a NUL terminated string, but as binary.
- *   Also, contrary to strncpy(), this will read all the
- *   first @len bytes. It won't stop at the first NUL.
- * @len: the length of the string (usually there is no NUL character
- *   within the first @len bytes, but that would be acceptable as well
- *   to add binary data).
- *
- * Note that the resulting NMRefString instance will always be NUL terminated
- * (at position @len).
- *
- * Note that NMRefString are always interned/deduplicated. If such a string
- * already exists, the existing instance will be referred and returned.
- *
- *
- * Since all NMRefString are shared and interned, you may use
- * pointer equality to compare them. Note that if a NMRefString contains
- * a NUL character (meaning, if
- *
- *    strlen (nm_ref_string_get_str (str)) != nm_ref_string_get_len (str)
- *
- * ), then pointer in-equality does not mean that the NUL terminated strings
- * are also unequal. In other words, for strings that contain NUL characters,
- *
- *    if (str1 != str2)
- *       assert (!nm_streq0 (nm_ref_string_get_str (str1), nm_ref_string_get_str (str2)));
- *
- * might not hold!
- *
- *
- * NMRefString is thread-safe.
- *
- * Returns: (transfer full): the interned string. This is
- *   never %NULL, but note that %NULL is also a valid NMRefString.
- *   The result must be unrefed with nm_ref_string_unref().
- */
-NMRefString *
-nm_ref_string_new_len(const char *cstr, gsize len)
-{
-    RefString *rstr0;
-
-    G_LOCK(gl_lock);
-
-    if (G_UNLIKELY(!gl_hash)) {
-        gl_hash = g_hash_table_new_full(_ref_string_hash, _ref_string_equal, g_free, NULL);
-        rstr0   = NULL;
-    } else {
-        NMRefString rr_lookup = {
-            .len = len,
-            .str = cstr,
-        };
-
-        rstr0 = g_hash_table_lookup(gl_hash, &rr_lookup);
-    }
-
-    if (rstr0) {
-        nm_assert(({
-            int r = g_atomic_int_get(&rstr0->ref_count);
-
-            (r >= 0 && r < G_MAXINT);
-        }));
-        g_atomic_int_inc(&rstr0->ref_count);
-    } else {
-        rstr0                            = g_malloc(sizeof(RefString) + 1 + len);
-        rstr0->ref_count                 = 1;
-        *((gsize *) &rstr0->r.len)       = len;
-        *((const char **) &rstr0->r.str) = rstr0->str_data;
-        if (len > 0)
-            memcpy(rstr0->str_data, cstr, len);
-        rstr0->str_data[len] = '\0';
-
-        if (!g_hash_table_add(gl_hash, rstr0))
-            nm_assert_not_reached();
-    }
-
-    G_UNLOCK(gl_lock);
-
-    return &rstr0->r;
-}
-
-NMRefString *
-nm_ref_string_ref(NMRefString *rstr)
-{
-    RefString *const rstr0 = (RefString *) rstr;
-
-    if (!rstr)
-        return NULL;
-
-    _ASSERT(rstr0);
-
-    g_atomic_int_inc(&rstr0->ref_count);
-    return &rstr0->r;
-}
-
-void
-_nm_ref_string_unref_non_null(NMRefString *rstr)
-{
-    RefString *const rstr0 = (RefString *) rstr;
-    int              r;
-
-    _ASSERT(rstr0);
-
-    /* fast-path: first try to decrement the ref-count without bringing it
-     * to zero. */
-    r = rstr0->ref_count;
-    if (G_LIKELY(r > 1 && g_atomic_int_compare_and_exchange(&rstr0->ref_count, r, r - 1)))
-        return;
-
-    /* We apparently are about to return the last reference. Take a lock. */
-
-    G_LOCK(gl_lock);
-
-    nm_assert(g_hash_table_lookup(gl_hash, rstr0) == rstr0);
-
-    if (G_LIKELY(g_atomic_int_dec_and_test(&rstr0->ref_count))) {
-        if (!g_hash_table_remove(gl_hash, rstr0))
-            nm_assert_not_reached();
-    }
-
-    G_UNLOCK(gl_lock);
-}
-
-/*****************************************************************************/
diff --git a/shared/nm-glib-aux/nm-ref-string.h b/shared/nm-glib-aux/nm-ref-string.h
deleted file mode 100644
index 97c263b0..00000000
--- a/shared/nm-glib-aux/nm-ref-string.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef __NM_REF_STRING_H__
-#define __NM_REF_STRING_H__
-
-/*****************************************************************************/
-
-typedef struct _NMRefString {
-    const char *const str;
-    const gsize       len;
-} NMRefString;
-
-/*****************************************************************************/
-
-NMRefString *nm_ref_string_new_len(const char *cstr, gsize len);
-
-static inline NMRefString *
-nm_ref_string_new(const char *cstr)
-{
-    return cstr ? nm_ref_string_new_len(cstr, strlen(cstr)) : NULL;
-}
-
-NMRefString *nm_ref_string_ref(NMRefString *rstr);
-void         _nm_ref_string_unref_non_null(NMRefString *rstr);
-
-static inline void
-nm_ref_string_unref(NMRefString *rstr)
-{
-    if (rstr)
-        _nm_ref_string_unref_non_null(rstr);
-}
-
-NM_AUTO_DEFINE_FCN_VOID0(NMRefString *, _nm_auto_ref_string, _nm_ref_string_unref_non_null);
-#define nm_auto_ref_string nm_auto(_nm_auto_ref_string)
-
-/*****************************************************************************/
-
-static inline const char *
-nm_ref_string_get_str(NMRefString *rstr)
-{
-    return rstr ? rstr->str : NULL;
-}
-
-static inline gsize
-nm_ref_string_get_len(NMRefString *rstr)
-{
-    return rstr ? rstr->len : 0u;
-}
-
-static inline gboolean
-nm_ref_string_equals_str(NMRefString *rstr, const char *s)
-{
-    /* Note that rstr->len might be greater than strlen(rstr->str). This function does
-     * not cover that and would ignore everything after the first NUL byte. If you need
-     * that distinction, this function is not for you. */
-
-    return rstr ? (s && nm_streq(rstr->str, s)) : (s == NULL);
-}
-
-static inline gboolean
-NM_IS_REF_STRING(const NMRefString *rstr)
-{
-#if NM_MORE_ASSERTS > 10
-    if (rstr) {
-        nm_auto_ref_string NMRefString *r2 = NULL;
-
-        r2 = nm_ref_string_new_len(rstr->str, rstr->len);
-        nm_assert(rstr == r2);
-    }
-#endif
-
-    /* Technically, %NULL is also a valid NMRefString (according to nm_ref_string_new(),
-     * nm_ref_string_get_str() and nm_ref_string_unref()). However, NM_IS_REF_STRING()
-     * does not think so. If callers want to allow %NULL, they need to check
-     * separately. */
-    return !!rstr;
-}
-
-#endif /* __NM_REF_STRING_H__ */
diff --git a/shared/nm-glib-aux/nm-secret-utils.c b/shared/nm-glib-aux/nm-secret-utils.c
deleted file mode 100644
index 8188b503..00000000
--- a/shared/nm-glib-aux/nm-secret-utils.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- * Copyright (C) 2015 - 2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-secret-utils.h"
-
-#include <malloc.h>
-
-/*****************************************************************************/
-
-void
-nm_explicit_bzero(void *s, gsize n)
-{
-    /* gracefully handle n == 0. This is important, callers rely on it. */
-    if (G_UNLIKELY(n == 0))
-        return;
-
-    nm_assert(s);
-
-#if defined(HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO
-    explicit_bzero(s, n);
-#else
-    {
-        volatile guint8 *p = s;
-
-        memset(s, '\0', n);
-        while (n-- > 0)
-            *(p++) = '\0';
-    }
-#endif
-}
-
-void
-nm_free_secret(char *secret)
-{
-    gsize len;
-
-    if (!secret)
-        return;
-
-#if GLIB_CHECK_VERSION(2, 44, 0)
-    /* Here we mix malloc() and g_malloc() API. Usually we avoid this,
-     * however since glib 2.44.0 we are in fact guaranteed that g_malloc()/g_free()
-     * just wraps malloc()/free(), so this is actually fine.
-     *
-     * See https://gitlab.gnome.org/GNOME/glib/commit/3be6ed60aa58095691bd697344765e715a327fc1
-     */
-    len = malloc_usable_size(secret);
-#else
-    len = strlen(secret);
-#endif
-
-    nm_explicit_bzero(secret, len);
-    g_free(secret);
-}
-
-/*****************************************************************************/
-
-char *
-nm_secret_strchomp(char *secret)
-{
-    gsize len;
-
-    g_return_val_if_fail(secret, NULL);
-
-    /* it's actually identical to g_strchomp(). However,
-     * the glib function does not document, that it clears the
-     * memory. For @secret, we don't only want to truncate trailing
-     * spaces, we want to overwrite them with NUL. */
-
-    len = strlen(secret);
-    while (len--) {
-        if (g_ascii_isspace((guchar) secret[len]))
-            secret[len] = '\0';
-        else
-            break;
-    }
-
-    return secret;
-}
-
-/*****************************************************************************/
-
-GBytes *
-nm_secret_copy_to_gbytes(gconstpointer mem, gsize mem_len)
-{
-    NMSecretBuf *b;
-
-    if (mem_len == 0)
-        return g_bytes_new_static("", 0);
-
-    nm_assert(mem);
-
-    /* NUL terminate the buffer.
-     *
-     * The entire buffer is already malloc'ed and likely has some room for padding.
-     * Thus, in many situations, this additional byte will cause no overhead in
-     * practice.
-     *
-     * Even if it causes an overhead, do it just for safety. Yes, the returned
-     * bytes is not a NUL terminated string and no user must rely on this. Do
-     * not treat binary data as NUL terminated strings, unless you know what
-     * you are doing. Anyway, defensive FTW.
-     */
-
-    b = nm_secret_buf_new(mem_len + 1);
-    memcpy(b->bin, mem, mem_len);
-    b->bin[mem_len] = 0;
-    return nm_secret_buf_to_gbytes_take(b, mem_len);
-}
-
-/*****************************************************************************/
-
-NMSecretBuf *
-nm_secret_buf_new(gsize len)
-{
-    NMSecretBuf *secret;
-
-    nm_assert(len > 0);
-
-    secret                      = g_malloc(sizeof(NMSecretBuf) + len);
-    *((gsize *) &(secret->len)) = len;
-    return secret;
-}
-
-static void
-_secret_buf_free(gpointer user_data)
-{
-    NMSecretBuf *secret = user_data;
-
-    nm_assert(secret);
-    nm_assert(secret->len > 0);
-
-    nm_explicit_bzero(secret->bin, secret->len);
-    g_free(user_data);
-}
-
-GBytes *
-nm_secret_buf_to_gbytes_take(NMSecretBuf *secret, gssize actual_len)
-{
-    nm_assert(secret);
-    nm_assert(secret->len > 0);
-    nm_assert(actual_len == -1 || (actual_len >= 0 && actual_len <= secret->len));
-    return g_bytes_new_with_free_func(secret->bin,
-                                      actual_len >= 0 ? (gsize) actual_len : secret->len,
-                                      _secret_buf_free,
-                                      secret);
-}
-
-/*****************************************************************************/
-
-/**
- * nm_utils_memeqzero_secret:
- * @data: the data pointer to check (may be %NULL if @length is zero).
- * @length: the number of bytes to check.
- *
- * Checks that all bytes are zero. This always takes the same amount
- * of time to prevent timing attacks.
- *
- * Returns: whether all bytes are zero.
- */
-gboolean
-nm_utils_memeqzero_secret(gconstpointer data, gsize length)
-{
-    const guint8 *const key = data;
-    volatile guint8     acc = 0;
-    gsize               i;
-
-    for (i = 0; i < length; i++) {
-        acc |= key[i];
-        asm volatile("" : "=r"(acc) : "0"(acc));
-    }
-    return 1 & ((acc - 1) >> 8);
-}
diff --git a/shared/nm-glib-aux/nm-secret-utils.h b/shared/nm-glib-aux/nm-secret-utils.h
deleted file mode 100644
index ac279635..00000000
--- a/shared/nm-glib-aux/nm-secret-utils.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_SECRET_UTILS_H__
-#define __NM_SECRET_UTILS_H__
-
-#include "nm-macros-internal.h"
-
-/*****************************************************************************/
-
-void nm_explicit_bzero(void *s, gsize n);
-
-/*****************************************************************************/
-
-char *nm_secret_strchomp(char *secret);
-
-/*****************************************************************************/
-
-void nm_free_secret(char *secret);
-
-NM_AUTO_DEFINE_FCN0(char *, _nm_auto_free_secret, nm_free_secret);
-/**
- * nm_auto_free_secret:
- *
- * Call g_free() on a variable location when it goes out of scope.
- * Also, previously, calls memset(loc, 0, strlen(loc)) to clear out
- * the secret.
- */
-#define nm_auto_free_secret nm_auto(_nm_auto_free_secret)
-
-/*****************************************************************************/
-
-GBytes *nm_secret_copy_to_gbytes(gconstpointer mem, gsize mem_len);
-
-/*****************************************************************************/
-
-/* NMSecretPtr is a pair of malloc'ed data pointer and the length of the
- * data. The purpose is to use it in combination with nm_auto_clear_secret_ptr
- * which ensures that the data pointer (with all len bytes) is cleared upon
- * cleanup. */
-typedef struct {
-    gsize len;
-
-    /* the data pointer. This pointer must be allocated with malloc (at least
-     * when used with nm_secret_ptr_clear()). */
-    union {
-        char *  str;
-        void *  ptr;
-        guint8 *bin;
-    };
-} NMSecretPtr;
-
-static inline void
-nm_secret_ptr_bzero(NMSecretPtr *secret)
-{
-    if (secret) {
-        if (secret->len > 0) {
-            if (secret->ptr)
-                nm_explicit_bzero(secret->ptr, secret->len);
-        }
-    }
-}
-
-#define nm_auto_bzero_secret_ptr nm_auto(nm_secret_ptr_bzero)
-
-static inline void
-nm_secret_ptr_clear(NMSecretPtr *secret)
-{
-    if (secret) {
-        if (secret->len > 0) {
-            if (secret->ptr)
-                nm_explicit_bzero(secret->ptr, secret->len);
-            secret->len = 0;
-        }
-        nm_clear_g_free(&secret->ptr);
-    }
-}
-
-#define nm_auto_clear_secret_ptr nm_auto(nm_secret_ptr_clear)
-
-#define NM_SECRET_PTR_INIT() \
-    ((const NMSecretPtr){    \
-        .len = 0,            \
-        .ptr = NULL,         \
-    })
-
-#define NM_SECRET_PTR_STATIC(_len) \
-    ((const NMSecretPtr){          \
-        .len = _len,               \
-        .ptr = ((guint8[_len]){}), \
-    })
-
-#define NM_SECRET_PTR_ARRAY(_arr)                      \
-    ((const NMSecretPtr){                              \
-        .len = G_N_ELEMENTS(_arr) * sizeof((_arr)[0]), \
-        .ptr = &((_arr)[0]),                           \
-    })
-
-static inline void
-nm_secret_ptr_clear_static(const NMSecretPtr *secret)
-{
-    if (secret) {
-        if (secret->len > 0) {
-            nm_assert(secret->ptr);
-            nm_explicit_bzero(secret->ptr, secret->len);
-        }
-    }
-}
-
-#define nm_auto_clear_static_secret_ptr nm_auto(nm_secret_ptr_clear_static)
-
-static inline void
-nm_secret_ptr_move(NMSecretPtr *dst, NMSecretPtr *src)
-{
-    if (dst && dst != src) {
-        *dst     = *src;
-        src->len = 0;
-        src->ptr = NULL;
-    }
-}
-
-/*****************************************************************************/
-
-typedef struct {
-    const gsize len;
-    union {
-        char   str[0];
-        guint8 bin[0];
-    };
-} NMSecretBuf;
-
-static inline void
-_nm_auto_free_secret_buf(NMSecretBuf **ptr)
-{
-    NMSecretBuf *b = *ptr;
-
-    if (b) {
-        nm_assert(b->len > 0);
-        nm_explicit_bzero(b->bin, b->len);
-        g_free(b);
-    }
-}
-#define nm_auto_free_secret_buf nm_auto(_nm_auto_free_secret_buf)
-
-NMSecretBuf *nm_secret_buf_new(gsize len);
-
-GBytes *nm_secret_buf_to_gbytes_take(NMSecretBuf *secret, gssize actual_len);
-
-/*****************************************************************************/
-
-gboolean nm_utils_memeqzero_secret(gconstpointer data, gsize length);
-
-/*****************************************************************************/
-
-/**
- * nm_secret_mem_realloc:
- * @m_old: the current buffer of length @cur_len.
- * @do_bzero_mem: if %TRUE, bzero the old buffer
- * @cur_len: the current buffer length of @m_old. It is necessary for bzero.
- * @new_len: the desired new length
- *
- * If @do_bzero_mem is false, this is like g_realloc().
- * Otherwise, this will allocate a new buffer of the desired size, copy over the
- * old data, and bzero the old buffer before freeing it. As such, it also behaves
- * similar to g_realloc(), with the overhead of nm_explicit_bzero() and using
- * malloc/free instead of realloc().
- *
- * Returns: the new allocated buffer. Think of it behaving like g_realloc().
- */
-static inline gpointer
-nm_secret_mem_realloc(gpointer m_old, gboolean do_bzero_mem, gsize cur_len, gsize new_len)
-{
-    gpointer m_new;
-
-    nm_assert(m_old || cur_len == 0);
-
-    if (do_bzero_mem && G_LIKELY(cur_len > 0)) {
-        m_new = g_malloc(new_len);
-        if (G_LIKELY(new_len > 0))
-            memcpy(m_new, m_old, NM_MIN(cur_len, new_len));
-        nm_explicit_bzero(m_old, cur_len);
-        g_free(m_old);
-    } else
-        m_new = g_realloc(m_old, new_len);
-
-    return m_new;
-}
-
-/**
- * nm_secret_mem_try_realloc:
- * @m_old: the current buffer of length @cur_len.
- * @do_bzero_mem: if %TRUE, bzero the old buffer
- * @cur_len: the current buffer length of @m_old. It is necessary for bzero.
- * @new_len: the desired new length
- *
- * If @do_bzero_mem is false, this is like g_try_realloc().
- * Otherwise, this will try to allocate a new buffer of the desired size, copy over the
- * old data, and bzero the old buffer before freeing it. As such, it also behaves
- * similar to g_try_realloc(), with the overhead of nm_explicit_bzero() and using
- * malloc/free instead of realloc().
- *
- * Returns: the new allocated buffer or NULL. Think of it behaving like g_try_realloc().
- */
-static inline gpointer
-nm_secret_mem_try_realloc(gpointer m_old, gboolean do_bzero_mem, gsize cur_len, gsize new_len)
-{
-    gpointer m_new;
-
-    nm_assert(m_old || cur_len == 0);
-
-    if (do_bzero_mem && G_LIKELY(cur_len > 0)) {
-        if (G_UNLIKELY(new_len == 0))
-            m_new = NULL;
-        else {
-            m_new = g_try_malloc(new_len);
-            if (!m_new)
-                return NULL;
-            memcpy(m_new, m_old, NM_MIN(cur_len, new_len));
-        }
-        nm_explicit_bzero(m_old, cur_len);
-        g_free(m_old);
-        return m_new;
-    }
-
-    return g_try_realloc(m_old, new_len);
-}
-
-/**
- * nm_secret_mem_try_realloc_take:
- * @m_old: the current buffer of length @cur_len.
- * @do_bzero_mem: if %TRUE, bzero the old buffer
- * @cur_len: the current buffer length of @m_old. It is necessary for bzero.
- * @new_len: the desired new length
- *
- * This works like nm_secret_mem_try_realloc(), which is not unlike g_try_realloc().
- * The difference is, if we fail to allocate a new buffer, then @m_old will be
- * freed (and possibly cleared). This differs from plain realloc(), where the
- * old buffer is unchanged if the operation fails.
- *
- * Returns: the new allocated buffer or NULL. Think of it behaving like g_try_realloc()
- *   but it will always free @m_old.
- */
-static inline gpointer
-nm_secret_mem_try_realloc_take(gpointer m_old, gboolean do_bzero_mem, gsize cur_len, gsize new_len)
-{
-    gpointer m_new;
-
-    nm_assert(m_old || cur_len == 0);
-
-    if (do_bzero_mem && G_LIKELY(cur_len > 0)) {
-        if (G_UNLIKELY(new_len == 0))
-            m_new = NULL;
-        else {
-            m_new = g_try_malloc(new_len);
-            if (G_LIKELY(m_new))
-                memcpy(m_new, m_old, NM_MIN(cur_len, new_len));
-        }
-        nm_explicit_bzero(m_old, cur_len);
-        g_free(m_old);
-        return m_new;
-    }
-
-    m_new = g_try_realloc(m_old, new_len);
-    if (G_UNLIKELY(!m_new && new_len > 0))
-        g_free(m_old);
-    return m_new;
-}
-
-/*****************************************************************************/
-
-#endif /* __NM_SECRET_UTILS_H__ */
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
deleted file mode 100644
index e7cea23a..00000000
--- a/shared/nm-glib-aux/nm-shared-utils.c
+++ /dev/null
@@ -1,5789 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2016 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-shared-utils.h"
-
-#include <pwd.h>
-#include <arpa/inet.h>
-#include <poll.h>
-#include <fcntl.h>
-#include <sys/syscall.h>
-#include <glib-unix.h>
-#include <net/if.h>
-#include <net/ethernet.h>
-#include <pthread.h>
-
-#include "c-list/src/c-list.h"
-#include "nm-errno.h"
-#include "nm-str-buf.h"
-
-G_STATIC_ASSERT(sizeof(NMEtherAddr) == 6);
-G_STATIC_ASSERT(_nm_alignof(NMEtherAddr) == 1);
-
-G_STATIC_ASSERT(sizeof(NMUtilsNamedEntry) == sizeof(const char *));
-G_STATIC_ASSERT(G_STRUCT_OFFSET(NMUtilsNamedValue, value_ptr) == sizeof(const char *));
-
-/*****************************************************************************/
-
-const char _nm_hexchar_table_lower[16] = "0123456789abcdef";
-const char _nm_hexchar_table_upper[16] = "0123456789ABCDEF";
-
-const void *const _NM_PTRARRAY_EMPTY[1] = {NULL};
-
-/*****************************************************************************/
-
-const NMIPAddr nm_ip_addr_zero = {};
-
-/* this initializes a struct in_addr/in6_addr and allows for untrusted
- * arguments (like unsuitable @addr_family or @src_len). It's almost safe
- * in the sense that it verifies input arguments strictly. Also, it
- * uses memcpy() to access @src, so alignment is not an issue.
- *
- * Only potential pitfalls:
- *
- * - it allows for @addr_family to be AF_UNSPEC. If that is the case (and the
- *   caller allows for that), the caller MUST provide @out_addr_family.
- * - when setting @dst to an IPv4 address, the trailing bytes are not touched.
- *   Meaning, if @dst is an NMIPAddr union, only the first bytes will be set.
- *   If that matter to you, clear @dst before. */
-gboolean
-nm_ip_addr_set_from_untrusted(int           addr_family,
-                              gpointer      dst,
-                              gconstpointer src,
-                              gsize         src_len,
-                              int *         out_addr_family)
-{
-    nm_assert(dst);
-
-    switch (addr_family) {
-    case AF_UNSPEC:
-        if (!out_addr_family) {
-            /* when the callers allow undefined @addr_family, they must provide
-             * an @out_addr_family argument. */
-            nm_assert_not_reached();
-            return FALSE;
-        }
-        switch (src_len) {
-        case sizeof(struct in_addr):
-            addr_family = AF_INET;
-            break;
-        case sizeof(struct in6_addr):
-            addr_family = AF_INET6;
-            break;
-        default:
-            return FALSE;
-        }
-        break;
-    case AF_INET:
-        if (src_len != sizeof(struct in_addr))
-            return FALSE;
-        break;
-    case AF_INET6:
-        if (src_len != sizeof(struct in6_addr))
-            return FALSE;
-        break;
-    default:
-        /* when the callers allow undefined @addr_family, they must provide
-         * an @out_addr_family argument. */
-        nm_assert(out_addr_family);
-        return FALSE;
-    }
-
-    nm_assert(src);
-
-    memcpy(dst, src, src_len);
-    NM_SET_OUT(out_addr_family, addr_family);
-    return TRUE;
-}
-
-/*****************************************************************************/
-
-G_STATIC_ASSERT(ETH_ALEN == sizeof(struct ether_addr));
-G_STATIC_ASSERT(ETH_ALEN == 6);
-
-/*****************************************************************************/
-
-pid_t
-nm_utils_gettid(void)
-{
-    return (pid_t) syscall(SYS_gettid);
-}
-
-/* Used for asserting that this function is called on the main-thread.
- * The main-thread is determined by remembering the thread-id
- * of when the function was called the first time.
- *
- * When forking, the thread-id is again reset upon first call. */
-gboolean
-_nm_assert_on_main_thread(void)
-{
-    G_LOCK_DEFINE_STATIC(lock);
-    static pid_t seen_tid;
-    static pid_t seen_pid;
-    pid_t        tid;
-    pid_t        pid;
-    gboolean     success = FALSE;
-
-    tid = nm_utils_gettid();
-    nm_assert(tid != 0);
-
-    G_LOCK(lock);
-
-    if (G_LIKELY(tid == seen_tid)) {
-        /* we don't care about false positives (when the process forked, and the thread-id
-         * is accidentally re-used) . It's for assertions only. */
-        success = TRUE;
-    } else {
-        pid = getpid();
-        nm_assert(pid != 0);
-
-        if (seen_tid == 0 || seen_pid != pid) {
-            /* either this is the first time we call the function, or the process
-             * forked. In both cases, remember the thread-id. */
-            seen_tid = tid;
-            seen_pid = pid;
-            success  = TRUE;
-        }
-    }
-
-    G_UNLOCK(lock);
-
-    return success;
-}
-
-/*****************************************************************************/
-
-void
-nm_utils_strbuf_append_c(char **buf, gsize *len, char c)
-{
-    switch (*len) {
-    case 0:
-        return;
-    case 1:
-        (*buf)[0] = '\0';
-        *len      = 0;
-        (*buf)++;
-        return;
-    default:
-        (*buf)[0] = c;
-        (*buf)[1] = '\0';
-        (*len)--;
-        (*buf)++;
-        return;
-    }
-}
-
-void
-nm_utils_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len)
-{
-    switch (*len) {
-    case 0:
-        return;
-    case 1:
-        if (str_len == 0) {
-            (*buf)[0] = '\0';
-            return;
-        }
-        (*buf)[0] = '\0';
-        *len      = 0;
-        (*buf)++;
-        return;
-    default:
-        if (str_len == 0) {
-            (*buf)[0] = '\0';
-            return;
-        }
-        if (str_len >= *len) {
-            memcpy(*buf, str, *len - 1);
-            (*buf)[*len - 1] = '\0';
-            *buf             = &(*buf)[*len];
-            *len             = 0;
-        } else {
-            memcpy(*buf, str, str_len);
-            *buf      = &(*buf)[str_len];
-            (*buf)[0] = '\0';
-            *len -= str_len;
-        }
-        return;
-    }
-}
-
-void
-nm_utils_strbuf_append_str(char **buf, gsize *len, const char *str)
-{
-    gsize src_len;
-
-    switch (*len) {
-    case 0:
-        return;
-    case 1:
-        if (!str || !*str) {
-            (*buf)[0] = '\0';
-            return;
-        }
-        (*buf)[0] = '\0';
-        *len      = 0;
-        (*buf)++;
-        return;
-    default:
-        if (!str || !*str) {
-            (*buf)[0] = '\0';
-            return;
-        }
-        src_len = g_strlcpy(*buf, str, *len);
-        if (src_len >= *len) {
-            *buf = &(*buf)[*len];
-            *len = 0;
-        } else {
-            *buf = &(*buf)[src_len];
-            *len -= src_len;
-        }
-        return;
-    }
-}
-
-void
-nm_utils_strbuf_append(char **buf, gsize *len, const char *format, ...)
-{
-    char *  p = *buf;
-    va_list args;
-    int     retval;
-
-    if (*len == 0)
-        return;
-
-    va_start(args, format);
-    retval = g_vsnprintf(p, *len, format, args);
-    va_end(args);
-
-    if ((gsize) retval >= *len) {
-        *buf = &p[*len];
-        *len = 0;
-    } else {
-        *buf = &p[retval];
-        *len -= retval;
-    }
-}
-
-/**
- * nm_utils_strbuf_seek_end:
- * @buf: the input/output buffer
- * @len: the input/output length of the buffer.
- *
- * Commonly, one uses nm_utils_strbuf_append*(), to incrementally
- * append strings to the buffer. However, sometimes we need to use
- * existing API to write to the buffer.
- * After doing so, we want to adjust the buffer counter.
- * Essentially,
- *
- *   g_snprintf (buf, len, ...);
- *   nm_utils_strbuf_seek_end (&buf, &len);
- *
- * is almost the same as
- *
- *   nm_utils_strbuf_append (&buf, &len, ...);
- *
- * The only difference is the behavior when the string got truncated:
- * nm_utils_strbuf_append() will recognize that and set the remaining
- * length to zero.
- *
- * In general, the behavior is:
- *
- *  - if *len is zero, do nothing
- *  - if the buffer contains a NUL byte within the first *len characters,
- *    the buffer is pointed to the NUL byte and len is adjusted. In this
- *    case, the remaining *len is always >= 1.
- *    In particular, that is also the case if the NUL byte is at the very last
- *    position ((*buf)[*len -1]). That happens, when the previous operation
- *    either fit the string exactly into the buffer or the string was truncated
- *    by g_snprintf(). The difference cannot be determined.
- *  - if the buffer contains no NUL bytes within the first *len characters,
- *    write NUL at the last position, set *len to zero, and point *buf past
- *    the NUL byte. This would happen with
- *
- *       strncpy (buf, long_str, len);
- *       nm_utils_strbuf_seek_end (&buf, &len).
- *
- *    where strncpy() does truncate the string and not NUL terminate it.
- *    nm_utils_strbuf_seek_end() would then NUL terminate it.
- */
-void
-nm_utils_strbuf_seek_end(char **buf, gsize *len)
-{
-    gsize l;
-    char *end;
-
-    nm_assert(len);
-    nm_assert(buf && *buf);
-
-    if (*len <= 1) {
-        if (*len == 1 && (*buf)[0])
-            goto truncate;
-        return;
-    }
-
-    end = memchr(*buf, 0, *len);
-    if (end) {
-        l = end - *buf;
-        nm_assert(l < *len);
-
-        *buf = end;
-        *len -= l;
-        return;
-    }
-
-truncate:
-    /* hm, no NUL character within len bytes.
-     * Just NUL terminate the array and consume them
-     * all. */
-    *buf += *len;
-    (*buf)[-1] = '\0';
-    *len       = 0;
-    return;
-}
-
-/*****************************************************************************/
-
-GBytes *
-nm_gbytes_get_empty(void)
-{
-    static GBytes *bytes = NULL;
-    GBytes *       b;
-
-again:
-    b = g_atomic_pointer_get(&bytes);
-    if (G_UNLIKELY(!b)) {
-        b = g_bytes_new_static("", 0);
-        if (!g_atomic_pointer_compare_and_exchange(&bytes, NULL, b)) {
-            g_bytes_unref(b);
-            goto again;
-        }
-    }
-    return b;
-}
-
-GBytes *
-nm_g_bytes_new_from_str(const char *str)
-{
-    gsize l;
-
-    if (!str)
-        return NULL;
-
-    /* the returned array is guaranteed to have a trailing '\0'
-     * character *after* the length. */
-
-    l = strlen(str);
-    return g_bytes_new_take(nm_memdup(str, l + 1u), l);
-}
-
-/**
- * nm_utils_gbytes_equals:
- * @bytes: (allow-none): a #GBytes array to compare. Note that
- *   %NULL is treated like an #GBytes array of length zero.
- * @mem_data: the data pointer with @mem_len bytes
- * @mem_len: the length of the data pointer
- *
- * Returns: %TRUE if @bytes contains the same data as @mem_data. As a
- *   special case, a %NULL @bytes is treated like an empty array.
- */
-gboolean
-nm_utils_gbytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len)
-{
-    gconstpointer p;
-    gsize         l;
-
-    if (!bytes) {
-        /* as a special case, let %NULL GBytes compare identical
-         * to an empty array. */
-        return (mem_len == 0);
-    }
-
-    p = g_bytes_get_data(bytes, &l);
-    return l == mem_len
-           && (mem_len == 0 /* allow @mem_data to be %NULL */
-               || memcmp(p, mem_data, mem_len) == 0);
-}
-
-GVariant *
-nm_utils_gbytes_to_variant_ay(GBytes *bytes)
-{
-    const guint8 *p;
-    gsize         l;
-
-    if (!bytes) {
-        /* for convenience, accept NULL to return an empty variant */
-        return g_variant_new_array(G_VARIANT_TYPE_BYTE, NULL, 0);
-    }
-
-    p = g_bytes_get_data(bytes, &l);
-    return g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, p, l, 1);
-}
-
-/*****************************************************************************/
-
-#define _variant_singleton_get(create_variant)                                   \
-    ({                                                                           \
-        static GVariant *_singleton = NULL;                                      \
-        GVariant *       _v;                                                     \
-                                                                                 \
-again:                                                                           \
-        _v = g_atomic_pointer_get(&_singleton);                                  \
-        if (G_UNLIKELY(!_v)) {                                                   \
-            _v = (create_variant);                                               \
-            nm_assert(_v);                                                       \
-            nm_assert(g_variant_is_floating(_v));                                \
-            g_variant_ref_sink(_v);                                              \
-            if (!g_atomic_pointer_compare_and_exchange(&_singleton, NULL, _v)) { \
-                g_variant_unref(_v);                                             \
-                goto again;                                                      \
-            }                                                                    \
-        }                                                                        \
-        _v;                                                                      \
-    })
-
-GVariant *
-nm_g_variant_singleton_u_0(void)
-{
-    return _variant_singleton_get(g_variant_new_uint32(0));
-}
-
-/*****************************************************************************/
-
-GHashTable *
-nm_utils_strdict_clone(GHashTable *src)
-{
-    GHashTable *   dst;
-    GHashTableIter iter;
-    const char *   key;
-    const char *   val;
-
-    if (!src)
-        return NULL;
-
-    dst = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
-    g_hash_table_iter_init(&iter, src);
-    while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val))
-        g_hash_table_insert(dst, g_strdup(key), g_strdup(val));
-    return dst;
-}
-
-/* Convert a hash table with "char *" keys and values to an "a{ss}" GVariant.
- * The keys will be sorted asciibetically.
- * Returns a floating reference.
- */
-GVariant *
-nm_utils_strdict_to_variant_ass(GHashTable *strdict)
-{
-    gs_free NMUtilsNamedValue *values_free = NULL;
-    NMUtilsNamedValue          values_prepared[20];
-    const NMUtilsNamedValue *  values;
-    GVariantBuilder            builder;
-    guint                      i;
-    guint                      n;
-
-    values = nm_utils_named_values_from_strdict(strdict, &n, values_prepared, &values_free);
-
-    g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
-    for (i = 0; i < n; i++) {
-        g_variant_builder_add(&builder, "{ss}", values[i].name, values[i].value_str);
-    }
-    return g_variant_builder_end(&builder);
-}
-
-/*****************************************************************************/
-
-GVariant *
-nm_utils_strdict_to_variant_asv(GHashTable *strdict)
-{
-    gs_free NMUtilsNamedValue *values_free = NULL;
-    NMUtilsNamedValue          values_prepared[20];
-    const NMUtilsNamedValue *  values;
-    GVariantBuilder            builder;
-    guint                      i;
-    guint                      n;
-
-    values = nm_utils_named_values_from_strdict(strdict, &n, values_prepared, &values_free);
-
-    g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}"));
-    for (i = 0; i < n; i++) {
-        g_variant_builder_add(&builder,
-                              "{sv}",
-                              values[i].name,
-                              g_variant_new_string(values[i].value_str));
-    }
-    return g_variant_builder_end(&builder);
-}
-
-/*****************************************************************************/
-
-/**
- * nm_strquote:
- * @buf: the output buffer of where to write the quoted @str argument.
- * @buf_len: the size of @buf.
- * @str: (allow-none): the string to quote.
- *
- * Writes @str to @buf with quoting. The resulting buffer
- * is always NUL terminated, unless @buf_len is zero.
- * If @str is %NULL, it writes "(null)".
- *
- * If @str needs to be truncated, the closing quote is '^' instead
- * of '"'.
- *
- * This is similar to nm_strquote_a(), which however uses alloca()
- * to allocate a new buffer. Also, here @buf_len is the size of @buf,
- * while nm_strquote_a() has the number of characters to print. The latter
- * doesn't include the quoting.
- *
- * Returns: the input buffer with the quoted string.
- */
-const char *
-nm_strquote(char *buf, gsize buf_len, const char *str)
-{
-    const char *const buf0 = buf;
-
-    if (!str) {
-        nm_utils_strbuf_append_str(&buf, &buf_len, "(null)");
-        goto out;
-    }
-
-    if (G_UNLIKELY(buf_len <= 2)) {
-        switch (buf_len) {
-        case 2:
-            *(buf++) = '^';
-            /* fall-through */
-        case 1:
-            *(buf++) = '\0';
-            break;
-        }
-        goto out;
-    }
-
-    *(buf++) = '"';
-    buf_len--;
-
-    nm_utils_strbuf_append_str(&buf, &buf_len, str);
-
-    /* if the string was too long we indicate truncation with a
-     * '^' instead of a closing quote. */
-    if (G_UNLIKELY(buf_len <= 1)) {
-        switch (buf_len) {
-        case 1:
-            buf[-1] = '^';
-            break;
-        case 0:
-            buf[-2] = '^';
-            break;
-        default:
-            nm_assert_not_reached();
-            break;
-        }
-    } else {
-        nm_assert(buf_len >= 2);
-        *(buf++) = '"';
-        *(buf++) = '\0';
-    }
-
-out:
-    return buf0;
-}
-
-/*****************************************************************************/
-
-char _nm_utils_to_string_buffer[];
-
-void
-nm_utils_to_string_buffer_init(char **buf, gsize *len)
-{
-    if (!*buf) {
-        *buf = _nm_utils_to_string_buffer;
-        *len = sizeof(_nm_utils_to_string_buffer);
-    }
-}
-
-gboolean
-nm_utils_to_string_buffer_init_null(gconstpointer obj, char **buf, gsize *len)
-{
-    nm_utils_to_string_buffer_init(buf, len);
-    if (!obj) {
-        g_strlcpy(*buf, "(null)", *len);
-        return FALSE;
-    }
-    return TRUE;
-}
-
-/*****************************************************************************/
-
-const char *
-nm_utils_flags2str(const NMUtilsFlags2StrDesc *descs,
-                   gsize                       n_descs,
-                   unsigned                    flags,
-                   char *                      buf,
-                   gsize                       len)
-{
-    gsize i;
-    char *p;
-
-#if NM_MORE_ASSERTS > 10
-    nm_assert(descs);
-    nm_assert(n_descs > 0);
-    for (i = 0; i < n_descs; i++) {
-        gsize j;
-
-        nm_assert(descs[i].name && descs[i].name[0]);
-        for (j = 0; j < i; j++)
-            nm_assert(descs[j].flag != descs[i].flag);
-    }
-#endif
-
-    nm_utils_to_string_buffer_init(&buf, &len);
-
-    if (!len)
-        return buf;
-
-    buf[0] = '\0';
-    p      = buf;
-    if (!flags) {
-        for (i = 0; i < n_descs; i++) {
-            if (!descs[i].flag) {
-                nm_utils_strbuf_append_str(&p, &len, descs[i].name);
-                break;
-            }
-        }
-        return buf;
-    }
-
-    for (i = 0; flags && i < n_descs; i++) {
-        if (descs[i].flag && NM_FLAGS_ALL(flags, descs[i].flag)) {
-            flags &= ~descs[i].flag;
-
-            if (buf[0] != '\0')
-                nm_utils_strbuf_append_c(&p, &len, ',');
-            nm_utils_strbuf_append_str(&p, &len, descs[i].name);
-        }
-    }
-    if (flags) {
-        if (buf[0] != '\0')
-            nm_utils_strbuf_append_c(&p, &len, ',');
-        nm_utils_strbuf_append(&p, &len, "0x%x", flags);
-    }
-    return buf;
-};
-
-/*****************************************************************************/
-
-/**
- * _nm_utils_ip4_prefix_to_netmask:
- * @prefix: a CIDR prefix
- *
- * Returns: the netmask represented by the prefix, in network byte order
- **/
-guint32
-_nm_utils_ip4_prefix_to_netmask(guint32 prefix)
-{
-    return prefix < 32 ? ~htonl(0xFFFFFFFFu >> prefix) : 0xFFFFFFFFu;
-}
-
-gconstpointer
-nm_utils_ipx_address_clear_host_address(int family, gpointer dst, gconstpointer src, guint8 plen)
-{
-    g_return_val_if_fail(dst, NULL);
-
-    switch (family) {
-    case AF_INET:
-        g_return_val_if_fail(plen <= 32, NULL);
-
-        if (!src) {
-            /* allow "self-assignment", by specifying %NULL as source. */
-            src = dst;
-        }
-
-        *((guint32 *) dst) = nm_utils_ip4_address_clear_host_address(*((guint32 *) src), plen);
-        break;
-    case AF_INET6:
-        nm_utils_ip6_address_clear_host_address(dst, src, plen);
-        break;
-    default:
-        g_return_val_if_reached(NULL);
-    }
-    return dst;
-}
-
-/* nm_utils_ip4_address_clear_host_address:
- * @addr: source ip6 address
- * @plen: prefix length of network
- *
- * returns: the input address, with the host address set to 0.
- */
-in_addr_t
-nm_utils_ip4_address_clear_host_address(in_addr_t addr, guint8 plen)
-{
-    return addr & _nm_utils_ip4_prefix_to_netmask(plen);
-}
-
-/* nm_utils_ip6_address_clear_host_address:
- * @dst: destination output buffer, will contain the network part of the @src address
- * @src: source ip6 address
- * @plen: prefix length of network
- *
- * Note: this function is self assignment safe, to update @src inplace, set both
- * @dst and @src to the same destination or set @src NULL.
- */
-const struct in6_addr *
-nm_utils_ip6_address_clear_host_address(struct in6_addr *      dst,
-                                        const struct in6_addr *src,
-                                        guint8                 plen)
-{
-    g_return_val_if_fail(plen <= 128, NULL);
-    g_return_val_if_fail(dst, NULL);
-
-    if (!src)
-        src = dst;
-
-    if (plen < 128) {
-        guint nbytes = plen / 8;
-        guint nbits  = plen % 8;
-
-        if (nbytes && dst != src)
-            memcpy(dst, src, nbytes);
-        if (nbits) {
-            dst->s6_addr[nbytes] = (src->s6_addr[nbytes] & (0xFF << (8 - nbits)));
-            nbytes++;
-        }
-        if (nbytes <= 15)
-            memset(&dst->s6_addr[nbytes], 0, 16 - nbytes);
-    } else if (src != dst)
-        *dst = *src;
-
-    return dst;
-}
-
-int
-nm_utils_ip6_address_same_prefix_cmp(const struct in6_addr *addr_a,
-                                     const struct in6_addr *addr_b,
-                                     guint8                 plen)
-{
-    int    nbytes;
-    guint8 va, vb, m;
-
-    if (plen >= 128)
-        NM_CMP_DIRECT_MEMCMP(addr_a, addr_b, sizeof(struct in6_addr));
-    else {
-        nbytes = plen / 8;
-        if (nbytes)
-            NM_CMP_DIRECT_MEMCMP(addr_a, addr_b, nbytes);
-
-        plen = plen % 8;
-        if (plen != 0) {
-            m  = ~((1 << (8 - plen)) - 1);
-            va = ((((const guint8 *) addr_a))[nbytes]) & m;
-            vb = ((((const guint8 *) addr_b))[nbytes]) & m;
-            NM_CMP_DIRECT(va, vb);
-        }
-    }
-    return 0;
-}
-
-/*****************************************************************************/
-
-guint32
-_nm_utils_ip4_get_default_prefix0(in_addr_t ip)
-{
-    /* The function is originally from ipcalc.c of Red Hat's initscripts. */
-    switch (ntohl(ip) >> 24) {
-    case 0 ... 127:
-        return 8; /* Class A */
-    case 128 ... 191:
-        return 16; /* Class B */
-    case 192 ... 223:
-        return 24; /* Class C */
-    }
-    return 0;
-}
-
-guint32
-_nm_utils_ip4_get_default_prefix(in_addr_t ip)
-{
-    return _nm_utils_ip4_get_default_prefix0(ip) ?: 24;
-}
-
-gboolean
-nm_utils_ip_is_site_local(int addr_family, const void *address)
-{
-    in_addr_t addr4;
-
-    switch (addr_family) {
-    case AF_INET:
-        /* RFC1918 private addresses
-         * 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 */
-        addr4 = ntohl(*((const in_addr_t *) address));
-        return (addr4 & 0xff000000) == 0x0a000000 || (addr4 & 0xfff00000) == 0xac100000
-               || (addr4 & 0xffff0000) == 0xc0a80000;
-    case AF_INET6:
-        return IN6_IS_ADDR_SITELOCAL(address);
-    default:
-        g_return_val_if_reached(FALSE);
-    }
-}
-
-/*****************************************************************************/
-
-static gboolean
-_parse_legacy_addr4(const char *text, in_addr_t *out_addr, GError **error)
-{
-    gs_free char * s_free = NULL;
-    struct in_addr a1;
-    guint8         bin[sizeof(a1)];
-    char *         s;
-    int            i;
-
-    if (inet_aton(text, &a1) != 1) {
-        g_set_error_literal(error,
-                            NM_UTILS_ERROR,
-                            NM_UTILS_ERROR_INVALID_ARGUMENT,
-                            "address invalid according to inet_aton()");
-        return FALSE;
-    }
-
-    /* OK, inet_aton() accepted the format. That's good, because we want
-     * to accept IPv4 addresses in octal format, like 255.255.000.000.
-     * That's what "legacy" means here. inet_pton() doesn't accept those.
-     *
-     * But inet_aton() also ignores trailing garbage and formats with fewer than
-     * 4 digits. That is just too crazy and we don't do that. Perform additional checks
-     * and reject some forms that inet_aton() accepted.
-     *
-     * Note that we still should (of course) accept everything that inet_pton()
-     * accepts. However this code never gets called if inet_pton() succeeds
-     * (see below, aside the assertion code). */
-
-    if (NM_STRCHAR_ANY(text, ch, (!(ch >= '0' && ch <= '9') && !NM_IN_SET(ch, '.', 'x')))) {
-        /* We only accepts '.', digits, and 'x' for "0x". */
-        g_set_error_literal(error,
-                            NM_UTILS_ERROR,
-                            NM_UTILS_ERROR_INVALID_ARGUMENT,
-                            "contains an invalid character");
-        return FALSE;
-    }
-
-    s = nm_memdup_maybe_a(300, text, strlen(text) + 1, &s_free);
-
-    for (i = 0; i < G_N_ELEMENTS(bin); i++) {
-        char * current_token = s;
-        gint32 v;
-
-        s = strchr(s, '.');
-        if (s) {
-            s[0] = '\0';
-            s++;
-        }
-
-        if ((i == G_N_ELEMENTS(bin) - 1) != (s == NULL)) {
-            /* Exactly for the last digit, we expect to have no more following token.
-             * But this isn't the case. Abort. */
-            g_set_error(error,
-                        NM_UTILS_ERROR,
-                        NM_UTILS_ERROR_INVALID_ARGUMENT,
-                        "wrong number of tokens (index %d, token '%s')",
-                        i,
-                        s);
-            return FALSE;
-        }
-
-        v = _nm_utils_ascii_str_to_int64(current_token, 0, 0, 0xFF, -1);
-        if (v == -1) {
-            int errsv = errno;
-
-            /* we do accept octal and hex (even with leading "0x"). But something
-             * about this token is wrong. */
-            g_set_error(error,
-                        NM_UTILS_ERROR,
-                        NM_UTILS_ERROR_INVALID_ARGUMENT,
-                        "invalid token '%s': %s (%d)",
-                        current_token,
-                        nm_strerror_native(errsv),
-                        errsv);
-            return FALSE;
-        }
-
-        bin[i] = v;
-    }
-
-    if (memcmp(bin, &a1, sizeof(bin)) != 0) {
-        /* our parsing did not agree with what inet_aton() gave. Something
-         * is wrong. Abort. */
-        g_set_error(
-            error,
-            NM_UTILS_ERROR,
-            NM_UTILS_ERROR_INVALID_ARGUMENT,
-            "inet_aton() result 0x%08x differs from computed value 0x%02hhx%02hhx%02hhx%02hhx",
-            a1.s_addr,
-            bin[0],
-            bin[1],
-            bin[2],
-            bin[3]);
-        return FALSE;
-    }
-
-    *out_addr = a1.s_addr;
-    return TRUE;
-}
-
-gboolean
-nm_utils_parse_inaddr_bin_full(int         addr_family,
-                               gboolean    accept_legacy,
-                               const char *text,
-                               int *       out_addr_family,
-                               gpointer    out_addr)
-{
-    NMIPAddr addrbin;
-
-    g_return_val_if_fail(text, FALSE);
-
-    if (addr_family == AF_UNSPEC) {
-        g_return_val_if_fail(!out_addr || out_addr_family, FALSE);
-        addr_family = strchr(text, ':') ? AF_INET6 : AF_INET;
-    } else
-        g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE);
-
-    if (inet_pton(addr_family, text, &addrbin) != 1) {
-        if (accept_legacy && addr_family == AF_INET
-            && _parse_legacy_addr4(text, &addrbin.addr4, NULL)) {
-            /* The address is in some legacy format which inet_aton() accepts, but not inet_pton().
-             * Most likely octal digits (leading zeros). We accept the address. */
-        } else
-            return FALSE;
-    }
-
-#if NM_MORE_ASSERTS > 10
-    if (addr_family == AF_INET) {
-        gs_free_error GError *error = NULL;
-        in_addr_t             a;
-
-        /* The legacy parser should accept everything that inet_pton() accepts too. Meaning,
-         * it should strictly parse *more* formats. And of course, parse it the same way. */
-        if (!_parse_legacy_addr4(text, &a, &error)) {
-            char buf[INET_ADDRSTRLEN];
-
-            g_error("unexpected assertion failure: could parse \"%s\" as %s, but not accepted by "
-                    "legacy parser: %s",
-                    text,
-                    _nm_utils_inet4_ntop(addrbin.addr4, buf),
-                    error->message);
-        }
-        nm_assert(addrbin.addr4 == a);
-    }
-#endif
-
-    NM_SET_OUT(out_addr_family, addr_family);
-    if (out_addr)
-        nm_ip_addr_set(addr_family, out_addr, &addrbin);
-    return TRUE;
-}
-
-gboolean
-nm_utils_parse_inaddr(int addr_family, const char *text, char **out_addr)
-{
-    NMIPAddr addrbin;
-    char     addrstr_buf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
-
-    g_return_val_if_fail(text, FALSE);
-
-    if (addr_family == AF_UNSPEC)
-        addr_family = strchr(text, ':') ? AF_INET6 : AF_INET;
-    else
-        g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE);
-
-    if (inet_pton(addr_family, text, &addrbin) != 1)
-        return FALSE;
-
-    NM_SET_OUT(out_addr,
-               g_strdup(inet_ntop(addr_family, &addrbin, addrstr_buf, sizeof(addrstr_buf))));
-    return TRUE;
-}
-
-gboolean
-nm_utils_parse_inaddr_prefix_bin(int         addr_family,
-                                 const char *text,
-                                 int *       out_addr_family,
-                                 gpointer    out_addr,
-                                 int *       out_prefix)
-{
-    gs_free char *addrstr_free = NULL;
-    int           prefix       = -1;
-    const char *  slash;
-    const char *  addrstr;
-    NMIPAddr      addrbin;
-
-    g_return_val_if_fail(text, FALSE);
-
-    if (addr_family == AF_UNSPEC) {
-        g_return_val_if_fail(!out_addr || out_addr_family, FALSE);
-        addr_family = strchr(text, ':') ? AF_INET6 : AF_INET;
-    } else
-        g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), FALSE);
-
-    slash = strchr(text, '/');
-    if (slash)
-        addrstr = nm_strndup_a(300, text, slash - text, &addrstr_free);
-    else
-        addrstr = text;
-
-    if (inet_pton(addr_family, addrstr, &addrbin) != 1)
-        return FALSE;
-
-    if (slash) {
-        /* For IPv4, `ip addr add` supports the prefix-length as a netmask. We don't
-         * do that. */
-        prefix =
-            _nm_utils_ascii_str_to_int64(&slash[1], 10, 0, addr_family == AF_INET ? 32 : 128, -1);
-        if (prefix == -1)
-            return FALSE;
-    }
-
-    NM_SET_OUT(out_addr_family, addr_family);
-    if (out_addr)
-        nm_ip_addr_set(addr_family, out_addr, &addrbin);
-    NM_SET_OUT(out_prefix, prefix);
-    return TRUE;
-}
-
-gboolean
-nm_utils_parse_inaddr_prefix(int addr_family, const char *text, char **out_addr, int *out_prefix)
-{
-    NMIPAddr addrbin;
-    char     addrstr_buf[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
-
-    if (!nm_utils_parse_inaddr_prefix_bin(addr_family, text, &addr_family, &addrbin, out_prefix))
-        return FALSE;
-    NM_SET_OUT(out_addr,
-               g_strdup(inet_ntop(addr_family, &addrbin, addrstr_buf, sizeof(addrstr_buf))));
-    return TRUE;
-}
-
-gboolean
-nm_utils_parse_next_line(const char **inout_ptr,
-                         gsize *      inout_len,
-                         const char **out_line,
-                         gsize *      out_line_len)
-{
-    gboolean    eol_is_carriage_return;
-    const char *line_start;
-    gsize       line_len;
-
-    nm_assert(inout_ptr);
-    nm_assert(inout_len);
-    nm_assert(*inout_len == 0 || *inout_ptr);
-    nm_assert(out_line);
-    nm_assert(out_line_len);
-
-    if (G_UNLIKELY(*inout_len == 0))
-        return FALSE;
-
-    line_start = *inout_ptr;
-
-    eol_is_carriage_return = FALSE;
-    for (line_len = 0;; line_len++) {
-        if (line_len >= *inout_len) {
-            /* if we consumed the entire line, we place the pointer at
-             * one character after the end. */
-            *inout_ptr = &line_start[line_len];
-            *inout_len = 0;
-            goto done;
-        }
-        switch (line_start[line_len]) {
-        case '\r':
-            eol_is_carriage_return = TRUE;
-            /* fall-through*/
-        case '\0':
-        case '\n':
-            *inout_ptr = &line_start[line_len + 1];
-            *inout_len = *inout_len - line_len - 1u;
-            if (eol_is_carriage_return && *inout_len > 0 && (*inout_ptr)[0] == '\n') {
-                /* also consume "\r\n" as one. */
-                (*inout_len)--;
-                (*inout_ptr)++;
-            }
-            goto done;
-        }
-    }
-
-done:
-    *out_line     = line_start;
-    *out_line_len = line_len;
-    return TRUE;
-}
-
-/*****************************************************************************/
-
-gboolean
-nm_utils_ipaddr_is_valid(int addr_family, const char *str_addr)
-{
-    nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
-
-    return str_addr && nm_utils_parse_inaddr_bin(addr_family, str_addr, NULL, NULL);
-}
-
-gboolean
-nm_utils_ipaddr_is_normalized(int addr_family, const char *str_addr)
-{
-    NMIPAddr addr;
-    char     sbuf[NM_UTILS_INET_ADDRSTRLEN];
-
-    nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
-
-    if (!str_addr)
-        return FALSE;
-
-    if (!nm_utils_parse_inaddr_bin(addr_family, str_addr, &addr_family, &addr))
-        return FALSE;
-
-    nm_utils_inet_ntop(addr_family, &addr, sbuf);
-    return nm_streq(sbuf, str_addr);
-}
-
-/*****************************************************************************/
-
-/**
- * nm_g_ascii_strtoll()
- * @nptr: the string to parse
- * @endptr: the pointer on the first invalid chars
- * @base: the base.
- *
- * This wraps g_ascii_strtoll() and should in almost all cases behave identical
- * to it.
- *
- * However, it seems there are situations where g_ascii_strtoll() might set
- * errno to some unexpected value EAGAIN. Possibly this is related to creating
- * the C locale during
- *
- *   #ifdef USE_XLOCALE
- *   return strtoll_l (nptr, endptr, base, get_C_locale ());
- *
- * This wrapper tries to workaround that condition.
- */
-gint64
-nm_g_ascii_strtoll(const char *nptr, char **endptr, guint base)
-{
-    int       try_count = 2;
-    gint64    v;
-    const int errsv_orig = errno;
-    int       errsv;
-
-    nm_assert(nptr);
-    nm_assert(base == 0u || (base >= 2u && base <= 36u));
-
-again:
-    errno = 0;
-    v     = g_ascii_strtoll(nptr, endptr, base);
-    errsv = errno;
-
-    if (errsv == 0) {
-        if (errsv_orig != 0)
-            errno = errsv_orig;
-        return v;
-    }
-
-    if (errsv == ERANGE && NM_IN_SET(v, G_MININT64, G_MAXINT64))
-        return v;
-
-    if (errsv == EINVAL && v == 0 && nptr && nptr[0] == '\0')
-        return v;
-
-    if (try_count-- > 0)
-        goto again;
-
-#if NM_MORE_ASSERTS
-    g_critical("g_ascii_strtoll() for \"%s\" failed with errno=%d (%s) and v=%" G_GINT64_FORMAT,
-               nptr,
-               errsv,
-               nm_strerror_native(errsv),
-               v);
-#endif
-
-    return v;
-}
-
-/* See nm_g_ascii_strtoll() */
-guint64
-nm_g_ascii_strtoull(const char *nptr, char **endptr, guint base)
-{
-    int       try_count = 2;
-    guint64   v;
-    const int errsv_orig = errno;
-    int       errsv;
-
-    nm_assert(nptr);
-    nm_assert(base == 0u || (base >= 2u && base <= 36u));
-
-again:
-    errno = 0;
-    v     = g_ascii_strtoull(nptr, endptr, base);
-    errsv = errno;
-
-    if (errsv == 0) {
-        if (errsv_orig != 0)
-            errno = errsv_orig;
-        return v;
-    }
-
-    if (errsv == ERANGE && NM_IN_SET(v, G_MAXUINT64))
-        return v;
-
-    if (errsv == EINVAL && v == 0 && nptr && nptr[0] == '\0')
-        return v;
-
-    if (try_count-- > 0)
-        goto again;
-
-#if NM_MORE_ASSERTS
-    g_critical("g_ascii_strtoull() for \"%s\" failed with errno=%d (%s) and v=%" G_GUINT64_FORMAT,
-               nptr,
-               errsv,
-               nm_strerror_native(errsv),
-               v);
-#endif
-
-    return v;
-}
-
-/* see nm_g_ascii_strtoll(). */
-double
-nm_g_ascii_strtod(const char *nptr, char **endptr)
-{
-    int    try_count = 2;
-    double v;
-    int    errsv;
-
-    nm_assert(nptr);
-
-again:
-    v     = g_ascii_strtod(nptr, endptr);
-    errsv = errno;
-
-    if (errsv == 0)
-        return v;
-
-    if (errsv == ERANGE)
-        return v;
-
-    if (try_count-- > 0)
-        goto again;
-
-#if NM_MORE_ASSERTS
-    g_critical("g_ascii_strtod() for \"%s\" failed with errno=%d (%s) and v=%f",
-               nptr,
-               errsv,
-               nm_strerror_native(errsv),
-               v);
-#endif
-
-    /* Not really much else to do. Return the parsed value and leave errno set
-     * to the unexpected value. */
-    return v;
-}
-
-/* _nm_utils_ascii_str_to_int64:
- *
- * A wrapper for g_ascii_strtoll, that checks whether the whole string
- * can be successfully converted to a number and is within a given
- * range. On any error, @fallback will be returned and %errno will be set
- * to a non-zero value. On success, %errno will be set to zero, check %errno
- * for errors. Any trailing or leading (ascii) white space is ignored and the
- * functions is locale independent.
- *
- * The function is guaranteed to return a value between @min and @max
- * (inclusive) or @fallback. Also, the parsing is rather strict, it does
- * not allow for any unrecognized characters, except leading and trailing
- * white space.
- **/
-gint64
-_nm_utils_ascii_str_to_int64(const char *str, guint base, gint64 min, gint64 max, gint64 fallback)
-{
-    gint64      v;
-    const char *s = NULL;
-
-    str = nm_str_skip_leading_spaces(str);
-    if (!str || !str[0]) {
-        errno = EINVAL;
-        return fallback;
-    }
-
-    errno = 0;
-    v     = nm_g_ascii_strtoll(str, (char **) &s, base);
-
-    if (errno != 0)
-        return fallback;
-
-    if (s[0] != '\0') {
-        s = nm_str_skip_leading_spaces(s);
-        if (s[0] != '\0') {
-            errno = EINVAL;
-            return fallback;
-        }
-    }
-    if (v > max || v < min) {
-        errno = ERANGE;
-        return fallback;
-    }
-
-    return v;
-}
-
-guint64
-_nm_utils_ascii_str_to_uint64(const char *str,
-                              guint       base,
-                              guint64     min,
-                              guint64     max,
-                              guint64     fallback)
-{
-    guint64     v;
-    const char *s = NULL;
-
-    if (str) {
-        while (g_ascii_isspace(str[0]))
-            str++;
-    }
-    if (!str || !str[0]) {
-        errno = EINVAL;
-        return fallback;
-    }
-
-    errno = 0;
-    v     = nm_g_ascii_strtoull(str, (char **) &s, base);
-
-    if (errno != 0)
-        return fallback;
-    if (s[0] != '\0') {
-        while (g_ascii_isspace(s[0]))
-            s++;
-        if (s[0] != '\0') {
-            errno = EINVAL;
-            return fallback;
-        }
-    }
-    if (v > max || v < min) {
-        errno = ERANGE;
-        return fallback;
-    }
-
-    if (v != 0 && str[0] == '-') {
-        /* As documented, g_ascii_strtoull() accepts negative values, and returns their
-         * absolute value. We don't. */
-        errno = ERANGE;
-        return fallback;
-    }
-
-    return v;
-}
-
-/*****************************************************************************/
-
-int
-nm_strcmp_with_data(gconstpointer a, gconstpointer b, gpointer user_data)
-{
-    const char *s1 = a;
-    const char *s2 = b;
-
-    return strcmp(s1, s2);
-}
-
-/* like nm_strcmp_p(), suitable for g_ptr_array_sort_with_data().
- * g_ptr_array_sort() just casts nm_strcmp_p() to a function of different
- * signature. I guess, in glib there are knowledgeable people that ensure
- * that this additional argument doesn't cause problems due to different ABI
- * for every architecture that glib supports.
- * For NetworkManager, we'd rather avoid such stunts.
- **/
-int
-nm_strcmp_p_with_data(gconstpointer a, gconstpointer b, gpointer user_data)
-{
-    const char *s1 = *((const char **) a);
-    const char *s2 = *((const char **) b);
-
-    return strcmp(s1, s2);
-}
-
-int
-nm_strcmp0_p_with_data(gconstpointer a, gconstpointer b, gpointer user_data)
-{
-    const char *s1 = *((const char **) a);
-    const char *s2 = *((const char **) b);
-
-    return nm_strcmp0(s1, s2);
-}
-
-int
-nm_strcmp_ascii_case_with_data(gconstpointer a, gconstpointer b, gpointer user_data)
-{
-    const char *s1 = a;
-    const char *s2 = b;
-
-    return g_ascii_strcasecmp(s1, s2);
-}
-
-int
-nm_cmp_uint32_p_with_data(gconstpointer p_a, gconstpointer p_b, gpointer user_data)
-{
-    const guint32 a = *((const guint32 *) p_a);
-    const guint32 b = *((const guint32 *) p_b);
-
-    if (a < b)
-        return -1;
-    if (a > b)
-        return 1;
-    return 0;
-}
-
-int
-nm_cmp_int2ptr_p_with_data(gconstpointer p_a, gconstpointer p_b, gpointer user_data)
-{
-    /* p_a and p_b are two pointers to a pointer, where the pointer is
-     * interpreted as a integer using GPOINTER_TO_INT().
-     *
-     * That is the case of a hash-table that uses GINT_TO_POINTER() to
-     * convert integers as pointers, and the resulting keys-as-array
-     * array. */
-    const int a = GPOINTER_TO_INT(*((gconstpointer *) p_a));
-    const int b = GPOINTER_TO_INT(*((gconstpointer *) p_b));
-
-    if (a < b)
-        return -1;
-    if (a > b)
-        return 1;
-    return 0;
-}
-
-/*****************************************************************************/
-
-const char *
-nm_utils_dbus_path_get_last_component(const char *dbus_path)
-{
-    if (dbus_path) {
-        dbus_path = strrchr(dbus_path, '/');
-        if (dbus_path)
-            return dbus_path + 1;
-    }
-    return NULL;
-}
-
-static gint64
-_dbus_path_component_as_num(const char *p)
-{
-    gint64 n;
-
-    /* no odd stuff. No leading zeros, only a non-negative, decimal integer.
-     *
-     * Otherwise, there would be multiple ways to encode the same number "10"
-     * and "010". That is just confusing. A number has no leading zeros,
-     * if it has, it's not a number (as far as we are concerned here). */
-    if (p[0] == '0') {
-        if (p[1] != '\0')
-            return -1;
-        else
-            return 0;
-    }
-    if (!(p[0] >= '1' && p[0] <= '9'))
-        return -1;
-    if (!NM_STRCHAR_ALL(&p[1], ch, (ch >= '0' && ch <= '9')))
-        return -1;
-    n = _nm_utils_ascii_str_to_int64(p, 10, 0, G_MAXINT64, -1);
-    nm_assert(n == -1 || nm_streq0(p, nm_sprintf_bufa(100, "%" G_GINT64_FORMAT, n)));
-    return n;
-}
-
-int
-nm_utils_dbus_path_cmp(const char *dbus_path_a, const char *dbus_path_b)
-{
-    const char *l_a, *l_b;
-    gsize       plen;
-    gint64      n_a, n_b;
-
-    /* compare function for two D-Bus paths. It behaves like
-     * strcmp(), except, if both paths have the same prefix,
-     * and both end in a (positive) number, then the paths
-     * will be sorted by number. */
-
-    NM_CMP_SELF(dbus_path_a, dbus_path_b);
-
-    /* if one or both paths have no slash (and no last component)
-     * compare the full paths directly. */
-    if (!(l_a = nm_utils_dbus_path_get_last_component(dbus_path_a))
-        || !(l_b = nm_utils_dbus_path_get_last_component(dbus_path_b)))
-        goto comp_full;
-
-    /* check if both paths have the same prefix (up to the last-component). */
-    plen = l_a - dbus_path_a;
-    if (plen != (l_b - dbus_path_b))
-        goto comp_full;
-    NM_CMP_RETURN(strncmp(dbus_path_a, dbus_path_b, plen));
-
-    n_a = _dbus_path_component_as_num(l_a);
-    n_b = _dbus_path_component_as_num(l_b);
-    if (n_a == -1 && n_b == -1)
-        goto comp_l;
-
-    /* both components must be convertible to a number. If they are not,
-     * (and only one of them is), then we must always strictly sort numeric parts
-     * after non-numeric components. If we wouldn't, we wouldn't have
-     * a total order.
-     *
-     * An example of a not total ordering would be:
-     *   "8"   < "010"  (numeric)
-     *   "0x"  < "8"    (lexical)
-     *   "0x"  > "010"  (lexical)
-     * We avoid this, by forcing that a non-numeric entry "0x" always sorts
-     * before numeric entries.
-     *
-     * Additionally, _dbus_path_component_as_num() would also reject "010" as
-     * not a valid number.
-     */
-    if (n_a == -1)
-        return -1;
-    if (n_b == -1)
-        return 1;
-
-    NM_CMP_DIRECT(n_a, n_b);
-    nm_assert(nm_streq(dbus_path_a, dbus_path_b));
-    return 0;
-
-comp_full:
-    NM_CMP_DIRECT_STRCMP0(dbus_path_a, dbus_path_b);
-    return 0;
-comp_l:
-    NM_CMP_DIRECT_STRCMP0(l_a, l_b);
-    nm_assert(nm_streq(dbus_path_a, dbus_path_b));
-    return 0;
-}
-
-/*****************************************************************************/
-
-typedef struct {
-    union {
-        guint8  table[256];
-        guint64 _dummy_for_alignment;
-    };
-} CharLookupTable;
-
-static void
-_char_lookup_table_set_one(CharLookupTable *lookup, char ch)
-{
-    lookup->table[(guint8) ch] = 1;
-}
-
-static void
-_char_lookup_table_set_all(CharLookupTable *lookup, const char *candidates)
-{
-    while (candidates[0] != '\0')
-        _char_lookup_table_set_one(lookup, (candidates++)[0]);
-}
-
-static void
-_char_lookup_table_init(CharLookupTable *lookup, const char *candidates)
-{
-    *lookup = (CharLookupTable){
-        .table = {0},
-    };
-    if (candidates)
-        _char_lookup_table_set_all(lookup, candidates);
-}
-
-static gboolean
-_char_lookup_has(const CharLookupTable *lookup, char ch)
-{
-    /* with some optimization levels, the compiler thinks this code
-     * might access uninitialized @lookup. It is not -- when you look at the
-     * callers of this function. */
-    NM_PRAGMA_WARNING_DISABLE("-Wmaybe-uninitialized")
-    nm_assert(lookup->table[(guint8) '\0'] == 0);
-    return lookup->table[(guint8) ch] != 0;
-    NM_PRAGMA_WARNING_REENABLE
-}
-
-static gboolean
-_char_lookup_has_all(const CharLookupTable *lookup, const char *candidates)
-{
-    if (candidates) {
-        while (candidates[0] != '\0') {
-            if (!_char_lookup_has(lookup, (candidates++)[0]))
-                return FALSE;
-        }
-    }
-    return TRUE;
-}
-
-/**
- * nm_utils_strsplit_set_full:
- * @str: the string to split.
- * @delimiters: the set of delimiters.
- * @flags: additional flags for controlling the operation.
- *
- * This is a replacement for g_strsplit_set() which avoids copying
- * each word once (the entire strv array), but instead copies it once
- * and all words point into that internal copy.
- *
- * Note that for @str %NULL and "", this always returns %NULL too. That differs
- * from g_strsplit_set(), which would return an empty strv array for "".
- * This never returns an empty array.
- *
- * Returns: %NULL if @str is %NULL or "".
- *   If @str only contains delimiters and %NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY
- *   is not set, it also returns %NULL.
- *   Otherwise, a %NULL terminated strv array containing the split words.
- *   (delimiter characters are removed).
- *   The strings to which the result strv array points to are allocated
- *   after the returned result itself. Don't free the strings themself,
- *   but free everything with g_free().
- *   It is however safe and allowed to modify the individual strings in-place,
- *   like "g_strstrip((char *) iter[0])".
- */
-const char **
-nm_utils_strsplit_set_full(const char *str, const char *delimiters, NMUtilsStrsplitSetFlags flags)
-{
-    const char **   ptr;
-    gsize           num_tokens;
-    gsize           i_token;
-    gsize           str_len_p1;
-    const char *    c_str;
-    char *          s;
-    CharLookupTable ch_lookup;
-    const gboolean  f_escaped = NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED);
-    const gboolean  f_allow_escaping =
-        f_escaped || NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
-    const gboolean f_preserve_empty =
-        NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY);
-    const gboolean f_strstrip = NM_FLAGS_HAS(flags, NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
-
-    if (!str)
-        return NULL;
-
-    if (!delimiters) {
-        nm_assert_not_reached();
-        delimiters = " \t\n";
-    }
-    _char_lookup_table_init(&ch_lookup, delimiters);
-
-    nm_assert(!f_allow_escaping || !_char_lookup_has(&ch_lookup, '\\'));
-
-    if (!f_preserve_empty) {
-        while (_char_lookup_has(&ch_lookup, str[0]))
-            str++;
-    }
-
-    if (!str[0]) {
-        /* We return %NULL here, also with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY.
-         * That makes nm_utils_strsplit_set_full() with NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY
-         * different from g_strsplit_set(), which would in this case return an empty array.
-         * If you need to handle %NULL, and "" specially, then check the input string first. */
-        return NULL;
-    }
-
-#define _char_is_escaped(str_start, str_cur)              \
-    ({                                                    \
-        const char *const _str_start = (str_start);       \
-        const char *const _str_cur   = (str_cur);         \
-        const char *      _str_i     = (_str_cur);        \
-                                                          \
-        while (_str_i > _str_start && _str_i[-1] == '\\') \
-            _str_i--;                                     \
-        (((_str_cur - _str_i) % 2) != 0);                 \
-    })
-
-    num_tokens = 1;
-    c_str      = str;
-    while (TRUE) {
-        while (G_LIKELY(!_char_lookup_has(&ch_lookup, c_str[0]))) {
-            if (c_str[0] == '\0')
-                goto done1;
-            c_str++;
-        }
-
-        /* we assume escapings are not frequent. After we found
-         * this delimiter, check whether it was escaped by counting
-         * the backslashed before. */
-        if (f_allow_escaping && _char_is_escaped(str, c_str)) {
-            /* the delimiter is escaped. This was not an accepted delimiter. */
-            c_str++;
-            continue;
-        }
-
-        c_str++;
-
-        /* if we drop empty tokens, then we now skip over all consecutive delimiters. */
-        if (!f_preserve_empty) {
-            while (_char_lookup_has(&ch_lookup, c_str[0]))
-                c_str++;
-            if (c_str[0] == '\0')
-                break;
-        }
-
-        num_tokens++;
-    }
-
-done1:
-
-    nm_assert(c_str[0] == '\0');
-
-    str_len_p1 = (c_str - str) + 1;
-
-    nm_assert(str[str_len_p1 - 1] == '\0');
-
-    ptr = g_malloc((sizeof(const char *) * (num_tokens + 1)) + str_len_p1);
-    s   = (char *) &ptr[num_tokens + 1];
-    memcpy(s, str, str_len_p1);
-
-    i_token = 0;
-
-    while (TRUE) {
-        nm_assert(i_token < num_tokens);
-        ptr[i_token++] = s;
-
-        if (s[0] == '\0') {
-            nm_assert(f_preserve_empty);
-            goto done2;
-        }
-        nm_assert(f_preserve_empty || !_char_lookup_has(&ch_lookup, s[0]));
-
-        while (!_char_lookup_has(&ch_lookup, s[0])) {
-            if (G_UNLIKELY(s[0] == '\\' && f_allow_escaping)) {
-                s++;
-                if (s[0] == '\0')
-                    goto done2;
-                s++;
-            } else if (s[0] == '\0')
-                goto done2;
-            else
-                s++;
-        }
-
-        nm_assert(_char_lookup_has(&ch_lookup, s[0]));
-        s[0] = '\0';
-        s++;
-
-        if (!f_preserve_empty) {
-            while (_char_lookup_has(&ch_lookup, s[0]))
-                s++;
-            if (s[0] == '\0')
-                goto done2;
-        }
-    }
-
-done2:
-    nm_assert(i_token == num_tokens);
-    ptr[i_token] = NULL;
-
-    if (f_strstrip) {
-        gsize i;
-
-        i_token = 0;
-        for (i = 0; ptr[i]; i++) {
-            s = (char *) nm_str_skip_leading_spaces(ptr[i]);
-            if (s[0] != '\0') {
-                char *s_last;
-
-                s_last = &s[strlen(s) - 1];
-                while (s_last > s && g_ascii_isspace(s_last[0])
-                       && (!f_allow_escaping || !_char_is_escaped(s, s_last)))
-                    (s_last--)[0] = '\0';
-            }
-
-            if (!f_preserve_empty && s[0] == '\0')
-                continue;
-
-            ptr[i_token++] = s;
-        }
-
-        if (i_token == 0) {
-            g_free(ptr);
-            return NULL;
-        }
-        ptr[i_token] = NULL;
-    }
-
-    if (f_escaped) {
-        gsize i, j;
-
-        /* We no longer need ch_lookup for its original purpose. Modify it, so it
-         * can detect the delimiters, '\\', and (optionally) whitespaces. */
-        _char_lookup_table_set_one(&ch_lookup, '\\');
-        if (f_strstrip)
-            _char_lookup_table_set_all(&ch_lookup, NM_ASCII_SPACES);
-
-        for (i_token = 0; ptr[i_token]; i_token++) {
-            s = (char *) ptr[i_token];
-            j = 0;
-            for (i = 0; s[i] != '\0';) {
-                if (s[i] == '\\' && _char_lookup_has(&ch_lookup, s[i + 1]))
-                    i++;
-                s[j++] = s[i++];
-            }
-            s[j] = '\0';
-        }
-    }
-
-    nm_assert(ptr && ptr[0]);
-    return ptr;
-}
-
-/*****************************************************************************/
-
-const char *
-nm_utils_escaped_tokens_escape_full(const char *                    str,
-                                    const char *                    delimiters,
-                                    const char *                    delimiters_as_needed,
-                                    NMUtilsEscapedTokensEscapeFlags flags,
-                                    char **                         out_to_free)
-{
-    CharLookupTable ch_lookup;
-    CharLookupTable ch_lookup_as_needed;
-    gboolean        has_ch_lookup_as_needed = FALSE;
-    char *          ret;
-    gsize           str_len;
-    gsize           alloc_len;
-    gsize           n_escapes;
-    gsize           i, j;
-    gboolean        escape_leading_space;
-    gboolean        escape_trailing_space;
-    gboolean        escape_backslash_as_needed;
-
-    nm_assert(
-        !delimiters_as_needed
-        || (delimiters_as_needed[0]
-            && NM_FLAGS_HAS(flags,
-                            NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED)));
-
-    if (!str || str[0] == '\0') {
-        *out_to_free = NULL;
-        return str;
-    }
-
-    str_len = strlen(str);
-
-    _char_lookup_table_init(&ch_lookup, delimiters);
-    if (!delimiters || NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_SPACES)) {
-        flags &= ~(NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE
-                   | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE);
-        _char_lookup_table_set_all(&ch_lookup, NM_ASCII_SPACES);
-    }
-
-    if (NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS)) {
-        _char_lookup_table_set_one(&ch_lookup, '\\');
-        escape_backslash_as_needed = FALSE;
-    } else if (_char_lookup_has(&ch_lookup, '\\'))
-        escape_backslash_as_needed = FALSE;
-    else {
-        escape_backslash_as_needed =
-            NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED);
-        if (escape_backslash_as_needed) {
-            if (NM_FLAGS_ANY(flags,
-                             NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE
-                                 | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE)
-                && !_char_lookup_has_all(&ch_lookup, NM_ASCII_SPACES)) {
-                /* ESCAPE_LEADING_SPACE and ESCAPE_TRAILING_SPACE implies that we escape backslash
-                 * before whitespaces. */
-                if (!has_ch_lookup_as_needed) {
-                    has_ch_lookup_as_needed = TRUE;
-                    _char_lookup_table_init(&ch_lookup_as_needed, NULL);
-                }
-                _char_lookup_table_set_all(&ch_lookup_as_needed, NM_ASCII_SPACES);
-            }
-            if (delimiters_as_needed && !_char_lookup_has_all(&ch_lookup, delimiters_as_needed)) {
-                if (!has_ch_lookup_as_needed) {
-                    has_ch_lookup_as_needed = TRUE;
-                    _char_lookup_table_init(&ch_lookup_as_needed, NULL);
-                }
-                _char_lookup_table_set_all(&ch_lookup_as_needed, delimiters_as_needed);
-            }
-        }
-    }
-
-    escape_leading_space =
-        NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE)
-        && g_ascii_isspace(str[0]) && !_char_lookup_has(&ch_lookup, str[0]);
-    if (str_len == 1)
-        escape_trailing_space = FALSE;
-    else {
-        escape_trailing_space =
-            NM_FLAGS_HAS(flags, NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE)
-            && g_ascii_isspace(str[str_len - 1]) && !_char_lookup_has(&ch_lookup, str[str_len - 1]);
-    }
-
-    n_escapes = 0;
-    for (i = 0; str[i] != '\0'; i++) {
-        if (_char_lookup_has(&ch_lookup, str[i]))
-            n_escapes++;
-        else if (str[i] == '\\' && escape_backslash_as_needed
-                 && (_char_lookup_has(&ch_lookup, str[i + 1]) || NM_IN_SET(str[i + 1], '\0', '\\')
-                     || (has_ch_lookup_as_needed
-                         && _char_lookup_has(&ch_lookup_as_needed, str[i + 1]))))
-            n_escapes++;
-    }
-    if (escape_leading_space)
-        n_escapes++;
-    if (escape_trailing_space)
-        n_escapes++;
-
-    if (n_escapes == 0u) {
-        *out_to_free = NULL;
-        return str;
-    }
-
-    alloc_len = str_len + n_escapes + 1u;
-    ret       = g_new(char, alloc_len);
-
-    j = 0;
-    i = 0;
-
-    if (escape_leading_space) {
-        ret[j++] = '\\';
-        ret[j++] = str[i++];
-    }
-    for (; str[i] != '\0'; i++) {
-        if (_char_lookup_has(&ch_lookup, str[i]))
-            ret[j++] = '\\';
-        else if (str[i] == '\\' && escape_backslash_as_needed
-                 && (_char_lookup_has(&ch_lookup, str[i + 1]) || NM_IN_SET(str[i + 1], '\0', '\\')
-                     || (has_ch_lookup_as_needed
-                         && _char_lookup_has(&ch_lookup_as_needed, str[i + 1]))))
-            ret[j++] = '\\';
-        ret[j++] = str[i];
-    }
-    if (escape_trailing_space) {
-        nm_assert(!_char_lookup_has(&ch_lookup, ret[j - 1]) && g_ascii_isspace(ret[j - 1]));
-        ret[j]     = ret[j - 1];
-        ret[j - 1] = '\\';
-        j++;
-    }
-
-    nm_assert(j == alloc_len - 1);
-    ret[j] = '\0';
-    nm_assert(strlen(ret) == j);
-
-    *out_to_free = ret;
-    return ret;
-}
-
-/**
- * nm_utils_escaped_tokens_options_split:
- * @str: the src string. This string will be modified in-place.
- *   The output values will point into @str.
- * @out_key: (allow-none): the returned output key. This will always be set to @str
- *   itself. @str will be modified to contain only the unescaped, truncated
- *   key name.
- * @out_val: returns the parsed (and unescaped) value or %NULL, if @str contains
- *   no '=' delimiter.
- *
- * Honors backslash escaping to parse @str as "key=value" pairs. Optionally, if no '='
- * is present, @out_val will be returned as %NULL. Backslash can be used to escape
- * '=', ',', '\\', and ascii whitespace. Other backslash sequences are taken verbatim.
- *
- * For keys, '=' obviously must be escaped. For values, that is optional because an
- * unescaped '=' is just taken verbatim. For example, in a key, the sequence "\\="
- * must be escaped as "\\\\\\=". For the value, that works too, but "\\\\=" is also
- * accepted.
- *
- * Unescaped Space around the key and value are also removed. Space in general must
- * not be escaped, unless they are at the beginning or the end of key/value.
- */
-void
-nm_utils_escaped_tokens_options_split(char *str, const char **out_key, const char **out_val)
-{
-    const char *val = NULL;
-    gsize       i;
-    gsize       j;
-    gsize       last_space_idx;
-    gboolean    last_space_has;
-
-    nm_assert(str);
-
-    i = 0;
-    while (g_ascii_isspace(str[i]))
-        i++;
-
-    j              = 0;
-    last_space_idx = 0;
-    last_space_has = FALSE;
-    while (str[i] != '\0') {
-        if (g_ascii_isspace(str[i])) {
-            if (!last_space_has) {
-                last_space_has = TRUE;
-                last_space_idx = j;
-            }
-        } else {
-            if (str[i] == '\\') {
-                if (NM_IN_SET(str[i + 1u], '\\', ',', '=') || g_ascii_isspace(str[i + 1u]))
-                    i++;
-            } else if (str[i] == '=') {
-                /* Encounter an unescaped '=' character. When we still parse the key, this
-                 * is the separator we were waiting for. If we are parsing the value,
-                 * we take the character verbatim. */
-                if (!val) {
-                    if (last_space_has) {
-                        str[last_space_idx] = '\0';
-                        j                   = last_space_idx + 1;
-                        last_space_has      = FALSE;
-                    } else
-                        str[j++] = '\0';
-                    val = &str[j];
-                    i++;
-                    while (g_ascii_isspace(str[i]))
-                        i++;
-                    continue;
-                }
-            }
-            last_space_has = FALSE;
-        }
-        str[j++] = str[i++];
-    }
-
-    if (last_space_has)
-        str[last_space_idx] = '\0';
-    else
-        str[j] = '\0';
-
-    *out_key = str;
-    *out_val = val;
-}
-
-/*****************************************************************************/
-
-/**
- * nm_utils_strsplit_quoted:
- * @str: the string to split (e.g. from /proc/cmdline).
- *
- * This basically does that systemd's extract_first_word() does
- * with the flags "EXTRACT_UNQUOTE | EXTRACT_RELAX". This is what
- * systemd uses to parse /proc/cmdline, and we do too.
- *
- * Splits the string. We have nm_utils_strsplit_set() which
- * supports a variety of flags. However, extending that already
- * complex code to also support quotation and escaping is hard.
- * Instead, add a naive implementation.
- *
- * Returns: (transfer full): the split string.
- */
-char **
-nm_utils_strsplit_quoted(const char *str)
-{
-    gs_unref_ptrarray GPtrArray *arr     = NULL;
-    gs_free char *               str_out = NULL;
-    CharLookupTable              ch_lookup;
-
-    nm_assert(str);
-
-    _char_lookup_table_init(&ch_lookup, NM_ASCII_WHITESPACES);
-
-    for (;;) {
-        char  quote;
-        gsize j;
-
-        while (_char_lookup_has(&ch_lookup, str[0]))
-            str++;
-
-        if (str[0] == '\0')
-            break;
-
-        if (!str_out)
-            str_out = g_new(char, strlen(str) + 1);
-
-        quote = '\0';
-        j     = 0;
-        for (;;) {
-            if (str[0] == '\\') {
-                str++;
-                if (str[0] == '\0')
-                    break;
-                str_out[j++] = str[0];
-                str++;
-                continue;
-            }
-            if (quote) {
-                if (str[0] == '\0')
-                    break;
-                if (str[0] == quote) {
-                    quote = '\0';
-                    str++;
-                    continue;
-                }
-                str_out[j++] = str[0];
-                str++;
-                continue;
-            }
-            if (str[0] == '\0')
-                break;
-            if (NM_IN_SET(str[0], '\'', '"')) {
-                quote = str[0];
-                str++;
-                continue;
-            }
-            if (_char_lookup_has(&ch_lookup, str[0])) {
-                str++;
-                break;
-            }
-            str_out[j++] = str[0];
-            str++;
-        }
-
-        if (!arr)
-            arr = g_ptr_array_new();
-        g_ptr_array_add(arr, g_strndup(str_out, j));
-    }
-
-    if (!arr)
-        return g_new0(char *, 1);
-
-    g_ptr_array_add(arr, NULL);
-
-    /* We want to return an optimally sized strv array, with no excess
-     * memory allocated. Hence, clone once more. */
-    return nm_memdup(arr->pdata, sizeof(char *) * arr->len);
-}
-
-/*****************************************************************************/
-
-/**
- * nm_utils_strv_find_first:
- * @list: the strv list to search
- * @len: the length of the list, or a negative value if @list is %NULL terminated.
- * @needle: the value to search for. The search is done using strcmp().
- *
- * Searches @list for @needle and returns the index of the first match (based
- * on strcmp()).
- *
- * For convenience, @list has type 'char**' instead of 'const char **'.
- *
- * Returns: index of first occurrence or -1 if @needle is not found in @list.
- */
-gssize
-nm_utils_strv_find_first(char **list, gssize len, const char *needle)
-{
-    gssize i;
-
-    if (len > 0) {
-        g_return_val_if_fail(list, -1);
-
-        if (!needle) {
-            /* if we search a list with known length, %NULL is a valid @needle. */
-            for (i = 0; i < len; i++) {
-                if (!list[i])
-                    return i;
-            }
-        } else {
-            for (i = 0; i < len; i++) {
-                if (list[i] && !strcmp(needle, list[i]))
-                    return i;
-            }
-        }
-    } else if (len < 0) {
-        g_return_val_if_fail(needle, -1);
-
-        if (list) {
-            for (i = 0; list[i]; i++) {
-                if (strcmp(needle, list[i]) == 0)
-                    return i;
-            }
-        }
-    }
-    return -1;
-}
-
-char **
-_nm_utils_strv_cleanup(char **  strv,
-                       gboolean strip_whitespace,
-                       gboolean skip_empty,
-                       gboolean skip_repeated)
-{
-    guint i, j;
-
-    if (!strv || !*strv)
-        return strv;
-
-    if (strip_whitespace) {
-        /* we only modify the strings pointed to by @strv if @strip_whitespace is
-         * requested. Otherwise, the strings themselves are untouched. */
-        for (i = 0; strv[i]; i++)
-            g_strstrip(strv[i]);
-    }
-    if (!skip_empty && !skip_repeated)
-        return strv;
-    j = 0;
-    for (i = 0; strv[i]; i++) {
-        if ((skip_empty && !*strv[i])
-            || (skip_repeated && nm_utils_strv_find_first(strv, j, strv[i]) >= 0))
-            g_free(strv[i]);
-        else
-            strv[j++] = strv[i];
-    }
-    strv[j] = NULL;
-    return strv;
-}
-
-/*****************************************************************************/
-
-GPtrArray *
-_nm_g_ptr_array_copy(GPtrArray *    array,
-                     GCopyFunc      func,
-                     gpointer       user_data,
-                     GDestroyNotify element_free_func)
-{
-    GPtrArray *new_array;
-    guint      i;
-
-    g_return_val_if_fail(array, NULL);
-
-    new_array = g_ptr_array_new_full(array->len, element_free_func);
-    for (i = 0; i < array->len; i++) {
-        g_ptr_array_add(new_array, func ? func(array->pdata[i], user_data) : array->pdata[i]);
-    }
-    return new_array;
-}
-
-/*****************************************************************************/
-
-int
-_nm_utils_ascii_str_to_bool(const char *str, int default_value)
-{
-    gs_free char *str_free = NULL;
-
-    if (!str)
-        return default_value;
-
-    str = nm_strstrip_avoid_copy_a(300, str, &str_free);
-    if (str[0] == '\0')
-        return default_value;
-
-    if (!g_ascii_strcasecmp(str, "true") || !g_ascii_strcasecmp(str, "yes")
-        || !g_ascii_strcasecmp(str, "on") || !g_ascii_strcasecmp(str, "1"))
-        return TRUE;
-
-    if (!g_ascii_strcasecmp(str, "false") || !g_ascii_strcasecmp(str, "no")
-        || !g_ascii_strcasecmp(str, "off") || !g_ascii_strcasecmp(str, "0"))
-        return FALSE;
-
-    return default_value;
-}
-
-/*****************************************************************************/
-
-NM_CACHED_QUARK_FCN("nm-manager-error-quark", nm_manager_error_quark);
-
-NM_CACHED_QUARK_FCN("nm-utils-error-quark", nm_utils_error_quark);
-
-void
-nm_utils_error_set_cancelled(GError **error, gboolean is_disposing, const char *instance_name)
-{
-    if (is_disposing) {
-        g_set_error(error,
-                    NM_UTILS_ERROR,
-                    NM_UTILS_ERROR_CANCELLED_DISPOSING,
-                    "Disposing %s instance",
-                    instance_name && *instance_name ? instance_name : "source");
-    } else {
-        g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Request cancelled");
-    }
-}
-
-gboolean
-nm_utils_error_is_cancelled_or_disposing(GError *error)
-{
-    if (error) {
-        if (error->domain == G_IO_ERROR)
-            return NM_IN_SET(error->code, G_IO_ERROR_CANCELLED);
-        if (error->domain == NM_UTILS_ERROR)
-            return NM_IN_SET(error->code, NM_UTILS_ERROR_CANCELLED_DISPOSING);
-    }
-    return FALSE;
-}
-
-gboolean
-nm_utils_error_is_notfound(GError *error)
-{
-    if (error) {
-        if (error->domain == G_IO_ERROR)
-            return NM_IN_SET(error->code, G_IO_ERROR_NOT_FOUND);
-        if (error->domain == G_FILE_ERROR)
-            return NM_IN_SET(error->code, G_FILE_ERROR_NOENT);
-    }
-    return FALSE;
-}
-
-/*****************************************************************************/
-
-/**
- * nm_g_object_set_property:
- * @object: the target object
- * @property_name: the property name
- * @value: the #GValue to set
- * @error: (allow-none): optional error argument
- *
- * A reimplementation of g_object_set_property(), but instead
- * returning an error instead of logging a warning. All g_object_set*()
- * versions in glib require you to not pass invalid types or they will
- * log a g_warning() -- without reporting an error. We don't want that,
- * so we need to hack error checking around it.
- *
- * Returns: whether the value was successfully set.
- */
-gboolean
-nm_g_object_set_property(GObject *     object,
-                         const char *  property_name,
-                         const GValue *value,
-                         GError **     error)
-{
-    GParamSpec *                pspec;
-    nm_auto_unset_gvalue GValue tmp_value = G_VALUE_INIT;
-    GObjectClass *              klass;
-
-    g_return_val_if_fail(G_IS_OBJECT(object), FALSE);
-    g_return_val_if_fail(property_name != NULL, FALSE);
-    g_return_val_if_fail(G_IS_VALUE(value), FALSE);
-    g_return_val_if_fail(!error || !*error, FALSE);
-
-    /* g_object_class_find_property() does g_param_spec_get_redirect_target(),
-     * where we differ from a plain g_object_set_property(). */
-    pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(object), property_name);
-
-    if (!pspec) {
-        g_set_error(error,
-                    NM_UTILS_ERROR,
-                    NM_UTILS_ERROR_UNKNOWN,
-                    _("object class '%s' has no property named '%s'"),
-                    G_OBJECT_TYPE_NAME(object),
-                    property_name);
-        return FALSE;
-    }
-    if (!(pspec->flags & G_PARAM_WRITABLE)) {
-        g_set_error(error,
-                    NM_UTILS_ERROR,
-                    NM_UTILS_ERROR_UNKNOWN,
-                    _("property '%s' of object class '%s' is not writable"),
-                    pspec->name,
-                    G_OBJECT_TYPE_NAME(object));
-        return FALSE;
-    }
-    if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY)) {
-        g_set_error(error,
-                    NM_UTILS_ERROR,
-                    NM_UTILS_ERROR_UNKNOWN,
-                    _("construct property \"%s\" for object '%s' can't be set after construction"),
-                    pspec->name,
-                    G_OBJECT_TYPE_NAME(object));
-        return FALSE;
-    }
-
-    klass = g_type_class_peek(pspec->owner_type);
-    if (klass == NULL) {
-        g_set_error(error,
-                    NM_UTILS_ERROR,
-                    NM_UTILS_ERROR_UNKNOWN,
-                    _("'%s::%s' is not a valid property name; '%s' is not a GObject subtype"),
-                    g_type_name(pspec->owner_type),
-                    pspec->name,
-                    g_type_name(pspec->owner_type));
-        return FALSE;
-    }
-
-    /* provide a copy to work from, convert (if necessary) and validate */
-    g_value_init(&tmp_value, pspec->value_type);
-    if (!g_value_transform(value, &tmp_value)) {
-        g_set_error(error,
-                    NM_UTILS_ERROR,
-                    NM_UTILS_ERROR_UNKNOWN,
-                    _("unable to set property '%s' of type '%s' from value of type '%s'"),
-                    pspec->name,
-                    g_type_name(pspec->value_type),
-                    G_VALUE_TYPE_NAME(value));
-        return FALSE;
-    }
-    if (g_param_value_validate(pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION)) {
-        gs_free char *contents = g_strdup_value_contents(value);
-
-        g_set_error(error,
-                    NM_UTILS_ERROR,
-                    NM_UTILS_ERROR_UNKNOWN,
-                    _("value \"%s\" of type '%s' is invalid or out of range for property '%s' of "
-                      "type '%s'"),
-                    contents,
-                    G_VALUE_TYPE_NAME(value),
-                    pspec->name,
-                    g_type_name(pspec->value_type));
-        return FALSE;
-    }
-
-    g_object_set_property(object, property_name, &tmp_value);
-    return TRUE;
-}
-
-#define _set_property(object, property_name, gtype, gtype_set, value, error)          \
-    G_STMT_START                                                                      \
-    {                                                                                 \
-        nm_auto_unset_gvalue GValue gvalue = {0};                                     \
-                                                                                      \
-        g_value_init(&gvalue, gtype);                                                 \
-        gtype_set(&gvalue, (value));                                                  \
-        return nm_g_object_set_property((object), (property_name), &gvalue, (error)); \
-    }                                                                                 \
-    G_STMT_END
-
-gboolean
-nm_g_object_set_property_string(GObject *   object,
-                                const char *property_name,
-                                const char *value,
-                                GError **   error)
-{
-    _set_property(object, property_name, G_TYPE_STRING, g_value_set_string, value, error);
-}
-
-gboolean
-nm_g_object_set_property_string_static(GObject *   object,
-                                       const char *property_name,
-                                       const char *value,
-                                       GError **   error)
-{
-    _set_property(object, property_name, G_TYPE_STRING, g_value_set_static_string, value, error);
-}
-
-gboolean
-nm_g_object_set_property_string_take(GObject *   object,
-                                     const char *property_name,
-                                     char *      value,
-                                     GError **   error)
-{
-    _set_property(object, property_name, G_TYPE_STRING, g_value_take_string, value, error);
-}
-
-gboolean
-nm_g_object_set_property_boolean(GObject *   object,
-                                 const char *property_name,
-                                 gboolean    value,
-                                 GError **   error)
-{
-    _set_property(object, property_name, G_TYPE_BOOLEAN, g_value_set_boolean, !!value, error);
-}
-
-gboolean
-nm_g_object_set_property_char(GObject *   object,
-                              const char *property_name,
-                              gint8       value,
-                              GError **   error)
-{
-    /* glib says about G_TYPE_CHAR:
-     *
-     * The type designated by G_TYPE_CHAR is unconditionally an 8-bit signed integer.
-     *
-     * This is always a (signed!) char. */
-    _set_property(object, property_name, G_TYPE_CHAR, g_value_set_schar, value, error);
-}
-
-gboolean
-nm_g_object_set_property_uchar(GObject *   object,
-                               const char *property_name,
-                               guint8      value,
-                               GError **   error)
-{
-    _set_property(object, property_name, G_TYPE_UCHAR, g_value_set_uchar, value, error);
-}
-
-gboolean
-nm_g_object_set_property_int(GObject *object, const char *property_name, int value, GError **error)
-{
-    _set_property(object, property_name, G_TYPE_INT, g_value_set_int, value, error);
-}
-
-gboolean
-nm_g_object_set_property_int64(GObject *   object,
-                               const char *property_name,
-                               gint64      value,
-                               GError **   error)
-{
-    _set_property(object, property_name, G_TYPE_INT64, g_value_set_int64, value, error);
-}
-
-gboolean
-nm_g_object_set_property_uint(GObject *   object,
-                              const char *property_name,
-                              guint       value,
-                              GError **   error)
-{
-    _set_property(object, property_name, G_TYPE_UINT, g_value_set_uint, value, error);
-}
-
-gboolean
-nm_g_object_set_property_uint64(GObject *   object,
-                                const char *property_name,
-                                guint64     value,
-                                GError **   error)
-{
-    _set_property(object, property_name, G_TYPE_UINT64, g_value_set_uint64, value, error);
-}
-
-gboolean
-nm_g_object_set_property_flags(GObject *   object,
-                               const char *property_name,
-                               GType       gtype,
-                               guint       value,
-                               GError **   error)
-{
-    nm_assert(({
-        nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref(gtype);
-        G_IS_FLAGS_CLASS(gtypeclass);
-    }));
-    _set_property(object, property_name, gtype, g_value_set_flags, value, error);
-}
-
-gboolean
-nm_g_object_set_property_enum(GObject *   object,
-                              const char *property_name,
-                              GType       gtype,
-                              int         value,
-                              GError **   error)
-{
-    nm_assert(({
-        nm_auto_unref_gtypeclass GTypeClass *gtypeclass = g_type_class_ref(gtype);
-        G_IS_ENUM_CLASS(gtypeclass);
-    }));
-    _set_property(object, property_name, gtype, g_value_set_enum, value, error);
-}
-
-GParamSpec *
-nm_g_object_class_find_property_from_gtype(GType gtype, const char *property_name)
-{
-    nm_auto_unref_gtypeclass GObjectClass *gclass = NULL;
-
-    gclass = g_type_class_ref(gtype);
-    return g_object_class_find_property(gclass, property_name);
-}
-
-/*****************************************************************************/
-
-/**
- * nm_g_type_find_implementing_class_for_property:
- * @gtype: the GObject type which has a property @pname
- * @pname: the name of the property to look up
- *
- * This is only a helper function for printf debugging. It's not
- * used in actual code. Hence, the function just asserts that
- * @pname and @gtype arguments are suitable. It cannot fail.
- *
- * Returns: the most ancestor type of @gtype, that
- *   implements the property @pname. It means, it
- *   searches the type hierarchy to find the type
- *   that added @pname.
- */
-GType
-nm_g_type_find_implementing_class_for_property(GType gtype, const char *pname)
-{
-    nm_auto_unref_gtypeclass GObjectClass *klass = NULL;
-    GParamSpec *                           pspec;
-
-    g_return_val_if_fail(pname, G_TYPE_INVALID);
-
-    klass = g_type_class_ref(gtype);
-    g_return_val_if_fail(G_IS_OBJECT_CLASS(klass), G_TYPE_INVALID);
-
-    pspec = g_object_class_find_property(klass, pname);
-    g_return_val_if_fail(pspec, G_TYPE_INVALID);
-
-    gtype = G_TYPE_FROM_CLASS(klass);
-
-    while (TRUE) {
-        nm_auto_unref_gtypeclass GObjectClass *k = NULL;
-
-        k = g_type_class_ref(g_type_parent(gtype));
-
-        g_return_val_if_fail(G_IS_OBJECT_CLASS(k), G_TYPE_INVALID);
-
-        if (g_object_class_find_property(k, pname) != pspec)
-            return gtype;
-
-        gtype = G_TYPE_FROM_CLASS(k);
-    }
-}
-
-/*****************************************************************************/
-
-static void
-_str_buf_append_c_escape_octal(NMStrBuf *strbuf, char ch)
-{
-    nm_str_buf_append_c4(strbuf,
-                         '\\',
-                         '0' + ((char) ((((guchar) ch) >> 6) & 07)),
-                         '0' + ((char) ((((guchar) ch) >> 3) & 07)),
-                         '0' + ((char) ((((guchar) ch)) & 07)));
-}
-
-/**
- * nm_utils_buf_utf8safe_unescape:
- * @str: (allow-none): the string to unescape. The string itself is a NUL terminated
- *   ASCII string, that can have C-style backslash escape sequences (which
- *   are to be unescaped). Non-ASCII characters (e.g. UTF-8) are taken verbatim, so
- *   it doesn't care that this string is UTF-8. However, usually this is a UTF-8 encoded
- *   string.
- * @flags: flags for unescaping. The following flags are supported.
- *   %NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES performs a g_strstrip() on the input string,
- *   but preserving escaped spaces. For example, "a\\t " gives "a\t" (that is, the escaped space does
- *   not get stripped). Likewise, the invalid escape sequence "a\\  " results in "a " (stripping
- *   the unescaped space, but preserving the escaped one).
- * @out_len: (out): the length of the parsed string.
- * @to_free: (out): if @str requires unescaping, the function will clone the string. In
- *   that case, the allocated buffer will be returned here.
- *
- * See C-style escapes at https://en.wikipedia.org/wiki/Escape_sequences_in_C#Table_of_escape_sequences.
- * Note that hex escapes ("\\xhh") and unicode escapes ("\\uhhhh", "\\Uhhhhhhhh") are not supported.
- *
- * Also, this function is very similar to g_strcompress() but without issuing g_warning()
- * assertions and proper handling of "\\000" escape sequences.
- *
- * Invalid escape sequences (or non-UTF-8 input) are gracefully accepted. For example "\\ "
- * is an invalid escape sequence, in this case the backslash is removed and " " gets returned.
- *
- * The function never leaks secrets in memory.
- *
- * Returns: the unescaped buffer of length @out_len. If @str is %NULL, this returns %NULL
- *   and sets @out_len to 0. Otherwise, a non-%NULL binary buffer is returned with
- *   @out_len bytes. Note that the binary buffer is guaranteed to be NUL terminated. That
- *   is @result[@out_len] is NUL.
- *   Note that the result is binary, and may have embedded NUL characters and non-UTF-8.
- *   If the function can avoid cloning the input string, it will return a pointer inside
- *   the input @str. For example, if there is no backslash, no cloning is necessary. In that
- *   case, @to_free will be %NULL. Otherwise, @to_free is set to a newly allocated buffer
- *   containing the unescaped string and returned.
- */
-gconstpointer
-nm_utils_buf_utf8safe_unescape(const char *            str,
-                               NMUtilsStrUtf8SafeFlags flags,
-                               gsize *                 out_len,
-                               gpointer *              to_free)
-{
-    gboolean    strip_spaces = NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES);
-    NMStrBuf    strbuf;
-    const char *s;
-    gsize       len;
-
-    g_return_val_if_fail(to_free, NULL);
-    g_return_val_if_fail(out_len, NULL);
-
-    if (!str) {
-        *out_len = 0;
-        *to_free = NULL;
-        return NULL;
-    }
-
-    if (strip_spaces)
-        str = nm_str_skip_leading_spaces(str);
-
-    len = strlen(str);
-
-    s = memchr(str, '\\', len);
-    if (!s) {
-        if (strip_spaces && len > 0 && g_ascii_isspace(str[len - 1])) {
-            len--;
-            while (len > 0 && g_ascii_isspace(str[len - 1]))
-                len--;
-            *out_len = len;
-            return (*to_free = g_strndup(str, len));
-        }
-        *out_len = len;
-        *to_free = NULL;
-        return str;
-    }
-
-    nm_str_buf_init(&strbuf, len + 1u, FALSE);
-
-    nm_str_buf_append_len(&strbuf, str, s - str);
-    str = s;
-
-    for (;;) {
-        char  ch;
-        guint v;
-
-        nm_assert(str[0] == '\\');
-
-        ch = (++str)[0];
-
-        if (ch == '\0') {
-            /* error. Trailing '\\' */
-            break;
-        }
-
-        if (ch >= '0' && ch <= '9') {
-            v  = ch - '0';
-            ch = (++str)[0];
-            if (ch >= '0' && ch <= '7') {
-                v  = v * 8 + (ch - '0');
-                ch = (++str)[0];
-                if (ch >= '0' && ch <= '7') {
-                    /* technically, escape sequences larger than \3FF are out of range
-                     * and invalid. We don't check for that, and do the same as
-                     * g_strcompress(): silently clip the value with & 0xFF. */
-                    v = v * 8 + (ch - '0');
-                    ++str;
-                }
-            }
-            ch = v;
-        } else {
-            switch (ch) {
-            case 'b':
-                ch = '\b';
-                break;
-            case 'f':
-                ch = '\f';
-                break;
-            case 'n':
-                ch = '\n';
-                break;
-            case 'r':
-                ch = '\r';
-                break;
-            case 't':
-                ch = '\t';
-                break;
-            case 'v':
-                ch = '\v';
-                break;
-            default:
-                /* Here we handle "\\\\", but all other unexpected escape sequences are really a bug.
-                 * Take them literally, after removing the escape character */
-                break;
-            }
-            str++;
-        }
-
-        nm_str_buf_append_c(&strbuf, ch);
-
-        s = strchr(str, '\\');
-        if (!s) {
-            gsize l = strlen(str);
-
-            if (strip_spaces) {
-                while (l > 0 && g_ascii_isspace(str[l - 1]))
-                    l--;
-            }
-            nm_str_buf_append_len(&strbuf, str, l);
-            break;
-        }
-
-        nm_str_buf_append_len(&strbuf, str, s - str);
-        str = s;
-    }
-
-    /* assert that no reallocation was necessary. For one, unescaping should
-     * never result in a longer string than the input. Also, when unescaping
-     * secrets, we want to ensure that we don't leak secrets in memory. */
-    nm_assert(strbuf.allocated == len + 1u);
-
-    return (*to_free = nm_str_buf_finalize(&strbuf, out_len));
-}
-
-/**
- * nm_utils_buf_utf8safe_escape:
- * @buf: byte array, possibly in utf-8 encoding, may have NUL characters.
- * @buflen: the length of @buf in bytes, or -1 if @buf is a NUL terminated
- *   string.
- * @flags: #NMUtilsStrUtf8SafeFlags flags
- * @to_free: (out): return the pointer location of the string
- *   if a copying was necessary.
- *
- * Based on the assumption, that @buf contains UTF-8 encoded bytes,
- * this will return valid UTF-8 sequence, and invalid sequences
- * will be escaped with backslash (C escaping, like g_strescape()).
- * This is sanitize non UTF-8 characters. The result is valid
- * UTF-8.
- *
- * The operation can be reverted with nm_utils_buf_utf8safe_unescape().
- * Note that if, and only if @buf contains no NUL bytes, the operation
- * can also be reverted with g_strcompress().
- *
- * Depending on @flags, valid UTF-8 characters are not escaped at all
- * (except the escape character '\\'). This is the difference to g_strescape(),
- * which escapes all non-ASCII characters. This allows to pass on
- * valid UTF-8 characters as-is and can be directly shown to the user
- * as UTF-8 -- with exception of the backslash escape character,
- * invalid UTF-8 sequences, and other (depending on @flags).
- *
- * Returns: the escaped input buffer, as valid UTF-8. If no escaping
- *   is necessary, it returns the input @buf. Otherwise, an allocated
- *   string @to_free is returned which must be freed by the caller
- *   with g_free. The escaping can be reverted by g_strcompress().
- **/
-const char *
-nm_utils_buf_utf8safe_escape(gconstpointer           buf,
-                             gssize                  buflen,
-                             NMUtilsStrUtf8SafeFlags flags,
-                             char **                 to_free)
-{
-    const char *const str = buf;
-    const char *      p   = NULL;
-    const char *      s;
-    gboolean          nul_terminated = FALSE;
-    NMStrBuf          strbuf;
-
-    g_return_val_if_fail(to_free, NULL);
-
-    *to_free = NULL;
-
-    if (buflen == 0)
-        return NULL;
-
-    if (buflen < 0) {
-        if (!str)
-            return NULL;
-        buflen = strlen(str);
-        if (buflen == 0)
-            return str;
-        nul_terminated = TRUE;
-    }
-
-    if (g_utf8_validate(str, buflen, &p) && nul_terminated) {
-        /* note that g_utf8_validate() does not allow NUL character inside @str. Good.
-         * We can treat @str like a NUL terminated string. */
-        if (!NM_STRCHAR_ANY(
-                str,
-                ch,
-                (ch == '\\'
-                 || (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) && ch < ' ')
-                 || (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII)
-                     && ((guchar) ch) >= 127))))
-            return str;
-    }
-
-    nm_str_buf_init(&strbuf, buflen + 5, NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET));
-
-    s = str;
-    do {
-        buflen -= p - s;
-        nm_assert(buflen >= 0);
-
-        for (; s < p; s++) {
-            char ch = s[0];
-
-            nm_assert(ch);
-            if (ch == '\\')
-                nm_str_buf_append_c2(&strbuf, '\\', '\\');
-            else if ((NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL) && ch < ' ')
-                     || (NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII)
-                         && ((guchar) ch) >= 127))
-                _str_buf_append_c_escape_octal(&strbuf, ch);
-            else
-                nm_str_buf_append_c(&strbuf, ch);
-        }
-
-        if (buflen <= 0)
-            break;
-
-        _str_buf_append_c_escape_octal(&strbuf, p[0]);
-
-        buflen--;
-        if (buflen == 0)
-            break;
-
-        s = &p[1];
-        (void) g_utf8_validate(s, buflen, &p);
-    } while (TRUE);
-
-    return (*to_free = nm_str_buf_finalize(&strbuf, NULL));
-}
-
-const char *
-nm_utils_buf_utf8safe_escape_bytes(GBytes *bytes, NMUtilsStrUtf8SafeFlags flags, char **to_free)
-{
-    gconstpointer p;
-    gsize         l;
-
-    if (bytes)
-        p = g_bytes_get_data(bytes, &l);
-    else {
-        p = NULL;
-        l = 0;
-    }
-
-    return nm_utils_buf_utf8safe_escape(p, l, flags, to_free);
-}
-
-char *
-nm_utils_buf_utf8safe_escape_cp(gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags)
-{
-    const char *s_const;
-    char *      s;
-
-    s_const = nm_utils_buf_utf8safe_escape(buf, buflen, flags, &s);
-    nm_assert(!s || s == s_const);
-    return s ?: g_strdup(s_const);
-}
-
-/*****************************************************************************/
-
-const char *
-nm_utils_str_utf8safe_unescape(const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free)
-{
-    const char *res;
-    gsize       len;
-
-    g_return_val_if_fail(to_free, NULL);
-
-    res = nm_utils_buf_utf8safe_unescape(str, flags, &len, (gpointer *) to_free);
-
-    nm_assert((!res && len == 0) || (strlen(res) <= len));
-
-    return res;
-}
-
-/**
- * nm_utils_str_utf8safe_escape:
- * @str: NUL terminated input string, possibly in utf-8 encoding
- * @flags: #NMUtilsStrUtf8SafeFlags flags
- * @to_free: (out): return the pointer location of the string
- *   if a copying was necessary.
- *
- * Returns the possible non-UTF-8 NUL terminated string @str
- * and uses backslash escaping (C escaping, like g_strescape())
- * to sanitize non UTF-8 characters. The result is valid
- * UTF-8.
- *
- * The operation can be reverted with g_strcompress() or
- * nm_utils_str_utf8safe_unescape().
- *
- * Depending on @flags, valid UTF-8 characters are not escaped at all
- * (except the escape character '\\'). This is the difference to g_strescape(),
- * which escapes all non-ASCII characters. This allows to pass on
- * valid UTF-8 characters as-is and can be directly shown to the user
- * as UTF-8 -- with exception of the backslash escape character,
- * invalid UTF-8 sequences, and other (depending on @flags).
- *
- * Returns: the escaped input string, as valid UTF-8. If no escaping
- *   is necessary, it returns the input @str. Otherwise, an allocated
- *   string @to_free is returned which must be freed by the caller
- *   with g_free. The escaping can be reverted by g_strcompress().
- **/
-const char *
-nm_utils_str_utf8safe_escape(const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free)
-{
-    return nm_utils_buf_utf8safe_escape(str, -1, flags, to_free);
-}
-
-/**
- * nm_utils_str_utf8safe_escape_cp:
- * @str: NUL terminated input string, possibly in utf-8 encoding
- * @flags: #NMUtilsStrUtf8SafeFlags flags
- *
- * Like nm_utils_str_utf8safe_escape(), except the returned value
- * is always a copy of the input and must be freed by the caller.
- *
- * Returns: the escaped input string in UTF-8 encoding. The returned
- *   value should be freed with g_free().
- *   The escaping can be reverted by g_strcompress().
- **/
-char *
-nm_utils_str_utf8safe_escape_cp(const char *str, NMUtilsStrUtf8SafeFlags flags)
-{
-    char *s;
-
-    nm_utils_str_utf8safe_escape(str, flags, &s);
-    return s ?: g_strdup(str);
-}
-
-char *
-nm_utils_str_utf8safe_unescape_cp(const char *str, NMUtilsStrUtf8SafeFlags flags)
-{
-    char *s;
-
-    str = nm_utils_str_utf8safe_unescape(str, flags, &s);
-    return s ?: g_strdup(str);
-}
-
-char *
-nm_utils_str_utf8safe_escape_take(char *str, NMUtilsStrUtf8SafeFlags flags)
-{
-    char *str_to_free;
-
-    nm_utils_str_utf8safe_escape(str, flags, &str_to_free);
-    if (str_to_free) {
-        g_free(str);
-        return str_to_free;
-    }
-    return str;
-}
-
-/*****************************************************************************/
-
-/* taken from systemd's fd_wait_for_event(). Note that the timeout
- * is here in nano-seconds, not micro-seconds. */
-int
-nm_utils_fd_wait_for_event(int fd, int event, gint64 timeout_nsec)
-{
-    struct pollfd pollfd = {
-        .fd     = fd,
-        .events = event,
-    };
-    struct timespec ts, *pts;
-    int             r;
-
-    if (timeout_nsec < 0)
-        pts = NULL;
-    else {
-        ts.tv_sec  = (time_t)(timeout_nsec / NM_UTILS_NSEC_PER_SEC);
-        ts.tv_nsec = (long int) (timeout_nsec % NM_UTILS_NSEC_PER_SEC);
-        pts        = &ts;
-    }
-
-    r = ppoll(&pollfd, 1, pts, NULL);
-    if (r < 0)
-        return -NM_ERRNO_NATIVE(errno);
-    if (r == 0)
-        return 0;
-    return pollfd.revents;
-}
-
-/* taken from systemd's loop_read() */
-ssize_t
-nm_utils_fd_read_loop(int fd, void *buf, size_t nbytes, bool do_poll)
-{
-    uint8_t *p = buf;
-    ssize_t  n = 0;
-
-    g_return_val_if_fail(fd >= 0, -EINVAL);
-    g_return_val_if_fail(buf, -EINVAL);
-
-    /* If called with nbytes == 0, let's call read() at least
-     * once, to validate the operation */
-
-    if (nbytes > (size_t) SSIZE_MAX)
-        return -EINVAL;
-
-    do {
-        ssize_t k;
-
-        k = read(fd, p, nbytes);
-        if (k < 0) {
-            int errsv = errno;
-
-            if (errsv == EINTR)
-                continue;
-
-            if (errsv == EAGAIN && do_poll) {
-                /* We knowingly ignore any return value here,
-                 * and expect that any error/EOF is reported
-                 * via read() */
-
-                (void) nm_utils_fd_wait_for_event(fd, POLLIN, -1);
-                continue;
-            }
-
-            return n > 0 ? n : -NM_ERRNO_NATIVE(errsv);
-        }
-
-        if (k == 0)
-            return n;
-
-        g_assert((size_t) k <= nbytes);
-
-        p += k;
-        nbytes -= k;
-        n += k;
-    } while (nbytes > 0);
-
-    return n;
-}
-
-/* taken from systemd's loop_read_exact() */
-int
-nm_utils_fd_read_loop_exact(int fd, void *buf, size_t nbytes, bool do_poll)
-{
-    ssize_t n;
-
-    n = nm_utils_fd_read_loop(fd, buf, nbytes, do_poll);
-    if (n < 0)
-        return (int) n;
-    if ((size_t) n != nbytes)
-        return -EIO;
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-void
-nm_utils_named_value_clear_with_g_free(NMUtilsNamedValue *val)
-{
-    if (val) {
-        gs_free gpointer x_name  = NULL;
-        gs_free gpointer x_value = NULL;
-
-        x_name  = (gpointer) g_steal_pointer(&val->name);
-        x_value = g_steal_pointer(&val->value_ptr);
-    }
-}
-
-G_STATIC_ASSERT(G_STRUCT_OFFSET(NMUtilsNamedValue, name) == 0);
-
-NMUtilsNamedValue *
-nm_utils_named_values_from_strdict_full(GHashTable *        hash,
-                                        guint *             out_len,
-                                        GCompareDataFunc    compare_func,
-                                        gpointer            user_data,
-                                        NMUtilsNamedValue * provided_buffer,
-                                        guint               provided_buffer_len,
-                                        NMUtilsNamedValue **out_allocated_buffer)
-{
-    GHashTableIter     iter;
-    NMUtilsNamedValue *values;
-    guint              i, len;
-
-    nm_assert(provided_buffer_len == 0 || provided_buffer);
-    nm_assert(!out_allocated_buffer || !*out_allocated_buffer);
-
-    if (!hash || !(len = g_hash_table_size(hash))) {
-        NM_SET_OUT(out_len, 0);
-        return NULL;
-    }
-
-    if (provided_buffer_len >= len + 1) {
-        /* the buffer provided by the caller is large enough. Use it. */
-        values = provided_buffer;
-    } else {
-        /* allocate a new buffer. */
-        values = g_new(NMUtilsNamedValue, len + 1);
-        NM_SET_OUT(out_allocated_buffer, values);
-    }
-
-    i = 0;
-    g_hash_table_iter_init(&iter, hash);
-    while (g_hash_table_iter_next(&iter, (gpointer *) &values[i].name, &values[i].value_ptr))
-        i++;
-    nm_assert(i == len);
-    values[i].name      = NULL;
-    values[i].value_ptr = NULL;
-
-    if (compare_func)
-        nm_utils_named_value_list_sort(values, len, compare_func, user_data);
-
-    NM_SET_OUT(out_len, len);
-    return values;
-}
-
-gssize
-nm_utils_named_value_list_find(const NMUtilsNamedValue *arr,
-                               gsize                    len,
-                               const char *             name,
-                               gboolean                 sorted)
-{
-    gsize i;
-
-    nm_assert(name);
-
-#if NM_MORE_ASSERTS > 5
-    {
-        for (i = 0; i < len; i++) {
-            const NMUtilsNamedValue *v = &arr[i];
-
-            nm_assert(v->name);
-            if (sorted && i > 0)
-                nm_assert(strcmp(arr[i - 1].name, v->name) < 0);
-        }
-    }
-
-    nm_assert(!sorted || nm_utils_named_value_list_is_sorted(arr, len, FALSE, NULL, NULL));
-#endif
-
-    if (sorted) {
-        return nm_utils_array_find_binary_search(arr,
-                                                 sizeof(NMUtilsNamedValue),
-                                                 len,
-                                                 &name,
-                                                 nm_strcmp_p_with_data,
-                                                 NULL);
-    }
-    for (i = 0; i < len; i++) {
-        if (nm_streq(arr[i].name, name))
-            return i;
-    }
-    return ~((gssize) len);
-}
-
-gboolean
-nm_utils_named_value_list_is_sorted(const NMUtilsNamedValue *arr,
-                                    gsize                    len,
-                                    gboolean                 accept_duplicates,
-                                    GCompareDataFunc         compare_func,
-                                    gpointer                 user_data)
-{
-    gsize i;
-    int   c_limit;
-
-    if (len == 0)
-        return TRUE;
-
-    g_return_val_if_fail(arr, FALSE);
-
-    if (!compare_func)
-        compare_func = nm_strcmp_p_with_data;
-
-    c_limit = accept_duplicates ? 0 : -1;
-
-    for (i = 1; i < len; i++) {
-        int c;
-
-        c = compare_func(&arr[i - 1], &arr[i], user_data);
-        if (c > c_limit)
-            return FALSE;
-    }
-    return TRUE;
-}
-
-void
-nm_utils_named_value_list_sort(NMUtilsNamedValue *arr,
-                               gsize              len,
-                               GCompareDataFunc   compare_func,
-                               gpointer           user_data)
-{
-    if (len == 0)
-        return;
-
-    g_return_if_fail(arr);
-
-    if (len == 1)
-        return;
-
-    g_qsort_with_data(arr,
-                      len,
-                      sizeof(NMUtilsNamedValue),
-                      compare_func ?: nm_strcmp_p_with_data,
-                      user_data);
-}
-
-/*****************************************************************************/
-
-gpointer *
-nm_utils_hash_keys_to_array(GHashTable *     hash,
-                            GCompareDataFunc compare_func,
-                            gpointer         user_data,
-                            guint *          out_len)
-{
-    guint     len;
-    gpointer *keys;
-
-    /* by convention, we never return an empty array. In that
-     * case, always %NULL. */
-    if (!hash || g_hash_table_size(hash) == 0) {
-        NM_SET_OUT(out_len, 0);
-        return NULL;
-    }
-
-    keys = g_hash_table_get_keys_as_array(hash, &len);
-    if (len > 1 && compare_func) {
-        g_qsort_with_data(keys, len, sizeof(gpointer), compare_func, user_data);
-    }
-    NM_SET_OUT(out_len, len);
-    return keys;
-}
-
-gpointer *
-nm_utils_hash_values_to_array(GHashTable *     hash,
-                              GCompareDataFunc compare_func,
-                              gpointer         user_data,
-                              guint *          out_len)
-{
-    GHashTableIter iter;
-    gpointer       value;
-    gpointer *     arr;
-    guint          i, len;
-
-    if (!hash || (len = g_hash_table_size(hash)) == 0u) {
-        NM_SET_OUT(out_len, 0);
-        return NULL;
-    }
-
-    arr = g_new(gpointer, ((gsize) len) + 1);
-    i   = 0;
-    g_hash_table_iter_init(&iter, hash);
-    while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &value))
-        arr[i++] = value;
-
-    nm_assert(i == len);
-    arr[len] = NULL;
-
-    if (len > 1 && compare_func) {
-        g_qsort_with_data(arr, len, sizeof(gpointer), compare_func, user_data);
-    }
-
-    NM_SET_OUT(out_len, len);
-    return arr;
-}
-
-/*****************************************************************************/
-
-/**
- * nm_utils_hashtable_equal:
- * @a: one #GHashTable
- * @b: other #GHashTable
- * @treat_null_as_empty: if %TRUE, when either @a or @b is %NULL, it is
- *   treated like an empty hash. It means, a %NULL hash will compare equal
- *   to an empty hash.
- * @equal_func: the equality function, for comparing the values.
- *   If %NULL, the values are not compared. In that case, the function
- *   only checks, if both dictionaries have the same keys -- according
- *   to @b's key equality function.
- *   Note that the values of @a will be passed as first argument
- *   to @equal_func.
- *
- * Compares two hash tables, whether they have equal content.
- * This only makes sense, if @a and @b have the same key types and
- * the same key compare-function.
- *
- * Returns: %TRUE, if both dictionaries have the same content.
- */
-gboolean
-nm_utils_hashtable_equal(const GHashTable *a,
-                         const GHashTable *b,
-                         gboolean          treat_null_as_empty,
-                         GEqualFunc        equal_func)
-{
-    guint          n;
-    GHashTableIter iter;
-    gconstpointer  key, v_a, v_b;
-
-    if (a == b)
-        return TRUE;
-    if (!treat_null_as_empty) {
-        if (!a || !b)
-            return FALSE;
-    }
-
-    n = a ? g_hash_table_size((GHashTable *) a) : 0;
-    if (n != (b ? g_hash_table_size((GHashTable *) b) : 0))
-        return FALSE;
-
-    if (n > 0) {
-        g_hash_table_iter_init(&iter, (GHashTable *) a);
-        while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &v_a)) {
-            if (!g_hash_table_lookup_extended((GHashTable *) b, key, NULL, (gpointer *) &v_b))
-                return FALSE;
-            if (equal_func && !equal_func(v_a, v_b))
-                return FALSE;
-        }
-    }
-
-    return TRUE;
-}
-
-static gboolean
-_utils_hashtable_equal(GHashTable *     hash_a,
-                       GHashTable *     hash_b,
-                       GCompareDataFunc cmp_values,
-                       gpointer         user_data)
-{
-    GHashTableIter h;
-    gpointer       a_key;
-    gpointer       a_val;
-    gpointer       b_val;
-
-    nm_assert(hash_a);
-    nm_assert(hash_b);
-    nm_assert(hash_a != hash_b);
-    nm_assert(g_hash_table_size(hash_a) == g_hash_table_size(hash_b));
-
-    /* We rely on both hashes to have the same hash/equal function. Otherwise, we would have to iterate
-     * both hashes and check whether all keys/values are present in the respective other hash (which
-     * would be O(n^2), since we couldn't use the plain lookup function. That is not a useful thing
-     * for this function. */
-
-    g_hash_table_iter_init(&h, hash_a);
-    while (g_hash_table_iter_next(&h, &a_key, &a_val)) {
-        if (!g_hash_table_lookup_extended(hash_b, a_key, NULL, &b_val))
-            return FALSE;
-
-        if (!cmp_values) {
-            /* we accept %NULL compare function to indicate that we don't care about the key. */
-            continue;
-        }
-
-        if (cmp_values(a_val, b_val, user_data) != 0)
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
-/**
- * nm_utils_hashtable_cmp_equal:
- * @a: (allow-none): the hash table or %NULL
- * @b: (allow-none): the other hash table or %NULL
- * @cmp_values: (allow-none): if %NULL, only the keys
- *   will be compared. Otherwise, this function is used to
- *   check whether all keys are equal.
- * @user_data: the argument for @cmp_values.
- *
- * It is required that both @a and @b have the same hash and equals
- * function.
- *
- * Returns: %TRUE, if both keys have the same keys and (if
- *   @cmp_values is given) all values are the same.
- */
-gboolean
-nm_utils_hashtable_cmp_equal(const GHashTable *a,
-                             const GHashTable *b,
-                             GCompareDataFunc  cmp_values,
-                             gpointer          user_data)
-{
-    GHashTable *hash_a = (GHashTable *) a;
-    GHashTable *hash_b = (GHashTable *) b;
-    gboolean    same;
-    guint       size;
-
-    if (hash_a == hash_b)
-        return TRUE;
-
-    if (!hash_a || !hash_b)
-        return FALSE;
-
-    size = g_hash_table_size(hash_a);
-    if (size != g_hash_table_size(hash_b))
-        return FALSE;
-
-    if (size == 0)
-        return TRUE;
-
-    same = _utils_hashtable_equal(hash_a, hash_b, cmp_values, user_data);
-
-#if NM_MORE_ASSERTS > 5
-    nm_assert(same == _utils_hashtable_equal(hash_b, hash_a, cmp_values, user_data));
-#endif
-
-    return same;
-}
-
-typedef struct {
-    gpointer key;
-    gpointer val;
-} HashTableCmpData;
-
-typedef struct {
-    GCompareDataFunc cmp_keys;
-    gpointer         user_data;
-} HashTableUserData;
-
-static int
-_hashtable_cmp_func(gconstpointer a, gconstpointer b, gpointer user_data)
-{
-    const HashTableUserData *d   = user_data;
-    const HashTableCmpData * d_a = *((const HashTableCmpData *const *) a);
-    const HashTableCmpData * d_b = *((const HashTableCmpData *const *) b);
-
-    NM_CMP_RETURN(d->cmp_keys(d_a, d_b, d->user_data));
-    return 0;
-}
-
-/**
- * nm_utils_hashtable_cmp:
- * @a: (allow-none): the hash to compare. May be %NULL.
- * @b: (allow-none): the other hash to compare. May be %NULL.
- * @do_fast_precheck: if %TRUE, assume that the hashes are equal
- *   and that it is worth calling nm_utils_hashtable_cmp_equal() first.
- *   That requires, that both hashes have the same equals function
- *   which is compatible with the @cmp_keys function.
- * @cmp_keys: the compare function for keys. Usually, the hash/equal function
- *   of both hashes corresponds to this function. If you set @do_fast_precheck
- *   to false, then this is not a requirement.
- * @cmp_values: (allow-none): if %NULL, only the keys are compared.
- *   Otherwise, the values must are also compared with this function.
- *
- * Both hashes must have keys/values of the same domain, so that
- * they can be effectively compared with @cmp_keys and @cmp_values.
- *
- * %NULL hashes compare equal to %NULL, but not to empty hashes.
- *
- * Returns: 0 if both hashes are equal, or -1 or 1 if one of the hashes
- *   sorts before/after.
- */
-int
-nm_utils_hashtable_cmp(const GHashTable *a,
-                       const GHashTable *b,
-                       gboolean          do_fast_precheck,
-                       GCompareDataFunc  cmp_keys,
-                       GCompareDataFunc  cmp_values,
-                       gpointer          user_data)
-{
-    GHashTable *hash_a                       = (GHashTable *) a;
-    GHashTable *hash_b                       = (GHashTable *) b;
-    gs_free HashTableCmpData *cmp_array_free = NULL;
-    HashTableCmpData *        cmp_array_a;
-    HashTableCmpData *        cmp_array_b;
-    GHashTableIter            h;
-    gpointer                  i_key;
-    gpointer                  i_val;
-    gsize                     size2;
-    guint                     size;
-    guint                     i;
-
-    nm_assert(cmp_keys);
-
-    NM_CMP_SELF(hash_a, hash_b);
-
-    size = g_hash_table_size(hash_a);
-
-    NM_CMP_DIRECT(size, g_hash_table_size(hash_b));
-
-    if (size == 0)
-        return 0;
-
-    if (do_fast_precheck) {
-        gboolean same;
-
-        /* we expect that the hashes are equal and the caller ensures us that they
-         * use the same hash/equal functions. Do a fast path check first...
-         *
-         * It's unclear whether this is worth it. The full comparison is O(n*ln(n)),
-         * while the fast check (using the hash lookup) is O(n). But then, the pre-check
-         * makes additional requirements on the hash's hash/equal functions -- the
-         * full comparison does not make such requirements. */
-        same = _utils_hashtable_equal(hash_a, hash_b, cmp_values, user_data);
-#if NM_MORE_ASSERTS > 5
-        nm_assert(same == _utils_hashtable_equal(hash_b, hash_a, cmp_values, user_data));
-#endif
-        if (same)
-            return 0;
-    }
-
-    size2 = ((gsize) size) * 2u;
-    if (size2 > 600u / sizeof(HashTableCmpData)) {
-        cmp_array_free = g_new(HashTableCmpData, size2);
-        cmp_array_a    = cmp_array_free;
-    } else
-        cmp_array_a = g_newa(HashTableCmpData, size2);
-    cmp_array_b = &cmp_array_a[size];
-
-    i = 0;
-    g_hash_table_iter_init(&h, hash_a);
-    while (g_hash_table_iter_next(&h, &i_key, &i_val)) {
-        nm_assert(i < size);
-        cmp_array_a[i++] = (HashTableCmpData){
-            .key = i_key,
-            .val = i_val,
-        };
-    }
-    nm_assert(i == size);
-
-    i = 0;
-    g_hash_table_iter_init(&h, hash_b);
-    while (g_hash_table_iter_next(&h, &i_key, &i_val)) {
-        nm_assert(i < size);
-        cmp_array_b[i++] = (HashTableCmpData){
-            .key = i_key,
-            .val = i_val,
-        };
-    }
-    nm_assert(i == size);
-
-    g_qsort_with_data(cmp_array_a,
-                      size,
-                      sizeof(HashTableCmpData),
-                      _hashtable_cmp_func,
-                      &((HashTableUserData){
-                          .cmp_keys  = cmp_keys,
-                          .user_data = user_data,
-                      }));
-
-    g_qsort_with_data(cmp_array_b,
-                      size,
-                      sizeof(HashTableCmpData),
-                      _hashtable_cmp_func,
-                      &((HashTableUserData){
-                          .cmp_keys  = cmp_keys,
-                          .user_data = user_data,
-                      }));
-
-    for (i = 0; i < size; i++) {
-        NM_CMP_RETURN(cmp_keys(cmp_array_a[i].key, cmp_array_b[i].key, user_data));
-    }
-
-    if (cmp_values) {
-        for (i = 0; i < size; i++) {
-            NM_CMP_RETURN(cmp_values(cmp_array_a[i].val, cmp_array_b[i].val, user_data));
-        }
-    }
-
-    /* the fast-precheck should have already told that the arrays are equal. */
-    nm_assert(!do_fast_precheck);
-
-    return 0;
-}
-
-char **
-nm_utils_strv_make_deep_copied(const char **strv)
-{
-    gsize i;
-
-    /* it takes a strv list, and copies each
-     * strings. Note that this updates @strv *in-place*
-     * and returns it. */
-
-    if (!strv)
-        return NULL;
-    for (i = 0; strv[i]; i++)
-        strv[i] = g_strdup(strv[i]);
-
-    return (char **) strv;
-}
-
-char **
-nm_utils_strv_make_deep_copied_n(const char **strv, gsize len)
-{
-    gsize i;
-
-    /* it takes a strv array with len elements, and copies each
-     * strings. Note that this updates @strv *in-place*
-     * and returns it. */
-
-    if (!strv)
-        return NULL;
-    for (i = 0; i < len; i++)
-        strv[i] = g_strdup(strv[i]);
-
-    return (char **) strv;
-}
-
-/**
- * @strv: the strv array to copy. It may be %NULL if @len
- *   is negative or zero (in which case %NULL will be returned).
- * @len: the length of strings in @str. If negative, strv is assumed
- *   to be a NULL terminated array.
- * @deep_copied: if %TRUE, clones the individual strings. In that case,
- *   the returned array must be freed with g_strfreev(). Otherwise, the
- *   strings themself are not copied. You must take care of who owns the
- *   strings yourself.
- *
- * Like g_strdupv(), with two differences:
- *
- * - accepts a @len parameter for non-null terminated strv array.
- *
- * - this never returns an empty strv array, but always %NULL if
- *   there are no strings.
- *
- * Note that if @len is non-negative, then it still must not
- * contain any %NULL pointers within the first @len elements.
- * Otherwise, you would leak elements if you try to free the
- * array with g_strfreev(). Allowing that would be error prone.
- *
- * Returns: (transfer full): a clone of the strv array. Always
- *   %NULL terminated. Depending on @deep_copied, the strings are
- *   cloned or not.
- */
-char **
-_nm_utils_strv_dup(const char *const *strv, gssize len, gboolean deep_copied)
-{
-    gsize  i, l;
-    char **v;
-
-    if (len < 0)
-        l = NM_PTRARRAY_LEN(strv);
-    else
-        l = len;
-    if (l == 0) {
-        /* this function never returns an empty strv array. If you
-         * need that, handle it yourself. */
-        return NULL;
-    }
-
-    v = g_new(char *, l + 1);
-    for (i = 0; i < l; i++) {
-        if (G_UNLIKELY(!strv[i])) {
-            /* NULL strings are not allowed. Clear the remainder of the array
-             * and return it (with assertion failure). */
-            l++;
-            for (; i < l; i++)
-                v[i] = NULL;
-            g_return_val_if_reached(v);
-        }
-
-        if (deep_copied)
-            v[i] = g_strdup(strv[i]);
-        else
-            v[i] = (char *) strv[i];
-    }
-    v[l] = NULL;
-    return v;
-}
-
-const char **
-_nm_utils_strv_dup_packed(const char *const *strv, gssize len)
-
-{
-    gs_free gsize *str_len_free = NULL;
-    gsize *        str_len;
-    const char **  result;
-    gsize          mem_len;
-    gsize          pre_len;
-    gsize          len2;
-    char *         sbuf;
-    gsize          i;
-
-    nm_assert(len >= -1);
-
-    if (G_LIKELY(len < 0)) {
-        if (!strv || !strv[0]) {
-            /* This function never returns an empty strv array. If you need that, handle it
-             * yourself. */
-            return NULL;
-        }
-        len2 = NM_PTRARRAY_LEN(strv);
-    } else {
-        if (len == 0)
-            return NULL;
-        len2 = len;
-    }
-
-    if (len2 > 300u / sizeof(gsize)) {
-        str_len_free = g_new(gsize, len2);
-        str_len      = str_len_free;
-    } else
-        str_len = g_newa(gsize, len2);
-
-    mem_len = 0;
-    for (i = 0; i < len2; i++) {
-        gsize l;
-
-        if (G_LIKELY(strv[i]))
-            l = strlen(strv[i]) + 1u;
-        else
-            l = 0;
-        str_len[i] = l;
-        mem_len += l;
-    }
-
-    pre_len = sizeof(const char *) * (len2 + 1u);
-
-    result = g_malloc(pre_len + mem_len);
-    sbuf   = &(((char *) result)[pre_len]);
-    for (i = 0; i < len2; i++) {
-        gsize l;
-
-        if (G_UNLIKELY(!strv[i])) {
-            /* Technically there is no problem with accepting NULL strings. But that
-             * does not really result in a strv array, and likely this only happens due
-             * to a bug. We want to catch such bugs by asserting.
-             *
-             * We clear the remainder of the buffer and fail with an assertion. */
-            len2++;
-            for (; i < len2; i++)
-                result[i] = NULL;
-            g_return_val_if_reached(result);
-        }
-
-        result[i] = sbuf;
-
-        l = str_len[i];
-        memcpy(sbuf, strv[i], l);
-        sbuf += l;
-    }
-    result[i] = NULL;
-    nm_assert(i == len2);
-    nm_assert(sbuf == (&((const char *) result)[pre_len]) + mem_len);
-
-    return result;
-}
-
-/*****************************************************************************/
-
-gssize
-nm_utils_ptrarray_find_binary_search(gconstpointer *  list,
-                                     gsize            len,
-                                     gconstpointer    needle,
-                                     GCompareDataFunc cmpfcn,
-                                     gpointer         user_data,
-                                     gssize *         out_idx_first,
-                                     gssize *         out_idx_last)
-{
-    gssize imin, imax, imid, i2min, i2max, i2mid;
-    int    cmp;
-
-    g_return_val_if_fail(list || !len, ~((gssize) 0));
-    g_return_val_if_fail(cmpfcn, ~((gssize) 0));
-
-    imin = 0;
-    if (len > 0) {
-        imax = len - 1;
-
-        while (imin <= imax) {
-            imid = imin + (imax - imin) / 2;
-
-            cmp = cmpfcn(list[imid], needle, user_data);
-            if (cmp == 0) {
-                /* we found a matching entry at index imid.
-                 *
-                 * Does the caller request the first/last index as well (in case that
-                 * there are multiple entries which compare equal). */
-
-                if (out_idx_first) {
-                    i2min = imin;
-                    i2max = imid + 1;
-                    while (i2min <= i2max) {
-                        i2mid = i2min + (i2max - i2min) / 2;
-
-                        cmp = cmpfcn(list[i2mid], needle, user_data);
-                        if (cmp == 0)
-                            i2max = i2mid - 1;
-                        else {
-                            nm_assert(cmp < 0);
-                            i2min = i2mid + 1;
-                        }
-                    }
-                    *out_idx_first = i2min;
-                }
-                if (out_idx_last) {
-                    i2min = imid + 1;
-                    i2max = imax;
-                    while (i2min <= i2max) {
-                        i2mid = i2min + (i2max - i2min) / 2;
-
-                        cmp = cmpfcn(list[i2mid], needle, user_data);
-                        if (cmp == 0)
-                            i2min = i2mid + 1;
-                        else {
-                            nm_assert(cmp > 0);
-                            i2max = i2mid - 1;
-                        }
-                    }
-                    *out_idx_last = i2min - 1;
-                }
-                return imid;
-            }
-
-            if (cmp < 0)
-                imin = imid + 1;
-            else
-                imax = imid - 1;
-        }
-    }
-
-    /* return the inverse of @imin. This is a negative number, but
-     * also is ~imin the position where the value should be inserted. */
-    imin = ~imin;
-    NM_SET_OUT(out_idx_first, imin);
-    NM_SET_OUT(out_idx_last, imin);
-    return imin;
-}
-
-/*****************************************************************************/
-
-/**
- * nm_utils_array_find_binary_search:
- * @list: the list to search. It must be sorted according to @cmpfcn ordering.
- * @elem_size: the size in bytes of each element in the list
- * @len: the number of elements in @list
- * @needle: the value that is searched
- * @cmpfcn: the compare function. The elements @list are passed as first
- *   argument to @cmpfcn, while @needle is passed as second. Usually, the
- *   needle is the same data type as inside the list, however, that is
- *   not necessary, as long as @cmpfcn takes care to cast the two arguments
- *   accordingly.
- * @user_data: optional argument passed to @cmpfcn
- *
- * Performs binary search for @needle in @list. On success, returns the
- * (non-negative) index where the compare function found the searched element.
- * On success, it returns a negative value. Note that the return negative value
- * is the bitwise inverse of the position where the element should be inserted.
- *
- * If the list contains multiple matching elements, an arbitrary index is
- * returned.
- *
- * Returns: the index to the element in the list, or the (negative, bitwise inverted)
- *   position where it should be.
- */
-gssize
-nm_utils_array_find_binary_search(gconstpointer    list,
-                                  gsize            elem_size,
-                                  gsize            len,
-                                  gconstpointer    needle,
-                                  GCompareDataFunc cmpfcn,
-                                  gpointer         user_data)
-{
-    gssize imin, imax, imid;
-    int    cmp;
-
-    g_return_val_if_fail(list || !len, ~((gssize) 0));
-    g_return_val_if_fail(cmpfcn, ~((gssize) 0));
-    g_return_val_if_fail(elem_size > 0, ~((gssize) 0));
-
-    imin = 0;
-    if (len == 0)
-        return ~imin;
-
-    imax = len - 1;
-
-    while (imin <= imax) {
-        imid = imin + (imax - imin) / 2;
-
-        cmp = cmpfcn(&((const char *) list)[elem_size * imid], needle, user_data);
-        if (cmp == 0)
-            return imid;
-
-        if (cmp < 0)
-            imin = imid + 1;
-        else
-            imax = imid - 1;
-    }
-
-    /* return the inverse of @imin. This is a negative number, but
-     * also is ~imin the position where the value should be inserted. */
-    return ~imin;
-}
-
-/*****************************************************************************/
-
-/**
- * nm_utils_get_start_time_for_pid:
- * @pid: the process identifier
- * @out_state: return the state character, like R, S, Z. See `man 5 proc`.
- * @out_ppid: parent process id
- *
- * Originally copied from polkit source (src/polkit/polkitunixprocess.c)
- * and adjusted.
- *
- * Returns: the timestamp when the process started (by parsing /proc/$PID/stat).
- * If an error occurs (e.g. the process does not exist), 0 is returned.
- *
- * The returned start time counts since boot, in the unit HZ (with HZ usually being (1/100) seconds)
- **/
-guint64
-nm_utils_get_start_time_for_pid(pid_t pid, char *out_state, pid_t *out_ppid)
-{
-    guint64              start_time;
-    char                 filename[256];
-    gs_free char *       contents = NULL;
-    size_t               length;
-    gs_free const char **tokens = NULL;
-    char *               p;
-    char                 state = ' ';
-    gint64               ppid  = 0;
-
-    start_time = 0;
-    contents   = NULL;
-
-    g_return_val_if_fail(pid > 0, 0);
-
-    G_STATIC_ASSERT_EXPR(sizeof(GPid) >= sizeof(pid_t));
-
-    nm_sprintf_buf(filename, "/proc/%" G_PID_FORMAT "/stat", (GPid) pid);
-
-    if (!g_file_get_contents(filename, &contents, &length, NULL))
-        goto fail;
-
-    /* start time is the token at index 19 after the '(process name)' entry - since only this
-     * field can contain the ')' character, search backwards for this to avoid malicious
-     * processes trying to fool us
-     */
-    p = strrchr(contents, ')');
-    if (!p)
-        goto fail;
-    p += 2; /* skip ') ' */
-    if (p - contents >= (int) length)
-        goto fail;
-
-    state = p[0];
-
-    tokens = nm_utils_strsplit_set(p, " ");
-
-    if (NM_PTRARRAY_LEN(tokens) < 20)
-        goto fail;
-
-    if (out_ppid) {
-        ppid = _nm_utils_ascii_str_to_int64(tokens[1], 10, 1, G_MAXINT, 0);
-        if (ppid == 0)
-            goto fail;
-    }
-
-    start_time = _nm_utils_ascii_str_to_int64(tokens[19], 10, 1, G_MAXINT64, 0);
-    if (start_time == 0)
-        goto fail;
-
-    NM_SET_OUT(out_state, state);
-    NM_SET_OUT(out_ppid, ppid);
-    return start_time;
-
-fail:
-    NM_SET_OUT(out_state, ' ');
-    NM_SET_OUT(out_ppid, 0);
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
- * _nm_utils_strv_sort:
- * @strv: pointer containing strings that will be sorted
- *   in-place, %NULL is allowed, unless @len indicates
- *   that there are more elements.
- * @len: the number of elements in strv. If negative,
- *   strv must be a NULL terminated array and the length
- *   will be calculated first. If @len is a positive
- *   number, @strv is allowed to contain %NULL strings
- *   too.
- *
- * Ascending sort of the array @strv inplace, using plain strcmp() string
- * comparison.
- */
-void
-_nm_utils_strv_sort(const char **strv, gssize len)
-{
-    GCompareDataFunc cmp;
-    gsize            l;
-
-    if (len < 0) {
-        l   = NM_PTRARRAY_LEN(strv);
-        cmp = nm_strcmp_p_with_data;
-    } else {
-        l   = len;
-        cmp = nm_strcmp0_p_with_data;
-    }
-
-    if (l <= 1)
-        return;
-
-    nm_assert(l <= (gsize) G_MAXINT);
-
-    g_qsort_with_data(strv, l, sizeof(const char *), cmp, NULL);
-}
-
-/**
- * _nm_utils_strv_cmp_n:
- * @strv1: a string array
- * @len1: the length of @strv1, or -1 for NULL terminated array.
- * @strv2: a string array
- * @len2: the length of @strv2, or -1 for NULL terminated array.
- *
- * Note that
- *   - len == -1 && strv == NULL
- * is treated like a %NULL argument and compares differently from
- * other arrays.
- *
- * Note that an empty array can be represented as
- *   - len == -1 &&  strv && !strv[0]
- *   - len ==  0 && !strv
- *   - len ==  0 &&  strv
- * These 3 forms all compare equal.
- * It also means, if length is 0, then it is permissible for strv to be %NULL.
- *
- * The strv arrays may contain %NULL strings (if len is positive).
- *
- * Returns: 0 if the arrays are equal (using strcmp).
- **/
-int
-_nm_utils_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2)
-{
-    gsize n, n2;
-
-    if (len1 < 0) {
-        if (!strv1)
-            return (len2 < 0 && !strv2) ? 0 : -1;
-        n = NM_PTRARRAY_LEN(strv1);
-    } else
-        n = len1;
-
-    if (len2 < 0) {
-        if (!strv2)
-            return 1;
-        n2 = NM_PTRARRAY_LEN(strv2);
-    } else
-        n2 = len2;
-
-    NM_CMP_DIRECT(n, n2);
-    for (; n > 0; n--, strv1++, strv2++)
-        NM_CMP_DIRECT_STRCMP0(*strv1, *strv2);
-    return 0;
-}
-
-/*****************************************************************************/
-
-/**
- * nm_utils_g_slist_find_str:
- * @list: the #GSList with NUL terminated strings to search
- * @needle: the needle string to look for.
- *
- * Search the list for @needle and return the first found match
- * (or %NULL if not found). Uses strcmp() for finding the first matching
- * element.
- *
- * Returns: the #GSList element with @needle as string value or
- *   %NULL if not found.
- */
-GSList *
-nm_utils_g_slist_find_str(const GSList *list, const char *needle)
-{
-    nm_assert(needle);
-
-    for (; list; list = list->next) {
-        nm_assert(list->data);
-        if (nm_streq(list->data, needle))
-            return (GSList *) list;
-    }
-    return NULL;
-}
-
-/**
- * nm_utils_g_slist_strlist_cmp:
- * @a: the left #GSList of strings
- * @b: the right #GSList of strings to compare.
- *
- * Compares two string lists. The data elements are compared with
- * strcmp(), allowing %NULL elements.
- *
- * Returns: 0, 1, or -1, depending on how the lists compare.
- */
-int
-nm_utils_g_slist_strlist_cmp(const GSList *a, const GSList *b)
-{
-    while (TRUE) {
-        if (!a)
-            return !b ? 0 : -1;
-        if (!b)
-            return 1;
-        NM_CMP_DIRECT_STRCMP0(a->data, b->data);
-        a = a->next;
-        b = b->next;
-    }
-}
-
-char *
-nm_utils_g_slist_strlist_join(const GSList *a, const char *separator)
-{
-    GString *str = NULL;
-
-    if (!a)
-        return NULL;
-
-    for (; a; a = a->next) {
-        if (!str)
-            str = g_string_new(NULL);
-        else
-            g_string_append(str, separator);
-        g_string_append(str, a->data);
-    }
-    return g_string_free(str, FALSE);
-}
-
-/*****************************************************************************/
-
-NMUtilsUserData *
-_nm_utils_user_data_pack(int nargs, gconstpointer *args)
-{
-    int       i;
-    gpointer *data;
-
-    nm_assert(nargs > 0);
-    nm_assert(args);
-
-    data = g_slice_alloc(((gsize) nargs) * sizeof(gconstpointer));
-    for (i = 0; i < nargs; i++)
-        data[i] = (gpointer) args[i];
-    return (NMUtilsUserData *) data;
-}
-
-void
-_nm_utils_user_data_unpack(NMUtilsUserData *user_data, int nargs, ...)
-{
-    gpointer *data = (gpointer *) user_data;
-    va_list   ap;
-    int       i;
-
-    nm_assert(data);
-    nm_assert(nargs > 0);
-
-    va_start(ap, nargs);
-    for (i = 0; i < nargs; i++) {
-        gpointer *dst;
-
-        dst = va_arg(ap, gpointer *);
-        nm_assert(dst);
-
-        *dst = data[i];
-    }
-    va_end(ap);
-
-    g_slice_free1(((gsize) nargs) * sizeof(gconstpointer), data);
-}
-
-/*****************************************************************************/
-
-typedef struct {
-    gpointer                    callback_user_data;
-    GCancellable *              cancellable;
-    GSource *                   source;
-    NMUtilsInvokeOnIdleCallback callback;
-    gulong                      cancelled_id;
-} InvokeOnIdleData;
-
-static gboolean
-_nm_utils_invoke_on_idle_cb_idle(gpointer user_data)
-{
-    InvokeOnIdleData *data = user_data;
-
-    nm_clear_g_signal_handler(data->cancellable, &data->cancelled_id);
-
-    data->callback(data->callback_user_data, data->cancellable);
-
-    nm_g_object_unref(data->cancellable);
-    g_source_destroy(data->source);
-    nm_g_slice_free(data);
-    return G_SOURCE_REMOVE;
-}
-
-static void
-_nm_utils_invoke_on_idle_cb_cancelled(GCancellable *cancellable, InvokeOnIdleData *data)
-{
-    /* on cancellation, we invoke the callback synchronously. */
-    nm_clear_g_signal_handler(data->cancellable, &data->cancelled_id);
-    nm_clear_g_source_inst(&data->source);
-    data->callback(data->callback_user_data, data->cancellable);
-    nm_g_object_unref(data->cancellable);
-    nm_g_slice_free(data);
-}
-
-static void
-_nm_utils_invoke_on_idle_start(gboolean                    use_timeout,
-                               guint                       timeout_msec,
-                               GCancellable *              cancellable,
-                               NMUtilsInvokeOnIdleCallback callback,
-                               gpointer                    callback_user_data)
-{
-    InvokeOnIdleData *data;
-    GSource *         source;
-
-    g_return_if_fail(callback);
-
-    data  = g_slice_new(InvokeOnIdleData);
-    *data = (InvokeOnIdleData){
-        .callback           = callback,
-        .callback_user_data = callback_user_data,
-        .cancellable        = nm_g_object_ref(cancellable),
-        .cancelled_id       = 0,
-    };
-
-    if (cancellable) {
-        if (g_cancellable_is_cancelled(cancellable)) {
-            /* the cancellable is already cancelled. We ignore the timeout
-             * and always schedule an idle action. */
-            use_timeout = FALSE;
-        } else {
-            /* if we are passed a non-cancelled cancellable, we register to the "cancelled"
-             * signal an invoke the callback synchronously (from the signal handler).
-             *
-             * We don't do that,
-             *  - if the cancellable is already cancelled (because we don't want to invoke
-             *    the callback synchronously from the caller).
-             *  - if we have no cancellable at hand. */
-            data->cancelled_id = g_signal_connect(cancellable,
-                                                  "cancelled",
-                                                  G_CALLBACK(_nm_utils_invoke_on_idle_cb_cancelled),
-                                                  data);
-        }
-    }
-
-    if (use_timeout) {
-        source = nm_g_timeout_source_new(timeout_msec,
-                                         G_PRIORITY_DEFAULT,
-                                         _nm_utils_invoke_on_idle_cb_idle,
-                                         data,
-                                         NULL);
-    } else {
-        source =
-            nm_g_idle_source_new(G_PRIORITY_DEFAULT, _nm_utils_invoke_on_idle_cb_idle, data, NULL);
-    }
-
-    /* use the current thread default context. */
-    g_source_attach(source, g_main_context_get_thread_default());
-
-    data->source = source;
-}
-
-void
-nm_utils_invoke_on_idle(GCancellable *              cancellable,
-                        NMUtilsInvokeOnIdleCallback callback,
-                        gpointer                    callback_user_data)
-{
-    _nm_utils_invoke_on_idle_start(FALSE, 0, cancellable, callback, callback_user_data);
-}
-
-void
-nm_utils_invoke_on_timeout(guint                       timeout_msec,
-                           GCancellable *              cancellable,
-                           NMUtilsInvokeOnIdleCallback callback,
-                           gpointer                    callback_user_data)
-{
-    _nm_utils_invoke_on_idle_start(TRUE, timeout_msec, cancellable, callback, callback_user_data);
-}
-
-/*****************************************************************************/
-
-int
-nm_utils_getpagesize(void)
-{
-    static volatile int val = 0;
-    long                l;
-    int                 v;
-
-    v = g_atomic_int_get(&val);
-
-    if (G_UNLIKELY(v == 0)) {
-        l = sysconf(_SC_PAGESIZE);
-
-        g_return_val_if_fail(l > 0 && l < G_MAXINT, 4 * 1024);
-
-        v = (int) l;
-        if (!g_atomic_int_compare_and_exchange(&val, 0, v)) {
-            v = g_atomic_int_get(&val);
-            g_return_val_if_fail(v > 0, 4 * 1024);
-        }
-    }
-
-    nm_assert(v > 0);
-#if NM_MORE_ASSERTS > 5
-    nm_assert(v == getpagesize());
-    nm_assert(v == sysconf(_SC_PAGESIZE));
-#endif
-
-    return v;
-}
-
-gboolean
-nm_utils_memeqzero(gconstpointer data, gsize length)
-{
-    const unsigned char *p = data;
-    int                  len;
-
-    /* Taken from https://github.com/rustyrussell/ccan/blob/9d2d2c49f053018724bcc6e37029da10b7c3d60d/ccan/mem/mem.c#L92,
-     * CC-0 licensed. */
-
-    /* Check first 16 bytes manually */
-    for (len = 0; len < 16; len++) {
-        if (!length)
-            return TRUE;
-        if (*p)
-            return FALSE;
-        p++;
-        length--;
-    }
-
-    /* Now we know that's zero, memcmp with self. */
-    return memcmp(data, p, length) == 0;
-}
-
-/**
- * nm_utils_bin2hexstr_full:
- * @addr: pointer of @length bytes. If @length is zero, this may
- *   also be %NULL.
- * @length: number of bytes in @addr. May also be zero, in which
- *   case this will return an empty string.
- * @delimiter: either '\0', otherwise the output string will have the
- *   given delimiter character between each two hex numbers.
- * @upper_case: if TRUE, use upper case ASCII characters for hex.
- * @out: if %NULL, the function will allocate a new buffer of
- *   either (@length*2+1) or (@length*3) bytes, depending on whether
- *   a @delimiter is specified. In that case, the allocated buffer will
- *   be returned and must be freed by the caller.
- *   If not %NULL, the buffer must already be preallocated and contain
- *   at least (@length*2+1) or (@length*3) bytes, depending on the delimiter.
- *   If @length is zero, then of course at least one byte will be allocated
- *   or @out (if given) must contain at least room for the trailing NUL byte.
- *
- * Returns: the binary value converted to a hex string. If @out is given,
- *   this always returns @out. If @out is %NULL, a newly allocated string
- *   is returned. This never returns %NULL, for buffers of length zero
- *   an empty string is returned.
- */
-char *
-nm_utils_bin2hexstr_full(gconstpointer addr,
-                         gsize         length,
-                         char          delimiter,
-                         gboolean      upper_case,
-                         char *        out)
-{
-    const guint8 *in     = addr;
-    const char *  LOOKUP = upper_case ? "0123456789ABCDEF" : "0123456789abcdef";
-    char *        out0;
-
-    if (out)
-        out0 = out;
-    else {
-        out0 = out =
-            g_new(char, length == 0 ? 1u : (delimiter == '\0' ? length * 2u + 1u : length * 3u));
-    }
-
-    /* @out must contain at least @length*3 bytes if @delimiter is set,
-     * otherwise, @length*2+1. */
-
-    if (length > 0) {
-        nm_assert(in);
-        for (;;) {
-            const guint8 v = *in++;
-
-            *out++ = LOOKUP[v >> 4];
-            *out++ = LOOKUP[v & 0x0F];
-            length--;
-            if (!length)
-                break;
-            if (delimiter)
-                *out++ = delimiter;
-        }
-    }
-
-    *out = '\0';
-    return out0;
-}
-
-guint8 *
-nm_utils_hexstr2bin_full(const char *hexstr,
-                         gboolean    allow_0x_prefix,
-                         gboolean    delimiter_required,
-                         gboolean    hexdigit_pairs_required,
-                         const char *delimiter_candidates,
-                         gsize       required_len,
-                         guint8 *    buffer,
-                         gsize       buffer_len,
-                         gsize *     out_len)
-{
-    const char *in            = hexstr;
-    guint8 *    out           = buffer;
-    gboolean    delimiter_has = TRUE;
-    guint8      delimiter     = '\0';
-    gsize       len;
-
-    nm_assert(hexstr);
-    nm_assert(buffer);
-    nm_assert(required_len > 0 || out_len);
-
-    if (allow_0x_prefix && in[0] == '0' && in[1] == 'x')
-        in += 2;
-
-    while (TRUE) {
-        const guint8 d1 = in[0];
-        guint8       d2;
-        int          i1, i2;
-
-        i1 = nm_utils_hexchar_to_int(d1);
-        if (i1 < 0)
-            goto fail;
-
-        /* If there's no leading zero (ie "aa:b:cc") then fake it */
-        d2 = in[1];
-        if (d2 && (i2 = nm_utils_hexchar_to_int(d2)) >= 0) {
-            *out++ = (i1 << 4) + i2;
-            d2     = in[2];
-            if (!d2)
-                break;
-            in += 2;
-        } else {
-            /* Fake leading zero */
-            *out++ = i1;
-            if (!d2) {
-                if (!delimiter_has || hexdigit_pairs_required) {
-                    /* when using no delimiter, there must be pairs of hex chars */
-                    goto fail;
-                }
-                break;
-            } else if (hexdigit_pairs_required)
-                goto fail;
-            in += 1;
-        }
-
-        if (--buffer_len == 0)
-            goto fail;
-
-        if (delimiter_has) {
-            if (d2 != delimiter) {
-                if (delimiter)
-                    goto fail;
-                if (delimiter_candidates) {
-                    while (delimiter_candidates[0]) {
-                        if (delimiter_candidates++[0] == d2)
-                            delimiter = d2;
-                    }
-                }
-                if (!delimiter) {
-                    if (delimiter_required)
-                        goto fail;
-                    delimiter_has = FALSE;
-                    continue;
-                }
-            }
-            in++;
-        }
-    }
-
-    len = out - buffer;
-    if (required_len == 0 || len == required_len) {
-        NM_SET_OUT(out_len, len);
-        return buffer;
-    }
-
-fail:
-    NM_SET_OUT(out_len, 0);
-    return NULL;
-}
-
-guint8 *
-nm_utils_hexstr2bin_alloc(const char *hexstr,
-                          gboolean    allow_0x_prefix,
-                          gboolean    delimiter_required,
-                          const char *delimiter_candidates,
-                          gsize       required_len,
-                          gsize *     out_len)
-{
-    guint8 *buffer;
-    gsize   buffer_len, len;
-
-    if (G_UNLIKELY(!hexstr)) {
-        NM_SET_OUT(out_len, 0);
-        g_return_val_if_fail(hexstr, NULL);
-    }
-
-    nm_assert(required_len > 0 || out_len);
-
-    if (allow_0x_prefix && hexstr[0] == '0' && hexstr[1] == 'x')
-        hexstr += 2;
-
-    if (!hexstr[0])
-        goto fail;
-
-    if (required_len > 0)
-        buffer_len = required_len;
-    else
-        buffer_len = strlen(hexstr) / 2 + 3;
-
-    buffer = g_malloc(buffer_len);
-
-    if (nm_utils_hexstr2bin_full(hexstr,
-                                 FALSE,
-                                 delimiter_required,
-                                 FALSE,
-                                 delimiter_candidates,
-                                 required_len,
-                                 buffer,
-                                 buffer_len,
-                                 &len)) {
-        NM_SET_OUT(out_len, len);
-        return buffer;
-    }
-
-    g_free(buffer);
-
-fail:
-    NM_SET_OUT(out_len, 0);
-    return NULL;
-}
-
-/*****************************************************************************/
-
-GVariant *
-nm_utils_gvariant_vardict_filter(GVariant *src,
-                                 gboolean (*filter_fcn)(const char *key,
-                                                        GVariant *  val,
-                                                        char **     out_key,
-                                                        GVariant ** out_val,
-                                                        gpointer    user_data),
-                                 gpointer user_data)
-{
-    GVariantIter    iter;
-    GVariantBuilder builder;
-    const char *    key;
-    GVariant *      val;
-
-    g_return_val_if_fail(src && g_variant_is_of_type(src, G_VARIANT_TYPE_VARDICT), NULL);
-    g_return_val_if_fail(filter_fcn, NULL);
-
-    g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
-
-    g_variant_iter_init(&iter, src);
-    while (g_variant_iter_next(&iter, "{&sv}", &key, &val)) {
-        _nm_unused gs_unref_variant GVariant *val_free = val;
-        gs_free char *                        key2     = NULL;
-        gs_unref_variant GVariant *val2                = NULL;
-
-        if (filter_fcn(key, val, &key2, &val2, user_data)) {
-            g_variant_builder_add(&builder, "{sv}", key2 ?: key, val2 ?: val);
-        }
-    }
-
-    return g_variant_builder_end(&builder);
-}
-
-static gboolean
-_gvariant_vardict_filter_drop_one(const char *key,
-                                  GVariant *  val,
-                                  char **     out_key,
-                                  GVariant ** out_val,
-                                  gpointer    user_data)
-{
-    return !nm_streq(key, user_data);
-}
-
-GVariant *
-nm_utils_gvariant_vardict_filter_drop_one(GVariant *src, const char *key)
-{
-    return nm_utils_gvariant_vardict_filter(src, _gvariant_vardict_filter_drop_one, (gpointer) key);
-}
-
-/*****************************************************************************/
-
-static gboolean
-debug_key_matches(const char *key, const char *token, guint length)
-{
-    /* may not call GLib functions: see note in g_parse_debug_string() */
-    for (; length; length--, key++, token++) {
-        char k = (*key == '_') ? '-' : g_ascii_tolower(*key);
-        char t = (*token == '_') ? '-' : g_ascii_tolower(*token);
-
-        if (k != t)
-            return FALSE;
-    }
-
-    return *key == '\0';
-}
-
-/**
- * nm_utils_parse_debug_string:
- * @string: the string to parse
- * @keys: the debug keys
- * @nkeys: number of entries in @keys
- *
- * Similar to g_parse_debug_string(), but does not special
- * case "help" or "all".
- *
- * Returns: the flags
- */
-guint
-nm_utils_parse_debug_string(const char *string, const GDebugKey *keys, guint nkeys)
-{
-    guint       i;
-    guint       result = 0;
-    const char *q;
-
-    if (string == NULL)
-        return 0;
-
-    while (*string) {
-        q = strpbrk(string, ":;, \t");
-        if (!q)
-            q = string + strlen(string);
-
-        for (i = 0; i < nkeys; i++) {
-            if (debug_key_matches(keys[i].key, string, q - string))
-                result |= keys[i].value;
-        }
-
-        string = q;
-        if (*string)
-            string++;
-    }
-
-    return result;
-}
-
-/*****************************************************************************/
-
-GSource *
-nm_g_idle_source_new(int            priority,
-                     GSourceFunc    func,
-                     gpointer       user_data,
-                     GDestroyNotify destroy_notify)
-{
-    GSource *source;
-
-    source = g_idle_source_new();
-    if (priority != G_PRIORITY_DEFAULT)
-        g_source_set_priority(source, priority);
-    g_source_set_callback(source, func, user_data, destroy_notify);
-    return source;
-}
-
-GSource *
-nm_g_timeout_source_new(guint          timeout_msec,
-                        int            priority,
-                        GSourceFunc    func,
-                        gpointer       user_data,
-                        GDestroyNotify destroy_notify)
-{
-    GSource *source;
-
-    source = g_timeout_source_new(timeout_msec);
-    if (priority != G_PRIORITY_DEFAULT)
-        g_source_set_priority(source, priority);
-    g_source_set_callback(source, func, user_data, destroy_notify);
-    return source;
-}
-
-GSource *
-nm_g_timeout_source_new_seconds(guint          timeout_sec,
-                                int            priority,
-                                GSourceFunc    func,
-                                gpointer       user_data,
-                                GDestroyNotify destroy_notify)
-{
-    GSource *source;
-
-    source = g_timeout_source_new_seconds(timeout_sec);
-    if (priority != G_PRIORITY_DEFAULT)
-        g_source_set_priority(source, priority);
-    g_source_set_callback(source, func, user_data, destroy_notify);
-    return source;
-}
-
-GSource *
-nm_g_unix_signal_source_new(int            signum,
-                            int            priority,
-                            GSourceFunc    handler,
-                            gpointer       user_data,
-                            GDestroyNotify notify)
-{
-    GSource *source;
-
-    source = g_unix_signal_source_new(signum);
-
-    if (priority != G_PRIORITY_DEFAULT)
-        g_source_set_priority(source, priority);
-    g_source_set_callback(source, handler, user_data, notify);
-    return source;
-}
-
-GSource *
-nm_g_unix_fd_source_new(int          fd,
-                        GIOCondition io_condition,
-                        int          priority,
-                        gboolean (*source_func)(int fd, GIOCondition condition, gpointer user_data),
-                        gpointer       user_data,
-                        GDestroyNotify destroy_notify)
-{
-    GSource *source;
-
-    source = g_unix_fd_source_new(fd, io_condition);
-
-    if (priority != G_PRIORITY_DEFAULT)
-        g_source_set_priority(source, priority);
-    g_source_set_callback(source, G_SOURCE_FUNC(source_func), user_data, destroy_notify);
-    return source;
-}
-
-/*****************************************************************************/
-
-#define _CTX_LOG(fmt, ...)                                                                       \
-    G_STMT_START                                                                                 \
-    {                                                                                            \
-        if (FALSE) {                                                                             \
-            gint64 _ts = g_get_monotonic_time() / 100;                                           \
-                                                                                                 \
-            g_printerr(">>>> [%" G_GINT64_FORMAT ".%05" G_GINT64_FORMAT "] [src:%p]: " fmt "\n", \
-                       _ts / 10000,                                                              \
-                       _ts % 10000,                                                              \
-                       (ctx_src),                                                                \
-                       ##__VA_ARGS__);                                                           \
-        }                                                                                        \
-    }                                                                                            \
-    G_STMT_END
-
-typedef struct {
-    int   fd;
-    guint events;
-    guint registered_events;
-    union {
-        int  one;
-        int *many;
-    } idx;
-    gpointer tag;
-    bool     stale : 1;
-    bool     has_many_idx : 1;
-} PollData;
-
-typedef struct {
-    GSource       source;
-    GMainContext *context;
-    GHashTable *  fds;
-    GPollFD *     fds_arr;
-    guint         fds_len;
-    int           max_priority;
-    bool          acquired : 1;
-} CtxIntegSource;
-
-static void
-_poll_data_free(gpointer user_data)
-{
-    PollData *poll_data = user_data;
-
-    if (poll_data->has_many_idx)
-        g_free(poll_data->idx.many);
-    nm_g_slice_free(poll_data);
-}
-
-static void
-_ctx_integ_source_reacquire(CtxIntegSource *ctx_src)
-{
-    if (G_LIKELY(ctx_src->acquired && g_main_context_is_owner(ctx_src->context)))
-        return;
-
-    /* the parent context now iterates on a different thread.
-     * We need to release and reacquire the inner context. */
-
-    if (ctx_src->acquired)
-        g_main_context_release(ctx_src->context);
-
-    if (G_UNLIKELY(!g_main_context_acquire(ctx_src->context))) {
-        /* Nobody is supposed to reacquire the context while we use it. This is a bug
-         * of the user. */
-        ctx_src->acquired = FALSE;
-        g_return_if_reached();
-    }
-    ctx_src->acquired = TRUE;
-}
-
-static gboolean
-_ctx_integ_source_prepare(GSource *source, int *out_timeout)
-{
-    CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
-    int             max_priority;
-    int             timeout = -1;
-    gboolean        any_ready;
-    GHashTableIter  h_iter;
-    PollData *      poll_data;
-    gboolean        fds_changed;
-    GPollFD         new_fds_stack[300u / sizeof(GPollFD)];
-    gs_free GPollFD *new_fds_heap = NULL;
-    GPollFD *        new_fds;
-    guint            new_fds_len;
-    guint            new_fds_alloc;
-    guint            i;
-
-    _CTX_LOG("prepare...");
-
-    _ctx_integ_source_reacquire(ctx_src);
-
-    any_ready = g_main_context_prepare(ctx_src->context, &max_priority);
-
-    new_fds_alloc = NM_MAX(G_N_ELEMENTS(new_fds_stack), ctx_src->fds_len);
-
-    if (new_fds_alloc > G_N_ELEMENTS(new_fds_stack)) {
-        new_fds_heap = g_new(GPollFD, new_fds_alloc);
-        new_fds      = new_fds_heap;
-    } else
-        new_fds = new_fds_stack;
-
-    for (;;) {
-        int l;
-
-        nm_assert(new_fds_alloc <= (guint) G_MAXINT);
-
-        l = g_main_context_query(ctx_src->context,
-                                 max_priority,
-                                 &timeout,
-                                 new_fds,
-                                 (int) new_fds_alloc);
-        nm_assert(l >= 0);
-
-        new_fds_len = (guint) l;
-
-        if (G_LIKELY(new_fds_len <= new_fds_alloc))
-            break;
-
-        new_fds_alloc = new_fds_len;
-        g_free(new_fds_heap);
-        new_fds_heap = g_new(GPollFD, new_fds_alloc);
-        new_fds      = new_fds_heap;
-    }
-
-    fds_changed = FALSE;
-    if (new_fds_len != ctx_src->fds_len)
-        fds_changed = TRUE;
-    else {
-        for (i = 0; i < new_fds_len; i++) {
-            if (new_fds[i].fd != ctx_src->fds_arr[i].fd
-                || new_fds[i].events != ctx_src->fds_arr[i].events) {
-                fds_changed = TRUE;
-                break;
-            }
-        }
-    }
-
-    if (G_UNLIKELY(fds_changed)) {
-        g_free(ctx_src->fds_arr);
-        ctx_src->fds_len = new_fds_len;
-        if (G_LIKELY(new_fds == new_fds_stack) || new_fds_alloc != new_fds_len)
-            ctx_src->fds_arr = nm_memdup(new_fds, sizeof(*new_fds) * new_fds_len);
-        else
-            ctx_src->fds_arr = g_steal_pointer(&new_fds_heap);
-
-        g_hash_table_iter_init(&h_iter, ctx_src->fds);
-        while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL))
-            poll_data->stale = TRUE;
-
-        for (i = 0; i < ctx_src->fds_len; i++) {
-            const GPollFD *fd = &ctx_src->fds_arr[i];
-
-            poll_data = g_hash_table_lookup(ctx_src->fds, &fd->fd);
-
-            if (G_UNLIKELY(!poll_data)) {
-                poll_data  = g_slice_new(PollData);
-                *poll_data = (PollData){
-                    .fd                = fd->fd,
-                    .idx.one           = i,
-                    .has_many_idx      = FALSE,
-                    .events            = fd->events,
-                    .registered_events = 0,
-                    .tag               = NULL,
-                    .stale             = FALSE,
-                };
-                g_hash_table_add(ctx_src->fds, poll_data);
-                nm_assert(poll_data == g_hash_table_lookup(ctx_src->fds, &fd->fd));
-                continue;
-            }
-
-            if (G_LIKELY(poll_data->stale)) {
-                if (poll_data->has_many_idx) {
-                    g_free(poll_data->idx.many);
-                    poll_data->has_many_idx = FALSE;
-                }
-                poll_data->events  = fd->events;
-                poll_data->idx.one = i;
-                poll_data->stale   = FALSE;
-                continue;
-            }
-
-            /* How odd. We have duplicate FDs. In fact, currently g_main_context_query() always
-             * coalesces the FDs and this cannot happen. However, that is not documented behavior,
-             * so we should not rely on that. So we need to keep a list of indexes... */
-            poll_data->events |= fd->events;
-            if (!poll_data->has_many_idx) {
-                int idx0;
-
-                idx0                    = poll_data->idx.one;
-                poll_data->has_many_idx = TRUE;
-                poll_data->idx.many     = g_new(int, 4);
-                poll_data->idx.many[0]  = 2; /* number allocated */
-                poll_data->idx.many[1]  = 2; /* number used */
-                poll_data->idx.many[2]  = idx0;
-                poll_data->idx.many[3]  = i;
-            } else {
-                if (poll_data->idx.many[0] == poll_data->idx.many[1]) {
-                    poll_data->idx.many[0] *= 2;
-                    poll_data->idx.many =
-                        g_realloc(poll_data->idx.many, sizeof(int) * (2 + poll_data->idx.many[0]));
-                }
-                poll_data->idx.many[2 + poll_data->idx.many[1]] = i;
-                poll_data->idx.many[1]++;
-            }
-        }
-
-        g_hash_table_iter_init(&h_iter, ctx_src->fds);
-        while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) {
-            if (poll_data->stale) {
-                nm_assert(poll_data->tag);
-                nm_assert(poll_data->events == poll_data->registered_events);
-                _CTX_LOG("prepare: remove poll fd=%d, events=0x%x",
-                         poll_data->fd,
-                         poll_data->events);
-                g_source_remove_unix_fd(&ctx_src->source, poll_data->tag);
-                g_hash_table_iter_remove(&h_iter);
-                continue;
-            }
-            if (!poll_data->tag) {
-                _CTX_LOG("prepare: add poll fd=%d, events=0x%x", poll_data->fd, poll_data->events);
-                poll_data->registered_events = poll_data->events;
-                poll_data->tag               = g_source_add_unix_fd(&ctx_src->source,
-                                                      poll_data->fd,
-                                                      poll_data->registered_events);
-                continue;
-            }
-            if (poll_data->registered_events != poll_data->events) {
-                _CTX_LOG("prepare: update poll fd=%d, events=0x%x",
-                         poll_data->fd,
-                         poll_data->events);
-                poll_data->registered_events = poll_data->events;
-                g_source_modify_unix_fd(&ctx_src->source,
-                                        poll_data->tag,
-                                        poll_data->registered_events);
-            }
-        }
-    }
-
-    NM_SET_OUT(out_timeout, timeout);
-    ctx_src->max_priority = max_priority;
-
-    _CTX_LOG("prepare: done, any-ready=%d, timeout=%d, max-priority=%d",
-             any_ready,
-             timeout,
-             max_priority);
-
-    /* we always need to poll, because we have some file descriptors. */
-    return FALSE;
-}
-
-static gboolean
-_ctx_integ_source_check(GSource *source)
-{
-    CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
-    GHashTableIter  h_iter;
-    gboolean        some_ready;
-    PollData *      poll_data;
-
-    nm_assert(ctx_src->context);
-
-    _CTX_LOG("check");
-
-    _ctx_integ_source_reacquire(ctx_src);
-
-    g_hash_table_iter_init(&h_iter, ctx_src->fds);
-    while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) {
-        guint revents;
-
-        revents = g_source_query_unix_fd(&ctx_src->source, poll_data->tag);
-        if (G_UNLIKELY(poll_data->has_many_idx)) {
-            int  num   = poll_data->idx.many[1];
-            int *p_idx = &poll_data->idx.many[2];
-
-            for (; num > 0; num--, p_idx++)
-                ctx_src->fds_arr[*p_idx].revents = revents;
-        } else
-            ctx_src->fds_arr[poll_data->idx.one].revents = revents;
-    }
-
-    nm_assert(ctx_src->fds_len <= (guint) G_MAXINT);
-
-    some_ready = g_main_context_check(ctx_src->context,
-                                      ctx_src->max_priority,
-                                      ctx_src->fds_arr,
-                                      (int) ctx_src->fds_len);
-
-    _CTX_LOG("check (some-ready=%d)...", some_ready);
-
-    return some_ready;
-}
-
-static gboolean
-_ctx_integ_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
-{
-    CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
-
-    nm_assert(ctx_src->context);
-
-    _ctx_integ_source_reacquire(ctx_src);
-
-    _CTX_LOG("dispatch");
-
-    g_main_context_dispatch(ctx_src->context);
-
-    return G_SOURCE_CONTINUE;
-}
-
-static void
-_ctx_integ_source_finalize(GSource *source)
-{
-    CtxIntegSource *ctx_src = ((CtxIntegSource *) source);
-    GHashTableIter  h_iter;
-    PollData *      poll_data;
-
-    g_return_if_fail(ctx_src->context);
-
-    _CTX_LOG("finalize...");
-
-    g_hash_table_iter_init(&h_iter, ctx_src->fds);
-    while (g_hash_table_iter_next(&h_iter, (gpointer *) &poll_data, NULL)) {
-        nm_assert(poll_data->tag);
-        _CTX_LOG("prepare: remove poll fd=%d, events=0x%x", poll_data->fd, poll_data->events);
-        g_source_remove_unix_fd(&ctx_src->source, poll_data->tag);
-        g_hash_table_iter_remove(&h_iter);
-    }
-
-    nm_clear_pointer(&ctx_src->fds, g_hash_table_unref);
-    nm_clear_g_free(&ctx_src->fds_arr);
-    ctx_src->fds_len = 0;
-
-    if (ctx_src->acquired) {
-        ctx_src->acquired = FALSE;
-        g_main_context_release(ctx_src->context);
-    }
-
-    nm_clear_pointer(&ctx_src->context, g_main_context_unref);
-}
-
-static GSourceFuncs ctx_integ_source_funcs = {
-    .prepare  = _ctx_integ_source_prepare,
-    .check    = _ctx_integ_source_check,
-    .dispatch = _ctx_integ_source_dispatch,
-    .finalize = _ctx_integ_source_finalize,
-};
-
-/**
- * nm_utils_g_main_context_create_integrate_source:
- * @inner_context: the inner context that will be integrated to an
- *   outer #GMainContext.
- *
- * By integrating the inner context with an outer context, when iterating the outer
- * context sources on the inner context will be dispatched. Note that while the
- * created source exists, the @inner_context will be acquired. The user gets restricted
- * what to do with the inner context. In particular while the inner context is integrated,
- * the user should not acquire the inner context again or explicitly iterate it. What
- * the user of course still can (and wants to) do is attaching new sources to the inner
- * context.
- *
- * Note that GSource has a priority. While each context dispatches events based on
- * their source's priorities, the outer context dispatches to the inner context
- * only with one priority (the priority of the created source). That is, the sources
- * from the two contexts are kept separate and are not sorted by their priorities.
- *
- * Returns: a newly created GSource that should be attached to the
- *   outer context.
- */
-GSource *
-nm_utils_g_main_context_create_integrate_source(GMainContext *inner_context)
-{
-    CtxIntegSource *ctx_src;
-
-    g_return_val_if_fail(inner_context, NULL);
-
-    if (!g_main_context_acquire(inner_context)) {
-        /* We require to acquire the context while it's integrated. We need to keep it acquired
-         * for the entire duration.
-         *
-         * This is also necessary because g_source_attach() only wakes up the context, if
-         * the context is currently acquired. */
-        g_return_val_if_reached(NULL);
-    }
-
-    ctx_src = (CtxIntegSource *) g_source_new(&ctx_integ_source_funcs, sizeof(CtxIntegSource));
-
-    g_source_set_name(&ctx_src->source, "ContextIntegrateSource");
-
-    ctx_src->context  = g_main_context_ref(inner_context);
-    ctx_src->fds      = g_hash_table_new_full(nm_pint_hash, nm_pint_equals, _poll_data_free, NULL);
-    ctx_src->fds_len  = 0;
-    ctx_src->fds_arr  = NULL;
-    ctx_src->acquired = TRUE;
-    ctx_src->max_priority = G_MAXINT;
-
-    _CTX_LOG("create new integ-source for %p", inner_context);
-
-    return &ctx_src->source;
-}
-
-/*****************************************************************************/
-
-void
-nm_utils_ifname_cpy(char *dst, const char *name)
-{
-    int i;
-
-    g_return_if_fail(dst);
-    g_return_if_fail(name && name[0]);
-
-    nm_assert(nm_utils_ifname_valid_kernel(name, NULL));
-
-    /* ensures NUL padding of the entire IFNAMSIZ buffer. */
-
-    for (i = 0; i < (int) IFNAMSIZ && name[i] != '\0'; i++)
-        dst[i] = name[i];
-
-    nm_assert(name[i] == '\0');
-
-    for (; i < (int) IFNAMSIZ; i++)
-        dst[i] = '\0';
-}
-
-/*****************************************************************************/
-
-gboolean
-nm_utils_ifname_valid_kernel(const char *name, GError **error)
-{
-    int i;
-
-    /* This function follows kernel's interface validation
-     * function dev_valid_name() in net/core/dev.c.
-     */
-
-    if (!name) {
-        g_set_error_literal(error,
-                            NM_UTILS_ERROR,
-                            NM_UTILS_ERROR_UNKNOWN,
-                            _("interface name is missing"));
-        return FALSE;
-    }
-
-    if (name[0] == '\0') {
-        g_set_error_literal(error,
-                            NM_UTILS_ERROR,
-                            NM_UTILS_ERROR_UNKNOWN,
-                            _("interface name is too short"));
-        return FALSE;
-    }
-
-    if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) {
-        g_set_error_literal(error,
-                            NM_UTILS_ERROR,
-                            NM_UTILS_ERROR_UNKNOWN,
-                            _("interface name is reserved"));
-        return FALSE;
-    }
-
-    for (i = 0; i < IFNAMSIZ; i++) {
-        char ch = name[i];
-
-        if (ch == '\0')
-            return TRUE;
-        if (NM_IN_SET(ch, '/', ':') || g_ascii_isspace(ch)) {
-            g_set_error_literal(error,
-                                NM_UTILS_ERROR,
-                                NM_UTILS_ERROR_UNKNOWN,
-                                _("interface name contains an invalid character"));
-            return FALSE;
-        }
-    }
-
-    g_set_error_literal(error,
-                        NM_UTILS_ERROR,
-                        NM_UTILS_ERROR_UNKNOWN,
-                        _("interface name is longer than 15 characters"));
-    return FALSE;
-}
-
-/*****************************************************************************/
-
-static gboolean
-_nm_utils_ifname_valid_kernel(const char *name, GError **error)
-{
-    if (!nm_utils_ifname_valid_kernel(name, error))
-        return FALSE;
-
-    if (strchr(name, '%')) {
-        /* Kernel's dev_valid_name() accepts (almost) any binary up to 15 chars.
-         * However, '%' is treated special as a format specifier. Try
-         *
-         *   ip link add 'dummy%dx' type dummy
-         *
-         * Don't allow that for "connection.interface-name", which either
-         * matches an existing netdev name (thus, it cannot have a '%') or
-         * is used to configure a name (in which case we don't want kernel
-         * to replace the format specifier). */
-        g_set_error_literal(error,
-                            NM_UTILS_ERROR,
-                            NM_UTILS_ERROR_UNKNOWN,
-                            _("'%%' is not allowed in interface names"));
-        return FALSE;
-    }
-
-    if (NM_IN_STRSET(name, "all", "default", "bonding_masters")) {
-        /* Certain names are not allowed. The "all" and "default" names are reserved
-         * due to their directories in "/proc/sys/net/ipv4/conf/" and "/proc/sys/net/ipv6/conf/".
-         *
-         * Also, there is "/sys/class/net/bonding_masters" file.
-         */
-        nm_utils_error_set(error,
-                           NM_UTILS_ERROR_UNKNOWN,
-                           _("'%s' is not allowed as interface name"),
-                           name);
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-static gboolean
-_nm_utils_ifname_valid_ovs(const char *name, GError **error)
-{
-    const char *ch;
-
-    /* OVS actually accepts a wider range of chars (all printable UTF-8 chars),
-     * NetworkManager restricts this to ASCII char as it's a safer option for
-     * now since OVS is not well documented on this matter.
-     **/
-    for (ch = name; *ch; ++ch) {
-        if (*ch == '\\' || *ch == '/' || !g_ascii_isgraph(*ch)) {
-            g_set_error_literal(error,
-                                NM_UTILS_ERROR,
-                                NM_UTILS_ERROR_UNKNOWN,
-                                _("interface name must be alphanumerical with "
-                                  "no forward or backward slashes"));
-            return FALSE;
-        }
-    };
-    return TRUE;
-}
-
-gboolean
-nm_utils_ifname_valid(const char *name, NMUtilsIfaceType type, GError **error)
-{
-    g_return_val_if_fail(!error || !(*error), FALSE);
-
-    if (!name || !(name[0])) {
-        g_set_error_literal(error,
-                            NM_UTILS_ERROR,
-                            NM_UTILS_ERROR_UNKNOWN,
-                            _("interface name must not be empty"));
-        return FALSE;
-    }
-
-    if (!g_utf8_validate(name, -1, NULL)) {
-        g_set_error_literal(error,
-                            NM_UTILS_ERROR,
-                            NM_UTILS_ERROR_UNKNOWN,
-                            _("interface name must be UTF-8 encoded"));
-        return FALSE;
-    }
-
-    switch (type) {
-    case NMU_IFACE_KERNEL:
-        return _nm_utils_ifname_valid_kernel(name, error);
-    case NMU_IFACE_OVS:
-        return _nm_utils_ifname_valid_ovs(name, error);
-    case NMU_IFACE_OVS_AND_KERNEL:
-        return _nm_utils_ifname_valid_kernel(name, error)
-               && _nm_utils_ifname_valid_ovs(name, error);
-    case NMU_IFACE_ANY:
-    {
-        gs_free_error GError *local = NULL;
-
-        if (_nm_utils_ifname_valid_kernel(name, error ? &local : NULL))
-            return TRUE;
-        if (_nm_utils_ifname_valid_ovs(name, NULL))
-            return TRUE;
-        if (error)
-            g_propagate_error(error, g_steal_pointer(&local));
-        return FALSE;
-    }
-    }
-
-    g_return_val_if_reached(FALSE);
-}
-
-/*****************************************************************************/
-
-void
-_nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact)
-{
-    _nm_str_buf_assert(strbuf);
-
-    /* Currently, this only supports strictly growing the buffer. */
-    nm_assert(new_size > strbuf->_priv_allocated);
-
-    if (!reserve_exact) {
-        new_size = nm_utils_get_next_realloc_size(!strbuf->_priv_do_bzero_mem, new_size);
-    }
-
-    strbuf->_priv_str       = nm_secret_mem_realloc(strbuf->_priv_str,
-                                              strbuf->_priv_do_bzero_mem,
-                                              strbuf->_priv_allocated,
-                                              new_size);
-    strbuf->_priv_allocated = new_size;
-}
-
-void
-nm_str_buf_append_printf(NMStrBuf *strbuf, const char *format, ...)
-{
-    va_list args;
-    gsize   available;
-    int     l;
-
-    _nm_str_buf_assert(strbuf);
-
-    available = strbuf->_priv_allocated - strbuf->_priv_len;
-
-    nm_assert(available < G_MAXULONG);
-
-    va_start(args, format);
-    l = g_vsnprintf(&strbuf->_priv_str[strbuf->_priv_len], available, format, args);
-    va_end(args);
-
-    nm_assert(l >= 0);
-    nm_assert(l < G_MAXINT);
-
-    if ((gsize) l >= available) {
-        gsize l2;
-
-        if (l == 0)
-            return;
-
-        l2 = ((gsize) l) + 1u;
-
-        nm_str_buf_maybe_expand(strbuf, l2, FALSE);
-
-        va_start(args, format);
-        l = g_vsnprintf(&strbuf->_priv_str[strbuf->_priv_len], l2, format, args);
-        va_end(args);
-
-        nm_assert(l >= 0);
-        nm_assert((gsize) l == l2 - 1u);
-    }
-
-    strbuf->_priv_len += (gsize) l;
-}
-
-/*****************************************************************************/
-
-/**
- * nm_indirect_g_free:
- * @arg: a pointer to a pointer that is to be freed.
- *
- * This does the same as nm_clear_g_free(arg) (g_clear_pointer (arg, g_free)).
- * This is for example useful when you have a GArray with pointers and a
- * clear function to free them. g_array_set_clear_func()'s destroy notify
- * function gets a pointer to the array location, so we have to follow
- * the first pointer.
- */
-void
-nm_indirect_g_free(gpointer arg)
-{
-    gpointer *p = arg;
-
-    nm_clear_g_free(p);
-}
-
-/*****************************************************************************/
-
-static char *
-attribute_escape(const char *src, char c1, char c2)
-{
-    char *ret, *dest;
-
-    dest = ret = g_malloc(strlen(src) * 2 + 1);
-
-    while (*src) {
-        if (*src == c1 || *src == c2 || *src == '\\')
-            *dest++ = '\\';
-        *dest++ = *src++;
-    }
-    *dest++ = '\0';
-
-    return ret;
-}
-
-void
-_nm_utils_format_variant_attributes_full(GString *                            str,
-                                         const NMUtilsNamedValue *            values,
-                                         guint                                num_values,
-                                         const NMVariantAttributeSpec *const *spec,
-                                         char                                 attr_separator,
-                                         char                                 key_value_separator)
-{
-    const NMVariantAttributeSpec *const *s;
-    const char *                         name, *value;
-    GVariant *                           variant;
-    char *                               escaped;
-    char                                 buf[64];
-    char                                 sep = 0;
-    guint                                i;
-
-    for (i = 0; i < num_values; i++) {
-        name    = values[i].name;
-        variant = values[i].value_ptr;
-        value   = NULL;
-        s       = NULL;
-
-        if (spec) {
-            for (s = spec; *s; s++) {
-                if (nm_streq0((*s)->name, name))
-                    break;
-            }
-
-            if (!*s)
-                continue;
-        }
-
-        if (g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32))
-            value = nm_sprintf_buf(buf, "%u", g_variant_get_uint32(variant));
-        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_INT32))
-            value = nm_sprintf_buf(buf, "%d", (int) g_variant_get_int32(variant));
-        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT64))
-            value = nm_sprintf_buf(buf, "%" G_GUINT64_FORMAT, g_variant_get_uint64(variant));
-        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BYTE))
-            value = nm_sprintf_buf(buf, "%hhu", g_variant_get_byte(variant));
-        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN))
-            value = g_variant_get_boolean(variant) ? "true" : "false";
-        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING))
-            value = g_variant_get_string(variant, NULL);
-        else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BYTESTRING)) {
-            /* FIXME: there is no guarantee that the byte array
-             * is valid UTF-8.*/
-            value = g_variant_get_bytestring(variant);
-        } else
-            continue;
-
-        if (sep)
-            g_string_append_c(str, sep);
-
-        escaped = attribute_escape(name, attr_separator, key_value_separator);
-        g_string_append(str, escaped);
-        g_free(escaped);
-
-        if (!s || !*s || !(*s)->no_value) {
-            g_string_append_c(str, key_value_separator);
-
-            escaped = attribute_escape(value, attr_separator, key_value_separator);
-            g_string_append(str, escaped);
-            g_free(escaped);
-        }
-
-        sep = attr_separator;
-    }
-}
-
-char *
-_nm_utils_format_variant_attributes(GHashTable *                         attributes,
-                                    const NMVariantAttributeSpec *const *spec,
-                                    char                                 attr_separator,
-                                    char                                 key_value_separator)
-{
-    gs_free NMUtilsNamedValue *values_free = NULL;
-    NMUtilsNamedValue          values_prepared[20];
-    const NMUtilsNamedValue *  values;
-    GString *                  str = NULL;
-    guint                      len;
-
-    g_return_val_if_fail(attr_separator, NULL);
-    g_return_val_if_fail(key_value_separator, NULL);
-
-    if (!attributes)
-        return NULL;
-
-    values = nm_utils_named_values_from_strdict(attributes, &len, values_prepared, &values_free);
-    if (len == 0)
-        return NULL;
-
-    str = g_string_new("");
-    _nm_utils_format_variant_attributes_full(str,
-                                             values,
-                                             len,
-                                             spec,
-                                             attr_separator,
-                                             key_value_separator);
-    return g_string_free(str, FALSE);
-}
-
-/*****************************************************************************/
-
-gboolean
-nm_utils_is_localhost(const char *name)
-{
-    static const char *const NAMES[] = {
-        "localhost",
-        "localhost4",
-        "localhost6",
-        "localhost.localdomain",
-        "localhost4.localdomain4",
-        "localhost6.localdomain6",
-    };
-    gsize name_len;
-    int   i;
-
-    if (!name)
-        return FALSE;
-
-    /* This tries to identify local host and domain names
-     * described in RFC6761 plus the redhatism of localdomain.
-     *
-     * Similar to systemd's is_localhost(). */
-
-    name_len = strlen(name);
-
-    if (name_len == 0)
-        return FALSE;
-
-    if (name[name_len - 1] == '.') {
-        /* one trailing dot is fine. Hide it. */
-        name_len--;
-    }
-
-    for (i = 0; i < (int) G_N_ELEMENTS(NAMES); i++) {
-        const char *n = NAMES[i];
-        gsize       l = strlen(n);
-        gsize       s;
-
-        if (name_len < l)
-            continue;
-
-        s = name_len - l;
-
-        if (g_ascii_strncasecmp(&name[s], n, l) != 0)
-            continue;
-
-        /* we accept the name if it is equal to one of the well-known names,
-         * or if it is some prefix, a '.' and the well-known name. */
-        if (s == 0)
-            return TRUE;
-        if (name[s - 1] == '.')
-            return TRUE;
-    }
-
-    return FALSE;
-}
-
-gboolean
-nm_utils_is_specific_hostname(const char *name)
-{
-    if (nm_str_is_empty(name))
-        return FALSE;
-
-    if (nm_streq(name, "(none)")) {
-        /* This is not a special hostname. Probably an artefact by somebody wrongly
-         * printing NULL. */
-        return FALSE;
-    }
-
-    if (nm_utils_is_localhost(name))
-        return FALSE;
-
-    /* FIXME: properly validate the hostname, like systemd's hostname_is_valid() */
-
-    return TRUE;
-}
-
-/*****************************************************************************/
-
-/* taken from systemd's uid_to_name(). */
-char *
-nm_utils_uid_to_name(uid_t uid)
-{
-    gs_free char *buf_heap = NULL;
-    char          buf_stack[4096];
-    gsize         bufsize;
-    char *        buf;
-
-    bufsize = sizeof(buf_stack);
-    buf     = buf_stack;
-
-    for (;;) {
-        struct passwd  pwbuf;
-        struct passwd *pw = NULL;
-        int            r;
-
-        r = getpwuid_r(uid, &pwbuf, buf, bufsize, &pw);
-        if (r == 0 && pw)
-            return nm_strdup_not_empty(pw->pw_name);
-
-        if (r != ERANGE)
-            return NULL;
-
-        if (bufsize > G_MAXSIZE / 2u)
-            return NULL;
-
-        bufsize *= 2u;
-        g_free(buf_heap);
-        buf_heap = g_malloc(bufsize);
-        buf      = buf_heap;
-    }
-}
-
-/* taken from systemd's nss_user_record_by_name() */
-gboolean
-nm_utils_name_to_uid(const char *name, uid_t *out_uid)
-{
-    gs_free char *buf_heap = NULL;
-    char          buf_stack[4096];
-    gsize         bufsize;
-    char *        buf;
-
-    if (!name)
-        return nm_assert_unreachable_val(FALSE);
-
-    bufsize = sizeof(buf_stack);
-    buf     = buf_stack;
-
-    for (;;) {
-        struct passwd *result;
-        struct passwd  pwd;
-        int            r;
-
-        r = getpwnam_r(name, &pwd, buf, bufsize, &result);
-        if (r == 0) {
-            if (!result)
-                return FALSE;
-            NM_SET_OUT(out_uid, pwd.pw_uid);
-            return TRUE;
-        }
-
-        if (r != ERANGE)
-            return FALSE;
-
-        if (bufsize > G_MAXSIZE / 2u)
-            return FALSE;
-
-        bufsize *= 2u;
-        g_free(buf_heap);
-        buf_heap = g_malloc(bufsize);
-        buf      = buf_heap;
-    }
-}
-
-/*****************************************************************************/
-
-typedef struct {
-    CList          lst;
-    gpointer       tls_data;
-    GDestroyNotify destroy_notify;
-} TlsRegData;
-
-static pthread_key_t _tls_reg_key;
-
-static void
-_tls_reg_destroy(gpointer data)
-{
-    CList *     lst_head = data;
-    TlsRegData *entry;
-
-    if (!lst_head)
-        return;
-
-    /* For no strong reason are we destroying the elements in reverse
-     * order than they were added. It seems a bit more sensible (but shouldn't
-     * matter nor should you rely on that). */
-    while ((entry = c_list_last_entry(lst_head, TlsRegData, lst))) {
-        c_list_unlink_stale(&entry->lst);
-        entry->destroy_notify(entry->tls_data);
-        nm_g_slice_free(entry);
-    }
-
-    nm_g_slice_free(lst_head);
-}
-
-static void
-_tls_reg_make_key(void)
-{
-    if (pthread_key_create(&_tls_reg_key, _tls_reg_destroy) != 0)
-        g_return_if_reached();
-}
-
-/**
- * nm_utils_thread_local_register_destroy:
- * @tls_data: the thread local storage data that should be destroyed when the thread
- *   exits. This pointer will be "owned" by the current thread. There is no way
- *   to un-register the destruction.
- * @destroy_notify: the free function that will be called when the thread exits.
- *
- * If _nm_tread_local storage is heap allocated it requires freeing the pointer
- * when the thread exits. Use this function to register the pointer to be
- * released.
- *
- * This function does not change errno.
- */
-void
-nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify)
-{
-    NM_AUTO_PROTECT_ERRNO(errsv);
-    static pthread_once_t key_once = PTHREAD_ONCE_INIT;
-    CList *               lst_head;
-    TlsRegData *          entry;
-
-    nm_assert(destroy_notify);
-
-    if (pthread_once(&key_once, _tls_reg_make_key) != 0)
-        g_return_if_reached();
-
-    if ((lst_head = pthread_getspecific(_tls_reg_key)) == NULL) {
-        lst_head = g_slice_new(CList);
-        c_list_init(lst_head);
-        if (pthread_setspecific(_tls_reg_key, lst_head) != 0)
-            g_return_if_reached();
-    }
-
-    entry                 = g_slice_new(TlsRegData);
-    entry->tls_data       = tls_data;
-    entry->destroy_notify = destroy_notify;
-    c_list_link_tail(lst_head, &entry->lst);
-}
diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h
deleted file mode 100644
index f9c21a00..00000000
--- a/shared/nm-glib-aux/nm-shared-utils.h
+++ /dev/null
@@ -1,2484 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2016 Red Hat, Inc.
- */
-
-#ifndef __NM_SHARED_UTILS_H__
-#define __NM_SHARED_UTILS_H__
-
-#include <netinet/in.h>
-
-/*****************************************************************************/
-
-/* An optional boolean (like NMTernary, with identical numerical
- * enum values). Note that this enum type is _nm_packed! */
-typedef enum _nm_packed {
-    NM_OPTION_BOOL_DEFAULT = -1,
-    NM_OPTION_BOOL_FALSE   = 0,
-    NM_OPTION_BOOL_TRUE    = 1,
-} NMOptionBool;
-
-/*****************************************************************************/
-
-static inline gboolean
-nm_is_ascii(char ch)
-{
-    return ((uint8_t) ch) < 128;
-}
-
-/*****************************************************************************/
-
-pid_t nm_utils_gettid(void);
-
-gboolean _nm_assert_on_main_thread(void);
-
-#if NM_MORE_ASSERTS > 5
-    #define NM_ASSERT_ON_MAIN_THREAD()              \
-        G_STMT_START                                \
-        {                                           \
-            nm_assert(_nm_assert_on_main_thread()); \
-        }                                           \
-        G_STMT_END
-#else
-    #define NM_ASSERT_ON_MAIN_THREAD() \
-        G_STMT_START                   \
-        {                              \
-            ;                          \
-        }                              \
-        G_STMT_END
-#endif
-
-/*****************************************************************************/
-
-static inline gboolean
-_NM_INT_NOT_NEGATIVE(gssize val)
-{
-    /* whether an enum (without negative values) is a signed int, depends on compiler options
-     * and compiler implementation.
-     *
-     * When using such an enum for accessing an array, one naturally wants to check
-     * that the enum is not negative. However, the compiler doesn't like a plain
-     * comparison "enum_val >= 0", because (if the enum is unsigned), it will warn
-     * that the expression is always true *duh*. Not even a cast to a signed
-     * type helps to avoid the compiler warning in any case.
-     *
-     * The sole purpose of this function is to avoid a compiler warning, when checking
-     * that an enum is not negative. */
-    return val >= 0;
-}
-
-/* check whether the integer value is smaller than G_MAXINT32. This macro exists
- * for the sole purpose, that a plain "((int) value <= G_MAXINT32)" comparison
- * may cause the compiler or coverity that this check is always TRUE. But the
- * check depends on compile time and the size of C type "int".  Of course, most
- * of the time in is gint32 and an int value is always <= G_MAXINT32.  The check
- * exists to catch cases where that is not true.
- *
- * Together with the G_STATIC_ASSERT(), we make sure that this is always satisfied. */
-G_STATIC_ASSERT(sizeof(int) == sizeof(gint32));
-#if _NM_CC_SUPPORT_GENERIC
-    #define _NM_INT_LE_MAXINT32(value)                 \
-        ({                                             \
-            _nm_unused typeof(value) _value = (value); \
-                                                       \
-            _Generic((value), int : TRUE);             \
-        })
-#else
-    #define _NM_INT_LE_MAXINT32(value)                 \
-        ({                                             \
-            _nm_unused typeof(value) _value = (value); \
-            _nm_unused const int *_p_value  = &_value; \
-                                                       \
-            TRUE;                                      \
-        })
-#endif
-
-/*****************************************************************************/
-
-typedef struct {
-    guint8 ether_addr_octet[6 /*ETH_ALEN*/];
-} NMEtherAddr;
-
-#define NM_ETHER_ADDR_FORMAT_STR "%02X:%02X:%02X:%02X:%02X:%02X"
-
-#define NM_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]
-
-#define _NM_ETHER_ADDR_INIT(a0, a1, a2, a3, a4, a5) \
-    {                                               \
-        .ether_addr_octet = {                       \
-            (a0),                                   \
-            (a1),                                   \
-            (a2),                                   \
-            (a3),                                   \
-            (a4),                                   \
-            (a5),                                   \
-        },                                          \
-    }
-
-#define NM_ETHER_ADDR_INIT(...) ((NMEtherAddr) _NM_ETHER_ADDR_INIT(__VA_ARGS__))
-
-static inline int
-nm_ether_addr_cmp(const NMEtherAddr *a, const NMEtherAddr *b)
-{
-    NM_CMP_SELF(a, b);
-    NM_CMP_DIRECT_MEMCMP(a, b, sizeof(NMEtherAddr));
-    return 0;
-}
-
-static inline gboolean
-nm_ether_addr_equal(const NMEtherAddr *a, const NMEtherAddr *b)
-{
-    return nm_ether_addr_cmp(a, b) == 0;
-}
-
-/*****************************************************************************/
-
-typedef struct {
-    union {
-        guint8          addr_ptr[1];
-        in_addr_t       addr4;
-        struct in_addr  addr4_struct;
-        struct in6_addr addr6;
-
-        /* NMIPAddr is really a union for IP addresses.
-         * However, as ethernet addresses fit in here nicely, use
-         * it also for an ethernet MAC address. */
-        guint8      ether_addr_octet[6 /*ETH_ALEN*/];
-        NMEtherAddr ether_addr;
-
-        guint8 array[sizeof(struct in6_addr)];
-    };
-} NMIPAddr;
-
-#define NM_IP_ADDR_INIT \
-    {                   \
-        .array = { 0 }  \
-    }
-
-extern const NMIPAddr nm_ip_addr_zero;
-
-#define nm_ether_addr_zero (nm_ip_addr_zero.ether_addr)
-
-static inline int
-nm_ip_addr_cmp(int addr_family, gconstpointer a, gconstpointer b)
-{
-    nm_assert_addr_family(addr_family);
-    nm_assert(a);
-    nm_assert(b);
-
-    return memcmp(a, b, nm_utils_addr_family_to_size(addr_family));
-}
-
-static inline gboolean
-nm_ip_addr_equal(int addr_family, gconstpointer a, gconstpointer b)
-{
-    return nm_ip_addr_cmp(addr_family, a, b) == 0;
-}
-
-static inline gboolean
-nm_ip_addr_is_null(int addr_family, gconstpointer addr)
-{
-    nm_assert(addr);
-    if (addr_family == AF_INET6)
-        return IN6_IS_ADDR_UNSPECIFIED((const struct in6_addr *) addr);
-    nm_assert(addr_family == AF_INET);
-    return ((const struct in_addr *) addr)->s_addr == 0;
-}
-
-static inline void
-nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src)
-{
-    nm_assert_addr_family(addr_family);
-    nm_assert(dst);
-    nm_assert(src);
-
-    memcpy(dst, src, (addr_family != AF_INET6) ? sizeof(in_addr_t) : sizeof(struct in6_addr));
-}
-
-gboolean nm_ip_addr_set_from_untrusted(int           addr_family,
-                                       gpointer      dst,
-                                       gconstpointer src,
-                                       gsize         src_len,
-                                       int *         out_addr_family);
-
-static inline gboolean
-nm_ip4_addr_is_localhost(in_addr_t addr4)
-{
-    return (addr4 & htonl(0xFF000000u)) == htonl(0x7F000000u);
-}
-
-/*****************************************************************************/
-
-struct ether_addr;
-
-static inline int
-nm_utils_ether_addr_cmp(const struct ether_addr *a1, const struct ether_addr *a2)
-{
-    nm_assert(a1);
-    nm_assert(a2);
-    return memcmp(a1, a2, 6 /*ETH_ALEN*/);
-}
-
-static inline gboolean
-nm_utils_ether_addr_equal(const struct ether_addr *a1, const struct ether_addr *a2)
-{
-    return nm_utils_ether_addr_cmp(a1, a2) == 0;
-}
-
-/*****************************************************************************/
-
-#define NM_UTILS_INET_ADDRSTRLEN INET6_ADDRSTRLEN
-
-static inline const char *
-nm_utils_inet_ntop(int addr_family, gconstpointer addr, char *dst)
-{
-    const char *s;
-
-    const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
-
-    nm_assert_addr_family(addr_family);
-    nm_assert(addr);
-    nm_assert(dst);
-
-    s = inet_ntop(addr_family,
-                  addr,
-                  dst,
-                  addr_family == AF_INET6 ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN);
-    nm_assert(s);
-    return s;
-}
-
-static inline const char *
-_nm_utils_inet4_ntop(in_addr_t addr, char dst[static INET_ADDRSTRLEN])
-{
-    return nm_utils_inet_ntop(AF_INET, &addr, dst);
-}
-
-static inline const char *
-_nm_utils_inet6_ntop(const struct in6_addr *addr, char dst[static INET6_ADDRSTRLEN])
-{
-    return nm_utils_inet_ntop(AF_INET6, addr, dst);
-}
-
-static inline char *
-nm_utils_inet_ntop_dup(int addr_family, gconstpointer addr)
-{
-    char buf[NM_UTILS_INET_ADDRSTRLEN];
-
-    return g_strdup(nm_utils_inet_ntop(addr_family, addr, buf));
-}
-
-static inline char *
-nm_utils_inet4_ntop_dup(in_addr_t addr)
-{
-    return nm_utils_inet_ntop_dup(AF_INET, &addr);
-}
-
-static inline char *
-nm_utils_inet6_ntop_dup(const struct in6_addr *addr)
-{
-    return nm_utils_inet_ntop_dup(AF_INET6, addr);
-}
-
-/*****************************************************************************/
-
-gboolean nm_utils_ipaddr_is_valid(int addr_family, const char *str_addr);
-
-gboolean nm_utils_ipaddr_is_normalized(int addr_family, const char *str_addr);
-
-/*****************************************************************************/
-
-gboolean nm_utils_memeqzero(gconstpointer data, gsize length);
-
-/*****************************************************************************/
-
-extern const void *const _NM_PTRARRAY_EMPTY[1];
-
-#define NM_PTRARRAY_EMPTY(type) ((type const *) _NM_PTRARRAY_EMPTY)
-
-static inline void
-_nm_utils_strbuf_init(char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len)
-{
-    NM_SET_OUT(p_buf_len, len);
-    NM_SET_OUT(p_buf_ptr, buf);
-    buf[0] = '\0';
-}
-
-#define nm_utils_strbuf_init(buf, p_buf_ptr, p_buf_len)                                    \
-    G_STMT_START                                                                           \
-    {                                                                                      \
-        G_STATIC_ASSERT(G_N_ELEMENTS(buf) == sizeof(buf) && sizeof(buf) > sizeof(char *)); \
-        _nm_utils_strbuf_init((buf), sizeof(buf), (p_buf_ptr), (p_buf_len));               \
-    }                                                                                      \
-    G_STMT_END
-void nm_utils_strbuf_append(char **buf, gsize *len, const char *format, ...) _nm_printf(3, 4);
-void nm_utils_strbuf_append_c(char **buf, gsize *len, char c);
-void nm_utils_strbuf_append_str(char **buf, gsize *len, const char *str);
-void nm_utils_strbuf_append_bin(char **buf, gsize *len, gconstpointer str, gsize str_len);
-void nm_utils_strbuf_seek_end(char **buf, gsize *len);
-
-const char *nm_strquote(char *buf, gsize buf_len, const char *str);
-
-static inline gboolean
-nm_utils_is_separator(const char c)
-{
-    return NM_IN_SET(c, ' ', '\t');
-}
-
-/*****************************************************************************/
-
-GBytes *nm_gbytes_get_empty(void);
-
-GBytes *nm_g_bytes_new_from_str(const char *str);
-
-static inline gboolean
-nm_gbytes_equal0(GBytes *a, GBytes *b)
-{
-    return a == b || (a && b && g_bytes_equal(a, b));
-}
-
-gboolean nm_utils_gbytes_equal_mem(GBytes *bytes, gconstpointer mem_data, gsize mem_len);
-
-GVariant *nm_utils_gbytes_to_variant_ay(GBytes *bytes);
-
-GHashTable *nm_utils_strdict_clone(GHashTable *src);
-
-GVariant *nm_utils_strdict_to_variant_ass(GHashTable *strdict);
-GVariant *nm_utils_strdict_to_variant_asv(GHashTable *strdict);
-
-/*****************************************************************************/
-
-GVariant *nm_utils_gvariant_vardict_filter(GVariant *src,
-                                           gboolean (*filter_fcn)(const char *key,
-                                                                  GVariant *  val,
-                                                                  char **     out_key,
-                                                                  GVariant ** out_val,
-                                                                  gpointer    user_data),
-                                           gpointer user_data);
-
-GVariant *nm_utils_gvariant_vardict_filter_drop_one(GVariant *src, const char *key);
-
-/*****************************************************************************/
-
-static inline int
-nm_utils_hexchar_to_int(char ch)
-{
-    G_STATIC_ASSERT_EXPR('0' < 'A');
-    G_STATIC_ASSERT_EXPR('A' < 'a');
-
-    if (ch >= '0') {
-        if (ch <= '9')
-            return ch - '0';
-        if (ch >= 'A') {
-            if (ch <= 'F')
-                return ((int) ch) + (10 - (int) 'A');
-            if (ch >= 'a' && ch <= 'f')
-                return ((int) ch) + (10 - (int) 'a');
-        }
-    }
-    return -1;
-}
-
-/*****************************************************************************/
-
-const char *nm_utils_dbus_path_get_last_component(const char *dbus_path);
-
-int nm_utils_dbus_path_cmp(const char *dbus_path_a, const char *dbus_path_b);
-
-/*****************************************************************************/
-
-typedef enum {
-    NM_UTILS_STRSPLIT_SET_FLAGS_NONE = 0,
-
-    /* by default, strsplit will coalesce consecutive delimiters and remove
-     * them from the result. If this flag is present, empty values are preserved
-     * and returned.
-     *
-     * When combined with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, if a value gets
-     * empty after strstrip(), it also gets removed. */
-    NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY = (1u << 0),
-
-    /* %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING means that delimiters prefixed
-     * by a backslash are not treated as a separator. Such delimiters and their escape
-     * character are copied to the current word without unescaping them. In general,
-     * nm_utils_strsplit_set_full() does not remove any backslash escape characters
-     * and does no unescaping. It only considers them for skipping to split at
-     * an escaped delimiter.
-     *
-     * If this is combined with (or implied by %NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED), then
-     * the backslash escapes are removed from the result.
-     */
-    NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING = (1u << 1),
-
-    /* If flag is set, does the same as g_strstrip() on the returned tokens.
-     * This will remove leading and trailing ascii whitespaces (g_ascii_isspace()
-     * and NM_ASCII_SPACES).
-     *
-     * - when combined with !%NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY,
-     *   empty tokens will be removed (and %NULL will be returned if that
-     *   results in an empty string array).
-     * - when combined with %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING,
-     *   trailing whitespace escaped by backslash are not stripped. */
-    NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP = (1u << 2),
-
-    /* This implies %NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING.
-     *
-     * This will do a final run over all tokens and remove all backslash
-     * escape characters that
-     *   - precede a delimiter.
-     *   - precede a backslash.
-     *   - preceed a whitespace (with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP).
-     *
-     *  Note that with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP, it is only
-     *  necessary to escape the very last whitespace (if the delimiters
-     *  are not whitespace themself). So, technically, it would be sufficient
-     *  to only unescape a backslash before the last whitespace and the user
-     *  still could express everything. However, such a rule would be complicated
-     *  to understand, so when using backslash escaping with nm_utils_strsplit_set_full(),
-     *  then all characters (including backslash) are treated verbatim, except:
-     *
-     *    - "\\$DELIMITER" (escaped delimiter)
-     *    - "\\\\" (escaped backslash)
-     *    - "\\$SPACE" (escaped space) (with %NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP).
-     *
-     * Note that all other escapes like "\\n" or "\\001" are left alone.
-     * That makes the escaping/unescaping rules simple. Also, for the most part
-     * a text is just taken as-is, with little additional rules. Only backslashes
-     * need extra care, and then only if they proceed one of the relevant characters.
-     */
-    NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED = (1u << 3),
-
-} NMUtilsStrsplitSetFlags;
-
-const char **
-nm_utils_strsplit_set_full(const char *str, const char *delimiter, NMUtilsStrsplitSetFlags flags);
-
-static inline const char **
-nm_utils_strsplit_set_with_empty(const char *str, const char *delimiters)
-{
-    /* this returns the same result as g_strsplit_set(str, delimiters, -1), except
-     * it does not deep-clone the strv array.
-     * Also, for @str == "", this returns %NULL while g_strsplit_set() would return
-     * an empty strv array. */
-    return nm_utils_strsplit_set_full(str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_PRESERVE_EMPTY);
-}
-
-static inline const char **
-nm_utils_strsplit_set(const char *str, const char *delimiters)
-{
-    return nm_utils_strsplit_set_full(str, delimiters, NM_UTILS_STRSPLIT_SET_FLAGS_NONE);
-}
-
-gssize nm_utils_strv_find_first(char **list, gssize len, const char *needle);
-
-char **_nm_utils_strv_cleanup(char **  strv,
-                              gboolean strip_whitespace,
-                              gboolean skip_empty,
-                              gboolean skip_repeated);
-
-/*****************************************************************************/
-
-static inline gpointer
-nm_copy_func_g_strdup(gconstpointer arg, gpointer user_data)
-{
-    return g_strdup(arg);
-}
-
-/*****************************************************************************/
-
-static inline const char **
-nm_utils_escaped_tokens_split(const char *str, const char *delimiters)
-{
-    return nm_utils_strsplit_set_full(str,
-                                      delimiters,
-                                      NM_UTILS_STRSPLIT_SET_FLAGS_ESCAPED
-                                          | NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP);
-}
-
-typedef enum {
-    NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_NONE                  = 0,
-    NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_SPACES         = (1ull << 0),
-    NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE  = (1ull << 1),
-    NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE = (1ull << 2),
-
-    /* Backslash characters will be escaped as "\\\\" if they precede another
-     * character that makes it necessary. Such characters are:
-     *
-     *  1) before another '\\' backslash.
-     *  2) before any delimiter in @delimiters.
-     *  3) before any delimiter in @delimiters_as_needed.
-     *  4) before a white space, if ESCAPE_LEADING_SPACE or ESCAPE_TRAILING_SPACE is set.
-     *  5) before the end of the word
-     *
-     * Rule 4) is an extension. It's not immediately clear why with ESCAPE_LEADING_SPACE
-     * and ESCAPE_TRAILING_SPACE we want *all* backslashes before a white space escaped.
-     * The reason is, that we obviously want to use ESCAPE_LEADING_SPACE and ESCAPE_TRAILING_SPACE
-     * in cases, where we later parse the backslash escaped strings back, but allowing to strip
-     * unescaped white spaces. That means, we want that " a " gets escaped as "\\ a\\ ".
-     * On the other hand, we also want that " a\\ b " gets escaped as "\\ a\\\\ b\\ ",
-     * and not "\\ a\\ b\\ ". Because otherwise, the parser would need to treat "\\ "
-     * differently depending on whether the sequence is at the beginning, end or middle
-     * of the word.
-     *
-     * Rule 5) is also not immediately obvious. When used with ESCAPE_TRAILING_SPACE,
-     * we clearly want to allow that an escaped word can have arbitrary
-     * whitespace suffixes. That's why this mode exists. So we must escape "a\\" as
-     * "a\\\\", so that appending " " does not change the meaning.
-     * Also without ESCAPE_TRAILING_SPACE, we want in general that we can concatenate
-     * two escaped words without changing their meaning. If the words would be "a\\"
-     * and "," (with ',' being a delimiter), then the result must be "a\\\\" and "\\,"
-     * so that the concatenated word ("a\\\\\\,") is still the same. If we would escape
-     * them instead as "a\\" + "\\,", then the concatenated word would be "a\\\\," and
-     * different.
-     * */
-    NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED = (1ull << 3),
-
-    NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS = (1ull << 4),
-} NMUtilsEscapedTokensEscapeFlags;
-
-const char *nm_utils_escaped_tokens_escape_full(const char *str,
-                                                const char *delimiters,
-                                                const char *delimiters_as_needed,
-                                                NMUtilsEscapedTokensEscapeFlags flags,
-                                                char **                         out_to_free);
-
-static inline const char *
-nm_utils_escaped_tokens_escape(const char *str, const char *delimiters, char **out_to_free)
-{
-    return nm_utils_escaped_tokens_escape_full(
-        str,
-        delimiters,
-        NULL,
-        NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_ALWAYS
-            | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE,
-        out_to_free);
-}
-
-/**
- * nm_utils_escaped_tokens_escape_unnecessary:
- * @str: the string to check for "escape"
- * @delimiters: the delimiters
- *
- * This asserts that calling nm_utils_escaped_tokens_escape()
- * on @str has no effect and returns @str directly. This is only
- * for asserting that @str is safe to not require any escaping.
- *
- * Returns: @str
- */
-static inline const char *
-nm_utils_escaped_tokens_escape_unnecessary(const char *str, const char *delimiters)
-{
-#if NM_MORE_ASSERTS > 0
-
-    nm_assert(str);
-    nm_assert(delimiters);
-
-    {
-        gs_free char *str_to_free = NULL;
-        const char *  str0;
-
-        str0 = nm_utils_escaped_tokens_escape(str, delimiters, &str_to_free);
-        nm_assert(str0 == str);
-        nm_assert(!str_to_free);
-    }
-#endif
-
-    return str;
-}
-
-static inline void
-nm_utils_escaped_tokens_escape_gstr_assert(const char *str,
-                                           const char *delimiters,
-                                           GString *   gstring)
-{
-    g_string_append(gstring, nm_utils_escaped_tokens_escape_unnecessary(str, delimiters));
-}
-
-static inline GString *
-nm_utils_escaped_tokens_escape_gstr(const char *str, const char *delimiters, GString *gstring)
-{
-    gs_free char *str_to_free = NULL;
-
-    nm_assert(str);
-    nm_assert(gstring);
-
-    g_string_append(gstring, nm_utils_escaped_tokens_escape(str, delimiters, &str_to_free));
-    return gstring;
-}
-
-/*****************************************************************************/
-
-char **nm_utils_strsplit_quoted(const char *str);
-
-/*****************************************************************************/
-
-static inline const char **
-nm_utils_escaped_tokens_options_split_list(const char *str)
-{
-    return nm_utils_strsplit_set_full(str,
-                                      ",",
-                                      NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP
-                                          | NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
-}
-
-void nm_utils_escaped_tokens_options_split(char *str, const char **out_key, const char **out_val);
-
-static inline const char *
-nm_utils_escaped_tokens_options_escape_key(const char *key, char **out_to_free)
-{
-    return nm_utils_escaped_tokens_escape_full(
-        key,
-        ",=",
-        NULL,
-        NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED
-            | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE
-            | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE,
-        out_to_free);
-}
-
-static inline const char *
-nm_utils_escaped_tokens_options_escape_val(const char *val, char **out_to_free)
-{
-    return nm_utils_escaped_tokens_escape_full(
-        val,
-        ",",
-        "=",
-        NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_BACKSLASH_AS_NEEDED
-            | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_LEADING_SPACE
-            | NM_UTILS_ESCAPED_TOKENS_ESCAPE_FLAGS_ESCAPE_TRAILING_SPACE,
-        out_to_free);
-}
-
-/*****************************************************************************/
-
-#define NM_UTILS_CHECKSUM_LENGTH_MD5    16
-#define NM_UTILS_CHECKSUM_LENGTH_SHA1   20
-#define NM_UTILS_CHECKSUM_LENGTH_SHA256 32
-
-#define nm_utils_checksum_get_digest(sum, arr)                                   \
-    G_STMT_START                                                                 \
-    {                                                                            \
-        GChecksum *const _sum = (sum);                                           \
-        gsize            _len;                                                   \
-                                                                                 \
-        G_STATIC_ASSERT_EXPR(sizeof(arr) == NM_UTILS_CHECKSUM_LENGTH_MD5         \
-                             || sizeof(arr) == NM_UTILS_CHECKSUM_LENGTH_SHA1     \
-                             || sizeof(arr) == NM_UTILS_CHECKSUM_LENGTH_SHA256); \
-        G_STATIC_ASSERT_EXPR(sizeof(arr) == G_N_ELEMENTS(arr));                  \
-                                                                                 \
-        nm_assert(_sum);                                                         \
-                                                                                 \
-        _len = G_N_ELEMENTS(arr);                                                \
-                                                                                 \
-        g_checksum_get_digest(_sum, (arr), &_len);                               \
-        nm_assert(_len == G_N_ELEMENTS(arr));                                    \
-    }                                                                            \
-    G_STMT_END
-
-#define nm_utils_checksum_get_digest_len(sum, buf, len)        \
-    G_STMT_START                                               \
-    {                                                          \
-        GChecksum *const _sum  = (sum);                        \
-        const gsize      _len0 = (len);                        \
-        gsize            _len;                                 \
-                                                               \
-        nm_assert(NM_IN_SET(_len0,                             \
-                            NM_UTILS_CHECKSUM_LENGTH_MD5,      \
-                            NM_UTILS_CHECKSUM_LENGTH_SHA1,     \
-                            NM_UTILS_CHECKSUM_LENGTH_SHA256)); \
-        nm_assert(_sum);                                       \
-                                                               \
-        _len = _len0;                                          \
-        g_checksum_get_digest(_sum, (buf), &_len);             \
-        nm_assert(_len == _len0);                              \
-    }                                                          \
-    G_STMT_END
-
-/*****************************************************************************/
-
-guint32 _nm_utils_ip4_prefix_to_netmask(guint32 prefix);
-guint32 _nm_utils_ip4_get_default_prefix0(in_addr_t ip);
-guint32 _nm_utils_ip4_get_default_prefix(in_addr_t ip);
-
-gconstpointer
-nm_utils_ipx_address_clear_host_address(int family, gpointer dst, gconstpointer src, guint8 plen);
-in_addr_t              nm_utils_ip4_address_clear_host_address(in_addr_t addr, guint8 plen);
-const struct in6_addr *nm_utils_ip6_address_clear_host_address(struct in6_addr *      dst,
-                                                               const struct in6_addr *src,
-                                                               guint8                 plen);
-int                    nm_utils_ip6_address_same_prefix_cmp(const struct in6_addr *addr_a,
-                                                            const struct in6_addr *addr_b,
-                                                            guint8                 plen);
-
-gboolean nm_utils_ip_is_site_local(int addr_family, const void *address);
-
-/*****************************************************************************/
-
-gboolean nm_utils_parse_inaddr_bin_full(int         addr_family,
-                                        gboolean    accept_legacy,
-                                        const char *text,
-                                        int *       out_addr_family,
-                                        gpointer    out_addr);
-static inline gboolean
-nm_utils_parse_inaddr_bin(int         addr_family,
-                          const char *text,
-                          int *       out_addr_family,
-                          gpointer    out_addr)
-{
-    return nm_utils_parse_inaddr_bin_full(addr_family, FALSE, text, out_addr_family, out_addr);
-}
-
-gboolean nm_utils_parse_inaddr(int addr_family, const char *text, char **out_addr);
-
-gboolean nm_utils_parse_inaddr_prefix_bin(int         addr_family,
-                                          const char *text,
-                                          int *       out_addr_family,
-                                          gpointer    out_addr,
-                                          int *       out_prefix);
-
-gboolean
-nm_utils_parse_inaddr_prefix(int addr_family, const char *text, char **out_addr, int *out_prefix);
-
-gboolean nm_utils_parse_next_line(const char **inout_ptr,
-                                  gsize *      inout_len,
-                                  const char **out_line,
-                                  gsize *      out_line_len);
-
-gint64 nm_g_ascii_strtoll(const char *nptr, char **endptr, guint base);
-
-guint64 nm_g_ascii_strtoull(const char *nptr, char **endptr, guint base);
-
-double nm_g_ascii_strtod(const char *nptr, char **endptr);
-
-gint64
-_nm_utils_ascii_str_to_int64(const char *str, guint base, gint64 min, gint64 max, gint64 fallback);
-guint64 _nm_utils_ascii_str_to_uint64(const char *str,
-                                      guint       base,
-                                      guint64     min,
-                                      guint64     max,
-                                      guint64     fallback);
-
-int _nm_utils_ascii_str_to_bool(const char *str, int default_value);
-
-/*****************************************************************************/
-
-extern char _nm_utils_to_string_buffer[2096];
-
-void     nm_utils_to_string_buffer_init(char **buf, gsize *len);
-gboolean nm_utils_to_string_buffer_init_null(gconstpointer obj, char **buf, gsize *len);
-
-/*****************************************************************************/
-
-typedef struct {
-    unsigned    flag;
-    const char *name;
-} NMUtilsFlags2StrDesc;
-
-#define NM_UTILS_FLAGS2STR(f, n) \
-    {                            \
-        .flag = f, .name = "" n, \
-    }
-
-#define NM_UTILS_FLAGS2STR_DEFINE(fcn_name, flags_type, ...)                    \
-    const char *fcn_name(flags_type flags, char *buf, gsize len)                \
-    {                                                                           \
-        static const NMUtilsFlags2StrDesc descs[] = {__VA_ARGS__};              \
-        G_STATIC_ASSERT(sizeof(flags_type) <= sizeof(unsigned));                \
-                                                                                \
-        return nm_utils_flags2str(descs, G_N_ELEMENTS(descs), flags, buf, len); \
-    }                                                                           \
-    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
-
-const char *nm_utils_flags2str(const NMUtilsFlags2StrDesc *descs,
-                               gsize                       n_descs,
-                               unsigned                    flags,
-                               char *                      buf,
-                               gsize                       len);
-
-/*****************************************************************************/
-
-#define NM_UTILS_ENUM2STR(v, n) \
-    (void) 0;                   \
-case v:                         \
-    s = "" n "";                \
-    break;                      \
-    (void) 0
-#define NM_UTILS_ENUM2STR_IGNORE(v) \
-    (void) 0;                       \
-case v:                             \
-    break;                          \
-    (void) 0
-
-#define NM_UTILS_ENUM2STR_DEFINE_FULL(fcn_name, lookup_type, int_fmt, ...) \
-    const char *fcn_name(lookup_type val, char *buf, gsize len)            \
-    {                                                                      \
-        nm_utils_to_string_buffer_init(&buf, &len);                        \
-        if (len) {                                                         \
-            const char *s = NULL;                                          \
-            switch (val) {                                                 \
-                (void) 0, __VA_ARGS__(void) 0;                             \
-            };                                                             \
-            if (s)                                                         \
-                g_strlcpy(buf, s, len);                                    \
-            else                                                           \
-                g_snprintf(buf, len, "(%" int_fmt ")", val);               \
-        }                                                                  \
-        return buf;                                                        \
-    }                                                                      \
-    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
-
-#define NM_UTILS_ENUM2STR_DEFINE(fcn_name, lookup_type, ...) \
-    NM_UTILS_ENUM2STR_DEFINE_FULL(fcn_name, lookup_type, "d", __VA_ARGS__)
-
-/*****************************************************************************/
-
-#define _nm_g_slice_free_fcn_define(mem_size)                              \
-    static inline void _nm_g_slice_free_fcn_##mem_size(gpointer mem_block) \
-    {                                                                      \
-        g_slice_free1(mem_size, mem_block);                                \
-    }
-
-_nm_g_slice_free_fcn_define(1) _nm_g_slice_free_fcn_define(2) _nm_g_slice_free_fcn_define(4)
-    _nm_g_slice_free_fcn_define(8) _nm_g_slice_free_fcn_define(10) _nm_g_slice_free_fcn_define(12)
-        _nm_g_slice_free_fcn_define(16) _nm_g_slice_free_fcn_define(32)
-
-#define nm_g_slice_free_fcn1(mem_size)                                                        \
-    ({                                                                                        \
-        void (*_fcn)(gpointer);                                                               \
-                                                                                              \
-        /* If mem_size is a compile time constant, the compiler
-         * will be able to optimize this. Hence, you don't want
-         * to call this with a non-constant size argument. */                               \
-        G_STATIC_ASSERT_EXPR(((mem_size) == 1) || ((mem_size) == 2) || ((mem_size) == 4)      \
-                             || ((mem_size) == 8) || ((mem_size) == 10) || ((mem_size) == 12) \
-                             || ((mem_size) == 16) || ((mem_size) == 32));                    \
-        switch ((mem_size)) {                                                                 \
-        case 1:                                                                               \
-            _fcn = _nm_g_slice_free_fcn_1;                                                    \
-            break;                                                                            \
-        case 2:                                                                               \
-            _fcn = _nm_g_slice_free_fcn_2;                                                    \
-            break;                                                                            \
-        case 4:                                                                               \
-            _fcn = _nm_g_slice_free_fcn_4;                                                    \
-            break;                                                                            \
-        case 8:                                                                               \
-            _fcn = _nm_g_slice_free_fcn_8;                                                    \
-            break;                                                                            \
-        case 10:                                                                              \
-            _fcn = _nm_g_slice_free_fcn_10;                                                   \
-            break;                                                                            \
-        case 12:                                                                              \
-            _fcn = _nm_g_slice_free_fcn_12;                                                   \
-            break;                                                                            \
-        case 16:                                                                              \
-            _fcn = _nm_g_slice_free_fcn_16;                                                   \
-            break;                                                                            \
-        case 32:                                                                              \
-            _fcn = _nm_g_slice_free_fcn_32;                                                   \
-            break;                                                                            \
-        default:                                                                              \
-            g_assert_not_reached();                                                           \
-            _fcn = NULL;                                                                      \
-            break;                                                                            \
-        }                                                                                     \
-        _fcn;                                                                                 \
-    })
-
-/**
- * nm_g_slice_free_fcn:
- * @type: type argument for sizeof() operator that you would
- *   pass to g_slice_new().
- *
- * Returns: a function pointer with GDestroyNotify signature
- *   for g_slice_free(type,*).
- *
- * Only certain types are implemented. You'll get a compile time
- * error for the wrong types. */
-#define nm_g_slice_free_fcn(type) (nm_g_slice_free_fcn1(sizeof(type)))
-
-#define nm_g_slice_free_fcn_gint64 (nm_g_slice_free_fcn(gint64))
-
-/*****************************************************************************/
-
-/* Like g_error_matches() however:
- * - as macro it is always inlined.
- * - the @domain is usually a error quark getter function that cannot
- *   be inlined. This macro calls the getter only if there is an error (lazy).
- * - accept a list of allowed codes, instead of only one.
- */
-#define nm_g_error_matches(error, err_domain, ...)                                        \
-    ({                                                                                    \
-        const GError *const _error = (error);                                             \
-                                                                                          \
-        _error && _error->domain == (err_domain) && NM_IN_SET(_error->code, __VA_ARGS__); \
-    })
-
-            static inline void nm_g_set_error_take(GError **error, GError *error_take)
-{
-    if (!error_take)
-        g_return_if_reached();
-    if (!error) {
-        g_error_free(error_take);
-        return;
-    }
-    if (*error) {
-        g_error_free(error_take);
-        g_return_if_reached();
-    }
-    *error = error_take;
-}
-
-#define nm_g_set_error_take_lazy(error, error_take_lazy)    \
-    G_STMT_START                                            \
-    {                                                       \
-        GError **_error = (error);                          \
-                                                            \
-        if (_error)                                         \
-            nm_g_set_error_take(_error, (error_take_lazy)); \
-    }                                                       \
-    G_STMT_END
-
-/**
- * NMUtilsError:
- * @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error
- * @NM_UTILS_ERROR_CANCELLED_DISPOSING: when disposing an object that has
- *   pending asynchronous operations, the operation is cancelled with this
- *   error reason. Depending on the usage, this might indicate a bug because
- *   usually the target object should stay alive as long as there are pending
- *   operations.
- * @NM_UTILS_ERROR_NOT_READY: the failure is related to being currently
- *   not ready to perform the operation.
- *
- * @NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE: used for a very particular
- *   purpose during nm_device_check_connection_compatible() to indicate that
- *   the profile does not match the device already because their type differs.
- *   That is, there is a fundamental reason of trying to check a profile that
- *   cannot possibly match on this device.
- * @NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE: used for a very particular
- *   purpose during nm_device_check_connection_available(), to indicate that the
- *   device is not available because it is unmanaged.
- * @NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY: the profile is currently not
- *   available/compatible with the device, but this may be only temporary.
- *
- * @NM_UTILS_ERROR_SETTING_MISSING: the setting is missing
- *
- * @NM_UTILS_ERROR_INVALID_ARGUMENT: invalid argument.
- */
-typedef enum {
-    NM_UTILS_ERROR_UNKNOWN = 0,         /*< nick=Unknown >*/
-    NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/
-    NM_UTILS_ERROR_INVALID_ARGUMENT,    /*< nick=InvalidArgument >*/
-    NM_UTILS_ERROR_NOT_READY,           /*< nick=NotReady >*/
-
-    /* the following codes have a special meaning and are exactly used for
-     * nm_device_check_connection_compatible() and nm_device_check_connection_available().
-     *
-     * Actually, their meaning is not very important (so, don't think too
-     * hard about the name of these error codes). What is important, is their
-     * relative order (i.e. the integer value of the codes). When manager
-     * searches for a suitable device, it will check all devices whether
-     * a profile can be activated. If they all fail, it will pick the error
-     * message from the device that returned the *highest* error code,
-     * in the hope that this message makes the most sense for the caller.
-     * */
-    NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
-    NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE,
-    NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
-
-    NM_UTILS_ERROR_SETTING_MISSING,
-
-} NMUtilsError;
-
-#define NM_UTILS_ERROR (nm_utils_error_quark())
-GQuark nm_utils_error_quark(void);
-
-GQuark nm_manager_error_quark(void);
-#define _NM_MANAGER_ERROR (nm_manager_error_quark())
-
-#define _NM_MANAGER_ERROR_UNKNOWN_LOG_LEVEL  10
-#define _NM_MANAGER_ERROR_UNKNOWN_LOG_DOMAIN 11
-
-void nm_utils_error_set_cancelled(GError **error, gboolean is_disposing, const char *instance_name);
-
-static inline GError *
-nm_utils_error_new_cancelled(gboolean is_disposing, const char *instance_name)
-{
-    GError *error = NULL;
-
-    nm_utils_error_set_cancelled(&error, is_disposing, instance_name);
-    return error;
-}
-
-gboolean nm_utils_error_is_cancelled_or_disposing(GError *error);
-
-static inline gboolean
-nm_utils_error_is_cancelled(GError *error)
-{
-    return error && error->code == G_IO_ERROR_CANCELLED && error->domain == G_IO_ERROR;
-}
-
-gboolean nm_utils_error_is_notfound(GError *error);
-
-static inline void
-nm_utils_error_set_literal(GError **error, int error_code, const char *literal)
-{
-    g_set_error_literal(error, NM_UTILS_ERROR, error_code, literal);
-}
-
-#define nm_utils_error_set(error, error_code, ...)                           \
-    G_STMT_START                                                             \
-    {                                                                        \
-        if (NM_NARG(__VA_ARGS__) == 1) {                                     \
-            g_set_error_literal((error),                                     \
-                                NM_UTILS_ERROR,                              \
-                                (error_code),                                \
-                                _NM_UTILS_MACRO_FIRST(__VA_ARGS__));         \
-        } else {                                                             \
-            g_set_error((error), NM_UTILS_ERROR, (error_code), __VA_ARGS__); \
-        }                                                                    \
-    }                                                                        \
-    G_STMT_END
-
-#define nm_utils_error_set_errno(error, errsv, fmt, ...)                                          \
-    G_STMT_START                                                                                  \
-    {                                                                                             \
-        char _bstrerr[NM_STRERROR_BUFSIZE];                                                       \
-                                                                                                  \
-        g_set_error((error),                                                                      \
-                    NM_UTILS_ERROR,                                                               \
-                    NM_UTILS_ERROR_UNKNOWN,                                                       \
-                    fmt,                                                                          \
-                    ##__VA_ARGS__,                                                                \
-                    nm_strerror_native_r(                                                         \
-                        ({                                                                        \
-                            const int _errsv = (errsv);                                           \
-                                                                                                  \
-                            (_errsv >= 0 ? _errsv                                                 \
-                                         : (G_UNLIKELY(_errsv == G_MININT) ? G_MAXINT : -errsv)); \
-                        }),                                                                       \
-                        _bstrerr,                                                                 \
-                        sizeof(_bstrerr)));                                                       \
-    }                                                                                             \
-    G_STMT_END
-
-#define nm_utils_error_new(error_code, ...)                                                      \
-    ((NM_NARG(__VA_ARGS__) == 1)                                                                 \
-         ? g_error_new_literal(NM_UTILS_ERROR, (error_code), _NM_UTILS_MACRO_FIRST(__VA_ARGS__)) \
-         : g_error_new(NM_UTILS_ERROR, (error_code), __VA_ARGS__))
-
-/*****************************************************************************/
-
-gboolean nm_g_object_set_property(GObject *     object,
-                                  const char *  property_name,
-                                  const GValue *value,
-                                  GError **     error);
-
-gboolean nm_g_object_set_property_string(GObject *   object,
-                                         const char *property_name,
-                                         const char *value,
-                                         GError **   error);
-
-gboolean nm_g_object_set_property_string_static(GObject *   object,
-                                                const char *property_name,
-                                                const char *value,
-                                                GError **   error);
-
-gboolean nm_g_object_set_property_string_take(GObject *   object,
-                                              const char *property_name,
-                                              char *      value,
-                                              GError **   error);
-
-gboolean nm_g_object_set_property_boolean(GObject *   object,
-                                          const char *property_name,
-                                          gboolean    value,
-                                          GError **   error);
-
-gboolean nm_g_object_set_property_char(GObject *   object,
-                                       const char *property_name,
-                                       gint8       value,
-                                       GError **   error);
-
-gboolean nm_g_object_set_property_uchar(GObject *   object,
-                                        const char *property_name,
-                                        guint8      value,
-                                        GError **   error);
-
-gboolean
-nm_g_object_set_property_int(GObject *object, const char *property_name, int value, GError **error);
-
-gboolean nm_g_object_set_property_int64(GObject *   object,
-                                        const char *property_name,
-                                        gint64      value,
-                                        GError **   error);
-
-gboolean nm_g_object_set_property_uint(GObject *   object,
-                                       const char *property_name,
-                                       guint       value,
-                                       GError **   error);
-
-gboolean nm_g_object_set_property_uint64(GObject *   object,
-                                         const char *property_name,
-                                         guint64     value,
-                                         GError **   error);
-
-gboolean nm_g_object_set_property_flags(GObject *   object,
-                                        const char *property_name,
-                                        GType       gtype,
-                                        guint       value,
-                                        GError **   error);
-
-gboolean nm_g_object_set_property_enum(GObject *   object,
-                                       const char *property_name,
-                                       GType       gtype,
-                                       int         value,
-                                       GError **   error);
-
-GParamSpec *nm_g_object_class_find_property_from_gtype(GType gtype, const char *property_name);
-
-/*****************************************************************************/
-
-#define _NM_G_PARAM_SPEC_CAST(param_spec, _value_type, _c_type)              \
-    ({                                                                       \
-        const GParamSpec *const _param_spec = (param_spec);                  \
-                                                                             \
-        nm_assert(!_param_spec || _param_spec->value_type == (_value_type)); \
-        ((const _c_type *) _param_spec);                                     \
-    })
-
-#define NM_G_PARAM_SPEC_CAST_BOOLEAN(param_spec) \
-    _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_BOOLEAN, GParamSpecBoolean)
-#define NM_G_PARAM_SPEC_CAST_UINT(param_spec) \
-    _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_UINT, GParamSpecUInt)
-#define NM_G_PARAM_SPEC_CAST_UINT64(param_spec) \
-    _NM_G_PARAM_SPEC_CAST(param_spec, G_TYPE_UINT64, GParamSpecUInt64)
-
-#define NM_G_PARAM_SPEC_GET_DEFAULT_BOOLEAN(param_spec) \
-    (NM_G_PARAM_SPEC_CAST_BOOLEAN(NM_ENSURE_NOT_NULL(param_spec))->default_value)
-#define NM_G_PARAM_SPEC_GET_DEFAULT_UINT(param_spec) \
-    (NM_G_PARAM_SPEC_CAST_UINT(NM_ENSURE_NOT_NULL(param_spec))->default_value)
-#define NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(param_spec) \
-    (NM_G_PARAM_SPEC_CAST_UINT64(NM_ENSURE_NOT_NULL(param_spec))->default_value)
-
-/*****************************************************************************/
-
-GType nm_g_type_find_implementing_class_for_property(GType gtype, const char *pname);
-
-/*****************************************************************************/
-
-typedef enum {
-    NM_UTILS_STR_UTF8_SAFE_FLAG_NONE = 0,
-
-    /* This flag only has an effect during escaping. */
-    NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL = 0x0001,
-
-    /* This flag only has an effect during escaping. */
-    NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII = 0x0002,
-
-    /* This flag only has an effect during escaping to ensure we
-     * don't leak secrets in memory. Note that during unescape we
-     * know the maximum result size from the beginning, and no
-     * reallocation happens. Thus, unescape always avoids leaking
-     * secrets already. */
-    NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET = 0x0004,
-
-    /* This flag only has an effect during unescaping. It means
-     * that non-escaped whitespaces (g_ascii_isspace()) will be
-     * stripped from the front and end of the string. Note that
-     * this flag is only useful for gracefully accepting user input
-     * with spaces. With this flag, escape and unescape may no longer
-     * yield the original input. */
-    NM_UTILS_STR_UTF8_SAFE_UNESCAPE_STRIP_SPACES = 0x0008,
-} NMUtilsStrUtf8SafeFlags;
-
-const char *nm_utils_buf_utf8safe_escape(gconstpointer           buf,
-                                         gssize                  buflen,
-                                         NMUtilsStrUtf8SafeFlags flags,
-                                         char **                 to_free);
-char *
-nm_utils_buf_utf8safe_escape_cp(gconstpointer buf, gssize buflen, NMUtilsStrUtf8SafeFlags flags);
-const char *
-nm_utils_buf_utf8safe_escape_bytes(GBytes *bytes, NMUtilsStrUtf8SafeFlags flags, char **to_free);
-gconstpointer nm_utils_buf_utf8safe_unescape(const char *            str,
-                                             NMUtilsStrUtf8SafeFlags flags,
-                                             gsize *                 out_len,
-                                             gpointer *              to_free);
-
-const char *
-nm_utils_str_utf8safe_escape(const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free);
-const char *
-nm_utils_str_utf8safe_unescape(const char *str, NMUtilsStrUtf8SafeFlags flags, char **to_free);
-
-char *nm_utils_str_utf8safe_escape_cp(const char *str, NMUtilsStrUtf8SafeFlags flags);
-char *nm_utils_str_utf8safe_unescape_cp(const char *str, NMUtilsStrUtf8SafeFlags flags);
-
-char *nm_utils_str_utf8safe_escape_take(char *str, NMUtilsStrUtf8SafeFlags flags);
-
-GVariant *nm_g_variant_singleton_u_0(void);
-
-static inline void
-nm_g_variant_unref_floating(GVariant *var)
-{
-    /* often a function wants to keep a reference to an input variant.
-     * It uses g_variant_ref_sink() to either increase the ref-count,
-     * or take ownership of a possibly floating reference.
-     *
-     * If the function doesn't actually want to do anything with the
-     * input variant, it still must make sure that a passed in floating
-     * reference is consumed. Hence, this helper which:
-     *
-     *   - does nothing if @var is not floating
-     *   - unrefs (consumes) @var if it is floating. */
-    if (g_variant_is_floating(var))
-        g_variant_unref(var);
-}
-
-#define nm_g_variant_lookup(dictionary, ...)                         \
-    ({                                                               \
-        GVariant *const _dictionary = (dictionary);                  \
-                                                                     \
-        (_dictionary && g_variant_lookup(_dictionary, __VA_ARGS__)); \
-    })
-
-static inline GVariant *
-nm_g_variant_lookup_value(GVariant *dictionary, const char *key, const GVariantType *expected_type)
-{
-    return dictionary ? g_variant_lookup_value(dictionary, key, expected_type) : NULL;
-}
-
-static inline gboolean
-nm_g_variant_is_of_type(GVariant *value, const GVariantType *type)
-{
-    return value && g_variant_is_of_type(value, type);
-}
-
-static inline GVariant *
-nm_g_variant_new_ay_inaddr(int addr_family, gconstpointer addr)
-{
-    return g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE,
-                                     addr ?: &nm_ip_addr_zero,
-                                     nm_utils_addr_family_to_size(addr_family),
-                                     1);
-}
-
-static inline GVariant *
-nm_g_variant_new_ay_in4addr(in_addr_t addr)
-{
-    return nm_g_variant_new_ay_inaddr(AF_INET, &addr);
-}
-
-static inline GVariant *
-nm_g_variant_new_ay_in6addr(const struct in6_addr *addr)
-{
-    return nm_g_variant_new_ay_inaddr(AF_INET6, addr);
-}
-
-static inline void
-nm_g_variant_builder_add_sv(GVariantBuilder *builder, const char *key, GVariant *val)
-{
-    g_variant_builder_add(builder, "{sv}", key, val);
-}
-
-static inline void
-nm_g_variant_builder_add_sv_bytearray(GVariantBuilder *builder,
-                                      const char *     key,
-                                      const guint8 *   arr,
-                                      gsize            len)
-{
-    g_variant_builder_add(builder,
-                          "{sv}",
-                          key,
-                          g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, arr, len, 1));
-}
-
-static inline void
-nm_g_variant_builder_add_sv_uint32(GVariantBuilder *builder, const char *key, guint32 val)
-{
-    nm_g_variant_builder_add_sv(builder, key, g_variant_new_uint32(val));
-}
-
-static inline void
-nm_g_variant_builder_add_sv_str(GVariantBuilder *builder, const char *key, const char *str)
-{
-    nm_g_variant_builder_add_sv(builder, key, g_variant_new_string(str));
-}
-
-static inline void
-nm_g_source_destroy_and_unref(GSource *source)
-{
-    g_source_destroy(source);
-    g_source_unref(source);
-}
-
-#define nm_clear_g_source_inst(ptr) (nm_clear_pointer((ptr), nm_g_source_destroy_and_unref))
-
-NM_AUTO_DEFINE_FCN0(GSource *, _nm_auto_destroy_and_unref_gsource, nm_g_source_destroy_and_unref);
-#define nm_auto_destroy_and_unref_gsource nm_auto(_nm_auto_destroy_and_unref_gsource)
-
-NM_AUTO_DEFINE_FCN0(GMainContext *, _nm_auto_pop_gmaincontext, g_main_context_pop_thread_default);
-#define nm_auto_pop_gmaincontext nm_auto(_nm_auto_pop_gmaincontext)
-
-static inline gboolean
-nm_source_func_unref_gobject(gpointer user_data)
-{
-    nm_assert(G_IS_OBJECT(user_data));
-    g_object_unref(user_data);
-    return G_SOURCE_REMOVE;
-}
-
-GSource *nm_g_idle_source_new(int            priority,
-                              GSourceFunc    func,
-                              gpointer       user_data,
-                              GDestroyNotify destroy_notify);
-
-GSource *nm_g_timeout_source_new(guint          timeout_msec,
-                                 int            priority,
-                                 GSourceFunc    func,
-                                 gpointer       user_data,
-                                 GDestroyNotify destroy_notify);
-
-GSource *nm_g_timeout_source_new_seconds(guint          timeout_sec,
-                                         int            priority,
-                                         GSourceFunc    func,
-                                         gpointer       user_data,
-                                         GDestroyNotify destroy_notify);
-
-GSource *
-         nm_g_unix_fd_source_new(int          fd,
-                                 GIOCondition io_condition,
-                                 int          priority,
-                                 gboolean (*source_func)(int fd, GIOCondition condition, gpointer user_data),
-                                 gpointer       user_data,
-                                 GDestroyNotify destroy_notify);
-GSource *nm_g_unix_signal_source_new(int            signum,
-                                     int            priority,
-                                     GSourceFunc    handler,
-                                     gpointer       user_data,
-                                     GDestroyNotify notify);
-
-static inline GSource *
-nm_g_source_attach(GSource *source, GMainContext *context)
-{
-    g_source_attach(source, context);
-    return source;
-}
-
-static inline GSource *
-nm_g_idle_add_source(GSourceFunc func, gpointer user_data)
-{
-    /* G convenience function to attach a new timeout source to the default GMainContext.
-     * In that sense it's very similar to g_idle_add() except that it returns a
-     * reference to the new source.  */
-    return nm_g_source_attach(nm_g_idle_source_new(G_PRIORITY_DEFAULT, func, user_data, NULL),
-                              NULL);
-}
-
-static inline GSource *
-nm_g_timeout_add_source(guint timeout_msec, GSourceFunc func, gpointer user_data)
-{
-    /* G convenience function to attach a new timeout source to the default GMainContext.
-     * In that sense it's very similar to g_timeout_add() except that it returns a
-     * reference to the new source.  */
-    return nm_g_source_attach(
-        nm_g_timeout_source_new(timeout_msec, G_PRIORITY_DEFAULT, func, user_data, NULL),
-        NULL);
-}
-
-static inline GSource *
-nm_g_timeout_add_source_seconds(guint timeout_sec, GSourceFunc func, gpointer user_data)
-{
-    /* G convenience function to attach a new timeout source to the default GMainContext.
-     * In that sense it's very similar to g_timeout_add_seconds() except that it returns a
-     * reference to the new source.  */
-    return nm_g_source_attach(
-        nm_g_timeout_source_new_seconds(timeout_sec, G_PRIORITY_DEFAULT, func, user_data, NULL),
-        NULL);
-}
-
-static inline GSource *
-nm_g_timeout_add_source_approx(guint       timeout_msec,
-                               guint       timeout_sec_threshold,
-                               GSourceFunc func,
-                               gpointer    user_data)
-{
-    GSource *source;
-
-    /* If timeout_msec is larger or equal than a threshold, then we use g_timeout_source_new_seconds()
-     * instead. */
-    if (timeout_msec / 1000u >= timeout_sec_threshold)
-        source = nm_g_timeout_source_new_seconds(timeout_msec / 1000u,
-                                                 G_PRIORITY_DEFAULT,
-                                                 func,
-                                                 user_data,
-                                                 NULL);
-    else
-        source = nm_g_timeout_source_new(timeout_msec, G_PRIORITY_DEFAULT, func, user_data, NULL);
-    return nm_g_source_attach(source, NULL);
-}
-
-NM_AUTO_DEFINE_FCN0(GMainContext *, _nm_auto_unref_gmaincontext, g_main_context_unref);
-#define nm_auto_unref_gmaincontext nm_auto(_nm_auto_unref_gmaincontext)
-
-static inline GMainContext *
-nm_g_main_context_push_thread_default(GMainContext *context)
-{
-    /* This function is to work together with nm_auto_pop_gmaincontext. */
-    if (G_UNLIKELY(!context))
-        context = g_main_context_default();
-    g_main_context_push_thread_default(context);
-    return context;
-}
-
-static inline gboolean
-nm_g_main_context_is_thread_default(GMainContext *context)
-{
-    GMainContext *cur_context;
-
-    cur_context = g_main_context_get_thread_default();
-    if (cur_context == context)
-        return TRUE;
-
-    if (G_UNLIKELY(!cur_context))
-        cur_context = g_main_context_default();
-    else if (G_UNLIKELY(!context))
-        context = g_main_context_default();
-    else
-        return FALSE;
-
-    return (cur_context == context);
-}
-
-static inline GMainContext *
-nm_g_main_context_push_thread_default_if_necessary(GMainContext *context)
-{
-    GMainContext *cur_context;
-
-    cur_context = g_main_context_get_thread_default();
-    if (cur_context == context)
-        return NULL;
-
-    if (G_UNLIKELY(!cur_context)) {
-        cur_context = g_main_context_default();
-        if (cur_context == context)
-            return NULL;
-    } else if (G_UNLIKELY(!context)) {
-        context = g_main_context_default();
-        if (cur_context == context)
-            return NULL;
-    }
-
-    g_main_context_push_thread_default(context);
-    return context;
-}
-
-/*****************************************************************************/
-
-static inline int
-nm_utf8_collate0(const char *a, const char *b)
-{
-    if (!a)
-        return !b ? 0 : -1;
-    if (!b)
-        return 1;
-    return g_utf8_collate(a, b);
-}
-
-int nm_strcmp_with_data(gconstpointer a, gconstpointer b, gpointer user_data);
-int nm_strcmp_p_with_data(gconstpointer a, gconstpointer b, gpointer user_data);
-int nm_strcmp0_p_with_data(gconstpointer a, gconstpointer b, gpointer user_data);
-int nm_strcmp_ascii_case_with_data(gconstpointer a, gconstpointer b, gpointer user_data);
-int nm_cmp_uint32_p_with_data(gconstpointer p_a, gconstpointer p_b, gpointer user_data);
-int nm_cmp_int2ptr_p_with_data(gconstpointer p_a, gconstpointer p_b, gpointer user_data);
-
-/*****************************************************************************/
-
-typedef struct {
-    const char *name;
-} NMUtilsNamedEntry;
-
-typedef struct {
-    union {
-        NMUtilsNamedEntry named_entry;
-        const char *      name;
-    };
-    union {
-        const char *value_str;
-        gpointer    value_ptr;
-    };
-} NMUtilsNamedValue;
-
-#define NM_UTILS_NAMED_VALUE_INIT(n, v) \
-    {                                   \
-        .name = (n), .value_ptr = (v)   \
-    }
-
-NMUtilsNamedValue *
-nm_utils_named_values_from_strdict_full(GHashTable *        hash,
-                                        guint *             out_len,
-                                        GCompareDataFunc    compare_func,
-                                        gpointer            user_data,
-                                        NMUtilsNamedValue * provided_buffer,
-                                        guint               provided_buffer_len,
-                                        NMUtilsNamedValue **out_allocated_buffer);
-
-#define nm_utils_named_values_from_strdict(hash, out_len, array, out_allocated_buffer) \
-    nm_utils_named_values_from_strdict_full((hash),                                    \
-                                            (out_len),                                 \
-                                            nm_strcmp_p_with_data,                     \
-                                            NULL,                                      \
-                                            (array),                                   \
-                                            G_N_ELEMENTS(array),                       \
-                                            (out_allocated_buffer))
-
-gssize nm_utils_named_value_list_find(const NMUtilsNamedValue *arr,
-                                      gsize                    len,
-                                      const char *             name,
-                                      gboolean                 sorted);
-
-gboolean nm_utils_named_value_list_is_sorted(const NMUtilsNamedValue *arr,
-                                             gsize                    len,
-                                             gboolean                 accept_duplicates,
-                                             GCompareDataFunc         compare_func,
-                                             gpointer                 user_data);
-
-void nm_utils_named_value_list_sort(NMUtilsNamedValue *arr,
-                                    gsize              len,
-                                    GCompareDataFunc   compare_func,
-                                    gpointer           user_data);
-
-void nm_utils_named_value_clear_with_g_free(NMUtilsNamedValue *val);
-
-/*****************************************************************************/
-
-gpointer *nm_utils_hash_keys_to_array(GHashTable *     hash,
-                                      GCompareDataFunc compare_func,
-                                      gpointer         user_data,
-                                      guint *          out_len);
-
-gpointer *nm_utils_hash_values_to_array(GHashTable *     hash,
-                                        GCompareDataFunc compare_func,
-                                        gpointer         user_data,
-                                        guint *          out_len);
-
-static inline const char **
-nm_utils_strdict_get_keys(const GHashTable *hash, gboolean sorted, guint *out_length)
-{
-    return (const char **) nm_utils_hash_keys_to_array((GHashTable *) hash,
-                                                       sorted ? nm_strcmp_p_with_data : NULL,
-                                                       NULL,
-                                                       out_length);
-}
-
-gboolean nm_utils_hashtable_equal(const GHashTable *a,
-                                  const GHashTable *b,
-                                  gboolean          treat_null_as_empty,
-                                  GEqualFunc        equal_func);
-
-gboolean nm_utils_hashtable_cmp_equal(const GHashTable *a,
-                                      const GHashTable *b,
-                                      GCompareDataFunc  cmp_values,
-                                      gpointer          user_data);
-
-static inline gboolean
-nm_utils_hashtable_same_keys(const GHashTable *a, const GHashTable *b)
-{
-    return nm_utils_hashtable_cmp_equal(a, b, NULL, NULL);
-}
-
-int nm_utils_hashtable_cmp(const GHashTable *a,
-                           const GHashTable *b,
-                           gboolean          do_fast_precheck,
-                           GCompareDataFunc  cmp_keys,
-                           GCompareDataFunc  cmp_values,
-                           gpointer          user_data);
-
-char **nm_utils_strv_make_deep_copied(const char **strv);
-
-char **nm_utils_strv_make_deep_copied_n(const char **strv, gsize len);
-
-static inline char **
-nm_utils_strv_make_deep_copied_nonnull(const char **strv)
-{
-    return nm_utils_strv_make_deep_copied(strv) ?: g_new0(char *, 1);
-}
-
-char **_nm_utils_strv_dup(const char *const *strv, gssize len, gboolean deep_copied);
-
-#define nm_utils_strv_dup(strv, len, deep_copied) \
-    _nm_utils_strv_dup(NM_CAST_STRV_CC(strv), (len), (deep_copied))
-
-const char **_nm_utils_strv_dup_packed(const char *const *strv, gssize len);
-
-#define nm_utils_strv_dup_packed(strv, len) _nm_utils_strv_dup_packed(NM_CAST_STRV_CC(strv), (len))
-
-/*****************************************************************************/
-
-GSList *nm_utils_g_slist_find_str(const GSList *list, const char *needle);
-
-int nm_utils_g_slist_strlist_cmp(const GSList *a, const GSList *b);
-
-char *nm_utils_g_slist_strlist_join(const GSList *a, const char *separator);
-
-/*****************************************************************************/
-
-static inline guint
-nm_g_array_len(const GArray *arr)
-{
-    return arr ? arr->len : 0u;
-}
-
-static inline void
-nm_g_array_unref(GArray *arr)
-{
-    if (arr)
-        g_array_unref(arr);
-}
-
-#define nm_g_array_append_new(arr, type)   \
-    ({                                     \
-        GArray *const _arr = (arr);        \
-        guint         _len;                \
-                                           \
-        nm_assert(_arr);                   \
-        _len = _arr->len;                  \
-        nm_assert(_len < G_MAXUINT);       \
-        g_array_set_size(_arr, _len + 1u); \
-        &g_array_index(arr, type, _len);   \
-    })
-
-/*****************************************************************************/
-
-static inline GPtrArray *
-nm_g_ptr_array_ref(GPtrArray *arr)
-{
-    return arr ? g_ptr_array_ref(arr) : NULL;
-}
-
-static inline void
-nm_g_ptr_array_unref(GPtrArray *arr)
-{
-    if (arr)
-        g_ptr_array_unref(arr);
-}
-
-#define nm_g_ptr_array_set(pdst, val)                              \
-    ({                                                             \
-        GPtrArray **_pdst    = (pdst);                             \
-        GPtrArray * _val     = (val);                              \
-        gboolean    _changed = FALSE;                              \
-                                                                   \
-        nm_assert(_pdst);                                          \
-                                                                   \
-        if (*_pdst != _val) {                                      \
-            _nm_unused gs_unref_ptrarray GPtrArray *_old = *_pdst; \
-                                                                   \
-            *_pdst   = nm_g_ptr_array_ref(_val);                   \
-            _changed = TRUE;                                       \
-        }                                                          \
-        _changed;                                                  \
-    })
-
-#define nm_g_ptr_array_set_take(pdst, val)                         \
-    ({                                                             \
-        GPtrArray **_pdst    = (pdst);                             \
-        GPtrArray * _val     = (val);                              \
-        gboolean    _changed = FALSE;                              \
-                                                                   \
-        nm_assert(_pdst);                                          \
-                                                                   \
-        if (*_pdst != _val) {                                      \
-            _nm_unused gs_unref_ptrarray GPtrArray *_old = *_pdst; \
-                                                                   \
-            *_pdst   = _val;                                       \
-            _changed = TRUE;                                       \
-        } else {                                                   \
-            nm_g_ptr_array_unref(_val);                            \
-        }                                                          \
-        _changed;                                                  \
-    })
-
-static inline guint
-nm_g_ptr_array_len(const GPtrArray *arr)
-{
-    return arr ? arr->len : 0u;
-}
-
-static inline gpointer *
-nm_g_ptr_array_pdata(const GPtrArray *arr)
-{
-    return arr ? arr->pdata : NULL;
-}
-
-GPtrArray *_nm_g_ptr_array_copy(GPtrArray *    array,
-                                GCopyFunc      func,
-                                gpointer       user_data,
-                                GDestroyNotify element_free_func);
-
-/**
- * nm_g_ptr_array_copy:
- * @array: the #GPtrArray to clone.
- * @func: the copy function.
- * @user_data: the user data for the copy function
- * @element_free_func: the free function of the elements. @array MUST have
- *   the same element_free_func. This argument is only used on older
- *   glib, that doesn't support g_ptr_array_copy().
- *
- * This is a replacement for g_ptr_array_copy(), which is not available
- * before glib 2.62. Since GPtrArray does not allow to access the internal
- * element_free_func, we cannot add a compatibility implementation of g_ptr_array_copy()
- * and the user must provide a suitable destroy function.
- *
- * Note that the @element_free_func MUST correspond to free function set in @array.
- */
-#if GLIB_CHECK_VERSION(2, 62, 0)
-    #define nm_g_ptr_array_copy(array, func, user_data, element_free_func)            \
-        ({                                                                            \
-            _nm_unused GDestroyNotify const _element_free_func = (element_free_func); \
-                                                                                      \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS;                                         \
-            g_ptr_array_copy((array), (func), (user_data));                           \
-            G_GNUC_END_IGNORE_DEPRECATIONS;                                           \
-        })
-#else
-    #define nm_g_ptr_array_copy(array, func, user_data, element_free_func) \
-        _nm_g_ptr_array_copy((array), (func), (user_data), (element_free_func))
-#endif
-
-/*****************************************************************************/
-
-static inline GHashTable *
-nm_g_hash_table_ref(GHashTable *hash)
-{
-    return hash ? g_hash_table_ref(hash) : NULL;
-}
-
-static inline void
-nm_g_hash_table_unref(GHashTable *hash)
-{
-    if (hash)
-        g_hash_table_unref(hash);
-}
-
-static inline guint
-nm_g_hash_table_size(GHashTable *hash)
-{
-    return hash ? g_hash_table_size(hash) : 0u;
-}
-
-static inline gpointer
-nm_g_hash_table_lookup(GHashTable *hash, gconstpointer key)
-{
-    return hash ? g_hash_table_lookup(hash, key) : NULL;
-}
-
-static inline gboolean
-nm_g_hash_table_contains(GHashTable *hash, gconstpointer key)
-{
-    return hash ? g_hash_table_contains(hash, key) : FALSE;
-}
-
-static inline gboolean
-nm_g_hash_table_remove(GHashTable *hash, gconstpointer key)
-{
-    return hash ? g_hash_table_remove(hash, key) : FALSE;
-}
-
-/*****************************************************************************/
-
-gssize nm_utils_ptrarray_find_binary_search(gconstpointer *  list,
-                                            gsize            len,
-                                            gconstpointer    needle,
-                                            GCompareDataFunc cmpfcn,
-                                            gpointer         user_data,
-                                            gssize *         out_idx_first,
-                                            gssize *         out_idx_last);
-
-gssize nm_utils_array_find_binary_search(gconstpointer    list,
-                                         gsize            elem_size,
-                                         gsize            len,
-                                         gconstpointer    needle,
-                                         GCompareDataFunc cmpfcn,
-                                         gpointer         user_data);
-
-/*****************************************************************************/
-
-void _nm_utils_strv_sort(const char **strv, gssize len);
-#define nm_utils_strv_sort(strv, len) _nm_utils_strv_sort(NM_CAST_STRV_MC(strv), len)
-
-int
-_nm_utils_strv_cmp_n(const char *const *strv1, gssize len1, const char *const *strv2, gssize len2);
-
-#define nm_utils_strv_cmp_n(strv1, len1, strv2, len2) \
-    _nm_utils_strv_cmp_n(NM_CAST_STRV_CC(strv1), (len1), NM_CAST_STRV_CC(strv2), (len2))
-
-#define nm_utils_strv_equal(strv1, strv2) (nm_utils_strv_cmp_n((strv1), -1, (strv2), -1) == 0)
-
-/*****************************************************************************/
-
-#define NM_UTILS_NSEC_PER_SEC  ((gint64) 1000000000)
-#define NM_UTILS_USEC_PER_SEC  ((gint64) 1000000)
-#define NM_UTILS_MSEC_PER_SEC  ((gint64) 1000)
-#define NM_UTILS_NSEC_PER_MSEC ((gint64) 1000000)
-
-static inline gint64
-NM_UTILS_NSEC_TO_MSEC_CEIL(gint64 nsec)
-{
-    return (nsec + (NM_UTILS_NSEC_PER_MSEC - 1)) / NM_UTILS_NSEC_PER_MSEC;
-}
-
-/*****************************************************************************/
-
-int     nm_utils_fd_wait_for_event(int fd, int event, gint64 timeout_nsec);
-ssize_t nm_utils_fd_read_loop(int fd, void *buf, size_t nbytes, bool do_poll);
-int     nm_utils_fd_read_loop_exact(int fd, void *buf, size_t nbytes, bool do_poll);
-
-/*****************************************************************************/
-
-#define NM_DEFINE_GDBUS_ARG_INFO_FULL(name_, ...) \
-    ((GDBusArgInfo *) (&((const GDBusArgInfo){.ref_count = -1, .name = name_, __VA_ARGS__})))
-
-#define NM_DEFINE_GDBUS_ARG_INFO(name_, a_signature) \
-    NM_DEFINE_GDBUS_ARG_INFO_FULL(name_, .signature = a_signature, )
-
-#define NM_DEFINE_GDBUS_ARG_INFOS(...)            \
-    ((GDBusArgInfo **) ((const GDBusArgInfo *[]){ \
-        __VA_ARGS__ NULL,                         \
-    }))
-
-#define NM_DEFINE_GDBUS_PROPERTY_INFO(name_, ...) \
-    ((GDBusPropertyInfo *) (&(                    \
-        (const GDBusPropertyInfo){.ref_count = -1, .name = name_, __VA_ARGS__})))
-
-#define NM_DEFINE_GDBUS_PROPERTY_INFO_READABLE(name_, m_signature) \
-    NM_DEFINE_GDBUS_PROPERTY_INFO(name_,                           \
-                                  .signature = m_signature,        \
-                                  .flags     = G_DBUS_PROPERTY_INFO_FLAGS_READABLE, )
-
-#define NM_DEFINE_GDBUS_PROPERTY_INFOS(...)                 \
-    ((GDBusPropertyInfo **) ((const GDBusPropertyInfo *[]){ \
-        __VA_ARGS__ NULL,                                   \
-    }))
-
-#define NM_DEFINE_GDBUS_SIGNAL_INFO_INIT(name_, ...) \
-    {                                                \
-        .ref_count = -1, .name = name_, __VA_ARGS__  \
-    }
-
-#define NM_DEFINE_GDBUS_SIGNAL_INFO(name_, ...) \
-    ((GDBusSignalInfo *) (&(                    \
-        (const GDBusSignalInfo) NM_DEFINE_GDBUS_SIGNAL_INFO_INIT(name_, __VA_ARGS__))))
-
-#define NM_DEFINE_GDBUS_SIGNAL_INFOS(...)               \
-    ((GDBusSignalInfo **) ((const GDBusSignalInfo *[]){ \
-        __VA_ARGS__ NULL,                               \
-    }))
-
-#define NM_DEFINE_GDBUS_METHOD_INFO_INIT(name_, ...) \
-    {                                                \
-        .ref_count = -1, .name = name_, __VA_ARGS__  \
-    }
-
-#define NM_DEFINE_GDBUS_METHOD_INFO(name_, ...) \
-    ((GDBusMethodInfo *) (&(                    \
-        (const GDBusMethodInfo) NM_DEFINE_GDBUS_METHOD_INFO_INIT(name_, __VA_ARGS__))))
-
-#define NM_DEFINE_GDBUS_METHOD_INFOS(...)               \
-    ((GDBusMethodInfo **) ((const GDBusMethodInfo *[]){ \
-        __VA_ARGS__ NULL,                               \
-    }))
-
-#define NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(name_, ...) \
-    {                                                   \
-        .ref_count = -1, .name = name_, __VA_ARGS__     \
-    }
-
-#define NM_DEFINE_GDBUS_INTERFACE_INFO(name_, ...) \
-    ((GDBusInterfaceInfo *) (&(                    \
-        (const GDBusInterfaceInfo) NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(name_, __VA_ARGS__))))
-
-#define NM_DEFINE_GDBUS_INTERFACE_VTABLE(...) \
-    ((GDBusInterfaceVTable *) (&((const GDBusInterfaceVTable){__VA_ARGS__})))
-
-/*****************************************************************************/
-
-guint64 nm_utils_get_start_time_for_pid(pid_t pid, char *out_state, pid_t *out_ppid);
-
-static inline gboolean
-nm_utils_process_state_is_dead(char pstate)
-{
-    /* "/proc/[pid]/stat" returns a state as the 3rd fields (see `man 5 proc`).
-     * Some of these states indicate the process is effectively dead (or a zombie).
-     */
-    return NM_IN_SET(pstate, 'Z', 'x', 'X');
-}
-
-/*****************************************************************************/
-
-typedef struct _NMUtilsUserData NMUtilsUserData;
-
-NMUtilsUserData *_nm_utils_user_data_pack(int nargs, gconstpointer *args);
-
-#define nm_utils_user_data_pack(...) \
-    _nm_utils_user_data_pack(NM_NARG(__VA_ARGS__), (gconstpointer[]){__VA_ARGS__})
-
-void _nm_utils_user_data_unpack(NMUtilsUserData *user_data, int nargs, ...);
-
-#define nm_utils_user_data_unpack(user_data, ...) \
-    _nm_utils_user_data_unpack(user_data, NM_NARG(__VA_ARGS__), __VA_ARGS__)
-
-/*****************************************************************************/
-
-typedef void (*NMUtilsInvokeOnIdleCallback)(gpointer user_data, GCancellable *cancellable);
-
-void nm_utils_invoke_on_idle(GCancellable *              cancellable,
-                             NMUtilsInvokeOnIdleCallback callback,
-                             gpointer                    callback_user_data);
-
-void nm_utils_invoke_on_timeout(guint                       timeout_msec,
-                                GCancellable *              cancellable,
-                                NMUtilsInvokeOnIdleCallback callback,
-                                gpointer                    callback_user_data);
-
-/*****************************************************************************/
-
-GSource *nm_utils_g_main_context_create_integrate_source(GMainContext *internal);
-
-/*****************************************************************************/
-
-static inline GPtrArray *
-nm_strv_ptrarray_ensure(GPtrArray **p_arr)
-{
-    nm_assert(p_arr);
-
-    if (G_UNLIKELY(!*p_arr))
-        *p_arr = g_ptr_array_new_with_free_func(g_free);
-
-    return *p_arr;
-}
-
-static inline const char *const *
-nm_strv_ptrarray_get_unsafe(GPtrArray *arr, guint *out_len)
-{
-    /* warning: the GPtrArray is not NULL terminated. So, it
-     * isn't really a strv array (sorry the misnomer). That's why
-     * the function is potentially "unsafe" and you must provide a
-     * out_len parameter. */
-    if (!arr || arr->len == 0) {
-        *out_len = 0;
-        return NULL;
-    }
-    *out_len = arr->len;
-    return (const char *const *) arr->pdata;
-}
-
-static inline GPtrArray *
-nm_strv_ptrarray_clone(const GPtrArray *src, gboolean null_if_empty)
-{
-    if (!src || (null_if_empty && src->len == 0))
-        return NULL;
-    return nm_g_ptr_array_copy((GPtrArray *) src, nm_copy_func_g_strdup, NULL, g_free);
-}
-
-static inline void
-nm_strv_ptrarray_add_string_take(GPtrArray *cmd, char *str)
-{
-    nm_assert(cmd);
-    nm_assert(str);
-
-    g_ptr_array_add(cmd, str);
-}
-
-static inline void
-nm_strv_ptrarray_add_string_dup(GPtrArray *cmd, const char *str)
-{
-    nm_strv_ptrarray_add_string_take(cmd, g_strdup(str));
-}
-
-#define nm_strv_ptrarray_add_string_concat(cmd, ...) \
-    nm_strv_ptrarray_add_string_take((cmd), g_strconcat(__VA_ARGS__, NULL))
-
-#define nm_strv_ptrarray_add_string_printf(cmd, ...) \
-    nm_strv_ptrarray_add_string_take((cmd), g_strdup_printf(__VA_ARGS__))
-
-#define nm_strv_ptrarray_add_int(cmd, val) \
-    nm_strv_ptrarray_add_string_take((cmd), nm_strdup_int(val))
-
-static inline void
-nm_strv_ptrarray_take_gstring(GPtrArray *cmd, GString **gstr)
-{
-    nm_assert(gstr && *gstr);
-
-    nm_strv_ptrarray_add_string_take(cmd, g_string_free(g_steal_pointer(gstr), FALSE));
-}
-
-static inline gssize
-nm_strv_ptrarray_find_first(const GPtrArray *strv, const char *str)
-{
-    if (!strv)
-        return -1;
-    return nm_utils_strv_find_first((char **) strv->pdata, strv->len, str);
-}
-
-static inline gboolean
-nm_strv_ptrarray_contains(const GPtrArray *strv, const char *str)
-{
-    return nm_strv_ptrarray_find_first(strv, str) >= 0;
-}
-
-static inline int
-nm_strv_ptrarray_cmp(const GPtrArray *a, const GPtrArray *b)
-{
-    /* nm_utils_strv_cmp_n() will treat NULL and empty arrays the same.
-     * That means, an empty strv array can both be represented by NULL
-     * and an array of length zero.
-     * If you need to distinguish between these case, do that yourself. */
-    return nm_utils_strv_cmp_n((const char *const *) nm_g_ptr_array_pdata(a),
-                               nm_g_ptr_array_len(a),
-                               (const char *const *) nm_g_ptr_array_pdata(b),
-                               nm_g_ptr_array_len(b));
-}
-
-/*****************************************************************************/
-
-int nm_utils_getpagesize(void);
-
-/*****************************************************************************/
-
-extern const char _nm_hexchar_table_lower[16];
-extern const char _nm_hexchar_table_upper[16];
-
-static inline char
-nm_hexchar(int x, gboolean upper_case)
-{
-    return upper_case ? _nm_hexchar_table_upper[x & 15] : _nm_hexchar_table_lower[x & 15];
-}
-
-char *nm_utils_bin2hexstr_full(gconstpointer addr,
-                               gsize         length,
-                               char          delimiter,
-                               gboolean      upper_case,
-                               char *        out);
-
-#define nm_utils_bin2hexstr_a(addr, length, delimiter, upper_case, str_to_free)               \
-    ({                                                                                        \
-        gconstpointer _addr        = (addr);                                                  \
-        gsize         _length      = (length);                                                \
-        char          _delimiter   = (delimiter);                                             \
-        char **       _str_to_free = (str_to_free);                                           \
-        char *        _s;                                                                     \
-        gsize         _s_len;                                                                 \
-                                                                                              \
-        nm_assert(_str_to_free);                                                              \
-                                                                                              \
-        _s_len = _length == 0 ? 1u : (_delimiter == '\0' ? _length * 2u + 1u : _length * 3u); \
-        if (_s_len < 100)                                                                     \
-            _s = g_alloca(_s_len);                                                            \
-        else {                                                                                \
-            _s            = g_malloc(_s_len);                                                 \
-            *_str_to_free = _s;                                                               \
-        }                                                                                     \
-        nm_utils_bin2hexstr_full(_addr, _length, _delimiter, (upper_case), _s);               \
-    })
-
-static inline const char *
-nm_ether_addr_to_string(const NMEtherAddr *ether_addr, char sbuf[static(sizeof(NMEtherAddr) * 3)])
-{
-    nm_assert(ether_addr);
-    nm_assert(sbuf);
-
-    return nm_utils_bin2hexstr_full(ether_addr, sizeof(NMEtherAddr), ':', TRUE, sbuf);
-}
-
-#define nm_ether_addr_to_string_a(ether_addr) \
-    nm_ether_addr_to_string((ether_addr), g_alloca(sizeof(NMEtherAddr) * 3))
-
-guint8 *nm_utils_hexstr2bin_full(const char *hexstr,
-                                 gboolean    allow_0x_prefix,
-                                 gboolean    delimiter_required,
-                                 gboolean    hexdigit_pairs_required,
-                                 const char *delimiter_candidates,
-                                 gsize       required_len,
-                                 guint8 *    buffer,
-                                 gsize       buffer_len,
-                                 gsize *     out_len);
-
-#define nm_utils_hexstr2bin_buf(hexstr,               \
-                                allow_0x_prefix,      \
-                                delimiter_required,   \
-                                delimiter_candidates, \
-                                buffer)               \
-    nm_utils_hexstr2bin_full((hexstr),                \
-                             (allow_0x_prefix),       \
-                             (delimiter_required),    \
-                             FALSE,                   \
-                             (delimiter_candidates),  \
-                             G_N_ELEMENTS(buffer),    \
-                             (buffer),                \
-                             G_N_ELEMENTS(buffer),    \
-                             NULL)
-
-guint8 *nm_utils_hexstr2bin_alloc(const char *hexstr,
-                                  gboolean    allow_0x_prefix,
-                                  gboolean    delimiter_required,
-                                  const char *delimiter_candidates,
-                                  gsize       required_len,
-                                  gsize *     out_len);
-
-/**
- * _nm_utils_hwaddr_aton:
- * @asc: the ASCII representation of a hardware address
- * @buffer: buffer to store the result into. Must have
- *   at least a size of @buffer_length.
- * @buffer_length: the length of the input buffer @buffer.
- *   The result must fit into that buffer, otherwise
- *   the function fails and returns %NULL.
- * @out_length: the output length in case of success.
- *
- * Parses @asc and converts it to binary form in @buffer.
- * Bytes in @asc can be separated by colons (:), or hyphens (-), but not mixed.
- *
- * It is like nm_utils_hwaddr_aton(), but contrary to that it
- * can parse addresses of any length. That is, you don't need
- * to know the length before-hand.
- *
- * Return value: @buffer, or %NULL if @asc couldn't be parsed.
- */
-static inline guint8 *
-_nm_utils_hwaddr_aton(const char *asc, gpointer buffer, gsize buffer_length, gsize *out_length)
-{
-    g_return_val_if_fail(asc, NULL);
-    g_return_val_if_fail(buffer, NULL);
-    g_return_val_if_fail(buffer_length > 0, NULL);
-    g_return_val_if_fail(out_length, NULL);
-
-    return nm_utils_hexstr2bin_full(asc,
-                                    FALSE,
-                                    TRUE,
-                                    FALSE,
-                                    ":-",
-                                    0,
-                                    buffer,
-                                    buffer_length,
-                                    out_length);
-}
-
-static inline guint8 *
-_nm_utils_hwaddr_aton_exact(const char *asc, gpointer buffer, gsize buffer_length)
-{
-    g_return_val_if_fail(asc, NULL);
-    g_return_val_if_fail(buffer, NULL);
-    g_return_val_if_fail(buffer_length > 0, NULL);
-
-    return nm_utils_hexstr2bin_full(asc,
-                                    FALSE,
-                                    TRUE,
-                                    FALSE,
-                                    ":-",
-                                    buffer_length,
-                                    buffer,
-                                    buffer_length,
-                                    NULL);
-}
-
-static inline const char *
-_nm_utils_hwaddr_ntoa(gconstpointer addr,
-                      gsize         addr_len,
-                      gboolean      upper_case,
-                      char *        buf,
-                      gsize         buf_len)
-{
-    g_return_val_if_fail(addr, NULL);
-    g_return_val_if_fail(addr_len > 0, NULL);
-    g_return_val_if_fail(buf, NULL);
-    if (buf_len < addr_len * 3)
-        g_return_val_if_reached(NULL);
-
-    return nm_utils_bin2hexstr_full(addr, addr_len, ':', upper_case, buf);
-}
-
-/*****************************************************************************/
-
-#define _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(fcn_name,                                         \
-                                             value_type,                                       \
-                                             value_type_result,                                \
-                                             entry_cmd,                                        \
-                                             unknown_val_cmd,                                  \
-                                             get_operator,                                     \
-                                             ...)                                              \
-    value_type_result fcn_name(const char *name)                                               \
-    {                                                                                          \
-        static const struct {                                                                  \
-            const char *name;                                                                  \
-            value_type  value;                                                                 \
-        } LIST[] = {__VA_ARGS__};                                                              \
-                                                                                               \
-        if (NM_MORE_ASSERT_ONCE(5)) {                                                          \
-            int i;                                                                             \
-                                                                                               \
-            for (i = 0; i < G_N_ELEMENTS(LIST); i++) {                                         \
-                nm_assert(LIST[i].name);                                                       \
-                if (i > 0)                                                                     \
-                    nm_assert(strcmp(LIST[i - 1].name, LIST[i].name) < 0);                     \
-            }                                                                                  \
-        }                                                                                      \
-                                                                                               \
-        {                                                                                      \
-            entry_cmd;                                                                         \
-        }                                                                                      \
-                                                                                               \
-        if (G_LIKELY(name)) {                                                                  \
-            G_STATIC_ASSERT(G_N_ELEMENTS(LIST) > 1);                                           \
-            G_STATIC_ASSERT(G_N_ELEMENTS(LIST) < G_MAXINT / 2 - 10);                           \
-            int imin = 0;                                                                      \
-            int imax = (G_N_ELEMENTS(LIST) - 1);                                               \
-            int imid = (G_N_ELEMENTS(LIST) - 1) / 2;                                           \
-                                                                                               \
-            for (;;) {                                                                         \
-                const int cmp = strcmp(LIST[imid].name, name);                                 \
-                                                                                               \
-                if (G_UNLIKELY(cmp == 0))                                                      \
-                    return get_operator(LIST[imid].value);                                     \
-                                                                                               \
-                if (cmp < 0)                                                                   \
-                    imin = imid + 1;                                                           \
-                else                                                                           \
-                    imax = imid - 1;                                                           \
-                                                                                               \
-                if (G_UNLIKELY(imin > imax))                                                   \
-                    break;                                                                     \
-                                                                                               \
-                /* integer overflow cannot happen, because LIST is shorter than G_MAXINT/2. */ \
-                imid = (imin + imax) / 2;                                                      \
-            }                                                                                  \
-        }                                                                                      \
-                                                                                               \
-        {                                                                                      \
-            unknown_val_cmd;                                                                   \
-        }                                                                                      \
-    }                                                                                          \
-    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
-
-#define NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE(fcn_name,        \
-                                                   result_type,     \
-                                                   entry_cmd,       \
-                                                   unknown_val_cmd, \
-                                                   ...)             \
-    _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(fcn_name,                  \
-                                         result_type,               \
-                                         const result_type *,       \
-                                         entry_cmd,                 \
-                                         unknown_val_cmd,           \
-                                             &,                     \
-                                         __VA_ARGS__)
-
-#define NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(fcn_name,        \
-                                            result_type,     \
-                                            entry_cmd,       \
-                                            unknown_val_cmd, \
-                                            ...)             \
-    _NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(fcn_name,           \
-                                         result_type,        \
-                                         result_type,        \
-                                         entry_cmd,          \
-                                         unknown_val_cmd,    \
-                                         ,                   \
-                                         __VA_ARGS__)
-
-/*****************************************************************************/
-
-static inline GTask *
-nm_g_task_new(gpointer            source_object,
-              GCancellable *      cancellable,
-              gpointer            source_tag,
-              GAsyncReadyCallback callback,
-              gpointer            callback_data)
-{
-    GTask *task;
-
-    task = g_task_new(source_object, cancellable, callback, callback_data);
-    if (source_tag)
-        g_task_set_source_tag(task, source_tag);
-    return task;
-}
-
-static inline gboolean
-nm_g_task_is_valid(gpointer task, gpointer source_object, gpointer source_tag)
-{
-    return g_task_is_valid(task, source_object) && g_task_get_source_tag(task) == source_tag;
-}
-
-guint nm_utils_parse_debug_string(const char *string, const GDebugKey *keys, guint nkeys);
-
-/*****************************************************************************/
-
-static inline gboolean
-nm_utils_strdup_reset(char **dst, const char *src)
-{
-    char *old;
-
-    nm_assert(dst);
-
-    if (nm_streq0(*dst, src))
-        return FALSE;
-    old  = *dst;
-    *dst = g_strdup(src);
-    g_free(old);
-    return TRUE;
-}
-
-static inline gboolean
-nm_utils_strdup_reset_take(char **dst, char *src)
-{
-    char *old;
-
-    nm_assert(dst);
-    nm_assert(src != *dst);
-
-    if (nm_streq0(*dst, src)) {
-        if (src)
-            g_free(src);
-        return FALSE;
-    }
-    old  = *dst;
-    *dst = src;
-    g_free(old);
-    return TRUE;
-}
-
-void nm_indirect_g_free(gpointer arg);
-
-/*****************************************************************************/
-
-void nm_utils_ifname_cpy(char *dst, const char *name);
-
-typedef enum {
-    NMU_IFACE_ANY,
-    NMU_IFACE_KERNEL,
-    NMU_IFACE_OVS,
-    NMU_IFACE_OVS_AND_KERNEL,
-} NMUtilsIfaceType;
-
-gboolean nm_utils_ifname_valid_kernel(const char *name, GError **error);
-
-gboolean nm_utils_ifname_valid(const char *name, NMUtilsIfaceType type, GError **error);
-
-/*****************************************************************************/
-
-static inline GArray *
-nm_strvarray_ensure(GArray **p)
-{
-    if (!*p) {
-        *p = g_array_new(TRUE, FALSE, sizeof(char *));
-        g_array_set_clear_func(*p, nm_indirect_g_free);
-    }
-    return *p;
-}
-
-static inline void
-nm_strvarray_add(GArray *array, const char *str)
-{
-    char *s;
-
-    s = g_strdup(str);
-    g_array_append_val(array, s);
-}
-
-static inline const char *const *
-nm_strvarray_get_strv_non_empty(GArray *arr, guint *length)
-{
-    if (!arr || arr->len == 0) {
-        NM_SET_OUT(length, 0);
-        return NULL;
-    }
-
-    NM_SET_OUT(length, arr->len);
-    return &g_array_index(arr, const char *, 0);
-}
-
-static inline const char *const *
-nm_strvarray_get_strv(GArray **arr, guint *length)
-{
-    if (!*arr) {
-        NM_SET_OUT(length, 0);
-        return (const char *const *) arr;
-    }
-
-    NM_SET_OUT(length, (*arr)->len);
-    return &g_array_index(*arr, const char *, 0);
-}
-
-static inline void
-nm_strvarray_set_strv(GArray **array, const char *const *strv)
-{
-    gs_unref_array GArray *array_old = NULL;
-
-    array_old = g_steal_pointer(array);
-
-    if (!strv || !strv[0])
-        return;
-
-    nm_strvarray_ensure(array);
-    for (; strv[0]; strv++)
-        nm_strvarray_add(*array, strv[0]);
-}
-
-static inline gboolean
-nm_strvarray_remove_first(GArray *strv, const char *needle)
-{
-    guint i;
-
-    nm_assert(needle);
-
-    if (strv) {
-        for (i = 0; i < strv->len; i++) {
-            if (nm_streq(needle, g_array_index(strv, const char *, i))) {
-                g_array_remove_index(strv, i);
-                return TRUE;
-            }
-        }
-    }
-    return FALSE;
-}
-
-/*****************************************************************************/
-
-struct _NMVariantAttributeSpec {
-    char *              name;
-    const GVariantType *type;
-    bool                v4 : 1;
-    bool                v6 : 1;
-    bool                no_value : 1;
-    bool                consumes_rest : 1;
-    char                str_type;
-};
-
-typedef struct _NMVariantAttributeSpec NMVariantAttributeSpec;
-
-void _nm_utils_format_variant_attributes_full(GString *                            str,
-                                              const NMUtilsNamedValue *            values,
-                                              guint                                num_values,
-                                              const NMVariantAttributeSpec *const *spec,
-                                              char                                 attr_separator,
-                                              char key_value_separator);
-
-char *_nm_utils_format_variant_attributes(GHashTable *                         attributes,
-                                          const NMVariantAttributeSpec *const *spec,
-                                          char                                 attr_separator,
-                                          char                                 key_value_separator);
-
-/*****************************************************************************/
-
-gboolean nm_utils_is_localhost(const char *name);
-
-gboolean nm_utils_is_specific_hostname(const char *name);
-
-char *   nm_utils_uid_to_name(uid_t uid);
-gboolean nm_utils_name_to_uid(const char *name, uid_t *out_uid);
-
-/*****************************************************************************/
-
-void nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify);
-
-#endif /* __NM_SHARED_UTILS_H__ */
diff --git a/shared/nm-glib-aux/nm-str-buf.h b/shared/nm-glib-aux/nm-str-buf.h
deleted file mode 100644
index cb0d3fb1..00000000
--- a/shared/nm-glib-aux/nm-str-buf.h
+++ /dev/null
@@ -1,488 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef __NM_STR_BUF_H__
-#define __NM_STR_BUF_H__
-
-#include "nm-shared-utils.h"
-#include "nm-secret-utils.h"
-
-/*****************************************************************************/
-
-/* NMStrBuf is not unlike GString. The main difference is that it can use
- * nm_explicit_bzero() when growing the buffer. */
-typedef struct _NMStrBuf {
-    char *_priv_str;
-
-    /* The unions only exist because we allow/encourage read-only access
-     * to the "len" and "allocated" fields, but modifying the fields is
-     * only allowed to the NMStrBuf implementation itself. */
-    union {
-        /*const*/ gsize len;
-        gsize           _priv_len;
-    };
-    union {
-        /*const*/ gsize allocated;
-        gsize           _priv_allocated;
-    };
-
-    bool _priv_do_bzero_mem;
-} NMStrBuf;
-
-/*****************************************************************************/
-
-static inline void
-_nm_str_buf_assert(const NMStrBuf *strbuf)
-{
-    nm_assert(strbuf);
-    nm_assert((!!strbuf->_priv_str) == (strbuf->_priv_allocated > 0));
-    nm_assert(strbuf->_priv_len <= strbuf->_priv_allocated);
-}
-
-static inline NMStrBuf
-NM_STR_BUF_INIT(gsize allocated, gboolean do_bzero_mem)
-{
-    NMStrBuf strbuf = {
-        ._priv_str          = allocated ? g_malloc(allocated) : NULL,
-        ._priv_allocated    = allocated,
-        ._priv_len          = 0,
-        ._priv_do_bzero_mem = do_bzero_mem,
-    };
-
-    return strbuf;
-}
-
-static inline void
-nm_str_buf_init(NMStrBuf *strbuf, gsize len, bool do_bzero_mem)
-{
-    nm_assert(strbuf);
-    *strbuf = NM_STR_BUF_INIT(len, do_bzero_mem);
-    _nm_str_buf_assert(strbuf);
-}
-
-void _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact);
-
-static inline void
-nm_str_buf_maybe_expand(NMStrBuf *strbuf, gsize reserve, gboolean reserve_exact)
-{
-    _nm_str_buf_assert(strbuf);
-    nm_assert(strbuf->_priv_len < G_MAXSIZE - reserve);
-
-    /* @reserve is the extra space that we require. */
-    if (G_UNLIKELY(reserve > strbuf->_priv_allocated - strbuf->_priv_len))
-        _nm_str_buf_ensure_size(strbuf, strbuf->_priv_len + reserve, reserve_exact);
-}
-
-/*****************************************************************************/
-
-/**
- * nm_str_buf_set_size:
- * @strbuf: the initialized #NMStrBuf
- * @new_len: the new length
- * @honor_do_bzero_mem: if %TRUE, the shrunk memory will be cleared, if
- *   do_bzero_mem is set. This should be usually set to %TRUE, unless
- *   you know that the shrunk memory does not contain data that requires to be
- *   cleared. When growing the size, this value has no effect.
- * @reserve_exact: when growing the buffer, reserve the exact amount of bytes.
- *   If %FALSE, the buffer may allocate more memory than requested to grow
- *   exponentially.
- *
- * This is like g_string_set_size(). If new_len is smaller than the
- * current length, the string gets truncated (excess memory will be cleared).
- *
- * When extending the length, the added bytes are undefined (like with
- * g_string_set_size(). Likewise, if you first pre-allocate a buffer with
- * nm_str_buf_maybe_expand(), then write to the bytes, and finally set
- * the appropriate size, then that works as expected (by not clearing the
- * pre-existing, grown buffer).
- */
-static inline void
-nm_str_buf_set_size(NMStrBuf *strbuf,
-                    gsize     new_len,
-                    gboolean  honor_do_bzero_mem,
-                    gboolean  reserve_exact)
-{
-    _nm_str_buf_assert(strbuf);
-
-    if (new_len < strbuf->_priv_len) {
-        if (honor_do_bzero_mem && strbuf->_priv_do_bzero_mem) {
-            /* we only clear the memory that we wrote to. */
-            nm_explicit_bzero(&strbuf->_priv_str[new_len], strbuf->_priv_len - new_len);
-        }
-    } else if (new_len > strbuf->_priv_len) {
-        nm_str_buf_maybe_expand(strbuf,
-                                new_len - strbuf->_priv_len + (reserve_exact ? 0u : 1u),
-                                reserve_exact);
-    } else
-        return;
-
-    strbuf->_priv_len = new_len;
-}
-
-/*****************************************************************************/
-
-static inline void
-nm_str_buf_erase(NMStrBuf *strbuf, gsize pos, gssize len, gboolean honor_do_bzero_mem)
-{
-    gsize new_len;
-
-    _nm_str_buf_assert(strbuf);
-
-    nm_assert(pos <= strbuf->_priv_len);
-
-    if (len == 0)
-        return;
-
-    if (len < 0) {
-        /* truncate the string before pos */
-        nm_assert(len == -1);
-        new_len = pos;
-    } else {
-        gsize l = len;
-
-        nm_assert(l <= strbuf->_priv_len - pos);
-
-        new_len = strbuf->_priv_len - l;
-        if (pos + l < strbuf->_priv_len) {
-            memmove(&strbuf->_priv_str[pos],
-                    &strbuf->_priv_str[pos + l],
-                    strbuf->_priv_len - (pos + l));
-        }
-    }
-
-    nm_assert(new_len <= strbuf->_priv_len);
-    nm_str_buf_set_size(strbuf, new_len, honor_do_bzero_mem, TRUE);
-}
-
-/*****************************************************************************/
-
-static inline void
-nm_str_buf_append_c_repeated(NMStrBuf *strbuf, char ch, guint len)
-{
-    if (len > 0) {
-        nm_str_buf_maybe_expand(strbuf, len + 1, FALSE);
-        do {
-            strbuf->_priv_str[strbuf->_priv_len++] = ch;
-        } while (--len > 0);
-    }
-}
-
-static inline void
-nm_str_buf_append_c(NMStrBuf *strbuf, char ch)
-{
-    nm_str_buf_maybe_expand(strbuf, 2, FALSE);
-    strbuf->_priv_str[strbuf->_priv_len++] = ch;
-}
-
-static inline void
-nm_str_buf_append_c2(NMStrBuf *strbuf, char ch0, char ch1)
-{
-    nm_str_buf_maybe_expand(strbuf, 3, FALSE);
-    strbuf->_priv_str[strbuf->_priv_len++] = ch0;
-    strbuf->_priv_str[strbuf->_priv_len++] = ch1;
-}
-
-static inline void
-nm_str_buf_append_c4(NMStrBuf *strbuf, char ch0, char ch1, char ch2, char ch3)
-{
-    nm_str_buf_maybe_expand(strbuf, 5, FALSE);
-    strbuf->_priv_str[strbuf->_priv_len++] = ch0;
-    strbuf->_priv_str[strbuf->_priv_len++] = ch1;
-    strbuf->_priv_str[strbuf->_priv_len++] = ch2;
-    strbuf->_priv_str[strbuf->_priv_len++] = ch3;
-}
-
-static inline void
-nm_str_buf_append_c_hex(NMStrBuf *strbuf, char ch, gboolean upper_case)
-{
-    nm_str_buf_maybe_expand(strbuf, 3, FALSE);
-    strbuf->_priv_str[strbuf->_priv_len++] = nm_hexchar(((guchar) ch) >> 4, upper_case);
-    strbuf->_priv_str[strbuf->_priv_len++] = nm_hexchar((guchar) ch, upper_case);
-}
-
-static inline void
-nm_str_buf_append_len(NMStrBuf *strbuf, const char *str, gsize len)
-{
-    _nm_str_buf_assert(strbuf);
-
-    if (len > 0) {
-        nm_str_buf_maybe_expand(strbuf, len + 1, FALSE);
-        memcpy(&strbuf->_priv_str[strbuf->_priv_len], str, len);
-        strbuf->_priv_len += len;
-    }
-}
-
-static inline char *
-nm_str_buf_append_len0(NMStrBuf *strbuf, const char *str, gsize len)
-{
-    _nm_str_buf_assert(strbuf);
-
-    /* this is basically like nm_str_buf_append_len() and
-     * nm_str_buf_get_str() in one. */
-
-    nm_str_buf_maybe_expand(strbuf, len + 1u, FALSE);
-    if (len > 0) {
-        memcpy(&strbuf->_priv_str[strbuf->_priv_len], str, len);
-        strbuf->_priv_len += len;
-    }
-    strbuf->_priv_str[strbuf->_priv_len] = '\0';
-    return strbuf->_priv_str;
-}
-
-static inline void
-nm_str_buf_append(NMStrBuf *strbuf, const char *str)
-{
-    nm_assert(str);
-
-    nm_str_buf_append_len(strbuf, str, strlen(str));
-}
-
-static inline char *
-nm_str_buf_append0(NMStrBuf *strbuf, const char *str)
-{
-    nm_assert(str);
-
-    return nm_str_buf_append_len0(strbuf, str, strlen(str));
-}
-
-void nm_str_buf_append_printf(NMStrBuf *strbuf, const char *format, ...) _nm_printf(2, 3);
-
-static inline void
-nm_str_buf_ensure_trailing_c(NMStrBuf *strbuf, char ch)
-{
-    _nm_str_buf_assert(strbuf);
-
-    if (strbuf->_priv_len == 0 || strbuf->_priv_str[strbuf->_priv_len - 1] != ch)
-        nm_str_buf_append_c(strbuf, ch);
-}
-
-static inline NMStrBuf *
-nm_str_buf_append_required_delimiter(NMStrBuf *strbuf, char delimiter)
-{
-    _nm_str_buf_assert(strbuf);
-
-    /* appends the @delimiter if it is required (that is, if the
-     * string is not empty). */
-    if (strbuf->len > 0)
-        nm_str_buf_append_c(strbuf, delimiter);
-    return strbuf;
-}
-
-static inline void
-nm_str_buf_append_dirty(NMStrBuf *strbuf, gsize len)
-{
-    _nm_str_buf_assert(strbuf);
-
-    /* this append @len bytes to the buffer, but it does not
-     * initialize them! */
-    if (len > 0) {
-        nm_str_buf_maybe_expand(strbuf, len, FALSE);
-        strbuf->_priv_len += len;
-    }
-}
-
-static inline void
-nm_str_buf_append_c_len(NMStrBuf *strbuf, char ch, gsize len)
-{
-    _nm_str_buf_assert(strbuf);
-
-    if (len > 0) {
-        nm_str_buf_maybe_expand(strbuf, len, FALSE);
-        memset(&strbuf->_priv_str[strbuf->_priv_len], ch, len);
-        strbuf->_priv_len += len;
-    }
-}
-
-/*****************************************************************************/
-
-static inline NMStrBuf *
-nm_str_buf_reset(NMStrBuf *strbuf)
-{
-    _nm_str_buf_assert(strbuf);
-
-    if (strbuf->_priv_len > 0) {
-        if (strbuf->_priv_do_bzero_mem) {
-            /* we only clear the memory that we wrote to. */
-            nm_explicit_bzero(strbuf->_priv_str, strbuf->_priv_len);
-        }
-        strbuf->_priv_len = 0;
-    }
-
-    return strbuf;
-}
-
-/*****************************************************************************/
-
-/* Calls nm_utils_escaped_tokens_escape() on @str and appends the
- * result to @strbuf. */
-static inline void
-nm_utils_escaped_tokens_escape_strbuf(const char *str, const char *delimiters, NMStrBuf *strbuf)
-{
-    gs_free char *str_to_free = NULL;
-
-    nm_assert(str);
-
-    nm_str_buf_append(strbuf, nm_utils_escaped_tokens_escape(str, delimiters, &str_to_free));
-}
-
-/* Calls nm_utils_escaped_tokens_escape_unnecessary() on @str and appends the
- * string to @strbuf. */
-static inline void
-nm_utils_escaped_tokens_escape_strbuf_assert(const char *str,
-                                             const char *delimiters,
-                                             NMStrBuf *  strbuf)
-{
-    nm_str_buf_append(strbuf, nm_utils_escaped_tokens_escape_unnecessary(str, delimiters));
-}
-
-/*****************************************************************************/
-
-static inline gboolean
-nm_str_buf_is_initalized(NMStrBuf *strbuf)
-{
-    nm_assert(strbuf);
-#if NM_MORE_ASSERTS
-    if (strbuf->_priv_str)
-        _nm_str_buf_assert(strbuf);
-#endif
-    return !!strbuf->_priv_str;
-}
-
-/**
- * nm_str_buf_get_str:
- * @strbuf: the #NMStrBuf instance
- *
- * Returns the NUL terminated internal string.
- *
- * While constructing the string, the intermediate buffer
- * is not NUL terminated (this makes it different from GString).
- * Usually, one would build the string and retrieve it at the
- * end with nm_str_buf_finalize(). This returns the NUL terminated
- * buffer that was appended so far. Contrary to nm_str_buf_finalize(), you
- * can still append more data to the buffer and this does not transfer ownership
- * of the string.
- *
- * Returns: (transfer none): the internal string. The string
- *   is of length "strbuf->len", which may be larger if the
- *   returned string contains NUL characters (binary). The terminating
- *   NUL character is always present after "strbuf->len" characters.
- *   If currently no buffer is allocated, this will return %NULL.
- */
-static inline char *
-nm_str_buf_get_str(NMStrBuf *strbuf)
-{
-    _nm_str_buf_assert(strbuf);
-
-    if (!strbuf->_priv_str)
-        return NULL;
-
-    nm_str_buf_maybe_expand(strbuf, 1, FALSE);
-    strbuf->_priv_str[strbuf->_priv_len] = '\0';
-    return strbuf->_priv_str;
-}
-
-static inline char *
-nm_str_buf_get_str_unsafe(NMStrBuf *strbuf)
-{
-    _nm_str_buf_assert(strbuf);
-    return strbuf->_priv_str;
-}
-
-static inline char *
-nm_str_buf_get_str_at_unsafe(NMStrBuf *strbuf, gsize index)
-{
-    _nm_str_buf_assert(strbuf);
-
-    /* it is acceptable to ask for a pointer at the end of the buffer -- even
-     * if there is no data there. The caller is anyway required to take care
-     * of the length (that's the "unsafe" part), and in that case, the length
-     * is merely zero. */
-    nm_assert(index <= strbuf->allocated);
-
-    if (!strbuf->_priv_str)
-        return NULL;
-
-    return &strbuf->_priv_str[index];
-}
-
-static inline char
-nm_str_buf_get_char(const NMStrBuf *strbuf, gsize index)
-{
-    _nm_str_buf_assert(strbuf);
-    nm_assert(index < strbuf->allocated);
-    return strbuf->_priv_str[index];
-}
-
-/**
- * nm_str_buf_finalize:
- * @strbuf: an initilized #NMStrBuf
- * @out_len: (out): (allow-none): optional output
- *   argument with the length of the returned string.
- *
- * Returns: (transfer full): the string of the buffer
- *   which must be freed by the caller. The @strbuf
- *   is afterwards in undefined state, though it can be
- *   reused after nm_str_buf_init().
- *   Note that if no string is allocated yet (after nm_str_buf_init() with
- *   length zero), this will return %NULL. */
-static inline char *
-nm_str_buf_finalize(NMStrBuf *strbuf, gsize *out_len)
-{
-    _nm_str_buf_assert(strbuf);
-
-    NM_SET_OUT(out_len, strbuf->_priv_len);
-
-    if (!strbuf->_priv_str)
-        return NULL;
-
-    nm_str_buf_maybe_expand(strbuf, 1, TRUE);
-    strbuf->_priv_str[strbuf->_priv_len] = '\0';
-
-    /* the buffer is in invalid state afterwards, however, we clear it
-     * so far, that nm_auto_str_buf and nm_str_buf_destroy() is happy.  */
-    return g_steal_pointer(&strbuf->_priv_str);
-}
-
-static inline GBytes *
-nm_str_buf_finalize_to_gbytes(NMStrBuf *strbuf)
-{
-    char *s;
-    gsize l;
-
-    /* this always returns a non-NULL, newly allocated GBytes instance.
-     * The data buffer always has an additional NUL character after
-     * the data, and the data is allocated with malloc.
-     *
-     * That means, the caller who takes ownership of the GBytes can
-     * safely modify the content of the buffer (including the additional
-     * NUL sentinel). */
-    s = nm_str_buf_finalize(strbuf, &l);
-    return g_bytes_new_take(s ?: g_new0(char, 1), l);
-}
-
-/**
- * nm_str_buf_destroy:
- * @strbuf: an initialized #NMStrBuf
- *
- * Frees the associated memory of @strbuf. The buffer
- * afterwards is in undefined state, but can be re-initialized
- * with nm_str_buf_init().
- */
-static inline void
-nm_str_buf_destroy(NMStrBuf *strbuf)
-{
-    if (!strbuf->_priv_str)
-        return;
-    _nm_str_buf_assert(strbuf);
-    if (strbuf->_priv_do_bzero_mem)
-        nm_explicit_bzero(strbuf->_priv_str, strbuf->_priv_len);
-    g_free(strbuf->_priv_str);
-
-    /* the buffer is in invalid state afterwards, however, we clear it
-     * so far, that nm_auto_str_buf is happy when calling
-     * nm_str_buf_destroy() again.  */
-    strbuf->_priv_str = NULL;
-}
-
-#define nm_auto_str_buf nm_auto(nm_str_buf_destroy)
-
-#endif /* __NM_STR_BUF_H__ */
diff --git a/shared/nm-glib-aux/nm-time-utils.c b/shared/nm-glib-aux/nm-time-utils.c
deleted file mode 100644
index df98176a..00000000
--- a/shared/nm-glib-aux/nm-time-utils.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-time-utils.h"
-
-#include "nm-logging-fwd.h"
-
-/*****************************************************************************/
-
-typedef struct {
-    /* the offset to the native clock, in seconds. */
-    gint64    offset_sec;
-    clockid_t clk_id;
-} GlobalState;
-
-static const GlobalState *volatile p_global_state;
-
-static const GlobalState *
-_t_init_global_state(void)
-{
-    static GlobalState global_state = {};
-    static gsize       init_once    = 0;
-    const GlobalState *p;
-    clockid_t          clk_id;
-    struct timespec    tp;
-    gint64             offset_sec;
-    int                r;
-
-    clk_id = CLOCK_BOOTTIME;
-    r      = clock_gettime(clk_id, &tp);
-    if (r == -1 && errno == EINVAL) {
-        clk_id = CLOCK_MONOTONIC;
-        r      = clock_gettime(clk_id, &tp);
-    }
-
-    /* The only failure we tolerate is that CLOCK_BOOTTIME is not supported.
-     * Other than that, we rely on kernel to not fail on this. */
-    g_assert(r == 0);
-    g_assert(tp.tv_nsec >= 0 && tp.tv_nsec < NM_UTILS_NSEC_PER_SEC);
-
-    /* Calculate an offset for the time stamp.
-     *
-     * We always want positive values, because then we can initialize
-     * a timestamp with 0 and be sure, that it will be less then any
-     * value nm_utils_get_monotonic_timestamp_*() might return.
-     * For this to be true also for nm_utils_get_monotonic_timestamp_sec() at
-     * early boot, we have to shift the timestamp to start counting at
-     * least from 1 second onward.
-     *
-     * Another advantage of shifting is, that this way we make use of the whole 31 bit
-     * range of signed int, before the time stamp for nm_utils_get_monotonic_timestamp_sec()
-     * wraps (~68 years).
-     **/
-    offset_sec = (-((gint64) tp.tv_sec)) + 1;
-
-    if (!g_once_init_enter(&init_once)) {
-        /* there was a race. We expect the pointer to be fully initialized now. */
-        p = g_atomic_pointer_get(&p_global_state);
-        g_assert(p);
-        return p;
-    }
-
-    global_state.offset_sec = offset_sec;
-    global_state.clk_id     = clk_id;
-    p                       = &global_state;
-    g_atomic_pointer_set(&p_global_state, p);
-    g_once_init_leave(&init_once, 1);
-
-    _nm_utils_monotonic_timestamp_initialized(&tp, p->offset_sec, p->clk_id == CLOCK_BOOTTIME);
-
-    return p;
-}
-
-#define _t_get_global_state()                         \
-    ({                                                \
-        const GlobalState *_p;                        \
-                                                      \
-        _p = g_atomic_pointer_get(&p_global_state);   \
-        (G_LIKELY(_p) ? _p : _t_init_global_state()); \
-    })
-
-#define _t_clock_gettime_eval(p, tp)                                          \
-    ({                                                                        \
-        struct timespec *const   _tp = (tp);                                  \
-        const GlobalState *const _p2 = (p);                                   \
-        int                      _r;                                          \
-                                                                              \
-        nm_assert(_tp);                                                       \
-                                                                              \
-        _r = clock_gettime(_p2->clk_id, _tp);                                 \
-                                                                              \
-        nm_assert(_r == 0);                                                   \
-        nm_assert(_tp->tv_nsec >= 0 && _tp->tv_nsec < NM_UTILS_NSEC_PER_SEC); \
-                                                                              \
-        _p2;                                                                  \
-    })
-
-#define _t_clock_gettime(tp) _t_clock_gettime_eval(_t_get_global_state(), tp);
-
-/*****************************************************************************/
-
-/**
- * nm_utils_get_monotonic_timestamp_nsec:
- *
- * Returns: a monotonically increasing time stamp in nanoseconds,
- * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME.
- *
- * The returned value will start counting at an undefined point
- * in the past and will always be positive.
- *
- * All the nm_utils_get_monotonic_timestamp_*sec functions return the same
- * timestamp but in different scales (nsec, usec, msec, sec).
- **/
-gint64
-nm_utils_get_monotonic_timestamp_nsec(void)
-{
-    const GlobalState *p;
-    struct timespec    tp;
-
-    p = _t_clock_gettime(&tp);
-
-    /* Although the result will always be positive, we return a signed
-     * integer, which makes it easier to calculate time differences (when
-     * you want to subtract signed values).
-     **/
-    return (((gint64) tp.tv_sec) + p->offset_sec) * NM_UTILS_NSEC_PER_SEC + tp.tv_nsec;
-}
-
-/**
- * nm_utils_get_monotonic_timestamp_usec:
- *
- * Returns: a monotonically increasing time stamp in microseconds,
- * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME.
- *
- * The returned value will start counting at an undefined point
- * in the past and will always be positive.
- *
- * All the nm_utils_get_monotonic_timestamp_*sec functions return the same
- * timestamp but in different scales (nsec, usec, msec, sec).
- **/
-gint64
-nm_utils_get_monotonic_timestamp_usec(void)
-{
-    const GlobalState *p;
-    struct timespec    tp;
-
-    p = _t_clock_gettime(&tp);
-
-    /* Although the result will always be positive, we return a signed
-     * integer, which makes it easier to calculate time differences (when
-     * you want to subtract signed values).
-     **/
-    return (((gint64) tp.tv_sec) + p->offset_sec) * ((gint64) G_USEC_PER_SEC)
-           + (tp.tv_nsec / (NM_UTILS_NSEC_PER_SEC / G_USEC_PER_SEC));
-}
-
-/**
- * nm_utils_get_monotonic_timestamp_msec:
- *
- * Returns: a monotonically increasing time stamp in milliseconds,
- * starting at an unspecified offset. See clock_gettime(), %CLOCK_BOOTTIME.
- *
- * The returned value will start counting at an undefined point
- * in the past and will always be positive.
- *
- * All the nm_utils_get_monotonic_timestamp_*sec functions return the same
- * timestamp but in different scales (nsec, usec, msec, sec).
- **/
-gint64
-nm_utils_get_monotonic_timestamp_msec(void)
-{
-    const GlobalState *p;
-    struct timespec    tp;
-
-    p = _t_clock_gettime(&tp);
-
-    /* Although the result will always be positive, we return a signed
-     * integer, which makes it easier to calculate time differences (when
-     * you want to subtract signed values).
-     **/
-    return (((gint64) tp.tv_sec) + p->offset_sec) * ((gint64) 1000)
-           + (tp.tv_nsec / (NM_UTILS_NSEC_PER_SEC / 1000));
-}
-
-/**
- * nm_utils_get_monotonic_timestamp_sec:
- *
- * Returns: nm_utils_get_monotonic_timestamp_msec() in seconds (throwing
- * away sub second parts). The returned value will always be positive.
- *
- * This value wraps after roughly 68 years which should be fine for any
- * practical purpose.
- *
- * All the nm_utils_get_monotonic_timestamp_*sec functions return the same
- * timestamp but in different scales (nsec, usec, msec, sec).
- **/
-gint32
-nm_utils_get_monotonic_timestamp_sec(void)
-{
-    const GlobalState *p;
-    struct timespec    tp;
-
-    p = _t_clock_gettime(&tp);
-
-    return (((gint64) tp.tv_sec) + p->offset_sec);
-}
-
-/**
- * nm_utils_monotonic_timestamp_as_boottime:
- * @timestamp: the monotonic-timestamp that should be converted into CLOCK_BOOTTIME.
- * @timestamp_nsec_per_tick: How many nanoseconds make one unit of @timestamp? E.g. if
- *   @timestamp is in unit seconds, pass %NM_UTILS_NSEC_PER_SEC; if @timestamp is
- *   in nanoseconds, pass 1; if @timestamp is in milliseconds, pass %NM_UTILS_NSEC_PER_SEC/1000.
- *   This must be a multiple of 10, and between 1 and %NM_UTILS_NSEC_PER_SEC.
- *
- * Returns: the monotonic-timestamp as CLOCK_BOOTTIME, as returned by clock_gettime().
- *   The unit is the same as the passed in @timestamp based on @timestamp_nsec_per_tick.
- *   E.g. if you passed @timestamp in as seconds, it will return boottime in seconds.
- *
- *   Note that valid monotonic-timestamps are always positive numbers (counting roughly since
- *   the application is running). However, it might make sense to calculate a timestamp from
- *   before the application was running, hence negative @timestamp is allowed. The result
- *   in that case might also be a negative timestamp (in CLOCK_BOOTTIME), which would indicate
- *   that the timestamp lies in the past before the machine was booted.
- *
- * On older kernels that don't support CLOCK_BOOTTIME, the returned time is instead CLOCK_MONOTONIC.
- **/
-gint64
-nm_utils_monotonic_timestamp_as_boottime(gint64 timestamp, gint64 timestamp_nsec_per_tick)
-{
-    const GlobalState *p;
-    gint64             offset;
-
-    /* only support nsec-per-tick being a multiple of 10. */
-    g_return_val_if_fail(timestamp_nsec_per_tick == 1
-                             || (timestamp_nsec_per_tick > 0
-                                 && timestamp_nsec_per_tick <= NM_UTILS_NSEC_PER_SEC
-                                 && timestamp_nsec_per_tick % 10 == 0),
-                         -1);
-
-    /* if the caller didn't yet ever fetch a monotonic-timestamp, he cannot pass any meaningful
-     * value (because he has no idea what these timestamps would be). That would be a bug. */
-    nm_assert(g_atomic_pointer_get(&p_global_state));
-
-    p = _t_get_global_state();
-
-    nm_assert(p->offset_sec <= 0);
-
-    /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */
-    offset = p->offset_sec * (NM_UTILS_NSEC_PER_SEC / timestamp_nsec_per_tick);
-
-    nm_assert(offset <= 0 && offset > G_MININT64);
-
-    /* check for overflow (note that offset is non-positive). */
-    g_return_val_if_fail(timestamp < G_MAXINT64 + offset, G_MAXINT64);
-
-    return timestamp - offset;
-}
-
-/**
- * nm_utils_monotonic_timestamp_from_boottime:
- * @boottime: the timestamp from CLOCK_BOOTTIME (or CLOCK_MONOTONIC, if
- *   kernel does not support CLOCK_BOOTTIME and monotonic timestamps are based
- *   on CLOCK_MONOTONIC).
- * @timestamp_nsec_per_tick: the scale in which @boottime is. If @boottime is in
- *   nano seconds, this should be 1. If it is in milli seconds, this should be
- *   %NM_UTILS_NSEC_PER_SEC/1000, etc.
- *
- * Returns: the same timestamp in monotonic timestamp scale.
- *
- * Note that commonly monotonic timestamps are positive. But they may not
- * be positive in this case. That's when boottime is taken from a time before
- * the monotonic timestamps started counting. So, that means a zero or negative
- * value is still a valid timestamp.
- *
- * This is the inverse of nm_utils_monotonic_timestamp_as_boottime().
- */
-gint64
-nm_utils_monotonic_timestamp_from_boottime(guint64 boottime, gint64 timestamp_nsec_per_tick)
-{
-    const GlobalState *p;
-    gint64             offset;
-
-    /* only support nsec-per-tick being a multiple of 10. */
-    g_return_val_if_fail(timestamp_nsec_per_tick == 1
-                             || (timestamp_nsec_per_tick > 0
-                                 && timestamp_nsec_per_tick <= NM_UTILS_NSEC_PER_SEC
-                                 && timestamp_nsec_per_tick % 10 == 0),
-                         -1);
-
-    p = _t_get_global_state();
-
-    nm_assert(p->offset_sec <= 0);
-
-    /* calculate the offset of monotonic-timestamp to boottime. offset_s is <= 1. */
-    offset = p->offset_sec * (NM_UTILS_NSEC_PER_SEC / timestamp_nsec_per_tick);
-
-    nm_assert(offset <= 0 && offset > G_MININT64);
-
-    /* check for overflow (note that offset is non-positive). */
-    g_return_val_if_fail(boottime < G_MAXINT64, G_MAXINT64);
-
-    return (gint64) boottime + offset;
-}
-
-gint64
-nm_utils_clock_gettime_nsec(clockid_t clockid)
-{
-    struct timespec tp;
-
-    if (clock_gettime(clockid, &tp) != 0)
-        return -NM_ERRNO_NATIVE(errno);
-    return nm_utils_timespec_to_nsec(&tp);
-}
-
-gint64
-nm_utils_clock_gettime_msec(clockid_t clockid)
-{
-    struct timespec tp;
-
-    if (clock_gettime(clockid, &tp) != 0)
-        return -NM_ERRNO_NATIVE(errno);
-    return nm_utils_timespec_to_msec(&tp);
-}
diff --git a/shared/nm-glib-aux/nm-time-utils.h b/shared/nm-glib-aux/nm-time-utils.h
deleted file mode 100644
index 3c3e935f..00000000
--- a/shared/nm-glib-aux/nm-time-utils.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_TIME_UTILS_H__
-#define __NM_TIME_UTILS_H__
-
-#include <time.h>
-
-static inline gint64
-nm_utils_timespec_to_nsec(const struct timespec *ts)
-{
-    return (((gint64) ts->tv_sec) * ((gint64) NM_UTILS_NSEC_PER_SEC)) + ((gint64) ts->tv_nsec);
-}
-
-static inline gint64
-nm_utils_timespec_to_msec(const struct timespec *ts)
-{
-    return (((gint64) ts->tv_sec) * ((gint64) 1000))
-           + (((gint64) ts->tv_nsec) / ((gint64) NM_UTILS_NSEC_PER_SEC / 1000));
-}
-
-gint64 nm_utils_get_monotonic_timestamp_nsec(void);
-gint64 nm_utils_get_monotonic_timestamp_usec(void);
-gint64 nm_utils_get_monotonic_timestamp_msec(void);
-gint32 nm_utils_get_monotonic_timestamp_sec(void);
-
-gint64 nm_utils_monotonic_timestamp_as_boottime(gint64 timestamp, gint64 timestamp_ticks_per_nsec);
-gint64 nm_utils_monotonic_timestamp_from_boottime(guint64 boottime, gint64 timestamp_nsec_per_tick);
-
-static inline gint64
-nm_utils_get_monotonic_timestamp_nsec_cached(gint64 *cache_now)
-{
-    return (*cache_now) ?: (*cache_now = nm_utils_get_monotonic_timestamp_nsec());
-}
-
-static inline gint64
-nm_utils_get_monotonic_timestamp_msec_cached(gint64 *cache_now)
-{
-    return (*cache_now) ?: (*cache_now = nm_utils_get_monotonic_timestamp_msec());
-}
-
-gint64 nm_utils_clock_gettime_nsec(clockid_t clockid);
-gint64 nm_utils_clock_gettime_msec(clockid_t clockid);
-
-#endif /* __NM_TIME_UTILS_H__ */
diff --git a/shared/nm-glib-aux/nm-value-type.h b/shared/nm-glib-aux/nm-value-type.h
deleted file mode 100644
index f9edebdb..00000000
--- a/shared/nm-glib-aux/nm-value-type.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019 Red Hat, Inc.
- */
-
-#ifndef __NM_VALUE_TYPE_H__
-#define __NM_VALUE_TYPE_H__
-
-typedef enum {
-    NM_VALUE_TYPE_UNSPEC = 1,
-    NM_VALUE_TYPE_BOOL   = 2,
-    NM_VALUE_TYPE_INT32  = 3,
-    NM_VALUE_TYPE_INT    = 4,
-    NM_VALUE_TYPE_STRING = 5,
-} NMValueType;
-
-/*****************************************************************************/
-
-#ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS
-
-typedef union {
-    bool        v_bool;
-    gint32      v_int32;
-    int         v_int;
-    const char *v_string;
-
-    /* for convenience, also let the union contain other pointer types. These are
-     * for NM_VALUE_TYPE_UNSPEC. */
-    gconstpointer *  v_ptr;
-    const GPtrArray *v_ptrarray;
-
-} NMValueTypUnion;
-
-    /* Set the NMValueTypUnion. You can also assign the member directly.
- * The only purpose of this is that it also returns a pointer to the
- * union. So, you can do
- *
- *   ptr = NM_VALUE_TYP_UNION_SET (&value_typ_union_storage, v_bool, TRUE);
- */
-    #define NM_VALUE_TYP_UNION_SET(_arg, _type, _val) \
-        ({                                            \
-            NMValueTypUnion *const _arg2 = (_arg);    \
-                                                      \
-            *_arg2 = (NMValueTypUnion){               \
-                ._type = (_val),                      \
-            };                                        \
-            _arg2;                                    \
-        })
-
-typedef struct {
-    bool            has;
-    NMValueTypUnion val;
-} NMValueTypUnioMaybe;
-
-    #define NM_VALUE_TYP_UNIO_MAYBE_SET(_arg, _type, _val) \
-        ({                                                 \
-            NMValueTypUnioMaybe *const _arg2 = (_arg);     \
-                                                           \
-            *_arg2 = (NMValueTypUnioMaybe){                \
-                .has       = TRUE,                         \
-                .val._type = (_val),                       \
-            };                                             \
-            _arg2;                                         \
-        })
-
-/*****************************************************************************/
-
-static inline int
-nm_value_type_cmp(NMValueType value_type, gconstpointer p_a, gconstpointer p_b)
-{
-    switch (value_type) {
-    case NM_VALUE_TYPE_BOOL:
-        NM_CMP_DIRECT(*((const bool *) p_a), *((const bool *) p_b));
-        return 0;
-    case NM_VALUE_TYPE_INT32:
-        NM_CMP_DIRECT(*((const gint32 *) p_a), *((const gint32 *) p_b));
-        return 0;
-    case NM_VALUE_TYPE_INT:
-        NM_CMP_DIRECT(*((const int *) p_a), *((const int *) p_b));
-        return 0;
-    case NM_VALUE_TYPE_STRING:
-        return nm_strcmp0(*((const char *const *) p_a), *((const char *const *) p_b));
-    case NM_VALUE_TYPE_UNSPEC:
-        break;
-    }
-    nm_assert_not_reached();
-    return 0;
-}
-
-static inline gboolean
-nm_value_type_equal(NMValueType value_type, gconstpointer p_a, gconstpointer p_b)
-{
-    return nm_value_type_cmp(value_type, p_a, p_b) == 0;
-}
-
-static inline void
-nm_value_type_copy(NMValueType value_type, gpointer dst, gconstpointer src)
-{
-    switch (value_type) {
-    case NM_VALUE_TYPE_BOOL:
-        (*((bool *) dst) = *((const bool *) src));
-        return;
-    case NM_VALUE_TYPE_INT32:
-        (*((gint32 *) dst) = *((const gint32 *) src));
-        return;
-    case NM_VALUE_TYPE_INT:
-        (*((int *) dst) = *((const int *) src));
-        return;
-    case NM_VALUE_TYPE_STRING:
-        /* self assignment safe! */
-        if (*((char **) dst) != *((const char *const *) src)) {
-            g_free(*((char **) dst));
-            *((char **) dst) = g_strdup(*((const char *const *) src));
-        }
-        return;
-    case NM_VALUE_TYPE_UNSPEC:
-        break;
-    }
-    nm_assert_not_reached();
-}
-
-static inline void
-nm_value_type_get_from_variant(NMValueType value_type,
-                               gpointer    dst,
-                               GVariant *  variant,
-                               gboolean    clone)
-{
-    switch (value_type) {
-    case NM_VALUE_TYPE_BOOL:
-        *((bool *) dst) = g_variant_get_boolean(variant);
-        return;
-    case NM_VALUE_TYPE_INT32:
-        *((gint32 *) dst) = g_variant_get_int32(variant);
-        return;
-    case NM_VALUE_TYPE_STRING:
-        if (clone) {
-            g_free(*((char **) dst));
-            *((char **) dst) = g_variant_dup_string(variant, NULL);
-        } else {
-            /* we don't clone the string, nor free the previous value. */
-            *((const char **) dst) = g_variant_get_string(variant, NULL);
-        }
-        return;
-
-    case NM_VALUE_TYPE_INT:
-        /* "int" also does not have a define variant type, because it's not
-         * clear how many bits we would need. */
-
-        /* fall-through */
-    case NM_VALUE_TYPE_UNSPEC:
-        break;
-    }
-    nm_assert_not_reached();
-}
-
-static inline GVariant *
-nm_value_type_to_variant(NMValueType value_type, gconstpointer src)
-{
-    const char *v_string;
-
-    switch (value_type) {
-    case NM_VALUE_TYPE_BOOL:
-        return g_variant_new_boolean(*((const bool *) src));
-    case NM_VALUE_TYPE_INT32:
-        return g_variant_new_int32(*((const gint32 *) src));
-    case NM_VALUE_TYPE_STRING:
-        v_string = *((const char *const *) src);
-        return v_string ? g_variant_new_string(v_string) : NULL;
-
-    case NM_VALUE_TYPE_INT:
-        /* "int" also does not have a define variant type, because it's not
-         * clear how many bits we would need. */
-
-        /* fall-through */
-    case NM_VALUE_TYPE_UNSPEC:
-        break;
-    }
-    nm_assert_not_reached();
-    return NULL;
-}
-
-static inline const GVariantType *
-nm_value_type_get_variant_type(NMValueType value_type)
-{
-    switch (value_type) {
-    case NM_VALUE_TYPE_BOOL:
-        return G_VARIANT_TYPE_BOOLEAN;
-    case NM_VALUE_TYPE_INT32:
-        return G_VARIANT_TYPE_INT32;
-    case NM_VALUE_TYPE_STRING:
-        return G_VARIANT_TYPE_STRING;
-
-    case NM_VALUE_TYPE_INT:
-        /* "int" also does not have a define variant type, because it's not
-         * clear how many bits we would need. */
-
-        /* fall-through */
-    case NM_VALUE_TYPE_UNSPEC:
-        break;
-    }
-    nm_assert_not_reached();
-    return NULL;
-}
-
-    /*****************************************************************************/
-
-#endif /* NM_VALUE_TYPE_DEFINE_FUNCTIONS */
-
-#endif /* __NM_VALUE_TYPE_H__ */
diff --git a/shared/nm-glib-aux/tests/meson.build b/shared/nm-glib-aux/tests/meson.build
deleted file mode 100644
index 464f4e7c..00000000
--- a/shared/nm-glib-aux/tests/meson.build
+++ /dev/null
@@ -1,41 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-
-exe = executable(
-  'test-shared-general',
-  'test-shared-general.c',
-  c_args: [
-    '-DG_LOG_DOMAIN="test"',
-  ],
-  dependencies: libnm_glib_aux_dep,
-  link_with: libnm_systemd_logging_stub,
-)
-
-test(
-  'shared/nm-glib-aux/test-shared-general',
-  test_script,
-  args: test_args + [exe.full_path()],
-  timeout: default_test_timeout,
-)
-
-if jansson_dep.found()
-  exe = executable(
-    'test-json-aux',
-    'test-json-aux.c',
-    c_args: [
-      '-DG_LOG_DOMAIN="test"',
-    ],
-    dependencies: [
-      libnm_glib_aux_dep,
-      jansson_dep,
-      dl_dep,
-    ],
-    link_with: libnm_systemd_logging_stub,
-  )
-
-  test(
-    'shared/nm-glib-aux/test-json-aux',
-    test_script,
-    args: test_args + [exe.full_path()],
-    timeout: default_test_timeout,
-  )
-endif
diff --git a/shared/nm-glib-aux/tests/test-json-aux.c b/shared/nm-glib-aux/tests/test-json-aux.c
deleted file mode 100644
index b07d673f..00000000
--- a/shared/nm-glib-aux/tests/test-json-aux.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-glib-aux/nm-default-glib-i18n-prog.h"
-
-#include <jansson.h>
-
-#include "nm-glib-aux/nm-json-aux.h"
-
-#include "nm-utils/nm-test-utils.h"
-
-/*****************************************************************************/
-
-static void
-test_jansson(void)
-{
-    const NMJsonVt *    vt;
-    nm_auto_decref_json nm_json_t *js1 = NULL;
-    nm_auto_decref_json nm_json_t *js2 = NULL;
-
-#define _ASSERT_FIELD(type1, type2, field)                                                        \
-    G_STMT_START                                                                                  \
-    {                                                                                             \
-        G_STATIC_ASSERT_EXPR(sizeof(((type1 *) NULL)->field) == sizeof(((type2 *) NULL)->field)); \
-        G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(type1, field) == G_STRUCT_OFFSET(type2, field));     \
-    }                                                                                             \
-    G_STMT_END
-
-    G_STATIC_ASSERT_EXPR(NM_JSON_REJECT_DUPLICATES == JSON_REJECT_DUPLICATES);
-
-    G_STATIC_ASSERT_EXPR(sizeof(nm_json_type) == sizeof(json_type));
-
-    G_STATIC_ASSERT_EXPR((int) NM_JSON_OBJECT == JSON_OBJECT);
-    G_STATIC_ASSERT_EXPR((int) NM_JSON_ARRAY == JSON_ARRAY);
-    G_STATIC_ASSERT_EXPR((int) NM_JSON_STRING == JSON_STRING);
-    G_STATIC_ASSERT_EXPR((int) NM_JSON_INTEGER == JSON_INTEGER);
-    G_STATIC_ASSERT_EXPR((int) NM_JSON_REAL == JSON_REAL);
-    G_STATIC_ASSERT_EXPR((int) NM_JSON_TRUE == JSON_TRUE);
-    G_STATIC_ASSERT_EXPR((int) NM_JSON_FALSE == JSON_FALSE);
-    G_STATIC_ASSERT_EXPR((int) NM_JSON_NULL == JSON_NULL);
-
-    G_STATIC_ASSERT_EXPR(sizeof(nm_json_int_t) == sizeof(json_int_t));
-
-    G_STATIC_ASSERT_EXPR(sizeof(nm_json_t) == sizeof(json_t));
-    _ASSERT_FIELD(nm_json_t, json_t, refcount);
-    _ASSERT_FIELD(nm_json_t, json_t, type);
-
-    G_STATIC_ASSERT_EXPR(NM_JSON_ERROR_TEXT_LENGTH == JSON_ERROR_TEXT_LENGTH);
-    G_STATIC_ASSERT_EXPR(NM_JSON_ERROR_SOURCE_LENGTH == JSON_ERROR_SOURCE_LENGTH);
-
-    G_STATIC_ASSERT_EXPR(sizeof(nm_json_error_t) == sizeof(json_error_t));
-    _ASSERT_FIELD(nm_json_error_t, json_error_t, line);
-    _ASSERT_FIELD(nm_json_error_t, json_error_t, column);
-    _ASSERT_FIELD(nm_json_error_t, json_error_t, position);
-    _ASSERT_FIELD(nm_json_error_t, json_error_t, source);
-    _ASSERT_FIELD(nm_json_error_t, json_error_t, text);
-
-    vt = nm_json_vt();
-
-    g_assert(vt);
-    g_assert(vt->loaded);
-
-    js1 = vt->nm_json_loads("{ \"a\": 5 }", 0, NULL);
-    g_assert(js1);
-    nm_json_decref(vt, g_steal_pointer(&js1));
-
-    js2 = vt->nm_json_loads("{ \"a\": 6 }", 0, NULL);
-    g_assert(js2);
-
-#define CHECK_FCN(vt, fcn, nm_type, js_type)             \
-    G_STMT_START                                         \
-    {                                                    \
-        const NMJsonVt *const _vt     = (vt);            \
-        _nm_unused            nm_type = (_vt->nm_##fcn); \
-        _nm_unused            js_type = (fcn);           \
-                                                         \
-        g_assert(_vt->nm_##fcn);                         \
-        g_assert(_f_nm);                                 \
-        g_assert(_f_js);                                 \
-        g_assert(_f_nm == _vt->nm_##fcn);                \
-    }                                                    \
-    G_STMT_END
-
-    CHECK_FCN(vt, json_array, nm_json_t * (*_f_nm)(void), json_t * (*_f_js)(void) );
-    CHECK_FCN(vt,
-              json_array_append_new,
-              int (*_f_nm)(nm_json_t *, nm_json_t *),
-              int (*_f_js)(json_t *, json_t *));
-    CHECK_FCN(vt,
-              json_array_get,
-              nm_json_t * (*_f_nm)(const nm_json_t *, gsize),
-              json_t * (*_f_js)(const json_t *, size_t));
-    CHECK_FCN(vt,
-              json_array_size,
-              gsize(*_f_nm)(const nm_json_t *),
-              size_t(*_f_js)(const json_t *));
-    CHECK_FCN(vt, json_delete, void (*_f_nm)(nm_json_t *), void (*_f_js)(json_t *));
-    CHECK_FCN(vt,
-              json_dumps,
-              char *(*_f_nm)(const nm_json_t *, gsize),
-              char *(*_f_js)(const json_t *, size_t));
-    CHECK_FCN(vt, json_false, nm_json_t * (*_f_nm)(void), json_t * (*_f_js)(void) );
-    CHECK_FCN(vt, json_integer, nm_json_t * (*_f_nm)(nm_json_int_t), json_t * (*_f_js)(json_int_t));
-    CHECK_FCN(vt,
-              json_integer_value,
-              nm_json_int_t(*_f_nm)(const nm_json_t *),
-              json_int_t(*_f_js)(const json_t *));
-    CHECK_FCN(vt,
-              json_loads,
-              nm_json_t * (*_f_nm)(const char *, gsize, nm_json_error_t *),
-              json_t * (*_f_js)(const char *, size_t, json_error_t *) );
-    CHECK_FCN(vt, json_object, nm_json_t * (*_f_nm)(void), json_t * (*_f_js)(void) );
-    CHECK_FCN(vt,
-              json_object_del,
-              int (*_f_nm)(nm_json_t *, const char *),
-              int (*_f_js)(json_t *, const char *));
-    CHECK_FCN(vt,
-              json_object_get,
-              nm_json_t * (*_f_nm)(const nm_json_t *, const char *),
-              json_t * (*_f_js)(const json_t *, const char *) );
-    CHECK_FCN(vt, json_object_iter, void *(*_f_nm)(nm_json_t *), void *(*_f_js)(json_t *) );
-    CHECK_FCN(vt,
-              json_object_iter_key,
-              const char *(*_f_nm)(void *),
-              const char *(*_f_js)(void *) );
-    CHECK_FCN(vt,
-              json_object_iter_next,
-              void *(*_f_nm)(nm_json_t *, void *),
-              void *(*_f_js)(json_t *, void *) );
-    CHECK_FCN(vt, json_object_iter_value, nm_json_t * (*_f_nm)(void *), json_t * (*_f_js)(void *) );
-    CHECK_FCN(vt,
-              json_object_key_to_iter,
-              void *(*_f_nm)(const char *),
-              void *(*_f_js)(const char *) );
-    CHECK_FCN(vt,
-              json_object_set_new,
-              int (*_f_nm)(nm_json_t *, const char *, nm_json_t *),
-              int (*_f_js)(json_t *, const char *, json_t *));
-    CHECK_FCN(vt,
-              json_object_size,
-              gsize(*_f_nm)(const nm_json_t *),
-              size_t(*_f_js)(const json_t *));
-    CHECK_FCN(vt,
-              json_string,
-              nm_json_t * (*_f_nm)(const char *),
-              json_t * (*_f_js)(const char *) );
-    CHECK_FCN(vt,
-              json_string_value,
-              const char *(*_f_nm)(const nm_json_t *),
-              const char *(*_f_js)(const json_t *) );
-    CHECK_FCN(vt, json_true, nm_json_t * (*_f_nm)(void), json_t * (*_f_js)(void) );
-}
-
-/*****************************************************************************/
-
-NMTST_DEFINE();
-
-int
-main(int argc, char **argv)
-{
-    nmtst_init(&argc, &argv, TRUE);
-
-    g_test_add_func("/general/test_jansson", test_jansson);
-
-    return g_test_run();
-}
diff --git a/shared/nm-glib-aux/tests/test-shared-general.c b/shared/nm-glib-aux/tests/test-shared-general.c
deleted file mode 100644
index f42c6fb1..00000000
--- a/shared/nm-glib-aux/tests/test-shared-general.c
+++ /dev/null
@@ -1,1289 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-prog.h"
-
-#include "nm-std-aux/unaligned.h"
-#include "nm-glib-aux/nm-random-utils.h"
-#include "nm-glib-aux/nm-str-buf.h"
-#include "nm-glib-aux/nm-time-utils.h"
-#include "nm-glib-aux/nm-ref-string.h"
-
-#include "nm-utils/nm-test-utils.h"
-
-/*****************************************************************************/
-
-G_STATIC_ASSERT(NM_AF_UNSPEC == AF_UNSPEC);
-G_STATIC_ASSERT(NM_AF_INET == AF_INET);
-G_STATIC_ASSERT(NM_AF_INET6 == AF_INET6);
-
-G_STATIC_ASSERT(NM_AF_INET_SIZE == sizeof(in_addr_t));
-G_STATIC_ASSERT(NM_AF_INET_SIZE == sizeof(struct in_addr));
-G_STATIC_ASSERT(NM_AF_INET6_SIZE == sizeof(struct in6_addr));
-
-G_STATIC_ASSERT(4 == _nm_alignof(in_addr_t));
-G_STATIC_ASSERT(4 == _nm_alignof(struct in_addr));
-G_STATIC_ASSERT(4 == _nm_alignof(struct in6_addr));
-G_STATIC_ASSERT(4 == _nm_alignof(NMIPAddr));
-
-/*****************************************************************************/
-
-static void
-test_gpid(void)
-{
-    const int *int_ptr;
-    GPid       pid = 42;
-
-    /* We redefine G_PID_FORMAT, because it's only available since glib 2.53.5.
-     *
-     * Also, this is the format for GPid, which for glib is always a typedef
-     * for "int". Add a check for that here.
-     *
-     * G_PID_FORMAT is not about pid_t, which might be a smaller int, and which we would
-     * check with SIZEOF_PID_T. */
-    G_STATIC_ASSERT(sizeof(GPid) == sizeof(int));
-
-    g_assert_cmpstr("" G_PID_FORMAT, ==, "i");
-
-    /* check that it's really "int". We will get a compiler warning, if that's not
-     * the case. */
-    int_ptr = &pid;
-    g_assert_cmpint(*int_ptr, ==, 42);
-}
-
-/*****************************************************************************/
-
-static void
-test_monotonic_timestamp(void)
-{
-    g_assert(nm_utils_get_monotonic_timestamp_sec() > 0);
-}
-
-/*****************************************************************************/
-
-static void
-test_nmhash(void)
-{
-    int rnd;
-
-    nm_utils_random_bytes(&rnd, sizeof(rnd));
-
-    g_assert(nm_hash_val(555, 4) != 0);
-}
-
-/*****************************************************************************/
-
-static const char *
-_make_strv_foo(void)
-{
-    return "foo";
-}
-
-static const char *const *const _tst_make_strv_1 = NM_MAKE_STRV("1", "2");
-
-static void
-test_make_strv(void)
-{
-    const char *const *v1a  = NM_MAKE_STRV("a");
-    const char *const *v1b  = NM_MAKE_STRV("a", );
-    const char *const *v2a  = NM_MAKE_STRV("a", "b");
-    const char *const *v2b  = NM_MAKE_STRV("a", "b", );
-    const char *const  v3[] = {
-        "a",
-        "b",
-    };
-    const char *const *v4b = NM_MAKE_STRV("a", _make_strv_foo(), );
-
-    g_assert(NM_PTRARRAY_LEN(v1a) == 1);
-    g_assert(NM_PTRARRAY_LEN(v1b) == 1);
-    g_assert(NM_PTRARRAY_LEN(v2a) == 2);
-    g_assert(NM_PTRARRAY_LEN(v2b) == 2);
-
-    g_assert(NM_PTRARRAY_LEN(_tst_make_strv_1) == 2);
-    g_assert_cmpstr(_tst_make_strv_1[0], ==, "1");
-    g_assert_cmpstr(_tst_make_strv_1[1], ==, "2");
-    /* writing the static read-only variable leads to crash .*/
-    //((char **) _tst_make_strv_1)[0] = NULL;
-    //((char **) _tst_make_strv_1)[2] = "c";
-
-    G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(v3) == 2);
-
-    g_assert(NM_PTRARRAY_LEN(v4b) == 2);
-
-    G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(NM_MAKE_STRV("a", "b")) == 3);
-    G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(NM_MAKE_STRV("a", "b", )) == 3);
-
-    nm_strquote_a(300, "");
-}
-
-/*****************************************************************************/
-
-typedef enum {
-    TEST_NM_STRDUP_ENUM_m1 = -1,
-    TEST_NM_STRDUP_ENUM_3  = 3,
-} TestNMStrdupIntEnum;
-
-static void
-test_nm_strdup_int(void)
-{
-#define _NM_STRDUP_INT_TEST(num, str)  \
-    G_STMT_START                       \
-    {                                  \
-        gs_free char *_s1 = NULL;      \
-                                       \
-        _s1 = nm_strdup_int((num));    \
-                                       \
-        g_assert(_s1);                 \
-        g_assert_cmpstr(_s1, ==, str); \
-    }                                  \
-    G_STMT_END
-
-#define _NM_STRDUP_INT_TEST_TYPED(type, num)         \
-    G_STMT_START                                     \
-    {                                                \
-        type _num = ((type) num);                    \
-                                                     \
-        _NM_STRDUP_INT_TEST(_num, G_STRINGIFY(num)); \
-    }                                                \
-    G_STMT_END
-
-    _NM_STRDUP_INT_TEST_TYPED(char, 0);
-    _NM_STRDUP_INT_TEST_TYPED(char, 1);
-    _NM_STRDUP_INT_TEST_TYPED(guint8, 0);
-    _NM_STRDUP_INT_TEST_TYPED(gint8, 25);
-    _NM_STRDUP_INT_TEST_TYPED(char, 47);
-    _NM_STRDUP_INT_TEST_TYPED(short, 47);
-    _NM_STRDUP_INT_TEST_TYPED(int, 47);
-    _NM_STRDUP_INT_TEST_TYPED(long, 47);
-    _NM_STRDUP_INT_TEST_TYPED(unsigned char, 47);
-    _NM_STRDUP_INT_TEST_TYPED(unsigned short, 47);
-    _NM_STRDUP_INT_TEST_TYPED(unsigned, 47);
-    _NM_STRDUP_INT_TEST_TYPED(unsigned long, 47);
-    _NM_STRDUP_INT_TEST_TYPED(gint64, 9223372036854775807);
-    _NM_STRDUP_INT_TEST_TYPED(gint64, -9223372036854775807);
-    _NM_STRDUP_INT_TEST_TYPED(guint64, 0);
-    _NM_STRDUP_INT_TEST_TYPED(guint64, 9223372036854775807);
-
-    _NM_STRDUP_INT_TEST(TEST_NM_STRDUP_ENUM_m1, "-1");
-    _NM_STRDUP_INT_TEST(TEST_NM_STRDUP_ENUM_3, "3");
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_strndup_a(void)
-{
-    int run;
-
-    for (run = 0; run < 20; run++) {
-        gs_free char *input = NULL;
-        char          ch;
-        gsize         i, l;
-
-        input = g_strnfill(nmtst_get_rand_uint32() % 20, 'x');
-
-        for (i = 0; input[i]; i++) {
-            while ((ch = ((char) nmtst_get_rand_uint32())) == '\0') {
-                /* repeat. */
-            }
-            input[i] = ch;
-        }
-
-        {
-            gs_free char *dup_free = NULL;
-            const char *  dup;
-
-            l   = strlen(input) + 1;
-            dup = nm_strndup_a(10, input, l - 1, &dup_free);
-            g_assert_cmpstr(dup, ==, input);
-            if (strlen(dup) < 10)
-                g_assert(!dup_free);
-            else
-                g_assert(dup == dup_free);
-        }
-
-        {
-            gs_free char *dup_free = NULL;
-            const char *  dup;
-
-            l   = nmtst_get_rand_uint32() % 23;
-            dup = nm_strndup_a(10, input, l, &dup_free);
-            g_assert(strncmp(dup, input, l) == 0);
-            g_assert(strlen(dup) <= l);
-            if (l < 10)
-                g_assert(!dup_free);
-            else
-                g_assert(dup == dup_free);
-            if (strlen(input) < l)
-                g_assert(nm_utils_memeqzero(&dup[strlen(input)], l - strlen(input)));
-        }
-    }
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_ip4_addr_is_localhost(void)
-{
-    g_assert(nm_ip4_addr_is_localhost(nmtst_inet4_from_string("127.0.0.0")));
-    g_assert(nm_ip4_addr_is_localhost(nmtst_inet4_from_string("127.0.0.1")));
-    g_assert(nm_ip4_addr_is_localhost(nmtst_inet4_from_string("127.5.0.1")));
-    g_assert(!nm_ip4_addr_is_localhost(nmtst_inet4_from_string("126.5.0.1")));
-    g_assert(!nm_ip4_addr_is_localhost(nmtst_inet4_from_string("128.5.0.1")));
-    g_assert(!nm_ip4_addr_is_localhost(nmtst_inet4_from_string("129.5.0.1")));
-}
-
-/*****************************************************************************/
-
-static void
-test_unaligned(void)
-{
-    int shift;
-
-    for (shift = 0; shift <= 32; shift++) {
-        guint8 buf[100] = {};
-        guint8 val      = 0;
-
-        while (val == 0)
-            val = nmtst_get_rand_uint32() % 256;
-
-        buf[shift] = val;
-
-        g_assert_cmpint(unaligned_read_le64(&buf[shift]), ==, (guint64) val);
-        g_assert_cmpint(unaligned_read_be64(&buf[shift]), ==, ((guint64) val) << 56);
-        g_assert_cmpint(unaligned_read_ne64(&buf[shift]), !=, 0);
-
-        g_assert_cmpint(unaligned_read_le32(&buf[shift]), ==, (guint32) val);
-        g_assert_cmpint(unaligned_read_be32(&buf[shift]), ==, ((guint32) val) << 24);
-        g_assert_cmpint(unaligned_read_ne32(&buf[shift]), !=, 0);
-
-        g_assert_cmpint(unaligned_read_le16(&buf[shift]), ==, (guint16) val);
-        g_assert_cmpint(unaligned_read_be16(&buf[shift]), ==, ((guint16) val) << 8);
-        g_assert_cmpint(unaligned_read_ne16(&buf[shift]), !=, 0);
-    }
-}
-
-/*****************************************************************************/
-
-static void
-_strv_cmp_fuzz_input(const char *const * in,
-                     gssize              l,
-                     const char ***      out_strv_free_shallow,
-                     char ***            out_strv_free_deep,
-                     const char *const **out_s1,
-                     const char *const **out_s2)
-{
-    const char **strv;
-    gsize        i;
-
-    /* Fuzz the input argument. It will return two output arrays that are semantically
-     * equal the input. */
-
-    if (nmtst_get_rand_bool()) {
-        char **ss;
-
-        if (l < 0)
-            ss = g_strdupv((char **) in);
-        else if (l == 0) {
-            ss = nmtst_get_rand_bool() ? NULL : g_new0(char *, 1);
-        } else {
-            ss = nm_memdup(in, sizeof(const char *) * l);
-            for (i = 0; i < (gsize) l; i++)
-                ss[i] = g_strdup(ss[i]);
-        }
-        strv                = (const char **) ss;
-        *out_strv_free_deep = ss;
-    } else {
-        if (l < 0) {
-            strv = in ? nm_memdup(in, sizeof(const char *) * (NM_PTRARRAY_LEN(in) + 1)) : NULL;
-        } else if (l == 0) {
-            strv = nmtst_get_rand_bool() ? NULL : g_new0(const char *, 1);
-        } else
-            strv = nm_memdup(in, sizeof(const char *) * l);
-        *out_strv_free_shallow = strv;
-    }
-
-    *out_s1 = in;
-    *out_s2 = strv;
-
-    if (nmtst_get_rand_bool()) {
-        /* randomly swap the original and the clone. That means, out_s1 is either
-         * the input argument (as-is) or the sementically equal clone. */
-        NM_SWAP(out_s1, out_s2);
-    }
-    if (nmtst_get_rand_bool()) {
-        /* randomly make s1 and s2 the same. This is for testing that
-         * comparing two identical pointers yields the same result. */
-        *out_s2 = *out_s1;
-    }
-}
-
-static void
-_strv_cmp_free_deep(char **strv, gssize len)
-{
-    gssize i;
-
-    if (strv) {
-        if (len < 0)
-            g_strfreev(strv);
-        else {
-            for (i = 0; i < len; i++)
-                g_free(strv[i]);
-            g_free(strv);
-        }
-    }
-}
-
-static void
-test_strv_cmp(void)
-{
-    const char *const strv0[1] = {};
-    const char *const strv1[2] = {
-        "",
-    };
-
-#define _STRV_CMP(a1, l1, a2, l2, equal)                                                            \
-    G_STMT_START                                                                                    \
-    {                                                                                               \
-        gssize               _l1 = (l1);                                                            \
-        gssize               _l2 = (l2);                                                            \
-        const char *const *  _a1;                                                                   \
-        const char *const *  _a2;                                                                   \
-        const char *const *  _a1x;                                                                  \
-        const char *const *  _a2x;                                                                  \
-        char **              _a1_free_deep    = NULL;                                               \
-        char **              _a2_free_deep    = NULL;                                               \
-        gs_free const char **_a1_free_shallow = NULL;                                               \
-        gs_free const char **_a2_free_shallow = NULL;                                               \
-        int                  _c1, _c2;                                                              \
-                                                                                                    \
-        _strv_cmp_fuzz_input((a1), _l1, &_a1_free_shallow, &_a1_free_deep, &_a1, &_a1x);            \
-        _strv_cmp_fuzz_input((a2), _l2, &_a2_free_shallow, &_a2_free_deep, &_a2, &_a2x);            \
-                                                                                                    \
-        _c1 = nm_utils_strv_cmp_n(_a1, _l1, _a2, _l2);                                              \
-        _c2 = nm_utils_strv_cmp_n(_a2, _l2, _a1, _l1);                                              \
-        if (equal) {                                                                                \
-            g_assert_cmpint(_c1, ==, 0);                                                            \
-            g_assert_cmpint(_c2, ==, 0);                                                            \
-        } else {                                                                                    \
-            g_assert_cmpint(_c1, ==, -1);                                                           \
-            g_assert_cmpint(_c2, ==, 1);                                                            \
-        }                                                                                           \
-                                                                                                    \
-        /* Compare with self. _strv_cmp_fuzz_input() randomly swapped the arguments (_a1 and _a1x).
-         * Either way, the arrays must compare equal to their semantically equal alternative. */ \
-        g_assert_cmpint(nm_utils_strv_cmp_n(_a1, _l1, _a1x, _l1), ==, 0);                           \
-        g_assert_cmpint(nm_utils_strv_cmp_n(_a2, _l2, _a2x, _l2), ==, 0);                           \
-                                                                                                    \
-        _strv_cmp_free_deep(_a1_free_deep, _l1);                                                    \
-        _strv_cmp_free_deep(_a2_free_deep, _l2);                                                    \
-    }                                                                                               \
-    G_STMT_END
-
-    _STRV_CMP(NULL, -1, NULL, -1, TRUE);
-
-    _STRV_CMP(NULL, -1, NULL, 0, FALSE);
-    _STRV_CMP(NULL, -1, strv0, 0, FALSE);
-    _STRV_CMP(NULL, -1, strv0, -1, FALSE);
-
-    _STRV_CMP(NULL, 0, NULL, 0, TRUE);
-    _STRV_CMP(NULL, 0, strv0, 0, TRUE);
-    _STRV_CMP(NULL, 0, strv0, -1, TRUE);
-    _STRV_CMP(strv0, 0, strv0, 0, TRUE);
-    _STRV_CMP(strv0, 0, strv0, -1, TRUE);
-    _STRV_CMP(strv0, -1, strv0, -1, TRUE);
-
-    _STRV_CMP(NULL, 0, strv1, -1, FALSE);
-    _STRV_CMP(NULL, 0, strv1, 1, FALSE);
-    _STRV_CMP(strv0, 0, strv1, -1, FALSE);
-    _STRV_CMP(strv0, 0, strv1, 1, FALSE);
-    _STRV_CMP(strv0, -1, strv1, -1, FALSE);
-    _STRV_CMP(strv0, -1, strv1, 1, FALSE);
-
-    _STRV_CMP(strv1, -1, strv1, 1, TRUE);
-    _STRV_CMP(strv1, 1, strv1, 1, TRUE);
-}
-
-/*****************************************************************************/
-
-static void
-_do_strstrip_avoid_copy(const char *str)
-{
-    gs_free char *str1 = g_strdup(str);
-    gs_free char *str2 = g_strdup(str);
-    gs_free char *str3 = NULL;
-    gs_free char *str4 = NULL;
-    const char *  s3;
-    const char *  s4;
-
-    if (str1)
-        g_strstrip(str1);
-
-    nm_strstrip(str2);
-
-    g_assert_cmpstr(str1, ==, str2);
-
-    s3 = nm_strstrip_avoid_copy(str, &str3);
-    g_assert_cmpstr(str1, ==, s3);
-
-    s4 = nm_strstrip_avoid_copy_a(10, str, &str4);
-    g_assert_cmpstr(str1, ==, s4);
-    g_assert(!str == !s4);
-    g_assert(!s4 || strlen(s4) <= strlen(str));
-    if (s4 && s4 == &str[strlen(str) - strlen(s4)]) {
-        g_assert(!str4);
-        g_assert(s3 == s4);
-    } else if (s4 && strlen(s4) >= 10) {
-        g_assert(str4);
-        g_assert(s4 == str4);
-    } else
-        g_assert(!str4);
-
-    if (!nm_streq0(str1, str))
-        _do_strstrip_avoid_copy(str1);
-}
-
-static void
-test_strstrip_avoid_copy(void)
-{
-    _do_strstrip_avoid_copy(NULL);
-    _do_strstrip_avoid_copy("");
-    _do_strstrip_avoid_copy(" ");
-    _do_strstrip_avoid_copy(" a ");
-    _do_strstrip_avoid_copy(" 012345678 ");
-    _do_strstrip_avoid_copy(" 0123456789 ");
-    _do_strstrip_avoid_copy(" 01234567890 ");
-    _do_strstrip_avoid_copy(" 012345678901 ");
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_utils_bin2hexstr(void)
-{
-    int n_run;
-
-    for (n_run = 0; n_run < 500; n_run++) {
-        guint8   buf[100];
-        guint8   buf2[G_N_ELEMENTS(buf) + 1];
-        gsize    len = nmtst_get_rand_uint32() % (G_N_ELEMENTS(buf) + 1);
-        char     strbuf1[G_N_ELEMENTS(buf) * 3];
-        gboolean allocate   = nmtst_get_rand_bool();
-        char     delimiter  = nmtst_get_rand_bool() ? ':' : '\0';
-        gboolean upper_case = nmtst_get_rand_bool();
-        gboolean hexdigit_pairs_mangled;
-        gsize    expected_strlen;
-        char *   str_hex;
-        gsize    required_len;
-        gboolean outlen_set;
-        gsize    outlen;
-        guint8 * bin2;
-        guint    i, j;
-
-        nmtst_rand_buf(NULL, buf, len);
-
-        if (len == 0)
-            expected_strlen = 0;
-        else if (delimiter != '\0')
-            expected_strlen = (len * 3u) - 1;
-        else
-            expected_strlen = len * 2u;
-
-        g_assert_cmpint(expected_strlen, <, G_N_ELEMENTS(strbuf1));
-
-        str_hex =
-            nm_utils_bin2hexstr_full(buf, len, delimiter, upper_case, !allocate ? strbuf1 : NULL);
-
-        g_assert(str_hex);
-        if (!allocate)
-            g_assert(str_hex == strbuf1);
-        g_assert_cmpint(strlen(str_hex), ==, expected_strlen);
-
-        g_assert(NM_STRCHAR_ALL(
-            str_hex,
-            ch,
-            (ch >= '0' && ch <= '9') || ch == delimiter
-                || (upper_case ? (ch >= 'A' && ch <= 'F') : (ch >= 'a' && ch <= 'f'))));
-
-        hexdigit_pairs_mangled = FALSE;
-        if (delimiter && len > 1 && nmtst_get_rand_bool()) {
-            /* randomly convert "0?" sequences to single digits, so we can get hexdigit_pairs_required
-             * parameter. */
-            g_assert(strlen(str_hex) >= 5);
-            g_assert(str_hex[2] == delimiter);
-            i = 0;
-            j = 0;
-            for (;;) {
-                g_assert(g_ascii_isxdigit(str_hex[i]));
-                g_assert(g_ascii_isxdigit(str_hex[i + 1]));
-                g_assert(NM_IN_SET(str_hex[i + 2], delimiter, '\0'));
-                if (str_hex[i] == '0' && nmtst_get_rand_bool()) {
-                    i++;
-                    str_hex[j++]           = str_hex[i++];
-                    hexdigit_pairs_mangled = TRUE;
-                } else {
-                    str_hex[j++] = str_hex[i++];
-                    str_hex[j++] = str_hex[i++];
-                }
-                if (str_hex[i] == '\0') {
-                    str_hex[j] = '\0';
-                    break;
-                }
-                g_assert(str_hex[i] == delimiter);
-                str_hex[j++] = str_hex[i++];
-            }
-        }
-
-        required_len = nmtst_get_rand_bool() ? len : 0u;
-
-        outlen_set = required_len == 0 || nmtst_get_rand_bool();
-
-        memset(buf2, 0, sizeof(buf2));
-
-        bin2 = nm_utils_hexstr2bin_full(str_hex,
-                                        nmtst_get_rand_bool(),
-                                        delimiter != '\0' && nmtst_get_rand_bool(),
-                                        !hexdigit_pairs_mangled && nmtst_get_rand_bool(),
-                                        delimiter != '\0'
-                                            ? nmtst_rand_select((const char *) ":", ":-")
-                                            : nmtst_rand_select((const char *) ":", ":-", "", NULL),
-                                        required_len,
-                                        buf2,
-                                        len,
-                                        outlen_set ? &outlen : NULL);
-        if (len > 0) {
-            g_assert(bin2);
-            g_assert(bin2 == buf2);
-        } else
-            g_assert(!bin2);
-
-        if (outlen_set)
-            g_assert_cmpint(outlen, ==, len);
-
-        g_assert_cmpmem(buf, len, buf2, len);
-
-        g_assert(buf2[len] == '\0');
-
-        if (hexdigit_pairs_mangled) {
-            /* we mangled the hexstr to contain single digits. Trying to parse with
-             * hexdigit_pairs_required must now fail. */
-            bin2 = nm_utils_hexstr2bin_full(
-                str_hex,
-                nmtst_get_rand_bool(),
-                delimiter != '\0' && nmtst_get_rand_bool(),
-                TRUE,
-                delimiter != '\0' ? nmtst_rand_select((const char *) ":", ":-")
-                                  : nmtst_rand_select((const char *) ":", ":-", "", NULL),
-                required_len,
-                buf2,
-                len,
-                outlen_set ? &outlen : NULL);
-            g_assert(!bin2);
-        }
-
-        if (allocate)
-            g_free(str_hex);
-    }
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_ref_string(void)
-{
-    nm_auto_ref_string NMRefString *s1 = NULL;
-    NMRefString *                   s2;
-
-    s1 = nm_ref_string_new("hallo");
-    g_assert(s1);
-    g_assert_cmpstr(s1->str, ==, "hallo");
-    g_assert_cmpint(s1->len, ==, strlen("hallo"));
-
-    s2 = nm_ref_string_new("hallo");
-    g_assert(s2 == s1);
-    nm_ref_string_unref(s2);
-
-    s2 = nm_ref_string_new(NULL);
-    g_assert(!s2);
-    nm_ref_string_unref(s2);
-
-#define STR_WITH_NUL "hallo\0test\0"
-    s2 = nm_ref_string_new_len(STR_WITH_NUL, NM_STRLEN(STR_WITH_NUL));
-    g_assert(s2);
-    g_assert_cmpstr(s2->str, ==, "hallo");
-    g_assert_cmpint(s2->len, ==, NM_STRLEN(STR_WITH_NUL));
-    g_assert_cmpint(s2->len, >, strlen(s2->str));
-    g_assert_cmpmem(s2->str, s2->len, STR_WITH_NUL, NM_STRLEN(STR_WITH_NUL));
-    g_assert(s2->str[s2->len] == '\0');
-    nm_ref_string_unref(s2);
-}
-
-/*****************************************************************************/
-
-static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE(
-    _do_string_table_lookup,
-    int,
-    { ; },
-    { return -1; },
-    {"0", 0},
-    {"1", 1},
-    {"2", 2},
-    {"3", 3}, );
-
-static void
-test_string_table_lookup(void)
-{
-    const char *const args[] = {
-        NULL,
-        "0",
-        "1",
-        "2",
-        "3",
-        "x",
-    };
-    int i;
-
-    for (i = 0; i < G_N_ELEMENTS(args); i++) {
-        const char *needle = args[i];
-        const int   val2   = _nm_utils_ascii_str_to_int64(needle, 10, 0, 100, -1);
-        int         val;
-
-        val = _do_string_table_lookup(needle);
-        g_assert_cmpint(val, ==, val2);
-    }
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_utils_get_next_realloc_size(void)
-{
-    static const struct {
-        gsize requested;
-        gsize reserved_true;
-        gsize reserved_false;
-    } test_data[] = {
-        {0, 8, 8},
-        {1, 8, 8},
-        {8, 8, 8},
-        {9, 16, 16},
-        {16, 16, 16},
-        {17, 32, 32},
-        {32, 32, 32},
-        {33, 40, 40},
-        {40, 40, 40},
-        {41, 104, 104},
-        {104, 104, 104},
-        {105, 232, 232},
-        {232, 232, 232},
-        {233, 488, 488},
-        {488, 488, 488},
-        {489, 1000, 1000},
-        {1000, 1000, 1000},
-        {1001, 2024, 2024},
-        {2024, 2024, 2024},
-        {2025, 4072, 4072},
-        {4072, 4072, 4072},
-        {4073, 8168, 8168},
-        {8168, 8168, 8168},
-        {8169, 12264, 16360},
-        {12263, 12264, 16360},
-        {12264, 12264, 16360},
-        {12265, 16360, 16360},
-        {16360, 16360, 16360},
-        {16361, 20456, 32744},
-        {20456, 20456, 32744},
-        {20457, 24552, 32744},
-        {24552, 24552, 32744},
-        {24553, 28648, 32744},
-        {28648, 28648, 32744},
-        {28649, 32744, 32744},
-        {32744, 32744, 32744},
-        {32745, 36840, 65512},
-        {36840, 36840, 65512},
-        {G_MAXSIZE - 0x1000u, G_MAXSIZE, G_MAXSIZE},
-        {G_MAXSIZE - 25u, G_MAXSIZE, G_MAXSIZE},
-        {G_MAXSIZE - 24u, G_MAXSIZE, G_MAXSIZE},
-        {G_MAXSIZE - 1u, G_MAXSIZE, G_MAXSIZE},
-        {G_MAXSIZE, G_MAXSIZE, G_MAXSIZE},
-        {NM_UTILS_GET_NEXT_REALLOC_SIZE_32,
-         NM_UTILS_GET_NEXT_REALLOC_SIZE_32,
-         NM_UTILS_GET_NEXT_REALLOC_SIZE_32},
-        {NM_UTILS_GET_NEXT_REALLOC_SIZE_40,
-         NM_UTILS_GET_NEXT_REALLOC_SIZE_40,
-         NM_UTILS_GET_NEXT_REALLOC_SIZE_40},
-        {NM_UTILS_GET_NEXT_REALLOC_SIZE_104,
-         NM_UTILS_GET_NEXT_REALLOC_SIZE_104,
-         NM_UTILS_GET_NEXT_REALLOC_SIZE_104},
-        {NM_UTILS_GET_NEXT_REALLOC_SIZE_1000,
-         NM_UTILS_GET_NEXT_REALLOC_SIZE_1000,
-         NM_UTILS_GET_NEXT_REALLOC_SIZE_1000},
-    };
-    guint i;
-
-    G_STATIC_ASSERT_EXPR(NM_UTILS_GET_NEXT_REALLOC_SIZE_104 == 104u);
-    G_STATIC_ASSERT_EXPR(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 == 1000u);
-
-    for (i = 0; i < G_N_ELEMENTS(test_data) + 5000u; i++) {
-        gsize requested0;
-
-        if (i < G_N_ELEMENTS(test_data))
-            requested0 = test_data[i].requested;
-        else {
-            /* find some interesting random values for testing. */
-            switch (nmtst_get_rand_uint32() % 5) {
-            case 0:
-                requested0 = nmtst_get_rand_size();
-                break;
-            case 1:
-                /* values close to G_MAXSIZE. */
-                requested0 = G_MAXSIZE - (nmtst_get_rand_uint32() % 12000u);
-                break;
-            case 2:
-                /* values around G_MAXSIZE/2. */
-                requested0 = (G_MAXSIZE / 2u) + 6000u - (nmtst_get_rand_uint32() % 12000u);
-                break;
-            case 3:
-                /* values around powers of 2. */
-                requested0 = (((gsize) 1) << (nmtst_get_rand_uint32() % (sizeof(gsize) * 8u)))
-                             + 6000u - (nmtst_get_rand_uint32() % 12000u);
-                break;
-            case 4:
-                /* values around 4k borders. */
-                requested0 = (nmtst_get_rand_size() & ~((gsize) 0xFFFu)) + 30u
-                             - (nmtst_get_rand_uint32() % 60u);
-                break;
-            default:
-                g_assert_not_reached();
-            }
-        }
-
-        {
-            const gsize requested = requested0;
-            gsize       reserved_true;
-            gsize       reserved_false;
-            bool        truncated_true  = FALSE;
-            bool        truncated_false = FALSE;
-
-            if (sizeof(gsize) > 4 && requested > SIZE_MAX / 2u - 24u) {
-                reserved_false  = G_MAXSSIZE;
-                truncated_false = TRUE;
-            } else
-                reserved_false = nm_utils_get_next_realloc_size(FALSE, requested);
-
-            if (sizeof(gsize) > 4 && requested > SIZE_MAX - 0x1000u - 24u) {
-                reserved_true  = G_MAXSSIZE;
-                truncated_true = TRUE;
-            } else
-                reserved_true = nm_utils_get_next_realloc_size(TRUE, requested);
-
-            g_assert_cmpuint(reserved_true, >, 0);
-            g_assert_cmpuint(reserved_false, >, 0);
-            if (!truncated_true)
-                g_assert_cmpuint(reserved_true, >=, requested);
-            if (!truncated_false)
-                g_assert_cmpuint(reserved_false, >=, requested);
-            if (!truncated_true && !truncated_false)
-                g_assert_cmpuint(reserved_false, >=, reserved_true);
-
-            if (i < G_N_ELEMENTS(test_data)) {
-                if (!truncated_true)
-                    g_assert_cmpuint(reserved_true, ==, test_data[i].reserved_true);
-                if (!truncated_false)
-                    g_assert_cmpuint(reserved_false, ==, test_data[i].reserved_false);
-            }
-
-            /* reserved_false is generally the next power of two - 24. */
-            if (reserved_false == G_MAXSIZE)
-                g_assert_cmpuint(requested, >, G_MAXSIZE / 2u - 24u);
-            else if (!reserved_false) {
-                g_assert_cmpuint(reserved_false, <=, G_MAXSIZE - 24u);
-                if (reserved_false >= 40) {
-                    const gsize _pow2 = reserved_false + 24u;
-
-                    /* reserved_false must always be a power of two minus 24. */
-                    g_assert_cmpuint(_pow2, >=, 64u);
-                    g_assert_cmpuint(_pow2, >, requested);
-                    g_assert(nm_utils_is_power_of_two(_pow2));
-
-                    /* but _pow2/2 must also be smaller than what we requested. */
-                    g_assert_cmpuint(_pow2 / 2u - 24u, <, requested);
-                } else {
-                    /* smaller values are hard-coded. */
-                }
-            }
-
-            /* reserved_true is generally the next 4k border - 24. */
-            if (reserved_true == G_MAXSIZE)
-                g_assert_cmpuint(requested, >, G_MAXSIZE - 0x1000u - 24u);
-            else if (!truncated_true) {
-                g_assert_cmpuint(reserved_true, <=, G_MAXSIZE - 24u);
-                if (reserved_true > 8168u) {
-                    const gsize page_border = reserved_true + 24u;
-
-                    /* reserved_true must always be aligned to 4k (minus 24). */
-                    g_assert_cmpuint(page_border % 0x1000u, ==, 0);
-                    if (requested > 0x1000u - 24u) {
-                        /* page_border not be more than 4k above requested. */
-                        g_assert_cmpuint(page_border, >=, 0x1000u - 24u);
-                        g_assert_cmpuint(page_border - 0x1000u - 24u, <, requested);
-                    }
-                } else {
-                    /* for smaller sizes, reserved_true and reserved_false are the same. */
-                    g_assert_cmpuint(reserved_true, ==, reserved_false);
-                }
-            }
-        }
-    }
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_str_buf(void)
-{
-    guint i_run;
-
-    for (i_run = 0; TRUE; i_run++) {
-        nm_auto_str_buf NMStrBuf strbuf    = {};
-        nm_auto_free_gstring GString *gstr = NULL;
-        int                           i, j, k;
-        int                           c;
-
-        nm_str_buf_init(&strbuf, nmtst_get_rand_uint32() % 200u + 1u, nmtst_get_rand_bool());
-
-        if (i_run < 1000) {
-            c = nmtst_get_rand_word_length(NULL);
-            for (i = 0; i < c; i++)
-                nm_str_buf_append_c(&strbuf, '0' + (i % 10));
-            gstr = g_string_new(nm_str_buf_get_str(&strbuf));
-            j    = nmtst_get_rand_uint32() % (strbuf.len + 1);
-            k    = nmtst_get_rand_uint32() % (strbuf.len - j + 2) - 1;
-
-            nm_str_buf_erase(&strbuf, j, k, nmtst_get_rand_bool());
-            g_string_erase(gstr, j, k);
-            g_assert_cmpstr(gstr->str, ==, nm_str_buf_get_str(&strbuf));
-        } else
-            return;
-    }
-}
-
-/*****************************************************************************/
-
-static void
-test_nm_utils_parse_next_line(void)
-{
-    const char *data;
-    const char *data0;
-    gsize       data_len;
-    const char *line_start;
-    gsize       line_len;
-    int         i_run;
-    gsize       j, k;
-
-    data     = NULL;
-    data_len = 0;
-    g_assert(!nm_utils_parse_next_line(&data, &data_len, &line_start, &line_len));
-
-    for (i_run = 0; i_run < 1000; i_run++) {
-        gs_unref_ptrarray GPtrArray *strv     = g_ptr_array_new_with_free_func(g_free);
-        gs_unref_ptrarray GPtrArray *strv2    = g_ptr_array_new_with_free_func(g_free);
-        gsize                        strv_len = nmtst_get_rand_word_length(NULL);
-        nm_auto_str_buf NMStrBuf     strbuf   = NM_STR_BUF_INIT(0, nmtst_get_rand_bool());
-
-        /* create a list of random words. */
-        for (j = 0; j < strv_len; j++) {
-            gsize    w_len = nmtst_get_rand_word_length(NULL);
-            NMStrBuf w_buf =
-                NM_STR_BUF_INIT(nmtst_get_rand_uint32() % (w_len + 1), nmtst_get_rand_bool());
-
-            for (k = 0; k < w_len; k++)
-                nm_str_buf_append_c(&w_buf, '0' + (k % 10));
-            nm_str_buf_maybe_expand(&w_buf, 1, TRUE);
-            g_ptr_array_add(strv, nm_str_buf_finalize(&w_buf, NULL));
-        }
-
-        /* join the list of random words with (random) line delimiters
-         * ("\0", "\n", "\r" or EOF). */
-        for (j = 0; j < strv_len; j++) {
-            nm_str_buf_append(&strbuf, strv->pdata[j]);
-again:
-            switch (nmtst_get_rand_uint32() % 5) {
-            case 0:
-                nm_str_buf_append_c(&strbuf, '\0');
-                break;
-            case 1:
-                if (strbuf.len > 0
-                    && (nm_str_buf_get_str_unsafe(&strbuf))[strbuf.len - 1] == '\r') {
-                    /* the previous line was empty and terminated by "\r". We
-                     * must not join with "\n". Retry. */
-                    goto again;
-                }
-                nm_str_buf_append_c(&strbuf, '\n');
-                break;
-            case 2:
-                nm_str_buf_append_c(&strbuf, '\r');
-                break;
-            case 3:
-                nm_str_buf_append(&strbuf, "\r\n");
-                break;
-            case 4:
-                /* the last word randomly is delimited or not, but not if the last
-                 * word is "". */
-                if (j + 1 < strv_len) {
-                    /* it's not the last word. Retry. */
-                    goto again;
-                }
-                g_assert(j == strv_len - 1);
-                if (((const char *) strv->pdata[j])[0] == '\0') {
-                    /* if the last word was "", we need a delimiter (to parse it back).
-                     * Retry. */
-                    goto again;
-                }
-                /* The final delimiter gets omitted. It's EOF. */
-                break;
-            }
-        }
-
-        data0 = nm_str_buf_get_str_unsafe(&strbuf);
-        if (!data0 && nmtst_get_rand_bool()) {
-            nm_str_buf_maybe_expand(&strbuf, 1, TRUE);
-            data0 = nm_str_buf_get_str_unsafe(&strbuf);
-            g_assert(data0);
-        }
-        data_len = strbuf.len;
-        g_assert((data_len > 0 && data0) || data_len == 0);
-        data = data0;
-        while (nm_utils_parse_next_line(&data, &data_len, &line_start, &line_len)) {
-            g_assert(line_start);
-            g_assert(line_start >= data0);
-            g_assert(line_start < &data0[strbuf.len]);
-            g_assert(!memchr(line_start, '\0', line_len));
-            g_ptr_array_add(strv2, g_strndup(line_start, line_len));
-        }
-        g_assert(data_len == 0);
-        if (data0)
-            g_assert(data == &data0[strbuf.len]);
-        else
-            g_assert(!data);
-
-        g_assert(nm_utils_strv_cmp_n((const char *const *) strv->pdata,
-                                     strv->len,
-                                     (const char *const *) strv2->pdata,
-                                     strv2->len)
-                 == 0);
-    }
-}
-
-/*****************************************************************************/
-
-static void
-test_in_strset_ascii_case(void)
-{
-    const char *x;
-
-    x = NULL;
-    g_assert(NM_IN_STRSET_ASCII_CASE(x, NULL));
-    g_assert(NM_IN_STRSET_ASCII_CASE(x, NULL, "b"));
-    g_assert(!NM_IN_STRSET_ASCII_CASE(x, "b"));
-
-    x = "b";
-    g_assert(NM_IN_STRSET(x, "b"));
-    g_assert(NM_IN_STRSET_ASCII_CASE(x, "b"));
-    g_assert(!NM_IN_STRSET(x, "B"));
-    g_assert(NM_IN_STRSET_ASCII_CASE(x, "B"));
-}
-
-/*****************************************************************************/
-
-static void
-test_is_specific_hostname(void)
-{
-    g_assert(!nm_utils_is_specific_hostname(NULL));
-    g_assert(!nm_utils_is_specific_hostname(""));
-    g_assert(!nm_utils_is_specific_hostname("(none)"));
-    g_assert(nm_utils_is_specific_hostname("(NONE)"));
-
-    g_assert(!nm_utils_is_specific_hostname("localhost"));
-    g_assert(!nm_utils_is_specific_hostname("lOcalHost"));
-    g_assert(!nm_utils_is_specific_hostname("LOCALHOST"));
-
-    g_assert(!nm_utils_is_specific_hostname("LOCALHOST.localdomain"));
-
-    g_assert(nm_utils_is_specific_hostname("xlocalhost"));
-    g_assert(nm_utils_is_specific_hostname("lOcalHxost"));
-    g_assert(nm_utils_is_specific_hostname("LOCALxHOST"));
-
-    g_assert(!nm_utils_is_specific_hostname("foo.LOCALHOST"));
-    g_assert(!nm_utils_is_specific_hostname("foo.LOCALHOsT6."));
-    g_assert(!nm_utils_is_specific_hostname("foo.LOCALHOsT6.localdomain6"));
-    g_assert(!nm_utils_is_specific_hostname(".LOCALHOsT6.localdomain6"));
-    g_assert(!nm_utils_is_specific_hostname("LOCALHOsT6.localdomain6"));
-    g_assert(!nm_utils_is_specific_hostname("LOCALHOsT6.localdomain6."));
-    g_assert(nm_utils_is_specific_hostname("LOCALHOsT6.localdomain."));
-
-    g_assert(nm_utils_is_specific_hostname(" "));
-}
-
-/*****************************************************************************/
-
-static void
-test_strv_dup_packed(void)
-{
-    gs_unref_ptrarray GPtrArray *src = NULL;
-    int                          i_run;
-
-    src = g_ptr_array_new_with_free_func(g_free);
-
-    for (i_run = 0; i_run < 500; i_run++) {
-        const int            strv_len = nmtst_get_rand_word_length(NULL);
-        gs_free const char **strv_cpy = NULL;
-        const char *const *  strv_src;
-        int                  i, j;
-
-        g_ptr_array_set_size(src, 0);
-        for (i = 0; i < strv_len; i++) {
-            const int word_len = nmtst_get_rand_word_length(NULL);
-            NMStrBuf  sbuf     = NM_STR_BUF_INIT(0, nmtst_get_rand_bool());
-
-            for (j = 0; j < word_len; j++)
-                nm_str_buf_append_c(&sbuf, 'a' + (nmtst_get_rand_uint32() % 20));
-
-            g_ptr_array_add(src, nm_str_buf_finalize(&sbuf, NULL) ?: g_new0(char, 1));
-        }
-        g_ptr_array_add(src, NULL);
-
-        strv_src = (const char *const *) src->pdata;
-        g_assert(strv_src);
-        g_assert(NM_PTRARRAY_LEN(strv_src) == strv_len);
-
-        strv_cpy =
-            nm_utils_strv_dup_packed(strv_src,
-                                     nmtst_get_rand_bool() ? (gssize) strv_len : (gssize) -1);
-        if (strv_len == 0)
-            g_assert(!strv_cpy);
-        else
-            g_assert(strv_cpy);
-        g_assert(NM_PTRARRAY_LEN(strv_cpy) == strv_len);
-        if (strv_cpy)
-            g_assert(nm_utils_strv_equal(strv_cpy, strv_src));
-    }
-}
-
-/*****************************************************************************/
-
-static int
-_hash_func_cmp_direct(gconstpointer a, gconstpointer b, gpointer user_data)
-{
-    NM_CMP_DIRECT(GPOINTER_TO_INT(a), GPOINTER_TO_INT(b));
-    return 0;
-}
-
-static void
-test_utils_hashtable_cmp(void)
-{
-    static struct {
-        int         val_i;
-        const char *val_s;
-    } vals[] = {
-        {
-            0,
-            "0",
-        },
-        {
-            1,
-            "1",
-        },
-        {
-            2,
-            "2",
-        },
-        {
-            3,
-            "3",
-        },
-        {
-            4,
-            "4",
-        },
-        {
-            5,
-            "5",
-        },
-        {
-            6,
-            "6",
-        },
-        {
-            7,
-            "7",
-        },
-        {
-            8,
-            "8",
-        },
-        {
-            9,
-            "9",
-        },
-        {
-            0,
-            "a",
-        },
-        {
-            1,
-            "a",
-        },
-        {
-            2,
-            "a",
-        },
-        {
-            3,
-            "a",
-        },
-        {
-            4,
-            "a",
-        },
-        {
-            5,
-            "a",
-        },
-        {
-            0,
-            "0",
-        },
-        {
-            0,
-            "1",
-        },
-        {
-            0,
-            "2",
-        },
-        {
-            0,
-            "3",
-        },
-        {
-            0,
-            "4",
-        },
-        {
-            0,
-            "5",
-        },
-    };
-    guint test_run;
-    int   is_num_key;
-
-    for (test_run = 0; test_run < 30; test_run++) {
-        for (is_num_key = 0; is_num_key < 2; is_num_key++) {
-            GHashFunc        func_key_hash  = is_num_key ? nm_direct_hash : nm_str_hash;
-            GEqualFunc       func_key_equal = is_num_key ? g_direct_equal : g_str_equal;
-            GCompareDataFunc func_key_cmp =
-                is_num_key ? _hash_func_cmp_direct : (GCompareDataFunc) nm_strcmp_with_data;
-            GCompareDataFunc func_val_cmp =
-                !is_num_key ? _hash_func_cmp_direct : (GCompareDataFunc) nm_strcmp_with_data;
-            gs_unref_hashtable GHashTable *h1 = NULL;
-            gs_unref_hashtable GHashTable *h2 = NULL;
-            gboolean                       has_same_keys;
-            guint                          i, n;
-
-            h1 = g_hash_table_new(func_key_hash, func_key_equal);
-            h2 = g_hash_table_new(func_key_hash, func_key_equal);
-
-            n = nmtst_get_rand_word_length(NULL);
-            for (i = 0; i < n; i++) {
-                typeof(vals[0]) *v     = &vals[nmtst_get_rand_uint32() % G_N_ELEMENTS(vals)];
-                gconstpointer    v_key = is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s;
-                gconstpointer    v_val = !is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s;
-
-                g_hash_table_insert(h1, (gpointer) v_key, (gpointer) v_val);
-                g_hash_table_insert(h2, (gpointer) v_key, (gpointer) v_val);
-            }
-
-            g_assert(nm_utils_hashtable_same_keys(h1, h2));
-            g_assert(nm_utils_hashtable_cmp_equal(h1, h2, NULL, NULL));
-            g_assert(nm_utils_hashtable_cmp_equal(h1, h2, func_val_cmp, NULL));
-            g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0);
-            g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0);
-            g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) == 0);
-            g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) == 0);
-
-            n             = nmtst_get_rand_word_length(NULL) + 1;
-            has_same_keys = TRUE;
-            for (i = 0; i < n; i++) {
-again:
-{
-    typeof(vals[0]) *v     = &vals[nmtst_get_rand_uint32() % G_N_ELEMENTS(vals)];
-    gconstpointer    v_key = is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s;
-    gconstpointer    v_val = !is_num_key ? GINT_TO_POINTER(v->val_i) : v->val_s;
-    gpointer         v_key2;
-    gpointer         v_val2;
-
-    if (g_hash_table_lookup_extended(h1, v_key, &v_key2, &v_val2)) {
-        g_assert(func_key_cmp(v_key, v_key2, NULL) == 0);
-        if (func_val_cmp(v_val, v_val2, NULL) == 0)
-            goto again;
-    } else
-        has_same_keys = FALSE;
-
-    g_hash_table_insert(h2, (gpointer) v_key, (gpointer) v_val);
-}
-            }
-
-            if (has_same_keys) {
-                g_assert(nm_utils_hashtable_same_keys(h1, h2));
-                g_assert(nm_utils_hashtable_cmp_equal(h1, h2, NULL, NULL));
-                g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0);
-                g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0);
-            } else {
-                g_assert(!nm_utils_hashtable_same_keys(h1, h2));
-                g_assert(!nm_utils_hashtable_cmp_equal(h1, h2, NULL, NULL));
-                g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, NULL, NULL) != 0);
-                g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, NULL, NULL) != 0);
-            }
-            g_assert(!nm_utils_hashtable_cmp_equal(h1, h2, func_val_cmp, NULL));
-            g_assert(nm_utils_hashtable_cmp(h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) != 0);
-            g_assert(nm_utils_hashtable_cmp(h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) != 0);
-        }
-    }
-}
-
-/*****************************************************************************/
-
-NMTST_DEFINE();
-
-int
-main(int argc, char **argv)
-{
-    nmtst_init(&argc, &argv, TRUE);
-
-    g_test_add_func("/general/test_gpid", test_gpid);
-    g_test_add_func("/general/test_monotonic_timestamp", test_monotonic_timestamp);
-    g_test_add_func("/general/test_nmhash", test_nmhash);
-    g_test_add_func("/general/test_nm_make_strv", test_make_strv);
-    g_test_add_func("/general/test_nm_strdup_int", test_nm_strdup_int);
-    g_test_add_func("/general/test_nm_strndup_a", test_nm_strndup_a);
-    g_test_add_func("/general/test_nm_ip4_addr_is_localhost", test_nm_ip4_addr_is_localhost);
-    g_test_add_func("/general/test_unaligned", test_unaligned);
-    g_test_add_func("/general/test_strv_cmp", test_strv_cmp);
-    g_test_add_func("/general/test_strstrip_avoid_copy", test_strstrip_avoid_copy);
-    g_test_add_func("/general/test_nm_utils_bin2hexstr", test_nm_utils_bin2hexstr);
-    g_test_add_func("/general/test_nm_ref_string", test_nm_ref_string);
-    g_test_add_func("/general/test_string_table_lookup", test_string_table_lookup);
-    g_test_add_func("/general/test_nm_utils_get_next_realloc_size",
-                    test_nm_utils_get_next_realloc_size);
-    g_test_add_func("/general/test_nm_str_buf", test_nm_str_buf);
-    g_test_add_func("/general/test_nm_utils_parse_next_line", test_nm_utils_parse_next_line);
-    g_test_add_func("/general/test_in_strset_ascii_case", test_in_strset_ascii_case);
-    g_test_add_func("/general/test_is_specific_hostname", test_is_specific_hostname);
-    g_test_add_func("/general/test_strv_dup_packed", test_strv_dup_packed);
-    g_test_add_func("/general/test_utils_hashtable_cmp", test_utils_hashtable_cmp);
-
-    return g_test_run();
-}
diff --git a/shared/nm-log-core/nm-logging.c b/shared/nm-log-core/nm-logging.c
deleted file mode 100644
index cf3c3a86..00000000
--- a/shared/nm-log-core/nm-logging.c
+++ /dev/null
@@ -1,1035 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2006 - 2012 Red Hat, Inc.
- * Copyright (C) 2006 - 2008 Novell, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-logging.h"
-
-#include <dlfcn.h>
-#include <syslog.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <strings.h>
-
-#if SYSTEMD_JOURNAL
-    #define SD_JOURNAL_SUPPRESS_LOCATION
-    #include <systemd/sd-journal.h>
-#endif
-
-#include "nm-glib-aux/nm-logging-base.h"
-#include "nm-glib-aux/nm-time-utils.h"
-
-/*****************************************************************************/
-
-/* Notes about thread-safety:
- *
- * NetworkManager generally is single-threaded and uses a (GLib) mainloop.
- * However, nm-logging is in parts thread-safe. That means:
- *
- * - functions that configure logging (nm_logging_init(), nm_logging_setup()) and
- *   most other functions MUST be called only from the main-thread. These functions
- *   are expected to be called infrequently, so they may or may not use a mutex
- *   (but the overhead is negligible here).
- *
- * - functions that do the actual logging logging (nm_log(), nm_logging_enabled()) are
- *   thread-safe and may be used from multiple threads.
- *    - When called from the not-main-thread, @mt_require_locking must be set to %TRUE.
- *      In this case, a Mutex will be used for accessing the global state.
- *    - When called from the main-thread, they may optionally pass @mt_require_locking %FALSE.
- *      This avoids extra locking and is in particular interesting for nm_logging_enabled(),
- *      which is expected to be called frequently and from the main-thread.
- *
- * Note that the logging macros honor %NM_THREAD_SAFE_ON_MAIN_THREAD define, to automatically
- * set @mt_require_locking. That means, by default %NM_THREAD_SAFE_ON_MAIN_THREAD is "1",
- * and code that only runs on the main-thread (which is the majority), can get away
- * without locking.
- */
-
-/*****************************************************************************/
-
-G_STATIC_ASSERT(LOG_EMERG == 0);
-G_STATIC_ASSERT(LOG_ALERT == 1);
-G_STATIC_ASSERT(LOG_CRIT == 2);
-G_STATIC_ASSERT(LOG_ERR == 3);
-G_STATIC_ASSERT(LOG_WARNING == 4);
-G_STATIC_ASSERT(LOG_NOTICE == 5);
-G_STATIC_ASSERT(LOG_INFO == 6);
-G_STATIC_ASSERT(LOG_DEBUG == 7);
-
-/* We have more then 32 logging domains. Assert that it compiles to a 64 bit sized enum */
-G_STATIC_ASSERT(sizeof(NMLogDomain) >= sizeof(guint64));
-
-/* Combined domains */
-#define LOGD_ALL_STRING     "ALL"
-#define LOGD_DEFAULT_STRING "DEFAULT"
-#define LOGD_DHCP_STRING    "DHCP"
-#define LOGD_IP_STRING      "IP"
-
-/*****************************************************************************/
-
-typedef enum {
-    LOG_BACKEND_GLIB,
-    LOG_BACKEND_SYSLOG,
-    LOG_BACKEND_JOURNAL,
-} LogBackend;
-
-typedef struct {
-    NMLogDomain num;
-    const char *name;
-} LogDesc;
-
-typedef struct {
-    char *logging_domains_to_string;
-} GlobalMain;
-
-typedef struct {
-    NMLogLevel  log_level;
-    bool        uses_syslog : 1;
-    bool        init_pre_done : 1;
-    bool        init_done : 1;
-    bool        debug_stderr : 1;
-    const char *prefix;
-    const char *syslog_identifier;
-
-    /* before we setup syslog (during start), the backend defaults to GLIB, meaning:
-     * we use g_log() for all logging. At that point, the application is not yet supposed
-     * to do any logging and doing so indicates a bug.
-     *
-     * Afterwards, the backend is either SYSLOG or JOURNAL. From that point, also
-     * g_log() is redirected to this backend via a logging handler. */
-    LogBackend log_backend;
-} Global;
-
-/*****************************************************************************/
-
-G_LOCK_DEFINE_STATIC(log);
-
-/* This data must only be accessed from the main-thread (and as
- * such does not need any lock). */
-static GlobalMain gl_main = {};
-
-static union {
-    /* a union with an immutable and a mutable alias for the Global.
-     * Since nm-logging must be thread-safe, we must take care at which
-     * places we only read value ("imm") and where we modify them ("mut"). */
-    Global       mut;
-    const Global imm;
-} gl = {
-    .imm =
-        {
-            /* nm_logging_setup ("INFO", LOGD_DEFAULT_STRING, NULL, NULL); */
-            .log_level         = LOGL_INFO,
-            .log_backend       = LOG_BACKEND_GLIB,
-            .syslog_identifier = "SYSLOG_IDENTIFIER=" G_LOG_DOMAIN,
-            .prefix            = "",
-        },
-};
-
-NMLogDomain _nm_logging_enabled_state[_LOGL_N_REAL] = {
-    /* nm_logging_setup ("INFO", LOGD_DEFAULT_STRING, NULL, NULL);
-     *
-     * Note: LOGD_VPN_PLUGIN is special and must be disabled for
-     * DEBUG and TRACE levels. */
-    [LOGL_INFO] = LOGD_DEFAULT,
-    [LOGL_WARN] = LOGD_DEFAULT,
-    [LOGL_ERR]  = LOGD_DEFAULT,
-};
-
-/*****************************************************************************/
-
-static const LogDesc domain_desc[] = {
-    {LOGD_PLATFORM, "PLATFORM"},
-    {LOGD_RFKILL, "RFKILL"},
-    {LOGD_ETHER, "ETHER"},
-    {LOGD_WIFI, "WIFI"},
-    {LOGD_BT, "BT"},
-    {LOGD_MB, "MB"},
-    {LOGD_DHCP4, "DHCP4"},
-    {LOGD_DHCP6, "DHCP6"},
-    {LOGD_PPP, "PPP"},
-    {LOGD_WIFI_SCAN, "WIFI_SCAN"},
-    {LOGD_IP4, "IP4"},
-    {LOGD_IP6, "IP6"},
-    {LOGD_AUTOIP4, "AUTOIP4"},
-    {LOGD_DNS, "DNS"},
-    {LOGD_VPN, "VPN"},
-    {LOGD_SHARING, "SHARING"},
-    {LOGD_SUPPLICANT, "SUPPLICANT"},
-    {LOGD_AGENTS, "AGENTS"},
-    {LOGD_SETTINGS, "SETTINGS"},
-    {LOGD_SUSPEND, "SUSPEND"},
-    {LOGD_CORE, "CORE"},
-    {LOGD_DEVICE, "DEVICE"},
-    {LOGD_OLPC, "OLPC"},
-    {LOGD_INFINIBAND, "INFINIBAND"},
-    {LOGD_FIREWALL, "FIREWALL"},
-    {LOGD_ADSL, "ADSL"},
-    {LOGD_BOND, "BOND"},
-    {LOGD_VLAN, "VLAN"},
-    {LOGD_BRIDGE, "BRIDGE"},
-    {LOGD_DBUS_PROPS, "DBUS_PROPS"},
-    {LOGD_TEAM, "TEAM"},
-    {LOGD_CONCHECK, "CONCHECK"},
-    {LOGD_DCB, "DCB"},
-    {LOGD_DISPATCH, "DISPATCH"},
-    {LOGD_AUDIT, "AUDIT"},
-    {LOGD_SYSTEMD, "SYSTEMD"},
-    {LOGD_VPN_PLUGIN, "VPN_PLUGIN"},
-    {LOGD_PROXY, "PROXY"},
-    {0},
-};
-
-/*****************************************************************************/
-
-static char *_domains_to_string(gboolean          include_level_override,
-                                NMLogLevel        log_level,
-                                const NMLogDomain log_state[static _LOGL_N_REAL]);
-
-/*****************************************************************************/
-
-static gboolean
-_syslog_identifier_valid_domain(const char *domain)
-{
-    char c;
-
-    if (!domain || !domain[0])
-        return FALSE;
-
-    /* we pass the syslog identifier as format string. No funny stuff. */
-
-    for (; (c = domain[0]); domain++) {
-        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
-            || NM_IN_SET(c, '-', '_'))
-            continue;
-        return FALSE;
-    }
-    return TRUE;
-}
-
-static gboolean
-_syslog_identifier_assert(const char *syslog_identifier)
-{
-    g_assert(syslog_identifier);
-    g_assert(g_str_has_prefix(syslog_identifier, "SYSLOG_IDENTIFIER="));
-    g_assert(_syslog_identifier_valid_domain(&syslog_identifier[NM_STRLEN("SYSLOG_IDENTIFIER=")]));
-    return TRUE;
-}
-
-static const char *
-syslog_identifier_domain(const char *syslog_identifier)
-{
-    nm_assert(_syslog_identifier_assert(syslog_identifier));
-    return &syslog_identifier[NM_STRLEN("SYSLOG_IDENTIFIER=")];
-}
-
-#if SYSTEMD_JOURNAL
-static const char *
-syslog_identifier_full(const char *syslog_identifier)
-{
-    nm_assert(_syslog_identifier_assert(syslog_identifier));
-    return &syslog_identifier[0];
-}
-#endif
-
-/*****************************************************************************/
-
-static gboolean
-match_log_level(const char *level, NMLogLevel *out_level, GError **error)
-{
-    if (_nm_log_parse_level(level, out_level))
-        return TRUE;
-
-    g_set_error(error,
-                _NM_MANAGER_ERROR,
-                _NM_MANAGER_ERROR_UNKNOWN_LOG_LEVEL,
-                _("Unknown log level '%s'"),
-                level);
-    return FALSE;
-}
-
-gboolean
-nm_logging_setup(const char *level, const char *domains, char **bad_domains, GError **error)
-{
-    GString *            unrecognized = NULL;
-    NMLogDomain          cur_log_state[_LOGL_N_REAL];
-    NMLogDomain          new_log_state[_LOGL_N_REAL];
-    NMLogLevel           cur_log_level;
-    NMLogLevel           new_log_level;
-    gs_free const char **domains_v = NULL;
-    gsize                i_d;
-    int                  i;
-    gboolean             had_platform_debug;
-    gs_free char *       domains_free = NULL;
-
-    NM_ASSERT_ON_MAIN_THREAD();
-
-    g_return_val_if_fail(!bad_domains || !*bad_domains, FALSE);
-    g_return_val_if_fail(!error || !*error, FALSE);
-
-    cur_log_level = gl.imm.log_level;
-    memcpy(cur_log_state, _nm_logging_enabled_state, sizeof(cur_log_state));
-
-    new_log_level = cur_log_level;
-
-    if (!domains || !*domains) {
-        domains_free = _domains_to_string(FALSE, cur_log_level, cur_log_state);
-        domains      = domains_free;
-    }
-
-    for (i = 0; i < G_N_ELEMENTS(new_log_state); i++)
-        new_log_state[i] = 0;
-
-    if (level && *level) {
-        if (!match_log_level(level, &new_log_level, error))
-            return FALSE;
-        if (new_log_level == _LOGL_KEEP) {
-            new_log_level = cur_log_level;
-            for (i = 0; i < G_N_ELEMENTS(new_log_state); i++)
-                new_log_state[i] = cur_log_state[i];
-        }
-    }
-
-    domains_v = nm_utils_strsplit_set(domains, ", ");
-    for (i_d = 0; domains_v && domains_v[i_d]; i_d++) {
-        const char *   s = domains_v[i_d];
-        const char *   p;
-        const LogDesc *diter;
-        NMLogLevel     domain_log_level;
-        NMLogDomain    bits;
-
-        /* LOGD_VPN_PLUGIN is protected, that is, when setting ALL or DEFAULT,
-         * it does not enable the verbose levels DEBUG and TRACE, because that
-         * may expose sensitive data. */
-        NMLogDomain protect = LOGD_NONE;
-
-        p = strchr(s, ':');
-        if (p) {
-            *((char *) p) = '\0';
-            if (!match_log_level(p + 1, &domain_log_level, error))
-                return FALSE;
-        } else
-            domain_log_level = new_log_level;
-
-        bits = 0;
-
-        if (domains_free) {
-            /* The caller didn't provide any domains to set (`nmcli general logging level DEBUG`).
-             * We reset all domains that were previously set, but we still want to protect
-             * VPN_PLUGIN domain. */
-            protect = LOGD_VPN_PLUGIN;
-        }
-
-        /* Check for combined domains */
-        if (!g_ascii_strcasecmp(s, LOGD_ALL_STRING)) {
-            bits    = LOGD_ALL;
-            protect = LOGD_VPN_PLUGIN;
-        } else if (!g_ascii_strcasecmp(s, LOGD_DEFAULT_STRING)) {
-            bits    = LOGD_DEFAULT;
-            protect = LOGD_VPN_PLUGIN;
-        } else if (!g_ascii_strcasecmp(s, LOGD_DHCP_STRING))
-            bits = LOGD_DHCP;
-        else if (!g_ascii_strcasecmp(s, LOGD_IP_STRING))
-            bits = LOGD_IP;
-
-        /* Check for compatibility domains */
-        else if (!g_ascii_strcasecmp(s, "HW"))
-            bits = LOGD_PLATFORM;
-        else if (!g_ascii_strcasecmp(s, "WIMAX"))
-            continue;
-
-        else {
-            for (diter = &domain_desc[0]; diter->name; diter++) {
-                if (!g_ascii_strcasecmp(diter->name, s)) {
-                    bits = diter->num;
-                    break;
-                }
-            }
-
-            if (!bits) {
-                if (!bad_domains) {
-                    g_set_error(error,
-                                _NM_MANAGER_ERROR,
-                                _NM_MANAGER_ERROR_UNKNOWN_LOG_DOMAIN,
-                                _("Unknown log domain '%s'"),
-                                s);
-                    return FALSE;
-                }
-
-                if (unrecognized)
-                    g_string_append(unrecognized, ", ");
-                else
-                    unrecognized = g_string_new(NULL);
-                g_string_append(unrecognized, s);
-                continue;
-            }
-        }
-
-        if (domain_log_level == _LOGL_KEEP) {
-            for (i = 0; i < G_N_ELEMENTS(new_log_state); i++)
-                new_log_state[i] = (new_log_state[i] & ~bits) | (cur_log_state[i] & bits);
-        } else {
-            for (i = 0; i < G_N_ELEMENTS(new_log_state); i++) {
-                if (i < domain_log_level)
-                    new_log_state[i] &= ~bits;
-                else {
-                    new_log_state[i] |= bits;
-                    if ((protect & bits) && i < LOGL_INFO)
-                        new_log_state[i] &= ~protect;
-                }
-            }
-        }
-    }
-
-    nm_clear_g_free(&gl_main.logging_domains_to_string);
-
-    had_platform_debug = _nm_logging_enabled_lockfree(LOGL_DEBUG, LOGD_PLATFORM);
-
-    G_LOCK(log);
-
-    gl.mut.log_level = new_log_level;
-    for (i = 0; i < G_N_ELEMENTS(new_log_state); i++)
-        _nm_logging_enabled_state[i] = new_log_state[i];
-
-    G_UNLOCK(log);
-
-    if (had_platform_debug && !_nm_logging_enabled_lockfree(LOGL_DEBUG, LOGD_PLATFORM)) {
-        /* when debug logging is enabled, platform will cache all access to
-         * sysctl. When the user disables debug-logging, we want to clear that
-         * cache right away. */
-        _nm_logging_clear_platform_logging_cache();
-    }
-
-    if (unrecognized)
-        *bad_domains = g_string_free(unrecognized, FALSE);
-
-    return TRUE;
-}
-
-const char *
-nm_logging_level_to_string(void)
-{
-    NM_ASSERT_ON_MAIN_THREAD();
-
-    return level_desc[gl.imm.log_level].name;
-}
-
-const char *
-nm_logging_all_levels_to_string(void)
-{
-    static GString *str;
-
-    if (G_UNLIKELY(!str)) {
-        int i;
-
-        str = g_string_new(NULL);
-        for (i = 0; i < G_N_ELEMENTS(level_desc); i++) {
-            if (str->len)
-                g_string_append_c(str, ',');
-            g_string_append(str, level_desc[i].name);
-        }
-    }
-
-    return str->str;
-}
-
-const char *
-nm_logging_domains_to_string(void)
-{
-    NM_ASSERT_ON_MAIN_THREAD();
-
-    if (G_UNLIKELY(!gl_main.logging_domains_to_string)) {
-        gl_main.logging_domains_to_string =
-            _domains_to_string(TRUE, gl.imm.log_level, _nm_logging_enabled_state);
-    }
-
-    return gl_main.logging_domains_to_string;
-}
-
-static char *
-_domains_to_string(gboolean          include_level_override,
-                   NMLogLevel        log_level,
-                   const NMLogDomain log_state[static _LOGL_N_REAL])
-{
-    const LogDesc *diter;
-    GString *      str;
-    int            i;
-
-    /* We don't just return g_strdup() the logging domains that were set during
-     * nm_logging_setup(), because we want to expand "DEFAULT" and "ALL".
-     */
-
-    str = g_string_sized_new(75);
-    for (diter = &domain_desc[0]; diter->name; diter++) {
-        /* If it's set for any lower level, it will also be set for LOGL_ERR */
-        if (!(diter->num & log_state[LOGL_ERR]))
-            continue;
-
-        if (str->len)
-            g_string_append_c(str, ',');
-        g_string_append(str, diter->name);
-
-        if (!include_level_override)
-            continue;
-
-        /* Check if it's logging at a lower level than the default. */
-        for (i = 0; i < log_level; i++) {
-            if (diter->num & log_state[i]) {
-                g_string_append_printf(str, ":%s", level_desc[i].name);
-                break;
-            }
-        }
-        /* Check if it's logging at a higher level than the default. */
-        if (!(diter->num & log_state[log_level])) {
-            for (i = log_level + 1; i < _LOGL_N_REAL; i++) {
-                if (diter->num & log_state[i]) {
-                    g_string_append_printf(str, ":%s", level_desc[i].name);
-                    break;
-                }
-            }
-        }
-    }
-    return g_string_free(str, FALSE);
-}
-
-static char _all_logging_domains_to_str[273];
-
-const char *
-nm_logging_all_domains_to_string(void)
-{
-    static const char *volatile str = NULL;
-    const char *s;
-
-again:
-    s = g_atomic_pointer_get(&str);
-    if (G_UNLIKELY(!s)) {
-        static gsize   once = 0;
-        const LogDesc *diter;
-        gsize          buf_l;
-        char *         buf_p;
-
-        if (!g_once_init_enter(&once))
-            goto again;
-
-        buf_p = _all_logging_domains_to_str;
-        buf_l = sizeof(_all_logging_domains_to_str);
-
-        nm_utils_strbuf_append_str(&buf_p, &buf_l, LOGD_DEFAULT_STRING);
-        for (diter = &domain_desc[0]; diter->name; diter++) {
-            nm_utils_strbuf_append_c(&buf_p, &buf_l, ',');
-            nm_utils_strbuf_append_str(&buf_p, &buf_l, diter->name);
-            if (diter->num == LOGD_DHCP6)
-                nm_utils_strbuf_append_str(&buf_p, &buf_l, "," LOGD_DHCP_STRING);
-            else if (diter->num == LOGD_IP6)
-                nm_utils_strbuf_append_str(&buf_p, &buf_l, "," LOGD_IP_STRING);
-        }
-        nm_utils_strbuf_append_str(&buf_p, &buf_l, LOGD_ALL_STRING);
-
-        /* Did you modify the logging domains (or their names)? Adjust the size of
-         * _all_logging_domains_to_str buffer above to have the exact size. */
-        nm_assert(strlen(_all_logging_domains_to_str) == sizeof(_all_logging_domains_to_str) - 1);
-        nm_assert(buf_l == 1);
-
-        s = _all_logging_domains_to_str;
-        g_atomic_pointer_set(&str, s);
-        g_once_init_leave(&once, 1);
-    }
-
-    return s;
-}
-
-/**
- * nm_logging_get_level:
- * @domain: find the lowest enabled logging level for the
- *   given domain. If this is a set of multiple
- *   domains, the most verbose level will be returned.
- *
- * Returns: the lowest (most verbose) logging level for the
- *   give @domain, or %_LOGL_OFF if it is disabled.
- **/
-NMLogLevel
-nm_logging_get_level(NMLogDomain domain)
-{
-    NMLogLevel sl = _LOGL_OFF;
-
-    G_STATIC_ASSERT(LOGL_TRACE == 0);
-    while (sl > LOGL_TRACE && _nm_logging_enabled_lockfree(sl - 1, domain))
-        sl--;
-    return sl;
-}
-
-gboolean
-_nm_logging_enabled_locking(NMLogLevel level, NMLogDomain domain)
-{
-    gboolean v;
-
-    G_LOCK(log);
-    v = _nm_logging_enabled_lockfree(level, domain);
-    G_UNLOCK(log);
-    return v;
-}
-
-gboolean
-_nm_log_enabled_impl(gboolean mt_require_locking, NMLogLevel level, NMLogDomain domain)
-{
-    return nm_logging_enabled_mt(mt_require_locking, level, domain);
-}
-
-#if SYSTEMD_JOURNAL
-static void
-_iovec_set(struct iovec *iov, const void *str, gsize len)
-{
-    iov->iov_base = (void *) str;
-    iov->iov_len  = len;
-}
-
-static void
-_iovec_set_string(struct iovec *iov, const char *str)
-{
-    _iovec_set(iov, str, strlen(str));
-}
-
-    #define _iovec_set_string_literal(iov, str) _iovec_set((iov), "" str "", NM_STRLEN(str))
-
-_nm_printf(3, 4) static void _iovec_set_format(struct iovec *iov,
-                                               char **       iov_free,
-                                               const char *  format,
-                                               ...)
-{
-    va_list ap;
-    char *  str;
-
-    va_start(ap, format);
-    str = g_strdup_vprintf(format, ap);
-    va_end(ap);
-
-    _iovec_set_string(iov, str);
-    *iov_free = str;
-}
-
-    #define _iovec_set_format_a(iov, reserve_extra, format, ...)                   \
-        G_STMT_START                                                               \
-        {                                                                          \
-            const gsize _size = (reserve_extra) + (NM_STRLEN(format) + 3);         \
-            char *const _buf  = g_alloca(_size);                                   \
-            int         _len;                                                      \
-                                                                                   \
-            G_STATIC_ASSERT_EXPR((reserve_extra) + (NM_STRLEN(format) + 3) <= 96); \
-                                                                                   \
-            _len = g_snprintf(_buf, _size, "" format "", ##__VA_ARGS__);           \
-                                                                                   \
-            nm_assert(_len >= 0);                                                  \
-            nm_assert(_len < _size);                                               \
-            nm_assert(_len == strlen(_buf));                                       \
-                                                                                   \
-            _iovec_set((iov), _buf, _len);                                         \
-        }                                                                          \
-        G_STMT_END
-
-    #define _iovec_set_format_str_a(iov, max_str_len, format, str_arg)  \
-        G_STMT_START                                                    \
-        {                                                               \
-            const char *_str_arg = (str_arg);                           \
-                                                                        \
-            nm_assert(_str_arg &&strlen(_str_arg) < (max_str_len));     \
-            _iovec_set_format_a((iov), (max_str_len), format, str_arg); \
-        }                                                               \
-        G_STMT_END
-
-#endif
-
-void
-_nm_log_impl(const char *file,
-             guint       line,
-             const char *func,
-             gboolean    mt_require_locking,
-             NMLogLevel  level,
-             NMLogDomain domain,
-             int         error,
-             const char *ifname,
-             const char *conn_uuid,
-             const char *fmt,
-             ...)
-{
-    va_list            args;
-    char *             msg;
-    GTimeVal           tv;
-    int                errsv;
-    const NMLogDomain *cur_log_state;
-    NMLogDomain        cur_log_state_copy[_LOGL_N_REAL];
-    Global             g_copy;
-    const Global *     g;
-
-    if (G_UNLIKELY(mt_require_locking)) {
-        G_LOCK(log);
-        /* we evaluate logging-enabled under lock. There is still a race that
-         * we might log the message below *after* logging was disabled. That means,
-         * when disabling logging, we might still log messages. */
-        if (!_nm_logging_enabled_lockfree(level, domain)) {
-            G_UNLOCK(log);
-            return;
-        }
-        g_copy = gl.imm;
-        memcpy(cur_log_state_copy, _nm_logging_enabled_state, sizeof(cur_log_state_copy));
-        G_UNLOCK(log);
-        g             = &g_copy;
-        cur_log_state = cur_log_state_copy;
-    } else {
-        NM_ASSERT_ON_MAIN_THREAD();
-        if (!_nm_logging_enabled_lockfree(level, domain))
-            return;
-        g             = &gl.imm;
-        cur_log_state = _nm_logging_enabled_state;
-    }
-
-    (void) cur_log_state;
-
-    errsv = errno;
-
-    /* Make sure that %m maps to the specified error */
-    if (error != 0) {
-        if (error < 0)
-            error = -error;
-        errno = error;
-    }
-
-    va_start(args, fmt);
-    msg = g_strdup_vprintf(fmt, args);
-    va_end(args);
-
-#define MESSAGE_FMT "%s%-7s [%ld.%04ld] %s"
-#define MESSAGE_ARG(prefix, tv, msg) \
-    prefix, level_desc[level].level_str, (tv).tv_sec, ((tv).tv_usec / 100), (msg)
-
-    g_get_current_time(&tv);
-
-    if (g->debug_stderr)
-        g_printerr(MESSAGE_FMT "\n", MESSAGE_ARG(g->prefix, tv, msg));
-
-    switch (g->log_backend) {
-#if SYSTEMD_JOURNAL
-    case LOG_BACKEND_JOURNAL:
-    {
-        gint64         now, boottime;
-        struct iovec   iov_data[15];
-        struct iovec * iov = iov_data;
-        char *         iov_free_data[5];
-        char **        iov_free = iov_free_data;
-        const LogDesc *diter;
-        NMLogDomain    dom_all;
-        char  s_log_domains_buf[NM_STRLEN("NM_LOG_DOMAINS=") + sizeof(_all_logging_domains_to_str)];
-        char *s_log_domains;
-        gsize l_log_domains;
-
-        now      = nm_utils_get_monotonic_timestamp_nsec();
-        boottime = nm_utils_monotonic_timestamp_as_boottime(now, 1);
-
-        _iovec_set_format_a(iov++, 30, "PRIORITY=%d", level_desc[level].syslog_level);
-        _iovec_set_format(iov++,
-                          iov_free++,
-                          "MESSAGE=" MESSAGE_FMT,
-                          MESSAGE_ARG(g->prefix, tv, msg));
-        _iovec_set_string(iov++, syslog_identifier_full(g->syslog_identifier));
-        _iovec_set_format_a(iov++, 30, "SYSLOG_PID=%ld", (long) getpid());
-
-        dom_all       = domain;
-        s_log_domains = s_log_domains_buf;
-        l_log_domains = sizeof(s_log_domains_buf);
-
-        nm_utils_strbuf_append_str(&s_log_domains, &l_log_domains, "NM_LOG_DOMAINS=");
-        for (diter = &domain_desc[0]; dom_all != 0 && diter->name; diter++) {
-            if (!NM_FLAGS_ANY(dom_all, diter->num))
-                continue;
-            if (dom_all != domain)
-                nm_utils_strbuf_append_c(&s_log_domains, &l_log_domains, ',');
-            nm_utils_strbuf_append_str(&s_log_domains, &l_log_domains, diter->name);
-            dom_all &= ~diter->num;
-        }
-        nm_assert(l_log_domains > 0);
-        _iovec_set(iov++, s_log_domains_buf, s_log_domains - s_log_domains_buf);
-
-        G_STATIC_ASSERT_EXPR(LOG_FAC(LOG_DAEMON) == 3);
-        _iovec_set_string_literal(iov++, "SYSLOG_FACILITY=3");
-        _iovec_set_format_str_a(iov++, 15, "NM_LOG_LEVEL=%s", level_desc[level].name);
-        if (func)
-            _iovec_set_format(iov++, iov_free++, "CODE_FUNC=%s", func);
-        _iovec_set_format(iov++, iov_free++, "CODE_FILE=%s", file ?: "");
-        _iovec_set_format_a(iov++, 20, "CODE_LINE=%u", line);
-        _iovec_set_format_a(iov++,
-                            60,
-                            "TIMESTAMP_MONOTONIC=%lld.%06lld",
-                            (long long) (now / NM_UTILS_NSEC_PER_SEC),
-                            (long long) ((now % NM_UTILS_NSEC_PER_SEC) / 1000));
-        _iovec_set_format_a(iov++,
-                            60,
-                            "TIMESTAMP_BOOTTIME=%lld.%06lld",
-                            (long long) (boottime / NM_UTILS_NSEC_PER_SEC),
-                            (long long) ((boottime % NM_UTILS_NSEC_PER_SEC) / 1000));
-        if (error != 0)
-            _iovec_set_format_a(iov++, 30, "ERRNO=%d", error);
-        if (ifname)
-            _iovec_set_format(iov++, iov_free++, "NM_DEVICE=%s", ifname);
-        if (conn_uuid)
-            _iovec_set_format(iov++, iov_free++, "NM_CONNECTION=%s", conn_uuid);
-
-        nm_assert(iov <= &iov_data[G_N_ELEMENTS(iov_data)]);
-        nm_assert(iov_free <= &iov_free_data[G_N_ELEMENTS(iov_free_data)]);
-
-        sd_journal_sendv(iov_data, iov - iov_data);
-
-        for (; --iov_free >= iov_free_data;)
-            g_free(*iov_free);
-    } break;
-#endif
-    case LOG_BACKEND_SYSLOG:
-        syslog(level_desc[level].syslog_level, MESSAGE_FMT, MESSAGE_ARG(g->prefix, tv, msg));
-        break;
-    default:
-        g_log(syslog_identifier_domain(g->syslog_identifier),
-              level_desc[level].g_log_level,
-              MESSAGE_FMT,
-              MESSAGE_ARG(g->prefix, tv, msg));
-        break;
-    }
-
-    g_free(msg);
-
-    errno = errsv;
-}
-
-/*****************************************************************************/
-
-void
-_nm_utils_monotonic_timestamp_initialized(const struct timespec *tp,
-                                          gint64                 offset_sec,
-                                          gboolean               is_boottime)
-{
-    NM_ASSERT_ON_MAIN_THREAD();
-
-    if (_nm_logging_enabled_lockfree(LOGL_DEBUG, LOGD_CORE)) {
-        time_t    now = time(NULL);
-        struct tm tm;
-        char      s[255];
-
-        strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime_r(&now, &tm));
-        nm_log_dbg(LOGD_CORE,
-                   "monotonic timestamp started counting 1.%09ld seconds ago with "
-                   "an offset of %lld.0 seconds to %s (local time is %s)",
-                   tp->tv_nsec,
-                   (long long) -offset_sec,
-                   is_boottime ? "CLOCK_BOOTTIME" : "CLOCK_MONOTONIC",
-                   s);
-    }
-}
-
-/*****************************************************************************/
-
-static void
-nm_log_handler(const char *log_domain, GLogLevelFlags level, const char *message, gpointer ignored)
-{
-    int syslog_priority;
-
-    switch (level & G_LOG_LEVEL_MASK) {
-    case G_LOG_LEVEL_ERROR:
-        syslog_priority = LOG_CRIT;
-        break;
-    case G_LOG_LEVEL_CRITICAL:
-        syslog_priority = LOG_ERR;
-        break;
-    case G_LOG_LEVEL_WARNING:
-        syslog_priority = LOG_WARNING;
-        break;
-    case G_LOG_LEVEL_MESSAGE:
-        syslog_priority = LOG_NOTICE;
-        break;
-    case G_LOG_LEVEL_DEBUG:
-        syslog_priority = LOG_DEBUG;
-        break;
-    case G_LOG_LEVEL_INFO:
-    default:
-        syslog_priority = LOG_INFO;
-        break;
-    }
-
-    /* we don't need any locking here. The glib log handler gets only registered
-     * once during nm_logging_init() and the global data is not modified afterwards. */
-    nm_assert(gl.imm.init_done);
-
-    if (gl.imm.debug_stderr)
-        g_printerr("%s%s\n", gl.imm.prefix, message ?: "");
-
-    switch (gl.imm.log_backend) {
-#if SYSTEMD_JOURNAL
-    case LOG_BACKEND_JOURNAL:
-    {
-        gint64 now, boottime;
-
-        now      = nm_utils_get_monotonic_timestamp_nsec();
-        boottime = nm_utils_monotonic_timestamp_as_boottime(now, 1);
-
-        sd_journal_send("PRIORITY=%d",
-                        syslog_priority,
-                        "MESSAGE=%s%s",
-                        gl.imm.prefix,
-                        message ?: "",
-                        syslog_identifier_full(gl.imm.syslog_identifier),
-                        "SYSLOG_PID=%ld",
-                        (long) getpid(),
-                        "SYSLOG_FACILITY=3",
-                        "GLIB_DOMAIN=%s",
-                        log_domain ?: "",
-                        "GLIB_LEVEL=%d",
-                        (int) (level & G_LOG_LEVEL_MASK),
-                        "TIMESTAMP_MONOTONIC=%lld.%06lld",
-                        (long long) (now / NM_UTILS_NSEC_PER_SEC),
-                        (long long) ((now % NM_UTILS_NSEC_PER_SEC) / 1000),
-                        "TIMESTAMP_BOOTTIME=%lld.%06lld",
-                        (long long) (boottime / NM_UTILS_NSEC_PER_SEC),
-                        (long long) ((boottime % NM_UTILS_NSEC_PER_SEC) / 1000),
-                        NULL);
-    } break;
-#endif
-    default:
-        syslog(syslog_priority, "%s%s", gl.imm.prefix, message ?: "");
-        break;
-    }
-}
-
-gboolean
-nm_logging_syslog_enabled(void)
-{
-    NM_ASSERT_ON_MAIN_THREAD();
-
-    return gl.imm.uses_syslog;
-}
-
-void
-nm_logging_init_pre(const char *syslog_identifier, char *prefix_take)
-{
-    /* this function may be called zero or one times, and only
-     * - on the main thread
-     * - not after nm_logging_init(). */
-
-    NM_ASSERT_ON_MAIN_THREAD();
-
-    if (gl.imm.init_pre_done)
-        g_return_if_reached();
-
-    if (gl.imm.init_done)
-        g_return_if_reached();
-
-    if (!_syslog_identifier_valid_domain(syslog_identifier))
-        g_return_if_reached();
-
-    if (!prefix_take || !prefix_take[0])
-        g_return_if_reached();
-
-    G_LOCK(log);
-
-    gl.mut.init_pre_done = TRUE;
-
-    gl.mut.syslog_identifier = g_strdup_printf("SYSLOG_IDENTIFIER=%s", syslog_identifier);
-    nm_assert(_syslog_identifier_assert(gl.imm.syslog_identifier));
-
-    /* we pass the allocated string on and never free it. */
-    gl.mut.prefix = prefix_take;
-
-    G_UNLOCK(log);
-}
-
-void
-nm_logging_init(const char *logging_backend, gboolean debug)
-{
-    gboolean   fetch_monotonic_timestamp = FALSE;
-    gboolean   obsolete_debug_backend    = FALSE;
-    LogBackend x_log_backend;
-
-    /* this function may be called zero or one times, and only on the
-     * main thread. */
-
-    NM_ASSERT_ON_MAIN_THREAD();
-
-    nm_assert(NM_IN_STRSET("" NM_CONFIG_DEFAULT_LOGGING_BACKEND,
-                           NM_LOG_CONFIG_BACKEND_JOURNAL,
-                           NM_LOG_CONFIG_BACKEND_SYSLOG));
-
-    if (gl.imm.init_done)
-        g_return_if_reached();
-
-    if (!logging_backend)
-        logging_backend = "" NM_CONFIG_DEFAULT_LOGGING_BACKEND;
-
-    if (nm_streq(logging_backend, NM_LOG_CONFIG_BACKEND_DEBUG)) {
-        /* "debug" was wrongly documented as a valid logging backend. It makes no sense however,
-         * because printing to stderr only makes sense when not demonizing. Whether to daemonize
-         * is only controlled via command line arguments (--no-daemon, --debug) and not via the
-         * logging backend from configuration.
-         *
-         * Fall back to the default. */
-        logging_backend        = "" NM_CONFIG_DEFAULT_LOGGING_BACKEND;
-        obsolete_debug_backend = TRUE;
-    }
-
-    G_LOCK(log);
-
-#if SYSTEMD_JOURNAL
-    if (!nm_streq(logging_backend, NM_LOG_CONFIG_BACKEND_SYSLOG)) {
-        x_log_backend = LOG_BACKEND_JOURNAL;
-
-        /* We only log the monotonic-timestamp with structured logging (journal).
-         * Only in this case, fetch the timestamp. */
-        fetch_monotonic_timestamp = TRUE;
-    } else
-#endif
-    {
-        x_log_backend = LOG_BACKEND_SYSLOG;
-        openlog(syslog_identifier_domain(gl.imm.syslog_identifier), LOG_PID, LOG_DAEMON);
-    }
-
-    gl.mut.init_done    = TRUE;
-    gl.mut.log_backend  = x_log_backend;
-    gl.mut.uses_syslog  = TRUE;
-    gl.mut.debug_stderr = debug;
-
-    g_log_set_handler(syslog_identifier_domain(gl.imm.syslog_identifier),
-                      G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
-                      nm_log_handler,
-                      NULL);
-
-    G_UNLOCK(log);
-
-    if (fetch_monotonic_timestamp) {
-        /* ensure we read a monotonic timestamp. Reading the timestamp the first
-         * time causes a logging message. We don't want to do that during _nm_log_impl. */
-        nm_utils_get_monotonic_timestamp_nsec();
-    }
-
-    if (obsolete_debug_backend)
-        nm_log_dbg(LOGD_CORE,
-                   "config: ignore deprecated logging backend 'debug', fallback to '%s'",
-                   logging_backend);
-
-    if (nm_streq(logging_backend, NM_LOG_CONFIG_BACKEND_SYSLOG)) {
-        /* good */
-    } else if (nm_streq(logging_backend, NM_LOG_CONFIG_BACKEND_JOURNAL)) {
-#if !SYSTEMD_JOURNAL
-        nm_log_warn(LOGD_CORE,
-                    "config: logging backend 'journal' is not available, fallback to 'syslog'");
-#endif
-    } else {
-        nm_log_warn(LOGD_CORE,
-                    "config: invalid logging backend '%s', fallback to '%s'",
-                    logging_backend,
-#if SYSTEMD_JOURNAL
-                    NM_LOG_CONFIG_BACKEND_JOURNAL
-#else
-                    NM_LOG_CONFIG_BACKEND_SYSLOG
-#endif
-        );
-    }
-}
diff --git a/shared/nm-log-core/nm-logging.h b/shared/nm-log-core/nm-logging.h
deleted file mode 100644
index d3143d39..00000000
--- a/shared/nm-log-core/nm-logging.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2006 - 2012 Red Hat, Inc.
- * Copyright (C) 2006 - 2008 Novell, Inc.
- */
-
-#ifndef __NETWORKMANAGER_LOGGING_H__
-#define __NETWORKMANAGER_LOGGING_H__
-
-#ifdef __NM_TEST_UTILS_H__
-    #error nm-test-utils.h must be included as last header
-#endif
-
-#include "nm-glib-aux/nm-logging-fwd.h"
-
-#define NM_LOG_CONFIG_BACKEND_DEBUG   "debug"
-#define NM_LOG_CONFIG_BACKEND_SYSLOG  "syslog"
-#define NM_LOG_CONFIG_BACKEND_JOURNAL "journal"
-
-#define nm_log_err(domain, ...)   nm_log(LOGL_ERR, (domain), NULL, NULL, __VA_ARGS__)
-#define nm_log_warn(domain, ...)  nm_log(LOGL_WARN, (domain), NULL, NULL, __VA_ARGS__)
-#define nm_log_info(domain, ...)  nm_log(LOGL_INFO, (domain), NULL, NULL, __VA_ARGS__)
-#define nm_log_dbg(domain, ...)   nm_log(LOGL_DEBUG, (domain), NULL, NULL, __VA_ARGS__)
-#define nm_log_trace(domain, ...) nm_log(LOGL_TRACE, (domain), NULL, NULL, __VA_ARGS__)
-
-//#define _NM_LOG_FUNC G_STRFUNC
-#define _NM_LOG_FUNC NULL
-
-/* A wrapper for the _nm_log_impl() function that adds call site information.
- * Contrary to nm_log(), it unconditionally calls the function without
- * checking whether logging for the given level and domain is enabled. */
-#define _nm_log_mt(mt_require_locking, level, domain, error, ifname, con_uuid, ...) \
-    G_STMT_START                                                                    \
-    {                                                                               \
-        _nm_log_impl(__FILE__,                                                      \
-                     __LINE__,                                                      \
-                     _NM_LOG_FUNC,                                                  \
-                     (mt_require_locking),                                          \
-                     (level),                                                       \
-                     (domain),                                                      \
-                     (error),                                                       \
-                     (ifname),                                                      \
-                     (con_uuid),                                                    \
-                     ""__VA_ARGS__);                                                \
-    }                                                                               \
-    G_STMT_END
-
-#define _nm_log(level, domain, error, ifname, con_uuid, ...) \
-    _nm_log_mt(!(NM_THREAD_SAFE_ON_MAIN_THREAD),             \
-               level,                                        \
-               domain,                                       \
-               error,                                        \
-               ifname,                                       \
-               con_uuid,                                     \
-               __VA_ARGS__)
-
-/* nm_log() only evaluates its argument list after checking
- * whether logging for the given level/domain is enabled.  */
-#define nm_log(level, domain, ifname, con_uuid, ...)                  \
-    G_STMT_START                                                      \
-    {                                                                 \
-        if (nm_logging_enabled((level), (domain))) {                  \
-            _nm_log(level, domain, 0, ifname, con_uuid, __VA_ARGS__); \
-        }                                                             \
-    }                                                                 \
-    G_STMT_END
-
-#define _nm_log_ptr(level, domain, ifname, con_uuid, self, prefix, ...)             \
-    nm_log((level),                                                                 \
-           (domain),                                                                \
-           (ifname),                                                                \
-           (con_uuid),                                                              \
-           "%s[" NM_HASH_OBFUSCATE_PTR_FMT "] " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
-           (prefix) ?: "",                                                          \
-           NM_HASH_OBFUSCATE_PTR(self) _NM_UTILS_MACRO_REST(__VA_ARGS__))
-
-static inline gboolean
-_nm_log_ptr_is_debug(NMLogLevel level)
-{
-    return level <= LOGL_DEBUG;
-}
-
-/* log a message for an object (with providing a generic @self pointer) */
-#define nm_log_ptr(level, domain, ifname, con_uuid, self, prefix, ...)                           \
-    G_STMT_START                                                                                 \
-    {                                                                                            \
-        if (_nm_log_ptr_is_debug(level)) {                                                       \
-            _nm_log_ptr((level), (domain), (ifname), (con_uuid), (self), (prefix), __VA_ARGS__); \
-        } else {                                                                                 \
-            const char *__prefix = (prefix);                                                     \
-                                                                                                 \
-            nm_log((level),                                                                      \
-                   (domain),                                                                     \
-                   (ifname),                                                                     \
-                   (con_uuid),                                                                   \
-                   "%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__),                                    \
-                   __prefix ?: "",                                                               \
-                   __prefix ? " " : "" _NM_UTILS_MACRO_REST(__VA_ARGS__));                       \
-        }                                                                                        \
-    }                                                                                            \
-    G_STMT_END
-
-#define _nm_log_obj(level, domain, ifname, con_uuid, self, prefix, ...) \
-    _nm_log_ptr((level), (domain), (ifname), (con_uuid), (self), prefix, __VA_ARGS__)
-
-/* log a message for an object (with providing a @self pointer to a GObject).
- * Contrary to nm_log_ptr(), @self must be a GObject type (or %NULL).
- * As of now, nm_log_obj() is identical to nm_log_ptr(), but we might change that */
-#define nm_log_obj(level, domain, ifname, con_uuid, self, prefix, ...) \
-    nm_log_ptr((level), (domain), (ifname), (con_uuid), (self), prefix, __VA_ARGS__)
-
-const char *nm_logging_level_to_string(void);
-const char *nm_logging_domains_to_string(void);
-
-/*****************************************************************************/
-
-extern NMLogDomain _nm_logging_enabled_state[_LOGL_N_REAL];
-
-static inline gboolean
-_nm_logging_enabled_lockfree(NMLogLevel level, NMLogDomain domain)
-{
-    nm_assert(((guint) level) < G_N_ELEMENTS(_nm_logging_enabled_state));
-    return (((guint) level) < G_N_ELEMENTS(_nm_logging_enabled_state))
-           && !!(_nm_logging_enabled_state[level] & domain);
-}
-
-gboolean _nm_logging_enabled_locking(NMLogLevel level, NMLogDomain domain);
-
-static inline gboolean
-nm_logging_enabled_mt(gboolean mt_require_locking, NMLogLevel level, NMLogDomain domain)
-{
-    if (mt_require_locking)
-        return _nm_logging_enabled_locking(level, domain);
-
-    NM_ASSERT_ON_MAIN_THREAD();
-    return _nm_logging_enabled_lockfree(level, domain);
-}
-
-#define nm_logging_enabled(level, domain) \
-    nm_logging_enabled_mt(!(NM_THREAD_SAFE_ON_MAIN_THREAD), level, domain)
-
-/*****************************************************************************/
-
-NMLogLevel nm_logging_get_level(NMLogDomain domain);
-
-const char *nm_logging_all_levels_to_string(void);
-const char *nm_logging_all_domains_to_string(void);
-
-gboolean
-nm_logging_setup(const char *level, const char *domains, char **bad_domains, GError **error);
-
-void nm_logging_init_pre(const char *syslog_identifier, char *prefix_take);
-
-void nm_logging_init(const char *logging_backend, gboolean debug);
-
-gboolean nm_logging_syslog_enabled(void);
-
-/*****************************************************************************/
-
-#define __NMLOG_DEFAULT(level, domain, prefix, ...)         \
-    G_STMT_START                                            \
-    {                                                       \
-        nm_log((level),                                     \
-               (domain),                                    \
-               NULL,                                        \
-               NULL,                                        \
-               "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__),   \
-               (prefix) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
-    }                                                       \
-    G_STMT_END
-
-#define __NMLOG_DEFAULT_WITH_ADDR(level, domain, prefix, ...)                            \
-    G_STMT_START                                                                         \
-    {                                                                                    \
-        nm_log((level),                                                                  \
-               (domain),                                                                 \
-               NULL,                                                                     \
-               NULL,                                                                     \
-               "%s[" NM_HASH_OBFUSCATE_PTR_FMT "]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
-               (prefix),                                                                 \
-               NM_HASH_OBFUSCATE_PTR(self) _NM_UTILS_MACRO_REST(__VA_ARGS__));           \
-    }                                                                                    \
-    G_STMT_END
-
-/*****************************************************************************/
-
-extern void _nm_logging_clear_platform_logging_cache(void);
-
-#endif /* __NETWORKMANAGER_LOGGING_H__ */
diff --git a/shared/nm-platform/nm-netlink.c b/shared/nm-platform/nm-netlink.c
deleted file mode 100644
index 7a6d7e04..00000000
--- a/shared/nm-platform/nm-netlink.c
+++ /dev/null
@@ -1,1518 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-netlink.h"
-
-#include <unistd.h>
-#include <fcntl.h>
-
-/*****************************************************************************/
-
-#ifndef SOL_NETLINK
-    #define SOL_NETLINK 270
-#endif
-
-/*****************************************************************************/
-
-#define NL_SOCK_PASSCRED     (1 << 1)
-#define NL_MSG_PEEK          (1 << 3)
-#define NL_MSG_PEEK_EXPLICIT (1 << 4)
-#define NL_NO_AUTO_ACK       (1 << 5)
-
-#ifndef NETLINK_EXT_ACK
-    #define NETLINK_EXT_ACK 11
-#endif
-
-struct nl_msg {
-    int                nm_protocol;
-    struct sockaddr_nl nm_src;
-    struct sockaddr_nl nm_dst;
-    struct ucred       nm_creds;
-    struct nlmsghdr *  nm_nlh;
-    size_t             nm_size;
-    bool               nm_creds_has : 1;
-};
-
-struct nl_sock {
-    struct sockaddr_nl s_local;
-    struct sockaddr_nl s_peer;
-    int                s_fd;
-    int                s_proto;
-    unsigned int       s_seq_next;
-    unsigned int       s_seq_expect;
-    int                s_flags;
-    size_t             s_bufsize;
-};
-
-/*****************************************************************************/
-
-NM_UTILS_ENUM2STR_DEFINE(nl_nlmsgtype2str,
-                         int,
-                         NM_UTILS_ENUM2STR(NLMSG_NOOP, "NOOP"),
-                         NM_UTILS_ENUM2STR(NLMSG_ERROR, "ERROR"),
-                         NM_UTILS_ENUM2STR(NLMSG_DONE, "DONE"),
-                         NM_UTILS_ENUM2STR(NLMSG_OVERRUN, "OVERRUN"), );
-
-NM_UTILS_FLAGS2STR_DEFINE(nl_nlmsg_flags2str,
-                          int,
-                          NM_UTILS_FLAGS2STR(NLM_F_REQUEST, "REQUEST"),
-                          NM_UTILS_FLAGS2STR(NLM_F_MULTI, "MULTI"),
-                          NM_UTILS_FLAGS2STR(NLM_F_ACK, "ACK"),
-                          NM_UTILS_FLAGS2STR(NLM_F_ECHO, "ECHO"),
-                          NM_UTILS_FLAGS2STR(NLM_F_ROOT, "ROOT"),
-                          NM_UTILS_FLAGS2STR(NLM_F_MATCH, "MATCH"),
-                          NM_UTILS_FLAGS2STR(NLM_F_ATOMIC, "ATOMIC"),
-                          NM_UTILS_FLAGS2STR(NLM_F_REPLACE, "REPLACE"),
-                          NM_UTILS_FLAGS2STR(NLM_F_EXCL, "EXCL"),
-                          NM_UTILS_FLAGS2STR(NLM_F_CREATE, "CREATE"),
-                          NM_UTILS_FLAGS2STR(NLM_F_APPEND, "APPEND"), );
-
-/*****************************************************************************/
-
-const char *
-nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len)
-{
-    const char *b;
-    const char *s;
-    guint       flags, flags_before;
-    const char *prefix;
-
-    if (!nm_utils_to_string_buffer_init_null(hdr, &buf, &len))
-        return buf;
-
-    b = buf;
-
-    switch (hdr->nlmsg_type) {
-    case RTM_GETLINK:
-        s = "RTM_GETLINK";
-        break;
-    case RTM_NEWLINK:
-        s = "RTM_NEWLINK";
-        break;
-    case RTM_DELLINK:
-        s = "RTM_DELLINK";
-        break;
-    case RTM_SETLINK:
-        s = "RTM_SETLINK";
-        break;
-    case RTM_GETADDR:
-        s = "RTM_GETADDR";
-        break;
-    case RTM_NEWADDR:
-        s = "RTM_NEWADDR";
-        break;
-    case RTM_DELADDR:
-        s = "RTM_DELADDR";
-        break;
-    case RTM_GETROUTE:
-        s = "RTM_GETROUTE";
-        break;
-    case RTM_NEWROUTE:
-        s = "RTM_NEWROUTE";
-        break;
-    case RTM_DELROUTE:
-        s = "RTM_DELROUTE";
-        break;
-    case RTM_GETRULE:
-        s = "RTM_GETRULE";
-        break;
-    case RTM_NEWRULE:
-        s = "RTM_NEWRULE";
-        break;
-    case RTM_DELRULE:
-        s = "RTM_DELRULE";
-        break;
-    case RTM_GETQDISC:
-        s = "RTM_GETQDISC";
-        break;
-    case RTM_NEWQDISC:
-        s = "RTM_NEWQDISC";
-        break;
-    case RTM_DELQDISC:
-        s = "RTM_DELQDISC";
-        break;
-    case RTM_GETTFILTER:
-        s = "RTM_GETTFILTER";
-        break;
-    case RTM_NEWTFILTER:
-        s = "RTM_NEWTFILTER";
-        break;
-    case RTM_DELTFILTER:
-        s = "RTM_DELTFILTER";
-        break;
-    case NLMSG_NOOP:
-        s = "NLMSG_NOOP";
-        break;
-    case NLMSG_ERROR:
-        s = "NLMSG_ERROR";
-        break;
-    case NLMSG_DONE:
-        s = "NLMSG_DONE";
-        break;
-    case NLMSG_OVERRUN:
-        s = "NLMSG_OVERRUN";
-        break;
-    default:
-        s = NULL;
-        break;
-    }
-
-    if (s)
-        nm_utils_strbuf_append_str(&buf, &len, s);
-    else
-        nm_utils_strbuf_append(&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type);
-
-    flags = hdr->nlmsg_flags;
-
-    if (!flags) {
-        nm_utils_strbuf_append_str(&buf, &len, ", flags 0");
-        goto flags_done;
-    }
-
-#define _F(f, n)                                                   \
-    G_STMT_START                                                   \
-    {                                                              \
-        if (NM_FLAGS_ALL(flags, f)) {                              \
-            flags &= ~(f);                                         \
-            nm_utils_strbuf_append(&buf, &len, "%s%s", prefix, n); \
-            if (!flags)                                            \
-                goto flags_done;                                   \
-            prefix = ",";                                          \
-        }                                                          \
-    }                                                              \
-    G_STMT_END
-
-    prefix       = ", flags ";
-    flags_before = flags;
-    _F(NLM_F_REQUEST, "request");
-    _F(NLM_F_MULTI, "multi");
-    _F(NLM_F_ACK, "ack");
-    _F(NLM_F_ECHO, "echo");
-    _F(NLM_F_DUMP_INTR, "dump_intr");
-    _F(0x20 /*NLM_F_DUMP_FILTERED*/, "dump_filtered");
-
-    if (flags_before != flags)
-        prefix = ";";
-
-    switch (hdr->nlmsg_type) {
-    case RTM_NEWLINK:
-    case RTM_NEWADDR:
-    case RTM_NEWROUTE:
-    case RTM_NEWQDISC:
-    case RTM_NEWTFILTER:
-        _F(NLM_F_REPLACE, "replace");
-        _F(NLM_F_EXCL, "excl");
-        _F(NLM_F_CREATE, "create");
-        _F(NLM_F_APPEND, "append");
-        break;
-    case RTM_GETLINK:
-    case RTM_GETADDR:
-    case RTM_GETROUTE:
-    case RTM_DELQDISC:
-    case RTM_DELTFILTER:
-        _F(NLM_F_DUMP, "dump");
-        _F(NLM_F_ROOT, "root");
-        _F(NLM_F_MATCH, "match");
-        _F(NLM_F_ATOMIC, "atomic");
-        break;
-    }
-
-#undef _F
-
-    if (flags_before != flags)
-        prefix = ";";
-    nm_utils_strbuf_append(&buf, &len, "%s0x%04x", prefix, flags);
-
-flags_done:
-
-    nm_utils_strbuf_append(&buf, &len, ", seq %u", (unsigned) hdr->nlmsg_seq);
-
-    return b;
-}
-
-/*****************************************************************************/
-
-struct nlmsghdr *
-nlmsg_hdr(struct nl_msg *n)
-{
-    return n->nm_nlh;
-}
-
-void *
-nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
-{
-    char * buf       = (char *) n->nm_nlh;
-    size_t nlmsg_len = n->nm_nlh->nlmsg_len;
-    size_t tlen;
-
-    nm_assert(pad >= 0);
-
-    if (len > n->nm_size)
-        return NULL;
-
-    tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
-
-    if ((tlen + nlmsg_len) > n->nm_size)
-        return NULL;
-
-    buf += nlmsg_len;
-    n->nm_nlh->nlmsg_len += tlen;
-
-    if (tlen > len)
-        memset(buf + len, 0, tlen - len);
-
-    return buf;
-}
-
-/*****************************************************************************/
-
-struct nlattr *
-nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
-{
-    struct nlattr *nla;
-    int            tlen;
-
-    if (attrlen < 0)
-        return NULL;
-
-    tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen);
-
-    if (tlen > msg->nm_size)
-        return NULL;
-
-    nla           = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
-    nla->nla_type = attrtype;
-    nla->nla_len  = nla_attr_size(attrlen);
-
-    if (attrlen)
-        memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
-    msg->nm_nlh->nlmsg_len = tlen;
-
-    return nla;
-}
-
-/*****************************************************************************/
-
-struct nl_msg *
-nlmsg_alloc_size(size_t len)
-{
-    struct nl_msg *nm;
-
-    if (len < sizeof(struct nlmsghdr))
-        len = sizeof(struct nlmsghdr);
-
-    nm  = g_slice_new(struct nl_msg);
-    *nm = (struct nl_msg){
-        .nm_protocol = -1,
-        .nm_size     = len,
-        .nm_nlh      = g_malloc0(len),
-    };
-    nm->nm_nlh->nlmsg_len = nlmsg_total_size(0);
-    return nm;
-}
-
-/**
- * Allocate a new netlink message with the default maximum payload size.
- *
- * Allocates a new netlink message without any further payload. The
- * maximum payload size defaults to PAGESIZE or as otherwise specified
- * with nlmsg_set_default_size().
- *
- * @return Newly allocated netlink message or NULL.
- */
-struct nl_msg *
-nlmsg_alloc(void)
-{
-    return nlmsg_alloc_size(nm_utils_getpagesize());
-}
-
-struct nl_msg *
-nlmsg_alloc_convert(struct nlmsghdr *hdr)
-{
-    struct nl_msg *nm;
-
-    nm = nlmsg_alloc_size(NLMSG_ALIGN(hdr->nlmsg_len));
-    memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
-    return nm;
-}
-
-struct nl_msg *
-nlmsg_alloc_simple(int nlmsgtype, int flags)
-{
-    struct nl_msg *nm;
-    struct nlmsghdr *new;
-
-    nm               = nlmsg_alloc();
-    new              = nm->nm_nlh;
-    new->nlmsg_type  = nlmsgtype;
-    new->nlmsg_flags = flags;
-    return nm;
-}
-
-void
-nlmsg_free(struct nl_msg *msg)
-{
-    if (!msg)
-        return;
-
-    g_free(msg->nm_nlh);
-    g_slice_free(struct nl_msg, msg);
-}
-
-/*****************************************************************************/
-
-int
-nlmsg_append(struct nl_msg *n, const void *data, size_t len, int pad)
-{
-    void *tmp;
-
-    nm_assert(n);
-    nm_assert(data);
-    nm_assert(len > 0);
-    nm_assert(pad >= 0);
-
-    tmp = nlmsg_reserve(n, len, pad);
-    if (tmp == NULL)
-        return -ENOMEM;
-
-    memcpy(tmp, data, len);
-    return 0;
-}
-
-/*****************************************************************************/
-
-int
-nlmsg_parse(struct nlmsghdr *        nlh,
-            int                      hdrlen,
-            struct nlattr *          tb[],
-            int                      maxtype,
-            const struct nla_policy *policy)
-{
-    if (!nlmsg_valid_hdr(nlh, hdrlen))
-        return -NME_NL_MSG_TOOSHORT;
-
-    return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), policy);
-}
-
-struct nlmsghdr *
-nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags)
-{
-    struct nlmsghdr *nlh;
-
-    if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
-        g_return_val_if_reached(NULL);
-
-    nlh              = (struct nlmsghdr *) n->nm_nlh;
-    nlh->nlmsg_type  = type;
-    nlh->nlmsg_flags = flags;
-    nlh->nlmsg_pid   = pid;
-    nlh->nlmsg_seq   = seq;
-
-    if (payload > 0 && nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
-        return NULL;
-
-    return nlh;
-}
-
-size_t
-nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
-{
-    const char *src;
-    size_t      srclen;
-    size_t      len;
-
-    /* - Always writes @dstsize bytes to @dst
-     * - Copies the first non-NUL characters to @dst.
-     *   Any characters after the first NUL bytes in @nla are ignored.
-     * - If the string @nla is longer than @dstsize, the string
-     *   gets truncated. @dst will always be NUL terminated. */
-
-    if (G_UNLIKELY(dstsize <= 1)) {
-        if (dstsize == 1)
-            dst[0] = '\0';
-        if (nla && (srclen = nla_len(nla)) > 0)
-            return strnlen(nla_data(nla), srclen);
-        return 0;
-    }
-
-    nm_assert(dst);
-
-    if (nla) {
-        srclen = nla_len(nla);
-        if (srclen > 0) {
-            src    = nla_data(nla);
-            srclen = strnlen(src, srclen);
-            if (srclen > 0) {
-                len = NM_MIN(dstsize - 1, srclen);
-                memcpy(dst, src, len);
-                memset(&dst[len], 0, dstsize - len);
-                return srclen;
-            }
-        }
-    }
-
-    memset(dst, 0, dstsize);
-    return 0;
-}
-
-size_t
-nla_memcpy(void *dst, const struct nlattr *nla, size_t dstsize)
-{
-    size_t len;
-    int    srclen;
-
-    if (!nla)
-        return 0;
-
-    srclen = nla_len(nla);
-
-    if (srclen <= 0) {
-        nm_assert(srclen == 0);
-        return 0;
-    }
-
-    len = NM_MIN((size_t) srclen, dstsize);
-    if (len > 0) {
-        /* there is a crucial difference between nla_strlcpy() and nla_memcpy().
-         * The former always write @dstsize bytes (akin to strncpy()), here, we only
-         * write the bytes that we actually have (leaving the remainder undefined). */
-        memcpy(dst, nla_data(nla), len);
-    }
-
-    return srclen;
-}
-
-int
-nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
-{
-    struct nlattr *nla;
-
-    nla = nla_reserve(msg, attrtype, datalen);
-    if (!nla) {
-        if (datalen < 0)
-            g_return_val_if_reached(-NME_BUG);
-
-        return -ENOMEM;
-    }
-
-    if (datalen > 0)
-        memcpy(nla_data(nla), data, datalen);
-
-    return 0;
-}
-
-struct nlattr *
-nla_find(const struct nlattr *head, int len, int attrtype)
-{
-    const struct nlattr *nla;
-    int                  rem;
-
-    nla_for_each_attr (nla, head, len, rem) {
-        if (nla_type(nla) == attrtype)
-            return (struct nlattr *) nla;
-    }
-
-    return NULL;
-}
-
-void
-nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr)
-{
-    ssize_t len;
-
-    len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) attr;
-    if (len < 0)
-        g_return_if_reached();
-    else if (len > 0) {
-        msg->nm_nlh->nlmsg_len -= len;
-        memset(nlmsg_tail(msg->nm_nlh), 0, len);
-    }
-}
-
-struct nlattr *
-nla_nest_start(struct nl_msg *msg, int attrtype)
-{
-    struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh);
-
-    if (nla_put(msg, NLA_F_NESTED | attrtype, 0, NULL) < 0)
-        return NULL;
-
-    return start;
-}
-
-static int
-_nest_end(struct nl_msg *msg, struct nlattr *start, int keep_empty)
-{
-    size_t pad, len;
-
-    len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) start;
-
-    if (len > USHRT_MAX || (!keep_empty && len == NLA_HDRLEN)) {
-        /*
-         * Max nlattr size exceeded or empty nested attribute, trim the
-         * attribute header again
-         */
-        nla_nest_cancel(msg, start);
-
-        /* Return error only if nlattr size was exceeded */
-        return (len == NLA_HDRLEN) ? 0 : -NME_NL_ATTRSIZE;
-    }
-
-    start->nla_len = len;
-
-    pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len;
-    if (pad > 0) {
-        /*
-         * Data inside attribute does not end at a alignment boundary.
-         * Pad accordingly and account for the additional space in
-         * the message. nlmsg_reserve() may never fail in this situation,
-         * the allocate message buffer must be a multiple of NLMSG_ALIGNTO.
-         */
-        if (!nlmsg_reserve(msg, pad, 0))
-            g_return_val_if_reached(-NME_BUG);
-    }
-
-    return 0;
-}
-
-int
-nla_nest_end(struct nl_msg *msg, struct nlattr *start)
-{
-    return _nest_end(msg, start, 0);
-}
-
-static const uint16_t nla_attr_minlen[NLA_TYPE_MAX + 1] = {
-    [NLA_U8]     = sizeof(uint8_t),
-    [NLA_U16]    = sizeof(uint16_t),
-    [NLA_U32]    = sizeof(uint32_t),
-    [NLA_U64]    = sizeof(uint64_t),
-    [NLA_STRING] = 1,
-    [NLA_FLAG]   = 0,
-};
-
-static int
-validate_nla(const struct nlattr *nla, int maxtype, const struct nla_policy *policy)
-{
-    const struct nla_policy *pt;
-    unsigned int             minlen = 0;
-    int                      type   = nla_type(nla);
-
-    if (type < 0 || type > maxtype)
-        return 0;
-
-    pt = &policy[type];
-
-    if (pt->type > NLA_TYPE_MAX)
-        g_return_val_if_reached(-NME_BUG);
-
-    if (pt->minlen)
-        minlen = pt->minlen;
-    else if (pt->type != NLA_UNSPEC)
-        minlen = nla_attr_minlen[pt->type];
-
-    if (nla_len(nla) < minlen)
-        return -NME_UNSPEC;
-
-    if (pt->maxlen && nla_len(nla) > pt->maxlen)
-        return -NME_UNSPEC;
-
-    if (pt->type == NLA_STRING) {
-        const char *data;
-
-        nm_assert(minlen > 0);
-
-        data = nla_data(nla);
-        if (data[nla_len(nla) - 1] != '\0')
-            return -NME_UNSPEC;
-    }
-
-    return 0;
-}
-
-int
-nla_parse(struct nlattr *          tb[],
-          int                      maxtype,
-          struct nlattr *          head,
-          int                      len,
-          const struct nla_policy *policy)
-{
-    struct nlattr *nla;
-    int            rem, nmerr;
-
-    memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
-
-    nla_for_each_attr (nla, head, len, rem) {
-        int type = nla_type(nla);
-
-        if (type > maxtype)
-            continue;
-
-        if (policy) {
-            nmerr = validate_nla(nla, maxtype, policy);
-            if (nmerr < 0)
-                return nmerr;
-        }
-
-        tb[type] = nla;
-    }
-
-    return 0;
-}
-
-/*****************************************************************************/
-
-int
-nlmsg_get_proto(struct nl_msg *msg)
-{
-    return msg->nm_protocol;
-}
-
-void
-nlmsg_set_proto(struct nl_msg *msg, int protocol)
-{
-    msg->nm_protocol = protocol;
-}
-
-void
-nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
-{
-    memcpy(&msg->nm_src, addr, sizeof(*addr));
-}
-
-struct ucred *
-nlmsg_get_creds(struct nl_msg *msg)
-{
-    if (msg->nm_creds_has)
-        return &msg->nm_creds;
-    return NULL;
-}
-
-void
-nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
-{
-    if (creds) {
-        memcpy(&msg->nm_creds, creds, sizeof(*creds));
-        msg->nm_creds_has = TRUE;
-    } else
-        msg->nm_creds_has = FALSE;
-}
-
-/*****************************************************************************/
-
-void *
-genlmsg_put(struct nl_msg *msg,
-            uint32_t       port,
-            uint32_t       seq,
-            int            family,
-            int            hdrlen,
-            int            flags,
-            uint8_t        cmd,
-            uint8_t        version)
-{
-    struct nlmsghdr * nlh;
-    struct genlmsghdr hdr = {
-        .cmd     = cmd,
-        .version = version,
-    };
-
-    nlh = nlmsg_put(msg, port, seq, family, GENL_HDRLEN + hdrlen, flags);
-    if (nlh == NULL)
-        return NULL;
-
-    memcpy(nlmsg_data(nlh), &hdr, sizeof(hdr));
-
-    return (char *) nlmsg_data(nlh) + GENL_HDRLEN;
-}
-
-void *
-genlmsg_data(const struct genlmsghdr *gnlh)
-{
-    return ((unsigned char *) gnlh + GENL_HDRLEN);
-}
-
-void *
-genlmsg_user_hdr(const struct genlmsghdr *gnlh)
-{
-    return genlmsg_data(gnlh);
-}
-
-struct genlmsghdr *
-genlmsg_hdr(struct nlmsghdr *nlh)
-{
-    return nlmsg_data(nlh);
-}
-
-void *
-genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen)
-{
-    return (char *) genlmsg_user_hdr(gnlh) + NLMSG_ALIGN(hdrlen);
-}
-
-struct nlattr *
-genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
-{
-    return genlmsg_user_data(gnlh, hdrlen);
-}
-
-int
-genlmsg_len(const struct genlmsghdr *gnlh)
-{
-    const struct nlmsghdr *nlh;
-
-    nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN);
-    return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
-}
-
-int
-genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
-{
-    return genlmsg_len(gnlh) - NLMSG_ALIGN(hdrlen);
-}
-
-int
-genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
-{
-    struct genlmsghdr *ghdr;
-
-    if (!nlmsg_valid_hdr(nlh, GENL_HDRLEN))
-        return 0;
-
-    ghdr = nlmsg_data(nlh);
-    if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
-        return 0;
-
-    return 1;
-}
-
-int
-genlmsg_parse(struct nlmsghdr *        nlh,
-              int                      hdrlen,
-              struct nlattr *          tb[],
-              int                      maxtype,
-              const struct nla_policy *policy)
-{
-    struct genlmsghdr *ghdr;
-
-    if (!genlmsg_valid_hdr(nlh, hdrlen))
-        return -NME_NL_MSG_TOOSHORT;
-
-    ghdr = nlmsg_data(nlh);
-    return nla_parse(tb,
-                     maxtype,
-                     genlmsg_attrdata(ghdr, hdrlen),
-                     genlmsg_attrlen(ghdr, hdrlen),
-                     policy);
-}
-
-static int
-_genl_parse_getfamily(struct nl_msg *msg, void *arg)
-{
-    static const struct nla_policy ctrl_policy[] = {
-        [CTRL_ATTR_FAMILY_ID]    = {.type = NLA_U16},
-        [CTRL_ATTR_FAMILY_NAME]  = {.type = NLA_STRING, .maxlen = GENL_NAMSIZ},
-        [CTRL_ATTR_VERSION]      = {.type = NLA_U32},
-        [CTRL_ATTR_HDRSIZE]      = {.type = NLA_U32},
-        [CTRL_ATTR_MAXATTR]      = {.type = NLA_U32},
-        [CTRL_ATTR_OPS]          = {.type = NLA_NESTED},
-        [CTRL_ATTR_MCAST_GROUPS] = {.type = NLA_NESTED},
-    };
-    struct nlattr *  tb[G_N_ELEMENTS(ctrl_policy)];
-    struct nlmsghdr *nlh           = nlmsg_hdr(msg);
-    gint32 *         response_data = arg;
-
-    if (genlmsg_parse_arr(nlh, 0, tb, ctrl_policy) < 0)
-        return NL_SKIP;
-
-    if (tb[CTRL_ATTR_FAMILY_ID])
-        *response_data = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
-
-    return NL_STOP;
-}
-
-int
-genl_ctrl_resolve(struct nl_sock *sk, const char *name)
-{
-    nm_auto_nlmsg struct nl_msg *msg = NULL;
-    int                          nmerr;
-    gint32                       response_data = -1;
-    const struct nl_cb           cb            = {
-        .valid_cb  = _genl_parse_getfamily,
-        .valid_arg = &response_data,
-    };
-
-    msg = nlmsg_alloc();
-
-    if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY, 1))
-        return -ENOMEM;
-
-    nmerr = nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, name);
-    if (nmerr < 0)
-        return nmerr;
-
-    nmerr = nl_send_auto(sk, msg);
-    if (nmerr < 0)
-        return nmerr;
-
-    nmerr = nl_recvmsgs(sk, &cb);
-    if (nmerr < 0)
-        return nmerr;
-
-    /* If search was successful, request may be ACKed after data */
-    nmerr = nl_wait_for_ack(sk, NULL);
-    if (nmerr < 0)
-        return nmerr;
-
-    if (response_data < 0)
-        return -NME_UNSPEC;
-
-    return response_data;
-}
-
-/*****************************************************************************/
-
-struct nl_sock *
-nl_socket_alloc(void)
-{
-    struct nl_sock *sk;
-
-    sk = g_slice_new0(struct nl_sock);
-
-    sk->s_fd              = -1;
-    sk->s_local.nl_family = AF_NETLINK;
-    sk->s_peer.nl_family  = AF_NETLINK;
-    sk->s_seq_expect = sk->s_seq_next = time(NULL);
-
-    return sk;
-}
-
-void
-nl_socket_free(struct nl_sock *sk)
-{
-    if (!sk)
-        return;
-
-    if (sk->s_fd >= 0)
-        nm_close(sk->s_fd);
-    g_slice_free(struct nl_sock, sk);
-}
-
-int
-nl_socket_get_fd(const struct nl_sock *sk)
-{
-    return sk->s_fd;
-}
-
-uint32_t
-nl_socket_get_local_port(const struct nl_sock *sk)
-{
-    return sk->s_local.nl_pid;
-}
-
-size_t
-nl_socket_get_msg_buf_size(struct nl_sock *sk)
-{
-    return sk->s_bufsize;
-}
-
-int
-nl_socket_set_passcred(struct nl_sock *sk, int state)
-{
-    int err;
-
-    if (sk->s_fd == -1)
-        return -NME_NL_BAD_SOCK;
-
-    err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof(state));
-    if (err < 0)
-        return -nm_errno_from_native(errno);
-
-    if (state)
-        sk->s_flags |= NL_SOCK_PASSCRED;
-    else
-        sk->s_flags &= ~NL_SOCK_PASSCRED;
-
-    return 0;
-}
-
-int
-nl_socket_set_msg_buf_size(struct nl_sock *sk, size_t bufsize)
-{
-    sk->s_bufsize = bufsize;
-
-    return 0;
-}
-
-struct sockaddr_nl *
-nlmsg_get_dst(struct nl_msg *msg)
-{
-    return &msg->nm_dst;
-}
-
-int
-nl_socket_set_nonblocking(const struct nl_sock *sk)
-{
-    if (sk->s_fd == -1)
-        return -NME_NL_BAD_SOCK;
-
-    if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
-        return -nm_errno_from_native(errno);
-
-    return 0;
-}
-
-int
-nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
-{
-    int err;
-
-    if (rxbuf <= 0)
-        rxbuf = 32768;
-
-    if (txbuf <= 0)
-        txbuf = 32768;
-
-    if (sk->s_fd == -1)
-        return -NME_NL_BAD_SOCK;
-
-    err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, &txbuf, sizeof(txbuf));
-    if (err < 0) {
-        return -nm_errno_from_native(errno);
-    }
-
-    err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, &rxbuf, sizeof(rxbuf));
-    if (err < 0) {
-        return -nm_errno_from_native(errno);
-    }
-
-    return 0;
-}
-
-int
-nl_socket_add_memberships(struct nl_sock *sk, int group, ...)
-{
-    int     err;
-    va_list ap;
-
-    if (sk->s_fd == -1)
-        return -NME_NL_BAD_SOCK;
-
-    va_start(ap, group);
-
-    while (group != 0) {
-        if (group < 0) {
-            va_end(ap);
-            g_return_val_if_reached(-NME_BUG);
-        }
-
-        err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
-        if (err < 0) {
-            int errsv = errno;
-
-            va_end(ap);
-            return -nm_errno_from_native(errsv);
-        }
-
-        group = va_arg(ap, int);
-    }
-
-    va_end(ap);
-
-    return 0;
-}
-
-int
-nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable)
-{
-    int err, val;
-
-    if (sk->s_fd == -1)
-        return -NME_NL_BAD_SOCK;
-
-    val = !!enable;
-    err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof(val));
-    if (err < 0)
-        return -nm_errno_from_native(errno);
-
-    return 0;
-}
-
-void
-nl_socket_disable_msg_peek(struct nl_sock *sk)
-{
-    sk->s_flags |= NL_MSG_PEEK_EXPLICIT;
-    sk->s_flags &= ~NL_MSG_PEEK;
-}
-
-int
-nl_connect(struct nl_sock *sk, int protocol)
-{
-    int                err, nmerr;
-    socklen_t          addrlen;
-    struct sockaddr_nl local = {0};
-
-    if (sk->s_fd != -1)
-        return -NME_NL_BAD_SOCK;
-
-    sk->s_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
-    if (sk->s_fd < 0) {
-        nmerr = -nm_errno_from_native(errno);
-        goto errout;
-    }
-
-    nmerr = nl_socket_set_buffer_size(sk, 0, 0);
-    if (nmerr < 0)
-        goto errout;
-
-    nm_assert(sk->s_local.nl_pid == 0);
-
-    err = bind(sk->s_fd, (struct sockaddr *) &sk->s_local, sizeof(sk->s_local));
-    if (err != 0) {
-        nmerr = -nm_errno_from_native(errno);
-        goto errout;
-    }
-
-    addrlen = sizeof(local);
-    err     = getsockname(sk->s_fd, (struct sockaddr *) &local, &addrlen);
-    if (err < 0) {
-        nmerr = -nm_errno_from_native(errno);
-        goto errout;
-    }
-
-    if (addrlen != sizeof(local)) {
-        nmerr = -NME_UNSPEC;
-        goto errout;
-    }
-
-    if (local.nl_family != AF_NETLINK) {
-        nmerr = -NME_UNSPEC;
-        goto errout;
-    }
-
-    sk->s_local = local;
-    sk->s_proto = protocol;
-
-    return 0;
-
-errout:
-    if (sk->s_fd != -1) {
-        close(sk->s_fd);
-        sk->s_fd = -1;
-    }
-    return nmerr;
-}
-
-/*****************************************************************************/
-
-static void
-_cb_init(struct nl_cb *dst, const struct nl_cb *src)
-{
-    nm_assert(dst);
-
-    if (src)
-        *dst = *src;
-    else
-        memset(dst, 0, sizeof(*dst));
-}
-
-static int
-ack_wait_handler(struct nl_msg *msg, void *arg)
-{
-    return NL_STOP;
-}
-
-int
-nl_wait_for_ack(struct nl_sock *sk, const struct nl_cb *cb)
-{
-    struct nl_cb cb2;
-
-    _cb_init(&cb2, cb);
-    cb2.ack_cb = ack_wait_handler;
-    return nl_recvmsgs(sk, &cb2);
-}
-
-#define NL_CB_CALL(cb, type, msg)                                \
-    do {                                                         \
-        const struct nl_cb *_cb = (cb);                          \
-                                                                 \
-        if (_cb && _cb->type##_cb) {                             \
-            /* the returned value here must be either a negative
-         * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ \
-            nmerr = _cb->type##_cb((msg), _cb->type##_arg);      \
-            switch (nmerr) {                                     \
-            case NL_OK:                                          \
-                nm_assert(nmerr == 0);                           \
-                break;                                           \
-            case NL_SKIP:                                        \
-                goto skip;                                       \
-            case NL_STOP:                                        \
-                goto stop;                                       \
-            default:                                             \
-                if (nmerr >= 0) {                                \
-                    nm_assert_not_reached();                     \
-                    nmerr = -NME_BUG;                            \
-                }                                                \
-                goto out;                                        \
-            }                                                    \
-        }                                                        \
-    } while (0)
-
-int
-nl_recvmsgs(struct nl_sock *sk, const struct nl_cb *cb)
-{
-    int                    n, nmerr = 0, multipart = 0, interrupted = 0, nrecv = 0;
-    gs_free unsigned char *buf = NULL;
-    struct nlmsghdr *      hdr;
-    struct sockaddr_nl     nla = {0};
-    struct ucred           creds;
-    gboolean               creds_has;
-
-continue_reading:
-    n = nl_recv(sk, &nla, &buf, &creds, &creds_has);
-    if (n <= 0)
-        return n;
-
-    hdr = (struct nlmsghdr *) buf;
-    while (nlmsg_ok(hdr, n)) {
-        nm_auto_nlmsg struct nl_msg *msg = NULL;
-
-        msg = nlmsg_alloc_convert(hdr);
-
-        nlmsg_set_proto(msg, sk->s_proto);
-        nlmsg_set_src(msg, &nla);
-        nlmsg_set_creds(msg, creds_has ? &creds : NULL);
-
-        nrecv++;
-
-        /* Only do sequence checking if auto-ack mode is enabled */
-        if (!(sk->s_flags & NL_NO_AUTO_ACK)) {
-            if (hdr->nlmsg_seq != sk->s_seq_expect) {
-                nmerr = -NME_NL_SEQ_MISMATCH;
-                goto out;
-            }
-        }
-
-        if (hdr->nlmsg_type == NLMSG_DONE || hdr->nlmsg_type == NLMSG_ERROR
-            || hdr->nlmsg_type == NLMSG_NOOP || hdr->nlmsg_type == NLMSG_OVERRUN) {
-            /* We can't check for !NLM_F_MULTI since some netlink
-             * users in the kernel are broken. */
-            sk->s_seq_expect++;
-        }
-
-        if (hdr->nlmsg_flags & NLM_F_MULTI)
-            multipart = 1;
-
-        if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) {
-            /*
-             * We have to continue reading to clear
-             * all messages until a NLMSG_DONE is
-             * received and report the inconsistency.
-             */
-            interrupted = 1;
-        }
-
-        /* messages terminates a multipart message, this is
-         * usually the end of a message and therefore we slip
-         * out of the loop by default. the user may overrule
-         * this action by skipping this packet. */
-        if (hdr->nlmsg_type == NLMSG_DONE) {
-            multipart = 0;
-            NL_CB_CALL(cb, finish, msg);
-        }
-
-        /* Message to be ignored, the default action is to
-         * skip this message if no callback is specified. The
-         * user may overrule this action by returning
-         * NL_PROCEED. */
-        else if (hdr->nlmsg_type == NLMSG_NOOP)
-            goto skip;
-
-        /* Data got lost, report back to user. The default action is to
-         * quit parsing. The user may overrule this action by returning
-         * NL_SKIP or NL_PROCEED (dangerous) */
-        else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
-            nmerr = -NME_NL_MSG_OVERFLOW;
-            goto out;
-        }
-
-        /* Message carries a nlmsgerr */
-        else if (hdr->nlmsg_type == NLMSG_ERROR) {
-            struct nlmsgerr *e = nlmsg_data(hdr);
-
-            if (hdr->nlmsg_len < nlmsg_size(sizeof(*e))) {
-                /* Truncated error message, the default action
-                 * is to stop parsing. The user may overrule
-                 * this action by returning NL_SKIP or
-                 * NL_PROCEED (dangerous) */
-                nmerr = -NME_NL_MSG_TRUNC;
-                goto out;
-            }
-            if (e->error) {
-                /* Error message reported back from kernel. */
-                if (cb && cb->err_cb) {
-                    /* the returned value here must be either a negative
-                     * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */
-                    nmerr = cb->err_cb(&nla, e, cb->err_arg);
-                    if (nmerr < 0)
-                        goto out;
-                    else if (nmerr == NL_SKIP)
-                        goto skip;
-                    else if (nmerr == NL_STOP) {
-                        nmerr = -nm_errno_from_native(e->error);
-                        goto out;
-                    }
-                    nm_assert(nmerr == NL_OK);
-                } else {
-                    nmerr = -nm_errno_from_native(e->error);
-                    goto out;
-                }
-            } else
-                NL_CB_CALL(cb, ack, msg);
-        } else {
-            /* Valid message (not checking for MULTIPART bit to
-             * get along with broken kernels. NL_SKIP has no
-             * effect on this.  */
-            NL_CB_CALL(cb, valid, msg);
-        }
-skip:
-        nmerr = 0;
-        hdr   = nlmsg_next(hdr, &n);
-    }
-
-    if (multipart) {
-        /* Multipart message not yet complete, continue reading */
-        nm_clear_g_free(&buf);
-
-        nmerr = 0;
-        goto continue_reading;
-    }
-
-stop:
-    nmerr = 0;
-
-out:
-    if (interrupted)
-        nmerr = -NME_NL_DUMP_INTR;
-
-    nm_assert(nmerr <= 0);
-    return nmerr ?: nrecv;
-}
-
-int
-nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
-{
-    int ret;
-
-    if (sk->s_fd < 0)
-        return -NME_NL_BAD_SOCK;
-
-    nlmsg_set_src(msg, &sk->s_local);
-
-    ret = sendmsg(sk->s_fd, hdr, 0);
-    if (ret < 0)
-        return -nm_errno_from_native(errno);
-
-    return ret;
-}
-
-int
-nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen)
-{
-    struct sockaddr_nl *dst;
-    struct ucred *      creds;
-    struct msghdr       hdr = {
-        .msg_name    = (void *) &sk->s_peer,
-        .msg_namelen = sizeof(struct sockaddr_nl),
-        .msg_iov     = iov,
-        .msg_iovlen  = iovlen,
-    };
-    char buf[CMSG_SPACE(sizeof(struct ucred))];
-
-    /* Overwrite destination if specified in the message itself, defaults
-     * to the peer address of the socket.
-     */
-    dst = nlmsg_get_dst(msg);
-    if (dst->nl_family == AF_NETLINK)
-        hdr.msg_name = dst;
-
-    /* Add credentials if present. */
-    creds = nlmsg_get_creds(msg);
-    if (creds != NULL) {
-        struct cmsghdr *cmsg;
-
-        hdr.msg_control    = buf;
-        hdr.msg_controllen = sizeof(buf);
-
-        cmsg             = CMSG_FIRSTHDR(&hdr);
-        cmsg->cmsg_level = SOL_SOCKET;
-        cmsg->cmsg_type  = SCM_CREDENTIALS;
-        cmsg->cmsg_len   = CMSG_LEN(sizeof(struct ucred));
-        memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred));
-    }
-
-    return nl_sendmsg(sk, msg, &hdr);
-}
-
-void
-nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg)
-{
-    struct nlmsghdr *nlh;
-
-    nlh = nlmsg_hdr(msg);
-    if (nlh->nlmsg_pid == NL_AUTO_PORT)
-        nlh->nlmsg_pid = nl_socket_get_local_port(sk);
-
-    if (nlh->nlmsg_seq == NL_AUTO_SEQ)
-        nlh->nlmsg_seq = sk->s_seq_next++;
-
-    if (msg->nm_protocol == -1)
-        msg->nm_protocol = sk->s_proto;
-
-    nlh->nlmsg_flags |= NLM_F_REQUEST;
-
-    if (!(sk->s_flags & NL_NO_AUTO_ACK))
-        nlh->nlmsg_flags |= NLM_F_ACK;
-}
-
-int
-nl_send(struct nl_sock *sk, struct nl_msg *msg)
-{
-    struct iovec iov = {
-        .iov_base = (void *) nlmsg_hdr(msg),
-        .iov_len  = nlmsg_hdr(msg)->nlmsg_len,
-    };
-
-    return nl_send_iovec(sk, msg, &iov, 1);
-}
-
-int
-nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
-{
-    nl_complete_msg(sk, msg);
-
-    return nl_send(sk, msg);
-}
-
-int
-nl_recv(struct nl_sock *    sk,
-        struct sockaddr_nl *nla,
-        unsigned char **    buf,
-        struct ucred *      out_creds,
-        gboolean *          out_creds_has)
-{
-    ssize_t       n;
-    int           flags = 0;
-    struct iovec  iov;
-    struct msghdr msg = {
-        .msg_name    = (void *) nla,
-        .msg_namelen = sizeof(struct sockaddr_nl),
-        .msg_iov     = &iov,
-        .msg_iovlen  = 1,
-    };
-    struct ucred tmpcreds;
-    gboolean     tmpcreds_has = FALSE;
-    int          retval;
-    int          errsv;
-
-    nm_assert(nla);
-    nm_assert(buf && !*buf);
-    nm_assert(!out_creds_has == !out_creds);
-
-    if ((sk->s_flags & NL_MSG_PEEK)
-        || (!(sk->s_flags & NL_MSG_PEEK_EXPLICIT) && sk->s_bufsize == 0))
-        flags |= MSG_PEEK | MSG_TRUNC;
-
-    iov.iov_len  = sk->s_bufsize ?: (((size_t) nm_utils_getpagesize()) * 4u);
-    iov.iov_base = g_malloc(iov.iov_len);
-
-    if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) {
-        msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
-        msg.msg_control    = g_malloc(msg.msg_controllen);
-    }
-
-retry:
-    n = recvmsg(sk->s_fd, &msg, flags);
-    if (!n) {
-        retval = 0;
-        goto abort;
-    }
-
-    if (n < 0) {
-        errsv = errno;
-        if (errsv == EINTR)
-            goto retry;
-        retval = -nm_errno_from_native(errsv);
-        goto abort;
-    }
-
-    if (msg.msg_flags & MSG_CTRUNC) {
-        if (msg.msg_controllen == 0) {
-            retval = -NME_NL_MSG_TRUNC;
-            goto abort;
-        }
-
-        msg.msg_controllen *= 2;
-        msg.msg_control = g_realloc(msg.msg_control, msg.msg_controllen);
-        goto retry;
-    }
-
-    if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) {
-        /* respond with error to an incomplete message */
-        if (flags == 0) {
-            retval = -NME_NL_MSG_TRUNC;
-            goto abort;
-        }
-
-        /* Provided buffer is not long enough, enlarge it
-         * to size of n (which should be total length of the message)
-         * and try again. */
-        iov.iov_base = g_realloc(iov.iov_base, n);
-        iov.iov_len  = n;
-        flags        = 0;
-        goto retry;
-    }
-
-    if (flags != 0) {
-        /* Buffer is big enough, do the actual reading */
-        flags = 0;
-        goto retry;
-    }
-
-    if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
-        retval = -NME_UNSPEC;
-        goto abort;
-    }
-
-    if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) {
-        struct cmsghdr *cmsg;
-
-        for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
-            if (cmsg->cmsg_level != SOL_SOCKET)
-                continue;
-            if (cmsg->cmsg_type != SCM_CREDENTIALS)
-                continue;
-            memcpy(&tmpcreds, CMSG_DATA(cmsg), sizeof(tmpcreds));
-            tmpcreds_has = TRUE;
-            break;
-        }
-    }
-
-    retval = n;
-
-abort:
-    g_free(msg.msg_control);
-
-    if (retval <= 0) {
-        g_free(iov.iov_base);
-        return retval;
-    }
-
-    *buf = iov.iov_base;
-    if (out_creds && tmpcreds_has)
-        *out_creds = tmpcreds;
-    NM_SET_OUT(out_creds_has, tmpcreds_has);
-    return retval;
-}
diff --git a/shared/nm-platform/nm-netlink.h b/shared/nm-platform/nm-netlink.h
deleted file mode 100644
index 8de42531..00000000
--- a/shared/nm-platform/nm-netlink.h
+++ /dev/null
@@ -1,616 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_NETLINK_H__
-#define __NM_NETLINK_H__
-
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/genetlink.h>
-
-#include "nm-std-aux/unaligned.h"
-
-/*****************************************************************************/
-
-#define NLMSGERR_ATTR_UNUSED 0
-#define NLMSGERR_ATTR_MSG    1
-#define NLMSGERR_ATTR_OFFS   2
-#define NLMSGERR_ATTR_COOKIE 3
-#define NLMSGERR_ATTR_MAX    3
-
-#ifndef NLM_F_ACK_TLVS
-    #define NLM_F_ACK_TLVS 0x200
-#endif
-
-/*****************************************************************************/
-
-/* Basic attribute data types */
-enum {
-    NLA_UNSPEC, /* Unspecified type, binary data chunk */
-    NLA_U8,     /* 8 bit integer */
-    NLA_U16,    /* 16 bit integer */
-    NLA_U32,    /* 32 bit integer */
-    NLA_U64,    /* 64 bit integer */
-    NLA_STRING, /* NUL terminated character string */
-    NLA_FLAG,   /* Flag */
-    NLA_MSECS,  /* Micro seconds (64bit) */
-    NLA_NESTED, /* Nested attributes */
-    NLA_NESTED_COMPAT,
-    NLA_NUL_STRING,
-    NLA_BINARY,
-    NLA_S8,
-    NLA_S16,
-    NLA_S32,
-    NLA_S64,
-    __NLA_TYPE_MAX,
-};
-
-#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
-
-struct nl_msg;
-
-/*****************************************************************************/
-
-const char *nl_nlmsgtype2str(int type, char *buf, size_t size);
-
-const char *nl_nlmsg_flags2str(int flags, char *buf, size_t len);
-
-const char *nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len);
-
-/*****************************************************************************/
-
-struct nla_policy {
-    /* Type of attribute or NLA_UNSPEC */
-    uint16_t type;
-
-    /* Minimal length of payload required */
-    uint16_t minlen;
-
-    /* Maximal length of payload allowed */
-    uint16_t maxlen;
-};
-
-/*****************************************************************************/
-
-/* static asserts that @tb and @policy are suitable arguments to nla_parse(). */
-#define _nl_static_assert_tb(tb, policy)                                                      \
-    G_STMT_START                                                                              \
-    {                                                                                         \
-        G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(tb) > 0);                                           \
-                                                                                              \
-        /* We allow @policy to be either a C array or NULL. The sizeof()
-         * must either match the expected array size or the sizeof(NULL),
-         * but not both. */                      \
-        G_STATIC_ASSERT_EXPR((sizeof(policy) == G_N_ELEMENTS(tb) * sizeof(struct nla_policy)) \
-                             ^ (sizeof(policy) == sizeof(NULL)));                             \
-    }                                                                                         \
-    G_STMT_END
-
-/*****************************************************************************/
-
-static inline int
-nla_attr_size(int payload)
-{
-    nm_assert(payload >= 0);
-
-    return NLA_HDRLEN + payload;
-}
-
-static inline int
-nla_total_size(int payload)
-{
-    return NLA_ALIGN(nla_attr_size(payload));
-}
-
-static inline int
-nla_padlen(int payload)
-{
-    return nla_total_size(payload) - nla_attr_size(payload);
-}
-
-struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen);
-
-static inline int
-nla_len(const struct nlattr *nla)
-{
-    nm_assert(nla);
-    nm_assert(nla->nla_len >= NLA_HDRLEN);
-
-    return ((int) nla->nla_len) - NLA_HDRLEN;
-}
-
-static inline int
-nla_type(const struct nlattr *nla)
-{
-    nm_assert(nla_len(nla) >= 0);
-
-    return nla->nla_type & NLA_TYPE_MASK;
-}
-
-static inline void *
-nla_data(const struct nlattr *nla)
-{
-    nm_assert(nla_len(nla) >= 0);
-
-    return &(((char *) nla)[NLA_HDRLEN]);
-}
-
-#define nla_data_as(type, nla)                                          \
-    ({                                                                  \
-        const struct nlattr *_nla = (nla);                              \
-                                                                        \
-        nm_assert(nla_len(_nla) >= sizeof(type));                       \
-                                                                        \
-        /* note that casting the pointer is undefined behavior in C, if
-         * the data has wrong alignment. Netlink data is aligned to 4 bytes,
-         * that means, if the alignment is larger than 4, this is invalid. */ \
-        G_STATIC_ASSERT_EXPR(_nm_alignof(type) <= NLA_ALIGNTO);         \
-                                                                        \
-        (type *) nla_data(_nla);                                        \
-    })
-
-static inline uint8_t
-nla_get_u8(const struct nlattr *nla)
-{
-    nm_assert(nla_len(nla) >= sizeof(uint8_t));
-
-    return *((const uint8_t *) nla_data(nla));
-}
-
-static inline int8_t
-nla_get_s8(const struct nlattr *nla)
-{
-    nm_assert(nla_len(nla) >= sizeof(int8_t));
-
-    return *((const int8_t *) nla_data(nla));
-}
-
-static inline uint8_t
-nla_get_u8_cond(/*const*/ struct nlattr *const *tb, int attr, uint8_t default_val)
-{
-    nm_assert(tb);
-    nm_assert(attr >= 0);
-
-    return tb[attr] ? nla_get_u8(tb[attr]) : default_val;
-}
-
-static inline uint16_t
-nla_get_u16(const struct nlattr *nla)
-{
-    nm_assert(nla_len(nla) >= sizeof(uint16_t));
-
-    return *((const uint16_t *) nla_data(nla));
-}
-
-static inline uint32_t
-nla_get_u32(const struct nlattr *nla)
-{
-    nm_assert(nla_len(nla) >= sizeof(uint32_t));
-
-    return *((const uint32_t *) nla_data(nla));
-}
-
-static inline int32_t
-nla_get_s32(const struct nlattr *nla)
-{
-    nm_assert(nla_len(nla) >= sizeof(int32_t));
-
-    return *((const int32_t *) nla_data(nla));
-}
-
-static inline uint64_t
-nla_get_u64(const struct nlattr *nla)
-{
-    nm_assert(nla_len(nla) >= sizeof(uint64_t));
-
-    return unaligned_read_ne64(nla_data(nla));
-}
-
-static inline uint64_t
-nla_get_be64(const struct nlattr *nla)
-{
-    nm_assert(nla_len(nla) >= sizeof(uint64_t));
-
-    return unaligned_read_be64(nla_data(nla));
-}
-
-static inline char *
-nla_get_string(const struct nlattr *nla)
-{
-    nm_assert(nla_len(nla) >= 0);
-
-    return (char *) nla_data(nla);
-}
-
-size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize);
-
-size_t nla_memcpy(void *dst, const struct nlattr *nla, size_t dstsize);
-
-#define nla_memcpy_checked_size(dst, nla, dstsize)                       \
-    G_STMT_START                                                         \
-    {                                                                    \
-        void *const                _dst     = (dst);                     \
-        const struct nlattr *const _nla     = (nla);                     \
-        const size_t               _dstsize = (dstsize);                 \
-        size_t                     _srcsize;                             \
-                                                                         \
-        /* assert that, if @nla is given, that it has the exact expected
-         * size. This implies that the caller previously verified the length
-         * of the attribute (via minlen/maxlen at nla_parse()). */ \
-                                                                         \
-        if (_nla) {                                                      \
-            _srcsize = nla_memcpy(_dst, _nla, _dstsize);                 \
-            nm_assert(_srcsize == _dstsize);                             \
-        }                                                                \
-    }                                                                    \
-    G_STMT_END
-
-int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data);
-
-static inline int
-nla_put_string(struct nl_msg *msg, int attrtype, const char *str)
-{
-    nm_assert(str);
-
-    return nla_put(msg, attrtype, strlen(str) + 1, str);
-}
-
-static inline int
-nla_put_uint8(struct nl_msg *msg, int attrtype, uint8_t val)
-{
-    return nla_put(msg, attrtype, sizeof(val), &val);
-}
-
-static inline int
-nla_put_uint16(struct nl_msg *msg, int attrtype, uint16_t val)
-{
-    return nla_put(msg, attrtype, sizeof(val), &val);
-}
-
-static inline int
-nla_put_uint32(struct nl_msg *msg, int attrtype, uint32_t val)
-{
-    return nla_put(msg, attrtype, sizeof(val), &val);
-}
-
-#define NLA_PUT(msg, attrtype, attrlen, data)          \
-    G_STMT_START                                       \
-    {                                                  \
-        if (nla_put(msg, attrtype, attrlen, data) < 0) \
-            goto nla_put_failure;                      \
-    }                                                  \
-    G_STMT_END
-
-#define NLA_PUT_TYPE(msg, type, attrtype, value)          \
-    G_STMT_START                                          \
-    {                                                     \
-        type __nla_tmp = value;                           \
-        NLA_PUT(msg, attrtype, sizeof(type), &__nla_tmp); \
-    }                                                     \
-    G_STMT_END
-
-#define NLA_PUT_U8(msg, attrtype, value) NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
-
-#define NLA_PUT_S8(msg, attrtype, value) NLA_PUT_TYPE(msg, int8_t, attrtype, value)
-
-#define NLA_PUT_U16(msg, attrtype, value) NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
-
-#define NLA_PUT_U32(msg, attrtype, value) NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
-
-#define NLA_PUT_S32(msg, attrtype, value) NLA_PUT_TYPE(msg, int32_t, attrtype, value)
-
-#define NLA_PUT_U64(msg, attrtype, value) NLA_PUT_TYPE(msg, uint64_t, attrtype, value)
-
-#define NLA_PUT_STRING(msg, attrtype, value) NLA_PUT(msg, attrtype, (int) strlen(value) + 1, value)
-
-#define NLA_PUT_FLAG(msg, attrtype) NLA_PUT(msg, attrtype, 0, NULL)
-
-struct nlattr *nla_find(const struct nlattr *head, int len, int attrtype);
-
-static inline int
-nla_ok(const struct nlattr *nla, int remaining)
-{
-    return remaining >= (int) sizeof(*nla) && nla->nla_len >= sizeof(*nla)
-           && nla->nla_len <= remaining;
-}
-
-static inline struct nlattr *
-nla_next(const struct nlattr *nla, int *remaining)
-{
-    int totlen = NLA_ALIGN(nla->nla_len);
-
-    *remaining -= totlen;
-    return (struct nlattr *) ((char *) nla + totlen);
-}
-
-#define nla_for_each_attr(pos, head, len, rem) \
-    for (pos = head, rem = len; nla_ok(pos, rem); pos = nla_next(pos, &(rem)))
-
-#define nla_for_each_nested(pos, nla, rem)                                            \
-    for (pos = (struct nlattr *) nla_data(nla), rem = nla_len(nla); nla_ok(pos, rem); \
-         pos = nla_next(pos, &(rem)))
-
-void           nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr);
-struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype);
-int            nla_nest_end(struct nl_msg *msg, struct nlattr *start);
-
-int nla_parse(struct nlattr *          tb[],
-              int                      maxtype,
-              struct nlattr *          head,
-              int                      len,
-              const struct nla_policy *policy);
-
-#define nla_parse_arr(tb, head, len, policy)                            \
-    ({                                                                  \
-        _nl_static_assert_tb((tb), (policy));                           \
-                                                                        \
-        nla_parse((tb), G_N_ELEMENTS(tb) - 1, (head), (len), (policy)); \
-    })
-
-static inline int
-nla_parse_nested(struct nlattr *          tb[],
-                 int                      maxtype,
-                 struct nlattr *          nla,
-                 const struct nla_policy *policy)
-{
-    return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
-}
-
-#define nla_parse_nested_arr(tb, nla, policy)                          \
-    ({                                                                 \
-        _nl_static_assert_tb((tb), (policy));                          \
-                                                                       \
-        nla_parse_nested((tb), G_N_ELEMENTS(tb) - 1, (nla), (policy)); \
-    })
-
-/*****************************************************************************/
-
-struct nl_msg *nlmsg_alloc(void);
-
-struct nl_msg *nlmsg_alloc_size(size_t max);
-
-struct nl_msg *nlmsg_alloc_convert(struct nlmsghdr *hdr);
-
-struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags);
-
-void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad);
-
-int nlmsg_append(struct nl_msg *n, const void *data, size_t len, int pad);
-
-#define nlmsg_append_struct(n, data) nlmsg_append(n, (data), sizeof(*(data)), NLMSG_ALIGNTO)
-
-void nlmsg_free(struct nl_msg *msg);
-
-static inline int
-nlmsg_size(int payload)
-{
-    nm_assert(payload >= 0 && payload < G_MAXINT - NLMSG_HDRLEN - 4);
-    return NLMSG_HDRLEN + payload;
-}
-
-static inline int
-nlmsg_total_size(int payload)
-{
-    return NLMSG_ALIGN(nlmsg_size(payload));
-}
-
-static inline int
-nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
-{
-    return (remaining >= (int) sizeof(struct nlmsghdr) && nlh->nlmsg_len >= sizeof(struct nlmsghdr)
-            && nlh->nlmsg_len <= remaining);
-}
-
-static inline struct nlmsghdr *
-nlmsg_next(struct nlmsghdr *nlh, int *remaining)
-{
-    int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
-
-    *remaining -= totlen;
-
-    return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
-}
-
-int  nlmsg_get_proto(struct nl_msg *msg);
-void nlmsg_set_proto(struct nl_msg *msg, int protocol);
-
-void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr);
-
-struct ucred *nlmsg_get_creds(struct nl_msg *msg);
-void          nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds);
-
-static inline void
-_nm_auto_nl_msg_cleanup(struct nl_msg **ptr)
-{
-    nlmsg_free(*ptr);
-}
-#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup)
-
-static inline void *
-nlmsg_data(const struct nlmsghdr *nlh)
-{
-    return (unsigned char *) nlh + NLMSG_HDRLEN;
-}
-
-static inline void *
-nlmsg_tail(const struct nlmsghdr *nlh)
-{
-    return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
-}
-
-struct nlmsghdr *nlmsg_hdr(struct nl_msg *n);
-
-static inline int
-nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
-{
-    if (nlh->nlmsg_len < nlmsg_size(hdrlen))
-        return 0;
-
-    return 1;
-}
-
-static inline int
-nlmsg_datalen(const struct nlmsghdr *nlh)
-{
-    return nlh->nlmsg_len - NLMSG_HDRLEN;
-}
-
-static inline int
-nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
-{
-    return NM_MAX((int) (nlmsg_datalen(nlh) - NLMSG_ALIGN(hdrlen)), 0);
-}
-
-static inline struct nlattr *
-nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
-{
-    unsigned char *data = nlmsg_data(nlh);
-    return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
-}
-
-static inline struct nlattr *
-nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
-{
-    return nla_find(nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), attrtype);
-}
-
-int nlmsg_parse(struct nlmsghdr *        nlh,
-                int                      hdrlen,
-                struct nlattr *          tb[],
-                int                      maxtype,
-                const struct nla_policy *policy);
-
-#define nlmsg_parse_arr(nlh, hdrlen, tb, policy)                            \
-    ({                                                                      \
-        _nl_static_assert_tb((tb), (policy));                               \
-        G_STATIC_ASSERT_EXPR((hdrlen) >= 0);                                \
-                                                                            \
-        nlmsg_parse((nlh), (hdrlen), (tb), G_N_ELEMENTS(tb) - 1, (policy)); \
-    })
-
-struct nlmsghdr *
-nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags);
-
-/*****************************************************************************/
-
-#define NL_AUTO_PORT 0
-#define NL_AUTO_SEQ  0
-
-struct nl_sock;
-
-struct nl_sock *nl_socket_alloc(void);
-
-void nl_socket_free(struct nl_sock *sk);
-
-int nl_socket_get_fd(const struct nl_sock *sk);
-
-struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg);
-
-size_t nl_socket_get_msg_buf_size(struct nl_sock *sk);
-int    nl_socket_set_msg_buf_size(struct nl_sock *sk, size_t bufsize);
-
-int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf);
-
-int nl_socket_set_passcred(struct nl_sock *sk, int state);
-
-int nl_socket_set_nonblocking(const struct nl_sock *sk);
-
-void nl_socket_disable_msg_peek(struct nl_sock *sk);
-
-uint32_t nl_socket_get_local_port(const struct nl_sock *sk);
-
-int nl_socket_add_memberships(struct nl_sock *sk, int group, ...);
-
-int nl_connect(struct nl_sock *sk, int protocol);
-
-int nl_recv(struct nl_sock *    sk,
-            struct sockaddr_nl *nla,
-            unsigned char **    buf,
-            struct ucred *      out_creds,
-            gboolean *          out_creds_has);
-
-int nl_send(struct nl_sock *sk, struct nl_msg *msg);
-
-int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg);
-
-/*****************************************************************************/
-
-enum nl_cb_action {
-    /* Proceed with wathever would come next */
-    NL_OK,
-    /* Skip this message */
-    NL_SKIP,
-    /* Stop parsing altogether and discard remaining messages */
-    NL_STOP,
-};
-
-typedef int (*nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg);
-
-typedef int (*nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg);
-
-struct nl_cb {
-    nl_recvmsg_msg_cb_t valid_cb;
-    void *              valid_arg;
-
-    nl_recvmsg_msg_cb_t finish_cb;
-    void *              finish_arg;
-
-    nl_recvmsg_msg_cb_t ack_cb;
-    void *              ack_arg;
-
-    nl_recvmsg_err_cb_t err_cb;
-    void *              err_arg;
-};
-
-int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr);
-
-int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen);
-
-void nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg);
-
-int nl_recvmsgs(struct nl_sock *sk, const struct nl_cb *cb);
-
-int nl_wait_for_ack(struct nl_sock *sk, const struct nl_cb *cb);
-
-int nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable);
-
-/*****************************************************************************/
-
-void *             genlmsg_put(struct nl_msg *msg,
-                               uint32_t       port,
-                               uint32_t       seq,
-                               int            family,
-                               int            hdrlen,
-                               int            flags,
-                               uint8_t        cmd,
-                               uint8_t        version);
-void *             genlmsg_data(const struct genlmsghdr *gnlh);
-void *             genlmsg_user_hdr(const struct genlmsghdr *gnlh);
-struct genlmsghdr *genlmsg_hdr(struct nlmsghdr *nlh);
-void *             genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen);
-struct nlattr *    genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen);
-int                genlmsg_len(const struct genlmsghdr *gnlh);
-int                genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen);
-int                genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen);
-
-int genlmsg_parse(struct nlmsghdr *        nlh,
-                  int                      hdrlen,
-                  struct nlattr *          tb[],
-                  int                      maxtype,
-                  const struct nla_policy *policy);
-
-#define genlmsg_parse_arr(nlh, hdrlen, tb, policy)                            \
-    ({                                                                        \
-        _nl_static_assert_tb((tb), (policy));                                 \
-        G_STATIC_ASSERT_EXPR((hdrlen) >= 0);                                  \
-                                                                              \
-        genlmsg_parse((nlh), (hdrlen), (tb), G_N_ELEMENTS(tb) - 1, (policy)); \
-    })
-
-int genl_ctrl_resolve(struct nl_sock *sk, const char *name);
-
-/*****************************************************************************/
-
-#endif /* __NM_NETLINK_H__ */
diff --git a/shared/nm-platform/nm-platform-utils.c b/shared/nm-platform/nm-platform-utils.c
deleted file mode 100644
index c1c5b1a3..00000000
--- a/shared/nm-platform/nm-platform-utils.c
+++ /dev/null
@@ -1,1807 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-platform-utils.h"
-
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <linux/ethtool.h>
-#include <linux/sockios.h>
-#include <linux/mii.h>
-#include <linux/if.h>
-#include <linux/version.h>
-#include <linux/rtnetlink.h>
-#include <fcntl.h>
-#include <libudev.h>
-
-#include "nm-base/nm-ethtool-base.h"
-#include "nm-log-core/nm-logging.h"
-
-/*****************************************************************************/
-
-#define ONOFF(bool_val) ((bool_val) ? "on" : "off")
-
-/******************************************************************************
- * utils
- *****************************************************************************/
-
-extern char *if_indextoname(unsigned __ifindex, char *__ifname);
-unsigned     if_nametoindex(const char *__ifname);
-
-const char *
-nmp_utils_if_indextoname(int ifindex, char *out_ifname /*IFNAMSIZ*/)
-{
-    g_return_val_if_fail(ifindex > 0, NULL);
-    g_return_val_if_fail(out_ifname, NULL);
-
-    return if_indextoname(ifindex, out_ifname);
-}
-
-int
-nmp_utils_if_nametoindex(const char *ifname)
-{
-    g_return_val_if_fail(ifname, 0);
-
-    return if_nametoindex(ifname);
-}
-
-/*****************************************************************************/
-
-NM_UTILS_LOOKUP_STR_DEFINE(nm_platform_link_duplex_type_to_string,
-                           NMPlatformLinkDuplexType,
-                           NM_UTILS_LOOKUP_DEFAULT_WARN(NULL),
-                           NM_UTILS_LOOKUP_STR_ITEM(NM_PLATFORM_LINK_DUPLEX_UNKNOWN, "unknown"),
-                           NM_UTILS_LOOKUP_STR_ITEM(NM_PLATFORM_LINK_DUPLEX_FULL, "full"),
-                           NM_UTILS_LOOKUP_STR_ITEM(NM_PLATFORM_LINK_DUPLEX_HALF, "half"), );
-
-/*****************************************************************************/
-
-typedef struct {
-    int       fd;
-    const int ifindex;
-    char      ifname[IFNAMSIZ];
-} SocketHandle;
-
-#define SOCKET_HANDLE_INIT(_ifindex)     \
-    {                                    \
-        .fd = -1, .ifindex = (_ifindex), \
-    }
-
-static void
-_nm_auto_socket_handle(SocketHandle *shandle)
-{
-    if (shandle->fd >= 0)
-        nm_close(shandle->fd);
-}
-
-#define nm_auto_socket_handle nm_auto(_nm_auto_socket_handle)
-
-/*****************************************************************************/
-
-typedef enum {
-    IOCTL_CALL_DATA_TYPE_NONE,
-    IOCTL_CALL_DATA_TYPE_IFRDATA,
-    IOCTL_CALL_DATA_TYPE_IFRU,
-} IoctlCallDataType;
-
-static int
-_ioctl_call(const char *      log_ioctl_type,
-            const char *      log_subtype,
-            unsigned long int ioctl_request,
-            int               ifindex,
-            int *             inout_fd,
-            char *            inout_ifname,
-            IoctlCallDataType edata_type,
-            gpointer          edata,
-            gsize             edata_size,
-            struct ifreq *    out_ifreq)
-{
-    nm_auto_close int fd_close = -1;
-    int               fd;
-    int               r;
-    gpointer          edata_backup      = NULL;
-    gs_free gpointer  edata_backup_free = NULL;
-    guint             try_count;
-    char              known_ifnames[2][IFNAMSIZ];
-    const char *      failure_reason = NULL;
-    struct ifreq      ifr;
-
-    nm_assert(ifindex > 0);
-    nm_assert(NM_IN_SET(edata_type,
-                        IOCTL_CALL_DATA_TYPE_NONE,
-                        IOCTL_CALL_DATA_TYPE_IFRDATA,
-                        IOCTL_CALL_DATA_TYPE_IFRU));
-    nm_assert(edata_type != IOCTL_CALL_DATA_TYPE_NONE || edata_size == 0);
-    nm_assert(edata_type != IOCTL_CALL_DATA_TYPE_IFRDATA || edata_size > 0);
-    nm_assert(edata_type != IOCTL_CALL_DATA_TYPE_IFRU
-              || (edata_size > 0 && edata_size <= sizeof(ifr.ifr_ifru)));
-    nm_assert(edata_size == 0 || edata);
-
-    /* open a file descriptor (or use the one provided). */
-    if (inout_fd && *inout_fd >= 0)
-        fd = *inout_fd;
-    else {
-        fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-        if (fd < 0) {
-            r              = -NM_ERRNO_NATIVE(errno);
-            failure_reason = "failed creating socket or ioctl";
-            goto out;
-        }
-        if (inout_fd)
-            *inout_fd = fd;
-        else
-            fd_close = fd;
-    }
-
-    /* resolve the ifindex to name (or use the one provided). */
-    if (inout_ifname && inout_ifname[0])
-        nm_utils_ifname_cpy(known_ifnames[0], inout_ifname);
-    else {
-        if (!nmp_utils_if_indextoname(ifindex, known_ifnames[0])) {
-            failure_reason = "cannot resolve ifindex";
-            r              = -ENODEV;
-            goto out;
-        }
-        if (inout_ifname)
-            nm_utils_ifname_cpy(inout_ifname, known_ifnames[0]);
-    }
-
-    /* we might need to retry the request. Backup edata so that we can
-     * restore it on retry. */
-    if (edata_size > 0)
-        edata_backup = nm_memdup_maybe_a(500, edata, edata_size, &edata_backup_free);
-
-    try_count = 0;
-
-again:
-{
-    const char *ifname = known_ifnames[try_count % 2];
-
-    nm_assert(ifindex > 0);
-    nm_assert(ifname && nm_utils_ifname_valid_kernel(ifname, NULL));
-    nm_assert(fd >= 0);
-
-    memset(&ifr, 0, sizeof(ifr));
-    nm_utils_ifname_cpy(ifr.ifr_name, ifname);
-    if (edata_type == IOCTL_CALL_DATA_TYPE_IFRDATA)
-        ifr.ifr_data = edata;
-    else if (edata_type == IOCTL_CALL_DATA_TYPE_IFRU)
-        memcpy(&ifr.ifr_ifru, edata, NM_MIN(edata_size, sizeof(ifr.ifr_ifru)));
-
-    if (ioctl(fd, ioctl_request, &ifr) < 0) {
-        r = -NM_ERRNO_NATIVE(errno);
-        nm_log_trace(LOGD_PLATFORM,
-                     "%s[%d]: %s, %s: failed: %s",
-                     log_ioctl_type,
-                     ifindex,
-                     log_subtype,
-                     ifname,
-                     nm_strerror_native(-r));
-    } else {
-        r = 0;
-        nm_log_trace(LOGD_PLATFORM,
-                     "%s[%d]: %s, %s: success",
-                     log_ioctl_type,
-                     ifindex,
-                     log_subtype,
-                     ifname);
-    }
-}
-
-    try_count++;
-
-    /* resolve the name again to see whether the ifindex still has the same name. */
-    if (!nmp_utils_if_indextoname(ifindex, known_ifnames[try_count % 2])) {
-        /* we could not find the ifindex again. Probably the device just got
-         * removed.
-         *
-         * In both cases we return the error code we got from ioctl above.
-         * Either it failed because the device was gone already or it still
-         * managed to complete the call. In both cases, the error code is good. */
-        failure_reason =
-            "cannot resolve ifindex after ioctl call. Probably the device was just removed";
-        goto out;
-    }
-
-    /* check whether the ifname changed in the meantime. If yes, would render the result
-     * invalid. Note that this cannot detect every race regarding renames, for example:
-     *
-     *  - if_indextoname(#10) gives eth0
-     *  - rename(#10) => eth0_tmp
-     *  - rename(#11) => eth0
-     *  - ioctl(eth0) (wrongly fetching #11, formerly eth1)
-     *  - rename(#11) => eth_something
-     *  - rename(#10) => eth0
-     *  - if_indextoname(#10) gives eth0
-     */
-    if (!nm_streq(known_ifnames[0], known_ifnames[1])) {
-        gboolean retry;
-
-        /* we detected a possible(!) rename.
-         *
-         * For getters it's straight forward to just retry the call.
-         *
-         * For setters we also always retry. If our previous call operated on the right device,
-         * calling it again should have no bad effect (just setting the same thing more than once).
-         *
-         * The only potential bad thing is if there was a race involving swapping names, and we just
-         * set the ioctl option on the wrong device. But then the bad thing already happenned and
-         * we cannot detect it (nor do anything about it). At least, we can retry and set the
-         * option on the right interface. */
-        retry = (try_count < 5);
-
-        nm_log_trace(LOGD_PLATFORM,
-                     "%s[%d]: %s: rename detected from \"%s\" to \"%s\". %s",
-                     log_ioctl_type,
-                     ifindex,
-                     log_subtype,
-                     known_ifnames[(try_count - 1) % 2],
-                     known_ifnames[try_count % 2],
-                     retry ? "Retry" : "No retry");
-        if (inout_ifname)
-            nm_utils_ifname_cpy(inout_ifname, known_ifnames[try_count % 2]);
-        if (retry) {
-            if (edata_size > 0)
-                memcpy(edata, edata_backup, edata_size);
-            goto again;
-        }
-    }
-
-out:
-    if (failure_reason) {
-        nm_log_trace(LOGD_PLATFORM,
-                     "%s[%d]: %s: %s: %s",
-                     log_ioctl_type,
-                     ifindex,
-                     log_subtype,
-                     failure_reason,
-                     r < 0 ? nm_strerror_native(-r) : "assume success");
-    }
-    if (r >= 0)
-        NM_SET_OUT(out_ifreq, ifr);
-    return r;
-}
-
-/******************************************************************************
- * ethtool
- *****************************************************************************/
-
-static NM_UTILS_ENUM2STR_DEFINE(_ethtool_cmd_to_string,
-                                guint32,
-                                NM_UTILS_ENUM2STR(ETHTOOL_GCOALESCE, "ETHTOOL_GCOALESCE"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_GDRVINFO, "ETHTOOL_GDRVINFO"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_GFEATURES, "ETHTOOL_GFEATURES"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_GLINK, "ETHTOOL_GLINK"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_GPERMADDR, "ETHTOOL_GPERMADDR"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_GRINGPARAM, "ETHTOOL_GRINGPARAM"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_GSET, "ETHTOOL_GSET"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_GSSET_INFO, "ETHTOOL_GSSET_INFO"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_GSTATS, "ETHTOOL_GSTATS"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_GSTRINGS, "ETHTOOL_GSTRINGS"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_GWOL, "ETHTOOL_GWOL"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_SCOALESCE, "ETHTOOL_SCOALESCE"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_SFEATURES, "ETHTOOL_SFEATURES"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_SRINGPARAM, "ETHTOOL_SRINGPARAM"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_SSET, "ETHTOOL_SSET"),
-                                NM_UTILS_ENUM2STR(ETHTOOL_SWOL, "ETHTOOL_SWOL"), );
-
-static const char *
-_ethtool_edata_to_string(gpointer edata, gsize edata_size, char *sbuf, gsize sbuf_len)
-{
-    nm_assert(edata);
-    nm_assert(edata_size >= sizeof(guint32));
-    nm_assert((((intptr_t) edata) % _nm_alignof(guint32)) == 0);
-
-    return _ethtool_cmd_to_string(*((guint32 *) edata), sbuf, sbuf_len);
-}
-
-/*****************************************************************************/
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
-    #define ethtool_cmd_speed(pedata) ((pedata)->speed)
-
-    #define ethtool_cmd_speed_set(pedata, speed) \
-        G_STMT_START                             \
-        {                                        \
-            (pedata)->speed = (guint16)(speed);  \
-        }                                        \
-        G_STMT_END
-#endif
-
-static int
-_ethtool_call_handle(SocketHandle *shandle, gpointer edata, gsize edata_size)
-{
-    char sbuf[50];
-
-    return _ioctl_call("ethtool",
-                       _ethtool_edata_to_string(edata, edata_size, sbuf, sizeof(sbuf)),
-                       SIOCETHTOOL,
-                       shandle->ifindex,
-                       &shandle->fd,
-                       shandle->ifname,
-                       IOCTL_CALL_DATA_TYPE_IFRDATA,
-                       edata,
-                       edata_size,
-                       NULL);
-}
-
-static int
-_ethtool_call_once(int ifindex, gpointer edata, gsize edata_size)
-{
-    char sbuf[50];
-
-    return _ioctl_call("ethtool",
-                       _ethtool_edata_to_string(edata, edata_size, sbuf, sizeof(sbuf)),
-                       SIOCETHTOOL,
-                       ifindex,
-                       NULL,
-                       NULL,
-                       IOCTL_CALL_DATA_TYPE_IFRDATA,
-                       edata,
-                       edata_size,
-                       NULL);
-}
-
-/*****************************************************************************/
-
-static struct ethtool_gstrings *
-ethtool_get_stringset(SocketHandle *shandle, int stringset_id)
-{
-    struct {
-        struct ethtool_sset_info info;
-        guint32                  sentinel;
-    } sset_info = {
-        .info.cmd       = ETHTOOL_GSSET_INFO,
-        .info.reserved  = 0,
-        .info.sset_mask = (1ULL << stringset_id),
-    };
-    const guint32 *                  pdata;
-    gs_free struct ethtool_gstrings *gstrings = NULL;
-    gsize                            gstrings_len;
-    guint32                          i, len;
-
-    if (_ethtool_call_handle(shandle, &sset_info, sizeof(sset_info)) < 0)
-        return NULL;
-    if (!sset_info.info.sset_mask)
-        return NULL;
-
-    pdata = (guint32 *) sset_info.info.data;
-
-    len = *pdata;
-
-    gstrings_len         = sizeof(*gstrings) + (len * ETH_GSTRING_LEN);
-    gstrings             = g_malloc0(gstrings_len);
-    gstrings->cmd        = ETHTOOL_GSTRINGS;
-    gstrings->string_set = stringset_id;
-    gstrings->len        = len;
-    if (gstrings->len > 0) {
-        if (_ethtool_call_handle(shandle, gstrings, gstrings_len) < 0)
-            return NULL;
-        for (i = 0; i < gstrings->len; i++) {
-            /* ensure NUL terminated */
-            gstrings->data[i * ETH_GSTRING_LEN + (ETH_GSTRING_LEN - 1)] = '\0';
-        }
-    }
-
-    return g_steal_pointer(&gstrings);
-}
-
-static int
-ethtool_gstrings_find(const struct ethtool_gstrings *gstrings, const char *needle)
-{
-    guint32 i;
-
-    /* ethtool_get_stringset() always ensures NUL terminated strings at ETH_GSTRING_LEN.
-     * that means, we cannot possibly request longer names. */
-    nm_assert(needle && strlen(needle) < ETH_GSTRING_LEN);
-
-    for (i = 0; i < gstrings->len; i++) {
-        if (nm_streq((char *) &gstrings->data[i * ETH_GSTRING_LEN], needle))
-            return i;
-    }
-    return -1;
-}
-
-static int
-ethtool_get_stringset_index(SocketHandle *shandle, int stringset_id, const char *needle)
-{
-    gs_free struct ethtool_gstrings *gstrings = NULL;
-
-    /* ethtool_get_stringset() always ensures NUL terminated strings at ETH_GSTRING_LEN.
-     * that means, we cannot possibly request longer names. */
-    nm_assert(needle && strlen(needle) < ETH_GSTRING_LEN);
-
-    gstrings = ethtool_get_stringset(shandle, stringset_id);
-    if (gstrings)
-        return ethtool_gstrings_find(gstrings, needle);
-    return -1;
-}
-
-/*****************************************************************************/
-
-static const NMEthtoolFeatureInfo _ethtool_feature_infos[_NM_ETHTOOL_ID_FEATURE_NUM] = {
-#define ETHT_FEAT(eid, ...)                                        \
-    {                                                              \
-        .ethtool_id = eid, .n_kernel_names = NM_NARG(__VA_ARGS__), \
-        .kernel_names = ((const char *const[]){__VA_ARGS__}),      \
-    }
-
-    /* the order does only matter for one thing: if it happens that more than one NMEthtoolID
-     * reference the same kernel-name, then the one that is mentioned *later* will win in
-     * case these NMEthtoolIDs are set. That mostly only makes sense for ethtool-ids which
-     * refer to multiple features ("feature-tso"), while also having more specific ids
-     * ("feature-tx-tcp-segmentation"). */
-
-    /* names from ethtool utility, which are aliases for multiple features. */
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_SG, "tx-scatter-gather", "tx-scatter-gather-fraglist"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TSO,
-              "tx-tcp-segmentation",
-              "tx-tcp-ecn-segmentation",
-              "tx-tcp-mangleid-segmentation",
-              "tx-tcp6-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX,
-              "tx-checksum-ipv4",
-              "tx-checksum-ip-generic",
-              "tx-checksum-ipv6",
-              "tx-checksum-fcoe-crc",
-              "tx-checksum-sctp"),
-
-    /* names from ethtool utility, which are aliases for one feature. */
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_GRO, "rx-gro"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_GSO, "tx-generic-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_LRO, "rx-lro"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_NTUPLE, "rx-ntuple-filter"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX, "rx-checksum"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RXHASH, "rx-hashing"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RXVLAN, "rx-vlan-hw-parse"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TXVLAN, "tx-vlan-hw-insert"),
-
-    /* names of features, as known by kernel. */
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD, "esp-hw-offload"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD, "esp-tx-csum-hw-offload"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_FCOE_MTU, "fcoe-mtu"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_HIGHDMA, "highdma"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD, "hw-tc-offload"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD, "l2-fwd-offload"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_LOOPBACK, "loopback"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_MACSEC_HW_OFFLOAD, "macsec-hw-offload"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_ALL, "rx-all"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_FCS, "rx-fcs"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_GRO_HW, "rx-gro-hw"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_GRO_LIST, "rx-gro-list"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_UDP_GRO_FORWARDING, "rx-udp-gro-forwarding"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD, "rx-udp_tunnel-port-offload"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER, "rx-vlan-filter"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER, "rx-vlan-stag-filter"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE, "rx-vlan-stag-hw-parse"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD, "tls-hw-record"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TLS_HW_RX_OFFLOAD, "tls-hw-rx-offload"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD, "tls-hw-tx-offload"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC, "tx-checksum-fcoe-crc"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4, "tx-checksum-ipv4"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6, "tx-checksum-ipv6"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC, "tx-checksum-ip-generic"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP, "tx-checksum-sctp"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION, "tx-esp-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION, "tx-fcoe-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION, "tx-gre-csum-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION, "tx-gre-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_GSO_LIST, "tx-gso-list"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL, "tx-gso-partial"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST, "tx-gso-robust"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION, "tx-ipxip4-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION, "tx-ipxip6-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY, "tx-nocache-copy"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER, "tx-scatter-gather"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST, "tx-scatter-gather-fraglist"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION, "tx-sctp-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION, "tx-tcp6-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION, "tx-tcp-ecn-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION, "tx-tcp-mangleid-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION, "tx-tcp-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_TUNNEL_REMCSUM_SEGMENTATION,
-              "tx-tunnel-remcsum-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION, "tx-udp-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION, "tx-udp_tnl-csum-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION, "tx-udp_tnl-segmentation"),
-    ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, "tx-vlan-stag-hw-insert"),
-};
-
-/* the number of kernel features that we handle. It essentially is the sum of all
- * kernel_names. So, all ethtool-ids that reference exactly one kernel-name
- * (_NM_ETHTOOL_ID_FEATURE_NUM) + some extra, for ethtool-ids that are aliases
- * for multiple kernel-names. */
-#define N_ETHTOOL_KERNEL_FEATURES (((guint) _NM_ETHTOOL_ID_FEATURE_NUM) + 8u)
-
-static void
-_ASSERT_ethtool_feature_infos(void)
-{
-#if NM_MORE_ASSERTS > 10
-    guint i, k, n;
-    bool  found[_NM_ETHTOOL_ID_FEATURE_NUM] = {};
-
-    G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(_ethtool_feature_infos) == _NM_ETHTOOL_ID_FEATURE_NUM);
-
-    n = 0;
-    for (i = 0; i < G_N_ELEMENTS(_ethtool_feature_infos); i++) {
-        NMEthtoolFeatureState       kstate;
-        const NMEthtoolFeatureInfo *inf = &_ethtool_feature_infos[i];
-
-        g_assert(inf->ethtool_id >= _NM_ETHTOOL_ID_FEATURE_FIRST);
-        g_assert(inf->ethtool_id <= _NM_ETHTOOL_ID_FEATURE_LAST);
-        g_assert(inf->n_kernel_names > 0);
-
-        for (k = 0; k < i; k++)
-            g_assert(inf->ethtool_id != _ethtool_feature_infos[k].ethtool_id);
-
-        g_assert(!found[_NM_ETHTOOL_ID_FEATURE_AS_IDX(inf->ethtool_id)]);
-        found[_NM_ETHTOOL_ID_FEATURE_AS_IDX(inf->ethtool_id)] = TRUE;
-
-        kstate.idx_kernel_name = inf->n_kernel_names - 1;
-        g_assert((guint) kstate.idx_kernel_name == (guint)(inf->n_kernel_names - 1));
-
-        n += inf->n_kernel_names;
-        for (k = 0; k < inf->n_kernel_names; k++) {
-            const char *name = inf->kernel_names[k];
-
-            g_assert(nm_utils_strv_find_first((char **) inf->kernel_names, k, name) < 0);
-
-            /* these offload features are only informational and cannot be set from user-space
-             * (NETIF_F_NEVER_CHANGE). We should not track them in _ethtool_feature_infos. */
-            g_assert(!nm_streq(name, "netns-local"));
-            g_assert(!nm_streq(name, "tx-lockless"));
-            g_assert(!nm_streq(name, "vlan-challenged"));
-        }
-    }
-
-    for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++)
-        g_assert(found[i]);
-
-    g_assert(n == N_ETHTOOL_KERNEL_FEATURES);
-#endif
-}
-
-static NMEthtoolFeatureStates *
-ethtool_get_features(SocketHandle *shandle)
-{
-    gs_free NMEthtoolFeatureStates * states      = NULL;
-    gs_free struct ethtool_gstrings *ss_features = NULL;
-
-    _ASSERT_ethtool_feature_infos();
-
-    ss_features = ethtool_get_stringset(shandle, ETH_SS_FEATURES);
-    if (!ss_features)
-        return NULL;
-
-    if (ss_features->len > 0) {
-        gs_free struct ethtool_gfeatures *  gfeatures_free = NULL;
-        struct ethtool_gfeatures *          gfeatures;
-        gsize                               gfeatures_len;
-        guint                               idx;
-        const NMEthtoolFeatureState *       states_list0   = NULL;
-        const NMEthtoolFeatureState *const *states_plist0  = NULL;
-        guint                               states_plist_n = 0;
-
-        gfeatures_len = sizeof(struct ethtool_gfeatures)
-                        + (NM_DIV_ROUND_UP(ss_features->len, 32u) * sizeof(gfeatures->features[0]));
-        gfeatures       = nm_malloc0_maybe_a(300, gfeatures_len, &gfeatures_free);
-        gfeatures->cmd  = ETHTOOL_GFEATURES;
-        gfeatures->size = NM_DIV_ROUND_UP(ss_features->len, 32u);
-        if (_ethtool_call_handle(shandle, gfeatures, gfeatures_len) < 0)
-            return NULL;
-
-        for (idx = 0; idx < G_N_ELEMENTS(_ethtool_feature_infos); idx++) {
-            const NMEthtoolFeatureInfo *info = &_ethtool_feature_infos[idx];
-            guint                       idx_kernel_name;
-
-            for (idx_kernel_name = 0; idx_kernel_name < info->n_kernel_names; idx_kernel_name++) {
-                NMEthtoolFeatureState *kstate;
-                const char *           kernel_name = info->kernel_names[idx_kernel_name];
-                int                    i_feature;
-                guint                  i_block;
-                guint32                i_flag;
-
-                i_feature = ethtool_gstrings_find(ss_features, kernel_name);
-                if (i_feature < 0)
-                    continue;
-
-                i_block = ((guint) i_feature) / 32u;
-                i_flag  = (guint32)(1u << (((guint) i_feature) % 32u));
-
-                if (!states) {
-                    states = g_malloc0(
-                        sizeof(NMEthtoolFeatureStates)
-                        + (N_ETHTOOL_KERNEL_FEATURES * sizeof(NMEthtoolFeatureState))
-                        + ((N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS(_ethtool_feature_infos))
-                           * sizeof(NMEthtoolFeatureState *)));
-                    states_list0          = &states->states_list[0];
-                    states_plist0         = (gpointer) &states_list0[N_ETHTOOL_KERNEL_FEATURES];
-                    states->n_ss_features = ss_features->len;
-                }
-
-                nm_assert(states->n_states < N_ETHTOOL_KERNEL_FEATURES);
-                kstate = (NMEthtoolFeatureState *) &states_list0[states->n_states];
-                states->n_states++;
-
-                kstate->info            = info;
-                kstate->idx_ss_features = i_feature;
-                kstate->idx_kernel_name = idx_kernel_name;
-                kstate->available       = !!(gfeatures->features[i_block].available & i_flag);
-                kstate->requested       = !!(gfeatures->features[i_block].requested & i_flag);
-                kstate->active          = !!(gfeatures->features[i_block].active & i_flag);
-                kstate->never_changed   = !!(gfeatures->features[i_block].never_changed & i_flag);
-
-                nm_assert(states_plist_n
-                          < N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS(_ethtool_feature_infos));
-
-                if (!states->states_indexed[_NM_ETHTOOL_ID_FEATURE_AS_IDX(info->ethtool_id)])
-                    states->states_indexed[_NM_ETHTOOL_ID_FEATURE_AS_IDX(info->ethtool_id)] =
-                        &states_plist0[states_plist_n];
-                ((const NMEthtoolFeatureState **) states_plist0)[states_plist_n] = kstate;
-                states_plist_n++;
-            }
-
-            if (states && states->states_indexed[_NM_ETHTOOL_ID_FEATURE_AS_IDX(info->ethtool_id)]) {
-                nm_assert(states_plist_n
-                          < N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS(_ethtool_feature_infos));
-                nm_assert(!states_plist0[states_plist_n]);
-                states_plist_n++;
-            }
-        }
-    }
-
-    return g_steal_pointer(&states);
-}
-
-NMEthtoolFeatureStates *
-nmp_utils_ethtool_get_features(int ifindex)
-{
-    nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-    NMEthtoolFeatureStates *           features;
-
-    g_return_val_if_fail(ifindex > 0, 0);
-
-    features = ethtool_get_features(&shandle);
-
-    if (!features) {
-        nm_log_trace(LOGD_PLATFORM,
-                     "ethtool[%d]: %s: failure getting features",
-                     ifindex,
-                     "get-features");
-        return NULL;
-    }
-
-    nm_log_trace(LOGD_PLATFORM,
-                 "ethtool[%d]: %s: retrieved kernel features",
-                 ifindex,
-                 "get-features");
-    return features;
-}
-
-static const char *
-_ethtool_feature_state_to_string(char *                       buf,
-                                 gsize                        buf_size,
-                                 const NMEthtoolFeatureState *s,
-                                 const char *                 prefix)
-{
-    int l;
-
-    l = g_snprintf(buf,
-                   buf_size,
-                   "%s %s%s",
-                   prefix ?: "",
-                   ONOFF(s->active),
-                   (!s->available || s->never_changed)
-                       ? ", [fixed]"
-                       : ((s->requested != s->active)
-                              ? (s->requested ? ", [requested on]" : ", [requested off]")
-                              : ""));
-    nm_assert(l < buf_size);
-    return buf;
-}
-
-gboolean
-nmp_utils_ethtool_set_features(
-    int                           ifindex,
-    const NMEthtoolFeatureStates *features,
-    const NMOptionBool *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
-    gboolean            do_set /* or reset */)
-{
-    nm_auto_socket_handle SocketHandle shandle        = SOCKET_HANDLE_INIT(ifindex);
-    gs_free struct ethtool_sfeatures * sfeatures_free = NULL;
-    struct ethtool_sfeatures *         sfeatures;
-    gsize                              sfeatures_len;
-    int                                r;
-    guint                              i, j;
-    struct {
-        const NMEthtoolFeatureState *f_state;
-        NMOptionBool                 requested;
-    } set_states[N_ETHTOOL_KERNEL_FEATURES];
-    guint    set_states_n = 0;
-    gboolean success      = TRUE;
-
-    g_return_val_if_fail(ifindex > 0, 0);
-    g_return_val_if_fail(features, 0);
-    g_return_val_if_fail(requested, 0);
-
-    nm_assert(features->n_states <= N_ETHTOOL_KERNEL_FEATURES);
-
-    for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) {
-        const NMEthtoolFeatureState *const *states_indexed;
-
-        if (requested[i] == NM_OPTION_BOOL_DEFAULT)
-            continue;
-
-        if (!(states_indexed = features->states_indexed[i])) {
-            if (do_set) {
-                nm_log_trace(LOGD_PLATFORM,
-                             "ethtool[%d]: %s: set feature %s: skip (not found)",
-                             ifindex,
-                             "set-features",
-                             nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname);
-                success = FALSE;
-            }
-            continue;
-        }
-
-        for (j = 0; states_indexed[j]; j++) {
-            const NMEthtoolFeatureState *s = states_indexed[j];
-            char                         sbuf[255];
-
-            if (set_states_n >= G_N_ELEMENTS(set_states))
-                g_return_val_if_reached(FALSE);
-
-            if (s->never_changed) {
-                nm_log_trace(LOGD_PLATFORM,
-                             "ethtool[%d]: %s: %s feature %s (%s): %s, %s (skip feature marked as "
-                             "never changed)",
-                             ifindex,
-                             "set-features",
-                             do_set ? "set" : "reset",
-                             nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname,
-                             s->info->kernel_names[s->idx_kernel_name],
-                             ONOFF(do_set ? requested[i] == NM_OPTION_BOOL_TRUE : s->active),
-                             _ethtool_feature_state_to_string(sbuf,
-                                                              sizeof(sbuf),
-                                                              s,
-                                                              do_set ? " currently:" : " before:"));
-                continue;
-            }
-
-            nm_log_trace(LOGD_PLATFORM,
-                         "ethtool[%d]: %s: %s feature %s (%s): %s, %s",
-                         ifindex,
-                         "set-features",
-                         do_set ? "set" : "reset",
-                         nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname,
-                         s->info->kernel_names[s->idx_kernel_name],
-                         ONOFF(do_set ? requested[i] == NM_OPTION_BOOL_TRUE : s->active),
-                         _ethtool_feature_state_to_string(sbuf,
-                                                          sizeof(sbuf),
-                                                          s,
-                                                          do_set ? " currently:" : " before:"));
-
-            if (do_set && (!s->available || s->never_changed)
-                && (s->active != (requested[i] == NM_OPTION_BOOL_TRUE))) {
-                /* we request to change a flag which kernel reported as fixed.
-                 * While the ethtool operation will silently succeed, mark the request
-                 * as failure. */
-                success = FALSE;
-            }
-
-            set_states[set_states_n].f_state   = s;
-            set_states[set_states_n].requested = requested[i];
-            set_states_n++;
-        }
-    }
-
-    if (set_states_n == 0) {
-        nm_log_trace(LOGD_PLATFORM,
-                     "ethtool[%d]: %s: no feature requested",
-                     ifindex,
-                     "set-features");
-        return TRUE;
-    }
-
-    sfeatures_len =
-        sizeof(struct ethtool_sfeatures)
-        + (NM_DIV_ROUND_UP(features->n_ss_features, 32U) * sizeof(sfeatures->features[0]));
-    sfeatures       = nm_malloc0_maybe_a(300, sfeatures_len, &sfeatures_free);
-    sfeatures->cmd  = ETHTOOL_SFEATURES;
-    sfeatures->size = NM_DIV_ROUND_UP(features->n_ss_features, 32U);
-
-    for (i = 0; i < set_states_n; i++) {
-        const NMEthtoolFeatureState *s = set_states[i].f_state;
-        guint                        i_block;
-        guint32                      i_flag;
-        gboolean                     is_requested;
-
-        i_block = s->idx_ss_features / 32u;
-        i_flag  = (guint32)(1u << (s->idx_ss_features % 32u));
-
-        sfeatures->features[i_block].valid |= i_flag;
-
-        if (do_set)
-            is_requested = (set_states[i].requested == NM_OPTION_BOOL_TRUE);
-        else
-            is_requested = s->active;
-
-        if (is_requested)
-            sfeatures->features[i_block].requested |= i_flag;
-        else
-            sfeatures->features[i_block].requested &= ~i_flag;
-    }
-
-    r = _ethtool_call_handle(&shandle, sfeatures, sfeatures_len);
-    if (r < 0) {
-        success = FALSE;
-        nm_log_trace(LOGD_PLATFORM,
-                     "ethtool[%d]: %s: failure setting features (%s)",
-                     ifindex,
-                     "set-features",
-                     nm_strerror_native(-r));
-        return FALSE;
-    }
-
-    nm_log_trace(LOGD_PLATFORM,
-                 "ethtool[%d]: %s: %s",
-                 ifindex,
-                 "set-features",
-                 success ? "successfully setting features"
-                         : "at least some of the features were not successfully set");
-    return success;
-}
-
-static gboolean
-ethtool_get_coalesce(SocketHandle *shandle, NMEthtoolCoalesceState *coalesce)
-{
-    struct ethtool_coalesce eth_data;
-
-    eth_data.cmd = ETHTOOL_GCOALESCE;
-
-    if (_ethtool_call_handle(shandle, &eth_data, sizeof(struct ethtool_coalesce)) != 0)
-        return FALSE;
-
-    *coalesce = (NMEthtoolCoalesceState){
-        .s = {
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS)] =
-                eth_data.rx_coalesce_usecs,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES)] =
-                eth_data.rx_max_coalesced_frames,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ)] =
-                eth_data.rx_coalesce_usecs_irq,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ)] =
-                eth_data.rx_max_coalesced_frames_irq,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS)] =
-                eth_data.tx_coalesce_usecs,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES)] =
-                eth_data.tx_max_coalesced_frames,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ)] =
-                eth_data.tx_coalesce_usecs_irq,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ)] =
-                eth_data.tx_max_coalesced_frames_irq,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS)] =
-                eth_data.stats_block_coalesce_usecs,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX)] =
-                eth_data.use_adaptive_rx_coalesce,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX)] =
-                eth_data.use_adaptive_tx_coalesce,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW)] =
-                eth_data.pkt_rate_low,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW)] =
-                eth_data.rx_coalesce_usecs_low,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW)] =
-                eth_data.rx_max_coalesced_frames_low,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW)] =
-                eth_data.tx_coalesce_usecs_low,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW)] =
-                eth_data.tx_max_coalesced_frames_low,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH)] =
-                eth_data.pkt_rate_high,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH)] =
-                eth_data.rx_coalesce_usecs_high,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH)] =
-                eth_data.rx_max_coalesced_frames_high,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH)] =
-                eth_data.tx_coalesce_usecs_high,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH)] =
-                eth_data.tx_max_coalesced_frames_high,
-            [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL)] =
-                eth_data.rate_sample_interval,
-        }};
-    return TRUE;
-}
-
-gboolean
-nmp_utils_ethtool_get_coalesce(int ifindex, NMEthtoolCoalesceState *coalesce)
-{
-    nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-    g_return_val_if_fail(coalesce, FALSE);
-
-    if (!ethtool_get_coalesce(&shandle, coalesce)) {
-        nm_log_trace(LOGD_PLATFORM,
-                     "ethtool[%d]: %s: failure getting coalesce settings",
-                     ifindex,
-                     "get-coalesce");
-        return FALSE;
-    }
-
-    nm_log_trace(LOGD_PLATFORM,
-                 "ethtool[%d]: %s: retrieved kernel coalesce settings",
-                 ifindex,
-                 "get-coalesce");
-    return TRUE;
-}
-
-static gboolean
-ethtool_set_coalesce(SocketHandle *shandle, const NMEthtoolCoalesceState *coalesce)
-{
-    struct ethtool_coalesce eth_data;
-    gboolean                success;
-
-    nm_assert(shandle);
-    nm_assert(coalesce);
-
-    eth_data = (struct ethtool_coalesce){
-        .cmd = ETHTOOL_SCOALESCE,
-        .rx_coalesce_usecs =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS)],
-        .rx_max_coalesced_frames =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES)],
-        .rx_coalesce_usecs_irq =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ)],
-        .rx_max_coalesced_frames_irq =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ)],
-        .tx_coalesce_usecs =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS)],
-        .tx_max_coalesced_frames =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES)],
-        .tx_coalesce_usecs_irq =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ)],
-        .tx_max_coalesced_frames_irq =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ)],
-        .stats_block_coalesce_usecs =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS)],
-        .use_adaptive_rx_coalesce =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX)],
-        .use_adaptive_tx_coalesce =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX)],
-        .pkt_rate_low =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW)],
-        .rx_coalesce_usecs_low =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW)],
-        .rx_max_coalesced_frames_low =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW)],
-        .tx_coalesce_usecs_low =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW)],
-        .tx_max_coalesced_frames_low =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW)],
-        .pkt_rate_high =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH)],
-        .rx_coalesce_usecs_high =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH)],
-        .rx_max_coalesced_frames_high =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH)],
-        .tx_coalesce_usecs_high =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH)],
-        .tx_max_coalesced_frames_high =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH)],
-        .rate_sample_interval =
-            coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL)],
-    };
-
-    success = (_ethtool_call_handle(shandle, &eth_data, sizeof(struct ethtool_coalesce)) == 0);
-    return success;
-}
-
-gboolean
-nmp_utils_ethtool_set_coalesce(int ifindex, const NMEthtoolCoalesceState *coalesce)
-{
-    nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-    g_return_val_if_fail(coalesce, FALSE);
-
-    if (!ethtool_set_coalesce(&shandle, coalesce)) {
-        nm_log_trace(LOGD_PLATFORM,
-                     "ethtool[%d]: %s: failure setting coalesce settings",
-                     ifindex,
-                     "set-coalesce");
-        return FALSE;
-    }
-
-    nm_log_trace(LOGD_PLATFORM,
-                 "ethtool[%d]: %s: set kernel coalesce settings",
-                 ifindex,
-                 "set-coalesce");
-    return TRUE;
-}
-
-static gboolean
-ethtool_get_ring(SocketHandle *shandle, NMEthtoolRingState *ring)
-{
-    struct ethtool_ringparam eth_data;
-
-    eth_data.cmd = ETHTOOL_GRINGPARAM;
-
-    if (_ethtool_call_handle(shandle, &eth_data, sizeof(struct ethtool_ringparam)) != 0)
-        return FALSE;
-
-    ring->rx_pending       = eth_data.rx_pending;
-    ring->rx_jumbo_pending = eth_data.rx_jumbo_pending;
-    ring->rx_mini_pending  = eth_data.rx_mini_pending;
-    ring->tx_pending       = eth_data.tx_pending;
-
-    return TRUE;
-}
-
-gboolean
-nmp_utils_ethtool_get_ring(int ifindex, NMEthtoolRingState *ring)
-{
-    nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-    g_return_val_if_fail(ring, FALSE);
-
-    if (!ethtool_get_ring(&shandle, ring)) {
-        nm_log_trace(LOGD_PLATFORM,
-                     "ethtool[%d]: %s: failure getting ring settings",
-                     ifindex,
-                     "get-ring");
-        return FALSE;
-    }
-
-    nm_log_trace(LOGD_PLATFORM,
-                 "ethtool[%d]: %s: retrieved kernel ring settings",
-                 ifindex,
-                 "get-ring");
-    return TRUE;
-}
-
-static gboolean
-ethtool_set_ring(SocketHandle *shandle, const NMEthtoolRingState *ring)
-{
-    gboolean                 success;
-    struct ethtool_ringparam eth_data;
-
-    g_return_val_if_fail(shandle, FALSE);
-    g_return_val_if_fail(ring, FALSE);
-
-    eth_data = (struct ethtool_ringparam){
-        .cmd              = ETHTOOL_SRINGPARAM,
-        .rx_pending       = ring->rx_pending,
-        .rx_jumbo_pending = ring->rx_jumbo_pending,
-        .rx_mini_pending  = ring->rx_mini_pending,
-        .tx_pending       = ring->tx_pending,
-    };
-
-    success = (_ethtool_call_handle(shandle, &eth_data, sizeof(struct ethtool_ringparam)) == 0);
-    return success;
-}
-
-gboolean
-nmp_utils_ethtool_set_ring(int ifindex, const NMEthtoolRingState *ring)
-{
-    nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-    g_return_val_if_fail(ring, FALSE);
-
-    if (!ethtool_set_ring(&shandle, ring)) {
-        nm_log_trace(LOGD_PLATFORM,
-                     "ethtool[%d]: %s: failure setting ring settings",
-                     ifindex,
-                     "set-ring");
-        return FALSE;
-    }
-
-    nm_log_trace(LOGD_PLATFORM, "ethtool[%d]: %s: set kernel ring settings", ifindex, "set-ring");
-    return TRUE;
-}
-
-/*****************************************************************************/
-
-gboolean
-nmp_utils_ethtool_get_driver_info(int ifindex, NMPUtilsEthtoolDriverInfo *data)
-{
-    struct ethtool_drvinfo *drvinfo;
-
-    G_STATIC_ASSERT_EXPR(sizeof(*data) == sizeof(*drvinfo));
-    G_STATIC_ASSERT_EXPR(offsetof(NMPUtilsEthtoolDriverInfo, driver)
-                         == offsetof(struct ethtool_drvinfo, driver));
-    G_STATIC_ASSERT_EXPR(offsetof(NMPUtilsEthtoolDriverInfo, version)
-                         == offsetof(struct ethtool_drvinfo, version));
-    G_STATIC_ASSERT_EXPR(offsetof(NMPUtilsEthtoolDriverInfo, fw_version)
-                         == offsetof(struct ethtool_drvinfo, fw_version));
-    G_STATIC_ASSERT_EXPR(sizeof(data->driver) == sizeof(drvinfo->driver));
-    G_STATIC_ASSERT_EXPR(sizeof(data->version) == sizeof(drvinfo->version));
-    G_STATIC_ASSERT_EXPR(sizeof(data->fw_version) == sizeof(drvinfo->fw_version));
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-    g_return_val_if_fail(data, FALSE);
-
-    drvinfo  = (struct ethtool_drvinfo *) data;
-    *drvinfo = (struct ethtool_drvinfo){
-        .cmd = ETHTOOL_GDRVINFO,
-    };
-    return _ethtool_call_once(ifindex, drvinfo, sizeof(*drvinfo)) >= 0;
-}
-
-gboolean
-nmp_utils_ethtool_get_permanent_address(int ifindex, guint8 *buf, size_t *length)
-{
-    struct {
-        struct ethtool_perm_addr e;
-        guint8                   _extra_data[_NM_UTILS_HWADDR_LEN_MAX + 1];
-    } edata = {
-        .e.cmd  = ETHTOOL_GPERMADDR,
-        .e.size = _NM_UTILS_HWADDR_LEN_MAX,
-    };
-    const guint8 *pdata;
-
-    guint i;
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-
-    if (_ethtool_call_once(ifindex, &edata, sizeof(edata)) < 0)
-        return FALSE;
-
-    if (edata.e.size > _NM_UTILS_HWADDR_LEN_MAX)
-        return FALSE;
-    if (edata.e.size < 1)
-        return FALSE;
-
-    pdata = (const guint8 *) edata.e.data;
-
-    if (NM_IN_SET(pdata[0], 0, 0xFF)) {
-        /* Some drivers might return a permanent address of all zeros.
-         * Reject that (rh#1264024)
-         *
-         * Some drivers return a permanent address of all ones. Reject that too */
-        for (i = 1; i < edata.e.size; i++) {
-            if (pdata[0] != pdata[i])
-                goto not_all_0or1;
-        }
-        return FALSE;
-    }
-
-not_all_0or1:
-    memcpy(buf, pdata, edata.e.size);
-    *length = edata.e.size;
-    return TRUE;
-}
-
-gboolean
-nmp_utils_ethtool_supports_carrier_detect(int ifindex)
-{
-    struct ethtool_cmd edata = {.cmd = ETHTOOL_GLINK};
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-
-    /* We ignore the result. If the ETHTOOL_GLINK call succeeded, then we
-     * assume the device supports carrier-detect, otherwise we assume it
-     * doesn't.
-     */
-    return _ethtool_call_once(ifindex, &edata, sizeof(edata)) >= 0;
-}
-
-gboolean
-nmp_utils_ethtool_supports_vlans(int ifindex)
-{
-    nm_auto_socket_handle SocketHandle shandle       = SOCKET_HANDLE_INIT(ifindex);
-    gs_free struct ethtool_gfeatures * features_free = NULL;
-    struct ethtool_gfeatures *         features;
-    gsize                              features_len;
-    int                                idx, block, bit, size;
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-
-    idx = ethtool_get_stringset_index(&shandle, ETH_SS_FEATURES, "vlan-challenged");
-    if (idx < 0) {
-        nm_log_dbg(LOGD_PLATFORM,
-                   "ethtool[%d]: vlan-challenged ethtool feature does not exist?",
-                   ifindex);
-        return FALSE;
-    }
-
-    block = idx / 32;
-    bit   = idx % 32;
-    size  = block + 1;
-
-    features_len   = sizeof(*features) + (size * sizeof(struct ethtool_get_features_block));
-    features       = nm_malloc0_maybe_a(300, features_len, &features_free);
-    features->cmd  = ETHTOOL_GFEATURES;
-    features->size = size;
-
-    if (_ethtool_call_handle(&shandle, features, features_len) < 0)
-        return FALSE;
-
-    return !(features->features[block].active & (1 << bit));
-}
-
-int
-nmp_utils_ethtool_get_peer_ifindex(int ifindex)
-{
-    nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-    gsize                              stats_len;
-    gs_free struct ethtool_stats *     stats_free = NULL;
-    struct ethtool_stats *             stats;
-    int                                peer_ifindex_stat;
-
-    g_return_val_if_fail(ifindex > 0, 0);
-
-    peer_ifindex_stat = ethtool_get_stringset_index(&shandle, ETH_SS_STATS, "peer_ifindex");
-    if (peer_ifindex_stat < 0) {
-        nm_log_dbg(LOGD_PLATFORM, "ethtool[%d]: peer_ifindex stat does not exist?", ifindex);
-        return FALSE;
-    }
-
-    stats_len      = sizeof(*stats) + (peer_ifindex_stat + 1) * sizeof(guint64);
-    stats          = nm_malloc0_maybe_a(300, stats_len, &stats_free);
-    stats->cmd     = ETHTOOL_GSTATS;
-    stats->n_stats = peer_ifindex_stat + 1;
-    if (_ethtool_call_handle(&shandle, stats, stats_len) < 0)
-        return 0;
-
-    return stats->data[peer_ifindex_stat];
-}
-
-gboolean
-nmp_utils_ethtool_get_wake_on_lan(int ifindex)
-{
-    struct ethtool_wolinfo wol = {
-        .cmd = ETHTOOL_GWOL,
-    };
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-
-    if (_ethtool_call_once(ifindex, &wol, sizeof(wol)) < 0)
-        return FALSE;
-
-    return wol.wolopts != 0;
-}
-
-gboolean
-nmp_utils_ethtool_get_link_settings(int                       ifindex,
-                                    gboolean *                out_autoneg,
-                                    guint32 *                 out_speed,
-                                    NMPlatformLinkDuplexType *out_duplex)
-{
-    struct ethtool_cmd edata = {
-        .cmd = ETHTOOL_GSET,
-    };
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-
-    if (_ethtool_call_once(ifindex, &edata, sizeof(edata)) < 0)
-        return FALSE;
-
-    NM_SET_OUT(out_autoneg, (edata.autoneg == AUTONEG_ENABLE));
-
-    if (out_speed) {
-        guint32 speed;
-
-        speed = ethtool_cmd_speed(&edata);
-        if (speed == G_MAXUINT16 || speed == G_MAXUINT32)
-            speed = 0;
-
-        *out_speed = speed;
-    }
-
-    if (out_duplex) {
-        switch (edata.duplex) {
-        case DUPLEX_HALF:
-            *out_duplex = NM_PLATFORM_LINK_DUPLEX_HALF;
-            break;
-        case DUPLEX_FULL:
-            *out_duplex = NM_PLATFORM_LINK_DUPLEX_FULL;
-            break;
-        default: /* DUPLEX_UNKNOWN */
-            *out_duplex = NM_PLATFORM_LINK_DUPLEX_UNKNOWN;
-            break;
-        }
-    }
-
-    return TRUE;
-}
-
-#define ADVERTISED_INVALID 0
-#define BASET_ALL_MODES                                                                 \
-    (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half       \
-     | ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full \
-     | ADVERTISED_10000baseT_Full)
-
-static guint32
-get_baset_mode(guint32 speed, NMPlatformLinkDuplexType duplex)
-{
-    if (duplex == NM_PLATFORM_LINK_DUPLEX_UNKNOWN)
-        return ADVERTISED_INVALID;
-
-    if (duplex == NM_PLATFORM_LINK_DUPLEX_HALF) {
-        switch (speed) {
-        case 10:
-            return ADVERTISED_10baseT_Half;
-        case 100:
-            return ADVERTISED_100baseT_Half;
-        case 1000:
-            return ADVERTISED_1000baseT_Half;
-        default:
-            return ADVERTISED_INVALID;
-        }
-    } else {
-        switch (speed) {
-        case 10:
-            return ADVERTISED_10baseT_Full;
-        case 100:
-            return ADVERTISED_100baseT_Full;
-        case 1000:
-            return ADVERTISED_1000baseT_Full;
-        case 10000:
-            return ADVERTISED_10000baseT_Full;
-        default:
-            return ADVERTISED_INVALID;
-        }
-    }
-}
-
-gboolean
-nmp_utils_ethtool_set_link_settings(int                      ifindex,
-                                    gboolean                 autoneg,
-                                    guint32                  speed,
-                                    NMPlatformLinkDuplexType duplex)
-{
-    nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-    struct ethtool_cmd                 edata   = {
-        .cmd = ETHTOOL_GSET,
-    };
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-    g_return_val_if_fail((speed && duplex != NM_PLATFORM_LINK_DUPLEX_UNKNOWN)
-                             || (!speed && duplex == NM_PLATFORM_LINK_DUPLEX_UNKNOWN),
-                         FALSE);
-
-    /* retrieve first current settings */
-    if (_ethtool_call_handle(&shandle, &edata, sizeof(edata)) < 0)
-        return FALSE;
-
-    /* FIXME: try first new ETHTOOL_GLINKSETTINGS/SLINKSETTINGS API
-     * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3f1ac7a700d039c61d8d8b99f28d605d489a60cf
-     */
-
-    /* then change the needed ones */
-    edata.cmd = ETHTOOL_SSET;
-    if (autoneg) {
-        edata.autoneg = AUTONEG_ENABLE;
-        if (!speed)
-            edata.advertising = edata.supported;
-        else {
-            guint32 mode;
-
-            mode = get_baset_mode(speed, duplex);
-
-            if (!mode) {
-                nm_log_trace(LOGD_PLATFORM,
-                             "ethtool[%d]: %uBASE-T %s duplex mode cannot be advertised",
-                             ifindex,
-                             speed,
-                             nm_platform_link_duplex_type_to_string(duplex));
-                return FALSE;
-            }
-            if (!(edata.supported & mode)) {
-                nm_log_trace(LOGD_PLATFORM,
-                             "ethtool[%d]: device does not support %uBASE-T %s duplex mode",
-                             ifindex,
-                             speed,
-                             nm_platform_link_duplex_type_to_string(duplex));
-                return FALSE;
-            }
-            edata.advertising = (edata.supported & ~BASET_ALL_MODES) | mode;
-        }
-    } else {
-        edata.autoneg = AUTONEG_DISABLE;
-
-        if (speed)
-            ethtool_cmd_speed_set(&edata, speed);
-
-        switch (duplex) {
-        case NM_PLATFORM_LINK_DUPLEX_HALF:
-            edata.duplex = DUPLEX_HALF;
-            break;
-        case NM_PLATFORM_LINK_DUPLEX_FULL:
-            edata.duplex = DUPLEX_FULL;
-            break;
-        case NM_PLATFORM_LINK_DUPLEX_UNKNOWN:
-            break;
-        default:
-            g_return_val_if_reached(FALSE);
-        }
-    }
-
-    return _ethtool_call_handle(&shandle, &edata, sizeof(edata)) >= 0;
-}
-
-gboolean
-nmp_utils_ethtool_set_wake_on_lan(int                      ifindex,
-                                  _NMSettingWiredWakeOnLan wol,
-                                  const char *             wol_password)
-{
-    struct ethtool_wolinfo wol_info = {
-        .cmd     = ETHTOOL_SWOL,
-        .wolopts = 0,
-    };
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-
-    if (wol == _NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE)
-        return TRUE;
-
-    nm_log_dbg(LOGD_PLATFORM,
-               "ethtool[%d]: setting Wake-on-LAN options 0x%x, password '%s'",
-               ifindex,
-               (unsigned) wol,
-               wol_password);
-
-    if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_PHY))
-        wol_info.wolopts |= WAKE_PHY;
-    if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST))
-        wol_info.wolopts |= WAKE_UCAST;
-    if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST))
-        wol_info.wolopts |= WAKE_MCAST;
-    if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST))
-        wol_info.wolopts |= WAKE_BCAST;
-    if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_ARP))
-        wol_info.wolopts |= WAKE_ARP;
-    if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC))
-        wol_info.wolopts |= WAKE_MAGIC;
-
-    if (wol_password) {
-        if (!_nm_utils_hwaddr_aton_exact(wol_password, wol_info.sopass, ETH_ALEN)) {
-            nm_log_dbg(LOGD_PLATFORM,
-                       "ethtool[%d]: couldn't parse Wake-on-LAN password '%s'",
-                       ifindex,
-                       wol_password);
-            return FALSE;
-        }
-        wol_info.wolopts |= WAKE_MAGICSECURE;
-    }
-
-    return _ethtool_call_once(ifindex, &wol_info, sizeof(wol_info)) >= 0;
-}
-
-/******************************************************************************
- * mii
- *****************************************************************************/
-
-gboolean
-nmp_utils_mii_supports_carrier_detect(int ifindex)
-{
-    nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-    int                                r;
-    struct ifreq                       ifr;
-    struct mii_ioctl_data *            mii;
-
-    g_return_val_if_fail(ifindex > 0, FALSE);
-
-    r = _ioctl_call("mii",
-                    "SIOCGMIIPHY",
-                    SIOCGMIIPHY,
-                    shandle.ifindex,
-                    &shandle.fd,
-                    shandle.ifname,
-                    IOCTL_CALL_DATA_TYPE_NONE,
-                    NULL,
-                    0,
-                    &ifr);
-    if (r < 0)
-        return FALSE;
-
-    /* If we can read the BMSR register, we assume that the card supports MII link detection */
-    mii          = (struct mii_ioctl_data *) &ifr.ifr_ifru;
-    mii->reg_num = MII_BMSR;
-
-    r = _ioctl_call("mii",
-                    "SIOCGMIIREG",
-                    SIOCGMIIREG,
-                    shandle.ifindex,
-                    &shandle.fd,
-                    shandle.ifname,
-                    IOCTL_CALL_DATA_TYPE_IFRU,
-                    mii,
-                    sizeof(*mii),
-                    &ifr);
-    if (r < 0)
-        return FALSE;
-
-    mii = (struct mii_ioctl_data *) &ifr.ifr_ifru;
-    nm_log_trace(LOGD_PLATFORM,
-                 "mii[%d,%s]: carrier-detect yes: SIOCGMIIREG result 0x%X",
-                 ifindex,
-                 shandle.ifname,
-                 mii->val_out);
-    return TRUE;
-}
-
-/******************************************************************************
- * udev
- *****************************************************************************/
-
-const char *
-nmp_utils_udev_get_driver(struct udev_device *udevice)
-{
-    struct udev_device *parent = NULL, *grandparent = NULL;
-    const char *        driver, *subsys;
-
-    driver = udev_device_get_driver(udevice);
-    if (driver)
-        goto out;
-
-    /* Try the parent */
-    parent = udev_device_get_parent(udevice);
-    if (parent) {
-        driver = udev_device_get_driver(parent);
-        if (!driver) {
-            /* Try the grandparent if it's an ibmebus device or if the
-             * subsys is NULL which usually indicates some sort of
-             * platform device like a 'gadget' net interface.
-             */
-            subsys = udev_device_get_subsystem(parent);
-            if ((g_strcmp0(subsys, "ibmebus") == 0) || (subsys == NULL)) {
-                grandparent = udev_device_get_parent(parent);
-                if (grandparent)
-                    driver = udev_device_get_driver(grandparent);
-            }
-        }
-    }
-
-out:
-    /* Intern the string so we don't have to worry about memory
-     * management in NMPlatformLink. */
-    return g_intern_string(driver);
-}
-
-/******************************************************************************
- * utils
- *****************************************************************************/
-
-NMIPConfigSource
-nmp_utils_ip_config_source_from_rtprot(guint8 rtprot)
-{
-    return ((int) rtprot) + 1;
-}
-
-NMIPConfigSource
-nmp_utils_ip_config_source_round_trip_rtprot(NMIPConfigSource source)
-{
-    /* when adding a route to kernel for a give @source, the resulting route
-     * will be put into the cache with a source of NM_IP_CONFIG_SOURCE_RTPROT_*.
-     * This function returns that. */
-    return nmp_utils_ip_config_source_from_rtprot(
-        nmp_utils_ip_config_source_coerce_to_rtprot(source));
-}
-
-guint8
-nmp_utils_ip_config_source_coerce_to_rtprot(NMIPConfigSource source)
-{
-    /* when adding a route to kernel, we coerce the @source field
-     * to rtm_protocol. This is not lossless as we map different
-     * source values to the same RTPROT uint8 value. */
-    if (source <= NM_IP_CONFIG_SOURCE_UNKNOWN)
-        return RTPROT_UNSPEC;
-
-    if (source <= _NM_IP_CONFIG_SOURCE_RTPROT_LAST)
-        return source - 1;
-
-    switch (source) {
-    case NM_IP_CONFIG_SOURCE_KERNEL:
-        return RTPROT_KERNEL;
-    case NM_IP_CONFIG_SOURCE_IP6LL:
-        return RTPROT_KERNEL;
-    case NM_IP_CONFIG_SOURCE_DHCP:
-        return RTPROT_DHCP;
-    case NM_IP_CONFIG_SOURCE_NDISC:
-        return RTPROT_RA;
-
-    default:
-        return RTPROT_STATIC;
-    }
-}
-
-NMIPConfigSource
-nmp_utils_ip_config_source_coerce_from_rtprot(NMIPConfigSource source)
-{
-    /* When we receive a route from kernel and put it into the platform cache,
-     * we preserve the protocol field by converting it to a NMIPConfigSource
-     * via nmp_utils_ip_config_source_from_rtprot().
-     *
-     * However, that is not the inverse of nmp_utils_ip_config_source_coerce_to_rtprot().
-     * Instead, to go back to the original value, you need another step:
-     *   nmp_utils_ip_config_source_coerce_from_rtprot (nmp_utils_ip_config_source_from_rtprot (rtprot)).
-     *
-     * This might partly restore the original source value, but of course that
-     * is not really possible because nmp_utils_ip_config_source_coerce_to_rtprot()
-     * is not injective.
-     * */
-    switch (source) {
-    case NM_IP_CONFIG_SOURCE_RTPROT_UNSPEC:
-        return NM_IP_CONFIG_SOURCE_UNKNOWN;
-
-    case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
-    case NM_IP_CONFIG_SOURCE_RTPROT_REDIRECT:
-        return NM_IP_CONFIG_SOURCE_KERNEL;
-
-    case NM_IP_CONFIG_SOURCE_RTPROT_RA:
-        return NM_IP_CONFIG_SOURCE_NDISC;
-
-    case NM_IP_CONFIG_SOURCE_RTPROT_DHCP:
-        return NM_IP_CONFIG_SOURCE_DHCP;
-
-    default:
-        return NM_IP_CONFIG_SOURCE_USER;
-    }
-}
-
-const char *
-nmp_utils_ip_config_source_to_string(NMIPConfigSource source, char *buf, gsize len)
-{
-    const char *s = NULL;
-    nm_utils_to_string_buffer_init(&buf, &len);
-
-    if (!len)
-        return buf;
-
-    switch (source) {
-    case NM_IP_CONFIG_SOURCE_UNKNOWN:
-        s = "unknown";
-        break;
-
-    case NM_IP_CONFIG_SOURCE_RTPROT_UNSPEC:
-        s = "rt-unspec";
-        break;
-    case NM_IP_CONFIG_SOURCE_RTPROT_REDIRECT:
-        s = "rt-redirect";
-        break;
-    case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
-        s = "rt-kernel";
-        break;
-    case NM_IP_CONFIG_SOURCE_RTPROT_BOOT:
-        s = "rt-boot";
-        break;
-    case NM_IP_CONFIG_SOURCE_RTPROT_STATIC:
-        s = "rt-static";
-        break;
-    case NM_IP_CONFIG_SOURCE_RTPROT_DHCP:
-        s = "rt-dhcp";
-        break;
-    case NM_IP_CONFIG_SOURCE_RTPROT_RA:
-        s = "rt-ra";
-        break;
-
-    case NM_IP_CONFIG_SOURCE_KERNEL:
-        s = "kernel";
-        break;
-    case NM_IP_CONFIG_SOURCE_SHARED:
-        s = "shared";
-        break;
-    case NM_IP_CONFIG_SOURCE_IP4LL:
-        s = "ipv4ll";
-        break;
-    case NM_IP_CONFIG_SOURCE_IP6LL:
-        s = "ipv6ll";
-        break;
-    case NM_IP_CONFIG_SOURCE_PPP:
-        s = "ppp";
-        break;
-    case NM_IP_CONFIG_SOURCE_WWAN:
-        s = "wwan";
-        break;
-    case NM_IP_CONFIG_SOURCE_VPN:
-        s = "vpn";
-        break;
-    case NM_IP_CONFIG_SOURCE_DHCP:
-        s = "dhcp";
-        break;
-    case NM_IP_CONFIG_SOURCE_NDISC:
-        s = "ndisc";
-        break;
-    case NM_IP_CONFIG_SOURCE_USER:
-        s = "user";
-        break;
-    default:
-        break;
-    }
-
-    if (source >= 1 && source <= 0x100) {
-        if (s)
-            g_snprintf(buf, len, "%s", s);
-        else
-            g_snprintf(buf, len, "rt-%d", ((int) source) - 1);
-    } else {
-        if (s)
-            g_strlcpy(buf, s, len);
-        else
-            g_snprintf(buf, len, "(%d)", source);
-    }
-    return buf;
-}
-
-/**
- * nmp_utils_sysctl_open_netdir:
- * @ifindex: the ifindex for which to open "/sys/class/net/%s"
- * @ifname_guess: (allow-none): optional argument, if present used as initial
- *   guess as the current name for @ifindex. If guessed right,
- *   it saves an additional if_indextoname() call.
- * @out_ifname: (allow-none): if present, must be at least IFNAMSIZ
- *   characters. On success, this will contain the actual ifname
- *   found while opening the directory.
- *
- * Returns: a negative value on failure, on success returns the open fd
- *   to the "/sys/class/net/%s" directory for @ifindex.
- */
-int
-nmp_utils_sysctl_open_netdir(int ifindex, const char *ifname_guess, char *out_ifname)
-{
-#define SYS_CLASS_NET "/sys/class/net/"
-    const char *ifname = ifname_guess;
-    char        ifname_buf_last_try[IFNAMSIZ];
-    char        ifname_buf[IFNAMSIZ];
-    guint       try_count                                   = 0;
-    char        sysdir[NM_STRLEN(SYS_CLASS_NET) + IFNAMSIZ] = SYS_CLASS_NET;
-    char        fd_buf[256];
-    ssize_t     nn;
-
-    g_return_val_if_fail(ifindex >= 0, -1);
-
-    ifname_buf_last_try[0] = '\0';
-
-    for (try_count = 0; try_count < 10; try_count++, ifname = NULL) {
-        nm_auto_close int fd_dir     = -1;
-        nm_auto_close int fd_ifindex = -1;
-
-        if (!ifname) {
-            ifname = nmp_utils_if_indextoname(ifindex, ifname_buf);
-            if (!ifname)
-                return -1;
-        }
-
-        nm_assert(nm_utils_ifname_valid_kernel(ifname, NULL));
-
-        if (g_strlcpy(&sysdir[NM_STRLEN(SYS_CLASS_NET)], ifname, IFNAMSIZ) >= IFNAMSIZ)
-            g_return_val_if_reached(-1);
-
-        /* we only retry, if the name changed since previous attempt.
-         * Hence, it is extremely unlikely that this loop runes until the
-         * end of the @try_count. */
-        if (nm_streq(ifname, ifname_buf_last_try))
-            return -1;
-        strcpy(ifname_buf_last_try, ifname);
-
-        fd_dir = open(sysdir, O_DIRECTORY | O_CLOEXEC);
-        if (fd_dir < 0)
-            continue;
-
-        fd_ifindex = openat(fd_dir, "ifindex", O_CLOEXEC);
-        if (fd_ifindex < 0)
-            continue;
-
-        nn = nm_utils_fd_read_loop(fd_ifindex, fd_buf, sizeof(fd_buf) - 2, FALSE);
-        if (nn <= 0)
-            continue;
-        fd_buf[nn] = '\0';
-
-        if (ifindex != (int) _nm_utils_ascii_str_to_int64(fd_buf, 10, 1, G_MAXINT, -1))
-            continue;
-
-        if (out_ifname)
-            strcpy(out_ifname, ifname);
-
-        return nm_steal_fd(&fd_dir);
-    }
-
-    return -1;
-}
diff --git a/shared/nm-platform/nm-platform-utils.h b/shared/nm-platform/nm-platform-utils.h
deleted file mode 100644
index d74723eb..00000000
--- a/shared/nm-platform/nm-platform-utils.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#ifndef __NM_PLATFORM_UTILS_H__
-#define __NM_PLATFORM_UTILS_H__
-
-#include "nm-base/nm-base.h"
-#include "nm-platform/nmp-base.h"
-
-/*****************************************************************************/
-
-const char *nmp_utils_ethtool_get_driver(int ifindex);
-gboolean    nmp_utils_ethtool_supports_carrier_detect(int ifindex);
-gboolean    nmp_utils_ethtool_supports_vlans(int ifindex);
-int         nmp_utils_ethtool_get_peer_ifindex(int ifindex);
-gboolean    nmp_utils_ethtool_get_wake_on_lan(int ifindex);
-gboolean    nmp_utils_ethtool_set_wake_on_lan(int                      ifindex,
-                                              _NMSettingWiredWakeOnLan wol,
-                                              const char *             wol_password);
-
-const char *nm_platform_link_duplex_type_to_string(NMPlatformLinkDuplexType duplex);
-
-gboolean nmp_utils_ethtool_get_link_settings(int                       ifindex,
-                                             gboolean *                out_autoneg,
-                                             guint32 *                 out_speed,
-                                             NMPlatformLinkDuplexType *out_duplex);
-gboolean nmp_utils_ethtool_set_link_settings(int                      ifindex,
-                                             gboolean                 autoneg,
-                                             guint32                  speed,
-                                             NMPlatformLinkDuplexType duplex);
-
-gboolean nmp_utils_ethtool_get_permanent_address(int ifindex, guint8 *buf, size_t *length);
-
-gboolean nmp_utils_ethtool_get_driver_info(int ifindex, NMPUtilsEthtoolDriverInfo *data);
-
-NMEthtoolFeatureStates *nmp_utils_ethtool_get_features(int ifindex);
-
-gboolean nmp_utils_ethtool_set_features(
-    int                           ifindex,
-    const NMEthtoolFeatureStates *features,
-    const NMOptionBool *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
-    gboolean            do_set /* or reset */);
-
-gboolean nmp_utils_ethtool_get_coalesce(int ifindex, NMEthtoolCoalesceState *coalesce);
-
-gboolean nmp_utils_ethtool_set_coalesce(int ifindex, const NMEthtoolCoalesceState *coalesce);
-
-gboolean nmp_utils_ethtool_get_ring(int ifindex, NMEthtoolRingState *ring);
-
-gboolean nmp_utils_ethtool_set_ring(int ifindex, const NMEthtoolRingState *ring);
-
-/*****************************************************************************/
-
-gboolean nmp_utils_mii_supports_carrier_detect(int ifindex);
-
-struct udev_device;
-
-const char *nmp_utils_udev_get_driver(struct udev_device *udevice);
-
-NMIPConfigSource nmp_utils_ip_config_source_from_rtprot(guint8 rtprot) _nm_const;
-guint8           nmp_utils_ip_config_source_coerce_to_rtprot(NMIPConfigSource source) _nm_const;
-NMIPConfigSource nmp_utils_ip_config_source_coerce_from_rtprot(NMIPConfigSource source) _nm_const;
-NMIPConfigSource nmp_utils_ip_config_source_round_trip_rtprot(NMIPConfigSource source) _nm_const;
-const char *nmp_utils_ip_config_source_to_string(NMIPConfigSource source, char *buf, gsize len);
-
-const char *nmp_utils_if_indextoname(int ifindex, char *out_ifname /*IFNAMSIZ*/);
-int         nmp_utils_if_nametoindex(const char *ifname);
-
-int nmp_utils_sysctl_open_netdir(int ifindex, const char *ifname_guess, char *out_ifname);
-
-#endif /* __NM_PLATFORM_UTILS_H__ */
diff --git a/shared/nm-platform/nmp-base.h b/shared/nm-platform/nmp-base.h
deleted file mode 100644
index 210c26d6..00000000
--- a/shared/nm-platform/nmp-base.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#ifndef __NMP_FWD_H__
-#define __NMP_FWD_H__
-
-#include "nm-base/nm-base.h"
-
-/*****************************************************************************/
-
-typedef enum {
-    NM_PLATFORM_LINK_DUPLEX_UNKNOWN,
-    NM_PLATFORM_LINK_DUPLEX_HALF,
-    NM_PLATFORM_LINK_DUPLEX_FULL,
-} NMPlatformLinkDuplexType;
-
-/*****************************************************************************/
-
-typedef struct {
-    /* We don't want to include <linux/ethtool.h> in header files,
-     * thus create a ABI compatible version of struct ethtool_drvinfo.*/
-    guint32 _private_cmd;
-    char    driver[32];
-    char    version[32];
-    char    fw_version[32];
-    char    _private_bus_info[32];
-    char    _private_erom_version[32];
-    char    _private_reserved2[12];
-    guint32 _private_n_priv_flags;
-    guint32 _private_n_stats;
-    guint32 _private_testinfo_len;
-    guint32 _private_eedump_len;
-    guint32 _private_regdump_len;
-} NMPUtilsEthtoolDriverInfo;
-
-typedef struct {
-    NMEthtoolID ethtool_id;
-
-    guint8 n_kernel_names;
-
-    /* one NMEthtoolID refers to one or more kernel_names. The reason for supporting this complexity
-     * (where one NMSettingEthtool option refers to multiple kernel features)  is to follow what
-     * ethtool does, where "tx" is an alias for multiple features. */
-    const char *const *kernel_names;
-} NMEthtoolFeatureInfo;
-
-typedef struct {
-    const NMEthtoolFeatureInfo *info;
-
-    guint idx_ss_features;
-
-    /* one NMEthtoolFeatureInfo references one or more kernel_names. This is the index
-     * of the matching info->kernel_names */
-    guint8 idx_kernel_name;
-
-    bool available : 1;
-    bool requested : 1;
-    bool active : 1;
-    bool never_changed : 1;
-} NMEthtoolFeatureState;
-
-typedef struct {
-    guint n_states;
-
-    guint n_ss_features;
-
-    /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */
-    const NMEthtoolFeatureState *const *states_indexed[_NM_ETHTOOL_ID_FEATURE_NUM];
-
-    /* the same content, here as a list of n_states entries. */
-    const NMEthtoolFeatureState states_list[];
-} NMEthtoolFeatureStates;
-
-/*****************************************************************************/
-
-typedef struct {
-    guint32
-        s[_NM_ETHTOOL_ID_COALESCE_NUM /* indexed by (NMEthtoolID - _NM_ETHTOOL_ID_COALESCE_FIRST) */
-    ];
-} NMEthtoolCoalesceState;
-
-/*****************************************************************************/
-
-typedef struct {
-    guint32 rx_pending;
-    guint32 rx_mini_pending;
-    guint32 rx_jumbo_pending;
-    guint32 tx_pending;
-} NMEthtoolRingState;
-
-/*****************************************************************************/
-
-typedef struct _NMPNetns NMPNetns;
-
-#endif /* __NMP_FWD_H__ */
diff --git a/shared/nm-platform/nmp-netns.c b/shared/nm-platform/nmp-netns.c
deleted file mode 100644
index 4dd9e848..00000000
--- a/shared/nm-platform/nmp-netns.c
+++ /dev/null
@@ -1,759 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2016 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nmp-netns.h"
-
-#include <fcntl.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "nm-log-core/nm-logging.h"
-
-/*****************************************************************************/
-
-/* NOTE: NMPNetns and all code used here must be thread-safe! */
-
-/* we may not call logging functions from the main-thread alone. Hence, we
- * require locking from nm-logging. Indicate that by setting NM_THREAD_SAFE_ON_MAIN_THREAD
- * to zero. */
-#undef NM_THREAD_SAFE_ON_MAIN_THREAD
-#define NM_THREAD_SAFE_ON_MAIN_THREAD 0
-
-/*****************************************************************************/
-
-#define PROC_SELF_NS_MNT "/proc/self/ns/mnt"
-#define PROC_SELF_NS_NET "/proc/self/ns/net"
-
-#define _CLONE_NS_ALL   ((int) (CLONE_NEWNS | CLONE_NEWNET))
-#define _CLONE_NS_ALL_V CLONE_NEWNS, CLONE_NEWNET
-
-static NM_UTILS_FLAGS2STR_DEFINE(_clone_ns_to_str,
-                                 int,
-                                 NM_UTILS_FLAGS2STR(CLONE_NEWNS, "mnt"),
-                                 NM_UTILS_FLAGS2STR(CLONE_NEWNET, "net"), );
-
-static const char *
-__ns_types_to_str(int ns_types, int ns_types_already_set, char *buf, gsize len)
-{
-    const char *b = buf;
-    char        bb[200];
-
-    nm_utils_strbuf_append_c(&buf, &len, '[');
-    if (ns_types & ~ns_types_already_set) {
-        nm_utils_strbuf_append_str(
-            &buf,
-            &len,
-            _clone_ns_to_str(ns_types & ~ns_types_already_set, bb, sizeof(bb)));
-    }
-    if (ns_types & ns_types_already_set) {
-        if (ns_types & ~ns_types_already_set)
-            nm_utils_strbuf_append_c(&buf, &len, '/');
-        nm_utils_strbuf_append_str(
-            &buf,
-            &len,
-            _clone_ns_to_str(ns_types & ns_types_already_set, bb, sizeof(bb)));
-    }
-    nm_utils_strbuf_append_c(&buf, &len, ']');
-    return b;
-}
-#define _ns_types_to_str(ns_types, ns_types_already_set, buf) \
-    __ns_types_to_str(ns_types, ns_types_already_set, buf, sizeof(buf))
-
-/*****************************************************************************/
-
-#define _NMLOG_DOMAIN      LOGD_PLATFORM
-#define _NMLOG_PREFIX_NAME "netns"
-#define _NMLOG(level, netns, ...)                                     \
-    G_STMT_START                                                      \
-    {                                                                 \
-        NMLogLevel _level = (level);                                  \
-                                                                      \
-        if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) {              \
-            NMPNetns *_netns = (netns);                               \
-            char      _sbuf[20];                                      \
-                                                                      \
-            _nm_log(_level,                                           \
-                    _NMLOG_DOMAIN,                                    \
-                    0,                                                \
-                    NULL,                                             \
-                    NULL,                                             \
-                    "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__),      \
-                    _NMLOG_PREFIX_NAME,                               \
-                    (_netns ? nm_sprintf_buf(_sbuf, "[%p]", _netns)   \
-                            : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
-        }                                                             \
-    }                                                                 \
-    G_STMT_END
-
-/*****************************************************************************/
-
-NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_FD_NET, PROP_FD_MNT, );
-
-typedef struct {
-    int fd_net;
-    int fd_mnt;
-} NMPNetnsPrivate;
-
-struct _NMPNetns {
-    GObject         parent;
-    NMPNetnsPrivate _priv;
-};
-
-struct _NMPNetnsClass {
-    GObjectClass parent;
-};
-
-G_DEFINE_TYPE(NMPNetns, nmp_netns, G_TYPE_OBJECT);
-
-#define NMP_NETNS_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMPNetns, NMP_IS_NETNS)
-
-/*****************************************************************************/
-
-typedef struct {
-    NMPNetns *netns;
-    int       count;
-    int       ns_types;
-} NetnsInfo;
-
-static void      _stack_push(GArray *netns_stack, NMPNetns *netns, int ns_types);
-static NMPNetns *_netns_new(GError **error);
-
-/*****************************************************************************/
-
-static NMPNetns *
-_netns_get(NetnsInfo *info)
-{
-    nm_assert(!info || NMP_IS_NETNS(info->netns));
-    return info ? info->netns : NULL;
-}
-
-/*****************************************************************************/
-
-static _nm_thread_local GArray *_netns_stack = NULL;
-
-static void
-_netns_stack_clear_cb(gpointer data)
-{
-    NetnsInfo *info = data;
-
-    nm_assert(NMP_IS_NETNS(info->netns));
-    g_object_unref(info->netns);
-}
-
-static GArray *
-_netns_stack_get_impl(void)
-{
-    gs_unref_object NMPNetns *netns = NULL;
-    gs_free_error GError *error     = NULL;
-    GArray *              s;
-
-    s = g_array_new(FALSE, FALSE, sizeof(NetnsInfo));
-    g_array_set_clear_func(s, _netns_stack_clear_cb);
-    _netns_stack = s;
-
-    nm_utils_thread_local_register_destroy(s, (GDestroyNotify) g_array_unref);
-
-    /* at the bottom of the stack we must try to create a netns instance
-     * that we never pop. It's the base to which we need to return. */
-    netns = _netns_new(&error);
-
-    if (!netns) {
-        _LOGD(NULL, "failed to create initial netns: %s", error->message);
-        return s;
-    }
-
-    /* we leak this instance inside the stack. */
-    _stack_push(s, netns, _CLONE_NS_ALL);
-
-    return s;
-}
-
-#define _netns_stack_get()                \
-    ({                                    \
-        GArray *_s = _netns_stack;        \
-                                          \
-        if (G_UNLIKELY(!_s))              \
-            _s = _netns_stack_get_impl(); \
-        _s;                               \
-    })
-
-/*****************************************************************************/
-
-static NMPNetns *
-_stack_current_netns(GArray *netns_stack, int ns_types)
-{
-    guint j;
-
-    nm_assert(netns_stack && netns_stack->len > 0);
-
-    /* we search the stack top-down to find the netns that has
-     * all @ns_types set. */
-    for (j = netns_stack->len; ns_types && j >= 1;) {
-        NetnsInfo *info;
-
-        info = &g_array_index(netns_stack, NetnsInfo, --j);
-
-        if (NM_FLAGS_ALL(info->ns_types, ns_types))
-            return info->netns;
-    }
-
-    g_return_val_if_reached(NULL);
-}
-
-static int
-_stack_current_ns_types(GArray *netns_stack, NMPNetns *netns, int ns_types)
-{
-    const int ns_types_check[] = {_CLONE_NS_ALL_V};
-    guint     i, j;
-    int       res = 0;
-
-    nm_assert(netns);
-    nm_assert(netns_stack && netns_stack->len > 0);
-
-    /* we search the stack top-down to check which of @ns_types
-     * are already set to @netns. */
-    for (j = netns_stack->len; ns_types && j >= 1;) {
-        NetnsInfo *info;
-
-        info = &g_array_index(netns_stack, NetnsInfo, --j);
-        if (info->netns != netns) {
-            ns_types = NM_FLAGS_UNSET(ns_types, info->ns_types);
-            continue;
-        }
-
-        for (i = 0; i < G_N_ELEMENTS(ns_types_check); i++) {
-            if (NM_FLAGS_ANY(ns_types, ns_types_check[i])
-                && NM_FLAGS_ANY(info->ns_types, ns_types_check[i])) {
-                res      = NM_FLAGS_SET(res, ns_types_check[i]);
-                ns_types = NM_FLAGS_UNSET(ns_types, ns_types_check[i]);
-            }
-        }
-    }
-
-    return res;
-}
-
-static NetnsInfo *
-_stack_peek(GArray *netns_stack)
-{
-    if (netns_stack->len > 0)
-        return &g_array_index(netns_stack, NetnsInfo, (netns_stack->len - 1));
-    return NULL;
-}
-
-static NetnsInfo *
-_stack_bottom(GArray *netns_stack)
-{
-    if (netns_stack->len > 0)
-        return &g_array_index(netns_stack, NetnsInfo, 0);
-    return NULL;
-}
-
-static void
-_stack_push(GArray *netns_stack, NMPNetns *netns, int ns_types)
-{
-    NetnsInfo *info;
-
-    nm_assert(netns_stack);
-    nm_assert(NMP_IS_NETNS(netns));
-    nm_assert(NM_FLAGS_ANY(ns_types, _CLONE_NS_ALL));
-    nm_assert(!NM_FLAGS_ANY(ns_types, ~_CLONE_NS_ALL));
-
-    g_array_set_size(netns_stack, netns_stack->len + 1);
-
-    info  = &g_array_index(netns_stack, NetnsInfo, (netns_stack->len - 1));
-    *info = (NetnsInfo){
-        .netns    = g_object_ref(netns),
-        .ns_types = ns_types,
-        .count    = 1,
-    };
-}
-
-static void
-_stack_pop(GArray *netns_stack)
-{
-    NetnsInfo *info;
-
-    nm_assert(netns_stack);
-    nm_assert(netns_stack->len > 1);
-
-    info = &g_array_index(netns_stack, NetnsInfo, (netns_stack->len - 1));
-
-    nm_assert(NMP_IS_NETNS(info->netns));
-    nm_assert(info->count == 1);
-
-    g_array_set_size(netns_stack, netns_stack->len - 1);
-}
-
-static guint
-_stack_size(GArray *netns_stack)
-{
-    nm_assert(netns_stack);
-
-    return netns_stack->len;
-}
-
-/*****************************************************************************/
-
-static NMPNetns *
-_netns_new(GError **error)
-{
-    NMPNetns *self;
-    int       fd_net, fd_mnt;
-    int       errsv;
-
-    fd_net = open(PROC_SELF_NS_NET, O_RDONLY | O_CLOEXEC);
-    if (fd_net == -1) {
-        errsv = errno;
-        g_set_error(error,
-                    NM_UTILS_ERROR,
-                    NM_UTILS_ERROR_UNKNOWN,
-                    "Failed opening netns: %s",
-                    nm_strerror_native(errsv));
-        errno = errsv;
-        return NULL;
-    }
-
-    fd_mnt = open(PROC_SELF_NS_MNT, O_RDONLY | O_CLOEXEC);
-    if (fd_mnt == -1) {
-        errsv = errno;
-        g_set_error(error,
-                    NM_UTILS_ERROR,
-                    NM_UTILS_ERROR_UNKNOWN,
-                    "Failed opening mntns: %s",
-                    nm_strerror_native(errsv));
-        nm_close(fd_net);
-        errno = errsv;
-        return NULL;
-    }
-
-    self = g_object_new(NMP_TYPE_NETNS, NMP_NETNS_FD_NET, fd_net, NMP_NETNS_FD_MNT, fd_mnt, NULL);
-
-    _LOGD(self, "new netns (net:%d, mnt:%d)", fd_net, fd_mnt);
-
-    return self;
-}
-
-static int
-_setns(NMPNetns *self, int type)
-{
-    char             buf[100];
-    int              fd;
-    NMPNetnsPrivate *priv = NMP_NETNS_GET_PRIVATE(self);
-
-    nm_assert(NM_IN_SET(type, _CLONE_NS_ALL_V));
-
-    fd = (type == CLONE_NEWNET) ? priv->fd_net : priv->fd_mnt;
-
-    _LOGt(self, "set netns(%s, %d)", _ns_types_to_str(type, 0, buf), fd);
-
-    return setns(fd, type);
-}
-
-static gboolean
-_netns_switch_push(GArray *netns_stack, NMPNetns *self, int ns_types)
-{
-    int errsv;
-
-    if (NM_FLAGS_HAS(ns_types, CLONE_NEWNET)
-        && !_stack_current_ns_types(netns_stack, self, CLONE_NEWNET)
-        && _setns(self, CLONE_NEWNET) != 0) {
-        errsv = errno;
-        _LOGE(self, "failed to switch netns: %s", nm_strerror_native(errsv));
-        return FALSE;
-    }
-    if (NM_FLAGS_HAS(ns_types, CLONE_NEWNS)
-        && !_stack_current_ns_types(netns_stack, self, CLONE_NEWNS)
-        && _setns(self, CLONE_NEWNS) != 0) {
-        errsv = errno;
-        _LOGE(self, "failed to switch mntns: %s", nm_strerror_native(errsv));
-
-        /* try to fix the mess by returning to the previous netns. */
-        if (NM_FLAGS_HAS(ns_types, CLONE_NEWNET)
-            && !_stack_current_ns_types(netns_stack, self, CLONE_NEWNET)) {
-            self = _stack_current_netns(netns_stack, CLONE_NEWNET);
-            if (self && _setns(self, CLONE_NEWNET) != 0) {
-                errsv = errno;
-                _LOGE(self, "failed to restore netns: %s", nm_strerror_native(errsv));
-            }
-        }
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-static gboolean
-_netns_switch_pop(GArray *netns_stack, NMPNetns *self, int ns_types)
-{
-    int       errsv;
-    NMPNetns *current;
-    int       success = TRUE;
-
-    if (NM_FLAGS_HAS(ns_types, CLONE_NEWNET)
-        && (!self || !_stack_current_ns_types(netns_stack, self, CLONE_NEWNET))) {
-        current = _stack_current_netns(netns_stack, CLONE_NEWNET);
-        if (!current) {
-            g_warn_if_reached();
-            success = FALSE;
-        } else if (_setns(current, CLONE_NEWNET) != 0) {
-            errsv = errno;
-            _LOGE(self, "failed to switch netns: %s", nm_strerror_native(errsv));
-            success = FALSE;
-        }
-    }
-    if (NM_FLAGS_HAS(ns_types, CLONE_NEWNS)
-        && (!self || !_stack_current_ns_types(netns_stack, self, CLONE_NEWNS))) {
-        current = _stack_current_netns(netns_stack, CLONE_NEWNS);
-        if (!current) {
-            g_warn_if_reached();
-            success = FALSE;
-        } else if (_setns(current, CLONE_NEWNS) != 0) {
-            errsv = errno;
-            _LOGE(self, "failed to switch mntns: %s", nm_strerror_native(errsv));
-            success = FALSE;
-        }
-    }
-
-    return success;
-}
-
-/*****************************************************************************/
-
-int
-nmp_netns_get_fd_net(NMPNetns *self)
-{
-    g_return_val_if_fail(NMP_IS_NETNS(self), 0);
-
-    return NMP_NETNS_GET_PRIVATE(self)->fd_net;
-}
-
-int
-nmp_netns_get_fd_mnt(NMPNetns *self)
-{
-    g_return_val_if_fail(NMP_IS_NETNS(self), 0);
-
-    return NMP_NETNS_GET_PRIVATE(self)->fd_mnt;
-}
-
-/*****************************************************************************/
-
-static gboolean
-_nmp_netns_push_type(NMPNetns *self, int ns_types)
-{
-    GArray *   netns_stack = _netns_stack_get();
-    NetnsInfo *info;
-    char       sbuf[100];
-
-    info = _stack_peek(netns_stack);
-    g_return_val_if_fail(info, FALSE);
-
-    if (info->netns == self && info->ns_types == ns_types) {
-        info->count++;
-        _LOGt(self,
-              "push#%u* %s (increase count to %d)",
-              _stack_size(netns_stack) - 1,
-              _ns_types_to_str(ns_types, ns_types, sbuf),
-              info->count);
-        return TRUE;
-    }
-
-    _LOGD(self,
-          "push#%u %s",
-          _stack_size(netns_stack),
-          _ns_types_to_str(ns_types, _stack_current_ns_types(netns_stack, self, ns_types), sbuf));
-
-    if (!_netns_switch_push(netns_stack, self, ns_types))
-        return FALSE;
-
-    _stack_push(netns_stack, self, ns_types);
-    return TRUE;
-}
-
-gboolean
-nmp_netns_push(NMPNetns *self)
-{
-    g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
-
-    return _nmp_netns_push_type(self, _CLONE_NS_ALL);
-}
-
-gboolean
-nmp_netns_push_type(NMPNetns *self, int ns_types)
-{
-    g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
-    g_return_val_if_fail(!NM_FLAGS_ANY(ns_types, ~_CLONE_NS_ALL), FALSE);
-
-    return _nmp_netns_push_type(self, ns_types == 0 ? _CLONE_NS_ALL : ns_types);
-}
-
-NMPNetns *
-nmp_netns_new(void)
-{
-    GArray *      netns_stack = _netns_stack_get();
-    NMPNetns *    self;
-    int           errsv;
-    GError *      error      = NULL;
-    unsigned long mountflags = 0;
-
-    if (!_stack_peek(netns_stack)) {
-        /* there are no netns instances. We cannot create a new one
-         * (because after unshare we couldn't return to the original one). */
-        errno = ENOTSUP;
-        return NULL;
-    }
-
-    if (unshare(_CLONE_NS_ALL) != 0) {
-        errsv = errno;
-        _LOGE(NULL, "failed to create new net and mnt namespace: %s", nm_strerror_native(errsv));
-        return NULL;
-    }
-
-    if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL) != 0) {
-        errsv = errno;
-        _LOGE(NULL, "failed mount --make-rslave: %s", nm_strerror_native(errsv));
-        goto err_out;
-    }
-
-    if (umount2("/sys", MNT_DETACH) != 0) {
-        errsv = errno;
-        _LOGE(NULL, "failed umount /sys: %s", nm_strerror_native(errsv));
-        goto err_out;
-    }
-
-    if (access("/sys", W_OK) == -1)
-        mountflags = MS_RDONLY;
-
-    if (mount("sysfs", "/sys", "sysfs", mountflags, NULL) != 0) {
-        errsv = errno;
-        _LOGE(NULL, "failed mount /sys: %s", nm_strerror_native(errsv));
-        goto err_out;
-    }
-
-    self = _netns_new(&error);
-    if (!self) {
-        errsv = errno;
-        _LOGE(NULL, "failed to create netns after unshare: %s", error->message);
-        g_clear_error(&error);
-        goto err_out;
-    }
-
-    _stack_push(netns_stack, self, _CLONE_NS_ALL);
-
-    return self;
-err_out:
-    _netns_switch_pop(netns_stack, NULL, _CLONE_NS_ALL);
-    errno = errsv;
-    return NULL;
-}
-
-gboolean
-nmp_netns_pop(NMPNetns *self)
-{
-    GArray *   netns_stack = _netns_stack_get();
-    NetnsInfo *info;
-    int        ns_types;
-
-    g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
-
-    info = _stack_peek(netns_stack);
-
-    g_return_val_if_fail(info, FALSE);
-    g_return_val_if_fail(info->netns == self, FALSE);
-
-    if (info->count > 1) {
-        info->count--;
-        _LOGt(self, "pop#%u* (decrease count to %d)", _stack_size(netns_stack) - 1, info->count);
-        return TRUE;
-    }
-    g_return_val_if_fail(info->count == 1, FALSE);
-
-    /* cannot pop the original netns. */
-    g_return_val_if_fail(_stack_size(netns_stack) > 1, FALSE);
-
-    _LOGD(self, "pop#%u", _stack_size(netns_stack) - 1);
-
-    ns_types = info->ns_types;
-
-    _stack_pop(netns_stack);
-
-    return _netns_switch_pop(netns_stack, self, ns_types);
-}
-
-NMPNetns *
-nmp_netns_get_current(void)
-{
-    return _netns_get(_stack_peek(_netns_stack_get()));
-}
-
-NMPNetns *
-nmp_netns_get_initial(void)
-{
-    return _netns_get(_stack_bottom(_netns_stack_get()));
-}
-
-gboolean
-nmp_netns_is_initial(void)
-{
-    GArray *netns_stack = _netns_stack_get();
-
-    return (_netns_get(_stack_peek(netns_stack)) == _netns_get(_stack_bottom(netns_stack)));
-}
-
-/*****************************************************************************/
-
-gboolean
-nmp_netns_bind_to_path(NMPNetns *self, const char *filename, int *out_fd)
-{
-    gs_free char *    dirname = NULL;
-    int               errsv;
-    int               fd;
-    nm_auto_pop_netns NMPNetns *netns_pop = NULL;
-
-    g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
-    g_return_val_if_fail(filename && filename[0] == '/', FALSE);
-
-    if (!nmp_netns_push_type(self, CLONE_NEWNET))
-        return FALSE;
-    netns_pop = self;
-
-    dirname = g_path_get_dirname(filename);
-    if (mkdir(dirname, 0) != 0) {
-        errsv = errno;
-        if (errsv != EEXIST) {
-            _LOGE(self,
-                  "bind: failed to create directory %s: %s",
-                  dirname,
-                  nm_strerror_native(errsv));
-            return FALSE;
-        }
-    }
-
-    if ((fd = creat(filename, S_IRUSR | S_IRGRP | S_IROTH)) == -1) {
-        errsv = errno;
-        _LOGE(self, "bind: failed to create %s: %s", filename, nm_strerror_native(errsv));
-        return FALSE;
-    }
-    nm_close(fd);
-
-    if (mount(PROC_SELF_NS_NET, filename, "none", MS_BIND, NULL) != 0) {
-        errsv = errno;
-        _LOGE(self,
-              "bind: failed to mount %s to %s: %s",
-              PROC_SELF_NS_NET,
-              filename,
-              nm_strerror_native(errsv));
-        unlink(filename);
-        return FALSE;
-    }
-
-    if (out_fd) {
-        if ((fd = open(filename, O_RDONLY | O_CLOEXEC)) == -1) {
-            errsv = errno;
-            _LOGE(self, "bind: failed to open %s: %s", filename, nm_strerror_native(errsv));
-            umount2(filename, MNT_DETACH);
-            unlink(filename);
-            return FALSE;
-        }
-        *out_fd = fd;
-    }
-
-    return TRUE;
-}
-
-gboolean
-nmp_netns_bind_to_path_destroy(NMPNetns *self, const char *filename)
-{
-    int errsv;
-
-    g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
-    g_return_val_if_fail(filename && filename[0] == '/', FALSE);
-
-    if (umount2(filename, MNT_DETACH) != 0) {
-        errsv = errno;
-        _LOGE(self, "bind: failed to unmount2 %s: %s", filename, nm_strerror_native(errsv));
-        return FALSE;
-    }
-    if (unlink(filename) != 0) {
-        errsv = errno;
-        _LOGE(self, "bind: failed to unlink %s: %s", filename, nm_strerror_native(errsv));
-        return FALSE;
-    }
-    return TRUE;
-}
-
-/*****************************************************************************/
-
-static void
-set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
-    NMPNetns *       self = NMP_NETNS(object);
-    NMPNetnsPrivate *priv = NMP_NETNS_GET_PRIVATE(self);
-
-    switch (prop_id) {
-    case PROP_FD_NET:
-        /* construct-only */
-        priv->fd_net = g_value_get_int(value);
-        g_return_if_fail(priv->fd_net > 0);
-        break;
-    case PROP_FD_MNT:
-        /* construct-only */
-        priv->fd_mnt = g_value_get_int(value);
-        g_return_if_fail(priv->fd_mnt > 0);
-        break;
-    default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-        break;
-    }
-}
-
-static void
-nmp_netns_init(NMPNetns *self)
-{}
-
-static void
-dispose(GObject *object)
-{
-    NMPNetns *       self = NMP_NETNS(object);
-    NMPNetnsPrivate *priv = NMP_NETNS_GET_PRIVATE(self);
-
-    nm_close(priv->fd_net);
-    priv->fd_net = -1;
-
-    nm_close(priv->fd_mnt);
-    priv->fd_mnt = -1;
-
-    G_OBJECT_CLASS(nmp_netns_parent_class)->dispose(object);
-}
-
-static void
-nmp_netns_class_init(NMPNetnsClass *klass)
-{
-    GObjectClass *object_class = G_OBJECT_CLASS(klass);
-
-    object_class->set_property = set_property;
-    object_class->dispose      = dispose;
-
-    obj_properties[PROP_FD_NET] =
-        g_param_spec_int(NMP_NETNS_FD_NET,
-                         "",
-                         "",
-                         0,
-                         G_MAXINT,
-                         0,
-                         G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-    obj_properties[PROP_FD_MNT] =
-        g_param_spec_int(NMP_NETNS_FD_MNT,
-                         "",
-                         "",
-                         0,
-                         G_MAXINT,
-                         0,
-                         G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-    g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
-}
diff --git a/shared/nm-platform/nmp-netns.h b/shared/nm-platform/nmp-netns.h
deleted file mode 100644
index b18bd03e..00000000
--- a/shared/nm-platform/nmp-netns.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2016 Red Hat, Inc.
- */
-
-#ifndef __NMP_NETNS_UTILS_H__
-#define __NMP_NETNS_UTILS_H__
-
-#include "nmp-base.h"
-
-/*****************************************************************************/
-
-#define NMP_TYPE_NETNS            (nmp_netns_get_type())
-#define NMP_NETNS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), NMP_TYPE_NETNS, NMPNetns))
-#define NMP_NETNS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), NMP_TYPE_NETNS, NMPNetnsClass))
-#define NMP_IS_NETNS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMP_TYPE_NETNS))
-#define NMP_IS_NETNS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NMP_TYPE_NETNS))
-#define NMP_NETNS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), NMP_TYPE_NETNS, NMPNetnsClass))
-
-#define NMP_NETNS_FD_NET "fd-net"
-#define NMP_NETNS_FD_MNT "fd-mnt"
-
-typedef struct _NMPNetns      NMPNetns;
-typedef struct _NMPNetnsClass NMPNetnsClass;
-
-GType nmp_netns_get_type(void);
-
-NMPNetns *nmp_netns_new(void);
-
-gboolean nmp_netns_push(NMPNetns *self);
-gboolean nmp_netns_push_type(NMPNetns *self, int ns_types);
-gboolean nmp_netns_pop(NMPNetns *self);
-
-NMPNetns *nmp_netns_get_current(void);
-NMPNetns *nmp_netns_get_initial(void);
-gboolean  nmp_netns_is_initial(void);
-
-int nmp_netns_get_fd_net(NMPNetns *self);
-int nmp_netns_get_fd_mnt(NMPNetns *self);
-
-static inline void
-_nm_auto_pop_netns(NMPNetns **p)
-{
-    if (*p) {
-        int errsv = errno;
-
-        nmp_netns_pop(*p);
-        errno = errsv;
-    }
-}
-#define nm_auto_pop_netns nm_auto(_nm_auto_pop_netns)
-
-gboolean nmp_netns_bind_to_path(NMPNetns *self, const char *filename, int *out_fd);
-gboolean nmp_netns_bind_to_path_destroy(NMPNetns *self, const char *filename);
-
-#endif /* __NMP_NETNS_UTILS_H__ */
diff --git a/shared/nm-platform/tests/meson.build b/shared/nm-platform/tests/meson.build
deleted file mode 100644
index a8fcdbca..00000000
--- a/shared/nm-platform/tests/meson.build
+++ /dev/null
@@ -1,20 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-
-exe = executable(
-  'test-nm-platform',
-  'test-nm-platform.c',
-  c_args: [
-    '-DG_LOG_DOMAIN="test"',
-  ],
-  dependencies: [
-    libnm_log_core_dep,
-    libnm_platform_dep,
-  ],
-)
-
-test(
-  'shared/nm-glib-aux/test-nm-platform',
-  test_script,
-  args: test_args + [exe.full_path()],
-  timeout: default_test_timeout,
-)
diff --git a/shared/nm-platform/tests/test-nm-platform.c b/shared/nm-platform/tests/test-nm-platform.c
deleted file mode 100644
index a3e9ff13..00000000
--- a/shared/nm-platform/tests/test-nm-platform.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-glib-aux/nm-default-glib-i18n-prog.h"
-
-#include "nm-log-core/nm-logging.h"
-#include "nm-platform/nm-netlink.h"
-#include "nm-platform/nmp-netns.h"
-
-#include "nm-utils/nm-test-utils.h"
-
-/*****************************************************************************/
-
-void
-_nm_logging_clear_platform_logging_cache(void)
-{
-    /* this symbols is required by nm-log-core library. */
-}
-
-/*****************************************************************************/
-
-static void
-test_use_symbols(void)
-{
-    static void (*const SYMBOLS[])(void) = {
-        (void (*)(void)) nl_nlmsghdr_to_str,
-        (void (*)(void)) nlmsg_hdr,
-        (void (*)(void)) nlmsg_reserve,
-        (void (*)(void)) nla_reserve,
-        (void (*)(void)) nlmsg_alloc_size,
-        (void (*)(void)) nlmsg_alloc,
-        (void (*)(void)) nlmsg_alloc_convert,
-        (void (*)(void)) nlmsg_alloc_simple,
-        (void (*)(void)) nlmsg_free,
-        (void (*)(void)) nlmsg_append,
-        (void (*)(void)) nlmsg_parse,
-        (void (*)(void)) nlmsg_put,
-        (void (*)(void)) nla_strlcpy,
-        (void (*)(void)) nla_memcpy,
-        (void (*)(void)) nla_put,
-        (void (*)(void)) nla_find,
-        (void (*)(void)) nla_nest_cancel,
-        (void (*)(void)) nla_nest_start,
-        (void (*)(void)) nla_nest_end,
-        (void (*)(void)) nla_parse,
-        (void (*)(void)) nlmsg_get_proto,
-        (void (*)(void)) nlmsg_set_proto,
-        (void (*)(void)) nlmsg_set_src,
-        (void (*)(void)) nlmsg_get_creds,
-        (void (*)(void)) nlmsg_set_creds,
-        (void (*)(void)) genlmsg_put,
-        (void (*)(void)) genlmsg_data,
-        (void (*)(void)) genlmsg_user_hdr,
-        (void (*)(void)) genlmsg_hdr,
-        (void (*)(void)) genlmsg_user_data,
-        (void (*)(void)) genlmsg_attrdata,
-        (void (*)(void)) genlmsg_len,
-        (void (*)(void)) genlmsg_attrlen,
-        (void (*)(void)) genlmsg_valid_hdr,
-        (void (*)(void)) genlmsg_parse,
-        (void (*)(void)) genl_ctrl_resolve,
-        (void (*)(void)) nl_socket_alloc,
-        (void (*)(void)) nl_socket_free,
-        (void (*)(void)) nl_socket_get_fd,
-        (void (*)(void)) nl_socket_get_local_port,
-        (void (*)(void)) nl_socket_get_msg_buf_size,
-        (void (*)(void)) nl_socket_set_passcred,
-        (void (*)(void)) nl_socket_set_msg_buf_size,
-        (void (*)(void)) nlmsg_get_dst,
-        (void (*)(void)) nl_socket_set_nonblocking,
-        (void (*)(void)) nl_socket_set_buffer_size,
-        (void (*)(void)) nl_socket_add_memberships,
-        (void (*)(void)) nl_socket_set_ext_ack,
-        (void (*)(void)) nl_socket_disable_msg_peek,
-        (void (*)(void)) nl_connect,
-        (void (*)(void)) nl_wait_for_ack,
-        (void (*)(void)) nl_recvmsgs,
-        (void (*)(void)) nl_sendmsg,
-        (void (*)(void)) nl_send_iovec,
-        (void (*)(void)) nl_complete_msg,
-        (void (*)(void)) nl_send,
-        (void (*)(void)) nl_send_auto,
-        (void (*)(void)) nl_recv,
-
-        (void (*)(void)) nmp_netns_bind_to_path,
-        (void (*)(void)) nmp_netns_bind_to_path_destroy,
-        (void (*)(void)) nmp_netns_get_current,
-        (void (*)(void)) nmp_netns_get_fd_mnt,
-        (void (*)(void)) nmp_netns_get_fd_net,
-        (void (*)(void)) nmp_netns_get_initial,
-        (void (*)(void)) nmp_netns_is_initial,
-        (void (*)(void)) nmp_netns_new,
-        (void (*)(void)) nmp_netns_pop,
-        (void (*)(void)) nmp_netns_push,
-        (void (*)(void)) nmp_netns_push_type,
-
-        NULL,
-    };
-
-    /* The only (not very exciting) purpose of this test is to see that
-     * we can use various symbols and don't get a linker error. */
-    assert(G_N_ELEMENTS(SYMBOLS) == NM_PTRARRAY_LEN(SYMBOLS) + 1);
-}
-
-/*****************************************************************************/
-
-NMTST_DEFINE();
-
-int
-main(int argc, char **argv)
-{
-    nmtst_init(&argc, &argv, TRUE);
-
-    g_test_add_func("/nm-platform/test_use_symbols", test_use_symbols);
-
-    return g_test_run();
-}
diff --git a/shared/nm-std-aux/c-list-util.c b/shared/nm-std-aux/c-list-util.c
deleted file mode 100644
index d16bd6b7..00000000
--- a/shared/nm-std-aux/c-list-util.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#include "c-list-util.h"
-
-/*****************************************************************************/
-
-/**
- * c_list_relink:
- * @lst: the head list entry
- *
- * Takes an invalid list, that has undefined prev pointers.
- * Only the next pointers are valid, and the tail's next
- * pointer points to %NULL instead of the head.
- *
- * c_list_relink() fixes the list by updating all prev pointers
- * and close the circular linking by pointing the tails' next
- * pointer to @lst.
- *
- * The use of this function is to do a bulk update, that lets the
- * list degenerate by not updating the prev pointers. At the end,
- * the list can be fixed by c_list_relink().
- */
-void
-c_list_relink(CList *lst)
-{
-    CList *ls, *ls_prev;
-
-    ls_prev = lst;
-    ls      = lst->next;
-    do {
-        ls->prev = ls_prev;
-        ls_prev  = ls;
-        ls       = ls->next;
-    } while (ls);
-    ls_prev->next = lst;
-    lst->prev     = ls_prev;
-}
-
-/*****************************************************************************/
-
-static CList *
-_c_list_srt_split(CList *ls)
-{
-    CList *ls2;
-
-    ls2 = ls;
-    ls  = ls->next;
-    if (!ls)
-        return NULL;
-    do {
-        ls = ls->next;
-        if (!ls)
-            break;
-        ls  = ls->next;
-        ls2 = ls2->next;
-    } while (ls);
-    ls        = ls2->next;
-    ls2->next = NULL;
-    return ls;
-}
-
-static CList *
-_c_list_srt_merge(CList *ls1, CList *ls2, CListSortCmp cmp, const void *user_data)
-{
-    CList *ls;
-    CList  head;
-
-    ls = &head;
-    for (;;) {
-        /* while invoking the @cmp function, the list
-         * elements are not properly linked. Don't try to access
-         * their next/prev pointers. */
-        if (cmp(ls1, ls2, user_data) <= 0) {
-            ls->next = ls1;
-            ls       = ls1;
-            ls1      = ls1->next;
-            if (!ls1)
-                break;
-        } else {
-            ls->next = ls2;
-            ls       = ls2;
-            ls2      = ls2->next;
-            if (!ls2)
-                break;
-        }
-    }
-    ls->next = ls1 ?: ls2;
-
-    return head.next;
-}
-
-typedef struct {
-    CList *ls1;
-    CList *ls2;
-    char   ls1_sorted;
-} SortStack;
-
-static CList *
-_c_list_sort(CList *ls, CListSortCmp cmp, const void *user_data)
-{
-    /* reserve a huge stack-size. We need roughly log2(n) entries, hence this
-     * is much more we will ever need. We don't guard for stack-overflow either. */
-    SortStack  stack_arr[70];
-    SortStack *stack_head = stack_arr;
-
-    stack_arr[0].ls1 = ls;
-
-    /* A simple top-down, non-recursive, stable merge-sort.
-     *
-     * Maybe natural merge-sort would be better, to do better for
-     * partially sorted lists. Doing that would be much more complicated,
-     * so it's not done. */
-_split:
-    stack_head[0].ls2 = _c_list_srt_split(stack_head[0].ls1);
-    if (stack_head[0].ls2) {
-        stack_head[0].ls1_sorted = 0;
-        stack_head[1].ls1        = stack_head[0].ls1;
-        stack_head++;
-        goto _split;
-    }
-
-_backtrack:
-    if (stack_head == stack_arr)
-        return stack_arr[0].ls1;
-
-    stack_head--;
-    if (!stack_head[0].ls1_sorted) {
-        stack_head[0].ls1        = stack_head[1].ls1;
-        stack_head[0].ls1_sorted = 1;
-        stack_head[1].ls1        = stack_head[0].ls2;
-        stack_head++;
-        goto _split;
-    }
-
-    stack_head[0].ls1 = _c_list_srt_merge(stack_head[0].ls1, stack_head[1].ls1, cmp, user_data);
-    goto _backtrack;
-}
-
-/**
- * c_list_sort_headless:
- * @lst: the list.
- * @cmp: compare function for sorting. While comparing two
- *   CList elements, their next/prev pointers are in undefined
- *   state.
- * @user_data: user data for @cmp.
- *
- * Sorts the list @lst according to @cmp. Contrary to
- * c_list_sort(), @lst is not the list head but a
- * valid entry as well. This function returns the new
- * list head.
- */
-CList *
-c_list_sort_headless(CList *lst, CListSortCmp cmp, const void *user_data)
-{
-    if (!c_list_is_empty(lst)) {
-        lst->prev->next = NULL;
-        lst             = _c_list_sort(lst, cmp, user_data);
-        c_list_relink(lst);
-    }
-    return lst;
-}
-
-/**
- * c_list_sort:
- * @head: the list head.
- * @cmp: compare function for sorting. While comparing two
- *   CList elements, their next/prev pointers are in undefined
- *   state.
- * @user_data: user data for @cmp.
- *
- * Sorts the list @head according to @cmp.
- */
-void
-c_list_sort(CList *head, CListSortCmp cmp, const void *user_data)
-{
-    if (!c_list_is_empty(head) && head->next->next != head) {
-        head->prev->next = NULL;
-        head->next       = _c_list_sort(head->next, cmp, user_data);
-        c_list_relink(head);
-    }
-}
diff --git a/shared/nm-std-aux/c-list-util.h b/shared/nm-std-aux/c-list-util.h
deleted file mode 100644
index 9d86d663..00000000
--- a/shared/nm-std-aux/c-list-util.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#ifndef __C_LIST_UTIL_H__
-#define __C_LIST_UTIL_H__
-
-#include "c-list/src/c-list.h"
-
-/*****************************************************************************/
-
-void c_list_relink(CList *lst);
-
-typedef int (*CListSortCmp)(const CList *a, const CList *b, const void *user_data);
-
-CList *c_list_sort_headless(CList *lst, CListSortCmp cmp, const void *user_data);
-
-void c_list_sort(CList *head, CListSortCmp cmp, const void *user_data);
-
-/* c_list_length_is:
- * @list: the #CList list head
- * @check_len: the length to compare
- *
- * Returns: basically the same as (c_list_length (@list) == @check_len),
- *   but does not require to iterate the entire list first. There is only
- *   one real use: to find out whether there is exactly one element in the
- *   list, by passing @check_len as 1.
- */
-static inline int
-c_list_length_is(const CList *list, unsigned long check_len)
-{
-    unsigned long n = 0;
-    const CList * iter;
-
-    c_list_for_each (iter, list) {
-        ++n;
-        if (n > check_len)
-            return 0;
-    }
-
-    return n == check_len;
-}
-
-#define c_list_for_each_prev(_iter, _list) \
-    for (_iter = (_list)->prev; (_iter) != (_list); _iter = (_iter)->prev)
-
-#define c_list_for_each_prev_safe(_iter, _safe, _list)                     \
-    for (_iter = (_list)->prev, _safe = (_iter)->prev; (_iter) != (_list); \
-         _iter = (_safe), _safe = (_safe)->prev)
-
-#define c_list_for_each_entry_prev(_iter, _list, _m)                                           \
-    for (_iter = c_list_entry((_list)->prev, __typeof__(*_iter), _m); &(_iter)->_m != (_list); \
-         _iter = c_list_entry((_iter)->_m.prev, __typeof__(*_iter), _m))
-
-#endif /* __C_LIST_UTIL_H__ */
diff --git a/shared/nm-std-aux/nm-dbus-compat.h b/shared/nm-std-aux/nm-dbus-compat.h
deleted file mode 100644
index c1076200..00000000
--- a/shared/nm-std-aux/nm-dbus-compat.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef __NM_DBUS_COMPAT_H__
-#define __NM_DBUS_COMPAT_H__
-
-#define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
-
-#define DBUS_PATH_DBUS "/org/freedesktop/DBus"
-
-#define DBUS_INTERFACE_DBUS           "org.freedesktop.DBus"
-#define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable"
-#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager"
-#define DBUS_INTERFACE_PEER           "org.freedesktop.DBus.Peer"
-#define DBUS_INTERFACE_PROPERTIES     "org.freedesktop.DBus.Properties"
-
-#define DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1
-#define DBUS_NAME_FLAG_REPLACE_EXISTING  0x2
-#define DBUS_NAME_FLAG_DO_NOT_QUEUE      0x4
-
-#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1
-#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE      2
-#define DBUS_REQUEST_NAME_REPLY_EXISTS        3
-#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4
-
-#endif /* __NM_DBUS_COMPAT_H__ */
diff --git a/shared/nm-std-aux/nm-default-std.h b/shared/nm-std-aux/nm-default-std.h
deleted file mode 100644
index fe16d35f..00000000
--- a/shared/nm-std-aux/nm-default-std.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#ifndef __NM_DEFAULT_STD_H__
-#define __NM_DEFAULT_STD_H__
-
-#include "nm-networkmanager-compilation.h"
-
-#ifdef NETWORKMANAGER_COMPILATION
-    #error Dont define NETWORKMANAGER_COMPILATION
-#endif
-
-#ifndef G_LOG_DOMAIN
-    #error Define G_LOG_DOMAIN
-#endif
-
-/*****************************************************************************/
-
-#define NETWORKMANAGER_COMPILATION 0
-
-/*****************************************************************************/
-
-/* always include these headers for our internal source files. */
-
-#ifndef ___CONFIG_H__
-    #define ___CONFIG_H__
-    #include <config.h>
-#endif
-
-#include "config-extra.h"
-
-/* for internal compilation we don't want the deprecation macros
- * to be in effect. Define the widest range of versions to effectively
- * disable deprecation checks */
-#define NM_VERSION_MIN_REQUIRED NM_VERSION_0_9_8
-
-#ifndef NM_MORE_ASSERTS
-    #define NM_MORE_ASSERTS 0
-#endif
-
-#if NM_MORE_ASSERTS == 0
-    /* The cast macros like NM_TYPE() are implemented via G_TYPE_CHECK_INSTANCE_CAST()
-     * and _G_TYPE_CIC(). The latter, by default performs runtime checks of the type
-     * by calling g_type_check_instance_cast().
-     * This check has a certain overhead without being helpful.
-     *
-     * Example 1:
-     *     static void foo (NMType *obj)
-     *     {
-     *         access_obj_without_check (obj);
-     *     }
-     *     foo ((NMType *) obj);
-     *     // There is no runtime check and passing an invalid pointer
-     *     // leads to a crash.
-     *
-     * Example 2:
-     *     static void foo (NMType *obj)
-     *     {
-     *         access_obj_without_check (obj);
-     *     }
-     *     foo (NM_TYPE (obj));
-     *     // There is a runtime check which prints a g_warning(), but that doesn't
-     *     // avoid the crash as NM_TYPE() cannot do anything then passing on the
-     *     // invalid pointer.
-     *
-     * Example 3:
-     *     static void foo (NMType *obj)
-     *     {
-     *         g_return_if_fail (NM_IS_TYPE (obj));
-     *         access_obj_without_check (obj);
-     *     }
-     *     foo ((NMType *) obj);
-     *     // There is a runtime check which prints a g_critical() which also avoids
-     *     // the crash. That is actually helpful to catch bugs and avoid crashes.
-     *
-     * Example 4:
-     *     static void foo (NMType *obj)
-     *     {
-     *         g_return_if_fail (NM_IS_TYPE (obj));
-     *         access_obj_without_check (obj);
-     *     }
-     *     foo (NM_TYPE (obj));
-     *     // The runtime check is performed twice, with printing a g_warning() and
-     *     // a g_critical() and avoiding the crash.
-     *
-     * Example 3 is how it should be done. Type checks in NM_TYPE() are pointless.
-     * Disable them for our production builds.
-     */
-    #ifndef G_DISABLE_CAST_CHECKS
-        #define G_DISABLE_CAST_CHECKS
-    #endif
-#endif
-
-/*****************************************************************************/
-
-#include <stdlib.h>
-
-/*****************************************************************************/
-
-#endif /* __NM_DEFAULT_STD_H__ */
diff --git a/shared/nm-std-aux/nm-networkmanager-compilation.h b/shared/nm-std-aux/nm-networkmanager-compilation.h
deleted file mode 100644
index 025a158d..00000000
--- a/shared/nm-std-aux/nm-networkmanager-compilation.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#ifndef __NM_NETWORKMANAGER_COMPILATION_H__
-#define __NM_NETWORKMANAGER_COMPILATION_H__
-
-#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB                (1 << 0)
-#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB       (1 << 1)
-#define NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG      (1 << 2)
-#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM               (1 << 3)
-#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE       (1 << 4)
-#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE          (1 << 5)
-#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL (1 << 6)
-#define NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE  (1 << 7)
-#define NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON              (1 << 10)
-#define NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD             (1 << 11)
-
-#define NM_NETWORKMANAGER_COMPILATION_LIBNM_CORE             \
-    (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB             \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB      \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE         \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_PRIVATE \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL)
-
-#define NM_NETWORKMANAGER_COMPILATION_LIBNM                                                        \
-    (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB                                                   \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_PRIVATE                                            \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE                                               \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL)
-
-#define NM_NETWORKMANAGER_COMPILATION_CLIENT             \
-    (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB         \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE)
-
-#define NM_NETWORKMANAGER_COMPILATION_DAEMON                  \
-    (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB              \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG      \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE          \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL \
-     | NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON)
-
-#define NM_NETWORKMANAGER_COMPILATION_SYSTEMD_SHARED \
-    (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB | NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD)
-
-#define NM_NETWORKMANAGER_COMPILATION_SYSTEMD \
-    (0 | NM_NETWORKMANAGER_COMPILATION_DAEMON | NM_NETWORKMANAGER_COMPILATION_SYSTEMD_SHARED)
-
-#define NM_NETWORKMANAGER_COMPILATION_GLIB (0 | NM_NETWORKMANAGER_COMPILATION_WITH_GLIB)
-
-#endif /* __NM_NETWORKMANAGER_COMPILATION_H__ */
diff --git a/shared/nm-std-aux/nm-std-aux.h b/shared/nm-std-aux/nm-std-aux.h
deleted file mode 100644
index a619cebd..00000000
--- a/shared/nm-std-aux/nm-std-aux.h
+++ /dev/null
@@ -1,985 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef __NM_STD_AUX_H__
-#define __NM_STD_AUX_H__
-
-#include <assert.h>
-#include <string.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-
-/*****************************************************************************/
-
-#define _nm_packed        __attribute__((__packed__))
-#define _nm_unused        __attribute__((__unused__))
-#define _nm_used          __attribute__((__used__))
-#define _nm_pure          __attribute__((__pure__))
-#define _nm_const         __attribute__((__const__))
-#define _nm_printf(a, b)  __attribute__((__format__(__printf__, a, b)))
-#define _nm_align(s)      __attribute__((__aligned__(s)))
-#define _nm_section(s)    __attribute__((__section__(s)))
-#define _nm_alignof(type) __alignof(type)
-#define _nm_alignas(type) _nm_align(_nm_alignof(type))
-#define nm_auto(fcn)      __attribute__((__cleanup__(fcn)))
-
-/* This is required to make LTO working.
- *
- * See https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/76#note_112694
- *     https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48200#c28
- */
-#ifndef __clang__
-    #define _nm_externally_visible __attribute__((__externally_visible__))
-#else
-    #define _nm_externally_visible
-#endif
-
-#if __GNUC__ >= 7
-    #define _nm_fallthrough __attribute__((__fallthrough__))
-#else
-    #define _nm_fallthrough
-#endif
-
-/*****************************************************************************/
-
-#ifdef __CHECKER__
-    #define _nm_bitwise __attribute__((__bitwise__))
-    #define _nm_force   __attribute__((__force__))
-#else
-    #define _nm_bitwise
-    #define _nm_force
-#endif
-
-typedef uint16_t _nm_bitwise nm_le16_t;
-typedef uint16_t _nm_bitwise nm_be16_t;
-typedef uint32_t _nm_bitwise nm_le32_t;
-typedef uint32_t _nm_bitwise nm_be32_t;
-typedef uint64_t _nm_bitwise nm_le64_t;
-typedef uint64_t _nm_bitwise nm_be64_t;
-
-/*****************************************************************************/
-
-#ifdef thread_local
-    #define _nm_thread_local thread_local
-/*
- * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
- * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
- */
-#elif __STDC_VERSION__ >= 201112L     \
-    && !(defined(__STDC_NO_THREADS__) \
-         || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
-    #define _nm_thread_local _Thread_local
-#else
-    #define _nm_thread_local __thread
-#endif
-
-/*****************************************************************************/
-
-#define _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON struct _nm_dummy_struct_for_trailing_semicolon
-
-/*****************************************************************************/
-
-#define NM_PASTE_ARGS(identifier1, identifier2) identifier1##identifier2
-#define NM_PASTE(identifier1, identifier2)      NM_PASTE_ARGS(identifier1, identifier2)
-
-/* Taken from systemd's UNIQ_T and UNIQ macros. */
-
-#define NM_UNIQ_T(x, uniq) NM_PASTE(__unique_prefix_, NM_PASTE(x, uniq))
-#define NM_UNIQ            __COUNTER__
-
-/*****************************************************************************/
-
-#define _NM_BOOLEAN_EXPR_IMPL(v, expr) \
-    ({                                 \
-        int NM_UNIQ_T(V, v);           \
-                                       \
-        if (expr)                      \
-            NM_UNIQ_T(V, v) = 1;       \
-        else                           \
-            NM_UNIQ_T(V, v) = 0;       \
-        NM_UNIQ_T(V, v);               \
-    })
-#define NM_BOOLEAN_EXPR(expr) _NM_BOOLEAN_EXPR_IMPL(NM_UNIQ, expr)
-
-#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
-    #define NM_LIKELY(expr)   (__builtin_expect(NM_BOOLEAN_EXPR(expr), 1))
-    #define NM_UNLIKELY(expr) (__builtin_expect(NM_BOOLEAN_EXPR(expr), 0))
-#else
-    #define NM_LIKELY(expr)   NM_BOOLEAN_EXPR(expr)
-    #define NM_UNLIKELY(expr) NM_BOOLEAN_EXPR(expr)
-#endif
-
-/*****************************************************************************/
-
-/* glib/C provides the following kind of assertions:
- *   - assert() -- disable with NDEBUG
- *   - g_return_if_fail() -- disable with G_DISABLE_CHECKS
- *   - g_assert() -- disable with G_DISABLE_ASSERT
- * but they are all enabled by default and usually even production builds have
- * these kind of assertions enabled. It also means, that disabling assertions
- * is an untested configuration, and might have bugs.
- *
- * Add our own assertion macro nm_assert(), which is disabled by default and must
- * be explicitly enabled. They are useful for more expensive checks or checks that
- * depend less on runtime conditions (that is, are generally expected to be true). */
-
-#ifndef NM_MORE_ASSERTS
-    #define NM_MORE_ASSERTS 0
-#endif
-
-#ifndef _nm_assert_call
-    #define _nm_assert_call(cond)         assert(cond)
-    #define _nm_assert_call_not_reached() assert(0)
-#endif
-
-#if NM_MORE_ASSERTS
-    #define nm_assert(cond)        \
-        do {                       \
-            _nm_assert_call(cond); \
-        } while (0)
-    #define nm_assert_se(cond)                \
-        do {                                  \
-            if (NM_LIKELY(cond)) {            \
-                ;                             \
-            } else {                          \
-                _nm_assert_call(0 && (cond)); \
-            }                                 \
-        } while (0)
-    #define nm_assert_not_reached()        \
-        do {                               \
-            _nm_assert_call_not_reached(); \
-        } while (0)
-#else
-    #define nm_assert(cond)  \
-        do {                 \
-            if (0) {         \
-                if (cond) {} \
-            }                \
-        } while (0)
-    #define nm_assert_se(cond)     \
-        do {                       \
-            if (NM_LIKELY(cond)) { \
-                ;                  \
-            }                      \
-        } while (0)
-    #define nm_assert_not_reached() \
-        do {                        \
-            ;                       \
-        } while (0)
-#endif
-
-#define nm_assert_unreachable_val(val) \
-    ({                                 \
-        nm_assert_not_reached();       \
-        (val);                         \
-    })
-
-#define NM_STATIC_ASSERT(cond) static_assert(cond, "")
-#define NM_STATIC_ASSERT_EXPR(cond) \
-    ({                              \
-        NM_STATIC_ASSERT(cond);     \
-        1;                          \
-    })
-
-/*****************************************************************************/
-
-#define NM_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0]))
-
-/*****************************************************************************/
-
-static inline uint32_t
-nm_add_clamped_u32(uint32_t a, uint32_t b)
-{
-    uint32_t c;
-
-    /* returns a+b, or UINT32_MAX if the result would overflow. */
-
-    c = a + b;
-    if (c < a)
-        return UINT32_MAX;
-    return c;
-}
-
-static inline unsigned
-nm_mult_clamped_u(unsigned a, unsigned b)
-{
-    unsigned c;
-
-    /* returns a*b, or UINT_MAX if the result would overflow. */
-
-    if (b == 0)
-        return 0;
-
-    c = a * b;
-
-    if (c / b != a)
-        return (unsigned) -1;
-
-    return c;
-}
-
-/* glib's MIN()/MAX() macros don't have function-like behavior, in that they evaluate
- * the argument possibly twice.
- *
- * Taken from systemd's MIN()/MAX() macros. */
-
-#define NM_MIN(a, b) __NM_MIN(NM_UNIQ, a, NM_UNIQ, b)
-#define __NM_MIN(aq, a, bq, b)                                                         \
-    ({                                                                                 \
-        typeof(a) NM_UNIQ_T(A, aq) = (a);                                              \
-        typeof(b) NM_UNIQ_T(B, bq) = (b);                                              \
-        ((NM_UNIQ_T(A, aq) < NM_UNIQ_T(B, bq)) ? NM_UNIQ_T(A, aq) : NM_UNIQ_T(B, bq)); \
-    })
-
-#define NM_MAX(a, b) __NM_MAX(NM_UNIQ, a, NM_UNIQ, b)
-#define __NM_MAX(aq, a, bq, b)                                                         \
-    ({                                                                                 \
-        typeof(a) NM_UNIQ_T(A, aq) = (a);                                              \
-        typeof(b) NM_UNIQ_T(B, bq) = (b);                                              \
-        ((NM_UNIQ_T(A, aq) > NM_UNIQ_T(B, bq)) ? NM_UNIQ_T(A, aq) : NM_UNIQ_T(B, bq)); \
-    })
-
-#define NM_CLAMP(x, low, high) __NM_CLAMP(NM_UNIQ, x, NM_UNIQ, low, NM_UNIQ, high)
-#define __NM_CLAMP(xq, x, lowq, low, highq, high)                             \
-    ({                                                                        \
-        typeof(x) NM_UNIQ_T(X, xq)          = (x);                            \
-        typeof(low) NM_UNIQ_T(LOW, lowq)    = (low);                          \
-        typeof(high) NM_UNIQ_T(HIGH, highq) = (high);                         \
-                                                                              \
-        ((NM_UNIQ_T(X, xq) > NM_UNIQ_T(HIGH, highq)) ? NM_UNIQ_T(HIGH, highq) \
-         : (NM_UNIQ_T(X, xq) < NM_UNIQ_T(LOW, lowq)) ? NM_UNIQ_T(LOW, lowq)   \
-                                                     : NM_UNIQ_T(X, xq));     \
-    })
-
-#define NM_MAX_WITH_CMP(cmp, a, b)        \
-    ({                                    \
-        typeof(a) _a = (a);               \
-        typeof(b) _b = (b);               \
-                                          \
-        (((cmp(_a, _b)) >= 0) ? _a : _b); \
-    })
-
-/* evaluates to (void) if _A or _B are not constant or of different types */
-#define NM_CONST_MAX(_A, _B)                                                          \
-    (__builtin_choose_expr((__builtin_constant_p(_A) && __builtin_constant_p(_B)      \
-                            && __builtin_types_compatible_p(typeof(_A), typeof(_B))), \
-                           ((_A) > (_B)) ? (_A) : (_B),                               \
-                           ((void) 0)))
-
-/* Determine whether @x is a power of two (@x being an integer type).
- * Basically, this returns TRUE, if @x has exactly one bit set.
- * For negative values and zero, this always returns FALSE. */
-#define nm_utils_is_power_of_two(x)                       \
-    ({                                                    \
-        typeof(x) _x2          = (x);                     \
-        const typeof(_x2) _X_0 = ((typeof(_x2)) 0);       \
-        const typeof(_x2) _X_1 = ((typeof(_x2)) 1);       \
-                                                          \
-        ((_x2 > _X_0) && ((_x2 & (_x2 - _X_1)) == _X_0)); \
-    })
-
-#define nm_utils_is_power_of_two_or_zero(x)            \
-    ({                                                 \
-        typeof(x) _x1 = (x);                           \
-                                                       \
-        ((_x1 == 0) || nm_utils_is_power_of_two(_x1)); \
-    })
-
-/*****************************************************************************/
-
-#define NM_SWAP(p_a, p_b)                   \
-    do {                                    \
-        typeof(*(p_a)) *const _p_a = (p_a); \
-        typeof(*(p_a)) *const _p_b = (p_b); \
-        typeof(*(p_a)) _tmp;                \
-                                            \
-        _tmp  = *_p_a;                      \
-        *_p_a = *_p_b;                      \
-        *_p_b = _tmp;                       \
-    } while (0)
-
-/*****************************************************************************/
-
-/* macro to return strlen() of a compile time string. */
-#define NM_STRLEN(str) (sizeof("" str "") - 1u)
-
-/* returns the length of a NULL terminated array of pointers,
- * like g_strv_length() does. The difference is:
- *  - it operates on arrays of pointers (of any kind, requiring no cast).
- *  - it accepts NULL to return zero. */
-#define NM_PTRARRAY_LEN(array)                                         \
-    ({                                                                 \
-        typeof(*(array)) *const _array = (array);                      \
-        size_t                  _n     = 0;                            \
-                                                                       \
-        if (_array) {                                                  \
-            _nm_unused const void *_type_check_is_pointer = _array[0]; \
-                                                                       \
-            while (_array[_n])                                         \
-                _n++;                                                  \
-        }                                                              \
-        _n;                                                            \
-    })
-
-/*****************************************************************************/
-
-static inline int
-nm_strcmp0(const char *s1, const char *s2)
-{
-    int c;
-
-    /* like g_strcmp0(), but this is inlinable.
-     *
-     * Also, it is guaranteed to return either -1, 0, or 1. */
-    if (s1 == s2)
-        return 0;
-    if (!s1)
-        return -1;
-    if (!s2)
-        return 1;
-    c = strcmp(s1, s2);
-    if (c < 0)
-        return -1;
-    if (c > 0)
-        return 1;
-    return 0;
-}
-
-static inline int
-nm_streq(const char *s1, const char *s2)
-{
-    return strcmp(s1, s2) == 0;
-}
-
-static inline int
-nm_streq0(const char *s1, const char *s2)
-{
-    return (s1 == s2) || (s1 && s2 && strcmp(s1, s2) == 0);
-}
-
-#define NM_STR_HAS_PREFIX(str, prefix)                                                       \
-    ({                                                                                       \
-        const char *const _str_has_prefix = (str);                                           \
-                                                                                             \
-        nm_assert(strlen(prefix) == NM_STRLEN(prefix));                                      \
-                                                                                             \
-        _str_has_prefix && (strncmp(_str_has_prefix, "" prefix "", NM_STRLEN(prefix)) == 0); \
-    })
-
-#define NM_STR_HAS_SUFFIX(str, suffix)                                                         \
-    ({                                                                                         \
-        const char *const _str_has_suffix = (str);                                             \
-        size_t            _l;                                                                  \
-                                                                                               \
-        nm_assert(strlen(suffix) == NM_STRLEN(suffix));                                        \
-                                                                                               \
-        (_str_has_suffix && ((_l = strlen(_str_has_suffix)) >= NM_STRLEN(suffix))              \
-         && (memcmp(&_str_has_suffix[_l - NM_STRLEN(suffix)], "" suffix "", NM_STRLEN(suffix)) \
-             == 0));                                                                           \
-    })
-
-/* whether @str starts with the string literal @prefix and is followed by
- * some other text. It is like NM_STR_HAS_PREFIX() && !nm_streq() together. */
-#define NM_STR_HAS_PREFIX_WITH_MORE(str, prefix)                   \
-    ({                                                             \
-        const char *const _str_has_prefix_with_more = (str);       \
-                                                                   \
-        NM_STR_HAS_PREFIX(_str_has_prefix_with_more, "" prefix "") \
-        &&_str_has_prefix_with_more[NM_STRLEN(prefix)] != '\0';    \
-    })
-
-#define NM_STR_HAS_SUFFIX_WITH_MORE(str, suffix)                                               \
-    ({                                                                                         \
-        const char *const _str_has_suffix = (str);                                             \
-        size_t            _l;                                                                  \
-                                                                                               \
-        nm_assert(strlen(suffix) == NM_STRLEN(suffix));                                        \
-                                                                                               \
-        (_str_has_suffix && ((_l = strlen(_str_has_suffix)) > NM_STRLEN(suffix))               \
-         && (memcmp(&_str_has_suffix[_l - NM_STRLEN(suffix)], "" suffix "", NM_STRLEN(suffix)) \
-             == 0));                                                                           \
-    })
-
-/*****************************************************************************/
-
-#define _NM_IN_SET_EVAL_1(op, _x, y)       (_x == (y))
-#define _NM_IN_SET_EVAL_2(op, _x, y, ...)  (_x == (y)) op _NM_IN_SET_EVAL_1(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_3(op, _x, y, ...)  (_x == (y)) op _NM_IN_SET_EVAL_2(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_4(op, _x, y, ...)  (_x == (y)) op _NM_IN_SET_EVAL_3(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_5(op, _x, y, ...)  (_x == (y)) op _NM_IN_SET_EVAL_4(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_6(op, _x, y, ...)  (_x == (y)) op _NM_IN_SET_EVAL_5(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_7(op, _x, y, ...)  (_x == (y)) op _NM_IN_SET_EVAL_6(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_8(op, _x, y, ...)  (_x == (y)) op _NM_IN_SET_EVAL_7(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_9(op, _x, y, ...)  (_x == (y)) op _NM_IN_SET_EVAL_8(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_10(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_9(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_11(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_10(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_12(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_11(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_13(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_12(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_14(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_13(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_15(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_14(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_16(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_15(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_17(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_16(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_18(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_17(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_19(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_18(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_20(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_19(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_21(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_20(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_22(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_21(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_23(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_22(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_24(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_23(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_25(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_24(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_26(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_25(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_27(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_26(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_28(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_27(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_29(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_28(op, _x, __VA_ARGS__)
-#define _NM_IN_SET_EVAL_30(op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_29(op, _x, __VA_ARGS__)
-
-#define _NM_IN_SET_EVAL_N2(op, _x, n, ...) (_NM_IN_SET_EVAL_##n(op, _x, __VA_ARGS__))
-#define _NM_IN_SET_EVAL_N(op, type, x, n, ...)        \
-    ({                                                \
-        type _x = (x);                                \
-                                                      \
-        /* trigger a -Wenum-compare warning */        \
-        nm_assert(true || _x == (x));                 \
-                                                      \
-        !!_NM_IN_SET_EVAL_N2(op, _x, n, __VA_ARGS__); \
-    })
-
-#define _NM_IN_SET(op, type, x, ...) \
-    _NM_IN_SET_EVAL_N(op, type, x, NM_NARG(__VA_ARGS__), __VA_ARGS__)
-
-/* Beware that this does short-circuit evaluation (use "||" instead of "|")
- * which has a possibly unexpected non-function-like behavior.
- * Use NM_IN_SET_SE if you need all arguments to be evaluated. */
-#define NM_IN_SET(x, ...) _NM_IN_SET(||, typeof(x), x, __VA_ARGS__)
-
-/* "SE" stands for "side-effect". Contrary to NM_IN_SET(), this does not do
- * short-circuit evaluation, which can make a difference if the arguments have
- * side-effects. */
-#define NM_IN_SET_SE(x, ...) _NM_IN_SET(|, typeof(x), x, __VA_ARGS__)
-
-/* the *_TYPED forms allow to explicitly select the type of "x". This is useful
- * if "x" doesn't support typeof (bitfields) or you want to gracefully convert
- * a type using automatic type conversion rules (but not forcing the conversion
- * with a cast). */
-#define NM_IN_SET_TYPED(type, x, ...)    _NM_IN_SET(||, type, x, __VA_ARGS__)
-#define NM_IN_SET_SE_TYPED(type, x, ...) _NM_IN_SET(|, type, x, __VA_ARGS__)
-
-/*****************************************************************************/
-
-#define _NM_IN_SETOP_EVAL_1(op, op_eq, _x, y) (op_eq(_x, y))
-#define _NM_IN_SETOP_EVAL_2(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_1(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_3(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_2(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_4(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_3(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_5(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_4(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_6(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_5(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_7(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_6(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_8(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_7(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_9(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_8(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_10(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_9(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_11(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_10(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_12(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_11(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_13(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_12(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_14(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_13(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_15(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_14(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_16(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_15(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_17(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_16(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_18(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_17(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_19(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_18(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_20(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_19(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_21(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_20(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_22(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_21(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_23(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_22(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_24(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_23(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_25(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_24(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_26(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_25(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_27(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_26(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_28(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_27(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_29(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_28(op, op_eq, _x, __VA_ARGS__)
-#define _NM_IN_SETOP_EVAL_30(op, op_eq, _x, y, ...) \
-    (op_eq(_x, y)) op _NM_IN_SETOP_EVAL_29(op, op_eq, _x, __VA_ARGS__)
-
-/*****************************************************************************/
-
-#define _NM_IN_STRSET_EVAL_N2(op, op_ed, _x, n, ...) \
-    (_NM_IN_SETOP_EVAL_##n(op, op_ed, _x, __VA_ARGS__))
-#define _NM_IN_STRSET_EVAL_N(op, op_ed, x, n, ...)                                       \
-    ({                                                                                   \
-        const char *_x = (x);                                                            \
-        (((_x == NULL) && _NM_IN_SET_EVAL_N2(op, ((const char *) NULL), n, __VA_ARGS__)) \
-         || ((_x != NULL) && _NM_IN_STRSET_EVAL_N2(op, op_ed, _x, n, __VA_ARGS__)));     \
-    })
-
-/*****************************************************************************/
-
-static inline int
-_NM_IN_STRSET_op_streq(const char *x, const char *s)
-{
-    return s && strcmp(x, s) == 0;
-}
-
-/* Beware that this does short-circuit evaluation (use "||" instead of "|")
- * which has a possibly unexpected non-function-like behavior.
- * Use NM_IN_STRSET_SE if you need all arguments to be evaluated. */
-#define NM_IN_STRSET(x, ...) \
-    _NM_IN_STRSET_EVAL_N(||, _NM_IN_STRSET_op_streq, x, NM_NARG(__VA_ARGS__), __VA_ARGS__)
-
-/* "SE" stands for "side-effect". Contrary to NM_IN_STRSET(), this does not do
- * short-circuit evaluation, which can make a difference if the arguments have
- * side-effects. */
-#define NM_IN_STRSET_SE(x, ...) \
-    _NM_IN_STRSET_EVAL_N(|, _NM_IN_STRSET_op_streq, x, NM_NARG(__VA_ARGS__), __VA_ARGS__)
-
-/*****************************************************************************/
-
-#define NM_STRCHAR_ALL(str, ch_iter, predicate) \
-    ({                                          \
-        int         _val = true;                \
-        const char *_str = (str);               \
-                                                \
-        if (_str) {                             \
-            for (;;) {                          \
-                const char ch_iter = _str[0];   \
-                                                \
-                if (ch_iter != '\0') {          \
-                    if (predicate) {            \
-                        _str++;                 \
-                        continue;               \
-                    }                           \
-                    _val = false;               \
-                }                               \
-                break;                          \
-            }                                   \
-        }                                       \
-        _val;                                   \
-    })
-
-#define NM_STRCHAR_ANY(str, ch_iter, predicate) \
-    ({                                          \
-        int         _val = false;               \
-        const char *_str = (str);               \
-                                                \
-        if (_str) {                             \
-            for (;;) {                          \
-                const char ch_iter = _str[0];   \
-                                                \
-                if (ch_iter != '\0') {          \
-                    if (predicate) {            \
-                        ;                       \
-                    } else {                    \
-                        _str++;                 \
-                        continue;               \
-                    }                           \
-                    _val = true;                \
-                }                               \
-                break;                          \
-            }                                   \
-        }                                       \
-        _val;                                   \
-    })
-
-/*****************************************************************************/
-
-/**
- * nm_close:
- *
- * Like close() but throws an assertion if the input fd is
- * invalid.  Closing an invalid fd is a programming error, so
- * it's better to catch it early.
- */
-static inline int
-nm_close(int fd)
-{
-    int r;
-
-    r = close(fd);
-    nm_assert(r != -1 || fd < 0 || errno != EBADF);
-    return r;
-}
-
-/*****************************************************************************/
-
-/* Note: @value is only evaluated when *out_val is present.
- * Thus,
- *    NM_SET_OUT (out_str, g_strdup ("hallo"));
- * does the right thing.
- */
-#define NM_SET_OUT(out_val, value)                \
-    ({                                            \
-        typeof(*(out_val)) *_out_val = (out_val); \
-                                                  \
-        if (_out_val) {                           \
-            *_out_val = (value);                  \
-        }                                         \
-                                                  \
-        (!!_out_val);                             \
-    })
-
-/*****************************************************************************/
-
-#define NM_AUTO_DEFINE_FCN_VOID(CastType, name, func) \
-    static inline void name(void *v)                  \
-    {                                                 \
-        func(*((CastType *) v));                      \
-    }                                                 \
-    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
-
-#define NM_AUTO_DEFINE_FCN_VOID0(CastType, name, func) \
-    static inline void name(void *v)                   \
-    {                                                  \
-        if (*((CastType *) v))                         \
-            func(*((CastType *) v));                   \
-    }                                                  \
-    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
-
-#define NM_AUTO_DEFINE_FCN(Type, name, func) \
-    static inline void name(Type *v)         \
-    {                                        \
-        func(*v);                            \
-    }                                        \
-    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
-
-#define NM_AUTO_DEFINE_FCN0(Type, name, func) \
-    static inline void name(Type *v)          \
-    {                                         \
-        if (*v)                               \
-            func(*v);                         \
-    }                                         \
-    _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON
-
-/*****************************************************************************/
-
-/**
- * nm_auto_free:
- *
- * Call free() on a variable location when it goes out of scope.
- * This is for pointers that are allocated with malloc() instead of
- * g_malloc().
- *
- * In practice, since glib 2.45, g_malloc()/g_free() always wraps malloc()/free().
- * See bgo#751592. In that case, it would be safe to free pointers allocated with
- * malloc() with gs_free or g_free().
- *
- * However, let's never mix them. To free malloc'ed memory, always use
- * free() or nm_auto_free.
- */
-NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_free_impl, free);
-#define nm_auto_free nm_auto(_nm_auto_free_impl)
-
-static inline void
-_nm_auto_protect_errno(const int *p_saved_errno)
-{
-    errno = *p_saved_errno;
-}
-#define NM_AUTO_PROTECT_ERRNO(errsv_saved) \
-    nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno)
-
-/*****************************************************************************/
-
-static inline void
-_nm_auto_close(int *pfd)
-{
-    if (*pfd >= 0) {
-        int errsv = errno;
-
-        (void) nm_close(*pfd);
-        errno = errsv;
-    }
-}
-#define nm_auto_close nm_auto(_nm_auto_close)
-
-static inline void
-_nm_auto_fclose(FILE **pfd)
-{
-    if (*pfd) {
-        int errsv = errno;
-
-        (void) fclose(*pfd);
-        errno = errsv;
-    }
-}
-#define nm_auto_fclose nm_auto(_nm_auto_fclose)
-
-/*****************************************************************************/
-
-#define nm_clear_pointer(pp, destroy)                                                \
-    ({                                                                               \
-        typeof(*(pp)) *_pp = (pp);                                                   \
-        typeof(*_pp) _p;                                                             \
-        int _changed = false;                                                        \
-                                                                                     \
-        if (_pp && (_p = *_pp)) {                                                    \
-            _nm_unused const void *_p_check_is_pointer = _p;                         \
-                                                                                     \
-            *_pp = NULL;                                                             \
-                                                                                     \
-            /* g_clear_pointer() assigns @destroy first to a local variable, so that
-             * you can call "g_clear_pointer (pp, (GDestroyNotify) destroy);" without
-             * gcc emitting a warning. We don't do that, hence, you cannot cast
-             * "destroy" first.
-             *
-             * On the upside: you are not supposed to cast fcn, because the pointer
-             * types are preserved. If you really need a cast, you should cast @pp.
-             * But that is hardly ever necessary. */ \
-            (destroy)(_p);                                                           \
-                                                                                     \
-            _changed = true;                                                         \
-        }                                                                            \
-        _changed;                                                                    \
-    })
-
-#define nm_clear_free(pp) nm_clear_pointer(pp, free)
-
-/*****************************************************************************/
-
-static inline void *
-_nm_steal_pointer(void *pp)
-{
-    void **ptr = (void **) pp;
-    void * ref;
-
-    ref  = *ptr;
-    *ptr = NULL;
-    return ref;
-}
-
-#define nm_steal_pointer(pp) ((typeof(*(pp))) _nm_steal_pointer(pp))
-
-/**
- * nm_steal_int:
- * @p_val: pointer to an int type.
- *
- * Returns: *p_val and sets *p_val to zero the same time.
- *   Accepts %NULL, in which case also numeric 0 will be returned.
- */
-#define nm_steal_int(p_val)                   \
-    ({                                        \
-        typeof(p_val) const _p_val = (p_val); \
-        typeof(*_p_val) _val       = 0;       \
-                                              \
-        if (_p_val && (_val = *_p_val)) {     \
-            *_p_val = 0;                      \
-        }                                     \
-        _val;                                 \
-    })
-
-static inline int
-nm_steal_fd(int *p_fd)
-{
-    int fd;
-
-    if (p_fd && ((fd = *p_fd) >= 0)) {
-        *p_fd = -1;
-        return fd;
-    }
-    return -1;
-}
-
-/*****************************************************************************/
-
-static inline uintptr_t
-nm_ptr_to_uintptr(const void *p)
-{
-    /* in C, pointers can only be compared (with less-than or greater-than) under certain
-     * circumstances. Since uintptr_t is supposed to be able to represent the pointer
-     * as a plain integer and also support to convert the integer back to the pointer,
-     * it should be safer to compare the pointers directly.
-     *
-     * Of course, this function isn't very useful beyond that its use makes it clear
-     * that we want to compare pointers by value, which otherwise may not be valid. */
-    return (uintptr_t) p;
-}
-
-/*****************************************************************************/
-
-#define NM_CMP_RETURN(c)             \
-    do {                             \
-        const int _cc = (c);         \
-        if (_cc)                     \
-            return _cc < 0 ? -1 : 1; \
-    } while (0)
-
-#define NM_CMP_RETURN_DIRECT(c) \
-    do {                        \
-        const int _cc = (c);    \
-        if (_cc)                \
-            return _cc;         \
-    } while (0)
-
-#define NM_CMP_SELF(a, b)   \
-    do {                    \
-        typeof(a) _a = (a); \
-        typeof(b) _b = (b); \
-                            \
-        if (_a == _b)       \
-            return 0;       \
-        if (!_a)            \
-            return -1;      \
-        if (!_b)            \
-            return 1;       \
-    } while (0)
-
-#define NM_CMP_DIRECT(a, b)            \
-    do {                               \
-        typeof(a) _a = (a);            \
-        typeof(b) _b = (b);            \
-                                       \
-        if (_a != _b)                  \
-            return (_a < _b) ? -1 : 1; \
-    } while (0)
-
-#define NM_CMP_DIRECT_UNSAFE(a, b)       \
-    do {                                 \
-        if ((a) != (b))                  \
-            return ((a) < (b)) ? -1 : 1; \
-    } while (0)
-
-/* In the general case, direct pointer comparison is undefined behavior in C.
- * Avoid that by casting pointers to void* and then to uintptr_t. This comparison
- * is not really meaningful, except that it provides some kind of stable sort order
- * between pointers (that can otherwise not be compared). */
-#define NM_CMP_DIRECT_PTR(a, b) NM_CMP_DIRECT(nm_ptr_to_uintptr(a), nm_ptr_to_uintptr(b))
-
-#define NM_CMP_DIRECT_MEMCMP(a, b, size) NM_CMP_RETURN(memcmp((a), (b), (size)))
-
-#define NM_CMP_DIRECT_STRCMP(a, b) NM_CMP_RETURN_DIRECT(strcmp((a), (b)))
-
-#define NM_CMP_DIRECT_STRCMP0(a, b) NM_CMP_RETURN_DIRECT(nm_strcmp0((a), (b)))
-
-#define NM_CMP_DIRECT_IN6ADDR(a, b)                             \
-    do {                                                        \
-        const struct in6_addr *const _a = (a);                  \
-        const struct in6_addr *const _b = (b);                  \
-        NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \
-    } while (0)
-
-#define NM_CMP_FIELD(a, b, field) NM_CMP_DIRECT(((a)->field), ((b)->field))
-
-#define NM_CMP_FIELD_UNSAFE(a, b, field)                                   \
-    do {                                                                   \
-        /* it's unsafe, because it evaluates the arguments more then once.
-         * This is necessary for bitfields, for which typeof() doesn't work. */ \
-        if (((a)->field) != ((b)->field))                                  \
-            return ((a)->field < ((b)->field)) ? -1 : 1;                   \
-    } while (0)
-
-#define NM_CMP_FIELD_BOOL(a, b, field) NM_CMP_DIRECT(!!((a)->field), !!((b)->field))
-
-#define NM_CMP_FIELD_STR(a, b, field) NM_CMP_RETURN(strcmp(((a)->field), ((b)->field)))
-
-#define NM_CMP_FIELD_STR_INTERNED(a, b, field)        \
-    do {                                              \
-        const char *_a = ((a)->field);                \
-        const char *_b = ((b)->field);                \
-                                                      \
-        if (_a != _b) {                               \
-            NM_CMP_RETURN_DIRECT(nm_strcmp0(_a, _b)); \
-        }                                             \
-    } while (0)
-
-#define NM_CMP_FIELD_STR0(a, b, field) NM_CMP_RETURN_DIRECT(nm_strcmp0(((a)->field), ((b)->field)))
-
-#define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \
-    NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), NM_MIN(len, sizeof((a)->field))))
-
-#define NM_CMP_FIELD_MEMCMP(a, b, field) \
-    NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), sizeof((a)->field)))
-
-#define NM_CMP_FIELD_IN6ADDR(a, b, field)                       \
-    do {                                                        \
-        const struct in6_addr *const _a = &((a)->field);        \
-        const struct in6_addr *const _b = &((b)->field);        \
-        NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \
-    } while (0)
-
-/*****************************************************************************/
-
-#define NM_AF_UNSPEC 0 /* AF_UNSPEC */
-#define NM_AF_INET   2 /* AF_INET   */
-#define NM_AF_INET6  10 /* AF_INET6  */
-
-#define NM_AF_INET_SIZE  4 /* sizeof (in_addr_t)      */
-#define NM_AF_INET6_SIZE 16 /* sizeof (stuct in6_addr) */
-
-static inline char
-nm_utils_addr_family_to_char(int addr_family)
-{
-    switch (addr_family) {
-    case NM_AF_UNSPEC:
-        return 'X';
-    case NM_AF_INET:
-        return '4';
-    case NM_AF_INET6:
-        return '6';
-    }
-    nm_assert_not_reached();
-    return '?';
-}
-
-static inline size_t
-nm_utils_addr_family_to_size(int addr_family)
-{
-    switch (addr_family) {
-    case NM_AF_INET:
-        return NM_AF_INET_SIZE;
-    case NM_AF_INET6:
-        return NM_AF_INET6_SIZE;
-    }
-    nm_assert_not_reached();
-    return 0;
-}
-
-static inline int
-nm_utils_addr_family_from_size(size_t len)
-{
-    switch (len) {
-    case NM_AF_INET_SIZE:
-        return NM_AF_INET;
-    case NM_AF_INET6_SIZE:
-        return NM_AF_INET6;
-    }
-    return NM_AF_UNSPEC;
-}
-
-#define nm_assert_addr_family(addr_family) \
-    nm_assert(NM_IN_SET((addr_family), NM_AF_INET, NM_AF_INET6))
-
-#define NM_IS_IPv4(addr_family)                 \
-    ({                                          \
-        const int _addr_family = (addr_family); \
-                                                \
-        nm_assert_addr_family(_addr_family);    \
-                                                \
-        (_addr_family == NM_AF_INET);           \
-    })
-
-#endif /* __NM_STD_AUX_H__ */
diff --git a/shared/nm-std-aux/nm-std-utils.c b/shared/nm-std-aux/nm-std-utils.c
deleted file mode 100644
index 18692b19..00000000
--- a/shared/nm-std-aux/nm-std-utils.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-default-std.h"
-
-#include "nm-std-utils.h"
-
-#include <stdint.h>
-#include <assert.h>
-#include <limits.h>
-
-/*****************************************************************************/
-
-size_t
-nm_utils_get_next_realloc_size(bool true_realloc, size_t requested)
-{
-    size_t n, x;
-
-    /* https://doc.qt.io/qt-5/containers.html#growth-strategies */
-
-    if (requested <= 40) {
-        /* small allocations. Increase in small steps of 8 bytes.
-         *
-         * We get thus sizes of 8, 16, 32, 40. */
-        if (requested <= 8)
-            return 8;
-        if (requested <= 16)
-            return 16;
-        if (requested <= 32)
-            return 32;
-
-        /* The return values for < 104 are essentially hard-coded, and the choice here is
-         * made without very strong reasons.
-         *
-         * We want to stay 24 bytes below the power-of-two border 64. Hence, return 40 here.
-         * However, the next step then is already 104 (128 - 24). It's a larger gap than in
-         * the steps before.
-         *
-         * It's not clear whether some of the steps should be adjusted (or how exactly). */
-        return 40;
-    }
-
-    if (requested <= 0x2000u - 24u || NM_UNLIKELY(!true_realloc)) {
-        /* mid sized allocations. Return next power of two, minus 24 bytes extra space
-         * at the beginning.
-         * That means, we double the size as we grow.
-         *
-         * With !true_realloc, it means that the caller does not intend to call
-         * realloc() but instead clone the buffer. This is for example the case, when we
-         * want to nm_explicit_bzero() the old buffer. In that case we really want to grow
-         * the buffer exponentially every time and not increment in page sizes of 4K (below).
-         *
-         * We get thus sizes of 104, 232, 488, 1000, 2024, 4072, 8168... */
-
-        if (NM_UNLIKELY(requested > SIZE_MAX / 2u - 24u))
-            goto out_huge;
-
-        x = requested + 24u;
-        n = 128u;
-        while (n < x) {
-            n <<= 1;
-            nm_assert(n > 128u);
-        }
-
-        nm_assert(n > 24u && n - 24u >= requested);
-        return n - 24u;
-    }
-
-    if (NM_UNLIKELY(requested > SIZE_MAX - 0x1000u - 24u)) {
-        /* overflow happened. */
-        goto out_huge;
-    }
-
-    /* For large allocations (with !true_realloc) we allocate memory in chunks of
-     * 4K (- 24 bytes extra), assuming that the memory gets mmapped and thus
-     * realloc() is efficient by just reordering pages. */
-    n = ((requested + (0x0FFFu + 24u)) & ~((size_t) 0x0FFFu)) - 24u;
-    nm_assert(n >= requested);
-    return n;
-
-out_huge:
-    if (sizeof(size_t) > 4u) {
-        /* on s390x (64 bit), gcc with LTO can complain that the size argument to
-         * malloc must not be larger than 9223372036854775807.
-         *
-         * Work around that by returning SSIZE_MAX. It should be plenty still! */
-        assert(requested <= (size_t) SSIZE_MAX);
-        return (size_t) SSIZE_MAX;
-    }
-    return SIZE_MAX;
-}
diff --git a/shared/nm-std-aux/nm-std-utils.h b/shared/nm-std-aux/nm-std-utils.h
deleted file mode 100644
index 9c851f1f..00000000
--- a/shared/nm-std-aux/nm-std-utils.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef __NM_STD_UTILS_H__
-#define __NM_STD_UTILS_H__
-
-#include <stdbool.h>
-
-#include "nm-std-aux.h"
-
-/*****************************************************************************/
-
-/* nm_utils_get_next_realloc_size() is used to grow buffers exponentially, when
- * the final size is unknown. As such, it has borders for which it allocates
- * certain buffer sizes.
- *
- * The use of these defines is to get favorable allocation sequences.
- * For example, nm_str_buf_init() asks for an initial allocation size. Note that
- * it reserves the exactly requested amount, under the assumption that the
- * user may know how many bytes will be required. However, often the caller
- * doesn't know in advance, and NMStrBuf grows exponentially by calling
- * nm_utils_get_next_realloc_size().
- * Imagine you call nm_str_buf_init() with an initial buffer size 100, and you
- * add one character at a time. Then the first reallocation will increase the
- * buffer size only from 100 to 104.
- * If you however start with an initial buffer size of 104, then the next reallocation
- * via nm_utils_get_next_realloc_size() gives you 232, and so on. By using
- * these sizes, it results in one less allocation, if you anyway don't know the
- * exact size in advance. */
-#define NM_UTILS_GET_NEXT_REALLOC_SIZE_32   ((size_t) 32)
-#define NM_UTILS_GET_NEXT_REALLOC_SIZE_40   ((size_t) 40)
-#define NM_UTILS_GET_NEXT_REALLOC_SIZE_104  ((size_t) 104)
-#define NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 ((size_t) 1000)
-
-size_t nm_utils_get_next_realloc_size(bool true_realloc, size_t requested);
-
-#endif /* __NM_STD_UTILS_H__ */
diff --git a/shared/nm-std-aux/unaligned.h b/shared/nm-std-aux/unaligned.h
deleted file mode 100644
index 4100be08..00000000
--- a/shared/nm-std-aux/unaligned.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <endian.h>
-#include <stdint.h>
-
-/* BE */
-
-static inline uint16_t unaligned_read_be16(const void *_u) {
-        const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
-
-        return be16toh(u->x);
-}
-
-static inline uint32_t unaligned_read_be32(const void *_u) {
-        const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
-
-        return be32toh(u->x);
-}
-
-static inline uint64_t unaligned_read_be64(const void *_u) {
-        const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
-
-        return be64toh(u->x);
-}
-
-static inline void unaligned_write_be16(void *_u, uint16_t a) {
-        struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
-
-        u->x = be16toh(a);
-}
-
-static inline void unaligned_write_be32(void *_u, uint32_t a) {
-        struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
-
-        u->x = be32toh(a);
-}
-
-static inline void unaligned_write_be64(void *_u, uint64_t a) {
-        struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
-
-        u->x = be64toh(a);
-}
-
-/* LE */
-
-static inline uint16_t unaligned_read_le16(const void *_u) {
-        const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
-
-        return le16toh(u->x);
-}
-
-static inline uint32_t unaligned_read_le32(const void *_u) {
-        const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
-
-        return le32toh(u->x);
-}
-
-static inline uint64_t unaligned_read_le64(const void *_u) {
-        const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
-
-        return le64toh(u->x);
-}
-
-static inline void unaligned_write_le16(void *_u, uint16_t a) {
-        struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
-
-        u->x = le16toh(a);
-}
-
-static inline void unaligned_write_le32(void *_u, uint32_t a) {
-        struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
-
-        u->x = le32toh(a);
-}
-
-static inline void unaligned_write_le64(void *_u, uint64_t a) {
-        struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
-
-        u->x = le64toh(a);
-}
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define unaligned_read_ne16 unaligned_read_be16
-#define unaligned_read_ne32 unaligned_read_be32
-#define unaligned_read_ne64 unaligned_read_be64
-
-#define unaligned_write_ne16 unaligned_write_be16
-#define unaligned_write_ne32 unaligned_write_be32
-#define unaligned_write_ne64 unaligned_write_be64
-#else
-#define unaligned_read_ne16 unaligned_read_le16
-#define unaligned_read_ne32 unaligned_read_le32
-#define unaligned_read_ne64 unaligned_read_le64
-
-#define unaligned_write_ne16 unaligned_write_le16
-#define unaligned_write_ne32 unaligned_write_le32
-#define unaligned_write_ne64 unaligned_write_le64
-#endif
diff --git a/shared/nm-test-libnm-utils.h b/shared/nm-test-libnm-utils.h
deleted file mode 100644
index cac54076..00000000
--- a/shared/nm-test-libnm-utils.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2014 - 2015 Red Hat, Inc.
- */
-
-#ifndef __NM_TEST_LIBNM_UTILS_H__
-#define __NM_TEST_LIBNM_UTILS_H__
-
-#include "NetworkManager.h"
-
-#include "nm-utils/nm-test-utils.h"
-
-typedef struct {
-    GDBusConnection *bus;
-    GDBusProxy *     proxy;
-    GPid             pid;
-    int              keepalive_fd;
-} NMTstcServiceInfo;
-
-NMTstcServiceInfo *nmtstc_service_init(void);
-void               nmtstc_service_cleanup(NMTstcServiceInfo *info);
-NMTstcServiceInfo *nmtstc_service_available(NMTstcServiceInfo *info);
-
-static inline void
-_nmtstc_auto_service_cleanup(NMTstcServiceInfo **info)
-{
-    nmtstc_service_cleanup(g_steal_pointer(info));
-}
-#define nmtstc_auto_service_cleanup nm_auto(_nmtstc_auto_service_cleanup)
-
-#define NMTSTC_SERVICE_INFO_SETUP(sinfo)                      \
-    NM_PRAGMA_WARNING_DISABLE("-Wunused-variable")            \
-    nmtstc_auto_service_cleanup NMTstcServiceInfo *sinfo = ({ \
-        NMTstcServiceInfo *_sinfo;                            \
-                                                              \
-        _sinfo = nmtstc_service_init();                       \
-        if (!nmtstc_service_available(_sinfo))                \
-            return;                                           \
-        _sinfo;                                               \
-    });                                                       \
-    NM_PRAGMA_WARNING_REENABLE
-
-NMDevice *nmtstc_service_add_device(NMTstcServiceInfo *info,
-                                    NMClient *         client,
-                                    const char *       method,
-                                    const char *       ifname);
-
-NMDevice *nmtstc_service_add_wired_device(NMTstcServiceInfo *sinfo,
-                                          NMClient *         client,
-                                          const char *       ifname,
-                                          const char *       hwaddr,
-                                          const char **      subchannels);
-
-void nmtstc_service_add_connection(NMTstcServiceInfo *sinfo,
-                                   NMConnection *     connection,
-                                   gboolean           verify_connection,
-                                   char **            out_path);
-
-void nmtstc_service_add_connection_variant(NMTstcServiceInfo *sinfo,
-                                           GVariant *         connection,
-                                           gboolean           verify_connection,
-                                           char **            out_path);
-
-void nmtstc_service_update_connection(NMTstcServiceInfo *sinfo,
-                                      const char *       path,
-                                      NMConnection *     connection,
-                                      gboolean           verify_connection);
-
-void nmtstc_service_update_connection_variant(NMTstcServiceInfo *sinfo,
-                                              const char *       path,
-                                              GVariant *         connection,
-                                              gboolean           verify_connection);
-
-gpointer nmtstc_context_object_new_valist(GType       gtype,
-                                          gboolean    allow_iterate_main_context,
-                                          const char *first_property_name,
-                                          va_list     var_args);
-
-gpointer nmtstc_context_object_new(GType       gtype,
-                                   gboolean    allow_iterate_main_context,
-                                   const char *first_property_name,
-                                   ...);
-
-static inline NMClient *
-nmtstc_client_new(gboolean allow_iterate_main_context)
-{
-    return nmtstc_context_object_new(NM_TYPE_CLIENT, allow_iterate_main_context, NULL);
-}
-
-#endif /* __NM_TEST_LIBNM_UTILS_H__ */
diff --git a/shared/nm-test-utils-impl.c b/shared/nm-test-utils-impl.c
deleted file mode 100644
index f8f98d81..00000000
--- a/shared/nm-test-utils-impl.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2010 - 2015 Red Hat, Inc.
- */
-
-#include "libnm/nm-default-libnm.h"
-
-#include <sys/wait.h>
-
-#include "NetworkManager.h"
-#include "nm-std-aux/nm-dbus-compat.h"
-
-#include "nm-test-libnm-utils.h"
-
-#define NMTSTC_NM_SERVICE NM_BUILD_SRCDIR "/tools/test-networkmanager-service.py"
-
-/*****************************************************************************/
-
-static gboolean
-name_exists(GDBusConnection *c, const char *name)
-{
-    GVariant *reply;
-    gboolean  exists = FALSE;
-
-    reply = g_dbus_connection_call_sync(c,
-                                        DBUS_SERVICE_DBUS,
-                                        DBUS_PATH_DBUS,
-                                        DBUS_INTERFACE_DBUS,
-                                        "GetNameOwner",
-                                        g_variant_new("(s)", name),
-                                        NULL,
-                                        G_DBUS_CALL_FLAGS_NO_AUTO_START,
-                                        -1,
-                                        NULL,
-                                        NULL);
-    if (reply != NULL) {
-        exists = TRUE;
-        g_variant_unref(reply);
-    }
-
-    return exists;
-}
-
-typedef struct {
-    GMainLoop *      mainloop;
-    GDBusConnection *bus;
-    int              exit_code;
-    bool             exited : 1;
-    bool             name_found : 1;
-} ServiceInitWaitData;
-
-static gboolean
-_service_init_wait_probe_name(gpointer user_data)
-{
-    ServiceInitWaitData *data = user_data;
-
-    if (!name_exists(data->bus, "org.freedesktop.NetworkManager"))
-        return G_SOURCE_CONTINUE;
-
-    data->name_found = TRUE;
-    g_main_loop_quit(data->mainloop);
-    return G_SOURCE_REMOVE;
-}
-
-static void
-_service_init_wait_child_wait(GPid pid, int status, gpointer user_data)
-{
-    ServiceInitWaitData *data = user_data;
-
-    data->exited    = TRUE;
-    data->exit_code = status;
-    g_main_loop_quit(data->mainloop);
-}
-
-NMTstcServiceInfo *
-nmtstc_service_available(NMTstcServiceInfo *info)
-{
-    gs_free char *m = NULL;
-
-    if (info)
-        return info;
-
-    /* This happens, when test-networkmanager-service.py exits with 77 status
-     * code. */
-    m = g_strdup_printf("missing dependency for running NetworkManager stub service %s",
-                        NMTSTC_NM_SERVICE);
-    g_test_skip(m);
-    return NULL;
-}
-
-NMTstcServiceInfo *
-nmtstc_service_init(void)
-{
-    NMTstcServiceInfo *info;
-    const char *       args[] = {TEST_NM_PYTHON, NMTSTC_NM_SERVICE, NULL};
-    GError *           error  = NULL;
-
-    info = g_malloc0(sizeof(*info));
-
-    info->bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
-    g_assert_no_error(error);
-
-    /* Spawn the test service. info->keepalive_fd will be a pipe to the service's
-     * stdin; if it closes, the service will exit immediately. We use this to
-     * make sure the service exits if the test program crashes.
-     */
-    g_spawn_async_with_pipes(NULL,
-                             (char **) args,
-                             NULL,
-                             G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
-                             NULL,
-                             NULL,
-                             &info->pid,
-                             &info->keepalive_fd,
-                             NULL,
-                             NULL,
-                             &error);
-    g_assert_no_error(error);
-
-    {
-        nm_auto_unref_gsource GSource *timeout_source = NULL;
-        nm_auto_unref_gsource GSource *child_source   = NULL;
-        GMainContext *                 context        = g_main_context_new();
-        ServiceInitWaitData            data           = {
-            .bus      = info->bus,
-            .mainloop = g_main_loop_new(context, FALSE),
-        };
-        gboolean had_timeout;
-
-        timeout_source = g_timeout_source_new(50);
-        g_source_set_callback(timeout_source, _service_init_wait_probe_name, &data, NULL);
-        g_source_attach(timeout_source, context);
-
-        child_source = g_child_watch_source_new(info->pid);
-        g_source_set_callback(child_source,
-                              G_SOURCE_FUNC(_service_init_wait_child_wait),
-                              &data,
-                              NULL);
-        g_source_attach(child_source, context);
-
-        had_timeout = !nmtst_main_loop_run(data.mainloop, 30000);
-
-        g_source_destroy(timeout_source);
-        g_source_destroy(child_source);
-        g_main_loop_unref(data.mainloop);
-        g_main_context_unref(context);
-
-        if (had_timeout)
-            g_error("test service %s did not start in time", NMTSTC_NM_SERVICE);
-        if (!data.name_found) {
-            g_assert(data.exited);
-            info->pid = NM_PID_T_INVAL;
-            nmtstc_service_cleanup(info);
-
-            if (WIFEXITED(data.exit_code) && WEXITSTATUS(data.exit_code) == 77) {
-                /* If the stub service exited with status 77 it means that it decided
-                 * that it cannot conduct the tests and the test should be (gracefully)
-                 * skip. The likely reason for that, is that libnm is not available
-                 * via pygobject. */
-                return NULL;
-            }
-            g_error("test service %s exited with error code %d", NMTSTC_NM_SERVICE, data.exit_code);
-        }
-    }
-
-    /* Grab a proxy to our fake NM service to trigger tests */
-    info->proxy = g_dbus_proxy_new_sync(info->bus,
-                                        G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
-                                            | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
-                                            | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
-                                        NULL,
-                                        NM_DBUS_SERVICE,
-                                        NM_DBUS_PATH,
-                                        "org.freedesktop.NetworkManager.LibnmGlibTest",
-                                        NULL,
-                                        &error);
-    g_assert_no_error(error);
-
-    return info;
-}
-
-void
-nmtstc_service_cleanup(NMTstcServiceInfo *info)
-{
-    int    ret;
-    gint64 t;
-    int    status;
-
-    if (!info)
-        return;
-
-    nm_close(nm_steal_fd(&info->keepalive_fd));
-
-    g_clear_object(&info->proxy);
-
-    if (info->pid != NM_PID_T_INVAL) {
-        kill(info->pid, SIGTERM);
-
-        t = g_get_monotonic_time();
-again_wait:
-        ret = waitpid(info->pid, &status, WNOHANG);
-        if (ret == 0) {
-            if (t + 2000000 < g_get_monotonic_time()) {
-                kill(info->pid, SIGKILL);
-                g_error("child process %lld did not exit within timeout", (long long) info->pid);
-            }
-            g_usleep(G_USEC_PER_SEC / 50);
-            goto again_wait;
-        }
-        if (ret == -1 && errno == EINTR)
-            goto again_wait;
-
-        g_assert(ret == info->pid);
-    }
-
-    nmtst_main_context_iterate_until_assert_full(
-        NULL,
-        1000,
-        80,
-        (!name_exists(info->bus, "org.freedesktop.NetworkManager")));
-
-    g_clear_object(&info->bus);
-
-    memset(info, 0, sizeof(*info));
-    g_free(info);
-}
-
-typedef struct {
-    GMainLoop * loop;
-    const char *ifname;
-    const char *path;
-    NMDevice *  device;
-} AddDeviceInfo;
-
-static void
-device_added_cb(NMClient *client, NMDevice *device, gpointer user_data)
-{
-    AddDeviceInfo *info = user_data;
-
-    g_assert(info);
-    g_assert(!info->device);
-
-    g_assert(NM_IS_DEVICE(device));
-    g_assert_cmpstr(nm_object_get_path(NM_OBJECT(device)), ==, info->path);
-    g_assert_cmpstr(nm_device_get_iface(device), ==, info->ifname);
-
-    info->device = g_object_ref(device);
-    g_main_loop_quit(info->loop);
-}
-
-static GVariant *
-call_add_wired_device(GDBusProxy * proxy,
-                      const char * ifname,
-                      const char * hwaddr,
-                      const char **subchannels,
-                      GError **    error)
-{
-    const char *empty[] = {NULL};
-
-    if (!hwaddr)
-        hwaddr = "/";
-    if (!subchannels)
-        subchannels = empty;
-
-    return g_dbus_proxy_call_sync(proxy,
-                                  "AddWiredDevice",
-                                  g_variant_new("(ss^as)", ifname, hwaddr, subchannels),
-                                  G_DBUS_CALL_FLAGS_NO_AUTO_START,
-                                  3000,
-                                  NULL,
-                                  error);
-}
-
-static GVariant *
-call_add_device(GDBusProxy *proxy, const char *method, const char *ifname, GError **error)
-{
-    return g_dbus_proxy_call_sync(proxy,
-                                  method,
-                                  g_variant_new("(s)", ifname),
-                                  G_DBUS_CALL_FLAGS_NO_AUTO_START,
-                                  3000,
-                                  NULL,
-                                  error);
-}
-
-static NMDevice *
-add_device_common(NMTstcServiceInfo *sinfo,
-                  NMClient *         client,
-                  const char *       method,
-                  const char *       ifname,
-                  const char *       hwaddr,
-                  const char **      subchannels)
-{
-    nm_auto_unref_gmainloop GMainLoop *loop = NULL;
-    gs_unref_variant GVariant *ret          = NULL;
-    gs_free_error GError *error             = NULL;
-    AddDeviceInfo         info;
-
-    g_assert(sinfo);
-    g_assert(NM_IS_CLIENT(client));
-
-    if (nm_streq0(method, "AddWiredDevice"))
-        ret = call_add_wired_device(sinfo->proxy, ifname, hwaddr, subchannels, &error);
-    else
-        ret = call_add_device(sinfo->proxy, method, ifname, &error);
-
-    nmtst_assert_success(ret, error);
-    g_assert_cmpstr(g_variant_get_type_string(ret), ==, "(o)");
-
-    /* Wait for NMClient to find the device */
-
-    loop = g_main_loop_new(nm_client_get_main_context(client), FALSE);
-
-    info = (AddDeviceInfo){
-        .ifname = ifname,
-        .loop   = loop,
-    };
-    g_variant_get(ret, "(&o)", &info.path);
-
-    g_signal_connect(client, NM_CLIENT_DEVICE_ADDED, G_CALLBACK(device_added_cb), &info);
-
-    if (!nmtst_main_loop_run(loop, 5000))
-        g_assert_not_reached();
-
-    g_signal_handlers_disconnect_by_func(client, device_added_cb, &info);
-
-    g_assert(NM_IS_DEVICE(info.device));
-
-    g_assert(info.device
-             == nm_client_get_device_by_path(client, nm_object_get_path(NM_OBJECT(info.device))));
-    g_object_unref(info.device);
-    return info.device;
-}
-
-NMDevice *
-nmtstc_service_add_device(NMTstcServiceInfo *sinfo,
-                          NMClient *         client,
-                          const char *       method,
-                          const char *       ifname)
-{
-    return add_device_common(sinfo, client, method, ifname, NULL, NULL);
-}
-
-NMDevice *
-nmtstc_service_add_wired_device(NMTstcServiceInfo *sinfo,
-                                NMClient *         client,
-                                const char *       ifname,
-                                const char *       hwaddr,
-                                const char **      subchannels)
-{
-    return add_device_common(sinfo, client, "AddWiredDevice", ifname, hwaddr, subchannels);
-}
-
-void
-nmtstc_service_add_connection(NMTstcServiceInfo *sinfo,
-                              NMConnection *     connection,
-                              gboolean           verify_connection,
-                              char **            out_path)
-{
-    nmtstc_service_add_connection_variant(
-        sinfo,
-        nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL),
-        verify_connection,
-        out_path);
-}
-
-void
-nmtstc_service_add_connection_variant(NMTstcServiceInfo *sinfo,
-                                      GVariant *         connection,
-                                      gboolean           verify_connection,
-                                      char **            out_path)
-{
-    GVariant *result;
-    GError *  error = NULL;
-
-    g_assert(sinfo);
-    g_assert(G_IS_DBUS_PROXY(sinfo->proxy));
-    g_assert(g_variant_is_of_type(connection, G_VARIANT_TYPE("a{sa{sv}}")));
-
-    result = g_dbus_proxy_call_sync(sinfo->proxy,
-                                    "AddConnection",
-                                    g_variant_new("(vb)", connection, verify_connection),
-                                    G_DBUS_CALL_FLAGS_NO_AUTO_START,
-                                    3000,
-                                    NULL,
-                                    &error);
-    g_assert_no_error(error);
-    g_assert(g_variant_is_of_type(result, G_VARIANT_TYPE("(o)")));
-    if (out_path)
-        g_variant_get(result, "(o)", out_path);
-    g_variant_unref(result);
-}
-
-void
-nmtstc_service_update_connection(NMTstcServiceInfo *sinfo,
-                                 const char *       path,
-                                 NMConnection *     connection,
-                                 gboolean           verify_connection)
-{
-    if (!path)
-        path = nm_connection_get_path(connection);
-    g_assert(path);
-
-    nmtstc_service_update_connection_variant(
-        sinfo,
-        path,
-        nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_ALL),
-        verify_connection);
-}
-
-void
-nmtstc_service_update_connection_variant(NMTstcServiceInfo *sinfo,
-                                         const char *       path,
-                                         GVariant *         connection,
-                                         gboolean           verify_connection)
-{
-    GVariant *result;
-    GError *  error = NULL;
-
-    g_assert(sinfo);
-    g_assert(G_IS_DBUS_PROXY(sinfo->proxy));
-    g_assert(g_variant_is_of_type(connection, G_VARIANT_TYPE("a{sa{sv}}")));
-    g_assert(path && path[0] == '/');
-
-    result = g_dbus_proxy_call_sync(sinfo->proxy,
-                                    "UpdateConnection",
-                                    g_variant_new("(ovb)", path, connection, verify_connection),
-                                    G_DBUS_CALL_FLAGS_NO_AUTO_START,
-                                    3000,
-                                    NULL,
-                                    &error);
-    g_assert_no_error(error);
-    g_assert(g_variant_is_of_type(result, G_VARIANT_TYPE("()")));
-    g_variant_unref(result);
-}
-
-/*****************************************************************************/
-
-typedef struct {
-    GType      gtype;
-    GMainLoop *loop;
-    GObject *  obj;
-    bool       call_nm_client_new_async : 1;
-} NMTstcObjNewData;
-
-static void
-_context_object_new_do_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
-{
-    NMTstcObjNewData *d         = user_data;
-    gs_free_error GError *error = NULL;
-
-    g_assert(!d->obj);
-
-    if (d->call_nm_client_new_async) {
-        d->obj = G_OBJECT(nm_client_new_finish(res, nmtst_get_rand_bool() ? &error : NULL));
-    } else {
-        d->obj = g_async_initable_new_finish(G_ASYNC_INITABLE(source_object),
-                                             res,
-                                             nmtst_get_rand_bool() ? &error : NULL);
-    }
-
-    nmtst_assert_success(G_IS_OBJECT(d->obj), error);
-    g_assert(G_OBJECT_TYPE(d->obj) == d->gtype);
-
-    g_main_loop_quit(d->loop);
-}
-
-static GObject *
-_context_object_new_do(GType       gtype,
-                       gboolean    sync,
-                       const char *first_property_name,
-                       va_list     var_args)
-{
-    gs_free_error GError *error = NULL;
-    GObject *             obj;
-
-    /* Create a GObject instance synchronously, and arbitrarily use either
-     * the sync or async constructor.
-     *
-     * Note that the sync and async construct differ in one important aspect:
-     * the async constructor iterates the current g_main_context_get_thread_default(),
-     * while the sync constructor does not! Aside from that, both should behave
-     * pretty much the same way. */
-
-    if (sync) {
-        nm_auto_destroy_and_unref_gsource GSource *source = NULL;
-
-        if (nmtst_get_rand_bool()) {
-            /* the current main context must not be iterated! */
-            source = g_idle_source_new();
-            g_source_set_callback(source, nmtst_g_source_assert_not_called, NULL, NULL);
-            g_source_attach(source, g_main_context_get_thread_default());
-        }
-
-        if (gtype != NM_TYPE_CLIENT || first_property_name || nmtst_get_rand_bool()) {
-            gboolean success;
-
-            if (first_property_name || nmtst_get_rand_bool())
-                obj = g_object_new_valist(gtype, first_property_name, var_args);
-            else
-                obj = g_object_new(gtype, NULL);
-
-            success = g_initable_init(G_INITABLE(obj), NULL, nmtst_get_rand_bool() ? &error : NULL);
-            nmtst_assert_success(success, error);
-        } else {
-            obj = G_OBJECT(nm_client_new(NULL, nmtst_get_rand_bool() ? &error : NULL));
-        }
-    } else {
-        nm_auto_unref_gmainloop GMainLoop *loop = NULL;
-        NMTstcObjNewData                   d    = {
-            .gtype = gtype,
-            .loop  = NULL,
-        };
-        gs_unref_object GObject *obj2 = NULL;
-
-        loop   = g_main_loop_new(g_main_context_get_thread_default(), FALSE);
-        d.loop = loop;
-
-        if (gtype != NM_TYPE_CLIENT || first_property_name || nmtst_get_rand_bool()) {
-            if (first_property_name || nmtst_get_rand_bool())
-                obj2 = g_object_new_valist(gtype, first_property_name, var_args);
-            else
-                obj2 = g_object_new(gtype, NULL);
-
-            g_async_initable_init_async(G_ASYNC_INITABLE(obj2),
-                                        G_PRIORITY_DEFAULT,
-                                        NULL,
-                                        _context_object_new_do_cb,
-                                        &d);
-        } else {
-            d.call_nm_client_new_async = TRUE;
-            nm_client_new_async(NULL, _context_object_new_do_cb, &d);
-        }
-        g_main_loop_run(loop);
-        obj = d.obj;
-        g_assert(!obj2 || obj == obj2);
-    }
-
-    nmtst_assert_success(G_IS_OBJECT(obj), error);
-    g_assert(G_OBJECT_TYPE(obj) == gtype);
-    return obj;
-}
-
-typedef struct {
-    GType       gtype;
-    const char *first_property_name;
-    va_list     var_args;
-    GMainLoop * loop;
-    GObject *   obj;
-    bool        sync;
-} NewSyncInsideDispatchedData;
-
-static gboolean
-_context_object_new_inside_loop_do(gpointer user_data)
-{
-    NewSyncInsideDispatchedData *d = user_data;
-
-    g_assert(d->loop);
-    g_assert(!d->obj);
-
-    d->obj =
-        nmtstc_context_object_new_valist(d->gtype, d->sync, d->first_property_name, d->var_args);
-    g_main_loop_quit(d->loop);
-    return G_SOURCE_CONTINUE;
-}
-
-static GObject *
-_context_object_new_inside_loop(GType       gtype,
-                                gboolean    sync,
-                                const char *first_property_name,
-                                va_list     var_args)
-{
-    GMainContext *          context         = g_main_context_get_thread_default();
-    nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(context, FALSE);
-    NewSyncInsideDispatchedData        d    = {
-        .gtype               = gtype,
-        .first_property_name = first_property_name,
-        .sync                = sync,
-        .loop                = loop,
-    };
-    nm_auto_destroy_and_unref_gsource GSource *source = NULL;
-
-    va_copy(d.var_args, var_args);
-
-    source = g_idle_source_new();
-    g_source_set_callback(source, _context_object_new_inside_loop_do, &d, NULL);
-    g_source_attach(source, context);
-
-    g_main_loop_run(loop);
-
-    va_end(d.var_args);
-
-    g_assert(G_IS_OBJECT(d.obj));
-    g_assert(G_OBJECT_TYPE(d.obj) == gtype);
-    return d.obj;
-}
-
-gpointer
-nmtstc_context_object_new_valist(GType       gtype,
-                                 gboolean    allow_iterate_main_context,
-                                 const char *first_property_name,
-                                 va_list     var_args)
-{
-    gboolean inside_loop;
-    gboolean sync;
-
-    if (!allow_iterate_main_context) {
-        sync        = TRUE;
-        inside_loop = FALSE;
-    } else {
-        /* The caller allows to iterate the main context. On that point,
-         * we can both use the synchronous and the asynchronous initialization,
-         * both should yield the same result. Choose one randomly. */
-        sync        = nmtst_get_rand_bool();
-        inside_loop = ((nmtst_get_rand_uint32() % 3) == 0);
-    }
-
-    if (inside_loop) {
-        /* Create the obj on an idle handler of the current context.
-         * In practice, it should make no difference, which this check
-         * tries to prove. */
-        return _context_object_new_inside_loop(gtype, sync, first_property_name, var_args);
-    }
-
-    return _context_object_new_do(gtype, sync, first_property_name, var_args);
-}
-
-gpointer
-nmtstc_context_object_new(GType       gtype,
-                          gboolean    allow_iterate_main_context,
-                          const char *first_property_name,
-                          ...)
-{
-    GObject *obj;
-    va_list  var_args;
-
-    va_start(var_args, first_property_name);
-    obj = nmtstc_context_object_new_valist(gtype,
-                                           allow_iterate_main_context,
-                                           first_property_name,
-                                           var_args);
-    va_end(var_args);
-    return obj;
-}
diff --git a/shared/nm-udev-aux/nm-udev-utils.c b/shared/nm-udev-aux/nm-udev-utils.c
deleted file mode 100644
index 0b941dff..00000000
--- a/shared/nm-udev-aux/nm-udev-utils.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-udev-utils.h"
-
-#include <libudev.h>
-
-struct _NMPUdevClient {
-    char **              subsystems;
-    GSource *            watch_source;
-    struct udev *        udev;
-    struct udev_monitor *monitor;
-    NMUdevClientEvent    event_handler;
-    gpointer             event_user_data;
-};
-
-/*****************************************************************************/
-
-gboolean
-nm_udev_utils_property_as_boolean(const char *uproperty)
-{
-    /* taken from g_udev_device_get_property_as_boolean() */
-
-    if (uproperty) {
-        if (strcmp(uproperty, "1") == 0 || g_ascii_strcasecmp(uproperty, "true") == 0)
-            return TRUE;
-    }
-    return FALSE;
-}
-
-const char *
-nm_udev_utils_property_decode(const char *uproperty, char **to_free)
-{
-    const char *p;
-    char *      unescaped = NULL;
-    char *      n         = NULL;
-
-    if (!uproperty) {
-        *to_free = NULL;
-        return NULL;
-    }
-
-    p = uproperty;
-    while (*p) {
-        int a, b;
-
-        if (p[0] == '\\' && p[1] == 'x' && (a = g_ascii_xdigit_value(p[2])) >= 0
-            && (b = g_ascii_xdigit_value(p[3])) >= 0 && (a || b)) {
-            if (!n) {
-                gssize l = p - uproperty;
-
-                unescaped = g_malloc(l + strlen(p) + 1 - 3);
-                memcpy(unescaped, uproperty, l);
-                n = &unescaped[l];
-            }
-            *n++ = (a << 4) | b;
-            p += 4;
-        } else {
-            if (n)
-                *n++ = *p;
-            p++;
-        }
-    }
-
-    if (!n) {
-        *to_free = NULL;
-        return uproperty;
-    }
-
-    *n++ = '\0';
-    return (*to_free = unescaped);
-}
-
-char *
-nm_udev_utils_property_decode_cp(const char *uproperty)
-{
-    char *cpy;
-
-    uproperty = nm_udev_utils_property_decode(uproperty, &cpy);
-    return cpy ?: g_strdup(uproperty);
-}
-
-/*****************************************************************************/
-
-static void
-_subsystem_split(const char * subsystem_full,
-                 const char **out_subsystem,
-                 const char **out_devtype,
-                 char **      to_free)
-{
-    char *tmp, *s;
-
-    nm_assert(subsystem_full);
-    nm_assert(out_subsystem);
-    nm_assert(out_devtype);
-    nm_assert(to_free);
-
-    s = strstr(subsystem_full, "/");
-    if (s) {
-        tmp            = g_strdup(subsystem_full);
-        s              = &tmp[s - subsystem_full];
-        *s             = '\0';
-        *out_subsystem = tmp;
-        *out_devtype   = &s[1];
-        *to_free       = tmp;
-    } else {
-        *out_subsystem = subsystem_full;
-        *out_devtype   = NULL;
-        *to_free       = NULL;
-    }
-}
-
-static struct udev_enumerate *
-nm_udev_utils_enumerate(struct udev *uclient, const char *const *subsystems)
-{
-    struct udev_enumerate *enumerate;
-    guint                  n;
-
-    enumerate = udev_enumerate_new(uclient);
-
-    if (subsystems) {
-        for (n = 0; subsystems[n]; n++) {
-            const char *  subsystem;
-            const char *  devtype;
-            gs_free char *to_free = NULL;
-
-            _subsystem_split(subsystems[n], &subsystem, &devtype, &to_free);
-
-            udev_enumerate_add_match_subsystem(enumerate, subsystem);
-
-            if (devtype != NULL)
-                udev_enumerate_add_match_property(enumerate, "DEVTYPE", devtype);
-        }
-    }
-
-    return enumerate;
-}
-
-struct udev *
-nm_udev_client_get_udev(NMUdevClient *self)
-{
-    g_return_val_if_fail(self, NULL);
-
-    return self->udev;
-}
-
-struct udev_enumerate *
-nm_udev_client_enumerate_new(NMUdevClient *self)
-{
-    g_return_val_if_fail(self, NULL);
-
-    return nm_udev_utils_enumerate(self->udev, (const char *const *) self->subsystems);
-}
-
-/*****************************************************************************/
-
-static gboolean
-monitor_event(int fd, GIOCondition condition, gpointer user_data)
-{
-    NMUdevClient *      self = user_data;
-    struct udev_device *udevice;
-
-    if (!self->monitor)
-        goto out;
-
-    udevice = udev_monitor_receive_device(self->monitor);
-    if (udevice == NULL)
-        goto out;
-
-    self->event_handler(self, udevice, self->event_user_data);
-    udev_device_unref(udevice);
-
-out:
-    return TRUE;
-}
-
-/**
- * nm_udev_client_new:
- * @subsystems: the subsystems
- * @event_handler: callback for events
- * @event_user_data: user-data for @event_handler
- *
- * Basically, it is g_udev_client_new(), and most notably
- * g_udev_client_constructed().
- *
- * Returns: a new NMUdevClient instance.
- */
-NMUdevClient *
-nm_udev_client_new(const char *const *subsystems,
-                   NMUdevClientEvent  event_handler,
-                   gpointer           event_user_data)
-{
-    NMUdevClient *self;
-    guint         n;
-
-    self = g_slice_new0(NMUdevClient);
-
-    self->event_handler   = event_handler;
-    self->event_user_data = event_user_data;
-    self->subsystems      = subsystems && subsystems[0] ? g_strdupv((char **) subsystems) : NULL;
-
-    self->udev = udev_new();
-    if (!self->udev)
-        goto fail;
-
-    /* connect to event source */
-    if (self->event_handler) {
-        self->monitor = udev_monitor_new_from_netlink(self->udev, "udev");
-        if (!self->monitor)
-            goto fail;
-
-        if (self->subsystems) {
-            /* install subsystem filters to only wake up for certain events */
-            for (n = 0; self->subsystems[n]; n++) {
-                gs_free char *to_free = NULL;
-                const char *  subsystem;
-                const char *  devtype;
-
-                _subsystem_split(self->subsystems[n], &subsystem, &devtype, &to_free);
-                udev_monitor_filter_add_match_subsystem_devtype(self->monitor, subsystem, devtype);
-            }
-
-            /* listen to events, and buffer them */
-            udev_monitor_set_receive_buffer_size(self->monitor, 4 * 1024 * 1024);
-            udev_monitor_enable_receiving(self->monitor);
-
-            self->watch_source = nm_g_unix_fd_source_new(udev_monitor_get_fd(self->monitor),
-                                                         G_IO_IN,
-                                                         G_PRIORITY_DEFAULT,
-                                                         monitor_event,
-                                                         self,
-                                                         NULL);
-            g_source_attach(self->watch_source, g_main_context_get_thread_default());
-        }
-    }
-
-    return self;
-
-fail:
-    return nm_udev_client_destroy(self);
-}
-
-NMUdevClient *
-nm_udev_client_destroy(NMUdevClient *self)
-{
-    if (!self)
-        return NULL;
-
-    nm_clear_g_source_inst(&self->watch_source);
-
-    udev_monitor_unref(self->monitor);
-    self->monitor = NULL;
-    udev_unref(self->udev);
-    self->udev = NULL;
-
-    g_strfreev(self->subsystems);
-
-    g_slice_free(NMUdevClient, self);
-
-    return NULL;
-}
diff --git a/shared/nm-udev-aux/nm-udev-utils.h b/shared/nm-udev-aux/nm-udev-utils.h
deleted file mode 100644
index 191f9a89..00000000
--- a/shared/nm-udev-aux/nm-udev-utils.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#ifndef __NM_UDEV_UTILS_H__
-#define __NM_UDEV_UTILS_H__
-
-struct udev;
-struct udev_device;
-struct udev_enumerate;
-
-gboolean    nm_udev_utils_property_as_boolean(const char *uproperty);
-const char *nm_udev_utils_property_decode(const char *uproperty, char **to_free);
-char *      nm_udev_utils_property_decode_cp(const char *uproperty);
-
-typedef struct _NMPUdevClient NMUdevClient;
-
-typedef void (*NMUdevClientEvent)(NMUdevClient *      udev_client,
-                                  struct udev_device *udevice,
-                                  gpointer            event_user_data);
-
-NMUdevClient *nm_udev_client_new(const char *const *subsystems,
-                                 NMUdevClientEvent  event_handler,
-                                 gpointer           event_user_data);
-
-NMUdevClient *nm_udev_client_destroy(NMUdevClient *self);
-
-struct udev *nm_udev_client_get_udev(NMUdevClient *self);
-
-struct udev_enumerate *nm_udev_client_enumerate_new(NMUdevClient *self);
-
-#endif /* __NM_UDEV_UTILS_H__ */
diff --git a/shared/nm-utils/nm-compat.c b/shared/nm-utils/nm-compat.c
deleted file mode 100644
index dad48227..00000000
--- a/shared/nm-utils/nm-compat.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#include "libnm/nm-default-libnm.h"
-
-#include "nm-compat.h"
-
-/*****************************************************************************/
-
-static void
-_get_keys_cb(const char *key, const char *val, gpointer user_data)
-{
-    GPtrArray *a = user_data;
-
-    g_ptr_array_add(a, g_strdup(key));
-}
-
-static const char **
-_get_keys(NMSettingVpn *setting, gboolean is_secrets, guint *out_length)
-{
-    guint        len;
-    const char **keys = NULL;
-    GPtrArray *  a;
-
-    nm_assert(NM_IS_SETTING_VPN(setting));
-
-    if (is_secrets)
-        len = nm_setting_vpn_get_num_secrets(setting);
-    else
-        len = nm_setting_vpn_get_num_data_items(setting);
-
-    a = g_ptr_array_sized_new(len + 1);
-
-    if (is_secrets)
-        nm_setting_vpn_foreach_secret(setting, _get_keys_cb, a);
-    else
-        nm_setting_vpn_foreach_data_item(setting, _get_keys_cb, a);
-
-    len = a->len;
-    if (len) {
-        g_ptr_array_sort(a, nm_strcmp_p);
-        g_ptr_array_add(a, NULL);
-        keys = g_malloc(a->len * sizeof(gpointer));
-        memcpy(keys, a->pdata, a->len * sizeof(gpointer));
-
-        /* we need to cache the keys *somewhere*. */
-        g_object_set_qdata_full(G_OBJECT(setting),
-                                is_secrets
-                                    ? NM_CACHED_QUARK("libnm._nm_setting_vpn_get_secret_keys")
-                                    : NM_CACHED_QUARK("libnm._nm_setting_vpn_get_data_keys"),
-                                g_ptr_array_free(a, FALSE),
-                                (GDestroyNotify) g_strfreev);
-    } else
-        g_ptr_array_free(a, TRUE);
-
-    NM_SET_OUT(out_length, len);
-    return keys;
-}
-
-const char **
-_nm_setting_vpn_get_data_keys(NMSettingVpn *setting, guint *out_length)
-{
-    g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL);
-
-    return _get_keys(setting, FALSE, out_length);
-}
-
-const char **
-_nm_setting_vpn_get_secret_keys(NMSettingVpn *setting, guint *out_length)
-{
-    g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL);
-
-    return _get_keys(setting, TRUE, out_length);
-}
diff --git a/shared/nm-utils/nm-compat.h b/shared/nm-utils/nm-compat.h
deleted file mode 100644
index 559afd5d..00000000
--- a/shared/nm-utils/nm-compat.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2017 Red Hat, Inc.
- */
-
-#ifndef __NM_COMPAT_H__
-#define __NM_COMPAT_H__
-
-#include "nm-setting-vpn.h"
-
-const char **_nm_setting_vpn_get_data_keys(NMSettingVpn *setting, guint *out_length);
-
-const char **_nm_setting_vpn_get_secret_keys(NMSettingVpn *setting, guint *out_length);
-
-#if NM_CHECK_VERSION(1, 11, 0)
-    #define nm_setting_vpn_get_data_keys(setting, out_length)  \
-        ({                                                     \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                   \
-            nm_setting_vpn_get_data_keys(setting, out_length); \
-            G_GNUC_END_IGNORE_DEPRECATIONS                     \
-        })
-    #define nm_setting_vpn_get_secret_keys(setting, out_length)  \
-        ({                                                       \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                     \
-            nm_setting_vpn_get_secret_keys(setting, out_length); \
-            G_GNUC_END_IGNORE_DEPRECATIONS                       \
-        })
-#else
-    #define nm_setting_vpn_get_data_keys(setting, out_length) \
-        _nm_setting_vpn_get_data_keys(setting, out_length)
-    #define nm_setting_vpn_get_secret_keys(setting, out_length) \
-        _nm_setting_vpn_get_secret_keys(setting, out_length)
-#endif
-
-#endif /* __NM_COMPAT_H__ */
diff --git a/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h
deleted file mode 100644
index d51f972e..00000000
--- a/shared/nm-utils/nm-test-utils.h
+++ /dev/null
@@ -1,2824 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2014 Red Hat, Inc.
- */
-
-#ifndef __NM_TEST_UTILS_H__
-#define __NM_TEST_UTILS_H__
-
-/*******************************************************************************
- * HOWTO run tests.
- *
- * Our tests (make check) include this header-only file nm-test-utils.h.
- *
- * You should always include this header *as last*. Reason is, that depending on
- * previous includes, functionality will be enabled.
- *
- * Logging:
- *   In tests, nm-logging redirects to glib logging. By default, glib suppresses all debug
- *   messages unless you set G_MESSAGES_DEBUG. To enable debug logging, you can explicitly set
- *   G_MESSAGES_DEBUG. Otherwise, nm-test will set G_MESSAGES_DEBUG=all in debug mode (see below).
- *   For nm-logging, you can configure the log-level and domains via NMTST_DEBUG environment
- *   variable.
- *
- * Assert-logging:
- *   Some tests assert against logged messages (g_test_expect_message()).
- *   By specifying no-expect-message in NMTST_DEBUG, you can disable assert logging
- *   and g_test_assert_expected_messages() will not fail.
- *
- * NMTST_SEED_RAND environment variable:
- *   Tests that use random numbers from nmtst_get_rand() get seeded at each start.
- *   You can specify the seed by setting NMTST_SEED_RAND to a particular number or empty ("")
- *   for a random one. If NMTST_SEED_RAND is not set (default) a stable seed gets chosen.
- *   Tests will print the seed to stdout, so that you know which one was chosen or generated.
- *
- *
- * NMTST_DEBUG environment variable:
- *
- * "debug", "no-debug": when at test is run in debug mode, it might behave differently,
- *   depending on the test. See nmtst_is_debug().
- *   Known differences:
- *    - a test might leave the logging level unspecified. In this case, running in
- *      debug mode, will turn on DEBUG logging, otherwise WARN logging only.
- *    - if G_MESSAGES_DEBUG is unset, nm-test will set G_MESSAGES_DEBUG=all
- *      for tests that don't do assert-logging.
- *   Debug mode is determined as follows (highest priority first):
- *    - command line option --debug/--no-debug
- *    - NMTST_DEBUG=debug/no-debug
- *    - setting NMTST_DEBUG implies debugging turned on
- *    - g_test_verbose()
- *
- * "no-expect-message": for tests that would assert against log messages, disable
- *   those asserts.
- *
- * "log-level=LEVEL", "log-domains=DOMAIN": reset the log level and domain for tests.
- *    It only has an effect for nm-logging messages.
- *    This has no effect if the test asserts against logging (unless no-expect-message),
- *    otherwise, changing the logging would break tests.
- *    If you set the level to DEBUG or TRACE, it also sets G_MESSAGES_DEBUG=all (unless
- *    in assert-logging mode and unless G_MESSAGES_DEBUG is already defined).
- *
- * "TRACE", this is shorthand for "log-level=TRACE".
- *
- * "D", this is shorthand for "log-level=TRACE,no-expect-message".
- *
- * "sudo-cmd=PATH": when running root tests as normal user, the test will execute
- *   itself by invoking sudo at PATH.
- *   For example
- *     NMTST_DEBUG="sudo-cmd=$PWD/tools/test-sudo-wrapper.sh" make -C src/platform/tests/ check
- *
- * "slow|quick|thorough": enable/disable long-running tests. This sets nmtst_test_quick().
- *   Whether long-running tests are enabled is determined as follows (highest priority first):
- *     - specifying the value in NMTST_DEBUG has highest priority
- *     - respect g_test_quick(), if the command line contains '-mslow', '-mquick', '-mthorough'.
- *     - use compile time default (CFLAGS=-DNMTST_TEST_QUICK=TRUE)
- *     - enable slow tests by default
- *
- * "p=PATH"|"s=PATH": passes the path to g_test_init() as "-p" and "-s", respectively.
- *   Unfortunately, these options conflict with "--tap" which our makefile passes to the
- *   tests, thus it's only useful outside of `make check`.
- *
- *******************************************************************************/
-
-#if defined(NM_ASSERT_NO_MSG) && NM_ASSERT_NO_MSG
-    #undef g_return_if_fail_warning
-    #undef g_assertion_message_expr
-#endif
-
-#include <arpa/inet.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-/*****************************************************************************/
-
-#define NMTST_G_RETURN_MSG_S(expr) "*: assertion '" NM_ASSERT_G_RETURN_EXPR(expr) "' failed"
-#define NMTST_G_RETURN_MSG(expr)   NMTST_G_RETURN_MSG_S(#expr)
-
-/*****************************************************************************/
-
-/* general purpose functions that have no dependency on other nmtst functions */
-
-#define nmtst_assert_error(error, expect_error_domain, expect_error_code, expect_error_pattern) \
-    G_STMT_START                                                                                \
-    {                                                                                           \
-        GError *    _error                = (error);                                            \
-        GQuark      _expect_error_domain  = (expect_error_domain);                              \
-        const char *_expect_error_pattern = (expect_error_pattern);                             \
-                                                                                                \
-        if (_expect_error_domain)                                                               \
-            g_assert_error(_error, _expect_error_domain, (expect_error_code));                  \
-        else                                                                                    \
-            g_assert(_error);                                                                   \
-        g_assert(_error->message);                                                              \
-        if (_expect_error_pattern                                                               \
-            && !g_pattern_match_simple(_expect_error_pattern, _error->message)) {               \
-            g_error("%s:%d: error message does not have expected pattern '%s'. Instead it is "  \
-                    "'%s' (%s, %d)",                                                            \
-                    __FILE__,                                                                   \
-                    __LINE__,                                                                   \
-                    _expect_error_pattern,                                                      \
-                    _error->message,                                                            \
-                    g_quark_to_string(_error->domain),                                          \
-                    _error->code);                                                              \
-        }                                                                                       \
-    }                                                                                           \
-    G_STMT_END
-
-#define NMTST_WAIT(max_wait_ms, wait)                                                         \
-    ({                                                                                        \
-        gboolean     _not_expired             = TRUE;                                         \
-        const gint64 nmtst_wait_start_us      = g_get_monotonic_time();                       \
-        const gint64 nmtst_wait_duration_us   = (max_wait_ms) *1000L;                         \
-        const gint64 nmtst_wait_end_us        = nmtst_wait_start_us + nmtst_wait_duration_us; \
-        gint64       _nmtst_wait_remaining_us = nmtst_wait_duration_us;                       \
-        int          _nmtst_wait_iteration    = 0;                                            \
-                                                                                              \
-        while (TRUE) {                                                                        \
-            _nm_unused const gint64 nmtst_wait_remaining_us = _nmtst_wait_remaining_us;       \
-            _nm_unused int          nmtst_wait_iteration    = _nmtst_wait_iteration++;        \
-                                                                                              \
-            {wait};                                                                           \
-            _nmtst_wait_remaining_us = (nmtst_wait_end_us - g_get_monotonic_time());          \
-            if (_nmtst_wait_remaining_us <= 0) {                                              \
-                _not_expired = FALSE;                                                         \
-                break;                                                                        \
-            }                                                                                 \
-        }                                                                                     \
-        _not_expired;                                                                         \
-    })
-
-#define NMTST_WAIT_ASSERT(max_wait_ms, wait)  \
-    G_STMT_START                              \
-    {                                         \
-        if (!(NMTST_WAIT(max_wait_ms, wait))) \
-            g_assert_not_reached();           \
-    }                                         \
-    G_STMT_END
-
-#define nmtst_assert_nonnull(command)          \
-    ({                                         \
-        typeof(*(command)) *_ptr = (command);  \
-                                               \
-        g_assert(_ptr && (TRUE || (command))); \
-        _ptr;                                  \
-    })
-
-#define nmtst_assert_success(success, error) \
-    G_STMT_START                             \
-    {                                        \
-        g_assert_no_error(error);            \
-        g_assert((success));                 \
-    }                                        \
-    G_STMT_END
-
-#define nmtst_assert_no_success(success, error) \
-    G_STMT_START                                \
-    {                                           \
-        g_assert(error);                        \
-        g_assert(!(success));                   \
-    }                                           \
-    G_STMT_END
-
-/*****************************************************************************/
-
-/* Our nm-error error numbers use negative values to signal failure.
- * A non-negative value signals success. Hence, the correct way for checking
- * is always (r < 0) vs. (r >= 0). Never (r == 0).
- *
- * For assertions in tests, we also want to assert that no positive values
- * are returned. For a lot of functions, positive return values are unexpected
- * and a bug. This macro evaluates @r to success or failure, while asserting
- * that @r is not positive. */
-#define NMTST_NM_ERR_SUCCESS(r)         \
-    ({                                  \
-        const int _r = (r);             \
-                                        \
-        if (_r >= 0)                    \
-            g_assert_cmpint(_r, ==, 0); \
-        (_r >= 0);                      \
-    })
-
-/*****************************************************************************/
-
-struct __nmtst_internal {
-    GRand *  rand0;
-    guint32  rand_seed;
-    GRand *  rand;
-    gboolean is_debug;
-    gboolean assert_logging;
-    gboolean no_expect_message;
-    gboolean test_quick;
-    gboolean test_tap_log;
-    char *   sudo_cmd;
-    char **  orig_argv;
-};
-
-extern struct __nmtst_internal __nmtst_internal;
-
-#define NMTST_DEFINE()                                        \
-    struct __nmtst_internal __nmtst_internal = {0};           \
-                                                              \
-    __attribute__((destructor)) static void _nmtst_exit(void) \
-    {                                                         \
-        __nmtst_internal.assert_logging = FALSE;              \
-        g_test_assert_expected_messages();                    \
-        nmtst_free();                                         \
-    }
-
-static inline gboolean
-nmtst_initialized(void)
-{
-    return !!__nmtst_internal.rand0;
-}
-
-#define __NMTST_LOG(cmd, ...)                                                                  \
-    G_STMT_START                                                                               \
-    {                                                                                          \
-        g_assert(nmtst_initialized());                                                         \
-        if (!__nmtst_internal.assert_logging || __nmtst_internal.no_expect_message) {          \
-            cmd(__VA_ARGS__);                                                                  \
-        } else {                                                                               \
-            printf(_NM_UTILS_MACRO_FIRST(__VA_ARGS__) "\n" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
-        }                                                                                      \
-    }                                                                                          \
-    G_STMT_END
-
-/* split the string inplace at specific delimiters, allowing escaping with '\\'.
- * Returns a zero terminated array of pointers into @str.
- *
- * The caller must g_free() the returned argv array.
- **/
-static inline char **
-nmtst_str_split(char *str, const char *delimiters)
-{
-    const char *d;
-    GArray *    result = g_array_sized_new(TRUE, FALSE, sizeof(char *), 3);
-
-    g_assert(str);
-    g_assert(delimiters && !strchr(delimiters, '\\'));
-
-    while (*str) {
-        gsize i = 0, j = 0;
-
-        while (TRUE) {
-            char c = str[i];
-
-            if (c == '\0') {
-                str[j++] = 0;
-                break;
-            } else if (c == '\\') {
-                str[j++] = str[++i];
-                if (!str[i])
-                    break;
-            } else {
-                for (d = delimiters; *d; d++) {
-                    if (c == *d) {
-                        str[j++] = 0;
-                        i++;
-                        goto BREAK_INNER_LOOPS;
-                    }
-                }
-                str[j++] = c;
-            }
-            i++;
-        }
-
-BREAK_INNER_LOOPS:
-        g_array_append_val(result, str);
-        str = &str[i];
-    }
-
-    return (char **) g_array_free(result, FALSE);
-}
-
-/* free instances allocated by nmtst (especially nmtst_init()) on shutdown
- * to release memory. After nmtst_free(), the test is uninitialized again. */
-static inline void
-nmtst_free(void)
-{
-    if (!nmtst_initialized())
-        return;
-
-    g_rand_free(__nmtst_internal.rand0);
-    if (__nmtst_internal.rand)
-        g_rand_free(__nmtst_internal.rand);
-    g_free(__nmtst_internal.sudo_cmd);
-    g_strfreev(__nmtst_internal.orig_argv);
-
-    memset(&__nmtst_internal, 0, sizeof(__nmtst_internal));
-}
-
-static inline void
-_nmtst_log_handler(const char *   log_domain,
-                   GLogLevelFlags log_level,
-                   const char *   message,
-                   gpointer       user_data)
-{
-    g_print("%s\n", message);
-}
-
-static inline void
-__nmtst_init(int *       argc,
-             char ***    argv,
-             gboolean    assert_logging,
-             const char *log_level,
-             const char *log_domains,
-             gboolean *  out_set_logging)
-{
-    const char *      nmtst_debug;
-    gboolean          is_debug    = FALSE;
-    char *            c_log_level = NULL, *c_log_domains = NULL;
-    char *            sudo_cmd       = NULL;
-    GArray *          debug_messages = g_array_new(TRUE, FALSE, sizeof(char *));
-    int               i;
-    gboolean          no_expect_message = FALSE;
-    gboolean          _out_set_logging;
-    gboolean          test_quick         = FALSE;
-    gboolean          test_quick_set     = FALSE;
-    gboolean          test_quick_argv    = FALSE;
-    gs_unref_ptrarray GPtrArray *p_tests = NULL;
-    gs_unref_ptrarray GPtrArray *s_tests = NULL;
-
-    if (!out_set_logging)
-        out_set_logging = &_out_set_logging;
-    *out_set_logging = FALSE;
-
-    g_assert(!nmtst_initialized());
-
-    g_assert(!((!!argc) ^ (!!argv)));
-    g_assert(!argc || (g_strv_length(*argv) == *argc));
-    g_assert(!assert_logging || (!log_level && !log_domains));
-
-#ifdef __NETWORKMANAGER_UTILS_H__
-    if (!nm_utils_get_testing_initialized())
-        _nm_utils_set_testing(_NM_UTILS_TEST_GENERAL);
-#endif
-
-    if (argc)
-        __nmtst_internal.orig_argv = g_strdupv(*argv);
-
-    __nmtst_internal.assert_logging = !!assert_logging;
-
-    nm_g_type_init();
-
-    is_debug = g_test_verbose();
-
-    nmtst_debug = g_getenv("NMTST_DEBUG");
-    if (nmtst_debug) {
-        char **d_argv, **i_argv, *nmtst_debug_copy;
-
-        /* By setting then NMTST_DEBUG variable, @is_debug is set automatically.
-         * This can be reverted with no-debug (on command line or environment variable). */
-        is_debug = TRUE;
-
-        nmtst_debug_copy = g_strdup(nmtst_debug);
-        d_argv           = nmtst_str_split(nmtst_debug_copy, ",; \t\r\n");
-
-        for (i_argv = d_argv; *i_argv; i_argv++) {
-            const char *debug = *i_argv;
-
-            if (!g_ascii_strcasecmp(debug, "debug"))
-                is_debug = TRUE;
-            else if (!g_ascii_strcasecmp(debug, "no-debug")) {
-                /* when specifying the NMTST_DEBUG variable, we set is_debug to true. Use this flag to disable this
-                 * (e.g. for only setting the log-level, but not is_debug). */
-                is_debug = FALSE;
-            } else if (!g_ascii_strncasecmp(debug, "log-level=", strlen("log-level="))) {
-                g_free(c_log_level);
-                log_level = c_log_level = g_strdup(&debug[strlen("log-level=")]);
-            } else if (!g_ascii_strcasecmp(debug, "D")) {
-                /* shorthand for "log-level=TRACE,no-expect-message" */
-                g_free(c_log_level);
-                log_level = c_log_level = g_strdup("TRACE");
-                no_expect_message       = TRUE;
-            } else if (!g_ascii_strcasecmp(debug, "TRACE")) {
-                g_free(c_log_level);
-                log_level = c_log_level = g_strdup("TRACE");
-            } else if (!g_ascii_strncasecmp(debug, "log-domains=", strlen("log-domains="))) {
-                g_free(c_log_domains);
-                log_domains = c_log_domains = g_strdup(&debug[strlen("log-domains=")]);
-            } else if (!g_ascii_strncasecmp(debug, "sudo-cmd=", strlen("sudo-cmd="))) {
-                g_free(sudo_cmd);
-                sudo_cmd = g_strdup(&debug[strlen("sudo-cmd=")]);
-            } else if (!g_ascii_strcasecmp(debug, "no-expect-message")) {
-                no_expect_message = TRUE;
-            } else if (!g_ascii_strncasecmp(debug, "p=", strlen("p="))) {
-                if (!p_tests)
-                    p_tests = g_ptr_array_new_with_free_func(g_free);
-                g_ptr_array_add(p_tests, g_strdup(&debug[strlen("p=")]));
-            } else if (!g_ascii_strncasecmp(debug, "s=", strlen("s="))) {
-                if (!s_tests)
-                    s_tests = g_ptr_array_new_with_free_func(g_free);
-                g_ptr_array_add(s_tests, g_strdup(&debug[strlen("s=")]));
-            } else if (!g_ascii_strcasecmp(debug, "slow")
-                       || !g_ascii_strcasecmp(debug, "thorough")) {
-                test_quick     = FALSE;
-                test_quick_set = TRUE;
-            } else if (!g_ascii_strcasecmp(debug, "quick")) {
-                test_quick     = TRUE;
-                test_quick_set = TRUE;
-            } else {
-                char *msg =
-                    g_strdup_printf(">>> nmtst: ignore unrecognized NMTST_DEBUG option \"%s\"",
-                                    debug);
-
-                g_array_append_val(debug_messages, msg);
-            }
-        }
-
-        g_free(d_argv);
-        g_free(nmtst_debug_copy);
-    }
-
-    if (__nmtst_internal.orig_argv) {
-        char **a = __nmtst_internal.orig_argv;
-
-        for (; *a; a++) {
-            if (!g_ascii_strcasecmp(*a, "--debug"))
-                is_debug = TRUE;
-            else if (!g_ascii_strcasecmp(*a, "--no-debug"))
-                is_debug = FALSE;
-            else if (!strcmp(*a, "-m=slow") || !strcmp(*a, "-m=thorough") || !strcmp(*a, "-m=quick")
-                     || (!strcmp(*a, "-m") && *(a + 1)
-                         && (!strcmp(*(a + 1), "quick") || !strcmp(*(a + 1), "slow")
-                             || !strcmp(*(a + 1), "thorough"))))
-                test_quick_argv = TRUE;
-            else if (strcmp(*a, "--tap") == 0)
-                __nmtst_internal.test_tap_log = TRUE;
-        }
-    }
-
-    if (!argc || g_test_initialized()) {
-        if (p_tests || s_tests) {
-            char *msg = g_strdup_printf(
-                ">>> nmtst: ignore -p and -s options for test which calls g_test_init() itself");
-
-            g_array_append_val(debug_messages, msg);
-        }
-    } else {
-        /* We're intentionally assigning a value to static variables
-         * s_tests_x and p_tests_x without using it afterwards, just
-         * so that valgrind doesn't complain about the leak. */
-        NM_PRAGMA_WARNING_DISABLE("-Wunused-but-set-variable")
-
-        /* g_test_init() is a variadic function, so we cannot pass it
-         * (variadic) arguments. If you need to pass additional parameters,
-         * call nmtst_init() with argc==NULL and call g_test_init() yourself. */
-
-        /* g_test_init() sets g_log_set_always_fatal() for G_LOG_LEVEL_WARNING
-         * and G_LOG_LEVEL_CRITICAL. So, beware that the test will fail if you
-         * have any WARN or ERR log messages -- unless you g_test_expect_message(). */
-        GPtrArray *    arg_array   = g_ptr_array_new();
-        gs_free char **arg_array_c = NULL;
-        int            arg_array_n, j;
-        static char ** s_tests_x, **p_tests_x;
-
-        if (*argc) {
-            for (i = 0; i < *argc; i++)
-                g_ptr_array_add(arg_array, (*argv)[i]);
-        } else
-            g_ptr_array_add(arg_array, "./test");
-
-        if (test_quick_set && !test_quick_argv)
-            g_ptr_array_add(arg_array, "-m=quick");
-
-        if (!__nmtst_internal.test_tap_log) {
-            for (i = 0; p_tests && i < p_tests->len; i++) {
-                g_ptr_array_add(arg_array, "-p");
-                g_ptr_array_add(arg_array, p_tests->pdata[i]);
-            }
-            for (i = 0; s_tests && i < s_tests->len; i++) {
-                g_ptr_array_add(arg_array, "-s");
-                g_ptr_array_add(arg_array, s_tests->pdata[i]);
-            }
-        } else if (p_tests || s_tests) {
-            char *msg = g_strdup_printf(">>> nmtst: ignore -p and -s options for tap-tests");
-
-            g_array_append_val(debug_messages, msg);
-        }
-
-        g_ptr_array_add(arg_array, NULL);
-
-        arg_array_n = arg_array->len - 1;
-        arg_array_c = (char **) g_ptr_array_free(arg_array, FALSE);
-
-        g_test_init(&arg_array_n, &arg_array_c, NULL);
-
-        if (*argc > 1) {
-            /* collaps argc/argv by removing the arguments detected
-             * by g_test_init(). */
-            for (i = 1, j = 1; i < *argc; i++) {
-                if ((*argv)[i] == arg_array_c[j])
-                    j++;
-                else
-                    (*argv)[i] = NULL;
-            }
-            for (i = 1, j = 1; i < *argc; i++) {
-                if ((*argv)[i]) {
-                    (*argv)[j++] = (*argv)[i];
-                    if (i >= j)
-                        (*argv)[i] = NULL;
-                }
-            }
-            *argc = j;
-        }
-
-        /* we must "leak" the test paths because they are not cloned by g_test_init(). */
-        if (!__nmtst_internal.test_tap_log) {
-            if (p_tests) {
-                p_tests_x = (char **) g_ptr_array_free(p_tests, FALSE);
-                p_tests   = NULL;
-            }
-            if (s_tests) {
-                s_tests_x = (char **) g_ptr_array_free(s_tests, FALSE);
-                s_tests   = NULL;
-            }
-        }
-
-        NM_PRAGMA_WARNING_REENABLE
-    }
-
-    if (test_quick_set)
-        __nmtst_internal.test_quick = test_quick;
-    else if (test_quick_argv)
-        __nmtst_internal.test_quick = g_test_quick();
-    else {
-#ifdef NMTST_TEST_QUICK
-        __nmtst_internal.test_quick = NMTST_TEST_QUICK;
-#else
-        __nmtst_internal.test_quick = FALSE;
-#endif
-    }
-
-    __nmtst_internal.is_debug          = is_debug;
-    __nmtst_internal.rand0             = g_rand_new_with_seed(0);
-    __nmtst_internal.sudo_cmd          = sudo_cmd;
-    __nmtst_internal.no_expect_message = no_expect_message;
-
-    if (!log_level && log_domains) {
-        /* if the log level is not specified (but the domain is), we assume
-         * the caller wants to set it depending on is_debug */
-        log_level = is_debug ? "DEBUG" : "WARN";
-    }
-
-    if (!__nmtst_internal.assert_logging) {
-        gboolean success = TRUE;
-#ifdef _NMTST_INSIDE_CORE
-        success          = nm_logging_setup(log_level, log_domains, NULL, NULL);
-        *out_set_logging = TRUE;
-#endif
-        g_assert(success);
-#if GLIB_CHECK_VERSION(2, 34, 0)
-        if (__nmtst_internal.no_expect_message)
-            g_log_set_always_fatal(G_LOG_FATAL_MASK);
-#else
-        /* g_test_expect_message() is a NOP, so allow any messages */
-        g_log_set_always_fatal(G_LOG_FATAL_MASK);
-#endif
-    } else if (__nmtst_internal.no_expect_message) {
-        /* We have a test that would be assert_logging, but the user specified no_expect_message.
-         * This transforms g_test_expect_message() into a NOP, but we also have to relax
-         * g_log_set_always_fatal(), which was set by g_test_init(). */
-        g_log_set_always_fatal(G_LOG_FATAL_MASK);
-#ifdef _NMTST_INSIDE_CORE
-        if (c_log_domains || c_log_level) {
-            /* Normally, tests with assert_logging do not overwrite the logging level/domains because
-             * the logging statements are part of the assertions. But if the test is run with
-             * no-expect-message *and* the logging is set explicitly via environment variables,
-             * we still reset the logging. */
-            gboolean success;
-
-            success          = nm_logging_setup(log_level, log_domains, NULL, NULL);
-            *out_set_logging = TRUE;
-            g_assert(success);
-        }
-#endif
-    } else {
-#if GLIB_CHECK_VERSION(2, 34, 0)
-        /* We were called not to set logging levels. This means, that the user
-         * expects to assert against (all) messages.
-         * Any uncaught message on >debug level is fatal. */
-        g_log_set_always_fatal(G_LOG_LEVEL_MASK & ~G_LOG_LEVEL_DEBUG);
-#else
-        /* g_test_expect_message() is a NOP, so allow any messages */
-        g_log_set_always_fatal(G_LOG_FATAL_MASK);
-#endif
-    }
-
-    if ((!__nmtst_internal.assert_logging
-         || (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message))
-        && (is_debug
-            || (c_log_level
-                && (!g_ascii_strcasecmp(c_log_level, "DEBUG")
-                    || !g_ascii_strcasecmp(c_log_level, "TRACE"))))
-        && !g_getenv("G_MESSAGES_DEBUG")) {
-        /* if we are @is_debug or @log_level=="DEBUG" and
-         * G_MESSAGES_DEBUG is unset, we set G_MESSAGES_DEBUG=all.
-         * To disable this default behaviour, set G_MESSAGES_DEBUG='' */
-
-        /* Note that g_setenv is not thread safe, but you should anyway call
-         * nmtst_init() at the very start. */
-        g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
-    }
-
-    /* "tc" is in /sbin, which might not be in $PATH of a regular user. Unconditionally
-     * add "/bin" and "/sbin" to $PATH for all tests. */
-    {
-        static char *path_new;
-        const char * path_old;
-
-        g_assert(!path_new);
-
-        path_old = g_getenv("PATH");
-        path_new = g_strjoin("",
-                             path_old ?: "",
-                             (nm_str_is_empty(path_old) ? "" : ":"),
-                             "/bin:/sbin",
-                             NULL);
-        g_setenv("PATH", path_new, TRUE);
-    }
-
-    /* Delay messages until we setup logging. */
-    for (i = 0; i < debug_messages->len; i++)
-        __NMTST_LOG(g_message, "%s", g_array_index(debug_messages, const char *, i));
-
-    g_strfreev((char **) g_array_free(debug_messages, FALSE));
-    g_free(c_log_level);
-    g_free(c_log_domains);
-
-#ifdef __NETWORKMANAGER_UTILS_H__
-    /* ensure that monotonic timestamp is called (because it initially logs a line) */
-    nm_utils_get_monotonic_timestamp_sec();
-#endif
-
-#ifdef NM_UTILS_H
-    {
-        gs_free_error GError *error = NULL;
-
-        if (!nm_utils_init(&error))
-            g_assert_not_reached();
-        g_assert_no_error(error);
-    }
-#endif
-
-    g_log_set_handler(G_LOG_DOMAIN,
-                      G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
-                      _nmtst_log_handler,
-                      NULL);
-}
-
-#ifndef _NMTST_INSIDE_CORE
-static inline void
-nmtst_init(int *argc, char ***argv, gboolean assert_logging)
-{
-    __nmtst_init(argc, argv, assert_logging, NULL, NULL, NULL);
-}
-#endif
-
-static inline gboolean
-nmtst_is_debug(void)
-{
-    g_assert(nmtst_initialized());
-    return __nmtst_internal.is_debug;
-}
-
-static inline gboolean
-nmtst_test_quick(void)
-{
-    g_assert(nmtst_initialized());
-    return __nmtst_internal.test_quick;
-}
-
-#if GLIB_CHECK_VERSION(2, 34, 0)
-    #undef g_test_expect_message
-    #define g_test_expect_message(...)                                                   \
-        G_STMT_START                                                                     \
-        {                                                                                \
-            g_assert(nmtst_initialized());                                               \
-            if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message) { \
-                g_debug("nmtst: assert-logging: g_test_expect_message %s",               \
-                        G_STRINGIFY((__VA_ARGS__)));                                     \
-            } else {                                                                     \
-                G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                         \
-                g_test_expect_message(__VA_ARGS__);                                      \
-                G_GNUC_END_IGNORE_DEPRECATIONS                                           \
-            }                                                                            \
-        }                                                                                \
-        G_STMT_END
-    #undef g_test_assert_expected_messages_internal
-    #define g_test_assert_expected_messages_internal(domain, file, line, func)                   \
-        G_STMT_START                                                                             \
-        {                                                                                        \
-            const char *_domain = (domain);                                                      \
-            const char *_file   = (file);                                                        \
-            const char *_func   = (func);                                                        \
-            int         _line   = (line);                                                        \
-                                                                                                 \
-            if (__nmtst_internal.assert_logging && __nmtst_internal.no_expect_message)           \
-                g_debug("nmtst: assert-logging: g_test_assert_expected_messages(%s, %s:%d, %s)", \
-                        _domain ?: "",                                                           \
-                        _file ?: "",                                                             \
-                        _line,                                                                   \
-                        _func ?: "");                                                            \
-                                                                                                 \
-            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                                                     \
-            g_test_assert_expected_messages_internal(_domain, _file, _line, _func);              \
-            G_GNUC_END_IGNORE_DEPRECATIONS                                                       \
-        }                                                                                        \
-        G_STMT_END
-#endif
-
-#define NMTST_EXPECT(domain, level, msg) g_test_expect_message(domain, level, msg)
-
-#define NMTST_EXPECT_LIBNM(level, msg) NMTST_EXPECT("libnm", level, msg)
-
-#define NMTST_EXPECT_LIBNM_WARNING(msg)  NMTST_EXPECT_LIBNM(G_LOG_LEVEL_WARNING, msg)
-#define NMTST_EXPECT_LIBNM_CRITICAL(msg) NMTST_EXPECT_LIBNM(G_LOG_LEVEL_CRITICAL, msg)
-
-/*****************************************************************************/
-
-typedef struct _NmtstTestData NmtstTestData;
-
-typedef void (*NmtstTestHandler)(const NmtstTestData *test_data);
-
-struct _NmtstTestData {
-    union {
-        const char *testpath;
-        char *      _testpath;
-    };
-    gsize            n_args;
-    gpointer *       args;
-    NmtstTestHandler _func_setup;
-    GTestDataFunc    _func_test;
-    NmtstTestHandler _func_teardown;
-};
-
-static inline void
-_nmtst_test_data_unpack(const NmtstTestData *test_data, gsize n_args, ...)
-{
-    gsize     i;
-    va_list   ap;
-    gpointer *p;
-
-    g_assert(test_data);
-    g_assert_cmpint(n_args, ==, test_data->n_args);
-
-    va_start(ap, n_args);
-    for (i = 0; i < n_args; i++) {
-        p = va_arg(ap, gpointer *);
-
-        if (p)
-            *p = test_data->args[i];
-    }
-    va_end(ap);
-}
-#define nmtst_test_data_unpack(test_data, ...) \
-    _nmtst_test_data_unpack(test_data, NM_NARG(__VA_ARGS__), ##__VA_ARGS__)
-
-static inline void
-_nmtst_test_data_free(gpointer data)
-{
-    NmtstTestData *test_data = data;
-
-    g_assert(test_data);
-
-    g_free(test_data->_testpath);
-    g_free(test_data);
-}
-
-static inline void
-_nmtst_test_run(gconstpointer data)
-{
-    const NmtstTestData *test_data = data;
-
-    if (test_data->_func_setup)
-        test_data->_func_setup(test_data);
-
-    test_data->_func_test(test_data);
-
-    if (test_data->_func_teardown)
-        test_data->_func_teardown(test_data);
-}
-
-static inline void
-_nmtst_add_test_func_full(const char *     testpath,
-                          GTestDataFunc    func_test,
-                          NmtstTestHandler func_setup,
-                          NmtstTestHandler func_teardown,
-                          gsize            n_args,
-                          ...)
-{
-    gsize          i;
-    NmtstTestData *data;
-    va_list        ap;
-
-    g_assert(testpath && testpath[0]);
-    g_assert(func_test);
-
-    data = g_malloc0(sizeof(NmtstTestData) + (sizeof(gpointer) * (n_args + 1)));
-
-    data->_testpath      = g_strdup(testpath);
-    data->_func_test     = func_test;
-    data->_func_setup    = func_setup;
-    data->_func_teardown = func_teardown;
-    data->n_args         = n_args;
-    data->args           = (gpointer) &data[1];
-    va_start(ap, n_args);
-    for (i = 0; i < n_args; i++)
-        data->args[i] = va_arg(ap, gpointer);
-    data->args[i] = NULL;
-    va_end(ap);
-
-    g_test_add_data_func_full(testpath, data, _nmtst_test_run, _nmtst_test_data_free);
-}
-#define nmtst_add_test_func_full(testpath, func_test, func_setup, func_teardown, ...) \
-    _nmtst_add_test_func_full(testpath,                                               \
-                              func_test,                                              \
-                              func_setup,                                             \
-                              func_teardown,                                          \
-                              NM_NARG(__VA_ARGS__),                                   \
-                              ##__VA_ARGS__)
-#define nmtst_add_test_func(testpath, func_test, ...) \
-    nmtst_add_test_func_full(testpath, func_test, NULL, NULL, ##__VA_ARGS__)
-
-/*****************************************************************************/
-
-static inline GRand *
-nmtst_get_rand0(void)
-{
-    g_assert(nmtst_initialized());
-    return __nmtst_internal.rand0;
-}
-
-static inline GRand *
-nmtst_get_rand(void)
-{
-    g_assert(nmtst_initialized());
-
-    if (G_UNLIKELY(!__nmtst_internal.rand)) {
-        guint32     seed;
-        const char *str = g_getenv("NMTST_SEED_RAND");
-
-        if (!str) {
-            /* No NMTST_SEED_RAND. Pick a stable one. */
-            seed                  = 0;
-            __nmtst_internal.rand = g_rand_new_with_seed(seed);
-        } else if (str[0] == '\0') {
-            /* NMTST_SEED_RAND is set but empty. Pick a random one. */
-            __nmtst_internal.rand = g_rand_new();
-
-            seed = g_rand_int(__nmtst_internal.rand);
-            g_rand_set_seed(__nmtst_internal.rand, seed);
-        } else {
-            /* NMTST_SEED_RAND is set. Use it as a seed. */
-            char * s;
-            gint64 i;
-
-            i = g_ascii_strtoll(str, &s, 0);
-            g_assert(s[0] == '\0' && i >= 0 && i < G_MAXUINT32);
-
-            seed                  = i;
-            __nmtst_internal.rand = g_rand_new_with_seed(seed);
-        }
-        __nmtst_internal.rand_seed = seed;
-
-        g_print("\nnmtst: initialize nmtst_get_rand() with NMTST_SEED_RAND=%u\n", seed);
-    }
-    return __nmtst_internal.rand;
-}
-
-static inline guint32
-nmtst_get_rand_uint32(void)
-{
-    return g_rand_int(nmtst_get_rand());
-}
-
-static inline guint64
-nmtst_get_rand_uint64(void)
-{
-    GRand *rand = nmtst_get_rand();
-
-    return (((guint64) g_rand_int(rand))) | (((guint64) g_rand_int(rand)) << 32);
-}
-
-static inline guint
-nmtst_get_rand_uint(void)
-{
-    G_STATIC_ASSERT_EXPR((sizeof(guint) == sizeof(guint32) || (sizeof(guint) == sizeof(guint64))));
-    if (sizeof(guint32) == sizeof(guint))
-        return nmtst_get_rand_uint32();
-    return nmtst_get_rand_uint64();
-}
-
-static inline gsize
-nmtst_get_rand_size(void)
-{
-    G_STATIC_ASSERT_EXPR((sizeof(gsize) == sizeof(guint32) || (sizeof(gsize) == sizeof(guint64))));
-    if (sizeof(gsize) == sizeof(guint32))
-        return nmtst_get_rand_uint32();
-    return nmtst_get_rand_uint64();
-}
-
-static inline gboolean
-nmtst_get_rand_bool(void)
-{
-    return nmtst_get_rand_uint32() % 2;
-}
-
-static inline gboolean
-nmtst_get_rand_one_case_in(guint32 num)
-{
-    /* num=1 doesn't make much sense, because it will always return %TRUE.
-     * Still accept it, it might be that @num is calculated, so 1 might be
-     * a valid edge case. */
-    g_assert(num > 0);
-
-    return (nmtst_get_rand_uint32() % num) == 0;
-}
-
-static inline gpointer
-nmtst_rand_buf(GRand *rand, gpointer buffer, gsize buffer_length)
-{
-    guint32 v;
-    guint8 *b = buffer;
-
-    if (!buffer_length)
-        return buffer;
-
-    g_assert(buffer);
-
-    if (!rand)
-        rand = nmtst_get_rand();
-
-    for (; buffer_length >= sizeof(guint32);
-         buffer_length -= sizeof(guint32), b += sizeof(guint32)) {
-        v = g_rand_int(rand);
-        memcpy(b, &v, sizeof(guint32));
-    }
-    if (buffer_length > 0) {
-        v = g_rand_int(rand);
-        do {
-            *(b++) = v & 0xFF;
-            v >>= 8;
-        } while (--buffer_length > 0);
-    }
-    return buffer;
-}
-
-#define _nmtst_rand_select(uniq, v0, ...)                                                     \
-    ({                                                                                        \
-        typeof(v0) NM_UNIQ_T(UNIQ, uniq)[1 + NM_NARG(__VA_ARGS__)] = {(v0), __VA_ARGS__};     \
-                                                                                              \
-        NM_UNIQ_T(UNIQ, uniq)[nmtst_get_rand_uint32() % G_N_ELEMENTS(NM_UNIQ_T(UNIQ, uniq))]; \
-    })
-
-#define nmtst_rand_select(...) _nmtst_rand_select(NM_UNIQ, __VA_ARGS__)
-
-static inline void *
-nmtst_rand_perm(GRand *rand, void *dst, const void *src, gsize elmt_size, gsize n_elmt)
-{
-    gsize i, j;
-    char *p_, *pj;
-    char *bu;
-
-    g_assert(dst);
-    g_assert(elmt_size > 0);
-    g_assert(n_elmt < G_MAXINT32);
-
-    if (n_elmt == 0)
-        return dst;
-
-    if (src && dst != src)
-        memcpy(dst, src, elmt_size * n_elmt);
-
-    if (!rand)
-        rand = nmtst_get_rand();
-
-    bu = g_slice_alloc(elmt_size);
-
-    p_ = dst;
-    for (i = n_elmt; i > 1; i--) {
-        j = g_rand_int_range(rand, 0, i);
-
-        if (j != 0) {
-            pj = &p_[j * elmt_size];
-
-            /* swap */
-            memcpy(bu, p_, elmt_size);
-            memcpy(p_, pj, elmt_size);
-            memcpy(pj, bu, elmt_size);
-        }
-        p_ += elmt_size;
-    }
-
-    g_slice_free1(elmt_size, bu);
-    return dst;
-}
-
-static inline const char **
-nmtst_rand_perm_strv(const char *const *strv)
-{
-    const char **res;
-    gsize        n;
-
-    if (!strv)
-        return NULL;
-
-    /* this returns a (scrambled) SHALLOW copy of the strv array! */
-
-    n   = NM_PTRARRAY_LEN(strv);
-    res = (const char **) (nm_utils_strv_dup(strv, n, FALSE) ?: g_new0(char *, 1));
-    nmtst_rand_perm(NULL, res, res, sizeof(char *), n);
-    return res;
-}
-
-static inline GSList *
-nmtst_rand_perm_gslist(GRand *rand, GSList *list)
-{
-    GSList *result;
-    guint   l;
-
-    if (!rand)
-        rand = nmtst_get_rand();
-
-    /* no need for an efficient implementation :) */
-
-    result = 0;
-    for (l = g_slist_length(list); l > 0; l--) {
-        GSList *tmp;
-
-        tmp = g_slist_nth(list, g_rand_int(rand) % l);
-        g_assert(tmp);
-
-        list   = g_slist_remove_link(list, tmp);
-        result = g_slist_concat(tmp, result);
-    }
-    g_assert(!list);
-    return result;
-}
-
-static inline void
-nmtst_stable_rand(guint64 seed, gpointer buf, gsize len)
-{
-    const guint64 C = 1442695040888963407llu;
-    const guint64 A = 6364136223846793005llu;
-    guint8 *      b;
-    union {
-        guint8  a[sizeof(guint64)];
-        guint64 n;
-    } n;
-
-    /* We want a stable random generator that is in our control and does not
-     * depend on glibc/glib versions.
-     * Use a linear congruential generator (x[n+1] = (A * x[n] + C) % M)
-     * https://en.wikipedia.org/wiki/Linear_congruential_generator
-     *
-     * We choose (Knuth’s LCG MMIX)
-     *   A = 6364136223846793005llu
-     *   C = 1442695040888963407llu
-     *   M = 2^64
-     */
-
-    g_assert(len == 0 || buf);
-
-    n.n = seed;
-    b   = buf;
-    for (; len > 0; len--, b++) {
-        n.n = (A * n.n + C);
-
-        /* let's combine the 64 bits randomness in one byte. By xor-ing, it's
-         * also independent of endianness. */
-        b[0] = n.a[0] ^ n.a[1] ^ n.a[2] ^ n.a[3] ^ n.a[4] ^ n.a[5] ^ n.a[6] ^ n.a[7];
-    }
-}
-
-/*****************************************************************************/
-
-/**
- * nmtst_get_rand_word_length:
- * @rand: (allow-none): #GRand instance or %NULL to use the singleton.
- *
- * Returns: a random integer >= 0, that most frequently is somewhere between
- * 0 and 16, but (with decreasing) probability, it can be larger. This can
- * be used when we generate random input for unit tests.
- */
-static inline guint
-nmtst_get_rand_word_length(GRand *rand)
-{
-    guint n;
-
-    if (!rand)
-        rand = nmtst_get_rand();
-
-    n = 0;
-    while (TRUE) {
-        guint32 rnd = g_rand_int(rand);
-        guint   probability;
-
-        /* The following python code implements a random sample with this
-         * distribution:
-         *
-         *    def random_histogram(n_tries, scale = None):
-         *        def probability(n_tok):
-         *            import math
-         *            return max(2, math.floor(100 / (2*(n_tok+1))))
-         *        def n_tokens():
-         *            import random
-         *            n_tok = 0
-         *            while True:
-         *                if random.randint(0, 0xFFFFFFFF) % probability(n_tok) == 0:
-         *                   return n_tok
-         *                n_tok += 1
-         *        hist = []
-         *        i = 0;
-         *        while i < n_tries:
-         *            n_tok = n_tokens()
-         *            while n_tok >= len(hist):
-         *                hist.append(0)
-         *            hist[n_tok] = hist[n_tok] + 1
-         *            i += 1
-         *        if scale is not None:
-         *            hist = list([round(x / n_tries * scale) for x in hist])
-         *        return hist
-         *
-         * For example, random_histogram(n_tries = 1000000, scale = 1000) may give
-         *
-         *   IDX:  [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
-         *   SEEN: [20, 39, 59, 73, 80, 91, 92, 90, 91, 73, 73, 54, 55, 36, 24, 16, 16,  8,  4,  2,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0]
-         *
-         * which give a sense of the probability with this individual results are returned.
-         */
-        probability = NM_MAX(2u, (100u / (2u * (n + 1u))));
-        if ((rnd % probability) == 0)
-            return n;
-        n++;
-    }
-}
-
-/*****************************************************************************/
-
-static inline gboolean
-nmtst_g_source_assert_not_called(gpointer user_data)
-{
-    g_assert_not_reached();
-    return G_SOURCE_CONTINUE;
-}
-
-static inline gboolean
-nmtst_g_source_nop(gpointer user_data)
-{
-    g_assert(!user_data);
-    return G_SOURCE_CONTINUE;
-}
-
-static inline gboolean
-nmtst_g_source_set_boolean_true(gpointer user_data)
-{
-    gboolean *ptr = user_data;
-
-    g_assert(ptr);
-    g_assert(!*ptr);
-    *ptr = TRUE;
-    return G_SOURCE_CONTINUE;
-}
-
-/*****************************************************************************/
-
-static inline gboolean
-_nmtst_main_loop_run_timeout(gpointer user_data)
-{
-    GMainLoop **p_loop = user_data;
-
-    g_assert(p_loop && *p_loop);
-    g_main_loop_quit(g_steal_pointer(p_loop));
-    return G_SOURCE_REMOVE;
-}
-
-static inline gboolean
-nmtst_main_loop_run(GMainLoop *loop, guint timeout_msec)
-{
-    nm_auto_unref_gsource GSource *source = NULL;
-    GMainLoop *                    loopx  = loop;
-
-    if (timeout_msec > 0) {
-        source = g_timeout_source_new(timeout_msec);
-        g_source_set_callback(source, _nmtst_main_loop_run_timeout, &loopx, NULL);
-        g_source_attach(source, g_main_loop_get_context(loop));
-    }
-
-    g_main_loop_run(loop);
-
-    if (source)
-        g_source_destroy(source);
-
-    /* if the timeout was reached, return FALSE. */
-    return loopx != NULL;
-}
-
-#define nmtst_main_loop_run_assert(loop, timeout_msec)    \
-    G_STMT_START                                          \
-    {                                                     \
-        if (!nmtst_main_loop_run((loop), (timeout_msec))) \
-            g_assert_not_reached();                       \
-    }                                                     \
-    G_STMT_END
-
-static inline void
-_nmtst_main_loop_quit_on_notify(GObject *object, GParamSpec *pspec, gpointer user_data)
-{
-    GMainLoop *loop = user_data;
-
-    g_assert(G_IS_OBJECT(object));
-    g_assert(loop);
-
-    g_main_loop_quit(loop);
-}
-#define nmtst_main_loop_quit_on_notify ((GCallback) _nmtst_main_loop_quit_on_notify)
-
-#define nmtst_main_context_iterate_until_full(context, timeout_msec, poll_msec, condition)      \
-    ({                                                                                          \
-        nm_auto_destroy_and_unref_gsource GSource *_source_timeout = NULL;                      \
-        nm_auto_destroy_and_unref_gsource GSource *_source_poll    = NULL;                      \
-        GMainContext *                             _context        = (context);                 \
-        gboolean                                   _had_timeout    = FALSE;                     \
-        typeof(timeout_msec) _timeout_msec0                        = (timeout_msec);            \
-        typeof(poll_msec) _poll_msec0                              = (poll_msec);               \
-        gint64 _timeout_msec                                       = _timeout_msec0;            \
-        guint  _poll_msec                                          = _poll_msec0;               \
-                                                                                                \
-        g_assert_cmpint(_timeout_msec0, ==, _timeout_msec);                                     \
-        g_assert_cmpint(_poll_msec0, ==, _poll_msec);                                           \
-                                                                                                \
-        _source_timeout = g_timeout_source_new(NM_CLAMP(_timeout_msec, 0, (gint64) G_MAXUINT)); \
-        g_source_set_callback(_source_timeout,                                                  \
-                              nmtst_g_source_set_boolean_true,                                  \
-                              &_had_timeout,                                                    \
-                              NULL);                                                            \
-        g_source_attach(_source_timeout, _context);                                             \
-                                                                                                \
-        if (_poll_msec > 0) {                                                                   \
-            _source_poll = g_timeout_source_new(_poll_msec);                                    \
-            g_source_set_callback(_source_poll, nmtst_g_source_nop, NULL, NULL);                \
-            g_source_attach(_source_poll, _context);                                            \
-        }                                                                                       \
-                                                                                                \
-        while (TRUE) {                                                                          \
-            if (condition)                                                                      \
-                break;                                                                          \
-            g_main_context_iteration(_context, TRUE);                                           \
-            if (_had_timeout)                                                                   \
-                break;                                                                          \
-        }                                                                                       \
-                                                                                                \
-        !_had_timeout;                                                                          \
-    })
-
-#define nmtst_main_context_iterate_until(context, timeout_msec, condition) \
-    nmtst_main_context_iterate_until_full((context), (timeout_msec), 0, condition)
-
-#define nmtst_main_context_iterate_until_assert_full(context, timeout_msec, poll_msec, condition) \
-    G_STMT_START                                                                                  \
-    {                                                                                             \
-        if (!nmtst_main_context_iterate_until_full((context),                                     \
-                                                   (timeout_msec),                                \
-                                                   (poll_msec),                                   \
-                                                   condition))                                    \
-            g_assert(FALSE &&#condition);                                                         \
-    }                                                                                             \
-    G_STMT_END
-
-#define nmtst_main_context_iterate_until_assert(context, timeout_msec, condition) \
-    nmtst_main_context_iterate_until_assert_full((context), (timeout_msec), 0, condition)
-
-/*****************************************************************************/
-
-static inline void
-nmtst_main_context_assert_no_dispatch(GMainContext *context, guint timeout_msec)
-{
-    nm_auto_destroy_and_unref_gsource GSource *source      = NULL;
-    gboolean                                   timeout_hit = FALSE;
-
-    source = g_timeout_source_new(timeout_msec);
-    g_source_set_callback(source, nmtst_g_source_set_boolean_true, &timeout_hit, NULL);
-    g_source_attach(source, context);
-
-    while (g_main_context_iteration(context, TRUE)) {
-        if (timeout_hit)
-            return;
-        g_assert_not_reached();
-    }
-}
-
-/*****************************************************************************/
-
-typedef struct {
-    GMainLoop *_main_loop;
-    union {
-        GSList *          _list;
-        const void *const is_waiting;
-    };
-} NMTstContextBusyWatcherData;
-
-static inline void
-_nmtst_context_busy_watcher_add_cb(gpointer data, GObject *where_the_object_was)
-{
-    NMTstContextBusyWatcherData *watcher_data = data;
-    GSList *                     l;
-
-    g_assert(watcher_data);
-
-    l = g_slist_find(watcher_data->_list, where_the_object_was);
-    g_assert(l);
-
-    watcher_data->_list = g_slist_delete_link(watcher_data->_list, l);
-    if (!watcher_data->_list)
-        g_main_loop_quit(watcher_data->_main_loop);
-}
-
-static inline void
-nmtst_context_busy_watcher_add(NMTstContextBusyWatcherData *watcher_data, GObject *object)
-{
-    g_assert(watcher_data);
-    g_assert(G_IS_OBJECT(object));
-
-    if (!watcher_data->_main_loop) {
-        watcher_data->_main_loop = g_main_loop_new(g_main_context_get_thread_default(), FALSE);
-        g_assert(!watcher_data->_list);
-    } else {
-        g_assert(g_main_loop_get_context(watcher_data->_main_loop)
-                 == (g_main_context_get_thread_default() ?: g_main_context_default()));
-    }
-
-    g_object_weak_ref(object, _nmtst_context_busy_watcher_add_cb, watcher_data);
-    watcher_data->_list = g_slist_prepend(watcher_data->_list, object);
-}
-
-static inline void
-nmtst_context_busy_watcher_wait(NMTstContextBusyWatcherData *watcher_data)
-{
-    g_assert(watcher_data);
-
-    if (!watcher_data->_main_loop) {
-        g_assert(!watcher_data->_list);
-        return;
-    }
-
-    if (watcher_data->_list) {
-        if (!nmtst_main_loop_run(watcher_data->_main_loop, 5000))
-            g_error("timeout running mainloop waiting for GObject to destruct");
-    }
-
-    g_assert(!watcher_data->_list);
-    nm_clear_pointer(&watcher_data->_main_loop, g_main_loop_unref);
-}
-
-/*****************************************************************************/
-
-static inline const char *
-nmtst_get_sudo_cmd(void)
-{
-    g_assert(nmtst_initialized());
-    return __nmtst_internal.sudo_cmd;
-}
-
-static inline void
-nmtst_reexec_sudo(void)
-{
-    char * str;
-    char **argv;
-    int    i;
-    int    errsv;
-
-    g_assert(nmtst_initialized());
-    g_assert(__nmtst_internal.orig_argv);
-
-    if (!__nmtst_internal.sudo_cmd)
-        return;
-
-    str = g_strjoinv(" ", __nmtst_internal.orig_argv);
-    __NMTST_LOG(g_message, ">> exec %s %s", __nmtst_internal.sudo_cmd, str);
-
-    argv    = g_new0(char *, 1 + g_strv_length(__nmtst_internal.orig_argv) + 1);
-    argv[0] = __nmtst_internal.sudo_cmd;
-    for (i = 0; __nmtst_internal.orig_argv[i]; i++)
-        argv[i + 1] = __nmtst_internal.orig_argv[i];
-
-    execvp(__nmtst_internal.sudo_cmd, argv);
-
-    errsv = errno;
-    g_error(">> exec %s failed: %d - %s",
-            __nmtst_internal.sudo_cmd,
-            errsv,
-            nm_strerror_native(errsv));
-}
-
-/*****************************************************************************/
-
-static inline gsize
-nmtst_find_all_indexes(gpointer *elements,
-                       gsize     n_elements,
-                       gpointer *needles,
-                       gsize     n_needles,
-                       gboolean (*equal_fcn)(gpointer element, gpointer needle, gpointer user_data),
-                       gpointer user_data,
-                       gssize * out_idx)
-{
-    gsize i, j, k;
-    gsize found = 0;
-
-    for (i = 0; i < n_needles; i++) {
-        gssize idx = -1;
-
-        for (j = 0; j < n_elements; j++) {
-            /* no duplicates */
-            for (k = 0; k < i; k++) {
-                if (out_idx[k] == j)
-                    goto next;
-            }
-
-            if (equal_fcn(elements[j], needles[i], user_data)) {
-                idx = j;
-                break;
-            }
-next:;
-        }
-
-        out_idx[i] = idx;
-        if (idx >= 0)
-            found++;
-    }
-
-    return found;
-}
-
-/*****************************************************************************/
-
-#define __define_nmtst_static(NUM, SIZE)                                   \
-    static inline const char *nmtst_static_##SIZE##_##NUM(const char *str) \
-    {                                                                      \
-        gsize                        l;                                    \
-        static _nm_thread_local char buf[SIZE];                            \
-                                                                           \
-        if (!str)                                                          \
-            return NULL;                                                   \
-        l = g_strlcpy(buf, str, sizeof(buf));                              \
-        g_assert(l < sizeof(buf));                                         \
-        return buf;                                                        \
-    }
-__define_nmtst_static(01, 1024) __define_nmtst_static(02, 1024) __define_nmtst_static(03, 1024)
-#undef __define_nmtst_static
-
-#if defined(__NM_UTILS_H__) || defined(NM_UTILS_H)
-
-    #define NMTST_UUID_INIT(uuid)                                          \
-        gs_free char *    _nmtst_hidden_##uuid = nm_utils_uuid_generate(); \
-        const char *const uuid                 = _nmtst_hidden_##uuid
-
-    static inline const char *nmtst_uuid_generate(void)
-{
-    static _nm_thread_local char u[37];
-    gs_free char *               m = NULL;
-
-    m = nm_utils_uuid_generate();
-    g_assert(m && strlen(m) == sizeof(u) - 1);
-    memcpy(u, m, sizeof(u));
-    return u;
-}
-
-#endif
-
-#define nmtst_assert_str_has_substr(str, substr)                                                  \
-    G_STMT_START                                                                                  \
-    {                                                                                             \
-        const char *__str    = (str);                                                             \
-        const char *__substr = (substr);                                                          \
-                                                                                                  \
-        g_assert(__str);                                                                          \
-        g_assert(__substr);                                                                       \
-        if (strstr(__str, __substr) == NULL)                                                      \
-            g_error("%s:%d: Expects \"%s\" but got \"%s\"", __FILE__, __LINE__, __substr, __str); \
-    }                                                                                             \
-    G_STMT_END
-
-static inline in_addr_t
-nmtst_inet4_from_string(const char *str)
-{
-    in_addr_t addr;
-    int       success;
-
-    if (!str)
-        return 0;
-
-    success = inet_pton(AF_INET, str, &addr);
-
-    g_assert(success == 1);
-
-    return addr;
-}
-
-static inline const struct in6_addr *
-nmtst_inet6_from_string(const char *str)
-{
-    static _nm_thread_local struct in6_addr addr;
-    int                                     success;
-
-    if (!str)
-        addr = in6addr_any;
-    else {
-        success = inet_pton(AF_INET6, str, &addr);
-        g_assert(success == 1);
-    }
-
-    return &addr;
-}
-
-static inline gconstpointer
-nmtst_inet_from_string(int addr_family, const char *str)
-{
-    if (addr_family == AF_INET) {
-        static in_addr_t a;
-
-        a = nmtst_inet4_from_string(str);
-        return &a;
-    }
-    if (addr_family == AF_INET6)
-        return nmtst_inet6_from_string(str);
-
-    g_assert_not_reached();
-    return NULL;
-}
-
-static inline const char *
-nmtst_inet_to_string(int addr_family, gconstpointer addr)
-{
-    static _nm_thread_local char buf[NM_CONST_MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
-
-    g_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6));
-    g_assert(addr);
-
-    if (inet_ntop(addr_family, addr, buf, sizeof(buf)) != buf)
-        g_assert_not_reached();
-
-    return buf;
-}
-
-static inline const char *
-nmtst_inet4_to_string(in_addr_t addr)
-{
-    return nmtst_inet_to_string(AF_INET, &addr);
-}
-
-static inline const char *
-nmtst_inet6_to_string(const struct in6_addr *addr)
-{
-    return nmtst_inet_to_string(AF_INET6, addr);
-}
-
-static inline void
-_nmtst_assert_ip4_address(const char *file, int line, in_addr_t addr, const char *str_expected)
-{
-    if (nmtst_inet4_from_string(str_expected) != addr) {
-        char buf[100];
-
-        g_error("%s:%d: Unexpected IPv4 address: expected %s, got %s",
-                file,
-                line,
-                str_expected ?: "0.0.0.0",
-                inet_ntop(AF_INET, &addr, buf, sizeof(buf)));
-    }
-}
-#define nmtst_assert_ip4_address(addr, str_expected) \
-    _nmtst_assert_ip4_address(__FILE__, __LINE__, addr, str_expected)
-
-static inline void
-_nmtst_assert_ip6_address(const char *           file,
-                          int                    line,
-                          const struct in6_addr *addr,
-                          const char *           str_expected)
-{
-    struct in6_addr any = in6addr_any;
-
-    if (!addr)
-        addr = &any;
-
-    if (memcmp(nmtst_inet6_from_string(str_expected), addr, sizeof(*addr)) != 0) {
-        char buf[100];
-
-        g_error("%s:%d: Unexpected IPv6 address: expected %s, got %s",
-                file,
-                line,
-                str_expected ?: "::",
-                inet_ntop(AF_INET6, addr, buf, sizeof(buf)));
-    }
-}
-#define nmtst_assert_ip6_address(addr, str_expected) \
-    _nmtst_assert_ip6_address(__FILE__, __LINE__, addr, str_expected)
-
-#define nmtst_assert_ip_address(addr_family, addr, str_expected)                        \
-    G_STMT_START                                                                        \
-    {                                                                                   \
-        if (NM_IS_IPv4(addr_family))                                                    \
-            nmtst_assert_ip4_address(*((const in_addr_t *) (addr)), (str_expected));    \
-        else                                                                            \
-            nmtst_assert_ip6_address((const struct in6_addr *) (addr), (str_expected)); \
-    }                                                                                   \
-    G_STMT_END
-
-#define nmtst_spawn_sync(working_directory, standard_out, standard_err, assert_exit_status, ...) \
-    __nmtst_spawn_sync(working_directory,                                                        \
-                       standard_out,                                                             \
-                       standard_err,                                                             \
-                       assert_exit_status,                                                       \
-                       ##__VA_ARGS__,                                                            \
-                       NULL)
-static inline int __nmtst_spawn_sync(const char *working_directory,
-                                     char **     standard_out,
-                                     char **     standard_err,
-                                     int         assert_exit_status,
-                                     ...) G_GNUC_NULL_TERMINATED;
-static inline int
-__nmtst_spawn_sync(const char *working_directory,
-                   char **     standard_out,
-                   char **     standard_err,
-                   int         assert_exit_status,
-                   ...)
-{
-    int        exit_status = 0;
-    GError *   error       = NULL;
-    char *     arg;
-    va_list    va_args;
-    GPtrArray *argv = g_ptr_array_new();
-    gboolean   success;
-
-    va_start(va_args, assert_exit_status);
-    while ((arg = va_arg(va_args, char *)))
-        g_ptr_array_add(argv, arg);
-    va_end(va_args);
-
-    g_assert(argv->len >= 1);
-    g_ptr_array_add(argv, NULL);
-
-    success = g_spawn_sync(working_directory,
-                           (char **) argv->pdata,
-                           NULL,
-                           0 /*G_SPAWN_DEFAULT*/,
-                           NULL,
-                           NULL,
-                           standard_out,
-                           standard_err,
-                           &exit_status,
-                           &error);
-    if (!success)
-        g_error("nmtst_spawn_sync(%s): %s", ((char **) argv->pdata)[0], error->message);
-    g_assert(!error);
-
-    g_assert(!standard_out || *standard_out);
-    g_assert(!standard_err || *standard_err);
-
-    if (assert_exit_status != -1) {
-        /* exit status is a guint8 on success. Set @assert_exit_status to -1
-         * not to check for the exit status. */
-        g_assert(WIFEXITED(exit_status));
-        g_assert_cmpint(WEXITSTATUS(exit_status), ==, assert_exit_status);
-    }
-
-    g_ptr_array_free(argv, TRUE);
-    return exit_status;
-}
-
-/*****************************************************************************/
-
-static inline char *
-nmtst_file_resolve_relative_path(const char *rel, const char *cwd)
-{
-    gs_free char *cwd_free = NULL;
-
-    g_assert(rel && *rel);
-
-    if (g_path_is_absolute(rel))
-        return g_strdup(rel);
-
-    if (!cwd)
-        cwd = cwd_free = g_get_current_dir();
-    return g_build_filename(cwd, rel, NULL);
-}
-
-static inline char *
-nmtst_file_get_contents(const char *filename)
-{
-    GError * error = NULL;
-    gboolean success;
-    char *   contents = NULL;
-    gsize    len;
-
-    success = g_file_get_contents(filename, &contents, &len, &error);
-    nmtst_assert_success(success && contents, error);
-    g_assert_cmpint(strlen(contents), ==, len);
-    return contents;
-}
-
-#define nmtst_file_set_contents_size(filename, content, size)                 \
-    G_STMT_START                                                              \
-    {                                                                         \
-        GError *    _error = NULL;                                            \
-        gboolean    _success;                                                 \
-        const char *_content = (content);                                     \
-        gssize      _size    = (size);                                        \
-                                                                              \
-        g_assert(_content);                                                   \
-                                                                              \
-        if (_size < 0) {                                                      \
-            g_assert(_size == -1);                                            \
-            _size = strlen(_content);                                         \
-        }                                                                     \
-                                                                              \
-        _success = g_file_set_contents((filename), _content, _size, &_error); \
-        nmtst_assert_success(_success, _error);                               \
-    }                                                                         \
-    G_STMT_END
-
-#define nmtst_file_set_contents(filename, content) \
-    nmtst_file_set_contents_size(filename, content, -1)
-
-/*****************************************************************************/
-
-static inline void
-nmtst_file_unlink_if_exists(const char *name)
-{
-    int errsv;
-
-    g_assert(name && name[0]);
-
-    if (unlink(name) != 0) {
-        errsv = errno;
-        if (errsv != ENOENT)
-            g_error("nmtst_file_unlink_if_exists(%s): failed with %s",
-                    name,
-                    nm_strerror_native(errsv));
-    }
-}
-
-static inline void
-nmtst_file_unlink(const char *name)
-{
-    int errsv;
-
-    g_assert(name && name[0]);
-
-    if (unlink(name) != 0) {
-        errsv = errno;
-        g_error("nmtst_file_unlink(%s): failed with %s", name, nm_strerror_native(errsv));
-    }
-}
-
-static inline void
-_nmtst_auto_unlinkfile(char **p_name)
-{
-    if (*p_name) {
-        nmtst_file_unlink(*p_name);
-        nm_clear_g_free(p_name);
-    }
-}
-
-#define nmtst_auto_unlinkfile nm_auto(_nmtst_auto_unlinkfile)
-
-/*****************************************************************************/
-
-static inline void
-_nmtst_assert_resolve_relative_path_equals(const char *f1,
-                                           const char *f2,
-                                           const char *file,
-                                           int         line)
-{
-    gs_free char *p1 = NULL, *p2 = NULL;
-
-    p1 = nmtst_file_resolve_relative_path(f1, NULL);
-    p2 = nmtst_file_resolve_relative_path(f2, NULL);
-    g_assert(p1 && *p1);
-
-    /* Fixme: later we might need to coalesce repeated '/', "./", and "../".
-     * For now, it's good enough. */
-    if (g_strcmp0(p1, p2) != 0)
-        g_error("%s:%d : filenames don't match \"%s\" vs. \"%s\" // \"%s\" - \"%s\"",
-                file,
-                line,
-                f1,
-                f2,
-                p1,
-                p2);
-}
-#define nmtst_assert_resolve_relative_path_equals(f1, f2) \
-    _nmtst_assert_resolve_relative_path_equals(f1, f2, __FILE__, __LINE__);
-
-/*****************************************************************************/
-
-#ifdef __NETWORKMANAGER_LOGGING_H__
-static inline gpointer
-nmtst_logging_disable(gboolean always)
-{
-    gpointer p;
-
-    g_assert(nmtst_initialized());
-    if (!always && __nmtst_internal.no_expect_message) {
-        /* The caller does not want to @always suppress logging. Instead,
-         * the caller wants to suppress unexpected log messages that would
-         * fail assertions (since we possibly assert against all unexpected
-         * log messages).
-         *
-         * If the test is run with no-expect-message, then don't suppress
-         * the loggings, because they also wouldn't fail assertions. */
-        return NULL;
-    }
-
-    p = g_memdup(_nm_logging_enabled_state, sizeof(_nm_logging_enabled_state));
-    memset(_nm_logging_enabled_state, 0, sizeof(_nm_logging_enabled_state));
-    return p;
-}
-
-static inline void
-nmtst_logging_reenable(gpointer old_state)
-{
-    g_assert(nmtst_initialized());
-    if (old_state) {
-        memcpy(_nm_logging_enabled_state, old_state, sizeof(_nm_logging_enabled_state));
-        g_free(old_state);
-    }
-}
-#endif
-
-/*****************************************************************************/
-
-#ifdef NM_SETTING_IP_CONFIG_H
-static inline void
-nmtst_setting_ip_config_add_address(NMSettingIPConfig *s_ip, const char *address, guint prefix)
-{
-    NMIPAddress *addr;
-    int          family;
-
-    g_assert(s_ip);
-
-    if (nm_utils_ipaddr_is_valid(AF_INET, address))
-        family = AF_INET;
-    else if (nm_utils_ipaddr_is_valid(AF_INET6, address))
-        family = AF_INET6;
-    else
-        g_assert_not_reached();
-
-    addr = nm_ip_address_new(family, address, prefix, NULL);
-    g_assert(addr);
-    g_assert(nm_setting_ip_config_add_address(s_ip, addr));
-    nm_ip_address_unref(addr);
-}
-
-static inline void
-nmtst_setting_ip_config_add_route(NMSettingIPConfig *s_ip,
-                                  const char *       dest,
-                                  guint              prefix,
-                                  const char *       next_hop,
-                                  gint64             metric)
-{
-    NMIPRoute *route;
-    int        family;
-
-    g_assert(s_ip);
-
-    if (nm_utils_ipaddr_is_valid(AF_INET, dest))
-        family = AF_INET;
-    else if (nm_utils_ipaddr_is_valid(AF_INET6, dest))
-        family = AF_INET6;
-    else
-        g_assert_not_reached();
-
-    route = nm_ip_route_new(family, dest, prefix, next_hop, metric, NULL);
-    g_assert(route);
-    g_assert(nm_setting_ip_config_add_route(s_ip, route));
-    nm_ip_route_unref(route);
-}
-
-static inline void
-nmtst_assert_route_attribute_string(NMIPRoute *route, const char *name, const char *value)
-{
-    GVariant *variant;
-
-    variant = nm_ip_route_get_attribute(route, name);
-    g_assert(variant);
-    g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING));
-    g_assert_cmpstr(g_variant_get_string(variant, NULL), ==, value);
-}
-
-static inline void
-nmtst_assert_route_attribute_byte(NMIPRoute *route, const char *name, guchar value)
-{
-    GVariant *variant;
-
-    variant = nm_ip_route_get_attribute(route, name);
-    g_assert(variant);
-    g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BYTE));
-    g_assert_cmpint(g_variant_get_byte(variant), ==, value);
-}
-
-static inline void
-nmtst_assert_route_attribute_uint32(NMIPRoute *route, const char *name, guint32 value)
-{
-    GVariant *variant;
-
-    variant = nm_ip_route_get_attribute(route, name);
-    g_assert(variant);
-    g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32));
-    g_assert_cmpint(g_variant_get_uint32(variant), ==, value);
-}
-
-static inline void
-nmtst_assert_route_attribute_boolean(NMIPRoute *route, const char *name, gboolean value)
-{
-    GVariant *variant;
-
-    variant = nm_ip_route_get_attribute(route, name);
-    g_assert(variant);
-    g_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN));
-    g_assert_cmpint(g_variant_get_boolean(variant), ==, value);
-}
-#endif /* NM_SETTING_IP_CONFIG_H */
-
-#if (defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__)) \
-    || (defined(NM_CONNECTION_H))
-
-static inline NMConnection *
-nmtst_clone_connection(NMConnection *connection)
-{
-    g_assert(NM_IS_CONNECTION(connection));
-
-    #if defined(__NM_SIMPLE_CONNECTION_H__)
-    return nm_simple_connection_new_clone(connection);
-    #else
-    return nm_connection_duplicate(connection);
-    #endif
-}
-
-static inline NMConnection *
-nmtst_create_minimal_connection(const char *          id,
-                                const char *          uuid,
-                                const char *          type,
-                                NMSettingConnection **out_s_con)
-{
-    NMConnection *       con;
-    NMSetting *          s_base = NULL;
-    NMSettingConnection *s_con;
-    gs_free char *       uuid_free = NULL;
-
-    g_assert(id);
-
-    if (uuid)
-        g_assert(nm_utils_is_uuid(uuid));
-    else
-        uuid = uuid_free = nm_utils_uuid_generate();
-
-    if (type) {
-        GType type_g;
-
-    #if defined(__NM_SIMPLE_CONNECTION_H__)
-        type_g = nm_setting_lookup_type(type);
-    #else
-        type_g = nm_connection_lookup_setting_type(type);
-    #endif
-
-        g_assert(type_g != G_TYPE_INVALID);
-
-        s_base = g_object_new(type_g, NULL);
-        g_assert(NM_IS_SETTING(s_base));
-    }
-
-    #if defined(__NM_SIMPLE_CONNECTION_H__)
-    con = nm_simple_connection_new();
-    #else
-    con = nm_connection_new();
-    #endif
-
-    g_assert(con);
-
-    s_con = NM_SETTING_CONNECTION(nm_setting_connection_new());
-
-    g_assert(s_con);
-
-    g_object_set(s_con,
-                 NM_SETTING_CONNECTION_ID,
-                 id,
-                 NM_SETTING_CONNECTION_UUID,
-                 uuid,
-                 NM_SETTING_CONNECTION_TYPE,
-                 type,
-                 NULL);
-    nm_connection_add_setting(con, NM_SETTING(s_con));
-
-    if (s_base)
-        nm_connection_add_setting(con, s_base);
-
-    if (out_s_con)
-        *out_s_con = s_con;
-    return con;
-}
-
-static inline gboolean
-_nmtst_connection_normalize_v(NMConnection *connection, va_list args)
-{
-    GError *    error = NULL;
-    gboolean    success;
-    gboolean    was_modified = FALSE;
-    GHashTable *parameters   = NULL;
-    const char *p_name;
-
-    g_assert(NM_IS_CONNECTION(connection));
-
-    while ((p_name = va_arg(args, const char *))) {
-        if (!parameters)
-            parameters = g_hash_table_new(g_str_hash, g_str_equal);
-        g_hash_table_insert(parameters, (gpointer *) p_name, va_arg(args, gpointer));
-    }
-
-    success = nm_connection_normalize(connection, parameters, &was_modified, &error);
-    g_assert_no_error(error);
-    g_assert(success);
-
-    if (parameters)
-        g_hash_table_destroy(parameters);
-
-    return was_modified;
-}
-
-static inline gboolean
-_nmtst_connection_normalize(NMConnection *connection, ...)
-{
-    gboolean was_modified;
-    va_list  args;
-
-    va_start(args, connection);
-    was_modified = _nmtst_connection_normalize_v(connection, args);
-    va_end(args);
-
-    return was_modified;
-}
-    #define nmtst_connection_normalize(connection, ...) \
-        _nmtst_connection_normalize(connection, ##__VA_ARGS__, NULL)
-
-static inline NMConnection *
-_nmtst_connection_duplicate_and_normalize(NMConnection *connection, ...)
-{
-    va_list args;
-
-    connection = nmtst_clone_connection(connection);
-
-    va_start(args, connection);
-    _nmtst_connection_normalize_v(connection, args);
-    va_end(args);
-
-    return connection;
-}
-    #define nmtst_connection_duplicate_and_normalize(connection, ...) \
-        _nmtst_connection_duplicate_and_normalize(connection, ##__VA_ARGS__, NULL)
-
-static inline void
-nmtst_assert_connection_equals(NMConnection *a,
-                               gboolean      normalize_a,
-                               NMConnection *b,
-                               gboolean      normalize_b)
-{
-    gboolean        compare;
-    gs_unref_object NMConnection *a2           = NULL;
-    gs_unref_object NMConnection *b2           = NULL;
-    GHashTable *                  out_settings = NULL;
-
-    g_assert(NM_IS_CONNECTION(a));
-    g_assert(NM_IS_CONNECTION(b));
-
-    if (normalize_a)
-        a = a2 = nmtst_connection_duplicate_and_normalize(a);
-    if (normalize_b)
-        b = b2 = nmtst_connection_duplicate_and_normalize(b);
-
-    compare = nm_connection_diff(a, b, NM_SETTING_COMPARE_FLAG_EXACT, &out_settings);
-    if (!compare || out_settings) {
-        const char *   name, *pname;
-        GHashTable *   setting;
-        GHashTableIter iter, iter2;
-
-        __NMTST_LOG(g_message, ">>> ASSERTION nmtst_assert_connection_equals() fails");
-        if (out_settings) {
-            g_hash_table_iter_init(&iter, out_settings);
-            while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &setting)) {
-                __NMTST_LOG(g_message, ">>> differences in setting '%s':", name);
-
-                g_hash_table_iter_init(&iter2, setting);
-                while (g_hash_table_iter_next(&iter2, (gpointer *) &pname, NULL))
-                    __NMTST_LOG(g_message, ">>> differences in setting '%s.%s'", name, pname);
-            }
-        }
-
-    #ifdef __NM_KEYFILE_INTERNAL_H__
-        {
-            nm_auto_unref_keyfile GKeyFile *kf_a = NULL, *kf_b = NULL;
-            gs_free char *                  str_a = NULL, *str_b = NULL;
-
-            kf_a = nm_keyfile_write(a, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, NULL);
-            kf_b = nm_keyfile_write(b, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, NULL);
-
-            if (kf_a)
-                str_a = g_key_file_to_data(kf_a, NULL, NULL);
-            if (kf_b)
-                str_b = g_key_file_to_data(kf_b, NULL, NULL);
-
-            __NMTST_LOG(g_message,
-                        ">>> Connection A as kf (*WARNING: keyfile representation might not show "
-                        "the difference*):\n%s",
-                        str_a);
-            __NMTST_LOG(g_message,
-                        ">>> Connection B as kf (*WARNING: keyfile representation might not show "
-                        "the difference*):\n%s",
-                        str_b);
-        }
-    #endif
-    }
-    g_assert(compare);
-    g_assert(!out_settings);
-
-    compare = nm_connection_compare(a, b, NM_SETTING_COMPARE_FLAG_EXACT);
-    g_assert(compare);
-}
-
-static inline void
-nmtst_assert_connection_verifies(NMConnection *con)
-{
-    /* assert that the connection does verify, it might be normaliziable or not */
-    GError * error = NULL;
-    gboolean success;
-
-    g_assert(NM_IS_CONNECTION(con));
-
-    success = nm_connection_verify(con, &error);
-    g_assert_no_error(error);
-    g_assert(success);
-}
-
-static inline void
-nmtst_assert_connection_verifies_without_normalization(NMConnection *con)
-{
-    /* assert that the connection verifies and does not need any normalization */
-    GError *        error = NULL;
-    gboolean        success;
-    gboolean        was_modified        = FALSE;
-    gs_unref_object NMConnection *clone = NULL;
-
-    clone = nmtst_clone_connection(con);
-
-    nmtst_assert_connection_verifies(con);
-
-    success = nm_connection_normalize(clone, NULL, &was_modified, &error);
-    g_assert_no_error(error);
-    g_assert(success);
-    nmtst_assert_connection_equals(con, FALSE, clone, FALSE);
-    g_assert(!was_modified);
-}
-
-static inline void
-nmtst_assert_connection_verifies_and_normalizable(NMConnection *con)
-{
-    /* assert that the connection does verify, but normalization still modifies it */
-    GError *        error = NULL;
-    gboolean        success;
-    gboolean        was_modified        = FALSE;
-    gs_unref_object NMConnection *clone = NULL;
-
-    clone = nmtst_clone_connection(con);
-
-    nmtst_assert_connection_verifies(con);
-
-    success = nm_connection_normalize(clone, NULL, &was_modified, &error);
-    g_assert_no_error(error);
-    g_assert(success);
-    g_assert(was_modified);
-
-    /* again! */
-    nmtst_assert_connection_verifies_without_normalization(clone);
-}
-
-static inline void
-nmtst_assert_connection_verifies_after_normalization(NMConnection *con,
-                                                     GQuark        expect_error_domain,
-                                                     int           expect_error_code)
-{
-    /* assert that the connection does not verify, but normalization does fix it */
-    GError *        error = NULL;
-    gboolean        success;
-    gboolean        was_modified        = FALSE;
-    gs_unref_object NMConnection *clone = NULL;
-
-    clone = nmtst_clone_connection(con);
-
-    success = nm_connection_verify(con, &error);
-    nmtst_assert_error(error, expect_error_domain, expect_error_code, NULL);
-    g_assert(!success);
-    g_clear_error(&error);
-
-    success = nm_connection_normalize(clone, NULL, &was_modified, &error);
-    g_assert_no_error(error);
-    g_assert(success);
-    g_assert(was_modified);
-
-    /* again! */
-    nmtst_assert_connection_verifies_without_normalization(clone);
-}
-
-static inline void
-nmtst_assert_connection_unnormalizable(NMConnection *con,
-                                       GQuark        expect_error_domain,
-                                       int           expect_error_code)
-{
-    /* assert that the connection does not verify, and it cannot be fixed by normalization */
-
-    GError *        error = NULL;
-    gboolean        success;
-    gboolean        was_modified        = FALSE;
-    gs_unref_object NMConnection *clone = NULL;
-
-    clone = nmtst_clone_connection(con);
-
-    success = nm_connection_verify(con, &error);
-    nmtst_assert_error(error, expect_error_domain, expect_error_code, NULL);
-    g_assert(!success);
-    g_clear_error(&error);
-
-    success = nm_connection_normalize(clone, NULL, &was_modified, &error);
-    nmtst_assert_error(error, expect_error_domain, expect_error_code, NULL);
-    g_assert(!success);
-    g_assert(!was_modified);
-    nmtst_assert_connection_equals(con, FALSE, clone, FALSE);
-    g_clear_error(&error);
-}
-
-static inline void
-nmtst_assert_setting_verifies(NMSetting *setting)
-{
-    /* assert that the setting verifies without an error */
-
-    GError * error = NULL;
-    gboolean success;
-
-    g_assert(NM_IS_SETTING(setting));
-
-    success = nm_setting_verify(setting, NULL, &error);
-    g_assert_no_error(error);
-    g_assert(success);
-}
-
-    #if defined(__NM_SIMPLE_CONNECTION_H__) && NM_CHECK_VERSION(1, 10, 0) \
-        && (!defined(NM_VERSION_MAX_ALLOWED) || NM_VERSION_MAX_ALLOWED >= NM_VERSION_1_10)
-static inline void
-_nmtst_assert_connection_has_settings(NMConnection *connection,
-                                      gboolean      has_at_least,
-                                      gboolean      has_at_most,
-                                      ...)
-{
-    gs_unref_hashtable GHashTable *names = NULL;
-    gs_free NMSetting **settings         = NULL;
-    va_list             ap;
-    const char *        name;
-    guint               i, len;
-    gs_unref_ptrarray GPtrArray *names_arr = NULL;
-
-    g_assert(NM_IS_CONNECTION(connection));
-
-    names     = g_hash_table_new(g_str_hash, g_str_equal);
-    names_arr = g_ptr_array_new();
-
-    va_start(ap, has_at_most);
-    while ((name = va_arg(ap, const char *))) {
-        if (!nm_g_hash_table_add(names, (gpointer) name))
-            g_assert_not_reached();
-        g_ptr_array_add(names_arr, (gpointer) name);
-    }
-    va_end(ap);
-
-    g_ptr_array_add(names_arr, NULL);
-
-    settings = nm_connection_get_settings(connection, &len);
-    for (i = 0; i < len; i++) {
-        if (!g_hash_table_remove(names, nm_setting_get_name(settings[i])) && has_at_most) {
-            g_error(
-                "nmtst_assert_connection_has_settings(): has setting \"%s\" which is not expected",
-                nm_setting_get_name(settings[i]));
-        }
-    }
-    if (g_hash_table_size(names) > 0 && has_at_least) {
-        gs_free char *       expected_str   = g_strjoinv(" ", (char **) names_arr->pdata);
-        gs_free const char **settings_names = NULL;
-        gs_free char *       has_str        = NULL;
-
-        settings_names = g_new0(const char *, len + 1);
-        for (i = 0; i < len; i++)
-            settings_names[i] = nm_setting_get_name(settings[i]);
-        has_str = g_strjoinv(" ", (char **) settings_names);
-
-        g_error("nmtst_assert_connection_has_settings(): the setting lacks %u expected settings "
-                "(expected: [%s] vs. has: [%s])",
-                g_hash_table_size(names),
-                expected_str,
-                has_str);
-    }
-}
-        #define nmtst_assert_connection_has_settings(connection, ...) \
-            _nmtst_assert_connection_has_settings((connection), TRUE, TRUE, __VA_ARGS__, NULL)
-        #define nmtst_assert_connection_has_settings_at_least(connection, ...) \
-            _nmtst_assert_connection_has_settings((connection), TRUE, FALSE, __VA_ARGS__, NULL)
-        #define nmtst_assert_connection_has_settings_at_most(connection, ...) \
-            _nmtst_assert_connection_has_settings((connection), FALSE, TRUE, __VA_ARGS__, NULL)
-    #endif
-
-static inline void
-nmtst_assert_setting_verify_fails(NMSetting *setting,
-                                  GQuark     expect_error_domain,
-                                  int        expect_error_code)
-{
-    /* assert that the setting verification fails */
-
-    GError * error = NULL;
-    gboolean success;
-
-    g_assert(NM_IS_SETTING(setting));
-
-    success = nm_setting_verify(setting, NULL, &error);
-    nmtst_assert_error(error, expect_error_domain, expect_error_code, NULL);
-    g_assert(!success);
-    g_clear_error(&error);
-}
-
-static inline void
-nmtst_assert_setting_is_equal(gconstpointer /* const NMSetting * */ a,
-                              gconstpointer /* const NMSetting * */ b,
-                              NMSettingCompareFlags                 flags)
-{
-    gs_unref_hashtable GHashTable *hash = NULL;
-    guint32                        r    = nmtst_get_rand_uint32();
-
-    g_assert(NM_IS_SETTING(a));
-    g_assert(NM_IS_SETTING(b));
-
-    if (NM_FLAGS_HAS(r, 0x4))
-        NM_SWAP(&a, &b);
-
-    g_assert(nm_setting_compare((NMSetting *) a, (NMSetting *) b, flags));
-
-    if (NM_FLAGS_HAS(r, 0x8))
-        NM_SWAP(&a, &b);
-
-    g_assert(nm_setting_diff((NMSetting *) a, (NMSetting *) b, flags, NM_FLAGS_HAS(r, 0x1), &hash));
-    g_assert(!hash);
-}
-#endif
-
-#ifdef __NM_SETTING_PRIVATE_H__
-static inline NMSetting *
-nmtst_assert_setting_dbus_new(GType gtype, GVariant *variant)
-{
-    NMSetting *   setting;
-    gs_free_error GError *error = NULL;
-
-    g_assert(g_type_is_a(gtype, NM_TYPE_SETTING));
-    g_assert(gtype != NM_TYPE_SETTING);
-    g_assert(variant);
-    g_assert(g_variant_is_of_type(variant, NM_VARIANT_TYPE_SETTING));
-
-    setting =
-        _nm_setting_new_from_dbus(gtype, variant, NULL, NM_SETTING_PARSE_FLAGS_STRICT, &error);
-    nmtst_assert_success(setting, error);
-    return setting;
-}
-
-static inline void
-nmtst_assert_setting_dbus_roundtrip(gconstpointer /* const NMSetting * */ setting)
-{
-    gs_unref_object NMSetting *setting2 = NULL;
-    gs_unref_variant GVariant *variant  = NULL;
-
-    g_assert(NM_IS_SETTING(setting));
-
-    variant  = _nm_setting_to_dbus((NMSetting *) setting, NULL, NM_CONNECTION_SERIALIZE_ALL, NULL);
-    setting2 = nmtst_assert_setting_dbus_new(G_OBJECT_TYPE(setting), variant);
-    nmtst_assert_setting_is_equal(setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT);
-}
-#endif
-
-#ifdef __NM_UTILS_H__
-static inline void
-nmtst_assert_hwaddr_equals(gconstpointer hwaddr1,
-                           gssize        hwaddr1_len,
-                           const char *  expected,
-                           const char *  file,
-                           int           line)
-{
-    guint8      buf2[NM_UTILS_HWADDR_LEN_MAX];
-    gsize       hwaddr2_len = 1;
-    const char *p;
-    gboolean    success;
-
-    g_assert(hwaddr1_len > 0 && hwaddr1_len <= NM_UTILS_HWADDR_LEN_MAX);
-
-    g_assert(expected);
-    for (p = expected; *p; p++) {
-        if (*p == ':' || *p == '-')
-            hwaddr2_len++;
-    }
-    g_assert(hwaddr2_len <= NM_UTILS_HWADDR_LEN_MAX);
-    g_assert(nm_utils_hwaddr_aton(expected, buf2, hwaddr2_len));
-
-    /* Manually check the entire hardware address instead of using
-     * nm_utils_hwaddr_matches() because that function doesn't compare
-     * entire InfiniBand addresses for various (legitimate) reasons.
-     */
-    success = (hwaddr1_len == hwaddr2_len);
-    if (success)
-        success = !memcmp(hwaddr1, buf2, hwaddr1_len);
-    if (!success) {
-        g_error("assert: %s:%d: hwaddr '%s' (%zd) expected, but got %s (%zd)",
-                file,
-                line,
-                expected,
-                hwaddr2_len,
-                nm_utils_hwaddr_ntoa(hwaddr1, hwaddr1_len),
-                hwaddr1_len);
-    }
-}
-    #define nmtst_assert_hwaddr_equals(hwaddr1, hwaddr1_len, expected) \
-        nmtst_assert_hwaddr_equals(hwaddr1, hwaddr1_len, expected, __FILE__, __LINE__)
-#endif
-
-#if defined(__NM_SIMPLE_CONNECTION_H__) && defined(__NM_SETTING_CONNECTION_H__) \
-    && defined(__NM_KEYFILE_INTERNAL_H__)
-
-static inline NMConnection *
-nmtst_create_connection_from_keyfile(const char *keyfile_str, const char *full_filename)
-{
-    nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
-    gs_free_error GError *error             = NULL;
-    gboolean              success;
-    NMConnection *        con;
-    gs_free char *        filename = g_path_get_basename(full_filename);
-    gs_free char *        base_dir = g_path_get_dirname(full_filename);
-
-    g_assert(keyfile_str);
-    g_assert(full_filename && full_filename[0] == '/');
-
-    keyfile = g_key_file_new();
-    success = g_key_file_load_from_data(keyfile,
-                                        keyfile_str,
-                                        strlen(keyfile_str),
-                                        G_KEY_FILE_NONE,
-                                        &error);
-    nmtst_assert_success(success, error);
-
-    con = nm_keyfile_read(keyfile, base_dir, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
-    nmtst_assert_success(NM_IS_CONNECTION(con), error);
-
-    nm_keyfile_read_ensure_id(con, filename);
-    nm_keyfile_read_ensure_uuid(con, full_filename);
-
-    nmtst_connection_normalize(con);
-
-    return con;
-}
-
-#endif
-
-#ifdef __NM_CONNECTION_H__
-
-static inline GVariant *
-_nmtst_variant_new_vardict(int dummy, ...)
-{
-    GVariantBuilder builder;
-    va_list         ap;
-    const char *    name;
-    GVariant *      variant;
-
-    g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
-
-    va_start(ap, dummy);
-    while ((name = va_arg(ap, const char *))) {
-        variant = va_arg(ap, GVariant *);
-        g_variant_builder_add(&builder, "{sv}", name, variant);
-    }
-    va_end(ap);
-
-    return g_variant_builder_end(&builder);
-}
-    #define nmtst_variant_new_vardict(...) _nmtst_variant_new_vardict(0, __VA_ARGS__, NULL)
-
-    #define nmtst_assert_variant_is_of_type(variant, type)     \
-        G_STMT_START                                           \
-        {                                                      \
-            GVariant *_variantx = (variant);                   \
-                                                               \
-            g_assert(_variantx);                               \
-            g_assert(g_variant_is_of_type(_variantx, (type))); \
-        }                                                      \
-        G_STMT_END
-
-    #define nmtst_assert_variant_uint32(variant, val)                         \
-        G_STMT_START                                                          \
-        {                                                                     \
-            GVariant *_variant = (variant);                                   \
-                                                                              \
-            nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_UINT32); \
-            g_assert_cmpint(g_variant_get_uint32(_variant), ==, (val));       \
-        }                                                                     \
-        G_STMT_END
-
-    #define nmtst_assert_variant_string(variant, str)                         \
-        G_STMT_START                                                          \
-        {                                                                     \
-            gsize       _l;                                                   \
-            GVariant *  _variant = (variant);                                 \
-            const char *_str     = (str);                                     \
-                                                                              \
-            nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_STRING); \
-            g_assert(_str);                                                   \
-            g_assert_cmpstr(g_variant_get_string(_variant, &_l), ==, _str);   \
-            g_assert_cmpint(_l, ==, strlen(_str));                            \
-        }                                                                     \
-        G_STMT_END
-
-    #ifdef __NM_SHARED_UTILS_H__
-        #define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len)                      \
-            G_STMT_START                                                                         \
-            {                                                                                    \
-                if (memcmp(_ptr2, _ptr, _len) != 0) {                                            \
-                    gs_free char *_x1 = NULL;                                                    \
-                    gs_free char *_x2 = NULL;                                                    \
-                    const char *  _xx1;                                                          \
-                    const char *  _xx2;                                                          \
-                                                                                                 \
-                    _xx1 = nm_utils_buf_utf8safe_escape(_ptr,                                    \
-                                                        _len,                                    \
-                                                        NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, \
-                                                        &_x1);                                   \
-                    _xx2 = nm_utils_buf_utf8safe_escape(_ptr2,                                   \
-                                                        _len,                                    \
-                                                        NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, \
-                                                        &_x2);                                   \
-                    g_assert_cmpstr(_xx1, ==, _xx2);                                             \
-                    g_assert_not_reached();                                                      \
-                }                                                                                \
-            }                                                                                    \
-            G_STMT_END
-    #else
-        #define _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len) \
-            G_STMT_START {}                                                 \
-            G_STMT_END
-    #endif
-
-    #define nmtst_assert_variant_bytestring(variant, ptr, len)                    \
-        G_STMT_START                                                              \
-        {                                                                         \
-            GVariant *    _variant = (variant);                                   \
-            gconstpointer _ptr     = (ptr);                                       \
-            gconstpointer _ptr2;                                                  \
-            gsize         _len = (len);                                           \
-            gsize         _len2;                                                  \
-                                                                                  \
-            nmtst_assert_variant_is_of_type(_variant, G_VARIANT_TYPE_BYTESTRING); \
-            _ptr2 = g_variant_get_fixed_array(_variant, &_len2, 1);               \
-            g_assert_cmpint(_len2, ==, _len);                                     \
-            if (_len != 0 && _ptr) {                                              \
-                _nmtst_assert_variant_bytestring_cmp_str(_ptr, _ptr2, _len);      \
-                g_assert_cmpmem(_ptr2, _len2, _ptr, _len);                        \
-            }                                                                     \
-        }                                                                         \
-        G_STMT_END
-
-typedef enum {
-    NMTST_VARIANT_EDITOR_CONNECTION,
-    NMTST_VARIANT_EDITOR_SETTING,
-    NMTST_VARIANT_EDITOR_PROPERTY
-} NmtstVariantEditorPhase;
-
-    #define NMTST_VARIANT_EDITOR(__connection_variant, __code)                         \
-        G_STMT_START                                                                   \
-        {                                                                              \
-            GVariantIter            __connection_iter, *__setting_iter;                \
-            GVariantBuilder         __connection_builder, __setting_builder;           \
-            const char *            __cur_setting_name, *__cur_property_name;          \
-            GVariant *              __property_val;                                    \
-            NmtstVariantEditorPhase __phase;                                           \
-                                                                                       \
-            g_variant_builder_init(&__connection_builder, NM_VARIANT_TYPE_CONNECTION); \
-            g_variant_iter_init(&__connection_iter, __connection_variant);             \
-                                                                                       \
-            __phase             = NMTST_VARIANT_EDITOR_CONNECTION;                     \
-            __cur_setting_name  = NULL;                                                \
-            __cur_property_name = NULL;                                                \
-            __code;                                                                    \
-            while (g_variant_iter_next(&__connection_iter,                             \
-                                       "{&sa{sv}}",                                    \
-                                       &__cur_setting_name,                            \
-                                       &__setting_iter)) {                             \
-                g_variant_builder_init(&__setting_builder, NM_VARIANT_TYPE_SETTING);   \
-                __phase             = NMTST_VARIANT_EDITOR_SETTING;                    \
-                __cur_property_name = NULL;                                            \
-                __code;                                                                \
-                                                                                       \
-                while (__cur_setting_name                                              \
-                       && g_variant_iter_next(__setting_iter,                          \
-                                              "{&sv}",                                 \
-                                              &__cur_property_name,                    \
-                                              &__property_val)) {                      \
-                    __phase = NMTST_VARIANT_EDITOR_PROPERTY;                           \
-                    __code;                                                            \
-                                                                                       \
-                    if (__cur_property_name) {                                         \
-                        g_variant_builder_add(&__setting_builder,                      \
-                                              "{sv}",                                  \
-                                              __cur_property_name,                     \
-                                              __property_val);                         \
-                    }                                                                  \
-                    g_variant_unref(__property_val);                                   \
-                }                                                                      \
-                                                                                       \
-                if (__cur_setting_name)                                                \
-                    g_variant_builder_add(&__connection_builder,                       \
-                                          "{sa{sv}}",                                  \
-                                          __cur_setting_name,                          \
-                                          &__setting_builder);                         \
-                else                                                                   \
-                    g_variant_builder_clear(&__setting_builder);                       \
-                g_variant_iter_free(__setting_iter);                                   \
-            }                                                                          \
-                                                                                       \
-            g_variant_unref(__connection_variant);                                     \
-                                                                                       \
-            __connection_variant = g_variant_builder_end(&__connection_builder);       \
-        }                                                                              \
-        G_STMT_END;
-
-    #define NMTST_VARIANT_ADD_SETTING(__setting_name, __setting_variant) \
-        G_STMT_START                                                     \
-        {                                                                \
-            if (__phase == NMTST_VARIANT_EDITOR_CONNECTION)              \
-                g_variant_builder_add(&__connection_builder,             \
-                                      "{s@a{sv}}",                       \
-                                      __setting_name,                    \
-                                      __setting_variant);                \
-        }                                                                \
-        G_STMT_END
-
-    #define NMTST_VARIANT_DROP_SETTING(__setting_name)                           \
-        G_STMT_START                                                             \
-        {                                                                        \
-            if (__phase == NMTST_VARIANT_EDITOR_SETTING && __cur_setting_name) { \
-                if (!strcmp(__cur_setting_name, __setting_name))                 \
-                    __cur_setting_name = NULL;                                   \
-            }                                                                    \
-        }                                                                        \
-        G_STMT_END
-
-    #define NMTST_VARIANT_ADD_PROPERTY(__setting_name, __property_name, __format_string, __value) \
-        G_STMT_START                                                                              \
-        {                                                                                         \
-            if (__phase == NMTST_VARIANT_EDITOR_SETTING) {                                        \
-                if (!strcmp(__cur_setting_name, __setting_name)) {                                \
-                    g_variant_builder_add(&__setting_builder,                                     \
-                                          "{sv}",                                                 \
-                                          __property_name,                                        \
-                                          g_variant_new(__format_string, __value));               \
-                }                                                                                 \
-            }                                                                                     \
-        }                                                                                         \
-        G_STMT_END
-
-    #define NMTST_VARIANT_DROP_PROPERTY(__setting_name, __property_name)           \
-        G_STMT_START                                                               \
-        {                                                                          \
-            if (__phase == NMTST_VARIANT_EDITOR_PROPERTY && __cur_property_name) { \
-                if (!strcmp(__cur_setting_name, __setting_name)                    \
-                    && !strcmp(__cur_property_name, __property_name))              \
-                    __cur_property_name = NULL;                                    \
-            }                                                                      \
-        }                                                                          \
-        G_STMT_END
-
-    #define NMTST_VARIANT_CHANGE_PROPERTY(__setting_name,                                          \
-                                          __property_name,                                         \
-                                          __format_string,                                         \
-                                          __value)                                                 \
-        G_STMT_START                                                                               \
-        {                                                                                          \
-            NMTST_VARIANT_DROP_PROPERTY(__setting_name, __property_name);                          \
-            NMTST_VARIANT_ADD_PROPERTY(__setting_name, __property_name, __format_string, __value); \
-        }                                                                                          \
-        G_STMT_END
-
-#endif /* __NM_CONNECTION_H__ */
-
-static inline GVariant *
-nmtst_variant_from_string(const GVariantType *variant_type, const char *variant_str)
-{
-    GVariant *variant;
-    GError *  error = NULL;
-
-    g_assert(variant_type);
-    g_assert(variant_str);
-
-    variant = g_variant_parse(variant_type, variant_str, NULL, NULL, &error);
-    nmtst_assert_success(variant, error);
-    return variant;
-}
-
-/*****************************************************************************/
-
-static inline void
-nmtst_keyfile_assert_data(GKeyFile *kf, const char *data, gssize data_len)
-{
-    nm_auto_unref_keyfile GKeyFile *kf2 = NULL;
-    gs_free_error GError *error         = NULL;
-    gs_free char *        d1            = NULL;
-    gs_free char *        d2            = NULL;
-    gboolean              success;
-    gsize                 d1_len;
-    gsize                 d2_len;
-
-    g_assert(kf);
-    g_assert(data || data_len == 0);
-    g_assert(data_len >= -1);
-
-    d1 = g_key_file_to_data(kf, &d1_len, &error);
-    nmtst_assert_success(d1, error);
-
-    if (data_len == -1) {
-        g_assert_cmpint(strlen(d1), ==, d1_len);
-        data_len = strlen(data);
-        g_assert_cmpstr(d1, ==, data);
-    }
-
-    g_assert_cmpmem(d1, d1_len, data, (gsize) data_len);
-
-    /* also check that we can re-generate the same keyfile from the data. */
-
-    kf2     = g_key_file_new();
-    success = g_key_file_load_from_data(kf2, d1, d1_len, G_KEY_FILE_NONE, &error);
-    nmtst_assert_success(success, error);
-
-    d2 = g_key_file_to_data(kf2, &d2_len, &error);
-    nmtst_assert_success(d2, error);
-
-    g_assert_cmpmem(d2, d2_len, d1, d1_len);
-}
-
-static inline gssize
-nmtst_keyfile_get_num_keys(GKeyFile *keyfile, const char *group_name)
-{
-    gs_strfreev char **keys     = NULL;
-    gs_free_error GError *error = NULL;
-    gsize                 l;
-
-    g_assert(keyfile);
-    g_assert(group_name);
-
-    if (!g_key_file_has_group(keyfile, group_name))
-        return -1;
-
-    keys = g_key_file_get_keys(keyfile, group_name, &l, &error);
-
-    nmtst_assert_success(keys, error);
-
-    g_assert_cmpint(NM_PTRARRAY_LEN(keys), ==, l);
-
-    return l;
-}
-
-/*****************************************************************************/
-
-#if defined(NM_SETTING_IP_CONFIG_H) && defined(__NM_SHARED_UTILS_H__)
-
-static inline NMIPAddress *
-nmtst_ip_address_new(int addr_family, const char *str)
-{
-    NMIPAddr     addr;
-    int          plen;
-    GError *     error = NULL;
-    NMIPAddress *a;
-
-    if (!nm_utils_parse_inaddr_prefix_bin(addr_family, str, &addr_family, &addr, &plen))
-        g_assert_not_reached();
-
-    if (plen == -1)
-        plen = addr_family == AF_INET ? 32 : 128;
-
-    a = nm_ip_address_new_binary(addr_family, &addr, plen, &error);
-    nmtst_assert_success(a, error);
-    return a;
-}
-
-#endif
-
-/*****************************************************************************/
-
-#endif /* __NM_TEST_UTILS_H__ */
diff --git a/shared/nm-utils/nm-vpn-editor-plugin-call.h b/shared/nm-utils/nm-vpn-editor-plugin-call.h
deleted file mode 100644
index 5772b843..00000000
--- a/shared/nm-utils/nm-vpn-editor-plugin-call.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2016 Red Hat, Inc.
- */
-
-#ifndef __NM_VPN_EDITOR_PLUGIN_CALL_H__
-#define __NM_VPN_EDITOR_PLUGIN_CALL_H__
-
-/* This header is an internal, header-only file that can be copied to
- * other projects to call well-known service functions on VPN plugins.
- *
- * This uses the NMVpnEditorPluginVT and allows a user (nm-applet)
- * to directly communicate with a VPN plugin using API that is newer
- * then the current libnm version. That is, it allows to call to a VPN
- * plugin bypassing libnm. */
-
-#include <NetworkManager.h>
-
-/* we make use of other internal header files, you need those too. */
-#include "nm-glib-aux/nm-macros-internal.h"
-
-/*****************************************************************************/
-
-/**
- * NMVpnEditorPluginServiceFlags:
- * @NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_NONE: no flags
- * @NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD: whether the plugin can
- *   add a new connection for the given service-type.
- **/
-typedef enum { /*< skip >*/
-               NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_NONE    = 0x00,
-               NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD = 0x01,
-} NMVpnEditorPluginServiceFlags;
-
-struct _NMVpnEditorPluginVT {
-    gboolean (*fcn_get_service_info)(NMVpnEditorPlugin *            plugin,
-                                     const char *                   service_type,
-                                     char **                        out_short_name,
-                                     char **                        out_pretty_name,
-                                     char **                        out_description,
-                                     NMVpnEditorPluginServiceFlags *out_flags);
-    char **(*fcn_get_service_add_details)(NMVpnEditorPlugin *plugin, const char *service_name);
-    gboolean (*fcn_get_service_add_detail)(NMVpnEditorPlugin *plugin,
-                                           const char *       service_type,
-                                           const char *       add_detail,
-                                           char **            out_pretty_name,
-                                           char **            out_description,
-                                           char **            out_add_detail_key,
-                                           char **            out_add_detail_val,
-                                           guint *            out_flags);
-};
-
-/*****************************************************************************
- * Call
- *
- * The following wrap the calling of generic functions for a VPN plugin.
- * They are used by callers (for example nm-connection-editor).
- *****************************************************************************/
-
-static inline gboolean
-nm_vpn_editor_plugin_get_service_info(NMVpnEditorPlugin *            plugin,
-                                      const char *                   service_type,
-                                      char **                        out_short_name,
-                                      char **                        out_pretty_name,
-                                      char **                        out_description,
-                                      NMVpnEditorPluginServiceFlags *out_flags)
-{
-    NMVpnEditorPluginVT vt;
-    gs_free char *      short_name_local  = NULL;
-    gs_free char *      pretty_name_local = NULL;
-    gs_free char *      description_local = NULL;
-    guint               flags_local       = 0;
-
-    g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(plugin), FALSE);
-    g_return_val_if_fail(service_type, FALSE);
-
-    nm_vpn_editor_plugin_get_vt(plugin, &vt, sizeof(vt));
-    if (!vt.fcn_get_service_info
-        || !vt.fcn_get_service_info(plugin,
-                                    service_type,
-                                    out_short_name ? &short_name_local : NULL,
-                                    out_pretty_name ? &pretty_name_local : NULL,
-                                    out_description ? &description_local : NULL,
-                                    out_flags ? &flags_local : NULL))
-        return FALSE;
-    NM_SET_OUT(out_short_name, g_steal_pointer(&short_name_local));
-    NM_SET_OUT(out_pretty_name, g_steal_pointer(&pretty_name_local));
-    NM_SET_OUT(out_description, g_steal_pointer(&description_local));
-    NM_SET_OUT(out_flags, flags_local);
-    return TRUE;
-}
-
-static inline char **
-nm_vpn_editor_plugin_get_service_add_details(NMVpnEditorPlugin *plugin, const char *service_name)
-{
-    NMVpnEditorPluginVT vt;
-    char **             details = NULL;
-
-    g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(plugin), NULL);
-    g_return_val_if_fail(service_name, NULL);
-
-    nm_vpn_editor_plugin_get_vt(plugin, &vt, sizeof(vt));
-    if (vt.fcn_get_service_add_details)
-        details = vt.fcn_get_service_add_details(plugin, service_name);
-    if (!details)
-        return g_new0(char *, 1);
-    return details;
-}
-
-static inline gboolean
-nm_vpn_editor_plugin_get_service_add_detail(NMVpnEditorPlugin *plugin,
-                                            const char *       service_type,
-                                            const char *       add_detail,
-                                            char **            out_pretty_name,
-                                            char **            out_description,
-                                            char **            out_add_detail_key,
-                                            char **            out_add_detail_val,
-                                            guint *            out_flags)
-{
-    NMVpnEditorPluginVT vt;
-    gs_free char *      pretty_name_local    = NULL;
-    gs_free char *      description_local    = NULL;
-    gs_free char *      add_detail_key_local = NULL;
-    gs_free char *      add_detail_val_local = NULL;
-    guint               flags_local          = 0;
-
-    g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(plugin), FALSE);
-    g_return_val_if_fail(service_type, FALSE);
-    g_return_val_if_fail(add_detail, FALSE);
-
-    nm_vpn_editor_plugin_get_vt(plugin, &vt, sizeof(vt));
-    if (!vt.fcn_get_service_add_detail
-        || !vt.fcn_get_service_add_detail(plugin,
-                                          service_type,
-                                          add_detail,
-                                          out_pretty_name ? &pretty_name_local : NULL,
-                                          out_description ? &description_local : NULL,
-                                          out_add_detail_key ? &add_detail_key_local : NULL,
-                                          out_add_detail_val ? &add_detail_val_local : NULL,
-                                          out_flags ? &flags_local : NULL))
-        return FALSE;
-    NM_SET_OUT(out_pretty_name, g_steal_pointer(&pretty_name_local));
-    NM_SET_OUT(out_description, g_steal_pointer(&description_local));
-    NM_SET_OUT(out_add_detail_key, g_steal_pointer(&add_detail_key_local));
-    NM_SET_OUT(out_add_detail_val, g_steal_pointer(&add_detail_val_local));
-    NM_SET_OUT(out_flags, flags_local);
-    return TRUE;
-}
-
-/*****************************************************************************
- * Implementation
- *
- * The following glue code can be used to implement calls in a VPN plugin.
- *****************************************************************************/
-
-#define NM_VPN_EDITOR_PLUGIN_VT_DEFINE(vt_name, get_vt, ...)                                \
-    static const NMVpnEditorPluginVT  vt_name = {__VA_ARGS__};                              \
-    static const NMVpnEditorPluginVT *get_vt(NMVpnEditorPlugin *plugin, gsize *out_vt_size) \
-    {                                                                                       \
-        nm_assert(NM_IS_VPN_EDITOR_PLUGIN(plugin));                                         \
-        nm_assert(out_vt_size);                                                             \
-                                                                                            \
-        *out_vt_size = sizeof(vt_name);                                                     \
-        return &vt_name;                                                                    \
-    }
-
-#endif /* __NM_VPN_EDITOR_PLUGIN_CALL_H__ */
diff --git a/shared/nm-utils/nm-vpn-plugin-macros.h b/shared/nm-utils/nm-vpn-plugin-macros.h
deleted file mode 100644
index 4ca22427..00000000
--- a/shared/nm-utils/nm-vpn-plugin-macros.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2016 Red Hat, Inc.
- */
-
-#ifndef __NM_VPN_PLUGIN_MACROS_H__
-#define __NM_VPN_PLUGIN_MACROS_H__
-
-#include <syslog.h>
-
-static inline int
-nm_utils_syslog_coerce_from_nm(int syslog_level)
-{
-    /* NetworkManager uses internally NMLogLevel levels. When spawning
-     * the VPN plugin, it maps those levels to syslog levels as follows:
-     *
-     *  LOGL_INFO = LOG_NOTICE,
-     *  LOGL_DEBUG = LOG_INFO,
-     *  LOGL_TRACE = LOG_DEBUG,
-     *
-     * However, when actually printing to syslog, we don't want to print messages
-     * with LOGL_INFO level as LOG_NOTICE, because they are *not* to be highlighted.
-     *
-     * In other words: NetworkManager has 3 levels that should not require highlighting:
-     * LOGL_INFO, LOGL_DEBUG, LOGL_TRACE. syslog on the other hand has only LOG_INFO and LOG_DEBUG.
-     *
-     * So, coerce those values before printing to syslog. When you receive the syslog_level
-     * from NetworkManager, instead of calling
-     *   syslog(syslog_level, ...)
-     * you should call
-     *   syslog(nm_utils_syslog_coerce_from_nm(syslog_level), ...)
-     */
-    switch (syslog_level) {
-    case LOG_INFO:
-        return LOG_DEBUG;
-    case LOG_NOTICE:
-        return LOG_INFO;
-    default:
-        return syslog_level;
-    }
-}
-
-static inline const char *
-nm_utils_syslog_to_str(int syslog_level)
-{
-    /* Maps the levels the same way as NetworkManager's nm-logging.c does */
-    if (syslog_level >= LOG_DEBUG)
-        return "<trace>";
-    if (syslog_level >= LOG_INFO)
-        return "<debug>";
-    if (syslog_level >= LOG_NOTICE)
-        return "<info>";
-    if (syslog_level >= LOG_WARNING)
-        return "<warn>";
-    return "<error>";
-}
-
-/*****************************************************************************/
-
-/* possibly missing defines from newer libnm API. */
-
-#ifndef NM_VPN_PLUGIN_CONFIG_PROXY_PAC
-    #define NM_VPN_PLUGIN_CONFIG_PROXY_PAC "pac"
-#endif
-
-#ifndef NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES
-    #define NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES "preserve-routes"
-#endif
-
-#ifndef NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES
-    #define NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES "preserve-routes"
-#endif
-
-/*****************************************************************************/
-
-#endif /* __NM_VPN_PLUGIN_MACROS_H__ */
diff --git a/shared/nm-utils/nm-vpn-plugin-utils.c b/shared/nm-utils/nm-vpn-plugin-utils.c
deleted file mode 100644
index 89285ecd..00000000
--- a/shared/nm-utils/nm-vpn-plugin-utils.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2016, 2018 Red Hat, Inc.
- */
-
-#include "libnm/nm-default-client.h"
-
-#include "nm-vpn-plugin-utils.h"
-
-#include <dlfcn.h>
-
-/*****************************************************************************/
-
-NMVpnEditor *
-nm_vpn_plugin_utils_load_editor(const char *                  module_name,
-                                const char *                  factory_name,
-                                NMVpnPluginUtilsEditorFactory editor_factory,
-                                NMVpnEditorPlugin *           editor_plugin,
-                                NMConnection *                connection,
-                                gpointer                      user_data,
-                                GError **                     error)
-
-{
-    static struct {
-        gpointer factory;
-        void *   dl_module;
-        char *   module_name;
-        char *   factory_name;
-    } cached = {0};
-    NMVpnEditor * editor;
-    gs_free char *module_path = NULL;
-    gs_free char *dirname     = NULL;
-    Dl_info       plugin_info;
-
-    g_return_val_if_fail(module_name, NULL);
-    g_return_val_if_fail(factory_name && factory_name[0], NULL);
-    g_return_val_if_fail(editor_factory, NULL);
-    g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(editor_plugin), NULL);
-    g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL);
-    g_return_val_if_fail(!error || !*error, NULL);
-
-    if (!g_path_is_absolute(module_name)) {
-        /*
-         * Load an editor from the same directory this plugin is in.
-         * Ideally, we'd get our .so name from the NMVpnEditorPlugin if it
-         * would just have a property with it...
-         */
-        if (!dladdr(nm_vpn_plugin_utils_load_editor, &plugin_info)) {
-            /* Really a "can not happen" scenario. */
-            g_set_error(error,
-                        NM_VPN_PLUGIN_ERROR,
-                        NM_VPN_PLUGIN_ERROR_FAILED,
-                        _("unable to get editor plugin name: %s"),
-                        dlerror());
-        }
-
-        dirname     = g_path_get_dirname(plugin_info.dli_fname);
-        module_path = g_build_filename(dirname, module_name, NULL);
-    } else {
-        module_path = g_strdup(module_name);
-    }
-
-    /* we really expect this function to be called with unchanging @module_name
-     * and @factory_name. And we only want to load the module once, hence it would
-     * be more complicated to accept changing @module_name/@factory_name arguments.
-     *
-     * The reason for only loading once is that due to glib types, we cannot create a
-     * certain type-name more then once, so loading the same module or another version
-     * of the same module will fail horribly as both try to create a GType with the same
-     * name.
-     *
-     * Only support loading once, any future calls will reuse the handle. To simplify
-     * that, we enforce that the @factory_name and @module_name is the same. */
-    if (cached.factory) {
-        g_return_val_if_fail(cached.dl_module, NULL);
-        g_return_val_if_fail(cached.factory_name && nm_streq0(cached.factory_name, factory_name),
-                             NULL);
-        g_return_val_if_fail(cached.module_name && nm_streq0(cached.module_name, module_name),
-                             NULL);
-    } else {
-        gpointer factory;
-        void *   dl_module;
-
-        dl_module = dlopen(module_path, RTLD_LAZY | RTLD_LOCAL);
-        if (!dl_module) {
-            if (!g_file_test(module_path, G_FILE_TEST_EXISTS)) {
-                g_set_error(error,
-                            G_FILE_ERROR,
-                            G_FILE_ERROR_NOENT,
-                            _("missing plugin file \"%s\""),
-                            module_path);
-                return NULL;
-            }
-            g_set_error(error,
-                        NM_VPN_PLUGIN_ERROR,
-                        NM_VPN_PLUGIN_ERROR_FAILED,
-                        _("cannot load editor plugin: %s"),
-                        dlerror());
-            return NULL;
-        }
-
-        factory = dlsym(dl_module, factory_name);
-        if (!factory) {
-            g_set_error(error,
-                        NM_VPN_PLUGIN_ERROR,
-                        NM_VPN_PLUGIN_ERROR_FAILED,
-                        _("cannot load factory %s from plugin: %s"),
-                        factory_name,
-                        dlerror());
-            dlclose(dl_module);
-            return NULL;
-        }
-
-        /* we cannot ever unload the module because it creates glib types, which
-         * cannot be unregistered.
-         *
-         * Thus we just leak the dl_module handle indefinitely. */
-        cached.factory      = factory;
-        cached.dl_module    = dl_module;
-        cached.module_name  = g_strdup(module_name);
-        cached.factory_name = g_strdup(factory_name);
-    }
-
-    editor = editor_factory(cached.factory, editor_plugin, connection, user_data, error);
-    if (!editor) {
-        if (error && !*error) {
-            g_set_error_literal(error,
-                                NM_VPN_PLUGIN_ERROR,
-                                NM_VPN_PLUGIN_ERROR_FAILED,
-                                _("unknown error creating editor instance"));
-            g_return_val_if_reached(NULL);
-        }
-        return NULL;
-    }
-
-    g_return_val_if_fail(NM_IS_VPN_EDITOR(editor), NULL);
-    return editor;
-}
diff --git a/shared/nm-utils/nm-vpn-plugin-utils.h b/shared/nm-utils/nm-vpn-plugin-utils.h
deleted file mode 100644
index 881a368a..00000000
--- a/shared/nm-utils/nm-vpn-plugin-utils.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2016 Red Hat, Inc.
- */
-
-#ifndef __NM_VPN_PLUGIN_UTILS_H__
-#define __NM_VPN_PLUGIN_UTILS_H__
-
-#include <NetworkManager.h>
-
-typedef NMVpnEditor *(NMVpnPluginUtilsEditorFactory)(gpointer           factory,
-                                                     NMVpnEditorPlugin *editor_plugin,
-                                                     NMConnection *     connection,
-                                                     gpointer           user_data,
-                                                     GError **          error);
-
-NMVpnEditor *nm_vpn_plugin_utils_load_editor(const char *                  module_name,
-                                             const char *                  factory_name,
-                                             NMVpnPluginUtilsEditorFactory editor_factory,
-                                             NMVpnEditorPlugin *           editor_plugin,
-                                             NMConnection *                connection,
-                                             gpointer                      user_data,
-                                             GError **                     error);
-
-#endif /* __NM_VPN_PLUGIN_UTILS_H__ */
diff --git a/shared/systemd/nm-default-systemd-shared.h b/shared/systemd/nm-default-systemd-shared.h
deleted file mode 100644
index bc0e6c4c..00000000
--- a/shared/systemd/nm-default-systemd-shared.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* 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
deleted file mode 100644
index 8db90cd9..00000000
--- a/shared/systemd/nm-logging-stub.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "shared/systemd/nm-default-systemd-shared.h"
-
-#include "nm-glib-aux/nm-logging-fwd.h"
-
-/*****************************************************************************/
-
-gboolean
-_nm_log_enabled_impl(gboolean mt_require_locking, NMLogLevel level, NMLogDomain domain)
-{
-    return FALSE;
-}
-
-void
-_nm_log_impl(const char *file,
-             guint       line,
-             const char *func,
-             gboolean    mt_require_locking,
-             NMLogLevel  level,
-             NMLogDomain domain,
-             int         error,
-             const char *ifname,
-             const char *con_uuid,
-             const char *fmt,
-             ...)
-{}
-
-void
-_nm_utils_monotonic_timestamp_initialized(const struct timespec *tp,
-                                          gint64                 offset_sec,
-                                          gboolean               is_boottime)
-{}
diff --git a/shared/systemd/nm-sd-utils-shared.c b/shared/systemd/nm-sd-utils-shared.c
deleted file mode 100644
index f0504aa9..00000000
--- a/shared/systemd/nm-sd-utils-shared.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "shared/systemd/nm-default-systemd-shared.h"
-
-#include "nm-sd-utils-shared.h"
-
-#include "nm-sd-adapt-shared.h"
-
-#include "dns-domain.h"
-#include "hexdecoct.h"
-#include "hostname-util.h"
-#include "path-util.h"
-#include "web-util.h"
-
-/*****************************************************************************/
-
-const bool mempool_use_allowed = true;
-
-/*****************************************************************************/
-
-gboolean
-nm_sd_utils_path_equal(const char *a, const char *b)
-{
-    return path_equal(a, b);
-}
-
-char *
-nm_sd_utils_path_simplify(char *path, gboolean kill_dots)
-{
-    return path_simplify(path, kill_dots);
-}
-
-const char *
-nm_sd_utils_path_startswith(const char *path, const char *prefix)
-{
-    return path_startswith(path, prefix);
-}
-
-/*****************************************************************************/
-
-int
-nm_sd_utils_unbase64char(char ch, gboolean accept_padding_equal)
-{
-    if (ch == '=' && accept_padding_equal)
-        return G_MAXINT;
-    return unbase64char(ch);
-}
-
-/**
- * nm_sd_utils_unbase64mem:
- * @p: a valid base64 string. Whitespace is ignored, but invalid encodings
- *   will cause the function to fail.
- * @l: the length of @p. @p is not treated as NUL terminated string but
- *   merely as a buffer of ascii characters.
- * @secure: whether the temporary memory will be cleared to avoid leaving
- *   secrets in memory (see also nm_explicit_bzero()).
- * @mem: (transfer full): the decoded buffer on success.
- * @len: the length of @mem on success.
- *
- * glib provides g_base64_decode(), but that does not report any errors
- * from invalid encodings. Expose systemd's implementation which does
- * reject invalid inputs.
- *
- * Returns: a non-negative code on success. Invalid encoding let the
- *   function fail.
- */
-int
-nm_sd_utils_unbase64mem(const char *p, size_t l, gboolean secure, guint8 **mem, size_t *len)
-{
-    return unbase64mem_full(p, l, secure, (void **) mem, len);
-}
-
-int
-nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gboolean canonical)
-{
-    return dns_name_to_wire_format(domain, buffer, len, canonical);
-}
-
-int
-nm_sd_dns_name_is_valid(const char *s)
-{
-    return dns_name_is_valid(s);
-}
-
-gboolean
-nm_sd_hostname_is_valid(const char *s, bool 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);
-}
-
-/*****************************************************************************/
-
-static gboolean
-_http_url_is_valid(const char *url, gboolean only_https)
-{
-    if (!url || !url[0])
-        return FALSE;
-
-    if (!only_https && NM_STR_HAS_PREFIX(url, "http://"))
-        url += NM_STRLEN("http://");
-    else if (NM_STR_HAS_PREFIX(url, "https://"))
-        url += NM_STRLEN("https://");
-    else
-        return FALSE;
-
-    if (!url[0])
-        return FALSE;
-
-    return !NM_STRCHAR_ANY(url, ch, (guchar) ch >= 128u);
-}
-
-gboolean
-nm_sd_http_url_is_valid_https(const char *url)
-{
-    /* We use this function to verify connection:mud-url property, it must thus
-     * not change behavior.
-     *
-     * Note that sd_dhcp_client_set_mud_url() and sd_dhcp6_client_set_request_mud_url()
-     * assert with http_url_is_valid() that the argument is valid. We thus must make
-     * sure to only pass URLs that are valid according to http_url_is_valid().
-     *
-     * This is given, because our nm_sd_http_url_is_valid_https() is more strict
-     * than http_url_is_valid().
-     *
-     * We only must make sure that this is also correct in the future, when we
-     * re-import systemd code. */
-    nm_assert(_http_url_is_valid(url, FALSE) == http_url_is_valid(url));
-    return _http_url_is_valid(url, TRUE);
-}
-
-/*****************************************************************************/
-
-int
-nmtst_systemd_extract_first_word_all(const char *str, char ***out_strv)
-{
-    gs_unref_ptrarray GPtrArray *arr = NULL;
-
-    /* we implement a str split function to parse `/proc/cmdline`. This
-     * code should behave like systemd, which uses extract_first_word()
-     * for that.
-     *
-     * As we want to unit-test our implementation to match systemd,
-     * expose this function for testing. */
-
-    g_assert(out_strv);
-    g_assert(!*out_strv);
-
-    if (!str)
-        return 0;
-
-    arr = g_ptr_array_new_with_free_func(g_free);
-
-    for (;;) {
-        gs_free char *word = NULL;
-        int           r;
-
-        r = extract_first_word(&str, &word, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX);
-        if (r < 0)
-            return r;
-        if (r == 0)
-            break;
-        g_ptr_array_add(arr, g_steal_pointer(&word));
-    }
-
-    g_ptr_array_add(arr, NULL);
-
-    *out_strv = (char **) g_ptr_array_free(g_steal_pointer(&arr), FALSE);
-    return 1;
-}
diff --git a/shared/systemd/nm-sd-utils-shared.h b/shared/systemd/nm-sd-utils-shared.h
deleted file mode 100644
index 45089c07..00000000
--- a/shared/systemd/nm-sd-utils-shared.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_SD_UTILS_SHARED_H__
-#define __NM_SD_UTILS_SHARED_H__
-
-/*****************************************************************************/
-
-gboolean nm_sd_utils_path_equal(const char *a, const char *b);
-
-char *nm_sd_utils_path_simplify(char *path, gboolean kill_dots);
-
-const char *nm_sd_utils_path_startswith(const char *path, const char *prefix);
-
-/*****************************************************************************/
-
-int nm_sd_utils_unbase64char(char ch, gboolean accept_padding_equal);
-
-int nm_sd_utils_unbase64mem(const char *p, size_t l, gboolean secure, guint8 **mem, size_t *len);
-
-/*****************************************************************************/
-
-int
-nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gboolean canonical);
-
-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);
-
-/*****************************************************************************/
-
-int nmtst_systemd_extract_first_word_all(const char *str, char ***out_strv);
-
-#endif /* __NM_SD_UTILS_SHARED_H__ */
diff --git a/shared/systemd/sd-adapt-shared/architecture.h b/shared/systemd/sd-adapt-shared/architecture.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/architecture.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/arphrd-list.h b/shared/systemd/sd-adapt-shared/arphrd-list.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/arphrd-list.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/blockdev-util.h b/shared/systemd/sd-adapt-shared/blockdev-util.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/blockdev-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/build.h b/shared/systemd/sd-adapt-shared/build.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/build.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/copy.h b/shared/systemd/sd-adapt-shared/copy.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/copy.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/def.h b/shared/systemd/sd-adapt-shared/def.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/def.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/dhcp-server-internal.h b/shared/systemd/sd-adapt-shared/dhcp-server-internal.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/dhcp-server-internal.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/dirent-util.h b/shared/systemd/sd-adapt-shared/dirent-util.h
deleted file mode 100644
index 7132dfcc..00000000
--- a/shared/systemd/sd-adapt-shared/dirent-util.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-
-/* dummy header */
-
-#include "path-util.h"
diff --git a/shared/systemd/sd-adapt-shared/errno-list.h b/shared/systemd/sd-adapt-shared/errno-list.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/errno-list.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/glob-util.h b/shared/systemd/sd-adapt-shared/glob-util.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/glob-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/gunicode.h b/shared/systemd/sd-adapt-shared/gunicode.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/gunicode.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/idn-util.h b/shared/systemd/sd-adapt-shared/idn-util.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/idn-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/ioprio.h b/shared/systemd/sd-adapt-shared/ioprio.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/ioprio.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/locale-util.h b/shared/systemd/sd-adapt-shared/locale-util.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/locale-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/memfd-util.h b/shared/systemd/sd-adapt-shared/memfd-util.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/memfd-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/missing_fs.h b/shared/systemd/sd-adapt-shared/missing_fs.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/missing_fs.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/missing_keyctl.h b/shared/systemd/sd-adapt-shared/missing_keyctl.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/missing_keyctl.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/missing_magic.h b/shared/systemd/sd-adapt-shared/missing_magic.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/missing_magic.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/missing_network.h b/shared/systemd/sd-adapt-shared/missing_network.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/missing_network.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/missing_sched.h b/shared/systemd/sd-adapt-shared/missing_sched.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/missing_sched.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/missing_timerfd.h b/shared/systemd/sd-adapt-shared/missing_timerfd.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/missing_timerfd.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/mkdir.h b/shared/systemd/sd-adapt-shared/mkdir.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/mkdir.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/namespace-util.h b/shared/systemd/sd-adapt-shared/namespace-util.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/namespace-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#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
deleted file mode 100644
index b094ce40..00000000
--- a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2014 - 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_SD_ADAPT_SHARED_H__
-#define __NM_SD_ADAPT_SHARED_H__
-
-#include "shared/systemd/nm-default-systemd-shared.h"
-
-#include "nm-glib-aux/nm-logging-fwd.h"
-
-/*****************************************************************************/
-
-/* strerror() is not thread-safe. Patch systemd-sources via a define. */
-#define strerror(errsv) nm_strerror_native(errsv)
-
-/*****************************************************************************/
-
-/* systemd detects whether compiler supports "-Wstringop-truncation" to disable
- * the warning at particular places. Since we anyway build with -Wno-pragma,
- * we don't do that and just let systemd call
- *
- *   _Pragma("GCC diagnostic ignored \"-Wstringop-truncation\"")
- *
- * regadless whether that would result in a -Wpragma warning. */
-#define HAVE_WSTRINGOP_TRUNCATION 1
-
-/*****************************************************************************/
-
-static inline int
-_nm_log_get_max_level_realm(void)
-{
-    /* inline function, to avoid coverity warning about constant expression. */
-    return 7 /* LOG_DEBUG */;
-}
-#define log_get_max_level_realm(realm) _nm_log_get_max_level_realm()
-
-#define log_internal_realm(level, error, file, line, func, format, ...)                    \
-    ({                                                                                     \
-        const int        _nm_e = (error);                                                  \
-        const NMLogLevel _nm_l = nm_log_level_from_syslog(LOG_PRI(level));                 \
-                                                                                           \
-        if (_nm_log_enabled_impl(!(NM_THREAD_SAFE_ON_MAIN_THREAD), _nm_l, LOGD_SYSTEMD)) { \
-            const char *_nm_location = strrchr(("" file), '/');                            \
-                                                                                           \
-            _nm_log_impl(_nm_location ? _nm_location + 1 : ("" file),                      \
-                         (line),                                                           \
-                         (func),                                                           \
-                         !(NM_THREAD_SAFE_ON_MAIN_THREAD),                                 \
-                         _nm_l,                                                            \
-                         LOGD_SYSTEMD,                                                     \
-                         _nm_e,                                                            \
-                         NULL,                                                             \
-                         NULL,                                                             \
-                         ("%s" format),                                                    \
-                         "libsystemd: ",                                                   \
-                         ##__VA_ARGS__);                                                   \
-        }                                                                                  \
-        (_nm_e > 0 ? -_nm_e : _nm_e);                                                      \
-    })
-
-#define log_assert_failed(text, file, line, func)                                \
-    G_STMT_START                                                                 \
-    {                                                                            \
-        log_internal(LOG_CRIT,                                                   \
-                     0,                                                          \
-                     file,                                                       \
-                     line,                                                       \
-                     func,                                                       \
-                     "Assertion '%s' failed at %s:%u, function %s(). Aborting.", \
-                     text,                                                       \
-                     file,                                                       \
-                     line,                                                       \
-                     func);                                                      \
-        g_assert_not_reached();                                                  \
-    }                                                                            \
-    G_STMT_END
-
-#define log_assert_failed_unreachable(text, file, line, func)                              \
-    G_STMT_START                                                                           \
-    {                                                                                      \
-        log_internal(LOG_CRIT,                                                             \
-                     0,                                                                    \
-                     file,                                                                 \
-                     line,                                                                 \
-                     func,                                                                 \
-                     "Code should not be reached '%s' at %s:%u, function %s(). Aborting.", \
-                     text,                                                                 \
-                     file,                                                                 \
-                     line,                                                                 \
-                     func);                                                                \
-        g_assert_not_reached();                                                            \
-    }                                                                                      \
-    G_STMT_END
-
-#define log_assert_failed_return(text, file, line, func)                         \
-    ({                                                                           \
-        log_internal(LOG_DEBUG,                                                  \
-                     0,                                                          \
-                     file,                                                       \
-                     line,                                                       \
-                     func,                                                       \
-                     "Assertion '%s' failed at %s:%u, function %s(). Ignoring.", \
-                     text,                                                       \
-                     file,                                                       \
-                     line,                                                       \
-                     func);                                                      \
-        g_return_if_fail_warning(G_LOG_DOMAIN, G_STRFUNC, text);                 \
-        (void) 0;                                                                \
-    })
-
-/*****************************************************************************/
-
-#ifndef VALGRIND
-    #define VALGRIND 0
-#endif
-
-#define ENABLE_DEBUG_HASHMAP 0
-
-/*****************************************************************************
- * The remainder of the header is only enabled when building the systemd code
- * itself.
- *****************************************************************************/
-
-#if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD
-
-    #include <sys/syscall.h>
-    #include <sys/ioctl.h>
-    #include <pthread.h>
-
-    #define ENABLE_GSHADOW FALSE
-
-    #define HAVE_SECCOMP 0
-
-/*****************************************************************************/
-
-/* systemd cannot be compiled with "-Wdeclaration-after-statement". In particular
- * in combination with assert_cc(). */
-NM_PRAGMA_WARNING_DISABLE("-Wdeclaration-after-statement")
-
-/*****************************************************************************/
-
-struct statx;
-
-/*****************************************************************************/
-
-static inline pid_t
-raw_getpid(void)
-{
-    #if defined(__alpha__)
-    return (pid_t) syscall(__NR_getxpid);
-    #else
-    return (pid_t) syscall(__NR_getpid);
-    #endif
-}
-
-static inline pid_t
-_nm_gettid(void)
-{
-    return (pid_t) syscall(SYS_gettid);
-}
-    #define gettid() _nm_gettid()
-
-    /* we build with C11 and thus <uchar.h> provides char32_t,char16_t. */
-    #define HAVE_CHAR32_T 1
-    #define HAVE_CHAR16_T 1
-
-    #if defined(HAVE_DECL_REALLOCARRAY) && HAVE_DECL_REALLOCARRAY == 1
-        #define HAVE_REALLOCARRAY 1
-    #else
-        #define HAVE_REALLOCARRAY 0
-    #endif
-
-    #if defined(HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO == 1
-        #define HAVE_EXPLICIT_BZERO 1
-    #else
-        #define HAVE_EXPLICIT_BZERO 0
-    #endif
-
-    #if defined(HAVE_DECL_PIDFD_OPEN) && HAVE_DECL_PIDFD_OPEN == 1
-        #define HAVE_PIDFD_OPEN 1
-    #else
-        #define HAVE_PIDFD_OPEN 0
-    #endif
-
-    #if defined(HAVE_DECL_PIDFD_SEND_SIGNAL) && HAVE_DECL_PIDFD_SEND_SIGNAL == 1
-        #define HAVE_PIDFD_SEND_SIGNAL 1
-    #else
-        #define HAVE_PIDFD_SEND_SIGNAL 0
-    #endif
-
-    #if defined(HAVE_DECL_RT_SIGQUEUEINFO) && HAVE_DECL_RT_SIGQUEUEINFO == 1
-        #define HAVE_RT_SIGQUEUEINFO 1
-    #else
-        #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 */
-
-/*****************************************************************************/
-
-#endif /* __NM_SD_ADAPT_SHARED_H__ */
diff --git a/shared/systemd/sd-adapt-shared/nulstr-util.h b/shared/systemd/sd-adapt-shared/nulstr-util.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/nulstr-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/raw-clone.h b/shared/systemd/sd-adapt-shared/raw-clone.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/raw-clone.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/rlimit-util.h b/shared/systemd/sd-adapt-shared/rlimit-util.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/rlimit-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/terminal-util.h b/shared/systemd/sd-adapt-shared/terminal-util.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/terminal-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/unaligned.h b/shared/systemd/sd-adapt-shared/unaligned.h
deleted file mode 100644
index ac1a6928..00000000
--- a/shared/systemd/sd-adapt-shared/unaligned.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-#include "nm-std-aux/unaligned.h"
diff --git a/shared/systemd/sd-adapt-shared/user-util.h b/shared/systemd/sd-adapt-shared/user-util.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/user-util.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/sd-adapt-shared/virt.h b/shared/systemd/sd-adapt-shared/virt.h
deleted file mode 100644
index 637892c2..00000000
--- a/shared/systemd/sd-adapt-shared/virt.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-/* dummy header */
diff --git a/shared/systemd/src/basic/alloc-util.c b/shared/systemd/src/basic/alloc-util.c
deleted file mode 100644
index 7f7eb433..00000000
--- a/shared/systemd/src/basic/alloc-util.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <malloc.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "alloc-util.h"
-#include "macro.h"
-#include "memory-util.h"
-
-void* memdup(const void *p, size_t l) {
-        void *ret;
-
-        assert(l == 0 || p);
-
-        ret = malloc(l ?: 1);
-        if (!ret)
-                return NULL;
-
-        memcpy(ret, p, l);
-        return ret;
-}
-
-void* memdup_suffix0(const void *p, size_t l) {
-        void *ret;
-
-        assert(l == 0 || p);
-
-        /* The same as memdup() but place a safety NUL byte after the allocated memory */
-
-        if (_unlikely_(l == SIZE_MAX)) /* prevent overflow */
-                return NULL;
-
-        ret = malloc(l + 1);
-        if (!ret)
-                return NULL;
-
-        *((uint8_t*) mempcpy(ret, p, l)) = 0;
-        return ret;
-}
-
-void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
-        size_t a, newalloc;
-        void *q;
-
-        assert(p);
-        assert(allocated);
-
-        if (*allocated >= need)
-                return *p;
-
-        if (_unlikely_(need > SIZE_MAX/2)) /* Overflow check */
-                return NULL;
-
-        newalloc = need * 2;
-        if (size_multiply_overflow(newalloc, size))
-                return NULL;
-
-        a = newalloc * size;
-        if (a < 64) /* Allocate at least 64 bytes */
-                a = 64;
-
-        q = realloc(*p, a);
-        if (!q)
-                return NULL;
-
-        if (size > 0) {
-                size_t bn;
-
-                /* Adjust for the 64 byte minimum */
-                newalloc = a / size;
-
-                bn = malloc_usable_size(q) / size;
-                if (bn > newalloc) {
-                        void *qq;
-
-                        /* The actual size allocated is larger than what we asked for. Let's call realloc() again to
-                         * take possession of the extra space. This should be cheap, since libc doesn't have to move
-                         * the memory for this. */
-
-                        qq = reallocarray(q, bn, size);
-                        if (_likely_(qq)) {
-                                *p = qq;
-                                *allocated = bn;
-                                return qq;
-                        }
-                }
-        }
-
-        *p = q;
-        *allocated = newalloc;
-        return q;
-}
-
-void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
-        size_t prev;
-        uint8_t *q;
-
-        assert(p);
-        assert(allocated);
-
-        prev = *allocated;
-
-        q = greedy_realloc(p, allocated, need, size);
-        if (!q)
-                return NULL;
-
-        if (*allocated > prev)
-                memzero(q + prev * size, (*allocated - prev) * size);
-
-        return q;
-}
diff --git a/shared/systemd/src/basic/alloc-util.h b/shared/systemd/src/basic/alloc-util.h
deleted file mode 100644
index f3e192dd..00000000
--- a/shared/systemd/src/basic/alloc-util.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <alloca.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "macro.h"
-
-#if HAS_FEATURE_MEMORY_SANITIZER
-#  include <sanitizer/msan_interface.h>
-#endif
-
-typedef void (*free_func_t)(void *p);
-
-/* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than
- * proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */
-#define ALLOCA_MAX (4U*1024U*1024U)
-
-#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
-
-#define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t)))
-
-#define newa(t, n)                                                      \
-        ({                                                              \
-                size_t _n_ = n;                                         \
-                assert(!size_multiply_overflow(sizeof(t), _n_));        \
-                assert(sizeof(t)*_n_ <= ALLOCA_MAX);                    \
-                (t*) alloca((sizeof(t)*_n_) ?: 1);                      \
-        })
-
-#define newa0(t, n)                                                     \
-        ({                                                              \
-                size_t _n_ = n;                                         \
-                assert(!size_multiply_overflow(sizeof(t), _n_));        \
-                assert(sizeof(t)*_n_ <= ALLOCA_MAX);                    \
-                (t*) alloca0((sizeof(t)*_n_) ?: 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) ?: 1))
-
-static inline void *mfree(void *memory) {
-        free(memory);
-        return NULL;
-}
-
-#define free_and_replace(a, b)                  \
-        ({                                      \
-                free(a);                        \
-                (a) = (b);                      \
-                (b) = NULL;                     \
-                0;                              \
-        })
-
-void* memdup(const void *p, size_t l) _alloc_(2);
-void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, since we return a buffer one byte larger than the specified size */
-
-#define memdupa(p, l)                           \
-        ({                                      \
-                void *_q_;                      \
-                size_t _l_ = l;                 \
-                assert(_l_ <= ALLOCA_MAX);      \
-                _q_ = alloca(_l_ ?: 1);         \
-                memcpy(_q_, p, _l_);            \
-        })
-
-#define memdupa_suffix0(p, l)                   \
-        ({                                      \
-                void *_q_;                      \
-                size_t _l_ = l;                 \
-                assert(_l_ <= ALLOCA_MAX);      \
-                _q_ = alloca(_l_ + 1);          \
-                ((uint8_t*) _q_)[_l_] = 0;      \
-                memcpy(_q_, p, _l_);            \
-        })
-
-static inline void freep(void *p) {
-        free(*(void**) p);
-}
-
-#define _cleanup_free_ _cleanup_(freep)
-
-static inline bool size_multiply_overflow(size_t size, size_t need) {
-        return _unlikely_(need != 0 && size > (SIZE_MAX / need));
-}
-
-_malloc_  _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
-        if (size_multiply_overflow(size, need))
-                return NULL;
-
-        return malloc(size * need ?: 1);
-}
-
-#if !HAVE_REALLOCARRAY
-_alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) {
-        if (size_multiply_overflow(size, need))
-                return NULL;
-
-        return realloc(p, size * need ?: 1);
-}
-#endif
-
-_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
-        if (size_multiply_overflow(size, need))
-                return NULL;
-
-        return memdup(p, size * need);
-}
-
-/* Note that we can't decorate this function with _alloc_() since the returned memory area is one byte larger
- * than the product of its parameters. */
-static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
-        if (size_multiply_overflow(size, need))
-                return NULL;
-
-        return memdup_suffix0(p, size * need);
-}
-
-void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
-void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
-
-#define GREEDY_REALLOC(array, allocated, need)                          \
-        greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
-
-#define GREEDY_REALLOC0(array, allocated, need)                         \
-        greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
-
-#define alloca0(n)                                      \
-        ({                                              \
-                char *_new_;                            \
-                size_t _len_ = n;                       \
-                assert(_len_ <= ALLOCA_MAX);            \
-                _new_ = alloca(_len_ ?: 1);             \
-                (void *) memset(_new_, 0, _len_);       \
-        })
-
-/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
-#define alloca_align(size, align)                                       \
-        ({                                                              \
-                void *_ptr_;                                            \
-                size_t _mask_ = (align) - 1;                            \
-                size_t _size_ = size;                                   \
-                assert(_size_ <= ALLOCA_MAX);                           \
-                _ptr_ = alloca((_size_ + _mask_) ?: 1);                 \
-                (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_);         \
-        })
-
-#define alloca0_align(size, align)                                      \
-        ({                                                              \
-                void *_new_;                                            \
-                size_t _xsize_ = (size);                                \
-                _new_ = alloca_align(_xsize_, (align));                 \
-                (void*)memset(_new_, 0, _xsize_);                       \
-        })
-
-/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time
- * resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
-#define TAKE_PTR(ptr)                           \
-        ({                                      \
-                typeof(ptr) _ptr_ = (ptr);      \
-                (ptr) = NULL;                   \
-                _ptr_;                          \
-        })
-
-#if HAS_FEATURE_MEMORY_SANITIZER
-#  define msan_unpoison(r, s) __msan_unpoison(r, s)
-#else
-#  define msan_unpoison(r, s)
-#endif
diff --git a/shared/systemd/src/basic/async.h b/shared/systemd/src/basic/async.h
deleted file mode 100644
index e0bbaa56..00000000
--- a/shared/systemd/src/basic/async.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* 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
deleted file mode 100644
index bdc0d0d0..00000000
--- a/shared/systemd/src/basic/cgroup-util.h
+++ /dev/null
@@ -1,290 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <dirent.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-
-#include "def.h"
-#include "set.h"
-
-#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=systemd"
-#define SYSTEMD_CGROUP_CONTROLLER_HYBRID "name=unified"
-#define SYSTEMD_CGROUP_CONTROLLER "_systemd"
-
-/* An enum of well known cgroup controllers */
-typedef enum CGroupController {
-        /* Original cgroup controllers */
-        CGROUP_CONTROLLER_CPU,
-        CGROUP_CONTROLLER_CPUACCT,    /* v1 only */
-        CGROUP_CONTROLLER_CPUSET,     /* v2 only */
-        CGROUP_CONTROLLER_IO,         /* v2 only */
-        CGROUP_CONTROLLER_BLKIO,      /* v1 only */
-        CGROUP_CONTROLLER_MEMORY,
-        CGROUP_CONTROLLER_DEVICES,    /* v1 only */
-        CGROUP_CONTROLLER_PIDS,
-
-        /* BPF-based pseudo-controllers, v2 only */
-        CGROUP_CONTROLLER_BPF_FIREWALL,
-        CGROUP_CONTROLLER_BPF_DEVICES,
-
-        _CGROUP_CONTROLLER_MAX,
-        _CGROUP_CONTROLLER_INVALID = -1,
-} CGroupController;
-
-#define CGROUP_CONTROLLER_TO_MASK(c) (1U << (c))
-
-/* A bit mask of well known cgroup controllers */
-typedef enum CGroupMask {
-        CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU),
-        CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT),
-        CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET),
-        CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO),
-        CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
-        CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
-        CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES),
-        CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS),
-        CGROUP_MASK_BPF_FIREWALL = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FIREWALL),
-        CGROUP_MASK_BPF_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_DEVICES),
-
-        /* All real cgroup v1 controllers */
-        CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS,
-
-        /* All real cgroup v2 controllers */
-        CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS,
-
-        /* All cgroup v2 BPF pseudo-controllers */
-        CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES,
-
-        _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
-} CGroupMask;
-
-static inline CGroupMask CGROUP_MASK_EXTEND_JOINED(CGroupMask mask) {
-        /* We always mount "cpu" and "cpuacct" in the same hierarchy. Hence, when one bit is set also set the other */
-
-        if (mask & (CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT))
-                mask |= (CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT);
-
-        return mask;
-}
-
-CGroupMask get_cpu_accounting_mask(void);
-bool cpu_accounting_is_cheap(void);
-
-/* Special values for all weight knobs on unified hierarchy */
-#define CGROUP_WEIGHT_INVALID ((uint64_t) -1)
-#define CGROUP_WEIGHT_MIN UINT64_C(1)
-#define CGROUP_WEIGHT_MAX UINT64_C(10000)
-#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
-
-#define CGROUP_LIMIT_MIN UINT64_C(0)
-#define CGROUP_LIMIT_MAX ((uint64_t) -1)
-
-static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) {
-        return
-            x == CGROUP_WEIGHT_INVALID ||
-            (x >= CGROUP_WEIGHT_MIN && x <= CGROUP_WEIGHT_MAX);
-}
-
-/* IO limits on unified hierarchy */
-typedef enum CGroupIOLimitType {
-        CGROUP_IO_RBPS_MAX,
-        CGROUP_IO_WBPS_MAX,
-        CGROUP_IO_RIOPS_MAX,
-        CGROUP_IO_WIOPS_MAX,
-
-        _CGROUP_IO_LIMIT_TYPE_MAX,
-        _CGROUP_IO_LIMIT_TYPE_INVALID = -1
-} CGroupIOLimitType;
-
-extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX];
-
-const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_;
-CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_;
-
-/* Special values for the cpu.shares attribute */
-#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1)
-#define CGROUP_CPU_SHARES_MIN UINT64_C(2)
-#define CGROUP_CPU_SHARES_MAX UINT64_C(262144)
-#define CGROUP_CPU_SHARES_DEFAULT UINT64_C(1024)
-
-static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) {
-        return
-            x == CGROUP_CPU_SHARES_INVALID ||
-            (x >= CGROUP_CPU_SHARES_MIN && x <= CGROUP_CPU_SHARES_MAX);
-}
-
-/* Special values for the blkio.weight attribute */
-#define CGROUP_BLKIO_WEIGHT_INVALID ((uint64_t) -1)
-#define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10)
-#define CGROUP_BLKIO_WEIGHT_MAX UINT64_C(1000)
-#define CGROUP_BLKIO_WEIGHT_DEFAULT UINT64_C(500)
-
-static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) {
-        return
-            x == CGROUP_BLKIO_WEIGHT_INVALID ||
-            (x >= CGROUP_BLKIO_WEIGHT_MIN && x <= CGROUP_BLKIO_WEIGHT_MAX);
-}
-
-typedef enum CGroupUnified {
-        CGROUP_UNIFIED_UNKNOWN = -1,
-        CGROUP_UNIFIED_NONE = 0,        /* Both systemd and controllers on legacy */
-        CGROUP_UNIFIED_SYSTEMD = 1,     /* Only systemd on unified */
-        CGROUP_UNIFIED_ALL = 2,         /* Both systemd and controllers on unified */
-} CGroupUnified;
-
-/*
- * General rules:
- *
- * We accept named hierarchies in the syntax "foo" and "name=foo".
- *
- * We expect that named hierarchies do not conflict in name with a
- * kernel hierarchy, modulo the "name=" prefix.
- *
- * We always generate "normalized" controller names, i.e. without the
- * "name=" prefix.
- *
- * We require absolute cgroup paths. When returning, we will always
- * generate paths with multiple adjacent / removed.
- */
-
-int cg_enumerate_processes(const char *controller, const char *path, FILE **_f);
-int cg_read_pid(FILE *f, pid_t *_pid);
-int cg_read_event(const char *controller, const char *path, const char *event,
-                  char **val);
-
-int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d);
-int cg_read_subgroup(DIR *d, char **fn);
-
-typedef enum CGroupFlags {
-        CGROUP_SIGCONT     = 1 << 0,
-        CGROUP_IGNORE_SELF = 1 << 1,
-        CGROUP_REMOVE      = 1 << 2,
-} CGroupFlags;
-
-typedef int (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata);
-
-int cg_kill(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
-int cg_kill_recursive(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
-
-int cg_split_spec(const char *spec, char **ret_controller, char **ret_path);
-int cg_mangle_path(const char *path, char **result);
-
-int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs);
-int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs);
-
-int cg_pid_get_path(const char *controller, pid_t pid, char **path);
-
-int cg_rmdir(const char *controller, const char *path);
-
-typedef enum  {
-        CG_KEY_MODE_GRACEFUL = 1 << 0,
-} CGroupKeyMode;
-
-int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value);
-int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret);
-int cg_get_keyed_attribute_full(const char *controller, const char *path, const char *attribute, char **keys, char **values, CGroupKeyMode mode);
-
-static inline int cg_get_keyed_attribute(
-                const char *controller,
-                const char *path,
-                const char *attribute,
-                char **keys,
-                char **ret_values) {
-        return cg_get_keyed_attribute_full(controller, path, attribute, keys, ret_values, 0);
-}
-
-static inline int cg_get_keyed_attribute_graceful(
-                const char *controller,
-                const char *path,
-                const char *attribute,
-                char **keys,
-                char **ret_values) {
-        return cg_get_keyed_attribute_full(controller, path, attribute, keys, ret_values, CG_KEY_MODE_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);
-int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size);
-int cg_get_xattr_malloc(const char *controller, const char *path, const char *name, char **ret);
-int cg_remove_xattr(const char *controller, const char *path, const char *name);
-
-int cg_install_release_agent(const char *controller, const char *agent);
-int cg_uninstall_release_agent(const char *controller);
-
-int cg_is_empty(const char *controller, const char *path);
-int cg_is_empty_recursive(const char *controller, const char *path);
-
-int cg_get_root_path(char **path);
-
-int cg_path_get_session(const char *path, char **session);
-int cg_path_get_owner_uid(const char *path, uid_t *uid);
-int cg_path_get_unit(const char *path, char **unit);
-int cg_path_get_user_unit(const char *path, char **unit);
-int cg_path_get_machine_name(const char *path, char **machine);
-int cg_path_get_slice(const char *path, char **slice);
-int cg_path_get_user_slice(const char *path, char **slice);
-
-int cg_shift_path(const char *cgroup, const char *cached_root, const char **shifted);
-int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **cgroup);
-
-int cg_pid_get_session(pid_t pid, char **session);
-int cg_pid_get_owner_uid(pid_t pid, uid_t *uid);
-int cg_pid_get_unit(pid_t pid, char **unit);
-int cg_pid_get_user_unit(pid_t pid, char **unit);
-int cg_pid_get_machine_name(pid_t pid, char **machine);
-int cg_pid_get_slice(pid_t pid, char **slice);
-int cg_pid_get_user_slice(pid_t pid, char **slice);
-
-int cg_path_decode_unit(const char *cgroup, char **unit);
-
-char *cg_escape(const char *p);
-char *cg_unescape(const char *p) _pure_;
-
-bool cg_controller_is_valid(const char *p);
-
-int cg_slice_to_path(const char *unit, char **ret);
-
-typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata);
-
-int cg_mask_supported(CGroupMask *ret);
-int cg_mask_from_string(const char *s, CGroupMask *ret);
-int cg_mask_to_string(CGroupMask mask, char **ret);
-
-int cg_kernel_controllers(Set **controllers);
-
-bool cg_ns_supported(void);
-bool cg_freezer_supported(void);
-
-int cg_all_unified(void);
-int cg_hybrid_unified(void);
-int cg_unified_controller(const char *controller);
-int cg_unified_cached(bool flush);
-static inline int cg_unified(void) {
-        return cg_unified_cached(true);
-}
-
-const char* cgroup_controller_to_string(CGroupController c) _const_;
-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
deleted file mode 100644
index 568b742f..00000000
--- a/shared/systemd/src/basic/env-file.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include "alloc-util.h"
-#include "env-file.h"
-#include "env-util.h"
-#include "escape.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "tmpfile-util.h"
-#include "utf8.h"
-
-static int parse_env_file_internal(
-                FILE *f,
-                const char *fname,
-                int (*push) (const char *filename, unsigned line,
-                             const char *key, char *value, void *userdata, int *n_pushed),
-                void *userdata,
-                int *n_pushed) {
-
-        size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
-        _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
-        unsigned line = 1;
-        char *p;
-        int r;
-
-        enum {
-                PRE_KEY,
-                KEY,
-                PRE_VALUE,
-                VALUE,
-                VALUE_ESCAPE,
-                SINGLE_QUOTE_VALUE,
-                DOUBLE_QUOTE_VALUE,
-                DOUBLE_QUOTE_VALUE_ESCAPE,
-                COMMENT,
-                COMMENT_ESCAPE
-        } state = PRE_KEY;
-
-        if (f)
-                r = read_full_stream(f, &contents, NULL);
-        else
-                r = read_full_file(fname, &contents, NULL);
-        if (r < 0)
-                return r;
-
-        for (p = contents; *p; p++) {
-                char c = *p;
-
-                switch (state) {
-
-                case PRE_KEY:
-                        if (strchr(COMMENTS, c))
-                                state = COMMENT;
-                        else if (!strchr(WHITESPACE, c)) {
-                                state = KEY;
-                                last_key_whitespace = (size_t) -1;
-
-                                if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
-                                        return -ENOMEM;
-
-                                key[n_key++] = c;
-                        }
-                        break;
-
-                case KEY:
-                        if (strchr(NEWLINE, c)) {
-                                state = PRE_KEY;
-                                line++;
-                                n_key = 0;
-                        } else if (c == '=') {
-                                state = PRE_VALUE;
-                                last_value_whitespace = (size_t) -1;
-                        } else {
-                                if (!strchr(WHITESPACE, c))
-                                        last_key_whitespace = (size_t) -1;
-                                else if (last_key_whitespace == (size_t) -1)
-                                         last_key_whitespace = n_key;
-
-                                if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
-                                        return -ENOMEM;
-
-                                key[n_key++] = c;
-                        }
-
-                        break;
-
-                case PRE_VALUE:
-                        if (strchr(NEWLINE, c)) {
-                                state = PRE_KEY;
-                                line++;
-                                key[n_key] = 0;
-
-                                if (value)
-                                        value[n_value] = 0;
-
-                                /* strip trailing whitespace from key */
-                                if (last_key_whitespace != (size_t) -1)
-                                        key[last_key_whitespace] = 0;
-
-                                r = push(fname, line, key, value, userdata, n_pushed);
-                                if (r < 0)
-                                        return r;
-
-                                n_key = 0;
-                                value = NULL;
-                                value_alloc = n_value = 0;
-
-                        } else if (c == '\'')
-                                state = SINGLE_QUOTE_VALUE;
-                        else if (c == '"')
-                                state = DOUBLE_QUOTE_VALUE;
-                        else if (c == '\\')
-                                state = VALUE_ESCAPE;
-                        else if (!strchr(WHITESPACE, c)) {
-                                state = VALUE;
-
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return  -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-
-                        break;
-
-                case VALUE:
-                        if (strchr(NEWLINE, c)) {
-                                state = PRE_KEY;
-                                line++;
-
-                                key[n_key] = 0;
-
-                                if (value)
-                                        value[n_value] = 0;
-
-                                /* Chomp off trailing whitespace from value */
-                                if (last_value_whitespace != (size_t) -1)
-                                        value[last_value_whitespace] = 0;
-
-                                /* strip trailing whitespace from key */
-                                if (last_key_whitespace != (size_t) -1)
-                                        key[last_key_whitespace] = 0;
-
-                                r = push(fname, line, key, value, userdata, n_pushed);
-                                if (r < 0)
-                                        return r;
-
-                                n_key = 0;
-                                value = NULL;
-                                value_alloc = n_value = 0;
-
-                        } else if (c == '\\') {
-                                state = VALUE_ESCAPE;
-                                last_value_whitespace = (size_t) -1;
-                        } else {
-                                if (!strchr(WHITESPACE, c))
-                                        last_value_whitespace = (size_t) -1;
-                                else if (last_value_whitespace == (size_t) -1)
-                                        last_value_whitespace = n_value;
-
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-
-                        break;
-
-                case VALUE_ESCAPE:
-                        state = VALUE;
-
-                        if (!strchr(NEWLINE, c)) {
-                                /* Escaped newlines we eat up entirely */
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-                        break;
-
-                case SINGLE_QUOTE_VALUE:
-                        if (c == '\'')
-                                state = PRE_VALUE;
-                        else {
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-
-                        break;
-
-                case DOUBLE_QUOTE_VALUE:
-                        if (c == '"')
-                                state = PRE_VALUE;
-                        else if (c == '\\')
-                                state = DOUBLE_QUOTE_VALUE_ESCAPE;
-                        else {
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-
-                                value[n_value++] = c;
-                        }
-
-                        break;
-
-                case DOUBLE_QUOTE_VALUE_ESCAPE:
-                        state = DOUBLE_QUOTE_VALUE;
-
-                        if (strchr(SHELL_NEED_ESCAPE, c)) {
-                                /* If this is a char that needs escaping, just unescape it. */
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
-                                        return -ENOMEM;
-                                value[n_value++] = c;
-                        } else if (c != '\n') {
-                                /* If other char than what needs escaping, keep the "\" in place, like the
-                                 * real shell does. */
-                                if (!GREEDY_REALLOC(value, value_alloc, n_value+3))
-                                        return -ENOMEM;
-                                value[n_value++] = '\\';
-                                value[n_value++] = c;
-                        }
-
-                        /* Escaped newlines (aka "continuation lines") are eaten up entirely */
-                        break;
-
-                case COMMENT:
-                        if (c == '\\')
-                                state = COMMENT_ESCAPE;
-                        else if (strchr(NEWLINE, c)) {
-                                state = PRE_KEY;
-                                line++;
-                        }
-                        break;
-
-                case COMMENT_ESCAPE:
-                        state = COMMENT;
-                        break;
-                }
-        }
-
-        if (IN_SET(state,
-                   PRE_VALUE,
-                   VALUE,
-                   VALUE_ESCAPE,
-                   SINGLE_QUOTE_VALUE,
-                   DOUBLE_QUOTE_VALUE,
-                   DOUBLE_QUOTE_VALUE_ESCAPE)) {
-
-                key[n_key] = 0;
-
-                if (value)
-                        value[n_value] = 0;
-
-                if (state == VALUE)
-                        if (last_value_whitespace != (size_t) -1)
-                                value[last_value_whitespace] = 0;
-
-                /* strip trailing whitespace from key */
-                if (last_key_whitespace != (size_t) -1)
-                        key[last_key_whitespace] = 0;
-
-                r = push(fname, line, key, value, userdata, n_pushed);
-                if (r < 0)
-                        return r;
-
-                value = NULL;
-        }
-
-        return 0;
-}
-
-static int check_utf8ness_and_warn(
-                const char *filename, unsigned line,
-                const char *key, char *value) {
-
-        if (!utf8_is_valid(key)) {
-                _cleanup_free_ char *p = NULL;
-
-                p = utf8_escape_invalid(key);
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "%s:%u: invalid UTF-8 in key '%s', ignoring.",
-                                       strna(filename), line, p);
-        }
-
-        if (value && !utf8_is_valid(value)) {
-                _cleanup_free_ char *p = NULL;
-
-                p = utf8_escape_invalid(value);
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.",
-                                       strna(filename), line, key, p);
-        }
-
-        return 0;
-}
-
-static int parse_env_file_push(
-                const char *filename, unsigned line,
-                const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
-
-        const char *k;
-        va_list aq, *ap = userdata;
-        int r;
-
-        r = check_utf8ness_and_warn(filename, line, key, value);
-        if (r < 0)
-                return r;
-
-        va_copy(aq, *ap);
-
-        while ((k = va_arg(aq, const char *))) {
-                char **v;
-
-                v = va_arg(aq, char **);
-
-                if (streq(key, k)) {
-                        va_end(aq);
-                        free(*v);
-                        *v = value;
-
-                        if (n_pushed)
-                                (*n_pushed)++;
-
-                        return 1;
-                }
-        }
-
-        va_end(aq);
-        free(value);
-
-        return 0;
-}
-
-int parse_env_filev(
-                FILE *f,
-                const char *fname,
-                va_list ap) {
-
-        int r, n_pushed = 0;
-        va_list aq;
-
-        va_copy(aq, ap);
-        r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed);
-        va_end(aq);
-        if (r < 0)
-                return r;
-
-        return n_pushed;
-}
-
-int parse_env_file_sentinel(
-                FILE *f,
-                const char *fname,
-                ...) {
-
-        va_list ap;
-        int r;
-
-        va_start(ap, fname);
-        r = parse_env_filev(f, fname, ap);
-        va_end(ap);
-
-        return r;
-}
-
-#if 0 /* NM_IGNORED */
-static int load_env_file_push(
-                const char *filename, unsigned line,
-                const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
-        char ***m = userdata;
-        char *p;
-        int r;
-
-        r = check_utf8ness_and_warn(filename, line, key, value);
-        if (r < 0)
-                return r;
-
-        p = strjoin(key, "=", value);
-        if (!p)
-                return -ENOMEM;
-
-        r = strv_env_replace(m, p);
-        if (r < 0) {
-                free(p);
-                return r;
-        }
-
-        if (n_pushed)
-                (*n_pushed)++;
-
-        free(value);
-        return 0;
-}
-
-int load_env_file(FILE *f, const char *fname, char ***rl) {
-        char **m = NULL;
-        int r;
-
-        r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL);
-        if (r < 0) {
-                strv_free(m);
-                return r;
-        }
-
-        *rl = m;
-        return 0;
-}
-
-static int load_env_file_push_pairs(
-                const char *filename, unsigned line,
-                const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
-        char ***m = userdata;
-        int r;
-
-        r = check_utf8ness_and_warn(filename, line, key, value);
-        if (r < 0)
-                return r;
-
-        r = strv_extend(m, key);
-        if (r < 0)
-                return -ENOMEM;
-
-        if (!value) {
-                r = strv_extend(m, "");
-                if (r < 0)
-                        return -ENOMEM;
-        } else {
-                r = strv_push(m, value);
-                if (r < 0)
-                        return r;
-        }
-
-        if (n_pushed)
-                (*n_pushed)++;
-
-        return 0;
-}
-
-int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
-        char **m = NULL;
-        int r;
-
-        r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL);
-        if (r < 0) {
-                strv_free(m);
-                return r;
-        }
-
-        *rl = m;
-        return 0;
-}
-
-static int merge_env_file_push(
-                const char *filename, unsigned line,
-                const char *key, char *value,
-                void *userdata,
-                int *n_pushed) {
-
-        char ***env = userdata;
-        char *expanded_value;
-
-        assert(env);
-
-        if (!value) {
-                log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
-                return 0;
-        }
-
-        if (!env_name_is_valid(key)) {
-                log_error("%s:%u: invalid variable name \"%s\", ignoring.", strna(filename), line, key);
-                free(value);
-                return 0;
-        }
-
-        expanded_value = replace_env(value, *env,
-                                     REPLACE_ENV_USE_ENVIRONMENT|
-                                     REPLACE_ENV_ALLOW_BRACELESS|
-                                     REPLACE_ENV_ALLOW_EXTENDED);
-        if (!expanded_value)
-                return -ENOMEM;
-
-        free_and_replace(value, expanded_value);
-
-        log_debug("%s:%u: setting %s=%s", filename, line, key, value);
-
-        return load_env_file_push(filename, line, key, value, env, n_pushed);
-}
-
-int merge_env_file(
-                char ***env,
-                FILE *f,
-                const char *fname) {
-
-        /* NOTE: this function supports braceful and braceless variable expansions,
-         * plus "extended" substitutions, unlike other exported parsing functions.
-         */
-
-        return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL);
-}
-
-static void write_env_var(FILE *f, const char *v) {
-        const char *p;
-
-        p = strchr(v, '=');
-        if (!p) {
-                /* Fallback */
-                fputs_unlocked(v, f);
-                fputc_unlocked('\n', f);
-                return;
-        }
-
-        p++;
-        fwrite_unlocked(v, 1, p-v, f);
-
-        if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
-                fputc_unlocked('"', f);
-
-                for (; *p; p++) {
-                        if (strchr(SHELL_NEED_ESCAPE, *p))
-                                fputc_unlocked('\\', f);
-
-                        fputc_unlocked(*p, f);
-                }
-
-                fputc_unlocked('"', f);
-        } else
-                fputs_unlocked(p, f);
-
-        fputc_unlocked('\n', f);
-}
-
-int write_env_file(const char *fname, char **l) {
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *p = NULL;
-        char **i;
-        int r;
-
-        assert(fname);
-
-        r = fopen_temporary(fname, &f, &p);
-        if (r < 0)
-                return r;
-
-        (void) fchmod_umask(fileno(f), 0644);
-
-        STRV_FOREACH(i, l)
-                write_env_var(f, *i);
-
-        r = fflush_and_check(f);
-        if (r >= 0) {
-                if (rename(p, fname) >= 0)
-                        return 0;
-
-                r = -errno;
-        }
-
-        (void) unlink(p);
-        return r;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/env-file.h b/shared/systemd/src/basic/env-file.h
deleted file mode 100644
index de475885..00000000
--- a/shared/systemd/src/basic/env-file.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdarg.h>
-#include <stdio.h>
-
-#include "macro.h"
-
-int parse_env_filev(FILE *f, const char *fname, va_list ap);
-int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_;
-#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL)
-int load_env_file(FILE *f, const char *fname, char ***l);
-int load_env_file_pairs(FILE *f, const char *fname, char ***l);
-
-int merge_env_file(char ***env, FILE *f, const char *fname);
-
-int write_env_file(const char *fname, char **l);
diff --git a/shared/systemd/src/basic/env-util.c b/shared/systemd/src/basic/env-util.c
deleted file mode 100644
index a311ee00..00000000
--- a/shared/systemd/src/basic/env-util.c
+++ /dev/null
@@ -1,767 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "env-util.h"
-#include "escape.h"
-#include "extract-word.h"
-#include "macro.h"
-#include "parse-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "utf8.h"
-
-#if 0 /* NM_IGNORED */
-/* We follow bash for the character set. Different shells have different rules. */
-#define VALID_BASH_ENV_NAME_CHARS               \
-        DIGITS LETTERS                          \
-        "_"
-
-static bool env_name_is_valid_n(const char *e, size_t n) {
-        const char *p;
-
-        if (!e)
-                return false;
-
-        if (n <= 0)
-                return false;
-
-        if (e[0] >= '0' && e[0] <= '9')
-                return false;
-
-        /* POSIX says the overall size of the environment block cannot
-         * be > ARG_MAX, an individual assignment hence cannot be
-         * either. Discounting the equal sign and trailing NUL this
-         * hence leaves ARG_MAX-2 as longest possible variable
-         * name. */
-        if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
-                return false;
-
-        for (p = e; p < e + n; p++)
-                if (!strchr(VALID_BASH_ENV_NAME_CHARS, *p))
-                        return false;
-
-        return true;
-}
-
-bool env_name_is_valid(const char *e) {
-        return env_name_is_valid_n(e, strlen_ptr(e));
-}
-
-bool env_value_is_valid(const char *e) {
-        if (!e)
-                return false;
-
-        if (!utf8_is_valid(e))
-                return false;
-
-        /* bash allows tabs and newlines in environment variables, and so
-         * should we */
-        if (string_has_cc(e, "\t\n"))
-                return false;
-
-        /* POSIX says the overall size of the environment block cannot
-         * be > ARG_MAX, an individual assignment hence cannot be
-         * either. Discounting the shortest possible variable name of
-         * length 1, the equal sign and trailing NUL this hence leaves
-         * ARG_MAX-3 as longest possible variable value. */
-        if (strlen(e) > sc_arg_max() - 3)
-                return false;
-
-        return true;
-}
-
-bool env_assignment_is_valid(const char *e) {
-        const char *eq;
-
-        eq = strchr(e, '=');
-        if (!eq)
-                return false;
-
-        if (!env_name_is_valid_n(e, eq - e))
-                return false;
-
-        if (!env_value_is_valid(eq + 1))
-                return false;
-
-        /* POSIX says the overall size of the environment block cannot
-         * be > ARG_MAX, hence the individual variable assignments
-         * cannot be either, but let's leave room for one trailing NUL
-         * byte. */
-        if (strlen(e) > sc_arg_max() - 1)
-                return false;
-
-        return true;
-}
-
-bool strv_env_is_valid(char **e) {
-        char **p, **q;
-
-        STRV_FOREACH(p, e) {
-                size_t k;
-
-                if (!env_assignment_is_valid(*p))
-                        return false;
-
-                /* Check if there are duplicate assignments */
-                k = strcspn(*p, "=");
-                STRV_FOREACH(q, p + 1)
-                        if (strneq(*p, *q, k) && (*q)[k] == '=')
-                                return false;
-        }
-
-        return true;
-}
-
-bool strv_env_name_is_valid(char **l) {
-        char **p;
-
-        STRV_FOREACH(p, l) {
-                if (!env_name_is_valid(*p))
-                        return false;
-
-                if (strv_contains(p + 1, *p))
-                        return false;
-        }
-
-        return true;
-}
-
-bool strv_env_name_or_assignment_is_valid(char **l) {
-        char **p;
-
-        STRV_FOREACH(p, l) {
-                if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
-                        return false;
-
-                if (strv_contains(p + 1, *p))
-                        return false;
-        }
-
-        return true;
-}
-
-static int env_append(char **r, char ***k, char **a) {
-        assert(r);
-        assert(k);
-        assert(*k >= r);
-
-        if (!a)
-                return 0;
-
-        /* Expects the following arguments: 'r' shall point to the beginning of an strv we are going to append to, 'k'
-         * to a pointer pointing to the NULL entry at the end of the same array. 'a' shall point to another strv.
-         *
-         * This call adds every entry of 'a' to 'r', either overriding an existing matching entry, or appending to it.
-         *
-         * This call assumes 'r' has enough pre-allocated space to grow by all of 'a''s items. */
-
-        for (; *a; a++) {
-                char **j, *c;
-                size_t n;
-
-                n = strcspn(*a, "=");
-                if ((*a)[n] == '=')
-                        n++;
-
-                for (j = r; j < *k; j++)
-                        if (strneq(*j, *a, n))
-                                break;
-
-                c = strdup(*a);
-                if (!c)
-                        return -ENOMEM;
-
-                if (j >= *k) { /* Append to the end? */
-                        (*k)[0] = c;
-                        (*k)[1] = NULL;
-                        (*k)++;
-                } else
-                        free_and_replace(*j, c); /* Override existing item */
-        }
-
-        return 0;
-}
-
-char **strv_env_merge(size_t n_lists, ...) {
-        _cleanup_strv_free_ char **ret = NULL;
-        size_t n = 0, i;
-        char **l, **k;
-        va_list ap;
-
-        /* Merges an arbitrary number of environment sets */
-
-        va_start(ap, n_lists);
-        for (i = 0; i < n_lists; i++) {
-                l = va_arg(ap, char**);
-                n += strv_length(l);
-        }
-        va_end(ap);
-
-        ret = new(char*, n+1);
-        if (!ret)
-                return NULL;
-
-        *ret = NULL;
-        k = ret;
-
-        va_start(ap, n_lists);
-        for (i = 0; i < n_lists; i++) {
-                l = va_arg(ap, char**);
-                if (env_append(ret, &k, l) < 0) {
-                        va_end(ap);
-                        return NULL;
-                }
-        }
-        va_end(ap);
-
-        return TAKE_PTR(ret);
-}
-
-static bool env_match(const char *t, const char *pattern) {
-        assert(t);
-        assert(pattern);
-
-        /* pattern a matches string a
-         *         a matches a=
-         *         a matches a=b
-         *         a= matches a=
-         *         a=b matches a=b
-         *         a= does not match a
-         *         a=b does not match a=
-         *         a=b does not match a
-         *         a=b does not match a=c */
-
-        if (streq(t, pattern))
-                return true;
-
-        if (!strchr(pattern, '=')) {
-                size_t l = strlen(pattern);
-
-                return strneq(t, pattern, l) && t[l] == '=';
-        }
-
-        return false;
-}
-
-static bool env_entry_has_name(const char *entry, const char *name) {
-        const char *t;
-
-        assert(entry);
-        assert(name);
-
-        t = startswith(entry, name);
-        if (!t)
-                return false;
-
-        return *t == '=';
-}
-
-char **strv_env_delete(char **x, size_t n_lists, ...) {
-        size_t n, i = 0;
-        char **k, **r;
-        va_list ap;
-
-        /* Deletes every entry from x that is mentioned in the other
-         * string lists */
-
-        n = strv_length(x);
-
-        r = new(char*, n+1);
-        if (!r)
-                return NULL;
-
-        STRV_FOREACH(k, x) {
-                size_t v;
-
-                va_start(ap, n_lists);
-                for (v = 0; v < n_lists; v++) {
-                        char **l, **j;
-
-                        l = va_arg(ap, char**);
-                        STRV_FOREACH(j, l)
-                                if (env_match(*k, *j))
-                                        goto skip;
-                }
-                va_end(ap);
-
-                r[i] = strdup(*k);
-                if (!r[i]) {
-                        strv_free(r);
-                        return NULL;
-                }
-
-                i++;
-                continue;
-
-        skip:
-                va_end(ap);
-        }
-
-        r[i] = NULL;
-
-        assert(i <= n);
-
-        return r;
-}
-
-char **strv_env_unset(char **l, const char *p) {
-
-        char **f, **t;
-
-        if (!l)
-                return NULL;
-
-        assert(p);
-
-        /* Drops every occurrence of the env var setting p in the
-         * string list. Edits in-place. */
-
-        for (f = t = l; *f; f++) {
-
-                if (env_match(*f, p)) {
-                        free(*f);
-                        continue;
-                }
-
-                *(t++) = *f;
-        }
-
-        *t = NULL;
-        return l;
-}
-
-char **strv_env_unset_many(char **l, ...) {
-        char **f, **t;
-
-        if (!l)
-                return NULL;
-
-        /* Like strv_env_unset() but applies many at once. Edits in-place. */
-
-        for (f = t = l; *f; f++) {
-                bool found = false;
-                const char *p;
-                va_list ap;
-
-                va_start(ap, l);
-
-                while ((p = va_arg(ap, const char*))) {
-                        if (env_match(*f, p)) {
-                                found = true;
-                                break;
-                        }
-                }
-
-                va_end(ap);
-
-                if (found) {
-                        free(*f);
-                        continue;
-                }
-
-                *(t++) = *f;
-        }
-
-        *t = NULL;
-        return l;
-}
-
-int strv_env_replace(char ***l, char *p) {
-        const char *t, *name;
-        char **f;
-        int r;
-
-        assert(p);
-
-        /* Replace first occurrence of the env var or add a new one in the string list. Drop other occurrences. Edits
-         * in-place. Does not copy p.  p must be a valid key=value assignment.
-         */
-
-        t = strchr(p, '=');
-        if (!t)
-                return -EINVAL;
-
-        name = strndupa(p, t - p);
-
-        STRV_FOREACH(f, *l)
-                if (env_entry_has_name(*f, name)) {
-                        free_and_replace(*f, p);
-                        strv_env_unset(f + 1, *f);
-                        return 0;
-                }
-
-        /* We didn't find a match, we need to append p or create a new strv */
-        r = strv_push(l, p);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-char **strv_env_set(char **x, const char *p) {
-        _cleanup_strv_free_ char **ret = NULL;
-        size_t n, m;
-        char **k;
-
-        /* Overrides the env var setting of p, returns a new copy */
-
-        n = strv_length(x);
-        m = n + 2;
-        if (m < n) /* overflow? */
-                return NULL;
-
-        ret = new(char*, m);
-        if (!ret)
-                return NULL;
-
-        *ret = NULL;
-        k = ret;
-
-        if (env_append(ret, &k, x) < 0)
-                return NULL;
-
-        if (env_append(ret, &k, STRV_MAKE(p)) < 0)
-                return NULL;
-
-        return TAKE_PTR(ret);
-}
-
-char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
-        char **i;
-
-        assert(name);
-
-        if (k <= 0)
-                return NULL;
-
-        STRV_FOREACH_BACKWARDS(i, l)
-                if (strneq(*i, name, k) &&
-                    (*i)[k] == '=')
-                        return *i + k + 1;
-
-        if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
-                const char *t;
-
-                t = strndupa(name, k);
-                return getenv(t);
-        };
-
-        return NULL;
-}
-
-char *strv_env_get(char **l, const char *name) {
-        assert(name);
-
-        return strv_env_get_n(l, name, strlen(name), 0);
-}
-
-char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
-        char **p, **q;
-        int k = 0;
-
-        STRV_FOREACH(p, e) {
-                size_t n;
-                bool duplicate = false;
-
-                if (!env_assignment_is_valid(*p)) {
-                        if (invalid_callback)
-                                invalid_callback(*p, userdata);
-                        free(*p);
-                        continue;
-                }
-
-                n = strcspn(*p, "=");
-                STRV_FOREACH(q, p + 1)
-                        if (strneq(*p, *q, n) && (*q)[n] == '=') {
-                                duplicate = true;
-                                break;
-                        }
-
-                if (duplicate) {
-                        free(*p);
-                        continue;
-                }
-
-                e[k++] = *p;
-        }
-
-        if (e)
-                e[k] = NULL;
-
-        return e;
-}
-
-char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
-        enum {
-                WORD,
-                CURLY,
-                VARIABLE,
-                VARIABLE_RAW,
-                TEST,
-                DEFAULT_VALUE,
-                ALTERNATE_VALUE,
-        } state = WORD;
-
-        const char *e, *word = format, *test_value;
-        char *k;
-        _cleanup_free_ char *r = NULL;
-        size_t i, len;
-        int nest = 0;
-
-        assert(format);
-
-        for (e = format, i = 0; *e && i < n; e ++, i ++)
-                switch (state) {
-
-                case WORD:
-                        if (*e == '$')
-                                state = CURLY;
-                        break;
-
-                case CURLY:
-                        if (*e == '{') {
-                                k = strnappend(r, word, e-word-1);
-                                if (!k)
-                                        return NULL;
-
-                                free_and_replace(r, k);
-
-                                word = e-1;
-                                state = VARIABLE;
-                                nest++;
-                        } else if (*e == '$') {
-                                k = strnappend(r, word, e-word);
-                                if (!k)
-                                        return NULL;
-
-                                free_and_replace(r, k);
-
-                                word = e+1;
-                                state = WORD;
-
-                        } 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;
-
-                                free_and_replace(r, k);
-
-                                word = e-1;
-                                state = VARIABLE_RAW;
-
-                        } else
-                                state = WORD;
-                        break;
-
-                case VARIABLE:
-                        if (*e == '}') {
-                                const char *t;
-
-                                t = strv_env_get_n(env, word+2, e-word-2, flags);
-
-                                k = strjoin(r, t);
-                                if (!k)
-                                        return NULL;
-
-                                free_and_replace(r, k);
-
-                                word = e+1;
-                                state = WORD;
-                        } else if (*e == ':') {
-                                if (!(flags & REPLACE_ENV_ALLOW_EXTENDED))
-                                        /* Treat this as unsupported syntax, i.e. do no replacement */
-                                        state = WORD;
-                                else {
-                                        len = e-word-2;
-                                        state = TEST;
-                                }
-                        }
-                        break;
-
-                case TEST:
-                        if (*e == '-')
-                                state = DEFAULT_VALUE;
-                        else if (*e == '+')
-                                state = ALTERNATE_VALUE;
-                        else {
-                                state = WORD;
-                                break;
-                        }
-
-                        test_value = e+1;
-                        break;
-
-                case DEFAULT_VALUE: /* fall through */
-                case ALTERNATE_VALUE:
-                        assert(flags & REPLACE_ENV_ALLOW_EXTENDED);
-
-                        if (*e == '{') {
-                                nest++;
-                                break;
-                        }
-
-                        if (*e != '}')
-                                break;
-
-                        nest--;
-                        if (nest == 0) {
-                                const char *t;
-                                _cleanup_free_ char *v = NULL;
-
-                                t = strv_env_get_n(env, word+2, len, flags);
-
-                                if (t && state == ALTERNATE_VALUE)
-                                        t = v = replace_env_n(test_value, e-test_value, env, flags);
-                                else if (!t && state == DEFAULT_VALUE)
-                                        t = v = replace_env_n(test_value, e-test_value, env, flags);
-
-                                k = strjoin(r, t);
-                                if (!k)
-                                        return NULL;
-
-                                free_and_replace(r, k);
-
-                                word = e+1;
-                                state = WORD;
-                        }
-                        break;
-
-                case VARIABLE_RAW:
-                        assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
-
-                        if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
-                                const char *t;
-
-                                t = strv_env_get_n(env, word+1, e-word-1, flags);
-
-                                k = strjoin(r, t);
-                                if (!k)
-                                        return NULL;
-
-                                free_and_replace(r, k);
-
-                                word = e--;
-                                i--;
-                                state = WORD;
-                        }
-                        break;
-                }
-
-        if (state == VARIABLE_RAW) {
-                const char *t;
-
-                assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
-
-                t = strv_env_get_n(env, word+1, e-word-1, flags);
-                return strjoin(r, t);
-        } else
-                return strnappend(r, word, e-word);
-}
-
-char **replace_env_argv(char **argv, char **env) {
-        char **ret, **i;
-        size_t k = 0, l = 0;
-
-        l = strv_length(argv);
-
-        ret = new(char*, l+1);
-        if (!ret)
-                return NULL;
-
-        STRV_FOREACH(i, argv) {
-
-                /* If $FOO appears as single word, replace it by the split up variable */
-                if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
-                        char *e;
-                        char **w, **m = NULL;
-                        size_t q;
-
-                        e = strv_env_get(env, *i+1);
-                        if (e) {
-                                int r;
-
-                                r = strv_split_full(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE);
-                                if (r < 0) {
-                                        ret[k] = NULL;
-                                        strv_free(ret);
-                                        return NULL;
-                                }
-                        } else
-                                m = NULL;
-
-                        q = strv_length(m);
-                        l = l + q - 1;
-
-                        w = reallocarray(ret, l + 1, sizeof(char *));
-                        if (!w) {
-                                ret[k] = NULL;
-                                strv_free(ret);
-                                strv_free(m);
-                                return NULL;
-                        }
-
-                        ret = w;
-                        if (m) {
-                                memcpy(ret + k, m, q * sizeof(char*));
-                                free(m);
-                        }
-
-                        k += q;
-                        continue;
-                }
-
-                /* If ${FOO} appears as part of a word, replace it by the variable as-is */
-                ret[k] = replace_env(*i, env, 0);
-                if (!ret[k]) {
-                        strv_free(ret);
-                        return NULL;
-                }
-                k++;
-        }
-
-        ret[k] = NULL;
-        return ret;
-}
-#endif /* NM_IGNORED */
-
-int getenv_bool(const char *p) {
-        const char *e;
-
-        e = getenv(p);
-        if (!e)
-                return -ENXIO;
-
-        return parse_boolean(e);
-}
-
-int getenv_bool_secure(const char *p) {
-        const char *e;
-
-        e = secure_getenv(p);
-        if (!e)
-                return -ENXIO;
-
-        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
deleted file mode 100644
index 6684b335..00000000
--- a/shared/systemd/src/basic/env-util.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include "macro.h"
-#include "string.h"
-
-static inline size_t sc_arg_max(void) {
-        long l = sysconf(_SC_ARG_MAX);
-        assert(l > 0);
-        return (size_t) l;
-}
-
-bool env_name_is_valid(const char *e);
-bool env_value_is_valid(const char *e);
-bool env_assignment_is_valid(const char *e);
-
-enum {
-        REPLACE_ENV_USE_ENVIRONMENT = 1 << 0,
-        REPLACE_ENV_ALLOW_BRACELESS = 1 << 1,
-        REPLACE_ENV_ALLOW_EXTENDED  = 1 << 2,
-};
-
-char *replace_env_n(const char *format, size_t n, char **env, unsigned flags);
-char **replace_env_argv(char **argv, char **env);
-
-static inline char *replace_env(const char *format, char **env, unsigned flags) {
-        return replace_env_n(format, strlen(format), env, flags);
-}
-
-bool strv_env_is_valid(char **e);
-#define strv_env_clean(l) strv_env_clean_with_callback(l, NULL, NULL)
-char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata);
-
-bool strv_env_name_is_valid(char **l);
-bool strv_env_name_or_assignment_is_valid(char **l);
-
-char **strv_env_merge(size_t n_lists, ...);
-char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
-
-char **strv_env_set(char **x, const char *p); /* New copy ... */
-char **strv_env_unset(char **l, const char *p); /* In place ... */
-char **strv_env_unset_many(char **l, ...) _sentinel_;
-int strv_env_replace(char ***l, char *p); /* In place ... */
-
-char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) _pure_;
-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
deleted file mode 100644
index 5609820b..00000000
--- a/shared/systemd/src/basic/errno-util.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "macro.h"
-
-static inline void _reset_errno_(int *saved_errno) {
-        if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
-                return;
-
-        errno = *saved_errno;
-}
-
-#define PROTECT_ERRNO                                                   \
-        _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
-
-#define UNPROTECT_ERRNO                         \
-        do {                                    \
-                errno = _saved_errno_;          \
-                _saved_errno_ = -1;             \
-        } while (false)
-
-static inline int negative_errno(void) {
-        /* This helper should be used to shut up gcc if you know 'errno' is
-         * negative. Instead of "return -errno;", use "return negative_errno();"
-         * It will suppress bogus gcc warnings in case it assumes 'errno' might
-         * be 0 and thus the caller's error-handling might not be triggered. */
-        assert_return(errno > 0, -EINVAL);
-        return -errno;
-}
-
-static inline const char *strerror_safe(int error) {
-        /* 'safe' here does NOT mean thread safety. */
-        return strerror(abs(error));
-}
-
-static inline int errno_or_else(int fallback) {
-        /* To be used when invoking library calls where errno handling is not defined clearly: we return
-         * errno if it is set, and the specified error otherwise. The idea is that the caller initializes
-         * errno to zero before doing an API call, and then uses this helper to retrieve a somewhat useful
-         * error code */
-        if (errno > 0)
-                return -errno;
-
-        return -abs(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.
- *
- * 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,
-                      ECONNREFUSED,
-                      ECONNRESET,
-                      EHOSTDOWN,
-                      EHOSTUNREACH,
-                      ENETDOWN,
-                      ENETRESET,
-                      ENETUNREACH,
-                      ENONET,
-                      ENOPROTOOPT,
-                      ENOTCONN,
-                      EPIPE,
-                      EPROTO,
-                      ESHUTDOWN,
-                      ETIMEDOUT);
-}
-
-/* Transient errors we might get on accept() that we should ignore. As per error handling comment in
- * the accept(2) man page. */
-static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) {
-        return ERRNO_IS_DISCONNECT(r) ||
-                IN_SET(abs(r),
-                       EAGAIN,
-                       EINTR,
-                       EOPNOTSUPP);
-}
-
-/* Resource exhaustion, could be our fault or general system trouble */
-static inline bool ERRNO_IS_RESOURCE(int r) {
-        return IN_SET(abs(r),
-                      EMFILE,
-                      ENFILE,
-                      ENOMEM);
-}
-
-/* Seven different errors for "operation/system call/ioctl/socket feature not supported" */
-static inline bool ERRNO_IS_NOT_SUPPORTED(int r) {
-        return IN_SET(abs(r),
-                      EOPNOTSUPP,
-                      ENOTTY,
-                      ENOSYS,
-                      EAFNOSUPPORT,
-                      EPFNOSUPPORT,
-                      EPROTONOSUPPORT,
-                      ESOCKTNOSUPPORT);
-}
-
-/* Two different errors for access problems */
-static inline bool ERRNO_IS_PRIVILEGE(int r) {
-        return IN_SET(abs(r),
-                      EACCES,
-                      EPERM);
-}
-
-/* Three difference errors for "not enough disk space" */
-static inline bool ERRNO_IS_DISK_SPACE(int r) {
-        return IN_SET(abs(r),
-                      ENOSPC,
-                      EDQUOT,
-                      EFBIG);
-}
diff --git a/shared/systemd/src/basic/escape.c b/shared/systemd/src/basic/escape.c
deleted file mode 100644
index 094b5c5f..00000000
--- a/shared/systemd/src/basic/escape.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "alloc-util.h"
-#include "escape.h"
-#include "hexdecoct.h"
-#include "macro.h"
-#include "utf8.h"
-
-int cescape_char(char c, char *buf) {
-        char *buf_old = buf;
-
-        /* Needs space for 4 characters in the buffer */
-
-        switch (c) {
-
-                case '\a':
-                        *(buf++) = '\\';
-                        *(buf++) = 'a';
-                        break;
-                case '\b':
-                        *(buf++) = '\\';
-                        *(buf++) = 'b';
-                        break;
-                case '\f':
-                        *(buf++) = '\\';
-                        *(buf++) = 'f';
-                        break;
-                case '\n':
-                        *(buf++) = '\\';
-                        *(buf++) = 'n';
-                        break;
-                case '\r':
-                        *(buf++) = '\\';
-                        *(buf++) = 'r';
-                        break;
-                case '\t':
-                        *(buf++) = '\\';
-                        *(buf++) = 't';
-                        break;
-                case '\v':
-                        *(buf++) = '\\';
-                        *(buf++) = 'v';
-                        break;
-                case '\\':
-                        *(buf++) = '\\';
-                        *(buf++) = '\\';
-                        break;
-                case '"':
-                        *(buf++) = '\\';
-                        *(buf++) = '"';
-                        break;
-                case '\'':
-                        *(buf++) = '\\';
-                        *(buf++) = '\'';
-                        break;
-
-                default:
-                        /* For special chars we prefer octal over
-                         * hexadecimal encoding, simply because glib's
-                         * g_strescape() does the same */
-                        if ((c < ' ') || (c >= 127)) {
-                                *(buf++) = '\\';
-                                *(buf++) = octchar((unsigned char) c >> 6);
-                                *(buf++) = octchar((unsigned char) c >> 3);
-                                *(buf++) = octchar((unsigned char) c);
-                        } else
-                                *(buf++) = c;
-                        break;
-        }
-
-        return buf - buf_old;
-}
-
-char* cescape_length(const char *s, size_t n) {
-        const char *f;
-        char *r, *t;
-
-        assert(s || n == 0);
-
-        /* Does C style string escaping. May be reversed with
-         * cunescape(). */
-
-        r = new(char, n*4 + 1);
-        if (!r)
-                return NULL;
-
-        for (f = s, t = r; f < s + n; f++)
-                t += cescape_char(*f, t);
-
-        *t = 0;
-
-        return r;
-}
-
-char* cescape(const char *s) {
-        assert(s);
-
-        return cescape_length(s, strlen(s));
-}
-
-int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul) {
-        int r = 1;
-
-        assert(p);
-        assert(ret);
-
-        /* Unescapes C style. Returns the unescaped character in ret.
-         * Sets *eight_bit to true if the escaped sequence either fits in
-         * one byte in UTF-8 or is a non-unicode literal byte and should
-         * instead be copied directly.
-         */
-
-        if (length != (size_t) -1 && length < 1)
-                return -EINVAL;
-
-        switch (p[0]) {
-
-        case 'a':
-                *ret = '\a';
-                break;
-        case 'b':
-                *ret = '\b';
-                break;
-        case 'f':
-                *ret = '\f';
-                break;
-        case 'n':
-                *ret = '\n';
-                break;
-        case 'r':
-                *ret = '\r';
-                break;
-        case 't':
-                *ret = '\t';
-                break;
-        case 'v':
-                *ret = '\v';
-                break;
-        case '\\':
-                *ret = '\\';
-                break;
-        case '"':
-                *ret = '"';
-                break;
-        case '\'':
-                *ret = '\'';
-                break;
-
-        case 's':
-                /* This is an extension of the XDG syntax files */
-                *ret = ' ';
-                break;
-
-        case 'x': {
-                /* hexadecimal encoding */
-                int a, b;
-
-                if (length != (size_t) -1 && length < 3)
-                        return -EINVAL;
-
-                a = unhexchar(p[1]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unhexchar(p[2]);
-                if (b < 0)
-                        return -EINVAL;
-
-                /* Don't allow NUL bytes */
-                if (a == 0 && b == 0 && !accept_nul)
-                        return -EINVAL;
-
-                *ret = (a << 4U) | b;
-                *eight_bit = true;
-                r = 3;
-                break;
-        }
-
-        case 'u': {
-                /* C++11 style 16bit unicode */
-
-                int a[4];
-                size_t i;
-                uint32_t c;
-
-                if (length != (size_t) -1 && length < 5)
-                        return -EINVAL;
-
-                for (i = 0; i < 4; i++) {
-                        a[i] = unhexchar(p[1 + i]);
-                        if (a[i] < 0)
-                                return a[i];
-                }
-
-                c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
-
-                /* Don't allow 0 chars */
-                if (c == 0 && !accept_nul)
-                        return -EINVAL;
-
-                *ret = c;
-                r = 5;
-                break;
-        }
-
-        case 'U': {
-                /* C++11 style 32bit unicode */
-
-                int a[8];
-                size_t i;
-                char32_t c;
-
-                if (length != (size_t) -1 && length < 9)
-                        return -EINVAL;
-
-                for (i = 0; i < 8; i++) {
-                        a[i] = unhexchar(p[1 + i]);
-                        if (a[i] < 0)
-                                return a[i];
-                }
-
-                c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
-                    ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] <<  8U) | ((uint32_t) a[6] <<  4U) |  (uint32_t) a[7];
-
-                /* Don't allow 0 chars */
-                if (c == 0 && !accept_nul)
-                        return -EINVAL;
-
-                /* Don't allow invalid code points */
-                if (!unichar_is_valid(c))
-                        return -EINVAL;
-
-                *ret = c;
-                r = 9;
-                break;
-        }
-
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7': {
-                /* octal encoding */
-                int a, b, c;
-                char32_t m;
-
-                if (length != (size_t) -1 && length < 3)
-                        return -EINVAL;
-
-                a = unoctchar(p[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unoctchar(p[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unoctchar(p[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                /* don't allow NUL bytes */
-                if (a == 0 && b == 0 && c == 0 && !accept_nul)
-                        return -EINVAL;
-
-                /* Don't allow bytes above 255 */
-                m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
-                if (m > 255)
-                        return -EINVAL;
-
-                *ret = m;
-                *eight_bit = true;
-                r = 3;
-                break;
-        }
-
-        default:
-                return -EINVAL;
-        }
-
-        return r;
-}
-
-#if 0 /* NM_IGNORED */
-int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
-        char *r, *t;
-        const char *f;
-        size_t pl;
-
-        assert(s);
-        assert(ret);
-
-        /* Undoes C style string escaping, and optionally prefixes it. */
-
-        pl = strlen_ptr(prefix);
-
-        r = new(char, pl+length+1);
-        if (!r)
-                return -ENOMEM;
-
-        if (prefix)
-                memcpy(r, prefix, pl);
-
-        for (f = s, t = r + pl; f < s + length; f++) {
-                size_t remaining;
-                bool eight_bit = false;
-                char32_t u;
-                int k;
-
-                remaining = s + length - f;
-                assert(remaining > 0);
-
-                if (*f != '\\') {
-                        /* A literal, copy verbatim */
-                        *(t++) = *f;
-                        continue;
-                }
-
-                if (remaining == 1) {
-                        if (flags & UNESCAPE_RELAX) {
-                                /* A trailing backslash, copy verbatim */
-                                *(t++) = *f;
-                                continue;
-                        }
-
-                        free(r);
-                        return -EINVAL;
-                }
-
-                k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit, flags & UNESCAPE_ACCEPT_NUL);
-                if (k < 0) {
-                        if (flags & UNESCAPE_RELAX) {
-                                /* Invalid escape code, let's take it literal then */
-                                *(t++) = '\\';
-                                continue;
-                        }
-
-                        free(r);
-                        return k;
-                }
-
-                f += k;
-                if (eight_bit)
-                        /* One byte? Set directly as specified */
-                        *(t++) = u;
-                else
-                        /* Otherwise encode as multi-byte UTF-8 */
-                        t += utf8_encode_unichar(t, u);
-        }
-
-        *t = 0;
-
-        *ret = r;
-        return t - r;
-}
-
-char* xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits) {
-        char *ans, *t, *prev, *prev2;
-        const char *f;
-
-        /* Escapes all chars in bad, in addition to \ and all special chars, in \xFF style escaping. May be
-         * reversed with cunescape(). If eight_bits is true, characters >= 127 are let through unchanged.
-         * This corresponds to non-ASCII printable characters in pre-unicode encodings.
-         *
-         * If console_width is reached, output is truncated and "..." is appended. */
-
-        if (console_width == 0)
-                return strdup("");
-
-        ans = new(char, MIN(strlen(s), console_width) * 4 + 1);
-        if (!ans)
-                return NULL;
-
-        memset(ans, '_', MIN(strlen(s), console_width) * 4);
-        ans[MIN(strlen(s), console_width) * 4] = 0;
-
-        for (f = s, t = prev = prev2 = ans; ; f++) {
-                char *tmp_t = t;
-
-                if (!*f) {
-                        *t = 0;
-                        return ans;
-                }
-
-                if ((unsigned char) *f < ' ' || (!eight_bits && (unsigned char) *f >= 127) ||
-                    *f == '\\' || strchr(bad, *f)) {
-                        if ((size_t) (t - ans) + 4 > console_width)
-                                break;
-
-                        *(t++) = '\\';
-                        *(t++) = 'x';
-                        *(t++) = hexchar(*f >> 4);
-                        *(t++) = hexchar(*f);
-                } else {
-                        if ((size_t) (t - ans) + 1 > console_width)
-                                break;
-
-                        *(t++) = *f;
-                }
-
-                /* We might need to go back two cycles to fit three dots, so remember two positions */
-                prev2 = prev;
-                prev = tmp_t;
-        }
-
-        /* We can just write where we want, since chars are one-byte */
-        size_t c = MIN(console_width, 3u); /* If the console is too narrow, write fewer dots */
-        size_t off;
-        if (console_width - c >= (size_t) (t - ans))
-                off = (size_t) (t - ans);
-        else if (console_width - c >= (size_t) (prev - ans))
-                off = (size_t) (prev - ans);
-        else if (console_width - c >= (size_t) (prev2 - ans))
-                off = (size_t) (prev2 - ans);
-        else
-                off = console_width - c;
-        assert(off <= (size_t) (t - ans));
-
-        memcpy(ans + off, "...", c);
-        ans[off + c] = '\0';
-        return ans;
-}
-
-char* escape_non_printable_full(const char *str, size_t console_width, bool eight_bit) {
-        if (eight_bit)
-                return xescape_full(str, "", console_width, true);
-        else
-                return utf8_escape_non_printable_full(str, console_width);
-}
-#endif /* NM_IGNORED */
-
-char* octescape(const char *s, size_t len) {
-        char *r, *t;
-        const char *f;
-
-        /* Escapes all chars in bad, in addition to \ and " chars,
-         * in \nnn style escaping. */
-
-        r = new(char, len * 4 + 1);
-        if (!r)
-                return NULL;
-
-        for (f = s, t = r; f < s + len; f++) {
-
-                if (*f < ' ' || *f >= 127 || IN_SET(*f, '\\', '"')) {
-                        *(t++) = '\\';
-                        *(t++) = '0' + (*f >> 6);
-                        *(t++) = '0' + ((*f >> 3) & 8);
-                        *(t++) = '0' + (*f & 8);
-                } else
-                        *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return r;
-
-}
-
-static char* strcpy_backslash_escaped(char *t, const char *s, const char *bad, bool escape_tab_nl) {
-        assert(bad);
-
-        for (; *s; s++) {
-                if (escape_tab_nl && IN_SET(*s, '\n', '\t')) {
-                        *(t++) = '\\';
-                        *(t++) = *s == '\n' ? 'n' : 't';
-                        continue;
-                }
-
-                if (*s == '\\' || strchr(bad, *s))
-                        *(t++) = '\\';
-
-                *(t++) = *s;
-        }
-
-        return t;
-}
-
-char* shell_escape(const char *s, const char *bad) {
-        char *r, *t;
-
-        r = new(char, strlen(s)*2+1);
-        if (!r)
-                return NULL;
-
-        t = strcpy_backslash_escaped(r, s, bad, false);
-        *t = 0;
-
-        return r;
-}
-
-char* shell_maybe_quote(const char *s, EscapeStyle style) {
-        const char *p;
-        char *r, *t;
-
-        assert(s);
-
-        /* Encloses a string in quotes if necessary to make it OK as a shell
-         * string. Note that we treat benign UTF-8 characters as needing
-         * escaping too, but that should be OK. */
-
-        for (p = s; *p; p++)
-                if (*p <= ' ' ||
-                    *p >= 127 ||
-                    strchr(SHELL_NEED_QUOTES, *p))
-                        break;
-
-        if (!*p)
-                return strdup(s);
-
-        r = new(char, (style == ESCAPE_POSIX) + 1 + strlen(s)*2 + 1 + 1);
-        if (!r)
-                return NULL;
-
-        t = r;
-        switch (style) {
-        case ESCAPE_BACKSLASH:
-        case ESCAPE_BACKSLASH_ONELINE:
-                *(t++) = '"';
-                break;
-        case ESCAPE_POSIX:
-                *(t++) = '$';
-                *(t++) = '\'';
-                break;
-        default:
-                assert_not_reached("Bad EscapeStyle");
-        }
-
-        t = mempcpy(t, s, p - s);
-
-        if (IN_SET(style, ESCAPE_BACKSLASH, ESCAPE_BACKSLASH_ONELINE))
-                t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE,
-                                             style == ESCAPE_BACKSLASH_ONELINE);
-        else
-                t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE_POSIX, true);
-
-        if (IN_SET(style, ESCAPE_BACKSLASH, ESCAPE_BACKSLASH_ONELINE))
-                *(t++) = '"';
-        else
-                *(t++) = '\'';
-        *t = 0;
-
-        return r;
-}
diff --git a/shared/systemd/src/basic/escape.h b/shared/systemd/src/basic/escape.h
deleted file mode 100644
index 691b6d80..00000000
--- a/shared/systemd/src/basic/escape.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <uchar.h>
-
-#include "string-util.h"
-#include "missing_type.h"
-
-/* What characters are special in the shell? */
-/* must be escaped outside and inside double-quotes */
-#define SHELL_NEED_ESCAPE "\"\\`$"
-
-/* Those that can be escaped or double-quoted.
- *
- * 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 "'()<>|&;!"
-
-/* Note that we assume control characters would need to be escaped too in
- * addition to the "special" characters listed here, if they appear in the
- * string. Current users disallow control characters. Also '"' shall not
- * be escaped.
- */
-#define SHELL_NEED_ESCAPE_POSIX "\\\'"
-
-typedef enum UnescapeFlags {
-        UNESCAPE_RELAX      = 1 << 0,
-        UNESCAPE_ACCEPT_NUL = 1 << 1,
-} UnescapeFlags;
-
-typedef enum EscapeStyle {
-        ESCAPE_BACKSLASH         = 1,  /* Add shell quotes ("") so the shell will consider this a single
-                                          argument, possibly multiline. Tabs and newlines are not escaped. */
-        ESCAPE_BACKSLASH_ONELINE = 2,  /* Similar to ESCAPE_BACKSLASH, but always produces a single-line
-                                          string instead. Shell escape sequences are produced for tabs and
-                                          newlines. */
-        ESCAPE_POSIX             = 3,  /* Similar to ESCAPE_BACKSLASH_ONELINE, but uses POSIX shell escape
-                                        * syntax (a string enclosed in $'') instead of plain quotes. */
-} EscapeStyle;
-
-char* cescape(const char *s);
-char* cescape_length(const char *s, size_t n);
-int cescape_char(char c, char *buf);
-
-int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
-static inline int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
-        return cunescape_length_with_prefix(s, length, NULL, flags, ret);
-}
-static inline int cunescape(const char *s, UnescapeFlags flags, char **ret) {
-        return cunescape_length(s, strlen(s), flags, ret);
-}
-int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul);
-
-char* xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits);
-static inline char* xescape(const char *s, const char *bad) {
-        return xescape_full(s, bad, SIZE_MAX, false);
-}
-char* octescape(const char *s, size_t len);
-char* escape_non_printable_full(const char *str, size_t console_width, bool eight_bit);
-
-char* shell_escape(const char *s, const char *bad);
-char* shell_maybe_quote(const char *s, EscapeStyle style);
diff --git a/shared/systemd/src/basic/ether-addr-util.c b/shared/systemd/src/basic/ether-addr-util.c
deleted file mode 100644
index ae83eade..00000000
--- a/shared/systemd/src/basic/ether-addr-util.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/* 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>
-
-#include "ether-addr-util.h"
-#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);
-
-        /* Like ether_ntoa() but uses %02x instead of %x to print
-         * ethernet addresses, which makes them look less funny. Also,
-         * doesn't use a static buffer. */
-
-        sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
-                addr->ether_addr_octet[0],
-                addr->ether_addr_octet[1],
-                addr->ether_addr_octet[2],
-                addr->ether_addr_octet[3],
-                addr->ether_addr_octet[4],
-                addr->ether_addr_octet[5]);
-
-        return buffer;
-}
-
-int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b) {
-        return memcmp(a, b, ETH_ALEN);
-}
-
-static void ether_addr_hash_func(const struct ether_addr *p, struct siphash *state) {
-        siphash24_compress(p, sizeof(struct ether_addr), state);
-}
-
-DEFINE_HASH_OPS(ether_addr_hash_ops, struct ether_addr, ether_addr_hash_func, ether_addr_compare);
-
-int ether_addr_from_string(const char *s, struct ether_addr *ret) {
-        size_t pos = 0, n, field;
-        char sep = '\0';
-        const char *hex = HEXDIGITS, *hexoff;
-        size_t x;
-        bool touched;
-
-#define parse_fields(v)                                         \
-        for (field = 0; field < ELEMENTSOF(v); field++) {       \
-                touched = false;                                \
-                for (n = 0; n < (2 * sizeof(v[0])); n++) {      \
-                        if (s[pos] == '\0')                     \
-                                break;                          \
-                        hexoff = strchr(hex, s[pos]);           \
-                        if (!hexoff)                            \
-                                break;                          \
-                        assert(hexoff >= hex);                  \
-                        x = hexoff - hex;                       \
-                        if (x >= 16)                            \
-                                x -= 6; /* A-F */               \
-                        assert(x < 16);                         \
-                        touched = true;                         \
-                        v[field] <<= 4;                         \
-                        v[field] += x;                          \
-                        pos++;                                  \
-                }                                               \
-                if (!touched)                                   \
-                        return -EINVAL;                         \
-                if (field < (ELEMENTSOF(v)-1)) {                \
-                        if (s[pos] != sep)                      \
-                                return -EINVAL;                 \
-                        else                                    \
-                                pos++;                          \
-                }                                               \
-        }
-
-        assert(s);
-        assert(ret);
-
-        s += strspn(s, WHITESPACE);
-        sep = s[strspn(s, hex)];
-
-        if (sep == '.') {
-                uint16_t shorts[3] = { 0 };
-
-                parse_fields(shorts);
-
-                if (s[pos] != '\0')
-                        return -EINVAL;
-
-                for (n = 0; n < ELEMENTSOF(shorts); n++) {
-                        ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8);
-                        ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff);
-                }
-
-        } else if (IN_SET(sep, ':', '-')) {
-                struct ether_addr out = ETHER_ADDR_NULL;
-
-                parse_fields(out.ether_addr_octet);
-
-                if (s[pos] != '\0')
-                        return -EINVAL;
-
-                for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++)
-                        ret->ether_addr_octet[n] = out.ether_addr_octet[n];
-
-        } else
-                return -EINVAL;
-
-        return 0;
-}
diff --git a/shared/systemd/src/basic/ether-addr-util.h b/shared/systemd/src/basic/ether-addr-util.h
deleted file mode 100644
index 942ce556..00000000
--- a/shared/systemd/src/basic/ether-addr-util.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* 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]
-
-#define ETHER_ADDR_TO_STRING_MAX (3*6)
-char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
-
-int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b);
-static inline bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
-        return ether_addr_compare(a, b) == 0;
-}
-
-#define ETHER_ADDR_NULL ((const struct ether_addr){})
-
-static inline bool ether_addr_is_null(const struct ether_addr *addr) {
-        return ether_addr_equal(addr, &ETHER_ADDR_NULL);
-}
-
-int ether_addr_from_string(const char *s, struct ether_addr *ret);
-
-extern const struct hash_ops ether_addr_hash_ops;
diff --git a/shared/systemd/src/basic/extract-word.c b/shared/systemd/src/basic/extract-word.c
deleted file mode 100644
index 1d86033f..00000000
--- a/shared/systemd/src/basic/extract-word.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <syslog.h>
-
-#include "alloc-util.h"
-#include "escape.h"
-#include "extract-word.h"
-#include "log.h"
-#include "macro.h"
-#include "string-util.h"
-#include "strv.h"
-#include "utf8.h"
-
-int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
-        _cleanup_free_ char *s = NULL;
-        size_t allocated = 0, sz = 0;
-        char c;
-        int r;
-
-        char quote = 0;                 /* 0 or ' or " */
-        bool backslash = false;         /* whether we've just seen a backslash */
-
-        assert(p);
-        assert(ret);
-
-        /* Bail early if called after last value or with no input */
-        if (!*p)
-                goto finish;
-        c = **p;
-
-        if (!separators)
-                separators = WHITESPACE;
-
-        /* Parses the first word of a string, and returns it in
-         * *ret. Removes all quotes in the process. When parsing fails
-         * (because of an uneven number of quotes or similar), leaves
-         * the pointer *p at the first invalid character. */
-
-        if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
-                if (!GREEDY_REALLOC(s, allocated, sz+1))
-                        return -ENOMEM;
-
-        for (;; (*p)++, c = **p) {
-                if (c == 0)
-                        goto finish_force_terminate;
-                else if (strchr(separators, c)) {
-                        if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
-                                (*p)++;
-                                goto finish_force_next;
-                        }
-                } else {
-                        /* We found a non-blank character, so we will always
-                         * want to return a string (even if it is empty),
-                         * allocate it here. */
-                        if (!GREEDY_REALLOC(s, allocated, sz+1))
-                                return -ENOMEM;
-                        break;
-                }
-        }
-
-        for (;; (*p)++, c = **p) {
-                if (backslash) {
-                        if (!GREEDY_REALLOC(s, allocated, sz+7))
-                                return -ENOMEM;
-
-                        if (c == 0) {
-                                if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
-                                    (!quote || flags & EXTRACT_RELAX)) {
-                                        /* If we find an unquoted trailing backslash and we're in
-                                         * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
-                                         * output.
-                                         *
-                                         * Unbalanced quotes will only be allowed in EXTRACT_RELAX
-                                         * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
-                                         */
-                                        s[sz++] = '\\';
-                                        goto finish_force_terminate;
-                                }
-                                if (flags & EXTRACT_RELAX)
-                                        goto finish_force_terminate;
-                                return -EINVAL;
-                        }
-
-                        if (flags & (EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS)) {
-                                bool eight_bit = false;
-                                char32_t u;
-
-                                if ((flags & EXTRACT_CUNESCAPE) &&
-                                    (r = cunescape_one(*p, (size_t) -1, &u, &eight_bit, false)) >= 0) {
-                                        /* A valid escaped sequence */
-                                        assert(r >= 1);
-
-                                        (*p) += r - 1;
-
-                                        if (eight_bit)
-                                                s[sz++] = u;
-                                        else
-                                                sz += utf8_encode_unichar(s + sz, u);
-                                } else if ((flags & EXTRACT_UNESCAPE_SEPARATORS) &&
-                                           strchr(separators, **p))
-                                        /* An escaped separator char */
-                                        s[sz++] = c;
-                                else if (flags & EXTRACT_CUNESCAPE_RELAX) {
-                                        s[sz++] = '\\';
-                                        s[sz++] = c;
-                                } else
-                                        return -EINVAL;
-                        } else
-                                s[sz++] = c;
-
-                        backslash = false;
-
-                } else if (quote) {     /* inside either single or double quotes */
-                        for (;; (*p)++, c = **p) {
-                                if (c == 0) {
-                                        if (flags & EXTRACT_RELAX)
-                                                goto finish_force_terminate;
-                                        return -EINVAL;
-                                } else if (c == quote) {        /* found the end quote */
-                                        quote = 0;
-                                        break;
-                                } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
-                                        backslash = true;
-                                        break;
-                                } else {
-                                        if (!GREEDY_REALLOC(s, allocated, sz+2))
-                                                return -ENOMEM;
-
-                                        s[sz++] = c;
-                                }
-                        }
-
-                } else {
-                        for (;; (*p)++, c = **p) {
-                                if (c == 0)
-                                        goto finish_force_terminate;
-                                else if (IN_SET(c, '\'', '"') && (flags & EXTRACT_UNQUOTE)) {
-                                        quote = c;
-                                        break;
-                                } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
-                                        backslash = true;
-                                        break;
-                                } else if (strchr(separators, c)) {
-                                        if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
-                                                (*p)++;
-                                                goto finish_force_next;
-                                        }
-                                        /* Skip additional coalesced separators. */
-                                        for (;; (*p)++, c = **p) {
-                                                if (c == 0)
-                                                        goto finish_force_terminate;
-                                                if (!strchr(separators, c))
-                                                        break;
-                                        }
-                                        goto finish;
-
-                                } else {
-                                        if (!GREEDY_REALLOC(s, allocated, sz+2))
-                                                return -ENOMEM;
-
-                                        s[sz++] = c;
-                                }
-                        }
-                }
-        }
-
-finish_force_terminate:
-        *p = NULL;
-finish:
-        if (!s) {
-                *p = NULL;
-                *ret = NULL;
-                return 0;
-        }
-
-finish_force_next:
-        s[sz] = 0;
-        *ret = TAKE_PTR(s);
-
-        return 1;
-}
-
-#if 0 /* NM_IGNORED */
-int extract_first_word_and_warn(
-                const char **p,
-                char **ret,
-                const char *separators,
-                ExtractFlags flags,
-                const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *rvalue) {
-
-        /* Try to unquote it, if it fails, warn about it and try again
-         * but this time using EXTRACT_CUNESCAPE_RELAX to keep the
-         * backslashes verbatim in invalid escape sequences. */
-
-        const char *save;
-        int r;
-
-        save = *p;
-        r = extract_first_word(p, ret, separators, flags);
-        if (r >= 0)
-                return r;
-
-        if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
-
-                /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
-                *p = save;
-                r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
-                if (r >= 0) {
-                        /* It worked this time, hence it must have been an invalid escape sequence. */
-                        log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Ignoring unknown escape sequences: \"%s\"", *ret);
-                        return r;
-                }
-
-                /* If it's still EINVAL; then it must be unbalanced quoting, report this. */
-                if (r == -EINVAL)
-                        return log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting, ignoring: \"%s\"", rvalue);
-        }
-
-        /* Can be any error, report it */
-        return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue);
-}
-
-/* We pass ExtractFlags as unsigned int (to avoid undefined behaviour when passing
- * an object that undergoes default argument promotion as an argument to va_start).
- * Let's make sure that ExtractFlags fits into an unsigned int. */
-assert_cc(sizeof(enum ExtractFlags) <= sizeof(unsigned));
-
-int extract_many_words(const char **p, const char *separators, unsigned flags, ...) {
-        va_list ap;
-        char **l;
-        int n = 0, i, c, r;
-
-        /* Parses a number of words from a string, stripping any
-         * quotes if necessary. */
-
-        assert(p);
-
-        /* Count how many words are expected */
-        va_start(ap, flags);
-        for (;;) {
-                if (!va_arg(ap, char **))
-                        break;
-                n++;
-        }
-        va_end(ap);
-
-        if (n <= 0)
-                return 0;
-
-        /* Read all words into a temporary array */
-        l = newa0(char*, n);
-        for (c = 0; c < n; c++) {
-
-                r = extract_first_word(p, &l[c], separators, flags);
-                if (r < 0) {
-                        int j;
-
-                        for (j = 0; j < c; j++)
-                                free(l[j]);
-
-                        return r;
-                }
-
-                if (r == 0)
-                        break;
-        }
-
-        /* If we managed to parse all words, return them in the passed
-         * in parameters */
-        va_start(ap, flags);
-        for (i = 0; i < n; i++) {
-                char **v;
-
-                v = va_arg(ap, char **);
-                assert(v);
-
-                *v = l[i];
-        }
-        va_end(ap);
-
-        return c;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/extract-word.h b/shared/systemd/src/basic/extract-word.h
deleted file mode 100644
index d1de32e5..00000000
--- a/shared/systemd/src/basic/extract-word.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include "macro.h"
-
-typedef enum ExtractFlags {
-        EXTRACT_RELAX                    = 1 << 0,
-        EXTRACT_CUNESCAPE                = 1 << 1,
-        EXTRACT_CUNESCAPE_RELAX          = 1 << 2,
-        EXTRACT_UNESCAPE_SEPARATORS      = 1 << 3,
-        EXTRACT_UNQUOTE                  = 1 << 4,
-        EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5,
-        EXTRACT_RETAIN_ESCAPE            = 1 << 6,
-} ExtractFlags;
-
-int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
-int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
-int extract_many_words(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
diff --git a/shared/systemd/src/basic/fd-util.c b/shared/systemd/src/basic/fd-util.c
deleted file mode 100644
index e53cf18d..00000000
--- a/shared/systemd/src/basic/fd-util.c
+++ /dev/null
@@ -1,1071 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "copy.h"
-#include "dirent-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "io-util.h"
-#include "macro.h"
-#include "memfd-util.h"
-#include "missing_fcntl.h"
-#include "missing_syscall.h"
-#include "parse-util.h"
-#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"
-#include "util.h"
-
-/* The maximum number of iterations in the loop to close descriptors in the fallback case
- * when /proc/self/fd/ is inaccessible. */
-#define MAX_FD_LOOP_LIMIT (1024*1024)
-
-int close_nointr(int fd) {
-        assert(fd >= 0);
-
-        if (close(fd) >= 0)
-                return 0;
-
-        /*
-         * Just ignore EINTR; a retry loop is the wrong thing to do on
-         * Linux.
-         *
-         * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
-         * https://bugzilla.gnome.org/show_bug.cgi?id=682819
-         * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
-         * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
-         */
-        if (errno == EINTR)
-                return 0;
-
-        return -errno;
-}
-
-int safe_close(int fd) {
-
-        /*
-         * Like close_nointr() but cannot fail. Guarantees errno is
-         * unchanged. Is a NOP with negative fds passed, and returns
-         * -1, so that it can be used in this syntax:
-         *
-         * fd = safe_close(fd);
-         */
-
-        if (fd >= 0) {
-                PROTECT_ERRNO;
-
-                /* The kernel might return pretty much any error code
-                 * via close(), but the fd will be closed anyway. The
-                 * only condition we want to check for here is whether
-                 * the fd was invalid at all... */
-
-                assert_se(close_nointr(fd) != -EBADF);
-        }
-
-        return -1;
-}
-
-void safe_close_pair(int p[static 2]) {
-        assert(p);
-
-        if (p[0] == p[1]) {
-                /* Special case pairs which use the same fd in both
-                 * directions... */
-                p[0] = p[1] = safe_close(p[0]);
-                return;
-        }
-
-        p[0] = safe_close(p[0]);
-        p[1] = safe_close(p[1]);
-}
-
-void close_many(const int fds[], size_t n_fd) {
-        size_t i;
-
-        assert(fds || n_fd <= 0);
-
-        for (i = 0; i < n_fd; i++)
-                safe_close(fds[i]);
-}
-
-int fclose_nointr(FILE *f) {
-        assert(f);
-
-        /* Same as close_nointr(), but for fclose() */
-
-        errno = 0; /* Extra safety: if the FILE* object is not encapsulating an fd, it might not set errno
-                    * correctly. Let's hence initialize it to zero first, so that we aren't confused by any
-                    * prior errno here */
-        if (fclose(f) == 0)
-                return 0;
-
-        if (errno == EINTR)
-                return 0;
-
-        return errno_or_else(EIO);
-}
-
-FILE* safe_fclose(FILE *f) {
-
-        /* Same as safe_close(), but for fclose() */
-
-        if (f) {
-                PROTECT_ERRNO;
-
-                assert_se(fclose_nointr(f) != -EBADF);
-        }
-
-        return NULL;
-}
-
-DIR* safe_closedir(DIR *d) {
-
-        if (d) {
-                PROTECT_ERRNO;
-
-                assert_se(closedir(d) >= 0 || errno != EBADF);
-        }
-
-        return NULL;
-}
-
-int fd_nonblock(int fd, bool nonblock) {
-        int flags, nflags;
-
-        assert(fd >= 0);
-
-        flags = fcntl(fd, F_GETFL, 0);
-        if (flags < 0)
-                return -errno;
-
-        nflags = UPDATE_FLAG(flags, O_NONBLOCK, nonblock);
-        if (nflags == flags)
-                return 0;
-
-        if (fcntl(fd, F_SETFL, nflags) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int fd_cloexec(int fd, bool cloexec) {
-        int flags, nflags;
-
-        assert(fd >= 0);
-
-        flags = fcntl(fd, F_GETFD, 0);
-        if (flags < 0)
-                return -errno;
-
-        nflags = UPDATE_FLAG(flags, FD_CLOEXEC, cloexec);
-        if (nflags == flags)
-                return 0;
-
-        if (fcntl(fd, F_SETFD, nflags) < 0)
-                return -errno;
-
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-_pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {
-        size_t i;
-
-        assert(n_fdset == 0 || fdset);
-
-        for (i = 0; i < n_fdset; i++)
-                if (fdset[i] == fd)
-                        return true;
-
-        return false;
-}
-
-static int get_max_fd(void) {
-        struct rlimit rl;
-        rlim_t m;
-
-        /* Return the highest possible fd, based RLIMIT_NOFILE, but enforcing FD_SETSIZE-1 as lower boundary
-         * and INT_MAX as upper boundary. */
-
-        if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
-                return -errno;
-
-        m = MAX(rl.rlim_cur, rl.rlim_max);
-        if (m < FD_SETSIZE) /* Let's always cover at least 1024 fds */
-                return FD_SETSIZE-1;
-
-        if (m == RLIM_INFINITY || m > INT_MAX) /* Saturate on overflow. After all fds are "int", hence can
-                                                * never be above INT_MAX */
-                return INT_MAX;
-
-        return (int) (m - 1);
-}
-
-int close_all_fds(const int except[], size_t n_except) {
-        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;
-
-                /* When /proc isn't available (for example in chroots) the fallback is brute forcing through
-                 * the fd table */
-
-                max_fd = get_max_fd();
-                if (max_fd < 0)
-                        return max_fd;
-
-                /* Refuse to do the loop over more too many elements. It's better to fail immediately than to
-                 * spin the CPU for a long time. */
-                if (max_fd > MAX_FD_LOOP_LIMIT)
-                        return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
-                                               "/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
-                                               max_fd);
-
-                for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
-                        int q;
-
-                        if (fd_in_set(fd, except, n_except))
-                                continue;
-
-                        q = close_nointr(fd);
-                        if (q < 0 && q != -EBADF && r >= 0)
-                                r = q;
-                }
-
-                return r;
-        }
-
-        FOREACH_DIRENT(de, d, return -errno) {
-                int fd = -1, q;
-
-                if (safe_atoi(de->d_name, &fd) < 0)
-                        /* Let's better ignore this, just in case */
-                        continue;
-
-                if (fd < 3)
-                        continue;
-
-                if (fd == dirfd(d))
-                        continue;
-
-                if (fd_in_set(fd, except, n_except))
-                        continue;
-
-                q = close_nointr(fd);
-                if (q < 0 && q != -EBADF && r >= 0) /* Valgrind has its own FD and doesn't want to have it closed */
-                        r = q;
-        }
-
-        return r;
-}
-
-int same_fd(int a, int b) {
-        struct stat sta, stb;
-        pid_t pid;
-        int r, fa, fb;
-
-        assert(a >= 0);
-        assert(b >= 0);
-
-        /* Compares two file descriptors. Note that semantics are
-         * quite different depending on whether we have kcmp() or we
-         * don't. If we have kcmp() this will only return true for
-         * dup()ed file descriptors, but not otherwise. If we don't
-         * have kcmp() this will also return true for two fds of the same
-         * file, created by separate open() calls. Since we use this
-         * call mostly for filtering out duplicates in the fd store
-         * this difference hopefully doesn't matter too much. */
-
-        if (a == b)
-                return true;
-
-        /* Try to use kcmp() if we have it. */
-        pid = getpid_cached();
-        r = kcmp(pid, pid, KCMP_FILE, a, b);
-        if (r == 0)
-                return true;
-        if (r > 0)
-                return false;
-        if (!IN_SET(errno, ENOSYS, EACCES, EPERM))
-                return -errno;
-
-        /* We don't have kcmp(), use fstat() instead. */
-        if (fstat(a, &sta) < 0)
-                return -errno;
-
-        if (fstat(b, &stb) < 0)
-                return -errno;
-
-        if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
-                return false;
-
-        /* We consider all device fds different, since two device fds
-         * might refer to quite different device contexts even though
-         * they share the same inode and backing dev_t. */
-
-        if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
-                return false;
-
-        if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
-                return false;
-
-        /* The fds refer to the same inode on disk, let's also check
-         * if they have the same fd flags. This is useful to
-         * distinguish the read and write side of a pipe created with
-         * pipe(). */
-        fa = fcntl(a, F_GETFL);
-        if (fa < 0)
-                return -errno;
-
-        fb = fcntl(b, F_GETFL);
-        if (fb < 0)
-                return -errno;
-
-        return fa == fb;
-}
-#endif /* NM_IGNORED */
-
-void cmsg_close_all(struct msghdr *mh) {
-        struct cmsghdr *cmsg;
-
-        assert(mh);
-
-        CMSG_FOREACH(cmsg, mh)
-                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
-                        close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
-}
-
-bool fdname_is_valid(const char *s) {
-        const char *p;
-
-        /* Validates a name for $LISTEN_FDNAMES. We basically allow
-         * everything ASCII that's not a control character. Also, as
-         * special exception the ":" character is not allowed, as we
-         * use that as field separator in $LISTEN_FDNAMES.
-         *
-         * Note that the empty string is explicitly allowed
-         * here. However, we limit the length of the names to 255
-         * characters. */
-
-        if (!s)
-                return false;
-
-        for (p = s; *p; p++) {
-                if (*p < ' ')
-                        return false;
-                if (*p >= 127)
-                        return false;
-                if (*p == ':')
-                        return false;
-        }
-
-        return p - s < 256;
-}
-
-#if 0 /* NM_IGNORED */
-int fd_get_path(int fd, char **ret) {
-        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
-        int r;
-
-        xsprintf(procfs_path, "/proc/self/fd/%i", fd);
-        r = readlink_malloc(procfs_path, ret);
-        if (r == -ENOENT) {
-                /* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make
-                 * things debuggable and distinguish the two. */
-
-                if (proc_mounted() == 0)
-                        return -ENOSYS;  /* /proc is not available or not set up properly, we're most likely in some chroot
-                                          * environment. */
-                return -EBADF; /* The directory exists, hence it's the fd that doesn't. */
-        }
-
-        return r;
-}
-
-int move_fd(int from, int to, int cloexec) {
-        int r;
-
-        /* Move fd 'from' to 'to', make sure FD_CLOEXEC remains equal if requested, and release the old fd. If
-         * 'cloexec' is passed as -1, the original FD_CLOEXEC is inherited for the new fd. If it is 0, it is turned
-         * off, if it is > 0 it is turned on. */
-
-        if (from < 0)
-                return -EBADF;
-        if (to < 0)
-                return -EBADF;
-
-        if (from == to) {
-
-                if (cloexec >= 0) {
-                        r = fd_cloexec(to, cloexec);
-                        if (r < 0)
-                                return r;
-                }
-
-                return to;
-        }
-
-        if (cloexec < 0) {
-                int fl;
-
-                fl = fcntl(from, F_GETFD, 0);
-                if (fl < 0)
-                        return -errno;
-
-                cloexec = !!(fl & FD_CLOEXEC);
-        }
-
-        r = dup3(from, to, cloexec ? O_CLOEXEC : 0);
-        if (r < 0)
-                return -errno;
-
-        assert(r == to);
-
-        safe_close(from);
-
-        return to;
-}
-
-int acquire_data_fd(const void *data, size_t size, unsigned flags) {
-
-        _cleanup_close_pair_ int pipefds[2] = { -1, -1 };
-        char pattern[] = "/dev/shm/data-fd-XXXXXX";
-        _cleanup_close_ int fd = -1;
-        int isz = 0, r;
-        ssize_t n;
-        off_t f;
-
-        assert(data || size == 0);
-
-        /* Acquire a read-only file descriptor that when read from returns the specified data. This is much more
-         * complex than I wish it was. But here's why:
-         *
-         * a) First we try to use memfds. They are the best option, as we can seal them nicely to make them
-         *    read-only. Unfortunately they require kernel 3.17, and – at the time of writing – we still support 3.14.
-         *
-         * b) Then, we try classic pipes. They are the second best options, as we can close the writing side, retaining
-         *    a nicely read-only fd in the reading side. However, they are by default quite small, and unprivileged
-         *    clients can only bump their size to a system-wide limit, which might be quite low.
-         *
-         * c) Then, we try an O_TMPFILE file in /dev/shm (that dir is the only suitable one known to exist from
-         *    earliest boot on). To make it read-only we open the fd a second time with O_RDONLY via
-         *    /proc/self/<fd>. Unfortunately O_TMPFILE is not available on older kernels on tmpfs.
-         *
-         * d) Finally, we try creating a regular file in /dev/shm, which we then delete.
-         *
-         * It sucks a bit that depending on the situation we return very different objects here, but that's Linux I
-         * figure. */
-
-        if (size == 0 && ((flags & ACQUIRE_NO_DEV_NULL) == 0)) {
-                /* As a special case, return /dev/null if we have been called for an empty data block */
-                r = open("/dev/null", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (r < 0)
-                        return -errno;
-
-                return r;
-        }
-
-        if ((flags & ACQUIRE_NO_MEMFD) == 0) {
-                fd = memfd_new("data-fd");
-                if (fd < 0)
-                        goto try_pipe;
-
-                n = write(fd, data, size);
-                if (n < 0)
-                        return -errno;
-                if ((size_t) n != size)
-                        return -EIO;
-
-                f = lseek(fd, 0, SEEK_SET);
-                if (f != 0)
-                        return -errno;
-
-                r = memfd_set_sealed(fd);
-                if (r < 0)
-                        return r;
-
-                return TAKE_FD(fd);
-        }
-
-try_pipe:
-        if ((flags & ACQUIRE_NO_PIPE) == 0) {
-                if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0)
-                        return -errno;
-
-                isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
-                if (isz < 0)
-                        return -errno;
-
-                if ((size_t) isz < size) {
-                        isz = (int) size;
-                        if (isz < 0 || (size_t) isz != size)
-                                return -E2BIG;
-
-                        /* Try to bump the pipe size */
-                        (void) fcntl(pipefds[1], F_SETPIPE_SZ, isz);
-
-                        /* See if that worked */
-                        isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
-                        if (isz < 0)
-                                return -errno;
-
-                        if ((size_t) isz < size)
-                                goto try_dev_shm;
-                }
-
-                n = write(pipefds[1], data, size);
-                if (n < 0)
-                        return -errno;
-                if ((size_t) n != size)
-                        return -EIO;
-
-                (void) fd_nonblock(pipefds[0], false);
-
-                return TAKE_FD(pipefds[0]);
-        }
-
-try_dev_shm:
-        if ((flags & ACQUIRE_NO_TMPFILE) == 0) {
-                fd = open("/dev/shm", O_RDWR|O_TMPFILE|O_CLOEXEC, 0500);
-                if (fd < 0)
-                        goto try_dev_shm_without_o_tmpfile;
-
-                n = write(fd, data, size);
-                if (n < 0)
-                        return -errno;
-                if ((size_t) n != size)
-                        return -EIO;
-
-                /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
-                return fd_reopen(fd, O_RDONLY|O_CLOEXEC);
-        }
-
-try_dev_shm_without_o_tmpfile:
-        if ((flags & ACQUIRE_NO_REGULAR) == 0) {
-                fd = mkostemp_safe(pattern);
-                if (fd < 0)
-                        return fd;
-
-                n = write(fd, data, size);
-                if (n < 0) {
-                        r = -errno;
-                        goto unlink_and_return;
-                }
-                if ((size_t) n != size) {
-                        r = -EIO;
-                        goto unlink_and_return;
-                }
-
-                /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
-                r = open(pattern, O_RDONLY|O_CLOEXEC);
-                if (r < 0)
-                        r = -errno;
-
-        unlink_and_return:
-                (void) unlink(pattern);
-                return r;
-        }
-
-        return -EOPNOTSUPP;
-}
-
-/* When the data is smaller or equal to 64K, try to place the copy in a memfd/pipe */
-#define DATA_FD_MEMORY_LIMIT (64U*1024U)
-
-/* If memfd/pipe didn't work out, then let's use a file in /tmp up to a size of 1M. If it's large than that use /var/tmp instead. */
-#define DATA_FD_TMP_LIMIT (1024U*1024U)
-
-int fd_duplicate_data_fd(int fd) {
-
-        _cleanup_close_ int copy_fd = -1, tmp_fd = -1;
-        _cleanup_free_ void *remains = NULL;
-        size_t remains_size = 0;
-        const char *td;
-        struct stat st;
-        int r;
-
-        /* Creates a 'data' fd from the specified source fd, containing all the same data in a read-only fashion, but
-         * independent of it (i.e. the source fd can be closed and unmounted after this call succeeded). Tries to be
-         * somewhat smart about where to place the data. In the best case uses a memfd(). If memfd() are not supported
-         * uses a pipe instead. For larger data will use an unlinked file in /tmp, and for even larger data one in
-         * /var/tmp. */
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        /* For now, let's only accept regular files, sockets, pipes and char devices */
-        if (S_ISDIR(st.st_mode))
-                return -EISDIR;
-        if (S_ISLNK(st.st_mode))
-                return -ELOOP;
-        if (!S_ISREG(st.st_mode) && !S_ISSOCK(st.st_mode) && !S_ISFIFO(st.st_mode) && !S_ISCHR(st.st_mode))
-                return -EBADFD;
-
-        /* If we have reason to believe the data is bounded in size, then let's use memfds or pipes as backing fd. Note
-         * that we use the reported regular file size only as a hint, given that there are plenty special files in
-         * /proc and /sys which report a zero file size but can be read from. */
-
-        if (!S_ISREG(st.st_mode) || st.st_size < DATA_FD_MEMORY_LIMIT) {
-
-                /* Try a memfd first */
-                copy_fd = memfd_new("data-fd");
-                if (copy_fd >= 0) {
-                        off_t f;
-
-                        r = copy_bytes(fd, copy_fd, DATA_FD_MEMORY_LIMIT, 0);
-                        if (r < 0)
-                                return r;
-
-                        f = lseek(copy_fd, 0, SEEK_SET);
-                        if (f != 0)
-                                return -errno;
-
-                        if (r == 0) {
-                                /* Did it fit into the limit? If so, we are done. */
-                                r = memfd_set_sealed(copy_fd);
-                                if (r < 0)
-                                        return r;
-
-                                return TAKE_FD(copy_fd);
-                        }
-
-                        /* Hmm, pity, this didn't fit. Let's fall back to /tmp then, see below */
-
-                } else {
-                        _cleanup_(close_pairp) int pipefds[2] = { -1, -1 };
-                        int isz;
-
-                        /* If memfds aren't available, use a pipe. Set O_NONBLOCK so that we will get EAGAIN rather
-                         * then block indefinitely when we hit the pipe size limit */
-
-                        if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0)
-                                return -errno;
-
-                        isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
-                        if (isz < 0)
-                                return -errno;
-
-                        /* Try to enlarge the pipe size if necessary */
-                        if ((size_t) isz < DATA_FD_MEMORY_LIMIT) {
-
-                                (void) fcntl(pipefds[1], F_SETPIPE_SZ, DATA_FD_MEMORY_LIMIT);
-
-                                isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0);
-                                if (isz < 0)
-                                        return -errno;
-                        }
-
-                        if ((size_t) isz >= DATA_FD_MEMORY_LIMIT) {
-
-                                r = copy_bytes_full(fd, pipefds[1], DATA_FD_MEMORY_LIMIT, 0, &remains, &remains_size, NULL, NULL);
-                                if (r < 0 && r != -EAGAIN)
-                                        return r; /* If we get EAGAIN it could be because of the source or because of
-                                                   * the destination fd, we can't know, as sendfile() and friends won't
-                                                   * tell us. Hence, treat this as reason to fall back, just to be
-                                                   * sure. */
-                                if (r == 0) {
-                                        /* Everything fit in, yay! */
-                                        (void) fd_nonblock(pipefds[0], false);
-
-                                        return TAKE_FD(pipefds[0]);
-                                }
-
-                                /* Things didn't fit in. But we read data into the pipe, let's remember that, so that
-                                 * when writing the new file we incorporate this first. */
-                                copy_fd = TAKE_FD(pipefds[0]);
-                        }
-                }
-        }
-
-        /* If we have reason to believe this will fit fine in /tmp, then use that as first fallback. */
-        if ((!S_ISREG(st.st_mode) || st.st_size < DATA_FD_TMP_LIMIT) &&
-            (DATA_FD_MEMORY_LIMIT + remains_size) < DATA_FD_TMP_LIMIT) {
-                off_t f;
-
-                tmp_fd = open_tmpfile_unlinkable(NULL /* NULL as directory means /tmp */, O_RDWR|O_CLOEXEC);
-                if (tmp_fd < 0)
-                        return tmp_fd;
-
-                if (copy_fd >= 0) {
-                        /* If we tried a memfd/pipe first and it ended up being too large, then copy this into the
-                         * temporary file first. */
-
-                        r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, 0);
-                        if (r < 0)
-                                return r;
-
-                        assert(r == 0);
-                }
-
-                if (remains_size > 0) {
-                        /* If there were remaining bytes (i.e. read into memory, but not written out yet) from the
-                         * failed copy operation, let's flush them out next. */
-
-                        r = loop_write(tmp_fd, remains, remains_size, false);
-                        if (r < 0)
-                                return r;
-                }
-
-                r = copy_bytes(fd, tmp_fd, DATA_FD_TMP_LIMIT - DATA_FD_MEMORY_LIMIT - remains_size, COPY_REFLINK);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        goto finish;  /* Yay, it fit in */
-
-                /* It didn't fit in. Let's not forget to use what we already used */
-                f = lseek(tmp_fd, 0, SEEK_SET);
-                if (f != 0)
-                        return -errno;
-
-                CLOSE_AND_REPLACE(copy_fd, tmp_fd);
-
-                remains = mfree(remains);
-                remains_size = 0;
-        }
-
-        /* As last fallback use /var/tmp */
-        r = var_tmp_dir(&td);
-        if (r < 0)
-                return r;
-
-        tmp_fd = open_tmpfile_unlinkable(td, O_RDWR|O_CLOEXEC);
-        if (tmp_fd < 0)
-                return tmp_fd;
-
-        if (copy_fd >= 0) {
-                /* If we tried a memfd/pipe first, or a file in /tmp, and it ended up being too large, than copy this
-                 * into the temporary file first. */
-                r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
-                if (r < 0)
-                        return r;
-
-                assert(r == 0);
-        }
-
-        if (remains_size > 0) {
-                /* Then, copy in any read but not yet written bytes. */
-                r = loop_write(tmp_fd, remains, remains_size, false);
-                if (r < 0)
-                        return r;
-        }
-
-        /* Copy in the rest */
-        r = copy_bytes(fd, tmp_fd, UINT64_MAX, COPY_REFLINK);
-        if (r < 0)
-                return r;
-
-        assert(r == 0);
-
-finish:
-        /* Now convert the O_RDWR file descriptor into an O_RDONLY one (and as side effect seek to the beginning of the
-         * file again */
-
-        return fd_reopen(tmp_fd, O_RDONLY|O_CLOEXEC);
-}
-#endif /* NM_IGNORED */
-
-int fd_move_above_stdio(int fd) {
-        int flags, copy;
-        PROTECT_ERRNO;
-
-        /* Moves the specified file descriptor if possible out of the range [0…2], i.e. the range of
-         * stdin/stdout/stderr. If it can't be moved outside of this range the original file descriptor is
-         * returned. This call is supposed to be used for long-lasting file descriptors we allocate in our code that
-         * might get loaded into foreign code, and where we want ensure our fds are unlikely used accidentally as
-         * stdin/stdout/stderr of unrelated code.
-         *
-         * Note that this doesn't fix any real bugs, it just makes it less likely that our code will be affected by
-         * buggy code from others that mindlessly invokes 'fprintf(stderr, …' or similar in places where stderr has
-         * been closed before.
-         *
-         * This function is written in a "best-effort" and "least-impact" style. This means whenever we encounter an
-         * error we simply return the original file descriptor, and we do not touch errno. */
-
-        if (fd < 0 || fd > 2)
-                return fd;
-
-        flags = fcntl(fd, F_GETFD, 0);
-        if (flags < 0)
-                return fd;
-
-        if (flags & FD_CLOEXEC)
-                copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-        else
-                copy = fcntl(fd, F_DUPFD, 3);
-        if (copy < 0)
-                return fd;
-
-        assert(copy > 2);
-
-        (void) close(fd);
-        return copy;
-}
-
-#if 0 /* NM_IGNORED */
-int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd) {
-
-        int fd[3] = { /* Put together an array of fds we work on */
-                original_input_fd,
-                original_output_fd,
-                original_error_fd
-        };
-
-        int r, i,
-                null_fd = -1,                /* if we open /dev/null, we store the fd to it here */
-                copy_fd[3] = { -1, -1, -1 }; /* This contains all fds we duplicate here temporarily, and hence need to close at the end */
-        bool null_readable, null_writable;
-
-        /* Sets up stdin, stdout, stderr with the three file descriptors passed in. If any of the descriptors is
-         * specified as -1 it will be connected with /dev/null instead. If any of the file descriptors is passed as
-         * itself (e.g. stdin as STDIN_FILENO) it is left unmodified, but the O_CLOEXEC bit is turned off should it be
-         * on.
-         *
-         * Note that if any of the passed file descriptors are > 2 they will be closed — both on success and on
-         * failure! Thus, callers should assume that when this function returns the input fds are invalidated.
-         *
-         * Note that when this function fails stdin/stdout/stderr might remain half set up!
-         *
-         * O_CLOEXEC is turned off for all three file descriptors (which is how it should be for
-         * stdin/stdout/stderr). */
-
-        null_readable = original_input_fd < 0;
-        null_writable = original_output_fd < 0 || original_error_fd < 0;
-
-        /* First step, open /dev/null once, if we need it */
-        if (null_readable || null_writable) {
-
-                /* Let's open this with O_CLOEXEC first, and convert it to non-O_CLOEXEC when we move the fd to the final position. */
-                null_fd = open("/dev/null", (null_readable && null_writable ? O_RDWR :
-                                             null_readable ? O_RDONLY : O_WRONLY) | O_CLOEXEC);
-                if (null_fd < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                /* If this fd is in the 0…2 range, let's move it out of it */
-                if (null_fd < 3) {
-                        int copy;
-
-                        copy = fcntl(null_fd, F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */
-                        if (copy < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
-
-                        CLOSE_AND_REPLACE(null_fd, copy);
-                }
-        }
-
-        /* Let's assemble fd[] with the fds to install in place of stdin/stdout/stderr */
-        for (i = 0; i < 3; i++) {
-
-                if (fd[i] < 0)
-                        fd[i] = null_fd;        /* A negative parameter means: connect this one to /dev/null */
-                else if (fd[i] != i && fd[i] < 3) {
-                        /* This fd is in the 0…2 territory, but not at its intended place, move it out of there, so that we can work there. */
-                        copy_fd[i] = fcntl(fd[i], F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */
-                        if (copy_fd[i] < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
-
-                        fd[i] = copy_fd[i];
-                }
-        }
-
-        /* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that we
-         * have freedom to move them around. If the fds already were at the right places then the specific fds are
-         * -1. Let's now move them to the right places. This is the point of no return. */
-        for (i = 0; i < 3; i++) {
-
-                if (fd[i] == i) {
-
-                        /* fd is already in place, but let's make sure O_CLOEXEC is off */
-                        r = fd_cloexec(i, false);
-                        if (r < 0)
-                                goto finish;
-
-                } else {
-                        assert(fd[i] > 2);
-
-                        if (dup2(fd[i], i) < 0) { /* Turns off O_CLOEXEC on the new fd. */
-                                r = -errno;
-                                goto finish;
-                        }
-                }
-        }
-
-        r = 0;
-
-finish:
-        /* Close the original fds, but only if they were outside of the stdio range. Also, properly check for the same
-         * fd passed in multiple times. */
-        safe_close_above_stdio(original_input_fd);
-        if (original_output_fd != original_input_fd)
-                safe_close_above_stdio(original_output_fd);
-        if (original_error_fd != original_input_fd && original_error_fd != original_output_fd)
-                safe_close_above_stdio(original_error_fd);
-
-        /* Close the copies we moved > 2 */
-        for (i = 0; i < 3; i++)
-                safe_close(copy_fd[i]);
-
-        /* Close our null fd, if it's > 2 */
-        safe_close_above_stdio(null_fd);
-
-        return r;
-}
-
-int fd_reopen(int fd, int flags) {
-        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
-        int new_fd;
-
-        /* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
-         * turn O_RDWR fds into O_RDONLY fds.
-         *
-         * This doesn't work on sockets (since they cannot be open()ed, ever).
-         *
-         * This implicitly resets the file read index to 0. */
-
-        xsprintf(procfs_path, "/proc/self/fd/%i", fd);
-        new_fd = open(procfs_path, flags);
-        if (new_fd < 0) {
-                if (errno != ENOENT)
-                        return -errno;
-
-                if (proc_mounted() == 0)
-                        return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
-
-                return -ENOENT;
-        }
-
-        return new_fd;
-}
-
-int read_nr_open(void) {
-        _cleanup_free_ char *nr_open = NULL;
-        int r;
-
-        /* Returns the kernel's current fd limit, either by reading it of /proc/sys if that works, or using the
-         * hard-coded default compiled-in value of current kernels (1M) if not. This call will never fail. */
-
-        r = read_one_line_file("/proc/sys/fs/nr_open", &nr_open);
-        if (r < 0)
-                log_debug_errno(r, "Failed to read /proc/sys/fs/nr_open, ignoring: %m");
-        else {
-                int v;
-
-                r = safe_atoi(nr_open, &v);
-                if (r < 0)
-                        log_debug_errno(r, "Failed to parse /proc/sys/fs/nr_open value '%s', ignoring: %m", nr_open);
-                else
-                        return v;
-        }
-
-        /* If we fail, fall back to the hard-coded kernel limit of 1024 * 1024. */
-        return 1024 * 1024;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/fd-util.h b/shared/systemd/src/basic/fd-util.h
deleted file mode 100644
index 2162537b..00000000
--- a/shared/systemd/src/basic/fd-util.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <dirent.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <sys/socket.h>
-
-#include "macro.h"
-
-/* Make sure we can distinguish fd 0 and NULL */
-#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
-#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
-
-int close_nointr(int fd);
-int safe_close(int fd);
-void safe_close_pair(int p[static 2]);
-
-static inline int safe_close_above_stdio(int fd) {
-        if (fd < 3) /* Don't close stdin/stdout/stderr, but still invalidate the fd by returning -1 */
-                return -1;
-
-        return safe_close(fd);
-}
-
-void close_many(const int fds[], size_t n_fd);
-
-int fclose_nointr(FILE *f);
-FILE* safe_fclose(FILE *f);
-DIR* safe_closedir(DIR *f);
-
-static inline void closep(int *fd) {
-        safe_close(*fd);
-}
-
-static inline void close_pairp(int (*p)[2]) {
-        safe_close_pair(*p);
-}
-
-static inline void fclosep(FILE **f) {
-        safe_fclose(*f);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);
-DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
-
-#define _cleanup_close_ _cleanup_(closep)
-#define _cleanup_fclose_ _cleanup_(fclosep)
-#define _cleanup_pclose_ _cleanup_(pclosep)
-#define _cleanup_closedir_ _cleanup_(closedirp)
-#define _cleanup_close_pair_ _cleanup_(close_pairp)
-
-int fd_nonblock(int fd, bool nonblock);
-int fd_cloexec(int fd, bool cloexec);
-
-int close_all_fds(const int except[], size_t n_except);
-
-int same_fd(int a, int b);
-
-void cmsg_close_all(struct msghdr *mh);
-
-bool fdname_is_valid(const char *s);
-
-int fd_get_path(int fd, char **ret);
-
-int move_fd(int from, int to, int cloexec);
-
-enum {
-        ACQUIRE_NO_DEV_NULL = 1 << 0,
-        ACQUIRE_NO_MEMFD    = 1 << 1,
-        ACQUIRE_NO_PIPE     = 1 << 2,
-        ACQUIRE_NO_TMPFILE  = 1 << 3,
-        ACQUIRE_NO_REGULAR  = 1 << 4,
-};
-
-int acquire_data_fd(const void *data, size_t size, unsigned flags);
-
-int fd_duplicate_data_fd(int fd);
-
-int fd_move_above_stdio(int fd);
-
-int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd);
-
-static inline int make_null_stdio(void) {
-        return rearrange_stdio(-1, -1, -1);
-}
-
-/* Like TAKE_PTR() but for file descriptors, resetting them to -1 */
-#define TAKE_FD(fd)                             \
-        ({                                      \
-                int _fd_ = (fd);                \
-                (fd) = -1;                      \
-                _fd_;                           \
-        })
-
-/* Like free_and_replace(), but for file descriptors */
-#define CLOSE_AND_REPLACE(a, b)                 \
-        ({                                      \
-                int *_fdp_ = &(a);              \
-                safe_close(*_fdp_);             \
-                *_fdp_ = TAKE_FD(b);            \
-                0;                              \
-        })
-
-
-int fd_reopen(int fd, int flags);
-
-int read_nr_open(void);
diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c
deleted file mode 100644
index ea90614a..00000000
--- a/shared/systemd/src/basic/fileio.c
+++ /dev/null
@@ -1,1360 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio_ext.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "hexdecoct.h"
-#include "log.h"
-#include "macro.h"
-#include "mkdir.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "socket-util.h"
-#include "stdio-util.h"
-#include "string-util.h"
-#include "tmpfile-util.h"
-
-#define READ_FULL_BYTES_MAX (4U*1024U*1024U)
-
-int fopen_unlocked(const char *path, const char *options, FILE **ret) {
-        assert(ret);
-
-        FILE *f = fopen(path, options);
-        if (!f)
-                return -errno;
-
-        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
-
-        *ret = f;
-        return 0;
-}
-
-int fdopen_unlocked(int fd, const char *options, FILE **ret) {
-        assert(ret);
-
-        FILE *f = fdopen(fd, options);
-        if (!f)
-                return -errno;
-
-        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
-
-        *ret = f;
-        return 0;
-}
-
-int take_fdopen_unlocked(int *fd, const char *options, FILE **ret) {
-        int     r;
-
-        assert(fd);
-
-        r = fdopen_unlocked(*fd, options, ret);
-        if (r < 0)
-                return r;
-
-        *fd = -1;
-
-        return 0;
-}
-
-FILE* take_fdopen(int *fd, const char *options) {
-        assert(fd);
-
-        FILE *f = fdopen(*fd, options);
-        if (!f)
-                return NULL;
-
-        *fd = -1;
-
-        return f;
-}
-
-DIR* take_fdopendir(int *dfd) {
-        assert(dfd);
-
-        DIR *d = fdopendir(*dfd);
-        if (!d)
-                return NULL;
-
-        *dfd = -1;
-
-        return d;
-}
-
-FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc) {
-        FILE *f = open_memstream(ptr, sizeloc);
-        if (!f)
-                return NULL;
-
-        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
-
-        return f;
-}
-
-FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode) {
-        FILE *f = fmemopen(buf, size, mode);
-        if (!f)
-                return NULL;
-
-        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
-
-        return f;
-}
-
-#if 0 /* NM_IGNORED */
-int write_string_stream_ts(
-                FILE *f,
-                const char *line,
-                WriteStringFileFlags flags,
-                const struct timespec *ts) {
-
-        bool needs_nl;
-        int r, fd;
-
-        assert(f);
-        assert(line);
-
-        if (ferror(f))
-                return -EIO;
-
-        if (ts) {
-                /* If we shall set the timestamp we need the fd. But fmemopen() streams generally don't have
-                 * an fd. Let's fail early in that case. */
-                fd = fileno(f);
-                if (fd < 0)
-                        return -EBADF;
-        }
-
-        needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");
-
-        if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) {
-                /* If STDIO buffering was disabled, then let's append the newline character to the string itself, so
-                 * that the write goes out in one go, instead of two */
-
-                line = strjoina(line, "\n");
-                needs_nl = false;
-        }
-
-        if (fputs(line, f) == EOF)
-                return -errno;
-
-        if (needs_nl)
-                if (fputc('\n', f) == EOF)
-                        return -errno;
-
-        if (flags & WRITE_STRING_FILE_SYNC)
-                r = fflush_sync_and_check(f);
-        else
-                r = fflush_and_check(f);
-        if (r < 0)
-                return r;
-
-        if (ts) {
-                const struct timespec twice[2] = {*ts, *ts};
-
-                if (futimens(fd, twice) < 0)
-                        return -errno;
-        }
-
-        return 0;
-}
-
-static int write_string_file_atomic(
-                const char *fn,
-                const char *line,
-                WriteStringFileFlags flags,
-                const struct timespec *ts) {
-
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        assert(fn);
-        assert(line);
-
-        /* Note that we'd really like to use O_TMPFILE here, but can't really, since we want replacement
-         * semantics here, and O_TMPFILE can't offer that. i.e. rename() replaces but linkat() doesn't. */
-
-        r = fopen_temporary(fn, &f, &p);
-        if (r < 0)
-                return r;
-
-        r = write_string_stream_ts(f, line, flags, ts);
-        if (r < 0)
-                goto fail;
-
-        r = fchmod_umask(fileno(f), FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0644);
-        if (r < 0)
-                goto fail;
-
-        if (rename(p, fn) < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        if (FLAGS_SET(flags, WRITE_STRING_FILE_SYNC)) {
-                /* Sync the rename, too */
-                r = fsync_directory_of_file(fileno(f));
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-
-fail:
-        (void) unlink(p);
-        return r;
-}
-
-int write_string_file_ts(
-                const char *fn,
-                const char *line,
-                WriteStringFileFlags flags,
-                const struct timespec *ts) {
-
-        _cleanup_fclose_ FILE *f = NULL;
-        int q, r, fd;
-
-        assert(fn);
-        assert(line);
-
-        /* We don't know how to verify whether the file contents was already on-disk. */
-        assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
-
-        if (flags & WRITE_STRING_FILE_MKDIR_0755) {
-                r = mkdir_parents(fn, 0755);
-                if (r < 0)
-                        return r;
-        }
-
-        if (flags & WRITE_STRING_FILE_ATOMIC) {
-                assert(flags & WRITE_STRING_FILE_CREATE);
-
-                r = write_string_file_atomic(fn, line, flags, ts);
-                if (r < 0)
-                        goto fail;
-
-                return r;
-        } else
-                assert(!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_TRUNCATE) ? O_TRUNC : 0),
-                  (FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
-        if (fd < 0) {
-                r = -errno;
-                goto fail;
-        }
-
-        r = fdopen_unlocked(fd, "w", &f);
-        if (r < 0) {
-                safe_close(fd);
-                goto fail;
-        }
-
-        if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
-                setvbuf(f, NULL, _IONBF, 0);
-
-        r = write_string_stream_ts(f, line, flags, ts);
-        if (r < 0)
-                goto fail;
-
-        return 0;
-
-fail:
-        if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
-                return r;
-
-        f = safe_fclose(f);
-
-        /* OK, the operation failed, but let's see if the right
-         * contents in place already. If so, eat up the error. */
-
-        q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
-        if (q <= 0)
-                return r;
-
-        return 0;
-}
-
-int write_string_filef(
-                const char *fn,
-                WriteStringFileFlags flags,
-                const char *format, ...) {
-
-        _cleanup_free_ char *p = NULL;
-        va_list ap;
-        int r;
-
-        va_start(ap, format);
-        r = vasprintf(&p, format, ap);
-        va_end(ap);
-
-        if (r < 0)
-                return -ENOMEM;
-
-        return write_string_file(fn, p, flags);
-}
-
-int read_one_line_file(const char *fn, char **line) {
-        _cleanup_fclose_ FILE *f = NULL;
-        int r;
-
-        assert(fn);
-        assert(line);
-
-        r = fopen_unlocked(fn, "re", &f);
-        if (r < 0)
-                return r;
-
-        return read_line(f, LONG_LINE_MAX, line);
-}
-
-int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *buf = NULL;
-        size_t l, k;
-        int r;
-
-        assert(fn);
-        assert(blob);
-
-        l = strlen(blob);
-
-        if (accept_extra_nl && endswith(blob, "\n"))
-                accept_extra_nl = false;
-
-        buf = malloc(l + accept_extra_nl + 1);
-        if (!buf)
-                return -ENOMEM;
-
-        r = fopen_unlocked(fn, "re", &f);
-        if (r < 0)
-                return r;
-
-        /* We try to read one byte more than we need, so that we know whether we hit eof */
-        errno = 0;
-        k = fread(buf, 1, l + accept_extra_nl + 1, f);
-        if (ferror(f))
-                return errno_or_else(EIO);
-
-        if (k != l && k != l + accept_extra_nl)
-                return 0;
-        if (memcmp(buf, blob, l) != 0)
-                return 0;
-        if (k > l && buf[l] != '\n')
-                return 0;
-
-        return 1;
-}
-#endif /* NM_IGNORED */
-
-int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size) {
-        _cleanup_free_ char *buf = NULL;
-        _cleanup_close_ int fd = -1;
-        struct stat st;
-        size_t n, size;
-        int n_retries;
-        char *p;
-
-        assert(ret_contents);
-
-        /* Virtual filesystems such as sysfs or procfs use kernfs, and kernfs can work
-         * with two sorts of virtual files. One sort uses "seq_file", and the results of
-         * the first read are buffered for the second read. The other sort uses "raw"
-         * reads which always go direct to the device. In the latter case, the content of
-         * the virtual file must be retrieved with a single read otherwise a second read
-         * might get the new value instead of finding EOF immediately. That's the reason
-         * why the usage of fread(3) is prohibited in this case as it always performs a
-         * second call to read(2) looking for EOF. See issue 13585. */
-
-        fd = open(filename, O_RDONLY|O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        /* Start size for files in /proc which usually report a file size of 0. */
-        size = LINE_MAX / 2;
-
-        /* Limit the number of attempts to read the number of bytes returned by fstat(). */
-        n_retries = 3;
-
-        for (;;) {
-                if (n_retries <= 0)
-                        return -EIO;
-
-                if (fstat(fd, &st) < 0)
-                        return -errno;
-
-                if (!S_ISREG(st.st_mode))
-                        return -EBADF;
-
-                /* Be prepared for files from /proc which generally report a file size of 0. */
-                if (st.st_size > 0) {
-                        size = st.st_size;
-                        n_retries--;
-                } else
-                        size = size * 2;
-
-                if (size > READ_FULL_BYTES_MAX)
-                        return -E2BIG;
-
-                p = realloc(buf, size + 1);
-                if (!p)
-                        return -ENOMEM;
-                buf = TAKE_PTR(p);
-
-                for (;;) {
-                        ssize_t k;
-
-                        /* Read one more byte so we can detect whether the content of the
-                         * file has already changed or the guessed size for files from /proc
-                         * wasn't large enough . */
-                        k = read(fd, buf, size + 1);
-                        if (k >= 0) {
-                                n = k;
-                                break;
-                        }
-
-                        if (errno != EINTR)
-                                return -errno;
-                }
-
-                /* Consider a short read as EOF */
-                if (n <= size)
-                        break;
-
-                /* Hmm... either we read too few bytes from /proc or less likely the content
-                 * of the file might have been changed (and is now bigger) while we were
-                 * processing, let's try again either with a bigger guessed size or the new
-                 * file size. */
-
-                if (lseek(fd, 0, SEEK_SET) < 0)
-                        return -errno;
-        }
-
-        if (n < size) {
-                p = realloc(buf, n + 1);
-                if (!p)
-                        return -ENOMEM;
-                buf = TAKE_PTR(p);
-        }
-
-        if (!ret_size) {
-                /* Safety check: if the caller doesn't want to know the size of what we
-                 * just read it will rely on the trailing NUL byte. But if there's an
-                 * embedded NUL byte, then we should refuse operation as otherwise
-                 * there'd be ambiguity about what we just read. */
-
-                if (memchr(buf, 0, n))
-                        return -EBADMSG;
-        } else
-                *ret_size = n;
-
-        buf[n] = 0;
-        *ret_contents = TAKE_PTR(buf);
-
-        return 0;
-}
-
-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;
-        size_t n, n_next, l;
-        int fd, r;
-
-        assert(f);
-        assert(ret_contents);
-        assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
-
-        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 */
-                struct stat st;
-
-                if (fstat(fd, &st) < 0)
-                        return -errno;
-
-                if (S_ISREG(st.st_mode)) {
-                        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;
-                size_t k;
-
-                if (flags & READ_FULL_FILE_SECURE) {
-                        t = malloc(n_next + 1);
-                        if (!t) {
-                                r = -ENOMEM;
-                                goto finalize;
-                        }
-                        memcpy_safe(t, buf, n);
-                        explicit_bzero_safe(buf, n);
-                        buf = mfree(buf);
-                } else {
-                        t = realloc(buf, n_next + 1);
-                        if (!t)
-                                return -ENOMEM;
-                }
-
-                buf = t;
-                n = n_next;
-
-                errno = 0;
-                k = fread(buf + l, 1, n - l, f);
-
-                assert(k <= n - l);
-                l += k;
-
-                if (ferror(f)) {
-                        r = errno_or_else(EIO);
-                        goto finalize;
-                }
-                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 */
-                if (n >= READ_FULL_BYTES_MAX) {
-                        r = -E2BIG;
-                        goto finalize;
-                }
-
-                n_next = MIN(n * 2, READ_FULL_BYTES_MAX);
-        }
-
-        if (flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) {
-                _cleanup_free_ void *decoded = NULL;
-                size_t decoded_size;
-
-                buf[l++] = 0;
-                if (flags & READ_FULL_FILE_UNBASE64)
-                        r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size);
-                else
-                        r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size);
-                if (r < 0)
-                        goto finalize;
-
-                if (flags & READ_FULL_FILE_SECURE)
-                        explicit_bzero_safe(buf, n);
-                free_and_replace(buf, decoded);
-                n = l = decoded_size;
-        }
-
-        if (!ret_size) {
-                /* Safety check: if the caller doesn't want to know the size of what we just read it will rely on the
-                 * trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise
-                 * there'd be ambiguity about what we just read. */
-
-                if (memchr(buf, 0, l)) {
-                        r = -EBADMSG;
-                        goto finalize;
-                }
-        }
-
-        buf[l] = 0;
-        *ret_contents = TAKE_PTR(buf);
-
-        if (ret_size)
-                *ret_size = l;
-
-        return 0;
-
-finalize:
-        if (flags & READ_FULL_FILE_SECURE)
-                explicit_bzero_safe(buf, n);
-
-        return r;
-}
-
-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(ret_contents);
-
-        r = xfopenat(dir_fd, filename, "re", 0, &f);
-        if (r < 0) {
-                _cleanup_close_ int dfd = -1, sk = -1;
-                union sockaddr_union sa;
-
-                /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
-                if (r != -ENXIO)
-                        return r;
-
-                /* If this is enabled, let's try to connect to it */
-                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 {
-                        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
-
-                        /* If we shall operate relative to some directory, then let's use O_PATH first to
-                         * open the socket inode, and then connect to it via /proc/self/fd/. We have to do
-                         * this since there's not connectat() that takes a directory fd as first arg. */
-
-                        dfd = openat(dir_fd, filename, O_PATH|O_CLOEXEC);
-                        if (dfd < 0)
-                                return -errno;
-
-                        xsprintf(procfs_path, "/proc/self/fd/%i", dfd);
-                        r = sockaddr_un_set_path(&sa.un, procfs_path);
-                }
-                if (r < 0)
-                        return r;
-
-                sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
-                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 */
-
-                if (shutdown(sk, SHUT_WR) < 0)
-                        return -errno;
-
-                f = fdopen(sk, "r");
-                if (!f)
-                        return -errno;
-
-                TAKE_FD(sk);
-        }
-
-        (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
-
-        return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
-}
-
-#if 0 /* NM_IGNORED */
-int executable_is_script(const char *path, char **interpreter) {
-        _cleanup_free_ char *line = NULL;
-        size_t len;
-        char *ans;
-        int r;
-
-        assert(path);
-
-        r = read_one_line_file(path, &line);
-        if (r == -ENOBUFS) /* First line overly long? if so, then it's not a script */
-                return 0;
-        if (r < 0)
-                return r;
-
-        if (!startswith(line, "#!"))
-                return 0;
-
-        ans = strstrip(line + 2);
-        len = strcspn(ans, " \t");
-
-        if (len == 0)
-                return 0;
-
-        ans = strndup(ans, len);
-        if (!ans)
-                return -ENOMEM;
-
-        *interpreter = ans;
-        return 1;
-}
-#endif /* NM_IGNORED */
-
-/**
- * Retrieve one field from a file like /proc/self/status.  pattern
- * should not include whitespace or the delimiter (':'). pattern matches only
- * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
- * zeros after the ':' will be skipped. field must be freed afterwards.
- * terminator specifies the terminating characters of the field value (not
- * included in the value).
- */
-int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
-        _cleanup_free_ char *status = NULL;
-        char *t, *f;
-        size_t len;
-        int r;
-
-        assert(terminator);
-        assert(filename);
-        assert(pattern);
-        assert(field);
-
-        r = read_full_virtual_file(filename, &status, NULL);
-        if (r < 0)
-                return r;
-
-        t = status;
-
-        do {
-                bool pattern_ok;
-
-                do {
-                        t = strstr(t, pattern);
-                        if (!t)
-                                return -ENOENT;
-
-                        /* Check that pattern occurs in beginning of line. */
-                        pattern_ok = (t == status || t[-1] == '\n');
-
-                        t += strlen(pattern);
-
-                } while (!pattern_ok);
-
-                t += strspn(t, " \t");
-                if (!*t)
-                        return -ENOENT;
-
-        } while (*t != ':');
-
-        t++;
-
-        if (*t) {
-                t += strspn(t, " \t");
-
-                /* Also skip zeros, because when this is used for
-                 * capabilities, we don't want the zeros. This way the
-                 * same capability set always maps to the same string,
-                 * irrespective of the total capability set size. For
-                 * other numbers it shouldn't matter. */
-                t += strspn(t, "0");
-                /* Back off one char if there's nothing but whitespace
-                   and zeros */
-                if (!*t || isspace(*t))
-                        t--;
-        }
-
-        len = strcspn(t, terminator);
-
-        f = strndup(t, len);
-        if (!f)
-                return -ENOMEM;
-
-        *field = f;
-        return 0;
-}
-
-DIR *xopendirat(int fd, const char *name, int flags) {
-        int nfd;
-        DIR *d;
-
-        assert(!(flags & O_CREAT));
-
-        nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
-        if (nfd < 0)
-                return NULL;
-
-        d = fdopendir(nfd);
-        if (!d) {
-                safe_close(nfd);
-                return NULL;
-        }
-
-        return d;
-}
-
-static int mode_to_flags(const char *mode) {
-        const char *p;
-        int flags;
-
-        if ((p = startswith(mode, "r+")))
-                flags = O_RDWR;
-        else if ((p = startswith(mode, "r")))
-                flags = O_RDONLY;
-        else if ((p = startswith(mode, "w+")))
-                flags = O_RDWR|O_CREAT|O_TRUNC;
-        else if ((p = startswith(mode, "w")))
-                flags = O_WRONLY|O_CREAT|O_TRUNC;
-        else if ((p = startswith(mode, "a+")))
-                flags = O_RDWR|O_CREAT|O_APPEND;
-        else if ((p = startswith(mode, "a")))
-                flags = O_WRONLY|O_CREAT|O_APPEND;
-        else
-                return -EINVAL;
-
-        for (; *p != 0; p++) {
-
-                switch (*p) {
-
-                case 'e':
-                        flags |= O_CLOEXEC;
-                        break;
-
-                case 'x':
-                        flags |= O_EXCL;
-                        break;
-
-                case 'm':
-                        /* ignore this here, fdopen() might care later though */
-                        break;
-
-                case 'c': /* not sure what to do about this one */
-                default:
-                        return -EINVAL;
-                }
-        }
-
-        return flags;
-}
-
-int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret) {
-        FILE *f;
-
-        /* A combination of fopen() with openat() */
-
-        if (dir_fd == AT_FDCWD && flags == 0) {
-                f = fopen(path, mode);
-                if (!f)
-                        return -errno;
-        } else {
-                int fd, mode_flags;
-
-                mode_flags = mode_to_flags(mode);
-                if (mode_flags < 0)
-                        return mode_flags;
-
-                fd = openat(dir_fd, path, mode_flags | flags);
-                if (fd < 0)
-                        return -errno;
-
-                f = fdopen(fd, mode);
-                if (!f) {
-                        safe_close(fd);
-                        return -errno;
-                }
-        }
-
-        *ret = f;
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
-        char **i;
-
-        assert(path);
-        assert(mode);
-        assert(_f);
-
-        if (!path_strv_resolve_uniq(search, root))
-                return -ENOMEM;
-
-        STRV_FOREACH(i, search) {
-                _cleanup_free_ char *p = NULL;
-                FILE *f;
-
-                p = path_join(root, *i, path);
-                if (!p)
-                        return -ENOMEM;
-
-                f = fopen(p, mode);
-                if (f) {
-                        *_f = f;
-                        return 0;
-                }
-
-                if (errno != ENOENT)
-                        return -errno;
-        }
-
-        return -ENOENT;
-}
-
-int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
-        _cleanup_strv_free_ char **copy = NULL;
-
-        assert(path);
-        assert(mode);
-        assert(_f);
-
-        if (path_is_absolute(path)) {
-                FILE *f;
-
-                f = fopen(path, mode);
-                if (f) {
-                        *_f = f;
-                        return 0;
-                }
-
-                return -errno;
-        }
-
-        copy = strv_copy((char**) search);
-        if (!copy)
-                return -ENOMEM;
-
-        return search_and_fopen_internal(path, mode, root, copy, _f);
-}
-
-int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
-        _cleanup_strv_free_ char **s = NULL;
-
-        if (path_is_absolute(path)) {
-                FILE *f;
-
-                f = fopen(path, mode);
-                if (f) {
-                        *_f = f;
-                        return 0;
-                }
-
-                return -errno;
-        }
-
-        s = strv_split_nulstr(search);
-        if (!s)
-                return -ENOMEM;
-
-        return search_and_fopen_internal(path, mode, root, s, _f);
-}
-
-int chase_symlinks_and_fopen_unlocked(
-                const char *path,
-                const char *root,
-                unsigned chase_flags,
-                const char *open_flags,
-                FILE **ret_file,
-                char **ret_path) {
-
-        _cleanup_close_ int fd = -1;
-        _cleanup_free_ char *final_path = NULL;
-        int mode_flags, r;
-        FILE *f;
-
-        assert(path);
-        assert(open_flags);
-        assert(ret_file);
-
-        mode_flags = mode_to_flags(open_flags);
-        if (mode_flags < 0)
-                return mode_flags;
-
-        fd = chase_symlinks_and_open(path, root, chase_flags, mode_flags, ret_path ? &final_path : NULL);
-        if (fd < 0)
-                return fd;
-
-        r = fdopen_unlocked(fd, open_flags, &f);
-        if (r < 0)
-                return r;
-        TAKE_FD(fd);
-
-        *ret_file = f;
-        if (ret_path)
-                *ret_path = TAKE_PTR(final_path);
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-int fflush_and_check(FILE *f) {
-        assert(f);
-
-        errno = 0;
-        fflush(f);
-
-        if (ferror(f))
-                return errno_or_else(EIO);
-
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int fflush_sync_and_check(FILE *f) {
-        int r, fd;
-
-        assert(f);
-
-        r = fflush_and_check(f);
-        if (r < 0)
-                return r;
-
-        /* Not all file streams have an fd associated (think: fmemopen()), let's handle this gracefully and
-         * assume that in that case we need no explicit syncing */
-        fd = fileno(f);
-        if (fd < 0)
-                return 0;
-
-        if (fsync(fd) < 0)
-                return -errno;
-
-        r = fsync_directory_of_file(fd);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int write_timestamp_file_atomic(const char *fn, usec_t n) {
-        char ln[DECIMAL_STR_MAX(n)+2];
-
-        /* Creates a "timestamp" file, that contains nothing but a
-         * usec_t timestamp, formatted in ASCII. */
-
-        if (n <= 0 || n >= USEC_INFINITY)
-                return -ERANGE;
-
-        xsprintf(ln, USEC_FMT "\n", n);
-
-        return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
-}
-
-int read_timestamp_file(const char *fn, usec_t *ret) {
-        _cleanup_free_ char *ln = NULL;
-        uint64_t t;
-        int r;
-
-        r = read_one_line_file(fn, &ln);
-        if (r < 0)
-                return r;
-
-        r = safe_atou64(ln, &t);
-        if (r < 0)
-                return r;
-
-        if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
-                return -ERANGE;
-
-        *ret = (usec_t) t;
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
-        int r;
-
-        assert(s);
-
-        /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
-         * when specified shall initially point to a boolean variable initialized to false. It is set to true after the
-         * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
-         * element, but not before the first one. */
-
-        if (!f)
-                f = stdout;
-
-        if (space) {
-                if (!separator)
-                        separator = " ";
-
-                if (*space) {
-                        r = fputs(separator, f);
-                        if (r < 0)
-                                return r;
-                }
-
-                *space = true;
-        }
-
-        return fputs(s, f);
-}
-
-#if 0 /* NM_IGNORED */
-/* A bitmask of the EOL markers we know */
-typedef enum EndOfLineMarker {
-        EOL_NONE     = 0,
-        EOL_ZERO     = 1 << 0,  /* \0 (aka NUL) */
-        EOL_TEN      = 1 << 1,  /* \n (aka NL, aka LF)  */
-        EOL_THIRTEEN = 1 << 2,  /* \r (aka CR)  */
-} EndOfLineMarker;
-
-static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
-
-        if (!IN_SET(flags, READ_LINE_ONLY_NUL)) {
-                if (c == '\n')
-                        return EOL_TEN;
-                if (c == '\r')
-                        return EOL_THIRTEEN;
-        }
-
-        if (c == '\0')
-                return EOL_ZERO;
-
-        return EOL_NONE;
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
-
-int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
-        size_t n = 0, allocated = 0, count = 0;
-        _cleanup_free_ char *buffer = NULL;
-        int r;
-
-        assert(f);
-
-        /* Something like a bounded version of getline().
-         *
-         * Considers EOF, \n, \r and \0 end of line delimiters (or combinations of these), and does not include these
-         * delimiters in the string returned. Specifically, recognizes the following combinations of markers as line
-         * endings:
-         *
-         *     • \n        (UNIX)
-         *     • \r        (old MacOS)
-         *     • \0        (C strings)
-         *     • \n\0
-         *     • \r\0
-         *     • \r\n      (Windows)
-         *     • \n\r
-         *     • \r\n\0
-         *     • \n\r\0
-         *
-         * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
-         * the number of characters in the returned string). When EOF is hit, 0 is returned.
-         *
-         * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
-         * delimiters. If the limit is hit we fail and return -ENOBUFS.
-         *
-         * If a line shall be skipped ret may be initialized as NULL. */
-
-        if (ret) {
-                if (!GREEDY_REALLOC(buffer, allocated, 1))
-                        return -ENOMEM;
-        }
-
-        {
-                _unused_ _cleanup_(funlockfilep) FILE *flocked = f;
-                EndOfLineMarker previous_eol = EOL_NONE;
-                flockfile(f);
-
-                for (;;) {
-                        EndOfLineMarker eol;
-                        char c;
-
-                        if (n >= limit)
-                                return -ENOBUFS;
-
-                        if (count >= INT_MAX) /* We couldn't return the counter anymore as "int", hence refuse this */
-                                return -ENOBUFS;
-
-                        r = safe_fgetc(f, &c);
-                        if (r < 0)
-                                return r;
-                        if (r == 0) /* EOF is definitely EOL */
-                                break;
-
-                        eol = categorize_eol(c, flags);
-
-                        if (FLAGS_SET(previous_eol, EOL_ZERO) ||
-                            (eol == EOL_NONE && previous_eol != EOL_NONE) ||
-                            (eol != EOL_NONE && (previous_eol & eol) != 0)) {
-                                /* Previous char was a NUL? This is not an EOL, but the previous char was? This type of
-                                 * EOL marker has been seen right before?  In either of these three cases we are
-                                 * done. But first, let's put this character back in the queue. (Note that we have to
-                                 * cast this to (unsigned char) here as ungetc() expects a positive 'int', and if we
-                                 * are on an architecture where 'char' equals 'signed char' we need to ensure we don't
-                                 * pass a negative value here. That said, to complicate things further ungetc() is
-                                 * actually happy with most negative characters and implicitly casts them back to
-                                 * positive ones as needed, except for \xff (aka -1, aka EOF), which it refuses. What a
-                                 * godawful API!) */
-                                assert_se(ungetc((unsigned char) c, f) != EOF);
-                                break;
-                        }
-
-                        count++;
-
-                        if (eol != EOL_NONE) {
-                                /* If we are on a tty, we can't shouldn't wait for more input, because that
-                                 * generally means waiting for the user, interactively. In the case of a TTY
-                                 * we expect only \n as the single EOL marker, so we are in the lucky
-                                 * position that there is no need to wait. We check this condition last, to
-                                 * avoid isatty() check if not necessary. */
-
-                                if ((flags & (READ_LINE_IS_A_TTY|READ_LINE_NOT_A_TTY)) == 0) {
-                                        int fd;
-
-                                        fd = fileno(f);
-                                        if (fd < 0) /* Maybe an fmemopen() stream? Handle this gracefully,
-                                                     * and don't call isatty() on an invalid fd */
-                                                flags |= READ_LINE_NOT_A_TTY;
-                                        else
-                                                flags |= isatty(fd) ? READ_LINE_IS_A_TTY : READ_LINE_NOT_A_TTY;
-                                }
-                                if (FLAGS_SET(flags, READ_LINE_IS_A_TTY))
-                                        break;
-                        }
-
-                        if (eol != EOL_NONE) {
-                                previous_eol |= eol;
-                                continue;
-                        }
-
-                        if (ret) {
-                                if (!GREEDY_REALLOC(buffer, allocated, n + 2))
-                                        return -ENOMEM;
-
-                                buffer[n] = c;
-                        }
-
-                        n++;
-                }
-        }
-
-        if (ret) {
-                buffer[n] = 0;
-
-                *ret = TAKE_PTR(buffer);
-        }
-
-        return (int) count;
-}
-
-int safe_fgetc(FILE *f, char *ret) {
-        int k;
-
-        assert(f);
-
-        /* A safer version of plain fgetc(): let's propagate the error that happened while reading as such, and
-         * separate the EOF condition from the byte read, to avoid those confusion signed/unsigned issues fgetc()
-         * has. */
-
-        errno = 0;
-        k = fgetc(f);
-        if (k == EOF) {
-                if (ferror(f))
-                        return errno_or_else(EIO);
-
-                if (ret)
-                        *ret = 0;
-
-                return 0;
-        }
-
-        if (ret)
-                *ret = k;
-
-        return 1;
-}
-#endif /* NM_IGNORED */
-
-int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line) {
-        struct stat _st;
-
-        if (!filename)
-                return 0;
-
-        if (!st) {
-                if (stat(filename, &_st) < 0)
-                        return -errno;
-                st = &_st;
-        }
-
-        if ((st->st_mode & S_IRWXO) == 0)
-                return 0;
-
-        if (unit)
-                log_syntax(unit, LOG_WARNING, filename, line, 0,
-                           "%s has %04o mode that is too permissive, please adjust the ownership and access mode.",
-                           filename, st->st_mode & 07777);
-        else
-                log_warning("%s has %04o mode that is too permissive, please adjust the ownership and access mode.",
-                            filename, st->st_mode & 07777);
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int sync_rights(int from, int to) {
-        struct stat st;
-
-        if (fstat(from, &st) < 0)
-                return -errno;
-
-        return fchmod_and_chown(to, st.st_mode & 07777, st.st_uid, st.st_gid);
-}
-
-int rename_and_apply_smack_floor_label(const char *from, const char *to) {
-        int r = 0;
-        if (rename(from, to) < 0)
-                return -errno;
-
-#ifdef SMACK_RUN_LABEL
-        r = mac_smack_apply(to, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
-        if (r < 0)
-                return r;
-#endif
-        return r;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/fileio.h b/shared/systemd/src/basic/fileio.h
deleted file mode 100644
index 5a028561..00000000
--- a/shared/systemd/src/basic/fileio.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <dirent.h>
-#include <stdbool.h>
-#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"
-#include "time-util.h"
-
-#define LONG_LINE_MAX (1U*1024U*1024U)
-
-typedef enum {
-        WRITE_STRING_FILE_CREATE            = 1 << 0,
-        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()
-           and friends. */
-
-} WriteStringFileFlags;
-
-typedef enum {
-        READ_FULL_FILE_SECURE              = 1 << 0, /* erase any buffers we employ internally, after use */
-        READ_FULL_FILE_UNBASE64            = 1 << 1, /* base64 decode what we read */
-        READ_FULL_FILE_UNHEX               = 1 << 2, /* hex decode what we read */
-        READ_FULL_FILE_WARN_WORLD_READABLE = 1 << 3, /* if regular file, log at LOG_WARNING level if access mode above 0700 */
-        READ_FULL_FILE_CONNECT_SOCKET      = 1 << 4, /* if socket inode, connect to it and read off it */
-} ReadFullFileFlags;
-
-int fopen_unlocked(const char *path, const char *options, FILE **ret);
-int fdopen_unlocked(int fd, const char *options, FILE **ret);
-int take_fdopen_unlocked(int *fd, const char *options, FILE **ret);
-FILE* take_fdopen(int *fd, const char *options);
-DIR* take_fdopendir(int *dfd);
-FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc);
-FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode);
-
-int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
-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, 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);
-}
-
-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, 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, 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);
-
-int executable_is_script(const char *path, char **interpreter);
-
-int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
-
-DIR *xopendirat(int dirfd, const char *name, int flags);
-int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret);
-
-int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
-int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);
-
-int chase_symlinks_and_fopen_unlocked(
-                const char *path,
-                const char *root,
-                unsigned chase_flags,
-                const char *open_flags,
-                FILE **ret_file,
-                char **ret_path);
-
-int fflush_and_check(FILE *f);
-int fflush_sync_and_check(FILE *f);
-
-int write_timestamp_file_atomic(const char *fn, usec_t n);
-int read_timestamp_file(const char *fn, usec_t *ret);
-
-int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);
-
-typedef enum ReadLineFlags {
-        READ_LINE_ONLY_NUL  = 1 << 0,
-        READ_LINE_IS_A_TTY  = 1 << 1,
-        READ_LINE_NOT_A_TTY = 1 << 2,
-} ReadLineFlags;
-
-int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret);
-
-static inline int read_line(FILE *f, size_t limit, char **ret) {
-        return read_line_full(f, limit, 0, ret);
-}
-
-static inline int read_nul_string(FILE *f, size_t limit, char **ret) {
-        return read_line_full(f, limit, READ_LINE_ONLY_NUL, ret);
-}
-
-int safe_fgetc(FILE *f, char *ret);
-
-int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line);
-
-int sync_rights(int from, int to);
-
-int rename_and_apply_smack_floor_label(const char *temp_path, const char *dest_path);
diff --git a/shared/systemd/src/basic/format-util.c b/shared/systemd/src/basic/format-util.c
deleted file mode 100644
index 42224b6f..00000000
--- a/shared/systemd/src/basic/format-util.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include "format-util.h"
-#include "memory-util.h"
-#include "stdio-util.h"
-
-assert_cc(DECIMAL_STR_MAX(int) + 1 <= IF_NAMESIZE + 1);
-char *format_ifname_full(int ifindex, char buf[static IF_NAMESIZE + 1], FormatIfnameFlag flag) {
-        /* Buffer is always cleared */
-        memzero(buf, IF_NAMESIZE + 1);
-        if (if_indextoname(ifindex, buf))
-                return buf;
-
-        if (!FLAGS_SET(flag, FORMAT_IFNAME_IFINDEX))
-                return NULL;
-
-        if (FLAGS_SET(flag, FORMAT_IFNAME_IFINDEX_WITH_PERCENT))
-                snprintf(buf, IF_NAMESIZE + 1, "%%%d", ifindex);
-        else
-                snprintf(buf, IF_NAMESIZE + 1, "%d", ifindex);
-
-        return buf;
-}
-
-char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {
-        typedef struct {
-                const char *suffix;
-                uint64_t factor;
-        } suffix_table;
-        static const suffix_table table_iec[] = {
-                { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
-                { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
-                { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
-                { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
-                { "M", UINT64_C(1024)*UINT64_C(1024) },
-                { "K", UINT64_C(1024) },
-        }, table_si[] = {
-                { "E", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
-                { "P", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
-                { "T", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
-                { "G", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
-                { "M", UINT64_C(1000)*UINT64_C(1000) },
-                { "K", UINT64_C(1000) },
-        };
-        const suffix_table *table;
-        size_t n, i;
-
-        assert_cc(ELEMENTSOF(table_iec) == ELEMENTSOF(table_si));
-
-        if (t == (uint64_t) -1)
-                return NULL;
-
-        table = flag & FORMAT_BYTES_USE_IEC ? table_iec : table_si;
-        n = ELEMENTSOF(table_iec);
-
-        for (i = 0; i < n; i++)
-                if (t >= table[i].factor) {
-                        if (flag & FORMAT_BYTES_BELOW_POINT) {
-                                snprintf(buf, l,
-                                         "%" PRIu64 ".%" PRIu64 "%s",
-                                         t / table[i].factor,
-                                         i != n - 1 ?
-                                         (t / table[i + 1].factor * UINT64_C(10) / table[n - 1].factor) % UINT64_C(10):
-                                         (t * UINT64_C(10) / table[i].factor) % UINT64_C(10),
-                                         table[i].suffix);
-                        } else
-                                snprintf(buf, l,
-                                         "%" PRIu64 "%s",
-                                         t / table[i].factor,
-                                         table[i].suffix);
-
-                        goto finish;
-                }
-
-        snprintf(buf, l, "%" PRIu64 "%s", t, flag & FORMAT_BYTES_TRAILING_B ? "B" : "");
-
-finish:
-        buf[l-1] = 0;
-        return buf;
-
-}
diff --git a/shared/systemd/src/basic/format-util.h b/shared/systemd/src/basic/format-util.h
deleted file mode 100644
index b7e18768..00000000
--- a/shared/systemd/src/basic/format-util.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <inttypes.h>
-#include <net/if.h>
-#include <stdbool.h>
-
-#include "cgroup-util.h"
-#include "macro.h"
-
-assert_cc(sizeof(pid_t) == sizeof(int32_t));
-#define PID_PRI PRIi32
-#define PID_FMT "%" PID_PRI
-
-assert_cc(sizeof(uid_t) == sizeof(uint32_t));
-#define UID_FMT "%" PRIu32
-
-assert_cc(sizeof(gid_t) == sizeof(uint32_t));
-#define GID_FMT "%" PRIu32
-
-#if SIZEOF_TIME_T == 8
-#  define PRI_TIME PRIi64
-#elif SIZEOF_TIME_T == 4
-#  define PRI_TIME "li"
-#else
-#  error Unknown time_t size
-#endif
-
-#if defined __x86_64__ && defined __ILP32__
-#  define PRI_TIMEX PRIi64
-#else
-#  define PRI_TIMEX "li"
-#endif
-
-#if SIZEOF_RLIM_T == 8
-#  define RLIM_FMT "%" PRIu64
-#elif SIZEOF_RLIM_T == 4
-#  define RLIM_FMT "%" PRIu32
-#else
-#  error Unknown rlim_t size
-#endif
-
-#if SIZEOF_DEV_T == 8
-#  define DEV_FMT "%" PRIu64
-#elif SIZEOF_DEV_T == 4
-#  define DEV_FMT "%" PRIu32
-#else
-#  error Unknown dev_t size
-#endif
-
-#if SIZEOF_INO_T == 8
-#  define INO_FMT "%" PRIu64
-#elif SIZEOF_INO_T == 4
-#  define INO_FMT "%" PRIu32
-#else
-#  error Unknown ino_t size
-#endif
-
-typedef enum {
-        FORMAT_IFNAME_IFINDEX              = 1 << 0,
-        FORMAT_IFNAME_IFINDEX_WITH_PERCENT = (1 << 1) | FORMAT_IFNAME_IFINDEX,
-} FormatIfnameFlag;
-
-char *format_ifname_full(int ifindex, char buf[static IF_NAMESIZE + 1], FormatIfnameFlag flag);
-static inline char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]) {
-        return format_ifname_full(ifindex, buf, 0);
-}
-
-typedef enum {
-        FORMAT_BYTES_USE_IEC     = 1 << 0,
-        FORMAT_BYTES_BELOW_POINT = 1 << 1,
-        FORMAT_BYTES_TRAILING_B  = 1 << 2,
-} FormatBytesFlag;
-
-#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");
-                return buf;
-        }
-        return format_bytes(buf, l, t);
-}
diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c
deleted file mode 100644
index 2ed9ee0e..00000000
--- a/shared/systemd/src/basic/fs-util.c
+++ /dev/null
@@ -1,1706 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <linux/falloc.h>
-#include <linux/magic.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "blockdev-util.h"
-#include "dirent-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "locale-util.h"
-#include "log.h"
-#include "macro.h"
-#include "missing_fcntl.h"
-#include "missing_fs.h"
-#include "missing_syscall.h"
-#include "mkdir.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "random-util.h"
-#include "stat-util.h"
-#include "stdio-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "time-util.h"
-#include "tmpfile-util.h"
-#include "user-util.h"
-#include "util.h"
-
-int unlink_noerrno(const char *path) {
-        PROTECT_ERRNO;
-        int r;
-
-        r = unlink(path);
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int rmdir_parents(const char *path, const char *stop) {
-        size_t l;
-        int r = 0;
-
-        assert(path);
-        assert(stop);
-
-        l = strlen(path);
-
-        /* Skip trailing slashes */
-        while (l > 0 && path[l-1] == '/')
-                l--;
-
-        while (l > 0) {
-                char *t;
-
-                /* Skip last component */
-                while (l > 0 && path[l-1] != '/')
-                        l--;
-
-                /* Skip trailing slashes */
-                while (l > 0 && path[l-1] == '/')
-                        l--;
-
-                if (l <= 0)
-                        break;
-
-                t = strndup(path, l);
-                if (!t)
-                        return -ENOMEM;
-
-                if (path_startswith(stop, t)) {
-                        free(t);
-                        return 0;
-                }
-
-                r = rmdir(t);
-                free(t);
-
-                if (r < 0)
-                        if (errno != ENOENT)
-                                return -errno;
-        }
-
-        return 0;
-}
-
-int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
-        int r;
-
-        /* Try the ideal approach first */
-        if (renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE) >= 0)
-                return 0;
-
-        /* renameat2() exists since Linux 3.15, btrfs and FAT added support for it later. If it is not implemented,
-         * fall back to a different method. */
-        if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY))
-                return -errno;
-
-        /* Let's try to use linkat()+unlinkat() as fallback. This doesn't work on directories and on some file systems
-         * that do not support hard links (such as FAT, most prominently), but for files it's pretty close to what we
-         * want — though not atomic (i.e. for a short period both the new and the old filename will exist). */
-        if (linkat(olddirfd, oldpath, newdirfd, newpath, 0) >= 0) {
-
-                if (unlinkat(olddirfd, oldpath, 0) < 0) {
-                        r = -errno; /* Backup errno before the following unlinkat() alters it */
-                        (void) unlinkat(newdirfd, newpath, 0);
-                        return r;
-                }
-
-                return 0;
-        }
-
-        if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)) /* FAT returns EPERM on link()… */
-                return -errno;
-
-        /* OK, neither RENAME_NOREPLACE nor linkat()+unlinkat() worked. Let's then fall back to the racy TOCTOU
-         * vulnerable accessat(F_OK) check followed by classic, replacing renameat(), we have nothing better. */
-
-        if (faccessat(newdirfd, newpath, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
-                return -EEXIST;
-        if (errno != ENOENT)
-                return -errno;
-
-        if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
-                return -errno;
-
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-int readlinkat_malloc(int fd, const char *p, char **ret) {
-        size_t l = FILENAME_MAX+1;
-        int r;
-
-        assert(p);
-        assert(ret);
-
-        for (;;) {
-                char *c;
-                ssize_t n;
-
-                c = new(char, l);
-                if (!c)
-                        return -ENOMEM;
-
-                n = readlinkat(fd, p, c, l-1);
-                if (n < 0) {
-                        r = -errno;
-                        free(c);
-                        return r;
-                }
-
-                if ((size_t) n < l-1) {
-                        c[n] = 0;
-                        *ret = c;
-                        return 0;
-                }
-
-                free(c);
-                l *= 2;
-        }
-}
-
-int readlink_malloc(const char *p, char **ret) {
-        return readlinkat_malloc(AT_FDCWD, p, ret);
-}
-
-#if 0 /* NM_IGNORED */
-int readlink_value(const char *p, char **ret) {
-        _cleanup_free_ char *link = NULL;
-        char *value;
-        int r;
-
-        r = readlink_malloc(p, &link);
-        if (r < 0)
-                return r;
-
-        value = basename(link);
-        if (!value)
-                return -ENOENT;
-
-        value = strdup(value);
-        if (!value)
-                return -ENOMEM;
-
-        *ret = value;
-
-        return 0;
-}
-
-int readlink_and_make_absolute(const char *p, char **r) {
-        _cleanup_free_ char *target = NULL;
-        char *k;
-        int j;
-
-        assert(p);
-        assert(r);
-
-        j = readlink_malloc(p, &target);
-        if (j < 0)
-                return j;
-
-        k = file_in_same_dir(p, target);
-        if (!k)
-                return -ENOMEM;
-
-        *r = k;
-        return 0;
-}
-
-int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
-        _cleanup_close_ int fd = -1;
-
-        assert(path);
-
-        fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change
-                                                       * mode/owner on the same file */
-        if (fd < 0)
-                return -errno;
-
-        return fchmod_and_chown(fd, mode, uid, gid);
-}
-
-int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
-        bool do_chown, do_chmod;
-        struct stat st;
-        int r;
-
-        /* Change ownership and access mode of the specified fd. Tries to do so safely, ensuring that at no
-         * point in time the access mode is above the old access mode under the old ownership or the new
-         * access mode under the new ownership. Note: this call tries hard to leave the access mode
-         * unaffected if the uid/gid is changed, i.e. it undoes implicit suid/sgid dropping the kernel does
-         * on chown().
-         *
-         * This call is happy with O_PATH fds. */
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        do_chown =
-                (uid != UID_INVALID && st.st_uid != uid) ||
-                (gid != GID_INVALID && st.st_gid != gid);
-
-        do_chmod =
-                !S_ISLNK(st.st_mode) && /* chmod is not defined on symlinks */
-                ((mode != MODE_INVALID && ((st.st_mode ^ mode) & 07777) != 0) ||
-                 do_chown); /* If we change ownership, make sure we reset the mode afterwards, since chown()
-                             * modifies the access mode too */
-
-        if (mode == MODE_INVALID)
-                mode = st.st_mode; /* If we only shall do a chown(), save original mode, since chown() might break it. */
-        else if ((mode & S_IFMT) != 0 && ((mode ^ st.st_mode) & S_IFMT) != 0)
-                return -EINVAL; /* insist on the right file type if it was specified */
-
-        if (do_chown && do_chmod) {
-                mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */
-
-                if (((minimal ^ st.st_mode) & 07777) != 0) {
-                        r = fchmod_opath(fd, minimal & 07777);
-                        if (r < 0)
-                                return r;
-                }
-        }
-
-        if (do_chown)
-                if (fchownat(fd, "", uid, gid, AT_EMPTY_PATH) < 0)
-                        return -errno;
-
-        if (do_chmod) {
-                r = fchmod_opath(fd, mode & 07777);
-                if (r < 0)
-                        return r;
-        }
-
-        return do_chown || do_chmod;
-}
-
-int fchmod_umask(int fd, mode_t m) {
-        mode_t u;
-        int r;
-
-        u = umask(0777);
-        r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
-        umask(u);
-
-        return r;
-}
-
-int fchmod_opath(int fd, mode_t m) {
-        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
-
-        /* This function operates also on fd that might have been opened with
-         * O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like
-         * fchownat() does. */
-
-        xsprintf(procfs_path, "/proc/self/fd/%i", fd);
-        if (chmod(procfs_path, m) < 0) {
-                if (errno != ENOENT)
-                        return -errno;
-
-                if (proc_mounted() == 0)
-                        return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
-
-                return -ENOENT;
-        }
-
-        return 0;
-}
-
-int futimens_opath(int fd, const struct timespec ts[2]) {
-        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
-
-        /* Similar to fchmod_path() but for futimens() */
-
-        xsprintf(procfs_path, "/proc/self/fd/%i", fd);
-        if (utimensat(AT_FDCWD, procfs_path, ts, 0) < 0) {
-                if (errno != ENOENT)
-                        return -errno;
-
-                if (proc_mounted() == 0)
-                        return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
-
-                return -ENOENT;
-        }
-
-        return 0;
-}
-
-int stat_warn_permissions(const char *path, const struct stat *st) {
-        assert(path);
-        assert(st);
-
-        /* Don't complain if we are reading something that is not a file, for example /dev/null */
-        if (!S_ISREG(st->st_mode))
-                return 0;
-
-        if (st->st_mode & 0111)
-                log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
-
-        if (st->st_mode & 0002)
-                log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
-
-        if (getpid_cached() == 1 && (st->st_mode & 0044) != 0044)
-                log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
-
-        return 0;
-}
-
-int fd_warn_permissions(const char *path, int fd) {
-        struct stat st;
-
-        assert(path);
-        assert(fd >= 0);
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        return stat_warn_permissions(path, &st);
-}
-
-int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
-        char fdpath[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
-        _cleanup_close_ int fd = -1;
-        int r, ret = 0;
-
-        assert(path);
-
-        /* Note that touch_file() does not follow symlinks: if invoked on an existing symlink, then it is the symlink
-         * itself which is updated, not its target
-         *
-         * Returns the first error we encounter, but tries to apply as much as possible. */
-
-        if (parents)
-                (void) mkdir_parents(path, 0755);
-
-        /* Initially, we try to open the node with O_PATH, so that we get a reference to the node. This is useful in
-         * case the path refers to an existing device or socket node, as we can open it successfully in all cases, and
-         * won't trigger any driver magic or so. */
-        fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW);
-        if (fd < 0) {
-                if (errno != ENOENT)
-                        return -errno;
-
-                /* if the node doesn't exist yet, we create it, but with O_EXCL, so that we only create a regular file
-                 * here, and nothing else */
-                fd = open(path, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode);
-                if (fd < 0)
-                        return -errno;
-        }
-
-        /* Let's make a path from the fd, and operate on that. With this logic, we can adjust the access mode,
-         * ownership and time of the file node in all cases, even if the fd refers to an O_PATH object — which is
-         * something fchown(), fchmod(), futimensat() don't allow. */
-        xsprintf(fdpath, "/proc/self/fd/%i", fd);
-
-        ret = fchmod_and_chown(fd, mode, uid, gid);
-
-        if (stamp != USEC_INFINITY) {
-                struct timespec ts[2];
-
-                timespec_store(&ts[0], stamp);
-                ts[1] = ts[0];
-                r = utimensat(AT_FDCWD, fdpath, ts, 0);
-        } else
-                r = utimensat(AT_FDCWD, fdpath, NULL, 0);
-        if (r < 0 && ret >= 0)
-                return -errno;
-
-        return ret;
-}
-
-int touch(const char *path) {
-        return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
-}
-
-int symlink_idempotent(const char *from, const char *to, bool make_relative) {
-        _cleanup_free_ char *relpath = NULL;
-        int r;
-
-        assert(from);
-        assert(to);
-
-        if (make_relative) {
-                _cleanup_free_ char *parent = NULL;
-
-                parent = dirname_malloc(to);
-                if (!parent)
-                        return -ENOMEM;
-
-                r = path_make_relative(parent, from, &relpath);
-                if (r < 0)
-                        return r;
-
-                from = relpath;
-        }
-
-        if (symlink(from, to) < 0) {
-                _cleanup_free_ char *p = NULL;
-
-                if (errno != EEXIST)
-                        return -errno;
-
-                r = readlink_malloc(to, &p);
-                if (r == -EINVAL) /* Not a symlink? In that case return the original error we encountered: -EEXIST */
-                        return -EEXIST;
-                if (r < 0) /* Any other error? In that case propagate it as is */
-                        return r;
-
-                if (!streq(p, from)) /* Not the symlink we want it to be? In that case, propagate the original -EEXIST */
-                        return -EEXIST;
-        }
-
-        return 0;
-}
-
-int symlink_atomic(const char *from, const char *to) {
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        assert(from);
-        assert(to);
-
-        r = tempfn_random(to, NULL, &t);
-        if (r < 0)
-                return r;
-
-        if (symlink(from, t) < 0)
-                return -errno;
-
-        if (rename(t, to) < 0) {
-                unlink_noerrno(t);
-                return -errno;
-        }
-
-        return 0;
-}
-
-int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        assert(path);
-
-        r = tempfn_random(path, NULL, &t);
-        if (r < 0)
-                return r;
-
-        if (mknod(t, mode, dev) < 0)
-                return -errno;
-
-        if (rename(t, path) < 0) {
-                unlink_noerrno(t);
-                return -errno;
-        }
-
-        return 0;
-}
-
-int mkfifo_atomic(const char *path, mode_t mode) {
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        assert(path);
-
-        r = tempfn_random(path, NULL, &t);
-        if (r < 0)
-                return r;
-
-        if (mkfifo(t, mode) < 0)
-                return -errno;
-
-        if (rename(t, path) < 0) {
-                unlink_noerrno(t);
-                return -errno;
-        }
-
-        return 0;
-}
-
-int mkfifoat_atomic(int dirfd, const char *path, mode_t mode) {
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        assert(path);
-
-        if (path_is_absolute(path))
-                return mkfifo_atomic(path, mode);
-
-        /* We're only interested in the (random) filename.  */
-        r = tempfn_random_child("", NULL, &t);
-        if (r < 0)
-                return r;
-
-        if (mkfifoat(dirfd, t, mode) < 0)
-                return -errno;
-
-        if (renameat(dirfd, t, dirfd, path) < 0) {
-                unlink_noerrno(t);
-                return -errno;
-        }
-
-        return 0;
-}
-
-int get_files_in_directory(const char *path, char ***list) {
-        _cleanup_closedir_ DIR *d = NULL;
-        struct dirent *de;
-        size_t bufsize = 0, n = 0;
-        _cleanup_strv_free_ char **l = NULL;
-
-        assert(path);
-
-        /* Returns all files in a directory in *list, and the number
-         * of files as return value. If list is NULL returns only the
-         * number. */
-
-        d = opendir(path);
-        if (!d)
-                return -errno;
-
-        FOREACH_DIRENT_ALL(de, d, return -errno) {
-                dirent_ensure_type(d, de);
-
-                if (!dirent_is_file(de))
-                        continue;
-
-                if (list) {
-                        /* one extra slot is needed for the terminating NULL */
-                        if (!GREEDY_REALLOC(l, bufsize, n + 2))
-                                return -ENOMEM;
-
-                        l[n] = strdup(de->d_name);
-                        if (!l[n])
-                                return -ENOMEM;
-
-                        l[++n] = NULL;
-                } else
-                        n++;
-        }
-
-        if (list)
-                *list = TAKE_PTR(l);
-
-        return n;
-}
-#endif /* NM_IGNORED */
-
-static int getenv_tmp_dir(const char **ret_path) {
-        const char *n;
-        int r, ret = 0;
-
-        assert(ret_path);
-
-        /* We use the same order of environment variables python uses in tempfile.gettempdir():
-         * https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */
-        FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") {
-                const char *e;
-
-                e = secure_getenv(n);
-                if (!e)
-                        continue;
-                if (!path_is_absolute(e)) {
-                        r = -ENOTDIR;
-                        goto next;
-                }
-                if (!path_is_normalized(e)) {
-                        r = -EPERM;
-                        goto next;
-                }
-
-                r = is_dir(e, true);
-                if (r < 0)
-                        goto next;
-                if (r == 0) {
-                        r = -ENOTDIR;
-                        goto next;
-                }
-
-                *ret_path = e;
-                return 1;
-
-        next:
-                /* Remember first error, to make this more debuggable */
-                if (ret >= 0)
-                        ret = r;
-        }
-
-        if (ret < 0)
-                return ret;
-
-        *ret_path = NULL;
-        return ret;
-}
-
-static int tmp_dir_internal(const char *def, const char **ret) {
-        const char *e;
-        int r, k;
-
-        assert(def);
-        assert(ret);
-
-        r = getenv_tmp_dir(&e);
-        if (r > 0) {
-                *ret = e;
-                return 0;
-        }
-
-        k = is_dir(def, true);
-        if (k == 0)
-                k = -ENOTDIR;
-        if (k < 0)
-                return r < 0 ? r : k;
-
-        *ret = def;
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int var_tmp_dir(const char **ret) {
-
-        /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
-         * even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
-         * returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR,
-         * making it a variable that overrides all temporary file storage locations. */
-
-        return tmp_dir_internal("/var/tmp", ret);
-}
-#endif /* NM_IGNORED */
-
-int tmp_dir(const char **ret) {
-
-        /* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
-         * backed by an in-memory file system: /tmp. */
-
-        return tmp_dir_internal("/tmp", ret);
-}
-
-#if 0 /* NM_IGNORED */
-int unlink_or_warn(const char *filename) {
-        if (unlink(filename) < 0 && errno != ENOENT)
-                /* If the file doesn't exist and the fs simply was read-only (in which
-                 * case unlink() returns EROFS even if the file doesn't exist), don't
-                 * complain */
-                if (errno != EROFS || access(filename, F_OK) >= 0)
-                        return log_error_errno(errno, "Failed to remove \"%s\": %m", filename);
-
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
-        char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
-        int wd;
-
-        /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
-        xsprintf(path, "/proc/self/fd/%i", what);
-
-        wd = inotify_add_watch(fd, path, mask);
-        if (wd < 0)
-                return -errno;
-
-        return wd;
-}
-
-#if 0 /* NM_IGNORED */
-int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask) {
-        int wd;
-
-        wd = inotify_add_watch(fd, pathname, mask);
-        if (wd < 0) {
-                if (errno == ENOSPC)
-                        return log_error_errno(errno, "Failed to add a watch for %s: inotify watch limit reached", pathname);
-
-                return log_error_errno(errno, "Failed to add a watch for %s: %m", pathname);
-        }
-
-        return wd;
-}
-
-static bool unsafe_transition(const struct stat *a, const struct stat *b) {
-        /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
-         * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
-         * making us believe we read something safe even though it isn't safe in the specific context we open it in. */
-
-        if (a->st_uid == 0) /* Transitioning from privileged to unprivileged is always fine */
-                return false;
-
-        return a->st_uid != b->st_uid; /* Otherwise we need to stay within the same UID */
-}
-
-static int log_unsafe_transition(int a, int b, const char *path, unsigned flags) {
-        _cleanup_free_ char *n1 = NULL, *n2 = NULL;
-
-        if (!FLAGS_SET(flags, CHASE_WARN))
-                return -ENOLINK;
-
-        (void) fd_get_path(a, &n1);
-        (void) fd_get_path(b, &n2);
-
-        return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK),
-                                 "Detected unsafe path transition %s %s %s during canonicalization of %s.",
-                                 strna(n1), special_glyph(SPECIAL_GLYPH_ARROW), strna(n2), path);
-}
-
-static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
-        _cleanup_free_ char *n1 = NULL;
-
-        if (!FLAGS_SET(flags, CHASE_WARN))
-                return -EREMOTE;
-
-        (void) fd_get_path(fd, &n1);
-
-        return log_warning_errno(SYNTHETIC_ERRNO(EREMOTE),
-                                 "Detected autofs mount point %s during canonicalization of %s.",
-                                 strna(n1), path);
-}
-
-int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) {
-        _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
-        _cleanup_close_ int fd = -1;
-        unsigned max_follow = CHASE_SYMLINKS_MAX; /* how many symlinks to follow before giving up and returning ELOOP */
-        struct stat previous_stat;
-        bool exists = true;
-        char *todo;
-        int r;
-
-        assert(path);
-
-        /* Either the file may be missing, or we return an fd to the final object, but both make no sense */
-        if ((flags & CHASE_NONEXISTENT) && ret_fd)
-                return -EINVAL;
-
-        if ((flags & CHASE_STEP) && ret_fd)
-                return -EINVAL;
-
-        if (isempty(path))
-                return -EINVAL;
-
-        /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
-         * symlinks relative to a root directory, instead of the root of the host.
-         *
-         * Note that "root" primarily matters if we encounter an absolute symlink. It is also used when following
-         * relative symlinks to ensure they cannot be used to "escape" the root directory. The path parameter passed is
-         * assumed to be already prefixed by it, except if the CHASE_PREFIX_ROOT flag is set, in which case it is first
-         * prefixed accordingly.
-         *
-         * Algorithmically this operates on two path buffers: "done" are the components of the path we already
-         * processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
-         * process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
-         * each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
-         * slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
-         * to a minimum.
-         *
-         * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got
-         * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this
-         * function what to do when encountering a symlink with an absolute path as directory: prefix it by the
-         * specified path.
-         *
-         * There are five ways to invoke this function:
-         *
-         * 1. Without CHASE_STEP or ret_fd: in this case the path is resolved and the normalized path is
-         *    returned in `ret_path`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set, 0
-         *    is returned if the file doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set, >= 0 is
-         *    returned if the destination was found, -ENOENT if it wasn't.
-         *
-         * 2. With ret_fd: in this case the destination is opened after chasing it as O_PATH and this file
-         *    descriptor is returned as return value. This is useful to open files relative to some root
-         *    directory. Note that the returned O_PATH file descriptors must be converted into a regular one (using
-         *    fd_reopen() or such) before it can be used for reading/writing. ret_fd may not be combined with
-         *    CHASE_NONEXISTENT.
-         *
-         * 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 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.
-         *
-         * 4. With CHASE_SAFE: in this case the path must not contain unsafe transitions, i.e. transitions from
-         *    unprivileged to privileged files or directories. In such cases the return value is -ENOLINK. If
-         *    CHASE_WARN is also set, a warning describing the unsafe transition is emitted.
-         *
-         * 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, path normalization
-         *    is aborted and -EREMOTE is returned. If CHASE_WARN is also set, a warning showing the path of
-         *    the mount point is emitted.
-         */
-
-        /* A root directory of "/" or "" is identical to none */
-        if (empty_or_root(original_root))
-                original_root = NULL;
-
-        if (!original_root && !ret_path && !(flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP)) && ret_fd) {
-                /* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root set
-                 * and doesn't care about any of the other special features we provide either. */
-                r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
-                if (r < 0)
-                        return -errno;
-
-                *ret_fd = r;
-                return 0;
-        }
-
-        if (original_root) {
-                r = path_make_absolute_cwd(original_root, &root);
-                if (r < 0)
-                        return r;
-
-                /* Simplify the root directory, so that it has no duplicate slashes and nothing at the
-                 * end. While we won't resolve the root path we still simplify it. Note that dropping the
-                 * trailing slash should not change behaviour, since when opening it we specify O_DIRECTORY
-                 * anyway. Moreover at the end of this function after processing everything we'll always turn
-                 * the empty string back to "/". */
-                delete_trailing_chars(root, "/");
-                path_simplify(root, true);
-
-                if (flags & CHASE_PREFIX_ROOT) {
-                        /* We don't support relative paths in combination with a root directory */
-                        if (!path_is_absolute(path))
-                                return -EINVAL;
-
-                        path = prefix_roota(root, path);
-                }
-        }
-
-        r = path_make_absolute_cwd(path, &buffer);
-        if (r < 0)
-                return r;
-
-        fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
-        if (fd < 0)
-                return -errno;
-
-        if (flags & CHASE_SAFE) {
-                if (fstat(fd, &previous_stat) < 0)
-                        return -errno;
-        }
-
-        if (root) {
-                _cleanup_free_ char *absolute = NULL;
-                const char *e;
-
-                /* If we are operating on a root directory, let's take the root directory as it is. */
-
-                e = path_startswith(buffer, root);
-                if (!e)
-                        return log_full_errno(flags & CHASE_WARN ? LOG_WARNING : LOG_DEBUG,
-                                              SYNTHETIC_ERRNO(ECHRNG),
-                                              "Specified path '%s' is outside of specified root directory '%s', refusing to resolve.",
-                                              path, root);
-
-                done = strdup(root);
-                if (!done)
-                        return -ENOMEM;
-
-                /* Make sure "todo" starts with a slash */
-                absolute = strjoin("/", e);
-                if (!absolute)
-                        return -ENOMEM;
-
-                free_and_replace(buffer, absolute);
-        }
-
-        todo = buffer;
-        for (;;) {
-                _cleanup_free_ char *first = NULL;
-                _cleanup_close_ int child = -1;
-                struct stat st;
-                size_t n, m;
-
-                /* Determine length of first component in the path */
-                n = strspn(todo, "/");                  /* The slashes */
-
-                if (n > 1) {
-                        /* If we are looking at more than a single slash then skip all but one, so that when
-                         * we are done with everything we have a normalized path with only single slashes
-                         * separating the path components. */
-                        todo += n - 1;
-                        n = 1;
-                }
-
-                m = n + strcspn(todo + n, "/");         /* The entire length of the component */
-
-                /* Extract the first component. */
-                first = strndup(todo, m);
-                if (!first)
-                        return -ENOMEM;
-
-                todo += m;
-
-                /* Empty? Then we reached the end. */
-                if (isempty(first))
-                        break;
-
-                /* Just a single slash? Then we reached the end. */
-                if (path_equal(first, "/")) {
-                        /* Preserve the trailing slash */
-
-                        if (flags & CHASE_TRAIL_SLASH)
-                                if (!strextend(&done, "/"))
-                                        return -ENOMEM;
-
-                        break;
-                }
-
-                /* Just a dot? Then let's eat this up. */
-                if (path_equal(first, "/."))
-                        continue;
-
-                /* Two dots? Then chop off the last bit of what we already found out. */
-                if (path_equal(first, "/..")) {
-                        _cleanup_free_ char *parent = NULL;
-                        _cleanup_close_ int fd_parent = -1;
-
-                        /* If we already are at the top, then going up will not change anything. This is in-line with
-                         * how the kernel handles this. */
-                        if (empty_or_root(done))
-                                continue;
-
-                        parent = dirname_malloc(done);
-                        if (!parent)
-                                return -ENOMEM;
-
-                        /* Don't allow this to leave the root dir.  */
-                        if (root &&
-                            path_startswith(done, root) &&
-                            !path_startswith(parent, root))
-                                continue;
-
-                        free_and_replace(done, parent);
-
-                        if (flags & CHASE_STEP)
-                                goto chased_one;
-
-                        fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH);
-                        if (fd_parent < 0)
-                                return -errno;
-
-                        if (flags & CHASE_SAFE) {
-                                if (fstat(fd_parent, &st) < 0)
-                                        return -errno;
-
-                                if (unsafe_transition(&previous_stat, &st))
-                                        return log_unsafe_transition(fd, fd_parent, path, flags);
-
-                                previous_stat = st;
-                        }
-
-                        safe_close(fd);
-                        fd = TAKE_FD(fd_parent);
-
-                        continue;
-                }
-
-                /* Otherwise let's see what this is. */
-                child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH);
-                if (child < 0) {
-
-                        if (errno == ENOENT &&
-                            (flags & CHASE_NONEXISTENT) &&
-                            (isempty(todo) || path_is_normalized(todo))) {
-
-                                /* If CHASE_NONEXISTENT is set, and the path does not exist, then that's OK, return
-                                 * what we got so far. But don't allow this if the remaining path contains "../ or "./"
-                                 * or something else weird. */
-
-                                /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
-                                if (streq_ptr(done, "/"))
-                                        *done = '\0';
-
-                                if (!strextend(&done, first, todo))
-                                        return -ENOMEM;
-
-                                exists = false;
-                                break;
-                        }
-
-                        return -errno;
-                }
-
-                if (fstat(child, &st) < 0)
-                        return -errno;
-                if ((flags & CHASE_SAFE) &&
-                    unsafe_transition(&previous_stat, &st))
-                        return log_unsafe_transition(fd, child, path, flags);
-
-                previous_stat = st;
-
-                if ((flags & CHASE_NO_AUTOFS) &&
-                    fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
-                        return log_autofs_mount_point(child, path, flags);
-
-                if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
-                        char *joined;
-                        _cleanup_free_ char *destination = NULL;
-
-                        /* This is a symlink, in this case read the destination. But let's make sure we don't follow
-                         * symlinks without bounds. */
-                        if (--max_follow <= 0)
-                                return -ELOOP;
-
-                        r = readlinkat_malloc(fd, first + n, &destination);
-                        if (r < 0)
-                                return r;
-                        if (isempty(destination))
-                                return -EINVAL;
-
-                        if (path_is_absolute(destination)) {
-
-                                /* An absolute destination. Start the loop from the beginning, but use the root
-                                 * directory as base. */
-
-                                safe_close(fd);
-                                fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
-                                if (fd < 0)
-                                        return -errno;
-
-                                if (flags & CHASE_SAFE) {
-                                        if (fstat(fd, &st) < 0)
-                                                return -errno;
-
-                                        if (unsafe_transition(&previous_stat, &st))
-                                                return log_unsafe_transition(child, fd, path, flags);
-
-                                        previous_stat = st;
-                                }
-
-                                free(done);
-
-                                /* Note that we do not revalidate the root, we take it as is. */
-                                if (isempty(root))
-                                        done = NULL;
-                                else {
-                                        done = strdup(root);
-                                        if (!done)
-                                                return -ENOMEM;
-                                }
-
-                                /* Prefix what's left to do with what we just read, and start the loop again, but
-                                 * remain in the current directory. */
-                                joined = path_join(destination, todo);
-                        } else
-                                joined = path_join("/", destination, todo);
-                        if (!joined)
-                                return -ENOMEM;
-
-                        free(buffer);
-                        todo = buffer = joined;
-
-                        if (flags & CHASE_STEP)
-                                goto chased_one;
-
-                        continue;
-                }
-
-                /* If this is not a symlink, then let's just add the name we read to what we already verified. */
-                if (!done)
-                        done = TAKE_PTR(first);
-                else {
-                        /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
-                        if (streq(done, "/"))
-                                *done = '\0';
-
-                        if (!strextend(&done, first))
-                                return -ENOMEM;
-                }
-
-                /* And iterate again, but go one directory further down. */
-                safe_close(fd);
-                fd = TAKE_FD(child);
-        }
-
-        if (!done) {
-                /* Special case, turn the empty string into "/", to indicate the root directory. */
-                done = strdup("/");
-                if (!done)
-                        return -ENOMEM;
-        }
-
-        if (ret_path)
-                *ret_path = TAKE_PTR(done);
-
-        if (ret_fd) {
-                /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a
-                 * proper fd by opening /proc/self/fd/xyz. */
-
-                assert(fd >= 0);
-                *ret_fd = TAKE_FD(fd);
-        }
-
-        if (flags & CHASE_STEP)
-                return 1;
-
-        return exists;
-
-chased_one:
-        if (ret_path) {
-                char *c;
-
-                c = strjoin(strempty(done), todo);
-                if (!c)
-                        return -ENOMEM;
-
-                *ret_path = c;
-        }
-
-        return 0;
-}
-
-int chase_symlinks_and_open(
-                const char *path,
-                const char *root,
-                unsigned chase_flags,
-                int open_flags,
-                char **ret_path) {
-
-        _cleanup_close_ int path_fd = -1;
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        if (chase_flags & CHASE_NONEXISTENT)
-                return -EINVAL;
-
-        if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
-                /* Shortcut this call if none of the special features of this call are requested */
-                r = open(path, open_flags);
-                if (r < 0)
-                        return -errno;
-
-                return r;
-        }
-
-        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
-        if (r < 0)
-                return r;
-        assert(path_fd >= 0);
-
-        r = fd_reopen(path_fd, open_flags);
-        if (r < 0)
-                return r;
-
-        if (ret_path)
-                *ret_path = TAKE_PTR(p);
-
-        return r;
-}
-
-int chase_symlinks_and_opendir(
-                const char *path,
-                const char *root,
-                unsigned chase_flags,
-                char **ret_path,
-                DIR **ret_dir) {
-
-        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
-        _cleanup_close_ int path_fd = -1;
-        _cleanup_free_ char *p = NULL;
-        DIR *d;
-        int r;
-
-        if (!ret_dir)
-                return -EINVAL;
-        if (chase_flags & CHASE_NONEXISTENT)
-                return -EINVAL;
-
-        if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
-                /* Shortcut this call if none of the special features of this call are requested */
-                d = opendir(path);
-                if (!d)
-                        return -errno;
-
-                *ret_dir = d;
-                return 0;
-        }
-
-        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
-        if (r < 0)
-                return r;
-        assert(path_fd >= 0);
-
-        xsprintf(procfs_path, "/proc/self/fd/%i", path_fd);
-        d = opendir(procfs_path);
-        if (!d)
-                return -errno;
-
-        if (ret_path)
-                *ret_path = TAKE_PTR(p);
-
-        *ret_dir = d;
-        return 0;
-}
-
-int chase_symlinks_and_stat(
-                const char *path,
-                const char *root,
-                unsigned chase_flags,
-                char **ret_path,
-                struct stat *ret_stat,
-                int *ret_fd) {
-
-        _cleanup_close_ int path_fd = -1;
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        assert(path);
-        assert(ret_stat);
-
-        if (chase_flags & CHASE_NONEXISTENT)
-                return -EINVAL;
-
-        if (empty_or_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
-                /* Shortcut this call if none of the special features of this call are requested */
-                if (stat(path, ret_stat) < 0)
-                        return -errno;
-
-                return 1;
-        }
-
-        r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
-        if (r < 0)
-                return r;
-        assert(path_fd >= 0);
-
-        if (fstat(path_fd, ret_stat) < 0)
-                return -errno;
-
-        if (ret_path)
-                *ret_path = TAKE_PTR(p);
-        if (ret_fd)
-                *ret_fd = TAKE_FD(path_fd);
-
-        return 1;
-}
-
-int access_fd(int fd, int mode) {
-        char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
-
-        /* Like access() but operates on an already open fd */
-
-        xsprintf(p, "/proc/self/fd/%i", fd);
-        if (access(p, mode) < 0) {
-                if (errno != ENOENT)
-                        return -errno;
-
-                /* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's
-                 * make things debuggable and distinguish the two. */
-
-                if (proc_mounted() == 0)
-                        return -ENOSYS;  /* /proc is not available or not set up properly, we're most likely in some chroot
-                                          * environment. */
-
-                return -EBADF; /* The directory exists, hence it's the fd that doesn't. */
-        }
-
-        return 0;
-}
-
-void unlink_tempfilep(char (*p)[]) {
-        /* If the file is created with mkstemp(), it will (almost always)
-         * change the suffix. Treat this as a sign that the file was
-         * successfully created. We ignore both the rare case where the
-         * original suffix is used and unlink failures. */
-        if (!endswith(*p, ".XXXXXX"))
-                (void) unlink_noerrno(*p);
-}
-
-int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
-        _cleanup_close_ int truncate_fd = -1;
-        struct stat st;
-        off_t l, bs;
-
-        assert((flags & ~(UNLINK_REMOVEDIR|UNLINK_ERASE)) == 0);
-
-        /* Operates like unlinkat() but also deallocates the file contents if it is a regular file and there's no other
-         * link to it. This is useful to ensure that other processes that might have the file open for reading won't be
-         * able to keep the data pinned on disk forever. This call is particular useful whenever we execute clean-up
-         * jobs ("vacuuming"), where we want to make sure the data is really gone and the disk space released and
-         * returned to the free pool.
-         *
-         * Deallocation is preferably done by FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE (👊) if supported, which means
-         * the file won't change size. That's a good thing since we shouldn't needlessly trigger SIGBUS in other
-         * programs that have mmap()ed the file. (The assumption here is that changing file contents to all zeroes
-         * underneath those programs is the better choice than simply triggering SIGBUS in them which truncation does.)
-         * However if hole punching is not implemented in the kernel or file system we'll fall back to normal file
-         * truncation (🔪), as our goal of deallocating the data space trumps our goal of being nice to readers (💐).
-         *
-         * Note that we attempt deallocation, but failure to succeed with that is not considered fatal, as long as the
-         * primary job – to delete the file – is accomplished. */
-
-        if (!FLAGS_SET(flags, UNLINK_REMOVEDIR)) {
-                truncate_fd = openat(fd, name, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
-                if (truncate_fd < 0) {
-
-                        /* If this failed because the file doesn't exist propagate the error right-away. Also,
-                         * AT_REMOVEDIR wasn't set, and we tried to open the file for writing, which means EISDIR is
-                         * returned when this is a directory but we are not supposed to delete those, hence propagate
-                         * the error right-away too. */
-                        if (IN_SET(errno, ENOENT, EISDIR))
-                                return -errno;
-
-                        if (errno != ELOOP) /* don't complain if this is a symlink */
-                                log_debug_errno(errno, "Failed to open file '%s' for deallocation, ignoring: %m", name);
-                }
-        }
-
-        if (unlinkat(fd, name, FLAGS_SET(flags, UNLINK_REMOVEDIR) ? AT_REMOVEDIR : 0) < 0)
-                return -errno;
-
-        if (truncate_fd < 0) /* Don't have a file handle, can't do more ☹️ */
-                return 0;
-
-        if (fstat(truncate_fd, &st) < 0) {
-                log_debug_errno(errno, "Failed to stat file '%s' for deallocation, ignoring: %m", name);
-                return 0;
-        }
-
-        if (!S_ISREG(st.st_mode))
-                return 0;
-
-        if (FLAGS_SET(flags, UNLINK_ERASE) && st.st_size > 0 && st.st_nlink == 0) {
-                uint64_t left = st.st_size;
-                char buffer[64 * 1024];
-
-                /* If erasing is requested, let's overwrite the file with random data once before deleting
-                 * it. This isn't going to give you shred(1) semantics, but hopefully should be good enough
-                 * for stuff backed by tmpfs at least.
-                 *
-                 * Note that we only erase like this if the link count of the file is zero. If it is higher it
-                 * is still linked by someone else and we'll leave it to them to remove it securely
-                 * eventually! */
-
-                random_bytes(buffer, sizeof(buffer));
-
-                while (left > 0) {
-                        ssize_t n;
-
-                        n = write(truncate_fd, buffer, MIN(sizeof(buffer), left));
-                        if (n < 0) {
-                                log_debug_errno(errno, "Failed to erase data in file '%s', ignoring.", name);
-                                break;
-                        }
-
-                        assert(left >= (size_t) n);
-                        left -= n;
-                }
-
-                /* Let's refresh metadata */
-                if (fstat(truncate_fd, &st) < 0) {
-                        log_debug_errno(errno, "Failed to stat file '%s' for deallocation, ignoring: %m", name);
-                        return 0;
-                }
-        }
-
-        /* Don't dallocate if there's nothing to deallocate or if the file is linked elsewhere */
-        if (st.st_blocks == 0 || st.st_nlink > 0)
-                return 0;
-
-        /* If this is a regular file, it actually took up space on disk and there are no other links it's time to
-         * punch-hole/truncate this to release the disk space. */
-
-        bs = MAX(st.st_blksize, 512);
-        l = DIV_ROUND_UP(st.st_size, bs) * bs; /* Round up to next block size */
-
-        if (fallocate(truncate_fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, 0, l) >= 0)
-                return 0; /* Successfully punched a hole! 😊 */
-
-        /* Fall back to truncation */
-        if (ftruncate(truncate_fd, 0) < 0) {
-                log_debug_errno(errno, "Failed to truncate file to 0, ignoring: %m");
-                return 0;
-        }
-
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int fsync_directory_of_file(int fd) {
-        _cleanup_free_ char *path = NULL;
-        _cleanup_close_ int dfd = -1;
-        int r;
-
-        r = fd_verify_regular(fd);
-        if (r < 0)
-                return r;
-
-        r = fd_get_path(fd, &path);
-        if (r < 0) {
-                log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m",
-                                fd,
-                                r == -ENOSYS ? ", ignoring" : "");
-
-                if (r == -ENOSYS)
-                        /* If /proc is not available, we're most likely running in some
-                         * chroot environment, and syncing the directory is not very
-                         * important in that case. Let's just silently do nothing. */
-                        return 0;
-
-                return r;
-        }
-
-        if (!path_is_absolute(path))
-                return -EINVAL;
-
-        dfd = open_parent(path, O_CLOEXEC, 0);
-        if (dfd < 0)
-                return dfd;
-
-        if (fsync(dfd) < 0)
-                return -errno;
-
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-int fsync_full(int fd) {
-        int r, q;
-
-        /* Sync both the file and the directory */
-
-        r = fsync(fd) < 0 ? -errno : 0;
-        q = fsync_directory_of_file(fd);
-
-        return r < 0 ? r : q;
-}
-
-int fsync_path_at(int at_fd, const char *path) {
-        _cleanup_close_ int opened_fd = -1;
-        int fd;
-
-        if (isempty(path)) {
-                if (at_fd == AT_FDCWD) {
-                        opened_fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
-                        if (opened_fd < 0)
-                                return -errno;
-
-                        fd = opened_fd;
-                } else
-                        fd = at_fd;
-        } else {
-
-                opened_fd = openat(at_fd, path, O_RDONLY|O_CLOEXEC);
-                if (opened_fd < 0)
-                        return -errno;
-
-                fd = opened_fd;
-        }
-
-        if (fsync(fd) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int syncfs_path(int atfd, const char *path) {
-        _cleanup_close_ int fd = -1;
-
-        assert(path);
-
-        fd = openat(atfd, path, O_CLOEXEC|O_RDONLY|O_NONBLOCK);
-        if (fd < 0)
-                return -errno;
-
-        if (syncfs(fd) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int open_parent(const char *path, int flags, mode_t mode) {
-        _cleanup_free_ char *parent = NULL;
-        int fd;
-
-        if (isempty(path))
-                return -EINVAL;
-        if (path_equal(path, "/")) /* requesting the parent of the root dir is fishy, let's prohibit that */
-                return -EINVAL;
-
-        parent = dirname_malloc(path);
-        if (!parent)
-                return -ENOMEM;
-
-        /* Let's insist on O_DIRECTORY since the parent of a file or directory is a directory. Except if we open an
-         * O_TMPFILE file, because in that case we are actually create a regular file below the parent directory. */
-
-        if (FLAGS_SET(flags, O_PATH))
-                flags |= O_DIRECTORY;
-        else if (!FLAGS_SET(flags, O_TMPFILE))
-                flags |= O_DIRECTORY|O_RDONLY;
-
-        fd = open(parent, flags, mode);
-        if (fd < 0)
-                return -errno;
-
-        return fd;
-}
-
-static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
-        _cleanup_free_ char *p = NULL, *uuids = NULL;
-        _cleanup_closedir_ DIR *d = NULL;
-        int r, found_encrypted = false;
-
-        assert(sysfs_path);
-
-        if (depth_left == 0)
-                return -EINVAL;
-
-        p = path_join(sysfs_path, "dm/uuid");
-        if (!p)
-                return -ENOMEM;
-
-        r = read_one_line_file(p, &uuids);
-        if (r != -ENOENT) {
-                if (r < 0)
-                        return r;
-
-                /* The DM device's uuid attribute is prefixed with "CRYPT-" if this is a dm-crypt device. */
-                if (startswith(uuids, "CRYPT-"))
-                        return true;
-        }
-
-        /* Not a dm-crypt device itself. But maybe it is on top of one? Follow the links in the "slaves/"
-         * subdir. */
-
-        p = mfree(p);
-        p = path_join(sysfs_path, "slaves");
-        if (!p)
-                return -ENOMEM;
-
-        d = opendir(p);
-        if (!d) {
-                if (errno == ENOENT) /* Doesn't have underlying devices */
-                        return false;
-
-                return -errno;
-        }
-
-        for (;;) {
-                _cleanup_free_ char *q = NULL;
-                struct dirent *de;
-
-                errno = 0;
-                de = readdir_no_dot(d);
-                if (!de) {
-                        if (errno != 0)
-                                return -errno;
-
-                        break; /* No more underlying devices */
-                }
-
-                q = path_join(p, de->d_name);
-                if (!q)
-                        return -ENOMEM;
-
-                r = blockdev_is_encrypted(q, depth_left - 1);
-                if (r < 0)
-                        return r;
-                if (r == 0) /* we found one that is not encrypted? then propagate that immediately */
-                        return false;
-
-                found_encrypted = true;
-        }
-
-        return found_encrypted;
-}
-
-int path_is_encrypted(const char *path) {
-        char p[SYS_BLOCK_PATH_MAX(NULL)];
-        dev_t devt;
-        int r;
-
-        r = get_block_device(path, &devt);
-        if (r < 0)
-                return r;
-        if (r == 0) /* doesn't have a block device */
-                return false;
-
-        xsprintf_sys_block_path(p, NULL, devt);
-
-        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
deleted file mode 100644
index 9a394735..00000000
--- a/shared/systemd/src/basic/fs-util.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <sys/inotify.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "errno-util.h"
-#include "time-util.h"
-
-#define MODE_INVALID ((mode_t) -1)
-
-/* The following macros add 1 when converting things, since 0 is a valid mode, while the pointer
- * NULL is special */
-#define PTR_TO_MODE(p) ((mode_t) ((uintptr_t) (p)-1))
-#define MODE_TO_PTR(u) ((void *) ((uintptr_t) (u)+1))
-
-int unlink_noerrno(const char *path);
-
-int rmdir_parents(const char *path, const char *stop);
-
-int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
-
-int readlinkat_malloc(int fd, const char *p, char **ret);
-int readlink_malloc(const char *p, char **r);
-int readlink_value(const char *p, char **ret);
-int readlink_and_make_absolute(const char *p, char **r);
-
-int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
-int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid);
-
-int fchmod_umask(int fd, mode_t mode);
-int fchmod_opath(int fd, mode_t m);
-
-int futimens_opath(int fd, const struct timespec ts[2]);
-
-int fd_warn_permissions(const char *path, int fd);
-int stat_warn_permissions(const char *path, const struct stat *st);
-
-#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
-
-int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
-int touch(const char *path);
-
-int symlink_idempotent(const char *from, const char *to, bool make_relative);
-
-int symlink_atomic(const char *from, const char *to);
-int mknod_atomic(const char *path, mode_t mode, dev_t dev);
-int mkfifo_atomic(const char *path, mode_t mode);
-int mkfifoat_atomic(int dir_fd, const char *path, mode_t mode);
-
-int get_files_in_directory(const char *path, char ***list);
-
-int tmp_dir(const char **ret);
-int var_tmp_dir(const char **ret);
-
-int unlink_or_warn(const char *filename);
-
-#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
-
-#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
-        for ((e) = &buffer.ev;                                \
-             (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \
-             (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
-
-union inotify_event_buffer {
-        struct inotify_event ev;
-        uint8_t raw[INOTIFY_EVENT_MAX];
-};
-
-int inotify_add_watch_fd(int fd, int what, uint32_t mask);
-int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask);
-
-enum {
-        CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */
-        CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */
-        CHASE_NO_AUTOFS   = 1 << 2, /* Return -EREMOTE if autofs mount point found */
-        CHASE_SAFE        = 1 << 3, /* Return -EPERM if we ever traverse from unprivileged to privileged files or directories */
-        CHASE_TRAIL_SLASH = 1 << 4, /* Any trailing slash will be preserved */
-        CHASE_STEP        = 1 << 5, /* Just execute a single step of the normalization */
-        CHASE_NOFOLLOW    = 1 << 6, /* Do not follow the path's right-most component. With ret_fd, when the path's
-                                     * right-most component refers to symlink, return O_PATH fd of the symlink. */
-        CHASE_WARN        = 1 << 7, /* Emit an appropriate warning when an error is encountered */
-};
-
-/* How many iterations to execute before returning -ELOOP */
-#define CHASE_SYMLINKS_MAX 32
-
-int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret_path, int *ret_fd);
-
-int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path);
-int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir);
-int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd);
-
-/* Useful for usage with _cleanup_(), removes a directory and frees the pointer */
-static inline void rmdir_and_free(char *p) {
-        PROTECT_ERRNO;
-        (void) rmdir(p);
-        free(p);
-}
-DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rmdir_and_free);
-
-static inline void unlink_and_free(char *p) {
-        (void) unlink_noerrno(p);
-        free(p);
-}
-DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free);
-
-int access_fd(int fd, int mode);
-
-void unlink_tempfilep(char (*p)[]);
-
-typedef enum UnlinkDeallocateFlags {
-        UNLINK_REMOVEDIR = 1 << 0,
-        UNLINK_ERASE     = 1 << 1,
-} UnlinkDeallocateFlags;
-
-int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags);
-
-int fsync_directory_of_file(int fd);
-int fsync_full(int fd);
-int fsync_path_at(int at_fd, const char *path);
-
-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
deleted file mode 100644
index 6f540b29..00000000
--- a/shared/systemd/src/basic/hash-funcs.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <string.h>
-
-#include "hash-funcs.h"
-#include "path-util.h"
-
-void string_hash_func(const char *p, struct siphash *state) {
-        siphash24_compress(p, strlen(p) + 1, state);
-}
-
-DEFINE_HASH_OPS(string_hash_ops, char, string_hash_func, string_compare_func);
-DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(string_hash_ops_free,
-                                    char, string_hash_func, string_compare_func, free);
-DEFINE_HASH_OPS_FULL(string_hash_ops_free_free,
-                     char, string_hash_func, string_compare_func, free,
-                     char, free);
-
-#if 0 /* NM_IGNORED */
-void path_hash_func(const char *q, struct siphash *state) {
-        size_t n;
-
-        assert(q);
-        assert(state);
-
-        /* Calculates a hash for a path in a way this duplicate inner slashes don't make a differences, and also
-         * whether there's a trailing slash or not. This fits well with the semantics of path_compare(), which does
-         * similar checks and also doesn't care for trailing slashes. Note that relative and absolute paths (i.e. those
-         * which begin in a slash or not) will hash differently though. */
-
-        n = strspn(q, "/");
-        if (n > 0) { /* Eat up initial slashes, and add one "/" to the hash for all of them */
-                siphash24_compress(q, 1, state);
-                q += n;
-        }
-
-        for (;;) {
-                /* Determine length of next component */
-                n = strcspn(q, "/");
-                if (n == 0) /* Reached the end? */
-                        break;
-
-                /* Add this component to the hash and skip over it */
-                siphash24_compress(q, n, state);
-                q += n;
-
-                /* How many slashes follow this component? */
-                n = strspn(q, "/");
-                if (q[n] == 0) /* Is this a trailing slash? If so, we are at the end, and don't care about the slashes anymore */
-                        break;
-
-                /* We are not add the end yet. Hash exactly one slash for all of the ones we just encountered. */
-                siphash24_compress(q, 1, state);
-                q += n;
-        }
-}
-
-DEFINE_HASH_OPS(path_hash_ops, char, path_hash_func, path_compare);
-DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(path_hash_ops_free,
-                                    char, path_hash_func, path_compare, free);
-#endif /* NM_IGNORED */
-
-void trivial_hash_func(const void *p, struct siphash *state) {
-        siphash24_compress(&p, sizeof(p), state);
-}
-
-int trivial_compare_func(const void *a, const void *b) {
-        return CMP(a, b);
-}
-
-const struct hash_ops trivial_hash_ops = {
-        .hash = trivial_hash_func,
-        .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);
-}
-
-int uint64_compare_func(const uint64_t *a, const uint64_t *b) {
-        return CMP(*a, *b);
-}
-
-DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func);
-
-#if 0 /* NM_IGNORED */
-#if SIZEOF_DEV_T != 8
-void devt_hash_func(const dev_t *p, struct siphash *state) {
-        siphash24_compress(p, sizeof(dev_t), state);
-}
-
-int devt_compare_func(const dev_t *a, const dev_t *b) {
-        return CMP(*a, *b);
-}
-
-DEFINE_HASH_OPS(devt_hash_ops, dev_t, devt_hash_func, devt_compare_func);
-#endif
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/hash-funcs.h b/shared/systemd/src/basic/hash-funcs.h
deleted file mode 100644
index 5672df1d..00000000
--- a/shared/systemd/src/basic/hash-funcs.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include "alloc-util.h"
-#include "macro.h"
-#include "siphash24.h"
-
-typedef void (*hash_func_t)(const void *p, struct siphash *state);
-typedef int (*compare_func_t)(const void *a, const void *b);
-
-struct hash_ops {
-        hash_func_t hash;
-        compare_func_t compare;
-        free_func_t free_key;
-        free_func_t free_value;
-};
-
-#define _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func, free_key_func, free_value_func, scope) \
-        _unused_ static void (* UNIQ_T(static_hash_wrapper, uq))(const type *, struct siphash *) = hash_func; \
-        _unused_ static int (* UNIQ_T(static_compare_wrapper, uq))(const type *, const type *) = compare_func; \
-        scope const struct hash_ops name = {                            \
-                .hash = (hash_func_t) hash_func,                        \
-                .compare = (compare_func_t) compare_func,               \
-                .free_key = free_key_func,                              \
-                .free_value = free_value_func,                          \
-        }
-
-#define _DEFINE_FREE_FUNC(uq, type, wrapper_name, func)                 \
-        /* Type-safe free function */                                   \
-        static void UNIQ_T(wrapper_name, uq)(void *a) {                 \
-                type *_a = a;                                           \
-                func(_a);                                               \
-        }
-
-#define _DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(uq, name, type, hash_func, compare_func, free_func, scope) \
-        _DEFINE_FREE_FUNC(uq, type, static_free_wrapper, free_func);    \
-        _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func,       \
-                         UNIQ_T(static_free_wrapper, uq), NULL, scope)
-
-#define _DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(uq, name, type, hash_func, compare_func, type_value, free_func, scope) \
-        _DEFINE_FREE_FUNC(uq, type_value, static_free_wrapper, free_func); \
-        _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func,       \
-                         NULL, UNIQ_T(static_free_wrapper, uq), scope)
-
-#define _DEFINE_HASH_OPS_FULL(uq, name, type, hash_func, compare_func, free_key_func, type_value, free_value_func, scope) \
-        _DEFINE_FREE_FUNC(uq, type, static_free_key_wrapper, free_key_func); \
-        _DEFINE_FREE_FUNC(uq, type_value, static_free_value_wrapper, free_value_func); \
-        _DEFINE_HASH_OPS(uq, name, type, hash_func, compare_func,       \
-                         UNIQ_T(static_free_key_wrapper, uq),           \
-                         UNIQ_T(static_free_value_wrapper, uq), scope)
-
-#define DEFINE_HASH_OPS(name, type, hash_func, compare_func)            \
-        _DEFINE_HASH_OPS(UNIQ, name, type, hash_func, compare_func, NULL, NULL,)
-
-#define DEFINE_PRIVATE_HASH_OPS(name, type, hash_func, compare_func)    \
-        _DEFINE_HASH_OPS(UNIQ, name, type, hash_func, compare_func, NULL, NULL, static)
-
-#define DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(name, type, hash_func, compare_func, free_func) \
-        _DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, free_func,)
-
-#define DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(name, type, hash_func, compare_func, free_func) \
-        _DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, free_func, static)
-
-#define DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(name, type, hash_func, compare_func, value_type, free_func) \
-        _DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, value_type, free_func,)
-
-#define DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(name, type, hash_func, compare_func, value_type, free_func) \
-        _DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(UNIQ, name, type, hash_func, compare_func, value_type, free_func, static)
-
-#define DEFINE_HASH_OPS_FULL(name, type, hash_func, compare_func, free_key_func, value_type, free_value_func) \
-        _DEFINE_HASH_OPS_FULL(UNIQ, name, type, hash_func, compare_func, free_key_func, value_type, free_value_func,)
-
-#define DEFINE_PRIVATE_HASH_OPS_FULL(name, type, hash_func, compare_func, free_key_func, value_type, free_value_func) \
-        _DEFINE_HASH_OPS_FULL(UNIQ, name, type, hash_func, compare_func, free_key_func, value_type, free_value_func, static)
-
-void string_hash_func(const char *p, struct siphash *state);
-#define string_compare_func strcmp
-extern const struct hash_ops string_hash_ops;
-extern const struct hash_ops string_hash_ops_free;
-extern const struct hash_ops string_hash_ops_free_free;
-
-void path_hash_func(const char *p, struct siphash *state);
-extern const struct hash_ops path_hash_ops;
-extern const struct hash_ops path_hash_ops_free;
-
-/* This will compare the passed pointers directly, and will not dereference them. This is hence not useful for strings
- * or suchlike. */
-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. */
-void uint64_hash_func(const uint64_t *p, struct siphash *state);
-int uint64_compare_func(const uint64_t *a, const uint64_t *b) _pure_;
-extern const struct hash_ops uint64_hash_ops;
-
-/* On some archs dev_t is 32bit, and on others 64bit. And sometimes it's 64bit on 32bit archs, and sometimes 32bit on
- * 64bit archs. Yuck! */
-#if SIZEOF_DEV_T != 8
-void devt_hash_func(const dev_t *p, struct siphash *state) _pure_;
-int devt_compare_func(const dev_t *a, const dev_t *b) _pure_;
-extern const struct hash_ops devt_hash_ops;
-#else
-#define devt_hash_func uint64_hash_func
-#define devt_compare_func uint64_compare_func
-#define devt_hash_ops uint64_hash_ops
-#endif
diff --git a/shared/systemd/src/basic/hashmap.c b/shared/systemd/src/basic/hashmap.c
deleted file mode 100644
index 0a5deabf..00000000
--- a/shared/systemd/src/basic/hashmap.c
+++ /dev/null
@@ -1,2032 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <pthread.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "alloc-util.h"
-#include "fileio.h"
-#include "hashmap.h"
-#include "macro.h"
-#include "memory-util.h"
-#include "mempool.h"
-#include "missing_syscall.h"
-#include "process-util.h"
-#include "random-util.h"
-#include "set.h"
-#include "siphash24.h"
-#include "string-util.h"
-#include "strv.h"
-
-#if ENABLE_DEBUG_HASHMAP
-#include "list.h"
-#endif
-
-/*
- * Implementation of hashmaps.
- * Addressing: open
- *   - uses less RAM compared to closed addressing (chaining), because
- *     our entries are small (especially in Sets, which tend to contain
- *     the majority of entries in systemd).
- * Collision resolution: Robin Hood
- *   - tends to equalize displacement of entries from their optimal buckets.
- * Probe sequence: linear
- *   - though theoretically worse than random probing/uniform hashing/double
- *     hashing, it is good for cache locality.
- *
- * References:
- * Celis, P. 1986. Robin Hood Hashing.
- * Ph.D. Dissertation. University of Waterloo, Waterloo, Ont., Canada, Canada.
- * https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf
- * - The results are derived for random probing. Suggests deletion with
- *   tombstones and two mean-centered search methods. None of that works
- *   well for linear probing.
- *
- * Janson, S. 2005. Individual displacements for linear probing hashing with different insertion policies.
- * ACM Trans. Algorithms 1, 2 (October 2005), 177-213.
- * DOI=10.1145/1103963.1103964 http://doi.acm.org/10.1145/1103963.1103964
- * http://www.math.uu.se/~svante/papers/sj157.pdf
- * - Applies to Robin Hood with linear probing. Contains remarks on
- *   the unsuitability of mean-centered search with linear probing.
- *
- * Viola, A. 2005. Exact distribution of individual displacements in linear probing hashing.
- * ACM Trans. Algorithms 1, 2 (October 2005), 214-242.
- * DOI=10.1145/1103963.1103965 http://doi.acm.org/10.1145/1103963.1103965
- * - Similar to Janson. Note that Viola writes about C_{m,n} (number of probes
- *   in a successful search), and Janson writes about displacement. C = d + 1.
- *
- * Goossaert, E. 2013. Robin Hood hashing: backward shift deletion.
- * http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/
- * - Explanation of backward shift deletion with pictures.
- *
- * Khuong, P. 2013. The Other Robin Hood Hashing.
- * http://www.pvk.ca/Blog/2013/11/26/the-other-robin-hood-hashing/
- * - Short summary of random vs. linear probing, and tombstones vs. backward shift.
- */
-
-/*
- * XXX Ideas for improvement:
- * For unordered hashmaps, randomize iteration order, similarly to Perl:
- * http://blog.booking.com/hardening-perls-hash-function.html
- */
-
-/* INV_KEEP_FREE = 1 / (1 - max_load_factor)
- * e.g. 1 / (1 - 0.8) = 5 ... keep one fifth of the buckets free. */
-#define INV_KEEP_FREE            5U
-
-/* Fields common to entries of all hashmap/set types */
-struct hashmap_base_entry {
-        const void *key;
-};
-
-/* Entry types for specific hashmap/set types
- * hashmap_base_entry must be at the beginning of each entry struct. */
-
-struct plain_hashmap_entry {
-        struct hashmap_base_entry b;
-        void *value;
-};
-
-struct ordered_hashmap_entry {
-        struct plain_hashmap_entry p;
-        unsigned iterate_next, iterate_previous;
-};
-
-struct set_entry {
-        struct hashmap_base_entry b;
-};
-
-/* In several functions it is advantageous to have the hash table extended
- * virtually by a couple of additional buckets. We reserve special index values
- * for these "swap" buckets. */
-#define _IDX_SWAP_BEGIN     (UINT_MAX - 3)
-#define IDX_PUT             (_IDX_SWAP_BEGIN + 0)
-#define IDX_TMP             (_IDX_SWAP_BEGIN + 1)
-#define _IDX_SWAP_END       (_IDX_SWAP_BEGIN + 2)
-
-#define IDX_FIRST           (UINT_MAX - 1) /* special index for freshly initialized iterators */
-#define IDX_NIL             UINT_MAX       /* special index value meaning "none" or "end" */
-
-assert_cc(IDX_FIRST == _IDX_SWAP_END);
-assert_cc(IDX_FIRST == _IDX_ITERATOR_FIRST);
-
-/* Storage space for the "swap" buckets.
- * All entry types can fit into a ordered_hashmap_entry. */
-struct swap_entries {
-        struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN];
-};
-
-/* Distance from Initial Bucket */
-typedef uint8_t dib_raw_t;
-#define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU)   /* indicates DIB value is greater than representable */
-#define DIB_RAW_REHASH   ((dib_raw_t)0xfeU)   /* entry yet to be rehashed during in-place resize */
-#define DIB_RAW_FREE     ((dib_raw_t)0xffU)   /* a free bucket */
-#define DIB_RAW_INIT     ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */
-
-#define DIB_FREE UINT_MAX
-
-#if ENABLE_DEBUG_HASHMAP
-struct hashmap_debug_info {
-        LIST_FIELDS(struct hashmap_debug_info, debug_list);
-        unsigned max_entries;  /* high watermark of n_entries */
-
-        /* who allocated this hashmap */
-        int line;
-        const char *file;
-        const char *func;
-
-        /* fields to detect modification while iterating */
-        unsigned put_count;    /* counts puts into the hashmap */
-        unsigned rem_count;    /* counts removals from hashmap */
-        unsigned last_rem_idx; /* remembers last removal index */
-};
-
-/* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */
-static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list);
-static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-enum HashmapType {
-        HASHMAP_TYPE_PLAIN,
-        HASHMAP_TYPE_ORDERED,
-        HASHMAP_TYPE_SET,
-        _HASHMAP_TYPE_MAX
-};
-
-struct _packed_ indirect_storage {
-        void *storage;                     /* where buckets and DIBs are stored */
-        uint8_t  hash_key[HASH_KEY_SIZE];  /* hash key; changes during resize */
-
-        unsigned n_entries;                /* number of stored entries */
-        unsigned n_buckets;                /* number of buckets */
-
-        unsigned idx_lowest_entry;         /* Index below which all buckets are free.
-                                              Makes "while(hashmap_steal_first())" loops
-                                              O(n) instead of O(n^2) for unordered hashmaps. */
-        uint8_t  _pad[3];                  /* padding for the whole HashmapBase */
-        /* The bitfields in HashmapBase complete the alignment of the whole thing. */
-};
-
-struct direct_storage {
-        /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit.
-         * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit,
-         *              or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */
-        uint8_t storage[sizeof(struct indirect_storage)];
-};
-
-#define DIRECT_BUCKETS(entry_t) \
-        (sizeof(struct direct_storage) / (sizeof(entry_t) + sizeof(dib_raw_t)))
-
-/* We should be able to store at least one entry directly. */
-assert_cc(DIRECT_BUCKETS(struct ordered_hashmap_entry) >= 1);
-
-/* We have 3 bits for n_direct_entries. */
-assert_cc(DIRECT_BUCKETS(struct set_entry) < (1 << 3));
-
-/* Hashmaps with directly stored entries all use this shared hash key.
- * It's no big deal if the key is guessed, because there can be only
- * a handful of directly stored entries in a hashmap. When a hashmap
- * outgrows direct storage, it gets its own key for indirect storage. */
-static uint8_t shared_hash_key[HASH_KEY_SIZE];
-
-/* Fields that all hashmap/set types must have */
-struct HashmapBase {
-        const struct hash_ops *hash_ops;  /* hash and compare ops to use */
-
-        union _packed_ {
-                struct indirect_storage indirect; /* if  has_indirect */
-                struct direct_storage direct;     /* if !has_indirect */
-        };
-
-        enum HashmapType type:2;     /* HASHMAP_TYPE_* */
-        bool has_indirect:1;         /* whether indirect storage is used */
-        unsigned n_direct_entries:3; /* Number of entries in direct storage.
-                                      * Only valid if !has_indirect. */
-        bool from_pool:1;            /* whether was allocated from mempool */
-        bool dirty:1;                /* whether dirtied since last iterated_cache_get() */
-        bool cached:1;               /* whether this hashmap is being cached */
-
-#if ENABLE_DEBUG_HASHMAP
-        struct hashmap_debug_info debug;
-#endif
-};
-
-/* Specific hash types
- * HashmapBase must be at the beginning of each hashmap struct. */
-
-struct Hashmap {
-        struct HashmapBase b;
-};
-
-struct OrderedHashmap {
-        struct HashmapBase b;
-        unsigned iterate_list_head, iterate_list_tail;
-};
-
-struct Set {
-        struct HashmapBase b;
-};
-
-typedef struct CacheMem {
-        const void **ptr;
-        size_t n_populated, n_allocated;
-        bool active:1;
-} CacheMem;
-
-struct IteratedCache {
-        HashmapBase *hashmap;
-        CacheMem keys, values;
-};
-
-DEFINE_MEMPOOL(hashmap_pool,         Hashmap,        8);
-DEFINE_MEMPOOL(ordered_hashmap_pool, OrderedHashmap, 8);
-/* No need for a separate Set pool */
-assert_cc(sizeof(Hashmap) == sizeof(Set));
-
-struct hashmap_type_info {
-        size_t head_size;
-        size_t entry_size;
-        struct mempool *mempool;
-        unsigned n_direct_buckets;
-};
-
-static _used_ const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
-        [HASHMAP_TYPE_PLAIN] = {
-                .head_size        = sizeof(Hashmap),
-                .entry_size       = sizeof(struct plain_hashmap_entry),
-                .mempool          = &hashmap_pool,
-                .n_direct_buckets = DIRECT_BUCKETS(struct plain_hashmap_entry),
-        },
-        [HASHMAP_TYPE_ORDERED] = {
-                .head_size        = sizeof(OrderedHashmap),
-                .entry_size       = sizeof(struct ordered_hashmap_entry),
-                .mempool          = &ordered_hashmap_pool,
-                .n_direct_buckets = DIRECT_BUCKETS(struct ordered_hashmap_entry),
-        },
-        [HASHMAP_TYPE_SET] = {
-                .head_size        = sizeof(Set),
-                .entry_size       = sizeof(struct set_entry),
-                .mempool          = &hashmap_pool,
-                .n_direct_buckets = DIRECT_BUCKETS(struct set_entry),
-        },
-};
-
-#if VALGRIND
-_destructor_ static void cleanup_pools(void) {
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        /* Be nice to valgrind */
-
-        /* The pool is only allocated by the main thread, but the memory can
-         * be passed to other threads. Let's clean up if we are the main thread
-         * and no other threads are live. */
-        /* We build our own is_main_thread() here, which doesn't use C11
-         * TLS based caching of the result. That's because valgrind apparently
-         * doesn't like malloc() (which C11 TLS internally uses) to be called
-         * from a GCC destructors. */
-        if (getpid() != gettid())
-                return;
-
-        r = get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t);
-        if (r < 0 || !streq(t, "1"))
-                return;
-
-        mempool_drop(&hashmap_pool);
-        mempool_drop(&ordered_hashmap_pool);
-}
-#endif
-
-static unsigned n_buckets(HashmapBase *h) {
-        return h->has_indirect ? h->indirect.n_buckets
-                               : hashmap_type_info[h->type].n_direct_buckets;
-}
-
-static unsigned n_entries(HashmapBase *h) {
-        return h->has_indirect ? h->indirect.n_entries
-                               : h->n_direct_entries;
-}
-
-static void n_entries_inc(HashmapBase *h) {
-        if (h->has_indirect)
-                h->indirect.n_entries++;
-        else
-                h->n_direct_entries++;
-}
-
-static void n_entries_dec(HashmapBase *h) {
-        if (h->has_indirect)
-                h->indirect.n_entries--;
-        else
-                h->n_direct_entries--;
-}
-
-static void* storage_ptr(HashmapBase *h) {
-        return h->has_indirect ? h->indirect.storage
-                               : h->direct.storage;
-}
-
-static uint8_t* hash_key(HashmapBase *h) {
-        return h->has_indirect ? h->indirect.hash_key
-                               : shared_hash_key;
-}
-
-static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
-        struct siphash state;
-        uint64_t hash;
-
-        siphash24_init(&state, hash_key(h));
-
-        h->hash_ops->hash(p, &state);
-
-        hash = siphash24_finalize(&state);
-
-        return (unsigned) (hash % n_buckets(h));
-}
-#define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p)
-
-static void base_set_dirty(HashmapBase *h) {
-        h->dirty = true;
-}
-#define hashmap_set_dirty(h) base_set_dirty(HASHMAP_BASE(h))
-
-static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
-        static uint8_t current[HASH_KEY_SIZE];
-        static bool current_initialized = false;
-
-        /* Returns a hash function key to use. In order to keep things
-         * fast we will not generate a new key each time we allocate a
-         * new hash table. Instead, we'll just reuse the most recently
-         * generated one, except if we never generated one or when we
-         * are rehashing an entire hash table because we reached a
-         * fill level */
-
-        if (!current_initialized || !reuse_is_ok) {
-                random_bytes(current, sizeof(current));
-                current_initialized = true;
-        }
-
-        memcpy(hash_key, current, sizeof(current));
-}
-
-static struct hashmap_base_entry* bucket_at(HashmapBase *h, unsigned idx) {
-        return (struct hashmap_base_entry*)
-                ((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
-}
-
-static struct plain_hashmap_entry* plain_bucket_at(Hashmap *h, unsigned idx) {
-        return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
-}
-
-static struct ordered_hashmap_entry* ordered_bucket_at(OrderedHashmap *h, unsigned idx) {
-        return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
-}
-
-static struct set_entry *set_bucket_at(Set *h, unsigned idx) {
-        return (struct set_entry*) bucket_at(HASHMAP_BASE(h), idx);
-}
-
-static struct ordered_hashmap_entry* bucket_at_swap(struct swap_entries *swap, unsigned idx) {
-        return &swap->e[idx - _IDX_SWAP_BEGIN];
-}
-
-/* Returns a pointer to the bucket at index idx.
- * Understands real indexes and swap indexes, hence "_virtual". */
-static struct hashmap_base_entry* bucket_at_virtual(HashmapBase *h, struct swap_entries *swap,
-                                                    unsigned idx) {
-        if (idx < _IDX_SWAP_BEGIN)
-                return bucket_at(h, idx);
-
-        if (idx < _IDX_SWAP_END)
-                return &bucket_at_swap(swap, idx)->p.b;
-
-        assert_not_reached("Invalid index");
-}
-
-static dib_raw_t* dib_raw_ptr(HashmapBase *h) {
-        return (dib_raw_t*)
-                ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
-}
-
-static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) {
-        return idx >= from ? idx - from
-                           : n_buckets(h) + idx - from;
-}
-
-static unsigned bucket_calculate_dib(HashmapBase *h, unsigned idx, dib_raw_t raw_dib) {
-        unsigned initial_bucket;
-
-        if (raw_dib == DIB_RAW_FREE)
-                return DIB_FREE;
-
-        if (_likely_(raw_dib < DIB_RAW_OVERFLOW))
-                return raw_dib;
-
-        /*
-         * Having an overflow DIB value is very unlikely. The hash function
-         * would have to be bad. For example, in a table of size 2^24 filled
-         * to load factor 0.9 the maximum observed DIB is only about 60.
-         * In theory (assuming I used Maxima correctly), for an infinite size
-         * hash table with load factor 0.8 the probability of a given entry
-         * having DIB > 40 is 1.9e-8.
-         * This returns the correct DIB value by recomputing the hash value in
-         * the unlikely case. XXX Hitting this case could be a hint to rehash.
-         */
-        initial_bucket = bucket_hash(h, bucket_at(h, idx)->key);
-        return bucket_distance(h, idx, initial_bucket);
-}
-
-static void bucket_set_dib(HashmapBase *h, unsigned idx, unsigned dib) {
-        dib_raw_ptr(h)[idx] = dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE;
-}
-
-static unsigned skip_free_buckets(HashmapBase *h, unsigned idx) {
-        dib_raw_t *dibs;
-
-        dibs = dib_raw_ptr(h);
-
-        for ( ; idx < n_buckets(h); idx++)
-                if (dibs[idx] != DIB_RAW_FREE)
-                        return idx;
-
-        return IDX_NIL;
-}
-
-static void bucket_mark_free(HashmapBase *h, unsigned idx) {
-        memzero(bucket_at(h, idx), hashmap_type_info[h->type].entry_size);
-        bucket_set_dib(h, idx, DIB_FREE);
-}
-
-static void bucket_move_entry(HashmapBase *h, struct swap_entries *swap,
-                              unsigned from, unsigned to) {
-        struct hashmap_base_entry *e_from, *e_to;
-
-        assert(from != to);
-
-        e_from = bucket_at_virtual(h, swap, from);
-        e_to   = bucket_at_virtual(h, swap, to);
-
-        memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size);
-
-        if (h->type == HASHMAP_TYPE_ORDERED) {
-                OrderedHashmap *lh = (OrderedHashmap*) h;
-                struct ordered_hashmap_entry *le, *le_to;
-
-                le_to = (struct ordered_hashmap_entry*) e_to;
-
-                if (le_to->iterate_next != IDX_NIL) {
-                        le = (struct ordered_hashmap_entry*)
-                             bucket_at_virtual(h, swap, le_to->iterate_next);
-                        le->iterate_previous = to;
-                }
-
-                if (le_to->iterate_previous != IDX_NIL) {
-                        le = (struct ordered_hashmap_entry*)
-                             bucket_at_virtual(h, swap, le_to->iterate_previous);
-                        le->iterate_next = to;
-                }
-
-                if (lh->iterate_list_head == from)
-                        lh->iterate_list_head = to;
-                if (lh->iterate_list_tail == from)
-                        lh->iterate_list_tail = to;
-        }
-}
-
-static unsigned next_idx(HashmapBase *h, unsigned idx) {
-        return (idx + 1U) % n_buckets(h);
-}
-
-static unsigned prev_idx(HashmapBase *h, unsigned idx) {
-        return (n_buckets(h) + idx - 1U) % n_buckets(h);
-}
-
-static void* entry_value(HashmapBase *h, struct hashmap_base_entry *e) {
-        switch (h->type) {
-
-        case HASHMAP_TYPE_PLAIN:
-        case HASHMAP_TYPE_ORDERED:
-                return ((struct plain_hashmap_entry*)e)->value;
-
-        case HASHMAP_TYPE_SET:
-                return (void*) e->key;
-
-        default:
-                assert_not_reached("Unknown hashmap type");
-        }
-}
-
-static void base_remove_entry(HashmapBase *h, unsigned idx) {
-        unsigned left, right, prev, dib;
-        dib_raw_t raw_dib, *dibs;
-
-        dibs = dib_raw_ptr(h);
-        assert(dibs[idx] != DIB_RAW_FREE);
-
-#if ENABLE_DEBUG_HASHMAP
-        h->debug.rem_count++;
-        h->debug.last_rem_idx = idx;
-#endif
-
-        left = idx;
-        /* Find the stop bucket ("right"). It is either free or has DIB == 0. */
-        for (right = next_idx(h, left); ; right = next_idx(h, right)) {
-                raw_dib = dibs[right];
-                if (IN_SET(raw_dib, 0, DIB_RAW_FREE))
-                        break;
-
-                /* The buckets are not supposed to be all occupied and with DIB > 0.
-                 * That would mean we could make everyone better off by shifting them
-                 * backward. This scenario is impossible. */
-                assert(left != right);
-        }
-
-        if (h->type == HASHMAP_TYPE_ORDERED) {
-                OrderedHashmap *lh = (OrderedHashmap*) h;
-                struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx);
-
-                if (le->iterate_next != IDX_NIL)
-                        ordered_bucket_at(lh, le->iterate_next)->iterate_previous = le->iterate_previous;
-                else
-                        lh->iterate_list_tail = le->iterate_previous;
-
-                if (le->iterate_previous != IDX_NIL)
-                        ordered_bucket_at(lh, le->iterate_previous)->iterate_next = le->iterate_next;
-                else
-                        lh->iterate_list_head = le->iterate_next;
-        }
-
-        /* Now shift all buckets in the interval (left, right) one step backwards */
-        for (prev = left, left = next_idx(h, left); left != right;
-             prev = left, left = next_idx(h, left)) {
-                dib = bucket_calculate_dib(h, left, dibs[left]);
-                assert(dib != 0);
-                bucket_move_entry(h, NULL, left, prev);
-                bucket_set_dib(h, prev, dib - 1);
-        }
-
-        bucket_mark_free(h, prev);
-        n_entries_dec(h);
-        base_set_dirty(h);
-}
-#define remove_entry(h, idx) base_remove_entry(HASHMAP_BASE(h), idx)
-
-static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *i) {
-        struct ordered_hashmap_entry *e;
-        unsigned idx;
-
-        assert(h);
-        assert(i);
-
-        if (i->idx == IDX_NIL)
-                goto at_end;
-
-        if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL)
-                goto at_end;
-
-        if (i->idx == IDX_FIRST) {
-                idx = h->iterate_list_head;
-                e = ordered_bucket_at(h, idx);
-        } else {
-                idx = i->idx;
-                e = ordered_bucket_at(h, idx);
-                /*
-                 * We allow removing the current entry while iterating, but removal may cause
-                 * a backward shift. The next entry may thus move one bucket to the left.
-                 * To detect when it happens, we remember the key pointer of the entry we were
-                 * going to iterate next. If it does not match, there was a backward shift.
-                 */
-                if (e->p.b.key != i->next_key) {
-                        idx = prev_idx(HASHMAP_BASE(h), idx);
-                        e = ordered_bucket_at(h, idx);
-                }
-                assert(e->p.b.key == i->next_key);
-        }
-
-#if ENABLE_DEBUG_HASHMAP
-        i->prev_idx = idx;
-#endif
-
-        if (e->iterate_next != IDX_NIL) {
-                struct ordered_hashmap_entry *n;
-                i->idx = e->iterate_next;
-                n = ordered_bucket_at(h, i->idx);
-                i->next_key = n->p.b.key;
-        } else
-                i->idx = IDX_NIL;
-
-        return idx;
-
-at_end:
-        i->idx = IDX_NIL;
-        return IDX_NIL;
-}
-
-static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
-        unsigned idx;
-
-        assert(h);
-        assert(i);
-
-        if (i->idx == IDX_NIL)
-                goto at_end;
-
-        if (i->idx == IDX_FIRST) {
-                /* fast forward to the first occupied bucket */
-                if (h->has_indirect) {
-                        i->idx = skip_free_buckets(h, h->indirect.idx_lowest_entry);
-                        h->indirect.idx_lowest_entry = i->idx;
-                } else
-                        i->idx = skip_free_buckets(h, 0);
-
-                if (i->idx == IDX_NIL)
-                        goto at_end;
-        } else {
-                struct hashmap_base_entry *e;
-
-                assert(i->idx > 0);
-
-                e = bucket_at(h, i->idx);
-                /*
-                 * We allow removing the current entry while iterating, but removal may cause
-                 * a backward shift. The next entry may thus move one bucket to the left.
-                 * To detect when it happens, we remember the key pointer of the entry we were
-                 * going to iterate next. If it does not match, there was a backward shift.
-                 */
-                if (e->key != i->next_key)
-                        e = bucket_at(h, --i->idx);
-
-                assert(e->key == i->next_key);
-        }
-
-        idx = i->idx;
-#if ENABLE_DEBUG_HASHMAP
-        i->prev_idx = idx;
-#endif
-
-        i->idx = skip_free_buckets(h, i->idx + 1);
-        if (i->idx != IDX_NIL)
-                i->next_key = bucket_at(h, i->idx)->key;
-        else
-                i->idx = IDX_NIL;
-
-        return idx;
-
-at_end:
-        i->idx = IDX_NIL;
-        return IDX_NIL;
-}
-
-static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
-        if (!h) {
-                i->idx = IDX_NIL;
-                return IDX_NIL;
-        }
-
-#if ENABLE_DEBUG_HASHMAP
-        if (i->idx == IDX_FIRST) {
-                i->put_count = h->debug.put_count;
-                i->rem_count = h->debug.rem_count;
-        } else {
-                /* While iterating, must not add any new entries */
-                assert(i->put_count == h->debug.put_count);
-                /* ... or remove entries other than the current one */
-                assert(i->rem_count == h->debug.rem_count ||
-                       (i->rem_count == h->debug.rem_count - 1 &&
-                        i->prev_idx == h->debug.last_rem_idx));
-                /* Reset our removals counter */
-                i->rem_count = h->debug.rem_count;
-        }
-#endif
-
-        return h->type == HASHMAP_TYPE_ORDERED ? hashmap_iterate_in_insertion_order((OrderedHashmap*) h, i)
-                                               : hashmap_iterate_in_internal_order(h, i);
-}
-
-bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
-        struct hashmap_base_entry *e;
-        void *data;
-        unsigned idx;
-
-        idx = hashmap_iterate_entry(h, i);
-        if (idx == IDX_NIL) {
-                if (value)
-                        *value = NULL;
-                if (key)
-                        *key = NULL;
-
-                return false;
-        }
-
-        e = bucket_at(h, idx);
-        data = entry_value(h, e);
-        if (value)
-                *value = data;
-        if (key)
-                *key = e->key;
-
-        return true;
-}
-
-#define HASHMAP_FOREACH_IDX(idx, h, i) \
-        for ((i) = ITERATOR_FIRST, (idx) = hashmap_iterate_entry((h), &(i)); \
-             (idx != IDX_NIL); \
-             (idx) = hashmap_iterate_entry((h), &(i)))
-
-IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h) {
-        IteratedCache *cache;
-
-        assert(h);
-        assert(!h->cached);
-
-        if (h->cached)
-                return NULL;
-
-        cache = new0(IteratedCache, 1);
-        if (!cache)
-                return NULL;
-
-        cache->hashmap = h;
-        h->cached = true;
-
-        return cache;
-}
-
-static void reset_direct_storage(HashmapBase *h) {
-        const struct hashmap_type_info *hi = &hashmap_type_info[h->type];
-        void *p;
-
-        assert(!h->has_indirect);
-
-        p = mempset(h->direct.storage, 0, hi->entry_size * hi->n_direct_buckets);
-        memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets);
-}
-
-static void shared_hash_key_initialize(void) {
-        random_bytes(shared_hash_key, sizeof(shared_hash_key));
-}
-
-static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type  HASHMAP_DEBUG_PARAMS) {
-        HashmapBase *h;
-        const struct hashmap_type_info *hi = &hashmap_type_info[type];
-        bool up;
-
-        up = mempool_enabled();
-
-        h = up ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
-        if (!h)
-                return NULL;
-
-        h->type = type;
-        h->from_pool = up;
-        h->hash_ops = hash_ops ?: &trivial_hash_ops;
-
-        if (type == HASHMAP_TYPE_ORDERED) {
-                OrderedHashmap *lh = (OrderedHashmap*)h;
-                lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
-        }
-
-        reset_direct_storage(h);
-
-        static pthread_once_t once = PTHREAD_ONCE_INIT;
-        assert_se(pthread_once(&once, shared_hash_key_initialize) == 0);
-
-#if ENABLE_DEBUG_HASHMAP
-        h->debug.func = func;
-        h->debug.file = file;
-        h->debug.line = line;
-        assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
-        LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug);
-        assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
-#endif
-
-        return h;
-}
-
-Hashmap *_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
-        return (Hashmap*)        hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN  HASHMAP_DEBUG_PASS_ARGS);
-}
-
-OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
-        return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED  HASHMAP_DEBUG_PASS_ARGS);
-}
-
-Set *_set_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
-        return (Set*)            hashmap_base_new(hash_ops, HASHMAP_TYPE_SET  HASHMAP_DEBUG_PASS_ARGS);
-}
-
-static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops,
-                                         enum HashmapType type  HASHMAP_DEBUG_PARAMS) {
-        HashmapBase *q;
-
-        assert(h);
-
-        if (*h)
-                return 0;
-
-        q = hashmap_base_new(hash_ops, type  HASHMAP_DEBUG_PASS_ARGS);
-        if (!q)
-                return -ENOMEM;
-
-        *h = q;
-        return 1;
-}
-
-int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
-        return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN  HASHMAP_DEBUG_PASS_ARGS);
-}
-
-int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
-        return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED  HASHMAP_DEBUG_PASS_ARGS);
-}
-
-int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS) {
-        return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET  HASHMAP_DEBUG_PASS_ARGS);
-}
-
-int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value  HASHMAP_DEBUG_PARAMS) {
-        int r;
-
-        r = _ordered_hashmap_ensure_allocated(h, hash_ops  HASHMAP_DEBUG_PASS_ARGS);
-        if (r < 0)
-                return r;
-
-        return ordered_hashmap_put(*h, key, value);
-}
-
-static void hashmap_free_no_clear(HashmapBase *h) {
-        assert(!h->has_indirect);
-        assert(h->n_direct_entries == 0);
-
-#if ENABLE_DEBUG_HASHMAP
-        assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
-        LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug);
-        assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
-#endif
-
-        if (h->from_pool) {
-                /* Ensure that the object didn't get migrated between threads. */
-                assert_se(is_main_thread());
-                mempool_free_tile(hashmap_type_info[h->type].mempool, h);
-        } else
-                free(h);
-}
-
-HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
-        if (h) {
-                _hashmap_clear(h, default_free_key, default_free_value);
-                hashmap_free_no_clear(h);
-        }
-
-        return NULL;
-}
-
-void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
-        free_func_t free_key, free_value;
-        if (!h)
-                return;
-
-        free_key = h->hash_ops->free_key ?: default_free_key;
-        free_value = h->hash_ops->free_value ?: default_free_value;
-
-        if (free_key || free_value) {
-
-                /* If destructor calls are defined, let's destroy things defensively: let's take the item out of the
-                 * hash table, and only then call the destructor functions. If these destructors then try to unregister
-                 * themselves from our hash table a second time, the entry is already gone. */
-
-                while (_hashmap_size(h) > 0) {
-                        void *k = NULL;
-                        void *v;
-
-                        v = _hashmap_first_key_and_value(h, true, &k);
-
-                        if (free_key)
-                                free_key(k);
-
-                        if (free_value)
-                                free_value(v);
-                }
-        }
-
-        if (h->has_indirect) {
-                free(h->indirect.storage);
-                h->has_indirect = false;
-        }
-
-        h->n_direct_entries = 0;
-        reset_direct_storage(h);
-
-        if (h->type == HASHMAP_TYPE_ORDERED) {
-                OrderedHashmap *lh = (OrderedHashmap*) h;
-                lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
-        }
-
-        base_set_dirty(h);
-}
-
-static int resize_buckets(HashmapBase *h, unsigned entries_add);
-
-/*
- * Finds an empty bucket to put an entry into, starting the scan at 'idx'.
- * Performs Robin Hood swaps as it goes. The entry to put must be placed
- * by the caller into swap slot IDX_PUT.
- * If used for in-place resizing, may leave a displaced entry in swap slot
- * IDX_PUT. Caller must rehash it next.
- * Returns: true if it left a displaced entry to rehash next in IDX_PUT,
- *          false otherwise.
- */
-static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
-                                   struct swap_entries *swap) {
-        dib_raw_t raw_dib, *dibs;
-        unsigned dib, distance;
-
-#if ENABLE_DEBUG_HASHMAP
-        h->debug.put_count++;
-#endif
-
-        dibs = dib_raw_ptr(h);
-
-        for (distance = 0; ; distance++) {
-                raw_dib = dibs[idx];
-                if (IN_SET(raw_dib, DIB_RAW_FREE, DIB_RAW_REHASH)) {
-                        if (raw_dib == DIB_RAW_REHASH)
-                                bucket_move_entry(h, swap, idx, IDX_TMP);
-
-                        if (h->has_indirect && h->indirect.idx_lowest_entry > idx)
-                                h->indirect.idx_lowest_entry = idx;
-
-                        bucket_set_dib(h, idx, distance);
-                        bucket_move_entry(h, swap, IDX_PUT, idx);
-                        if (raw_dib == DIB_RAW_REHASH) {
-                                bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
-                                return true;
-                        }
-
-                        return false;
-                }
-
-                dib = bucket_calculate_dib(h, idx, raw_dib);
-
-                if (dib < distance) {
-                        /* Found a wealthier entry. Go Robin Hood! */
-                        bucket_set_dib(h, idx, distance);
-
-                        /* swap the entries */
-                        bucket_move_entry(h, swap, idx, IDX_TMP);
-                        bucket_move_entry(h, swap, IDX_PUT, idx);
-                        bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
-
-                        distance = dib;
-                }
-
-                idx = next_idx(h, idx);
-        }
-}
-
-/*
- * Puts an entry into a hashmap, boldly - no check whether key already exists.
- * The caller must place the entry (only its key and value, not link indexes)
- * in swap slot IDX_PUT.
- * Caller must ensure: the key does not exist yet in the hashmap.
- *                     that resize is not needed if !may_resize.
- * Returns: 1 if entry was put successfully.
- *          -ENOMEM if may_resize==true and resize failed with -ENOMEM.
- *          Cannot return -ENOMEM if !may_resize.
- */
-static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
-                                   struct swap_entries *swap, bool may_resize) {
-        struct ordered_hashmap_entry *new_entry;
-        int r;
-
-        assert(idx < n_buckets(h));
-
-        new_entry = bucket_at_swap(swap, IDX_PUT);
-
-        if (may_resize) {
-                r = resize_buckets(h, 1);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        idx = bucket_hash(h, new_entry->p.b.key);
-        }
-        assert(n_entries(h) < n_buckets(h));
-
-        if (h->type == HASHMAP_TYPE_ORDERED) {
-                OrderedHashmap *lh = (OrderedHashmap*) h;
-
-                new_entry->iterate_next = IDX_NIL;
-                new_entry->iterate_previous = lh->iterate_list_tail;
-
-                if (lh->iterate_list_tail != IDX_NIL) {
-                        struct ordered_hashmap_entry *old_tail;
-
-                        old_tail = ordered_bucket_at(lh, lh->iterate_list_tail);
-                        assert(old_tail->iterate_next == IDX_NIL);
-                        old_tail->iterate_next = IDX_PUT;
-                }
-
-                lh->iterate_list_tail = IDX_PUT;
-                if (lh->iterate_list_head == IDX_NIL)
-                        lh->iterate_list_head = IDX_PUT;
-        }
-
-        assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
-
-        n_entries_inc(h);
-#if ENABLE_DEBUG_HASHMAP
-        h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h));
-#endif
-
-        base_set_dirty(h);
-
-        return 1;
-}
-#define hashmap_put_boldly(h, idx, swap, may_resize) \
-        hashmap_base_put_boldly(HASHMAP_BASE(h), idx, swap, may_resize)
-
-/*
- * Returns 0 if resize is not needed.
- *         1 if successfully resized.
- *         -ENOMEM on allocation failure.
- */
-static int resize_buckets(HashmapBase *h, unsigned entries_add) {
-        struct swap_entries swap;
-        void *new_storage;
-        dib_raw_t *old_dibs, *new_dibs;
-        const struct hashmap_type_info *hi;
-        unsigned idx, optimal_idx;
-        unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries;
-        uint8_t new_shift;
-        bool rehash_next;
-
-        assert(h);
-
-        hi = &hashmap_type_info[h->type];
-        new_n_entries = n_entries(h) + entries_add;
-
-        /* overflow? */
-        if (_unlikely_(new_n_entries < entries_add))
-                return -ENOMEM;
-
-        /* For direct storage we allow 100% load, because it's tiny. */
-        if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets)
-                return 0;
-
-        /*
-         * Load factor = n/m = 1 - (1/INV_KEEP_FREE).
-         * From it follows: m = n + n/(INV_KEEP_FREE - 1)
-         */
-        new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1);
-        /* overflow? */
-        if (_unlikely_(new_n_buckets < new_n_entries))
-                return -ENOMEM;
-
-        if (_unlikely_(new_n_buckets > UINT_MAX / (hi->entry_size + sizeof(dib_raw_t))))
-                return -ENOMEM;
-
-        old_n_buckets = n_buckets(h);
-
-        if (_likely_(new_n_buckets <= old_n_buckets))
-                return 0;
-
-        new_shift = log2u_round_up(MAX(
-                        new_n_buckets * (hi->entry_size + sizeof(dib_raw_t)),
-                        2 * sizeof(struct direct_storage)));
-
-        /* Realloc storage (buckets and DIB array). */
-        new_storage = realloc(h->has_indirect ? h->indirect.storage : NULL,
-                              1U << new_shift);
-        if (!new_storage)
-                return -ENOMEM;
-
-        /* Must upgrade direct to indirect storage. */
-        if (!h->has_indirect) {
-                memcpy(new_storage, h->direct.storage,
-                       old_n_buckets * (hi->entry_size + sizeof(dib_raw_t)));
-                h->indirect.n_entries = h->n_direct_entries;
-                h->indirect.idx_lowest_entry = 0;
-                h->n_direct_entries = 0;
-        }
-
-        /* Get a new hash key. If we've just upgraded to indirect storage,
-         * allow reusing a previously generated key. It's still a different key
-         * from the shared one that we used for direct storage. */
-        get_hash_key(h->indirect.hash_key, !h->has_indirect);
-
-        h->has_indirect = true;
-        h->indirect.storage = new_storage;
-        h->indirect.n_buckets = (1U << new_shift) /
-                                (hi->entry_size + sizeof(dib_raw_t));
-
-        old_dibs = (dib_raw_t*)((uint8_t*) new_storage + hi->entry_size * old_n_buckets);
-        new_dibs = dib_raw_ptr(h);
-
-        /*
-         * Move the DIB array to the new place, replacing valid DIB values with
-         * DIB_RAW_REHASH to indicate all of the used buckets need rehashing.
-         * Note: Overlap is not possible, because we have at least doubled the
-         * number of buckets and dib_raw_t is smaller than any entry type.
-         */
-        for (idx = 0; idx < old_n_buckets; idx++) {
-                assert(old_dibs[idx] != DIB_RAW_REHASH);
-                new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE
-                                                              : DIB_RAW_REHASH;
-        }
-
-        /* Zero the area of newly added entries (including the old DIB area) */
-        memzero(bucket_at(h, old_n_buckets),
-               (n_buckets(h) - old_n_buckets) * hi->entry_size);
-
-        /* The upper half of the new DIB array needs initialization */
-        memset(&new_dibs[old_n_buckets], DIB_RAW_INIT,
-               (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t));
-
-        /* Rehash entries that need it */
-        n_rehashed = 0;
-        for (idx = 0; idx < old_n_buckets; idx++) {
-                if (new_dibs[idx] != DIB_RAW_REHASH)
-                        continue;
-
-                optimal_idx = bucket_hash(h, bucket_at(h, idx)->key);
-
-                /*
-                 * Not much to do if by luck the entry hashes to its current
-                 * location. Just set its DIB.
-                 */
-                if (optimal_idx == idx) {
-                        new_dibs[idx] = 0;
-                        n_rehashed++;
-                        continue;
-                }
-
-                new_dibs[idx] = DIB_RAW_FREE;
-                bucket_move_entry(h, &swap, idx, IDX_PUT);
-                /* bucket_move_entry does not clear the source */
-                memzero(bucket_at(h, idx), hi->entry_size);
-
-                do {
-                        /*
-                         * Find the new bucket for the current entry. This may make
-                         * another entry homeless and load it into IDX_PUT.
-                         */
-                        rehash_next = hashmap_put_robin_hood(h, optimal_idx, &swap);
-                        n_rehashed++;
-
-                        /* Did the current entry displace another one? */
-                        if (rehash_next)
-                                optimal_idx = bucket_hash(h, bucket_at_swap(&swap, IDX_PUT)->p.b.key);
-                } while (rehash_next);
-        }
-
-        assert(n_rehashed == n_entries(h));
-
-        return 1;
-}
-
-/*
- * Finds an entry with a matching key
- * Returns: index of the found entry, or IDX_NIL if not found.
- */
-static unsigned base_bucket_scan(HashmapBase *h, unsigned idx, const void *key) {
-        struct hashmap_base_entry *e;
-        unsigned dib, distance;
-        dib_raw_t *dibs = dib_raw_ptr(h);
-
-        assert(idx < n_buckets(h));
-
-        for (distance = 0; ; distance++) {
-                if (dibs[idx] == DIB_RAW_FREE)
-                        return IDX_NIL;
-
-                dib = bucket_calculate_dib(h, idx, dibs[idx]);
-
-                if (dib < distance)
-                        return IDX_NIL;
-                if (dib == distance) {
-                        e = bucket_at(h, idx);
-                        if (h->hash_ops->compare(e->key, key) == 0)
-                                return idx;
-                }
-
-                idx = next_idx(h, idx);
-        }
-}
-#define bucket_scan(h, idx, key) base_bucket_scan(HASHMAP_BASE(h), idx, key)
-
-int hashmap_put(Hashmap *h, const void *key, void *value) {
-        struct swap_entries swap;
-        struct plain_hashmap_entry *e;
-        unsigned hash, idx;
-
-        assert(h);
-
-        hash = bucket_hash(h, key);
-        idx = bucket_scan(h, hash, key);
-        if (idx != IDX_NIL) {
-                e = plain_bucket_at(h, idx);
-                if (e->value == value)
-                        return 0;
-                return -EEXIST;
-        }
-
-        e = &bucket_at_swap(&swap, IDX_PUT)->p;
-        e->b.key = key;
-        e->value = value;
-        return hashmap_put_boldly(h, hash, &swap, true);
-}
-
-int set_put(Set *s, const void *key) {
-        struct swap_entries swap;
-        struct hashmap_base_entry *e;
-        unsigned hash, idx;
-
-        assert(s);
-
-        hash = bucket_hash(s, key);
-        idx = bucket_scan(s, hash, key);
-        if (idx != IDX_NIL)
-                return 0;
-
-        e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
-        e->key = key;
-        return hashmap_put_boldly(s, hash, &swap, true);
-}
-
-int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key  HASHMAP_DEBUG_PARAMS) {
-        int r;
-
-        r = _set_ensure_allocated(s, hash_ops  HASHMAP_DEBUG_PASS_ARGS);
-        if (r < 0)
-                return r;
-
-        return set_put(*s, key);
-}
-
-int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key  HASHMAP_DEBUG_PARAMS) {
-        int r;
-
-        r = _set_ensure_put(s, hash_ops, key  HASHMAP_DEBUG_PASS_ARGS);
-        if (r <= 0) {
-                if (hash_ops && hash_ops->free_key)
-                        hash_ops->free_key(key);
-                else
-                        free(key);
-        }
-
-        return r;
-}
-
-int hashmap_replace(Hashmap *h, const void *key, void *value) {
-        struct swap_entries swap;
-        struct plain_hashmap_entry *e;
-        unsigned hash, idx;
-
-        assert(h);
-
-        hash = bucket_hash(h, key);
-        idx = bucket_scan(h, hash, key);
-        if (idx != IDX_NIL) {
-                e = plain_bucket_at(h, idx);
-#if ENABLE_DEBUG_HASHMAP
-                /* Although the key is equal, the key pointer may have changed,
-                 * and this would break our assumption for iterating. So count
-                 * this operation as incompatible with iteration. */
-                if (e->b.key != key) {
-                        h->b.debug.put_count++;
-                        h->b.debug.rem_count++;
-                        h->b.debug.last_rem_idx = idx;
-                }
-#endif
-                e->b.key = key;
-                e->value = value;
-                hashmap_set_dirty(h);
-
-                return 0;
-        }
-
-        e = &bucket_at_swap(&swap, IDX_PUT)->p;
-        e->b.key = key;
-        e->value = value;
-        return hashmap_put_boldly(h, hash, &swap, true);
-}
-
-int hashmap_update(Hashmap *h, const void *key, void *value) {
-        struct plain_hashmap_entry *e;
-        unsigned hash, idx;
-
-        assert(h);
-
-        hash = bucket_hash(h, key);
-        idx = bucket_scan(h, hash, key);
-        if (idx == IDX_NIL)
-                return -ENOENT;
-
-        e = plain_bucket_at(h, idx);
-        e->value = value;
-        hashmap_set_dirty(h);
-
-        return 0;
-}
-
-void* _hashmap_get(HashmapBase *h, const void *key) {
-        struct hashmap_base_entry *e;
-        unsigned hash, idx;
-
-        if (!h)
-                return NULL;
-
-        hash = bucket_hash(h, key);
-        idx = bucket_scan(h, hash, key);
-        if (idx == IDX_NIL)
-                return NULL;
-
-        e = bucket_at(h, idx);
-        return entry_value(h, e);
-}
-
-void* hashmap_get2(Hashmap *h, const void *key, void **key2) {
-        struct plain_hashmap_entry *e;
-        unsigned hash, idx;
-
-        if (!h)
-                return NULL;
-
-        hash = bucket_hash(h, key);
-        idx = bucket_scan(h, hash, key);
-        if (idx == IDX_NIL)
-                return NULL;
-
-        e = plain_bucket_at(h, idx);
-        if (key2)
-                *key2 = (void*) e->b.key;
-
-        return e->value;
-}
-
-bool _hashmap_contains(HashmapBase *h, const void *key) {
-        unsigned hash;
-
-        if (!h)
-                return false;
-
-        hash = bucket_hash(h, key);
-        return bucket_scan(h, hash, key) != IDX_NIL;
-}
-
-void* _hashmap_remove(HashmapBase *h, const void *key) {
-        struct hashmap_base_entry *e;
-        unsigned hash, idx;
-        void *data;
-
-        if (!h)
-                return NULL;
-
-        hash = bucket_hash(h, key);
-        idx = bucket_scan(h, hash, key);
-        if (idx == IDX_NIL)
-                return NULL;
-
-        e = bucket_at(h, idx);
-        data = entry_value(h, e);
-        remove_entry(h, idx);
-
-        return data;
-}
-
-void* hashmap_remove2(Hashmap *h, const void *key, void **rkey) {
-        struct plain_hashmap_entry *e;
-        unsigned hash, idx;
-        void *data;
-
-        if (!h) {
-                if (rkey)
-                        *rkey = NULL;
-                return NULL;
-        }
-
-        hash = bucket_hash(h, key);
-        idx = bucket_scan(h, hash, key);
-        if (idx == IDX_NIL) {
-                if (rkey)
-                        *rkey = NULL;
-                return NULL;
-        }
-
-        e = plain_bucket_at(h, idx);
-        data = e->value;
-        if (rkey)
-                *rkey = (void*) e->b.key;
-
-        remove_entry(h, idx);
-
-        return data;
-}
-
-int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) {
-        struct swap_entries swap;
-        struct plain_hashmap_entry *e;
-        unsigned old_hash, new_hash, idx;
-
-        if (!h)
-                return -ENOENT;
-
-        old_hash = bucket_hash(h, old_key);
-        idx = bucket_scan(h, old_hash, old_key);
-        if (idx == IDX_NIL)
-                return -ENOENT;
-
-        new_hash = bucket_hash(h, new_key);
-        if (bucket_scan(h, new_hash, new_key) != IDX_NIL)
-                return -EEXIST;
-
-        remove_entry(h, idx);
-
-        e = &bucket_at_swap(&swap, IDX_PUT)->p;
-        e->b.key = new_key;
-        e->value = value;
-        assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1);
-
-        return 0;
-}
-
-int set_remove_and_put(Set *s, const void *old_key, const void *new_key) {
-        struct swap_entries swap;
-        struct hashmap_base_entry *e;
-        unsigned old_hash, new_hash, idx;
-
-        if (!s)
-                return -ENOENT;
-
-        old_hash = bucket_hash(s, old_key);
-        idx = bucket_scan(s, old_hash, old_key);
-        if (idx == IDX_NIL)
-                return -ENOENT;
-
-        new_hash = bucket_hash(s, new_key);
-        if (bucket_scan(s, new_hash, new_key) != IDX_NIL)
-                return -EEXIST;
-
-        remove_entry(s, idx);
-
-        e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
-        e->key = new_key;
-        assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1);
-
-        return 0;
-}
-
-int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) {
-        struct swap_entries swap;
-        struct plain_hashmap_entry *e;
-        unsigned old_hash, new_hash, idx_old, idx_new;
-
-        if (!h)
-                return -ENOENT;
-
-        old_hash = bucket_hash(h, old_key);
-        idx_old = bucket_scan(h, old_hash, old_key);
-        if (idx_old == IDX_NIL)
-                return -ENOENT;
-
-        old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key;
-
-        new_hash = bucket_hash(h, new_key);
-        idx_new = bucket_scan(h, new_hash, new_key);
-        if (idx_new != IDX_NIL)
-                if (idx_old != idx_new) {
-                        remove_entry(h, idx_new);
-                        /* Compensate for a possible backward shift. */
-                        if (old_key != bucket_at(HASHMAP_BASE(h), idx_old)->key)
-                                idx_old = prev_idx(HASHMAP_BASE(h), idx_old);
-                        assert(old_key == bucket_at(HASHMAP_BASE(h), idx_old)->key);
-                }
-
-        remove_entry(h, idx_old);
-
-        e = &bucket_at_swap(&swap, IDX_PUT)->p;
-        e->b.key = new_key;
-        e->value = value;
-        assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1);
-
-        return 0;
-}
-
-void* _hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
-        struct hashmap_base_entry *e;
-        unsigned hash, idx;
-
-        if (!h)
-                return NULL;
-
-        hash = bucket_hash(h, key);
-        idx = bucket_scan(h, hash, key);
-        if (idx == IDX_NIL)
-                return NULL;
-
-        e = bucket_at(h, idx);
-        if (entry_value(h, e) != value)
-                return NULL;
-
-        remove_entry(h, idx);
-
-        return value;
-}
-
-static unsigned find_first_entry(HashmapBase *h) {
-        Iterator i = ITERATOR_FIRST;
-
-        if (!h || !n_entries(h))
-                return IDX_NIL;
-
-        return hashmap_iterate_entry(h, &i);
-}
-
-void* _hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
-        struct hashmap_base_entry *e;
-        void *key, *data;
-        unsigned idx;
-
-        idx = find_first_entry(h);
-        if (idx == IDX_NIL) {
-                if (ret_key)
-                        *ret_key = NULL;
-                return NULL;
-        }
-
-        e = bucket_at(h, idx);
-        key = (void*) e->key;
-        data = entry_value(h, e);
-
-        if (remove)
-                remove_entry(h, idx);
-
-        if (ret_key)
-                *ret_key = key;
-
-        return data;
-}
-
-unsigned _hashmap_size(HashmapBase *h) {
-        if (!h)
-                return 0;
-
-        return n_entries(h);
-}
-
-unsigned _hashmap_buckets(HashmapBase *h) {
-        if (!h)
-                return 0;
-
-        return n_buckets(h);
-}
-
-int _hashmap_merge(Hashmap *h, Hashmap *other) {
-        Iterator i;
-        unsigned idx;
-
-        assert(h);
-
-        HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
-                struct plain_hashmap_entry *pe = plain_bucket_at(other, idx);
-                int r;
-
-                r = hashmap_put(h, pe->b.key, pe->value);
-                if (r < 0 && r != -EEXIST)
-                        return r;
-        }
-
-        return 0;
-}
-
-int set_merge(Set *s, Set *other) {
-        Iterator i;
-        unsigned idx;
-
-        assert(s);
-
-        HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
-                struct set_entry *se = set_bucket_at(other, idx);
-                int r;
-
-                r = set_put(s, se->b.key);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-int _hashmap_reserve(HashmapBase *h, unsigned entries_add) {
-        int r;
-
-        assert(h);
-
-        r = resize_buckets(h, entries_add);
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-/*
- * The same as hashmap_merge(), but every new item from other is moved to h.
- * Keys already in h are skipped and stay in other.
- * Returns: 0 on success.
- *          -ENOMEM on alloc failure, in which case no move has been done.
- */
-int _hashmap_move(HashmapBase *h, HashmapBase *other) {
-        struct swap_entries swap;
-        struct hashmap_base_entry *e, *n;
-        Iterator i;
-        unsigned idx;
-        int r;
-
-        assert(h);
-
-        if (!other)
-                return 0;
-
-        assert(other->type == h->type);
-
-        /*
-         * This reserves buckets for the worst case, where none of other's
-         * entries are yet present in h. This is preferable to risking
-         * an allocation failure in the middle of the moving and having to
-         * rollback or return a partial result.
-         */
-        r = resize_buckets(h, n_entries(other));
-        if (r < 0)
-                return r;
-
-        HASHMAP_FOREACH_IDX(idx, other, i) {
-                unsigned h_hash;
-
-                e = bucket_at(other, idx);
-                h_hash = bucket_hash(h, e->key);
-                if (bucket_scan(h, h_hash, e->key) != IDX_NIL)
-                        continue;
-
-                n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
-                n->key = e->key;
-                if (h->type != HASHMAP_TYPE_SET)
-                        ((struct plain_hashmap_entry*) n)->value =
-                                ((struct plain_hashmap_entry*) e)->value;
-                assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1);
-
-                remove_entry(other, idx);
-        }
-
-        return 0;
-}
-
-int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
-        struct swap_entries swap;
-        unsigned h_hash, other_hash, idx;
-        struct hashmap_base_entry *e, *n;
-        int r;
-
-        assert(h);
-
-        h_hash = bucket_hash(h, key);
-        if (bucket_scan(h, h_hash, key) != IDX_NIL)
-                return -EEXIST;
-
-        if (!other)
-                return -ENOENT;
-
-        assert(other->type == h->type);
-
-        other_hash = bucket_hash(other, key);
-        idx = bucket_scan(other, other_hash, key);
-        if (idx == IDX_NIL)
-                return -ENOENT;
-
-        e = bucket_at(other, idx);
-
-        n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
-        n->key = e->key;
-        if (h->type != HASHMAP_TYPE_SET)
-                ((struct plain_hashmap_entry*) n)->value =
-                        ((struct plain_hashmap_entry*) e)->value;
-        r = hashmap_put_boldly(h, h_hash, &swap, true);
-        if (r < 0)
-                return r;
-
-        remove_entry(other, idx);
-        return 0;
-}
-
-HashmapBase* _hashmap_copy(HashmapBase *h  HASHMAP_DEBUG_PARAMS) {
-        HashmapBase *copy;
-        int r;
-
-        assert(h);
-
-        copy = hashmap_base_new(h->hash_ops, h->type  HASHMAP_DEBUG_PASS_ARGS);
-        if (!copy)
-                return NULL;
-
-        switch (h->type) {
-        case HASHMAP_TYPE_PLAIN:
-        case HASHMAP_TYPE_ORDERED:
-                r = hashmap_merge((Hashmap*)copy, (Hashmap*)h);
-                break;
-        case HASHMAP_TYPE_SET:
-                r = set_merge((Set*)copy, (Set*)h);
-                break;
-        default:
-                assert_not_reached("Unknown hashmap type");
-        }
-
-        if (r < 0)
-                return _hashmap_free(copy, false, false);
-
-        return copy;
-}
-
-char** _hashmap_get_strv(HashmapBase *h) {
-        char **sv;
-        Iterator i;
-        unsigned idx, n;
-
-        sv = new(char*, n_entries(h)+1);
-        if (!sv)
-                return NULL;
-
-        n = 0;
-        HASHMAP_FOREACH_IDX(idx, h, i)
-                sv[n++] = entry_value(h, bucket_at(h, idx));
-        sv[n] = NULL;
-
-        return sv;
-}
-
-void* ordered_hashmap_next(OrderedHashmap *h, const void *key) {
-        struct ordered_hashmap_entry *e;
-        unsigned hash, idx;
-
-        if (!h)
-                return NULL;
-
-        hash = bucket_hash(h, key);
-        idx = bucket_scan(h, hash, key);
-        if (idx == IDX_NIL)
-                return NULL;
-
-        e = ordered_bucket_at(h, idx);
-        if (e->iterate_next == IDX_NIL)
-                return NULL;
-        return ordered_bucket_at(h, e->iterate_next)->p.value;
-}
-
-int set_consume(Set *s, void *value) {
-        int r;
-
-        assert(s);
-        assert(value);
-
-        r = set_put(s, value);
-        if (r <= 0)
-                free(value);
-
-        return r;
-}
-
-#if 0 /* NM_IGNORED */
-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, hash_ops  HASHMAP_DEBUG_PASS_ARGS);
-        if (r < 0)
-                return r;
-
-        _cleanup_free_ char *kdup = NULL, *vdup = NULL;
-
-        kdup = strdup(k);
-        if (!kdup)
-                return -ENOMEM;
-
-        if (v) {
-                vdup = strdup(v);
-                if (!vdup)
-                        return -ENOMEM;
-        }
-
-        r = hashmap_put(*h, kdup, vdup);
-        if (r < 0) {
-                if (r == -EEXIST && streq_ptr(v, hashmap_get(*h, kdup)))
-                        return 0;
-                return r;
-        }
-
-        /* 0 with non-null vdup would mean vdup is already in the hashmap, which cannot be */
-        assert(vdup == NULL || r > 0);
-        if (r > 0)
-                kdup = vdup = NULL;
-
-        return r;
-}
-#endif /* NM_IGNORED */
-
-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, hash_ops  HASHMAP_DEBUG_PASS_ARGS);
-        if (r < 0)
-                return r;
-
-        if (set_contains(*s, (char*) p))
-                return 0;
-
-        c = strdup(p);
-        if (!c)
-                return -ENOMEM;
-
-        return set_consume(*s, c);
-}
-
-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_full(s, hash_ops, *i  HASHMAP_DEBUG_PASS_ARGS);
-                if (r < 0)
-                        return r;
-
-                n += r;
-        }
-
-        return n;
-}
-
-int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) {
-        const char *p = v;
-        int r;
-
-        assert(s);
-        assert(v);
-
-        for (;;) {
-                char *word;
-
-                r = extract_first_word(&p, &word, separators, flags);
-                if (r <= 0)
-                        return r;
-
-                r = set_consume(s, word);
-                if (r < 0)
-                        return r;
-        }
-}
-
-/* expand the cachemem if needed, return true if newly (re)activated. */
-static int cachemem_maintain(CacheMem *mem, unsigned size) {
-        assert(mem);
-
-        if (!GREEDY_REALLOC(mem->ptr, mem->n_allocated, size)) {
-                if (size > 0)
-                        return -ENOMEM;
-        }
-
-        if (!mem->active) {
-                mem->active = true;
-                return true;
-        }
-
-        return false;
-}
-
-int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries) {
-        bool sync_keys = false, sync_values = false;
-        unsigned size;
-        int r;
-
-        assert(cache);
-        assert(cache->hashmap);
-
-        size = n_entries(cache->hashmap);
-
-        if (res_keys) {
-                r = cachemem_maintain(&cache->keys, size);
-                if (r < 0)
-                        return r;
-
-                sync_keys = r;
-        } else
-                cache->keys.active = false;
-
-        if (res_values) {
-                r = cachemem_maintain(&cache->values, size);
-                if (r < 0)
-                        return r;
-
-                sync_values = r;
-        } else
-                cache->values.active = false;
-
-        if (cache->hashmap->dirty) {
-                if (cache->keys.active)
-                        sync_keys = true;
-                if (cache->values.active)
-                        sync_values = true;
-
-                cache->hashmap->dirty = false;
-        }
-
-        if (sync_keys || sync_values) {
-                unsigned i, idx;
-                Iterator iter;
-
-                i = 0;
-                HASHMAP_FOREACH_IDX(idx, cache->hashmap, iter) {
-                        struct hashmap_base_entry *e;
-
-                        e = bucket_at(cache->hashmap, idx);
-
-                        if (sync_keys)
-                                cache->keys.ptr[i] = e->key;
-                        if (sync_values)
-                                cache->values.ptr[i] = entry_value(cache->hashmap, e);
-                        i++;
-                }
-        }
-
-        if (res_keys)
-                *res_keys = cache->keys.ptr;
-        if (res_values)
-                *res_values = cache->values.ptr;
-        if (res_n_entries)
-                *res_n_entries = size;
-
-        return 0;
-}
-
-IteratedCache* iterated_cache_free(IteratedCache *cache) {
-        if (cache) {
-                free(cache->keys.ptr);
-                free(cache->values.ptr);
-        }
-
-        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
deleted file mode 100644
index e9944837..00000000
--- a/shared/systemd/src/basic/hashmap.h
+++ /dev/null
@@ -1,449 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <limits.h>
-#include <stdbool.h>
-#include <stddef.h>
-
-#include "hash-funcs.h"
-#include "macro.h"
-#include "util.h"
-
-/*
- * A hash table implementation. As a minor optimization a NULL hashmap object
- * will be treated as empty hashmap for all read operations. That way it is not
- * necessary to instantiate an object for each Hashmap use.
- *
- * If ENABLE_DEBUG_HASHMAP is defined (by configuring with -Ddebug-extra=hashmap),
- * the implementation will:
- * - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
- * - perform extra checks for invalid use of iterators
- */
-
-#define HASH_KEY_SIZE 16
-
-typedef void* (*hashmap_destroy_t)(void *p);
-
-/* The base type for all hashmap and set types. Many functions in the implementation take (HashmapBase*)
- * parameters and are run-time polymorphic, though the API is not meant to be polymorphic (do not call
- * underscore-prefixed functions directly). */
-typedef struct HashmapBase HashmapBase;
-
-/* Specific hashmap/set types */
-typedef struct Hashmap Hashmap;               /* Maps keys to values */
-typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */
-typedef struct Set Set;                       /* Stores just keys */
-
-typedef struct IteratedCache IteratedCache;   /* Caches the iterated order of one of the above */
-
-/* Ideally the Iterator would be an opaque struct, but it is instantiated
- * by hashmap users, so the definition has to be here. Do not use its fields
- * directly. */
-typedef struct {
-        unsigned idx;         /* index of an entry to be iterated next */
-        const void *next_key; /* expected value of that entry's key pointer */
-#if ENABLE_DEBUG_HASHMAP
-        unsigned put_count;   /* hashmap's put_count recorded at start of iteration */
-        unsigned rem_count;   /* hashmap's rem_count in previous iteration */
-        unsigned prev_idx;    /* idx in previous iteration */
-#endif
-} Iterator;
-
-#define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
-#define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL })
-
-/* Macros for type checking */
-#define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \
-        (__builtin_types_compatible_p(typeof(h), HashmapBase*) || \
-         __builtin_types_compatible_p(typeof(h), Hashmap*) || \
-         __builtin_types_compatible_p(typeof(h), OrderedHashmap*) || \
-         __builtin_types_compatible_p(typeof(h), Set*))
-
-#define PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h) \
-        (__builtin_types_compatible_p(typeof(h), Hashmap*) || \
-         __builtin_types_compatible_p(typeof(h), OrderedHashmap*)) \
-
-#define HASHMAP_BASE(h) \
-        __builtin_choose_expr(PTR_COMPATIBLE_WITH_HASHMAP_BASE(h), \
-                (HashmapBase*)(h), \
-                (void)0)
-
-#define PLAIN_HASHMAP(h) \
-        __builtin_choose_expr(PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h), \
-                (Hashmap*)(h), \
-                (void)0)
-
-#if ENABLE_DEBUG_HASHMAP
-# define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line
-# define HASHMAP_DEBUG_SRC_ARGS   , __func__, PROJECT_FILE, __LINE__
-# define HASHMAP_DEBUG_PASS_ARGS   , func, file, line
-#else
-# define HASHMAP_DEBUG_PARAMS
-# define HASHMAP_DEBUG_SRC_ARGS
-# define HASHMAP_DEBUG_PASS_ARGS
-#endif
-
-Hashmap* _hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
-OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
-#define hashmap_new(ops) _hashmap_new(ops  HASHMAP_DEBUG_SRC_ARGS)
-#define ordered_hashmap_new(ops) _ordered_hashmap_new(ops  HASHMAP_DEBUG_SRC_ARGS)
-
-#define hashmap_free_and_replace(a, b)          \
-        ({                                      \
-                hashmap_free(a);                \
-                (a) = (b);                      \
-                (b) = NULL;                     \
-                0;                              \
-        })
-
-HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
-static inline Hashmap* hashmap_free(Hashmap *h) {
-        return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
-}
-static inline OrderedHashmap* ordered_hashmap_free(OrderedHashmap *h) {
-        return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
-}
-
-static inline Hashmap* hashmap_free_free(Hashmap *h) {
-        return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free);
-}
-static inline OrderedHashmap* ordered_hashmap_free_free(OrderedHashmap *h) {
-        return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free);
-}
-
-static inline Hashmap* hashmap_free_free_key(Hashmap *h) {
-        return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL);
-}
-static inline OrderedHashmap* ordered_hashmap_free_free_key(OrderedHashmap *h) {
-        return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL);
-}
-
-static inline Hashmap* hashmap_free_free_free(Hashmap *h) {
-        return (void*) _hashmap_free(HASHMAP_BASE(h), free, free);
-}
-static inline OrderedHashmap* ordered_hashmap_free_free_free(OrderedHashmap *h) {
-        return (void*) _hashmap_free(HASHMAP_BASE(h), free, free);
-}
-
-IteratedCache* iterated_cache_free(IteratedCache *cache);
-int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries);
-
-HashmapBase* _hashmap_copy(HashmapBase *h  HASHMAP_DEBUG_PARAMS);
-#define hashmap_copy(h) ((Hashmap*) _hashmap_copy(HASHMAP_BASE(h)  HASHMAP_DEBUG_SRC_ARGS))
-#define ordered_hashmap_copy(h) ((OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h)  HASHMAP_DEBUG_SRC_ARGS))
-
-int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
-int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops  HASHMAP_DEBUG_PARAMS);
-#define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops  HASHMAP_DEBUG_SRC_ARGS)
-#define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops  HASHMAP_DEBUG_SRC_ARGS)
-
-int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value  HASHMAP_DEBUG_PARAMS);
-#define ordered_hashmap_ensure_put(s, ops, key, value) _ordered_hashmap_ensure_put(s, ops, key, value  HASHMAP_DEBUG_SRC_ARGS)
-
-IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h);
-static inline IteratedCache* hashmap_iterated_cache_new(Hashmap *h) {
-        return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
-}
-static inline IteratedCache* ordered_hashmap_iterated_cache_new(OrderedHashmap *h) {
-        return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
-}
-
-int hashmap_put(Hashmap *h, const void *key, void *value);
-static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) {
-        return hashmap_put(PLAIN_HASHMAP(h), key, value);
-}
-
-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) {
-        return hashmap_update(PLAIN_HASHMAP(h), key, value);
-}
-
-int hashmap_replace(Hashmap *h, const void *key, void *value);
-static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, void *value) {
-        return hashmap_replace(PLAIN_HASHMAP(h), key, value);
-}
-
-void* _hashmap_get(HashmapBase *h, const void *key);
-static inline void *hashmap_get(Hashmap *h, const void *key) {
-        return _hashmap_get(HASHMAP_BASE(h), key);
-}
-static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) {
-        return _hashmap_get(HASHMAP_BASE(h), key);
-}
-
-void* hashmap_get2(Hashmap *h, const void *key, void **rkey);
-static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) {
-        return hashmap_get2(PLAIN_HASHMAP(h), key, rkey);
-}
-
-bool _hashmap_contains(HashmapBase *h, const void *key);
-static inline bool hashmap_contains(Hashmap *h, const void *key) {
-        return _hashmap_contains(HASHMAP_BASE(h), key);
-}
-static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) {
-        return _hashmap_contains(HASHMAP_BASE(h), key);
-}
-
-void* _hashmap_remove(HashmapBase *h, const void *key);
-static inline void *hashmap_remove(Hashmap *h, const void *key) {
-        return _hashmap_remove(HASHMAP_BASE(h), key);
-}
-static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) {
-        return _hashmap_remove(HASHMAP_BASE(h), key);
-}
-
-void* hashmap_remove2(Hashmap *h, const void *key, void **rkey);
-static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) {
-        return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey);
-}
-
-void* _hashmap_remove_value(HashmapBase *h, const void *key, void *value);
-static inline void *hashmap_remove_value(Hashmap *h, const void *key, void *value) {
-        return _hashmap_remove_value(HASHMAP_BASE(h), key, value);
-}
-
-static inline void* ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
-        return hashmap_remove_value(PLAIN_HASHMAP(h), key, value);
-}
-
-int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value);
-static inline int ordered_hashmap_remove_and_put(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) {
-        return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, value);
-}
-
-int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value);
-static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) {
-        return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, value);
-}
-
-/* Since merging data from a OrderedHashmap into a Hashmap or vice-versa
- * should just work, allow this by having looser type-checking here. */
-int _hashmap_merge(Hashmap *h, Hashmap *other);
-#define hashmap_merge(h, other) _hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
-#define ordered_hashmap_merge(h, other) hashmap_merge(h, other)
-
-int _hashmap_reserve(HashmapBase *h, unsigned entries_add);
-static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) {
-        return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
-}
-static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) {
-        return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
-}
-
-int _hashmap_move(HashmapBase *h, HashmapBase *other);
-/* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */
-static inline int hashmap_move(Hashmap *h, Hashmap *other) {
-        return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
-}
-static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) {
-        return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
-}
-
-int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
-static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
-        return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
-}
-static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) {
-        return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
-}
-
-unsigned _hashmap_size(HashmapBase *h) _pure_;
-static inline unsigned hashmap_size(Hashmap *h) {
-        return _hashmap_size(HASHMAP_BASE(h));
-}
-static inline unsigned ordered_hashmap_size(OrderedHashmap *h) {
-        return _hashmap_size(HASHMAP_BASE(h));
-}
-
-static inline bool hashmap_isempty(Hashmap *h) {
-        return hashmap_size(h) == 0;
-}
-static inline bool ordered_hashmap_isempty(OrderedHashmap *h) {
-        return ordered_hashmap_size(h) == 0;
-}
-
-unsigned _hashmap_buckets(HashmapBase *h) _pure_;
-static inline unsigned hashmap_buckets(Hashmap *h) {
-        return _hashmap_buckets(HASHMAP_BASE(h));
-}
-static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) {
-        return _hashmap_buckets(HASHMAP_BASE(h));
-}
-
-bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key);
-static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) {
-        return _hashmap_iterate(HASHMAP_BASE(h), i, value, key);
-}
-static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) {
-        return _hashmap_iterate(HASHMAP_BASE(h), i, value, key);
-}
-
-void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
-static inline void hashmap_clear(Hashmap *h) {
-        _hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
-}
-static inline void ordered_hashmap_clear(OrderedHashmap *h) {
-        _hashmap_clear(HASHMAP_BASE(h), NULL, NULL);
-}
-
-static inline void hashmap_clear_free(Hashmap *h) {
-        _hashmap_clear(HASHMAP_BASE(h), NULL, free);
-}
-static inline void ordered_hashmap_clear_free(OrderedHashmap *h) {
-        _hashmap_clear(HASHMAP_BASE(h), NULL, free);
-}
-
-static inline void hashmap_clear_free_key(Hashmap *h) {
-        _hashmap_clear(HASHMAP_BASE(h), free, NULL);
-}
-static inline void ordered_hashmap_clear_free_key(OrderedHashmap *h) {
-        _hashmap_clear(HASHMAP_BASE(h), free, NULL);
-}
-
-static inline void hashmap_clear_free_free(Hashmap *h) {
-        _hashmap_clear(HASHMAP_BASE(h), free, free);
-}
-static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
-        _hashmap_clear(HASHMAP_BASE(h), free, free);
-}
-
-/*
- * Note about all *_first*() functions
- *
- * For plain Hashmaps and Sets the order of entries is undefined.
- * The functions find whatever entry is first in the implementation
- * internal order.
- *
- * Only for OrderedHashmaps the order is well defined and finding
- * the first entry is O(1).
- */
-
-void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key);
-static inline void *hashmap_steal_first_key_and_value(Hashmap *h, void **ret) {
-        return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
-}
-static inline void *ordered_hashmap_steal_first_key_and_value(OrderedHashmap *h, void **ret) {
-        return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret);
-}
-static inline void *hashmap_first_key_and_value(Hashmap *h, void **ret) {
-        return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
-}
-static inline void *ordered_hashmap_first_key_and_value(OrderedHashmap *h, void **ret) {
-        return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret);
-}
-
-static inline void *hashmap_steal_first(Hashmap *h) {
-        return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
-}
-static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) {
-        return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL);
-}
-static inline void *hashmap_first(Hashmap *h) {
-        return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
-}
-static inline void *ordered_hashmap_first(OrderedHashmap *h) {
-        return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL);
-}
-
-static inline void *_hashmap_first_key(HashmapBase *h, bool remove) {
-        void *key = NULL;
-
-        (void) _hashmap_first_key_and_value(HASHMAP_BASE(h), remove, &key);
-        return key;
-}
-static inline void *hashmap_steal_first_key(Hashmap *h) {
-        return _hashmap_first_key(HASHMAP_BASE(h), true);
-}
-static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) {
-        return _hashmap_first_key(HASHMAP_BASE(h), true);
-}
-static inline void *hashmap_first_key(Hashmap *h) {
-        return _hashmap_first_key(HASHMAP_BASE(h), false);
-}
-static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
-        return _hashmap_first_key(HASHMAP_BASE(h), false);
-}
-
-#define hashmap_clear_with_destructor(_s, _f)                   \
-        ({                                                      \
-                void *_item;                                    \
-                while ((_item = hashmap_steal_first(_s)))       \
-                        _f(_item);                              \
-        })
-#define hashmap_free_with_destructor(_s, _f)                    \
-        ({                                                      \
-                hashmap_clear_with_destructor(_s, _f);          \
-                hashmap_free(_s);                               \
-        })
-#define ordered_hashmap_clear_with_destructor(_s, _f)                   \
-        ({                                                              \
-                void *_item;                                            \
-                while ((_item = ordered_hashmap_steal_first(_s)))       \
-                        _f(_item);                                      \
-        })
-#define ordered_hashmap_free_with_destructor(_s, _f)                    \
-        ({                                                              \
-                ordered_hashmap_clear_with_destructor(_s, _f);          \
-                ordered_hashmap_free(_s);                               \
-        })
-
-/* no hashmap_next */
-void* ordered_hashmap_next(OrderedHashmap *h, const void *key);
-
-char** _hashmap_get_strv(HashmapBase *h);
-static inline char** hashmap_get_strv(Hashmap *h) {
-        return _hashmap_get_strv(HASHMAP_BASE(h));
-}
-static inline char** ordered_hashmap_get_strv(OrderedHashmap *h) {
-        return _hashmap_get_strv(HASHMAP_BASE(h));
-}
-
-/*
- * Hashmaps are iterated in unpredictable order.
- * OrderedHashmaps are an exception to this. They are iterated in the order
- * the entries were inserted.
- * It is safe to remove the current entry.
- */
-#define _HASHMAP_FOREACH(e, h, i) \
-        for (Iterator i = ITERATOR_FIRST; hashmap_iterate((h), &i, (void**)&(e), NULL); )
-#define HASHMAP_FOREACH(e, h) \
-        _HASHMAP_FOREACH(e, h, UNIQ_T(i, UNIQ))
-
-#define _ORDERED_HASHMAP_FOREACH(e, h, i) \
-        for (Iterator i = ITERATOR_FIRST; ordered_hashmap_iterate((h), &i, (void**)&(e), NULL); )
-#define ORDERED_HASHMAP_FOREACH(e, h) \
-        _ORDERED_HASHMAP_FOREACH(e, h, UNIQ_T(i, UNIQ))
-
-#define _HASHMAP_FOREACH_KEY(e, k, h, i) \
-        for (Iterator i = ITERATOR_FIRST; hashmap_iterate((h), &i, (void**)&(e), (const void**) &(k)); )
-#define HASHMAP_FOREACH_KEY(e, k, h) \
-        _HASHMAP_FOREACH_KEY(e, k, h, UNIQ_T(i, UNIQ))
-
-#define _ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \
-        for (Iterator i = ITERATOR_FIRST; ordered_hashmap_iterate((h), &i, (void**)&(e), (const void**) &(k)); )
-#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h) \
-        _ORDERED_HASHMAP_FOREACH_KEY(e, k, h, UNIQ_T(i, UNIQ))
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
-DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free);
-DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_key);
-DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free);
-DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free);
-DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free);
-DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_key);
-DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free);
-
-#define _cleanup_hashmap_free_ _cleanup_(hashmap_freep)
-#define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep)
-#define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep)
-#define _cleanup_ordered_hashmap_free_ _cleanup_(ordered_hashmap_freep)
-#define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep)
-#define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep)
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(IteratedCache*, iterated_cache_free);
-
-#define _cleanup_iterated_cache_free_ _cleanup_(iterated_cache_freep)
diff --git a/shared/systemd/src/basic/hexdecoct.c b/shared/systemd/src/basic/hexdecoct.c
deleted file mode 100644
index 78930b32..00000000
--- a/shared/systemd/src/basic/hexdecoct.c
+++ /dev/null
@@ -1,869 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "alloc-util.h"
-#include "hexdecoct.h"
-#include "macro.h"
-#include "memory-util.h"
-#include "string-util.h"
-
-char octchar(int x) {
-        return '0' + (x & 7);
-}
-
-int unoctchar(char c) {
-
-        if (c >= '0' && c <= '7')
-                return c - '0';
-
-        return -EINVAL;
-}
-
-char decchar(int x) {
-        return '0' + (x % 10);
-}
-
-int undecchar(char c) {
-
-        if (c >= '0' && c <= '9')
-                return c - '0';
-
-        return -EINVAL;
-}
-
-char hexchar(int x) {
-        static const char table[16] = "0123456789abcdef";
-
-        return table[x & 15];
-}
-
-int unhexchar(char c) {
-
-        if (c >= '0' && c <= '9')
-                return c - '0';
-
-        if (c >= 'a' && c <= 'f')
-                return c - 'a' + 10;
-
-        if (c >= 'A' && c <= 'F')
-                return c - 'A' + 10;
-
-        return -EINVAL;
-}
-
-char *hexmem(const void *p, size_t l) {
-        const uint8_t *x;
-        char *r, *z;
-
-        z = r = new(char, l * 2 + 1);
-        if (!r)
-                return NULL;
-
-        for (x = p; x < (const uint8_t*) p + l; x++) {
-                *(z++) = hexchar(*x >> 4);
-                *(z++) = hexchar(*x & 15);
-        }
-
-        *z = 0;
-        return r;
-}
-
-static int unhex_next(const char **p, size_t *l) {
-        int r;
-
-        assert(p);
-        assert(l);
-
-        /* Find the next non-whitespace character, and decode it. We
-         * greedily skip all preceding and all following whitespace. */
-
-        for (;;) {
-                if (*l == 0)
-                        return -EPIPE;
-
-                if (!strchr(WHITESPACE, **p))
-                        break;
-
-                /* Skip leading whitespace */
-                (*p)++, (*l)--;
-        }
-
-        r = unhexchar(**p);
-        if (r < 0)
-                return r;
-
-        for (;;) {
-                (*p)++, (*l)--;
-
-                if (*l == 0 || !strchr(WHITESPACE, **p))
-                        break;
-
-                /* Skip following whitespace */
-        }
-
-        return r;
-}
-
-int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_len) {
-        _cleanup_free_ uint8_t *buf = NULL;
-        size_t buf_size;
-        const char *x;
-        uint8_t *z;
-        int r;
-
-        assert(ret);
-        assert(ret_len);
-        assert(p || l == 0);
-
-        if (l == (size_t) -1)
-                l = strlen(p);
-
-        /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
-        buf_size = (l + 1) / 2 + 1;
-        buf = malloc(buf_size);
-        if (!buf)
-                return -ENOMEM;
-
-        for (x = p, z = buf;;) {
-                int a, b;
-
-                a = unhex_next(&x, &l);
-                if (a == -EPIPE) /* End of string */
-                        break;
-                if (a < 0) {
-                        r = a;
-                        goto on_failure;
-                }
-
-                b = unhex_next(&x, &l);
-                if (b < 0) {
-                        r = b;
-                        goto on_failure;
-                }
-
-                *(z++) = (uint8_t) a << 4 | (uint8_t) b;
-        }
-
-        *z = 0;
-
-        *ret_len = (size_t) (z - buf);
-        *ret = TAKE_PTR(buf);
-
-        return 0;
-
-on_failure:
-        if (secure)
-                explicit_bzero_safe(buf, buf_size);
-
-        return r;
-}
-
-#if 0 /* NM_IGNORED */
-/* https://tools.ietf.org/html/rfc4648#section-6
- * Notice that base32hex differs from base32 in the alphabet it uses.
- * The distinction is that the base32hex representation preserves the
- * order of the underlying data when compared as bytestrings, this is
- * useful when representing NSEC3 hashes, as one can then verify the
- * order of hashes directly from their representation. */
-char base32hexchar(int x) {
-        static const char table[32] = "0123456789"
-                                      "ABCDEFGHIJKLMNOPQRSTUV";
-
-        return table[x & 31];
-}
-
-int unbase32hexchar(char c) {
-        unsigned offset;
-
-        if (c >= '0' && c <= '9')
-                return c - '0';
-
-        offset = '9' - '0' + 1;
-
-        if (c >= 'A' && c <= 'V')
-                return c - 'A' + offset;
-
-        return -EINVAL;
-}
-
-char *base32hexmem(const void *p, size_t l, bool padding) {
-        char *r, *z;
-        const uint8_t *x;
-        size_t len;
-
-        assert(p || l == 0);
-
-        if (padding)
-                /* five input bytes makes eight output bytes, padding is added so we must round up */
-                len = 8 * (l + 4) / 5;
-        else {
-                /* same, but round down as there is no padding */
-                len = 8 * l / 5;
-
-                switch (l % 5) {
-                case 4:
-                        len += 7;
-                        break;
-                case 3:
-                        len += 5;
-                        break;
-                case 2:
-                        len += 4;
-                        break;
-                case 1:
-                        len += 2;
-                        break;
-                }
-        }
-
-        z = r = malloc(len + 1);
-        if (!r)
-                return NULL;
-
-        for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
-                /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
-                 * x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
-                *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
-                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
-                *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
-                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);  /* 000YZZZZ */
-                *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
-                *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
-                *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5);  /* 000QQWWW */
-                *(z++) = base32hexchar((x[4] & 31));                  /* 000WWWWW */
-        }
-
-        switch (l % 5) {
-        case 4:
-                *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
-                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
-                *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
-                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);   /* 000YZZZZ */
-                *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
-                *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
-                *(z++) = base32hexchar((x[3] & 3) << 3);              /* 000QQ000 */
-                if (padding)
-                        *(z++) = '=';
-
-                break;
-
-        case 3:
-                *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
-                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
-                *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
-                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
-                *(z++) = base32hexchar((x[2] & 15) << 1);            /* 000ZZZZ0 */
-                if (padding) {
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                }
-
-                break;
-
-        case 2:
-                *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
-                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
-                *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
-                *(z++) = base32hexchar((x[1] & 1) << 4);             /* 000Y0000 */
-                if (padding) {
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                }
-
-                break;
-
-        case 1:
-                *(z++) = base32hexchar(x[0] >> 3);       /* 000XXXXX */
-                *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
-                if (padding) {
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                }
-
-                break;
-        }
-
-        *z = 0;
-        return r;
-}
-
-int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
-        _cleanup_free_ uint8_t *r = NULL;
-        int a, b, c, d, e, f, g, h;
-        uint8_t *z;
-        const char *x;
-        size_t len;
-        unsigned pad = 0;
-
-        assert(p || l == 0);
-        assert(mem);
-        assert(_len);
-
-        if (l == (size_t) -1)
-                l = strlen(p);
-
-        /* padding ensures any base32hex input has input divisible by 8 */
-        if (padding && l % 8 != 0)
-                return -EINVAL;
-
-        if (padding) {
-                /* strip the padding */
-                while (l > 0 && p[l - 1] == '=' && pad < 7) {
-                        pad++;
-                        l--;
-                }
-        }
-
-        /* a group of eight input bytes needs five output bytes, in case of
-         * padding we need to add some extra bytes */
-        len = (l / 8) * 5;
-
-        switch (l % 8) {
-        case 7:
-                len += 4;
-                break;
-        case 5:
-                len += 3;
-                break;
-        case 4:
-                len += 2;
-                break;
-        case 2:
-                len += 1;
-                break;
-        case 0:
-                break;
-        default:
-                return -EINVAL;
-        }
-
-        z = r = malloc(len + 1);
-        if (!r)
-                return -ENOMEM;
-
-        for (x = p; x < p + (l / 8) * 8; x += 8) {
-                /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
-                 * e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
-                a = unbase32hexchar(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase32hexchar(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unbase32hexchar(x[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                d = unbase32hexchar(x[3]);
-                if (d < 0)
-                        return -EINVAL;
-
-                e = unbase32hexchar(x[4]);
-                if (e < 0)
-                        return -EINVAL;
-
-                f = unbase32hexchar(x[5]);
-                if (f < 0)
-                        return -EINVAL;
-
-                g = unbase32hexchar(x[6]);
-                if (g < 0)
-                        return -EINVAL;
-
-                h = unbase32hexchar(x[7]);
-                if (h < 0)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
-                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
-                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
-                *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
-                *(z++) = (uint8_t) g << 5 | (uint8_t) h;                         /* VVVRRRRR */
-        }
-
-        switch (l % 8) {
-        case 7:
-                a = unbase32hexchar(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase32hexchar(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unbase32hexchar(x[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                d = unbase32hexchar(x[3]);
-                if (d < 0)
-                        return -EINVAL;
-
-                e = unbase32hexchar(x[4]);
-                if (e < 0)
-                        return -EINVAL;
-
-                f = unbase32hexchar(x[5]);
-                if (f < 0)
-                        return -EINVAL;
-
-                g = unbase32hexchar(x[6]);
-                if (g < 0)
-                        return -EINVAL;
-
-                /* g == 000VV000 */
-                if (g & 7)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
-                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
-                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
-                *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
-
-                break;
-        case 5:
-                a = unbase32hexchar(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase32hexchar(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unbase32hexchar(x[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                d = unbase32hexchar(x[3]);
-                if (d < 0)
-                        return -EINVAL;
-
-                e = unbase32hexchar(x[4]);
-                if (e < 0)
-                        return -EINVAL;
-
-                /* e == 000SSSS0 */
-                if (e & 1)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
-                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
-                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
-
-                break;
-        case 4:
-                a = unbase32hexchar(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase32hexchar(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unbase32hexchar(x[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                d = unbase32hexchar(x[3]);
-                if (d < 0)
-                        return -EINVAL;
-
-                /* d == 000W0000 */
-                if (d & 15)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
-                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
-
-                break;
-        case 2:
-                a = unbase32hexchar(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase32hexchar(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                /* b == 000YYY00 */
-                if (b & 3)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
-
-                break;
-        case 0:
-                break;
-        default:
-                return -EINVAL;
-        }
-
-        *z = 0;
-
-        *mem = TAKE_PTR(r);
-        *_len = len;
-
-        return 0;
-}
-
-/* https://tools.ietf.org/html/rfc4648#section-4 */
-char base64char(int x) {
-        static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                                      "abcdefghijklmnopqrstuvwxyz"
-                                      "0123456789+/";
-        return table[x & 63];
-}
-#endif /* NM_IGNORED */
-
-int unbase64char(char c) {
-        unsigned offset;
-
-        if (c >= 'A' && c <= 'Z')
-                return c - 'A';
-
-        offset = 'Z' - 'A' + 1;
-
-        if (c >= 'a' && c <= 'z')
-                return c - 'a' + offset;
-
-        offset += 'z' - 'a' + 1;
-
-        if (c >= '0' && c <= '9')
-                return c - '0' + offset;
-
-        offset += '9' - '0' + 1;
-
-        if (c == '+')
-                return offset;
-
-        offset++;
-
-        if (c == '/')
-                return offset;
-
-        return -EINVAL;
-}
-
-#if 0 /* NM_IGNORED */
-ssize_t base64mem(const void *p, size_t l, char **out) {
-        char *r, *z;
-        const uint8_t *x;
-
-        assert(p || l == 0);
-        assert(out);
-
-        /* three input bytes makes four output bytes, padding is added so we must round up */
-        z = r = malloc(4 * (l + 2) / 3 + 1);
-        if (!r)
-                return -ENOMEM;
-
-        for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
-                /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
-                *(z++) = base64char(x[0] >> 2);                    /* 00XXXXXX */
-                *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4);  /* 00XXYYYY */
-                *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
-                *(z++) = base64char(x[2] & 63);                    /* 00ZZZZZZ */
-        }
-
-        switch (l % 3) {
-        case 2:
-                *(z++) = base64char(x[0] >> 2);                   /* 00XXXXXX */
-                *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
-                *(z++) = base64char((x[1] & 15) << 2);            /* 00YYYY00 */
-                *(z++) = '=';
-
-                break;
-        case 1:
-                *(z++) = base64char(x[0] >> 2);        /* 00XXXXXX */
-                *(z++) = base64char((x[0] & 3) << 4);  /* 00XX0000 */
-                *(z++) = '=';
-                *(z++) = '=';
-
-                break;
-        }
-
-        *z = 0;
-        *out = r;
-        return z - r;
-}
-
-static int base64_append_width(
-                char **prefix, int plen,
-                char sep, int indent,
-                const void *p, size_t l,
-                int width) {
-
-        _cleanup_free_ char *x = NULL;
-        char *t, *s;
-        ssize_t len, avail, line, lines;
-
-        len = base64mem(p, l, &x);
-        if (len <= 0)
-                return len;
-
-        lines = DIV_ROUND_UP(len, width);
-
-        if ((size_t) plen >= SSIZE_MAX - 1 - 1 ||
-            lines > (SSIZE_MAX - plen - 1 - 1) / (indent + width + 1))
-                return -ENOMEM;
-
-        t = realloc(*prefix, (ssize_t) plen + 1 + 1 + (indent + width + 1) * lines);
-        if (!t)
-                return -ENOMEM;
-
-        t[plen] = sep;
-
-        for (line = 0, s = t + plen + 1, avail = len; line < lines; line++) {
-                int act = MIN(width, avail);
-
-                if (line > 0 || sep == '\n') {
-                        memset(s, ' ', indent);
-                        s += indent;
-                }
-
-                memcpy(s, x + width * line, act);
-                s += act;
-                *(s++) = line < lines - 1 ? '\n' : '\0';
-                avail -= act;
-        }
-        assert(avail == 0);
-
-        *prefix = t;
-        return 0;
-}
-
-int base64_append(
-                char **prefix, int plen,
-                const void *p, size_t l,
-                int indent, int width) {
-
-        if (plen > width / 2 || plen + indent > width)
-                /* leave indent on the left, keep last column free */
-                return base64_append_width(prefix, plen, '\n', indent, p, l, width - indent - 1);
-        else
-                /* leave plen on the left, keep last column free */
-                return base64_append_width(prefix, plen, ' ', plen + 1, p, l, width - plen - 1);
-}
-#endif /* NM_IGNORED */
-
-static int unbase64_next(const char **p, size_t *l) {
-        int ret;
-
-        assert(p);
-        assert(l);
-
-        /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
-         * greedily skip all preceding and all following whitespace. */
-
-        for (;;) {
-                if (*l == 0)
-                        return -EPIPE;
-
-                if (!strchr(WHITESPACE, **p))
-                        break;
-
-                /* Skip leading whitespace */
-                (*p)++, (*l)--;
-        }
-
-        if (**p == '=')
-                ret = INT_MAX; /* return padding as INT_MAX */
-        else {
-                ret = unbase64char(**p);
-                if (ret < 0)
-                        return ret;
-        }
-
-        for (;;) {
-                (*p)++, (*l)--;
-
-                if (*l == 0)
-                        break;
-                if (!strchr(WHITESPACE, **p))
-                        break;
-
-                /* Skip following whitespace */
-        }
-
-        return ret;
-}
-
-int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_size) {
-        _cleanup_free_ uint8_t *buf = NULL;
-        const char *x;
-        uint8_t *z;
-        size_t len;
-        int r;
-
-        assert(p || l == 0);
-        assert(ret);
-        assert(ret_size);
-
-        if (l == (size_t) -1)
-                l = strlen(p);
-
-        /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
-         * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
-        len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
-
-        buf = malloc(len + 1);
-        if (!buf)
-                return -ENOMEM;
-
-        for (x = p, z = buf;;) {
-                int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
-
-                a = unbase64_next(&x, &l);
-                if (a == -EPIPE) /* End of string */
-                        break;
-                if (a < 0) {
-                        r = a;
-                        goto on_failure;
-                }
-                if (a == INT_MAX) { /* Padding is not allowed at the beginning of a 4ch block */
-                        r = -EINVAL;
-                        goto on_failure;
-                }
-
-                b = unbase64_next(&x, &l);
-                if (b < 0) {
-                        r = b;
-                        goto on_failure;
-                }
-                if (b == INT_MAX) { /* Padding is not allowed at the second character of a 4ch block either */
-                        r = -EINVAL;
-                        goto on_failure;
-                }
-
-                c = unbase64_next(&x, &l);
-                if (c < 0) {
-                        r = c;
-                        goto on_failure;
-                }
-
-                d = unbase64_next(&x, &l);
-                if (d < 0) {
-                        r = d;
-                        goto on_failure;
-                }
-
-                if (c == INT_MAX) { /* Padding at the third character */
-
-                        if (d != INT_MAX) { /* If the third character is padding, the fourth must be too */
-                                r = -EINVAL;
-                                goto on_failure;
-                        }
-
-                        /* b == 00YY0000 */
-                        if (b & 15) {
-                                r = -EINVAL;
-                                goto on_failure;
-                        }
-
-                        if (l > 0) { /* Trailing rubbish? */
-                                r = -ENAMETOOLONG;
-                                goto on_failure;
-                        }
-
-                        *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
-                        break;
-                }
-
-                if (d == INT_MAX) {
-                        /* c == 00ZZZZ00 */
-                        if (c & 3) {
-                                r = -EINVAL;
-                                goto on_failure;
-                        }
-
-                        if (l > 0) { /* Trailing rubbish? */
-                                r = -ENAMETOOLONG;
-                                goto on_failure;
-                        }
-
-                        *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
-                        *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
-                        break;
-                }
-
-                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
-                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
-                *(z++) = (uint8_t) c << 6 | (uint8_t) d;      /* ZZWWWWWW */
-        }
-
-        *z = 0;
-
-        *ret_size = (size_t) (z - buf);
-        *ret = TAKE_PTR(buf);
-
-        return 0;
-
-on_failure:
-        if (secure)
-                explicit_bzero_safe(buf, len);
-
-        return r;
-}
-
-#if 0 /* NM_IGNORED */
-void hexdump(FILE *f, const void *p, size_t s) {
-        const uint8_t *b = p;
-        unsigned n = 0;
-
-        assert(b || s == 0);
-
-        if (!f)
-                f = stdout;
-
-        while (s > 0) {
-                size_t i;
-
-                fprintf(f, "%04x  ", n);
-
-                for (i = 0; i < 16; i++) {
-
-                        if (i >= s)
-                                fputs("   ", f);
-                        else
-                                fprintf(f, "%02x ", b[i]);
-
-                        if (i == 7)
-                                fputc(' ', f);
-                }
-
-                fputc(' ', f);
-
-                for (i = 0; i < 16; i++) {
-
-                        if (i >= s)
-                                fputc(' ', f);
-                        else
-                                fputc(isprint(b[i]) ? (char) b[i] : '.', f);
-                }
-
-                fputc('\n', f);
-
-                if (s < 16)
-                        break;
-
-                n += 16;
-                b += 16;
-                s -= 16;
-        }
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/hexdecoct.h b/shared/systemd/src/basic/hexdecoct.h
deleted file mode 100644
index 7e2a6892..00000000
--- a/shared/systemd/src/basic/hexdecoct.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <sys/types.h>
-
-#include "macro.h"
-
-char octchar(int x) _const_;
-int unoctchar(char c) _const_;
-
-char decchar(int x) _const_;
-int undecchar(char c) _const_;
-
-char hexchar(int x) _const_;
-int unhexchar(char c) _const_;
-
-char *hexmem(const void *p, size_t l);
-int unhexmem_full(const char *p, size_t l, bool secure, void **mem, size_t *len);
-static inline int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
-        return unhexmem_full(p, l, false, mem, len);
-}
-
-char base32hexchar(int x) _const_;
-int unbase32hexchar(char c) _const_;
-
-char base64char(int x) _const_;
-int unbase64char(char c) _const_;
-
-char *base32hexmem(const void *p, size_t l, bool padding);
-int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
-
-ssize_t base64mem(const void *p, size_t l, char **out);
-int base64_append(char **prefix, int plen,
-                  const void *p, size_t l,
-                  int margin, int width);
-int unbase64mem_full(const char *p, size_t l, bool secure, void **mem, size_t *len);
-static inline int unbase64mem(const char *p, size_t l, void **mem, size_t *len) {
-        return unbase64mem_full(p, l, false, mem, len);
-}
-
-void hexdump(FILE *f, const void *p, size_t s);
diff --git a/shared/systemd/src/basic/hostname-util.c b/shared/systemd/src/basic/hostname-util.c
deleted file mode 100644
index a3cdc62e..00000000
--- a/shared/systemd/src/basic/hostname-util.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <sys/utsname.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "hostname-util.h"
-#include "string-util.h"
-#include "strv.h"
-
-#if 0 /* NM_IGNORED */
-char* gethostname_malloc(void) {
-        struct utsname u;
-        const char *s;
-
-        /* This call tries to return something useful, either the actual hostname
-         * or it makes something up. The only reason it might fail is OOM.
-         * It might even return "localhost" if that's set. */
-
-        assert_se(uname(&u) >= 0);
-
-        s = u.nodename;
-        if (isempty(s) || streq(s, "(none)"))
-                s = FALLBACK_HOSTNAME;
-
-        return strdup(s);
-}
-
-char* gethostname_short_malloc(void) {
-        struct utsname u;
-        const char *s;
-
-        /* Like above, but kills the FQDN part if present. */
-
-        assert_se(uname(&u) >= 0);
-
-        s = u.nodename;
-        if (isempty(s) || streq(s, "(none)") || s[0] == '.') {
-                s = FALLBACK_HOSTNAME;
-                assert(s[0] != '.');
-        }
-
-        return strndup(s, strcspn(s, "."));
-}
-#endif /* NM_IGNORED */
-
-int gethostname_strict(char **ret) {
-        struct utsname u;
-        char *k;
-
-        /* This call will rather fail than make up a name. It will not return "localhost" either. */
-
-        assert_se(uname(&u) >= 0);
-
-        if (isempty(u.nodename))
-                return -ENXIO;
-
-        if (streq(u.nodename, "(none)"))
-                return -ENXIO;
-
-        if (is_localhost(u.nodename))
-                return -ENXIO;
-
-        k = strdup(u.nodename);
-        if (!k)
-                return -ENOMEM;
-
-        *ret = k;
-        return 0;
-}
-
-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') ||
-                (c >= '0' && c <= '9') ||
-                c == '-';
-}
-
-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;
-
-        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 == '.') {
-                        if (dot || hyphen)
-                                return false;
-
-                        dot = true;
-                        hyphen = false;
-                        n_dots++;
-
-                } else if (*p == '-') {
-                        if (dot)
-                                return false;
-
-                        dot = false;
-                        hyphen = true;
-
-                } else {
-                        if (!valid_ldh_char(*p))
-                                return false;
-
-                        dot = false;
-                        hyphen = false;
-                }
-
-        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 */
-                return false;
-
-        return true;
-}
-
-char* hostname_cleanup(char *s) {
-        char *p, *d;
-        bool dot, hyphen;
-
-        assert(s);
-
-        for (p = s, d = s, dot = hyphen = true; *p && d - s < HOST_NAME_MAX; p++)
-                if (*p == '.') {
-                        if (dot || hyphen)
-                                continue;
-
-                        *(d++) = '.';
-                        dot = true;
-                        hyphen = false;
-
-                } else if (*p == '-') {
-                        if (dot)
-                                continue;
-
-                        *(d++) = '-';
-                        dot = false;
-                        hyphen = true;
-
-                } else if (valid_ldh_char(*p)) {
-                        *(d++) = *p;
-                        dot = false;
-                        hyphen = false;
-                }
-
-        if (d > s && IN_SET(d[-1], '-', '.'))
-                /* The dot can occur at most once, but we might have multiple
-                 * hyphens, hence the loop */
-                d--;
-        *d = 0;
-
-        return s;
-}
-
-bool is_localhost(const char *hostname) {
-        assert(hostname);
-
-        /* This tries to identify local host and domain names
-         * described in RFC6761 plus the redhatism of localdomain */
-
-        return STRCASE_IN_SET(
-                        hostname,
-                        "localhost",
-                        "localhost.",
-                        "localhost.localdomain",
-                        "localhost.localdomain.") ||
-                endswith_no_case(hostname, ".localhost") ||
-                endswith_no_case(hostname, ".localhost.") ||
-                endswith_no_case(hostname, ".localhost.localdomain") ||
-                endswith_no_case(hostname, ".localhost.localdomain.");
-}
diff --git a/shared/systemd/src/basic/hostname-util.h b/shared/systemd/src/basic/hostname-util.h
deleted file mode 100644
index 6cff9c1d..00000000
--- a/shared/systemd/src/basic/hostname-util.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-#include <stdio.h>
-
-#include "macro.h"
-#include "strv.h"
-
-char* gethostname_malloc(void);
-char* gethostname_short_malloc(void);
-int gethostname_strict(char **ret);
-
-bool valid_ldh_char(char c) _const_;
-
-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;
-
-bool hostname_is_valid(const char *s, ValidHostnameFlags flags) _pure_;
-char* hostname_cleanup(char *s);
-
-bool is_localhost(const char *hostname);
-
-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
deleted file mode 100644
index c315dcbb..00000000
--- a/shared/systemd/src/basic/in-addr-util.c
+++ /dev/null
@@ -1,792 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <arpa/inet.h>
-#include <endian.h>
-#include <errno.h>
-#include <net/if.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "alloc-util.h"
-#include "errno-util.h"
-#include "in-addr-util.h"
-#include "macro.h"
-#include "parse-util.h"
-#include "random-util.h"
-#include "string-util.h"
-#include "strxcpyx.h"
-#include "util.h"
-
-bool in4_addr_is_null(const struct in_addr *a) {
-        assert(a);
-
-        return a->s_addr == 0;
-}
-
-int in_addr_is_null(int family, const union in_addr_union *u) {
-        assert(u);
-
-        if (family == AF_INET)
-                return in4_addr_is_null(&u->in);
-
-        if (family == AF_INET6)
-                return IN6_IS_ADDR_UNSPECIFIED(&u->in6);
-
-        return -EAFNOSUPPORT;
-}
-
-bool in4_addr_is_link_local(const struct in_addr *a) {
-        assert(a);
-
-        return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
-}
-
-int in_addr_is_link_local(int family, const union in_addr_union *u) {
-        assert(u);
-
-        if (family == AF_INET)
-                return in4_addr_is_link_local(&u->in);
-
-        if (family == AF_INET6)
-                return IN6_IS_ADDR_LINKLOCAL(&u->in6);
-
-        return -EAFNOSUPPORT;
-}
-
-bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) {
-        assert(a);
-
-        /* ff02::1 */
-        return be32toh(a->s6_addr32[0]) == UINT32_C(0xff020000) &&
-                a->s6_addr32[1] == 0 &&
-                a->s6_addr32[2] == 0 &&
-                be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001);
-}
-
-int in_addr_is_multicast(int family, const union in_addr_union *u) {
-        assert(u);
-
-        if (family == AF_INET)
-                return IN_MULTICAST(be32toh(u->in.s_addr));
-
-        if (family == AF_INET6)
-                return IN6_IS_ADDR_MULTICAST(&u->in6);
-
-        return -EAFNOSUPPORT;
-}
-
-bool in4_addr_is_local_multicast(const struct in_addr *a) {
-        assert(a);
-
-        return (be32toh(a->s_addr) & UINT32_C(0xffffff00)) == UINT32_C(0xe0000000);
-}
-
-bool in4_addr_is_localhost(const struct in_addr *a) {
-        assert(a);
-
-        /* All of 127.x.x.x is localhost. */
-        return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
-}
-
-bool in4_addr_is_non_local(const struct in_addr *a) {
-        /* Whether the address is not null and not localhost.
-         *
-         * As such, it is suitable to configure as DNS/NTP server from DHCP. */
-        return !in4_addr_is_null(a) &&
-               !in4_addr_is_localhost(a);
-}
-
-int in_addr_is_localhost(int family, const union in_addr_union *u) {
-        assert(u);
-
-        if (family == AF_INET)
-                return in4_addr_is_localhost(&u->in);
-
-        if (family == AF_INET6)
-                return IN6_IS_ADDR_LOOPBACK(&u->in6);
-
-        return -EAFNOSUPPORT;
-}
-
-bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
-        assert(a);
-        assert(b);
-
-        return a->s_addr == b->s_addr;
-}
-
-int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
-        assert(a);
-        assert(b);
-
-        if (family == AF_INET)
-                return in4_addr_equal(&a->in, &b->in);
-
-        if (family == AF_INET6)
-                return IN6_ARE_ADDR_EQUAL(&a->in6, &b->in6);
-
-        return -EAFNOSUPPORT;
-}
-
-#if 0 /* NM_IGNORED */
-int in_addr_prefix_intersect(
-                int family,
-                const union in_addr_union *a,
-                unsigned aprefixlen,
-                const union in_addr_union *b,
-                unsigned bprefixlen) {
-
-        unsigned m;
-
-        assert(a);
-        assert(b);
-
-        /* Checks whether there are any addresses that are in both
-         * networks */
-
-        m = MIN(aprefixlen, bprefixlen);
-
-        if (family == AF_INET) {
-                uint32_t x, nm;
-
-                x = be32toh(a->in.s_addr ^ b->in.s_addr);
-                nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m);
-
-                return (x & nm) == 0;
-        }
-
-        if (family == AF_INET6) {
-                unsigned i;
-
-                if (m > 128)
-                        m = 128;
-
-                for (i = 0; i < 16; i++) {
-                        uint8_t x, nm;
-
-                        x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i];
-
-                        if (m < 8)
-                                nm = 0xFF << (8 - m);
-                        else
-                                nm = 0xFF;
-
-                        if ((x & nm) != 0)
-                                return 0;
-
-                        if (m > 8)
-                                m -= 8;
-                        else
-                                m = 0;
-                }
-
-                return 1;
-        }
-
-        return -EAFNOSUPPORT;
-}
-
-int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
-        assert(u);
-
-        /* Increases the network part of an address by one. Returns
-         * positive if that succeeds, or -ERANGE if this overflows. */
-
-        return in_addr_prefix_nth(family, u, prefixlen, 1);
-}
-
-/*
- * Calculates the nth prefix of size prefixlen starting from the address denoted by u.
- *
- * On success 1 will be returned and the calculated prefix will be available in
- * u. In the case nth == 0 the input will be left unchanged and 1 will be returned.
- * In case the calculation cannot be performed (invalid prefix length,
- * overflows would occur) -ERANGE is returned. If the address family given isn't
- * supported -EAFNOSUPPORT will be returned.
- *
- *
- * Examples:
- *   - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 2), returns 1, writes 192.168.2.0 to u
- *   - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 0), returns 1, no data written
- *   - in_addr_prefix_nth(AF_INET, 255.255.255.0, 24, 1), returns -ERANGE, no data written
- *   - in_addr_prefix_nth(AF_INET, 255.255.255.0, 0, 1), returns -ERANGE, no data written
- *   - in_addr_prefix_nth(AF_INET6, 2001:db8, 64, 0xff00) returns 1, writes 2001:0db8:0000:ff00:: to u
- */
-int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth) {
-        assert(u);
-
-        if (prefixlen <= 0)
-                return -ERANGE;
-
-        if (nth == 0)
-                return 1;
-
-        if (family == AF_INET) {
-                uint32_t c, n, t;
-                if (prefixlen > 32)
-                        prefixlen = 32;
-
-                c = be32toh(u->in.s_addr);
-
-                t = nth << (32 - prefixlen);
-
-                /* Check for wrap */
-                if (c > UINT32_MAX - t)
-                        return -ERANGE;
-
-                n = c + t;
-
-                n &= UINT32_C(0xFFFFFFFF) << (32 - prefixlen);
-                u->in.s_addr = htobe32(n);
-                return 1;
-        }
-
-        if (family == AF_INET6) {
-                struct in6_addr result = {};
-                uint8_t overflow = 0;
-                uint64_t delta;  /* this assumes that we only ever have to up to 1<<64 subnets */
-                unsigned start_byte = (prefixlen - 1) / 8;
-
-                if (prefixlen > 128)
-                        prefixlen = 128;
-
-                /* First calculate what we have to add */
-                delta = nth << ((128 - prefixlen) % 8);
-
-                for (unsigned i = 16; i > 0; i--) {
-                        unsigned j = i - 1;
-                        unsigned d = 0;
-
-                        if (j <= start_byte) {
-                                int16_t t;
-
-                                d = delta & 0xFF;
-                                delta >>= 8;
-
-                                t = u->in6.s6_addr[j] + d + overflow;
-                                overflow = t > UINT8_MAX ? t - UINT8_MAX : 0;
-
-                                result.s6_addr[j] = (uint8_t)t;
-                        } else
-                                result.s6_addr[j] = u->in6.s6_addr[j];
-                }
-
-                if (overflow || delta != 0)
-                        return -ERANGE;
-
-                u->in6 = result;
-                return 1;
-        }
-
-        return -EAFNOSUPPORT;
-}
-
-int in_addr_random_prefix(
-                int family,
-                union in_addr_union *u,
-                unsigned prefixlen_fixed_part,
-                unsigned prefixlen) {
-
-        assert(u);
-
-        /* Random network part of an address by one. */
-
-        if (prefixlen <= 0)
-                return 0;
-
-        if (family == AF_INET) {
-                uint32_t c, n;
-
-                if (prefixlen_fixed_part > 32)
-                        prefixlen_fixed_part = 32;
-                if (prefixlen > 32)
-                        prefixlen = 32;
-                if (prefixlen_fixed_part >= prefixlen)
-                        return -EINVAL;
-
-                c = be32toh(u->in.s_addr);
-                c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
-
-                random_bytes(&n, sizeof(n));
-                n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
-
-                u->in.s_addr = htobe32(n | c);
-                return 1;
-        }
-
-        if (family == AF_INET6) {
-                struct in6_addr n;
-                unsigned i, j;
-
-                if (prefixlen_fixed_part > 128)
-                        prefixlen_fixed_part = 128;
-                if (prefixlen > 128)
-                        prefixlen = 128;
-                if (prefixlen_fixed_part >= prefixlen)
-                        return -EINVAL;
-
-                random_bytes(&n, sizeof(n));
-
-                for (i = 0; i < 16; i++) {
-                        uint8_t mask_fixed_part = 0, mask = 0;
-
-                        if (i < (prefixlen_fixed_part + 7) / 8) {
-                                if (i < prefixlen_fixed_part / 8)
-                                        mask_fixed_part = 0xffu;
-                                else {
-                                        j = prefixlen_fixed_part % 8;
-                                        mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j);
-                                }
-                        }
-
-                        if (i < (prefixlen + 7) / 8) {
-                                if (i < prefixlen / 8)
-                                        mask = 0xffu ^ mask_fixed_part;
-                                else {
-                                        j = prefixlen % 8;
-                                        mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part;
-                                }
-                        }
-
-                        u->in6.s6_addr[i] &= mask_fixed_part;
-                        u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
-                }
-
-                return 1;
-        }
-
-        return -EAFNOSUPPORT;
-}
-#endif /* NM_IGNORED */
-
-int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
-        _cleanup_free_ char *x = NULL;
-        size_t l;
-
-        assert(u);
-        assert(ret);
-
-        if (family == AF_INET)
-                l = INET_ADDRSTRLEN;
-        else if (family == AF_INET6)
-                l = INET6_ADDRSTRLEN;
-        else
-                return -EAFNOSUPPORT;
-
-        x = new(char, l);
-        if (!x)
-                return -ENOMEM;
-
-        errno = 0;
-        if (!inet_ntop(family, u, x, l))
-                return errno_or_else(EINVAL);
-
-        *ret = TAKE_PTR(x);
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) {
-        _cleanup_free_ char *x = NULL;
-        char *p;
-        size_t l;
-
-        assert(u);
-        assert(ret);
-
-        if (family == AF_INET)
-                l = INET_ADDRSTRLEN + 3;
-        else if (family == AF_INET6)
-                l = INET6_ADDRSTRLEN + 4;
-        else
-                return -EAFNOSUPPORT;
-
-        if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
-                return -EINVAL;
-
-        x = new(char, l);
-        if (!x)
-                return -ENOMEM;
-
-        errno = 0;
-        if (!inet_ntop(family, u, x, l))
-                return errno_or_else(EINVAL);
-
-        p = x + strlen(x);
-        l -= strlen(x);
-        (void) strpcpyf(&p, l, "/%u", prefixlen);
-
-        *ret = TAKE_PTR(x);
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret) {
-        _cleanup_free_ char *ip_str = NULL, *x = NULL;
-        int r;
-
-        assert(IN_SET(family, AF_INET, AF_INET6));
-        assert(u);
-        assert(ret);
-
-        /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
-         * handle IPv6 link-local addresses. */
-
-        r = in_addr_to_string(family, u, &ip_str);
-        if (r < 0)
-                return r;
-
-        if (family == AF_INET6) {
-                r = in_addr_is_link_local(family, u);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        ifindex = 0;
-        } else
-                ifindex = 0; /* For IPv4 address, ifindex is always ignored. */
-
-        if (port == 0 && ifindex == 0 && isempty(server_name)) {
-                *ret = TAKE_PTR(ip_str);
-                return 0;
-        }
-
-        const char *separator = isempty(server_name) ? "" : "#";
-        server_name = strempty(server_name);
-
-        if (port > 0) {
-                if (family == AF_INET6) {
-                        if (ifindex > 0)
-                                r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name);
-                        else
-                                r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name);
-                } else
-                        r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name);
-        } else {
-                if (ifindex > 0)
-                        r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name);
-                else {
-                        x = strjoin(ip_str, separator, server_name);
-                        r = x ? 0 : -ENOMEM;
-                }
-        }
-        if (r < 0)
-                return -ENOMEM;
-
-        *ret = TAKE_PTR(x);
-        return 0;
-}
-
-int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
-        union in_addr_union buffer;
-        assert(s);
-
-        if (!IN_SET(family, AF_INET, AF_INET6))
-                return -EAFNOSUPPORT;
-
-        errno = 0;
-        if (inet_pton(family, s, ret ?: &buffer) <= 0)
-                return errno_or_else(EINVAL);
-
-        return 0;
-}
-
-int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
-        int r;
-
-        assert(s);
-
-        r = in_addr_from_string(AF_INET, s, ret);
-        if (r >= 0) {
-                if (ret_family)
-                        *ret_family = AF_INET;
-                return 0;
-        }
-
-        r = in_addr_from_string(AF_INET6, s, ret);
-        if (r >= 0) {
-                if (ret_family)
-                        *ret_family = AF_INET6;
-                return 0;
-        }
-
-        return -EINVAL;
-}
-
-unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
-        assert(addr);
-
-        return 32U - u32ctz(be32toh(addr->s_addr));
-}
-
-struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
-        assert(addr);
-        assert(prefixlen <= 32);
-
-        /* Shifting beyond 32 is not defined, handle this specially. */
-        if (prefixlen == 0)
-                addr->s_addr = 0;
-        else
-                addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
-
-        return addr;
-}
-
-int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
-        uint8_t msb_octet = *(uint8_t*) addr;
-
-        /* addr may not be aligned, so make sure we only access it byte-wise */
-
-        assert(addr);
-        assert(prefixlen);
-
-        if (msb_octet < 128)
-                /* class A, leading bits: 0 */
-                *prefixlen = 8;
-        else if (msb_octet < 192)
-                /* class B, leading bits 10 */
-                *prefixlen = 16;
-        else if (msb_octet < 224)
-                /* class C, leading bits 110 */
-                *prefixlen = 24;
-        else
-                /* class D or E, no default prefixlen */
-                return -ERANGE;
-
-        return 0;
-}
-
-int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
-        unsigned char prefixlen;
-        int r;
-
-        assert(addr);
-        assert(mask);
-
-        r = in4_addr_default_prefixlen(addr, &prefixlen);
-        if (r < 0)
-                return r;
-
-        in4_addr_prefixlen_to_netmask(mask, prefixlen);
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
-        assert(addr);
-
-        if (family == AF_INET) {
-                struct in_addr mask;
-
-                if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
-                        return -EINVAL;
-
-                addr->in.s_addr &= mask.s_addr;
-                return 0;
-        }
-
-        if (family == AF_INET6) {
-                unsigned i;
-
-                for (i = 0; i < 16; i++) {
-                        uint8_t mask;
-
-                        if (prefixlen >= 8) {
-                                mask = 0xFF;
-                                prefixlen -= 8;
-                        } else {
-                                mask = 0xFF << (8 - prefixlen);
-                                prefixlen = 0;
-                        }
-
-                        addr->in6.s6_addr[i] &= mask;
-                }
-
-                return 0;
-        }
-
-        return -EAFNOSUPPORT;
-}
-
-int in_addr_prefix_covers(int family,
-                          const union in_addr_union *prefix,
-                          unsigned char prefixlen,
-                          const union in_addr_union *address) {
-
-        union in_addr_union masked_prefix, masked_address;
-        int r;
-
-        assert(prefix);
-        assert(address);
-
-        masked_prefix = *prefix;
-        r = in_addr_mask(family, &masked_prefix, prefixlen);
-        if (r < 0)
-                return r;
-
-        masked_address = *address;
-        r = in_addr_mask(family, &masked_address, prefixlen);
-        if (r < 0)
-                return r;
-
-        return in_addr_equal(family, &masked_prefix, &masked_address);
-}
-
-int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
-        uint8_t u;
-        int r;
-
-        if (!IN_SET(family, AF_INET, AF_INET6))
-                return -EAFNOSUPPORT;
-
-        r = safe_atou8(p, &u);
-        if (r < 0)
-                return r;
-
-        if (u > FAMILY_ADDRESS_SIZE(family) * 8)
-                return -ERANGE;
-
-        *ret = u;
-        return 0;
-}
-
-int in_addr_prefix_from_string(
-                const char *p,
-                int family,
-                union in_addr_union *ret_prefix,
-                unsigned char *ret_prefixlen) {
-
-        _cleanup_free_ char *str = NULL;
-        union in_addr_union buffer;
-        const char *e, *l;
-        unsigned char k;
-        int r;
-
-        assert(p);
-
-        if (!IN_SET(family, AF_INET, AF_INET6))
-                return -EAFNOSUPPORT;
-
-        e = strchr(p, '/');
-        if (e) {
-                str = strndup(p, e - p);
-                if (!str)
-                        return -ENOMEM;
-
-                l = str;
-        } else
-                l = p;
-
-        r = in_addr_from_string(family, l, &buffer);
-        if (r < 0)
-                return r;
-
-        if (e) {
-                r = in_addr_parse_prefixlen(family, e+1, &k);
-                if (r < 0)
-                        return r;
-        } else
-                k = FAMILY_ADDRESS_SIZE(family) * 8;
-
-        if (ret_prefix)
-                *ret_prefix = buffer;
-        if (ret_prefixlen)
-                *ret_prefixlen = k;
-
-        return 0;
-}
-
-int in_addr_prefix_from_string_auto_internal(
-                const char *p,
-                InAddrPrefixLenMode mode,
-                int *ret_family,
-                union in_addr_union *ret_prefix,
-                unsigned char *ret_prefixlen) {
-
-        _cleanup_free_ char *str = NULL;
-        union in_addr_union buffer;
-        const char *e, *l;
-        unsigned char k;
-        int family, r;
-
-        assert(p);
-
-        e = strchr(p, '/');
-        if (e) {
-                str = strndup(p, e - p);
-                if (!str)
-                        return -ENOMEM;
-
-                l = str;
-        } else
-                l = p;
-
-        r = in_addr_from_string_auto(l, &family, &buffer);
-        if (r < 0)
-                return r;
-
-        if (e) {
-                r = in_addr_parse_prefixlen(family, e+1, &k);
-                if (r < 0)
-                        return r;
-        } else
-                switch (mode) {
-                case PREFIXLEN_FULL:
-                        k = FAMILY_ADDRESS_SIZE(family) * 8;
-                        break;
-                case PREFIXLEN_REFUSE:
-                        return -ENOANO; /* To distinguish this error from others. */
-                case PREFIXLEN_LEGACY:
-                        if (family == AF_INET) {
-                                r = in4_addr_default_prefixlen(&buffer.in, &k);
-                                if (r < 0)
-                                        return r;
-                        } else
-                                k = 0;
-                        break;
-                default:
-                        assert_not_reached("Invalid prefixlen mode");
-                }
-
-        if (ret_family)
-                *ret_family = family;
-        if (ret_prefix)
-                *ret_prefix = buffer;
-        if (ret_prefixlen)
-                *ret_prefixlen = k;
-
-        return 0;
-
-}
-
-static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
-        siphash24_compress(&a->family, sizeof(a->family), state);
-        siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
-}
-
-static int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
-        int r;
-
-        r = CMP(x->family, y->family);
-        if (r != 0)
-                return r;
-
-        return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family));
-}
-
-DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
-
-void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
-        assert(addr);
-
-        siphash24_compress(addr, sizeof(*addr), state);
-}
-
-int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
-        return memcmp(a, b, sizeof(*a));
-}
-
-DEFINE_HASH_OPS(in6_addr_hash_ops, struct in6_addr, in6_addr_hash_func, in6_addr_compare_func);
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/in-addr-util.h b/shared/systemd/src/basic/in-addr-util.h
deleted file mode 100644
index 24308b70..00000000
--- a/shared/systemd/src/basic/in-addr-util.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <netinet/in.h>
-#include <stddef.h>
-#include <sys/socket.h>
-
-#include "hash-funcs.h"
-#include "macro.h"
-#include "util.h"
-
-union in_addr_union {
-        struct in_addr in;
-        struct in6_addr in6;
-        uint8_t bytes[CONST_MAX(sizeof(struct in_addr), sizeof(struct in6_addr))];
-};
-
-struct in_addr_data {
-        int family;
-        union in_addr_union address;
-};
-
-bool in4_addr_is_null(const struct in_addr *a);
-int in_addr_is_null(int family, const union in_addr_union *u);
-
-int in_addr_is_multicast(int family, const union in_addr_union *u);
-
-bool in4_addr_is_link_local(const struct in_addr *a);
-int in_addr_is_link_local(int family, const union in_addr_union *u);
-bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a);
-
-bool in4_addr_is_localhost(const struct in_addr *a);
-int in_addr_is_localhost(int family, const union in_addr_union *u);
-
-bool in4_addr_is_local_multicast(const struct in_addr *a);
-bool in4_addr_is_non_local(const struct in_addr *a);
-
-bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b);
-int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
-int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
-int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
-int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth);
-int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen);
-int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
-int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
-int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret);
-static inline int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
-        return in_addr_port_ifindex_name_to_string(family, u, 0, ifindex, NULL, ret);
-}
-static inline int in_addr_port_to_string(int family, const union in_addr_union *u, uint16_t port, char **ret) {
-        return in_addr_port_ifindex_name_to_string(family, u, port, 0, NULL, ret);
-}
-int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
-int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
-
-unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
-struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
-int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
-int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
-int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
-int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address);
-int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret);
-int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
-
-typedef enum InAddrPrefixLenMode {
-        PREFIXLEN_FULL,   /* Default to prefixlen of address size, 32 for IPv4 or 128 for IPv6, if not specified. */
-        PREFIXLEN_REFUSE, /* Fail with -ENOANO if prefixlen is not specified. */
-        PREFIXLEN_LEGACY, /* Default to legacy default prefixlen calculation from address if not specified. */
-} InAddrPrefixLenMode;
-
-int in_addr_prefix_from_string_auto_internal(const char *p, InAddrPrefixLenMode mode, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
-static inline int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) {
-        return in_addr_prefix_from_string_auto_internal(p, PREFIXLEN_FULL, ret_family, ret_prefix, ret_prefixlen);
-}
-
-static inline size_t FAMILY_ADDRESS_SIZE(int family) {
-        assert(IN_SET(family, AF_INET, AF_INET6));
-        return family == AF_INET6 ? 16 : 4;
-}
-
-/* Workaround for clang, explicitly specify the maximum-size element here.
- * See also oss-fuzz#11344. */
-#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
-
-void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state);
-int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b);
-
-extern const struct hash_ops in_addr_data_hash_ops;
-extern const struct hash_ops in6_addr_hash_ops;
diff --git a/shared/systemd/src/basic/io-util.c b/shared/systemd/src/basic/io-util.c
deleted file mode 100644
index f09c7fdd..00000000
--- a/shared/systemd/src/basic/io-util.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <limits.h>
-#include <poll.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include "io-util.h"
-#include "string-util.h"
-#include "time-util.h"
-
-#if 0 /* NM_IGNORED */
-int flush_fd(int fd) {
-        int count = 0;
-
-        /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
-         * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
-         * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
-         * was set to non-blocking too. */
-
-        for (;;) {
-                char buf[LINE_MAX];
-                ssize_t l;
-                int r;
-
-                r = fd_wait_for_event(fd, POLLIN, 0);
-                if (r < 0) {
-                        if (r == -EINTR)
-                                continue;
-
-                        return r;
-                }
-                if (r == 0)
-                        return count;
-
-                l = read(fd, buf, sizeof(buf));
-                if (l < 0) {
-                        if (errno == EINTR)
-                                continue;
-
-                        if (errno == EAGAIN)
-                                return count;
-
-                        return -errno;
-                } else if (l == 0)
-                        return count;
-
-                count += (int) l;
-        }
-}
-#endif /* NM_IGNORED */
-
-ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
-        uint8_t *p = buf;
-        ssize_t n = 0;
-
-        assert(fd >= 0);
-        assert(buf);
-
-        /* If called with nbytes == 0, let's call read() at least
-         * once, to validate the operation */
-
-        if (nbytes > (size_t) SSIZE_MAX)
-                return -EINVAL;
-
-        do {
-                ssize_t k;
-
-                k = read(fd, p, nbytes);
-                if (k < 0) {
-                        if (errno == EINTR)
-                                continue;
-
-                        if (errno == EAGAIN && do_poll) {
-
-                                /* We knowingly ignore any return value here,
-                                 * and expect that any error/EOF is reported
-                                 * via read() */
-
-                                (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
-                                continue;
-                        }
-
-                        return n > 0 ? n : -errno;
-                }
-
-                if (k == 0)
-                        return n;
-
-                assert((size_t) k <= nbytes);
-
-                p += k;
-                nbytes -= k;
-                n += k;
-        } while (nbytes > 0);
-
-        return n;
-}
-
-int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
-        ssize_t n;
-
-        n = loop_read(fd, buf, nbytes, do_poll);
-        if (n < 0)
-                return (int) n;
-        if ((size_t) n != nbytes)
-                return -EIO;
-
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
-        const uint8_t *p = buf;
-
-        assert(fd >= 0);
-        assert(buf);
-
-        if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
-                return -EINVAL;
-
-        do {
-                ssize_t k;
-
-                k = write(fd, p, nbytes);
-                if (k < 0) {
-                        if (errno == EINTR)
-                                continue;
-
-                        if (errno == EAGAIN && do_poll) {
-                                /* We knowingly ignore any return value here,
-                                 * and expect that any error/EOF is reported
-                                 * via write() */
-
-                                (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
-                                continue;
-                        }
-
-                        return -errno;
-                }
-
-                if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
-                        return -EIO;
-
-                assert((size_t) k <= nbytes);
-
-                p += k;
-                nbytes -= k;
-        } while (nbytes > 0);
-
-        return 0;
-}
-
-int pipe_eof(int fd) {
-        int r;
-
-        r = fd_wait_for_event(fd, POLLIN, 0);
-        if (r <= 0)
-                return r;
-
-        return !!(r & POLLHUP);
-}
-#endif /* NM_IGNORED */
-
-int fd_wait_for_event(int fd, int event, usec_t t) {
-
-        struct pollfd pollfd = {
-                .fd = fd,
-                .events = event,
-        };
-
-        struct timespec ts;
-        int r;
-
-        r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
-        if (r < 0)
-                return -errno;
-        if (r == 0)
-                return 0;
-
-        if (pollfd.revents & POLLNVAL)
-                return -EBADF;
-
-        return pollfd.revents;
-}
-
-#if 0 /* NM_IGNORED */
-static size_t nul_length(const uint8_t *p, size_t sz) {
-        size_t n = 0;
-
-        while (sz > 0) {
-                if (*p != 0)
-                        break;
-
-                n++;
-                p++;
-                sz--;
-        }
-
-        return n;
-}
-
-ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
-        const uint8_t *q, *w, *e;
-        ssize_t l;
-
-        q = w = p;
-        e = q + sz;
-        while (q < e) {
-                size_t n;
-
-                n = nul_length(q, e - q);
-
-                /* If there are more than the specified run length of
-                 * NUL bytes, or if this is the beginning or the end
-                 * of the buffer, then seek instead of write */
-                if ((n > run_length) ||
-                    (n > 0 && q == p) ||
-                    (n > 0 && q + n >= e)) {
-                        if (q > w) {
-                                l = write(fd, w, q - w);
-                                if (l < 0)
-                                        return -errno;
-                                if (l != q -w)
-                                        return -EIO;
-                        }
-
-                        if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
-                                return -errno;
-
-                        q += n;
-                        w = q;
-                } else if (n > 0)
-                        q += n;
-                else
-                        q++;
-        }
-
-        if (q > w) {
-                l = write(fd, w, q - w);
-                if (l < 0)
-                        return -errno;
-                if (l != q - w)
-                        return -EIO;
-        }
-
-        return q - (const uint8_t*) p;
-}
-
-char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) {
-        char *x;
-
-        x = strjoin(field, value);
-        if (x)
-                iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
-        return x;
-}
-
-char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) {
-        char *x;
-
-        x = set_iovec_string_field(iovec, n_iovec, field, value);
-        free(value);
-        return x;
-}
-
-struct iovec_wrapper *iovw_new(void) {
-        return malloc0(sizeof(struct iovec_wrapper));
-}
-
-void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors) {
-        if (free_vectors)
-                for (size_t i = 0; i < iovw->count; i++)
-                        free(iovw->iovec[i].iov_base);
-
-        iovw->iovec = mfree(iovw->iovec);
-        iovw->count = 0;
-        iovw->size_bytes = 0;
-}
-
-struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw) {
-        iovw_free_contents(iovw, true);
-
-        return mfree(iovw);
-}
-
-struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw) {
-        iovw_free_contents(iovw, false);
-
-        return mfree(iovw);
-}
-
-int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len) {
-        if (iovw->count >= IOV_MAX)
-                return -E2BIG;
-
-        if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
-                return -ENOMEM;
-
-        iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len);
-        return 0;
-}
-
-int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value) {
-        _cleanup_free_ char *x = NULL;
-        int r;
-
-        x = strjoin(field, value);
-        if (!x)
-                return -ENOMEM;
-
-        r = iovw_put(iovw, x, strlen(x));
-        if (r >= 0)
-                TAKE_PTR(x);
-
-        return r;
-}
-
-int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value) {
-        _cleanup_free_ _unused_ char *free_ptr = value;
-
-        return iovw_put_string_field(iovw, field, value);
-}
-
-void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) {
-        size_t i;
-
-        for (i = 0; i < iovw->count; i++)
-                iovw->iovec[i].iov_base = (char *)iovw->iovec[i].iov_base - old + new;
-}
-
-size_t iovw_size(struct iovec_wrapper *iovw) {
-        size_t n = 0, i;
-
-        for (i = 0; i < iovw->count; i++)
-                n += iovw->iovec[i].iov_len;
-
-        return n;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/io-util.h b/shared/systemd/src/basic/io-util.h
deleted file mode 100644
index d817714b..00000000
--- a/shared/systemd/src/basic/io-util.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-
-#include "macro.h"
-#include "time-util.h"
-
-int flush_fd(int fd);
-
-ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
-int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll);
-int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
-
-int pipe_eof(int fd);
-
-int fd_wait_for_event(int fd, int event, usec_t timeout);
-
-ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
-
-static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, size_t n) {
-        size_t j, r = 0;
-
-        for (j = 0; j < n; j++)
-                r += i[j].iov_len;
-
-        return r;
-}
-
-static inline size_t IOVEC_INCREMENT(struct iovec *i, size_t n, size_t k) {
-        size_t j;
-
-        for (j = 0; j < n; j++) {
-                size_t sub;
-
-                if (_unlikely_(k <= 0))
-                        break;
-
-                sub = MIN(i[j].iov_len, k);
-                i[j].iov_len -= sub;
-                i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
-                k -= sub;
-        }
-
-        return k;
-}
-
-static inline bool FILE_SIZE_VALID(uint64_t l) {
-        /* ftruncate() and friends take an unsigned file size, but actually cannot deal with file sizes larger than
-         * 2^63 since the kernel internally handles it as signed value. This call allows checking for this early. */
-
-        return (l >> 63) == 0;
-}
-
-static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
-
-        /* Same as above, but allows one extra value: -1 as indication for infinity. */
-
-        if (l == (uint64_t) -1)
-                return true;
-
-        return FILE_SIZE_VALID(l);
-
-}
-
-#define IOVEC_INIT(base, len) { .iov_base = (base), .iov_len = (len) }
-#define IOVEC_MAKE(base, len) (struct iovec) IOVEC_INIT(base, len)
-#define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string))
-#define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string)
-
-char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
-char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value);
-
-struct iovec_wrapper {
-        struct iovec *iovec;
-        size_t count;
-        size_t size_bytes;
-};
-
-struct iovec_wrapper *iovw_new(void);
-struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw);
-struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw);
-void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors);
-int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len);
-int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value);
-int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value);
-void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new);
-size_t iovw_size(struct iovec_wrapper *iovw);
diff --git a/shared/systemd/src/basic/list.h b/shared/systemd/src/basic/list.h
deleted file mode 100644
index 256b7187..00000000
--- a/shared/systemd/src/basic/list.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include "macro.h"
-
-/* The head of the linked list. Use this in the structure that shall
- * contain the head of the linked list */
-#define LIST_HEAD(t,name)                                               \
-        t *name
-
-/* The pointers in the linked list's items. Use this in the item structure */
-#define LIST_FIELDS(t,name)                                             \
-        t *name##_next, *name##_prev
-
-/* Initialize the list's head */
-#define LIST_HEAD_INIT(head)                                            \
-        do {                                                            \
-                (head) = NULL;                                          \
-        } while (false)
-
-/* Initialize a list item */
-#define LIST_INIT(name,item)                                            \
-        do {                                                            \
-                typeof(*(item)) *_item = (item);                        \
-                assert(_item);                                          \
-                _item->name##_prev = _item->name##_next = NULL;         \
-        } while (false)
-
-/* Prepend an item to the list */
-#define LIST_PREPEND(name,head,item)                                    \
-        do {                                                            \
-                typeof(*(head)) **_head = &(head), *_item = (item);     \
-                assert(_item);                                          \
-                if ((_item->name##_next = *_head))                      \
-                        _item->name##_next->name##_prev = _item;        \
-                _item->name##_prev = NULL;                              \
-                *_head = _item;                                         \
-        } while (false)
-
-/* Append an item to the list */
-#define LIST_APPEND(name,head,item)                                     \
-        do {                                                            \
-                typeof(*(head)) **_hhead = &(head), *_tail;             \
-                LIST_FIND_TAIL(name, *_hhead, _tail);                   \
-                LIST_INSERT_AFTER(name, *_hhead, _tail, item);          \
-        } while (false)
-
-/* Remove an item from the list */
-#define LIST_REMOVE(name,head,item)                                     \
-        do {                                                            \
-                typeof(*(head)) **_head = &(head), *_item = (item);     \
-                assert(_item);                                          \
-                if (_item->name##_next)                                 \
-                        _item->name##_next->name##_prev = _item->name##_prev; \
-                if (_item->name##_prev)                                 \
-                        _item->name##_prev->name##_next = _item->name##_next; \
-                else {                                                  \
-                        assert(*_head == _item);                        \
-                        *_head = _item->name##_next;                    \
-                }                                                       \
-                _item->name##_next = _item->name##_prev = NULL;         \
-        } while (false)
-
-/* Find the head of the list */
-#define LIST_FIND_HEAD(name,item,head)                                  \
-        do {                                                            \
-                typeof(*(item)) *_item = (item);                        \
-                if (!_item)                                             \
-                        (head) = NULL;                                  \
-                else {                                                  \
-                        while (_item->name##_prev)                      \
-                                _item = _item->name##_prev;             \
-                        (head) = _item;                                 \
-                }                                                       \
-        } while (false)
-
-/* Find the tail of the list */
-#define LIST_FIND_TAIL(name,item,tail)                                  \
-        do {                                                            \
-                typeof(*(item)) *_item = (item);                        \
-                if (!_item)                                             \
-                        (tail) = NULL;                                  \
-                else {                                                  \
-                        while (_item->name##_next)                      \
-                                _item = _item->name##_next;             \
-                        (tail) = _item;                                 \
-                }                                                       \
-        } while (false)
-
-/* Insert an item after another one (a = where, b = what) */
-#define LIST_INSERT_AFTER(name,head,a,b)                                \
-        do {                                                            \
-                typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \
-                assert(_b);                                             \
-                if (!_a) {                                              \
-                        if ((_b->name##_next = *_head))                 \
-                                _b->name##_next->name##_prev = _b;      \
-                        _b->name##_prev = NULL;                         \
-                        *_head = _b;                                    \
-                } else {                                                \
-                        if ((_b->name##_next = _a->name##_next))        \
-                                _b->name##_next->name##_prev = _b;      \
-                        _b->name##_prev = _a;                           \
-                        _a->name##_next = _b;                           \
-                }                                                       \
-        } while (false)
-
-/* Insert an item before another one (a = where, b = what) */
-#define LIST_INSERT_BEFORE(name,head,a,b)                               \
-        do {                                                            \
-                typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \
-                assert(_b);                                             \
-                if (!_a) {                                              \
-                        if (!*_head) {                                  \
-                                _b->name##_next = NULL;                 \
-                                _b->name##_prev = NULL;                 \
-                                *_head = _b;                            \
-                        } else {                                        \
-                                typeof(*(head)) *_tail = (head);        \
-                                while (_tail->name##_next)              \
-                                        _tail = _tail->name##_next;     \
-                                _b->name##_next = NULL;                 \
-                                _b->name##_prev = _tail;                \
-                                _tail->name##_next = _b;                \
-                        }                                               \
-                } else {                                                \
-                        if ((_b->name##_prev = _a->name##_prev))        \
-                                _b->name##_prev->name##_next = _b;      \
-                        else                                            \
-                                *_head = _b;                            \
-                        _b->name##_next = _a;                           \
-                        _a->name##_prev = _b;                           \
-                }                                                       \
-        } while (false)
-
-#define LIST_JUST_US(name,item)                                         \
-        (!(item)->name##_prev && !(item)->name##_next)                  \
-
-#define LIST_FOREACH(name,i,head)                                       \
-        for ((i) = (head); (i); (i) = (i)->name##_next)
-
-#define LIST_FOREACH_SAFE(name,i,n,head)                                \
-        for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n))
-
-#define LIST_FOREACH_BEFORE(name,i,p)                                   \
-        for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev)
-
-#define LIST_FOREACH_AFTER(name,i,p)                                    \
-        for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next)
-
-/* Iterate through all the members of the list p is included in, but skip over p */
-#define LIST_FOREACH_OTHERS(name,i,p)                                   \
-        for (({                                                         \
-                (i) = (p);                                              \
-                while ((i) && (i)->name##_prev)                         \
-                        (i) = (i)->name##_prev;                         \
-                if ((i) == (p))                                         \
-                        (i) = (p)->name##_next;                         \
-             });                                                        \
-             (i);                                                       \
-             (i) = (i)->name##_next == (p) ? (p)->name##_next : (i)->name##_next)
-
-/* Loop starting from p->next until p->prev.
-   p can be adjusted meanwhile. */
-#define LIST_LOOP_BUT_ONE(name,i,head,p)                                \
-        for ((i) = (p)->name##_next ? (p)->name##_next : (head);        \
-             (i) != (p);                                                \
-             (i) = (i)->name##_next ? (i)->name##_next : (head))
-
-#define LIST_IS_EMPTY(head)                                             \
-        (!(head))
-
-/* Join two lists tail to head: a->b, c->d to a->b->c->d and de-initialise second list */
-#define LIST_JOIN(name,a,b)                                             \
-        do {                                                            \
-                assert(b);                                              \
-                if (!(a))                                               \
-                        (a) = (b);                                      \
-                else {                                                  \
-                        typeof(*(a)) *_head = (b), *_tail;              \
-                        LIST_FIND_TAIL(name, (a), _tail);               \
-                        _tail->name##_next = _head;                     \
-                        _head->name##_prev = _tail;                     \
-                }                                                       \
-                (b) = NULL;                                             \
-        } while (false)
diff --git a/shared/systemd/src/basic/log.h b/shared/systemd/src/basic/log.h
deleted file mode 100644
index ee2e4839..00000000
--- a/shared/systemd/src/basic/log.h
+++ /dev/null
@@ -1,401 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <syslog.h>
-
-#include "macro.h"
-
-/* Some structures we reference but don't want to pull in headers for */
-struct iovec;
-struct signalfd_siginfo;
-
-typedef enum LogRealm {
-        LOG_REALM_SYSTEMD,
-        LOG_REALM_UDEV,
-        _LOG_REALM_MAX,
-} LogRealm;
-
-#ifndef LOG_REALM
-#  define LOG_REALM LOG_REALM_SYSTEMD
-#endif
-
-typedef enum LogTarget{
-        LOG_TARGET_CONSOLE,
-        LOG_TARGET_CONSOLE_PREFIXED,
-        LOG_TARGET_KMSG,
-        LOG_TARGET_JOURNAL,
-        LOG_TARGET_JOURNAL_OR_KMSG,
-        LOG_TARGET_SYSLOG,
-        LOG_TARGET_SYSLOG_OR_KMSG,
-        LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */
-        LOG_TARGET_NULL,
-        _LOG_TARGET_MAX,
-        _LOG_TARGET_INVALID = -1
-} LogTarget;
-
-/* Note to readers: << and >> have lower precedence than & and | */
-#define LOG_REALM_PLUS_LEVEL(realm, level)  ((realm) << 10 | (level))
-#define LOG_REALM_REMOVE_LEVEL(realm_level) ((realm_level) >> 10)
-#define SYNTHETIC_ERRNO(num)                (1 << 30 | (num))
-#define IS_SYNTHETIC_ERRNO(val)             ((val) >> 30 & 1)
-#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);
-int log_set_max_level_from_string_realm(LogRealm realm, const char *e);
-#define log_set_max_level_from_string(e)        \
-        log_set_max_level_from_string_realm(LOG_REALM, (e))
-
-void log_show_color(bool b);
-bool log_get_show_color(void) _pure_;
-void log_show_location(bool b);
-bool log_get_show_location(void) _pure_;
-void log_show_time(bool b);
-bool log_get_show_time(void) _pure_;
-void log_show_tid(bool b);
-bool log_get_show_tid(void) _pure_;
-
-int log_show_color_from_string(const char *e);
-int log_show_location_from_string(const char *e);
-int log_show_time_from_string(const char *e);
-int log_show_tid_from_string(const char *e);
-
-LogTarget log_get_target(void) _pure_;
-#if 0 /* NM_IGNORED */
-int log_get_max_level_realm(LogRealm realm) _pure_;
-#endif /* NM_IGNORED */
-#define log_get_max_level()                     \
-        log_get_max_level_realm(LOG_REALM)
-
-/* Functions below that open and close logs or configure logging based on the
- * environment should not be called from library code — this is always a job
- * for the application itself.
- */
-
-#if 0 /* NM_IGNORED */
-assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1);
-#define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1])
-#endif /* NM_IGNORED */
-#define PROJECT_FILE __FILE__
-
-int log_open(void);
-void log_close(void);
-void log_forget_fds(void);
-
-void log_parse_environment_realm(LogRealm realm);
-void log_parse_environment_cli_realm(LogRealm realm);
-#define log_parse_environment() \
-        log_parse_environment_realm(LOG_REALM)
-#define log_parse_environment_cli() \
-        log_parse_environment_cli_realm(LOG_REALM)
-
-#if 0 /* NM_IGNORED */
-int log_dispatch_internal(
-                int level,
-                int error,
-                const char *file,
-                int line,
-                const char *func,
-                const char *object_field,
-                const char *object,
-                const char *extra,
-                const char *extra_field,
-                char *buffer);
-
-int log_internal_realm(
-                int level,
-                int error,
-                const char *file,
-                int line,
-                const char *func,
-                const char *format, ...) _printf_(6,7);
-#endif /* NM_IGNORED */
-#define log_internal(level, ...) \
-        log_internal_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__)
-
-#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,
-                int error,
-                const char *file,
-                int line,
-                const char *func,
-                const char *format,
-                va_list ap) _printf_(6,0);
-#define log_internalv(level, ...) \
-        log_internalv_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__)
-
-/* Realm is fixed to LOG_REALM_SYSTEMD for those */
-int log_object_internalv(
-                int level,
-                int error,
-                const char *file,
-                int line,
-                const char *func,
-                const char *object_field,
-                const char *object,
-                const char *extra_field,
-                const char *extra,
-                const char *format,
-                va_list ap) _printf_(10,0);
-
-int log_object_internal(
-                int level,
-                int error,
-                const char *file,
-                int line,
-                const char *func,
-                const char *object_field,
-                const char *object,
-                const char *extra_field,
-                const char *extra,
-                const char *format, ...) _printf_(10,11);
-
-int log_struct_internal(
-                int level,
-                int error,
-                const char *file,
-                int line,
-                const char *func,
-                const char *format, ...) _printf_(6,0) _sentinel_;
-
-int log_oom_internal(
-                int level,
-                const char *file,
-                int line,
-                const char *func);
-#endif /* NM_IGNORED */
-#define log_oom_internal(realm, file, line, func) \
-    log_internal_realm (LOG_REALM_PLUS_LEVEL (realm, LOG_ERR), \
-                        ENOMEM, file, line, func, "Out of memory.")
-
-#if 0 /* NM_IGNORED */
-int log_format_iovec(
-                struct iovec *iovec,
-                size_t iovec_len,
-                size_t *n,
-                bool newline_separator,
-                int error,
-                const char *format,
-                va_list ap) _printf_(6, 0);
-
-int log_struct_iovec_internal(
-                int level,
-                int error,
-                const char *file,
-                int line,
-                const char *func,
-                const struct iovec *input_iovec,
-                size_t n_input_iovec);
-
-/* This modifies the buffer passed! */
-int log_dump_internal(
-                int level,
-                int error,
-                const char *file,
-                int line,
-                const char *func,
-                char *buffer);
-
-/* Logging for various assertions */
-_noreturn_ void log_assert_failed_realm(
-                LogRealm realm,
-                const char *text,
-                const char *file,
-                int line,
-                const char *func);
-#define log_assert_failed(text, ...) \
-        log_assert_failed_realm(LOG_REALM, (text), __VA_ARGS__)
-
-_noreturn_ void log_assert_failed_unreachable_realm(
-                LogRealm realm,
-                const char *text,
-                const char *file,
-                int line,
-                const char *func);
-#define log_assert_failed_unreachable(text, ...) \
-        log_assert_failed_unreachable_realm(LOG_REALM, (text), __VA_ARGS__)
-
-void log_assert_failed_return_realm(
-                LogRealm realm,
-                const char *text,
-                const char *file,
-                int line,
-                const char *func);
-#define log_assert_failed_return(text, ...) \
-        log_assert_failed_return_realm(LOG_REALM, (text), __VA_ARGS__)
-
-#define log_dispatch(level, error, buffer)                              \
-        log_dispatch_internal(level, error, PROJECT_FILE, __LINE__, __func__, NULL, NULL, NULL, NULL, buffer)
-#endif /* NM_IGNORED */
-
-/* Logging with level */
-#define log_full_errno_realm(realm, level, error, ...)                  \
-        ({                                                              \
-                int _level = (level), _e = (error), _realm = (realm);   \
-                (log_get_max_level_realm(_realm) >= LOG_PRI(_level))    \
-                        ? log_internal_realm(LOG_REALM_PLUS_LEVEL(_realm, _level), _e, \
-                                             PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
-                        : -ERRNO_VALUE(_e);                             \
-        })
-
-#define log_full_errno(level, error, ...)                               \
-        log_full_errno_realm(LOG_REALM, (level), (error), __VA_ARGS__)
-
-#define log_full(level, ...) (void) log_full_errno((level), 0, __VA_ARGS__)
-
-int log_emergency_level(void);
-
-/* Normal logging */
-#define log_debug(...)     log_full_errno(LOG_DEBUG, 0, __VA_ARGS__)
-#define log_info(...)      log_full(LOG_INFO,    __VA_ARGS__)
-#define log_notice(...)    log_full(LOG_NOTICE,  __VA_ARGS__)
-#define log_warning(...)   log_full(LOG_WARNING, __VA_ARGS__)
-#define log_error(...)     log_full(LOG_ERR,     __VA_ARGS__)
-#define log_emergency(...) log_full(log_emergency_level(), __VA_ARGS__)
-
-/* Logging triggered by an errno-like error */
-#define log_debug_errno(error, ...)     log_full_errno(LOG_DEBUG,   error, __VA_ARGS__)
-#define log_info_errno(error, ...)      log_full_errno(LOG_INFO,    error, __VA_ARGS__)
-#define log_notice_errno(error, ...)    log_full_errno(LOG_NOTICE,  error, __VA_ARGS__)
-#define log_warning_errno(error, ...)   log_full_errno(LOG_WARNING, error, __VA_ARGS__)
-#define log_error_errno(error, ...)     log_full_errno(LOG_ERR,     error, __VA_ARGS__)
-#define log_emergency_errno(error, ...) log_full_errno(log_emergency_level(), error, __VA_ARGS__)
-
-#ifdef LOG_TRACE
-#  define log_trace(...) log_debug(__VA_ARGS__)
-#else
-#  define log_trace(...) do {} while (0)
-#endif
-
-/* Structured logging */
-#define log_struct_errno(level, error, ...) \
-        log_struct_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
-                            error, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__, NULL)
-#define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__)
-
-#define log_struct_iovec_errno(level, error, iovec, n_iovec)            \
-        log_struct_iovec_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
-                                  error, PROJECT_FILE, __LINE__, __func__, iovec, n_iovec)
-#define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec)
-
-/* This modifies the buffer passed! */
-#define log_dump(level, buffer) \
-        log_dump_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
-                          0, PROJECT_FILE, __LINE__, __func__, buffer)
-
-#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_;
-
-const char *log_target_to_string(LogTarget target) _const_;
-LogTarget log_target_from_string(const char *s) _pure_;
-
-/* Helper to prepare various field for structured logging */
-#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
-
-void log_received_signal(int level, const struct signalfd_siginfo *si);
-
-/* If turned on, any requests for a log target involving "syslog" will be implicitly upgraded to the equivalent journal target */
-void log_set_upgrade_syslog_to_journal(bool b);
-
-/* If turned on, and log_open() is called, we'll not use STDERR_FILENO for logging ever, but rather open /dev/console */
-void log_set_always_reopen_console(bool b);
-
-/* If turned on, we'll open the log stream implicitly if needed on each individual log call. This is normally not
- * desired as we want to reuse our logging streams. It is useful however  */
-void log_set_open_when_needed(bool b);
-
-/* If turned on, then we'll never use IPC-based logging, i.e. never log to syslog or the journal. We'll only log to
- * stderr, the console or kmsg */
-void log_set_prohibit_ipc(bool b);
-
-int log_dup_console(void);
-
-#if 0 /* NM_IGNORED */
-int log_syntax_internal(
-                const char *unit,
-                int level,
-                const char *config_file,
-                unsigned config_line,
-                int error,
-                const char *file,
-                int line,
-                const char *func,
-                const char *format, ...) _printf_(9, 10);
-#endif /* NM_IGNORED */
-#define log_syntax_internal(unit, level, config_file, config_line, error, file, line, func, format, ...) \
-    log_internal_realm((level), (error), file, (line), (func), "syntax[%s]: "format, (config_file), __VA_ARGS__) \
-
-int log_syntax_invalid_utf8_internal(
-                const char *unit,
-                int level,
-                const char *config_file,
-                unsigned config_line,
-                const char *file,
-                int line,
-                const char *func,
-                const char *rvalue);
-
-#define log_syntax(unit, level, config_file, config_line, error, ...)   \
-        ({                                                              \
-                int _level = (level), _e = (error);                     \
-                (log_get_max_level() >= LOG_PRI(_level))                \
-                        ? log_syntax_internal(unit, _level, config_file, config_line, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
-                        : -ERRNO_VALUE(_e);                             \
-        })
-
-#define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \
-        ({                                                              \
-                int _level = (level);                                   \
-                (log_get_max_level() >= LOG_PRI(_level))                \
-                        ? log_syntax_invalid_utf8_internal(unit, _level, config_file, config_line, PROJECT_FILE, __LINE__, __func__, rvalue) \
-                        : -EINVAL;                                      \
-        })
-
-#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
-
-void log_setup_service(void);
-void log_setup_cli(void);
diff --git a/shared/systemd/src/basic/macro.h b/shared/systemd/src/basic/macro.h
deleted file mode 100644
index 34416b3d..00000000
--- a/shared/systemd/src/basic/macro.h
+++ /dev/null
@@ -1,666 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <sys/param.h>
-#include <sys/sysmacros.h>
-#include <sys/types.h>
-
-#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
-#ifdef __clang__
-#  define _alloc_(...)
-#else
-#  define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__)))
-#endif
-#define _sentinel_ __attribute__((__sentinel__))
-#define _section_(x) __attribute__((__section__(x)))
-#define _used_ __attribute__((__used__))
-#define _unused_ __attribute__((__unused__))
-#define _destructor_ __attribute__((__destructor__))
-#define _pure_ __attribute__((__pure__))
-#define _const_ __attribute__((__const__))
-#define _deprecated_ __attribute__((__deprecated__))
-#define _packed_ __attribute__((__packed__))
-#define _malloc_ __attribute__((__malloc__))
-#define _weak_ __attribute__((__weak__))
-#define _likely_(x) (__builtin_expect(!!(x), 1))
-#define _unlikely_(x) (__builtin_expect(!!(x), 0))
-#define _public_ __attribute__((__visibility__("default")))
-#define _hidden_ __attribute__((__visibility__("hidden")))
-#define _weakref_(x) __attribute__((__weakref__(#x)))
-#define _align_(x) __attribute__((__aligned__(x)))
-#define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
-#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
-#define _cleanup_(x) __attribute__((__cleanup__(x)))
-#if __GNUC__ >= 7
-#define _fallthrough_ __attribute__((__fallthrough__))
-#else
-#define _fallthrough_
-#endif
-/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
- * compiler versions */
-#ifndef _noreturn_
-#if __STDC_VERSION__ >= 201112L
-#define _noreturn_ _Noreturn
-#else
-#define _noreturn_ __attribute__((__noreturn__))
-#endif
-#endif
-
-#if !defined(HAS_FEATURE_MEMORY_SANITIZER)
-#  if defined(__has_feature)
-#    if __has_feature(memory_sanitizer)
-#      define HAS_FEATURE_MEMORY_SANITIZER 1
-#    endif
-#  endif
-#  if !defined(HAS_FEATURE_MEMORY_SANITIZER)
-#    define HAS_FEATURE_MEMORY_SANITIZER 0
-#  endif
-#endif
-
-#if !defined(HAS_FEATURE_ADDRESS_SANITIZER)
-#  ifdef __SANITIZE_ADDRESS__
-#      define HAS_FEATURE_ADDRESS_SANITIZER 1
-#  elif defined(__has_feature)
-#    if __has_feature(address_sanitizer)
-#      define HAS_FEATURE_ADDRESS_SANITIZER 1
-#    endif
-#  endif
-#  if !defined(HAS_FEATURE_ADDRESS_SANITIZER)
-#    define HAS_FEATURE_ADDRESS_SANITIZER 0
-#  endif
-#endif
-
-/* Note: on GCC "no_sanitize_address" is a function attribute only, on llvm it may also be applied to global
- * variables. We define a specific macro which knows this. Note that on GCC we don't need this decorator so much, since
- * our primary usecase for this attribute is registration structures placed in named ELF sections which shall not be
- * padded, but GCC doesn't pad those anyway if AddressSanitizer is enabled. */
-#if HAS_FEATURE_ADDRESS_SANITIZER && defined(__clang__)
-#define _variable_no_sanitize_address_ __attribute__((__no_sanitize_address__))
-#else
-#define _variable_no_sanitize_address_
-#endif
-
-/* Apparently there's no has_feature() call defined to check for ubsan, hence let's define this
- * unconditionally on llvm */
-#if defined(__clang__)
-#define _function_no_sanitize_float_cast_overflow_ __attribute__((no_sanitize("float-cast-overflow")))
-#else
-#define _function_no_sanitize_float_cast_overflow_
-#endif
-
-#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined (__clang__)
-/* Temporarily disable some warnings */
-#define DISABLE_WARNING_DEPRECATED_DECLARATIONS                         \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
-
-#define DISABLE_WARNING_FORMAT_NONLITERAL                               \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
-
-#define DISABLE_WARNING_MISSING_PROTOTYPES                              \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"")
-
-#define DISABLE_WARNING_NONNULL                                         \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wnonnull\"")
-
-#define DISABLE_WARNING_SHADOW                                          \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wshadow\"")
-
-#define DISABLE_WARNING_INCOMPATIBLE_POINTER_TYPES                      \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"")
-
-#if HAVE_WSTRINGOP_TRUNCATION
-#  define DISABLE_WARNING_STRINGOP_TRUNCATION                           \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wstringop-truncation\"")
-#else
-#  define DISABLE_WARNING_STRINGOP_TRUNCATION                           \
-        _Pragma("GCC diagnostic push")
-#endif
-
-#define DISABLE_WARNING_FLOAT_EQUAL \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"")
-
-#define DISABLE_WARNING_TYPE_LIMITS \
-        _Pragma("GCC diagnostic push");                                 \
-        _Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
-
-#define REENABLE_WARNING                                                \
-        _Pragma("GCC diagnostic pop")
-#else
-#define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT
-#define DISABLE_WARNING_FORMAT_NONLITERAL
-#define DISABLE_WARNING_MISSING_PROTOTYPES
-#define DISABLE_WARNING_NONNULL
-#define DISABLE_WARNING_SHADOW
-#define REENABLE_WARNING
-#endif
-
-/* automake test harness */
-#define EXIT_TEST_SKIP 77
-
-#define XSTRINGIFY(x) #x
-#define STRINGIFY(x) XSTRINGIFY(x)
-
-#define XCONCATENATE(x, y) x ## y
-#define CONCATENATE(x, y) XCONCATENATE(x, y)
-
-#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
-#define UNIQ __COUNTER__
-
-/* builtins */
-#if __SIZEOF_INT__ == 4
-#define BUILTIN_FFS_U32(x) __builtin_ffs(x);
-#elif __SIZEOF_LONG__ == 4
-#define BUILTIN_FFS_U32(x) __builtin_ffsl(x);
-#else
-#error "neither int nor long are four bytes long?!?"
-#endif
-
-/* Rounds up */
-
-#define ALIGN4(l) (((l) + 3) & ~3)
-#define ALIGN8(l) (((l) + 7) & ~7)
-
-#if __SIZEOF_POINTER__ == 8
-#define ALIGN(l) ALIGN8(l)
-#elif __SIZEOF_POINTER__ == 4
-#define ALIGN(l) ALIGN4(l)
-#else
-#error "Wut? Pointers are neither 4 nor 8 bytes long?"
-#endif
-
-#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) (p)))
-#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p)))
-#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p)))
-
-static inline size_t ALIGN_TO(size_t l, size_t ali) {
-        return ((l + ali - 1) & ~(ali - 1));
-}
-
-#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali)))
-
-/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */
-static inline unsigned long ALIGN_POWER2(unsigned long u) {
-
-        /* Avoid subtraction overflow */
-        if (u == 0)
-                return 0;
-
-        /* clz(0) is undefined */
-        if (u == 1)
-                return 1;
-
-        /* left-shift overflow is undefined */
-        if (__builtin_clzl(u - 1UL) < 1)
-                return 0;
-
-        return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL));
-}
-
-static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
-        size_t m;
-
-        /* Round up allocation sizes a bit to some reasonable, likely larger value. This is supposed to be
-         * used for cases which are likely called in an allocation loop of some form, i.e. that repetitively
-         * grow stuff, for example strv_extend() and suchlike.
-         *
-         * Note the difference to GREEDY_REALLOC() here, as this helper operates on a single size value only,
-         * and rounds up to next multiple of 2, needing no further counter.
-         *
-         * Note the benefits of direct ALIGN_POWER2() usage: type-safety for size_t, sane handling for very
-         * small (i.e. <= 2) and safe handling for very large (i.e. > SSIZE_MAX) values. */
-
-        if (l <= 2)
-                return 2; /* Never allocate less than 2 of something.  */
-
-        m = ALIGN_POWER2(l);
-        if (m == 0) /* overflow? */
-                return l;
-
-        return m;
-}
-
-#ifndef __COVERITY__
-#  define VOID_0 ((void)0)
-#else
-#  define VOID_0 ((void*)0)
-#endif
-
-#define ELEMENTSOF(x)                                                   \
-        (__builtin_choose_expr(                                         \
-                !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
-                sizeof(x)/sizeof((x)[0]),                               \
-                VOID_0))
-
-/*
- * STRLEN - return the length of a string literal, minus the trailing NUL byte.
- *          Contrary to strlen(), this is a constant expression.
- * @x: a string literal.
- */
-#define STRLEN(x) (sizeof(""x"") - 1)
-
-/*
- * container_of - cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- */
-#define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member)
-#define __container_of(uniq, ptr, type, member)                         \
-        ({                                                              \
-                const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \
-                (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type, member) ); \
-        })
-
-#undef MAX
-#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b))
-#define __MAX(aq, a, bq, b)                             \
-        ({                                              \
-                const typeof(a) UNIQ_T(A, aq) = (a);    \
-                const typeof(b) UNIQ_T(B, bq) = (b);    \
-                UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
-        })
-
-/* evaluates to (void) if _A or _B are not constant or of different types */
-#define CONST_MAX(_A, _B) \
-        (__builtin_choose_expr(                                         \
-                __builtin_constant_p(_A) &&                             \
-                __builtin_constant_p(_B) &&                             \
-                __builtin_types_compatible_p(typeof(_A), typeof(_B)),   \
-                ((_A) > (_B)) ? (_A) : (_B),                            \
-                VOID_0))
-
-/* takes two types and returns the size of the larger one */
-#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; }))
-
-#define MAX3(x, y, z)                                   \
-        ({                                              \
-                const typeof(x) _c = MAX(x, y);         \
-                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)                             \
-        ({                                              \
-                const typeof(a) UNIQ_T(A, aq) = (a);    \
-                const typeof(b) UNIQ_T(B, bq) = (b);    \
-                UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
-        })
-
-/* evaluates to (void) if _A or _B are not constant or of different types */
-#define CONST_MIN(_A, _B) \
-        (__builtin_choose_expr(                                         \
-                __builtin_constant_p(_A) &&                             \
-                __builtin_constant_p(_B) &&                             \
-                __builtin_types_compatible_p(typeof(_A), typeof(_B)),   \
-                ((_A) < (_B)) ? (_A) : (_B),                            \
-                VOID_0))
-
-#define MIN3(x, y, z)                                   \
-        ({                                              \
-                const typeof(x) _c = MIN(x, y);         \
-                MIN(_c, z);                             \
-        })
-
-#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
-#define __LESS_BY(aq, a, bq, b)                         \
-        ({                                              \
-                const typeof(a) UNIQ_T(A, aq) = (a);    \
-                const typeof(b) UNIQ_T(B, bq) = (b);    \
-                UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) - UNIQ_T(B, bq) : 0; \
-        })
-
-#define CMP(a, b) __CMP(UNIQ, (a), UNIQ, (b))
-#define __CMP(aq, a, bq, b)                             \
-        ({                                              \
-                const typeof(a) UNIQ_T(A, aq) = (a);    \
-                const typeof(b) UNIQ_T(B, bq) = (b);    \
-                UNIQ_T(A, aq) < UNIQ_T(B, bq) ? -1 :    \
-                UNIQ_T(A, aq) > UNIQ_T(B, bq) ? 1 : 0;  \
-        })
-
-#undef CLAMP
-#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high))
-#define __CLAMP(xq, x, lowq, low, highq, high)                          \
-        ({                                                              \
-                const typeof(x) UNIQ_T(X, xq) = (x);                    \
-                const typeof(low) UNIQ_T(LOW, lowq) = (low);            \
-                const typeof(high) UNIQ_T(HIGH, highq) = (high);        \
-                        UNIQ_T(X, xq) > UNIQ_T(HIGH, highq) ?           \
-                                UNIQ_T(HIGH, highq) :                   \
-                                UNIQ_T(X, xq) < UNIQ_T(LOW, lowq) ?     \
-                                        UNIQ_T(LOW, lowq) :             \
-                                        UNIQ_T(X, xq);                  \
-        })
-
-/* [(x + y - 1) / y] suffers from an integer overflow, even though the
- * computation should be possible in the given type. Therefore, we use
- * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the
- * quotient and the remainder, so both should be equally fast. */
-#define DIV_ROUND_UP(x, y) __DIV_ROUND_UP(UNIQ, (x), UNIQ, (y))
-#define __DIV_ROUND_UP(xq, x, yq, y)                                    \
-        ({                                                              \
-                const typeof(x) UNIQ_T(X, xq) = (x);                    \
-                const typeof(y) UNIQ_T(Y, yq) = (y);                    \
-                (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \
-        })
-
-#ifdef __COVERITY__
-
-/* Use special definitions of assertion macros in order to prevent
- * false positives of ASSERT_SIDE_EFFECT on Coverity static analyzer
- * for uses of assert_se() and assert_return().
- *
- * These definitions make expression go through a (trivial) function
- * call to ensure they are not discarded. Also use ! or !! to ensure
- * the boolean expressions are seen as such.
- *
- * This technique has been described and recommended in:
- * https://community.synopsys.com/s/question/0D534000046Yuzb/suppressing-assertsideeffect-for-functions-that-allow-for-sideeffects
- */
-
-extern void __coverity_panic__(void);
-
-static inline void __coverity_check__(int condition) {
-        if (!condition)
-                __coverity_panic__();
-}
-
-static inline int __coverity_check_and_return__(int condition) {
-        return condition;
-}
-
-#define assert_message_se(expr, message) __coverity_check__(!!(expr))
-
-#define assert_log(expr, message) __coverity_check_and_return__(!!(expr))
-
-#else  /* ! __COVERITY__ */
-
-#define assert_message_se(expr, message)                                \
-        do {                                                            \
-                if (_unlikely_(!(expr)))                                \
-                        log_assert_failed(message, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__); \
-        } while (false)
-
-#define assert_log(expr, message) ((_likely_(expr))                     \
-        ? (true)                                                        \
-        : (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__), false))
-
-#endif  /* __COVERITY__ */
-
-#define assert_se(expr) assert_message_se(expr, #expr)
-
-/* We override the glibc assert() here. */
-#undef assert
-#ifdef NDEBUG
-#define assert(expr) do {} while (false)
-#else
-#define assert(expr) assert_message_se(expr, #expr)
-#endif
-
-#define assert_not_reached(t)                                           \
-        log_assert_failed_unreachable(t, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__)
-
-#if defined(static_assert)
-#define assert_cc(expr)                                                 \
-        static_assert(expr, #expr)
-#else
-#define assert_cc(expr)                                                 \
-        struct CONCATENATE(_assert_struct_, __COUNTER__) {              \
-                char x[(expr) ? 0 : -1];                                \
-        }
-#endif
-
-#define assert_return(expr, r)                                          \
-        do {                                                            \
-                if (!assert_log(expr, #expr))                           \
-                        return (r);                                     \
-        } while (false)
-
-#define assert_return_errno(expr, r, err)                               \
-        do {                                                            \
-                if (!assert_log(expr, #expr)) {                         \
-                        errno = err;                                    \
-                        return (r);                                     \
-                }                                                       \
-        } while (false)
-
-#define return_with_errno(r, err)                     \
-        do {                                          \
-                errno = abs(err);                     \
-                return r;                             \
-        } while (false)
-
-#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
-#define INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
-#define PTR_TO_UINT(p) ((unsigned) ((uintptr_t) (p)))
-#define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u)))
-
-#define PTR_TO_LONG(p) ((long) ((intptr_t) (p)))
-#define LONG_TO_PTR(u) ((void *) ((intptr_t) (u)))
-#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)))
-#define UINT32_TO_PTR(u) ((void *) ((uintptr_t) (u)))
-
-#define PTR_TO_INT64(p) ((int64_t) ((intptr_t) (p)))
-#define INT64_TO_PTR(u) ((void *) ((intptr_t) (u)))
-#define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p)))
-#define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u)))
-
-#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p)))
-#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u)))
-
-#define CHAR_TO_STR(x) ((char[2]) { x, 0 })
-
-#define char_array_0(x) x[sizeof(x)-1] = 0;
-
-#define sizeof_field(struct_type, member) sizeof(((struct_type *) 0)->member)
-
-/* Returns the number of chars needed to format variables of the
- * specified type as a decimal string. Adds in extra space for a
- * negative '-' prefix (hence works correctly on signed
- * types). Includes space for the trailing NUL. */
-#define DECIMAL_STR_MAX(type)                                           \
-        (2+(sizeof(type) <= 1 ? 3 :                                     \
-            sizeof(type) <= 2 ? 5 :                                     \
-            sizeof(type) <= 4 ? 10 :                                    \
-            sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)])))
-
-#define DECIMAL_STR_WIDTH(x)                            \
-        ({                                              \
-                typeof(x) _x_ = (x);                    \
-                unsigned ans = 1;                       \
-                while ((_x_ /= 10) != 0)                \
-                        ans++;                          \
-                ans;                                    \
-        })
-
-#define UPDATE_FLAG(orig, flag, b)                      \
-        ((b) ? ((orig) | (flag)) : ((orig) & ~(flag)))
-#define SET_FLAG(v, flag, b) \
-        (v) = UPDATE_FLAG(v, flag, b)
-#define FLAGS_SET(v, flags) \
-        ((~(v) & (flags)) == 0)
-
-#define CASE_F(X) case X:
-#define CASE_F_1(CASE, X) CASE_F(X)
-#define CASE_F_2(CASE, X, ...)  CASE(X) CASE_F_1(CASE, __VA_ARGS__)
-#define CASE_F_3(CASE, X, ...)  CASE(X) CASE_F_2(CASE, __VA_ARGS__)
-#define CASE_F_4(CASE, X, ...)  CASE(X) CASE_F_3(CASE, __VA_ARGS__)
-#define CASE_F_5(CASE, X, ...)  CASE(X) CASE_F_4(CASE, __VA_ARGS__)
-#define CASE_F_6(CASE, X, ...)  CASE(X) CASE_F_5(CASE, __VA_ARGS__)
-#define CASE_F_7(CASE, X, ...)  CASE(X) CASE_F_6(CASE, __VA_ARGS__)
-#define CASE_F_8(CASE, X, ...)  CASE(X) CASE_F_7(CASE, __VA_ARGS__)
-#define CASE_F_9(CASE, X, ...)  CASE(X) CASE_F_8(CASE, __VA_ARGS__)
-#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__)
-#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__)
-#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__)
-#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__)
-#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__)
-#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__)
-#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__)
-#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__)
-#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__)
-#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__)
-#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__)
-
-#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
-#define FOR_EACH_MAKE_CASE(...) \
-        GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \
-                               CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
-                   (CASE_F,__VA_ARGS__)
-
-#define IN_SET(x, ...)                          \
-        ({                                      \
-                bool _found = false;            \
-                /* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as  \
-                 * type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
-                 * the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that  \
-                 * doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */         \
-                static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \
-                assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
-                switch(x) {                     \
-                FOR_EACH_MAKE_CASE(__VA_ARGS__) \
-                        _found = true;          \
-                        break;                  \
-                default:                        \
-                        break;                  \
-                }                               \
-                _found;                         \
-        })
-
-#define SWAP_TWO(x, y) do {                        \
-                typeof(x) _t = (x);                \
-                (x) = (y);                         \
-                (y) = (_t);                        \
-        } while (false)
-
-#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
-#define STRV_MAKE_EMPTY ((char*[1]) { NULL })
-
-/* 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
- * version */
-#ifndef thread_local
-/*
- * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
- * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
- */
-#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
-#define thread_local _Thread_local
-#else
-#define thread_local __thread
-#endif
-#endif
-
-#define DEFINE_TRIVIAL_DESTRUCTOR(name, type, func)             \
-        static inline void name(type *p) {                      \
-                func(p);                                        \
-        }
-
-#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func)                 \
-        static inline void func##p(type *p) {                   \
-                if (*p)                                         \
-                        func(*p);                               \
-        }
-
-#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope)             \
-        scope type *name##_ref(type *p) {                       \
-                if (!p)                                         \
-                        return NULL;                            \
-                                                                \
-                assert(p->n_ref > 0);                           \
-                p->n_ref++;                                     \
-                return p;                                       \
-        }
-
-#define _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, scope) \
-        scope type *name##_unref(type *p) {                      \
-                if (!p)                                          \
-                        return NULL;                             \
-                                                                 \
-                assert(p->n_ref > 0);                            \
-                p->n_ref--;                                      \
-                if (p->n_ref > 0)                                \
-                        return NULL;                             \
-                                                                 \
-                return free_func(p);                             \
-        }
-
-#define DEFINE_TRIVIAL_REF_FUNC(type, name)     \
-        _DEFINE_TRIVIAL_REF_FUNC(type, name,)
-#define DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name)     \
-        _DEFINE_TRIVIAL_REF_FUNC(type, name, static)
-#define DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name)      \
-        _DEFINE_TRIVIAL_REF_FUNC(type, name, _public_)
-
-#define DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func)        \
-        _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func,)
-#define DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func)        \
-        _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, static)
-#define DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func)         \
-        _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, _public_)
-
-#define DEFINE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func)    \
-        DEFINE_TRIVIAL_REF_FUNC(type, name);                    \
-        DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func);
-
-#define DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func)    \
-        DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name);                    \
-        DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func);
-
-#define DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(type, name, free_func)    \
-        DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name);                    \
-        DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func);
-
-/* A macro to force copying of a variable from memory. This is useful whenever we want to read something from
- * memory and want to make sure the compiler won't optimize away the destination variable for us. It's not
- * supposed to be a full CPU memory barrier, i.e. CPU is still allowed to reorder the reads, but it is not
- * allowed to remove our local copies of the variables. We want this to work for unaligned memory, hence
- * memcpy() is great for our purposes. */
-#define READ_NOW(x)                                                     \
-        ({                                                              \
-                typeof(x) _copy;                                        \
-                memcpy(&_copy, &(x), sizeof(_copy));                    \
-                asm volatile ("" : : : "memory");                       \
-                _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
deleted file mode 100644
index 7ee7c94e..00000000
--- a/shared/systemd/src/basic/memory-util.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <unistd.h>
-
-#include "memory-util.h"
-
-size_t page_size(void) {
-        static thread_local size_t pgsz = 0;
-        long r;
-
-        if (_likely_(pgsz > 0))
-                return pgsz;
-
-        r = sysconf(_SC_PAGESIZE);
-        assert(r > 0);
-
-        pgsz = (size_t) r;
-        return pgsz;
-}
-
-bool memeqzero(const void *data, size_t length) {
-        /* Does the buffer consist entirely of NULs?
-         * Copied from https://github.com/systemd/casync/, copied in turn from
-         * https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
-         * which is licensed CC-0.
-         */
-
-        const uint8_t *p = data;
-        size_t i;
-
-        /* Check first 16 bytes manually */
-        for (i = 0; i < 16; i++, length--) {
-                if (length == 0)
-                        return true;
-                if (p[i])
-                        return false;
-        }
-
-        /* Now we know first 16 bytes are NUL, memcmp with self.  */
-        return memcmp(data, p + i, length) == 0;
-}
-
-#if !HAVE_EXPLICIT_BZERO
-/*
- * The pointer to memset() is volatile so that compiler must de-reference the pointer and can't assume that
- * it points to any function in particular (such as memset(), which it then might further "optimize"). This
- * approach is inspired by openssl's crypto/mem_clr.c.
- */
-typedef void *(*memset_t)(void *,int,size_t);
-
-static volatile memset_t memset_func = memset;
-
-void* explicit_bzero_safe(void *p, size_t l) {
-        if (l > 0)
-                memset_func(p, '\0', l);
-
-        return p;
-}
-#endif
diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h
deleted file mode 100644
index 179edd24..00000000
--- a/shared/systemd/src/basic/memory-util.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <inttypes.h>
-#include <malloc.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "alloc-util.h"
-#include "macro.h"
-
-size_t page_size(void) _pure_;
-#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
-#define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1))
-#define PAGE_OFFSET(l) ((l) & (page_size() - 1))
-
-/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
-static inline void memcpy_safe(void *dst, const void *src, size_t n) {
-        if (n == 0)
-                return;
-        assert(src);
-        memcpy(dst, src, n);
-}
-
-/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */
-static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
-        if (n == 0)
-                return 0;
-        assert(s1);
-        assert(s2);
-        return memcmp(s1, s2, n);
-}
-
-/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */
-static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) {
-        return memcmp_safe(s1, s2, MIN(n1, n2))
-            ?: CMP(n1, n2);
-}
-
-#define memzero(x,l)                                            \
-        ({                                                      \
-                size_t _l_ = (l);                               \
-                if (_l_ > 0)                                    \
-                        memset(x, 0, _l_);                      \
-        })
-
-#define zero(x) (memzero(&(x), sizeof(x)))
-
-bool memeqzero(const void *data, size_t length);
-
-#define eqzero(x) memeqzero(x, sizeof(x))
-
-static inline void *mempset(void *s, int c, size_t n) {
-        memset(s, c, n);
-        return (uint8_t*)s + n;
-}
-
-/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
-static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
-
-        if (needlelen <= 0)
-                return (void*) haystack;
-
-        if (haystacklen < needlelen)
-                return NULL;
-
-        assert(haystack);
-        assert(needle);
-
-        return memmem(haystack, haystacklen, needle, needlelen);
-}
-
-#if HAVE_EXPLICIT_BZERO
-static inline void* explicit_bzero_safe(void *p, size_t l) {
-        if (l > 0)
-                explicit_bzero(p, l);
-
-        return p;
-}
-#else
-void *explicit_bzero_safe(void *p, size_t l);
-#endif
-
-static inline void* erase_and_free(void *p) {
-        size_t l;
-
-        if (!p)
-                return NULL;
-
-        l = malloc_usable_size(p);
-        explicit_bzero_safe(p, l);
-        return mfree(p);
-}
-
-static inline void erase_and_freep(void *p) {
-        erase_and_free(*(void**) p);
-}
-
-/* Use with _cleanup_ to erase a single 'char' when leaving scope */
-static inline void erase_char(char *p) {
-        explicit_bzero_safe(p, sizeof(char));
-}
diff --git a/shared/systemd/src/basic/mempool.c b/shared/systemd/src/basic/mempool.c
deleted file mode 100644
index 46c44914..00000000
--- a/shared/systemd/src/basic/mempool.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "env-util.h"
-#include "macro.h"
-#include "memory-util.h"
-#include "mempool.h"
-#include "process-util.h"
-#include "util.h"
-
-struct pool {
-        struct pool *next;
-        size_t n_tiles;
-        size_t n_used;
-};
-
-void* mempool_alloc_tile(struct mempool *mp) {
-        size_t i;
-
-        /* When a tile is released we add it to the list and simply
-         * place the next pointer at its offset 0. */
-
-        assert(mp->tile_size >= sizeof(void*));
-        assert(mp->at_least > 0);
-
-        if (mp->freelist) {
-                void *r;
-
-                r = mp->freelist;
-                mp->freelist = * (void**) mp->freelist;
-                return r;
-        }
-
-        if (_unlikely_(!mp->first_pool) ||
-            _unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) {
-                size_t size, n;
-                struct pool *p;
-
-                n = mp->first_pool ? mp->first_pool->n_tiles : 0;
-                n = MAX(mp->at_least, n * 2);
-                size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*mp->tile_size);
-                n = (size - ALIGN(sizeof(struct pool))) / mp->tile_size;
-
-                p = malloc(size);
-                if (!p)
-                        return NULL;
-
-                p->next = mp->first_pool;
-                p->n_tiles = n;
-                p->n_used = 0;
-
-                mp->first_pool = p;
-        }
-
-        i = mp->first_pool->n_used++;
-
-        return ((uint8_t*) mp->first_pool) + ALIGN(sizeof(struct pool)) + i*mp->tile_size;
-}
-
-void* mempool_alloc0_tile(struct mempool *mp) {
-        void *p;
-
-        p = mempool_alloc_tile(mp);
-        if (p)
-                memzero(p, mp->tile_size);
-        return p;
-}
-
-void mempool_free_tile(struct mempool *mp, void *p) {
-        * (void**) p = mp->freelist;
-        mp->freelist = p;
-}
-
-bool mempool_enabled(void) {
-        static int b = -1;
-
-        if (!is_main_thread())
-                return false;
-
-        if (!mempool_use_allowed)
-                b = false;
-        if (b < 0)
-                b = getenv_bool("SYSTEMD_MEMPOOL") != 0;
-
-        return b;
-}
-
-#if VALGRIND
-void mempool_drop(struct mempool *mp) {
-        struct pool *p = mp->first_pool;
-        while (p) {
-                struct pool *n;
-                n = p->next;
-                free(p);
-                p = n;
-        }
-}
-#endif
diff --git a/shared/systemd/src/basic/mempool.h b/shared/systemd/src/basic/mempool.h
deleted file mode 100644
index 0fe2f278..00000000
--- a/shared/systemd/src/basic/mempool.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-#include <stddef.h>
-
-struct pool;
-
-struct mempool {
-        struct pool *first_pool;
-        void *freelist;
-        size_t tile_size;
-        unsigned at_least;
-};
-
-void* mempool_alloc_tile(struct mempool *mp);
-void* mempool_alloc0_tile(struct mempool *mp);
-void mempool_free_tile(struct mempool *mp, void *p);
-
-#define DEFINE_MEMPOOL(pool_name, tile_type, alloc_at_least) \
-static struct mempool pool_name = { \
-        .tile_size = sizeof(tile_type), \
-        .at_least = alloc_at_least, \
-}
-
-extern const bool mempool_use_allowed;
-bool mempool_enabled(void);
-
-#if VALGRIND
-void mempool_drop(struct mempool *mp);
-#endif
diff --git a/shared/systemd/src/basic/missing_fcntl.h b/shared/systemd/src/basic/missing_fcntl.h
deleted file mode 100644
index 00937d2a..00000000
--- a/shared/systemd/src/basic/missing_fcntl.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <fcntl.h>
-
-#ifndef F_LINUX_SPECIFIC_BASE
-#define F_LINUX_SPECIFIC_BASE 1024
-#endif
-
-#ifndef F_SETPIPE_SZ
-#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
-#endif
-
-#ifndef F_GETPIPE_SZ
-#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8)
-#endif
-
-#ifndef F_ADD_SEALS
-#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
-#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
-
-#define F_SEAL_SEAL     0x0001  /* prevent further seals from being set */
-#define F_SEAL_SHRINK   0x0002  /* prevent file from shrinking */
-#define F_SEAL_GROW     0x0004  /* prevent file from growing */
-#define F_SEAL_WRITE    0x0008  /* prevent writes */
-#endif
-
-#ifndef F_OFD_GETLK
-#define F_OFD_GETLK     36
-#define F_OFD_SETLK     37
-#define F_OFD_SETLKW    38
-#endif
-
-#ifndef MAX_HANDLE_SZ
-#define MAX_HANDLE_SZ 128
-#endif
-
-/* The precise definition of __O_TMPFILE is arch specific; use the
- * values defined by the kernel (note: some are hexa, some are octal,
- * duplicated as-is from the kernel definitions):
- * - alpha, parisc, sparc: each has a specific value;
- * - others: they use the "generic" value.
- */
-
-#ifndef __O_TMPFILE
-#if defined(__alpha__)
-#define __O_TMPFILE     0100000000
-#elif defined(__parisc__) || defined(__hppa__)
-#define __O_TMPFILE     0400000000
-#elif defined(__sparc__) || defined(__sparc64__)
-#define __O_TMPFILE     0x2000000
-#else
-#define __O_TMPFILE     020000000
-#endif
-#endif
-
-/* a horrid kludge trying to make sure that this will fail on old kernels */
-#ifndef O_TMPFILE
-#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
-#endif
diff --git a/shared/systemd/src/basic/missing_random.h b/shared/systemd/src/basic/missing_random.h
deleted file mode 100644
index 443b9136..00000000
--- a/shared/systemd/src/basic/missing_random.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#if USE_SYS_RANDOM_H
-#  include <sys/random.h>
-#else
-#  include <linux/random.h>
-#endif
-
-#ifndef GRND_NONBLOCK
-#define GRND_NONBLOCK 0x0001
-#endif
-
-#ifndef GRND_RANDOM
-#define GRND_RANDOM 0x0002
-#endif
-
-#ifndef GRND_INSECURE
-#define GRND_INSECURE 0x0004
-#endif
diff --git a/shared/systemd/src/basic/missing_socket.h b/shared/systemd/src/basic/missing_socket.h
deleted file mode 100644
index a4f6836f..00000000
--- a/shared/systemd/src/basic/missing_socket.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <sys/socket.h>
-
-#if 0 /* NM_IGNORED */
-#if HAVE_LINUX_VM_SOCKETS_H
-#include <linux/vm_sockets.h>
-#else
-#define VMADDR_CID_ANY -1U
-struct sockaddr_vm {
-        unsigned short svm_family;
-        unsigned short svm_reserved1;
-        unsigned int svm_port;
-        unsigned int svm_cid;
-        unsigned char svm_zero[sizeof(struct sockaddr) -
-                               sizeof(unsigned short) -
-                               sizeof(unsigned short) -
-                               sizeof(unsigned int) -
-                               sizeof(unsigned int)];
-};
-#endif /* !HAVE_LINUX_VM_SOCKETS_H */
-#endif /* NM_IGNORED */
-
-#ifndef AF_VSOCK
-#define AF_VSOCK 40
-#endif
-
-#ifndef SO_REUSEPORT
-#define SO_REUSEPORT 15
-#endif
-
-#ifndef SO_PEERGROUPS
-#define SO_PEERGROUPS 59
-#endif
-
-#ifndef SO_BINDTOIFINDEX
-#define SO_BINDTOIFINDEX 62
-#endif
-
-#ifndef SOL_NETLINK
-#define SOL_NETLINK 270
-#endif
-
-#ifndef SOL_ALG
-#define SOL_ALG 279
-#endif
-
-/* Not exposed yet. Defined in include/linux/socket.h. */
-#ifndef SOL_SCTP
-#define SOL_SCTP 132
-#endif
-
-/* Not exposed yet. Defined in include/linux/socket.h */
-#ifndef SCM_SECURITY
-#define SCM_SECURITY 0x03
-#endif
-
-/* netinet/in.h */
-#ifndef IP_FREEBIND
-#define IP_FREEBIND 15
-#endif
-
-#ifndef IP_TRANSPARENT
-#define IP_TRANSPARENT 19
-#endif
-
-#ifndef IPV6_FREEBIND
-#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
-#endif
diff --git a/shared/systemd/src/basic/missing_stat.h b/shared/systemd/src/basic/missing_stat.h
deleted file mode 100644
index 9c1df698..00000000
--- a/shared/systemd/src/basic/missing_stat.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <linux/types.h>
-#include <sys/stat.h>
-
-#if 0 /* NM_IGNORED */
-#if WANT_LINUX_STAT_H
-#include <linux/stat.h>
-#endif
-
-/* Thew newest definition we are aware of (fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60; 5.8) */
-#define STATX_DEFINITION {                      \
-        __u32 stx_mask;                         \
-        __u32 stx_blksize;                      \
-        __u64 stx_attributes;                   \
-        __u32 stx_nlink;                        \
-        __u32 stx_uid;                          \
-        __u32 stx_gid;                          \
-        __u16 stx_mode;                         \
-        __u16 __spare0[1];                      \
-        __u64 stx_ino;                          \
-        __u64 stx_size;                         \
-        __u64 stx_blocks;                       \
-        __u64 stx_attributes_mask;              \
-        struct statx_timestamp stx_atime;       \
-        struct statx_timestamp stx_btime;       \
-        struct statx_timestamp stx_ctime;       \
-        struct statx_timestamp stx_mtime;       \
-        __u32 stx_rdev_major;                   \
-        __u32 stx_rdev_minor;                   \
-        __u32 stx_dev_major;                    \
-        __u32 stx_dev_minor;                    \
-        __u64 stx_mnt_id;                       \
-        __u64 __spare2;                         \
-        __u64 __spare3[12];                     \
-}
-
-#if !HAVE_STRUCT_STATX
-struct statx_timestamp {
-        __s64 tv_sec;
-        __u32 tv_nsec;
-        __s32 __reserved;
-};
-
-struct statx STATX_DEFINITION;
-#endif
-
-/* Always define the newest version we are aware of as a distinct type, so that we can use it even if glibc
- * defines an older definition */
-struct new_statx STATX_DEFINITION;
-#endif /* NM_IGNORED */
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef AT_STATX_SYNC_AS_STAT
-#define AT_STATX_SYNC_AS_STAT 0x0000
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef AT_STATX_FORCE_SYNC
-#define AT_STATX_FORCE_SYNC 0x2000
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef AT_STATX_DONT_SYNC
-#define AT_STATX_DONT_SYNC 0x4000
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_TYPE
-#define STATX_TYPE 0x00000001U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_MODE
-#define STATX_MODE 0x00000002U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_NLINK
-#define STATX_NLINK 0x00000004U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_UID
-#define STATX_UID 0x00000008U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_GID
-#define STATX_GID 0x00000010U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_ATIME
-#define STATX_ATIME 0x00000020U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_MTIME
-#define STATX_MTIME 0x00000040U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_CTIME
-#define STATX_CTIME 0x00000080U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_INO
-#define STATX_INO 0x00000100U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_SIZE
-#define STATX_SIZE 0x00000200U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_BLOCKS
-#define STATX_BLOCKS 0x00000400U
-#endif
-
-/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
-#ifndef STATX_BTIME
-#define STATX_BTIME 0x00000800U
-#endif
-
-/* fa2fcf4f1df1559a0a4ee0f46915b496cc2ebf60 (5.8) */
-#ifndef STATX_MNT_ID
-#define STATX_MNT_ID 0x00001000U
-#endif
-
-/* 80340fe3605c0e78cfe496c3b3878be828cfdbfe (5.8) */
-#ifndef STATX_ATTR_MOUNT_ROOT
-#define STATX_ATTR_MOUNT_ROOT 0x00002000 /* Root of a mount */
-#endif
diff --git a/shared/systemd/src/basic/missing_syscall.h b/shared/systemd/src/basic/missing_syscall.h
deleted file mode 100644
index 42d64753..00000000
--- a/shared/systemd/src/basic/missing_syscall.h
+++ /dev/null
@@ -1,889 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-/* Missing glibc definitions to access certain kernel APIs */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#ifdef ARCH_MIPS
-#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"
-
-#if 0 /* NM_IGNORED */
-
-/* linux/kcmp.h */
-#ifndef KCMP_FILE /* 3f4994cfc15f38a3159c6e3a4b3ab2e1481a6b02 (3.19) */
-#define KCMP_FILE 0
-#endif
-
-#if !HAVE_PIVOT_ROOT
-static inline int missing_pivot_root(const char *new_root, const char *put_old) {
-        return syscall(__NR_pivot_root, new_root, put_old);
-}
-
-#  define pivot_root missing_pivot_root
-#endif
-
-/* ======================================================================= */
-
-#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__)
-#  define systemd_NR_memfd_create 350
-#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 is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_memfd_create && __NR_memfd_create >= 0
-#  if defined systemd_NR_memfd_create
-assert_cc(__NR_memfd_create == systemd_NR_memfd_create);
-#  endif
-#else
-#  if defined __NR_memfd_create
-#    undef __NR_memfd_create
-#  endif
-#  if defined systemd_NR_memfd_create
-#    define __NR_memfd_create systemd_NR_memfd_create
-#  endif
-#endif
-
-#if !HAVE_MEMFD_CREATE
-static inline int missing_memfd_create(const char *name, unsigned int flags) {
-#  ifdef __NR_memfd_create
-        return syscall(__NR_memfd_create, name, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-}
-
-#  define memfd_create missing_memfd_create
-#endif
-
-/* ======================================================================= */
-
-#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(__i386__)
-#  define systemd_NR_getrandom 355
-#elif defined(__ia64__)
-#  define systemd_NR_getrandom systemd_SC_arch_bias(318)
-#elif defined(__m68k__)
-#  define systemd_NR_getrandom 352
-#elif defined(_MIPS_SIM)
-#  if _MIPS_SIM == _MIPS_SIM_ABI32
-#    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
-#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 is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_getrandom && __NR_getrandom >= 0
-#  if defined systemd_NR_getrandom
-assert_cc(__NR_getrandom == systemd_NR_getrandom);
-#  endif
-#else
-#  if defined __NR_getrandom
-#    undef __NR_getrandom
-#  endif
-#  if defined systemd_NR_getrandom
-#    define __NR_getrandom systemd_NR_getrandom
-#  endif
-#endif
-
-#if !HAVE_GETRANDOM
-static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) {
-#  ifdef __NR_getrandom
-        return syscall(__NR_getrandom, buffer, count, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-}
-
-#  define getrandom missing_getrandom
-#endif
-
-/* ======================================================================= */
-
-/* The syscall has been defined since forever, but the glibc wrapper was missing. */
-#if !HAVE_GETTID
-static inline pid_t missing_gettid(void) {
-#  if defined __NR_gettid && __NR_gettid >= 0
-        return (pid_t) syscall(__NR_gettid);
-#  else
-#    error "__NR_gettid not defined"
-#  endif
-}
-
-#  define gettid missing_gettid
-#endif
-
-/* ======================================================================= */
-
-#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(__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__)
-#  define systemd_NR_name_to_handle_at 335
-#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() syscall number is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_name_to_handle_at && __NR_name_to_handle_at >= 0
-#  if defined systemd_NR_name_to_handle_at
-assert_cc(__NR_name_to_handle_at == systemd_NR_name_to_handle_at);
-#  endif
-#else
-#  if defined __NR_name_to_handle_at
-#    undef __NR_name_to_handle_at
-#  endif
-#  if defined systemd_NR_name_to_handle_at
-#    define __NR_name_to_handle_at systemd_NR_name_to_handle_at
-#  endif
-#endif
-
-#if !HAVE_NAME_TO_HANDLE_AT
-struct file_handle {
-        unsigned int handle_bytes;
-        int handle_type;
-        unsigned char f_handle[0];
-};
-
-static inline int missing_name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) {
-#  ifdef __NR_name_to_handle_at
-        return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-}
-
-#  define name_to_handle_at missing_name_to_handle_at
-#endif
-
-/* ======================================================================= */
-
-#if defined(__aarch64__)
-#  define systemd_NR_setns 268
-#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(__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__)
-#  define systemd_NR_setns 339
-#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 is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_setns && __NR_setns >= 0
-#  if defined systemd_NR_setns
-assert_cc(__NR_setns == systemd_NR_setns);
-#  endif
-#else
-#  if defined __NR_setns
-#    undef __NR_setns
-#  endif
-#  if defined systemd_NR_setns
-#    define __NR_setns systemd_NR_setns
-#  endif
-#endif
-
-#if !HAVE_SETNS
-static inline int missing_setns(int fd, int nstype) {
-#  ifdef __NR_setns
-        return syscall(__NR_setns, fd, nstype);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-}
-
-#  define setns missing_setns
-#endif
-
-/* ======================================================================= */
-
-static inline pid_t raw_getpid(void) {
-#if defined(__alpha__)
-        return (pid_t) syscall(__NR_getxpid);
-#else
-        return (pid_t) syscall(__NR_getpid);
-#endif
-}
-
-/* ======================================================================= */
-
-#if defined(__aarch64__)
-#  define systemd_NR_renameat2 276
-#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 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
-#elif defined(__powerpc__)
-#  define systemd_NR_renameat2 357
-#elif defined(__s390__)
-#  define systemd_NR_renameat2 347
-#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 is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_renameat2 && __NR_renameat2 >= 0
-#  if defined systemd_NR_renameat2
-assert_cc(__NR_renameat2 == systemd_NR_renameat2);
-#  endif
-#else
-#  if defined __NR_renameat2
-#    undef __NR_renameat2
-#  endif
-#  if defined systemd_NR_renameat2
-#    define __NR_renameat2 systemd_NR_renameat2
-#  endif
-#endif
-
-#if !HAVE_RENAMEAT2
-static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) {
-#  ifdef __NR_renameat2
-        return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-}
-
-#  define renameat2 missing_renameat2
-#endif
-
-/* ======================================================================= */
-
-#if !HAVE_KCMP
-static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
-#  if defined __NR_kcmp && __NR_kcmp >= 0
-        return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-}
-
-#  define kcmp missing_kcmp
-#endif
-
-/* ======================================================================= */
-
-#if !HAVE_KEYCTL
-static inline long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) {
-#  if defined __NR_keyctl && __NR_keyctl >= 0
-        return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-
-#  define keyctl missing_keyctl
-}
-
-static inline key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) {
-#  if defined __NR_add_key && __NR_add_key >= 0
-        return syscall(__NR_add_key, type, description, payload, plen, ringid);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-
-#  define add_key missing_add_key
-}
-
-static inline key_serial_t missing_request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) {
-#  if defined __NR_request_key && __NR_request_key >= 0
-        return syscall(__NR_request_key, type, description, callout_info, destringid);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-
-#  define request_key missing_request_key
-}
-#endif
-
-/* ======================================================================= */
-
-#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(__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(__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 is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_copy_file_range && __NR_copy_file_range >= 0
-#  if defined systemd_NR_copy_file_range
-assert_cc(__NR_copy_file_range == systemd_NR_copy_file_range);
-#  endif
-#else
-#  if defined __NR_copy_file_range
-#    undef __NR_copy_file_range
-#  endif
-#  if defined systemd_NR_copy_file_range
-#    define __NR_copy_file_range systemd_NR_copy_file_range
-#  endif
-#endif
-
-#if !HAVE_COPY_FILE_RANGE
-static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in,
-                                              int fd_out, loff_t *off_out,
-                                              size_t len,
-                                              unsigned int flags) {
-#  ifdef __NR_copy_file_range
-        return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-}
-
-#  define copy_file_range missing_copy_file_range
-#endif
-
-/* ======================================================================= */
-
-#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__)
-#  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(__s390__)
-#  define systemd_NR_bpf 351
-#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 is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_bpf && __NR_bpf >= 0
-#  if defined systemd_NR_bpf
-assert_cc(__NR_bpf == systemd_NR_bpf);
-#  endif
-#else
-#  if defined __NR_bpf
-#    undef __NR_bpf
-#  endif
-#  if defined systemd_NR_bpf
-#    define __NR_bpf systemd_NR_bpf
-#  endif
-#endif
-
-#if !HAVE_BPF
-union bpf_attr;
-
-static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) {
-#ifdef __NR_bpf
-        return (int) syscall(__NR_bpf, cmd, attr, size);
-#else
-        errno = ENOSYS;
-        return -1;
-#endif
-}
-
-#  define bpf missing_bpf
-#endif
-
-/* ======================================================================= */
-
-#ifndef __IGNORE_pkey_mprotect
-#  if defined(__aarch64__)
-#    define systemd_NR_pkey_mprotect 288
-#  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(__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 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 is unknown for your architecture"
-#  endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#  if defined __NR_pkey_mprotect && __NR_pkey_mprotect >= 0
-#    if defined systemd_NR_pkey_mprotect
-assert_cc(__NR_pkey_mprotect == systemd_NR_pkey_mprotect);
-#    endif
-#  else
-#    if defined __NR_pkey_mprotect
-#      undef __NR_pkey_mprotect
-#    endif
-#    if defined systemd_NR_pkey_mprotect
-#      define __NR_pkey_mprotect systemd_NR_pkey_mprotect
-#    endif
-#  endif
-#endif
-
-/* ======================================================================= */
-
-#if defined(__aarch64__)
-#  define systemd_NR_statx 291
-#elif defined(__alpha__)
-#  define systemd_NR_statx 522
-#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__)
-#  define systemd_NR_statx 379
-#elif defined(__sparc__)
-#  define systemd_NR_statx 360
-#elif defined(__x86_64__)
-#  define systemd_NR_statx systemd_SC_arch_bias(332)
-#else
-#  warning "statx() syscall number is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_statx && __NR_statx >= 0
-#  if defined systemd_NR_statx
-assert_cc(__NR_statx == systemd_NR_statx);
-#  endif
-#else
-#  if defined __NR_statx
-#    undef __NR_statx
-#  endif
-#  if defined systemd_NR_statx
-#    define __NR_statx systemd_NR_statx
-#  endif
-#endif
-
-#if !HAVE_STATX
-struct statx;
-
-static inline ssize_t missing_statx(int dfd, const char *filename, unsigned flags, unsigned int mask, struct statx *buffer) {
-#  ifdef __NR_statx
-        return syscall(__NR_statx, dfd, filename, flags, mask, buffer);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-}
-#endif
-
-/* This typedef is supposed to be always defined. */
-typedef struct statx struct_statx;
-
-#if !HAVE_STATX
-#  define statx(dfd, filename, flags, mask, buffer) missing_statx(dfd, filename, flags, mask, buffer)
-#endif
-
-/* ======================================================================= */
-
-#if !HAVE_SET_MEMPOLICY
-enum {
-        MPOL_DEFAULT,
-        MPOL_PREFERRED,
-        MPOL_BIND,
-        MPOL_INTERLEAVE,
-        MPOL_LOCAL,
-};
-
-static inline long missing_set_mempolicy(int mode, const unsigned long *nodemask,
-                           unsigned long maxnode) {
-        long i;
-#  if defined __NR_set_mempolicy && __NR_set_mempolicy >= 0
-        i = syscall(__NR_set_mempolicy, mode, nodemask, maxnode);
-#  else
-        errno = ENOSYS;
-        i = -1;
-#  endif
-        return i;
-}
-
-#  define set_mempolicy missing_set_mempolicy
-#endif
-
-#if !HAVE_GET_MEMPOLICY
-static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask,
-                           unsigned long maxnode, void *addr,
-                           unsigned long flags) {
-        long i;
-#  if defined __NR_get_mempolicy && __NR_get_mempolicy >= 0
-        i = syscall(__NR_get_mempolicy, mode, nodemask, maxnode, addr, flags);
-#  else
-        errno = ENOSYS;
-        i = -1;
-#  endif
-        return i;
-}
-
-#  define get_mempolicy missing_get_mempolicy
-#endif
-
-#endif /* NM_IGNORED */
-
-/* ======================================================================= */
-
-/* should be always defined, see kernel 39036cd2727395c3369b1051005da74059a85317 */
-#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
-#  if defined systemd_NR_pidfd_send_signal
-assert_cc(__NR_pidfd_send_signal == systemd_NR_pidfd_send_signal);
-#  endif
-#else
-#  if defined __NR_pidfd_send_signal
-#    undef __NR_pidfd_send_signal
-#  endif
-#  define __NR_pidfd_send_signal systemd_NR_pidfd_send_signal
-#endif
-
-#if !HAVE_PIDFD_SEND_SIGNAL
-static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) {
-#  ifdef __NR_pidfd_send_signal
-        return syscall(__NR_pidfd_send_signal, fd, sig, info, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-}
-
-#  define pidfd_send_signal missing_pidfd_send_signal
-#endif
-
-/* should be always defined, see kernel 7615d9e1780e26e0178c93c55b73309a5dc093d7 */
-#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
-#  if defined systemd_NR_pidfd_open
-assert_cc(__NR_pidfd_open == systemd_NR_pidfd_open);
-#  endif
-#else
-#  if defined __NR_pidfd_open
-#    undef __NR_pidfd_open
-#  endif
-#  define __NR_pidfd_open systemd_NR_pidfd_open
-#endif
-
-#if !HAVE_PIDFD_OPEN
-static inline int missing_pidfd_open(pid_t pid, unsigned flags) {
-#  ifdef __NR_pidfd_open
-        return syscall(__NR_pidfd_open, pid, flags);
-#  else
-        errno = ENOSYS;
-        return -1;
-#  endif
-}
-
-#  define pidfd_open missing_pidfd_open
-#endif
-
-/* ======================================================================= */
-
-#if !HAVE_RT_SIGQUEUEINFO
-static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info) {
-#  if defined __NR_rt_sigqueueinfo && __NR_rt_sigqueueinfo >= 0
-        return syscall(__NR_rt_sigqueueinfo, tgid, sig, info);
-#  else
-#    error "__NR_rt_sigqueueinfo not defined"
-#  endif
-}
-
-#  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
deleted file mode 100644
index f6233090..00000000
--- a/shared/systemd/src/basic/missing_type.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <uchar.h>
-
-#if !HAVE_CHAR32_T
-#define char32_t uint32_t
-#endif
-
-#if !HAVE_CHAR16_T
-#define char16_t uint16_t
-#endif
diff --git a/shared/systemd/src/basic/parse-util.c b/shared/systemd/src/basic/parse-util.c
deleted file mode 100644
index d53bf620..00000000
--- a/shared/systemd/src/basic/parse-util.c
+++ /dev/null
@@ -1,912 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <linux/oom.h>
-#include <net/if.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-
-#include "alloc-util.h"
-#include "errno-list.h"
-#include "extract-word.h"
-#include "locale-util.h"
-#include "macro.h"
-#include "missing_network.h"
-#include "parse-util.h"
-#include "process-util.h"
-#if HAVE_SECCOMP
-#include "seccomp-util.h"
-#endif
-#include "stat-util.h"
-#include "string-util.h"
-#include "strv.h"
-
-int parse_boolean(const char *v) {
-        if (!v)
-                return -EINVAL;
-
-        if (STRCASE_IN_SET(v,
-                           "1",
-                           "yes",
-                           "y",
-                           "true",
-                           "t",
-                           "on"))
-                return 1;
-
-        if (STRCASE_IN_SET(v,
-                           "0",
-                           "no",
-                           "n",
-                           "false",
-                           "f",
-                           "off"))
-                return 0;
-
-        return -EINVAL;
-}
-
-#if 0 /* NM_IGNORED */
-int parse_pid(const char *s, pid_t* ret_pid) {
-        unsigned long ul = 0;
-        pid_t pid;
-        int r;
-
-        assert(s);
-        assert(ret_pid);
-
-        r = safe_atolu(s, &ul);
-        if (r < 0)
-                return r;
-
-        pid = (pid_t) ul;
-
-        if ((unsigned long) pid != ul)
-                return -ERANGE;
-
-        if (!pid_is_valid(pid))
-                return -ERANGE;
-
-        *ret_pid = pid;
-        return 0;
-}
-
-int parse_mode(const char *s, mode_t *ret) {
-        unsigned m;
-        int r;
-
-        assert(s);
-
-        r = safe_atou_full(s, 8 |
-                           SAFE_ATO_REFUSE_PLUS_MINUS, /* Leading '+' or even '-' char? that's just weird,
-                                                        * refuse. User might have wanted to add mode flags or
-                                                        * so, but this parser doesn't allow that, so let's
-                                                        * better be safe. */
-                           &m);
-        if (r < 0)
-                return r;
-        if (m > 07777)
-                return -ERANGE;
-
-        if (ret)
-                *ret = m;
-        return 0;
-}
-
-int parse_ifindex(const char *s) {
-        int ifi, r;
-
-        assert(s);
-
-        r = safe_atoi(s, &ifi);
-        if (r < 0)
-                return r;
-        if (ifi <= 0)
-                return -EINVAL;
-
-        return ifi;
-}
-
-int parse_mtu(int family, const char *s, uint32_t *ret) {
-        uint64_t u;
-        size_t m;
-        int r;
-
-        r = parse_size(s, 1024, &u);
-        if (r < 0)
-                return r;
-
-        if (u > UINT32_MAX)
-                return -ERANGE;
-
-        if (family == AF_INET6)
-                m = IPV6_MIN_MTU; /* This is 1280 */
-        else
-                m = IPV4_MIN_MTU; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */
-
-        if (u < m)
-                return -ERANGE;
-
-        *ret = (uint32_t) u;
-        return 0;
-}
-
-int parse_size(const char *t, uint64_t base, uint64_t *size) {
-
-        /* Soo, sometimes we want to parse IEC binary suffixes, and
-         * sometimes SI decimal suffixes. This function can parse
-         * both. Which one is the right way depends on the
-         * context. Wikipedia suggests that SI is customary for
-         * hardware metrics and network speeds, while IEC is
-         * customary for most data sizes used by software and volatile
-         * (RAM) memory. Hence be careful which one you pick!
-         *
-         * In either case we use just K, M, G as suffix, and not Ki,
-         * Mi, Gi or so (as IEC would suggest). That's because that's
-         * frickin' ugly. But this means you really need to make sure
-         * to document which base you are parsing when you use this
-         * call. */
-
-        struct table {
-                const char *suffix;
-                unsigned long long factor;
-        };
-
-        static const struct table iec[] = {
-                { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
-                { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
-                { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
-                { "G", 1024ULL*1024ULL*1024ULL },
-                { "M", 1024ULL*1024ULL },
-                { "K", 1024ULL },
-                { "B", 1ULL },
-                { "",  1ULL },
-        };
-
-        static const struct table si[] = {
-                { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
-                { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
-                { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
-                { "G", 1000ULL*1000ULL*1000ULL },
-                { "M", 1000ULL*1000ULL },
-                { "K", 1000ULL },
-                { "B", 1ULL },
-                { "",  1ULL },
-        };
-
-        const struct table *table;
-        const char *p;
-        unsigned long long r = 0;
-        unsigned n_entries, start_pos = 0;
-
-        assert(t);
-        assert(IN_SET(base, 1000, 1024));
-        assert(size);
-
-        if (base == 1000) {
-                table = si;
-                n_entries = ELEMENTSOF(si);
-        } else {
-                table = iec;
-                n_entries = ELEMENTSOF(iec);
-        }
-
-        p = t;
-        do {
-                unsigned long long l, tmp;
-                double frac = 0;
-                char *e;
-                unsigned i;
-
-                p += strspn(p, WHITESPACE);
-
-                errno = 0;
-                l = strtoull(p, &e, 10);
-                if (errno > 0)
-                        return -errno;
-                if (e == p)
-                        return -EINVAL;
-                if (*p == '-')
-                        return -ERANGE;
-
-                if (*e == '.') {
-                        e++;
-
-                        /* strtoull() itself would accept space/+/- */
-                        if (*e >= '0' && *e <= '9') {
-                                unsigned long long l2;
-                                char *e2;
-
-                                l2 = strtoull(e, &e2, 10);
-                                if (errno > 0)
-                                        return -errno;
-
-                                /* Ignore failure. E.g. 10.M is valid */
-                                frac = l2;
-                                for (; e < e2; e++)
-                                        frac /= 10;
-                        }
-                }
-
-                e += strspn(e, WHITESPACE);
-
-                for (i = start_pos; i < n_entries; i++)
-                        if (startswith(e, table[i].suffix))
-                                break;
-
-                if (i >= n_entries)
-                        return -EINVAL;
-
-                if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
-                        return -ERANGE;
-
-                tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
-                if (tmp > ULLONG_MAX - r)
-                        return -ERANGE;
-
-                r += tmp;
-                if ((unsigned long long) (uint64_t) r != r)
-                        return -ERANGE;
-
-                p = e + strlen(table[i].suffix);
-
-                start_pos = i + 1;
-
-        } while (*p);
-
-        *size = r;
-
-        return 0;
-}
-
-int parse_range(const char *t, unsigned *lower, unsigned *upper) {
-        _cleanup_free_ char *word = NULL;
-        unsigned l, u;
-        int r;
-
-        assert(lower);
-        assert(upper);
-
-        /* Extract the lower bound. */
-        r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return -EINVAL;
-
-        r = safe_atou(word, &l);
-        if (r < 0)
-                return r;
-
-        /* Check for the upper bound and extract it if needed */
-        if (!t)
-                /* Single number with no dashes. */
-                u = l;
-        else if (!*t)
-                /* Trailing dash is an error. */
-                return -EINVAL;
-        else {
-                r = safe_atou(t, &u);
-                if (r < 0)
-                        return r;
-        }
-
-        *lower = l;
-        *upper = u;
-        return 0;
-}
-
-int parse_errno(const char *t) {
-        int r, e;
-
-        assert(t);
-
-        r = errno_from_name(t);
-        if (r > 0)
-                return r;
-
-        r = safe_atoi(t, &e);
-        if (r < 0)
-                return r;
-
-        /* 0 is also allowed here */
-        if (!errno_is_valid(e) && e != 0)
-                return -ERANGE;
-
-        return e;
-}
-
-#if HAVE_SECCOMP
-int parse_syscall_and_errno(const char *in, char **name, int *error) {
-        _cleanup_free_ char *n = NULL;
-        char *p;
-        int e = -1;
-
-        assert(in);
-        assert(name);
-        assert(error);
-
-        /*
-         * This parse "syscall:errno" like "uname:EILSEQ", "@sync:255".
-         * If errno is omitted, then error is set to -1.
-         * Empty syscall name is not allowed.
-         * Here, we do not check that the syscall name is valid or not.
-         */
-
-        p = strchr(in, ':');
-        if (p) {
-                e = seccomp_parse_errno_or_action(p + 1);
-                if (e < 0)
-                        return e;
-
-                n = strndup(in, p - in);
-        } else
-                n = strdup(in);
-
-        if (!n)
-                return -ENOMEM;
-
-        if (isempty(n))
-                return -EINVAL;
-
-        *error = e;
-        *name = TAKE_PTR(n);
-
-        return 0;
-}
-#endif
-#endif /* NM_IGNORED */
-
-static const char *mangle_base(const char *s, unsigned *base) {
-        const char *k;
-
-        assert(s);
-        assert(base);
-
-        /* Base already explicitly specified, then don't do anything. */
-        if (SAFE_ATO_MASK_FLAGS(*base) != 0)
-                return s;
-
-        /* Support Python 3 style "0b" and 0x" prefixes, because they truly make sense, much more than C's "0" prefix for octal. */
-        k = STARTSWITH_SET(s, "0b", "0B");
-        if (k) {
-                *base = 2 | (*base & SAFE_ATO_ALL_FLAGS);
-                return k;
-        }
-
-        k = STARTSWITH_SET(s, "0o", "0O");
-        if (k) {
-                *base = 8 | (*base & SAFE_ATO_ALL_FLAGS);
-                return k;
-        }
-
-        return s;
-}
-
-int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
-        char *x = NULL;
-        unsigned long l;
-
-        assert(s);
-        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
-
-        /* strtoul() is happy to parse negative values, and silently converts them to unsigned values without
-         * generating an error. We want a clean error, hence let's look for the "-" prefix on our own, and
-         * generate an error. But let's do so only after strtoul() validated that the string is clean
-         * otherwise, so that we return EINVAL preferably over ERANGE. */
-
-        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
-            strchr(WHITESPACE, s[0]))
-                return -EINVAL;
-
-        s += strspn(s, WHITESPACE);
-
-        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
-            IN_SET(s[0], '+', '-'))
-                return -EINVAL; /* Note that we check the "-" prefix again a second time below, but return a
-                                 * different error. I.e. if the SAFE_ATO_REFUSE_PLUS_MINUS flag is set we
-                                 * blanket refuse +/- prefixed integers, while if it is missing we'll just
-                                 * return ERANGE, because the string actually parses correctly, but doesn't
-                                 * fit in the return type. */
-
-        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
-            s[0] == '0' && !streq(s, "0"))
-                return -EINVAL; /* This is particularly useful to avoid ambiguities between C's octal
-                                 * notation and assumed-to-be-decimal integers with a leading zero. */
-
-        s = mangle_base(s, &base);
-
-        errno = 0;
-        l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base) /* Let's mask off the flags bits so that only the actual
-                                                      * base is left */);
-        if (errno > 0)
-                return -errno;
-        if (!x || x == s || *x != 0)
-                return -EINVAL;
-        if (l != 0 && s[0] == '-')
-                return -ERANGE;
-        if ((unsigned long) (unsigned) l != l)
-                return -ERANGE;
-
-        if (ret_u)
-                *ret_u = (unsigned) l;
-
-        return 0;
-}
-
-int safe_atoi(const char *s, int *ret_i) {
-        unsigned base = 0;
-        char *x = NULL;
-        long l;
-
-        assert(s);
-
-        s += strspn(s, WHITESPACE);
-        s = mangle_base(s, &base);
-
-        errno = 0;
-        l = strtol(s, &x, base);
-        if (errno > 0)
-                return -errno;
-        if (!x || x == s || *x != 0)
-                return -EINVAL;
-        if ((long) (int) l != l)
-                return -ERANGE;
-
-        if (ret_i)
-                *ret_i = (int) l;
-
-        return 0;
-}
-
-int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu) {
-        char *x = NULL;
-        unsigned long long l;
-
-        assert(s);
-        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
-
-        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
-            strchr(WHITESPACE, s[0]))
-                return -EINVAL;
-
-        s += strspn(s, WHITESPACE);
-
-        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
-            IN_SET(s[0], '+', '-'))
-                return -EINVAL;
-
-        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
-            s[0] == '0' && s[1] != 0)
-                return -EINVAL;
-
-        s = mangle_base(s, &base);
-
-        errno = 0;
-        l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base));
-        if (errno > 0)
-                return -errno;
-        if (!x || x == s || *x != 0)
-                return -EINVAL;
-        if (l != 0 && s[0] == '-')
-                return -ERANGE;
-
-        if (ret_llu)
-                *ret_llu = l;
-
-        return 0;
-}
-
-int safe_atolli(const char *s, long long int *ret_lli) {
-        unsigned base = 0;
-        char *x = NULL;
-        long long l;
-
-        assert(s);
-
-        s += strspn(s, WHITESPACE);
-        s = mangle_base(s, &base);
-
-        errno = 0;
-        l = strtoll(s, &x, base);
-        if (errno > 0)
-                return -errno;
-        if (!x || x == s || *x != 0)
-                return -EINVAL;
-
-        if (ret_lli)
-                *ret_lli = l;
-
-        return 0;
-}
-
-int safe_atou8(const char *s, uint8_t *ret) {
-        unsigned base = 0;
-        unsigned long l;
-        char *x = NULL;
-
-        assert(s);
-
-        s += strspn(s, WHITESPACE);
-        s = mangle_base(s, &base);
-
-        errno = 0;
-        l = strtoul(s, &x, base);
-        if (errno > 0)
-                return -errno;
-        if (!x || x == s || *x != 0)
-                return -EINVAL;
-        if (l != 0 && s[0] == '-')
-                return -ERANGE;
-        if ((unsigned long) (uint8_t) l != l)
-                return -ERANGE;
-
-        if (ret)
-                *ret = (uint8_t) l;
-        return 0;
-}
-
-int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
-        char *x = NULL;
-        unsigned long l;
-
-        assert(s);
-        assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
-
-        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
-            strchr(WHITESPACE, s[0]))
-                return -EINVAL;
-
-        s += strspn(s, WHITESPACE);
-
-        if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
-            IN_SET(s[0], '+', '-'))
-                return -EINVAL;
-
-        if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
-            s[0] == '0' && s[1] != 0)
-                return -EINVAL;
-
-        s = mangle_base(s, &base);
-
-        errno = 0;
-        l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base));
-        if (errno > 0)
-                return -errno;
-        if (!x || x == s || *x != 0)
-                return -EINVAL;
-        if (l != 0 && s[0] == '-')
-                return -ERANGE;
-        if ((unsigned long) (uint16_t) l != l)
-                return -ERANGE;
-
-        if (ret)
-                *ret = (uint16_t) l;
-
-        return 0;
-}
-
-int safe_atoi16(const char *s, int16_t *ret) {
-        unsigned base = 0;
-        char *x = NULL;
-        long l;
-
-        assert(s);
-
-        s += strspn(s, WHITESPACE);
-        s = mangle_base(s, &base);
-
-        errno = 0;
-        l = strtol(s, &x, base);
-        if (errno > 0)
-                return -errno;
-        if (!x || x == s || *x != 0)
-                return -EINVAL;
-        if ((long) (int16_t) l != l)
-                return -ERANGE;
-
-        if (ret)
-                *ret = (int16_t) l;
-
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int safe_atod(const char *s, double *ret_d) {
-        _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
-        char *x = NULL;
-        double d = 0;
-
-        assert(s);
-
-        loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
-        if (loc == (locale_t) 0)
-                return -errno;
-
-        errno = 0;
-        d = strtod_l(s, &x, loc);
-        if (errno > 0)
-                return -errno;
-        if (!x || x == s || *x != 0)
-                return -EINVAL;
-
-        if (ret_d)
-                *ret_d = (double) d;
-
-        return 0;
-}
-
-int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
-        size_t i;
-        unsigned val = 0;
-        const char *s;
-
-        s = *p;
-
-        /* accept any number of digits, strtoull is limited to 19 */
-        for (i=0; i < digits; i++,s++) {
-                if (*s < '0' || *s > '9') {
-                        if (i == 0)
-                                return -EINVAL;
-
-                        /* too few digits, pad with 0 */
-                        for (; i < digits; i++)
-                                val *= 10;
-
-                        break;
-                }
-
-                val *= 10;
-                val += *s - '0';
-        }
-
-        /* maybe round up */
-        if (*s >= '5' && *s <= '9')
-                val++;
-
-        s += strspn(s, DIGITS);
-
-        *p = s;
-        *res = val;
-
-        return 0;
-}
-
-int parse_percent_unbounded(const char *p) {
-        const char *pc, *n;
-        int r, v;
-
-        pc = endswith(p, "%");
-        if (!pc)
-                return -EINVAL;
-
-        n = strndupa(p, pc - p);
-        r = safe_atoi(n, &v);
-        if (r < 0)
-                return r;
-        if (v < 0)
-                return -ERANGE;
-
-        return v;
-}
-
-int parse_percent(const char *p) {
-        int v;
-
-        v = parse_percent_unbounded(p);
-        if (v > 100)
-                return -ERANGE;
-
-        return v;
-}
-
-int parse_permille_unbounded(const char *p) {
-        const char *pc, *pm, *dot, *n;
-        int r, q, v;
-
-        pm = endswith(p, "‰");
-        if (pm) {
-                n = strndupa(p, pm - p);
-                r = safe_atoi(n, &v);
-                if (r < 0)
-                        return r;
-                if (v < 0)
-                        return -ERANGE;
-        } else {
-                pc = endswith(p, "%");
-                if (!pc)
-                        return -EINVAL;
-
-                dot = memchr(p, '.', pc - p);
-                if (dot) {
-                        if (dot + 2 != pc)
-                                return -EINVAL;
-                        if (dot[1] < '0' || dot[1] > '9')
-                                return -EINVAL;
-                        q = dot[1] - '0';
-                        n = strndupa(p, dot - p);
-                } else {
-                        q = 0;
-                        n = strndupa(p, pc - p);
-                }
-                r = safe_atoi(n, &v);
-                if (r < 0)
-                        return r;
-                if (v < 0)
-                        return -ERANGE;
-                if (v > (INT_MAX - q) / 10)
-                        return -ERANGE;
-
-                v = v * 10 + q;
-        }
-
-        return v;
-}
-
-int parse_permille(const char *p) {
-        int v;
-
-        v = parse_permille_unbounded(p);
-        if (v > 1000)
-                return -ERANGE;
-
-        return v;
-}
-
-int parse_nice(const char *p, int *ret) {
-        int n, r;
-
-        r = safe_atoi(p, &n);
-        if (r < 0)
-                return r;
-
-        if (!nice_is_valid(n))
-                return -ERANGE;
-
-        *ret = n;
-        return 0;
-}
-
-int parse_ip_port(const char *s, uint16_t *ret) {
-        uint16_t l;
-        int r;
-
-        r = safe_atou16(s, &l);
-        if (r < 0)
-                return r;
-
-        if (l == 0)
-                return -EINVAL;
-
-        *ret = (uint16_t) l;
-
-        return 0;
-}
-
-int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
-        unsigned l, h;
-        int r;
-
-        r = parse_range(s, &l, &h);
-        if (r < 0)
-                return r;
-
-        if (l <= 0 || l > 65535 || h <= 0 || h > 65535)
-                return -EINVAL;
-
-        if (h < l)
-                return -EINVAL;
-
-        *low = l;
-        *high = h;
-
-        return 0;
-}
-
-int parse_ip_prefix_length(const char *s, int *ret) {
-        unsigned l;
-        int r;
-
-        r = safe_atou(s, &l);
-        if (r < 0)
-                return r;
-
-        if (l > 128)
-                return -ERANGE;
-
-        *ret = (int) l;
-
-        return 0;
-}
-
-int parse_dev(const char *s, dev_t *ret) {
-        const char *major;
-        unsigned x, y;
-        size_t n;
-        int r;
-
-        n = strspn(s, DIGITS);
-        if (n == 0)
-                return -EINVAL;
-        if (s[n] != ':')
-                return -EINVAL;
-
-        major = strndupa(s, n);
-        r = safe_atou(major, &x);
-        if (r < 0)
-                return r;
-
-        r = safe_atou(s + n + 1, &y);
-        if (r < 0)
-                return r;
-
-        if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
-                return -ERANGE;
-
-        *ret = makedev(x, y);
-        return 0;
-}
-
-int parse_oom_score_adjust(const char *s, int *ret) {
-        int r, v;
-
-        assert(s);
-        assert(ret);
-
-        r = safe_atoi(s, &v);
-        if (r < 0)
-                return r;
-
-        if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX)
-                return -ERANGE;
-
-        *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
deleted file mode 100644
index ba4e727e..00000000
--- a/shared/systemd/src/basic/parse-util.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/* 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);
-int parse_mode(const char *s, mode_t *ret);
-int parse_ifindex(const char *s);
-int parse_mtu(int family, const char *s, uint32_t *ret);
-
-int parse_size(const char *t, uint64_t base, uint64_t *size);
-int parse_range(const char *t, unsigned *lower, unsigned *upper);
-int parse_errno(const char *t);
-#if HAVE_SECCOMP
-int parse_syscall_and_errno(const char *in, char **name, int *error);
-#endif
-
-#define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
-#define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)
-#define SAFE_ATO_REFUSE_LEADING_WHITESPACE (1U << 28)
-#define SAFE_ATO_ALL_FLAGS (SAFE_ATO_REFUSE_PLUS_MINUS|SAFE_ATO_REFUSE_LEADING_ZERO|SAFE_ATO_REFUSE_LEADING_WHITESPACE)
-#define SAFE_ATO_MASK_FLAGS(base) ((base) & ~SAFE_ATO_ALL_FLAGS)
-
-int safe_atou_full(const char *s, unsigned base, unsigned *ret_u);
-
-static inline int safe_atou(const char *s, unsigned *ret_u) {
-        return safe_atou_full(s, 0, ret_u);
-}
-
-int safe_atoi(const char *s, int *ret_i);
-int safe_atolli(const char *s, long long int *ret_i);
-
-int safe_atou8(const char *s, uint8_t *ret);
-
-int safe_atou16_full(const char *s, unsigned base, uint16_t *ret);
-
-static inline int safe_atou16(const char *s, uint16_t *ret) {
-        return safe_atou16_full(s, 0, ret);
-}
-
-static inline int safe_atoux16(const char *s, uint16_t *ret) {
-        return safe_atou16_full(s, 16, ret);
-}
-
-int safe_atoi16(const char *s, int16_t *ret);
-
-static inline int safe_atou32_full(const char *s, unsigned base, uint32_t *ret_u) {
-        assert_cc(sizeof(uint32_t) == sizeof(unsigned));
-        return safe_atou_full(s, base, (unsigned*) ret_u);
-}
-
-static inline int safe_atou32(const char *s, uint32_t *ret_u) {
-        return safe_atou32_full(s, 0, (unsigned*) ret_u);
-}
-
-static inline int safe_atoi32(const char *s, int32_t *ret_i) {
-        assert_cc(sizeof(int32_t) == sizeof(int));
-        return safe_atoi(s, (int*) ret_i);
-}
-
-int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu);
-
-static inline int safe_atollu(const char *s, long long unsigned *ret_llu) {
-        return safe_atollu_full(s, 0, ret_llu);
-}
-
-static inline int safe_atou64(const char *s, uint64_t *ret_u) {
-        assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
-        return safe_atollu(s, (unsigned long long*) ret_u);
-}
-
-static inline int safe_atoi64(const char *s, int64_t *ret_i) {
-        assert_cc(sizeof(int64_t) == sizeof(long long int));
-        return safe_atolli(s, (long long int*) ret_i);
-}
-
-static inline int safe_atoux64(const char *s, uint64_t *ret) {
-        assert_cc(sizeof(int64_t) == sizeof(long long unsigned));
-        return safe_atollu_full(s, 16, (long long unsigned*) ret);
-}
-
-#if LONG_MAX == INT_MAX
-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_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_full(const char *s, unsigned base, unsigned long *ret_u) {
-        assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
-        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));
-        return safe_atolli(s, (long 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));
-        return safe_atou(s, (unsigned *) ret_u);
-}
-#else
-static inline int safe_atozu(const char *s, size_t *ret_u) {
-        assert_cc(sizeof(size_t) == sizeof(long unsigned));
-        return safe_atolu(s, ret_u);
-}
-#endif
-
-int safe_atod(const char *s, double *ret_d);
-
-int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
-
-int parse_percent_unbounded(const char *p);
-int parse_percent(const char *p);
-
-int parse_permille_unbounded(const char *p);
-int parse_permille(const char *p);
-
-int parse_nice(const char *p, int *ret);
-
-int parse_ip_port(const char *s, uint16_t *ret);
-int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high);
-
-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
deleted file mode 100644
index ea44c32b..00000000
--- a/shared/systemd/src/basic/path-util.c
+++ /dev/null
@@ -1,1188 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-/* When we include libgen.h because we need dirname() we immediately
- * undefine basename() since libgen.h defines it as a macro to the
- * POSIX version which is really broken. We prefer GNU basename(). */
-#include <libgen.h>
-#undef basename
-
-#include "alloc-util.h"
-#include "extract-word.h"
-#include "fd-util.h"
-#include "fs-util.h"
-#include "glob-util.h"
-#include "log.h"
-#include "macro.h"
-#include "nulstr-util.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "stat-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "time-util.h"
-#include "utf8.h"
-
-#if 0 /* NM_IGNORED */
-int path_split_and_make_absolute(const char *p, char ***ret) {
-        char **l;
-        int r;
-
-        assert(p);
-        assert(ret);
-
-        l = strv_split(p, ":");
-        if (!l)
-                return -ENOMEM;
-
-        r = path_strv_make_absolute_cwd(l);
-        if (r < 0) {
-                strv_free(l);
-                return r;
-        }
-
-        *ret = l;
-        return r;
-}
-
-char *path_make_absolute(const char *p, const char *prefix) {
-        assert(p);
-
-        /* Makes every item in the list an absolute path by prepending
-         * the prefix, if specified and necessary */
-
-        if (path_is_absolute(p) || isempty(prefix))
-                return strdup(p);
-
-        return path_join(prefix, p);
-}
-
-int safe_getcwd(char **ret) {
-        char *cwd;
-
-        cwd = get_current_dir_name();
-        if (!cwd)
-                return negative_errno();
-
-        /* Let's make sure the directory is really absolute, to protect us from the logic behind
-         * CVE-2018-1000001 */
-        if (cwd[0] != '/') {
-                free(cwd);
-                return -ENOMEDIUM;
-        }
-
-        *ret = cwd;
-        return 0;
-}
-
-int path_make_absolute_cwd(const char *p, char **ret) {
-        char *c;
-        int r;
-
-        assert(p);
-        assert(ret);
-
-        /* Similar to path_make_absolute(), but prefixes with the
-         * current working directory. */
-
-        if (path_is_absolute(p))
-                c = strdup(p);
-        else {
-                _cleanup_free_ char *cwd = NULL;
-
-                r = safe_getcwd(&cwd);
-                if (r < 0)
-                        return r;
-
-                c = path_join(cwd, p);
-        }
-        if (!c)
-                return -ENOMEM;
-
-        *ret = c;
-        return 0;
-}
-
-int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
-        char *f, *t, *r, *p;
-        unsigned n_parents = 0;
-
-        assert(from_dir);
-        assert(to_path);
-        assert(_r);
-
-        /* Strips the common part, and adds ".." elements as necessary. */
-
-        if (!path_is_absolute(from_dir) || !path_is_absolute(to_path))
-                return -EINVAL;
-
-        f = strdupa(from_dir);
-        t = strdupa(to_path);
-
-        path_simplify(f, true);
-        path_simplify(t, true);
-
-        /* Skip the common part. */
-        for (;;) {
-                size_t a, b;
-
-                f += *f == '/';
-                t += *t == '/';
-
-                if (!*f) {
-                        if (!*t)
-                                /* from_dir equals to_path. */
-                                r = strdup(".");
-                        else
-                                /* from_dir is a parent directory of to_path. */
-                                r = strdup(t);
-                        if (!r)
-                                return -ENOMEM;
-
-                        *_r = r;
-                        return 0;
-                }
-
-                if (!*t)
-                        break;
-
-                a = strcspn(f, "/");
-                b = strcspn(t, "/");
-
-                if (a != b || memcmp(f, t, a) != 0)
-                        break;
-
-                f += a;
-                t += b;
-        }
-
-        /* If we're here, then "from_dir" has one or more elements that need to
-         * be replaced with "..". */
-
-        /* Count the number of necessary ".." elements. */
-        for (; *f;) {
-                size_t w;
-
-                w = strcspn(f, "/");
-
-                /* If this includes ".." we can't do a simple series of "..", refuse */
-                if (w == 2 && f[0] == '.' && f[1] == '.')
-                        return -EINVAL;
-
-                /* Count number of elements */
-                n_parents++;
-
-                f += w;
-                f += *f == '/';
-        }
-
-        r = new(char, n_parents * 3 + strlen(t) + 1);
-        if (!r)
-                return -ENOMEM;
-
-        for (p = r; n_parents > 0; n_parents--)
-                p = mempcpy(p, "../", 3);
-
-        if (*t)
-                strcpy(p, t);
-        else
-                /* Remove trailing slash */
-                *(--p) = 0;
-
-        *_r = r;
-        return 0;
-}
-
-char* path_startswith_strv(const char *p, char **set) {
-        char **s, *t;
-
-        STRV_FOREACH(s, set) {
-                t = path_startswith(p, *s);
-                if (t)
-                        return t;
-        }
-
-        return NULL;
-}
-
-int path_strv_make_absolute_cwd(char **l) {
-        char **s;
-        int r;
-
-        /* Goes through every item in the string list and makes it
-         * absolute. This works in place and won't rollback any
-         * changes on failure. */
-
-        STRV_FOREACH(s, l) {
-                char *t;
-
-                r = path_make_absolute_cwd(*s, &t);
-                if (r < 0)
-                        return r;
-
-                path_simplify(t, false);
-                free_and_replace(*s, t);
-        }
-
-        return 0;
-}
-
-char **path_strv_resolve(char **l, const char *root) {
-        char **s;
-        unsigned k = 0;
-        bool enomem = false;
-        int r;
-
-        if (strv_isempty(l))
-                return l;
-
-        /* Goes through every item in the string list and canonicalize
-         * the path. This works in place and won't rollback any
-         * changes on failure. */
-
-        STRV_FOREACH(s, l) {
-                _cleanup_free_ char *orig = NULL;
-                char *t, *u;
-
-                if (!path_is_absolute(*s)) {
-                        free(*s);
-                        continue;
-                }
-
-                if (root) {
-                        orig = *s;
-                        t = path_join(root, orig);
-                        if (!t) {
-                                enomem = true;
-                                continue;
-                        }
-                } else
-                        t = *s;
-
-                r = chase_symlinks(t, root, 0, &u, NULL);
-                if (r == -ENOENT) {
-                        if (root) {
-                                u = TAKE_PTR(orig);
-                                free(t);
-                        } else
-                                u = t;
-                } else if (r < 0) {
-                        free(t);
-
-                        if (r == -ENOMEM)
-                                enomem = true;
-
-                        continue;
-                } else if (root) {
-                        char *x;
-
-                        free(t);
-                        x = path_startswith(u, root);
-                        if (x) {
-                                /* restore the slash if it was lost */
-                                if (!startswith(x, "/"))
-                                        *(--x) = '/';
-
-                                t = strdup(x);
-                                free(u);
-                                if (!t) {
-                                        enomem = true;
-                                        continue;
-                                }
-                                u = t;
-                        } else {
-                                /* canonicalized path goes outside of
-                                 * prefix, keep the original path instead */
-                                free_and_replace(u, orig);
-                        }
-                } else
-                        free(t);
-
-                l[k++] = u;
-        }
-
-        l[k] = NULL;
-
-        if (enomem)
-                return NULL;
-
-        return l;
-}
-
-char **path_strv_resolve_uniq(char **l, const char *root) {
-
-        if (strv_isempty(l))
-                return l;
-
-        if (!path_strv_resolve(l, root))
-                return NULL;
-
-        return strv_uniq(l);
-}
-#endif /* NM_IGNORED */
-
-char *path_simplify(char *path, bool kill_dots) {
-        char *f, *t;
-        bool slash = false, ignore_slash = false, absolute;
-
-        assert(path);
-
-        /* Removes redundant inner and trailing slashes. Also removes unnecessary dots
-         * if kill_dots is true. Modifies the passed string in-place.
-         *
-         * ///foo//./bar/.   becomes /foo/./bar/.      (if kill_dots is false)
-         * ///foo//./bar/.   becomes /foo/bar          (if kill_dots is true)
-         * .//./foo//./bar/. becomes ././foo/./bar/.   (if kill_dots is false)
-         * .//./foo//./bar/. becomes foo/bar           (if kill_dots is true)
-         */
-
-        if (isempty(path))
-                return path;
-
-        absolute = path_is_absolute(path);
-
-        f = path;
-        if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/')) {
-                ignore_slash = true;
-                f++;
-        }
-
-        for (t = path; *f; f++) {
-
-                if (*f == '/') {
-                        slash = true;
-                        continue;
-                }
-
-                if (slash) {
-                        if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/'))
-                                continue;
-
-                        slash = false;
-                        if (ignore_slash)
-                                ignore_slash = false;
-                        else
-                                *(t++) = '/';
-                }
-
-                *(t++) = *f;
-        }
-
-        /* Special rule, if we stripped everything, we either need a "/" (for the root directory)
-         * or "." for the current directory */
-        if (t == path) {
-                if (absolute)
-                        *(t++) = '/';
-                else
-                        *(t++) = '.';
-        }
-
-        *t = 0;
-        return path;
-}
-
-#if 0 /* NM_IGNORED */
-int path_simplify_and_warn(
-                char *path,
-                unsigned flag,
-                const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *lvalue) {
-
-        bool fatal = flag & PATH_CHECK_FATAL;
-
-        assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
-
-        if (!utf8_is_valid(path))
-                return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
-
-        if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
-                bool absolute;
-
-                absolute = path_is_absolute(path);
-
-                if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
-                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
-                                          "%s= path is not absolute%s: %s",
-                                          lvalue, fatal ? "" : ", ignoring", path);
-
-                if (absolute && (flag & PATH_CHECK_RELATIVE))
-                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
-                                          "%s= path is absolute%s: %s",
-                                          lvalue, fatal ? "" : ", ignoring", path);
-        }
-
-        path_simplify(path, true);
-
-        if (!path_is_valid(path))
-                return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
-                                  "%s= path has invalid length (%zu bytes)%s.",
-                                  lvalue, strlen(path), fatal ? "" : ", ignoring");
-
-        if (!path_is_normalized(path))
-                return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
-                                  "%s= path is not normalized%s: %s",
-                                  lvalue, fatal ? "" : ", ignoring", path);
-
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-char* path_startswith(const char *path, const char *prefix) {
-        assert(path);
-        assert(prefix);
-
-        /* Returns a pointer to the start of the first component after the parts matched by
-         * the prefix, iff
-         * - both paths are absolute or both paths are relative,
-         * and
-         * - each component in prefix in turn matches a component in path at the same position.
-         * An empty string will be returned when the prefix and path are equivalent.
-         *
-         * Returns NULL otherwise.
-         */
-
-        if ((path[0] == '/') != (prefix[0] == '/'))
-                return NULL;
-
-        for (;;) {
-                size_t a, b;
-
-                path += strspn(path, "/");
-                prefix += strspn(prefix, "/");
-
-                if (*prefix == 0)
-                        return (char*) path;
-
-                if (*path == 0)
-                        return NULL;
-
-                a = strcspn(path, "/");
-                b = strcspn(prefix, "/");
-
-                if (a != b)
-                        return NULL;
-
-                if (memcmp(path, prefix, a) != 0)
-                        return NULL;
-
-                path += a;
-                prefix += b;
-        }
-}
-
-int path_compare(const char *a, const char *b) {
-        int d;
-
-        assert(a);
-        assert(b);
-
-        /* A relative path and an absolute path must not compare as equal.
-         * Which one is sorted before the other does not really matter.
-         * Here a relative path is ordered before an absolute path. */
-        d = (a[0] == '/') - (b[0] == '/');
-        if (d != 0)
-                return d;
-
-        for (;;) {
-                size_t j, k;
-
-                a += strspn(a, "/");
-                b += strspn(b, "/");
-
-                if (*a == 0 && *b == 0)
-                        return 0;
-
-                /* Order prefixes first: "/foo" before "/foo/bar" */
-                if (*a == 0)
-                        return -1;
-                if (*b == 0)
-                        return 1;
-
-                j = strcspn(a, "/");
-                k = strcspn(b, "/");
-
-                /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
-                d = memcmp(a, b, MIN(j, k));
-                if (d != 0)
-                        return (d > 0) - (d < 0); /* sign of d */
-
-                /* Sort "/foo/a" before "/foo/aaa" */
-                d = (j > k) - (j < k);  /* sign of (j - k) */
-                if (d != 0)
-                        return d;
-
-                a += j;
-                b += k;
-        }
-}
-
-bool path_equal(const char *a, const char *b) {
-        return path_compare(a, b) == 0;
-}
-
-#if 0 /* NM_IGNORED */
-bool path_equal_or_files_same(const char *a, const char *b, int flags) {
-        return path_equal(a, b) || files_same(a, b, flags) > 0;
-}
-#endif /* NM_IGNORED */
-
-char* path_join_internal(const char *first, ...) {
-        char *joined, *q;
-        const char *p;
-        va_list ap;
-        bool slash;
-        size_t sz;
-
-        /* Joins all listed strings until the sentinel and places a "/" between them unless the strings end/begin
-         * already with one so that it is unnecessary. Note that slashes which are already duplicate won't be
-         * removed. The string returned is hence always equal to or longer than the sum of the lengths of each
-         * individual string.
-         *
-         * Note: any listed empty string is simply skipped. This can be useful for concatenating strings of which some
-         * are optional.
-         *
-         * Examples:
-         *
-         * path_join("foo", "bar") → "foo/bar"
-         * path_join("foo/", "bar") → "foo/bar"
-         * path_join("", "foo", "", "bar", "") → "foo/bar" */
-
-        sz = strlen_ptr(first);
-        va_start(ap, first);
-        while ((p = va_arg(ap, char*)) != POINTER_MAX)
-                if (!isempty(p))
-                        sz += 1 + strlen(p);
-        va_end(ap);
-
-        joined = new(char, sz + 1);
-        if (!joined)
-                return NULL;
-
-        if (!isempty(first)) {
-                q = stpcpy(joined, first);
-                slash = endswith(first, "/");
-        } else {
-                /* Skip empty items */
-                joined[0] = 0;
-                q = joined;
-                slash = true; /* no need to generate a slash anymore */
-        }
-
-        va_start(ap, first);
-        while ((p = va_arg(ap, char*)) != POINTER_MAX) {
-                if (isempty(p))
-                        continue;
-
-                if (!slash && p[0] != '/')
-                        *(q++) = '/';
-
-                q = stpcpy(q, p);
-                slash = endswith(p, "/");
-        }
-        va_end(ap);
-
-        return joined;
-}
-
-#if 0 /* NM_IGNORED */
-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)) {
-                _cleanup_close_ int fd = -1;
-
-                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;
-        }
-
-        if (use_path_envvar)
-                /* Plain getenv, not secure_getenv, because we want to actually allow the user to pick the
-                 * binary. */
-                p = getenv("PATH");
-        if (!p)
-                p = DEFAULT_PATH;
-
-        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)
-                        return r;
-                if (r == 0)
-                        break;
-
-                if (!path_is_absolute(element))
-                        continue;
-
-                j = path_join(element, name);
-                if (!j)
-                        return -ENOMEM;
-
-                r = check_x_access(j, ret_fd ? &fd : NULL);
-                if (r >= 0) {
-                        _cleanup_free_ char *with_dash;
-
-                        with_dash = strjoin(j, "/");
-                        if (!with_dash)
-                                return -ENOMEM;
-
-                        /* If this passes, it must be a directory, and so should be skipped. */
-                        if (access(with_dash, X_OK) >= 0)
-                                continue;
-
-                        /* We can't just `continue` inverting this case, since we need to update last_error. */
-                        if (errno == ENOTDIR) {
-                                /* Found it! */
-                                if (ret_filename)
-                                        *ret_filename = path_simplify(TAKE_PTR(j), false);
-                                if (ret_fd)
-                                        *ret_fd = TAKE_FD(fd);
-
-                                return 0;
-                        }
-                }
-
-                /* PATH entries which we don't have access to are ignored, as per tradition. */
-                if (errno != EACCES)
-                        last_error = -errno;
-        }
-
-        return last_error;
-}
-
-bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
-        bool changed = false;
-        const char* const* i;
-
-        assert(timestamp);
-
-        if (!paths)
-                return false;
-
-        STRV_FOREACH(i, paths) {
-                struct stat stats;
-                usec_t u;
-
-                if (stat(*i, &stats) < 0)
-                        continue;
-
-                u = timespec_load(&stats.st_mtim);
-
-                /* first check */
-                if (*timestamp >= u)
-                        continue;
-
-                log_debug("timestamp of '%s' changed", *i);
-
-                /* update timestamp */
-                if (update) {
-                        *timestamp = u;
-                        changed = true;
-                } else
-                        return true;
-        }
-
-        return changed;
-}
-
-static int executable_is_good(const char *executable) {
-        _cleanup_free_ char *p = NULL, *d = NULL;
-        int r;
-
-        r = find_executable(executable, &p);
-        if (r == -ENOENT)
-                return 0;
-        if (r < 0)
-                return r;
-
-        /* An fsck that is linked to /bin/true is a non-existent fsck */
-
-        r = readlink_malloc(p, &d);
-        if (r == -EINVAL) /* not a symlink */
-                return 1;
-        if (r < 0)
-                return r;
-
-        return !PATH_IN_SET(d, "true"
-                               "/bin/true",
-                               "/usr/bin/true",
-                               "/dev/null");
-}
-
-int fsck_exists(const char *fstype) {
-        const char *checker;
-
-        assert(fstype);
-
-        if (streq(fstype, "auto"))
-                return -EINVAL;
-
-        checker = strjoina("fsck.", fstype);
-        return executable_is_good(checker);
-}
-
-int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
-        char *p;
-        int r;
-
-        /*
-         * This function is intended to be used in command line
-         * parsers, to handle paths that are passed in. It makes the
-         * path absolute, and reduces it to NULL if omitted or
-         * root (the latter optionally).
-         *
-         * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
-         * SUCCESS! Hence, do not pass in uninitialized pointers.
-         */
-
-        if (isempty(path)) {
-                *arg = mfree(*arg);
-                return 0;
-        }
-
-        r = path_make_absolute_cwd(path, &p);
-        if (r < 0)
-                return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
-
-        path_simplify(p, false);
-        if (suppress_root && empty_or_root(p))
-                p = mfree(p);
-
-        free_and_replace(*arg, p);
-
-        return 0;
-}
-
-char* dirname_malloc(const char *path) {
-        char *d, *dir, *dir2;
-
-        assert(path);
-
-        d = strdup(path);
-        if (!d)
-                return NULL;
-
-        dir = dirname(d);
-        assert(dir);
-
-        if (dir == d)
-                return d;
-
-        dir2 = strdup(dir);
-        free(d);
-
-        return dir2;
-}
-
-const char *last_path_component(const char *path) {
-
-        /* Finds the last component of the path, preserving the optional trailing slash that signifies a directory.
-         *
-         *    a/b/c → c
-         *    a/b/c/ → c/
-         *    x → x
-         *    x/ → x/
-         *    /y → y
-         *    /y/ → y/
-         *    / → /
-         *    // → /
-         *    /foo/a → a
-         *    /foo/a/ → a/
-         *
-         *    Also, the empty string is mapped to itself.
-         *
-         * This is different than basename(), which returns "" when a trailing slash is present.
-         */
-
-        unsigned l, k;
-
-        if (!path)
-                return NULL;
-
-        l = k = strlen(path);
-        if (l == 0) /* special case — an empty string */
-                return path;
-
-        while (k > 0 && path[k-1] == '/')
-                k--;
-
-        if (k == 0) /* the root directory */
-                return path + l - 1;
-
-        while (k > 0 && path[k-1] != '/')
-                k--;
-
-        return path + k;
-}
-
-int path_extract_filename(const char *p, char **ret) {
-        _cleanup_free_ char *a = NULL;
-        const char *c, *e = NULL, *q;
-
-        /* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes
-         * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing slashes. */
-
-        if (!p)
-                return -EINVAL;
-
-        c = last_path_component(p);
-
-        for (q = c; *q != 0; q++)
-                if (*q != '/')
-                        e = q + 1;
-
-        if (!e) /* no valid character? */
-                return -EINVAL;
-
-        a = strndup(c, e - c);
-        if (!a)
-                return -ENOMEM;
-
-        if (!filename_is_valid(a))
-                return -EINVAL;
-
-        *ret = TAKE_PTR(a);
-
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-bool filename_is_valid(const char *p) {
-        const char *e;
-
-        if (isempty(p))
-                return false;
-
-        if (dot_or_dot_dot(p))
-                return false;
-
-        e = strchrnul(p, '/');
-        if (*e != 0)
-                return false;
-
-        if (e - p > FILENAME_MAX) /* FILENAME_MAX is counted *without* the trailing NUL byte */
-                return false;
-
-        return true;
-}
-
-bool path_is_valid(const char *p) {
-
-        if (isempty(p))
-                return false;
-
-        if (strlen(p) >= PATH_MAX) /* PATH_MAX is counted *with* the trailing NUL byte */
-                return false;
-
-        return true;
-}
-
-bool path_is_normalized(const char *p) {
-
-        if (!path_is_valid(p))
-                return false;
-
-        if (dot_or_dot_dot(p))
-                return false;
-
-        if (startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
-                return false;
-
-        if (startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
-                return false;
-
-        if (strstr(p, "//"))
-                return false;
-
-        return true;
-}
-
-#if 0 /* NM_IGNORED */
-char *file_in_same_dir(const char *path, const char *filename) {
-        char *e, *ret;
-        size_t k;
-
-        assert(path);
-        assert(filename);
-
-        /* This removes the last component of path and appends
-         * filename, unless the latter is absolute anyway or the
-         * former isn't */
-
-        if (path_is_absolute(filename))
-                return strdup(filename);
-
-        e = strrchr(path, '/');
-        if (!e)
-                return strdup(filename);
-
-        k = strlen(filename);
-        ret = new(char, (e + 1 - path) + k + 1);
-        if (!ret)
-                return NULL;
-
-        memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
-        return ret;
-}
-
-bool hidden_or_backup_file(const char *filename) {
-        const char *p;
-
-        assert(filename);
-
-        if (filename[0] == '.' ||
-            streq(filename, "lost+found") ||
-            streq(filename, "aquota.user") ||
-            streq(filename, "aquota.group") ||
-            endswith(filename, "~"))
-                return true;
-
-        p = strrchr(filename, '.');
-        if (!p)
-                return false;
-
-        /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up
-         * with always new suffixes and that everybody else should just adjust to that, then it really should be on
-         * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt
-         * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional
-         * string. Specifically: there's now:
-         *
-         *    The generic suffixes "~" and ".bak" for backup files
-         *    The generic prefix "." for hidden files
-         *
-         * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist"
-         * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead.
-         */
-
-        return STR_IN_SET(p + 1,
-                          "rpmnew",
-                          "rpmsave",
-                          "rpmorig",
-                          "dpkg-old",
-                          "dpkg-new",
-                          "dpkg-tmp",
-                          "dpkg-dist",
-                          "dpkg-bak",
-                          "dpkg-backup",
-                          "dpkg-remove",
-                          "ucf-new",
-                          "ucf-old",
-                          "ucf-dist",
-                          "swp",
-                          "bak",
-                          "old",
-                          "new");
-}
-
-bool is_device_path(const char *path) {
-
-        /* Returns true on paths that likely refer to a device, either by path in sysfs or to something in /dev */
-
-        return PATH_STARTSWITH_SET(path, "/dev/", "/sys/");
-}
-
-bool valid_device_node_path(const char *path) {
-
-        /* Some superficial checks whether the specified path is a valid device node path, all without looking at the
-         * actual device node. */
-
-        if (!PATH_STARTSWITH_SET(path, "/dev/", "/run/systemd/inaccessible/"))
-                return false;
-
-        if (endswith(path, "/")) /* can't be a device node if it ends in a slash */
-                return false;
-
-        return path_is_normalized(path);
-}
-
-bool valid_device_allow_pattern(const char *path) {
-        assert(path);
-
-        /* Like valid_device_node_path(), but also allows full-subsystem expressions, like DeviceAllow= and DeviceDeny=
-         * accept it */
-
-        if (STARTSWITH_SET(path, "block-", "char-"))
-                return true;
-
-        return valid_device_node_path(path);
-}
-
-int systemd_installation_has_version(const char *root, unsigned minimal_version) {
-        const char *pattern;
-        int r;
-
-        /* Try to guess if systemd installation is later than the specified version. This
-         * is hacky and likely to yield false negatives, particularly if the installation
-         * is non-standard. False positives should be relatively rare.
-         */
-
-        NULSTR_FOREACH(pattern,
-                       /* /lib works for systems without usr-merge, and for systems with a sane
-                        * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
-                        * for Gentoo which does a merge without making /lib a symlink.
-                        */
-                       "lib/systemd/libsystemd-shared-*.so\0"
-                       "lib64/systemd/libsystemd-shared-*.so\0"
-                       "usr/lib/systemd/libsystemd-shared-*.so\0"
-                       "usr/lib64/systemd/libsystemd-shared-*.so\0") {
-
-                _cleanup_strv_free_ char **names = NULL;
-                _cleanup_free_ char *path = NULL;
-                char *c, **name;
-
-                path = path_join(root, pattern);
-                if (!path)
-                        return -ENOMEM;
-
-                r = glob_extend(&names, path, 0);
-                if (r == -ENOENT)
-                        continue;
-                if (r < 0)
-                        return r;
-
-                assert_se(c = endswith(path, "*.so"));
-                *c = '\0'; /* truncate the glob part */
-
-                STRV_FOREACH(name, names) {
-                        /* This is most likely to run only once, hence let's not optimize anything. */
-                        char *t, *t2;
-                        unsigned version;
-
-                        t = startswith(*name, path);
-                        if (!t)
-                                continue;
-
-                        t2 = endswith(t, ".so");
-                        if (!t2)
-                                continue;
-
-                        t2[0] = '\0'; /* truncate the suffix */
-
-                        r = safe_atou(t, &version);
-                        if (r < 0) {
-                                log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
-                                continue;
-                        }
-
-                        log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
-                                  *name, version,
-                                  version >= minimal_version ? "OK" : "too old");
-                        if (version >= minimal_version)
-                                return true;
-                }
-        }
-
-        return false;
-}
-#endif /* NM_IGNORED */
-
-bool dot_or_dot_dot(const char *path) {
-        if (!path)
-                return false;
-        if (path[0] != '.')
-                return false;
-        if (path[1] == 0)
-                return true;
-        if (path[1] != '.')
-                return false;
-
-        return path[2] == 0;
-}
-
-#if 0 /* NM_IGNORED */
-bool empty_or_root(const char *root) {
-
-        /* For operations relative to some root directory, returns true if the specified root directory is redundant,
-         * i.e. either / or NULL or the empty string or any equivalent. */
-
-        if (!root)
-                return true;
-
-        return root[strspn(root, "/")] == 0;
-}
-
-bool path_strv_contains(char **l, const char *path) {
-        char **i;
-
-        STRV_FOREACH(i, l)
-                if (path_equal(*i, path))
-                        return true;
-
-        return false;
-}
-
-bool prefixed_path_strv_contains(char **l, const char *path) {
-        char **i, *j;
-
-        STRV_FOREACH(i, l) {
-                j = *i;
-                if (*j == '-')
-                        j++;
-                if (*j == '+')
-                        j++;
-                if (path_equal(j, path))
-                        return true;
-        }
-
-        return false;
-}
-
-bool credential_name_valid(const char *s) {
-        /* We want that credential names are both valid in filenames (since that's our primary way to pass
-         * them around) and as fdnames (which is how we might want to pass them around eventually) */
-        return filename_is_valid(s) && fdname_is_valid(s);
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/path-util.h b/shared/systemd/src/basic/path-util.h
deleted file mode 100644
index 988f058b..00000000
--- a/shared/systemd/src/basic/path-util.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <alloca.h>
-#include <stdbool.h>
-#include <stddef.h>
-
-#include "macro.h"
-#include "string-util.h"
-#include "strv.h"
-#include "time-util.h"
-
-#if 0 /* NM_IGNORED */
-#define PATH_SPLIT_SBIN_BIN(x) x "sbin:" x "bin"
-#define PATH_SPLIT_SBIN_BIN_NULSTR(x) x "sbin\0" x "bin\0"
-
-#define PATH_NORMAL_SBIN_BIN(x) x "bin"
-#define PATH_NORMAL_SBIN_BIN_NULSTR(x) x "bin\0"
-
-#if HAVE_SPLIT_BIN
-#  define PATH_SBIN_BIN(x) PATH_SPLIT_SBIN_BIN(x)
-#  define PATH_SBIN_BIN_NULSTR(x) PATH_SPLIT_SBIN_BIN_NULSTR(x)
-#else
-#  define PATH_SBIN_BIN(x) PATH_NORMAL_SBIN_BIN(x)
-#  define PATH_SBIN_BIN_NULSTR(x) PATH_NORMAL_SBIN_BIN_NULSTR(x)
-#endif
-
-#define DEFAULT_PATH_NORMAL PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/")
-#define DEFAULT_PATH_NORMAL_NULSTR PATH_SBIN_BIN_NULSTR("/usr/local/") PATH_SBIN_BIN_NULSTR("/usr/")
-#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":" PATH_SBIN_BIN("/")
-#define DEFAULT_PATH_SPLIT_USR_NULSTR DEFAULT_PATH_NORMAL_NULSTR PATH_SBIN_BIN_NULSTR("/")
-#define DEFAULT_PATH_COMPAT PATH_SPLIT_SBIN_BIN("/usr/local/") ":" PATH_SPLIT_SBIN_BIN("/usr/") ":" PATH_SPLIT_SBIN_BIN("/")
-
-#if HAVE_SPLIT_USR
-#  define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR
-#  define DEFAULT_PATH_NULSTR DEFAULT_PATH_SPLIT_USR_NULSTR
-#else
-#  define DEFAULT_PATH DEFAULT_PATH_NORMAL
-#  define DEFAULT_PATH_NULSTR DEFAULT_PATH_NORMAL_NULSTR
-#endif
-#endif /* NM_IGNORED */
-
-#ifndef DEFAULT_USER_PATH
-#  define DEFAULT_USER_PATH DEFAULT_PATH
-#endif
-
-static inline bool is_path(const char *p) {
-        assert(p);
-        return strchr(p, '/');
-}
-
-static inline bool path_is_absolute(const char *p) {
-        assert(p);
-        return p[0] == '/';
-}
-
-int path_split_and_make_absolute(const char *p, char ***ret);
-char* path_make_absolute(const char *p, const char *prefix);
-int safe_getcwd(char **ret);
-int path_make_absolute_cwd(const char *p, char **ret);
-int path_make_relative(const char *from_dir, const char *to_path, char **_r);
-char* path_startswith(const char *path, const char *prefix) _pure_;
-int path_compare(const char *a, const char *b) _pure_;
-bool path_equal(const char *a, const char *b) _pure_;
-bool path_equal_or_files_same(const char *a, const char *b, int flags);
-char* path_join_internal(const char *first, ...);
-#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, POINTER_MAX)
-
-char* path_simplify(char *path, bool kill_dots);
-
-enum {
-        PATH_CHECK_FATAL    = 1 << 0,  /* If not set, then error message is appended with 'ignoring'. */
-        PATH_CHECK_ABSOLUTE = 1 << 1,
-        PATH_CHECK_RELATIVE = 1 << 2,
-};
-
-int path_simplify_and_warn(char *path, unsigned flag, const char *unit, const char *filename, unsigned line, const char *lvalue);
-
-static inline bool path_equal_ptr(const char *a, const char *b) {
-        return !!a == !!b && (!a || path_equal(a, b));
-}
-
-/* Note: the search terminates on the first NULL item. */
-#define PATH_IN_SET(p, ...) path_strv_contains(STRV_MAKE(__VA_ARGS__), p)
-
-char* path_startswith_strv(const char *p, char **set);
-#define PATH_STARTSWITH_SET(p, ...) path_startswith_strv(p, STRV_MAKE(__VA_ARGS__))
-
-int path_strv_make_absolute_cwd(char **l);
-char** path_strv_resolve(char **l, const char *root);
-char** path_strv_resolve_uniq(char **l, const char *root);
-
-int find_executable_full(const char *name, 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);
-
-int fsck_exists(const char *fstype);
-
-/* Iterates through the path prefixes of the specified path, going up
- * the tree, to root. Also returns "" (and not "/"!) for the root
- * directory. Excludes the specified directory itself */
-#define PATH_FOREACH_PREFIX(prefix, path)                               \
-        for (char *_slash = ({                                          \
-                                path_simplify(strcpy(prefix, path), false); \
-                                streq(prefix, "/") ? NULL : strrchr(prefix, '/'); \
-                        });                                             \
-             _slash && ((*_slash = 0), true);                           \
-             _slash = strrchr((prefix), '/'))
-
-/* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */
-#define PATH_FOREACH_PREFIX_MORE(prefix, path)                          \
-        for (char *_slash = ({                                          \
-                                path_simplify(strcpy(prefix, path), false); \
-                                if (streq(prefix, "/"))                 \
-                                        prefix[0] = 0;                  \
-                                strrchr(prefix, 0);                     \
-                        });                                             \
-             _slash && ((*_slash = 0), true);                           \
-             _slash = strrchr((prefix), '/'))
-
-/* Similar to path_join(), but only works for two components, and only the first one may be NULL and returns
- * an alloca() buffer, or possibly a const pointer into the path parameter. */
-#define prefix_roota(root, path)                                        \
-        ({                                                              \
-                const char* _path = (path), *_root = (root), *_ret;     \
-                char *_p, *_n;                                          \
-                size_t _l;                                              \
-                while (_path[0] == '/' && _path[1] == '/')              \
-                        _path ++;                                       \
-                if (isempty(_root))                                     \
-                        _ret = _path;                                   \
-                else {                                                  \
-                        _l = strlen(_root) + 1 + strlen(_path) + 1;     \
-                        _n = newa(char, _l);                            \
-                        _p = stpcpy(_n, _root);                         \
-                        while (_p > _n && _p[-1] == '/')                \
-                                _p--;                                   \
-                        if (_path[0] != '/')                            \
-                                *(_p++) = '/';                          \
-                        strcpy(_p, _path);                              \
-                        _ret = _n;                                      \
-                }                                                       \
-                _ret;                                                   \
-        })
-
-int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg);
-
-char* dirname_malloc(const char *path);
-const char *last_path_component(const char *path);
-int path_extract_filename(const char *p, char **ret);
-
-bool filename_is_valid(const char *p) _pure_;
-bool path_is_valid(const char *p) _pure_;
-bool path_is_normalized(const char *p) _pure_;
-
-char *file_in_same_dir(const char *path, const char *filename);
-
-bool hidden_or_backup_file(const char *filename) _pure_;
-
-bool is_device_path(const char *path);
-
-bool valid_device_node_path(const char *path);
-bool valid_device_allow_pattern(const char *path);
-
-int systemd_installation_has_version(const char *root, unsigned minimal_version);
-
-bool dot_or_dot_dot(const char *path);
-
-static inline const char *skip_dev_prefix(const char *p) {
-        const char *e;
-
-        /* Drop any /dev prefix if there is any */
-
-        e = path_startswith(p, "/dev/");
-
-        return e ?: p;
-}
-
-bool empty_or_root(const char *root);
-static inline const char *empty_to_root(const char *path) {
-        return isempty(path) ? "/" : path;
-}
-
-bool path_strv_contains(char **l, const char *path);
-bool prefixed_path_strv_contains(char **l, const char *path);
-
-bool credential_name_valid(const char *s);
diff --git a/shared/systemd/src/basic/prioq.c b/shared/systemd/src/basic/prioq.c
deleted file mode 100644
index 19a9bc57..00000000
--- a/shared/systemd/src/basic/prioq.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-/*
- * Priority Queue
- * The prioq object implements a priority queue. That is, it orders objects by
- * their priority and allows O(1) access to the object with the highest
- * priority. Insertion and removal are Θ(log n). Optionally, the caller can
- * provide a pointer to an index which will be kept up-to-date by the prioq.
- *
- * The underlying algorithm used in this implementation is a Heap.
- */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <stdlib.h>
-
-#include "alloc-util.h"
-#include "hashmap.h"
-#include "prioq.h"
-
-struct prioq_item {
-        void *data;
-        unsigned *idx;
-};
-
-struct Prioq {
-        compare_func_t compare_func;
-        unsigned n_items, n_allocated;
-
-        struct prioq_item *items;
-};
-
-Prioq *prioq_new(compare_func_t compare_func) {
-        Prioq *q;
-
-        q = new(Prioq, 1);
-        if (!q)
-                return q;
-
-        *q = (Prioq) {
-                .compare_func = compare_func,
-        };
-
-        return q;
-}
-
-Prioq* prioq_free(Prioq *q) {
-        if (!q)
-                return NULL;
-
-        free(q->items);
-        return mfree(q);
-}
-
-int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) {
-        assert(q);
-
-        if (*q)
-                return 0;
-
-        *q = prioq_new(compare_func);
-        if (!*q)
-                return -ENOMEM;
-
-        return 0;
-}
-
-static void swap(Prioq *q, unsigned j, unsigned k) {
-        assert(q);
-        assert(j < q->n_items);
-        assert(k < q->n_items);
-
-        assert(!q->items[j].idx || *(q->items[j].idx) == j);
-        assert(!q->items[k].idx || *(q->items[k].idx) == k);
-
-        SWAP_TWO(q->items[j].data, q->items[k].data);
-        SWAP_TWO(q->items[j].idx, q->items[k].idx);
-
-        if (q->items[j].idx)
-                *q->items[j].idx = j;
-
-        if (q->items[k].idx)
-                *q->items[k].idx = k;
-}
-
-static unsigned shuffle_up(Prioq *q, unsigned idx) {
-        assert(q);
-        assert(idx < q->n_items);
-
-        while (idx > 0) {
-                unsigned k;
-
-                k = (idx-1)/2;
-
-                if (q->compare_func(q->items[k].data, q->items[idx].data) <= 0)
-                        break;
-
-                swap(q, idx, k);
-                idx = k;
-        }
-
-        return idx;
-}
-
-static unsigned shuffle_down(Prioq *q, unsigned idx) {
-        assert(q);
-
-        for (;;) {
-                unsigned j, k, s;
-
-                k = (idx+1)*2; /* right child */
-                j = k-1;       /* left child */
-
-                if (j >= q->n_items)
-                        break;
-
-                if (q->compare_func(q->items[j].data, q->items[idx].data) < 0)
-
-                        /* So our left child is smaller than we are, let's
-                         * remember this fact */
-                        s = j;
-                else
-                        s = idx;
-
-                if (k < q->n_items &&
-                    q->compare_func(q->items[k].data, q->items[s].data) < 0)
-
-                        /* So our right child is smaller than we are, let's
-                         * remember this fact */
-                        s = k;
-
-                /* s now points to the smallest of the three items */
-
-                if (s == idx)
-                        /* No swap necessary, we're done */
-                        break;
-
-                swap(q, idx, s);
-                idx = s;
-        }
-
-        return idx;
-}
-
-int prioq_put(Prioq *q, void *data, unsigned *idx) {
-        struct prioq_item *i;
-        unsigned k;
-
-        assert(q);
-
-        if (q->n_items >= q->n_allocated) {
-                unsigned n;
-                struct prioq_item *j;
-
-                n = MAX((q->n_items+1) * 2, 16u);
-                j = reallocarray(q->items, n, sizeof(struct prioq_item));
-                if (!j)
-                        return -ENOMEM;
-
-                q->items = j;
-                q->n_allocated = n;
-        }
-
-        k = q->n_items++;
-        i = q->items + k;
-        i->data = data;
-        i->idx = idx;
-
-        if (idx)
-                *idx = k;
-
-        shuffle_up(q, k);
-
-        return 0;
-}
-
-static void remove_item(Prioq *q, struct prioq_item *i) {
-        struct prioq_item *l;
-
-        assert(q);
-        assert(i);
-
-        l = q->items + q->n_items - 1;
-
-        if (i == l)
-                /* Last entry, let's just remove it */
-                q->n_items--;
-        else {
-                unsigned k;
-
-                /* Not last entry, let's replace the last entry with
-                 * this one, and reshuffle */
-
-                k = i - q->items;
-
-                i->data = l->data;
-                i->idx = l->idx;
-                if (i->idx)
-                        *i->idx = k;
-                q->n_items--;
-
-                k = shuffle_down(q, k);
-                shuffle_up(q, k);
-        }
-}
-
-_pure_ static struct prioq_item* find_item(Prioq *q, void *data, unsigned *idx) {
-        struct prioq_item *i;
-
-        assert(q);
-
-        if (q->n_items <= 0)
-                return NULL;
-
-        if (idx) {
-                if (*idx == PRIOQ_IDX_NULL ||
-                    *idx >= q->n_items)
-                        return NULL;
-
-                i = q->items + *idx;
-                if (i->data != data)
-                        return NULL;
-
-                return i;
-        } else {
-                for (i = q->items; i < q->items + q->n_items; i++)
-                        if (i->data == data)
-                                return i;
-                return NULL;
-        }
-}
-
-int prioq_remove(Prioq *q, void *data, unsigned *idx) {
-        struct prioq_item *i;
-
-        if (!q)
-                return 0;
-
-        i = find_item(q, data, idx);
-        if (!i)
-                return 0;
-
-        remove_item(q, i);
-        return 1;
-}
-
-int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
-        struct prioq_item *i;
-        unsigned k;
-
-        assert(q);
-
-        i = find_item(q, data, idx);
-        if (!i)
-                return 0;
-
-        k = i - q->items;
-        k = shuffle_down(q, k);
-        shuffle_up(q, k);
-        return 1;
-}
-
-void *prioq_peek_by_index(Prioq *q, unsigned idx) {
-        if (!q)
-                return NULL;
-
-        if (idx >= q->n_items)
-                return NULL;
-
-        return q->items[idx].data;
-}
-
-void *prioq_pop(Prioq *q) {
-        void *data;
-
-        if (!q)
-                return NULL;
-
-        if (q->n_items <= 0)
-                return NULL;
-
-        data = q->items[0].data;
-        remove_item(q, q->items);
-        return data;
-}
-
-unsigned prioq_size(Prioq *q) {
-
-        if (!q)
-                return 0;
-
-        return q->n_items;
-}
-
-bool prioq_isempty(Prioq *q) {
-
-        if (!q)
-                return true;
-
-        return q->n_items <= 0;
-}
diff --git a/shared/systemd/src/basic/prioq.h b/shared/systemd/src/basic/prioq.h
deleted file mode 100644
index 951576c0..00000000
--- a/shared/systemd/src/basic/prioq.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-
-#include "hashmap.h"
-#include "macro.h"
-
-typedef struct Prioq Prioq;
-
-#define PRIOQ_IDX_NULL ((unsigned) -1)
-
-Prioq *prioq_new(compare_func_t compare);
-Prioq *prioq_free(Prioq *q);
-DEFINE_TRIVIAL_CLEANUP_FUNC(Prioq*, prioq_free);
-int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func);
-
-int prioq_put(Prioq *q, void *data, unsigned *idx);
-int prioq_remove(Prioq *q, void *data, unsigned *idx);
-int prioq_reshuffle(Prioq *q, void *data, unsigned *idx);
-
-void *prioq_peek_by_index(Prioq *q, unsigned idx) _pure_;
-static inline void *prioq_peek(Prioq *q) {
-        return prioq_peek_by_index(q, 0);
-}
-void *prioq_pop(Prioq *q);
-
-#define PRIOQ_FOREACH_ITEM(q, p)                                \
-        for (unsigned _i = 0; (p = prioq_peek_by_index(q, _i)); _i++)
-
-unsigned prioq_size(Prioq *q) _pure_;
-bool prioq_isempty(Prioq *q) _pure_;
diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c
deleted file mode 100644
index 0e25b020..00000000
--- a/shared/systemd/src/basic/process-util.c
+++ /dev/null
@@ -1,1662 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <linux/oom.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <sys/mount.h>
-#include <sys/personality.h>
-#include <sys/prctl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <syslog.h>
-#include <unistd.h>
-#if 0 /* NM_IGNORED */
-#if HAVE_VALGRIND_VALGRIND_H
-#include <valgrind/valgrind.h>
-#endif
-#endif /* NM_IGNORED */
-
-#include "alloc-util.h"
-#include "architecture.h"
-#include "env-util.h"
-#include "errno-util.h"
-#include "escape.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "ioprio.h"
-#include "locale-util.h"
-#include "log.h"
-#include "macro.h"
-#include "memory-util.h"
-#include "missing_sched.h"
-#include "missing_syscall.h"
-#include "namespace-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "raw-clone.h"
-#include "rlimit-util.h"
-#include "signal-util.h"
-#include "stat-util.h"
-#include "stdio-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "terminal-util.h"
-#include "user-util.h"
-#include "utf8.h"
-
-#if 0 /* NM_IGNORED */
-
-/* The kernel limits userspace processes to TASK_COMM_LEN (16 bytes), but allows higher values for its own
- * workers, e.g. "kworker/u9:3-kcryptd/253:0". Let's pick a fixed smallish limit that will work for the kernel.
- */
-#define COMM_MAX_LEN 128
-
-static int get_process_state(pid_t pid) {
-        _cleanup_free_ char *line = NULL;
-        const char *p;
-        char state;
-        int r;
-
-        assert(pid >= 0);
-
-        /* Shortcut: if we are enquired about our own state, we are obviously running */
-        if (pid == 0 || pid == getpid_cached())
-                return (unsigned char) 'R';
-
-        p = procfs_file_alloca(pid, "stat");
-
-        r = read_one_line_file(p, &line);
-        if (r == -ENOENT)
-                return -ESRCH;
-        if (r < 0)
-                return r;
-
-        p = strrchr(line, ')');
-        if (!p)
-                return -EIO;
-
-        p++;
-
-        if (sscanf(p, " %c", &state) != 1)
-                return -EIO;
-
-        return (unsigned char) state;
-}
-
-int get_process_comm(pid_t pid, char **ret) {
-        _cleanup_free_ char *escaped = NULL, *comm = NULL;
-        int r;
-
-        assert(ret);
-        assert(pid >= 0);
-
-        if (pid == 0 || pid == getpid_cached()) {
-                comm = new0(char, TASK_COMM_LEN + 1); /* Must fit in 16 byte according to prctl(2) */
-                if (!comm)
-                        return -ENOMEM;
-
-                if (prctl(PR_GET_NAME, comm) < 0)
-                        return -errno;
-        } else {
-                const char *p;
-
-                p = procfs_file_alloca(pid, "comm");
-
-                /* Note that process names of kernel threads can be much longer than TASK_COMM_LEN */
-                r = read_one_line_file(p, &comm);
-                if (r == -ENOENT)
-                        return -ESRCH;
-                if (r < 0)
-                        return r;
-        }
-
-        escaped = new(char, COMM_MAX_LEN);
-        if (!escaped)
-                return -ENOMEM;
-
-        /* Escape unprintable characters, just in case, but don't grow the string beyond the underlying size */
-        cellescape(escaped, COMM_MAX_LEN, comm);
-
-        *ret = TAKE_PTR(escaped);
-        return 0;
-}
-
-int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line) {
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *t = NULL, *ans = NULL;
-        const char *p;
-        int r;
-        size_t k;
-
-        /* This is supposed to be a safety guard against runaway command lines. */
-        size_t max_length = sc_arg_max();
-
-        assert(line);
-        assert(pid >= 0);
-
-        /* Retrieves a process' command line. Replaces non-utf8 bytes by replacement character (�). If
-         * max_columns is != -1 will return a string of the specified console width at most, abbreviated with
-         * an ellipsis. If PROCESS_CMDLINE_COMM_FALLBACK is specified in flags and the process has no command
-         * line set (the case for kernel threads), or has a command line that resolves to the empty string
-         * will return the "comm" name of the process instead. This will use at most _SC_ARG_MAX bytes of
-         * input data.
-         *
-         * Returns -ESRCH if the process doesn't exist, and -ENOENT if the process has no command line (and
-         * comm_fallback is false). Returns 0 and sets *line otherwise. */
-
-        p = procfs_file_alloca(pid, "cmdline");
-        r = fopen_unlocked(p, "re", &f);
-        if (r == -ENOENT)
-                return -ESRCH;
-        if (r < 0)
-                return r;
-
-        /* We assume that each four-byte character uses one or two columns. If we ever check for combining
-         * characters, this assumption will need to be adjusted. */
-        if ((size_t) 4 * max_columns + 1 < max_columns)
-                max_length = MIN(max_length, (size_t) 4 * max_columns + 1);
-
-        t = new(char, max_length);
-        if (!t)
-                return -ENOMEM;
-
-        k = fread(t, 1, max_length, f);
-        if (k > 0) {
-                /* Arguments are separated by NULs. Let's replace those with spaces. */
-                for (size_t i = 0; i < k - 1; i++)
-                        if (t[i] == '\0')
-                                t[i] = ' ';
-
-                t[k] = '\0'; /* Normally, t[k] is already NUL, so this is just a guard in case of short read */
-        } else {
-                /* We only treat getting nothing as an error. We *could* also get an error after reading some
-                 * data, but we ignore that case, as such an error is rather unlikely and we prefer to get
-                 * some data rather than none. */
-                if (ferror(f))
-                        return -errno;
-
-                if (!(flags & PROCESS_CMDLINE_COMM_FALLBACK))
-                        return -ENOENT;
-
-                /* Kernel threads have no argv[] */
-                _cleanup_free_ char *t2 = NULL;
-
-                r = get_process_comm(pid, &t2);
-                if (r < 0)
-                        return r;
-
-                mfree(t);
-                t = strjoin("[", t2, "]");
-                if (!t)
-                        return -ENOMEM;
-        }
-
-        delete_trailing_chars(t, WHITESPACE);
-
-        bool eight_bit = (flags & PROCESS_CMDLINE_USE_LOCALE) && !is_locale_utf8();
-
-        ans = escape_non_printable_full(t, max_columns, eight_bit);
-        if (!ans)
-                return -ENOMEM;
-
-        (void) str_realloc(&ans);
-        *line = TAKE_PTR(ans);
-        return 0;
-}
-
-static int update_argv(const char name[], size_t l) {
-        static int can_do = -1;
-
-        if (can_do == 0)
-                return 0;
-        can_do = false; /* We'll set it to true only if the whole process works */
-
-        /* Let's not bother with this if we don't have euid == 0. Strictly speaking we should check for the
-         * CAP_SYS_RESOURCE capability which is independent of the euid. In our own code the capability generally is
-         * present only for euid == 0, hence let's use this as quick bypass check, to avoid calling mmap() if
-         * PR_SET_MM_ARG_{START,END} fails with EPERM later on anyway. After all geteuid() is dead cheap to call, but
-         * mmap() is not. */
-        if (geteuid() != 0)
-                return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
-                                       "Skipping PR_SET_MM, as we don't have privileges.");
-
-        static size_t mm_size = 0;
-        static char *mm = NULL;
-        int r;
-
-        if (mm_size < l+1) {
-                size_t nn_size;
-                char *nn;
-
-                nn_size = PAGE_ALIGN(l+1);
-                nn = mmap(NULL, nn_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
-                if (nn == MAP_FAILED)
-                        return log_debug_errno(errno, "mmap() failed: %m");
-
-                strncpy(nn, name, nn_size);
-
-                /* Now, let's tell the kernel about this new memory */
-                if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) {
-                        if (ERRNO_IS_PRIVILEGE(errno))
-                                return log_debug_errno(errno, "PR_SET_MM_ARG_START failed: %m");
-
-                        /* HACK: prctl() API is kind of dumb on this point.  The existing end address may already be
-                         * below the desired start address, in which case the kernel may have kicked this back due
-                         * to a range-check failure (see linux/kernel/sys.c:validate_prctl_map() to see this in
-                         * action).  The proper solution would be to have a prctl() API that could set both start+end
-                         * simultaneously, or at least let us query the existing address to anticipate this condition
-                         * and respond accordingly.  For now, we can only guess at the cause of this failure and try
-                         * a workaround--which will briefly expand the arg space to something potentially huge before
-                         * resizing it to what we want. */
-                        log_debug_errno(errno, "PR_SET_MM_ARG_START failed, attempting PR_SET_MM_ARG_END hack: %m");
-
-                        if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0) {
-                                r = log_debug_errno(errno, "PR_SET_MM_ARG_END hack failed, proceeding without: %m");
-                                (void) munmap(nn, nn_size);
-                                return r;
-                        }
-
-                        if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0)
-                                return log_debug_errno(errno, "PR_SET_MM_ARG_START still failed, proceeding without: %m");
-                } else {
-                        /* And update the end pointer to the new end, too. If this fails, we don't really know what
-                         * to do, it's pretty unlikely that we can rollback, hence we'll just accept the failure,
-                         * and continue. */
-                        if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0)
-                                log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
-                }
-
-                if (mm)
-                        (void) munmap(mm, mm_size);
-
-                mm = nn;
-                mm_size = nn_size;
-        } else {
-                strncpy(mm, name, mm_size);
-
-                /* Update the end pointer, continuing regardless of any failure. */
-                if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) mm + l + 1, 0, 0) < 0)
-                        log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
-        }
-
-        can_do = true;
-        return 0;
-}
-
-int rename_process(const char name[]) {
-        bool truncated = false;
-
-        /* This is a like a poor man's setproctitle(). It changes the comm field, argv[0], and also the glibc's
-         * internally used name of the process. For the first one a limit of 16 chars applies; to the second one in
-         * many cases one of 10 (i.e. length of "/sbin/init") — however if we have CAP_SYS_RESOURCES it is unbounded;
-         * to the third one 7 (i.e. the length of "systemd". If you pass a longer string it will likely be
-         * truncated.
-         *
-         * Returns 0 if a name was set but truncated, > 0 if it was set but not truncated. */
-
-        if (isempty(name))
-                return -EINVAL; /* let's not confuse users unnecessarily with an empty name */
-
-        if (!is_main_thread())
-                return -EPERM; /* Let's not allow setting the process name from other threads than the main one, as we
-                                * cache things without locking, and we make assumptions that PR_SET_NAME sets the
-                                * process name that isn't correct on any other threads */
-
-        size_t l = strlen(name);
-
-        /* First step, change the comm field. The main thread's comm is identical to the process comm. This means we
-         * can use PR_SET_NAME, which sets the thread name for the calling thread. */
-        if (prctl(PR_SET_NAME, name) < 0)
-                log_debug_errno(errno, "PR_SET_NAME failed: %m");
-        if (l >= TASK_COMM_LEN) /* Linux userspace process names can be 15 chars at max */
-                truncated = true;
-
-        /* Second step, change glibc's ID of the process name. */
-        if (program_invocation_name) {
-                size_t k;
-
-                k = strlen(program_invocation_name);
-                strncpy(program_invocation_name, name, k);
-                if (l > k)
-                        truncated = true;
-        }
-
-        /* Third step, completely replace the argv[] array the kernel maintains for us. This requires privileges, but
-         * has the advantage that the argv[] array is exactly what we want it to be, and not filled up with zeros at
-         * the end. This is the best option for changing /proc/self/cmdline. */
-        (void) update_argv(name, l);
-
-        /* Fourth step: in all cases we'll also update the original argv[], so that our own code gets it right too if
-         * it still looks here */
-        if (saved_argc > 0) {
-                if (saved_argv[0]) {
-                        size_t k;
-
-                        k = strlen(saved_argv[0]);
-                        strncpy(saved_argv[0], name, k);
-                        if (l > k)
-                                truncated = true;
-                }
-
-                for (int i = 1; i < saved_argc; i++) {
-                        if (!saved_argv[i])
-                                break;
-
-                        memzero(saved_argv[i], strlen(saved_argv[i]));
-                }
-        }
-
-        return !truncated;
-}
-
-int is_kernel_thread(pid_t pid) {
-        _cleanup_free_ char *line = NULL;
-        unsigned long long flags;
-        size_t l, i;
-        const char *p;
-        char *q;
-        int r;
-
-        if (IN_SET(pid, 0, 1) || pid == getpid_cached()) /* pid 1, and we ourselves certainly aren't a kernel thread */
-                return 0;
-        if (!pid_is_valid(pid))
-                return -EINVAL;
-
-        p = procfs_file_alloca(pid, "stat");
-        r = read_one_line_file(p, &line);
-        if (r == -ENOENT)
-                return -ESRCH;
-        if (r < 0)
-                return r;
-
-        /* Skip past the comm field */
-        q = strrchr(line, ')');
-        if (!q)
-                return -EINVAL;
-        q++;
-
-        /* Skip 6 fields to reach the flags field */
-        for (i = 0; i < 6; i++) {
-                l = strspn(q, WHITESPACE);
-                if (l < 1)
-                        return -EINVAL;
-                q += l;
-
-                l = strcspn(q, WHITESPACE);
-                if (l < 1)
-                        return -EINVAL;
-                q += l;
-        }
-
-        /* Skip preceding whitespace */
-        l = strspn(q, WHITESPACE);
-        if (l < 1)
-                return -EINVAL;
-        q += l;
-
-        /* Truncate the rest */
-        l = strcspn(q, WHITESPACE);
-        if (l < 1)
-                return -EINVAL;
-        q[l] = 0;
-
-        r = safe_atollu(q, &flags);
-        if (r < 0)
-                return r;
-
-        return !!(flags & PF_KTHREAD);
-}
-
-int get_process_capeff(pid_t pid, char **capeff) {
-        const char *p;
-        int r;
-
-        assert(capeff);
-        assert(pid >= 0);
-
-        p = procfs_file_alloca(pid, "status");
-
-        r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
-        if (r == -ENOENT)
-                return -ESRCH;
-
-        return r;
-}
-
-static int get_process_link_contents(const char *proc_file, char **name) {
-        int r;
-
-        assert(proc_file);
-        assert(name);
-
-        r = readlink_malloc(proc_file, name);
-        if (r == -ENOENT)
-                return -ESRCH;
-        if (r < 0)
-                return r;
-
-        return 0;
-}
-
-int get_process_exe(pid_t pid, char **name) {
-        const char *p;
-        char *d;
-        int r;
-
-        assert(pid >= 0);
-
-        p = procfs_file_alloca(pid, "exe");
-        r = get_process_link_contents(p, name);
-        if (r < 0)
-                return r;
-
-        d = endswith(*name, " (deleted)");
-        if (d)
-                *d = '\0';
-
-        return 0;
-}
-
-static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
-        _cleanup_fclose_ FILE *f = NULL;
-        const char *p;
-        int r;
-
-        assert(field);
-        assert(uid);
-
-        if (pid < 0)
-                return -EINVAL;
-
-        p = procfs_file_alloca(pid, "status");
-        r = fopen_unlocked(p, "re", &f);
-        if (r == -ENOENT)
-                return -ESRCH;
-        if (r < 0)
-                return r;
-
-        for (;;) {
-                _cleanup_free_ char *line = NULL;
-                char *l;
-
-                r = read_line(f, LONG_LINE_MAX, &line);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                l = strstrip(line);
-
-                if (startswith(l, field)) {
-                        l += strlen(field);
-                        l += strspn(l, WHITESPACE);
-
-                        l[strcspn(l, WHITESPACE)] = 0;
-
-                        return parse_uid(l, uid);
-                }
-        }
-
-        return -EIO;
-}
-
-int get_process_uid(pid_t pid, uid_t *uid) {
-
-        if (pid == 0 || pid == getpid_cached()) {
-                *uid = getuid();
-                return 0;
-        }
-
-        return get_process_id(pid, "Uid:", uid);
-}
-
-int get_process_gid(pid_t pid, gid_t *gid) {
-
-        if (pid == 0 || pid == getpid_cached()) {
-                *gid = getgid();
-                return 0;
-        }
-
-        assert_cc(sizeof(uid_t) == sizeof(gid_t));
-        return get_process_id(pid, "Gid:", gid);
-}
-
-int get_process_cwd(pid_t pid, char **cwd) {
-        const char *p;
-
-        assert(pid >= 0);
-
-        if (pid == 0 || pid == getpid_cached())
-                return safe_getcwd(cwd);
-
-        p = procfs_file_alloca(pid, "cwd");
-
-        return get_process_link_contents(p, cwd);
-}
-
-int get_process_root(pid_t pid, char **root) {
-        const char *p;
-
-        assert(pid >= 0);
-
-        p = procfs_file_alloca(pid, "root");
-
-        return get_process_link_contents(p, root);
-}
-
-#define ENVIRONMENT_BLOCK_MAX (5U*1024U*1024U)
-
-int get_process_environ(pid_t pid, char **env) {
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *outcome = NULL;
-        size_t allocated = 0, sz = 0;
-        const char *p;
-        int r;
-
-        assert(pid >= 0);
-        assert(env);
-
-        p = procfs_file_alloca(pid, "environ");
-
-        r = fopen_unlocked(p, "re", &f);
-        if (r == -ENOENT)
-                return -ESRCH;
-        if (r < 0)
-                return r;
-
-        for (;;) {
-                char c;
-
-                if (sz >= ENVIRONMENT_BLOCK_MAX)
-                        return -ENOBUFS;
-
-                if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
-                        return -ENOMEM;
-
-                r = safe_fgetc(f, &c);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                if (c == '\0')
-                        outcome[sz++] = '\n';
-                else
-                        sz += cescape_char(c, outcome + sz);
-        }
-
-        outcome[sz] = '\0';
-        *env = TAKE_PTR(outcome);
-
-        return 0;
-}
-
-int get_process_ppid(pid_t pid, pid_t *_ppid) {
-        int r;
-        _cleanup_free_ char *line = NULL;
-        long unsigned ppid;
-        const char *p;
-
-        assert(pid >= 0);
-        assert(_ppid);
-
-        if (pid == 0 || pid == getpid_cached()) {
-                *_ppid = getppid();
-                return 0;
-        }
-
-        p = procfs_file_alloca(pid, "stat");
-        r = read_one_line_file(p, &line);
-        if (r == -ENOENT)
-                return -ESRCH;
-        if (r < 0)
-                return r;
-
-        /* Let's skip the pid and comm fields. The latter is enclosed
-         * in () but does not escape any () in its value, so let's
-         * skip over it manually */
-
-        p = strrchr(line, ')');
-        if (!p)
-                return -EIO;
-
-        p++;
-
-        if (sscanf(p, " "
-                   "%*c "  /* state */
-                   "%lu ", /* ppid */
-                   &ppid) != 1)
-                return -EIO;
-
-        if ((long unsigned) (pid_t) ppid != ppid)
-                return -ERANGE;
-
-        *_ppid = (pid_t) ppid;
-
-        return 0;
-}
-
-int get_process_umask(pid_t pid, mode_t *umask) {
-        _cleanup_free_ char *m = NULL;
-        const char *p;
-        int r;
-
-        assert(umask);
-        assert(pid >= 0);
-
-        p = procfs_file_alloca(pid, "status");
-
-        r = get_proc_field(p, "Umask", WHITESPACE, &m);
-        if (r == -ENOENT)
-                return -ESRCH;
-
-        return parse_mode(m, umask);
-}
-
-int wait_for_terminate(pid_t pid, siginfo_t *status) {
-        siginfo_t dummy;
-
-        assert(pid >= 1);
-
-        if (!status)
-                status = &dummy;
-
-        for (;;) {
-                zero(*status);
-
-                if (waitid(P_PID, pid, status, WEXITED) < 0) {
-
-                        if (errno == EINTR)
-                                continue;
-
-                        return negative_errno();
-                }
-
-                return 0;
-        }
-}
-
-/*
- * Return values:
- * < 0 : wait_for_terminate() failed to get the state of the
- *       process, the process was terminated by a signal, or
- *       failed for an unknown reason.
- * >=0 : The process terminated normally, and its exit code is
- *       returned.
- *
- * That is, success is indicated by a return value of zero, and an
- * error is indicated by a non-zero value.
- *
- * A warning is emitted if the process terminates abnormally,
- * and also if it returns non-zero unless check_exit_code is true.
- */
-int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags) {
-        _cleanup_free_ char *buffer = NULL;
-        siginfo_t status;
-        int r, prio;
-
-        assert(pid > 1);
-
-        if (!name) {
-                r = get_process_comm(pid, &buffer);
-                if (r < 0)
-                        log_debug_errno(r, "Failed to acquire process name of " PID_FMT ", ignoring: %m", pid);
-                else
-                        name = buffer;
-        }
-
-        prio = flags & WAIT_LOG_ABNORMAL ? LOG_ERR : LOG_DEBUG;
-
-        r = wait_for_terminate(pid, &status);
-        if (r < 0)
-                return log_full_errno(prio, r, "Failed to wait for %s: %m", strna(name));
-
-        if (status.si_code == CLD_EXITED) {
-                if (status.si_status != EXIT_SUCCESS)
-                        log_full(flags & WAIT_LOG_NON_ZERO_EXIT_STATUS ? LOG_ERR : LOG_DEBUG,
-                                 "%s failed with exit status %i.", strna(name), status.si_status);
-                else
-                        log_debug("%s succeeded.", name);
-
-                return status.si_status;
-
-        } else if (IN_SET(status.si_code, CLD_KILLED, CLD_DUMPED)) {
-
-                log_full(prio, "%s terminated by signal %s.", strna(name), signal_to_string(status.si_status));
-                return -EPROTO;
-        }
-
-        log_full(prio, "%s failed due to unknown reason.", strna(name));
-        return -EPROTO;
-}
-
-/*
- * Return values:
- *
- * < 0 : wait_for_terminate_with_timeout() failed to get the state of the process, the process timed out, the process
- *       was terminated by a signal, or failed for an unknown reason.
- *
- * >=0 : The process terminated normally with no failures.
- *
- * Success is indicated by a return value of zero, a timeout is indicated by ETIMEDOUT, and all other child failure
- * states are indicated by error is indicated by a non-zero value.
- *
- * This call assumes SIGCHLD has been blocked already, in particular before the child to wait for has been forked off
- * to remain entirely race-free.
- */
-int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
-        sigset_t mask;
-        int r;
-        usec_t until;
-
-        assert_se(sigemptyset(&mask) == 0);
-        assert_se(sigaddset(&mask, SIGCHLD) == 0);
-
-        /* Drop into a sigtimewait-based timeout. Waiting for the
-         * pid to exit. */
-        until = now(CLOCK_MONOTONIC) + timeout;
-        for (;;) {
-                usec_t n;
-                siginfo_t status = {};
-                struct timespec ts;
-
-                n = now(CLOCK_MONOTONIC);
-                if (n >= until)
-                        break;
-
-                r = sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)) < 0 ? -errno : 0;
-                /* Assuming we woke due to the child exiting. */
-                if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) {
-                        if (status.si_pid == pid) {
-                                /* This is the correct child.*/
-                                if (status.si_code == CLD_EXITED)
-                                        return (status.si_status == 0) ? 0 : -EPROTO;
-                                else
-                                        return -EPROTO;
-                        }
-                }
-                /* Not the child, check for errors and proceed appropriately */
-                if (r < 0) {
-                        switch (r) {
-                        case -EAGAIN:
-                                /* Timed out, child is likely hung. */
-                                return -ETIMEDOUT;
-                        case -EINTR:
-                                /* Received a different signal and should retry */
-                                continue;
-                        default:
-                                /* Return any unexpected errors */
-                                return r;
-                        }
-                }
-        }
-
-        return -EPROTO;
-}
-
-void sigkill_wait(pid_t pid) {
-        assert(pid > 1);
-
-        if (kill(pid, SIGKILL) >= 0)
-                (void) wait_for_terminate(pid, NULL);
-}
-
-void sigkill_waitp(pid_t *pid) {
-        PROTECT_ERRNO;
-
-        if (!pid)
-                return;
-        if (*pid <= 1)
-                return;
-
-        sigkill_wait(*pid);
-}
-
-void sigterm_wait(pid_t pid) {
-        assert(pid > 1);
-
-        if (kill_and_sigcont(pid, SIGTERM) >= 0)
-                (void) wait_for_terminate(pid, NULL);
-}
-
-int kill_and_sigcont(pid_t pid, int sig) {
-        int r;
-
-        r = kill(pid, sig) < 0 ? -errno : 0;
-
-        /* If this worked, also send SIGCONT, unless we already just sent a SIGCONT, or SIGKILL was sent which isn't
-         * affected by a process being suspended anyway. */
-        if (r >= 0 && !IN_SET(sig, SIGCONT, SIGKILL))
-                (void) kill(pid, SIGCONT);
-
-        return r;
-}
-
-int getenv_for_pid(pid_t pid, const char *field, char **ret) {
-        _cleanup_fclose_ FILE *f = NULL;
-        char *value = NULL;
-        const char *path;
-        size_t l, sum = 0;
-        int r;
-
-        assert(pid >= 0);
-        assert(field);
-        assert(ret);
-
-        if (pid == 0 || pid == getpid_cached()) {
-                const char *e;
-
-                e = getenv(field);
-                if (!e) {
-                        *ret = NULL;
-                        return 0;
-                }
-
-                value = strdup(e);
-                if (!value)
-                        return -ENOMEM;
-
-                *ret = value;
-                return 1;
-        }
-
-        if (!pid_is_valid(pid))
-                return -EINVAL;
-
-        path = procfs_file_alloca(pid, "environ");
-
-        r = fopen_unlocked(path, "re", &f);
-        if (r == -ENOENT)
-                return -ESRCH;
-        if (r < 0)
-                return r;
-
-        l = strlen(field);
-        for (;;) {
-                _cleanup_free_ char *line = NULL;
-
-                if (sum > ENVIRONMENT_BLOCK_MAX) /* Give up searching eventually */
-                        return -ENOBUFS;
-
-                r = read_nul_string(f, LONG_LINE_MAX, &line);
-                if (r < 0)
-                        return r;
-                if (r == 0)  /* EOF */
-                        break;
-
-                sum += r;
-
-                if (strneq(line, field, l) && line[l] == '=') {
-                        value = strdup(line + l + 1);
-                        if (!value)
-                                return -ENOMEM;
-
-                        *ret = value;
-                        return 1;
-                }
-        }
-
-        *ret = NULL;
-        return 0;
-}
-
-int pid_is_my_child(pid_t pid) {
-        pid_t ppid;
-        int r;
-
-        if (pid <= 1)
-                return false;
-
-        r = get_process_ppid(pid, &ppid);
-        if (r < 0)
-                return r;
-
-        return ppid == getpid_cached();
-}
-
-bool pid_is_unwaited(pid_t pid) {
-        /* Checks whether a PID is still valid at all, including a zombie */
-
-        if (pid < 0)
-                return false;
-
-        if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */
-                return true;
-
-        if (pid == getpid_cached())
-                return true;
-
-        if (kill(pid, 0) >= 0)
-                return true;
-
-        return errno != ESRCH;
-}
-
-bool pid_is_alive(pid_t pid) {
-        int r;
-
-        /* Checks whether a PID is still valid and not a zombie */
-
-        if (pid < 0)
-                return false;
-
-        if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */
-                return true;
-
-        if (pid == getpid_cached())
-                return true;
-
-        r = get_process_state(pid);
-        if (IN_SET(r, -ESRCH, 'Z'))
-                return false;
-
-        return true;
-}
-
-int pid_from_same_root_fs(pid_t pid) {
-        const char *root;
-
-        if (pid < 0)
-                return false;
-
-        if (pid == 0 || pid == getpid_cached())
-                return true;
-
-        root = procfs_file_alloca(pid, "root");
-
-        return files_same(root, "/proc/1/root", 0);
-}
-#endif /* NM_IGNORED */
-
-bool is_main_thread(void) {
-        static thread_local int cached = 0;
-
-        if (_unlikely_(cached == 0))
-                cached = getpid_cached() == gettid() ? 1 : -1;
-
-        return cached > 0;
-}
-
-#if 0 /* NM_IGNORED */
-_noreturn_ void freeze(void) {
-
-        log_close();
-
-        /* Make sure nobody waits for us on a socket anymore */
-        (void) close_all_fds(NULL, 0);
-
-        sync();
-
-        /* Let's not freeze right away, but keep reaping zombies. */
-        for (;;) {
-                int r;
-                siginfo_t si = {};
-
-                r = waitid(P_ALL, 0, &si, WEXITED);
-                if (r < 0 && errno != EINTR)
-                        break;
-        }
-
-        /* waitid() failed with an unexpected error, things are really borked. Freeze now! */
-        for (;;)
-                pause();
-}
-
-bool oom_score_adjust_is_valid(int oa) {
-        return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
-}
-
-unsigned long personality_from_string(const char *p) {
-        int architecture;
-
-        if (!p)
-                return PERSONALITY_INVALID;
-
-        /* Parse a personality specifier. We use our own identifiers that indicate specific ABIs, rather than just
-         * hints regarding the register size, since we want to keep things open for multiple locally supported ABIs for
-         * the same register size. */
-
-        architecture = architecture_from_string(p);
-        if (architecture < 0)
-                return PERSONALITY_INVALID;
-
-        if (architecture == native_architecture())
-                return PER_LINUX;
-#ifdef SECONDARY_ARCHITECTURE
-        if (architecture == SECONDARY_ARCHITECTURE)
-                return PER_LINUX32;
-#endif
-
-        return PERSONALITY_INVALID;
-}
-
-const char* personality_to_string(unsigned long p) {
-        int architecture = _ARCHITECTURE_INVALID;
-
-        if (p == PER_LINUX)
-                architecture = native_architecture();
-#ifdef SECONDARY_ARCHITECTURE
-        else if (p == PER_LINUX32)
-                architecture = SECONDARY_ARCHITECTURE;
-#endif
-
-        if (architecture < 0)
-                return NULL;
-
-        return architecture_to_string(architecture);
-}
-
-int safe_personality(unsigned long p) {
-        int ret;
-
-        /* So here's the deal, personality() is weirdly defined by glibc. In some cases it returns a failure via errno,
-         * and in others as negative return value containing an errno-like value. Let's work around this: this is a
-         * wrapper that uses errno if it is set, and uses the return value otherwise. And then it sets both errno and
-         * the return value indicating the same issue, so that we are definitely on the safe side.
-         *
-         * See https://github.com/systemd/systemd/issues/6737 */
-
-        errno = 0;
-        ret = personality(p);
-        if (ret < 0) {
-                if (errno != 0)
-                        return -errno;
-
-                errno = -ret;
-        }
-
-        return ret;
-}
-
-int opinionated_personality(unsigned long *ret) {
-        int current;
-
-        /* Returns the current personality, or PERSONALITY_INVALID if we can't determine it. This function is a bit
-         * opinionated though, and ignores all the finer-grained bits and exotic personalities, only distinguishing the
-         * two most relevant personalities: PER_LINUX and PER_LINUX32. */
-
-        current = safe_personality(PERSONALITY_INVALID);
-        if (current < 0)
-                return current;
-
-        if (((unsigned long) current & 0xffff) == PER_LINUX32)
-                *ret = PER_LINUX32;
-        else
-                *ret = PER_LINUX;
-
-        return 0;
-}
-
-void valgrind_summary_hack(void) {
-#if HAVE_VALGRIND_VALGRIND_H
-        if (getpid_cached() == 1 && RUNNING_ON_VALGRIND) {
-                pid_t pid;
-                pid = raw_clone(SIGCHLD);
-                if (pid < 0)
-                        log_emergency_errno(errno, "Failed to fork off valgrind helper: %m");
-                else if (pid == 0)
-                        exit(EXIT_SUCCESS);
-                else {
-                        log_info("Spawned valgrind helper as PID "PID_FMT".", pid);
-                        (void) wait_for_terminate(pid, NULL);
-                }
-        }
-#endif
-}
-
-int pid_compare_func(const pid_t *a, const pid_t *b) {
-        /* Suitable for usage in qsort() */
-        return CMP(*a, *b);
-}
-
-int ioprio_parse_priority(const char *s, int *ret) {
-        int i, r;
-
-        assert(s);
-        assert(ret);
-
-        r = safe_atoi(s, &i);
-        if (r < 0)
-                return r;
-
-        if (!ioprio_priority_is_valid(i))
-                return -EINVAL;
-
-        *ret = i;
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-/* The cached PID, possible values:
- *
- *     == UNSET [0]  → cache not initialized yet
- *     == BUSY [-1]  → some thread is initializing it at the moment
- *     any other     → the cached PID
- */
-
-#define CACHED_PID_UNSET ((pid_t) 0)
-#define CACHED_PID_BUSY ((pid_t) -1)
-
-static pid_t cached_pid = CACHED_PID_UNSET;
-
-void reset_cached_pid(void) {
-        /* Invoked in the child after a fork(), i.e. at the first moment the PID changed */
-        cached_pid = CACHED_PID_UNSET;
-}
-
-/* We use glibc __register_atfork() + __dso_handle directly here, as they are not included in the glibc
- * headers. __register_atfork() is mostly equivalent to pthread_atfork(), but doesn't require us to link against
- * libpthread, as it is part of glibc anyway. */
-extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void (*child) (void), void *dso_handle);
-extern void* __dso_handle _weak_;
-
-pid_t getpid_cached(void) {
-        static bool installed = false;
-        pid_t current_value;
-
-        /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a
-         * system call each time. This restores glibc behaviour from before 2.24, when getpid() was unconditionally
-         * cached. Starting with 2.24 getpid() started to become prohibitively expensive when used for detecting when
-         * objects were used across fork()s. With this caching the old behaviour is somewhat restored.
-         *
-         * https://bugzilla.redhat.com/show_bug.cgi?id=1443976
-         * https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=c579f48edba88380635ab98cb612030e3ed8691e
-         */
-
-        current_value = __sync_val_compare_and_swap(&cached_pid, CACHED_PID_UNSET, CACHED_PID_BUSY);
-
-        switch (current_value) {
-
-        case CACHED_PID_UNSET: { /* Not initialized yet, then do so now */
-                pid_t new_pid;
-
-                new_pid = raw_getpid();
-
-                if (!installed) {
-                        /* __register_atfork() either returns 0 or -ENOMEM, in its glibc implementation. Since it's
-                         * only half-documented (glibc doesn't document it but LSB does — though only superficially)
-                         * we'll check for errors only in the most generic fashion possible. */
-
-                        if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) {
-                                /* OOM? Let's try again later */
-                                cached_pid = CACHED_PID_UNSET;
-                                return new_pid;
-                        }
-
-                        installed = true;
-                }
-
-                cached_pid = new_pid;
-                return new_pid;
-        }
-
-        case CACHED_PID_BUSY: /* Somebody else is currently initializing */
-                return raw_getpid();
-
-        default: /* Properly initialized */
-                return current_value;
-        }
-}
-
-#if 0 /* NM_IGNORED */
-int must_be_root(void) {
-
-        if (geteuid() == 0)
-                return 0;
-
-        return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be root.");
-}
-
-static void restore_sigsetp(sigset_t **ssp) {
-        if (*ssp)
-                (void) sigprocmask(SIG_SETMASK, *ssp, NULL);
-}
-
-int safe_fork_full(
-                const char *name,
-                const int except_fds[],
-                size_t n_except_fds,
-                ForkFlags flags,
-                pid_t *ret_pid) {
-
-        pid_t original_pid, pid;
-        sigset_t saved_ss, ss;
-        _cleanup_(restore_sigsetp) sigset_t *saved_ssp = NULL;
-        bool block_signals = false, block_all = false;
-        int prio, r;
-
-        /* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always
-         * returns the child's PID in *ret_pid. Returns == 0 in the child, and > 0 in the parent. */
-
-        prio = flags & FORK_LOG ? LOG_ERR : LOG_DEBUG;
-
-        original_pid = getpid_cached();
-
-        if (flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG)) {
-                /* We temporarily block all signals, so that the new child has them blocked initially. This way, we can
-                 * be sure that SIGTERMs are not lost we might send to the child. */
-
-                assert_se(sigfillset(&ss) >= 0);
-                block_signals = block_all = true;
-
-        } else if (flags & FORK_WAIT) {
-                /* Let's block SIGCHLD at least, so that we can safely watch for the child process */
-
-                assert_se(sigemptyset(&ss) >= 0);
-                assert_se(sigaddset(&ss, SIGCHLD) >= 0);
-                block_signals = true;
-        }
-
-        if (block_signals) {
-                if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0)
-                        return log_full_errno(prio, errno, "Failed to set signal mask: %m");
-                saved_ssp = &saved_ss;
-        }
-
-        if (flags & FORK_NEW_MOUNTNS)
-                pid = raw_clone(SIGCHLD|CLONE_NEWNS);
-        else
-                pid = fork();
-        if (pid < 0)
-                return log_full_errno(prio, errno, "Failed to fork: %m");
-        if (pid > 0) {
-                /* We are in the parent process */
-
-                log_debug("Successfully forked off '%s' as PID " PID_FMT ".", strna(name), pid);
-
-                if (flags & FORK_WAIT) {
-                        if (block_all) {
-                                /* undo everything except SIGCHLD */
-                                ss = saved_ss;
-                                assert_se(sigaddset(&ss, SIGCHLD) >= 0);
-                                (void) sigprocmask(SIG_SETMASK, &ss, NULL);
-                        }
-
-                        r = wait_for_terminate_and_check(name, pid, (flags & FORK_LOG ? WAIT_LOG : 0));
-                        if (r < 0)
-                                return r;
-                        if (r != EXIT_SUCCESS) /* exit status > 0 should be treated as failure, too */
-                                return -EPROTO;
-                }
-
-                if (ret_pid)
-                        *ret_pid = pid;
-
-                return 1;
-        }
-
-        /* We are in the child process */
-
-        /* Restore signal mask manually */
-        saved_ssp = NULL;
-
-        if (flags & FORK_REOPEN_LOG) {
-                /* Close the logs if requested, before we log anything. And make sure we reopen it if needed. */
-                log_close();
-                log_set_open_when_needed(true);
-        }
-
-        if (name) {
-                r = rename_process(name);
-                if (r < 0)
-                        log_full_errno(flags & FORK_LOG ? LOG_WARNING : LOG_DEBUG,
-                                       r, "Failed to rename process, ignoring: %m");
-        }
-
-        if (flags & (FORK_DEATHSIG|FORK_DEATHSIG_SIGINT))
-                if (prctl(PR_SET_PDEATHSIG, (flags & FORK_DEATHSIG_SIGINT) ? SIGINT : SIGTERM) < 0) {
-                        log_full_errno(prio, errno, "Failed to set death signal: %m");
-                        _exit(EXIT_FAILURE);
-                }
-
-        if (flags & FORK_RESET_SIGNALS) {
-                r = reset_all_signal_handlers();
-                if (r < 0) {
-                        log_full_errno(prio, r, "Failed to reset signal handlers: %m");
-                        _exit(EXIT_FAILURE);
-                }
-
-                /* This implicitly undoes the signal mask stuff we did before the fork()ing above */
-                r = reset_signal_mask();
-                if (r < 0) {
-                        log_full_errno(prio, r, "Failed to reset signal mask: %m");
-                        _exit(EXIT_FAILURE);
-                }
-        } else if (block_signals) { /* undo what we did above */
-                if (sigprocmask(SIG_SETMASK, &saved_ss, NULL) < 0) {
-                        log_full_errno(prio, errno, "Failed to restore signal mask: %m");
-                        _exit(EXIT_FAILURE);
-                }
-        }
-
-        if (flags & FORK_DEATHSIG) {
-                pid_t ppid;
-                /* Let's see if the parent PID is still the one we started from? If not, then the parent
-                 * already died by the time we set PR_SET_PDEATHSIG, hence let's emulate the effect */
-
-                ppid = getppid();
-                if (ppid == 0)
-                        /* Parent is in a different PID namespace. */;
-                else if (ppid != original_pid) {
-                        log_debug("Parent died early, raising SIGTERM.");
-                        (void) raise(SIGTERM);
-                        _exit(EXIT_FAILURE);
-                }
-        }
-
-        if (FLAGS_SET(flags, FORK_NEW_MOUNTNS | FORK_MOUNTNS_SLAVE)) {
-
-                /* Optionally, make sure we never propagate mounts to the host. */
-
-                if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
-                        log_full_errno(prio, errno, "Failed to remount root directory as MS_SLAVE: %m");
-                        _exit(EXIT_FAILURE);
-                }
-        }
-
-        if (flags & FORK_CLOSE_ALL_FDS) {
-                /* Close the logs here in case it got reopened above, as close_all_fds() would close them for us */
-                log_close();
-
-                r = close_all_fds(except_fds, n_except_fds);
-                if (r < 0) {
-                        log_full_errno(prio, r, "Failed to close all file descriptors: %m");
-                        _exit(EXIT_FAILURE);
-                }
-        }
-
-        /* When we were asked to reopen the logs, do so again now */
-        if (flags & FORK_REOPEN_LOG) {
-                log_open();
-                log_set_open_when_needed(false);
-        }
-
-        if (flags & FORK_NULL_STDIO) {
-                r = make_null_stdio();
-                if (r < 0) {
-                        log_full_errno(prio, r, "Failed to connect stdin/stdout to /dev/null: %m");
-                        _exit(EXIT_FAILURE);
-                }
-
-        } else if (flags & FORK_STDOUT_TO_STDERR) {
-                if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) {
-                        log_full_errno(prio, errno, "Failed to connect stdout to stderr: %m");
-                        _exit(EXIT_FAILURE);
-                }
-        }
-
-        if (flags & FORK_RLIMIT_NOFILE_SAFE) {
-                r = rlimit_nofile_safe();
-                if (r < 0) {
-                        log_full_errno(prio, r, "Failed to lower RLIMIT_NOFILE's soft limit to 1K: %m");
-                        _exit(EXIT_FAILURE);
-                }
-        }
-
-        if (ret_pid)
-                *ret_pid = getpid_cached();
-
-        return 0;
-}
-
-int namespace_fork(
-                const char *outer_name,
-                const char *inner_name,
-                const int except_fds[],
-                size_t n_except_fds,
-                ForkFlags flags,
-                int pidns_fd,
-                int mntns_fd,
-                int netns_fd,
-                int userns_fd,
-                int root_fd,
-                pid_t *ret_pid) {
-
-        int r;
-
-        /* This is much like safe_fork(), but forks twice, and joins the specified namespaces in the middle
-         * process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that
-         * /proc/self/fd works correctly. */
-
-        r = safe_fork_full(outer_name, except_fds, n_except_fds, (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
-        if (r < 0)
-                return r;
-        if (r == 0) {
-                pid_t pid;
-
-                /* Child */
-
-                r = namespace_enter(pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd);
-                if (r < 0) {
-                        log_full_errno(FLAGS_SET(flags, FORK_LOG) ? LOG_ERR : LOG_DEBUG, r, "Failed to join namespace: %m");
-                        _exit(EXIT_FAILURE);
-                }
-
-                /* We mask a few flags here that either make no sense for the grandchild, or that we don't have to do again */
-                r = safe_fork_full(inner_name, except_fds, n_except_fds, flags & ~(FORK_WAIT|FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NULL_STDIO), &pid);
-                if (r < 0)
-                        _exit(EXIT_FAILURE);
-                if (r == 0) {
-                        /* Child */
-                        if (ret_pid)
-                                *ret_pid = pid;
-                        return 0;
-                }
-
-                r = wait_for_terminate_and_check(inner_name, pid, FLAGS_SET(flags, FORK_LOG) ? WAIT_LOG : 0);
-                if (r < 0)
-                        _exit(EXIT_FAILURE);
-
-                _exit(r);
-        }
-
-        return 1;
-}
-
-int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) {
-        bool stdout_is_tty, stderr_is_tty;
-        size_t n, i;
-        va_list ap;
-        char **l;
-        int r;
-
-        assert(path);
-
-        /* Spawns a temporary TTY agent, making sure it goes away when we go away */
-
-        r = safe_fork_full(name, except, n_except, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, ret_pid);
-        if (r < 0)
-                return r;
-        if (r > 0)
-                return 0;
-
-        /* In the child: */
-
-        stdout_is_tty = isatty(STDOUT_FILENO);
-        stderr_is_tty = isatty(STDERR_FILENO);
-
-        if (!stdout_is_tty || !stderr_is_tty) {
-                int fd;
-
-                /* Detach from stdout/stderr. and reopen
-                 * /dev/tty for them. This is important to
-                 * ensure that when systemctl is started via
-                 * popen() or a similar call that expects to
-                 * read EOF we actually do generate EOF and
-                 * not delay this indefinitely by because we
-                 * keep an unused copy of stdin around. */
-                fd = open("/dev/tty", O_WRONLY);
-                if (fd < 0) {
-                        log_error_errno(errno, "Failed to open /dev/tty: %m");
-                        _exit(EXIT_FAILURE);
-                }
-
-                if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
-                        log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
-                        _exit(EXIT_FAILURE);
-                }
-
-                if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
-                        log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
-                        _exit(EXIT_FAILURE);
-                }
-
-                safe_close_above_stdio(fd);
-        }
-
-        (void) rlimit_nofile_safe();
-
-        /* Count arguments */
-        va_start(ap, path);
-        for (n = 0; va_arg(ap, char*); n++)
-                ;
-        va_end(ap);
-
-        /* Allocate strv */
-        l = newa(char*, n + 1);
-
-        /* Fill in arguments */
-        va_start(ap, path);
-        for (i = 0; i <= n; i++)
-                l[i] = va_arg(ap, char*);
-        va_end(ap);
-
-        execv(path, l);
-        _exit(EXIT_FAILURE);
-}
-
-int set_oom_score_adjust(int value) {
-        char t[DECIMAL_STR_MAX(int)];
-
-        sprintf(t, "%i", value);
-
-        return write_string_file("/proc/self/oom_score_adj", t,
-                                 WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
-}
-
-int pidfd_get_pid(int fd, pid_t *ret) {
-        char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
-        _cleanup_free_ char *fdinfo = NULL;
-        char *p;
-        int r;
-
-        if (fd < 0)
-                return -EBADF;
-
-        xsprintf(path, "/proc/self/fdinfo/%i", fd);
-
-        r = read_full_file(path, &fdinfo, NULL);
-        if (r == -ENOENT) /* if fdinfo doesn't exist we assume the process does not exist */
-                return -ESRCH;
-        if (r < 0)
-                return r;
-
-        p = startswith(fdinfo, "Pid:");
-        if (!p) {
-                p = strstr(fdinfo, "\nPid:");
-                if (!p)
-                        return -ENOTTY; /* not a pidfd? */
-
-                p += 5;
-        }
-
-        p += strspn(p, WHITESPACE);
-        p[strcspn(p, WHITESPACE)] = 0;
-
-        return parse_pid(p, ret);
-}
-
-static int rlimit_to_nice(rlim_t limit) {
-        if (limit <= 1)
-                return PRIO_MAX-1; /* i.e. 19 */
-
-        if (limit >= -PRIO_MIN + PRIO_MAX)
-                return PRIO_MIN; /* i.e. -20 */
-
-        return PRIO_MAX - (int) limit;
-}
-
-int setpriority_closest(int priority) {
-        int current, limit, saved_errno;
-        struct rlimit highest;
-
-        /* Try to set requested nice level */
-        if (setpriority(PRIO_PROCESS, 0, priority) >= 0)
-                return 1;
-
-        /* Permission failed */
-        saved_errno = -errno;
-        if (!ERRNO_IS_PRIVILEGE(saved_errno))
-                return saved_errno;
-
-        errno = 0;
-        current = getpriority(PRIO_PROCESS, 0);
-        if (errno != 0)
-                return -errno;
-
-        if (priority == current)
-                return 1;
-
-       /* Hmm, we'd expect that raising the nice level from our status quo would always work. If it doesn't,
-        * then the whole setpriority() system call is blocked to us, hence let's propagate the error
-        * right-away */
-        if (priority > current)
-                return saved_errno;
-
-        if (getrlimit(RLIMIT_NICE, &highest) < 0)
-                return -errno;
-
-        limit = rlimit_to_nice(highest.rlim_cur);
-
-        /* We are already less nice than limit allows us */
-        if (current < limit) {
-                log_debug("Cannot raise nice level, permissions and the resource limit do not allow it.");
-                return 0;
-        }
-
-        /* Push to the allowed limit */
-        if (setpriority(PRIO_PROCESS, 0, limit) < 0)
-                return -errno;
-
-        log_debug("Cannot set requested nice level (%i), used next best (%i).", priority, limit);
-        return 0;
-}
-
-static const char *const ioprio_class_table[] = {
-        [IOPRIO_CLASS_NONE] = "none",
-        [IOPRIO_CLASS_RT] = "realtime",
-        [IOPRIO_CLASS_BE] = "best-effort",
-        [IOPRIO_CLASS_IDLE] = "idle",
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, IOPRIO_N_CLASSES);
-
-static const char *const sigchld_code_table[] = {
-        [CLD_EXITED] = "exited",
-        [CLD_KILLED] = "killed",
-        [CLD_DUMPED] = "dumped",
-        [CLD_TRAPPED] = "trapped",
-        [CLD_STOPPED] = "stopped",
-        [CLD_CONTINUED] = "continued",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
-
-static const char* const sched_policy_table[] = {
-        [SCHED_OTHER] = "other",
-        [SCHED_BATCH] = "batch",
-        [SCHED_IDLE] = "idle",
-        [SCHED_FIFO] = "fifo",
-        [SCHED_RR] = "rr",
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/process-util.h b/shared/systemd/src/basic/process-util.h
deleted file mode 100644
index aab2c7a1..00000000
--- a/shared/systemd/src/basic/process-util.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <errno.h>
-#include <sched.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <sys/types.h>
-
-#include "alloc-util.h"
-#include "format-util.h"
-#include "ioprio.h"
-#include "macro.h"
-#include "time-util.h"
-
-#define procfs_file_alloca(pid, field)                                  \
-        ({                                                              \
-                pid_t _pid_ = (pid);                                    \
-                const char *_field_ = (field);                          \
-                char *_r_;                                              \
-                if (_pid_ == 0) {                                       \
-                        _r_ = newa(char, STRLEN("/proc/self/") + strlen(_field_) + 1); \
-                        strcpy(stpcpy(_r_, "/proc/self/"), _field_);    \
-                } else {                                                \
-                        _r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + strlen(_field_) + 1); \
-                        sprintf(_r_, "/proc/" PID_FMT "/%s", _pid_, _field_); \
-                }                                                       \
-                (const char*) _r_;                                      \
-        })
-
-typedef enum ProcessCmdlineFlags {
-        PROCESS_CMDLINE_COMM_FALLBACK = 1 << 0,
-        PROCESS_CMDLINE_USE_LOCALE    = 1 << 1,
-} ProcessCmdlineFlags;
-
-int get_process_comm(pid_t pid, char **name);
-int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line);
-int get_process_exe(pid_t pid, char **name);
-int get_process_uid(pid_t pid, uid_t *uid);
-int get_process_gid(pid_t pid, gid_t *gid);
-int get_process_capeff(pid_t pid, char **capeff);
-int get_process_cwd(pid_t pid, char **cwd);
-int get_process_root(pid_t pid, char **root);
-int get_process_environ(pid_t pid, char **environ);
-int get_process_ppid(pid_t pid, pid_t *ppid);
-int get_process_umask(pid_t pid, mode_t *umask);
-
-int wait_for_terminate(pid_t pid, siginfo_t *status);
-
-typedef enum WaitFlags {
-        WAIT_LOG_ABNORMAL             = 1 << 0,
-        WAIT_LOG_NON_ZERO_EXIT_STATUS = 1 << 1,
-
-        /* A shortcut for requesting the most complete logging */
-        WAIT_LOG = WAIT_LOG_ABNORMAL|WAIT_LOG_NON_ZERO_EXIT_STATUS,
-} WaitFlags;
-
-int wait_for_terminate_and_check(const char *name, pid_t pid, WaitFlags flags);
-int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout);
-
-void sigkill_wait(pid_t pid);
-void sigkill_waitp(pid_t *pid);
-void sigterm_wait(pid_t pid);
-
-int kill_and_sigcont(pid_t pid, int sig);
-
-int rename_process(const char name[]);
-int is_kernel_thread(pid_t pid);
-
-int getenv_for_pid(pid_t pid, const char *field, char **_value);
-
-bool pid_is_alive(pid_t pid);
-bool pid_is_unwaited(pid_t pid);
-int pid_is_my_child(pid_t pid);
-int pid_from_same_root_fs(pid_t pid);
-
-bool is_main_thread(void);
-
-_noreturn_ void freeze(void);
-
-bool oom_score_adjust_is_valid(int oa);
-
-#ifndef PERSONALITY_INVALID
-/* personality(7) documents that 0xffffffffUL is used for querying the
- * current personality, hence let's use that here as error
- * indicator. */
-#define PERSONALITY_INVALID 0xffffffffLU
-#endif
-
-unsigned long personality_from_string(const char *p);
-const char *personality_to_string(unsigned long);
-
-int safe_personality(unsigned long p);
-int opinionated_personality(unsigned long *ret);
-
-int ioprio_class_to_string_alloc(int i, char **s);
-int ioprio_class_from_string(const char *s);
-
-const char *sigchld_code_to_string(int i) _const_;
-int sigchld_code_from_string(const char *s) _pure_;
-
-int sched_policy_to_string_alloc(int i, char **s);
-int sched_policy_from_string(const char *s);
-
-static inline pid_t PTR_TO_PID(const void *p) {
-        return (pid_t) ((uintptr_t) p);
-}
-
-static inline void* PID_TO_PTR(pid_t pid) {
-        return (void*) ((uintptr_t) pid);
-}
-
-void valgrind_summary_hack(void);
-
-int pid_compare_func(const pid_t *a, const pid_t *b);
-
-#if 0 /* NM_IGNORED */
-static inline bool nice_is_valid(int n) {
-        return n >= PRIO_MIN && n < PRIO_MAX;
-}
-
-static inline bool sched_policy_is_valid(int i) {
-        return IN_SET(i, SCHED_OTHER, SCHED_BATCH, SCHED_IDLE, SCHED_FIFO, SCHED_RR);
-}
-
-static inline bool sched_priority_is_valid(int i) {
-        return i >= 0 && i <= sched_get_priority_max(SCHED_RR);
-}
-
-static inline bool ioprio_class_is_valid(int i) {
-        return IN_SET(i, IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE);
-}
-
-static inline bool ioprio_priority_is_valid(int i) {
-        return i >= 0 && i < IOPRIO_BE_NR;
-}
-
-static inline bool pid_is_valid(pid_t p) {
-        return p > 0;
-}
-#endif /* NM_IGNORED */
-
-int ioprio_parse_priority(const char *s, int *ret);
-
-pid_t getpid_cached(void);
-void reset_cached_pid(void);
-
-int must_be_root(void);
-
-typedef enum ForkFlags {
-        FORK_RESET_SIGNALS      = 1 <<  0, /* Reset all signal handlers and signal mask */
-        FORK_CLOSE_ALL_FDS      = 1 <<  1, /* Close all open file descriptors in the child, except for 0,1,2 */
-        FORK_DEATHSIG           = 1 <<  2, /* Set PR_DEATHSIG in the child to SIGTERM */
-        FORK_DEATHSIG_SIGINT    = 1 <<  3, /* Set PR_DEATHSIG in the child to SIGINT */
-        FORK_NULL_STDIO         = 1 <<  4, /* Connect 0,1,2 to /dev/null */
-        FORK_REOPEN_LOG         = 1 <<  5, /* Reopen log connection */
-        FORK_LOG                = 1 <<  6, /* Log above LOG_DEBUG log level about failures */
-        FORK_WAIT               = 1 <<  7, /* Wait until child exited */
-        FORK_NEW_MOUNTNS        = 1 <<  8, /* Run child in its own mount namespace */
-        FORK_MOUNTNS_SLAVE      = 1 <<  9, /* Make child's mount namespace MS_SLAVE */
-        FORK_RLIMIT_NOFILE_SAFE = 1 << 10, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
-        FORK_STDOUT_TO_STDERR   = 1 << 11, /* Make stdout a copy of stderr */
-} ForkFlags;
-
-int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
-
-static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
-        return safe_fork_full(name, NULL, 0, flags, ret_pid);
-}
-
-int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
-
-int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...) _sentinel_;
-
-int set_oom_score_adjust(int value);
-
-/* The highest possibly (theoretic) pid_t value on this architecture. */
-#define PID_T_MAX ((pid_t) INT32_MAX)
-/* The maximum number of concurrent processes Linux allows on this architecture, as well as the highest valid PID value
- * the kernel will potentially assign. This reflects a value compiled into the kernel (PID_MAX_LIMIT), and sets the
- * upper boundary on what may be written to the /proc/sys/kernel/pid_max sysctl (but do note that the sysctl is off by
- * 1, since PID 0 can never exist and there can hence only be one process less than the limit would suggest). Since
- * these values are documented in proc(5) we feel quite confident that they are stable enough for the near future at
- * least to define them here too. */
-#define TASKS_MAX 4194303U
-
-assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
-
-/* Like TAKE_PTR() but for child PIDs, resetting them to 0 */
-#define TAKE_PID(pid)                           \
-        ({                                      \
-                pid_t _pid_ = (pid);            \
-                (pid) = 0;                      \
-                _pid_;                          \
-        })
-
-int pidfd_get_pid(int fd, pid_t *ret);
-
-int setpriority_closest(int priority);
diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c
deleted file mode 100644
index 4f67d9af..00000000
--- a/shared/systemd/src/basic/random-util.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#if defined(__i386__) || defined(__x86_64__)
-#include <cpuid.h>
-#endif
-
-#include <elf.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/random.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-
-#if HAVE_SYS_AUXV_H
-#  include <sys/auxv.h>
-#endif
-
-#include "alloc-util.h"
-#include "env-util.h"
-#include "errno-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "io-util.h"
-#include "missing_random.h"
-#include "missing_syscall.h"
-#include "parse-util.h"
-#include "random-util.h"
-#include "siphash24.h"
-#include "time-util.h"
-
-static bool srand_called = false;
-
-int rdrand(unsigned long *ret) {
-
-        /* So, you are a "security researcher", and you wonder why we bother with using raw RDRAND here,
-         * instead of sticking to /dev/urandom or getrandom()?
-         *
-         * Here's why: early boot. On Linux, during early boot the random pool that backs /dev/urandom and
-         * getrandom() is generally not initialized yet. It is very common that initialization of the random
-         * pool takes a longer time (up to many minutes), in particular on embedded devices that have no
-         * explicit hardware random generator, as well as in virtualized environments such as major cloud
-         * installations that do not provide virtio-rng or a similar mechanism.
-         *
-         * In such an environment using getrandom() synchronously means we'd block the entire system boot-up
-         * until the pool is initialized, i.e. *very* long. Using getrandom() asynchronously (GRND_NONBLOCK)
-         * would mean acquiring randomness during early boot would simply fail. Using /dev/urandom would mean
-         * generating many kmsg log messages about our use of it before the random pool is properly
-         * initialized. Neither of these outcomes is desirable.
-         *
-         * Thus, for very specific purposes we use RDRAND instead of either of these three options. RDRAND
-         * provides us quickly and relatively reliably with random values, without having to delay boot,
-         * without triggering warning messages in kmsg.
-         *
-         * Note that we use RDRAND only under very specific circumstances, when the requirements on the
-         * quality of the returned entropy permit it. Specifically, here are some cases where we *do* use
-         * RDRAND:
-         *
-         *         • UUID generation: UUIDs are supposed to be universally unique but are not cryptographic
-         *           key material. The quality and trust level of RDRAND should hence be OK: UUIDs should be
-         *           generated in a way that is reliably unique, but they do not require ultimate trust into
-         *           the entropy generator. systemd generates a number of UUIDs during early boot, including
-         *           'invocation IDs' for every unit spawned that identify the specific invocation of the
-         *           service globally, and a number of others. Other alternatives for generating these UUIDs
-         *           have been considered, but don't really work: for example, hashing uuids from a local
-         *           system identifier combined with a counter falls flat because during early boot disk
-         *           storage is not yet available (think: initrd) and thus a system-specific ID cannot be
-         *           stored or retrieved yet.
-         *
-         *         • Hash table seed generation: systemd uses many hash tables internally. Hash tables are
-         *           generally assumed to have O(1) access complexity, but can deteriorate to prohibitive
-         *           O(n) access complexity if an attacker manages to trigger a large number of hash
-         *           collisions. Thus, systemd (as any software employing hash tables should) uses seeded
-         *           hash functions for its hash tables, with a seed generated randomly. The hash tables
-         *           systemd employs watch the fill level closely and reseed if necessary. This allows use of
-         *           a low quality RNG initially, as long as it improves should a hash table be under attack:
-         *           the attacker after all needs to trigger many collisions to exploit it for the purpose
-         *           of DoS, but if doing so improves the seed the attack surface is reduced as the attack
-         *           takes place.
-         *
-         * Some cases where we do NOT use RDRAND are:
-         *
-         *         • Generation of cryptographic key material 🔑
-         *
-         *         • Generation of cryptographic salt values 🧂
-         *
-         * This function returns:
-         *
-         *         -EOPNOTSUPP → RDRAND is not available on this system 😔
-         *         -EAGAIN     → The operation failed this time, but is likely to work if you try again a few
-         *                       times ♻
-         *         -EUCLEAN    → We got some random value, but it looked strange, so we refused using it.
-         *                       This failure might or might not be temporary. 😕
-         */
-
-#if defined(__i386__) || defined(__x86_64__)
-        static int have_rdrand = -1;
-        unsigned long v;
-        uint8_t success;
-
-        if (have_rdrand < 0) {
-                uint32_t eax, ebx, ecx, edx;
-
-                /* Check if RDRAND is supported by the CPU */
-                if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0) {
-                        have_rdrand = false;
-                        return -EOPNOTSUPP;
-                }
-
-/* Compat with old gcc where bit_RDRND didn't exist yet */
-#ifndef bit_RDRND
-#define bit_RDRND (1U << 30)
-#endif
-
-                have_rdrand = !!(ecx & bit_RDRND);
-
-                if (have_rdrand > 0) {
-                        /* Allow disabling use of RDRAND with SYSTEMD_RDRAND=0
-                           If it is unset getenv_bool_secure will return a negative value. */
-                        if (getenv_bool_secure("SYSTEMD_RDRAND") == 0) {
-                                have_rdrand = false;
-                                return -EOPNOTSUPP;
-                        }
-                }
-        }
-
-        if (have_rdrand == 0)
-                return -EOPNOTSUPP;
-
-        asm volatile("rdrand %0;"
-                     "setc %1"
-                     : "=r" (v),
-                       "=qm" (success));
-        msan_unpoison(&success, sizeof(success));
-        if (!success)
-                return -EAGAIN;
-
-        /* Apparently on some AMD CPUs RDRAND will sometimes (after a suspend/resume cycle?) report success
-         * via the carry flag but nonetheless return the same fixed value -1 in all cases. This appears to be
-         * a bad bug in the CPU or firmware. Let's deal with that and work-around this by explicitly checking
-         * for this special value (and also 0, just to be sure) and filtering it out. This is a work-around
-         * only however and something AMD really should fix properly. The Linux kernel should probably work
-         * around this issue by turning off RDRAND altogether on those CPUs. See:
-         * https://github.com/systemd/systemd/issues/11810 */
-        if (v == 0 || v == ULONG_MAX)
-                return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
-                                       "RDRAND returned suspicious value %lx, assuming bad hardware RNG, not using value.", v);
-
-        *ret = v;
-        return 0;
-#else
-        return -EOPNOTSUPP;
-#endif
-}
-
-int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
-        static int have_syscall = -1;
-        _cleanup_close_ int fd = -1;
-        bool got_some = false;
-        int r;
-
-        /* Gathers some high-quality randomness from the kernel (or potentially mid-quality randomness from
-         * the CPU if the RANDOM_ALLOW_RDRAND flag is set). This call won't block, unless the RANDOM_BLOCK
-         * flag is set. If RANDOM_MAY_FAIL is set, an error is returned if the random pool is not
-         * initialized. Otherwise it will always return some data from the kernel, regardless of whether the
-         * random pool is fully initialized or not. If RANDOM_EXTEND_WITH_PSEUDO is set, and some but not
-         * enough better quality randomness could be acquired, the rest is filled up with low quality
-         * randomness.
-         *
-         * Of course, when creating cryptographic key material you really shouldn't use RANDOM_ALLOW_DRDRAND
-         * or even RANDOM_EXTEND_WITH_PSEUDO.
-         *
-         * When generating UUIDs it's fine to use RANDOM_ALLOW_RDRAND but not OK to use
-         * RANDOM_EXTEND_WITH_PSEUDO. In fact RANDOM_EXTEND_WITH_PSEUDO is only really fine when invoked via
-         * an "all bets are off" wrapper, such as random_bytes(), see below. */
-
-        if (n == 0)
-                return 0;
-
-        if (FLAGS_SET(flags, RANDOM_ALLOW_RDRAND))
-                /* Try x86-64' RDRAND intrinsic if we have it. We only use it if high quality randomness is
-                 * not required, as we don't trust it (who does?). Note that we only do a single iteration of
-                 * RDRAND here, even though the Intel docs suggest calling this in a tight loop of 10
-                 * invocations or so. That's because we don't really care about the quality here. We
-                 * generally prefer using RDRAND if the caller allows us to, since this way we won't upset
-                 * the kernel's random subsystem by accessing it before the pool is initialized (after all it
-                 * will kmsg log about every attempt to do so)..*/
-                for (;;) {
-                        unsigned long u;
-                        size_t m;
-
-                        if (rdrand(&u) < 0) {
-                                if (got_some && FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
-                                        /* Fill in the remaining bytes using pseudo-random values */
-                                        pseudo_random_bytes(p, n);
-                                        return 0;
-                                }
-
-                                /* OK, this didn't work, let's go to getrandom() + /dev/urandom instead */
-                                break;
-                        }
-
-                        m = MIN(sizeof(u), n);
-                        memcpy(p, &u, m);
-
-                        p = (uint8_t*) p + m;
-                        n -= m;
-
-                        if (n == 0)
-                                return 0; /* Yay, success! */
-
-                        got_some = true;
-                }
-
-        /* Use the getrandom() syscall unless we know we don't have it. */
-        if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
-
-                for (;;) {
-#if !HAVE_GETRANDOM
-                        /* NetworkManager Note: systemd calls the syscall directly in this case. Don't add that workaround.
-                         * If you don't compile against a libc that provides getrandom(), you don't get it. */
-                        r = -1;
-                        errno = ENOSYS;
-#else
-                        r = getrandom(p, n,
-                                      (FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK) |
-                                      (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE) ? GRND_INSECURE : 0));
-#endif
-                        if (r > 0) {
-                                have_syscall = true;
-
-                                if ((size_t) r == n)
-                                        return 0; /* Yay, success! */
-
-                                assert((size_t) r < n);
-                                p = (uint8_t*) p + r;
-                                n -= r;
-
-                                if (FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
-                                        /* Fill in the remaining bytes using pseudo-random values */
-                                        pseudo_random_bytes(p, n);
-                                        return 0;
-                                }
-
-                                got_some = true;
-
-                                /* Hmm, we didn't get enough good data but the caller insists on good data? Then try again */
-                                if (FLAGS_SET(flags, RANDOM_BLOCK))
-                                        continue;
-
-                                /* Fill in the rest with /dev/urandom */
-                                break;
-
-                        } else if (r == 0) {
-                                have_syscall = true;
-                                return -EIO;
-
-                        } else if (ERRNO_IS_NOT_SUPPORTED(errno)) {
-                                /* We lack the syscall, continue with reading from /dev/urandom. */
-                                have_syscall = false;
-                                break;
-
-                        } else if (errno == EAGAIN) {
-                                /* The kernel has no entropy whatsoever. Let's remember to use the syscall
-                                 * the next time again though.
-                                 *
-                                 * If RANDOM_MAY_FAIL is set, return an error so that random_bytes() can
-                                 * produce some pseudo-random bytes instead. Otherwise, fall back to
-                                 * /dev/urandom, which we know is empty, but the kernel will produce some
-                                 * bytes for us on a best-effort basis. */
-                                have_syscall = true;
-
-                                if (got_some && FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
-                                        /* Fill in the remaining bytes using pseudorandom values */
-                                        pseudo_random_bytes(p, n);
-                                        return 0;
-                                }
-
-                                if (FLAGS_SET(flags, RANDOM_MAY_FAIL))
-                                        return -ENODATA;
-
-                                /* Use /dev/urandom instead */
-                                break;
-
-                        } else if (errno == EINVAL) {
-
-                                /* Most likely: unknown flag. We know that GRND_INSECURE might cause this,
-                                 * hence try without. */
-
-                                if (FLAGS_SET(flags, RANDOM_ALLOW_INSECURE)) {
-                                        flags = flags &~ RANDOM_ALLOW_INSECURE;
-                                        continue;
-                                }
-
-                                return -errno;
-                        } else
-                                return -errno;
-                }
-        }
-
-        fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-        if (fd < 0)
-                return errno == ENOENT ? -ENOSYS : -errno;
-
-        return loop_read_exact(fd, p, n, true);
-}
-
-static void clear_srand_initialization(void) {
-        srand_called = false;
-}
-
-void initialize_srand(void) {
-        static bool pthread_atfork_registered = false;
-        unsigned x;
-#if HAVE_SYS_AUXV_H
-        const void *auxv;
-#endif
-        unsigned long k;
-
-        if (srand_called)
-                return;
-
-#if HAVE_SYS_AUXV_H
-        /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed
-         * the pseudo-random generator. It's better than nothing... But let's first hash it to make it harder
-         * to recover the original value by watching any pseudo-random bits we generate. After all the
-         * AT_RANDOM data might be used by other stuff too (in particular: ASLR), and we probably shouldn't
-         * leak the seed for that. */
-
-        auxv = ULONG_TO_PTR(getauxval(AT_RANDOM));
-        if (auxv) {
-                static const uint8_t auxval_hash_key[16] = {
-                        0x92, 0x6e, 0xfe, 0x1b, 0xcf, 0x00, 0x52, 0x9c, 0xcc, 0x42, 0xcf, 0xdc, 0x94, 0x1f, 0x81, 0x0f
-                };
-
-                x = (unsigned) siphash24(auxv, 16, auxval_hash_key);
-        } else
-#endif
-                x = 0;
-
-        x ^= (unsigned) now(CLOCK_REALTIME);
-        x ^= (unsigned) gettid();
-
-        if (rdrand(&k) >= 0)
-                x ^= (unsigned) k;
-
-        srand(x);
-        srand_called = true;
-
-        if (!pthread_atfork_registered) {
-                (void) pthread_atfork(NULL, NULL, clear_srand_initialization);
-                pthread_atfork_registered = true;
-        }
-}
-
-/* INT_MAX gives us only 31 bits, so use 24 out of that. */
-#if RAND_MAX >= INT_MAX
-assert_cc(RAND_MAX >= 16777215);
-#  define RAND_STEP 3
-#else
-/* SHORT_INT_MAX or lower gives at most 15 bits, we just use 8 out of that. */
-assert_cc(RAND_MAX >= 255);
-#  define RAND_STEP 1
-#endif
-
-void pseudo_random_bytes(void *p, size_t n) {
-        uint8_t *q;
-
-        /* This returns pseudo-random data using libc's rand() function. You probably never want to call this
-         * directly, because why would you use this if you can get better stuff cheaply? Use random_bytes()
-         * instead, see below: it will fall back to this function if there's nothing better to get, but only
-         * then. */
-
-        initialize_srand();
-
-        for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) {
-                unsigned rr;
-
-                rr = (unsigned) rand();
-
-#if RAND_STEP >= 3
-                if ((size_t) (q - (uint8_t*) p + 2) < n)
-                        q[2] = rr >> 16;
-#endif
-#if RAND_STEP >= 2
-                if ((size_t) (q - (uint8_t*) p + 1) < n)
-                        q[1] = rr >> 8;
-#endif
-                q[0] = rr;
-        }
-}
-
-void random_bytes(void *p, size_t n) {
-
-        /* This returns high quality randomness if we can get it cheaply. If we can't because for some reason
-         * it is not available we'll try some crappy fallbacks.
-         *
-         * What this function will do:
-         *
-         *         • This function will preferably use the CPU's RDRAND operation, if it is available, in
-         *           order to return "mid-quality" random values cheaply.
-         *
-         *         • Use getrandom() with GRND_NONBLOCK, to return high-quality random values if they are
-         *           cheaply available.
-         *
-         *         • This function will return pseudo-random data, generated via libc rand() if nothing
-         *           better is available.
-         *
-         *         • This function will work fine in early boot
-         *
-         *         • This function will always succeed
-         *
-         * What this function won't do:
-         *
-         *         • This function will never fail: it will give you randomness no matter what. It might not
-         *           be high quality, but it will return some, possibly generated via libc's rand() call.
-         *
-         *         • This function will never block: if the only way to get good randomness is a blocking,
-         *           synchronous getrandom() we'll instead provide you with pseudo-random data.
-         *
-         * This function is hence great for things like seeding hash tables, generating random numeric UNIX
-         * user IDs (that are checked for collisions before use) and such.
-         *
-         * This function is hence not useful for generating UUIDs or cryptographic key material.
-         */
-
-        if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND|RANDOM_ALLOW_INSECURE) >= 0)
-                return;
-
-        /* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
-        pseudo_random_bytes(p, n);
-}
-
-#if 0 /* NM_IGNORED */
-size_t random_pool_size(void) {
-        _cleanup_free_ char *s = NULL;
-        int r;
-
-        /* Read pool size, if possible */
-        r = read_one_line_file("/proc/sys/kernel/random/poolsize", &s);
-        if (r < 0)
-                log_debug_errno(r, "Failed to read pool size from kernel: %m");
-        else {
-                unsigned sz;
-
-                r = safe_atou(s, &sz);
-                if (r < 0)
-                        log_debug_errno(r, "Failed to parse pool size: %s", s);
-                else
-                        /* poolsize is in bits on 2.6, but we want bytes */
-                        return CLAMP(sz / 8, RANDOM_POOL_SIZE_MIN, RANDOM_POOL_SIZE_MAX);
-        }
-
-        /* Use the minimum as default, if we can't retrieve the correct value */
-        return RANDOM_POOL_SIZE_MIN;
-}
-
-int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
-        _cleanup_close_ int opened_fd = -1;
-        int r;
-
-        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;
-
-                /* The kernel API only accepts "int" as entropy count (which is in bits), let's avoid any
-                 * chance for confusion here. */
-                if (size > INT_MAX / 8)
-                        return -EOVERFLOW;
-
-                info = malloc(offsetof(struct rand_pool_info, buf) + size);
-                if (!info)
-                        return -ENOMEM;
-
-                info->entropy_count = size * 8;
-                info->buf_size = size;
-                memcpy(info->buf, seed, size);
-
-                if (ioctl(fd, RNDADDENTROPY, info) < 0)
-                        return -errno;
-        } else {
-                r = loop_write(fd, seed, size, false);
-                if (r < 0)
-                        return r;
-        }
-
-        return 1;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/random-util.h b/shared/systemd/src/basic/random-util.h
deleted file mode 100644
index f661fc09..00000000
--- a/shared/systemd/src/basic/random-util.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-typedef enum RandomFlags {
-        RANDOM_EXTEND_WITH_PSEUDO = 1 << 0, /* If we can't get enough genuine randomness, but some, fill up the rest with pseudo-randomness */
-        RANDOM_BLOCK              = 1 << 1, /* Rather block than return crap randomness (only if the kernel supports that) */
-        RANDOM_MAY_FAIL           = 1 << 2, /* If we can't get any randomness at all, return early with -ENODATA */
-        RANDOM_ALLOW_RDRAND       = 1 << 3, /* Allow usage of the CPU RNG */
-        RANDOM_ALLOW_INSECURE     = 1 << 4, /* Allow usage of GRND_INSECURE flag to kernel's getrandom() API */
-} RandomFlags;
-
-int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */
-void pseudo_random_bytes(void *p, size_t n);                    /* returns only pseudo-randommess (but possibly seeded from something better) */
-void random_bytes(void *p, size_t n);                           /* returns genuine randomness if cheaply available, and pseudo randomness if not. */
-
-void initialize_srand(void);
-
-static inline uint64_t random_u64(void) {
-        uint64_t u;
-        random_bytes(&u, sizeof(u));
-        return u;
-}
-
-static inline uint32_t random_u32(void) {
-        uint32_t u;
-        random_bytes(&u, sizeof(u));
-        return u;
-}
-
-int rdrand(unsigned long *ret);
-
-/* Some limits on the pool sizes when we deal with the kernel random pool */
-#define RANDOM_POOL_SIZE_MIN 512U
-#define RANDOM_POOL_SIZE_MAX (10U*1024U*1024U)
-
-size_t random_pool_size(void);
-
-int random_write_entropy(int fd, const void *seed, size_t size, bool credit);
diff --git a/shared/systemd/src/basic/ratelimit.c b/shared/systemd/src/basic/ratelimit.c
deleted file mode 100644
index 12c8324d..00000000
--- a/shared/systemd/src/basic/ratelimit.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* 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
deleted file mode 100644
index ee1d17c0..00000000
--- a/shared/systemd/src/basic/ratelimit.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 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
deleted file mode 100644
index 57ff7130..00000000
--- a/shared/systemd/src/basic/set.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include "extract-word.h"
-#include "hashmap.h"
-#include "macro.h"
-
-#define set_free_and_replace(a, b)              \
-        ({                                      \
-                set_free(a);                    \
-                (a) = (b);                      \
-                (b) = NULL;                     \
-                0;                              \
-        })
-
-Set* _set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define set_new(ops) _set_new(ops HASHMAP_DEBUG_SRC_ARGS)
-
-static inline Set* set_free(Set *s) {
-        return (Set*) _hashmap_free(HASHMAP_BASE(s), NULL, NULL);
-}
-
-static inline Set* set_free_free(Set *s) {
-        return (Set*) _hashmap_free(HASHMAP_BASE(s), free, NULL);
-}
-
-/* no set_free_free_free */
-
-#define set_copy(s) ((Set*) _hashmap_copy(HASHMAP_BASE(h)  HASHMAP_DEBUG_SRC_ARGS))
-
-int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
-#define set_ensure_allocated(h, ops) _set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
-
-int set_put(Set *s, const void *key);
-/* no set_update */
-/* no set_replace */
-static inline void *set_get(const Set *s, const void *key) {
-        return _hashmap_get(HASHMAP_BASE((Set *) s), key);
-}
-/* no set_get2 */
-
-static inline bool set_contains(const Set *s, const void *key) {
-        return _hashmap_contains(HASHMAP_BASE((Set *) s), key);
-}
-
-static inline void *set_remove(Set *s, const void *key) {
-        return _hashmap_remove(HASHMAP_BASE(s), key);
-}
-
-/* no set_remove2 */
-/* no set_remove_value */
-int set_remove_and_put(Set *s, const void *old_key, const void *new_key);
-/* no set_remove_and_replace */
-int set_merge(Set *s, Set *other);
-
-static inline int set_reserve(Set *h, unsigned entries_add) {
-        return _hashmap_reserve(HASHMAP_BASE(h), entries_add);
-}
-
-static inline int set_move(Set *s, Set *other) {
-        return _hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other));
-}
-
-static inline int set_move_one(Set *s, Set *other, const void *key) {
-        return _hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key);
-}
-
-static inline unsigned set_size(const Set *s) {
-        return _hashmap_size(HASHMAP_BASE((Set *) s));
-}
-
-static inline bool set_isempty(const Set *s) {
-        return set_size(s) == 0;
-}
-
-static inline unsigned set_buckets(const Set *s) {
-        return _hashmap_buckets(HASHMAP_BASE((Set *) s));
-}
-
-static inline bool set_iterate(const Set *s, Iterator *i, void **value) {
-        return _hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL);
-}
-
-static inline void set_clear(Set *s) {
-        _hashmap_clear(HASHMAP_BASE(s), NULL, NULL);
-}
-
-static inline void set_clear_free(Set *s) {
-        _hashmap_clear(HASHMAP_BASE(s), free, NULL);
-}
-
-/* no set_clear_free_free */
-
-static inline void *set_steal_first(Set *s) {
-        return _hashmap_first_key_and_value(HASHMAP_BASE(s), true, NULL);
-}
-
-#define set_clear_with_destructor(_s, _f)               \
-        ({                                              \
-                void *_item;                            \
-                while ((_item = set_steal_first(_s)))   \
-                        _f(_item);                      \
-        })
-#define set_free_with_destructor(_s, _f)                \
-        ({                                              \
-                set_clear_with_destructor(_s, _f);      \
-                set_free(_s);                           \
-        })
-
-/* no set_steal_first_key */
-/* no set_first_key */
-
-static inline void *set_first(const Set *s) {
-        return _hashmap_first_key_and_value(HASHMAP_BASE((Set *) s), false, NULL);
-}
-
-/* no set_next */
-
-static inline char **set_get_strv(Set *s) {
-        return _hashmap_get_strv(HASHMAP_BASE(s));
-}
-
-int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key  HASHMAP_DEBUG_PARAMS);
-#define set_ensure_put(s, hash_ops, key) _set_ensure_put(s, hash_ops, key  HASHMAP_DEBUG_SRC_ARGS)
-
-int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key  HASHMAP_DEBUG_PARAMS);
-#define set_ensure_consume(s, hash_ops, key) _set_ensure_consume(s, hash_ops, key  HASHMAP_DEBUG_SRC_ARGS)
-
-int set_consume(Set *s, void *value);
-
-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);
-
-#define _SET_FOREACH(e, s, i) \
-        for (Iterator i = ITERATOR_FIRST; set_iterate((s), &i, (void**)&(e)); )
-#define SET_FOREACH(e, s) \
-        _SET_FOREACH(e, s, UNIQ_T(i, UNIQ))
-
-#define SET_FOREACH_MOVE(e, d, s)                                       \
-        for (; ({ e = set_first(s); assert_se(!e || set_move_one(d, s, e) >= 0); e; }); )
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free);
-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
deleted file mode 100644
index 0c6f5818..00000000
--- a/shared/systemd/src/basic/signal-util.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <stdarg.h>
-
-#include "macro.h"
-#include "parse-util.h"
-#include "signal-util.h"
-#include "stdio-util.h"
-#include "string-table.h"
-#include "string-util.h"
-
-#if 0 /* NM_IGNORED */
-int reset_all_signal_handlers(void) {
-        static const struct sigaction sa = {
-                .sa_handler = SIG_DFL,
-                .sa_flags = SA_RESTART,
-        };
-        int sig, r = 0;
-
-        for (sig = 1; sig < _NSIG; sig++) {
-
-                /* These two cannot be caught... */
-                if (IN_SET(sig, SIGKILL, SIGSTOP))
-                        continue;
-
-                /* On Linux the first two RT signals are reserved by
-                 * glibc, and sigaction() will return EINVAL for them. */
-                if (sigaction(sig, &sa, NULL) < 0)
-                        if (errno != EINVAL && r >= 0)
-                                r = -errno;
-        }
-
-        return r;
-}
-
-int reset_signal_mask(void) {
-        sigset_t ss;
-
-        if (sigemptyset(&ss) < 0)
-                return -errno;
-
-        if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
-                return -errno;
-
-        return 0;
-}
-
-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. */
-        for (; sig >= 0; sig = va_arg(ap, int)) {
-
-                if (sig == 0)
-                        continue;
-
-                if (sigaction(sig, sa, NULL) < 0) {
-                        if (r >= 0)
-                                r = -errno;
-                }
-        }
-
-        return r;
-}
-
-int sigaction_many(const struct sigaction *sa, ...) {
-        va_list ap;
-        int r;
-
-        va_start(ap, sa);
-        r = sigaction_many_ap(sa, 0, ap);
-        va_end(ap);
-
-        return r;
-}
-
-int ignore_signals(int sig, ...) {
-
-        static const struct sigaction sa = {
-                .sa_handler = SIG_IGN,
-                .sa_flags = SA_RESTART,
-        };
-
-        va_list ap;
-        int r;
-
-        va_start(ap, sig);
-        r = sigaction_many_ap(&sa, sig, ap);
-        va_end(ap);
-
-        return r;
-}
-
-int default_signals(int sig, ...) {
-
-        static const struct sigaction sa = {
-                .sa_handler = SIG_DFL,
-                .sa_flags = SA_RESTART,
-        };
-
-        va_list ap;
-        int r;
-
-        va_start(ap, sig);
-        r = sigaction_many_ap(&sa, sig, ap);
-        va_end(ap);
-
-        return r;
-}
-
-static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
-        int sig, r = 0;
-
-        assert(ss);
-
-        while ((sig = va_arg(ap, int)) >= 0) {
-
-                if (sig == 0)
-                        continue;
-
-                if (sigaddset(ss, sig) < 0) {
-                        if (r >= 0)
-                                r = -errno;
-                }
-        }
-
-        return r;
-}
-
-int sigset_add_many(sigset_t *ss, ...) {
-        va_list ap;
-        int r;
-
-        va_start(ap, ss);
-        r = sigset_add_many_ap(ss, ap);
-        va_end(ap);
-
-        return r;
-}
-
-int sigprocmask_many(int how, sigset_t *old, ...) {
-        va_list ap;
-        sigset_t ss;
-        int r;
-
-        if (sigemptyset(&ss) < 0)
-                return -errno;
-
-        va_start(ap, old);
-        r = sigset_add_many_ap(&ss, ap);
-        va_end(ap);
-
-        if (r < 0)
-                return r;
-
-        if (sigprocmask(how, &ss, old) < 0)
-                return -errno;
-
-        return 0;
-}
-
-static const char *const __signal_table[] = {
-        [SIGHUP] = "HUP",
-        [SIGINT] = "INT",
-        [SIGQUIT] = "QUIT",
-        [SIGILL] = "ILL",
-        [SIGTRAP] = "TRAP",
-        [SIGABRT] = "ABRT",
-        [SIGBUS] = "BUS",
-        [SIGFPE] = "FPE",
-        [SIGKILL] = "KILL",
-        [SIGUSR1] = "USR1",
-        [SIGSEGV] = "SEGV",
-        [SIGUSR2] = "USR2",
-        [SIGPIPE] = "PIPE",
-        [SIGALRM] = "ALRM",
-        [SIGTERM] = "TERM",
-#ifdef SIGSTKFLT
-        [SIGSTKFLT] = "STKFLT",  /* Linux on SPARC doesn't know SIGSTKFLT */
-#endif
-        [SIGCHLD] = "CHLD",
-        [SIGCONT] = "CONT",
-        [SIGSTOP] = "STOP",
-        [SIGTSTP] = "TSTP",
-        [SIGTTIN] = "TTIN",
-        [SIGTTOU] = "TTOU",
-        [SIGURG] = "URG",
-        [SIGXCPU] = "XCPU",
-        [SIGXFSZ] = "XFSZ",
-        [SIGVTALRM] = "VTALRM",
-        [SIGPROF] = "PROF",
-        [SIGWINCH] = "WINCH",
-        [SIGIO] = "IO",
-        [SIGPWR] = "PWR",
-        [SIGSYS] = "SYS"
-};
-
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
-
-const char *signal_to_string(int signo) {
-        static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int) + 1];
-        const char *name;
-
-        name = __signal_to_string(signo);
-        if (name)
-                return name;
-
-        if (signo >= SIGRTMIN && signo <= SIGRTMAX)
-                xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN);
-        else
-                xsprintf(buf, "%d", signo);
-
-        return buf;
-}
-
-int signal_from_string(const char *s) {
-        const char *p;
-        int signo, r;
-
-        /* Check that the input is a signal number. */
-        if (safe_atoi(s, &signo) >= 0) {
-                if (SIGNAL_VALID(signo))
-                        return signo;
-                else
-                        return -ERANGE;
-        }
-
-        /* Drop "SIG" prefix. */
-        if (startswith(s, "SIG"))
-                s += 3;
-
-        /* Check that the input is a signal name. */
-        signo = __signal_from_string(s);
-        if (signo > 0)
-                return signo;
-
-        /* Check that the input is RTMIN or
-         * RTMIN+n (0 <= n <= SIGRTMAX-SIGRTMIN). */
-        p = startswith(s, "RTMIN");
-        if (p) {
-                if (*p == '\0')
-                        return SIGRTMIN;
-                if (*p != '+')
-                        return -EINVAL;
-
-                r = safe_atoi(p, &signo);
-                if (r < 0)
-                        return r;
-
-                if (signo < 0 || signo > SIGRTMAX - SIGRTMIN)
-                        return -ERANGE;
-
-                return signo + SIGRTMIN;
-        }
-
-        /* Check that the input is RTMAX or
-         * RTMAX-n (0 <= n <= SIGRTMAX-SIGRTMIN). */
-        p = startswith(s, "RTMAX");
-        if (p) {
-                if (*p == '\0')
-                        return SIGRTMAX;
-                if (*p != '-')
-                        return -EINVAL;
-
-                r = safe_atoi(p, &signo);
-                if (r < 0)
-                        return r;
-
-                if (signo > 0 || signo < SIGRTMIN - SIGRTMAX)
-                        return -ERANGE;
-
-                return signo + SIGRTMAX;
-        }
-
-        return -EINVAL;
-}
-
-void nop_signal_handler(int sig) {
-        /* nothing here */
-}
-#endif /* NM_IGNORED */
-
-int signal_is_blocked(int sig) {
-        sigset_t ss;
-        int r;
-
-        r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
-        if (r != 0)
-                return -r;
-
-        r = sigismember(&ss, sig);
-        if (r < 0)
-                return -errno;
-
-        return r;
-}
diff --git a/shared/systemd/src/basic/signal-util.h b/shared/systemd/src/basic/signal-util.h
deleted file mode 100644
index bdd39d42..00000000
--- a/shared/systemd/src/basic/signal-util.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <signal.h>
-
-#include "macro.h"
-
-int reset_all_signal_handlers(void);
-int reset_signal_mask(void);
-
-int ignore_signals(int sig, ...);
-int default_signals(int sig, ...);
-int sigaction_many(const struct sigaction *sa, ...);
-
-int sigset_add_many(sigset_t *ss, ...);
-int sigprocmask_many(int how, sigset_t *old, ...);
-
-const char *signal_to_string(int i) _const_;
-int signal_from_string(const char *s) _pure_;
-
-void nop_signal_handler(int sig);
-
-static inline void block_signals_reset(sigset_t *ss) {
-        assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0);
-}
-
-#define BLOCK_SIGNALS(...)                                                         \
-        _cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({        \
-                sigset_t _t;                                                       \
-                assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__, -1) >= 0); \
-                _t;                                                                \
-        })
-
-static inline bool SIGNAL_VALID(int signo) {
-        return signo > 0 && signo < _NSIG;
-}
-
-static inline const char* signal_to_string_with_check(int n) {
-        if (!SIGNAL_VALID(n))
-                return NULL;
-
-        return signal_to_string(n);
-}
-
-int signal_is_blocked(int sig);
diff --git a/shared/systemd/src/basic/siphash24.h b/shared/systemd/src/basic/siphash24.h
deleted file mode 100644
index e46f3cc5..00000000
--- a/shared/systemd/src/basic/siphash24.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* SPDX-License-Identifier: CC0-1.0 */
-
-#pragma once
-
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "string-util.h"
-#include "time-util.h"
-
-#if 0 /* NM_IGNORED */
-struct siphash {
-        uint64_t v0;
-        uint64_t v1;
-        uint64_t v2;
-        uint64_t v3;
-        uint64_t padding;
-        size_t inlen;
-};
-#else /* NM_IGNORED */
-struct siphash {
-    CSipHash _csiphash;
-};
-
-static inline void
-siphash24_init (struct siphash *state, const uint8_t k[16])
-{
-    c_siphash_init ((CSipHash *) state, k);
-}
-
-static inline void
-siphash24_compress (const void *in, size_t inlen, struct siphash *state)
-{
-    c_siphash_append ((CSipHash *) state, in, inlen);
-}
-
-static inline uint64_t
-siphash24_finalize (struct siphash *state)
-{
-    return c_siphash_finalize ((CSipHash *) state);
-}
-
-static inline uint64_t
-siphash24 (const void *in, size_t inlen, const uint8_t k[16])
-{
-    return c_siphash_hash (k, in, inlen);
-}
-#endif /* NM_IGNORED */
-
-void siphash24_init(struct siphash *state, const uint8_t k[static 16]);
-void siphash24_compress(const void *in, size_t inlen, struct siphash *state);
-#define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state))
-
-static inline void siphash24_compress_boolean(bool in, struct siphash *state) {
-        uint8_t i = in;
-
-        siphash24_compress(&i, sizeof i, state);
-}
-
-static inline void siphash24_compress_usec_t(usec_t in, struct siphash *state) {
-        siphash24_compress(&in, sizeof in, state);
-}
-
-static inline void siphash24_compress_safe(const void *in, size_t inlen, struct siphash *state) {
-        if (inlen == 0)
-                return;
-
-        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);
-
-uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]);
-
-static inline uint64_t siphash24_string(const char *s, const uint8_t k[static 16]) {
-        return siphash24(s, strlen(s) + 1, k);
-}
diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c
deleted file mode 100644
index e224091d..00000000
--- a/shared/systemd/src/basic/socket-util.c
+++ /dev/null
@@ -1,1360 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <limits.h>
-#include <net/if.h>
-#include <netdb.h>
-#include <netinet/ip.h>
-#include <poll.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#if 0 /* NM_IGNORED */
-#include <linux/if.h>
-#endif /* NM_IGNORED */
-
-#include "alloc-util.h"
-#include "errno-util.h"
-#include "escape.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "format-util.h"
-#include "io-util.h"
-#include "log.h"
-#include "memory-util.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "socket-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "user-util.h"
-#include "utf8.h"
-
-#if 0 /* NM_IGNORED */
-#if ENABLE_IDN
-#  define IDN_FLAGS NI_IDN
-#else
-#  define IDN_FLAGS 0
-#endif
-
-static const char* const socket_address_type_table[] = {
-        [SOCK_STREAM] =    "Stream",
-        [SOCK_DGRAM] =     "Datagram",
-        [SOCK_RAW] =       "Raw",
-        [SOCK_RDM] =       "ReliableDatagram",
-        [SOCK_SEQPACKET] = "SequentialPacket",
-        [SOCK_DCCP] =      "DatagramCongestionControl",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_address_type, int);
-
-int socket_address_verify(const SocketAddress *a, bool strict) {
-        assert(a);
-
-        /* With 'strict' we enforce additional sanity constraints which are not set by the standard,
-         * but should only apply to sockets we create ourselves. */
-
-        switch (socket_address_family(a)) {
-
-        case AF_INET:
-                if (a->size != sizeof(struct sockaddr_in))
-                        return -EINVAL;
-
-                if (a->sockaddr.in.sin_port == 0)
-                        return -EINVAL;
-
-                if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
-                        return -EINVAL;
-
-                return 0;
-
-        case AF_INET6:
-                if (a->size != sizeof(struct sockaddr_in6))
-                        return -EINVAL;
-
-                if (a->sockaddr.in6.sin6_port == 0)
-                        return -EINVAL;
-
-                if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
-                        return -EINVAL;
-
-                return 0;
-
-        case AF_UNIX:
-                if (a->size < offsetof(struct sockaddr_un, sun_path))
-                        return -EINVAL;
-                if (a->size > sizeof(struct sockaddr_un) + !strict)
-                        /* If !strict, allow one extra byte, since getsockname() on Linux will append
-                         * a NUL byte if we have path sockets that are above sun_path's full size. */
-                        return -EINVAL;
-
-                if (a->size > offsetof(struct sockaddr_un, sun_path) &&
-                    a->sockaddr.un.sun_path[0] != 0 &&
-                    strict) {
-                        /* Only validate file system sockets here, and only in strict mode */
-                        const char *e;
-
-                        e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path));
-                        if (e) {
-                                /* If there's an embedded NUL byte, make sure the size of the socket address matches it */
-                                if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1)
-                                        return -EINVAL;
-                        } else {
-                                /* If there's no embedded NUL byte, then the size needs to match the whole
-                                 * structure or the structure with one extra NUL byte suffixed. (Yeah, Linux is awful,
-                                 * and considers both equivalent: getsockname() even extends sockaddr_un beyond its
-                                 * size if the path is non NUL terminated.)*/
-                                if (!IN_SET(a->size, sizeof(a->sockaddr.un.sun_path), sizeof(a->sockaddr.un.sun_path)+1))
-                                        return -EINVAL;
-                        }
-                }
-
-                if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
-                        return -EINVAL;
-
-                return 0;
-
-        case AF_NETLINK:
-
-                if (a->size != sizeof(struct sockaddr_nl))
-                        return -EINVAL;
-
-                if (!IN_SET(a->type, 0, SOCK_RAW, SOCK_DGRAM))
-                        return -EINVAL;
-
-                return 0;
-
-        case AF_VSOCK:
-                if (a->size != sizeof(struct sockaddr_vm))
-                        return -EINVAL;
-
-                if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
-                        return -EINVAL;
-
-                return 0;
-
-        default:
-                return -EAFNOSUPPORT;
-        }
-}
-
-int socket_address_print(const SocketAddress *a, char **ret) {
-        int r;
-
-        assert(a);
-        assert(ret);
-
-        r = socket_address_verify(a, false); /* We do non-strict validation, because we want to be
-                                              * able to pretty-print any socket the kernel considers
-                                              * valid. We still need to do validation to know if we
-                                              * can meaningfully print the address. */
-        if (r < 0)
-                return r;
-
-        if (socket_address_family(a) == AF_NETLINK) {
-                _cleanup_free_ char *sfamily = NULL;
-
-                r = netlink_family_to_string_alloc(a->protocol, &sfamily);
-                if (r < 0)
-                        return r;
-
-                r = asprintf(ret, "%s %u", sfamily, a->sockaddr.nl.nl_groups);
-                if (r < 0)
-                        return -ENOMEM;
-
-                return 0;
-        }
-
-        return sockaddr_pretty(&a->sockaddr.sa, a->size, false, true, ret);
-}
-
-bool socket_address_can_accept(const SocketAddress *a) {
-        assert(a);
-
-        return
-                IN_SET(a->type, SOCK_STREAM, SOCK_SEQPACKET);
-}
-
-bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
-        assert(a);
-        assert(b);
-
-        /* Invalid addresses are unequal to all */
-        if (socket_address_verify(a, false) < 0 ||
-            socket_address_verify(b, false) < 0)
-                return false;
-
-        if (a->type != b->type)
-                return false;
-
-        if (socket_address_family(a) != socket_address_family(b))
-                return false;
-
-        switch (socket_address_family(a)) {
-
-        case AF_INET:
-                if (a->sockaddr.in.sin_addr.s_addr != b->sockaddr.in.sin_addr.s_addr)
-                        return false;
-
-                if (a->sockaddr.in.sin_port != b->sockaddr.in.sin_port)
-                        return false;
-
-                break;
-
-        case AF_INET6:
-                if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0)
-                        return false;
-
-                if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port)
-                        return false;
-
-                break;
-
-        case AF_UNIX:
-                if (a->size <= offsetof(struct sockaddr_un, sun_path) ||
-                    b->size <= offsetof(struct sockaddr_un, sun_path))
-                        return false;
-
-                if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0))
-                        return false;
-
-                if (a->sockaddr.un.sun_path[0]) {
-                        if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, 0))
-                                return false;
-                } else {
-                        if (a->size != b->size)
-                                return false;
-
-                        if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0)
-                                return false;
-                }
-
-                break;
-
-        case AF_NETLINK:
-                if (a->protocol != b->protocol)
-                        return false;
-
-                if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups)
-                        return false;
-
-                break;
-
-        case AF_VSOCK:
-                if (a->sockaddr.vm.svm_cid != b->sockaddr.vm.svm_cid)
-                        return false;
-
-                if (a->sockaddr.vm.svm_port != b->sockaddr.vm.svm_port)
-                        return false;
-
-                break;
-
-        default:
-                /* Cannot compare, so we assume the addresses are different */
-                return false;
-        }
-
-        return true;
-}
-
-const char* socket_address_get_path(const SocketAddress *a) {
-        assert(a);
-
-        if (socket_address_family(a) != AF_UNIX)
-                return NULL;
-
-        if (a->sockaddr.un.sun_path[0] == 0)
-                return NULL;
-
-        /* Note that this is only safe because we know that there's an extra NUL byte after the sockaddr_un
-         * structure. On Linux AF_UNIX file system socket addresses don't have to be NUL terminated if they take up the
-         * full sun_path space. */
-        assert_cc(sizeof(union sockaddr_union) >= sizeof(struct sockaddr_un)+1);
-        return a->sockaddr.un.sun_path;
-}
-
-bool socket_ipv6_is_supported(void) {
-        if (access("/proc/net/if_inet6", F_OK) != 0)
-                return false;
-
-        return true;
-}
-
-bool socket_address_matches_fd(const SocketAddress *a, int fd) {
-        SocketAddress b;
-        socklen_t solen;
-
-        assert(a);
-        assert(fd >= 0);
-
-        b.size = sizeof(b.sockaddr);
-        if (getsockname(fd, &b.sockaddr.sa, &b.size) < 0)
-                return false;
-
-        if (b.sockaddr.sa.sa_family != a->sockaddr.sa.sa_family)
-                return false;
-
-        solen = sizeof(b.type);
-        if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &b.type, &solen) < 0)
-                return false;
-
-        if (b.type != a->type)
-                return false;
-
-        if (a->protocol != 0)  {
-                solen = sizeof(b.protocol);
-                if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &b.protocol, &solen) < 0)
-                        return false;
-
-                if (b.protocol != a->protocol)
-                        return false;
-        }
-
-        return socket_address_equal(a, &b);
-}
-
-int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
-        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 */
-
-        assert(sa);
-
-        switch (sa->sa.sa_family) {
-
-        case AF_INET:
-                *ret_port = be16toh(sa->in.sin_port);
-                return 0;
-
-        case AF_INET6:
-                *ret_port = be16toh(sa->in6.sin6_port);
-                return 0;
-
-        case AF_VSOCK:
-                *ret_port = sa->vm.svm_port;
-                return 0;
-
-        default:
-                return -EAFNOSUPPORT;
-        }
-}
-
-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,
-                bool translate_ipv6,
-                bool include_port,
-                char **ret) {
-
-        union sockaddr_union *sa = (union sockaddr_union*) _sa;
-        char *p;
-        int r;
-
-        assert(sa);
-        assert(salen >= sizeof(sa->sa.sa_family));
-
-        switch (sa->sa.sa_family) {
-
-        case AF_INET: {
-                uint32_t a;
-
-                a = be32toh(sa->in.sin_addr.s_addr);
-
-                if (include_port)
-                        r = asprintf(&p,
-                                     "%u.%u.%u.%u:%u",
-                                     a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
-                                     be16toh(sa->in.sin_port));
-                else
-                        r = asprintf(&p,
-                                     "%u.%u.%u.%u",
-                                     a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF);
-                if (r < 0)
-                        return -ENOMEM;
-                break;
-        }
-
-        case AF_INET6: {
-                static const unsigned char ipv4_prefix[] = {
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
-                };
-
-                if (translate_ipv6 &&
-                    memcmp(&sa->in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
-                        const uint8_t *a = sa->in6.sin6_addr.s6_addr+12;
-                        if (include_port)
-                                r = asprintf(&p,
-                                             "%u.%u.%u.%u:%u",
-                                             a[0], a[1], a[2], a[3],
-                                             be16toh(sa->in6.sin6_port));
-                        else
-                                r = asprintf(&p,
-                                             "%u.%u.%u.%u",
-                                             a[0], a[1], a[2], a[3]);
-                        if (r < 0)
-                                return -ENOMEM;
-                } else {
-                        char a[INET6_ADDRSTRLEN], ifname[IF_NAMESIZE + 1];
-
-                        inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
-                        if (sa->in6.sin6_scope_id != 0)
-                                format_ifname_full(sa->in6.sin6_scope_id, ifname, FORMAT_IFNAME_IFINDEX);
-
-                        if (include_port) {
-                                r = asprintf(&p,
-                                             "[%s]:%u%s%s",
-                                             a,
-                                             be16toh(sa->in6.sin6_port),
-                                             sa->in6.sin6_scope_id != 0 ? "%" : "",
-                                             sa->in6.sin6_scope_id != 0 ? ifname : "");
-                                if (r < 0)
-                                        return -ENOMEM;
-                        } else {
-                                p = sa->in6.sin6_scope_id != 0 ? strjoin(a, "%", ifname) : strdup(a);
-                                if (!p)
-                                        return -ENOMEM;
-                        }
-                }
-
-                break;
-        }
-
-        case AF_UNIX:
-                if (salen <= offsetof(struct sockaddr_un, sun_path) ||
-                    (sa->un.sun_path[0] == 0 && salen == offsetof(struct sockaddr_un, sun_path) + 1))
-                        /* The name must have at least one character (and the leading NUL does not count) */
-                        p = strdup("<unnamed>");
-                else {
-                        /* Note that we calculate the path pointer here through the .un_buffer[] field, in order to
-                         * outtrick bounds checking tools such as ubsan, which are too smart for their own good: on
-                         * Linux the kernel may return sun_path[] data one byte longer than the declared size of the
-                         * field. */
-                        char *path = (char*) sa->un_buffer + offsetof(struct sockaddr_un, sun_path);
-                        size_t path_len = salen - offsetof(struct sockaddr_un, sun_path);
-
-                        if (path[0] == 0) {
-                                /* Abstract socket. When parsing address information from, we
-                                 * explicitly reject overly long paths and paths with embedded NULs.
-                                 * But we might get such a socket from the outside. Let's return
-                                 * something meaningful and printable in this case. */
-
-                                _cleanup_free_ char *e = NULL;
-
-                                e = cescape_length(path + 1, path_len - 1);
-                                if (!e)
-                                        return -ENOMEM;
-
-                                p = strjoin("@", e);
-                        } else {
-                                if (path[path_len - 1] == '\0')
-                                        /* We expect a terminating NUL and don't print it */
-                                        path_len --;
-
-                                p = cescape_length(path, path_len);
-                        }
-                }
-                if (!p)
-                        return -ENOMEM;
-
-                break;
-
-        case AF_VSOCK:
-                if (include_port) {
-                        if (sa->vm.svm_cid == VMADDR_CID_ANY)
-                                r = asprintf(&p, "vsock::%u", sa->vm.svm_port);
-                        else
-                                r = asprintf(&p, "vsock:%u:%u", sa->vm.svm_cid, sa->vm.svm_port);
-                } else
-                        r = asprintf(&p, "vsock:%u", sa->vm.svm_cid);
-                if (r < 0)
-                        return -ENOMEM;
-                break;
-
-        default:
-                return -EOPNOTSUPP;
-        }
-
-        *ret = p;
-        return 0;
-}
-
-int getpeername_pretty(int fd, bool include_port, char **ret) {
-        union sockaddr_union sa;
-        socklen_t salen = sizeof(sa);
-        int r;
-
-        assert(fd >= 0);
-        assert(ret);
-
-        if (getpeername(fd, &sa.sa, &salen) < 0)
-                return -errno;
-
-        if (sa.sa.sa_family == AF_UNIX) {
-                struct ucred ucred = {};
-
-                /* UNIX connection sockets are anonymous, so let's use
-                 * PID/UID as pretty credentials instead */
-
-                r = getpeercred(fd, &ucred);
-                if (r < 0)
-                        return r;
-
-                if (asprintf(ret, "PID "PID_FMT"/UID "UID_FMT, ucred.pid, ucred.uid) < 0)
-                        return -ENOMEM;
-
-                return 0;
-        }
-
-        /* For remote sockets we translate IPv6 addresses back to IPv4
-         * if applicable, since that's nicer. */
-
-        return sockaddr_pretty(&sa.sa, salen, true, include_port, ret);
-}
-
-int getsockname_pretty(int fd, char **ret) {
-        union sockaddr_union sa;
-        socklen_t salen = sizeof(sa);
-
-        assert(fd >= 0);
-        assert(ret);
-
-        if (getsockname(fd, &sa.sa, &salen) < 0)
-                return -errno;
-
-        /* For local sockets we do not translate IPv6 addresses back
-         * to IPv6 if applicable, since this is usually used for
-         * listening sockets where the difference between IPv4 and
-         * IPv6 matters. */
-
-        return sockaddr_pretty(&sa.sa, salen, false, true, ret);
-}
-
-int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) {
-        int r;
-        char host[NI_MAXHOST], *ret;
-
-        assert(_ret);
-
-        r = getnameinfo(&sa->sa, salen, host, sizeof(host), NULL, 0, IDN_FLAGS);
-        if (r != 0) {
-                int saved_errno = errno;
-
-                r = sockaddr_pretty(&sa->sa, salen, true, true, &ret);
-                if (r < 0)
-                        return r;
-
-                log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
-        } else {
-                ret = strdup(host);
-                if (!ret)
-                        return -ENOMEM;
-        }
-
-        *_ret = ret;
-        return 0;
-}
-
-static const char* const netlink_family_table[] = {
-        [NETLINK_ROUTE] = "route",
-        [NETLINK_FIREWALL] = "firewall",
-        [NETLINK_INET_DIAG] = "inet-diag",
-        [NETLINK_NFLOG] = "nflog",
-        [NETLINK_XFRM] = "xfrm",
-        [NETLINK_SELINUX] = "selinux",
-        [NETLINK_ISCSI] = "iscsi",
-        [NETLINK_AUDIT] = "audit",
-        [NETLINK_FIB_LOOKUP] = "fib-lookup",
-        [NETLINK_CONNECTOR] = "connector",
-        [NETLINK_NETFILTER] = "netfilter",
-        [NETLINK_IP6_FW] = "ip6-fw",
-        [NETLINK_DNRTMSG] = "dnrtmsg",
-        [NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
-        [NETLINK_GENERIC] = "generic",
-        [NETLINK_SCSITRANSPORT] = "scsitransport",
-        [NETLINK_ECRYPTFS] = "ecryptfs",
-        [NETLINK_RDMA] = "rdma",
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
-
-static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = {
-        [SOCKET_ADDRESS_DEFAULT] = "default",
-        [SOCKET_ADDRESS_BOTH] = "both",
-        [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
-
-SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *n) {
-        int r;
-
-        r = parse_boolean(n);
-        if (r > 0)
-                return SOCKET_ADDRESS_IPV6_ONLY;
-        if (r == 0)
-                return SOCKET_ADDRESS_BOTH;
-
-        return socket_address_bind_ipv6_only_from_string(n);
-}
-
-bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b) {
-        assert(a);
-        assert(b);
-
-        if (a->sa.sa_family != b->sa.sa_family)
-                return false;
-
-        if (a->sa.sa_family == AF_INET)
-                return a->in.sin_addr.s_addr == b->in.sin_addr.s_addr;
-
-        if (a->sa.sa_family == AF_INET6)
-                return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0;
-
-        if (a->sa.sa_family == AF_VSOCK)
-                return a->vm.svm_cid == b->vm.svm_cid;
-
-        return false;
-}
-
-int fd_set_sndbuf(int fd, size_t n, bool increase) {
-        int r, value;
-        socklen_t l = sizeof(value);
-
-        if (n > INT_MAX)
-                return -ERANGE;
-
-        r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
-        if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
-                return 0;
-
-        /* First, try to set the buffer size with SO_SNDBUF. */
-        r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, n);
-        if (r < 0)
-                return r;
-
-        /* SO_SNDBUF above may set to the kernel limit, instead of the requested size.
-         * So, we need to check the actual buffer size here. */
-        l = sizeof(value);
-        r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
-        if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
-                return 1;
-
-        /* If we have the privileges we will ignore the kernel limit. */
-        r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, n);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-int fd_set_rcvbuf(int fd, size_t n, bool increase) {
-        int r, value;
-        socklen_t l = sizeof(value);
-
-        if (n > INT_MAX)
-                return -ERANGE;
-
-        r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
-        if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
-                return 0;
-
-        /* First, try to set the buffer size with SO_RCVBUF. */
-        r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, n);
-        if (r < 0)
-                return r;
-
-        /* SO_RCVBUF above may set to the kernel limit, instead of the requested size.
-         * So, we need to check the actual buffer size here. */
-        l = sizeof(value);
-        r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
-        if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
-                return 1;
-
-        /* If we have the privileges we will ignore the kernel limit. */
-        r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUFFORCE, n);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-static const char* const ip_tos_table[] = {
-        [IPTOS_LOWDELAY] = "low-delay",
-        [IPTOS_THROUGHPUT] = "throughput",
-        [IPTOS_RELIABILITY] = "reliability",
-        [IPTOS_LOWCOST] = "low-cost",
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
-
-bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
-        bool numeric = true;
-
-        /* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
-         * but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We
-         * also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */
-
-        assert(!(flags & ~_IFNAME_VALID_ALL));
-
-        if (isempty(p))
-                return false;
-
-        if (flags & IFNAME_VALID_ALTERNATIVE) {
-                if (strlen(p) >= ALTIFNAMSIZ)
-                        return false;
-        } else {
-                if (strlen(p) >= IFNAMSIZ)
-                        return false;
-        }
-
-        if (dot_or_dot_dot(p))
-                return false;
-
-        for (const char *t = p; *t; t++) {
-                if ((unsigned char) *t >= 127U)
-                        return false;
-
-                if ((unsigned char) *t <= 32U)
-                        return false;
-
-                if (IN_SET(*t, ':', '/'))
-                        return false;
-
-                numeric = numeric && (*t >= '0' && *t <= '9');
-        }
-
-        if (numeric) {
-                if (!(flags & IFNAME_VALID_NUMERIC))
-                        return false;
-
-                /* Verify that the number is well-formatted and in range. */
-                if (parse_ifindex(p) < 0)
-                        return false;
-        }
-
-        return true;
-}
-
-bool address_label_valid(const char *p) {
-
-        if (isempty(p))
-                return false;
-
-        if (strlen(p) >= IFNAMSIZ)
-                return false;
-
-        while (*p) {
-                if ((uint8_t) *p >= 127U)
-                        return false;
-
-                if ((uint8_t) *p <= 31U)
-                        return false;
-                p++;
-        }
-
-        return true;
-}
-
-int getpeercred(int fd, struct ucred *ucred) {
-        socklen_t n = sizeof(struct ucred);
-        struct ucred u;
-        int r;
-
-        assert(fd >= 0);
-        assert(ucred);
-
-        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
-        if (r < 0)
-                return -errno;
-
-        if (n != sizeof(struct ucred))
-                return -EIO;
-
-        /* Check if the data is actually useful and not suppressed due to namespacing issues */
-        if (!pid_is_valid(u.pid))
-                return -ENODATA;
-
-        /* Note that we don't check UID/GID here, as namespace translation works differently there: instead of
-         * receiving in "invalid" user/group we get the overflow UID/GID. */
-
-        *ucred = u;
-        return 0;
-}
-
-int getpeersec(int fd, char **ret) {
-        _cleanup_free_ char *s = NULL;
-        socklen_t n = 64;
-
-        assert(fd >= 0);
-        assert(ret);
-
-        for (;;) {
-                s = new0(char, n+1);
-                if (!s)
-                        return -ENOMEM;
-
-                if (getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n) >= 0)
-                        break;
-
-                if (errno != ERANGE)
-                        return -errno;
-
-                s = mfree(s);
-        }
-
-        if (isempty(s))
-                return -EOPNOTSUPP;
-
-        *ret = TAKE_PTR(s);
-
-        return 0;
-}
-
-int getpeergroups(int fd, gid_t **ret) {
-        socklen_t n = sizeof(gid_t) * 64;
-        _cleanup_free_ gid_t *d = NULL;
-
-        assert(fd >= 0);
-        assert(ret);
-
-        for (;;) {
-                d = malloc(n);
-                if (!d)
-                        return -ENOMEM;
-
-                if (getsockopt(fd, SOL_SOCKET, SO_PEERGROUPS, d, &n) >= 0)
-                        break;
-
-                if (errno != ERANGE)
-                        return -errno;
-
-                d = mfree(d);
-        }
-
-        assert_se(n % sizeof(gid_t) == 0);
-        n /= sizeof(gid_t);
-
-        if ((socklen_t) (int) n != n)
-                return -E2BIG;
-
-        *ret = TAKE_PTR(d);
-
-        return (int) n;
-}
-
-ssize_t send_one_fd_iov_sa(
-                int transport_fd,
-                int fd,
-                struct iovec *iov, size_t iovlen,
-                const struct sockaddr *sa, socklen_t len,
-                int flags) {
-
-        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control = {};
-        struct msghdr mh = {
-                .msg_name = (struct sockaddr*) sa,
-                .msg_namelen = len,
-                .msg_iov = iov,
-                .msg_iovlen = iovlen,
-        };
-        ssize_t k;
-
-        assert(transport_fd >= 0);
-
-        /*
-         * We need either an FD or data to send.
-         * If there's nothing, return an error.
-         */
-        if (fd < 0 && !iov)
-                return -EINVAL;
-
-        if (fd >= 0) {
-                struct cmsghdr *cmsg;
-
-                mh.msg_control = &control;
-                mh.msg_controllen = sizeof(control);
-
-                cmsg = CMSG_FIRSTHDR(&mh);
-                cmsg->cmsg_level = SOL_SOCKET;
-                cmsg->cmsg_type = SCM_RIGHTS;
-                cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-                memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-        }
-        k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags);
-        if (k < 0)
-                return (ssize_t) -errno;
-
-        return k;
-}
-
-int send_one_fd_sa(
-                int transport_fd,
-                int fd,
-                const struct sockaddr *sa, socklen_t len,
-                int flags) {
-
-        assert(fd >= 0);
-
-        return (int) send_one_fd_iov_sa(transport_fd, fd, NULL, 0, sa, len, flags);
-}
-
-ssize_t receive_one_fd_iov(
-                int transport_fd,
-                struct iovec *iov, size_t iovlen,
-                int flags,
-                int *ret_fd) {
-
-        CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int))) control;
-        struct msghdr mh = {
-                .msg_control = &control,
-                .msg_controllen = sizeof(control),
-                .msg_iov = iov,
-                .msg_iovlen = iovlen,
-        };
-        struct cmsghdr *found;
-        ssize_t k;
-
-        assert(transport_fd >= 0);
-        assert(ret_fd);
-
-        /*
-         * Receive a single FD via @transport_fd. We don't care for
-         * the transport-type. We retrieve a single FD at most, so for
-         * packet-based transports, the caller must ensure to send
-         * only a single FD per packet.  This is best used in
-         * combination with send_one_fd().
-         */
-
-        k = recvmsg_safe(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags);
-        if (k < 0)
-                return k;
-
-        found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int)));
-        if (!found) {
-                cmsg_close_all(&mh);
-
-                /* If didn't receive an FD or any data, return an error. */
-                if (k == 0)
-                        return -EIO;
-        }
-
-        if (found)
-                *ret_fd = *(int*) CMSG_DATA(found);
-        else
-                *ret_fd = -1;
-
-        return k;
-}
-
-int receive_one_fd(int transport_fd, int flags) {
-        int fd;
-        ssize_t k;
-
-        k = receive_one_fd_iov(transport_fd, NULL, 0, flags, &fd);
-        if (k == 0)
-                return fd;
-
-        /* k must be negative, since receive_one_fd_iov() only returns
-         * a positive value if data was received through the iov. */
-        assert(k < 0);
-        return (int) k;
-}
-#endif /* NM_IGNORED */
-
-ssize_t next_datagram_size_fd(int fd) {
-        ssize_t l;
-        int k;
-
-        /* This is a bit like FIONREAD/SIOCINQ, however a bit more powerful. The difference being: recv(MSG_PEEK) will
-         * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD doesn't
-         * do. This difference is actually of major importance as we need to be sure that the size returned here
-         * actually matches what we will read with recvmsg() next, as otherwise we might end up allocating a buffer of
-         * the wrong size. */
-
-        l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC);
-        if (l < 0) {
-                if (IN_SET(errno, EOPNOTSUPP, EFAULT))
-                        goto fallback;
-
-                return -errno;
-        }
-        if (l == 0)
-                goto fallback;
-
-        return l;
-
-fallback:
-        k = 0;
-
-        /* Some sockets (AF_PACKET) do not support null-sized recv() with MSG_TRUNC set, let's fall back to FIONREAD
-         * for them. Checksums don't matter for raw sockets anyway, hence this should be fine. */
-
-        if (ioctl(fd, FIONREAD, &k) < 0)
-                return -errno;
-
-        return (ssize_t) k;
-}
-
-#if 0 /* NM_IGNORED */
-/* Put a limit on how many times will attempt to call accept4(). We loop
- * only on "transient" errors, but let's make sure we don't loop forever. */
-#define MAX_FLUSH_ITERATIONS 1024
-
-int flush_accept(int fd) {
-
-        int r, b;
-        socklen_t l = sizeof(b);
-
-        /* Similar to flush_fd() but flushes all incoming connections by accepting and immediately closing
-         * them. */
-
-        if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &b, &l) < 0)
-                return -errno;
-
-        assert(l == sizeof(b));
-        if (!b) /* Let's check if this socket accepts connections before calling accept(). accept4() can
-                 * return EOPNOTSUPP if the fd is not a listening socket, which we should treat as a fatal
-                 * error, or in case the incoming TCP connection triggered a network issue, which we want to
-                 * treat as a transient error. Thus, let's rule out the first reason for EOPNOTSUPP early, so
-                 * we can loop safely on transient errors below. */
-                return -ENOTTY;
-
-        for (unsigned iteration = 0;; iteration++) {
-                int cfd;
-
-                r = fd_wait_for_event(fd, POLLIN, 0);
-                if (r < 0) {
-                        if (r == -EINTR)
-                                continue;
-
-                        return r;
-                }
-                if (r == 0)
-                        return 0;
-
-                if (iteration >= MAX_FLUSH_ITERATIONS)
-                        return log_debug_errno(SYNTHETIC_ERRNO(EBUSY),
-                                               "Failed to flush connections within " STRINGIFY(MAX_FLUSH_ITERATIONS) " iterations.");
-
-                cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
-                if (cfd < 0) {
-                        if (errno == EAGAIN)
-                                return 0;
-
-                        if (ERRNO_IS_ACCEPT_AGAIN(errno))
-                                continue;
-
-                        return -errno;
-                }
-
-                safe_close(cfd);
-        }
-}
-#endif /* NM_IGNORED */
-
-struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length) {
-        struct cmsghdr *cmsg;
-
-        assert(mh);
-
-        CMSG_FOREACH(cmsg, mh)
-                if (cmsg->cmsg_level == level &&
-                    cmsg->cmsg_type == type &&
-                    (length == (socklen_t) -1 || length == cmsg->cmsg_len))
-                        return cmsg;
-
-        return NULL;
-}
-
-#if 0 /* NM_IGNORED */
-int socket_ioctl_fd(void) {
-        int fd;
-
-        /* Create a socket to invoke the various network interface ioctl()s on. Traditionally only AF_INET was good for
-         * that. Since kernel 4.6 AF_NETLINK works for this too. We first try to use AF_INET hence, but if that's not
-         * available (for example, because it is made unavailable via SECCOMP or such), we'll fall back to the more
-         * generic AF_NETLINK. */
-
-        fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
-        if (fd < 0)
-                fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_GENERIC);
-        if (fd < 0)
-                return -errno;
-
-        return fd;
-}
-
-int sockaddr_un_unlink(const struct sockaddr_un *sa) {
-        const char *p, * nul;
-
-        assert(sa);
-
-        if (sa->sun_family != AF_UNIX)
-                return -EPROTOTYPE;
-
-        if (sa->sun_path[0] == 0) /* Nothing to do for abstract sockets */
-                return 0;
-
-        /* The path in .sun_path is not necessarily NUL terminated. Let's fix that. */
-        nul = memchr(sa->sun_path, 0, sizeof(sa->sun_path));
-        if (nul)
-                p = sa->sun_path;
-        else
-                p = memdupa_suffix0(sa->sun_path, sizeof(sa->sun_path));
-
-        if (unlink(p) < 0)
-                return -errno;
-
-        return 1;
-}
-#endif /* NM_IGNORED */
-
-int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
-        size_t l;
-
-        assert(ret);
-        assert(path);
-
-        /* Initialize ret->sun_path from the specified argument. This will interpret paths starting with '@' as
-         * abstract namespace sockets, and those starting with '/' as regular filesystem sockets. It won't accept
-         * anything else (i.e. no relative paths), to avoid ambiguities. Note that this function cannot be used to
-         * reference paths in the abstract namespace that include NUL bytes in the name. */
-
-        l = strlen(path);
-        if (l < 2)
-                return -EINVAL;
-        if (!IN_SET(path[0], '/', '@'))
-                return -EINVAL;
-
-        /* Don't allow paths larger than the space in sockaddr_un. Note that we are a tiny bit more restrictive than
-         * the kernel is: we insist on NUL termination (both for abstract namespace and regular file system socket
-         * addresses!), which the kernel doesn't. We do this to reduce chance of incompatibility with other apps that
-         * do not expect non-NUL terminated file system path*/
-        if (l+1 > sizeof(ret->sun_path))
-                return -EINVAL;
-
-        *ret = (struct sockaddr_un) {
-                .sun_family = AF_UNIX,
-        };
-
-        if (path[0] == '@') {
-                /* Abstract namespace socket */
-                memcpy(ret->sun_path + 1, path + 1, l); /* copy *with* trailing NUL byte */
-                return (int) (offsetof(struct sockaddr_un, sun_path) + l); /* 🔥 *don't* 🔥 include trailing NUL in size */
-
-        } else {
-                assert(path[0] == '/');
-
-                /* File system socket */
-                memcpy(ret->sun_path, path, l + 1); /* copy *with* trailing NUL byte */
-                return (int) (offsetof(struct sockaddr_un, sun_path) + l + 1); /* include trailing NUL in size */
-        }
-}
-
-int socket_bind_to_ifname(int fd, const char *ifname) {
-        assert(fd >= 0);
-
-        /* Call with NULL to drop binding */
-
-        if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen_ptr(ifname)) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int socket_bind_to_ifindex(int fd, int ifindex) {
-        char ifname[IF_NAMESIZE + 1];
-        int r;
-
-        assert(fd >= 0);
-
-        if (ifindex <= 0) {
-                /* Drop binding */
-                if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0) < 0)
-                        return -errno;
-
-                return 0;
-        }
-
-        r = setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex);
-        if (r != -ENOPROTOOPT)
-                return r;
-
-        /* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */
-        if (!format_ifname(ifindex, ifname))
-                return -errno;
-
-        return socket_bind_to_ifname(fd, ifname);
-}
-
-ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags) {
-        ssize_t n;
-
-        /* A wrapper around recvmsg() that checks for MSG_CTRUNC, and turns it into an error, in a reasonably
-         * safe way, closing any SCM_RIGHTS fds in the error path.
-         *
-         * Note that unlike our usual coding style this might modify *msg on failure. */
-
-        n = recvmsg(sockfd, msg, flags);
-        if (n < 0)
-                return -errno;
-
-        if (FLAGS_SET(msg->msg_flags, MSG_CTRUNC)) {
-                cmsg_close_all(msg);
-                return -EXFULL; /* a recognizable error code */
-        }
-
-        return n;
-}
-
-#if 0 /* NM_IGNORED */
-int socket_get_family(int fd, int *ret) {
-        int af;
-        socklen_t sl = sizeof(af);
-
-        if (getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &af, &sl) < 0)
-                return -errno;
-
-        if (sl != sizeof(af))
-                return -EINVAL;
-
-        return af;
-}
-
-int socket_set_recvpktinfo(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_PKTINFO, b);
-
-        case AF_INET6:
-                return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, b);
-
-        case AF_NETLINK:
-                return setsockopt_int(fd, SOL_NETLINK, NETLINK_PKTINFO, b);
-
-        case AF_PACKET:
-                return setsockopt_int(fd, SOL_PACKET, PACKET_AUXDATA, b);
-
-        default:
-                return -EAFNOSUPPORT;
-        }
-}
-
-int socket_set_unicast_if(int fd, int af, int ifi) {
-        be32_t ifindex_be = htobe32(ifi);
-        int r;
-
-        if (af == AF_UNSPEC) {
-                r = socket_get_family(fd, &af);
-                if (r < 0)
-                        return r;
-        }
-
-        switch (af) {
-
-        case AF_INET:
-                if (setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)) < 0)
-                        return -errno;
-
-                return 0;
-
-        case AF_INET6:
-                if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)) < 0)
-                        return -errno;
-
-                return 0;
-
-        default:
-                return -EAFNOSUPPORT;
-        }
-}
-
-int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val) {
-        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, opt_ipv4, val);
-
-        case AF_INET6:
-                return setsockopt_int(fd, IPPROTO_IPV6, opt_ipv6, val);
-
-        default:
-                return -EAFNOSUPPORT;
-        }
-}
-
-int socket_get_mtu(int fd, int af, size_t *ret) {
-        int mtu, r;
-
-        if (af == AF_UNSPEC) {
-                r = socket_get_family(fd, &af);
-                if (r < 0)
-                        return r;
-        }
-
-        switch (af) {
-
-        case AF_INET:
-                r = getsockopt_int(fd, IPPROTO_IP, IP_MTU, &mtu);
-                break;
-
-        case AF_INET6:
-                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
deleted file mode 100644
index 1de06947..00000000
--- a/shared/systemd/src/basic/socket-util.h
+++ /dev/null
@@ -1,307 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <inttypes.h>
-#include <linux/netlink.h>
-#include <linux/if_ether.h>
-#include <linux/if_infiniband.h>
-#include <linux/if_packet.h>
-#include <netinet/in.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-
-#include "macro.h"
-#include "missing_network.h"
-#include "missing_socket.h"
-#include "sparse-endian.h"
-
-union sockaddr_union {
-        /* The minimal, abstract version */
-        struct sockaddr sa;
-
-        /* The libc provided version that allocates "enough room" for every protocol */
-        struct sockaddr_storage storage;
-
-        /* Protoctol-specific implementations */
-        struct sockaddr_in in;
-        struct sockaddr_in6 in6;
-        struct sockaddr_un un;
-        struct sockaddr_nl nl;
-        struct sockaddr_ll ll;
-#if 0 /* NM_IGNORED */
-        struct sockaddr_vm vm;
-#endif /* NM_IGNORED */
-
-        /* Ensure there is enough space to store Infiniband addresses */
-        uint8_t ll_buffer[offsetof(struct sockaddr_ll, sll_addr) + CONST_MAX(ETH_ALEN, INFINIBAND_ALEN)];
-
-        /* Ensure there is enough space after the AF_UNIX sun_path for one more NUL byte, just to be sure that the path
-         * component is always followed by at least one NUL byte. */
-        uint8_t un_buffer[sizeof(struct sockaddr_un) + 1];
-};
-
-#define SUN_PATH_LEN (sizeof(((struct sockaddr_un){}).sun_path))
-
-typedef struct SocketAddress {
-        union sockaddr_union sockaddr;
-
-        /* We store the size here explicitly due to the weird
-         * sockaddr_un semantics for abstract sockets */
-        socklen_t size;
-
-        /* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */
-        int type;
-
-        /* Socket protocol, IPPROTO_xxx, usually 0, except for netlink */
-        int protocol;
-} SocketAddress;
-
-typedef enum SocketAddressBindIPv6Only {
-        SOCKET_ADDRESS_DEFAULT,
-        SOCKET_ADDRESS_BOTH,
-        SOCKET_ADDRESS_IPV6_ONLY,
-        _SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX,
-        _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -1
-} SocketAddressBindIPv6Only;
-
-#define socket_address_family(a) ((a)->sockaddr.sa.sa_family)
-
-const char* socket_address_type_to_string(int t) _const_;
-int socket_address_type_from_string(const char *s) _pure_;
-
-int sockaddr_un_unlink(const struct sockaddr_un *sa);
-
-static inline int socket_address_unlink(const SocketAddress *a) {
-        return socket_address_family(a) == AF_UNIX ? sockaddr_un_unlink(&a->sockaddr.un) : 0;
-}
-
-bool socket_address_can_accept(const SocketAddress *a) _pure_;
-
-int socket_address_listen(
-                const SocketAddress *a,
-                int flags,
-                int backlog,
-                SocketAddressBindIPv6Only only,
-                const char *bind_to_device,
-                bool reuse_port,
-                bool free_bind,
-                bool transparent,
-                mode_t directory_mode,
-                mode_t socket_mode,
-                const char *label);
-
-int socket_address_verify(const SocketAddress *a, bool strict) _pure_;
-int socket_address_print(const SocketAddress *a, char **p);
-bool socket_address_matches_fd(const SocketAddress *a, int fd);
-
-bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_;
-
-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);
-int getsockname_pretty(int fd, char **ret);
-
-int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret);
-
-const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_;
-SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_;
-SocketAddressBindIPv6Only socket_address_bind_ipv6_only_or_bool_from_string(const char *s);
-
-int netlink_family_to_string_alloc(int b, char **s);
-int netlink_family_from_string(const char *s) _pure_;
-
-bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b);
-
-int fd_set_sndbuf(int fd, size_t n, bool increase);
-static inline int fd_inc_sndbuf(int fd, size_t n) {
-        return fd_set_sndbuf(fd, n, true);
-}
-int fd_set_rcvbuf(int fd, size_t n, bool increase);
-static inline int fd_inc_rcvbuf(int fd, size_t n) {
-        return fd_set_rcvbuf(fd, n, true);
-}
-
-int ip_tos_to_string_alloc(int i, char **s);
-int ip_tos_from_string(const char *s);
-
-typedef enum {
-      IFNAME_VALID_ALTERNATIVE = 1 << 0,
-      IFNAME_VALID_NUMERIC     = 1 << 1,
-      _IFNAME_VALID_ALL        = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC,
-} IfnameValidFlags;
-bool ifname_valid_full(const char *p, IfnameValidFlags flags);
-static inline bool ifname_valid(const char *p) {
-        return ifname_valid_full(p, 0);
-}
-bool address_label_valid(const char *p);
-
-int getpeercred(int fd, struct ucred *ucred);
-int getpeersec(int fd, char **ret);
-int getpeergroups(int fd, gid_t **ret);
-
-ssize_t send_one_fd_iov_sa(
-                int transport_fd,
-                int fd,
-                struct iovec *iov, size_t iovlen,
-                const struct sockaddr *sa, socklen_t len,
-                int flags);
-int send_one_fd_sa(int transport_fd,
-                   int fd,
-                   const struct sockaddr *sa, socklen_t len,
-                   int flags);
-#define send_one_fd_iov(transport_fd, fd, iov, iovlen, flags) send_one_fd_iov_sa(transport_fd, fd, iov, iovlen, NULL, 0, flags)
-#define send_one_fd(transport_fd, fd, flags) send_one_fd_iov_sa(transport_fd, fd, NULL, 0, NULL, 0, flags)
-ssize_t receive_one_fd_iov(int transport_fd, struct iovec *iov, size_t iovlen, int flags, int *ret_fd);
-int receive_one_fd(int transport_fd, int flags);
-
-ssize_t next_datagram_size_fd(int fd);
-
-int flush_accept(int fd);
-
-#define CMSG_FOREACH(cmsg, mh)                                          \
-        for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
-
-struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
-
-/* Type-safe, dereferencing version of cmsg_find() */
-#define CMSG_FIND_DATA(mh, level, type, ctype) \
-        ({                                                            \
-                struct cmsghdr *_found;                               \
-                _found = cmsg_find(mh, level, type, CMSG_LEN(sizeof(ctype))); \
-                (ctype*) (_found ? CMSG_DATA(_found) : NULL);         \
-        })
-
-/* Resolves to a type that can carry cmsghdr structures. Make sure things are properly aligned, i.e. the type
- * itself is placed properly in memory and the size is also aligned to what's appropriate for "cmsghdr"
- * structures. */
-#define CMSG_BUFFER_TYPE(size)                                          \
-        union {                                                         \
-                struct cmsghdr cmsghdr;                                 \
-                uint8_t buf[size];                                      \
-                uint8_t align_check[(size) >= CMSG_SPACE(0) &&          \
-                                    (size) == CMSG_ALIGN(size) ? 1 : -1]; \
-        }
-
-/*
- * Certain hardware address types (e.g Infiniband) do not fit into sll_addr
- * (8 bytes) and run over the structure. This macro returns the correct size that
- * must be passed to kernel.
- */
-#define SOCKADDR_LL_LEN(sa)                                             \
-        ({                                                              \
-                const struct sockaddr_ll *_sa = &(sa);                  \
-                size_t _mac_len = sizeof(_sa->sll_addr);                \
-                assert(_sa->sll_family == AF_PACKET);                   \
-                if (be16toh(_sa->sll_hatype) == ARPHRD_ETHER)           \
-                        _mac_len = MAX(_mac_len, (size_t) ETH_ALEN);    \
-                if (be16toh(_sa->sll_hatype) == ARPHRD_INFINIBAND)      \
-                        _mac_len = MAX(_mac_len, (size_t) INFINIBAND_ALEN); \
-                offsetof(struct sockaddr_ll, sll_addr) + _mac_len;      \
-        })
-
-/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
-#define SOCKADDR_UN_LEN(sa)                                             \
-        ({                                                              \
-                const struct sockaddr_un *_sa = &(sa);                  \
-                assert(_sa->sun_family == AF_UNIX);                     \
-                offsetof(struct sockaddr_un, sun_path) +                \
-                        (_sa->sun_path[0] == 0 ?                        \
-                         1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \
-                         strnlen(_sa->sun_path, sizeof(_sa->sun_path))+1); \
-        })
-
-#define SOCKADDR_LEN(sa)                                                \
-        ({                                                              \
-                const union sockaddr_union *__sa = &(sa);               \
-                size_t _len;                                            \
-                switch(__sa->sa.sa_family) {                            \
-                case AF_INET:                                           \
-                        _len = sizeof(struct sockaddr_in);              \
-                        break;                                          \
-                case AF_INET6:                                          \
-                        _len = sizeof(struct sockaddr_in6);             \
-                        break;                                          \
-                case AF_UNIX:                                           \
-                        _len = SOCKADDR_UN_LEN(__sa->un);               \
-                        break;                                          \
-                case AF_PACKET:                                         \
-                        _len = SOCKADDR_LL_LEN(__sa->ll);               \
-                        break;                                          \
-                case AF_NETLINK:                                        \
-                        _len = sizeof(struct sockaddr_nl);              \
-                        break;                                          \
-                case AF_VSOCK:                                          \
-                        _len = sizeof(struct sockaddr_vm);              \
-                        break;                                          \
-                default:                                                \
-                        assert_not_reached("invalid socket family");    \
-                }                                                       \
-                _len;                                                   \
-        })
-
-int socket_ioctl_fd(void);
-
-int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path);
-
-static inline int setsockopt_int(int fd, int level, int optname, int value) {
-        if (setsockopt(fd, level, optname, &value, sizeof(value)) < 0)
-                return -errno;
-
-        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);
-
-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_unicast_if(int fd, int af, int ifi);
-
-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
deleted file mode 100644
index a8984fc1..00000000
--- a/shared/systemd/src/basic/sort-util.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdlib.h>
-
-#include "macro.h"
-
-void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
-                 __compar_d_fn_t compar, void *arg);
-
-#define typesafe_bsearch_r(k, b, n, func, userdata)                     \
-        ({                                                              \
-                const typeof(b[0]) *_k = k;                             \
-                int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
-                xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
-        })
-
-/**
- * Normal bsearch requires base to be nonnull. Here were require
- * that only if nmemb > 0.
- */
-static inline void* bsearch_safe(const void *key, const void *base,
-                                 size_t nmemb, size_t size, __compar_fn_t compar) {
-        if (nmemb <= 0)
-                return NULL;
-
-        assert(base);
-        return bsearch(key, base, nmemb, size, compar);
-}
-
-#define typesafe_bsearch(k, b, n, func)                                 \
-        ({                                                              \
-                const typeof(b[0]) *_k = k;                             \
-                int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
-                bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
-        })
-
-/**
- * Normal qsort requires base to be nonnull. Here were require
- * that only if nmemb > 0.
- */
-static inline void _qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
-        if (nmemb <= 1)
-                return;
-
-        assert(base);
-        qsort(base, nmemb, size, compar);
-}
-
-/* A wrapper around the above, but that adds typesafety: the element size is automatically derived from the type and so
- * is the prototype for the comparison function */
-#define typesafe_qsort(p, n, func)                                      \
-        ({                                                              \
-                int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
-                _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;
-
-        assert(base);
-        qsort_r(base, nmemb, size, compar, userdata);
-}
-
-#define typesafe_qsort_r(p, n, func, userdata)                          \
-        ({                                                              \
-                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/sparse-endian.h b/shared/systemd/src/basic/sparse-endian.h
deleted file mode 100644
index 9583dda9..00000000
--- a/shared/systemd/src/basic/sparse-endian.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: MIT
- *
- * Copyright (c) 2012 Josh Triplett <josh@joshtriplett.org>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#pragma once
-
-#include <byteswap.h>
-#include <endian.h>
-#include <stdint.h>
-
-#ifdef __CHECKER__
-#define __sd_bitwise __attribute__((__bitwise__))
-#define __sd_force __attribute__((__force__))
-#else
-#define __sd_bitwise
-#define __sd_force
-#endif
-
-typedef uint16_t __sd_bitwise le16_t;
-typedef uint16_t __sd_bitwise be16_t;
-typedef uint32_t __sd_bitwise le32_t;
-typedef uint32_t __sd_bitwise be32_t;
-typedef uint64_t __sd_bitwise le64_t;
-typedef uint64_t __sd_bitwise be64_t;
-
-#undef htobe16
-#undef htole16
-#undef be16toh
-#undef le16toh
-#undef htobe32
-#undef htole32
-#undef be32toh
-#undef le32toh
-#undef htobe64
-#undef htole64
-#undef be64toh
-#undef le64toh
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define bswap_16_on_le(x) __bswap_16(x)
-#define bswap_32_on_le(x) __bswap_32(x)
-#define bswap_64_on_le(x) __bswap_64(x)
-#define bswap_16_on_be(x) (x)
-#define bswap_32_on_be(x) (x)
-#define bswap_64_on_be(x) (x)
-#elif __BYTE_ORDER == __BIG_ENDIAN
-#define bswap_16_on_le(x) (x)
-#define bswap_32_on_le(x) (x)
-#define bswap_64_on_le(x) (x)
-#define bswap_16_on_be(x) __bswap_16(x)
-#define bswap_32_on_be(x) __bswap_32(x)
-#define bswap_64_on_be(x) __bswap_64(x)
-#endif
-
-static inline le16_t htole16(uint16_t value) { return (le16_t __sd_force) bswap_16_on_be(value); }
-static inline le32_t htole32(uint32_t value) { return (le32_t __sd_force) bswap_32_on_be(value); }
-static inline le64_t htole64(uint64_t value) { return (le64_t __sd_force) bswap_64_on_be(value); }
-
-static inline be16_t htobe16(uint16_t value) { return (be16_t __sd_force) bswap_16_on_le(value); }
-static inline be32_t htobe32(uint32_t value) { return (be32_t __sd_force) bswap_32_on_le(value); }
-static inline be64_t htobe64(uint64_t value) { return (be64_t __sd_force) bswap_64_on_le(value); }
-
-static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __sd_force)value); }
-static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __sd_force)value); }
-static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __sd_force)value); }
-
-static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __sd_force)value); }
-static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __sd_force)value); }
-static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __sd_force)value); }
-
-#undef __sd_bitwise
-#undef __sd_force
diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c
deleted file mode 100644
index a9880096..00000000
--- a/shared/systemd/src/basic/stat-util.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <sys/statvfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "dirent-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "macro.h"
-#include "missing_fs.h"
-#include "missing_magic.h"
-#include "missing_syscall.h"
-#include "parse-util.h"
-#include "stat-util.h"
-#include "string-util.h"
-
-#if 0 /* NM_IGNORED */
-int is_symlink(const char *path) {
-        struct stat info;
-
-        assert(path);
-
-        if (lstat(path, &info) < 0)
-                return -errno;
-
-        return !!S_ISLNK(info.st_mode);
-}
-#endif /* NM_IGNORED */
-
-int is_dir(const char* path, bool follow) {
-        struct stat st;
-        int r;
-
-        assert(path);
-
-        if (follow)
-                r = stat(path, &st);
-        else
-                r = lstat(path, &st);
-        if (r < 0)
-                return -errno;
-
-        return !!S_ISDIR(st.st_mode);
-}
-
-#if 0 /* NM_IGNORED */
-int is_dir_fd(int fd) {
-        struct stat st;
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        return !!S_ISDIR(st.st_mode);
-}
-
-int is_device_node(const char *path) {
-        struct stat info;
-
-        assert(path);
-
-        if (lstat(path, &info) < 0)
-                return -errno;
-
-        return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
-}
-
-int dir_is_empty_at(int dir_fd, const char *path) {
-        _cleanup_close_ int fd = -1;
-        _cleanup_closedir_ DIR *d = NULL;
-        struct dirent *de;
-
-        if (path)
-                fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
-        else
-                fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-        if (fd < 0)
-                return -errno;
-
-        d = take_fdopendir(&fd);
-        if (!d)
-                return -errno;
-
-        FOREACH_DIRENT(de, d, return -errno)
-                return 0;
-
-        return 1;
-}
-
-bool null_or_empty(struct stat *st) {
-        assert(st);
-
-        if (S_ISREG(st->st_mode) && st->st_size <= 0)
-                return true;
-
-        /* We don't want to hardcode the major/minor of /dev/null, hence we do a simpler "is this a character
-         * device node?" check. */
-
-        if (S_ISCHR(st->st_mode))
-                return true;
-
-        return false;
-}
-
-int null_or_empty_path(const char *fn) {
-        struct stat st;
-
-        assert(fn);
-
-        /* If we have the path, let's do an easy text comparison first. */
-        if (path_equal(fn, "/dev/null"))
-                return true;
-
-        if (stat(fn, &st) < 0)
-                return -errno;
-
-        return null_or_empty(&st);
-}
-
-int null_or_empty_fd(int fd) {
-        struct stat st;
-
-        assert(fd >= 0);
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        return null_or_empty(&st);
-}
-
-int path_is_read_only_fs(const char *path) {
-        struct statvfs st;
-
-        assert(path);
-
-        if (statvfs(path, &st) < 0)
-                return -errno;
-
-        if (st.f_flag & ST_RDONLY)
-                return true;
-
-        /* On NFS, statvfs() might not reflect whether we can actually
-         * write to the remote share. Let's try again with
-         * access(W_OK) which is more reliable, at least sometimes. */
-        if (access(path, W_OK) < 0 && errno == EROFS)
-                return true;
-
-        return false;
-}
-
-int files_same(const char *filea, const char *fileb, int flags) {
-        struct stat a, b;
-
-        assert(filea);
-        assert(fileb);
-
-        if (fstatat(AT_FDCWD, filea, &a, flags) < 0)
-                return -errno;
-
-        if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
-                return -errno;
-
-        return a.st_dev == b.st_dev &&
-               a.st_ino == b.st_ino;
-}
-
-bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
-        assert(s);
-        assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
-
-        return F_TYPE_EQUAL(s->f_type, magic_value);
-}
-
-int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
-        struct statfs s;
-
-        if (fstatfs(fd, &s) < 0)
-                return -errno;
-
-        return is_fs_type(&s, magic_value);
-}
-
-int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
-        struct statfs s;
-
-        if (statfs(path, &s) < 0)
-                return -errno;
-
-        return is_fs_type(&s, magic_value);
-}
-
-bool is_temporary_fs(const struct statfs *s) {
-        return is_fs_type(s, TMPFS_MAGIC) ||
-                is_fs_type(s, RAMFS_MAGIC);
-}
-
-bool is_network_fs(const struct statfs *s) {
-        return is_fs_type(s, CIFS_MAGIC_NUMBER) ||
-                is_fs_type(s, CODA_SUPER_MAGIC) ||
-                is_fs_type(s, NCP_SUPER_MAGIC) ||
-                is_fs_type(s, NFS_SUPER_MAGIC) ||
-                is_fs_type(s, SMB_SUPER_MAGIC) ||
-                is_fs_type(s, V9FS_MAGIC) ||
-                is_fs_type(s, AFS_SUPER_MAGIC) ||
-                is_fs_type(s, OCFS2_SUPER_MAGIC);
-}
-
-int fd_is_temporary_fs(int fd) {
-        struct statfs s;
-
-        if (fstatfs(fd, &s) < 0)
-                return -errno;
-
-        return is_temporary_fs(&s);
-}
-
-int fd_is_network_fs(int fd) {
-        struct statfs s;
-
-        if (fstatfs(fd, &s) < 0)
-                return -errno;
-
-        return is_network_fs(&s);
-}
-
-int path_is_temporary_fs(const char *path) {
-        struct statfs s;
-
-        if (statfs(path, &s) < 0)
-                return -errno;
-
-        return is_temporary_fs(&s);
-}
-#endif /* NM_IGNORED */
-
-int stat_verify_regular(const struct stat *st) {
-        assert(st);
-
-        /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
-         * code. */
-
-        if (S_ISDIR(st->st_mode))
-                return -EISDIR;
-
-        if (S_ISLNK(st->st_mode))
-                return -ELOOP;
-
-        if (!S_ISREG(st->st_mode))
-                return -EBADFD;
-
-        return 0;
-}
-
-int fd_verify_regular(int fd) {
-        struct stat st;
-
-        assert(fd >= 0);
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        return stat_verify_regular(&st);
-}
-
-#if 0 /* NM_IGNORED */
-int stat_verify_directory(const struct stat *st) {
-        assert(st);
-
-        if (S_ISLNK(st->st_mode))
-                return -ELOOP;
-
-        if (!S_ISDIR(st->st_mode))
-                return -ENOTDIR;
-
-        return 0;
-}
-
-int fd_verify_directory(int fd) {
-        struct stat st;
-
-        assert(fd >= 0);
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        return stat_verify_directory(&st);
-}
-
-int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) {
-        const char *t;
-
-        /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
-
-        if (S_ISCHR(mode))
-                t = "char";
-        else if (S_ISBLK(mode))
-                t = "block";
-        else
-                return -ENODEV;
-
-        if (asprintf(ret, "/dev/%s/%u:%u", t, major(devno), minor(devno)) < 0)
-                return -ENOMEM;
-
-        return 0;
-}
-
-int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) {
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
-
-        assert(ret);
-
-        if (major(devno) == 0 && minor(devno) == 0) {
-                char *s;
-
-                /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
-                 * /dev/block/ and /dev/char/, hence we handle them specially here. */
-
-                if (S_ISCHR(mode))
-                        s = strdup("/run/systemd/inaccessible/chr");
-                else if (S_ISBLK(mode))
-                        s = strdup("/run/systemd/inaccessible/blk");
-                else
-                        return -ENODEV;
-
-                if (!s)
-                        return -ENOMEM;
-
-                *ret = s;
-                return 0;
-        }
-
-        r = device_path_make_major_minor(mode, devno, &p);
-        if (r < 0)
-                return r;
-
-        return chase_symlinks(p, NULL, 0, ret, NULL);
-}
-
-int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) {
-        mode_t mode;
-        dev_t devno;
-        int r;
-
-        /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
-         * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
-         * path cannot be parsed like this.  */
-
-        if (path_equal(path, "/run/systemd/inaccessible/chr")) {
-                mode = S_IFCHR;
-                devno = makedev(0, 0);
-        } else if (path_equal(path, "/run/systemd/inaccessible/blk")) {
-                mode = S_IFBLK;
-                devno = makedev(0, 0);
-        } else {
-                const char *w;
-
-                w = path_startswith(path, "/dev/block/");
-                if (w)
-                        mode = S_IFBLK;
-                else {
-                        w = path_startswith(path, "/dev/char/");
-                        if (!w)
-                                return -ENODEV;
-
-                        mode = S_IFCHR;
-                }
-
-                r = parse_dev(w, &devno);
-                if (r < 0)
-                        return r;
-        }
-
-        if (ret_mode)
-                *ret_mode = mode;
-        if (ret_devno)
-                *ret_devno = devno;
-
-        return 0;
-}
-
-int proc_mounted(void) {
-        int r;
-
-        /* A quick check of procfs is properly mounted */
-
-        r = path_is_fs_type("/proc/", PROC_SUPER_MAGIC);
-        if (r == -ENOENT) /* not mounted at all */
-                return false;
-
-        return r;
-}
-
-bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
-
-        /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
-         * be reasonably careful when detecting changes: we check both inode and mtime, to cater for file
-         * systems where mtimes are fixed to 0 (think: ostree/nixos type installations). We also check file
-         * size, backing device, inode type and if this refers to a device not the major/minor.
-         *
-         * Note that we don't care if file attributes such as ownership or access mode change, this here is
-         * about contents of the file. The purpose here is to detect file contents changes, and nothing
-         * else. */
-
-        return a && b &&
-                (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
-                ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 &&  /* same inode type */
-                a->st_mtim.tv_sec == b->st_mtim.tv_sec &&
-                a->st_mtim.tv_nsec == b->st_mtim.tv_nsec &&
-                (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
-                a->st_dev == b->st_dev &&
-                a->st_ino == b->st_ino &&
-                (!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
-}
-
-int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) {
-        static bool avoid_statx = false;
-        struct stat st;
-
-        if (!avoid_statx) {
-                if (statx(dfd, path, flags, mask, sx) < 0) {
-                        if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EPERM)
-                                return -errno;
-
-                        /* If statx() is not supported or if we see EPERM (which might indicate seccomp
-                         * filtering or so), let's do a fallback. Not that on EACCES we'll not fall back,
-                         * since that is likely an indication of fs access issues, which we should
-                         * propagate */
-                } else
-                        return 0;
-
-                avoid_statx = true;
-        }
-
-        /* Only do fallback if fstatat() supports the flag too, or if it's one of the sync flags, which are
-         * OK to ignore */
-        if ((flags & ~(AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW|
-                      AT_STATX_SYNC_AS_STAT|AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC)) != 0)
-                return -EOPNOTSUPP;
-
-        if (fstatat(dfd, path, &st, flags & (AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW)) < 0)
-                return -errno;
-
-        *sx = (struct statx) {
-                .stx_mask = STATX_TYPE|STATX_MODE|
-                STATX_NLINK|STATX_UID|STATX_GID|
-                STATX_ATIME|STATX_MTIME|STATX_CTIME|
-                STATX_INO|STATX_SIZE|STATX_BLOCKS,
-                .stx_blksize = st.st_blksize,
-                .stx_nlink = st.st_nlink,
-                .stx_uid = st.st_uid,
-                .stx_gid = st.st_gid,
-                .stx_mode = st.st_mode,
-                .stx_ino = st.st_ino,
-                .stx_size = st.st_size,
-                .stx_blocks = st.st_blocks,
-                .stx_rdev_major = major(st.st_rdev),
-                .stx_rdev_minor = minor(st.st_rdev),
-                .stx_dev_major = major(st.st_dev),
-                .stx_dev_minor = minor(st.st_dev),
-                .stx_atime.tv_sec = st.st_atim.tv_sec,
-                .stx_atime.tv_nsec = st.st_atim.tv_nsec,
-                .stx_mtime.tv_sec = st.st_mtim.tv_sec,
-                .stx_mtime.tv_nsec = st.st_mtim.tv_nsec,
-                .stx_ctime.tv_sec = st.st_ctim.tv_sec,
-                .stx_ctime.tv_nsec = st.st_ctim.tv_nsec,
-        };
-
-        return 0;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/stat-util.h b/shared/systemd/src/basic/stat-util.h
deleted file mode 100644
index a566114f..00000000
--- a/shared/systemd/src/basic/stat-util.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <sys/vfs.h>
-
-#include "macro.h"
-#include "missing_stat.h"
-
-int is_symlink(const char *path);
-int is_dir(const char *path, bool follow);
-int is_dir_fd(int fd);
-int is_device_node(const char *path);
-
-int dir_is_empty_at(int dir_fd, const char *path);
-static inline int dir_is_empty(const char *path) {
-        return dir_is_empty_at(AT_FDCWD, path);
-}
-
-static inline int dir_is_populated(const char *path) {
-        int r;
-        r = dir_is_empty(path);
-        if (r < 0)
-                return r;
-        return !r;
-}
-
-bool null_or_empty(struct stat *st) _pure_;
-int null_or_empty_path(const char *fn);
-int null_or_empty_fd(int fd);
-
-int path_is_read_only_fs(const char *path);
-
-int files_same(const char *filea, const char *fileb, int flags);
-
-/* The .f_type field of struct statfs is really weird defined on
- * different archs. Let's give its type a name. */
-typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t;
-
-bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_;
-int fd_is_fs_type(int fd, statfs_f_type_t magic_value);
-int path_is_fs_type(const char *path, statfs_f_type_t magic_value);
-
-bool is_temporary_fs(const struct statfs *s) _pure_;
-bool is_network_fs(const struct statfs *s) _pure_;
-
-int fd_is_temporary_fs(int fd);
-int fd_is_network_fs(int fd);
-
-int path_is_temporary_fs(const char *path);
-
-/* Because statfs.t_type can be int on some architectures, we have to cast
- * the const magic to the type, otherwise the compiler warns about
- * signed/unsigned comparison, because the magic can be 32 bit unsigned.
- */
-#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
-
-int stat_verify_regular(const struct stat *st);
-int fd_verify_regular(int fd);
-
-int stat_verify_directory(const struct stat *st);
-int fd_verify_directory(int fd);
-
-/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the
- * specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of
- * major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of
- * comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as
- * such a test would be pointless in such a case.) */
-
-#define DEVICE_MAJOR_VALID(x)                                           \
-        ({                                                              \
-                typeof(x) _x = (x), _y = 0;                             \
-                _x >= _y && _x < (UINT32_C(1) << 12);                   \
-                                                                        \
-        })
-
-#define DEVICE_MINOR_VALID(x)                                           \
-        ({                                                              \
-                typeof(x) _x = (x), _y = 0;                             \
-                _x >= _y && _x < (UINT32_C(1) << 20);                   \
-        })
-
-int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret);
-int device_path_make_canonical(mode_t mode, dev_t devno, char **ret);
-int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno);
-
-int proc_mounted(void);
-
-bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
-
-int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx);
-
-#if HAS_FEATURE_MEMORY_SANITIZER
-#  warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
-#  define STRUCT_STATX_DEFINE(var)              \
-        struct statx var = {}
-#  define STRUCT_NEW_STATX_DEFINE(var)          \
-        union {                                 \
-                struct statx sx;                \
-                struct new_statx nsx;           \
-        } var = {}
-#else
-#  define STRUCT_STATX_DEFINE(var)              \
-        struct statx var
-#  define STRUCT_NEW_STATX_DEFINE(var)          \
-        union {                                 \
-                struct statx sx;                \
-                struct new_statx nsx;           \
-        } var
-#endif
diff --git a/shared/systemd/src/basic/stdio-util.h b/shared/systemd/src/basic/stdio-util.h
deleted file mode 100644
index d45d3c1a..00000000
--- a/shared/systemd/src/basic/stdio-util.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* 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>
-
-#include "macro.h"
-#include "memory-util.h"
-
-#define snprintf_ok(buf, len, fmt, ...) \
-        ((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len))
-
-#define xsprintf(buf, fmt, ...) \
-        assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__), "xsprintf: " #buf "[] must be big enough")
-
-#define VA_FORMAT_ADVANCE(format, ap)                                   \
-do {                                                                    \
-        int _argtypes[128];                                             \
-        size_t _i, _k;                                                  \
-        /* See https://github.com/google/sanitizers/issues/992 */       \
-        if (HAS_FEATURE_MEMORY_SANITIZER)                               \
-                zero(_argtypes);                                        \
-        _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
-        assert(_k < ELEMENTSOF(_argtypes));                             \
-        for (_i = 0; _i < _k; _i++) {                                   \
-                if (_argtypes[_i] & PA_FLAG_PTR)  {                     \
-                        (void) va_arg(ap, void*);                       \
-                        continue;                                       \
-                }                                                       \
-                                                                        \
-                switch (_argtypes[_i]) {                                \
-                case PA_INT:                                            \
-                case PA_INT|PA_FLAG_SHORT:                              \
-                case PA_CHAR:                                           \
-                        (void) va_arg(ap, int);                         \
-                        break;                                          \
-                case PA_INT|PA_FLAG_LONG:                               \
-                        (void) va_arg(ap, long int);                    \
-                        break;                                          \
-                case PA_INT|PA_FLAG_LONG_LONG:                          \
-                        (void) va_arg(ap, long long int);               \
-                        break;                                          \
-                case PA_WCHAR:                                          \
-                        (void) va_arg(ap, wchar_t);                     \
-                        break;                                          \
-                case PA_WSTRING:                                        \
-                case PA_STRING:                                         \
-                case PA_POINTER:                                        \
-                        (void) va_arg(ap, void*);                       \
-                        break;                                          \
-                case PA_FLOAT:                                          \
-                case PA_DOUBLE:                                         \
-                        (void) va_arg(ap, double);                      \
-                        break;                                          \
-                case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:                     \
-                        (void) va_arg(ap, long double);                 \
-                        break;                                          \
-                default:                                                \
-                        assert_not_reached("Unknown format string argument."); \
-                }                                                       \
-        }                                                               \
-} while (false)
diff --git a/shared/systemd/src/basic/string-table.c b/shared/systemd/src/basic/string-table.c
deleted file mode 100644
index bd8047e6..00000000
--- a/shared/systemd/src/basic/string-table.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include "string-table.h"
-#include "string-util.h"
-
-ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
-        if (!key)
-                return -1;
-
-        for (size_t i = 0; i < len; ++i)
-                if (streq_ptr(table[i], key))
-                        return (ssize_t) i;
-
-        return -1;
-}
diff --git a/shared/systemd/src/basic/string-table.h b/shared/systemd/src/basic/string-table.h
deleted file mode 100644
index ae4ea145..00000000
--- a/shared/systemd/src/basic/string-table.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#pragma once
-
-#include <errno.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <sys/types.h>
-
-#include "macro.h"
-#include "parse-util.h"
-#include "string-util.h"
-
-ssize_t string_table_lookup(const char * const *table, size_t len, const char *key);
-
-/* For basic lookup tables with strictly enumerated entries */
-#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
-        scope const char *name##_to_string(type i) {                    \
-                if (i < 0 || i >= (type) ELEMENTSOF(name##_table))      \
-                        return NULL;                                    \
-                return name##_table[i];                                 \
-        }
-
-#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope)        \
-        scope type name##_from_string(const char *s) {                  \
-                return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
-        }
-
-#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
-        scope type name##_from_string(const char *s) {                  \
-                if (!s)                                                 \
-                        return -1;                                      \
-                int b = parse_boolean(s);                               \
-                if (b == 0)                                             \
-                        return (type) 0;                                \
-                if (b > 0)                                              \
-                        return yes;                                     \
-                return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
-        }
-
-#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,scope) \
-        scope int name##_to_string_alloc(type i, char **str) {          \
-                char *s;                                                \
-                if (i < 0 || i > max)                                   \
-                        return -ERANGE;                                 \
-                if (i < (type) ELEMENTSOF(name##_table) && name##_table[i]) { \
-                        s = strdup(name##_table[i]);                    \
-                        if (!s)                                         \
-                                return -ENOMEM;                         \
-                } else {                                                \
-                        if (asprintf(&s, "%i", i) < 0)                  \
-                                return -ENOMEM;                         \
-                }                                                       \
-                *str = s;                                               \
-                return 0;                                               \
-        }
-
-#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \
-        scope type name##_from_string(const char *s) {                  \
-                unsigned u = 0;                                         \
-                type i;                                                 \
-                if (!s)                                                 \
-                        return (type) -1;                               \
-                i = (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
-                if (i >= 0)                                             \
-                        return i;                                       \
-                if (safe_atou(s, &u) >= 0 && u <= max)                  \
-                        return (type) u;                                \
-                return (type) -1;                                       \
-        }                                                               \
-
-#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope)                    \
-        _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
-        _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope)
-
-#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope)   \
-        _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
-        _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)         \
-        _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,)  \
-        _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,)
-
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \
-        _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max) \
-        _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static)
-
-#define DUMP_STRING_TABLE(name,type,max)                                \
-        do {                                                            \
-                type _k;                                                \
-                flockfile(stdout);                                      \
-                for (_k = 0; _k < (max); _k++) {                        \
-                        const char *_t;                                 \
-                        _t = name##_to_string(_k);                      \
-                        if (!_t)                                        \
-                                continue;                               \
-                        fputs_unlocked(_t, stdout);                     \
-                        fputc_unlocked('\n', stdout);                   \
-                }                                                       \
-                funlockfile(stdout);                                    \
-        } while(false)
diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c
deleted file mode 100644
index 744a3606..00000000
--- a/shared/systemd/src/basic/string-util.c
+++ /dev/null
@@ -1,1146 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "alloc-util.h"
-#include "escape.h"
-#include "extract-word.h"
-#include "fileio.h"
-#include "gunicode.h"
-#include "locale-util.h"
-#include "macro.h"
-#include "memory-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "terminal-util.h"
-#include "utf8.h"
-#include "util.h"
-
-int strcmp_ptr(const char *a, const char *b) {
-        /* Like strcmp(), but tries to make sense of NULL pointers */
-
-        if (a && b)
-                return strcmp(a, b);
-        return CMP(a, b); /* Direct comparison of pointers, one of which is NULL */
-}
-
-int strcasecmp_ptr(const char *a, const char *b) {
-        /* Like strcasecmp(), but tries to make sense of NULL pointers */
-
-        if (a && b)
-                return strcasecmp(a, b);
-        return CMP(a, b); /* Direct comparison of pointers, one of which is NULL */
-}
-
-char* endswith(const char *s, const char *postfix) {
-        size_t sl, pl;
-
-        assert(s);
-        assert(postfix);
-
-        sl = strlen(s);
-        pl = strlen(postfix);
-
-        if (pl == 0)
-                return (char*) s + sl;
-
-        if (sl < pl)
-                return NULL;
-
-        if (memcmp(s + sl - pl, postfix, pl) != 0)
-                return NULL;
-
-        return (char*) s + sl - pl;
-}
-
-char* endswith_no_case(const char *s, const char *postfix) {
-        size_t sl, pl;
-
-        assert(s);
-        assert(postfix);
-
-        sl = strlen(s);
-        pl = strlen(postfix);
-
-        if (pl == 0)
-                return (char*) s + sl;
-
-        if (sl < pl)
-                return NULL;
-
-        if (strcasecmp(s + sl - pl, postfix) != 0)
-                return NULL;
-
-        return (char*) s + sl - pl;
-}
-
-char* first_word(const char *s, const char *word) {
-        size_t sl, wl;
-        const char *p;
-
-        assert(s);
-        assert(word);
-
-        /* Checks if the string starts with the specified word, either
-         * followed by NUL or by whitespace. Returns a pointer to the
-         * NUL or the first character after the whitespace. */
-
-        sl = strlen(s);
-        wl = strlen(word);
-
-        if (sl < wl)
-                return NULL;
-
-        if (wl == 0)
-                return (char*) s;
-
-        if (memcmp(s, word, wl) != 0)
-                return NULL;
-
-        p = s + wl;
-        if (*p == 0)
-                return (char*) p;
-
-        if (!strchr(WHITESPACE, *p))
-                return NULL;
-
-        p += strspn(p, WHITESPACE);
-        return (char*) p;
-}
-
-char *strnappend(const char *s, const char *suffix, size_t b) {
-        size_t a;
-        char *r;
-
-        if (!s && !suffix)
-                return strdup("");
-
-        if (!s)
-                return strndup(suffix, b);
-
-        if (!suffix)
-                return strdup(s);
-
-        assert(s);
-        assert(suffix);
-
-        a = strlen(s);
-        if (b > ((size_t) -1) - a)
-                return NULL;
-
-        r = new(char, a+b+1);
-        if (!r)
-                return NULL;
-
-        memcpy(r, s, a);
-        memcpy(r+a, suffix, b);
-        r[a+b] = 0;
-
-        return r;
-}
-
-char *strjoin_real(const char *x, ...) {
-        va_list ap;
-        size_t l = 1;
-        char *r, *p;
-
-        va_start(ap, x);
-        for (const char *t = x; t; t = va_arg(ap, const char *)) {
-                size_t n;
-
-                n = strlen(t);
-                if (n > SIZE_MAX - l) {
-                        va_end(ap);
-                        return NULL;
-                }
-                l += n;
-        }
-        va_end(ap);
-
-        p = r = new(char, l);
-        if (!r)
-                return NULL;
-
-        va_start(ap, x);
-        for (const char *t = x; t; t = va_arg(ap, const char *))
-                p = stpcpy(p, t);
-        va_end(ap);
-
-        *p = 0;
-
-        return r;
-}
-
-#if 0 /* NM_IGNORED */
-char *strstrip(char *s) {
-        if (!s)
-                return NULL;
-
-        /* Drops trailing whitespace. Modifies the string in place. Returns pointer to first non-space character */
-
-        return delete_trailing_chars(skip_leading_chars(s, WHITESPACE), WHITESPACE);
-}
-
-char *delete_chars(char *s, const char *bad) {
-        char *f, *t;
-
-        /* Drops all specified bad characters, regardless where in the string */
-
-        if (!s)
-                return NULL;
-
-        if (!bad)
-                bad = WHITESPACE;
-
-        for (f = s, t = s; *f; f++) {
-                if (strchr(bad, *f))
-                        continue;
-
-                *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return s;
-}
-
-char *delete_trailing_chars(char *s, const char *bad) {
-        char *p, *c = s;
-
-        /* Drops all specified bad characters, at the end of the string */
-
-        if (!s)
-                return NULL;
-
-        if (!bad)
-                bad = WHITESPACE;
-
-        for (p = s; *p; p++)
-                if (!strchr(bad, *p))
-                        c = p + 1;
-
-        *c = 0;
-
-        return s;
-}
-#endif /* NM_IGNORED */
-
-char *truncate_nl(char *s) {
-        assert(s);
-
-        s[strcspn(s, NEWLINE)] = 0;
-        return s;
-}
-
-char ascii_tolower(char x) {
-
-        if (x >= 'A' && x <= 'Z')
-                return x - 'A' + 'a';
-
-        return x;
-}
-
-char ascii_toupper(char x) {
-
-        if (x >= 'a' && x <= 'z')
-                return x - 'a' + 'A';
-
-        return x;
-}
-
-char *ascii_strlower(char *t) {
-        char *p;
-
-        assert(t);
-
-        for (p = t; *p; p++)
-                *p = ascii_tolower(*p);
-
-        return t;
-}
-
-char *ascii_strupper(char *t) {
-        char *p;
-
-        assert(t);
-
-        for (p = t; *p; p++)
-                *p = ascii_toupper(*p);
-
-        return t;
-}
-
-char *ascii_strlower_n(char *t, size_t n) {
-        size_t i;
-
-        if (n <= 0)
-                return t;
-
-        for (i = 0; i < n; i++)
-                t[i] = ascii_tolower(t[i]);
-
-        return t;
-}
-
-int ascii_strcasecmp_n(const char *a, const char *b, size_t n) {
-
-        for (; n > 0; a++, b++, n--) {
-                int x, y;
-
-                x = (int) (uint8_t) ascii_tolower(*a);
-                y = (int) (uint8_t) ascii_tolower(*b);
-
-                if (x != y)
-                        return x - y;
-        }
-
-        return 0;
-}
-
-int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m) {
-        int r;
-
-        r = ascii_strcasecmp_n(a, b, MIN(n, m));
-        if (r != 0)
-                return r;
-
-        return CMP(n, m);
-}
-
-bool chars_intersect(const char *a, const char *b) {
-        const char *p;
-
-        /* Returns true if any of the chars in a are in b. */
-        for (p = a; *p; p++)
-                if (strchr(b, *p))
-                        return true;
-
-        return false;
-}
-
-bool string_has_cc(const char *p, const char *ok) {
-        const char *t;
-
-        assert(p);
-
-        /*
-         * Check if a string contains control characters. If 'ok' is
-         * non-NULL it may be a string containing additional CCs to be
-         * considered OK.
-         */
-
-        for (t = p; *t; t++) {
-                if (ok && strchr(ok, *t))
-                        continue;
-
-                if (*t > 0 && *t < ' ')
-                        return true;
-
-                if (*t == 127)
-                        return true;
-        }
-
-        return false;
-}
-
-#if 0 /* NM_IGNORED */
-static int write_ellipsis(char *buf, bool unicode) {
-        if (unicode || is_locale_utf8()) {
-                buf[0] = 0xe2; /* tri-dot ellipsis: … */
-                buf[1] = 0x80;
-                buf[2] = 0xa6;
-        } else {
-                buf[0] = '.';
-                buf[1] = '.';
-                buf[2] = '.';
-        }
-
-        return 3;
-}
-
-static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
-        size_t x, need_space, suffix_len;
-        char *t;
-
-        assert(s);
-        assert(percent <= 100);
-        assert(new_length != (size_t) -1);
-
-        if (old_length <= new_length)
-                return strndup(s, old_length);
-
-        /* Special case short ellipsations */
-        switch (new_length) {
-
-        case 0:
-                return strdup("");
-
-        case 1:
-                if (is_locale_utf8())
-                        return strdup("…");
-                else
-                        return strdup(".");
-
-        case 2:
-                if (!is_locale_utf8())
-                        return strdup("..");
-
-                break;
-
-        default:
-                break;
-        }
-
-        /* Calculate how much space the ellipsis will take up. If we are in UTF-8 mode we only need space for one
-         * character ("…"), otherwise for three characters ("..."). Note that in both cases we need 3 bytes of storage,
-         * either for the UTF-8 encoded character or for three ASCII characters. */
-        need_space = is_locale_utf8() ? 1 : 3;
-
-        t = new(char, new_length+3);
-        if (!t)
-                return NULL;
-
-        assert(new_length >= need_space);
-
-        x = ((new_length - need_space) * percent + 50) / 100;
-        assert(x <= new_length - need_space);
-
-        memcpy(t, s, x);
-        write_ellipsis(t + x, false);
-        suffix_len = new_length - x - need_space;
-        memcpy(t + x + 3, s + old_length - suffix_len, suffix_len);
-        *(t + x + 3 + suffix_len) = '\0';
-
-        return t;
-}
-
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
-        size_t x, k, len, len2;
-        const char *i, *j;
-        char *e;
-        int r;
-
-        /* Note that 'old_length' refers to bytes in the string, while 'new_length' refers to character cells taken up
-         * on screen. This distinction doesn't matter for ASCII strings, but it does matter for non-ASCII UTF-8
-         * strings.
-         *
-         * Ellipsation is done in a locale-dependent way:
-         * 1. If the string passed in is fully ASCII and the current locale is not UTF-8, three dots are used ("...")
-         * 2. Otherwise, a unicode ellipsis is used ("…")
-         *
-         * In other words: you'll get a unicode ellipsis as soon as either the string contains non-ASCII characters or
-         * the current locale is UTF-8.
-         */
-
-        assert(s);
-        assert(percent <= 100);
-
-        if (new_length == (size_t) -1)
-                return strndup(s, old_length);
-
-        if (new_length == 0)
-                return strdup("");
-
-        /* If no multibyte characters use ascii_ellipsize_mem for speed */
-        if (ascii_is_valid_n(s, old_length))
-                return ascii_ellipsize_mem(s, old_length, new_length, percent);
-
-        x = ((new_length - 1) * percent) / 100;
-        assert(x <= new_length - 1);
-
-        k = 0;
-        for (i = s; i < s + old_length; i = utf8_next_char(i)) {
-                char32_t c;
-                int w;
-
-                r = utf8_encoded_to_unichar(i, &c);
-                if (r < 0)
-                        return NULL;
-
-                w = unichar_iswide(c) ? 2 : 1;
-                if (k + w <= x)
-                        k += w;
-                else
-                        break;
-        }
-
-        for (j = s + old_length; j > i; ) {
-                char32_t c;
-                int w;
-                const char *jj;
-
-                jj = utf8_prev_char(j);
-                r = utf8_encoded_to_unichar(jj, &c);
-                if (r < 0)
-                        return NULL;
-
-                w = unichar_iswide(c) ? 2 : 1;
-                if (k + w <= new_length) {
-                        k += w;
-                        j = jj;
-                } else
-                        break;
-        }
-        assert(i <= j);
-
-        /* we don't actually need to ellipsize */
-        if (i == j)
-                return memdup_suffix0(s, old_length);
-
-        /* make space for ellipsis, if possible */
-        if (j < s + old_length)
-                j = utf8_next_char(j);
-        else if (i > s)
-                i = utf8_prev_char(i);
-
-        len = i - s;
-        len2 = s + old_length - j;
-        e = new(char, len + 3 + len2 + 1);
-        if (!e)
-                return NULL;
-
-        /*
-        printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
-               old_length, new_length, x, len, len2, k);
-        */
-
-        memcpy(e, s, len);
-        write_ellipsis(e + len, true);
-        memcpy(e + len + 3, j, len2);
-        *(e + len + 3 + len2) = '\0';
-
-        return e;
-}
-
-char *cellescape(char *buf, size_t len, const char *s) {
-        /* Escape and ellipsize s into buffer buf of size len. Only non-control ASCII
-         * characters are copied as they are, everything else is escaped. The result
-         * is different then if escaping and ellipsization was performed in two
-         * separate steps, because each sequence is either stored in full or skipped.
-         *
-         * This function should be used for logging about strings which expected to
-         * be plain ASCII in a safe way.
-         *
-         * An ellipsis will be used if s is too long. It was always placed at the
-         * very end.
-         */
-
-        size_t i = 0, last_char_width[4] = {}, k = 0, j;
-
-        assert(len > 0); /* at least a terminating NUL */
-
-        for (;;) {
-                char four[4];
-                int w;
-
-                if (*s == 0) /* terminating NUL detected? then we are done! */
-                        goto done;
-
-                w = cescape_char(*s, four);
-                if (i + w + 1 > len) /* This character doesn't fit into the buffer anymore? In that case let's
-                                      * ellipsize at the previous location */
-                        break;
-
-                /* OK, there was space, let's add this escaped character to the buffer */
-                memcpy(buf + i, four, w);
-                i += w;
-
-                /* And remember its width in the ring buffer */
-                last_char_width[k] = w;
-                k = (k + 1) % 4;
-
-                s++;
-        }
-
-        /* Ellipsation is necessary. This means we might need to truncate the string again to make space for 4
-         * characters ideally, but the buffer is shorter than that in the first place take what we can get */
-        for (j = 0; j < ELEMENTSOF(last_char_width); j++) {
-
-                if (i + 4 <= len) /* nice, we reached our space goal */
-                        break;
-
-                k = k == 0 ? 3 : k - 1;
-                if (last_char_width[k] == 0) /* bummer, we reached the beginning of the strings */
-                        break;
-
-                assert(i >= last_char_width[k]);
-                i -= last_char_width[k];
-        }
-
-        if (i + 4 <= len) /* yay, enough space */
-                i += write_ellipsis(buf + i, false);
-        else if (i + 3 <= len) { /* only space for ".." */
-                buf[i++] = '.';
-                buf[i++] = '.';
-        } else if (i + 2 <= len) /* only space for a single "." */
-                buf[i++] = '.';
-        else
-                assert(i + 1 <= len);
-
- done:
-        buf[i] = '\0';
-        return buf;
-}
-#endif /* NM_IGNORED */
-
-char* strshorten(char *s, size_t l) {
-        assert(s);
-
-        if (strnlen(s, l+1) > l)
-                s[l] = 0;
-
-        return s;
-}
-
-char *strreplace(const char *text, const char *old_string, const char *new_string) {
-        size_t l, old_len, new_len, allocated = 0;
-        char *t, *ret = NULL;
-        const char *f;
-
-        assert(old_string);
-        assert(new_string);
-
-        if (!text)
-                return NULL;
-
-        old_len = strlen(old_string);
-        new_len = strlen(new_string);
-
-        l = strlen(text);
-        if (!GREEDY_REALLOC(ret, allocated, l+1))
-                return NULL;
-
-        f = text;
-        t = ret;
-        while (*f) {
-                size_t d, nl;
-
-                if (!startswith(f, old_string)) {
-                        *(t++) = *(f++);
-                        continue;
-                }
-
-                d = t - ret;
-                nl = l - old_len + new_len;
-
-                if (!GREEDY_REALLOC(ret, allocated, nl + 1))
-                        return mfree(ret);
-
-                l = nl;
-                t = ret + d;
-
-                t = stpcpy(t, new_string);
-                f += old_len;
-        }
-
-        *t = 0;
-        return ret;
-}
-
-#if 0 /* NM_IGNORED */
-static void advance_offsets(
-                ssize_t diff,
-                size_t offsets[2], /* note: we can't use [static 2] here, since this may be NULL */
-                size_t shift[static 2],
-                size_t size) {
-
-        if (!offsets)
-                return;
-
-        assert(shift);
-
-        if ((size_t) diff < offsets[0])
-                shift[0] += size;
-        if ((size_t) diff < offsets[1])
-                shift[1] += size;
-}
-
-char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
-        const char *begin = NULL;
-        enum {
-                STATE_OTHER,
-                STATE_ESCAPE,
-                STATE_CSI,
-                STATE_CSO,
-        } state = STATE_OTHER;
-        char *obuf = NULL;
-        size_t osz = 0, isz, shift[2] = {}, n_carriage_returns = 0;
-        FILE *f;
-
-        assert(ibuf);
-        assert(*ibuf);
-
-        /* This does three things:
-         *
-         * 1. Replaces TABs by 8 spaces
-         * 2. Strips ANSI color sequences (a subset of CSI), i.e. ESC '[' … 'm' sequences
-         * 3. Strips ANSI operating system sequences (CSO), i.e. ESC ']' … BEL sequences
-         * 4. Strip trailing \r characters (since they would "move the cursor", but have no
-         *    other effect).
-         *
-         * Everything else will be left as it is. In particular other ANSI sequences are left as they are, as
-         * are any other special characters. Truncated ANSI sequences are left-as is too. This call is
-         * supposed to suppress the most basic formatting noise, but nothing else.
-         *
-         * Why care for CSO sequences? Well, to undo what terminal_urlify() and friends generate. */
-
-        isz = _isz ? *_isz : strlen(*ibuf);
-
-        /* Note we turn off internal locking on f for performance reasons. It's safe to do so since we
-         * created f here and it doesn't leave our scope. */
-        f = open_memstream_unlocked(&obuf, &osz);
-        if (!f)
-                return NULL;
-
-        for (const char *i = *ibuf; i < *ibuf + isz + 1; i++) {
-
-                switch (state) {
-
-                case STATE_OTHER:
-                        if (i >= *ibuf + isz) /* EOT */
-                                break;
-
-                        if (*i == '\r') {
-                                n_carriage_returns++;
-                                break;
-                        } else if (*i == '\n')
-                                /* Ignore carriage returns before new line */
-                                n_carriage_returns = 0;
-                        for (; n_carriage_returns > 0; n_carriage_returns--)
-                                fputc('\r', f);
-
-                        if (*i == '\x1B')
-                                state = STATE_ESCAPE;
-                        else if (*i == '\t') {
-                                fputs("        ", f);
-                                advance_offsets(i - *ibuf, highlight, shift, 7);
-                        } else
-                                fputc(*i, f);
-
-                        break;
-
-                case STATE_ESCAPE:
-                        assert(n_carriage_returns == 0);
-
-                        if (i >= *ibuf + isz) { /* EOT */
-                                fputc('\x1B', f);
-                                advance_offsets(i - *ibuf, highlight, shift, 1);
-                                break;
-                        } else if (*i == '[') { /* ANSI CSI */
-                                state = STATE_CSI;
-                                begin = i + 1;
-                        } else if (*i == ']') { /* ANSI CSO */
-                                state = STATE_CSO;
-                                begin = i + 1;
-                        } else {
-                                fputc('\x1B', f);
-                                fputc(*i, f);
-                                advance_offsets(i - *ibuf, highlight, shift, 1);
-                                state = STATE_OTHER;
-                        }
-
-                        break;
-
-                case STATE_CSI:
-                        assert(n_carriage_returns == 0);
-
-                        if (i >= *ibuf + isz || /* EOT … */
-                            !strchr("01234567890;m", *i)) { /* … or invalid chars in sequence */
-                                fputc('\x1B', f);
-                                fputc('[', f);
-                                advance_offsets(i - *ibuf, highlight, shift, 2);
-                                state = STATE_OTHER;
-                                i = begin-1;
-                        } else if (*i == 'm')
-                                state = STATE_OTHER;
-
-                        break;
-
-                case STATE_CSO:
-                        assert(n_carriage_returns == 0);
-
-                        if (i >= *ibuf + isz || /* EOT … */
-                            (*i != '\a' && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */
-                                fputc('\x1B', f);
-                                fputc(']', f);
-                                advance_offsets(i - *ibuf, highlight, shift, 2);
-                                state = STATE_OTHER;
-                                i = begin-1;
-                        } else if (*i == '\a')
-                                state = STATE_OTHER;
-
-                        break;
-                }
-        }
-
-        if (fflush_and_check(f) < 0) {
-                fclose(f);
-                return mfree(obuf);
-        }
-        fclose(f);
-
-        free_and_replace(*ibuf, obuf);
-
-        if (_isz)
-                *_isz = osz;
-
-        if (highlight) {
-                highlight[0] += shift[0];
-                highlight[1] += shift[1];
-        }
-
-        return *ibuf;
-}
-
-char *strextend_with_separator_internal(char **x, const char *separator, ...) {
-        size_t f, l, l_separator;
-        bool need_separator;
-        char *nr, *p;
-        va_list ap;
-
-        assert(x);
-
-        l = f = strlen_ptr(*x);
-
-        need_separator = !isempty(*x);
-        l_separator = strlen_ptr(separator);
-
-        va_start(ap, separator);
-        for (;;) {
-                const char *t;
-                size_t n;
-
-                t = va_arg(ap, const char *);
-                if (!t)
-                        break;
-
-                n = strlen(t);
-
-                if (need_separator)
-                        n += l_separator;
-
-                if (n >= SIZE_MAX - l) {
-                        va_end(ap);
-                        return NULL;
-                }
-
-                l += n;
-                need_separator = true;
-        }
-        va_end(ap);
-
-        need_separator = !isempty(*x);
-
-        nr = realloc(*x, GREEDY_ALLOC_ROUND_UP(l+1));
-        if (!nr)
-                return NULL;
-
-        *x = nr;
-        p = nr + f;
-
-        va_start(ap, separator);
-        for (;;) {
-                const char *t;
-
-                t = va_arg(ap, const char *);
-                if (!t)
-                        break;
-
-                if (need_separator && separator)
-                        p = stpcpy(p, separator);
-
-                p = stpcpy(p, t);
-
-                need_separator = true;
-        }
-        va_end(ap);
-
-        assert(p == nr + l);
-
-        *p = 0;
-
-        return p;
-}
-#endif /* NM_IGNORED */
-
-char *strrep(const char *s, unsigned n) {
-        size_t l;
-        char *r, *p;
-        unsigned i;
-
-        assert(s);
-
-        l = strlen(s);
-        p = r = malloc(l * n + 1);
-        if (!r)
-                return NULL;
-
-        for (i = 0; i < n; i++)
-                p = stpcpy(p, s);
-
-        *p = 0;
-        return r;
-}
-
-int split_pair(const char *s, const char *sep, char **l, char **r) {
-        char *x, *a, *b;
-
-        assert(s);
-        assert(sep);
-        assert(l);
-        assert(r);
-
-        if (isempty(sep))
-                return -EINVAL;
-
-        x = strstr(s, sep);
-        if (!x)
-                return -EINVAL;
-
-        a = strndup(s, x - s);
-        if (!a)
-                return -ENOMEM;
-
-        b = strdup(x + strlen(sep));
-        if (!b) {
-                free(a);
-                return -ENOMEM;
-        }
-
-        *l = a;
-        *r = b;
-
-        return 0;
-}
-
-int free_and_strdup(char **p, const char *s) {
-        char *t;
-
-        assert(p);
-
-        /* Replaces a string pointer with a strdup()ed new string,
-         * possibly freeing the old one. */
-
-        if (streq_ptr(*p, s))
-                return 0;
-
-        if (s) {
-                t = strdup(s);
-                if (!t)
-                        return -ENOMEM;
-        } else
-                t = NULL;
-
-        free(*p);
-        *p = t;
-
-        return 1;
-}
-
-int free_and_strndup(char **p, const char *s, size_t l) {
-        char *t;
-
-        assert(p);
-        assert(s || l == 0);
-
-        /* Replaces a string pointer with a strndup()ed new string,
-         * freeing the old one. */
-
-        if (!*p && !s)
-                return 0;
-
-        if (*p && s && strneq(*p, s, l) && (l > strlen(*p) || (*p)[l] == '\0'))
-                return 0;
-
-        if (s) {
-                t = strndup(s, l);
-                if (!t)
-                        return -ENOMEM;
-        } else
-                t = NULL;
-
-        free_and_replace(*p, t);
-        return 1;
-}
-
-bool string_is_safe(const char *p) {
-        const char *t;
-
-        if (!p)
-                return false;
-
-        /* Checks if the specified string contains no quotes or control characters */
-
-        for (t = p; *t; t++) {
-                if (*t > 0 && *t < ' ') /* no control characters */
-                        return false;
-
-                if (strchr(QUOTES "\\\x7f", *t))
-                        return false;
-        }
-
-        return true;
-}
-
-#if 0 /* NM_IGNORED */
-char* string_erase(char *x) {
-        if (!x)
-                return NULL;
-
-        /* A delicious drop of snake-oil! To be called on memory where we stored passphrases or so, after we
-         * used them. */
-        explicit_bzero_safe(x, strlen(x));
-        return x;
-}
-
-int string_truncate_lines(const char *s, size_t n_lines, char **ret) {
-        const char *p = s, *e = s;
-        bool truncation_applied = false;
-        char *copy;
-        size_t n = 0;
-
-        assert(s);
-
-        /* Truncate after the specified number of lines. Returns > 0 if a truncation was applied or == 0 if
-         * there were fewer lines in the string anyway. Trailing newlines on input are ignored, and not
-         * generated either. */
-
-        for (;;) {
-                size_t k;
-
-                k = strcspn(p, "\n");
-
-                if (p[k] == 0) {
-                        if (k == 0) /* final empty line */
-                                break;
-
-                        if (n >= n_lines) /* above threshold */
-                                break;
-
-                        e = p + k; /* last line to include */
-                        break;
-                }
-
-                assert(p[k] == '\n');
-
-                if (n >= n_lines)
-                        break;
-
-                if (k > 0)
-                        e = p + k;
-
-                p += k + 1;
-                n++;
-        }
-
-        /* e points after the last character we want to keep */
-        if (isempty(e))
-                copy = strdup(s);
-        else {
-                if (!in_charset(e, "\n")) /* We only consider things truncated if we remove something that
-                                           * isn't a new-line or a series of them */
-                        truncation_applied = true;
-
-                copy = strndup(s, e - s);
-        }
-        if (!copy)
-                return -ENOMEM;
-
-        *ret = copy;
-        return truncation_applied;
-}
-
-int string_extract_line(const char *s, size_t i, char **ret) {
-        const char *p = s;
-        size_t c = 0;
-
-        /* Extract the i'nth line from the specified string. Returns > 0 if there are more lines after that,
-         * and == 0 if we are looking at the last line or already beyond the last line. As special
-         * optimization, if the first line is requested and the string only consists of one line we return
-         * NULL, indicating the input string should be used as is, and avoid a memory allocation for a very
-         * common case. */
-
-        for (;;) {
-                const char *q;
-
-                q = strchr(p, '\n');
-                if (i == c) {
-                        /* The line we are looking for! */
-
-                        if (q) {
-                                char *m;
-
-                                m = strndup(p, q - p);
-                                if (!m)
-                                        return -ENOMEM;
-
-                                *ret = m;
-                                return !isempty(q + 1); /* more coming? */
-                        } else {
-                                if (p == s)
-                                        *ret = NULL; /* Just use the input string */
-                                else {
-                                        char *m;
-
-                                        m = strdup(p);
-                                        if (!m)
-                                                return -ENOMEM;
-
-                                        *ret = m;
-                                }
-
-                                return 0; /* The end */
-                        }
-                }
-
-                if (!q) {
-                        char *m;
-
-                        /* No more lines, return empty line */
-
-                        m = strdup("");
-                        if (!m)
-                                return -ENOMEM;
-
-                        *ret = m;
-                        return 0; /* The end */
-                }
-
-                p = q + 1;
-                c++;
-        }
-}
-
-int string_contains_word_strv(const char *string, const char *separators, char **words, const char **ret_word) {
-        /* In the default mode with no separators specified, we split on whitespace and
-         * don't coalesce separators. */
-        const ExtractFlags flags = separators ? EXTRACT_DONT_COALESCE_SEPARATORS : 0;
-
-        const char *found = NULL;
-
-        for (const char *p = string;;) {
-                _cleanup_free_ char *w = NULL;
-                int r;
-
-                r = extract_first_word(&p, &w, separators, flags);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                found = strv_find(words, w);
-                if (found)
-                        break;
-        }
-
-        if (ret_word)
-                *ret_word = found;
-        return !!found;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h
deleted file mode 100644
index 593cf04a..00000000
--- a/shared/systemd/src/basic/string-util.h
+++ /dev/null
@@ -1,280 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-
-#include "alloc-util.h"
-#include "macro.h"
-
-/* What is interpreted as whitespace? */
-#define WHITESPACE        " \t\n\r"
-#define NEWLINE           "\n\r"
-#define QUOTES            "\"\'"
-#define COMMENTS          "#;"
-#define GLOB_CHARS        "*?["
-#define DIGITS            "0123456789"
-#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
-#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-#define LETTERS           LOWERCASE_LETTERS UPPERCASE_LETTERS
-#define ALPHANUMERICAL    LETTERS DIGITS
-#define HEXDIGITS         DIGITS "abcdefABCDEF"
-
-#define streq(a,b) (strcmp((a),(b)) == 0)
-#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
-#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
-#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
-
-int strcmp_ptr(const char *a, const char *b) _pure_;
-int strcasecmp_ptr(const char *a, const char *b) _pure_;
-
-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 ?: "";
-}
-
-static inline const char* strnull(const char *s) {
-        return s ?: "(null)";
-}
-
-static inline const char *strna(const char *s) {
-        return s ?: "n/a";
-}
-
-static inline const char* yes_no(bool b) {
-        return b ? "yes" : "no";
-}
-
-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";
-}
-
-static inline const char* enable_disable(bool b) {
-        return b ? "enable" : "disable";
-}
-
-static inline bool isempty(const char *p) {
-        return !p || !p[0];
-}
-
-static inline const char *empty_to_null(const char *p) {
-        return isempty(p) ? NULL : p;
-}
-
-static inline const char *empty_to_dash(const char *str) {
-        return isempty(str) ? "-" : str;
-}
-
-static inline bool empty_or_dash(const char *str) {
-        return !str ||
-                str[0] == 0 ||
-                (str[0] == '-' && str[1] == 0);
-}
-
-static inline const char *empty_or_dash_to_null(const char *p) {
-        return empty_or_dash(p) ? NULL : p;
-}
-
-static inline char *startswith(const char *s, const char *prefix) {
-        size_t l;
-
-        l = strlen(prefix);
-        if (strncmp(s, prefix, l) == 0)
-                return (char*) s + l;
-
-        return NULL;
-}
-
-static inline char *startswith_no_case(const char *s, const char *prefix) {
-        size_t l;
-
-        l = strlen(prefix);
-        if (strncasecmp(s, prefix, l) == 0)
-                return (char*) s + l;
-
-        return NULL;
-}
-
-char *endswith(const char *s, const char *postfix) _pure_;
-char *endswith_no_case(const char *s, const char *postfix) _pure_;
-
-char *first_word(const char *s, const char *word) _pure_;
-
-char *strnappend(const char *s, const char *suffix, size_t length);
-
-char *strjoin_real(const char *x, ...) _sentinel_;
-#define strjoin(a, ...) strjoin_real((a), __VA_ARGS__, NULL)
-
-#define strjoina(a, ...)                                                \
-        ({                                                              \
-                const char *_appendees_[] = { a, __VA_ARGS__ };         \
-                char *_d_, *_p_;                                        \
-                size_t _len_ = 0;                                       \
-                size_t _i_;                                             \
-                for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
-                        _len_ += strlen(_appendees_[_i_]);              \
-                _p_ = _d_ = newa(char, _len_ + 1);                      \
-                for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
-                        _p_ = stpcpy(_p_, _appendees_[_i_]);            \
-                *_p_ = 0;                                               \
-                _d_;                                                    \
-        })
-
-char *strstrip(char *s);
-char *delete_chars(char *s, const char *bad);
-char *delete_trailing_chars(char *s, const char *bad);
-char *truncate_nl(char *s);
-
-static inline char *skip_leading_chars(const char *s, const char *bad) {
-        if (!s)
-                return NULL;
-
-        if (!bad)
-                bad = WHITESPACE;
-
-        return (char*) s + strspn(s, bad);
-}
-
-char ascii_tolower(char x);
-char *ascii_strlower(char *s);
-char *ascii_strlower_n(char *s, size_t n);
-
-char ascii_toupper(char x);
-char *ascii_strupper(char *s);
-
-int ascii_strcasecmp_n(const char *a, const char *b, size_t n);
-int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m);
-
-bool chars_intersect(const char *a, const char *b) _pure_;
-
-static inline bool _pure_ in_charset(const char *s, const char* charset) {
-        assert(s);
-        assert(charset);
-        return s[strspn(s, charset)] == '\0';
-}
-
-bool string_has_cc(const char *p, const char *ok) _pure_;
-
-char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
-static inline char *ellipsize(const char *s, size_t length, unsigned percent) {
-        return ellipsize_mem(s, strlen(s), length, percent);
-}
-
-char *cellescape(char *buf, size_t len, const char *s);
-
-/* This limit is arbitrary, enough to give some idea what the string contains */
-#define CELLESCAPE_DEFAULT_LENGTH 64
-
-char* strshorten(char *s, size_t l);
-
-char *strreplace(const char *text, const char *old_string, const char *new_string);
-
-char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]);
-
-char *strextend_with_separator_internal(char **x, const char *separator, ...) _sentinel_;
-
-#define strextend_with_separator(x, separator, ...) strextend_with_separator_internal(x, separator, __VA_ARGS__, NULL)
-#define strextend(x, ...) strextend_with_separator_internal(x, NULL, __VA_ARGS__, NULL)
-
-char *strrep(const char *s, unsigned n);
-
-int split_pair(const char *s, const char *sep, char **l, char **r);
-
-int free_and_strdup(char **p, const char *s);
-static inline int free_and_strdup_warn(char **p, const char *s) {
-        if (free_and_strdup(p, s) < 0)
-                return log_oom();
-        return 0;
-}
-int free_and_strndup(char **p, const char *s, size_t l);
-
-bool string_is_safe(const char *p) _pure_;
-
-static inline size_t strlen_ptr(const char *s) {
-        if (!s)
-                return 0;
-
-        return strlen(s);
-}
-
-DISABLE_WARNING_STRINGOP_TRUNCATION;
-static inline void strncpy_exact(char *buf, const char *src, size_t buf_len) {
-        strncpy(buf, src, buf_len);
-}
-REENABLE_WARNING;
-
-/* Like startswith(), but operates on arbitrary memory blocks */
-static inline void *memory_startswith(const void *p, size_t sz, const char *token) {
-        assert(token);
-
-        size_t n = strlen(token);
-        if (sz < n)
-                return NULL;
-
-        assert(p);
-
-        if (memcmp(p, token, n) != 0)
-                return NULL;
-
-        return (uint8_t*) p + n;
-}
-
-/* Like startswith_no_case(), but operates on arbitrary memory blocks.
- * It works only for ASCII strings.
- */
-static inline void *memory_startswith_no_case(const void *p, size_t sz, const char *token) {
-        assert(token);
-
-        size_t n = strlen(token);
-        if (sz < n)
-                return NULL;
-
-        assert(p);
-
-        for (size_t i = 0; i < n; i++)
-                if (ascii_tolower(((char *)p)[i]) != ascii_tolower(token[i]))
-                        return NULL;
-
-        return (uint8_t*) p + n;
-}
-
-static inline char* str_realloc(char **p) {
-        /* Reallocate *p to actual size */
-
-        if (!*p)
-                return NULL;
-
-        char *t = realloc(*p, strlen(*p) + 1);
-        if (!t)
-                return NULL;
-
-        return (*p = t);
-}
-
-char* string_erase(char *x);
-
-int string_truncate_lines(const char *s, size_t n_lines, char **ret);
-int string_extract_line(const char *s, size_t i, char **ret);
-
-int string_contains_word_strv(const char *string, const char *separators, char **words, const char **ret_word);
-static inline int string_contains_word(const char *string, const char *separators, const char *word) {
-        return string_contains_word_strv(string, separators, STRV_MAKE(word), NULL);
-}
diff --git a/shared/systemd/src/basic/strv.c b/shared/systemd/src/basic/strv.c
deleted file mode 100644
index 7d3e3fc7..00000000
--- a/shared/systemd/src/basic/strv.c
+++ /dev/null
@@ -1,1005 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <fnmatch.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "alloc-util.h"
-#include "escape.h"
-#include "extract-word.h"
-#include "fileio.h"
-#include "memory-util.h"
-#include "nulstr-util.h"
-#include "sort-util.h"
-#include "string-util.h"
-#include "strv.h"
-
-char *strv_find(char * const *l, const char *name) {
-        char * const *i;
-
-        assert(name);
-
-        STRV_FOREACH(i, l)
-                if (streq(*i, name))
-                        return *i;
-
-        return NULL;
-}
-
-char *strv_find_case(char * const *l, const char *name) {
-        char * const *i;
-
-        assert(name);
-
-        STRV_FOREACH(i, l)
-                if (strcaseeq(*i, name))
-                        return *i;
-
-        return NULL;
-}
-
-char *strv_find_prefix(char * const *l, const char *name) {
-        char * const *i;
-
-        assert(name);
-
-        STRV_FOREACH(i, l)
-                if (startswith(*i, name))
-                        return *i;
-
-        return NULL;
-}
-
-char *strv_find_startswith(char * const *l, const char *name) {
-        char * const *i, *e;
-
-        assert(name);
-
-        /* Like strv_find_prefix, but actually returns only the
-         * suffix, not the whole item */
-
-        STRV_FOREACH(i, l) {
-                e = startswith(*i, name);
-                if (e)
-                        return e;
-        }
-
-        return NULL;
-}
-
-char **strv_free(char **l) {
-        char **k;
-
-        if (!l)
-                return NULL;
-
-        for (k = l; *k; k++)
-                free(*k);
-
-        return mfree(l);
-}
-
-char **strv_free_erase(char **l) {
-        char **i;
-
-        STRV_FOREACH(i, l)
-                erase_and_freep(i);
-
-        return mfree(l);
-}
-
-char **strv_copy(char * const *l) {
-        char **r, **k;
-
-        k = r = new(char*, strv_length(l) + 1);
-        if (!r)
-                return NULL;
-
-        if (l)
-                for (; *l; k++, l++) {
-                        *k = strdup(*l);
-                        if (!*k) {
-                                strv_free(r);
-                                return NULL;
-                        }
-                }
-
-        *k = NULL;
-        return r;
-}
-
-size_t strv_length(char * const *l) {
-        size_t n = 0;
-
-        if (!l)
-                return 0;
-
-        for (; *l; l++)
-                n++;
-
-        return n;
-}
-
-char **strv_new_ap(const char *x, va_list ap) {
-        _cleanup_strv_free_ char **a = NULL;
-        size_t n = 0, i = 0;
-        va_list aq;
-
-        /* As a special trick we ignore all listed strings that equal
-         * STRV_IGNORE. This is supposed to be used with the
-         * STRV_IFNOTNULL() macro to include possibly NULL strings in
-         * the string list. */
-
-        va_copy(aq, ap);
-        for (const char *s = x; s; s = va_arg(aq, const char*)) {
-                if (s == STRV_IGNORE)
-                        continue;
-
-                n++;
-        }
-        va_end(aq);
-
-        a = new(char*, n+1);
-        if (!a)
-                return NULL;
-
-        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;
-
-                i++;
-        }
-
-        a[i] = NULL;
-
-        return TAKE_PTR(a);
-}
-
-char **strv_new_internal(const char *x, ...) {
-        char **r;
-        va_list ap;
-
-        va_start(ap, x);
-        r = strv_new_ap(x, ap);
-        va_end(ap);
-
-        return r;
-}
-
-int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
-        char * const *s, **t;
-        size_t p, q, i = 0, j;
-
-        assert(a);
-
-        if (strv_isempty(b))
-                return 0;
-
-        p = strv_length(*a);
-        q = strv_length(b);
-
-        if (p >= SIZE_MAX - q)
-                return -ENOMEM;
-
-        t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
-        if (!t)
-                return -ENOMEM;
-
-        t[p] = NULL;
-        *a = t;
-
-        STRV_FOREACH(s, b) {
-
-                if (filter_duplicates && strv_contains(t, *s))
-                        continue;
-
-                t[p+i] = strdup(*s);
-                if (!t[p+i])
-                        goto rollback;
-
-                i++;
-                t[p+i] = NULL;
-        }
-
-        assert(i <= q);
-
-        return (int) i;
-
-rollback:
-        for (j = 0; j < i; j++)
-                free(t[p + j]);
-
-        t[p] = NULL;
-        return -ENOMEM;
-}
-
-#if 0 /* NM_IGNORED */
-int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) {
-        char * const *s;
-        int r;
-
-        STRV_FOREACH(s, b) {
-                char *v;
-
-                v = strjoin(*s, suffix);
-                if (!v)
-                        return -ENOMEM;
-
-                r = strv_push(a, v);
-                if (r < 0) {
-                        free(v);
-                        return r;
-                }
-        }
-
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-char **strv_split_newlines(const char *s) {
-        char **l;
-        size_t n;
-
-        assert(s);
-
-        /* Special version of strv_split() that splits on newlines and
-         * suppresses an empty string at the end */
-
-        l = strv_split(s, NEWLINE);
-        if (!l)
-                return NULL;
-
-        n = strv_length(l);
-        if (n <= 0)
-                return l;
-
-        if (isempty(l[n - 1]))
-                l[n - 1] = mfree(l[n - 1]);
-
-        return l;
-}
-
-int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags) {
-        _cleanup_strv_free_ char **l = NULL;
-        size_t n = 0, allocated = 0;
-        int r;
-
-        assert(t);
-        assert(s);
-
-        for (;;) {
-                _cleanup_free_ char *word = NULL;
-
-                r = extract_first_word(&s, &word, separators, flags);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                if (!GREEDY_REALLOC(l, allocated, n + 2))
-                        return -ENOMEM;
-
-                l[n++] = TAKE_PTR(word);
-
-                l[n] = NULL;
-        }
-
-        if (!l) {
-                l = new0(char*, 1);
-                if (!l)
-                        return -ENOMEM;
-        }
-
-        *t = TAKE_PTR(l);
-
-        return (int) n;
-}
-
-#if 0 /* NM_IGNORED */
-int strv_split_colon_pairs(char ***t, const char *s) {
-        _cleanup_strv_free_ char **l = NULL;
-        size_t n = 0, allocated = 0;
-        int r;
-
-        assert(t);
-        assert(s);
-
-        for (;;) {
-                _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL, *second_or_empty = NULL;
-
-                r = extract_first_word(&s, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                const char *p = tuple;
-                r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
-                                       &first, &second, NULL);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        continue;
-                /* Enforce that at most 2 colon-separated words are contained in each group */
-                if (!isempty(p))
-                        return -EINVAL;
-
-                second_or_empty = strdup(strempty(second));
-                if (!second_or_empty)
-                        return -ENOMEM;
-
-                if (!GREEDY_REALLOC(l, allocated, n + 3))
-                        return -ENOMEM;
-
-                l[n++] = TAKE_PTR(first);
-                l[n++] = TAKE_PTR(second_or_empty);
-
-                l[n] = NULL;
-        }
-
-        if (!l) {
-                l = new0(char*, 1);
-                if (!l)
-                        return -ENOMEM;
-        }
-
-        *t = TAKE_PTR(l);
-
-        return (int) n;
-}
-#endif /* NM_IGNORED */
-
-char *strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) {
-        char * const *s;
-        char *r, *e;
-        size_t n, k, m;
-
-        if (!separator)
-                separator = " ";
-
-        k = strlen(separator);
-        m = strlen_ptr(prefix);
-
-        if (unescape_separators) /* If there separator is multi-char, we won't know how to escape it. */
-                assert(k == 1);
-
-        n = 0;
-        STRV_FOREACH(s, l) {
-                if (s != l)
-                        n += k;
-
-                bool needs_escaping = unescape_separators && strchr(*s, separator[0]);
-
-                n += m + strlen(*s) * (1 + needs_escaping);
-        }
-
-        r = new(char, n+1);
-        if (!r)
-                return NULL;
-
-        e = r;
-        STRV_FOREACH(s, l) {
-                if (s != l)
-                        e = stpcpy(e, separator);
-
-                if (prefix)
-                        e = stpcpy(e, prefix);
-
-                bool needs_escaping = unescape_separators && strchr(*s, separator[0]);
-
-                if (needs_escaping)
-                        for (size_t i = 0; (*s)[i]; i++) {
-                                if ((*s)[i] == separator[0])
-                                        *(e++) = '\\';
-                                *(e++) = (*s)[i];
-                        }
-                else
-                        e = stpcpy(e, *s);
-        }
-
-        *e = 0;
-
-        return r;
-}
-
-int strv_push(char ***l, char *value) {
-        char **c;
-        size_t n;
-
-        if (!value)
-                return 0;
-
-        n = strv_length(*l);
-
-        /* Check for overflow */
-        if (n > SIZE_MAX-2)
-                return -ENOMEM;
-
-        c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + 2), sizeof(char*));
-        if (!c)
-                return -ENOMEM;
-
-        c[n] = value;
-        c[n+1] = NULL;
-
-        *l = c;
-        return 0;
-}
-
-int strv_push_pair(char ***l, char *a, char *b) {
-        char **c;
-        size_t n;
-
-        if (!a && !b)
-                return 0;
-
-        n = strv_length(*l);
-
-        /* Check for overflow */
-        if (n > SIZE_MAX-3)
-                return -ENOMEM;
-
-        /* increase and check for overflow */
-        c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + !!a + !!b + 1), sizeof(char*));
-        if (!c)
-                return -ENOMEM;
-
-        if (a)
-                c[n++] = a;
-        if (b)
-                c[n++] = b;
-        c[n] = NULL;
-
-        *l = c;
-        return 0;
-}
-
-int strv_insert(char ***l, size_t position, char *value) {
-        char **c;
-        size_t n, m, i;
-
-        if (!value)
-                return 0;
-
-        n = strv_length(*l);
-        position = MIN(position, n);
-
-        /* increase and check for overflow */
-        m = n + 2;
-        if (m < n)
-                return -ENOMEM;
-
-        c = new(char*, m);
-        if (!c)
-                return -ENOMEM;
-
-        for (i = 0; i < position; i++)
-                c[i] = (*l)[i];
-        c[position] = value;
-        for (i = position; i < n; i++)
-                c[i+1] = (*l)[i];
-
-        c[n+1] = NULL;
-
-        free(*l);
-        *l = c;
-
-        return 0;
-}
-
-int strv_consume(char ***l, char *value) {
-        int r;
-
-        r = strv_push(l, value);
-        if (r < 0)
-                free(value);
-
-        return r;
-}
-
-int strv_consume_pair(char ***l, char *a, char *b) {
-        int r;
-
-        r = strv_push_pair(l, a, b);
-        if (r < 0) {
-                free(a);
-                free(b);
-        }
-
-        return r;
-}
-
-int strv_consume_prepend(char ***l, char *value) {
-        int r;
-
-        r = strv_push_prepend(l, value);
-        if (r < 0)
-                free(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;
-
-        if (!value)
-                return 0;
-
-        v = strdup(value);
-        if (!v)
-                return -ENOMEM;
-
-        return strv_consume(l, v);
-}
-
-int strv_extend_front(char ***l, const char *value) {
-        size_t n, m;
-        char *v, **c;
-
-        assert(l);
-
-        /* Like strv_extend(), but prepends rather than appends the new entry */
-
-        if (!value)
-                return 0;
-
-        n = strv_length(*l);
-
-        /* Increase and overflow check. */
-        m = n + 2;
-        if (m < n)
-                return -ENOMEM;
-
-        v = strdup(value);
-        if (!v)
-                return -ENOMEM;
-
-        c = reallocarray(*l, m, sizeof(char*));
-        if (!c) {
-                free(v);
-                return -ENOMEM;
-        }
-
-        memmove(c+1, c, n * sizeof(char*));
-        c[0] = v;
-        c[n+1] = NULL;
-
-        *l = c;
-        return 0;
-}
-
-char **strv_uniq(char **l) {
-        char **i;
-
-        /* Drops duplicate entries. The first identical string will be
-         * kept, the others dropped */
-
-        STRV_FOREACH(i, l)
-                strv_remove(i+1, *i);
-
-        return l;
-}
-
-bool strv_is_uniq(char * const *l) {
-        char * const *i;
-
-        STRV_FOREACH(i, l)
-                if (strv_find(i+1, *i))
-                        return false;
-
-        return true;
-}
-
-char **strv_remove(char **l, const char *s) {
-        char **f, **t;
-
-        if (!l)
-                return NULL;
-
-        assert(s);
-
-        /* Drops every occurrence of s in the string list, edits
-         * in-place. */
-
-        for (f = t = l; *f; f++)
-                if (streq(*f, s))
-                        free(*f);
-                else
-                        *(t++) = *f;
-
-        *t = NULL;
-        return l;
-}
-
-char **strv_parse_nulstr(const char *s, size_t l) {
-        /* l is the length of the input data, which will be split at NULs into
-         * elements of the resulting strv. Hence, the number of items in the resulting strv
-         * will be equal to one plus the number of NUL bytes in the l bytes starting at s,
-         * unless s[l-1] is NUL, in which case the final empty string is not stored in
-         * the resulting strv, and length is equal to the number of NUL bytes.
-         *
-         * Note that contrary to a normal nulstr which cannot contain empty strings, because
-         * the input data is terminated by any two consequent NUL bytes, this parser accepts
-         * empty strings in s.
-         */
-
-        const char *p;
-        size_t c = 0, i = 0;
-        char **v;
-
-        assert(s || l <= 0);
-
-        if (l <= 0)
-                return new0(char*, 1);
-
-        for (p = s; p < s + l; p++)
-                if (*p == 0)
-                        c++;
-
-        if (s[l-1] != 0)
-                c++;
-
-        v = new0(char*, c+1);
-        if (!v)
-                return NULL;
-
-        p = s;
-        while (p < s + l) {
-                const char *e;
-
-                e = memchr(p, 0, s + l - p);
-
-                v[i] = strndup(p, e ? e - p : s + l - p);
-                if (!v[i]) {
-                        strv_free(v);
-                        return NULL;
-                }
-
-                i++;
-
-                if (!e)
-                        break;
-
-                p = e + 1;
-        }
-
-        assert(i == c);
-
-        return v;
-}
-
-#if 0 /* NM_IGNORED */
-char **strv_split_nulstr(const char *s) {
-        const char *i;
-        char **r = NULL;
-
-        NULSTR_FOREACH(i, s)
-                if (strv_extend(&r, i) < 0) {
-                        strv_free(r);
-                        return NULL;
-                }
-
-        if (!r)
-                return strv_new(NULL);
-
-        return r;
-}
-#endif /* NM_IGNORED */
-
-int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
-        /* A valid nulstr with two NULs at the end will be created, but
-         * q will be the length without the two trailing NULs. Thus the output
-         * string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
-         * and can also be parsed by strv_parse_nulstr as long as the length
-         * is provided separately.
-         */
-
-        size_t n_allocated = 0, n = 0;
-        _cleanup_free_ char *m = NULL;
-        char * const *i;
-
-        assert(ret);
-        assert(ret_size);
-
-        STRV_FOREACH(i, l) {
-                size_t z;
-
-                z = strlen(*i);
-
-                if (!GREEDY_REALLOC(m, n_allocated, n + z + 2))
-                        return -ENOMEM;
-
-                memcpy(m + n, *i, z + 1);
-                n += z + 1;
-        }
-
-        if (!m) {
-                m = new0(char, 1);
-                if (!m)
-                        return -ENOMEM;
-                n = 1;
-        } else
-                /* make sure there is a second extra NUL at the end of resulting nulstr */
-                m[n] = '\0';
-
-        assert(n > 0);
-        *ret = m;
-        *ret_size = n - 1;
-
-        m = NULL;
-
-        return 0;
-}
-
-bool strv_overlap(char * const *a, char * const *b) {
-        char * const *i;
-
-        STRV_FOREACH(i, a)
-                if (strv_contains(b, *i))
-                        return true;
-
-        return false;
-}
-
-#if 0 /* NM_IGNORED */
-static int str_compare(char * const *a, char * const *b) {
-        return strcmp(*a, *b);
-}
-
-char **strv_sort(char **l) {
-        typesafe_qsort(l, strv_length(l), str_compare);
-        return l;
-}
-#endif /* NM_IGNORED */
-
-int strv_compare(char * const *a, char * const *b) {
-        int r;
-
-        if (strv_isempty(a)) {
-                if (strv_isempty(b))
-                        return 0;
-                else
-                        return -1;
-        }
-
-        if (strv_isempty(b))
-                return 1;
-
-        for ( ; *a || *b; ++a, ++b) {
-                r = strcmp_ptr(*a, *b);
-                if (r != 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-void strv_print(char * const *l) {
-        char * const *s;
-
-        STRV_FOREACH(s, l)
-                puts(*s);
-}
-
-int strv_extendf(char ***l, const char *format, ...) {
-        va_list ap;
-        char *x;
-        int r;
-
-        va_start(ap, format);
-        r = vasprintf(&x, format, ap);
-        va_end(ap);
-
-        if (r < 0)
-                return -ENOMEM;
-
-        return strv_consume(l, x);
-}
-
-char **strv_reverse(char **l) {
-        size_t n, i;
-
-        n = strv_length(l);
-        if (n <= 1)
-                return l;
-
-        for (i = 0; i < n / 2; i++)
-                SWAP_TWO(l[i], l[n-1-i]);
-
-        return l;
-}
-
-char **strv_shell_escape(char **l, const char *bad) {
-        char **s;
-
-        /* Escapes every character in every string in l that is in bad,
-         * edits in-place, does not roll-back on error. */
-
-        STRV_FOREACH(s, l) {
-                char *v;
-
-                v = shell_escape(*s, bad);
-                if (!v)
-                        return NULL;
-
-                free(*s);
-                *s = v;
-        }
-
-        return l;
-}
-
-bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos) {
-        for (size_t i = 0; patterns && patterns[i]; i++)
-                if (fnmatch(patterns[i], s, flags) == 0) {
-                        if (matched_pos)
-                                *matched_pos = i;
-                        return true;
-                }
-
-        return false;
-}
-
-char ***strv_free_free(char ***l) {
-        char ***i;
-
-        if (!l)
-                return NULL;
-
-        for (i = l; *i; i++)
-                strv_free(*i);
-
-        return mfree(l);
-}
-
-char **strv_skip(char **l, size_t n) {
-
-        while (n > 0) {
-                if (strv_isempty(l))
-                        return l;
-
-                l++, n--;
-        }
-
-        return l;
-}
-
-int strv_extend_n(char ***l, const char *value, size_t n) {
-        size_t i, j, k;
-        char **nl;
-
-        assert(l);
-
-        if (!value)
-                return 0;
-        if (n == 0)
-                return 0;
-
-        /* Adds the value n times to l */
-
-        k = strv_length(*l);
-        if (n >= SIZE_MAX - k)
-                return -ENOMEM;
-
-        nl = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(k + n + 1), sizeof(char *));
-        if (!nl)
-                return -ENOMEM;
-
-        *l = nl;
-
-        for (i = k; i < k + n; i++) {
-                nl[i] = strdup(value);
-                if (!nl[i])
-                        goto rollback;
-        }
-
-        nl[i] = NULL;
-        return 0;
-
-rollback:
-        for (j = k; j < i; j++)
-                free(nl[j]);
-
-        nl[k] = NULL;
-        return -ENOMEM;
-}
-
-int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
-        bool b = false;
-        char * const *s;
-        int r;
-
-        /* Like fputs(), but for strv, and with a less stupid argument order */
-
-        if (!space)
-                space = &b;
-
-        STRV_FOREACH(s, l) {
-                r = fputs_with_space(f, *s, separator, space);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) {
-        char **l;
-        int r;
-
-        l = hashmap_get(h, key);
-        if (l) {
-                /* A list for this key already exists, let's append to it if it is not listed yet */
-                if (strv_contains(l, value))
-                        return 0;
-
-                r = strv_extend(&l, value);
-                if (r < 0)
-                        return r;
-
-                assert_se(hashmap_update(h, key, l) >= 0);
-        } else {
-                /* No list for this key exists yet, create one */
-                _cleanup_strv_free_ char **l2 = NULL;
-                _cleanup_free_ char *t = NULL;
-
-                t = strdup(key);
-                if (!t)
-                        return -ENOMEM;
-
-                r = strv_extend(&l2, value);
-                if (r < 0)
-                        return r;
-
-                r = hashmap_put(h, t, l2);
-                if (r < 0)
-                        return r;
-                TAKE_PTR(t);
-                TAKE_PTR(l2);
-        }
-
-        return 1;
-}
-
-int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS) {
-        int r;
-
-        r = _hashmap_ensure_allocated(h, &string_strv_hash_ops  HASHMAP_DEBUG_PASS_ARGS);
-        if (r < 0)
-                return r;
-
-        return string_strv_hashmap_put_internal(*h, key, value);
-}
-
-int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS) {
-        int r;
-
-        r = _ordered_hashmap_ensure_allocated(h, &string_strv_hash_ops  HASHMAP_DEBUG_PASS_ARGS);
-        if (r < 0)
-                return r;
-
-        return string_strv_hashmap_put_internal(PLAIN_HASHMAP(*h), key, value);
-}
-
-DEFINE_HASH_OPS_FULL(string_strv_hash_ops, char, string_hash_func, string_compare_func, free, char*, strv_free);
diff --git a/shared/systemd/src/basic/strv.h b/shared/systemd/src/basic/strv.h
deleted file mode 100644
index 6b3e8e7f..00000000
--- a/shared/systemd/src/basic/strv.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <fnmatch.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-
-#include "alloc-util.h"
-#include "extract-word.h"
-#include "hashmap.h"
-#include "macro.h"
-#include "string-util.h"
-
-char *strv_find(char * const *l, const char *name) _pure_;
-char *strv_find_case(char * const *l, const char *name) _pure_;
-char *strv_find_prefix(char * const *l, const char *name) _pure_;
-char *strv_find_startswith(char * const *l, const char *name) _pure_;
-
-#define strv_contains(l, s) (!!strv_find((l), (s)))
-#define strv_contains_case(l, s) (!!strv_find_case((l), (s)))
-
-char **strv_free(char **l);
-DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
-#define _cleanup_strv_free_ _cleanup_(strv_freep)
-
-char **strv_free_erase(char **l);
-DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase);
-#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep)
-
-char **strv_copy(char * const *l);
-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);
-int strv_push(char ***l, char *value);
-int strv_push_pair(char ***l, char *a, char *b);
-int strv_insert(char ***l, size_t position, char *value);
-
-static inline int strv_push_prepend(char ***l, char *value) {
-        return strv_insert(l, 0, value);
-}
-
-int strv_consume(char ***l, char *value);
-int strv_consume_pair(char ***l, char *a, char *b);
-int strv_consume_prepend(char ***l, char *value);
-
-char **strv_remove(char **l, const char *s);
-char **strv_uniq(char **l);
-bool strv_is_uniq(char * const *l);
-
-int strv_compare(char * const *a, char * const *b);
-static inline bool strv_equal(char * const *a, char * const *b) {
-        return strv_compare(a, b) == 0;
-}
-
-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 *) POINTER_MAX)
-
-static inline const char* STRV_IFNOTNULL(const char *x) {
-        return x ? x : STRV_IGNORE;
-}
-
-static inline bool strv_isempty(char * const *l) {
-        return !l || !*l;
-}
-
-char **strv_split_newlines(const char *s);
-
-int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags);
-static inline char **strv_split(const char *s, const char *separators) {
-        char **ret;
-        int r;
-
-        r = strv_split_full(&ret, s, separators, 0);
-        if (r < 0)
-                return NULL;
-
-        return ret;
-}
-
-/* Given a string containing white-space separated tuples of words themselves separated by ':',
- * returns a vector of strings. If the second element in a tuple is missing, the corresponding
- * string in the vector is an empty string. */
-int strv_split_colon_pairs(char ***t, const char *s);
-
-char *strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separtor);
-static inline char *strv_join(char * const *l, const char *separator) {
-        return strv_join_full(l, separator, NULL, false);
-}
-
-char **strv_parse_nulstr(const char *s, size_t l);
-char **strv_split_nulstr(const char *s);
-int strv_make_nulstr(char * const *l, char **p, size_t *n);
-
-static inline int strv_from_nulstr(char ***a, const char *nulstr) {
-        char **t;
-
-        t = strv_split_nulstr(nulstr);
-        if (!t)
-                return -ENOMEM;
-        *a = t;
-        return 0;
-}
-
-bool strv_overlap(char * const *a, char * const *b) _pure_;
-
-#define STRV_FOREACH(s, l)                      \
-        for ((s) = (l); (s) && *(s); (s)++)
-
-#define STRV_FOREACH_BACKWARDS(s, l)                                \
-        for (s = ({                                                 \
-                        typeof(l) _l = l;                           \
-                        _l ? _l + strv_length(_l) - 1U : NULL;      \
-                        });                                         \
-             (l) && ((s) >= (l));                                   \
-             (s)--)
-
-#define STRV_FOREACH_PAIR(x, y, l)               \
-        for ((x) = (l), (y) = (x) ? (x+1) : NULL; (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
-
-char **strv_sort(char **l);
-void strv_print(char * const *l);
-
-#define strv_from_stdarg_alloca(first)                          \
-        ({                                                      \
-                char **_l;                                      \
-                                                                \
-                if (!first)                                     \
-                        _l = (char**) &first;                   \
-                else {                                          \
-                        size_t _n;                              \
-                        va_list _ap;                            \
-                                                                \
-                        _n = 1;                                 \
-                        va_start(_ap, first);                   \
-                        while (va_arg(_ap, char*))              \
-                                _n++;                           \
-                        va_end(_ap);                            \
-                                                                \
-                        _l = newa(char*, _n+1);                 \
-                        _l[_n = 0] = (char*) first;             \
-                        va_start(_ap, first);                   \
-                        for (;;) {                              \
-                                _l[++_n] = va_arg(_ap, char*);  \
-                                if (!_l[_n])                    \
-                                        break;                  \
-                        }                                       \
-                        va_end(_ap);                            \
-                }                                               \
-                _l;                                             \
-        })
-
-#define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x)
-#define STRPTR_IN_SET(x, ...)                                    \
-        ({                                                       \
-                const char* _x = (x);                            \
-                _x && strv_contains(STRV_MAKE(__VA_ARGS__), _x); \
-        })
-
-#define STRCASE_IN_SET(x, ...) strv_contains_case(STRV_MAKE(__VA_ARGS__), x)
-#define STRCASEPTR_IN_SET(x, ...)                                    \
-        ({                                                       \
-                const char* _x = (x);                            \
-                _x && strv_contains_case(STRV_MAKE(__VA_ARGS__), _x); \
-        })
-
-#define STARTSWITH_SET(p, ...)                                  \
-        ({                                                      \
-                const char *_p = (p);                           \
-                char  *_found = NULL, **_i;                     \
-                STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) {      \
-                        _found = startswith(_p, *_i);           \
-                        if (_found)                             \
-                                break;                          \
-                }                                               \
-                _found;                                         \
-        })
-
-#define ENDSWITH_SET(p, ...)                                    \
-        ({                                                      \
-                const char *_p = (p);                           \
-                char  *_found = NULL, **_i;                     \
-                STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__)) {      \
-                        _found = endswith(_p, *_i);             \
-                        if (_found)                             \
-                                break;                          \
-                }                                               \
-                _found;                                         \
-        })
-
-#define FOREACH_STRING(x, y, ...)                                       \
-        for (char **_l = STRV_MAKE(({ x = y; }), ##__VA_ARGS__);        \
-             x;                                                         \
-             x = *(++_l))
-
-char **strv_reverse(char **l);
-char **strv_shell_escape(char **l, const char *bad);
-
-bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos);
-static inline bool strv_fnmatch(char* const* patterns, const char *s) {
-        return strv_fnmatch_full(patterns, s, 0, NULL);
-}
-
-static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) {
-        assert(s);
-        return strv_isempty(patterns) ||
-               strv_fnmatch_full(patterns, s, flags, NULL);
-}
-
-char ***strv_free_free(char ***l);
-DEFINE_TRIVIAL_CLEANUP_FUNC(char***, strv_free_free);
-
-char **strv_skip(char **l, size_t n);
-
-int strv_extend_n(char ***l, const char *value, size_t n);
-
-int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
-
-#define strv_free_and_replace(a, b)             \
-        ({                                      \
-                strv_free(a);                   \
-                (a) = (b);                      \
-                (b) = NULL;                     \
-                0;                              \
-        })
-
-extern const struct hash_ops string_strv_hash_ops;
-int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS);
-int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value  HASHMAP_DEBUG_PARAMS);
-#define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v  HASHMAP_DEBUG_SRC_ARGS)
-#define string_strv_ordered_hashmap_put(h, k, v) _string_strv_ordered_hashmap_put(h, k, v  HASHMAP_DEBUG_SRC_ARGS)
diff --git a/shared/systemd/src/basic/strxcpyx.c b/shared/systemd/src/basic/strxcpyx.c
deleted file mode 100644
index 39aebb88..00000000
--- a/shared/systemd/src/basic/strxcpyx.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-/*
- * Concatenates/copies strings. In any case, terminates in all cases
- * with '\0' and moves the @dest pointer forward to the added '\0'.
- * Returns the remaining size, and 0 if the string was truncated.
- *
- * Due to the intended usage, these helpers silently noop invocations
- * having zero size.  This is technically an exception to the above
- * statement "terminates in all cases".  It's unexpected for such calls to
- * occur outside of a loop where this is the preferred behavior.
- */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "strxcpyx.h"
-
-size_t strnpcpy(char **dest, size_t size, const char *src, size_t len) {
-        assert(dest);
-        assert(src);
-
-        if (size == 0)
-                return 0;
-
-        if (len >= size) {
-                if (size > 1)
-                        *dest = mempcpy(*dest, src, size-1);
-                size = 0;
-        } else if (len > 0) {
-                *dest = mempcpy(*dest, src, len);
-                size -= len;
-        }
-
-        *dest[0] = '\0';
-        return size;
-}
-
-size_t strpcpy(char **dest, size_t size, const char *src) {
-        assert(dest);
-        assert(src);
-
-        return strnpcpy(dest, size, src, strlen(src));
-}
-
-size_t strpcpyf(char **dest, size_t size, const char *src, ...) {
-        va_list va;
-        int i;
-
-        assert(dest);
-        assert(src);
-
-        if (size == 0)
-                return 0;
-
-        va_start(va, src);
-        i = vsnprintf(*dest, size, src, va);
-        if (i < (int)size) {
-                *dest += i;
-                size -= i;
-        } else
-                size = 0;
-        va_end(va);
-        return size;
-}
-
-size_t strpcpyl(char **dest, size_t size, const char *src, ...) {
-        va_list va;
-
-        assert(dest);
-        assert(src);
-
-        va_start(va, src);
-        do {
-                size = strpcpy(dest, size, src);
-                src = va_arg(va, char *);
-        } while (src);
-        va_end(va);
-        return size;
-}
-
-size_t strnscpy(char *dest, size_t size, const char *src, size_t len) {
-        char *s;
-
-        assert(dest);
-        assert(src);
-
-        s = dest;
-        return strnpcpy(&s, size, src, len);
-}
-
-size_t strscpy(char *dest, size_t size, const char *src) {
-        assert(dest);
-        assert(src);
-
-        return strnscpy(dest, size, src, strlen(src));
-}
-
-size_t strscpyl(char *dest, size_t size, const char *src, ...) {
-        va_list va;
-        char *s;
-
-        assert(dest);
-        assert(src);
-
-        va_start(va, src);
-        s = dest;
-        do {
-                size = strpcpy(&s, size, src);
-                src = va_arg(va, char *);
-        } while (src);
-        va_end(va);
-
-        return size;
-}
diff --git a/shared/systemd/src/basic/strxcpyx.h b/shared/systemd/src/basic/strxcpyx.h
deleted file mode 100644
index cdef492d..00000000
--- a/shared/systemd/src/basic/strxcpyx.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stddef.h>
-
-#include "macro.h"
-
-size_t strnpcpy(char **dest, size_t size, const char *src, size_t len);
-size_t strpcpy(char **dest, size_t size, const char *src);
-size_t strpcpyf(char **dest, size_t size, const char *src, ...) _printf_(3, 4);
-size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_;
-size_t strnscpy(char *dest, size_t size, const char *src, size_t len);
-size_t strscpy(char *dest, size_t size, const char *src);
-size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_;
diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c
deleted file mode 100644
index e5faa334..00000000
--- a/shared/systemd/src/basic/time-util.c
+++ /dev/null
@@ -1,1620 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <sys/timerfd.h>
-#include <sys/timex.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "io-util.h"
-#include "log.h"
-#include "macro.h"
-#include "missing_timerfd.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "stat-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "time-util.h"
-
-static clockid_t map_clock_id(clockid_t c) {
-
-        /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will
-         * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is
-         * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on
-         * those archs. */
-
-        switch (c) {
-
-        case CLOCK_BOOTTIME_ALARM:
-                return CLOCK_BOOTTIME;
-
-        case CLOCK_REALTIME_ALARM:
-                return CLOCK_REALTIME;
-
-        default:
-                return c;
-        }
-}
-
-usec_t now(clockid_t clock_id) {
-        struct timespec ts;
-
-        assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
-
-        return timespec_load(&ts);
-}
-
-nsec_t now_nsec(clockid_t clock_id) {
-        struct timespec ts;
-
-        assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
-
-        return timespec_load_nsec(&ts);
-}
-
-dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
-        assert(ts);
-
-        ts->realtime = now(CLOCK_REALTIME);
-        ts->monotonic = now(CLOCK_MONOTONIC);
-
-        return ts;
-}
-
-triple_timestamp* triple_timestamp_get(triple_timestamp *ts) {
-        assert(ts);
-
-        ts->realtime = now(CLOCK_REALTIME);
-        ts->monotonic = now(CLOCK_MONOTONIC);
-        ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY;
-
-        return ts;
-}
-
-static usec_t map_clock_usec_internal(usec_t from, usec_t from_base, usec_t to_base) {
-
-        /* Maps the time 'from' between two clocks, based on a common reference point where the first clock
-         * is at 'from_base' and the second clock at 'to_base'. Basically calculates:
-         *
-         *         from - from_base + to_base
-         *
-         * But takes care of overflows/underflows and avoids signed operations. */
-
-        if (from >= from_base) { /* In the future */
-                usec_t delta = from - from_base;
-
-                if (to_base >= USEC_INFINITY - delta) /* overflow? */
-                        return USEC_INFINITY;
-
-                return to_base + delta;
-
-        } else { /* In the past */
-                usec_t delta = from_base - from;
-
-                if (to_base <= delta) /* underflow? */
-                        return 0;
-
-                return to_base - delta;
-        }
-}
-
-usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock) {
-
-        /* Try to avoid any inaccuracy needlessly added in case we convert from effectively the same clock
-         * onto itself */
-        if (map_clock_id(from_clock) == map_clock_id(to_clock))
-                return from;
-
-        /* Keep infinity as is */
-        if (from == USEC_INFINITY)
-                return from;
-
-        return map_clock_usec_internal(from, now(from_clock), now(to_clock));
-}
-
-dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
-        assert(ts);
-
-        if (u == USEC_INFINITY || u == 0) {
-                ts->realtime = ts->monotonic = u;
-                return ts;
-        }
-
-        ts->realtime = u;
-        ts->monotonic = map_clock_usec(u, CLOCK_REALTIME, CLOCK_MONOTONIC);
-        return ts;
-}
-
-triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) {
-        usec_t nowr;
-
-        assert(ts);
-
-        if (u == USEC_INFINITY || u == 0) {
-                ts->realtime = ts->monotonic = ts->boottime = u;
-                return ts;
-        }
-
-        nowr = now(CLOCK_REALTIME);
-
-        ts->realtime = u;
-        ts->monotonic = map_clock_usec_internal(u, nowr, now(CLOCK_MONOTONIC));
-        ts->boottime = clock_boottime_supported() ?
-                map_clock_usec_internal(u, nowr, now(CLOCK_BOOTTIME)) :
-                USEC_INFINITY;
-
-        return ts;
-}
-
-dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
-        assert(ts);
-
-        if (u == USEC_INFINITY) {
-                ts->realtime = ts->monotonic = USEC_INFINITY;
-                return ts;
-        }
-
-        ts->monotonic = u;
-        ts->realtime = map_clock_usec(u, CLOCK_MONOTONIC, CLOCK_REALTIME);
-        return ts;
-}
-
-dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
-        clockid_t cid;
-        usec_t nowm;
-
-        if (u == USEC_INFINITY) {
-                ts->realtime = ts->monotonic = USEC_INFINITY;
-                return ts;
-        }
-
-        cid = clock_boottime_or_monotonic();
-        nowm = now(cid);
-
-        if (cid == CLOCK_MONOTONIC)
-                ts->monotonic = u;
-        else
-                ts->monotonic = map_clock_usec_internal(u, nowm, now(CLOCK_MONOTONIC));
-
-        ts->realtime = map_clock_usec_internal(u, nowm, now(CLOCK_REALTIME));
-        return ts;
-}
-
-usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) {
-
-        switch (clock) {
-
-        case CLOCK_REALTIME:
-        case CLOCK_REALTIME_ALARM:
-                return ts->realtime;
-
-        case CLOCK_MONOTONIC:
-                return ts->monotonic;
-
-        case CLOCK_BOOTTIME:
-        case CLOCK_BOOTTIME_ALARM:
-                return ts->boottime;
-
-        default:
-                return USEC_INFINITY;
-        }
-}
-
-usec_t timespec_load(const struct timespec *ts) {
-        assert(ts);
-
-        if (ts->tv_sec < 0 || ts->tv_nsec < 0)
-                return USEC_INFINITY;
-
-        if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
-                return USEC_INFINITY;
-
-        return
-                (usec_t) ts->tv_sec * USEC_PER_SEC +
-                (usec_t) ts->tv_nsec / NSEC_PER_USEC;
-}
-
-nsec_t timespec_load_nsec(const struct timespec *ts) {
-        assert(ts);
-
-        if (ts->tv_sec < 0 || ts->tv_nsec < 0)
-                return NSEC_INFINITY;
-
-        if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC)
-                return NSEC_INFINITY;
-
-        return (nsec_t) ts->tv_sec * NSEC_PER_SEC + (nsec_t) ts->tv_nsec;
-}
-
-struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
-        assert(ts);
-
-        if (u == USEC_INFINITY ||
-            u / USEC_PER_SEC >= TIME_T_MAX) {
-                ts->tv_sec = (time_t) -1;
-                ts->tv_nsec = -1L;
-                return ts;
-        }
-
-        ts->tv_sec = (time_t) (u / USEC_PER_SEC);
-        ts->tv_nsec = (long) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
-
-        return ts;
-}
-
-struct timespec *timespec_store_nsec(struct timespec *ts, nsec_t n)  {
-        assert(ts);
-
-        if (n == NSEC_INFINITY ||
-            n / NSEC_PER_SEC >= TIME_T_MAX) {
-                ts->tv_sec = (time_t) -1;
-                ts->tv_nsec = -1L;
-                return ts;
-        }
-
-        ts->tv_sec = (time_t) (n / NSEC_PER_SEC);
-        ts->tv_nsec = (long) (n % NSEC_PER_SEC);
-
-        return ts;
-}
-
-#if 0 /* NM_IGNORED */
-usec_t timeval_load(const struct timeval *tv) {
-        assert(tv);
-
-        if (tv->tv_sec < 0 || tv->tv_usec < 0)
-                return USEC_INFINITY;
-
-        if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
-                return USEC_INFINITY;
-
-        return
-                (usec_t) tv->tv_sec * USEC_PER_SEC +
-                (usec_t) tv->tv_usec;
-}
-
-struct timeval *timeval_store(struct timeval *tv, usec_t u) {
-        assert(tv);
-
-        if (u == USEC_INFINITY ||
-            u / USEC_PER_SEC > TIME_T_MAX) {
-                tv->tv_sec = (time_t) -1;
-                tv->tv_usec = (suseconds_t) -1;
-        } else {
-                tv->tv_sec = (time_t) (u / USEC_PER_SEC);
-                tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
-        }
-
-        return tv;
-}
-
-char *format_timestamp_style(
-                char *buf,
-                size_t l,
-                usec_t t,
-                TimestampStyle style) {
-
-        /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
-         * generated timestamps may be parsed with parse_timestamp(), and always read the same. */
-        static const char * const weekdays[] = {
-                [0] = "Sun",
-                [1] = "Mon",
-                [2] = "Tue",
-                [3] = "Wed",
-                [4] = "Thu",
-                [5] = "Fri",
-                [6] = "Sat",
-        };
-
-        struct tm tm;
-        time_t sec;
-        size_t n;
-        bool utc = false, us = false;
-
-        assert(buf);
-
-        switch (style) {
-                case TIMESTAMP_PRETTY:
-                        break;
-                case TIMESTAMP_US:
-                        us = true;
-                        break;
-                case TIMESTAMP_UTC:
-                        utc = true;
-                        break;
-                case TIMESTAMP_US_UTC:
-                        us = true;
-                        utc = true;
-                        break;
-                default:
-                        return NULL;
-        }
-
-        if (l < (size_t) (3 +                  /* week day */
-                          1 + 10 +             /* space and date */
-                          1 + 8 +              /* space and time */
-                          (us ? 1 + 6 : 0) +   /* "." and microsecond part */
-                          1 + 1 +              /* space and shortest possible zone */
-                          1))
-                return NULL; /* Not enough space even for the shortest form. */
-        if (t <= 0 || t == USEC_INFINITY)
-                return NULL; /* Timestamp is unset */
-
-        /* Let's not format times with years > 9999 */
-        if (t > USEC_TIMESTAMP_FORMATTABLE_MAX) {
-                assert(l >= STRLEN("--- XXXX-XX-XX XX:XX:XX") + 1);
-                strcpy(buf, "--- XXXX-XX-XX XX:XX:XX");
-                return buf;
-        }
-
-        sec = (time_t) (t / USEC_PER_SEC); /* Round down */
-
-        if (!localtime_or_gmtime_r(&sec, &tm, utc))
-                return NULL;
-
-        /* Start with the week day */
-        assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays));
-        memcpy(buf, weekdays[tm.tm_wday], 4);
-
-        /* Add the main components */
-        if (strftime(buf + 3, l - 3, " %Y-%m-%d %H:%M:%S", &tm) <= 0)
-                return NULL; /* Doesn't fit */
-
-        /* Append the microseconds part, if that's requested */
-        if (us) {
-                n = strlen(buf);
-                if (n + 8 > l)
-                        return NULL; /* Microseconds part doesn't fit. */
-
-                sprintf(buf + n, ".%06"PRI_USEC, t % USEC_PER_SEC);
-        }
-
-        /* Append the timezone */
-        n = strlen(buf);
-        if (utc) {
-                /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the
-                 * obsolete "GMT" instead. */
-                if (n + 5 > l)
-                        return NULL; /* "UTC" doesn't fit. */
-
-                strcpy(buf + n, " UTC");
-
-        } else if (!isempty(tm.tm_zone)) {
-                size_t tn;
-
-                /* An explicit timezone is specified, let's use it, if it fits */
-                tn = strlen(tm.tm_zone);
-                if (n + 1 + tn + 1 > l) {
-                        /* The full time zone does not fit in. Yuck. */
-
-                        if (n + 1 + _POSIX_TZNAME_MAX + 1 > l)
-                                return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */
-
-                        /* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX
-                         * minimum time zone length. In this case suppress the timezone entirely, in order not to dump
-                         * an overly long, hard to read string on the user. This should be safe, because the user will
-                         * assume the local timezone anyway if none is shown. And so does parse_timestamp(). */
-                } else {
-                        buf[n++] = ' ';
-                        strcpy(buf + n, tm.tm_zone);
-                }
-        }
-
-        return buf;
-}
-
-char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
-        const char *s;
-        usec_t n, d;
-
-        if (t <= 0 || t == USEC_INFINITY)
-                return NULL;
-
-        n = now(CLOCK_REALTIME);
-        if (n > t) {
-                d = n - t;
-                s = "ago";
-        } else {
-                d = t - n;
-                s = "left";
-        }
-
-        if (d >= USEC_PER_YEAR)
-                snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s",
-                         d / USEC_PER_YEAR,
-                         (d % USEC_PER_YEAR) / USEC_PER_MONTH, s);
-        else if (d >= USEC_PER_MONTH)
-                snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s",
-                         d / USEC_PER_MONTH,
-                         (d % USEC_PER_MONTH) / USEC_PER_DAY, s);
-        else if (d >= USEC_PER_WEEK)
-                snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s",
-                         d / USEC_PER_WEEK,
-                         (d % USEC_PER_WEEK) / USEC_PER_DAY, s);
-        else if (d >= 2*USEC_PER_DAY)
-                snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s);
-        else if (d >= 25*USEC_PER_HOUR)
-                snprintf(buf, l, "1 day " USEC_FMT "h %s",
-                         (d - USEC_PER_DAY) / USEC_PER_HOUR, s);
-        else if (d >= 6*USEC_PER_HOUR)
-                snprintf(buf, l, USEC_FMT "h %s",
-                         d / USEC_PER_HOUR, s);
-        else if (d >= USEC_PER_HOUR)
-                snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s",
-                         d / USEC_PER_HOUR,
-                         (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s);
-        else if (d >= 5*USEC_PER_MINUTE)
-                snprintf(buf, l, USEC_FMT "min %s",
-                         d / USEC_PER_MINUTE, s);
-        else if (d >= USEC_PER_MINUTE)
-                snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s",
-                         d / USEC_PER_MINUTE,
-                         (d % USEC_PER_MINUTE) / USEC_PER_SEC, s);
-        else if (d >= USEC_PER_SEC)
-                snprintf(buf, l, USEC_FMT "s %s",
-                         d / USEC_PER_SEC, s);
-        else if (d >= USEC_PER_MSEC)
-                snprintf(buf, l, USEC_FMT "ms %s",
-                         d / USEC_PER_MSEC, s);
-        else if (d > 0)
-                snprintf(buf, l, USEC_FMT"us %s",
-                         d, s);
-        else
-                snprintf(buf, l, "now");
-
-        buf[l-1] = 0;
-        return buf;
-}
-#endif /* NM_IGNORED */
-
-char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
-        static const struct {
-                const char *suffix;
-                usec_t usec;
-        } table[] = {
-                { "y",     USEC_PER_YEAR   },
-                { "month", USEC_PER_MONTH  },
-                { "w",     USEC_PER_WEEK   },
-                { "d",     USEC_PER_DAY    },
-                { "h",     USEC_PER_HOUR   },
-                { "min",   USEC_PER_MINUTE },
-                { "s",     USEC_PER_SEC    },
-                { "ms",    USEC_PER_MSEC   },
-                { "us",    1               },
-        };
-
-        size_t i;
-        char *p = buf;
-        bool something = false;
-
-        assert(buf);
-        assert(l > 0);
-
-        if (t == USEC_INFINITY) {
-                strncpy(p, "infinity", l-1);
-                p[l-1] = 0;
-                return p;
-        }
-
-        if (t <= 0) {
-                strncpy(p, "0", l-1);
-                p[l-1] = 0;
-                return p;
-        }
-
-        /* The result of this function can be parsed with parse_sec */
-
-        for (i = 0; i < ELEMENTSOF(table); i++) {
-                int k = 0;
-                size_t n;
-                bool done = false;
-                usec_t a, b;
-
-                if (t <= 0)
-                        break;
-
-                if (t < accuracy && something)
-                        break;
-
-                if (t < table[i].usec)
-                        continue;
-
-                if (l <= 1)
-                        break;
-
-                a = t / table[i].usec;
-                b = t % table[i].usec;
-
-                /* Let's see if we should shows this in dot notation */
-                if (t < USEC_PER_MINUTE && b > 0) {
-                        usec_t cc;
-                        signed char j;
-
-                        j = 0;
-                        for (cc = table[i].usec; cc > 1; cc /= 10)
-                                j++;
-
-                        for (cc = accuracy; cc > 1; cc /= 10) {
-                                b /= 10;
-                                j--;
-                        }
-
-                        if (j > 0) {
-                                k = snprintf(p, l,
-                                             "%s"USEC_FMT".%0*"PRI_USEC"%s",
-                                             p > buf ? " " : "",
-                                             a,
-                                             j,
-                                             b,
-                                             table[i].suffix);
-
-                                t = 0;
-                                done = true;
-                        }
-                }
-
-                /* No? Then let's show it normally */
-                if (!done) {
-                        k = snprintf(p, l,
-                                     "%s"USEC_FMT"%s",
-                                     p > buf ? " " : "",
-                                     a,
-                                     table[i].suffix);
-
-                        t = b;
-                }
-
-                n = MIN((size_t) k, l);
-
-                l -= n;
-                p += n;
-
-                something = true;
-        }
-
-        *p = 0;
-
-        return buf;
-}
-
-#if 0 /* NM_IGNORED */
-static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
-        static const struct {
-                const char *name;
-                const int nr;
-        } day_nr[] = {
-                { "Sunday",    0 },
-                { "Sun",       0 },
-                { "Monday",    1 },
-                { "Mon",       1 },
-                { "Tuesday",   2 },
-                { "Tue",       2 },
-                { "Wednesday", 3 },
-                { "Wed",       3 },
-                { "Thursday",  4 },
-                { "Thu",       4 },
-                { "Friday",    5 },
-                { "Fri",       5 },
-                { "Saturday",  6 },
-                { "Sat",       6 },
-        };
-
-        const char *k, *utc = NULL, *tzn = NULL;
-        struct tm tm, copy;
-        time_t x;
-        usec_t x_usec, plus = 0, minus = 0, ret;
-        int r, weekday = -1, dst = -1;
-        size_t i;
-
-        /* Allowed syntaxes:
-         *
-         *   2012-09-22 16:34:22
-         *   2012-09-22 16:34     (seconds will be set to 0)
-         *   2012-09-22           (time will be set to 00:00:00)
-         *   16:34:22             (date will be set to today)
-         *   16:34                (date will be set to today, seconds to 0)
-         *   now
-         *   yesterday            (time is set to 00:00:00)
-         *   today                (time is set to 00:00:00)
-         *   tomorrow             (time is set to 00:00:00)
-         *   +5min
-         *   -5days
-         *   @2147483647          (seconds since epoch)
-         */
-
-        assert(t);
-
-        if (t[0] == '@' && !with_tz)
-                return parse_sec(t + 1, usec);
-
-        ret = now(CLOCK_REALTIME);
-
-        if (!with_tz) {
-                if (streq(t, "now"))
-                        goto finish;
-
-                else if (t[0] == '+') {
-                        r = parse_sec(t+1, &plus);
-                        if (r < 0)
-                                return r;
-
-                        goto finish;
-
-                } else if (t[0] == '-') {
-                        r = parse_sec(t+1, &minus);
-                        if (r < 0)
-                                return r;
-
-                        goto finish;
-
-                } else if ((k = endswith(t, " ago"))) {
-                        t = strndupa(t, k - t);
-
-                        r = parse_sec(t, &minus);
-                        if (r < 0)
-                                return r;
-
-                        goto finish;
-
-                } else if ((k = endswith(t, " left"))) {
-                        t = strndupa(t, k - t);
-
-                        r = parse_sec(t, &plus);
-                        if (r < 0)
-                                return r;
-
-                        goto finish;
-                }
-
-                /* See if the timestamp is suffixed with UTC */
-                utc = endswith_no_case(t, " UTC");
-                if (utc)
-                        t = strndupa(t, utc - t);
-                else {
-                        const char *e = NULL;
-                        int j;
-
-                        tzset();
-
-                        /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
-                         * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
-                         * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
-                         * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
-                         * support arbitrary timezone specifications. */
-
-                        for (j = 0; j <= 1; j++) {
-
-                                if (isempty(tzname[j]))
-                                        continue;
-
-                                e = endswith_no_case(t, tzname[j]);
-                                if (!e)
-                                        continue;
-                                if (e == t)
-                                        continue;
-                                if (e[-1] != ' ')
-                                        continue;
-
-                                break;
-                        }
-
-                        if (IN_SET(j, 0, 1)) {
-                                /* Found one of the two timezones specified. */
-                                t = strndupa(t, e - t - 1);
-                                dst = j;
-                                tzn = tzname[j];
-                        }
-                }
-        }
-
-        x = (time_t) (ret / USEC_PER_SEC);
-        x_usec = 0;
-
-        if (!localtime_or_gmtime_r(&x, &tm, utc))
-                return -EINVAL;
-
-        tm.tm_isdst = dst;
-        if (!with_tz && tzn)
-                tm.tm_zone = tzn;
-
-        if (streq(t, "today")) {
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto from_tm;
-
-        } else if (streq(t, "yesterday")) {
-                tm.tm_mday--;
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto from_tm;
-
-        } else if (streq(t, "tomorrow")) {
-                tm.tm_mday++;
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto from_tm;
-        }
-
-        for (i = 0; i < ELEMENTSOF(day_nr); i++) {
-                size_t skip;
-
-                if (!startswith_no_case(t, day_nr[i].name))
-                        continue;
-
-                skip = strlen(day_nr[i].name);
-                if (t[skip] != ' ')
-                        continue;
-
-                weekday = day_nr[i].nr;
-                t += skip + 1;
-                break;
-        }
-
-        copy = tm;
-        k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
-        if (k) {
-                if (*k == '.')
-                        goto parse_usec;
-                else if (*k == 0)
-                        goto from_tm;
-        }
-
-        tm = copy;
-        k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
-        if (k) {
-                if (*k == '.')
-                        goto parse_usec;
-                else if (*k == 0)
-                        goto from_tm;
-        }
-
-        tm = copy;
-        k = strptime(t, "%y-%m-%d %H:%M", &tm);
-        if (k && *k == 0) {
-                tm.tm_sec = 0;
-                goto from_tm;
-        }
-
-        tm = copy;
-        k = strptime(t, "%Y-%m-%d %H:%M", &tm);
-        if (k && *k == 0) {
-                tm.tm_sec = 0;
-                goto from_tm;
-        }
-
-        tm = copy;
-        k = strptime(t, "%y-%m-%d", &tm);
-        if (k && *k == 0) {
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto from_tm;
-        }
-
-        tm = copy;
-        k = strptime(t, "%Y-%m-%d", &tm);
-        if (k && *k == 0) {
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto from_tm;
-        }
-
-        tm = copy;
-        k = strptime(t, "%H:%M:%S", &tm);
-        if (k) {
-                if (*k == '.')
-                        goto parse_usec;
-                else if (*k == 0)
-                        goto from_tm;
-        }
-
-        tm = copy;
-        k = strptime(t, "%H:%M", &tm);
-        if (k && *k == 0) {
-                tm.tm_sec = 0;
-                goto from_tm;
-        }
-
-        return -EINVAL;
-
-parse_usec:
-        {
-                unsigned add;
-
-                k++;
-                r = parse_fractional_part_u(&k, 6, &add);
-                if (r < 0)
-                        return -EINVAL;
-
-                if (*k)
-                        return -EINVAL;
-
-                x_usec = add;
-        }
-
-from_tm:
-        if (weekday >= 0 && tm.tm_wday != weekday)
-                return -EINVAL;
-
-        x = mktime_or_timegm(&tm, utc);
-        if (x < 0)
-                return -EINVAL;
-
-        ret = (usec_t) x * USEC_PER_SEC + x_usec;
-        if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
-                return -EINVAL;
-
-finish:
-        if (ret + plus < ret) /* overflow? */
-                return -EINVAL;
-        ret += plus;
-        if (ret > USEC_TIMESTAMP_FORMATTABLE_MAX)
-                return -EINVAL;
-
-        if (ret >= minus)
-                ret -= minus;
-        else
-                return -EINVAL;
-
-        if (usec)
-                *usec = ret;
-        return 0;
-}
-
-typedef struct ParseTimestampResult {
-        usec_t usec;
-        int return_value;
-} ParseTimestampResult;
-
-int parse_timestamp(const char *t, usec_t *usec) {
-        char *last_space, *tz = NULL;
-        ParseTimestampResult *shared, tmp;
-        int r;
-
-        last_space = strrchr(t, ' ');
-        if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG))
-                tz = last_space + 1;
-
-        if (!tz || endswith_no_case(t, " UTC"))
-                return parse_timestamp_impl(t, usec, false);
-
-        shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
-        if (shared == MAP_FAILED)
-                return negative_errno();
-
-        r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT, NULL);
-        if (r < 0) {
-                (void) munmap(shared, sizeof *shared);
-                return r;
-        }
-        if (r == 0) {
-                bool with_tz = true;
-                char *colon_tz;
-
-                /* tzset(3) says $TZ should be prefixed with ":" if we reference timezone files */
-                colon_tz = strjoina(":", tz);
-
-                if (setenv("TZ", colon_tz, 1) != 0) {
-                        shared->return_value = negative_errno();
-                        _exit(EXIT_FAILURE);
-                }
-
-                tzset();
-
-                /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
-                 * Otherwise just cut it off. */
-                with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
-
-                /* Cut off the timezone if we don't need it. */
-                if (with_tz)
-                        t = strndupa(t, last_space - t);
-
-                shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
-
-                _exit(EXIT_SUCCESS);
-        }
-
-        tmp = *shared;
-        if (munmap(shared, sizeof *shared) != 0)
-                return negative_errno();
-
-        if (tmp.return_value == 0 && usec)
-                *usec = tmp.usec;
-
-        return tmp.return_value;
-}
-
-static const char* extract_multiplier(const char *p, usec_t *multiplier) {
-        static const struct {
-                const char *suffix;
-                usec_t usec;
-        } table[] = {
-                { "seconds", USEC_PER_SEC    },
-                { "second",  USEC_PER_SEC    },
-                { "sec",     USEC_PER_SEC    },
-                { "s",       USEC_PER_SEC    },
-                { "minutes", USEC_PER_MINUTE },
-                { "minute",  USEC_PER_MINUTE },
-                { "min",     USEC_PER_MINUTE },
-                { "months",  USEC_PER_MONTH  },
-                { "month",   USEC_PER_MONTH  },
-                { "M",       USEC_PER_MONTH  },
-                { "msec",    USEC_PER_MSEC   },
-                { "ms",      USEC_PER_MSEC   },
-                { "m",       USEC_PER_MINUTE },
-                { "hours",   USEC_PER_HOUR   },
-                { "hour",    USEC_PER_HOUR   },
-                { "hr",      USEC_PER_HOUR   },
-                { "h",       USEC_PER_HOUR   },
-                { "days",    USEC_PER_DAY    },
-                { "day",     USEC_PER_DAY    },
-                { "d",       USEC_PER_DAY    },
-                { "weeks",   USEC_PER_WEEK   },
-                { "week",    USEC_PER_WEEK   },
-                { "w",       USEC_PER_WEEK   },
-                { "years",   USEC_PER_YEAR   },
-                { "year",    USEC_PER_YEAR   },
-                { "y",       USEC_PER_YEAR   },
-                { "usec",    1ULL            },
-                { "us",      1ULL            },
-                { "µs",      1ULL            },
-        };
-        size_t i;
-
-        for (i = 0; i < ELEMENTSOF(table); i++) {
-                char *e;
-
-                e = startswith(p, table[i].suffix);
-                if (e) {
-                        *multiplier = table[i].usec;
-                        return e;
-                }
-        }
-
-        return p;
-}
-
-int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
-        const char *p, *s;
-        usec_t r = 0;
-        bool something = false;
-
-        assert(t);
-        assert(default_unit > 0);
-
-        p = t;
-
-        p += strspn(p, WHITESPACE);
-        s = startswith(p, "infinity");
-        if (s) {
-                s += strspn(s, WHITESPACE);
-                if (*s != 0)
-                        return -EINVAL;
-
-                if (usec)
-                        *usec = USEC_INFINITY;
-                return 0;
-        }
-
-        for (;;) {
-                usec_t multiplier = default_unit, k;
-                long long l;
-                char *e;
-
-                p += strspn(p, WHITESPACE);
-
-                if (*p == 0) {
-                        if (!something)
-                                return -EINVAL;
-
-                        break;
-                }
-
-                if (*p == '-') /* Don't allow "-0" */
-                        return -ERANGE;
-
-                errno = 0;
-                l = strtoll(p, &e, 10);
-                if (errno > 0)
-                        return -errno;
-                if (l < 0)
-                        return -ERANGE;
-
-                if (*e == '.') {
-                        p = e + 1;
-                        p += strspn(p, DIGITS);
-                } else if (e == p)
-                        return -EINVAL;
-                else
-                        p = e;
-
-                s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier);
-                if (s == p && *s != '\0')
-                        /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
-                        return -EINVAL;
-
-                p = s;
-
-                if ((usec_t) l >= USEC_INFINITY / multiplier)
-                        return -ERANGE;
-
-                k = (usec_t) l * multiplier;
-                if (k >= USEC_INFINITY - r)
-                        return -ERANGE;
-
-                r += k;
-
-                something = true;
-
-                if (*e == '.') {
-                        usec_t m = multiplier / 10;
-                        const char *b;
-
-                        for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
-                                k = (usec_t) (*b - '0') * m;
-                                if (k >= USEC_INFINITY - r)
-                                        return -ERANGE;
-
-                                r += k;
-                        }
-
-                        /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
-                        if (b == e + 1)
-                                return -EINVAL;
-                }
-        }
-
-        if (usec)
-                *usec = r;
-        return 0;
-}
-
-int parse_sec(const char *t, usec_t *usec) {
-        return parse_time(t, usec, USEC_PER_SEC);
-}
-
-int parse_sec_fix_0(const char *t, usec_t *ret) {
-        usec_t k;
-        int r;
-
-        assert(t);
-        assert(ret);
-
-        r = parse_sec(t, &k);
-        if (r < 0)
-                return r;
-
-        *ret = k == 0 ? USEC_INFINITY : k;
-        return r;
-}
-
-int parse_sec_def_infinity(const char *t, usec_t *ret) {
-        t += strspn(t, WHITESPACE);
-        if (isempty(t)) {
-                *ret = USEC_INFINITY;
-                return 0;
-        }
-        return parse_sec(t, ret);
-}
-
-static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
-        static const struct {
-                const char *suffix;
-                nsec_t nsec;
-        } table[] = {
-                { "seconds", NSEC_PER_SEC    },
-                { "second",  NSEC_PER_SEC    },
-                { "sec",     NSEC_PER_SEC    },
-                { "s",       NSEC_PER_SEC    },
-                { "minutes", NSEC_PER_MINUTE },
-                { "minute",  NSEC_PER_MINUTE },
-                { "min",     NSEC_PER_MINUTE },
-                { "months",  NSEC_PER_MONTH  },
-                { "month",   NSEC_PER_MONTH  },
-                { "M",       NSEC_PER_MONTH  },
-                { "msec",    NSEC_PER_MSEC   },
-                { "ms",      NSEC_PER_MSEC   },
-                { "m",       NSEC_PER_MINUTE },
-                { "hours",   NSEC_PER_HOUR   },
-                { "hour",    NSEC_PER_HOUR   },
-                { "hr",      NSEC_PER_HOUR   },
-                { "h",       NSEC_PER_HOUR   },
-                { "days",    NSEC_PER_DAY    },
-                { "day",     NSEC_PER_DAY    },
-                { "d",       NSEC_PER_DAY    },
-                { "weeks",   NSEC_PER_WEEK   },
-                { "week",    NSEC_PER_WEEK   },
-                { "w",       NSEC_PER_WEEK   },
-                { "years",   NSEC_PER_YEAR   },
-                { "year",    NSEC_PER_YEAR   },
-                { "y",       NSEC_PER_YEAR   },
-                { "usec",    NSEC_PER_USEC   },
-                { "us",      NSEC_PER_USEC   },
-                { "µs",      NSEC_PER_USEC   },
-                { "nsec",    1ULL            },
-                { "ns",      1ULL            },
-                { "",        1ULL            }, /* default is nsec */
-        };
-        size_t i;
-
-        for (i = 0; i < ELEMENTSOF(table); i++) {
-                char *e;
-
-                e = startswith(p, table[i].suffix);
-                if (e) {
-                        *multiplier = table[i].nsec;
-                        return e;
-                }
-        }
-
-        return p;
-}
-
-int parse_nsec(const char *t, nsec_t *nsec) {
-        const char *p, *s;
-        nsec_t r = 0;
-        bool something = false;
-
-        assert(t);
-        assert(nsec);
-
-        p = t;
-
-        p += strspn(p, WHITESPACE);
-        s = startswith(p, "infinity");
-        if (s) {
-                s += strspn(s, WHITESPACE);
-                if (*s != 0)
-                        return -EINVAL;
-
-                *nsec = NSEC_INFINITY;
-                return 0;
-        }
-
-        for (;;) {
-                nsec_t multiplier = 1, k;
-                long long l;
-                char *e;
-
-                p += strspn(p, WHITESPACE);
-
-                if (*p == 0) {
-                        if (!something)
-                                return -EINVAL;
-
-                        break;
-                }
-
-                if (*p == '-') /* Don't allow "-0" */
-                        return -ERANGE;
-
-                errno = 0;
-                l = strtoll(p, &e, 10);
-                if (errno > 0)
-                        return -errno;
-                if (l < 0)
-                        return -ERANGE;
-
-                if (*e == '.') {
-                        p = e + 1;
-                        p += strspn(p, DIGITS);
-                } else if (e == p)
-                        return -EINVAL;
-                else
-                        p = e;
-
-                s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier);
-                if (s == p && *s != '\0')
-                        /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
-                        return -EINVAL;
-
-                p = s;
-
-                if ((nsec_t) l >= NSEC_INFINITY / multiplier)
-                        return -ERANGE;
-
-                k = (nsec_t) l * multiplier;
-                if (k >= NSEC_INFINITY - r)
-                        return -ERANGE;
-
-                r += k;
-
-                something = true;
-
-                if (*e == '.') {
-                        nsec_t m = multiplier / 10;
-                        const char *b;
-
-                        for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
-                                k = (nsec_t) (*b - '0') * m;
-                                if (k >= NSEC_INFINITY - r)
-                                        return -ERANGE;
-
-                                r += k;
-                        }
-
-                        /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
-                        if (b == e + 1)
-                                return -EINVAL;
-                }
-        }
-
-        *nsec = r;
-
-        return 0;
-}
-
-bool ntp_synced(void) {
-        struct timex txc = {};
-
-        if (adjtimex(&txc) < 0)
-                return false;
-
-        /* Consider the system clock synchronized if the reported maximum error is smaller than the maximum
-         * value (16 seconds). Ignore the STA_UNSYNC flag as it may have been set to prevent the kernel from
-         * touching the RTC. */
-        if (txc.maxerror >= 16000000)
-                return false;
-
-        return true;
-}
-
-int get_timezones(char ***ret) {
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_strv_free_ char **zones = NULL;
-        size_t n_zones = 0, n_allocated = 0;
-        int r;
-
-        assert(ret);
-
-        zones = strv_new("UTC");
-        if (!zones)
-                return -ENOMEM;
-
-        n_allocated = 2;
-        n_zones = 1;
-
-        f = fopen("/usr/share/zoneinfo/zone1970.tab", "re");
-        if (f) {
-                for (;;) {
-                        _cleanup_free_ char *line = NULL;
-                        char *p, *w;
-                        size_t k;
-
-                        r = read_line(f, LONG_LINE_MAX, &line);
-                        if (r < 0)
-                                return r;
-                        if (r == 0)
-                                break;
-
-                        p = strstrip(line);
-
-                        if (isempty(p) || *p == '#')
-                                continue;
-
-                        /* Skip over country code */
-                        p += strcspn(p, WHITESPACE);
-                        p += strspn(p, WHITESPACE);
-
-                        /* Skip over coordinates */
-                        p += strcspn(p, WHITESPACE);
-                        p += strspn(p, WHITESPACE);
-
-                        /* Found timezone name */
-                        k = strcspn(p, WHITESPACE);
-                        if (k <= 0)
-                                continue;
-
-                        w = strndup(p, k);
-                        if (!w)
-                                return -ENOMEM;
-
-                        if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) {
-                                free(w);
-                                return -ENOMEM;
-                        }
-
-                        zones[n_zones++] = w;
-                        zones[n_zones] = NULL;
-                }
-
-                strv_sort(zones);
-                strv_uniq(zones);
-
-        } else if (errno != ENOENT)
-                return -errno;
-
-        *ret = TAKE_PTR(zones);
-
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-bool timezone_is_valid(const char *name, int log_level) {
-        bool slash = false;
-        const char *p, *t;
-        _cleanup_close_ int fd = -1;
-        char buf[4];
-        int r;
-
-        if (isempty(name))
-                return false;
-
-        /* Always accept "UTC" as valid timezone, since it's the fallback, even if user has no timezones installed. */
-        if (streq(name, "UTC"))
-                return true;
-
-        if (name[0] == '/')
-                return false;
-
-        for (p = name; *p; p++) {
-                if (!(*p >= '0' && *p <= '9') &&
-                    !(*p >= 'a' && *p <= 'z') &&
-                    !(*p >= 'A' && *p <= 'Z') &&
-                    !IN_SET(*p, '-', '_', '+', '/'))
-                        return false;
-
-                if (*p == '/') {
-
-                        if (slash)
-                                return false;
-
-                        slash = true;
-                } else
-                        slash = false;
-        }
-
-        if (slash)
-                return false;
-
-        if (p - name >= PATH_MAX)
-                return false;
-
-        t = strjoina("/usr/share/zoneinfo/", name);
-
-        fd = open(t, O_RDONLY|O_CLOEXEC);
-        if (fd < 0) {
-                log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t);
-                return false;
-        }
-
-        r = fd_verify_regular(fd);
-        if (r < 0) {
-                log_full_errno(log_level, r, "Timezone file '%s' is not  a regular file: %m", t);
-                return false;
-        }
-
-        r = loop_read_exact(fd, buf, 4, false);
-        if (r < 0) {
-                log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t);
-                return false;
-        }
-
-        /* Magic from tzfile(5) */
-        if (memcmp(buf, "TZif", 4) != 0) {
-                log_full(log_level, "Timezone file '%s' has wrong magic bytes", t);
-                return false;
-        }
-
-        return true;
-}
-
-bool clock_boottime_supported(void) {
-        static int supported = -1;
-
-        /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
-
-        if (supported < 0) {
-                int fd;
-
-                fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
-                if (fd < 0)
-                        supported = false;
-                else {
-                        safe_close(fd);
-                        supported = true;
-                }
-        }
-
-        return supported;
-}
-
-clockid_t clock_boottime_or_monotonic(void) {
-        if (clock_boottime_supported())
-                return CLOCK_BOOTTIME;
-        else
-                return CLOCK_MONOTONIC;
-}
-
-bool clock_supported(clockid_t clock) {
-        struct timespec ts;
-
-        switch (clock) {
-
-        case CLOCK_MONOTONIC:
-        case CLOCK_REALTIME:
-                return true;
-
-        case CLOCK_BOOTTIME:
-                return clock_boottime_supported();
-
-        case CLOCK_BOOTTIME_ALARM:
-                if (!clock_boottime_supported())
-                        return false;
-
-                _fallthrough_;
-        default:
-                /* For everything else, check properly */
-                return clock_gettime(clock, &ts) >= 0;
-        }
-}
-
-#if 0 /* NM_IGNORED */
-int get_timezone(char **ret) {
-        _cleanup_free_ char *t = NULL;
-        const char *e;
-        char *z;
-        int r;
-
-        r = readlink_malloc("/etc/localtime", &t);
-        if (r == -ENOENT) {
-                /* If the symlink does not exist, assume "UTC", like glibc does*/
-                z = strdup("UTC");
-                if (!z)
-                        return -ENOMEM;
-
-                *ret = z;
-                return 0;
-        }
-        if (r < 0)
-                return r; /* returns EINVAL if not a symlink */
-
-        e = PATH_STARTSWITH_SET(t, "/usr/share/zoneinfo/", "../usr/share/zoneinfo/");
-        if (!e)
-                return -EINVAL;
-
-        if (!timezone_is_valid(e, LOG_DEBUG))
-                return -EINVAL;
-
-        z = strdup(e);
-        if (!z)
-                return -ENOMEM;
-
-        *ret = z;
-        return 0;
-}
-
-time_t mktime_or_timegm(struct tm *tm, bool utc) {
-        return utc ? timegm(tm) : mktime(tm);
-}
-
-struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
-        return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
-}
-
-static uint32_t sysconf_clock_ticks_cached(void) {
-        static thread_local uint32_t hz = 0;
-        long r;
-
-        if (hz == 0) {
-                r = sysconf(_SC_CLK_TCK);
-
-                assert(r > 0);
-                hz = r;
-        }
-
-        return hz;
-}
-
-uint32_t usec_to_jiffies(usec_t u) {
-        uint32_t hz = sysconf_clock_ticks_cached();
-        return DIV_ROUND_UP(u, USEC_PER_SEC / hz);
-}
-
-usec_t jiffies_to_usec(uint32_t j) {
-        uint32_t hz = sysconf_clock_ticks_cached();
-        return DIV_ROUND_UP(j * USEC_PER_SEC, hz);
-}
-
-usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) {
-        usec_t a, b;
-
-        if (x == USEC_INFINITY)
-                return USEC_INFINITY;
-        if (map_clock_id(from) == map_clock_id(to))
-                return x;
-
-        a = now(from);
-        b = now(to);
-
-        if (x > a)
-                /* x lies in the future */
-                return usec_add(b, usec_sub_unsigned(x, a));
-        else
-                /* x lies in the past */
-                return usec_sub_unsigned(b, usec_sub_unsigned(a, x));
-}
-
-bool in_utc_timezone(void) {
-        tzset();
-
-        return timezone == 0 && daylight == 0;
-}
-
-int time_change_fd(void) {
-
-        /* We only care for the cancellation event, hence we set the timeout to the latest possible value. */
-        static const struct itimerspec its = {
-                .it_value.tv_sec = TIME_T_MAX,
-        };
-
-        _cleanup_close_ int fd;
-
-        assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
-
-        /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever CLOCK_REALTIME makes a jump relative to
-         * CLOCK_MONOTONIC. */
-
-        fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) >= 0)
-                return TAKE_FD(fd);
-
-        /* So apparently there are systems where time_t is 64bit, but the kernel actually doesn't support
-         * 64bit time_t. In that case configuring a timer to TIME_T_MAX will fail with EOPNOTSUPP or a
-         * similar error. If that's the case let's try with INT32_MAX instead, maybe that works. It's a bit
-         * of a black magic thing though, but what can we do?
-         *
-         * We don't want this code on x86-64, hence let's conditionalize this for systems with 64bit time_t
-         * but where "long" is shorter than 64bit, i.e. 32bit archs.
-         *
-         * See: https://github.com/systemd/systemd/issues/14362 */
-
-#if SIZEOF_TIME_T == 8 && ULONG_MAX < UINT64_MAX
-        if (ERRNO_IS_NOT_SUPPORTED(errno) || errno == EOVERFLOW) {
-                static const struct itimerspec its32 = {
-                        .it_value.tv_sec = INT32_MAX,
-                };
-
-                if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its32, NULL) >= 0)
-                        return TAKE_FD(fd);
-        }
-#endif
-
-        return -errno;
-}
-
-static const char* const timestamp_style_table[_TIMESTAMP_STYLE_MAX] = {
-        [TIMESTAMP_PRETTY] = "pretty",
-        [TIMESTAMP_US] = "us",
-        [TIMESTAMP_UTC] = "utc",
-        [TIMESTAMP_US_UTC] = "us+utc",
-};
-
-/* Use the macro for enum → string to allow for aliases */
-_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(timestamp_style, TimestampStyle,);
-
-/* For the string → enum mapping we use the generic implementation, but also support two aliases */
-TimestampStyle timestamp_style_from_string(const char *s) {
-        TimestampStyle t;
-
-        t = (TimestampStyle) string_table_lookup(timestamp_style_table, ELEMENTSOF(timestamp_style_table), s);
-        if (t >= 0)
-                return t;
-        if (streq_ptr(s, "µs"))
-                return TIMESTAMP_US;
-        if (streq_ptr(s, "µs+utc"))
-                return TIMESTAMP_US_UTC;
-        return t;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/time-util.h b/shared/systemd/src/basic/time-util.h
deleted file mode 100644
index 89ee8b4a..00000000
--- a/shared/systemd/src/basic/time-util.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <time.h>
-
-typedef uint64_t usec_t;
-typedef uint64_t nsec_t;
-
-#define PRI_NSEC PRIu64
-#define PRI_USEC PRIu64
-#define NSEC_FMT "%" PRI_NSEC
-#define USEC_FMT "%" PRI_USEC
-
-#include "macro.h"
-
-typedef struct dual_timestamp {
-        usec_t realtime;
-        usec_t monotonic;
-} dual_timestamp;
-
-typedef struct triple_timestamp {
-        usec_t realtime;
-        usec_t monotonic;
-        usec_t boottime;
-} triple_timestamp;
-
-typedef enum TimestampStyle {
-        TIMESTAMP_PRETTY,
-        TIMESTAMP_US,
-        TIMESTAMP_UTC,
-        TIMESTAMP_US_UTC,
-        _TIMESTAMP_STYLE_MAX,
-        _TIMESTAMP_STYLE_INVALID = -1,
-} TimestampStyle;
-
-#define USEC_INFINITY ((usec_t) UINT64_MAX)
-#define NSEC_INFINITY ((nsec_t) UINT64_MAX)
-
-#define MSEC_PER_SEC  1000ULL
-#define USEC_PER_SEC  ((usec_t) 1000000ULL)
-#define USEC_PER_MSEC ((usec_t) 1000ULL)
-#define NSEC_PER_SEC  ((nsec_t) 1000000000ULL)
-#define NSEC_PER_MSEC ((nsec_t) 1000000ULL)
-#define NSEC_PER_USEC ((nsec_t) 1000ULL)
-
-#define USEC_PER_MINUTE ((usec_t) (60ULL*USEC_PER_SEC))
-#define NSEC_PER_MINUTE ((nsec_t) (60ULL*NSEC_PER_SEC))
-#define USEC_PER_HOUR ((usec_t) (60ULL*USEC_PER_MINUTE))
-#define NSEC_PER_HOUR ((nsec_t) (60ULL*NSEC_PER_MINUTE))
-#define USEC_PER_DAY ((usec_t) (24ULL*USEC_PER_HOUR))
-#define NSEC_PER_DAY ((nsec_t) (24ULL*NSEC_PER_HOUR))
-#define USEC_PER_WEEK ((usec_t) (7ULL*USEC_PER_DAY))
-#define NSEC_PER_WEEK ((nsec_t) (7ULL*NSEC_PER_DAY))
-#define USEC_PER_MONTH ((usec_t) (2629800ULL*USEC_PER_SEC))
-#define NSEC_PER_MONTH ((nsec_t) (2629800ULL*NSEC_PER_SEC))
-#define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC))
-#define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC))
-
-/* 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 (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)
-
-#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) {})
-#define TRIPLE_TIMESTAMP_NULL ((struct triple_timestamp) {})
-
-usec_t now(clockid_t clock);
-nsec_t now_nsec(clockid_t clock);
-
-usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock);
-
-dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
-dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
-dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u);
-dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u);
-
-triple_timestamp* triple_timestamp_get(triple_timestamp *ts);
-triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u);
-
-#define DUAL_TIMESTAMP_HAS_CLOCK(clock)                               \
-        IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC)
-
-#define TRIPLE_TIMESTAMP_HAS_CLOCK(clock)                               \
-        IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM)
-
-static inline bool timestamp_is_set(usec_t timestamp) {
-        return timestamp > 0 && timestamp != USEC_INFINITY;
-}
-
-static inline bool dual_timestamp_is_set(const dual_timestamp *ts) {
-        return timestamp_is_set(ts->realtime) ||
-               timestamp_is_set(ts->monotonic);
-}
-
-static inline bool triple_timestamp_is_set(const triple_timestamp *ts) {
-        return timestamp_is_set(ts->realtime) ||
-               timestamp_is_set(ts->monotonic) ||
-               timestamp_is_set(ts->boottime);
-}
-
-usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock);
-
-usec_t timespec_load(const struct timespec *ts) _pure_;
-nsec_t timespec_load_nsec(const struct timespec *ts) _pure_;
-struct timespec *timespec_store(struct timespec *ts, usec_t u);
-struct timespec *timespec_store_nsec(struct timespec *ts, nsec_t n);
-
-usec_t timeval_load(const struct timeval *tv) _pure_;
-struct timeval *timeval_store(struct timeval *tv, usec_t u);
-
-char *format_timestamp_style(char *buf, size_t l, usec_t t, TimestampStyle style);
-char *format_timestamp_relative(char *buf, size_t l, usec_t t);
-char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
-
-static inline char *format_timestamp(char *buf, size_t l, usec_t t) {
-        return format_timestamp_style(buf, l, t, TIMESTAMP_PRETTY);
-}
-
-int parse_timestamp(const char *t, usec_t *usec);
-
-int parse_sec(const char *t, usec_t *usec);
-int parse_sec_fix_0(const char *t, usec_t *usec);
-int parse_sec_def_infinity(const char *t, usec_t *usec);
-int parse_time(const char *t, usec_t *usec, usec_t default_unit);
-int parse_nsec(const char *t, nsec_t *nsec);
-
-bool ntp_synced(void);
-
-int get_timezones(char ***l);
-bool timezone_is_valid(const char *name, int log_level);
-
-bool clock_boottime_supported(void);
-bool clock_supported(clockid_t clock);
-clockid_t clock_boottime_or_monotonic(void);
-
-usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to);
-
-int get_timezone(char **timezone);
-
-time_t mktime_or_timegm(struct tm *tm, bool utc);
-struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
-
-uint32_t usec_to_jiffies(usec_t usec);
-usec_t jiffies_to_usec(uint32_t jiffies);
-
-bool in_utc_timezone(void);
-
-static inline usec_t usec_add(usec_t a, usec_t b) {
-        usec_t c;
-
-        /* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output, and doesn't
-         * overflow. */
-
-        c = a + b;
-        if (c < a || c < b) /* overflow check */
-                return USEC_INFINITY;
-
-        return c;
-}
-
-static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) {
-
-        if (timestamp == USEC_INFINITY) /* Make sure infinity doesn't degrade */
-                return USEC_INFINITY;
-        if (timestamp < delta)
-                return 0;
-
-        return timestamp - delta;
-}
-
-static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
-        if (delta < 0)
-                return usec_add(timestamp, (usec_t) (-delta));
-        else
-                return usec_sub_unsigned(timestamp, (usec_t) delta);
-}
-
-#if SIZEOF_TIME_T == 8
-/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit year
- * territory. However, since we want to stay away from this in all timezones we take one day off. */
-#define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 253402214399000000)
-#elif SIZEOF_TIME_T == 4
-/* With a 32bit time_t we can't go beyond 2038... */
-#define USEC_TIMESTAMP_FORMATTABLE_MAX ((usec_t) 2147483647000000)
-#else
-#error "Yuck, time_t is neither 4 nor 8 bytes wide?"
-#endif
-
-int time_change_fd(void);
-
-const char* timestamp_style_to_string(TimestampStyle t) _const_;
-TimestampStyle timestamp_style_from_string(const char *s) _pure_;
diff --git a/shared/systemd/src/basic/tmpfile-util.c b/shared/systemd/src/basic/tmpfile-util.c
deleted file mode 100644
index bbd6a1ed..00000000
--- a/shared/systemd/src/basic/tmpfile-util.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <sys/mman.h>
-
-#include "alloc-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "hexdecoct.h"
-#include "macro.h"
-#include "memfd-util.h"
-#include "missing_fcntl.h"
-#include "missing_syscall.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "random-util.h"
-#include "stdio-util.h"
-#include "string-util.h"
-#include "tmpfile-util.h"
-#include "umask-util.h"
-
-int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) {
-        _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *t = NULL;
-        _cleanup_close_ int fd = -1;
-        int r;
-
-        if (path) {
-                r = tempfn_xxxxxx(path, NULL, &t);
-                if (r < 0)
-                        return r;
-        } else {
-                const char *d;
-
-                r = tmp_dir(&d);
-                if (r < 0)
-                        return r;
-
-                t = path_join(d, "XXXXXX");
-                if (!t)
-                        return -ENOMEM;
-        }
-
-        fd = mkostemp_safe(t);
-        if (fd < 0)
-                return -errno;
-
-        /* This assumes that returned FILE object is short-lived and used within the same single-threaded
-         * context and never shared externally, hence locking is not necessary. */
-
-        r = take_fdopen_unlocked(&fd, "w", &f);
-        if (r < 0) {
-                (void) unlink(t);
-                return r;
-        }
-
-        if (ret_f)
-                *ret_f = TAKE_PTR(f);
-
-        if (ret_temp_path)
-                *ret_temp_path = TAKE_PTR(t);
-
-        return 0;
-}
-
-/* This is much like mkostemp() but is subject to umask(). */
-int mkostemp_safe(char *pattern) {
-        int fd = -1; /* avoid false maybe-uninitialized warning */
-
-        assert(pattern);
-
-        RUN_WITH_UMASK(0077)
-                fd = mkostemp(pattern, O_CLOEXEC);
-        if (fd < 0)
-                return -errno;
-
-        return fd;
-}
-
-#if 0 /* NM_IGNORED */
-int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
-        _cleanup_close_ int fd = -1;
-        FILE *f;
-
-        fd = mkostemp_safe(pattern);
-        if (fd < 0)
-                return fd;
-
-        f = take_fdopen(&fd, mode);
-        if (!f)
-                return -errno;
-
-        *ret_f = f;
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
-        const char *fn;
-        char *t;
-
-        assert(ret);
-
-        if (isempty(p))
-                return -EINVAL;
-        if (path_equal(p, "/"))
-                return -EINVAL;
-
-        /*
-         * Turns this:
-         *         /foo/bar/waldo
-         *
-         * Into this:
-         *         /foo/bar/.#<extra>waldoXXXXXX
-         */
-
-        fn = basename(p);
-        if (!filename_is_valid(fn))
-                return -EINVAL;
-
-        extra = strempty(extra);
-
-        t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
-        if (!t)
-                return -ENOMEM;
-
-        strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
-
-        *ret = path_simplify(t, false);
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-int tempfn_random(const char *p, const char *extra, char **ret) {
-        const char *fn;
-        char *t, *x;
-        uint64_t u;
-        unsigned i;
-
-        assert(ret);
-
-        if (isempty(p))
-                return -EINVAL;
-        if (path_equal(p, "/"))
-                return -EINVAL;
-
-        /*
-         * Turns this:
-         *         /foo/bar/waldo
-         *
-         * Into this:
-         *         /foo/bar/.#<extra>waldobaa2a261115984a9
-         */
-
-        fn = basename(p);
-        if (!filename_is_valid(fn))
-                return -EINVAL;
-
-        extra = strempty(extra);
-
-        t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
-        if (!t)
-                return -ENOMEM;
-
-        x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
-
-        u = random_u64();
-        for (i = 0; i < 16; i++) {
-                *(x++) = hexchar(u & 0xF);
-                u >>= 4;
-        }
-
-        *x = 0;
-
-        *ret = path_simplify(t, false);
-        return 0;
-}
-
-int tempfn_random_child(const char *p, const char *extra, char **ret) {
-        char *t, *x;
-        uint64_t u;
-        unsigned i;
-        int r;
-
-        assert(ret);
-
-        /* Turns this:
-         *         /foo/bar/waldo
-         * Into this:
-         *         /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
-         */
-
-        if (!p) {
-                r = tmp_dir(&p);
-                if (r < 0)
-                        return r;
-        }
-
-        extra = strempty(extra);
-
-        t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
-        if (!t)
-                return -ENOMEM;
-
-        if (isempty(p))
-                x = stpcpy(stpcpy(t, ".#"), extra);
-        else
-                x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
-
-        u = random_u64();
-        for (i = 0; i < 16; i++) {
-                *(x++) = hexchar(u & 0xF);
-                u >>= 4;
-        }
-
-        *x = 0;
-
-        *ret = path_simplify(t, false);
-        return 0;
-}
-
-int open_tmpfile_unlinkable(const char *directory, int flags) {
-        char *p;
-        int fd, r;
-
-        if (!directory) {
-                r = tmp_dir(&directory);
-                if (r < 0)
-                        return r;
-        } else if (isempty(directory))
-                return -EINVAL;
-
-        /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
-
-        /* Try O_TMPFILE first, if it is supported */
-        fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
-        if (fd >= 0)
-                return fd;
-
-        /* Fall back to unguessable name + unlinking */
-        p = strjoina(directory, "/systemd-tmp-XXXXXX");
-
-        fd = mkostemp_safe(p);
-        if (fd < 0)
-                return fd;
-
-        (void) unlink(p);
-
-        return fd;
-}
-
-int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
-        _cleanup_free_ char *tmp = NULL;
-        int r, fd;
-
-        assert(target);
-        assert(ret_path);
-
-        /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
-        assert((flags & O_EXCL) == 0);
-
-        /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
-         * which case "ret_path" will be returned as NULL. If not possible the temporary path name used is returned in
-         * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
-
-        fd = open_parent(target, O_TMPFILE|flags, 0640);
-        if (fd >= 0) {
-                *ret_path = NULL;
-                return fd;
-        }
-
-        log_debug_errno(fd, "Failed to use O_TMPFILE for %s: %m", target);
-
-        r = tempfn_random(target, NULL, &tmp);
-        if (r < 0)
-                return r;
-
-        fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
-        if (fd < 0)
-                return -errno;
-
-        *ret_path = TAKE_PTR(tmp);
-
-        return fd;
-}
-
-int link_tmpfile(int fd, const char *path, const char *target) {
-        int r;
-
-        assert(fd >= 0);
-        assert(target);
-
-        /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
-         * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
-         * on the directory, and renameat2() is used instead.
-         *
-         * Note that in both cases we will not replace existing files. This is because linkat() does not support this
-         * operation currently (renameat2() does), and there is no nice way to emulate this. */
-
-        if (path) {
-                r = rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
-                if (r < 0)
-                        return r;
-        } else {
-                char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
-
-                xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
-
-                if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
-                        return -errno;
-        }
-
-        return 0;
-}
-
-int mkdtemp_malloc(const char *template, char **ret) {
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        assert(ret);
-
-        if (template)
-                p = strdup(template);
-        else {
-                const char *tmp;
-
-                r = tmp_dir(&tmp);
-                if (r < 0)
-                        return r;
-
-                p = path_join(tmp, "XXXXXX");
-        }
-        if (!p)
-                return -ENOMEM;
-
-        if (!mkdtemp(p))
-                return -errno;
-
-        *ret = TAKE_PTR(p);
-        return 0;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/tmpfile-util.h b/shared/systemd/src/basic/tmpfile-util.h
deleted file mode 100644
index 45255fc0..00000000
--- a/shared/systemd/src/basic/tmpfile-util.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdio.h>
-
-int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
-int mkostemp_safe(char *pattern);
-int fmkostemp_safe(char *pattern, const char *mode, FILE**_f);
-
-int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
-int tempfn_random(const char *p, const char *extra, char **ret);
-int tempfn_random_child(const char *p, const char *extra, char **ret);
-
-int open_tmpfile_unlinkable(const char *directory, int flags);
-int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
-
-int link_tmpfile(int fd, const char *path, const char *target);
-
-int mkdtemp_malloc(const char *template, char **ret);
diff --git a/shared/systemd/src/basic/umask-util.h b/shared/systemd/src/basic/umask-util.h
deleted file mode 100644
index bd7c2bdb..00000000
--- a/shared/systemd/src/basic/umask-util.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "macro.h"
-
-static inline void umaskp(mode_t *u) {
-        umask(*u & 0777);
-}
-
-#define _cleanup_umask_ _cleanup_(umaskp)
-
-/* We make use of the fact here that the umask() concept is using only the lower 9 bits of mode_t, although
- * mode_t has space for the file type in the bits further up. We simply OR in the file type mask S_IFMT to
- * distinguish the first and the second iteration of the RUN_WITH_UMASK() loop, so that we can run the first
- * one, and exit on the second. */
-
-assert_cc((S_IFMT & 0777) == 0);
-
-#define RUN_WITH_UMASK(mask)                                            \
-        for (_cleanup_umask_ mode_t _saved_umask_ = umask(mask) | S_IFMT; \
-             FLAGS_SET(_saved_umask_, S_IFMT);                          \
-             _saved_umask_ &= 0777)
diff --git a/shared/systemd/src/basic/utf8.c b/shared/systemd/src/basic/utf8.c
deleted file mode 100644
index a7679bfa..00000000
--- a/shared/systemd/src/basic/utf8.c
+++ /dev/null
@@ -1,595 +0,0 @@
-/* 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. */
-
-/* gutf8.c - Operations on UTF-8 strings.
- *
- * Copyright (C) 1999 Tom Tromey
- * Copyright (C) 2000 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-#include "alloc-util.h"
-#include "gunicode.h"
-#include "hexdecoct.h"
-#include "macro.h"
-#include "string-util.h"
-#include "utf8.h"
-
-bool unichar_is_valid(char32_t ch) {
-
-        if (ch >= 0x110000) /* End of unicode space */
-                return false;
-        if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */
-                return false;
-        if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */
-                return false;
-        if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */
-                return false;
-
-        return true;
-}
-
-static bool unichar_is_control(char32_t ch) {
-
-        /*
-          0 to ' '-1 is the C0 range.
-          DEL=0x7F, and DEL+1 to 0x9F is C1 range.
-          '\t' is in C0 range, but more or less harmless and commonly used.
-        */
-
-        return (ch < ' ' && !IN_SET(ch, '\t', '\n')) ||
-                (0x7F <= ch && ch <= 0x9F);
-}
-
-/* count of characters used to encode one unicode char */
-static size_t utf8_encoded_expected_len(uint8_t c) {
-        if (c < 0x80)
-                return 1;
-        if ((c & 0xe0) == 0xc0)
-                return 2;
-        if ((c & 0xf0) == 0xe0)
-                return 3;
-        if ((c & 0xf8) == 0xf0)
-                return 4;
-        if ((c & 0xfc) == 0xf8)
-                return 5;
-        if ((c & 0xfe) == 0xfc)
-                return 6;
-
-        return 0;
-}
-
-/* decode one unicode char */
-int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
-        char32_t unichar;
-        size_t len, i;
-
-        assert(str);
-
-        len = utf8_encoded_expected_len(str[0]);
-
-        switch (len) {
-        case 1:
-                *ret_unichar = (char32_t)str[0];
-                return 0;
-        case 2:
-                unichar = str[0] & 0x1f;
-                break;
-        case 3:
-                unichar = (char32_t)str[0] & 0x0f;
-                break;
-        case 4:
-                unichar = (char32_t)str[0] & 0x07;
-                break;
-        case 5:
-                unichar = (char32_t)str[0] & 0x03;
-                break;
-        case 6:
-                unichar = (char32_t)str[0] & 0x01;
-                break;
-        default:
-                return -EINVAL;
-        }
-
-        for (i = 1; i < len; i++) {
-                if (((char32_t)str[i] & 0xc0) != 0x80)
-                        return -EINVAL;
-
-                unichar <<= 6;
-                unichar |= (char32_t)str[i] & 0x3f;
-        }
-
-        *ret_unichar = unichar;
-
-        return 0;
-}
-
-bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) {
-        const char *p;
-
-        assert(str);
-
-        for (p = str; length > 0;) {
-                int encoded_len, r;
-                char32_t val;
-
-                encoded_len = utf8_encoded_valid_unichar(p, length);
-                if (encoded_len < 0)
-                        return false;
-                assert(encoded_len > 0 && (size_t) encoded_len <= length);
-
-                r = utf8_encoded_to_unichar(p, &val);
-                if (r < 0 ||
-                    unichar_is_control(val) ||
-                    (!allow_newline && val == '\n'))
-                        return false;
-
-                length -= encoded_len;
-                p += encoded_len;
-        }
-
-        return true;
-}
-
-char *utf8_is_valid_n(const char *str, size_t len_bytes) {
-        /* Check if the string is composed of valid utf8 characters. If length len_bytes is given, stop after
-         * len_bytes. Otherwise, stop at NUL. */
-
-        assert(str);
-
-        for (const char *p = str; len_bytes != (size_t) -1 ? (size_t) (p - str) < len_bytes : *p != '\0'; ) {
-                int len;
-
-                if (_unlikely_(*p == '\0') && len_bytes != (size_t) -1)
-                        return NULL; /* embedded NUL */
-
-                len = utf8_encoded_valid_unichar(p,
-                                                 len_bytes != (size_t) -1 ? len_bytes - (p - str) : (size_t) -1);
-                if (_unlikely_(len < 0))
-                        return NULL; /* invalid character */
-
-                p += len;
-        }
-
-        return (char*) str;
-}
-
-char *utf8_escape_invalid(const char *str) {
-        char *p, *s;
-
-        assert(str);
-
-        p = s = malloc(strlen(str) * 4 + 1);
-        if (!p)
-                return NULL;
-
-        while (*str) {
-                int len;
-
-                len = utf8_encoded_valid_unichar(str, (size_t) -1);
-                if (len > 0) {
-                        s = mempcpy(s, str, len);
-                        str += len;
-                } else {
-                        s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER);
-                        str += 1;
-                }
-        }
-
-        *s = '\0';
-        (void) str_realloc(&p);
-        return p;
-}
-
-#if 0 /* NM_IGNORED */
-static int utf8_char_console_width(const char *str) {
-        char32_t c;
-        int r;
-
-        r = utf8_encoded_to_unichar(str, &c);
-        if (r < 0)
-                return r;
-
-        /* TODO: we should detect combining characters */
-
-        return unichar_iswide(c) ? 2 : 1;
-}
-
-char *utf8_escape_non_printable_full(const char *str, size_t console_width) {
-        char *p, *s, *prev_s;
-        size_t n = 0; /* estimated print width */
-
-        assert(str);
-
-        if (console_width == 0)
-                return strdup("");
-
-        p = s = prev_s = malloc(strlen(str) * 4 + 1);
-        if (!p)
-                return NULL;
-
-        for (;;) {
-                int len;
-                char *saved_s = s;
-
-                if (!*str) /* done! */
-                        goto finish;
-
-                len = utf8_encoded_valid_unichar(str, (size_t) -1);
-                if (len > 0) {
-                        if (utf8_is_printable(str, len)) {
-                                int w;
-
-                                w = utf8_char_console_width(str);
-                                assert(w >= 0);
-                                if (n + w > console_width)
-                                        goto truncation;
-
-                                s = mempcpy(s, str, len);
-                                str += len;
-                                n += w;
-
-                        } else {
-                                for (; len > 0; len--) {
-                                        if (n + 4 > console_width)
-                                                goto truncation;
-
-                                        *(s++) = '\\';
-                                        *(s++) = 'x';
-                                        *(s++) = hexchar((int) *str >> 4);
-                                        *(s++) = hexchar((int) *str);
-
-                                        str += 1;
-                                        n += 4;
-                                }
-                        }
-                } else {
-                        if (n + 1 > console_width)
-                                goto truncation;
-
-                        s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER));
-                        str += 1;
-                        n += 1;
-                }
-
-                prev_s = saved_s;
-        }
-
- truncation:
-        /* Try to go back one if we don't have enough space for the ellipsis */
-        if (n + 1 >= console_width)
-                s = prev_s;
-
-        s = mempcpy(s, "…", strlen("…"));
-
- finish:
-        *s = '\0';
-        (void) str_realloc(&p);
-        return p;
-}
-#endif /* NM_IGNORED */
-
-char *ascii_is_valid(const char *str) {
-        const char *p;
-
-        /* Check whether the string consists of valid ASCII bytes,
-         * i.e values between 0 and 127, inclusive. */
-
-        assert(str);
-
-        for (p = str; *p; p++)
-                if ((unsigned char) *p >= 128)
-                        return NULL;
-
-        return (char*) str;
-}
-
-#if 0 /* NM_IGNORED */
-char *ascii_is_valid_n(const char *str, size_t len) {
-        size_t i;
-
-        /* Very similar to ascii_is_valid(), but checks exactly len
-         * bytes and rejects any NULs in that range. */
-
-        assert(str);
-
-        for (i = 0; i < len; i++)
-                if ((unsigned char) str[i] >= 128 || str[i] == 0)
-                        return NULL;
-
-        return (char*) str;
-}
-#endif /* NM_IGNORED */
-
-/**
- * utf8_encode_unichar() - Encode single UCS-4 character as UTF-8
- * @out_utf8: output buffer of at least 4 bytes or NULL
- * @g: UCS-4 character to encode
- *
- * This encodes a single UCS-4 character as UTF-8 and writes it into @out_utf8.
- * The length of the character is returned. It is not zero-terminated! If the
- * output buffer is NULL, only the length is returned.
- *
- * Returns: The length in bytes that the UTF-8 representation does or would
- *          occupy.
- */
-size_t utf8_encode_unichar(char *out_utf8, char32_t g) {
-
-        if (g < (1 << 7)) {
-                if (out_utf8)
-                        out_utf8[0] = g & 0x7f;
-                return 1;
-        } else if (g < (1 << 11)) {
-                if (out_utf8) {
-                        out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f);
-                        out_utf8[1] = 0x80 | (g & 0x3f);
-                }
-                return 2;
-        } else if (g < (1 << 16)) {
-                if (out_utf8) {
-                        out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f);
-                        out_utf8[1] = 0x80 | ((g >> 6) & 0x3f);
-                        out_utf8[2] = 0x80 | (g & 0x3f);
-                }
-                return 3;
-        } else if (g < (1 << 21)) {
-                if (out_utf8) {
-                        out_utf8[0] = 0xf0 | ((g >> 18) & 0x07);
-                        out_utf8[1] = 0x80 | ((g >> 12) & 0x3f);
-                        out_utf8[2] = 0x80 | ((g >> 6) & 0x3f);
-                        out_utf8[3] = 0x80 | (g & 0x3f);
-                }
-                return 4;
-        }
-
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-char *utf16_to_utf8(const char16_t *s, size_t length /* bytes! */) {
-        const uint8_t *f;
-        char *r, *t;
-
-        assert(s);
-
-        /* Input length is in bytes, i.e. the shortest possible character takes 2 bytes. Each unicode character may
-         * take up to 4 bytes in UTF-8. Let's also account for a trailing NUL byte. */
-        if (length * 2 < length)
-                return NULL; /* overflow */
-
-        r = new(char, length * 2 + 1);
-        if (!r)
-                return NULL;
-
-        f = (const uint8_t*) s;
-        t = r;
-
-        while (f + 1 < (const uint8_t*) s + length) {
-                char16_t w1, w2;
-
-                /* see RFC 2781 section 2.2 */
-
-                w1 = f[1] << 8 | f[0];
-                f += 2;
-
-                if (!utf16_is_surrogate(w1)) {
-                        t += utf8_encode_unichar(t, w1);
-                        continue;
-                }
-
-                if (utf16_is_trailing_surrogate(w1))
-                        continue; /* spurious trailing surrogate, ignore */
-
-                if (f + 1 >= (const uint8_t*) s + length)
-                        break;
-
-                w2 = f[1] << 8 | f[0];
-                f += 2;
-
-                if (!utf16_is_trailing_surrogate(w2)) {
-                        f -= 2;
-                        continue; /* surrogate missing its trailing surrogate, ignore */
-                }
-
-                t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2));
-        }
-
-        *t = 0;
-        return r;
-}
-
-size_t utf16_encode_unichar(char16_t *out, char32_t c) {
-
-        /* Note that this encodes as little-endian. */
-
-        switch (c) {
-
-        case 0 ... 0xd7ffU:
-        case 0xe000U ... 0xffffU:
-                out[0] = htole16(c);
-                return 1;
-
-        case 0x10000U ... 0x10ffffU:
-                c -= 0x10000U;
-                out[0] = htole16((c >> 10) + 0xd800U);
-                out[1] = htole16((c & 0x3ffU) + 0xdc00U);
-                return 2;
-
-        default: /* A surrogate (invalid) */
-                return 0;
-        }
-}
-
-char16_t *utf8_to_utf16(const char *s, size_t length) {
-        char16_t *n, *p;
-        size_t i;
-        int r;
-
-        assert(s);
-
-        n = new(char16_t, length + 1);
-        if (!n)
-                return NULL;
-
-        p = n;
-
-        for (i = 0; i < length;) {
-                char32_t unichar;
-                size_t e;
-
-                e = utf8_encoded_expected_len(s[i]);
-                if (e <= 1) /* Invalid and single byte characters are copied as they are */
-                        goto copy;
-
-                if (i + e > length) /* sequence longer than input buffer, then copy as-is */
-                        goto copy;
-
-                r = utf8_encoded_to_unichar(s + i, &unichar);
-                if (r < 0) /* sequence invalid, then copy as-is */
-                        goto copy;
-
-                p += utf16_encode_unichar(p, unichar);
-                i += e;
-                continue;
-
-        copy:
-                *(p++) = htole16(s[i++]);
-        }
-
-        *p = 0;
-        return n;
-}
-
-size_t char16_strlen(const char16_t *s) {
-        size_t n = 0;
-
-        assert(s);
-
-        while (*s != 0)
-                n++, s++;
-
-        return n;
-}
-#endif /* NM_IGNORED */
-
-/* expected size used to encode one unicode char */
-static int utf8_unichar_to_encoded_len(char32_t unichar) {
-
-        if (unichar < 0x80)
-                return 1;
-        if (unichar < 0x800)
-                return 2;
-        if (unichar < 0x10000)
-                return 3;
-        if (unichar < 0x200000)
-                return 4;
-        if (unichar < 0x4000000)
-                return 5;
-
-        return 6;
-}
-
-/* validate one encoded unicode char and return its length */
-int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) {
-        char32_t unichar;
-        size_t len, i;
-        int r;
-
-        assert(str);
-        assert(length > 0);
-
-        /* We read until NUL, at most length bytes. (size_t) -1 may be used to disable the length check. */
-
-        len = utf8_encoded_expected_len(str[0]);
-        if (len == 0)
-                return -EINVAL;
-
-        /* Do we have a truncated multi-byte character? */
-        if (len > length)
-                return -EINVAL;
-
-        /* ascii is valid */
-        if (len == 1)
-                return 1;
-
-        /* check if expected encoded chars are available */
-        for (i = 0; i < len; i++)
-                if ((str[i] & 0x80) != 0x80)
-                        return -EINVAL;
-
-        r = utf8_encoded_to_unichar(str, &unichar);
-        if (r < 0)
-                return r;
-
-        /* check if encoded length matches encoded value */
-        if (utf8_unichar_to_encoded_len(unichar) != (int) len)
-                return -EINVAL;
-
-        /* check if value has valid range */
-        if (!unichar_is_valid(unichar))
-                return -EINVAL;
-
-        return (int) len;
-}
-
-#if 0 /* NM_IGNORED */
-size_t utf8_n_codepoints(const char *str) {
-        size_t n = 0;
-
-        /* Returns the number of UTF-8 codepoints in this string, or (size_t) -1 if the string is not valid UTF-8. */
-
-        while (*str != 0) {
-                int k;
-
-                k = utf8_encoded_valid_unichar(str, (size_t) -1);
-                if (k < 0)
-                        return (size_t) -1;
-
-                str += k;
-                n++;
-        }
-
-        return n;
-}
-
-size_t utf8_console_width(const char *str) {
-        size_t n = 0;
-
-        /* Returns the approximate width a string will take on screen when printed on a character cell
-         * terminal/console. */
-
-        while (*str) {
-                int w;
-
-                w = utf8_char_console_width(str);
-                if (w < 0)
-                        return (size_t) -1;
-
-                n += w;
-                str = utf8_next_char(str);
-        }
-
-        return n;
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/utf8.h b/shared/systemd/src/basic/utf8.h
deleted file mode 100644
index a6ea942c..00000000
--- a/shared/systemd/src/basic/utf8.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <uchar.h>
-
-#include "macro.h"
-#include "missing_type.h"
-
-#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd"
-#define UTF8_BYTE_ORDER_MARK "\xef\xbb\xbf"
-
-bool unichar_is_valid(char32_t c);
-
-char *utf8_is_valid_n(const char *str, size_t len_bytes) _pure_;
-static inline char *utf8_is_valid(const char *s) {
-        return utf8_is_valid_n(s, (size_t) -1);
-}
-char *ascii_is_valid(const char *s) _pure_;
-char *ascii_is_valid_n(const char *str, size_t len);
-
-bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) _pure_;
-#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
-
-char *utf8_escape_invalid(const char *s);
-char *utf8_escape_non_printable_full(const char *str, size_t console_width);
-static inline char *utf8_escape_non_printable(const char *str) {
-        return utf8_escape_non_printable_full(str, (size_t) -1);
-}
-
-size_t utf8_encode_unichar(char *out_utf8, char32_t g);
-size_t utf16_encode_unichar(char16_t *out, char32_t c);
-
-char *utf16_to_utf8(const char16_t *s, size_t length /* bytes! */);
-char16_t *utf8_to_utf16(const char *s, size_t length);
-
-size_t char16_strlen(const char16_t *s); /* returns the number of 16bit words in the string (not bytes!) */
-
-int utf8_encoded_valid_unichar(const char *str, size_t length);
-int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar);
-
-static inline bool utf16_is_surrogate(char16_t c) {
-        return c >= 0xd800U && c <= 0xdfffU;
-}
-
-static inline bool utf16_is_trailing_surrogate(char16_t c) {
-        return c >= 0xdc00U && c <= 0xdfffU;
-}
-
-static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail) {
-        return ((((char32_t) lead - 0xd800U) << 10) + ((char32_t) trail - 0xdc00U) + 0x10000U);
-}
-
-size_t utf8_n_codepoints(const char *str);
-size_t utf8_console_width(const char *str);
diff --git a/shared/systemd/src/basic/util.c b/shared/systemd/src/basic/util.c
deleted file mode 100644
index 10a5bcff..00000000
--- a/shared/systemd/src/basic/util.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#include "alloc-util.h"
-#include "build.h"
-#include "dirent-util.h"
-#include "env-file.h"
-#include "env-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "hostname-util.h"
-#include "log.h"
-#include "macro.h"
-#include "parse-util.h"
-#include "stat-util.h"
-#include "string-util.h"
-#include "util.h"
-#include "virt.h"
-
-#if 0 /* NM_IGNORED */
-int saved_argc = 0;
-char **saved_argv = NULL;
-static int saved_in_initrd = -1;
-
-bool kexec_loaded(void) {
-       _cleanup_free_ char *s = NULL;
-
-       if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0)
-               return false;
-
-       return s[0] == '1';
-}
-
-int prot_from_flags(int flags) {
-
-        switch (flags & O_ACCMODE) {
-
-        case O_RDONLY:
-                return PROT_READ;
-
-        case O_WRONLY:
-                return PROT_WRITE;
-
-        case O_RDWR:
-                return PROT_READ|PROT_WRITE;
-
-        default:
-                return -EINVAL;
-        }
-}
-
-bool in_initrd(void) {
-        struct statfs s;
-        int r;
-
-        if (saved_in_initrd >= 0)
-                return saved_in_initrd;
-
-        /* We make two checks here:
-         *
-         * 1. the flag file /etc/initrd-release must exist
-         * 2. the root file system must be a memory file system
-         *
-         * The second check is extra paranoia, since misdetecting an
-         * initrd can have bad consequences due the initrd
-         * emptying when transititioning to the main systemd.
-         */
-
-        r = getenv_bool_secure("SYSTEMD_IN_INITRD");
-        if (r < 0 && r != -ENXIO)
-                log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
-
-        if (r >= 0)
-                saved_in_initrd = r > 0;
-        else
-                saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
-                                  statfs("/", &s) >= 0 &&
-                                  is_temporary_fs(&s);
-
-        return saved_in_initrd;
-}
-
-void in_initrd_force(bool value) {
-        saved_in_initrd = value;
-}
-
-int on_ac_power(void) {
-        bool found_offline = false, found_online = false;
-        _cleanup_closedir_ DIR *d = NULL;
-        struct dirent *de;
-
-        d = opendir("/sys/class/power_supply");
-        if (!d)
-                return errno == ENOENT ? true : -errno;
-
-        FOREACH_DIRENT(de, d, return -errno) {
-                _cleanup_close_ int fd = -1, device = -1;
-                char contents[6];
-                ssize_t n;
-
-                device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (device < 0) {
-                        if (IN_SET(errno, ENOENT, ENOTDIR))
-                                continue;
-
-                        return -errno;
-                }
-
-                fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (fd < 0) {
-                        if (errno == ENOENT)
-                                continue;
-
-                        return -errno;
-                }
-
-                n = read(fd, contents, sizeof(contents));
-                if (n < 0)
-                        return -errno;
-
-                if (n != 6 || memcmp(contents, "Mains\n", 6))
-                        continue;
-
-                safe_close(fd);
-                fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (fd < 0) {
-                        if (errno == ENOENT)
-                                continue;
-
-                        return -errno;
-                }
-
-                n = read(fd, contents, sizeof(contents));
-                if (n < 0)
-                        return -errno;
-
-                if (n != 2 || contents[1] != '\n')
-                        return -EIO;
-
-                if (contents[0] == '1') {
-                        found_online = true;
-                        break;
-                } else if (contents[0] == '0')
-                        found_offline = true;
-                else
-                        return -EIO;
-        }
-
-        return found_online || !found_offline;
-}
-
-int container_get_leader(const char *machine, pid_t *pid) {
-        _cleanup_free_ char *s = NULL, *class = NULL;
-        const char *p;
-        pid_t leader;
-        int r;
-
-        assert(machine);
-        assert(pid);
-
-        if (streq(machine, ".host")) {
-                *pid = 1;
-                return 0;
-        }
-
-        if (!hostname_is_valid(machine, 0))
-                return -EINVAL;
-
-        p = strjoina("/run/systemd/machines/", machine);
-        r = parse_env_file(NULL, p,
-                           "LEADER", &s,
-                           "CLASS", &class);
-        if (r == -ENOENT)
-                return -EHOSTDOWN;
-        if (r < 0)
-                return r;
-        if (!s)
-                return -EIO;
-
-        if (!streq_ptr(class, "container"))
-                return -EIO;
-
-        r = parse_pid(s, &leader);
-        if (r < 0)
-                return r;
-        if (leader <= 1)
-                return -EIO;
-
-        *pid = leader;
-        return 0;
-}
-
-int version(void) {
-        printf("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n%s\n",
-               systemd_features);
-        return 0;
-}
-
-/* This is a direct translation of str_verscmp from boot.c */
-static bool is_digit(int c) {
-        return c >= '0' && c <= '9';
-}
-
-static int c_order(int c) {
-        if (c == 0 || is_digit(c))
-                return 0;
-
-        if ((c >= 'a') && (c <= 'z'))
-                return c;
-
-        return c + 0x10000;
-}
-
-int str_verscmp(const char *s1, const char *s2) {
-        const char *os1, *os2;
-
-        assert(s1);
-        assert(s2);
-
-        os1 = s1;
-        os2 = s2;
-
-        while (*s1 || *s2) {
-                int first;
-
-                while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
-                        int order;
-
-                        order = c_order(*s1) - c_order(*s2);
-                        if (order != 0)
-                                return order;
-                        s1++;
-                        s2++;
-                }
-
-                while (*s1 == '0')
-                        s1++;
-                while (*s2 == '0')
-                        s2++;
-
-                first = 0;
-                while (is_digit(*s1) && is_digit(*s2)) {
-                        if (first == 0)
-                                first = *s1 - *s2;
-                        s1++;
-                        s2++;
-                }
-
-                if (is_digit(*s1))
-                        return 1;
-                if (is_digit(*s2))
-                        return -1;
-
-                if (first != 0)
-                        return first;
-        }
-
-        return strcmp(os1, os2);
-}
-
-/* Turn off core dumps but only if we're running outside of a container. */
-void disable_coredumps(void) {
-        int r;
-
-        if (detect_container() > 0)
-                return;
-
-        r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", WRITE_STRING_FILE_DISABLE_BUFFER);
-        if (r < 0)
-                log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/basic/util.h b/shared/systemd/src/basic/util.h
deleted file mode 100644
index 942d773f..00000000
--- a/shared/systemd/src/basic/util.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdint.h>
-
-#include "macro.h"
-
-extern int saved_argc;
-extern char **saved_argv;
-
-static inline void save_argc_argv(int argc, char **argv) {
-        saved_argc = argc;
-        saved_argv = argv;
-}
-
-bool kexec_loaded(void);
-
-int prot_from_flags(int flags) _const_;
-
-bool in_initrd(void);
-void in_initrd_force(bool value);
-
-int on_ac_power(void);
-
-static inline unsigned u64log2(uint64_t n) {
-#if __SIZEOF_LONG_LONG__ == 8
-        return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
-#else
-#error "Wut?"
-#endif
-}
-
-static inline unsigned u32ctz(uint32_t n) {
-#if __SIZEOF_INT__ == 4
-        return n != 0 ? __builtin_ctz(n) : 32;
-#else
-#error "Wut?"
-#endif
-}
-
-static inline unsigned log2i(int x) {
-        assert(x > 0);
-
-        return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1;
-}
-
-static inline unsigned log2u(unsigned x) {
-        assert(x > 0);
-
-        return sizeof(unsigned) * 8 - __builtin_clz(x) - 1;
-}
-
-static inline unsigned log2u_round_up(unsigned x) {
-        assert(x > 0);
-
-        if (x == 1)
-                return 0;
-
-        return log2u(x - 1) + 1;
-}
-
-int container_get_leader(const char *machine, pid_t *pid);
-
-int version(void);
-
-int str_verscmp(const char *s1, const char *s2);
-
-void disable_coredumps(void);
diff --git a/shared/systemd/src/shared/dns-domain.c b/shared/systemd/src/shared/dns-domain.c
deleted file mode 100644
index 95e4a93a..00000000
--- a/shared/systemd/src/shared/dns-domain.c
+++ /dev/null
@@ -1,1429 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <endian.h>
-#include <netinet/in.h>
-#include <stdio.h>
-#include <sys/socket.h>
-
-#include "alloc-util.h"
-#include "dns-domain.h"
-#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"
-#include "string-util.h"
-#include "strv.h"
-#include "utf8.h"
-
-int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags) {
-        const char *n;
-        char *d, last_char = 0;
-        int r = 0;
-
-        assert(name);
-        assert(*name);
-
-        n = *name;
-        d = dest;
-
-        for (;;) {
-                if (IN_SET(*n, 0, '.')) {
-                        if (FLAGS_SET(flags, DNS_LABEL_LDH) && last_char == '-')
-                                /* Trailing dash */
-                                return -EINVAL;
-
-                        if (n[0] == '.' && (n[1] != 0 || !FLAGS_SET(flags, DNS_LABEL_LEAVE_TRAILING_DOT)))
-                                n++;
-
-                        break;
-                }
-
-                if (r >= DNS_LABEL_MAX)
-                        return -EINVAL;
-
-                if (sz <= 0)
-                        return -ENOBUFS;
-
-                if (*n == '\\') {
-                        /* Escaped character */
-                        if (FLAGS_SET(flags, DNS_LABEL_NO_ESCAPES))
-                                return -EINVAL;
-
-                        n++;
-
-                        if (*n == 0)
-                                /* Ending NUL */
-                                return -EINVAL;
-
-                        else if (IN_SET(*n, '\\', '.')) {
-                                /* Escaped backslash or dot */
-
-                                if (FLAGS_SET(flags, DNS_LABEL_LDH))
-                                        return -EINVAL;
-
-                                last_char = *n;
-                                if (d)
-                                        *(d++) = *n;
-                                sz--;
-                                r++;
-                                n++;
-
-                        } else if (n[0] >= '0' && n[0] <= '9') {
-                                unsigned k;
-
-                                /* Escaped literal ASCII character */
-
-                                if (!(n[1] >= '0' && n[1] <= '9') ||
-                                    !(n[2] >= '0' && n[2] <= '9'))
-                                        return -EINVAL;
-
-                                k = ((unsigned) (n[0] - '0') * 100) +
-                                        ((unsigned) (n[1] - '0') * 10) +
-                                        ((unsigned) (n[2] - '0'));
-
-                                /* Don't allow anything that doesn't
-                                 * fit in 8bit. Note that we do allow
-                                 * control characters, as some servers
-                                 * (e.g. cloudflare) are happy to
-                                 * generate labels with them
-                                 * inside. */
-                                if (k > 255)
-                                        return -EINVAL;
-
-                                if (FLAGS_SET(flags, DNS_LABEL_LDH) &&
-                                    !valid_ldh_char((char) k))
-                                        return -EINVAL;
-
-                                last_char = (char) k;
-                                if (d)
-                                        *(d++) = (char) k;
-                                sz--;
-                                r++;
-
-                                n += 3;
-                        } else
-                                return -EINVAL;
-
-                } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) {
-
-                        /* Normal character */
-
-                        if (FLAGS_SET(flags, DNS_LABEL_LDH)) {
-                                if (!valid_ldh_char(*n))
-                                        return -EINVAL;
-                                if (r == 0 && *n == '-')
-                                        /* Leading dash */
-                                        return -EINVAL;
-                        }
-
-                        last_char = *n;
-                        if (d)
-                                *(d++) = *n;
-                        sz--;
-                        r++;
-                        n++;
-                } else
-                        return -EINVAL;
-        }
-
-        /* Empty label that is not at the end? */
-        if (r == 0 && *n)
-                return -EINVAL;
-
-        /* More than one trailing dot? */
-        if (n[0] == '.' && !FLAGS_SET(flags, DNS_LABEL_LEAVE_TRAILING_DOT))
-                return -EINVAL;
-
-        if (sz >= 1 && d)
-                *d = 0;
-
-        *name = n;
-        return r;
-}
-
-#if 0 /* NM_IGNORED */
-/* @label_terminal: terminal character of a label, updated to point to the terminal character of
- *                  the previous label (always skipping one dot) or to NULL if there are no more
- *                  labels. */
-int dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) {
-        const char *terminal;
-        int r;
-
-        assert(name);
-        assert(label_terminal);
-        assert(dest);
-
-        /* no more labels */
-        if (!*label_terminal) {
-                if (sz >= 1)
-                        *dest = 0;
-
-                return 0;
-        }
-
-        terminal = *label_terminal;
-        assert(IN_SET(*terminal, 0, '.'));
-
-        /* Skip current terminal character (and accept domain names ending it ".") */
-        if (*terminal == 0)
-                terminal--;
-        if (terminal >= name && *terminal == '.')
-                terminal--;
-
-        /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
-        for (;;) {
-                if (terminal < name) {
-                        /* Reached the first label, so indicate that there are no more */
-                        terminal = NULL;
-                        break;
-                }
-
-                /* Find the start of the last label */
-                if (*terminal == '.') {
-                        const char *y;
-                        unsigned slashes = 0;
-
-                        for (y = terminal - 1; y >= name && *y == '\\'; y--)
-                                slashes++;
-
-                        if (slashes % 2 == 0) {
-                                /* The '.' was not escaped */
-                                name = terminal + 1;
-                                break;
-                        } else {
-                                terminal = y;
-                                continue;
-                        }
-                }
-
-                terminal--;
-        }
-
-        r = dns_label_unescape(&name, dest, sz, 0);
-        if (r < 0)
-                return r;
-
-        *label_terminal = terminal;
-
-        return r;
-}
-#endif /* NM_IGNORED */
-
-int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
-        char *q;
-
-        /* DNS labels must be between 1 and 63 characters long. A
-         * zero-length label does not exist. See RFC 2182, Section
-         * 11. */
-
-        if (l <= 0 || l > DNS_LABEL_MAX)
-                return -EINVAL;
-        if (sz < 1)
-                return -ENOBUFS;
-
-        assert(p);
-        assert(dest);
-
-        q = dest;
-        while (l > 0) {
-
-                if (IN_SET(*p, '.', '\\')) {
-
-                        /* Dot or backslash */
-
-                        if (sz < 3)
-                                return -ENOBUFS;
-
-                        *(q++) = '\\';
-                        *(q++) = *p;
-
-                        sz -= 2;
-
-                } else if (IN_SET(*p, '_', '-') ||
-                           (*p >= '0' && *p <= '9') ||
-                           (*p >= 'a' && *p <= 'z') ||
-                           (*p >= 'A' && *p <= 'Z')) {
-
-                        /* Proper character */
-
-                        if (sz < 2)
-                                return -ENOBUFS;
-
-                        *(q++) = *p;
-                        sz -= 1;
-
-                } else {
-
-                        /* Everything else */
-
-                        if (sz < 5)
-                                return -ENOBUFS;
-
-                        *(q++) = '\\';
-                        *(q++) = '0' + (char) ((uint8_t) *p / 100);
-                        *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10);
-                        *(q++) = '0' + (char) ((uint8_t) *p % 10);
-
-                        sz -= 4;
-                }
-
-                p++;
-                l--;
-        }
-
-        *q = 0;
-        return (int) (q - dest);
-}
-
-#if 0 /* NM_IGNORED */
-int dns_label_escape_new(const char *p, size_t l, char **ret) {
-        _cleanup_free_ char *s = NULL;
-        int r;
-
-        assert(p);
-        assert(ret);
-
-        if (l <= 0 || l > DNS_LABEL_MAX)
-                return -EINVAL;
-
-        s = new(char, DNS_LABEL_ESCAPED_MAX);
-        if (!s)
-                return -ENOMEM;
-
-        r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX);
-        if (r < 0)
-                return r;
-
-        *ret = TAKE_PTR(s);
-
-        return r;
-}
-
-#if HAVE_LIBIDN
-int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
-        _cleanup_free_ uint32_t *input = NULL;
-        size_t input_size, l;
-        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;
-
-        for (p = encoded; p < encoded + encoded_size; p++)
-                if ((uint8_t) *p > 127)
-                        contains_8bit = true;
-
-        if (!contains_8bit) {
-                if (encoded_size > DNS_LABEL_MAX)
-                        return -EINVAL;
-
-                return 0;
-        }
-
-        input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
-        if (!input)
-                return -ENOMEM;
-
-        if (sym_idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
-                return -EINVAL;
-
-        l = strlen(buffer);
-
-        /* Verify that the result is not longer than one DNS label. */
-        if (l <= 0 || l > DNS_LABEL_MAX)
-                return -EINVAL;
-        if (l > decoded_max)
-                return -ENOBUFS;
-
-        memcpy(decoded, buffer, l);
-
-        /* If there's room, append a trailing NUL byte, but only then */
-        if (decoded_max > l)
-                decoded[l] = 0;
-
-        return (int) l;
-}
-
-int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
-        size_t input_size, output_size;
-        _cleanup_free_ uint32_t *input = NULL;
-        _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 = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
-        if (!input)
-                return -ENOMEM;
-
-        output_size = input_size;
-        output = newa(uint32_t, output_size);
-
-        sym_idna_to_unicode_44i(input, input_size, output, &output_size, 0);
-
-        result = sym_stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
-        if (!result)
-                return -ENOMEM;
-        if (w <= 0)
-                return -EINVAL;
-        if (w > decoded_max)
-                return -ENOBUFS;
-
-        memcpy(decoded, result, w);
-
-        /* Append trailing NUL byte if there's space, but only then. */
-        if (decoded_max > w)
-                decoded[w] = 0;
-
-        return w;
-}
-#endif
-#endif /* NM_IGNORED */
-
-int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_ret) {
-        _cleanup_free_ char *ret = NULL;
-        size_t n = 0, allocated = 0;
-        const char *p;
-        bool first = true;
-        int r;
-
-        if (a)
-                p = a;
-        else if (b)
-                p = TAKE_PTR(b);
-        else
-                goto finish;
-
-        for (;;) {
-                char label[DNS_LABEL_MAX];
-
-                r = dns_label_unescape(&p, label, sizeof label, flags);
-                if (r < 0)
-                        return r;
-                if (r == 0) {
-                        if (*p != 0)
-                                return -EINVAL;
-
-                        if (b) {
-                                /* Now continue with the second string, if there is one */
-                                p = TAKE_PTR(b);
-                                continue;
-                        }
-
-                        break;
-                }
-
-                if (_ret) {
-                        if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
-                                return -ENOMEM;
-
-                        r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
-                        if (r < 0)
-                                return r;
-
-                        if (!first)
-                                ret[n] = '.';
-                } else {
-                        char escaped[DNS_LABEL_ESCAPED_MAX];
-
-                        r = dns_label_escape(label, r, escaped, sizeof(escaped));
-                        if (r < 0)
-                                return r;
-                }
-
-                if (!first)
-                        n++;
-                else
-                        first = false;
-
-                n += r;
-        }
-
-finish:
-        if (n > DNS_HOSTNAME_MAX)
-                return -EINVAL;
-
-        if (_ret) {
-                if (n == 0) {
-                        /* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
-                        if (!GREEDY_REALLOC(ret, allocated, 2))
-                                return -ENOMEM;
-
-                        ret[n++] = '.';
-                } else {
-                        if (!GREEDY_REALLOC(ret, allocated, n + 1))
-                                return -ENOMEM;
-                }
-
-                ret[n] = 0;
-                *_ret = TAKE_PTR(ret);
-        }
-
-        return 0;
-}
-
-#if 0 /* NM_IGNORED */
-void dns_name_hash_func(const char *p, struct siphash *state) {
-        int r;
-
-        assert(p);
-
-        for (;;) {
-                char label[DNS_LABEL_MAX+1];
-
-                r = dns_label_unescape(&p, label, sizeof label, 0);
-                if (r < 0)
-                        break;
-                if (r == 0)
-                        break;
-
-                ascii_strlower_n(label, r);
-                siphash24_compress(label, r, state);
-                siphash24_compress_byte(0, state); /* make sure foobar and foo.bar result in different hashes */
-        }
-
-        /* enforce that all names are terminated by the empty label */
-        string_hash_func("", state);
-}
-
-int dns_name_compare_func(const char *a, const char *b) {
-        const char *x, *y;
-        int r, q;
-
-        assert(a);
-        assert(b);
-
-        x = a + strlen(a);
-        y = b + strlen(b);
-
-        for (;;) {
-                char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
-
-                if (x == NULL && y == NULL)
-                        return 0;
-
-                r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
-                q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
-                if (r < 0 || q < 0)
-                        return CMP(r, q);
-
-                r = ascii_strcasecmp_nn(la, r, lb, q);
-                if (r != 0)
-                        return r;
-        }
-}
-
-DEFINE_HASH_OPS(dns_name_hash_ops, char, dns_name_hash_func, dns_name_compare_func);
-
-int dns_name_equal(const char *x, const char *y) {
-        int r, q;
-
-        assert(x);
-        assert(y);
-
-        for (;;) {
-                char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
-
-                r = dns_label_unescape(&x, la, sizeof la, 0);
-                if (r < 0)
-                        return r;
-
-                q = dns_label_unescape(&y, lb, sizeof lb, 0);
-                if (q < 0)
-                        return q;
-
-                if (r != q)
-                        return false;
-                if (r == 0)
-                        return true;
-
-                if (ascii_strcasecmp_n(la, lb, r) != 0)
-                        return false;
-        }
-}
-
-int dns_name_endswith(const char *name, const char *suffix) {
-        const char *n, *s, *saved_n = NULL;
-        int r, q;
-
-        assert(name);
-        assert(suffix);
-
-        n = name;
-        s = suffix;
-
-        for (;;) {
-                char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
-
-                r = dns_label_unescape(&n, ln, sizeof ln, 0);
-                if (r < 0)
-                        return r;
-
-                if (!saved_n)
-                        saved_n = n;
-
-                q = dns_label_unescape(&s, ls, sizeof ls, 0);
-                if (q < 0)
-                        return q;
-
-                if (r == 0 && q == 0)
-                        return true;
-                if (r == 0 && saved_n == n)
-                        return false;
-
-                if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) {
-
-                        /* Not the same, let's jump back, and try with the next label again */
-                        s = suffix;
-                        n = TAKE_PTR(saved_n);
-                }
-        }
-}
-
-int dns_name_startswith(const char *name, const char *prefix) {
-        const char *n, *p;
-        int r, q;
-
-        assert(name);
-        assert(prefix);
-
-        n = name;
-        p = prefix;
-
-        for (;;) {
-                char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX];
-
-                r = dns_label_unescape(&p, lp, sizeof lp, 0);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return true;
-
-                q = dns_label_unescape(&n, ln, sizeof ln, 0);
-                if (q < 0)
-                        return q;
-
-                if (r != q)
-                        return false;
-                if (ascii_strcasecmp_n(ln, lp, r) != 0)
-                        return false;
-        }
-}
-
-int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) {
-        const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix;
-        int r, q;
-
-        assert(name);
-        assert(old_suffix);
-        assert(new_suffix);
-        assert(ret);
-
-        n = name;
-        s = old_suffix;
-
-        for (;;) {
-                char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
-
-                if (!saved_before)
-                        saved_before = n;
-
-                r = dns_label_unescape(&n, ln, sizeof ln, 0);
-                if (r < 0)
-                        return r;
-
-                if (!saved_after)
-                        saved_after = n;
-
-                q = dns_label_unescape(&s, ls, sizeof ls, 0);
-                if (q < 0)
-                        return q;
-
-                if (r == 0 && q == 0)
-                        break;
-                if (r == 0 && saved_after == n) {
-                        *ret = NULL; /* doesn't match */
-                        return 0;
-                }
-
-                if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) {
-
-                        /* Not the same, let's jump back, and try with the next label again */
-                        s = old_suffix;
-                        n = TAKE_PTR(saved_after);
-                        saved_before = NULL;
-                }
-        }
-
-        /* Found it! Now generate the new name */
-        prefix = strndupa(name, saved_before - name);
-
-        r = dns_name_concat(prefix, new_suffix, 0, ret);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-int dns_name_between(const char *a, const char *b, const char *c) {
-        /* Determine if b is strictly greater than a and strictly smaller than c.
-           We consider the order of names to be circular, so that if a is
-           strictly greater than c, we consider b to be between them if it is
-           either greater than a or smaller than c. This is how the canonical
-           DNS name order used in NSEC records work. */
-
-        if (dns_name_compare_func(a, c) < 0)
-                /*
-                   a and c are properly ordered:
-                   a<---b--->c
-                */
-                return dns_name_compare_func(a, b) < 0 &&
-                       dns_name_compare_func(b, c) < 0;
-        else
-                /*
-                   a and c are equal or 'reversed':
-                   <--b--c         a----->
-                   or:
-                   <-----c         a--b-->
-                */
-                return dns_name_compare_func(b, c) < 0 ||
-                       dns_name_compare_func(a, b) < 0;
-}
-
-int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
-        const uint8_t *p;
-        int r;
-
-        assert(a);
-        assert(ret);
-
-        p = (const uint8_t*) a;
-
-        if (family == AF_INET)
-                r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]);
-        else if (family == AF_INET6)
-                r = asprintf(ret, "%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.ip6.arpa",
-                             hexchar(p[15] & 0xF), hexchar(p[15] >> 4), hexchar(p[14] & 0xF), hexchar(p[14] >> 4),
-                             hexchar(p[13] & 0xF), hexchar(p[13] >> 4), hexchar(p[12] & 0xF), hexchar(p[12] >> 4),
-                             hexchar(p[11] & 0xF), hexchar(p[11] >> 4), hexchar(p[10] & 0xF), hexchar(p[10] >> 4),
-                             hexchar(p[ 9] & 0xF), hexchar(p[ 9] >> 4), hexchar(p[ 8] & 0xF), hexchar(p[ 8] >> 4),
-                             hexchar(p[ 7] & 0xF), hexchar(p[ 7] >> 4), hexchar(p[ 6] & 0xF), hexchar(p[ 6] >> 4),
-                             hexchar(p[ 5] & 0xF), hexchar(p[ 5] >> 4), hexchar(p[ 4] & 0xF), hexchar(p[ 4] >> 4),
-                             hexchar(p[ 3] & 0xF), hexchar(p[ 3] >> 4), hexchar(p[ 2] & 0xF), hexchar(p[ 2] >> 4),
-                             hexchar(p[ 1] & 0xF), hexchar(p[ 1] >> 4), hexchar(p[ 0] & 0xF), hexchar(p[ 0] >> 4));
-        else
-                return -EAFNOSUPPORT;
-        if (r < 0)
-                return -ENOMEM;
-
-        return 0;
-}
-
-int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_address) {
-        int r;
-
-        assert(p);
-        assert(ret_family);
-        assert(ret_address);
-
-        r = dns_name_endswith(p, "in-addr.arpa");
-        if (r < 0)
-                return r;
-        if (r > 0) {
-                uint8_t a[4];
-                unsigned i;
-
-                for (i = 0; i < ELEMENTSOF(a); i++) {
-                        char label[DNS_LABEL_MAX+1];
-
-                        r = dns_label_unescape(&p, label, sizeof label, 0);
-                        if (r < 0)
-                                return r;
-                        if (r == 0)
-                                return -EINVAL;
-                        if (r > 3)
-                                return -EINVAL;
-
-                        r = safe_atou8(label, &a[i]);
-                        if (r < 0)
-                                return r;
-                }
-
-                r = dns_name_equal(p, "in-addr.arpa");
-                if (r <= 0)
-                        return r;
-
-                *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;
-        }
-
-        r = dns_name_endswith(p, "ip6.arpa");
-        if (r < 0)
-                return r;
-        if (r > 0) {
-                struct in6_addr a;
-                unsigned i;
-
-                for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
-                        char label[DNS_LABEL_MAX+1];
-                        int x, y;
-
-                        r = dns_label_unescape(&p, label, sizeof label, 0);
-                        if (r <= 0)
-                                return r;
-                        if (r != 1)
-                                return -EINVAL;
-                        x = unhexchar(label[0]);
-                        if (x < 0)
-                                return -EINVAL;
-
-                        r = dns_label_unescape(&p, label, sizeof label, 0);
-                        if (r <= 0)
-                                return r;
-                        if (r != 1)
-                                return -EINVAL;
-                        y = unhexchar(label[0]);
-                        if (y < 0)
-                                return -EINVAL;
-
-                        a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x;
-                }
-
-                r = dns_name_equal(p, "ip6.arpa");
-                if (r <= 0)
-                        return r;
-
-                *ret_family = AF_INET6;
-                ret_address->in6 = a;
-                return 1;
-        }
-
-        *ret_family = AF_UNSPEC;
-        *ret_address = IN_ADDR_NULL;
-
-        return 0;
-}
-#endif /* NM_IGNORED */
-
-bool dns_name_is_root(const char *name) {
-
-        assert(name);
-
-        /* There are exactly two ways to encode the root domain name:
-         * as empty string, or with a single dot. */
-
-        return STR_IN_SET(name, "", ".");
-}
-
-bool dns_name_is_single_label(const char *name) {
-        int r;
-
-        assert(name);
-
-        r = dns_name_parent(&name);
-        if (r <= 0)
-                return false;
-
-        return dns_name_is_root(name);
-}
-
-/* Encode a domain name according to RFC 1035 Section 3.1, without compression */
-int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical) {
-        uint8_t *label_length, *out;
-        int r;
-
-        assert(domain);
-        assert(buffer);
-
-        out = buffer;
-
-        do {
-                /* Reserve a byte for label length */
-                if (len <= 0)
-                        return -ENOBUFS;
-                len--;
-                label_length = out;
-                out++;
-
-                /* Convert and copy a single label. Note that
-                 * dns_label_unescape() returns 0 when it hits the end
-                 * of the domain name, which we rely on here to encode
-                 * the trailing NUL byte. */
-                r = dns_label_unescape(&domain, (char *) out, len, 0);
-                if (r < 0)
-                        return r;
-
-                /* Optionally, output the name in DNSSEC canonical
-                 * format, as described in RFC 4034, section 6.2. Or
-                 * in other words: in lower-case. */
-                if (canonical)
-                        ascii_strlower_n((char*) out, (size_t) r);
-
-                /* Fill label length, move forward */
-                *label_length = r;
-                out += r;
-                len -= r;
-
-        } while (r != 0);
-
-        /* Verify the maximum size of the encoded name. The trailing
-         * dot + NUL byte account are included this time, hence
-         * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
-         * time. */
-        if (out - buffer > DNS_HOSTNAME_MAX + 2)
-                return -EINVAL;
-
-        return out - buffer;
-}
-
-#if 0 /* NM_IGNORED */
-static bool srv_type_label_is_valid(const char *label, size_t n) {
-        size_t k;
-
-        assert(label);
-
-        if (n < 2) /* Label needs to be at least 2 chars long */
-                return false;
-
-        if (label[0] != '_') /* First label char needs to be underscore */
-                return false;
-
-        /* Second char must be a letter */
-        if (!(label[1] >= 'A' && label[1] <= 'Z') &&
-            !(label[1] >= 'a' && label[1] <= 'z'))
-                return false;
-
-        /* Third and further chars must be alphanumeric or a hyphen */
-        for (k = 2; k < n; k++) {
-                if (!(label[k] >= 'A' && label[k] <= 'Z') &&
-                    !(label[k] >= 'a' && label[k] <= 'z') &&
-                    !(label[k] >= '0' && label[k] <= '9') &&
-                    label[k] != '-')
-                        return false;
-        }
-
-        return true;
-}
-
-bool dns_srv_type_is_valid(const char *name) {
-        unsigned c = 0;
-        int r;
-
-        if (!name)
-                return false;
-
-        for (;;) {
-                char label[DNS_LABEL_MAX];
-
-                /* This more or less implements RFC 6335, Section 5.1 */
-
-                r = dns_label_unescape(&name, label, sizeof label, 0);
-                if (r < 0)
-                        return false;
-                if (r == 0)
-                        break;
-
-                if (c >= 2)
-                        return false;
-
-                if (!srv_type_label_is_valid(label, r))
-                        return false;
-
-                c++;
-        }
-
-        return c == 2; /* exactly two labels */
-}
-
-bool dnssd_srv_type_is_valid(const char *name) {
-        return dns_srv_type_is_valid(name) &&
-                ((dns_name_endswith(name, "_tcp") > 0) ||
-                 (dns_name_endswith(name, "_udp") > 0)); /* Specific to DNS-SD. RFC 6763, Section 7 */
-}
-
-bool dns_service_name_is_valid(const char *name) {
-        size_t l;
-
-        /* This more or less implements RFC 6763, Section 4.1.1 */
-
-        if (!name)
-                return false;
-
-        if (!utf8_is_valid(name))
-                return false;
-
-        if (string_has_cc(name, NULL))
-                return false;
-
-        l = strlen(name);
-        if (l <= 0)
-                return false;
-        if (l > 63)
-                return false;
-
-        return true;
-}
-
-int dns_service_join(const char *name, const char *type, const char *domain, char **ret) {
-        char escaped[DNS_LABEL_ESCAPED_MAX];
-        _cleanup_free_ char *n = NULL;
-        int r;
-
-        assert(type);
-        assert(domain);
-        assert(ret);
-
-        if (!dns_srv_type_is_valid(type))
-                return -EINVAL;
-
-        if (!name)
-                return dns_name_concat(type, domain, 0, ret);
-
-        if (!dns_service_name_is_valid(name))
-                return -EINVAL;
-
-        r = dns_label_escape(name, strlen(name), escaped, sizeof(escaped));
-        if (r < 0)
-                return r;
-
-        r = dns_name_concat(type, domain, 0, &n);
-        if (r < 0)
-                return r;
-
-        return dns_name_concat(escaped, n, 0, ret);
-}
-
-static bool dns_service_name_label_is_valid(const char *label, size_t n) {
-        char *s;
-
-        assert(label);
-
-        if (memchr(label, 0, n))
-                return false;
-
-        s = strndupa(label, n);
-        return dns_service_name_is_valid(s);
-}
-
-int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) {
-        _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
-        const char *p = joined, *q = NULL, *d = NULL;
-        char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX];
-        int an, bn, cn, r;
-        unsigned x = 0;
-
-        assert(joined);
-
-        /* Get first label from the full name */
-        an = dns_label_unescape(&p, a, sizeof(a), 0);
-        if (an < 0)
-                return an;
-
-        if (an > 0) {
-                x++;
-
-                /* If there was a first label, try to get the second one */
-                bn = dns_label_unescape(&p, b, sizeof(b), 0);
-                if (bn < 0)
-                        return bn;
-
-                if (bn > 0) {
-                        x++;
-
-                        /* If there was a second label, try to get the third one */
-                        q = p;
-                        cn = dns_label_unescape(&p, c, sizeof(c), 0);
-                        if (cn < 0)
-                                return cn;
-
-                        if (cn > 0)
-                                x++;
-                } else
-                        cn = 0;
-        } else
-                an = 0;
-
-        if (x >= 2 && srv_type_label_is_valid(b, bn)) {
-
-                if (x >= 3 && srv_type_label_is_valid(c, cn)) {
-
-                        if (dns_service_name_label_is_valid(a, an)) {
-                                /* OK, got <name> . <type> . <type2> . <domain> */
-
-                                name = strndup(a, an);
-                                if (!name)
-                                        return -ENOMEM;
-
-                                type = strjoin(b, ".", c);
-                                if (!type)
-                                        return -ENOMEM;
-
-                                d = p;
-                                goto finish;
-                        }
-
-                } else if (srv_type_label_is_valid(a, an)) {
-
-                        /* OK, got <type> . <type2> . <domain> */
-
-                        name = NULL;
-
-                        type = strjoin(a, ".", b);
-                        if (!type)
-                                return -ENOMEM;
-
-                        d = q;
-                        goto finish;
-                }
-        }
-
-        name = NULL;
-        type = NULL;
-        d = joined;
-
-finish:
-        r = dns_name_normalize(d, 0, &domain);
-        if (r < 0)
-                return r;
-
-        if (_domain)
-                *_domain = TAKE_PTR(domain);
-
-        if (_type)
-                *_type = TAKE_PTR(type);
-
-        if (_name)
-                *_name = TAKE_PTR(name);
-
-        return 0;
-}
-
-static int dns_name_build_suffix_table(const char *name, const char *table[]) {
-        const char *p;
-        unsigned n = 0;
-        int r;
-
-        assert(name);
-        assert(table);
-
-        p = name;
-        for (;;) {
-                if (n > DNS_N_LABELS_MAX)
-                        return -EINVAL;
-
-                table[n] = p;
-                r = dns_name_parent(&p);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                n++;
-        }
-
-        return (int) n;
-}
-
-int dns_name_suffix(const char *name, unsigned n_labels, const char **ret) {
-        const char* labels[DNS_N_LABELS_MAX+1];
-        int n;
-
-        assert(name);
-        assert(ret);
-
-        n = dns_name_build_suffix_table(name, labels);
-        if (n < 0)
-                return n;
-
-        if ((unsigned) n < n_labels)
-                return -EINVAL;
-
-        *ret = labels[n - n_labels];
-        return (int) (n - n_labels);
-}
-
-int dns_name_skip(const char *a, unsigned n_labels, const char **ret) {
-        int r;
-
-        assert(a);
-        assert(ret);
-
-        for (; n_labels > 0; n_labels--) {
-                r = dns_name_parent(&a);
-                if (r < 0)
-                        return r;
-                if (r == 0) {
-                        *ret = "";
-                        return 0;
-                }
-        }
-
-        *ret = a;
-        return 1;
-}
-
-int dns_name_count_labels(const char *name) {
-        unsigned n = 0;
-        const char *p;
-        int r;
-
-        assert(name);
-
-        p = name;
-        for (;;) {
-                r = dns_name_parent(&p);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                if (n >= DNS_N_LABELS_MAX)
-                        return -EINVAL;
-
-                n++;
-        }
-
-        return (int) n;
-}
-
-int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b) {
-        int r;
-
-        assert(a);
-        assert(b);
-
-        r = dns_name_skip(a, n_labels, &a);
-        if (r <= 0)
-                return r;
-
-        return dns_name_equal(a, b);
-}
-
-int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
-        const char *a_labels[DNS_N_LABELS_MAX+1], *b_labels[DNS_N_LABELS_MAX+1];
-        int n = 0, m = 0, k = 0, r, q;
-
-        assert(a);
-        assert(b);
-        assert(ret);
-
-        /* Determines the common suffix of domain names a and b */
-
-        n = dns_name_build_suffix_table(a, a_labels);
-        if (n < 0)
-                return n;
-
-        m = dns_name_build_suffix_table(b, b_labels);
-        if (m < 0)
-                return m;
-
-        for (;;) {
-                char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
-                const char *x, *y;
-
-                if (k >= n || k >= m) {
-                        *ret = a_labels[n - k];
-                        return 0;
-                }
-
-                x = a_labels[n - 1 - k];
-                r = dns_label_unescape(&x, la, sizeof la, 0);
-                if (r < 0)
-                        return r;
-
-                y = b_labels[m - 1 - k];
-                q = dns_label_unescape(&y, lb, sizeof lb, 0);
-                if (q < 0)
-                        return q;
-
-                if (r != q || ascii_strcasecmp_n(la, lb, r) != 0) {
-                        *ret = a_labels[n - k];
-                        return 0;
-                }
-
-                k++;
-        }
-}
-
-int dns_name_apply_idna(const char *name, char **ret) {
-
-        /* Return negative on error, 0 if not implemented, positive on success. */
-
-#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);
-
-        /* 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 = sym_idn2_to_unicode_8z8z(t, &s, 0);
-                        if (r != IDN2_OK) {
-                                log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
-                                          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, 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;
-        size_t n = 0, allocated = 0;
-        bool first = true;
-        int r, q;
-
-        assert(name);
-        assert(ret);
-
-        for (;;) {
-                char label[DNS_LABEL_MAX];
-
-                r = dns_label_unescape(&name, label, sizeof label, 0);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                q = dns_label_apply_idna(label, r, label, sizeof label);
-                if (q < 0)
-                        return q;
-                if (q > 0)
-                        r = q;
-
-                if (!GREEDY_REALLOC(buf, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
-                        return -ENOMEM;
-
-                r = dns_label_escape(label, r, buf + n + !first, DNS_LABEL_ESCAPED_MAX);
-                if (r < 0)
-                        return r;
-
-                if (first)
-                        first = false;
-                else
-                        buf[n++] = '.';
-
-                n += r;
-        }
-
-        if (n > DNS_HOSTNAME_MAX)
-                return -EINVAL;
-
-        if (!GREEDY_REALLOC(buf, allocated, n + 1))
-                return -ENOMEM;
-
-        buf[n] = 0;
-        *ret = TAKE_PTR(buf);
-
-        return 1;
-#else
-        *ret = NULL;
-        return 0;
-#endif
-}
-
-int dns_name_is_valid_or_address(const char *name) {
-        /* Returns > 0 if the specified name is either a valid IP address formatted as string or a valid DNS name */
-
-        if (isempty(name))
-                return 0;
-
-        if (in_addr_from_string_auto(name, NULL, NULL) >= 0)
-                return 1;
-
-        return dns_name_is_valid(name);
-}
-
-int dns_name_dot_suffixed(const char *name) {
-        const char *p = name;
-        int r;
-
-        for (;;) {
-                if (streq(p, "."))
-                        return true;
-
-                r = dns_label_unescape(&p, NULL, DNS_LABEL_MAX, DNS_LABEL_LEAVE_TRAILING_DOT);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return false;
-        }
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/shared/dns-domain.h b/shared/systemd/src/shared/dns-domain.h
deleted file mode 100644
index 984f4840..00000000
--- a/shared/systemd/src/shared/dns-domain.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <errno.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include "hashmap.h"
-#include "in-addr-util.h"
-
-/* Length of a single label, with all escaping removed, excluding any trailing dot or NUL byte */
-#define DNS_LABEL_MAX 63
-
-/* Worst case length of a single label, with all escaping applied and room for a trailing NUL byte. */
-#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1)
-
-/* Maximum length of a full hostname, consisting of a series of unescaped labels, and no trailing dot or NUL byte */
-#define DNS_HOSTNAME_MAX 253
-
-/* Maximum length of a full hostname, on the wire, including the final NUL byte */
-#define DNS_WIRE_FORMAT_HOSTNAME_MAX 255
-
-/* Maximum number of labels per valid hostname */
-#define DNS_N_LABELS_MAX 127
-
-typedef enum DNSLabelFlags {
-        DNS_LABEL_LDH                = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */
-        DNS_LABEL_NO_ESCAPES         = 1 << 1, /* Do not treat backslashes specially */
-        DNS_LABEL_LEAVE_TRAILING_DOT = 1 << 2, /* Leave trailing dot in place */
-} DNSLabelFlags;
-
-int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags);
-int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);
-int dns_label_escape(const char *p, size_t l, char *dest, size_t sz);
-int dns_label_escape_new(const char *p, size_t l, char **ret);
-
-static inline int dns_name_parent(const char **name) {
-        return dns_label_unescape(name, NULL, DNS_LABEL_MAX, 0);
-}
-
-#if 0 /* NM_IGNORED */
-#if HAVE_LIBIDN
-int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
-int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
-#endif
-#endif /* NM_IGNORED */
-
-int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **ret);
-
-static inline int dns_name_normalize(const char *s, DNSLabelFlags flags, char **ret) {
-        /* dns_name_concat() normalizes as a side-effect */
-        return dns_name_concat(s, NULL, flags, ret);
-}
-
-static inline int dns_name_is_valid(const char *s) {
-        int r;
-
-        /* dns_name_normalize() verifies as a side effect */
-        r = dns_name_normalize(s, 0, NULL);
-        if (r == -EINVAL)
-                return 0;
-        if (r < 0)
-                return r;
-        return 1;
-}
-
-static inline int dns_name_is_valid_ldh(const char *s) {
-        int r;
-
-        r = dns_name_concat(s, NULL, DNS_LABEL_LDH|DNS_LABEL_NO_ESCAPES, NULL);
-        if (r == -EINVAL)
-                return 0;
-        if (r < 0)
-                return r;
-        return 1;
-}
-
-void dns_name_hash_func(const char *s, struct siphash *state);
-int dns_name_compare_func(const char *a, const char *b);
-extern const struct hash_ops dns_name_hash_ops;
-
-int dns_name_between(const char *a, const char *b, const char *c);
-int dns_name_equal(const char *x, const char *y);
-int dns_name_endswith(const char *name, const char *suffix);
-int dns_name_startswith(const char *name, const char *prefix);
-
-int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret);
-
-int dns_name_reverse(int family, const union in_addr_union *a, char **ret);
-int dns_name_address(const char *p, int *family, union in_addr_union *a);
-
-bool dns_name_is_root(const char *name);
-bool dns_name_is_single_label(const char *name);
-
-int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical);
-
-bool dns_srv_type_is_valid(const char *name);
-bool dnssd_srv_type_is_valid(const char *name);
-bool dns_service_name_is_valid(const char *name);
-
-int dns_service_join(const char *name, const char *type, const char *domain, char **ret);
-int dns_service_split(const char *joined, char **name, char **type, char **domain);
-
-int dns_name_suffix(const char *name, unsigned n_labels, const char **ret);
-int dns_name_count_labels(const char *name);
-
-int dns_name_skip(const char *a, unsigned n_labels, const char **ret);
-int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b);
-
-int dns_name_common_suffix(const char *a, const char *b, const char **ret);
-
-int dns_name_apply_idna(const char *name, char **ret);
-
-int dns_name_is_valid_or_address(const char *name);
-
-int dns_name_dot_suffixed(const char *name);
diff --git a/shared/systemd/src/shared/log-link.h b/shared/systemd/src/shared/log-link.h
deleted file mode 100644
index 3a4dcaa2..00000000
--- a/shared/systemd/src/shared/log-link.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* 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
deleted file mode 100644
index 35ba1a2e..00000000
--- a/shared/systemd/src/shared/web-util.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-shared.h"
-
-#include <stdbool.h>
-
-#include "string-util.h"
-#include "strv.h"
-#include "utf8.h"
-#include "web-util.h"
-
-#if 0 /* NM_IGNORED */
-bool http_etag_is_valid(const char *etag) {
-        if (isempty(etag))
-                return false;
-
-        if (!endswith(etag, "\""))
-                return false;
-
-        if (!STARTSWITH_SET(etag, "\"", "W/\""))
-                return false;
-
-        return true;
-}
-#endif /* NM_IGNORED */
-
-/* NM: we use http_url_is_valid() for our own code, and it must not
- * change behavior. If a re-import results in a merge-conflict, you must
- * ensure that it does not change behavior, and possibly do something
- * about that. */
-/**/   bool http_url_is_valid(const char *url) {
-/**/           const char *p;
-/**/
-/**/           if (isempty(url))
-/**/                   return false;
-/**/
-/**/           p = STARTSWITH_SET(url, "http://", "https://");
-/**/           if (!p)
-/**/                   return false;
-/**/
-/**/           if (isempty(p))
-/**/                   return false;
-/**/
-/**/           return ascii_is_valid(p);
-/**/   }
-
-#if 0 /* NM_IGNORED */
-bool documentation_url_is_valid(const char *url) {
-        const char *p;
-
-        if (isempty(url))
-                return false;
-
-        if (http_url_is_valid(url))
-                return true;
-
-        p = STARTSWITH_SET(url, "file:/", "info:", "man:");
-        if (isempty(p))
-                return false;
-
-        return ascii_is_valid(p);
-}
-#endif /* NM_IGNORED */
diff --git a/shared/systemd/src/shared/web-util.h b/shared/systemd/src/shared/web-util.h
deleted file mode 100644
index ec54669f..00000000
--- a/shared/systemd/src/shared/web-util.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-
-#include "macro.h"
-
-bool http_url_is_valid(const char *url) _pure_;
-
-bool documentation_url_is_valid(const char *url) _pure_;
-
-bool http_etag_is_valid(const char *etag);