summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-10-24 22:35:04 +0200
committerThomas Haller <thaller@redhat.com>2023-02-08 18:59:33 +0100
commita300809f3c878fe588ea19f17ca9475c660f8696 (patch)
tree41118ea3c7c3a01dc9fd374f4cef682d614c16d1
parent5afa09e966ca57b8fc3b898cc6116465d71cc53e (diff)
systemd: update code from upstream (2023-02-07)
This is a direct dump from systemd git. $ git clean -fdx && \ git cat-file -p HEAD | sed '1,/^======$/ d' | bash - && \ git add . ====== SYSTEMD_DIR=../systemd COMMIT=9eba03c7b10fe98e0443508402b3f9804230453e ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files -z :/src/libnm-systemd-core/src/ \ :/src/libnm-systemd-shared/src/ \ :/src/libnm-std-aux/unaligned-fundamental.h \ :/src/libnm-std-aux/unaligned.h | \ xargs -0 rm -f nm_copy_sd_shared() { mkdir -p "./src/libnm-systemd-shared/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-shared/$1" } nm_copy_sd_core() { mkdir -p "./src/libnm-systemd-core/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-core/$1" } nm_copy_sd_stdaux() { mkdir -p "./src/libnm-std-aux/" cp "$SYSTEMD_DIR/$1" "./src/libnm-std-aux/${1##*/}" } nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.c" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h" nm_copy_sd_core "src/libsystemd-network/network-common.c" nm_copy_sd_core "src/libsystemd-network/network-common.h" nm_copy_sd_core "src/libsystemd-network/network-internal.h" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c" nm_copy_sd_core "src/libsystemd/sd-device/device-util.h" nm_copy_sd_core "src/libsystemd/sd-event/event-source.h" nm_copy_sd_core "src/libsystemd/sd-event/event-util.c" nm_copy_sd_core "src/libsystemd/sd-event/event-util.h" nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h" nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c" nm_copy_sd_core "src/systemd/_sd-common.h" nm_copy_sd_core "src/systemd/sd-device.h" nm_copy_sd_core "src/systemd/sd-dhcp6-client.h" nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h" nm_copy_sd_core "src/systemd/sd-dhcp6-option.h" nm_copy_sd_core "src/systemd/sd-event.h" nm_copy_sd_core "src/systemd/sd-id128.h" nm_copy_sd_core "src/systemd/sd-ndisc.h" nm_copy_sd_shared "src/basic/alloc-util.c" nm_copy_sd_shared "src/basic/alloc-util.h" nm_copy_sd_shared "src/basic/async.h" nm_copy_sd_shared "src/basic/cgroup-util.h" nm_copy_sd_shared "src/basic/constants.h" nm_copy_sd_shared "src/basic/dns-def.h" nm_copy_sd_shared "src/basic/env-file.c" nm_copy_sd_shared "src/basic/env-file.h" nm_copy_sd_shared "src/basic/env-util.c" nm_copy_sd_shared "src/basic/env-util.h" nm_copy_sd_shared "src/basic/errno-util.h" nm_copy_sd_shared "src/basic/escape.c" nm_copy_sd_shared "src/basic/escape.h" nm_copy_sd_shared "src/basic/ether-addr-util.c" nm_copy_sd_shared "src/basic/ether-addr-util.h" nm_copy_sd_shared "src/basic/extract-word.c" nm_copy_sd_shared "src/basic/extract-word.h" nm_copy_sd_shared "src/basic/fd-util.c" nm_copy_sd_shared "src/basic/fd-util.h" nm_copy_sd_shared "src/basic/fileio.c" nm_copy_sd_shared "src/basic/fileio.h" nm_copy_sd_shared "src/basic/format-util.c" nm_copy_sd_shared "src/basic/format-util.h" nm_copy_sd_shared "src/basic/fs-util.c" nm_copy_sd_shared "src/basic/fs-util.h" nm_copy_sd_shared "src/basic/glyph-util.c" nm_copy_sd_shared "src/basic/glyph-util.h" nm_copy_sd_shared "src/basic/hash-funcs.c" nm_copy_sd_shared "src/basic/hash-funcs.h" nm_copy_sd_shared "src/basic/hashmap.c" nm_copy_sd_shared "src/basic/hashmap.h" nm_copy_sd_shared "src/basic/hexdecoct.c" nm_copy_sd_shared "src/basic/hexdecoct.h" nm_copy_sd_shared "src/basic/hostname-util.c" nm_copy_sd_shared "src/basic/hostname-util.h" nm_copy_sd_shared "src/basic/in-addr-util.c" nm_copy_sd_shared "src/basic/in-addr-util.h" nm_copy_sd_shared "src/basic/inotify-util.c" nm_copy_sd_shared "src/basic/inotify-util.h" nm_copy_sd_shared "src/basic/io-util.c" nm_copy_sd_shared "src/basic/io-util.h" nm_copy_sd_shared "src/basic/list.h" nm_copy_sd_shared "src/basic/locale-util.c" nm_copy_sd_shared "src/basic/locale-util.h" nm_copy_sd_shared "src/basic/log.h" nm_copy_sd_shared "src/basic/logarithm.h" nm_copy_sd_shared "src/basic/macro.h" nm_copy_sd_shared "src/basic/memory-util.c" nm_copy_sd_shared "src/basic/memory-util.h" nm_copy_sd_shared "src/basic/mempool.c" nm_copy_sd_shared "src/basic/mempool.h" nm_copy_sd_shared "src/basic/missing_fcntl.h" nm_copy_sd_shared "src/basic/missing_random.h" nm_copy_sd_shared "src/basic/missing_socket.h" nm_copy_sd_shared "src/basic/missing_stat.h" nm_copy_sd_shared "src/basic/missing_syscall.h" nm_copy_sd_shared "src/basic/missing_type.h" nm_copy_sd_shared "src/basic/ordered-set.c" nm_copy_sd_shared "src/basic/ordered-set.h" nm_copy_sd_shared "src/basic/parse-util.c" nm_copy_sd_shared "src/basic/parse-util.h" nm_copy_sd_shared "src/basic/path-util.c" nm_copy_sd_shared "src/basic/path-util.h" nm_copy_sd_shared "src/basic/prioq.c" nm_copy_sd_shared "src/basic/prioq.h" nm_copy_sd_shared "src/basic/process-util.c" nm_copy_sd_shared "src/basic/process-util.h" nm_copy_sd_shared "src/basic/random-util.c" nm_copy_sd_shared "src/basic/random-util.h" nm_copy_sd_shared "src/basic/ratelimit.c" nm_copy_sd_shared "src/basic/ratelimit.h" nm_copy_sd_shared "src/basic/set.h" nm_copy_sd_shared "src/basic/signal-util.c" nm_copy_sd_shared "src/basic/signal-util.h" nm_copy_sd_shared "src/basic/siphash24.h" nm_copy_sd_shared "src/basic/socket-util.c" nm_copy_sd_shared "src/basic/socket-util.h" nm_copy_sd_shared "src/basic/sort-util.h" nm_copy_sd_shared "src/basic/sparse-endian.h" nm_copy_sd_shared "src/basic/stat-util.c" nm_copy_sd_shared "src/basic/stat-util.h" nm_copy_sd_shared "src/basic/stdio-util.h" nm_copy_sd_shared "src/basic/string-table.c" nm_copy_sd_shared "src/basic/string-table.h" nm_copy_sd_shared "src/basic/string-util.c" nm_copy_sd_shared "src/basic/string-util.h" nm_copy_sd_shared "src/basic/strv.c" nm_copy_sd_shared "src/basic/strv.h" nm_copy_sd_shared "src/basic/strxcpyx.c" nm_copy_sd_shared "src/basic/strxcpyx.h" nm_copy_sd_shared "src/basic/time-util.c" nm_copy_sd_shared "src/basic/time-util.h" nm_copy_sd_shared "src/basic/tmpfile-util.c" nm_copy_sd_shared "src/basic/tmpfile-util.h" nm_copy_sd_shared "src/basic/umask-util.h" nm_copy_sd_shared "src/basic/user-util.h" nm_copy_sd_shared "src/basic/utf8.c" nm_copy_sd_shared "src/basic/utf8.h" nm_copy_sd_shared "src/fundamental/macro-fundamental.h" nm_copy_sd_shared "src/fundamental/memory-util-fundamental.h" nm_copy_sd_shared "src/fundamental/sha256.c" nm_copy_sd_shared "src/fundamental/sha256.h" nm_copy_sd_shared "src/fundamental/string-util-fundamental.c" nm_copy_sd_shared "src/fundamental/string-util-fundamental.h" nm_copy_sd_shared "src/shared/dns-domain.c" nm_copy_sd_shared "src/shared/dns-domain.h" nm_copy_sd_shared "src/shared/log-link.h" nm_copy_sd_shared "src/shared/web-util.c" nm_copy_sd_shared "src/shared/web-util.h" nm_copy_sd_stdaux "src/basic/unaligned.h" nm_copy_sd_stdaux "src/fundamental/unaligned-fundamental.h"
-rw-r--r--src/libnm-std-aux/unaligned-fundamental.h40
-rw-r--r--src/libnm-std-aux/unaligned.h20
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/arp-util.c140
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/arp-util.h36
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c38
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h4
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h90
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h5
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c2
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c25
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c1
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h1
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c99
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c8
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h103
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c2
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c62
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c116
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h37
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c81
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-device.h167
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h3
-rw-r--r--src/libnm-systemd-shared/src/basic/alloc-util.c4
-rw-r--r--src/libnm-systemd-shared/src/basic/alloc-util.h39
-rw-r--r--src/libnm-systemd-shared/src/basic/cgroup-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/constants.h111
-rw-r--r--src/libnm-systemd-shared/src/basic/env-file.c76
-rw-r--r--src/libnm-systemd-shared/src/basic/env-file.h6
-rw-r--r--src/libnm-systemd-shared/src/basic/escape.c29
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.c118
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.h19
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.c65
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.h21
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.c57
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.h5
-rw-r--r--src/libnm-systemd-shared/src/basic/glyph-util.c22
-rw-r--r--src/libnm-systemd-shared/src/basic/glyph-util.h1
-rw-r--r--src/libnm-systemd-shared/src/basic/hashmap.c10
-rw-r--r--src/libnm-systemd-shared/src/basic/hashmap.h1
-rw-r--r--src/libnm-systemd-shared/src/basic/hexdecoct.c229
-rw-r--r--src/libnm-systemd-shared/src/basic/hexdecoct.h10
-rw-r--r--src/libnm-systemd-shared/src/basic/hostname-util.c2
-rw-r--r--src/libnm-systemd-shared/src/basic/hostname-util.h8
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.c34
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.h5
-rw-r--r--src/libnm-systemd-shared/src/basic/io-util.c18
-rw-r--r--src/libnm-systemd-shared/src/basic/io-util.h9
-rw-r--r--src/libnm-systemd-shared/src/basic/list.h71
-rw-r--r--src/libnm-systemd-shared/src/basic/locale-util.c14
-rw-r--r--src/libnm-systemd-shared/src/basic/log.h117
-rw-r--r--src/libnm-systemd-shared/src/basic/logarithm.h (renamed from src/libnm-systemd-shared/src/basic/util.h)27
-rw-r--r--src/libnm-systemd-shared/src/basic/macro.h43
-rw-r--r--src/libnm-systemd-shared/src/basic/memory-util.c18
-rw-r--r--src/libnm-systemd-shared/src/basic/memory-util.h12
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_syscall.h92
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.c20
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.h1
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.c54
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.h3
-rw-r--r--src/libnm-systemd-shared/src/basic/prioq.c5
-rw-r--r--src/libnm-systemd-shared/src/basic/prioq.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.c284
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.h32
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.c8
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.h1
-rw-r--r--src/libnm-systemd-shared/src/basic/ratelimit.c15
-rw-r--r--src/libnm-systemd-shared/src/basic/signal-util.c18
-rw-r--r--src/libnm-systemd-shared/src/basic/signal-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.c72
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.h20
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.c45
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.h5
-rw-r--r--src/libnm-systemd-shared/src/basic/stdio-util.h23
-rw-r--r--src/libnm-systemd-shared/src/basic/string-util.c60
-rw-r--r--src/libnm-systemd-shared/src/basic/string-util.h28
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.c131
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.h18
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.c74
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.h1
-rw-r--r--src/libnm-systemd-shared/src/basic/tmpfile-util.c102
-rw-r--r--src/libnm-systemd-shared/src/basic/tmpfile-util.h13
-rw-r--r--src/libnm-systemd-shared/src/basic/umask-util.h6
-rw-r--r--src/libnm-systemd-shared/src/basic/util.c174
-rw-r--r--src/libnm-systemd-shared/src/fundamental/macro-fundamental.h118
-rw-r--r--src/libnm-systemd-shared/src/fundamental/memory-util-fundamental.h66
-rw-r--r--src/libnm-systemd-shared/src/fundamental/sha256.c28
-rw-r--r--src/libnm-systemd-shared/src/fundamental/sha256.h8
-rw-r--r--src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c4
-rw-r--r--src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h10
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.c32
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.h5
91 files changed, 2156 insertions, 1707 deletions
diff --git a/src/libnm-std-aux/unaligned-fundamental.h b/src/libnm-std-aux/unaligned-fundamental.h
new file mode 100644
index 0000000000..a4c810a5fc
--- /dev/null
+++ b/src/libnm-std-aux/unaligned-fundamental.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdint.h>
+
+static inline uint16_t unaligned_read_ne16(const void *_u) {
+ const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
+
+ return u->x;
+}
+
+static inline uint32_t unaligned_read_ne32(const void *_u) {
+ const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
+
+ return u->x;
+}
+
+static inline uint64_t unaligned_read_ne64(const void *_u) {
+ const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
+
+ return u->x;
+}
+
+static inline void unaligned_write_ne16(void *_u, uint16_t a) {
+ struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
+
+ u->x = a;
+}
+
+static inline void unaligned_write_ne32(void *_u, uint32_t a) {
+ struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
+
+ u->x = a;
+}
+
+static inline void unaligned_write_ne64(void *_u, uint64_t a) {
+ struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
+
+ u->x = a;
+}
diff --git a/src/libnm-std-aux/unaligned.h b/src/libnm-std-aux/unaligned.h
index 4100be0803..04580cfb63 100644
--- a/src/libnm-std-aux/unaligned.h
+++ b/src/libnm-std-aux/unaligned.h
@@ -4,6 +4,8 @@
#include <endian.h>
#include <stdint.h>
+#include "unaligned-fundamental.h"
+
/* BE */
static inline uint16_t unaligned_read_be16(const void *_u) {
@@ -79,21 +81,3 @@ static inline void unaligned_write_le64(void *_u, uint64_t a) {
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/src/libnm-systemd-core/src/libsystemd-network/arp-util.c b/src/libnm-systemd-core/src/libsystemd-network/arp-util.c
deleted file mode 100644
index 99a5f69b70..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/arp-util.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/***
- Copyright © 2014 Axis Communications AB. All rights reserved.
-***/
-
-#include <arpa/inet.h>
-#include <linux/filter.h>
-#include <netinet/if_ether.h>
-
-#include "arp-util.h"
-#include "ether-addr-util.h"
-#include "fd-util.h"
-#include "in-addr-util.h"
-#include "unaligned.h"
-#include "util.h"
-
-int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac) {
- struct sock_filter filter[] = {
- BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
- BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hln)), /* A <- hardware address length */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct ether_addr), 1, 0), /* length == sizeof(ether_addr)? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pln)), /* A <- protocol address length */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct in_addr), 1, 0), /* length == sizeof(in_addr) ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), /* protocol == request ? */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- /* Sender Hardware Address must be different from our own */
- BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(&mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 4), /* A == X ? */
- BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(&mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- /* Sender Protocol Address or Target Protocol Address must be equal to the one we care about */
- BPF_STMT(BPF_LDX + BPF_IMM, htobe32(a->s_addr)), /* X <- clients IP */
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */
- BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == 0 ? */
- BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- };
- struct sock_fprog fprog = {
- .len = ELEMENTSOF(filter),
- .filter = (struct sock_filter*) filter,
- };
-
- assert(fd >= 0);
-
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
- return -errno;
-
- return 0;
-}
-
-int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac) {
- union sockaddr_union link = {
- .ll.sll_family = AF_PACKET,
- .ll.sll_protocol = htobe16(ETH_P_ARP),
- .ll.sll_ifindex = ifindex,
- .ll.sll_halen = ETH_ALEN,
- .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
- };
- _cleanup_close_ int s = -1;
- int r;
-
- assert(ifindex > 0);
- assert(mac);
-
- s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (s < 0)
- return -errno;
-
- r = arp_update_filter(s, a, mac);
- if (r < 0)
- return r;
-
- if (bind(s, &link.sa, sizeof(link.ll)) < 0)
- return -errno;
-
- return TAKE_FD(s);
-}
-
-int arp_send_packet(
- int fd,
- int ifindex,
- const struct in_addr *pa,
- const struct ether_addr *ha,
- bool announce) {
-
- union sockaddr_union link = {
- .ll.sll_family = AF_PACKET,
- .ll.sll_protocol = htobe16(ETH_P_ARP),
- .ll.sll_ifindex = ifindex,
- .ll.sll_halen = ETH_ALEN,
- .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
- };
- struct ether_arp arp = {
- .ea_hdr.ar_hrd = htobe16(ARPHRD_ETHER), /* HTYPE */
- .ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */
- .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */
- .ea_hdr.ar_pln = sizeof(struct in_addr), /* PLEN */
- .ea_hdr.ar_op = htobe16(ARPOP_REQUEST), /* REQUEST */
- };
- ssize_t n;
-
- assert(fd >= 0);
- assert(ifindex > 0);
- assert(pa);
- assert(in4_addr_is_set(pa));
- assert(ha);
- assert(!ether_addr_is_null(ha));
-
- memcpy(&arp.arp_sha, ha, ETH_ALEN);
- memcpy(&arp.arp_tpa, pa, sizeof(struct in_addr));
-
- if (announce)
- memcpy(&arp.arp_spa, pa, sizeof(struct in_addr));
-
- n = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll));
- if (n < 0)
- return -errno;
- if (n != sizeof(struct ether_arp))
- return -EIO;
-
- return 0;
-}
diff --git a/src/libnm-systemd-core/src/libsystemd-network/arp-util.h b/src/libnm-systemd-core/src/libsystemd-network/arp-util.h
deleted file mode 100644
index b66a81bf9b..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/arp-util.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-/***
- Copyright © 2014 Axis Communications AB. All rights reserved.
-***/
-
-#include <net/ethernet.h>
-#include <netinet/in.h>
-
-#include "socket-util.h"
-#include "sparse-endian.h"
-
-int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac);
-int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac);
-
-int arp_send_packet(
- int fd,
- int ifindex,
- const struct in_addr *pa,
- const struct ether_addr *ha,
- bool announce);
-static inline int arp_send_probe(
- int fd,
- int ifindex,
- const struct in_addr *pa,
- const struct ether_addr *ha) {
- return arp_send_packet(fd, ifindex, pa, ha, false);
-}
-static inline int arp_send_announcement(
- int fd,
- int ifindex,
- const struct in_addr *pa,
- const struct ether_addr *ha) {
- return arp_send_packet(fd, ifindex, pa, ha, true);
-}
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c
index 68f6a7cb3c..a27d67a315 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c
@@ -4,15 +4,11 @@
#include <net/ethernet.h>
#include <net/if_arp.h>
-#include "sd-device.h"
-#include "sd-id128.h"
-
#include "dhcp-identifier.h"
#include "netif-util.h"
#include "siphash24.h"
#include "sparse-endian.h"
#include "string-table.h"
-#include "udev-util.h"
#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
@@ -207,48 +203,20 @@ int dhcp_identifier_set_duid(
}
int dhcp_identifier_set_iaid(
- int ifindex,
+ sd_device *dev,
const struct hw_addr_data *hw_addr,
bool legacy_unstable_byteorder,
- bool use_mac,
void *ret) {
- /* name is a pointer to memory in the sd_device struct, so must
- * have the same scope */
- _cleanup_(sd_device_unrefp) sd_device *device = NULL;
const char *name = NULL;
uint32_t id32;
uint64_t id;
- int r;
- assert(ifindex > 0);
assert(hw_addr);
assert(ret);
- if (udev_available() && !use_mac) {
- /* udev should be around */
-
- r = sd_device_new_from_ifindex(&device, ifindex);
- if (r < 0)
- return r;
-
- r = sd_device_get_is_initialized(device);
- if (r < 0)
- return r;
- if (r == 0)
- /* not yet ready */
- return -EBUSY;
-
- r = device_is_renaming(device);
- if (r < 0)
- return r;
- if (r > 0)
- /* device is under renaming */
- return -EBUSY;
-
- name = net_get_persistent_name(device);
- }
-
+ if (dev)
+ name = net_get_persistent_name(dev);
if (name)
id = siphash24(name, strlen(name), HASH_KEY.bytes);
else
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h
index 8acb8c3210..523dfc4a71 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include "sd-device.h"
#include "sd-id128.h"
#include "ether-addr-util.h"
@@ -66,10 +67,9 @@ int dhcp_identifier_set_duid(
struct duid *ret_duid,
size_t *ret_len);
int dhcp_identifier_set_iaid(
- int ifindex,
+ sd_device *dev,
const struct hw_addr_data *hw_addr,
bool legacy_unstable_byteorder,
- bool use_mac,
void *ret);
const char *duid_type_to_string(DUIDType t) _const_;
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h
deleted file mode 100644
index c67e9511a1..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-/***
- Copyright © 2013 Intel Corporation. All rights reserved.
-***/
-
-#include "sd-dhcp-client.h"
-
-#include "dhcp-internal.h"
-#include "dhcp-protocol.h"
-#include "list.h"
-#include "util.h"
-
-struct sd_dhcp_route {
- struct in_addr dst_addr;
- struct in_addr gw_addr;
- unsigned char dst_prefixlen;
-};
-
-struct sd_dhcp_raw_option {
- LIST_FIELDS(struct sd_dhcp_raw_option, options);
-
- uint8_t tag;
- uint8_t length;
- void *data;
-};
-
-struct sd_dhcp_lease {
- unsigned n_ref;
-
- /* each 0 if unset */
- uint32_t t1;
- uint32_t t2;
- uint32_t lifetime;
-
- /* each 0 if unset */
- be32_t address;
- be32_t server_address;
- be32_t next_server;
-
- bool have_subnet_mask;
- be32_t subnet_mask;
-
- bool have_broadcast;
- be32_t broadcast;
-
- struct in_addr *router;
- size_t router_size;
-
- DHCPServerData servers[_SD_DHCP_LEASE_SERVER_TYPE_MAX];
-
- struct sd_dhcp_route *static_routes;
- size_t n_static_routes;
- struct sd_dhcp_route *classless_routes;
- size_t n_classless_routes;
-
- uint16_t mtu; /* 0 if unset */
-
- char *domainname;
- char **search_domains;
- char *hostname;
- char *root_path;
-
- void *client_id;
- size_t client_id_len;
-
- void *vendor_specific;
- size_t vendor_specific_len;
-
- char *timezone;
-
- uint8_t sixrd_ipv4masklen;
- uint8_t sixrd_prefixlen;
- struct in6_addr sixrd_prefix;
- struct in_addr *sixrd_br_addresses;
- size_t sixrd_n_br_addresses;
-
- LIST_HEAD(struct sd_dhcp_raw_option, private_options);
-};
-
-int dhcp_lease_new(sd_dhcp_lease **ret);
-
-int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata);
-int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains);
-int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len);
-
-int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);
-
-int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h
index 65f6cb057f..fa43f28eb5 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h
@@ -48,6 +48,8 @@ struct sd_dhcp6_client {
int event_priority;
int fd;
+ sd_device *dev;
+
DHCP6State state;
bool information_request;
usec_t information_request_time_usec;
@@ -77,8 +79,9 @@ struct sd_dhcp6_client {
sd_dhcp6_client_callback_t callback;
void *userdata;
+ bool send_release;
- /* Ignore ifindex when generating iaid. See dhcp_identifier_set_iaid(). */
+ /* Ignore machine-ID when generating DUID. See dhcp_identifier_set_duid_en(). */
bool test_mode;
};
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c
index eedd92d3c2..a3e4e19e8e 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c
@@ -23,7 +23,7 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) {
.in6.sin6_port = htobe16(DHCP6_PORT_CLIENT),
.in6.sin6_scope_id = ifindex,
};
- _cleanup_close_ int s = -1;
+ _cleanup_close_ int s = -EBADF;
int r;
assert(ifindex > 0);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
index 62873e0111..a6b74e07b2 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
@@ -495,13 +495,18 @@ int dhcp6_option_parse(
}
int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_status_message) {
+ DHCP6Status status;
+
assert(data || data_len == 0);
if (data_len < sizeof(uint16_t))
return -EBADMSG;
+ status = unaligned_read_be16(data);
+
if (ret_status_message) {
- char *msg;
+ _cleanup_free_ char *msg = NULL;
+ const char *s;
/* The status message MUST NOT be null-terminated. See section 21.13 of RFC8415.
* Let's escape unsafe characters for safety. */
@@ -509,10 +514,14 @@ int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_s
if (!msg)
return -ENOMEM;
- *ret_status_message = msg;
+ s = dhcp6_message_status_to_string(status);
+ if (s && !strextend_with_separator(&msg, ": ", s))
+ return -ENOMEM;
+
+ *ret_status_message = TAKE_PTR(msg);
}
- return unaligned_read_be16(data);
+ return status;
}
static int dhcp6_option_parse_ia_options(sd_dhcp6_client *client, const uint8_t *buf, size_t buflen) {
@@ -538,9 +547,8 @@ static int dhcp6_option_parse_ia_options(sd_dhcp6_client *client, const uint8_t
return r;
if (r > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
- "Received an IA address or PD prefix option with non-zero status: %s%s%s",
- strempty(msg), isempty(msg) ? "" : ": ",
- dhcp6_message_status_to_string(r));
+ "Received an IA address or PD prefix option with non-zero status%s%s",
+ isempty(msg) ? "." : ": ", strempty(msg));
if (r < 0)
/* Let's log but ignore the invalid status option. */
log_dhcp6_client_errno(client, r,
@@ -746,9 +754,8 @@ int dhcp6_option_parse_ia(
return r;
if (r > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
- "Received an IA option with non-zero status: %s%s%s",
- strempty(msg), isempty(msg) ? "" : ": ",
- dhcp6_message_status_to_string(r));
+ "Received an IA option with non-zero status%s%s",
+ isempty(msg) ? "." : ": ", strempty(msg));
if (r < 0)
log_dhcp6_client_errno(client, r,
"Received an IA option with an invalid status sub option, ignoring: %m");
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c
index f965ea40fe..be0f651f1a 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c
@@ -11,6 +11,7 @@ static const char * const dhcp6_state_table[_DHCP6_STATE_MAX] = {
[DHCP6_STATE_BOUND] = "bound",
[DHCP6_STATE_RENEW] = "renew",
[DHCP6_STATE_REBIND] = "rebind",
+ [DHCP6_STATE_STOPPING] = "stopping",
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(dhcp6_state, DHCP6State);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h
index 18217691b7..c70f93203d 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h
@@ -58,6 +58,7 @@ typedef enum DHCP6State {
DHCP6_STATE_BOUND,
DHCP6_STATE_RENEW,
DHCP6_STATE_REBIND,
+ DHCP6_STATE_STOPPING,
_DHCP6_STATE_MAX,
_DHCP6_STATE_INVALID = -EINVAL,
} DHCP6State;
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
index 375f984940..57dd91f81f 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
@@ -11,6 +11,7 @@
#include "sd-dhcp6-client.h"
#include "alloc-util.h"
+#include "device-util.h"
#include "dhcp-identifier.h"
#include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h"
@@ -299,9 +300,8 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
if (client->iaid_set)
return 0;
- r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr,
+ r = dhcp_identifier_set_iaid(client->dev, &client->hw_addr,
/* legacy_unstable_byteorder = */ true,
- /* use_mac = */ client->test_mode,
&iaid);
if (r < 0)
return r;
@@ -498,6 +498,14 @@ int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable) {
return 0;
}
+int sd_dhcp6_client_set_send_release(sd_dhcp6_client *client, int enable) {
+ assert_return(client, -EINVAL);
+ assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
+
+ client->send_release = enable;
+ return 0;
+}
+
int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
assert_return(client, -EINVAL);
@@ -586,7 +594,8 @@ static int client_append_common_options_in_managed_mode(
DHCP6_STATE_SOLICITATION,
DHCP6_STATE_REQUEST,
DHCP6_STATE_RENEW,
- DHCP6_STATE_REBIND));
+ DHCP6_STATE_REBIND,
+ DHCP6_STATE_STOPPING));
assert(buf);
assert(*buf);
assert(offset);
@@ -603,9 +612,11 @@ static int client_append_common_options_in_managed_mode(
return r;
}
- r = dhcp6_option_append_fqdn(buf, offset, client->fqdn);
- if (r < 0)
- return r;
+ if (client->state != DHCP6_STATE_STOPPING) {
+ r = dhcp6_option_append_fqdn(buf, offset, client->fqdn);
+ if (r < 0)
+ return r;
+ }
r = dhcp6_option_append_user_class(buf, offset, client->user_class);
if (r < 0)
@@ -636,6 +647,8 @@ static DHCP6MessageType client_message_type_from_state(sd_dhcp6_client *client)
return DHCP6_MESSAGE_RENEW;
case DHCP6_STATE_REBIND:
return DHCP6_MESSAGE_REBIND;
+ case DHCP6_STATE_STOPPING:
+ return DHCP6_MESSAGE_RELEASE;
default:
assert_not_reached();
}
@@ -679,6 +692,9 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **buf, size_t *off
req_opts = p;
break;
+ case DHCP6_STATE_STOPPING:
+ return 0;
+
default:
n = client->n_req_opts;
req_opts = client->req_opts;
@@ -690,6 +706,22 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **buf, size_t *off
return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
}
+static int client_append_mudurl(sd_dhcp6_client *client, uint8_t **buf, size_t *offset) {
+ assert(client);
+ assert(buf);
+ assert(*buf);
+ assert(offset);
+
+ if (!client->mudurl)
+ return 0;
+
+ if (client->state == DHCP6_STATE_STOPPING)
+ return 0;
+
+ return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_MUD_URL_V6,
+ strlen(client->mudurl), client->mudurl);
+}
+
int dhcp6_client_send_message(sd_dhcp6_client *client) {
_cleanup_free_ uint8_t *buf = NULL;
struct in6_addr all_servers =
@@ -735,7 +767,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
-
+ case DHCP6_STATE_STOPPING:
r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_SERVERID,
client->lease->serverid_len,
client->lease->serverid);
@@ -753,18 +785,15 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
return r;
break;
- case DHCP6_STATE_STOPPED:
case DHCP6_STATE_BOUND:
+ case DHCP6_STATE_STOPPED:
default:
assert_not_reached();
}
- if (client->mudurl) {
- r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_MUD_URL_V6,
- strlen(client->mudurl), client->mudurl);
- if (r < 0)
- return r;
- }
+ r = client_append_mudurl(client, &buf, &offset);
+ if (r < 0)
+ return r;
r = client_append_oro(client, &buf, &offset);
if (r < 0)
@@ -856,6 +885,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
break;
case DHCP6_STATE_STOPPED:
+ case DHCP6_STATE_STOPPING:
case DHCP6_STATE_BOUND:
default:
assert_not_reached();
@@ -911,6 +941,7 @@ static int client_start_transaction(sd_dhcp6_client *client, DHCP6State state) {
assert(IN_SET(client->state, DHCP6_STATE_BOUND, DHCP6_STATE_RENEW));
break;
case DHCP6_STATE_STOPPED:
+ case DHCP6_STATE_STOPPING:
case DHCP6_STATE_BOUND:
default:
assert_not_reached();
@@ -1293,7 +1324,7 @@ static int client_receive_message(
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SO_TIMESTAMP &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
- triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) CMSG_DATA(cmsg)));
+ triple_timestamp_from_realtime(&t, timeval_load(CMSG_TYPED_DATA(cmsg, struct timeval)));
}
if (client->transaction_id != (message->transaction_id & htobe32(0x00ffffff)))
@@ -1319,6 +1350,7 @@ static int client_receive_message(
case DHCP6_STATE_BOUND:
case DHCP6_STATE_STOPPED:
+ case DHCP6_STATE_STOPPING:
default:
assert_not_reached();
}
@@ -1326,10 +1358,37 @@ static int client_receive_message(
return 0;
}
+static int client_send_release(sd_dhcp6_client *client) {
+ sd_dhcp6_lease *lease;
+
+ assert(client);
+
+ if (!client->send_release)
+ return 0;
+
+ if (sd_dhcp6_client_get_lease(client, &lease) < 0)
+ return 0;
+
+ if (!lease->ia_na && !lease->ia_pd)
+ return 0;
+
+ client_set_state(client, DHCP6_STATE_STOPPING);
+ return dhcp6_client_send_message(client);
+}
+
int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
+ int r;
+
if (!client)
return 0;
+ /* Intentionally ignoring failure to send DHCP6 release. The DHCPv6 client
+ * engine is about to release its UDP socket unconditionally. */
+ r = client_send_release(client);
+ if (r < 0)
+ log_dhcp6_client_errno(client, r,
+ "Failed to send DHCP6 release message, ignoring: %m");
+
client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
client->receive_message = sd_event_source_unref(client->receive_message);
@@ -1446,6 +1505,12 @@ sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
return client->event;
}
+int sd_dhcp6_client_attach_device(sd_dhcp6_client *client, sd_device *dev) {
+ assert_return(client, -EINVAL);
+
+ return device_unref_and_replace(client->dev, dev);
+}
+
static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
if (!client)
return NULL;
@@ -1461,6 +1526,8 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
client->fd = safe_close(client->fd);
+ sd_device_unref(client->dev);
+
free(client->req_opts);
free(client->fqdn);
free(client->mudurl);
@@ -1491,7 +1558,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
.ia_pd.type = SD_DHCP6_OPTION_IA_PD,
.ifindex = -1,
.request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD,
- .fd = -1,
+ .fd = -EBADF,
.rapid_commit = true,
};
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
index 57c23965ed..d14c412c1f 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
@@ -510,13 +510,11 @@ static int dhcp6_lease_parse_message(
r = dhcp6_option_parse_status(optval, optlen, &msg);
if (r < 0)
return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m");
-
if (r > 0)
return log_dhcp6_client_errno(client, dhcp6_message_status_to_errno(r),
- "Received %s message with non-zero status: %s%s%s",
+ "Received %s message with non-zero status%s%s",
dhcp6_message_type_to_string(message->type),
- strempty(msg), isempty(msg) ? "" : ": ",
- dhcp6_message_status_to_string(r));
+ isempty(msg) ? "." : ": ", strempty(msg));
break;
}
case SD_DHCP6_OPTION_IA_NA: {
@@ -619,7 +617,7 @@ static int dhcp6_lease_parse_message(
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Received information refresh time option with an invalid length (%zu).", optlen);
- irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC;
+ irt = unaligned_read_be32(optval) * USEC_PER_SEC;
break;
}
}
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h b/src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h
new file mode 100644
index 0000000000..a1b5e91edf
--- /dev/null
+++ b/src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "sd-device.h"
+
+#include "log.h"
+#include "macro.h"
+
+#define device_unref_and_replace(a, b) \
+ unref_and_replace_full(a, b, sd_device_ref, sd_device_unref)
+
+#define FOREACH_DEVICE_PROPERTY(device, key, value) \
+ for (key = sd_device_get_property_first(device, &(value)); \
+ key; \
+ key = sd_device_get_property_next(device, &(value)))
+
+#define FOREACH_DEVICE_TAG(device, tag) \
+ for (tag = sd_device_get_tag_first(device); \
+ tag; \
+ tag = sd_device_get_tag_next(device))
+
+#define FOREACH_DEVICE_CURRENT_TAG(device, tag) \
+ for (tag = sd_device_get_current_tag_first(device); \
+ tag; \
+ tag = sd_device_get_current_tag_next(device))
+
+#define FOREACH_DEVICE_SYSATTR(device, attr) \
+ for (attr = sd_device_get_sysattr_first(device); \
+ attr; \
+ attr = sd_device_get_sysattr_next(device))
+
+#define FOREACH_DEVICE_DEVLINK(device, devlink) \
+ for (devlink = sd_device_get_devlink_first(device); \
+ devlink; \
+ devlink = sd_device_get_devlink_next(device))
+
+#define _FOREACH_DEVICE_CHILD(device, child, suffix_ptr) \
+ for (child = sd_device_get_child_first(device, suffix_ptr); \
+ child; \
+ child = sd_device_get_child_next(device, suffix_ptr))
+
+#define FOREACH_DEVICE_CHILD(device, child) \
+ _FOREACH_DEVICE_CHILD(device, child, NULL)
+
+#define FOREACH_DEVICE_CHILD_WITH_SUFFIX(device, child, suffix) \
+ _FOREACH_DEVICE_CHILD(device, child, &suffix)
+
+#define FOREACH_DEVICE(enumerator, device) \
+ for (device = sd_device_enumerator_get_device_first(enumerator); \
+ device; \
+ device = sd_device_enumerator_get_device_next(enumerator))
+
+#define FOREACH_SUBSYSTEM(enumerator, device) \
+ for (device = sd_device_enumerator_get_subsystem_first(enumerator); \
+ device; \
+ device = sd_device_enumerator_get_subsystem_next(enumerator))
+
+#define log_device_full_errno_zerook(device, level, error, ...) \
+ ({ \
+ const char *_sysname = NULL; \
+ sd_device *_d = (device); \
+ int _level = (level), _e = (error); \
+ \
+ if (_d && _unlikely_(log_get_max_level() >= LOG_PRI(_level))) \
+ (void) sd_device_get_sysname(_d, &_sysname); \
+ log_object_internal(_level, _e, PROJECT_FILE, __LINE__, __func__, \
+ _sysname ? "DEVICE=" : NULL, _sysname, \
+ NULL, NULL, __VA_ARGS__); \
+ })
+
+#define log_device_full_errno(device, level, error, ...) \
+ ({ \
+ int _error = (error); \
+ ASSERT_NON_ZERO(_error); \
+ log_device_full_errno_zerook(device, level, _error, __VA_ARGS__); \
+ })
+
+#define log_device_full(device, level, ...) (void) log_device_full_errno_zerook(device, level, 0, __VA_ARGS__)
+
+#define log_device_debug(device, ...) log_device_full(device, LOG_DEBUG, __VA_ARGS__)
+#define log_device_info(device, ...) log_device_full(device, LOG_INFO, __VA_ARGS__)
+#define log_device_notice(device, ...) log_device_full(device, LOG_NOTICE, __VA_ARGS__)
+#define log_device_warning(device, ...) log_device_full(device, LOG_WARNING, __VA_ARGS__)
+#define log_device_error(device, ...) log_device_full(device, LOG_ERR, __VA_ARGS__)
+
+#define log_device_debug_errno(device, error, ...) log_device_full_errno(device, LOG_DEBUG, error, __VA_ARGS__)
+#define log_device_info_errno(device, error, ...) log_device_full_errno(device, LOG_INFO, error, __VA_ARGS__)
+#define log_device_notice_errno(device, error, ...) log_device_full_errno(device, LOG_NOTICE, error, __VA_ARGS__)
+#define log_device_warning_errno(device, error, ...) log_device_full_errno(device, LOG_WARNING, error, __VA_ARGS__)
+#define log_device_error_errno(device, error, ...) log_device_full_errno(device, LOG_ERR, error, __VA_ARGS__)
+
+int devname_from_devnum(mode_t mode, dev_t devnum, char **ret);
+static inline int devname_from_stat_rdev(const struct stat *st, char **ret) {
+ assert(st);
+ return devname_from_devnum(st->st_mode, st->st_rdev, ret);
+}
+int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret);
+
+char** device_make_log_fields(sd_device *device);
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c
index a36eba9029..9863b07653 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c
@@ -111,7 +111,7 @@ int event_reset_time_relative(
int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata) {
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
int r;
assert(e);
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
index 778070a5fb..cefe2a36b4 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
@@ -16,6 +16,7 @@
#include "glyph-util.h"
#include "hashmap.h"
#include "list.h"
+#include "logarithm.h"
#include "macro.h"
#include "memory-util.h"
#include "missing_syscall.h"
@@ -377,22 +378,22 @@ _public_ int sd_event_new(sd_event** ret) {
*e = (sd_event) {
.n_ref = 1,
- .epoll_fd = -1,
- .watchdog_fd = -1,
+ .epoll_fd = -EBADF,
+ .watchdog_fd = -EBADF,
.realtime.wakeup = WAKEUP_CLOCK_DATA,
- .realtime.fd = -1,
+ .realtime.fd = -EBADF,
.realtime.next = USEC_INFINITY,
.boottime.wakeup = WAKEUP_CLOCK_DATA,
- .boottime.fd = -1,
+ .boottime.fd = -EBADF,
.boottime.next = USEC_INFINITY,
.monotonic.wakeup = WAKEUP_CLOCK_DATA,
- .monotonic.fd = -1,
+ .monotonic.fd = -EBADF,
.monotonic.next = USEC_INFINITY,
.realtime_alarm.wakeup = WAKEUP_CLOCK_DATA,
- .realtime_alarm.fd = -1,
+ .realtime_alarm.fd = -EBADF,
.realtime_alarm.next = USEC_INFINITY,
.boottime_alarm.wakeup = WAKEUP_CLOCK_DATA,
- .boottime_alarm.fd = -1,
+ .boottime_alarm.fd = -EBADF,
.boottime_alarm.next = USEC_INFINITY,
.perturb = USEC_INFINITY,
.original_pid = getpid_cached(),
@@ -642,7 +643,7 @@ static int event_make_signal_data(
*d = (struct signal_data) {
.wakeup = WAKEUP_SIGNAL_DATA,
- .fd = -1,
+ .fd = -EBADF,
.priority = priority,
};
@@ -658,7 +659,9 @@ static int event_make_signal_data(
ss_copy = d->sigset;
assert_se(sigaddset(&ss_copy, sig) >= 0);
- r = signalfd(d->fd, &ss_copy, SFD_NONBLOCK|SFD_CLOEXEC);
+ r = signalfd(d->fd >= 0 ? d->fd : -1, /* the first arg must be -1 or a valid signalfd */
+ &ss_copy,
+ SFD_NONBLOCK|SFD_CLOEXEC);
if (r < 0) {
r = -errno;
goto fail;
@@ -1177,7 +1180,7 @@ static int event_setup_timer_fd(
if (_likely_(d->fd >= 0))
return 0;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC);
if (fd < 0)
@@ -1513,7 +1516,7 @@ _public_ int sd_event_add_child(
} else
s->child.pidfd_owned = true; /* If we allocate the pidfd we own it by default */
} else
- s->child.pidfd = -1;
+ s->child.pidfd = -EBADF;
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
/* We have a pidfd and we only want to watch for exit */
@@ -1776,7 +1779,7 @@ static int event_make_inotify_data(
int64_t priority,
struct inotify_data **ret) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
struct inotify_data *d;
int r;
@@ -1973,7 +1976,7 @@ static int event_make_inode_data(
.dev = dev,
.ino = ino,
.wd = -1,
- .fd = -1,
+ .fd = -EBADF,
.inotify_data = inotify_data,
};
@@ -2069,7 +2072,7 @@ static int event_add_inotify_fd_internal(
sd_event_inotify_handler_t callback,
void *userdata) {
- _cleanup_close_ int donated_fd = donate ? fd : -1;
+ _cleanup_close_ int donated_fd = donate ? fd : -EBADF;
_cleanup_(source_freep) sd_event_source *s = NULL;
struct inotify_data *inotify_data = NULL;
struct inode_data *inode_data = NULL;
@@ -2171,9 +2174,9 @@ _public_ int sd_event_add_inotify(
assert_return(path, -EINVAL);
- fd = open(path, O_PATH|O_CLOEXEC|
- (mask & IN_ONLYDIR ? O_DIRECTORY : 0)|
- (mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0));
+ fd = open(path, O_PATH | O_CLOEXEC |
+ (mask & IN_ONLYDIR ? O_DIRECTORY : 0) |
+ (mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0));
if (fd < 0)
return -errno;
@@ -2723,6 +2726,9 @@ _public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec
assert_return(s, -EINVAL);
assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM);
+ if (usec == USEC_INFINITY)
+ return sd_event_source_set_time(s, USEC_INFINITY);
+
r = sd_event_now(s->event, event_source_type_to_clock(s->type), &t);
if (r < 0)
return r;
@@ -3176,7 +3182,7 @@ static int event_arm_timer(
assert_se(d->fd >= 0);
if (t == 0) {
- /* We don' want to disarm here, just mean some time looooong ago. */
+ /* We don't want to disarm here, just mean some time looooong ago. */
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = 1;
} else
@@ -3773,12 +3779,9 @@ static int event_prepare(sd_event *e) {
break;
s->prepare_iteration = e->iteration;
- r = prioq_reshuffle(e->prepare, s, &s->prepare_index);
- if (r < 0)
- return r;
+ prioq_reshuffle(e->prepare, s, &s->prepare_index);
assert(s->prepare);
-
s->dispatching = true;
r = s->prepare(s, s->userdata);
s->dispatching = false;
@@ -3968,15 +3971,18 @@ static int epoll_wait_usec(
usec_t timeout) {
int msec;
-#if 0
+ /* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not. */
+
+#if HAVE_EPOLL_PWAIT2
static bool epoll_pwait2_absent = false;
int r;
- /* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not.
- *
- * FIXME: this is temporarily disabled until epoll_pwait2() becomes more widely available.
- * See https://github.com/systemd/systemd/pull/18973 and
- * https://github.com/systemd/systemd/issues/19052. */
+ /* epoll_pwait2() was added to Linux 5.11 (2021-02-14) and to glibc in 2.35 (2022-02-03). In contrast
+ * to other syscalls we don't bother with our own fallback syscall wrappers on old libcs, since this
+ * is not that obvious to implement given the libc and kernel definitions differ in the last
+ * argument. Moreover, the only reason to use it is the more accurate time-outs (which is not a
+ * biggie), let's hence rely on glibc's definitions, and fallback to epoll_pwait() when that's
+ * missing. */
if (!epoll_pwait2_absent && timeout != USEC_INFINITY) {
r = epoll_pwait2(fd,
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
index 4f52c14f64..a009a110a9 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
@@ -13,59 +13,49 @@
#include "sync-util.h"
bool id128_is_valid(const char *s) {
- size_t i, l;
+ size_t l;
assert(s);
l = strlen(s);
- if (l == 32) {
+ if (l == SD_ID128_STRING_MAX - 1)
/* Plain formatted 128bit hex string */
+ return in_charset(s, HEXDIGITS);
- for (i = 0; i < l; i++) {
- char c = s[i];
-
- if (!ascii_isdigit(c) &&
- !(c >= 'a' && c <= 'f') &&
- !(c >= 'A' && c <= 'F'))
- return false;
- }
-
- } else if (l == 36) {
-
+ if (l == SD_ID128_UUID_STRING_MAX - 1) {
/* Formatted UUID */
-
- for (i = 0; i < l; i++) {
+ for (size_t i = 0; i < l; i++) {
char c = s[i];
if (IN_SET(i, 8, 13, 18, 23)) {
if (c != '-')
return false;
- } else {
- if (!ascii_isdigit(c) &&
- !(c >= 'a' && c <= 'f') &&
- !(c >= 'A' && c <= 'F'))
- return false;
- }
+ } else if (!ascii_ishex(c))
+ return false;
}
+ return true;
+ }
- } else
- return false;
-
- return true;
+ return false;
}
-int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
- char buffer[36 + 2];
+int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret) {
+ char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
ssize_t l;
+ int r;
assert(fd >= 0);
- assert(f < _ID128_FORMAT_MAX);
/* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
* optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
* aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
- * accept". */
+ * accept".
+ *
+ * This returns the following:
+ * -ENOMEDIUM: an empty string,
+ * -ENOPKG: "uninitialized" or "uninitialized\n",
+ * -EUCLEAN: other invalid strings. */
l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
if (l < 0)
@@ -75,44 +65,44 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
switch (l) {
- case 13:
- case 14:
- /* Treat an "uninitialized" id file like an empty one */
- return f == ID128_PLAIN_OR_UNINIT && strneq(buffer, "uninitialized\n", l) ? -ENOMEDIUM : -EINVAL;
+ case STRLEN("uninitialized"):
+ case STRLEN("uninitialized\n"):
+ return strneq(buffer, "uninitialized\n", l) ? -ENOPKG : -EINVAL;
- case 33: /* plain UUID with trailing newline */
- if (buffer[32] != '\n')
- return -EINVAL;
+ case SD_ID128_STRING_MAX: /* plain UUID with trailing newline */
+ if (buffer[SD_ID128_STRING_MAX-1] != '\n')
+ return -EUCLEAN;
_fallthrough_;
- case 32: /* plain UUID without trailing newline */
- if (f == ID128_UUID)
- return -EINVAL;
+ case SD_ID128_STRING_MAX-1: /* plain UUID without trailing newline */
+ if (!FLAGS_SET(f, ID128_FORMAT_PLAIN))
+ return -EUCLEAN;
- buffer[32] = 0;
+ buffer[SD_ID128_STRING_MAX-1] = 0;
break;
- case 37: /* RFC UUID with trailing newline */
- if (buffer[36] != '\n')
- return -EINVAL;
+ case SD_ID128_UUID_STRING_MAX: /* RFC UUID with trailing newline */
+ if (buffer[SD_ID128_UUID_STRING_MAX-1] != '\n')
+ return -EUCLEAN;
_fallthrough_;
- case 36: /* RFC UUID without trailing newline */
- if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT))
- return -EINVAL;
+ case SD_ID128_UUID_STRING_MAX-1: /* RFC UUID without trailing newline */
+ if (!FLAGS_SET(f, ID128_FORMAT_UUID))
+ return -EUCLEAN;
- buffer[36] = 0;
+ buffer[SD_ID128_UUID_STRING_MAX-1] = 0;
break;
default:
- return -EINVAL;
+ return -EUCLEAN;
}
- return sd_id128_from_string(buffer, ret);
+ r = sd_id128_from_string(buffer, ret);
+ return r == -EINVAL ? -EUCLEAN : r;
}
-int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
- _cleanup_close_ int fd = -1;
+int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret) {
+ _cleanup_close_ int fd = -EBADF;
fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
@@ -121,29 +111,28 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
return id128_read_fd(fd, f, ret);
}
-int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
- char buffer[36 + 2];
+int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id) {
+ char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
size_t sz;
int r;
assert(fd >= 0);
- assert(f < _ID128_FORMAT_MAX);
+ assert(IN_SET((f & ID128_FORMAT_ANY), ID128_FORMAT_PLAIN, ID128_FORMAT_UUID));
- if (f != ID128_UUID) {
+ if (FLAGS_SET(f, ID128_FORMAT_PLAIN)) {
assert_se(sd_id128_to_string(id, buffer));
- buffer[SD_ID128_STRING_MAX - 1] = '\n';
sz = SD_ID128_STRING_MAX;
} else {
assert_se(sd_id128_to_uuid_string(id, buffer));
- buffer[SD_ID128_UUID_STRING_MAX - 1] = '\n';
sz = SD_ID128_UUID_STRING_MAX;
}
+ buffer[sz - 1] = '\n';
r = loop_write(fd, buffer, sz, false);
if (r < 0)
return r;
- if (do_sync) {
+ if (FLAGS_SET(f, ID128_SYNC_ON_WRITE)) {
r = fsync_full(fd);
if (r < 0)
return r;
@@ -152,14 +141,14 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
return 0;
}
-int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
- _cleanup_close_ int fd = -1;
+int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id) {
+ _cleanup_close_ int fd = -EBADF;
fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444);
if (fd < 0)
return -errno;
- return id128_write_fd(fd, f, id, do_sync);
+ return id128_write_fd(fd, f, id);
}
void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
@@ -184,6 +173,7 @@ sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
}
DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(id128_hash_ops_free, sd_id128_t, id128_hash_func, id128_compare_func, free);
int id128_get_product(sd_id128_t *ret) {
sd_id128_t uuid;
@@ -194,9 +184,9 @@ int id128_get_product(sd_id128_t *ret) {
/* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
* particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
- r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
+ r = id128_read("/sys/class/dmi/id/product_uuid", ID128_FORMAT_UUID, &uuid);
if (r == -ENOENT)
- r = id128_read("/proc/device-tree/vm,uuid", ID128_UUID, &uuid);
+ r = id128_read("/proc/device-tree/vm,uuid", ID128_FORMAT_UUID, &uuid);
if (r < 0)
return r;
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h
index 17b180c10c..e094de6441 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h
+++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h
@@ -10,27 +10,32 @@
bool id128_is_valid(const char *s) _pure_;
-typedef enum Id128Format {
- ID128_ANY,
- ID128_PLAIN, /* formatted as 32 hex chars as-is */
- ID128_PLAIN_OR_UNINIT, /* formatted as 32 hex chars as-is; allow special "uninitialized"
- * value when reading from file (id128_read() and id128_read_fd()).
- *
- * This format should be used when reading a machine-id file. */
- ID128_UUID, /* formatted as 36 character uuid string */
- _ID128_FORMAT_MAX,
-} Id128Format;
-
-int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret);
-int id128_read(const char *p, Id128Format f, sd_id128_t *ret);
-
-int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync);
-int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
+typedef enum Id128FormatFlag {
+ ID128_FORMAT_PLAIN = 1 << 0, /* formatted as 32 hex chars as-is */
+ ID128_FORMAT_UUID = 1 << 1, /* formatted as 36 character uuid string */
+ ID128_FORMAT_ANY = ID128_FORMAT_PLAIN | ID128_FORMAT_UUID,
+
+ ID128_SYNC_ON_WRITE = 1 << 2, /* Sync the file after write. Used only when writing an ID. */
+} Id128FormatFlag;
+
+int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret);
+int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret);
+
+int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id);
+int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id);
void id128_hash_func(const sd_id128_t *p, struct siphash *state);
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
extern const struct hash_ops id128_hash_ops;
+extern const struct hash_ops id128_hash_ops_free;
sd_id128_t id128_make_v4_uuid(sd_id128_t id);
int id128_get_product(sd_id128_t *ret);
+
+/* A helper to check for the three relevant cases of "machine ID not initialized" */
+#define ERRNO_IS_MACHINE_ID_UNSET(r) \
+ IN_SET(abs(r), \
+ ENOENT, \
+ ENOMEDIUM, \
+ ENOPKG)
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c
index 709c8ffb57..ec3a496dba 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c
@@ -15,18 +15,21 @@
#include "macro.h"
#include "missing_syscall.h"
#include "random-util.h"
+#include "stat-util.h"
#include "user-util.h"
-#include "util.h"
_public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]) {
+ size_t k = 0;
+
assert_return(s, NULL);
- for (size_t n = 0; n < 16; n++) {
- s[n*2] = hexchar(id.bytes[n] >> 4);
- s[n*2+1] = hexchar(id.bytes[n] & 0xF);
+ for (size_t n = 0; n < sizeof(sd_id128_t); n++) {
+ s[k++] = hexchar(id.bytes[n] >> 4);
+ s[k++] = hexchar(id.bytes[n] & 0xF);
}
- s[SD_ID128_STRING_MAX-1] = 0;
+ assert(k == SD_ID128_STRING_MAX - 1);
+ s[k] = 0;
return s;
}
@@ -38,7 +41,7 @@ _public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD
/* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
- for (size_t n = 0; n < 16; n++) {
+ for (size_t n = 0; n < sizeof(sd_id128_t); n++) {
if (IN_SET(n, 4, 6, 8, 10))
s[k++] = '-';
@@ -53,14 +56,14 @@ _public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD
return s;
}
-_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
- unsigned n, i;
+_public_ int sd_id128_from_string(const char *s, sd_id128_t *ret) {
+ size_t n, i;
sd_id128_t t;
bool is_guid = false;
assert_return(s, -EINVAL);
- for (n = 0, i = 0; n < 16;) {
+ for (n = 0, i = 0; n < sizeof(sd_id128_t);) {
int a, b;
if (s[i] == '-') {
@@ -90,7 +93,7 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
t.bytes[n++] = (a << 4) | b;
}
- if (i != (is_guid ? 36 : 32))
+ if (i != (is_guid ? SD_ID128_UUID_STRING_MAX : SD_ID128_STRING_MAX) - 1)
return -EINVAL;
if (s[i] != 0)
@@ -121,10 +124,8 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
static thread_local sd_id128_t saved_machine_id = {};
int r;
- assert_return(ret, -EINVAL);
-
if (sd_id128_is_null(saved_machine_id)) {
- r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id);
+ r = id128_read("/etc/machine-id", ID128_FORMAT_PLAIN, &saved_machine_id);
if (r < 0)
return r;
@@ -132,7 +133,8 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
return -ENOMEDIUM;
}
- *ret = saved_machine_id;
+ if (ret)
+ *ret = saved_machine_id;
return 0;
}
@@ -140,15 +142,19 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
static thread_local sd_id128_t saved_boot_id = {};
int r;
- assert_return(ret, -EINVAL);
-
if (sd_id128_is_null(saved_boot_id)) {
- r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id);
+ r = id128_read("/proc/sys/kernel/random/boot_id", ID128_FORMAT_UUID, &saved_boot_id);
+ if (r == -ENOENT && proc_mounted() == 0)
+ return -ENOSYS;
if (r < 0)
return r;
+
+ if (sd_id128_is_null(saved_boot_id))
+ return -ENOMEDIUM;
}
- *ret = saved_boot_id;
+ if (ret)
+ *ret = saved_boot_id;
return 0;
}
@@ -198,22 +204,22 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
/* Chop off the final description string */
d = strrchr(description, ';');
if (!d)
- return -EIO;
+ return -EUCLEAN;
*d = 0;
/* Look for the permissions */
p = strrchr(description, ';');
if (!p)
- return -EIO;
+ return -EUCLEAN;
errno = 0;
perms = strtoul(p + 1, &e, 16);
if (errno > 0)
return -errno;
if (e == p + 1) /* Read at least one character */
- return -EIO;
+ return -EUCLEAN;
if (e != d) /* Must reached the end */
- return -EIO;
+ return -EUCLEAN;
if ((perms & ~MAX_PERMS) != 0)
return -EPERM;
@@ -223,7 +229,7 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
/* Look for the group ID */
g = strrchr(description, ';');
if (!g)
- return -EIO;
+ return -EUCLEAN;
r = parse_gid(g + 1, &gid);
if (r < 0)
return r;
@@ -234,7 +240,7 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
/* Look for the user ID */
u = strrchr(description, ';');
if (!u)
- return -EIO;
+ return -EUCLEAN;
r = parse_uid(u + 1, &uid);
if (r < 0)
return r;
@@ -245,13 +251,14 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
if (c < 0)
return -errno;
if (c != sizeof(sd_id128_t))
- return -EIO;
+ return -EUCLEAN;
return 0;
}
static int get_invocation_from_environment(sd_id128_t *ret) {
const char *e;
+ int r;
assert(ret);
@@ -259,33 +266,31 @@ static int get_invocation_from_environment(sd_id128_t *ret) {
if (!e)
return -ENXIO;
- return sd_id128_from_string(e, ret);
+ r = sd_id128_from_string(e, ret);
+ return r == -EINVAL ? -EUCLEAN : r;
}
_public_ int sd_id128_get_invocation(sd_id128_t *ret) {
static thread_local sd_id128_t saved_invocation_id = {};
int r;
- assert_return(ret, -EINVAL);
-
if (sd_id128_is_null(saved_invocation_id)) {
/* We first check the environment. The environment variable is primarily relevant for user
* services, and sufficiently safe as long as no privilege boundary is involved. */
r = get_invocation_from_environment(&saved_invocation_id);
- if (r >= 0) {
- *ret = saved_invocation_id;
- return 0;
- } else if (r != -ENXIO)
- return r;
-
- /* The kernel keyring is relevant for system services (as for user services we don't store
- * the invocation ID in the keyring, as there'd be no trust benefit in that). */
- r = get_invocation_from_keyring(&saved_invocation_id);
+ if (r == -ENXIO)
+ /* The kernel keyring is relevant for system services (as for user services we don't
+ * store the invocation ID in the keyring, as there'd be no trust benefit in that). */
+ r = get_invocation_from_keyring(&saved_invocation_id);
if (r < 0)
return r;
+
+ if (sd_id128_is_null(saved_invocation_id))
+ return -ENOMEDIUM;
}
- *ret = saved_invocation_id;
+ if (ret)
+ *ret = saved_invocation_id;
return 0;
}
diff --git a/src/libnm-systemd-core/src/systemd/sd-device.h b/src/libnm-systemd-core/src/systemd/sd-device.h
new file mode 100644
index 0000000000..e3d647f75d
--- /dev/null
+++ b/src/libnm-systemd-core/src/systemd/sd-device.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#ifndef foosddevicehfoo
+#define foosddevicehfoo
+
+/***
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <https://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+
+#include "sd-event.h"
+#include "sd-id128.h"
+
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+typedef struct sd_device sd_device;
+typedef struct sd_device_enumerator sd_device_enumerator;
+typedef struct sd_device_monitor sd_device_monitor;
+
+__extension__ typedef enum sd_device_action_t {
+ SD_DEVICE_ADD,
+ SD_DEVICE_REMOVE,
+ SD_DEVICE_CHANGE,
+ SD_DEVICE_MOVE,
+ SD_DEVICE_ONLINE,
+ SD_DEVICE_OFFLINE,
+ SD_DEVICE_BIND,
+ SD_DEVICE_UNBIND,
+ _SD_DEVICE_ACTION_MAX,
+ _SD_DEVICE_ACTION_INVALID = -EINVAL,
+ _SD_ENUM_FORCE_S64(DEVICE_ACTION)
+} sd_device_action_t;
+
+/* callback */
+
+typedef int (*sd_device_monitor_handler_t)(sd_device_monitor *m, sd_device *device, void *userdata);
+
+/* device */
+
+sd_device *sd_device_ref(sd_device *device);
+sd_device *sd_device_unref(sd_device *device);
+
+int sd_device_new_from_syspath(sd_device **ret, const char *syspath);
+int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum);
+int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname);
+int sd_device_new_from_device_id(sd_device **ret, const char *id);
+int sd_device_new_from_stat_rdev(sd_device **ret, const struct stat *st);
+int sd_device_new_from_devname(sd_device **ret, const char *devname);
+int sd_device_new_from_path(sd_device **ret, const char *path);
+int sd_device_new_from_ifname(sd_device **ret, const char *ifname);
+int sd_device_new_from_ifindex(sd_device **ret, int ifindex);
+
+int sd_device_new_child(sd_device **ret, sd_device *device, const char *suffix);
+
+int sd_device_get_parent(sd_device *child, sd_device **ret);
+int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret);
+
+int sd_device_get_syspath(sd_device *device, const char **ret);
+int sd_device_get_subsystem(sd_device *device, const char **ret);
+int sd_device_get_devtype(sd_device *device, const char **ret);
+int sd_device_get_devnum(sd_device *device, dev_t *devnum);
+int sd_device_get_ifindex(sd_device *device, int *ifindex);
+int sd_device_get_driver(sd_device *device, const char **ret);
+int sd_device_get_devpath(sd_device *device, const char **ret);
+int sd_device_get_devname(sd_device *device, const char **ret);
+int sd_device_get_sysname(sd_device *device, const char **ret);
+int sd_device_get_sysnum(sd_device *device, const char **ret);
+int sd_device_get_action(sd_device *device, sd_device_action_t *ret);
+int sd_device_get_seqnum(sd_device *device, uint64_t *ret);
+int sd_device_get_diskseq(sd_device *device, uint64_t *ret);
+
+int sd_device_get_is_initialized(sd_device *device);
+int sd_device_get_usec_initialized(sd_device *device, uint64_t *ret);
+int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *ret);
+
+const char *sd_device_get_tag_first(sd_device *device);
+const char *sd_device_get_tag_next(sd_device *device);
+const char *sd_device_get_current_tag_first(sd_device *device);
+const char *sd_device_get_current_tag_next(sd_device *device);
+const char *sd_device_get_devlink_first(sd_device *device);
+const char *sd_device_get_devlink_next(sd_device *device);
+const char *sd_device_get_property_first(sd_device *device, const char **value);
+const char *sd_device_get_property_next(sd_device *device, const char **value);
+const char *sd_device_get_sysattr_first(sd_device *device);
+const char *sd_device_get_sysattr_next(sd_device *device);
+sd_device *sd_device_get_child_first(sd_device *device, const char **ret_suffix);
+sd_device *sd_device_get_child_next(sd_device *device, const char **ret_suffix);
+
+int sd_device_has_tag(sd_device *device, const char *tag);
+int sd_device_has_current_tag(sd_device *device, const char *tag);
+int sd_device_get_property_value(sd_device *device, const char *key, const char **value);
+int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret);
+int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value);
+
+int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *value);
+int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr, const char *format, ...) _sd_printf_(3, 4);
+int sd_device_trigger(sd_device *device, sd_device_action_t action);
+int sd_device_trigger_with_uuid(sd_device *device, sd_device_action_t action, sd_id128_t *ret_uuid);
+int sd_device_open(sd_device *device, int flags);
+
+/* device enumerator */
+
+int sd_device_enumerator_new(sd_device_enumerator **ret);
+sd_device_enumerator *sd_device_enumerator_ref(sd_device_enumerator *enumerator);
+sd_device_enumerator *sd_device_enumerator_unref(sd_device_enumerator *enumerator);
+
+sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator);
+sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *enumerator);
+sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator);
+sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumerator);
+
+int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match);
+int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *sysattr, const char *value, int match);
+int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *property, const char *value);
+int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname);
+int sd_device_enumerator_add_nomatch_sysname(sd_device_enumerator *enumerator, const char *sysname);
+int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag);
+int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent);
+int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator);
+
+/* device monitor */
+
+int sd_device_monitor_new(sd_device_monitor **ret);
+sd_device_monitor *sd_device_monitor_ref(sd_device_monitor *m);
+sd_device_monitor *sd_device_monitor_unref(sd_device_monitor *m);
+
+int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, size_t size);
+int sd_device_monitor_attach_event(sd_device_monitor *m, sd_event *event);
+int sd_device_monitor_detach_event(sd_device_monitor *m);
+sd_event *sd_device_monitor_get_event(sd_device_monitor *m);
+sd_event_source *sd_device_monitor_get_event_source(sd_device_monitor *m);
+int sd_device_monitor_set_description(sd_device_monitor *m, const char *description);
+int sd_device_monitor_get_description(sd_device_monitor *m, const char **ret);
+int sd_device_monitor_start(sd_device_monitor *m, sd_device_monitor_handler_t callback, void *userdata);
+int sd_device_monitor_stop(sd_device_monitor *m);
+
+int sd_device_monitor_filter_add_match_subsystem_devtype(sd_device_monitor *m, const char *subsystem, const char *devtype);
+int sd_device_monitor_filter_add_match_tag(sd_device_monitor *m, const char *tag);
+int sd_device_monitor_filter_add_match_sysattr(sd_device_monitor *m, const char *sysattr, const char *value, int match);
+int sd_device_monitor_filter_add_match_parent(sd_device_monitor *m, sd_device *device, int match);
+int sd_device_monitor_filter_update(sd_device_monitor *m);
+int sd_device_monitor_filter_remove(sd_device_monitor *m);
+
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device, sd_device_unref);
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device_enumerator, sd_device_enumerator_unref);
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device_monitor, sd_device_monitor_unref);
+
+_SD_END_DECLARATIONS;
+
+#endif
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h
index 2c66c51b78..a9fa78569d 100644
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h
+++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h
@@ -23,6 +23,7 @@
#include <net/ethernet.h>
#include <sys/types.h>
+#include "sd-device.h"
#include "sd-dhcp6-lease.h"
#include "sd-dhcp6-option.h"
#include "sd-event.h"
@@ -263,6 +264,7 @@ int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client,
int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client,
sd_dhcp6_option *v);
int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable);
+int sd_dhcp6_client_set_send_release(sd_dhcp6_client *client, int enable);
int sd_dhcp6_client_get_lease(
sd_dhcp6_client *client,
@@ -279,6 +281,7 @@ int sd_dhcp6_client_attach_event(
int64_t priority);
int sd_dhcp6_client_detach_event(sd_dhcp6_client *client);
sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client);
+int sd_dhcp6_client_attach_device(sd_dhcp6_client *client, sd_device *dev);
sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client);
int sd_dhcp6_client_new(sd_dhcp6_client **ret);
diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.c b/src/libnm-systemd-shared/src/basic/alloc-util.c
index b030f454b2..6063943c88 100644
--- a/src/libnm-systemd-shared/src/basic/alloc-util.c
+++ b/src/libnm-systemd-shared/src/basic/alloc-util.c
@@ -102,3 +102,7 @@ void* greedy_realloc0(
return q;
}
+
+void *expand_to_usable(void *ptr, size_t newsize _unused_) {
+ return ptr;
+}
diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.h b/src/libnm-systemd-shared/src/basic/alloc-util.h
index b38db7d473..bf783b15a2 100644
--- a/src/libnm-systemd-shared/src/basic/alloc-util.h
+++ b/src/libnm-systemd-shared/src/basic/alloc-util.h
@@ -2,6 +2,7 @@
#pragma once
#include <alloca.h>
+#include <malloc.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@@ -184,17 +185,35 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
# define msan_unpoison(r, s)
#endif
-/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), in a way that
- * is compatible with _FORTIFY_SOURCES. If _FORTIFY_SOURCES is used many memory operations will take the
- * object size as returned by __builtin_object_size() into account. Hence, let's return the smaller size of
- * malloc_usable_size() and __builtin_object_size() here, so that we definitely operate in safe territory by
- * both the compiler's and libc's standards. Note that __builtin_object_size() evaluates to SIZE_MAX if the
- * size cannot be determined, hence the MIN() expression should be safe with dynamically sized memory,
- * too. Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and
- * __builtin_object_size() returns SIZE_MAX too, hence we also return a sensible value of 0 in this corner
- * case. */
+/* Dummy allocator to tell the compiler that the new size of p is newsize. The implementation returns the
+ * pointer as is; the only reason for its existence is as a conduit for the _alloc_ attribute. This must not
+ * be inlined (hence a non-static function with _noinline_ because LTO otherwise tries to inline it) because
+ * gcc then loses the attributes on the function.
+ * See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 */
+void *expand_to_usable(void *p, size_t newsize) _alloc_(2) _returns_nonnull_ _noinline_;
+
+static inline size_t malloc_sizeof_safe(void **xp) {
+ if (_unlikely_(!xp || !*xp))
+ return 0;
+
+ size_t sz = malloc_usable_size(*xp);
+ *xp = expand_to_usable(*xp, sz);
+ /* GCC doesn't see the _returns_nonnull_ when built with ubsan, so yet another hint to make it doubly
+ * clear that expand_to_usable won't return NULL.
+ * See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79265 */
+ if (!*xp)
+ assert_not_reached();
+ return sz;
+}
+
+/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), which may
+ * return a value larger than the size that was actually allocated. Access to that additional memory is
+ * discouraged because it violates the C standard; a compiler cannot see that this as valid. To help the
+ * compiler out, the MALLOC_SIZEOF_SAFE macro 'allocates' the usable size using a dummy allocator function
+ * expand_to_usable. There is a possibility of malloc_usable_size() returning different values during the
+ * lifetime of an object, which may cause problems, but the glibc allocator does not do that at the moment. */
#define MALLOC_SIZEOF_SAFE(x) \
- MIN(malloc_usable_size(x), __builtin_object_size(x, 0))
+ malloc_sizeof_safe((void**) &__builtin_choose_expr(__builtin_constant_p(x), (void*) { NULL }, (x)))
/* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items
* that fit into the specified memory block */
diff --git a/src/libnm-systemd-shared/src/basic/cgroup-util.h b/src/libnm-systemd-shared/src/basic/cgroup-util.h
index df6d5b7bbb..c9aae5abf6 100644
--- a/src/libnm-systemd-shared/src/basic/cgroup-util.h
+++ b/src/libnm-systemd-shared/src/basic/cgroup-util.h
@@ -9,7 +9,7 @@
#include <sys/statfs.h>
#include <sys/types.h>
-#include "def.h"
+#include "constants.h"
#include "set.h"
#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=systemd"
diff --git a/src/libnm-systemd-shared/src/basic/constants.h b/src/libnm-systemd-shared/src/basic/constants.h
new file mode 100644
index 0000000000..5d68cc6332
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/constants.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#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
+
+#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
+
+/* Many different things, but also system unit start/stop */
+#define DEFAULT_TIMEOUT_USEC (DEFAULT_TIMEOUT_SEC*USEC_PER_SEC)
+/* User unit start/stop */
+#define DEFAULT_USER_TIMEOUT_USEC (DEFAULT_USER_TIMEOUT_SEC*USEC_PER_SEC)
+/* Timeout for user confirmation on the console */
+#define DEFAULT_CONFIRM_USEC (30*USEC_PER_SEC)
+
+/* We use an extra-long timeout for the reload. This is because a reload or reexec means generators are rerun
+ * which are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can
+ * have their timeout, and for everything else there's the same time budget in place. */
+#define DAEMON_RELOAD_TIMEOUT_SEC (DEFAULT_TIMEOUT_USEC * 2)
+
+#define DEFAULT_START_LIMIT_INTERVAL (10*USEC_PER_SEC)
+#define DEFAULT_START_LIMIT_BURST 5
+
+/* The default time after which exit-on-idle services exit. This
+ * should be kept lower than the watchdog timeout, because otherwise
+ * the watchdog pings will keep the loop busy. */
+#define DEFAULT_EXIT_USEC (30*USEC_PER_SEC)
+
+/* The default value for the net.unix.max_dgram_qlen sysctl */
+#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512
+
+#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
+#define SIGNALS_IGNORE SIGPIPE
+
+#define NOTIFY_FD_MAX 768
+#define NOTIFY_BUFFER_MAX PIPE_BUF
+
+#if HAVE_SPLIT_USR
+# define _CONF_PATHS_SPLIT_USR_NULSTR(n) "/lib/" n "\0"
+# define _CONF_PATHS_SPLIT_USR(n) , "/lib/" n
+#else
+# define _CONF_PATHS_SPLIT_USR_NULSTR(n)
+# define _CONF_PATHS_SPLIT_USR(n)
+#endif
+
+/* Return a nulstr for a standard cascade of configuration paths,
+ * suitable to pass to conf_files_list_nulstr() or config_parse_many_nulstr()
+ * to implement drop-in directories for extending configuration
+ * files. */
+#define CONF_PATHS_NULSTR(n) \
+ "/etc/" n "\0" \
+ "/run/" n "\0" \
+ "/usr/local/lib/" n "\0" \
+ "/usr/lib/" n "\0" \
+ _CONF_PATHS_SPLIT_USR_NULSTR(n)
+
+#define CONF_PATHS_USR(n) \
+ "/etc/" n, \
+ "/run/" n, \
+ "/usr/local/lib/" n, \
+ "/usr/lib/" n
+
+#define CONF_PATHS(n) \
+ CONF_PATHS_USR(n) \
+ _CONF_PATHS_SPLIT_USR(n)
+
+#define CONF_PATHS_USR_STRV(n) \
+ STRV_MAKE(CONF_PATHS_USR(n))
+
+#define CONF_PATHS_STRV(n) \
+ STRV_MAKE(CONF_PATHS(n))
+
+/* The limit for PID 1 itself (which is not inherited to children) */
+#define HIGH_RLIMIT_MEMLOCK (1024ULL*1024ULL*64ULL)
+
+/* Since kernel 5.16 the kernel default limit was raised to 8M. Let's adjust things on old kernels too, and
+ * in containers so that our children inherit that. */
+#define DEFAULT_RLIMIT_MEMLOCK (1024ULL*1024ULL*8ULL)
+
+#define PLYMOUTH_SOCKET { \
+ .un.sun_family = AF_UNIX, \
+ .un.sun_path = "\0/org/freedesktop/plymouthd", \
+ }
+
+/* Path where PID1 listens for varlink subscriptions from systemd-oomd to notify of changes in ManagedOOM settings. */
+#define VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM "/run/systemd/io.system.ManagedOOM"
+/* Path where systemd-oomd listens for varlink connections from user managers to report changes in ManagedOOM settings. */
+#define VARLINK_ADDR_PATH_MANAGED_OOM_USER "/run/systemd/oom/io.system.ManagedOOM"
+
+#define KERNEL_BASELINE_VERSION "4.15"
diff --git a/src/libnm-systemd-shared/src/basic/env-file.c b/src/libnm-systemd-shared/src/basic/env-file.c
index e363bc80bf..45b0d901c5 100644
--- a/src/libnm-systemd-shared/src/basic/env-file.c
+++ b/src/libnm-systemd-shared/src/basic/env-file.c
@@ -12,11 +12,17 @@
#include "tmpfile-util.h"
#include "utf8.h"
+typedef int (*push_env_func_t)(
+ const char *filename,
+ unsigned line,
+ const char *key,
+ char *value,
+ void *userdata);
+
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),
+ push_env_func_t push,
void *userdata) {
size_t n_key = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX;
@@ -37,6 +43,9 @@ static int parse_env_file_internal(
COMMENT_ESCAPE
} state = PRE_KEY;
+ assert(f || fname);
+ assert(push);
+
if (f)
r = read_full_stream(f, &contents, NULL);
else
@@ -274,6 +283,8 @@ static int check_utf8ness_and_warn(
const char *filename, unsigned line,
const char *key, char *value) {
+ assert(key);
+
if (!utf8_is_valid(key)) {
_cleanup_free_ char *p = NULL;
@@ -304,6 +315,8 @@ static int parse_env_file_push(
va_list aq, *ap = userdata;
int r;
+ assert(key);
+
r = check_utf8ness_and_warn(filename, line, key, value);
if (r < 0)
return r;
@@ -338,6 +351,8 @@ int parse_env_filev(
int r;
va_list aq;
+ assert(f || fname);
+
va_copy(aq, ap);
r = parse_env_file_internal(f, fname, parse_env_file_push, &aq);
va_end(aq);
@@ -352,6 +367,37 @@ int parse_env_file_sentinel(
va_list ap;
int r;
+ assert(f || fname);
+
+ va_start(ap, fname);
+ r = parse_env_filev(f, fname, ap);
+ va_end(ap);
+
+ return r;
+}
+
+int parse_env_file_fd_sentinel(
+ int fd,
+ const char *fname, /* only used for logging */
+ ...) {
+
+ _cleanup_close_ int fd_ro = -EBADF;
+ _cleanup_fclose_ FILE *f = NULL;
+ va_list ap;
+ int r;
+
+ assert(fd >= 0);
+
+ fd_ro = fd_reopen(fd, O_CLOEXEC | O_RDONLY);
+ if (fd_ro < 0)
+ return fd_ro;
+
+ f = fdopen(fd_ro, "re");
+ if (!f)
+ return -errno;
+
+ TAKE_FD(fd_ro);
+
va_start(ap, fname);
r = parse_env_filev(f, fname, ap);
va_end(ap);
@@ -363,10 +409,13 @@ static int load_env_file_push(
const char *filename, unsigned line,
const char *key, char *value,
void *userdata) {
+
char ***m = userdata;
char *p;
int r;
+ assert(key);
+
r = check_utf8ness_and_warn(filename, line, key, value);
if (r < 0)
return r;
@@ -383,15 +432,18 @@ static int load_env_file_push(
return 0;
}
-int load_env_file(FILE *f, const char *fname, char ***rl) {
+int load_env_file(FILE *f, const char *fname, char ***ret) {
_cleanup_strv_free_ char **m = NULL;
int r;
+ assert(f || fname);
+ assert(ret);
+
r = parse_env_file_internal(f, fname, load_env_file_push, &m);
if (r < 0)
return r;
- *rl = TAKE_PTR(m);
+ *ret = TAKE_PTR(m);
return 0;
}
@@ -403,6 +455,8 @@ static int load_env_file_push_pairs(
char ***m = ASSERT_PTR(userdata);
int r;
+ assert(key);
+
r = check_utf8ness_and_warn(filename, line, key, value);
if (r < 0)
return r;
@@ -426,15 +480,17 @@ static int load_env_file_push_pairs(
return strv_extend(m, "");
}
-int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
+int load_env_file_pairs(FILE *f, const char *fname, char ***ret) {
_cleanup_strv_free_ char **m = NULL;
int r;
+ assert(f || fname);
+
r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m);
if (r < 0)
return r;
- *rl = TAKE_PTR(m);
+ *ret = TAKE_PTR(m);
return 0;
}
@@ -446,6 +502,8 @@ static int merge_env_file_push(
char ***env = ASSERT_PTR(userdata);
char *expanded_value;
+ assert(key);
+
if (!value) {
log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key);
return 0;
@@ -476,6 +534,9 @@ int merge_env_file(
FILE *f,
const char *fname) {
+ assert(env);
+ assert(f || fname);
+
/* NOTE: this function supports braceful and braceless variable expansions,
* plus "extended" substitutions, unlike other exported parsing functions.
*/
@@ -486,6 +547,9 @@ int merge_env_file(
static void write_env_var(FILE *f, const char *v) {
const char *p;
+ assert(f);
+ assert(v);
+
p = strchr(v, '=');
if (!p) {
/* Fallback */
diff --git a/src/libnm-systemd-shared/src/basic/env-file.h b/src/libnm-systemd-shared/src/basic/env-file.h
index de475885ac..2448d943cd 100644
--- a/src/libnm-systemd-shared/src/basic/env-file.h
+++ b/src/libnm-systemd-shared/src/basic/env-file.h
@@ -9,8 +9,10 @@
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 parse_env_file_fd_sentinel(int fd, const char *fname, ...) _sentinel_;
+#define parse_env_file_fd(fd, fname, ...) parse_env_file_fd_sentinel(fd, fname, __VA_ARGS__, NULL)
+int load_env_file(FILE *f, const char *fname, char ***ret);
+int load_env_file_pairs(FILE *f, const char *fname, char ***ret);
int merge_env_file(char ***env, FILE *f, const char *fname);
diff --git a/src/libnm-systemd-shared/src/basic/escape.c b/src/libnm-systemd-shared/src/basic/escape.c
index 1cb7ced545..e04b435d5b 100644
--- a/src/libnm-systemd-shared/src/basic/escape.c
+++ b/src/libnm-systemd-shared/src/basic/escape.c
@@ -445,31 +445,30 @@ char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFl
}
char* octescape(const char *s, size_t len) {
- char *r, *t;
- const char *f;
+ char *buf, *t;
- /* Escapes all chars in bad, in addition to \ and " chars,
- * in \nnn style escaping. */
+ /* Escapes all chars in bad, in addition to \ and " chars, in \nnn style escaping. */
- r = new(char, len * 4 + 1);
- if (!r)
+ assert(s || len == 0);
+
+ t = buf = new(char, len * 4 + 1);
+ if (!buf)
return NULL;
- for (f = s, t = r; f < s + len; f++) {
+ for (size_t i = 0; i < len; i++) {
+ uint8_t u = (uint8_t) s[i];
- if (*f < ' ' || *f >= 127 || IN_SET(*f, '\\', '"')) {
+ if (u < ' ' || u >= 127 || IN_SET(u, '\\', '"')) {
*(t++) = '\\';
- *(t++) = '0' + (*f >> 6);
- *(t++) = '0' + ((*f >> 3) & 8);
- *(t++) = '0' + (*f & 8);
+ *(t++) = '0' + (u >> 6);
+ *(t++) = '0' + ((u >> 3) & 7);
+ *(t++) = '0' + (u & 7);
} else
- *(t++) = *f;
+ *(t++) = u;
}
*t = 0;
-
- return r;
-
+ return buf;
}
static char* strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.c b/src/libnm-systemd-shared/src/basic/fd-util.c
index cee20a9a81..4d6d01cd99 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.c
+++ b/src/libnm-systemd-shared/src/basic/fd-util.c
@@ -29,7 +29,6 @@
#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. */
@@ -57,11 +56,9 @@ int close_nointr(int fd) {
}
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:
+ * Like close_nointr() but cannot fail. Guarantees errno is unchanged. Is a noop for negative fds,
+ * and returns -EBADF, so that it can be used in this syntax:
*
* fd = safe_close(fd);
*/
@@ -77,7 +74,7 @@ int safe_close(int fd) {
assert_se(close_nointr(fd) != -EBADF);
}
- return -1;
+ return -EBADF;
}
void safe_close_pair(int p[static 2]) {
@@ -174,12 +171,35 @@ int fd_cloexec(int fd, bool cloexec) {
return RET_NERRNO(fcntl(fd, F_SETFD, nflags));
}
+int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec) {
+ int ret = 0, r;
+
+ assert(n_fds == 0 || fds);
+
+ for (size_t i = 0; i < n_fds; i++) {
+ if (fds[i] < 0) /* Skip gracefully over already invalidated fds */
+ continue;
+
+ r = fd_cloexec(fds[i], cloexec);
+ if (r < 0 && ret >= 0) /* Continue going, but return first error */
+ ret = r;
+ else
+ ret = 1; /* report if we did anything */
+ }
+
+ return ret;
+}
+
_pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {
assert(n_fdset == 0 || fdset);
- for (size_t i = 0; i < n_fdset; i++)
+ for (size_t i = 0; i < n_fdset; i++) {
+ if (fdset[i] < 0)
+ continue;
+
if (fdset[i] == fd)
return true;
+ }
return false;
}
@@ -226,7 +246,7 @@ static int close_all_fds_frugal(const int except[], size_t n_except) {
"Refusing to loop over %d potential fds.",
max_fd);
- for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
+ for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -EBADF) {
int q;
if (fd_in_set(fd, except, n_except))
@@ -252,6 +272,10 @@ static int close_all_fds_special_case(const int except[], size_t n_except) {
if (!have_close_range)
return 0;
+ if (n_except == 1 && except[0] < 0) /* Minor optimization: if we only got one fd, and it's invalid,
+ * we got none */
+ n_except = 0;
+
switch (n_except) {
case 0:
@@ -386,7 +410,7 @@ int close_all_fds(const int except[], size_t n_except) {
return close_all_fds_frugal(except, n_except); /* ultimate fallback if /proc/ is not available */
FOREACH_DIRENT(de, d, return -errno) {
- int fd = -1, q;
+ int fd = -EBADF, q;
if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
continue;
@@ -475,7 +499,8 @@ void cmsg_close_all(struct msghdr *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));
+ close_many(CMSG_TYPED_DATA(cmsg, int),
+ (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
}
bool fdname_is_valid(const char *s) {
@@ -604,25 +629,23 @@ int fd_move_above_stdio(int fd) {
}
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 */
+ int fd[3] = { original_input_fd, /* Put together an array of fds we work on */
+ original_output_fd,
+ original_error_fd },
+ null_fd = -EBADF, /* If we open /dev/null, we store the fd to it here */
+ copy_fd[3] = { -EBADF, -EBADF, -EBADF }, /* This contains all fds we duplicate here
+ * temporarily, and hence need to close at the end. */
+ r;
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.
+ /* Sets up stdin, stdout, stderr with the three file descriptors passed in. If any of the descriptors
+ * is specified as -EBADF 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 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!
*
@@ -658,7 +681,7 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_
}
/* Let's assemble fd[] with the fds to install in place of stdin/stdout/stderr */
- for (i = 0; i < 3; i++) {
+ for (int i = 0; i < 3; i++) {
if (fd[i] < 0)
fd[i] = null_fd; /* A negative parameter means: connect this one to /dev/null */
@@ -674,10 +697,10 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_
}
}
- /* 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++) {
+ /* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that
+ * we have freedom to move them around. If the fds already were at the right places then the specific
+ * fds are -EBADF. Let's now move them to the right places. This is the point of no return. */
+ for (int i = 0; i < 3; i++) {
if (fd[i] == i) {
@@ -708,7 +731,7 @@ finish:
safe_close_above_stdio(original_error_fd);
/* Close the copies we moved > 2 */
- for (i = 0; i < 3; i++)
+ for (int i = 0; i < 3; i++)
safe_close(copy_fd[i]);
/* Close our null fd, if it's > 2 */
@@ -754,6 +777,37 @@ int fd_reopen(int fd, int flags) {
return new_fd;
}
+int fd_reopen_condition(
+ int fd,
+ int flags,
+ int mask,
+ int *ret_new_fd) {
+
+ int r, new_fd;
+
+ assert(fd >= 0);
+
+ /* Invokes fd_reopen(fd, flags), but only if the existing F_GETFL flags don't match the specified
+ * flags (masked by the specified mask). This is useful for converting O_PATH fds into real fds if
+ * needed, but only then. */
+
+ r = fcntl(fd, F_GETFL);
+ if (r < 0)
+ return -errno;
+
+ if ((r & mask) == (flags & mask)) {
+ *ret_new_fd = -EBADF;
+ return fd;
+ }
+
+ new_fd = fd_reopen(fd, flags);
+ if (new_fd < 0)
+ return new_fd;
+
+ *ret_new_fd = new_fd;
+ return new_fd;
+}
+
int read_nr_open(void) {
_cleanup_free_ char *nr_open = NULL;
int r;
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.h b/src/libnm-systemd-shared/src/basic/fd-util.h
index d9896e27e8..952afdd64f 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.h
+++ b/src/libnm-systemd-shared/src/basic/fd-util.h
@@ -15,14 +15,15 @@
/* 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)
+#define PIPE_EBADF { -EBADF, -EBADF }
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;
+ if (fd < 3) /* Don't close stdin/stdout/stderr, but still invalidate the fd by returning -EBADF. */
+ return -EBADF;
return safe_close(fd);
}
@@ -56,6 +57,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL);
int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec);
+int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec);
int get_max_fd(void);
@@ -85,17 +87,11 @@ 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);
+ return rearrange_stdio(-EBADF, -EBADF, -EBADF);
}
-/* Like TAKE_PTR() but for file descriptors, resetting them to -1 */
-#define TAKE_FD(fd) \
- ({ \
- int *_fd_ = &(fd); \
- int _ret_ = *_fd_; \
- *_fd_ = -1; \
- _ret_; \
- })
+/* Like TAKE_PTR() but for file descriptors, resetting them to -EBADF */
+#define TAKE_FD(fd) TAKE_GENERIC(fd, int, -EBADF)
/* Like free_and_replace(), but for file descriptors */
#define close_and_replace(a, b) \
@@ -107,6 +103,7 @@ static inline int make_null_stdio(void) {
})
int fd_reopen(int fd, int flags);
+int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
int read_nr_open(void);
int fd_get_diskseq(int fd, uint64_t *ret);
diff --git a/src/libnm-systemd-shared/src/basic/fileio.c b/src/libnm-systemd-shared/src/basic/fileio.c
index 2c4ba89a15..51b11ab9c7 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.c
+++ b/src/libnm-systemd-shared/src/basic/fileio.c
@@ -21,6 +21,7 @@
#include "log.h"
#include "macro.h"
#include "mkdir.h"
+#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "socket-util.h"
@@ -43,16 +44,17 @@
* can detect EOFs. */
#define READ_VIRTUAL_BYTES_MAX (4U*1024U*1024U - 2U)
-int fopen_unlocked(const char *path, const char *options, FILE **ret) {
+int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret) {
+ int r;
+
assert(ret);
- FILE *f = fopen(path, options);
- if (!f)
- return -errno;
+ r = xfopenat(dir_fd, path, options, flags, ret);
+ if (r < 0)
+ return r;
- (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
+ (void) __fsetlocking(*ret, FSETLOCKING_BYCALLER);
- *ret = f;
return 0;
}
@@ -78,7 +80,7 @@ int take_fdopen_unlocked(int *fd, const char *options, FILE **ret) {
if (r < 0)
return r;
- *fd = -1;
+ *fd = -EBADF;
return 0;
}
@@ -90,7 +92,7 @@ FILE* take_fdopen(int *fd, const char *options) {
if (!f)
return NULL;
- *fd = -1;
+ *fd = -EBADF;
return f;
}
@@ -102,7 +104,7 @@ DIR* take_fdopendir(int *dfd) {
if (!d)
return NULL;
- *dfd = -1;
+ *dfd = -EBADF;
return d;
}
@@ -134,7 +136,7 @@ int write_string_stream_ts(
const struct timespec *ts) {
bool needs_nl;
- int r, fd = -1;
+ int r, fd = -EBADF;
assert(f);
assert(line);
@@ -209,7 +211,8 @@ int write_string_stream_ts(
return 0;
}
-static int write_string_file_atomic(
+static int write_string_file_atomic_at(
+ int dir_fd,
const char *fn,
const char *line,
WriteStringFileFlags flags,
@@ -225,7 +228,7 @@ static int write_string_file_atomic(
/* 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);
+ r = fopen_temporary_at(dir_fd, fn, &f, &p);
if (r < 0)
return r;
@@ -237,7 +240,7 @@ static int write_string_file_atomic(
if (r < 0)
goto fail;
- if (rename(p, fn) < 0) {
+ if (renameat(dir_fd, p, dir_fd, fn) < 0) {
r = -errno;
goto fail;
}
@@ -252,11 +255,12 @@ static int write_string_file_atomic(
return 0;
fail:
- (void) unlink(p);
+ (void) unlinkat(dir_fd, p, 0);
return r;
}
-int write_string_file_ts(
+int write_string_file_ts_at(
+ int dir_fd,
const char *fn,
const char *line,
WriteStringFileFlags flags,
@@ -272,7 +276,7 @@ int write_string_file_ts(
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);
+ r = mkdirat_parents(dir_fd, fn, 0755);
if (r < 0)
return r;
}
@@ -280,7 +284,7 @@ int write_string_file_ts(
if (flags & WRITE_STRING_FILE_ATOMIC) {
assert(flags & WRITE_STRING_FILE_CREATE);
- r = write_string_file_atomic(fn, line, flags, ts);
+ r = write_string_file_atomic_at(dir_fd, fn, line, flags, ts);
if (r < 0)
goto fail;
@@ -289,12 +293,12 @@ int write_string_file_ts(
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_CLOEXEC|O_NOCTTY |
- (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
- (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
- (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
- (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY),
- (FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
+ fd = openat(dir_fd, fn, O_CLOEXEC|O_NOCTTY |
+ (FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
+ (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
+ (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
+ (FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY),
+ (FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
if (fd < 0) {
r = -errno;
goto fail;
@@ -364,7 +368,7 @@ int read_one_line_file(const char *fn, char **line) {
return read_line(f, LONG_LINE_MAX, line);
}
-int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
+int verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *buf = NULL;
size_t l, k;
@@ -382,7 +386,7 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
if (!buf)
return -ENOMEM;
- r = fopen_unlocked(fn, "re", &f);
+ r = fopen_unlocked_at(dir_fd, fn, "re", 0, &f);
if (r < 0)
return r;
@@ -554,7 +558,7 @@ int read_virtual_file_at(
char **ret_contents,
size_t *ret_size) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
@@ -763,7 +767,7 @@ int read_full_file_full(
r = xfopenat(dir_fd, filename, "re", 0, &f);
if (r < 0) {
- _cleanup_close_ int sk = -1;
+ _cleanup_close_ int sk = -EBADF;
/* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
if (r != -ENXIO)
@@ -858,7 +862,6 @@ int executable_is_script(const char *path, char **interpreter) {
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);
@@ -910,9 +913,7 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
t--;
}
- len = strcspn(t, terminator);
-
- f = strndup(t, len);
+ f = strdupcspn(t, terminator);
if (!f)
return -ENOMEM;
@@ -1245,7 +1246,7 @@ typedef enum EndOfLineMarker {
static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
- if (!IN_SET(flags, READ_LINE_ONLY_NUL)) {
+ if (!FLAGS_SET(flags, READ_LINE_ONLY_NUL)) {
if (c == '\n')
return EOL_TEN;
if (c == '\r')
diff --git a/src/libnm-systemd-shared/src/basic/fileio.h b/src/libnm-systemd-shared/src/basic/fileio.h
index 9151d8237a..7da3ee33e0 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.h
+++ b/src/libnm-systemd-shared/src/basic/fileio.h
@@ -43,7 +43,10 @@ typedef enum {
READ_FULL_FILE_FAIL_WHEN_LARGER = 1 << 5, /* fail loading if file is larger than specified size */
} ReadFullFileFlags;
-int fopen_unlocked(const char *path, const char *options, FILE **ret);
+int fopen_unlocked_at(int dir_fd, const char *path, const char *options, int flags, FILE **ret);
+static inline int fopen_unlocked(const char *path, const char *options, FILE **ret) {
+ return fopen_unlocked_at(AT_FDCWD, path, options, 0, 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);
@@ -55,7 +58,13 @@ int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags
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);
+int write_string_file_ts_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
+static inline int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts) {
+ return write_string_file_ts_at(AT_FDCWD, fn, line, flags, ts);
+}
+static inline int write_string_file_at(int dir_fd, const char *fn, const char *line, WriteStringFileFlags flags) {
+ return write_string_file_ts_at(dir_fd, fn, line, flags, NULL);
+}
static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
return write_string_file_ts(fn, line, flags, NULL);
}
@@ -64,6 +73,9 @@ int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *f
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_at(int dir_fd, const char *filename, char **ret_contents, size_t *ret_size) {
+ return read_full_file_full(dir_fd, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, 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);
}
@@ -82,7 +94,10 @@ static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_siz
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 verify_file_at(int dir_fd, const char *fn, const char *blob, bool accept_extra_nl);
+static inline int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
+ return verify_file_at(AT_FDCWD, fn, blob, accept_extra_nl);
+}
int executable_is_script(const char *path, char **interpreter);
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c
index 6b757bd570..a895f4f2df 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.c
+++ b/src/libnm-systemd-shared/src/basic/fs-util.c
@@ -32,7 +32,6 @@
#include "tmpfile-util.h"
#include "umask-util.h"
#include "user-util.h"
-#include "util.h"
int unlink_noerrno(const char *path) {
PROTECT_ERRNO;
@@ -175,37 +174,41 @@ int readlink_value(const char *p, char **ret) {
return 0;
}
-int readlink_and_make_absolute(const char *p, char **r) {
+int readlink_and_make_absolute(const char *p, char **ret) {
_cleanup_free_ char *target = NULL;
- char *k;
- int j;
+ int r;
assert(p);
- assert(r);
-
- j = readlink_malloc(p, &target);
- if (j < 0)
- return j;
+ assert(ret);
- k = file_in_same_dir(p, target);
- if (!k)
- return -ENOMEM;
+ r = readlink_malloc(p, &target);
+ if (r < 0)
+ return r;
- *r = k;
- return 0;
+ return file_in_same_dir(p, target, ret);
}
-int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
- _cleanup_close_ int fd = -1;
+int chmod_and_chown_at(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid) {
+ _cleanup_close_ int fd = -EBADF;
- assert(path);
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
- 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;
+ if (path) {
+ /* Let's acquire an O_PATH fd, as precaution to change mode/owner on the same file */
+ fd = openat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+ dir_fd = fd;
+
+ } else if (dir_fd == AT_FDCWD) {
+ /* Let's acquire an O_PATH fd of the current directory */
+ fd = openat(dir_fd, ".", O_PATH|O_CLOEXEC|O_NOFOLLOW|O_DIRECTORY);
+ if (fd < 0)
+ return -errno;
+ dir_fd = fd;
+ }
- return fchmod_and_chown(fd, mode, uid, gid);
+ return fchmod_and_chown(dir_fd, mode, uid, gid);
}
int fchmod_and_chown_with_fallback(int fd, const char *path, mode_t mode, uid_t uid, gid_t gid) {
@@ -351,7 +354,7 @@ int fd_warn_permissions(const char *path, int fd) {
}
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
int r, ret;
assert(path);
@@ -675,7 +678,7 @@ void unlink_tempfilep(char (*p)[]) {
}
int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
- _cleanup_close_ int truncate_fd = -1;
+ _cleanup_close_ int truncate_fd = -EBADF;
struct stat st;
off_t l, bs;
@@ -806,7 +809,7 @@ int conservative_renameat(
int olddirfd, const char *oldpath,
int newdirfd, const char *newpath) {
- _cleanup_close_ int old_fd = -1, new_fd = -1;
+ _cleanup_close_ int old_fd = -EBADF, new_fd = -EBADF;
struct stat old_stat, new_stat;
/* Renames the old path to thew new path, much like renameat() — except if both are regular files and
@@ -902,7 +905,7 @@ int posix_fallocate_loop(int fd, uint64_t offset, uint64_t size) {
/* On EINTR try a couple of times more, but protect against busy looping
* (not more than 16 times per 10s) */
- rl = (RateLimit) { 10 * USEC_PER_SEC, 16 };
+ rl = (const RateLimit) { 10 * USEC_PER_SEC, 16 };
while (ratelimit_below(&rl)) {
r = posix_fallocate(fd, offset, size);
if (r != EINTR)
@@ -988,7 +991,7 @@ int parse_cifs_service(
}
int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
- _cleanup_close_ int fd = -1, parent_fd = -1;
+ _cleanup_close_ int fd = -EBADF, parent_fd = -EBADF;
_cleanup_free_ char *fname = NULL;
bool made;
int r;
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.h b/src/libnm-systemd-shared/src/basic/fs-util.h
index c4dffc48f3..932d003f19 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.h
+++ b/src/libnm-systemd-shared/src/basic/fs-util.h
@@ -33,7 +33,10 @@ 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 chmod_and_chown_at(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid);
+static inline int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
+ return chmod_and_chown_at(AT_FDCWD, path, mode, uid, gid);
+}
int fchmod_and_chown_with_fallback(int fd, const char *path, mode_t mode, uid_t uid, gid_t gid);
static inline int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
return fchmod_and_chown_with_fallback(fd, NULL, mode, uid, gid); /* no fallback */
diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.c b/src/libnm-systemd-shared/src/basic/glyph-util.c
index 67f2270daf..2833125ed9 100644
--- a/src/libnm-systemd-shared/src/basic/glyph-util.c
+++ b/src/libnm-systemd-shared/src/basic/glyph-util.c
@@ -9,15 +9,15 @@ bool emoji_enabled(void) {
static int cached_emoji_enabled = -1;
if (cached_emoji_enabled < 0) {
- int val;
-
- val = getenv_bool("SYSTEMD_EMOJI");
- if (val < 0)
- cached_emoji_enabled =
- is_locale_utf8() &&
- !STRPTR_IN_SET(getenv("TERM"), "dumb", "linux");
- else
- cached_emoji_enabled = val;
+ int val = getenv_bool("SYSTEMD_EMOJI");
+ if (val >= 0)
+ return (cached_emoji_enabled = val);
+
+ const char *term = getenv("TERM");
+ if (!term || STR_IN_SET(term, "dumb", "linux"))
+ return (cached_emoji_enabled = false);
+
+ cached_emoji_enabled = is_locale_utf8();
}
return cached_emoji_enabled;
@@ -71,6 +71,7 @@ const char *special_glyph(SpecialGlyph code) {
[SPECIAL_GLYPH_RECYCLING] = "~",
[SPECIAL_GLYPH_DOWNLOAD] = "\\",
[SPECIAL_GLYPH_SPARKLES] = "*",
+ [SPECIAL_GLYPH_WARNING_SIGN] = "!",
},
/* UTF-8 */
@@ -124,10 +125,11 @@ const char *special_glyph(SpecialGlyph code) {
/* This emoji is a single character cell glyph in Unicode, and two in ASCII */
[SPECIAL_GLYPH_TOUCH] = u8"👆", /* actually called: BACKHAND INDEX POINTING UP */
- /* These three emojis are single character cell glyphs in Unicode and also in ASCII. */
+ /* These four emojis are single character cell glyphs in Unicode and also in ASCII. */
[SPECIAL_GLYPH_RECYCLING] = u8"♻️", /* actually called: UNIVERSAL RECYCLNG SYMBOL */
[SPECIAL_GLYPH_DOWNLOAD] = u8"⤵️", /* actually called: RIGHT ARROW CURVING DOWN */
[SPECIAL_GLYPH_SPARKLES] = u8"✨",
+ [SPECIAL_GLYPH_WARNING_SIGN] = u8"⚠️",
},
};
diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.h b/src/libnm-systemd-shared/src/basic/glyph-util.h
index 621d7a85b7..b64639622e 100644
--- a/src/libnm-systemd-shared/src/basic/glyph-util.h
+++ b/src/libnm-systemd-shared/src/basic/glyph-util.h
@@ -44,6 +44,7 @@ typedef enum SpecialGlyph {
SPECIAL_GLYPH_RECYCLING,
SPECIAL_GLYPH_DOWNLOAD,
SPECIAL_GLYPH_SPARKLES,
+ SPECIAL_GLYPH_WARNING_SIGN,
_SPECIAL_GLYPH_MAX,
_SPECIAL_GLYPH_INVALID = -EINVAL,
} SpecialGlyph;
diff --git a/src/libnm-systemd-shared/src/basic/hashmap.c b/src/libnm-systemd-shared/src/basic/hashmap.c
index f68cd36bb7..322b148b31 100644
--- a/src/libnm-systemd-shared/src/basic/hashmap.c
+++ b/src/libnm-systemd-shared/src/basic/hashmap.c
@@ -9,6 +9,7 @@
#include "alloc-util.h"
#include "fileio.h"
#include "hashmap.h"
+#include "logarithm.h"
#include "macro.h"
#include "memory-util.h"
#include "mempool.h"
@@ -372,8 +373,9 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
}
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);
+ return CAST_ALIGN_PTR(
+ 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) {
@@ -772,7 +774,7 @@ static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enu
HashmapBase *h;
const struct hashmap_type_info *hi = &hashmap_type_info[type];
- bool use_pool = mempool_enabled && mempool_enabled();
+ bool use_pool = mempool_enabled && mempool_enabled(); /* mempool_enabled is a weak symbol */
h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
if (!h)
@@ -1751,7 +1753,7 @@ HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) {
}
if (r < 0)
- return _hashmap_free(copy, false, false);
+ return _hashmap_free(copy, NULL, NULL);
return copy;
}
diff --git a/src/libnm-systemd-shared/src/basic/hashmap.h b/src/libnm-systemd-shared/src/basic/hashmap.h
index 91b3fe862b..ebb5a63eb4 100644
--- a/src/libnm-systemd-shared/src/basic/hashmap.h
+++ b/src/libnm-systemd-shared/src/basic/hashmap.h
@@ -7,7 +7,6 @@
#include "hash-funcs.h"
#include "macro.h"
-#include "util.h"
/*
* A hash table implementation. As a minor optimization a NULL hashmap object
diff --git a/src/libnm-systemd-shared/src/basic/hexdecoct.c b/src/libnm-systemd-shared/src/basic/hexdecoct.c
index 190fca8ee4..898ed83f86 100644
--- a/src/libnm-systemd-shared/src/basic/hexdecoct.c
+++ b/src/libnm-systemd-shared/src/basic/hexdecoct.c
@@ -59,11 +59,13 @@ char *hexmem(const void *p, size_t l) {
const uint8_t *x;
char *r, *z;
+ assert(p || l == 0);
+
z = r = new(char, l * 2 + 1);
if (!r)
return NULL;
- for (x = p; x < (const uint8_t*) p + l; x++) {
+ for (x = p; x && x < (const uint8_t*) p + l; x++) {
*(z++) = hexchar(*x >> 4);
*(z++) = hexchar(*x & 15);
}
@@ -108,12 +110,17 @@ static int unhex_next(const char **p, size_t *l) {
return r;
}
-int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_len) {
+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(p || l == 0);
@@ -126,22 +133,20 @@ int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_
if (!buf)
return -ENOMEM;
+ CLEANUP_ERASE_PTR(secure ? &buf : NULL, buf_size);
+
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;
- }
+ if (a < 0)
+ return a;
b = unhex_next(&x, &l);
- if (b < 0) {
- r = b;
- goto on_failure;
- }
+ if (b < 0)
+ return b;
*(z++) = (uint8_t) a << 4 | (uint8_t) b;
}
@@ -154,12 +159,6 @@ int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_
*ret = TAKE_PTR(buf);
return 0;
-
-on_failure:
- if (secure)
- explicit_bzero_safe(buf, buf_size);
-
- return r;
}
/* https://tools.ietf.org/html/rfc4648#section-6
@@ -586,121 +585,136 @@ ssize_t base64mem_full(
const void *p,
size_t l,
size_t line_break,
- char **out) {
+ char **ret) {
const uint8_t *x;
- char *r, *z;
+ char *b, *z;
size_t m;
assert(p || l == 0);
- assert(out);
assert(line_break > 0);
+ assert(ret);
/* three input bytes makes four output bytes, padding is added so we must round up */
m = 4 * (l + 2) / 3 + 1;
-
if (line_break != SIZE_MAX)
m += m / line_break;
- z = r = malloc(m);
- if (!r)
+ z = b = malloc(m);
+ if (!b)
return -ENOMEM;
- for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
+ for (x = p; x && x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
}
switch (l % 3) {
case 2:
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = '=';
-
break;
+
case 1:
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = '=';
- maybe_line_break(&z, r, line_break);
+ maybe_line_break(&z, b, line_break);
*(z++) = '=';
-
break;
}
*z = 0;
- *out = r;
- assert(z >= r); /* Let static analyzers know that the answer is non-negative. */
- return z - r;
+ *ret = b;
+
+ assert(z >= b); /* Let static analyzers know that the answer is non-negative. */
+ return z - b;
}
-static int base64_append_width(
- char **prefix, int plen,
- char sep, int indent,
- const void *p, size_t l,
- int width) {
+static ssize_t base64_append_width(
+ char **prefix,
+ size_t plen,
+ char sep,
+ size_t indent,
+ const void *p,
+ size_t l,
+ size_t width) {
_cleanup_free_ char *x = NULL;
char *t, *s;
- ssize_t len, avail, line, lines;
+ size_t lines;
+ ssize_t len;
+
+ assert(prefix);
+ assert(*prefix || plen == 0);
+ assert(p || l == 0);
len = base64mem(p, l, &x);
- if (len <= 0)
+ if (len < 0)
return len;
+ if (len == 0)
+ return plen;
lines = DIV_ROUND_UP(len, width);
- if ((size_t) plen >= SSIZE_MAX - 1 - 1 ||
+ if (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);
+ t = realloc(*prefix, plen + 1 + 1 + (indent + width + 1) * lines);
if (!t)
return -ENOMEM;
- t[plen] = sep;
+ s = t + plen;
+ for (size_t line = 0; line < lines; line++) {
+ size_t act = MIN(width, (size_t) len);
- for (line = 0, s = t + plen + 1, avail = len; line < lines; line++) {
- int act = MIN(width, avail);
+ if (line > 0)
+ sep = '\n';
- if (line > 0 || sep == '\n') {
- memset(s, ' ', indent);
- s += indent;
+ if (s > t) {
+ *s++ = sep;
+ if (sep == '\n')
+ s = mempset(s, ' ', indent);
}
s = mempcpy(s, x + width * line, act);
- *(s++) = line < lines - 1 ? '\n' : '\0';
- avail -= act;
+ len -= act;
}
- assert(avail == 0);
+ assert(len == 0);
+ *s = '\0';
*prefix = t;
- return 0;
+ return s - t;
}
-int base64_append(
- char **prefix, int plen,
- const void *p, size_t l,
- int indent, int width) {
+ssize_t base64_append(
+ char **prefix,
+ size_t plen,
+ const void *p,
+ size_t l,
+ size_t indent,
+ size_t 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);
+ return base64_append_width(prefix, plen, '\n', indent, p, l, width - indent);
else
/* leave plen on the left, keep last column free */
return base64_append_width(prefix, plen, ' ', plen + 1, p, l, width - plen - 1);
@@ -748,12 +762,17 @@ static int unbase64_next(const char **p, size_t *l) {
return ret;
}
-int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_size) {
+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);
@@ -768,60 +787,44 @@ int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *r
if (!buf)
return -ENOMEM;
+ CLEANUP_ERASE_PTR(secure ? &buf : NULL, len);
+
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;
- }
+ if (a < 0)
+ return a;
+ if (a == INT_MAX) /* Padding is not allowed at the beginning of a 4ch block */
+ return -EINVAL;
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;
- }
+ if (b < 0)
+ return b;
+ if (b == INT_MAX) /* Padding is not allowed at the second character of a 4ch block either */
+ return -EINVAL;
c = unbase64_next(&x, &l);
- if (c < 0) {
- r = c;
- goto on_failure;
- }
+ if (c < 0)
+ return c;
d = unbase64_next(&x, &l);
- if (d < 0) {
- r = d;
- goto on_failure;
- }
+ if (d < 0)
+ return d;
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;
- }
+ if (d != INT_MAX) /* If the third character is padding, the fourth must be too */
+ return -EINVAL;
/* b == 00YY0000 */
- if (b & 15) {
- r = -EINVAL;
- goto on_failure;
- }
+ if (b & 15)
+ return -EINVAL;
- if (l > 0) { /* Trailing rubbish? */
- r = -ENAMETOOLONG;
- goto on_failure;
- }
+ if (l > 0) /* Trailing rubbish? */
+ return -ENAMETOOLONG;
*(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
break;
@@ -829,15 +832,11 @@ int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *r
if (d == INT_MAX) {
/* c == 00ZZZZ00 */
- if (c & 3) {
- r = -EINVAL;
- goto on_failure;
- }
+ if (c & 3)
+ return -EINVAL;
- if (l > 0) { /* Trailing rubbish? */
- r = -ENAMETOOLONG;
- goto on_failure;
- }
+ if (l > 0) /* Trailing rubbish? */
+ return -ENAMETOOLONG;
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
@@ -851,18 +850,14 @@ int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *r
*z = 0;
+ assert((size_t) (z - buf) <= len);
+
if (ret_size)
*ret_size = (size_t) (z - buf);
if (ret)
*ret = TAKE_PTR(buf);
return 0;
-
-on_failure:
- if (secure)
- explicit_bzero_safe(buf, len);
-
- return r;
}
void hexdump(FILE *f, const void *p, size_t s) {
diff --git a/src/libnm-systemd-shared/src/basic/hexdecoct.h b/src/libnm-systemd-shared/src/basic/hexdecoct.h
index 5218f78665..319b21a17c 100644
--- a/src/libnm-systemd-shared/src/basic/hexdecoct.h
+++ b/src/libnm-systemd-shared/src/basic/hexdecoct.h
@@ -38,9 +38,13 @@ static inline ssize_t base64mem(const void *p, size_t l, char **ret) {
return base64mem_full(p, l, SIZE_MAX, ret);
}
-int base64_append(char **prefix, int plen,
- const void *p, size_t l,
- int margin, int width);
+ssize_t base64_append(
+ char **prefix,
+ size_t plen,
+ const void *p,
+ size_t l,
+ size_t margin,
+ size_t 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);
diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.c b/src/libnm-systemd-shared/src/basic/hostname-util.c
index b710f07929..e743033b1e 100644
--- a/src/libnm-systemd-shared/src/basic/hostname-util.c
+++ b/src/libnm-systemd-shared/src/basic/hostname-util.c
@@ -62,7 +62,7 @@ int gethostname_full(GetHostnameFlags flags, char **ret) {
}
if (FLAGS_SET(flags, GET_HOSTNAME_SHORT))
- buf = strndup(s, strcspn(s, "."));
+ buf = strdupcspn(s, ".");
else
buf = strdup(s);
if (!buf)
diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.h b/src/libnm-systemd-shared/src/basic/hostname-util.h
index a00b852395..bcac3d9fb0 100644
--- a/src/libnm-systemd-shared/src/basic/hostname-util.h
+++ b/src/libnm-systemd-shared/src/basic/hostname-util.h
@@ -60,4 +60,12 @@ static inline bool is_outbound_hostname(const char *hostname) {
return STRCASE_IN_SET(hostname, "_outbound", "_outbound.");
}
+static inline bool is_dns_stub_hostname(const char *hostname) {
+ return STRCASE_IN_SET(hostname, "_localdnsstub", "_localdnsstub.");
+}
+
+static inline bool is_dns_proxy_stub_hostname(const char *hostname) {
+ return STRCASE_IN_SET(hostname, "_localdnsproxy", "_localdnsproxy.");
+}
+
int get_pretty_hostname(char **ret);
diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.c b/src/libnm-systemd-shared/src/basic/in-addr-util.c
index 05c729d34d..30d90cce0d 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.c
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c
@@ -11,13 +11,13 @@
#include "alloc-util.h"
#include "errno-util.h"
#include "in-addr-util.h"
+#include "logarithm.h"
#include "macro.h"
#include "parse-util.h"
#include "random-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strxcpyx.h"
-#include "util.h"
bool in4_addr_is_null(const struct in_addr *a) {
assert(a);
@@ -898,14 +898,6 @@ int in_addr_prefix_from_string_auto_internal(
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();
}
@@ -921,7 +913,7 @@ int in_addr_prefix_from_string_auto_internal(
}
-static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
+void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
assert(a);
assert(state);
@@ -929,7 +921,7 @@ static void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash
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 in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
int r;
assert(x);
@@ -942,7 +934,18 @@ static int in_addr_data_compare_func(const struct in_addr_data *x, const struct
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);
+DEFINE_HASH_OPS(
+ in_addr_data_hash_ops,
+ struct in_addr_data,
+ in_addr_data_hash_func,
+ in_addr_data_compare_func);
+
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+ in_addr_data_hash_ops_free,
+ struct in_addr_data,
+ in_addr_data_hash_func,
+ in_addr_data_compare_func,
+ free);
void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
assert(addr);
@@ -958,7 +961,12 @@ 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);
+DEFINE_HASH_OPS(
+ in6_addr_hash_ops,
+ struct in6_addr,
+ in6_addr_hash_func,
+ in6_addr_compare_func);
+
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
in6_addr_hash_ops_free,
struct in6_addr,
diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.h b/src/libnm-systemd-shared/src/basic/in-addr-util.h
index 19fa35f1d2..200b9eb69d 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.h
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h
@@ -8,7 +8,6 @@
#include "hash-funcs.h"
#include "macro.h"
-#include "util.h"
union in_addr_union {
struct in_addr in;
@@ -154,7 +153,6 @@ int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *r
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);
@@ -178,10 +176,13 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
* See also oss-fuzz#11344. */
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
+void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state);
+int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y);
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 in_addr_data_hash_ops_free;
extern const struct hash_ops in6_addr_hash_ops;
extern const struct hash_ops in6_addr_hash_ops_free;
diff --git a/src/libnm-systemd-shared/src/basic/io-util.c b/src/libnm-systemd-shared/src/basic/io-util.c
index cdad939aa6..f642beca3a 100644
--- a/src/libnm-systemd-shared/src/basic/io-util.c
+++ b/src/libnm-systemd-shared/src/basic/io-util.c
@@ -161,6 +161,21 @@ int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) {
assert(fds || nfds == 0);
+ /* This is a wrapper around ppoll() that does primarily two things:
+ *
+ * ✅ Takes a usec_t instead of a struct timespec
+ *
+ * ✅ Guarantees that if an invalid fd is specified we return EBADF (i.e. converts POLLNVAL to
+ * EBADF). This is done because EBADF is a programming error usually, and hence should bubble up
+ * as error, and not be eaten up as non-error POLLNVAL event.
+ *
+ * ⚠️ ⚠️ ⚠️ Note that this function does not add any special handling for EINTR. Don't forget
+ * poll()/ppoll() will return with EINTR on any received signal always, there is no automatic
+ * restarting via SA_RESTART available. Thus, typically you want to handle EINTR not as an error,
+ * but just as reason to restart things, under the assumption you use a more appropriate mechanism
+ * to handle signals, such as signalfd() or signal handlers. ⚠️ ⚠️ ⚠️
+ */
+
if (nfds == 0)
return 0;
@@ -188,6 +203,9 @@ int fd_wait_for_event(int fd, int event, usec_t timeout) {
};
int r;
+ /* ⚠️ ⚠️ ⚠️ Keep in mind you almost certainly want to handle -EINTR gracefully in the caller, see
+ * ppoll_usec() above! ⚠️ ⚠️ ⚠️ */
+
r = ppoll_usec(&pollfd, 1, timeout);
if (r <= 0)
return r;
diff --git a/src/libnm-systemd-shared/src/basic/io-util.h b/src/libnm-systemd-shared/src/basic/io-util.h
index 39728e06bc..3afb134266 100644
--- a/src/libnm-systemd-shared/src/basic/io-util.h
+++ b/src/libnm-systemd-shared/src/basic/io-util.h
@@ -91,7 +91,16 @@ 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);
+static inline int iovw_consume(struct iovec_wrapper *iovw, void *data, size_t len) {
+ /* Move data into iovw or free on error */
+ int r = iovw_put(iovw, data, len);
+ if (r < 0)
+ free(data);
+ return r;
+}
+
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);
diff --git a/src/libnm-systemd-shared/src/basic/list.h b/src/libnm-systemd-shared/src/basic/list.h
index ca30039690..ffc8bd8304 100644
--- a/src/libnm-systemd-shared/src/basic/list.h
+++ b/src/libnm-systemd-shared/src/basic/list.h
@@ -1,8 +1,6 @@
/* 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) \
@@ -28,26 +26,27 @@
/* 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)
+ _item; \
+ })
/* Append an item to the list */
#define LIST_APPEND(name,head,item) \
- do { \
+ ({ \
typeof(*(head)) **_hhead = &(head), *_tail; \
- LIST_FIND_TAIL(name, *_hhead, _tail); \
+ _tail = LIST_FIND_TAIL(name, *_hhead); \
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) \
@@ -59,37 +58,30 @@
*_head = _item->name##_next; \
} \
_item->name##_next = _item->name##_prev = NULL; \
- } while (false)
+ _item; \
+ })
/* Find the head of the list */
-#define LIST_FIND_HEAD(name,item,head) \
- do { \
+#define LIST_FIND_HEAD(name,item) \
+ ({ \
typeof(*(item)) *_item = (item); \
- if (!_item) \
- (head) = NULL; \
- else { \
- while (_item->name##_prev) \
- _item = _item->name##_prev; \
- (head) = _item; \
- } \
- } while (false)
+ while (_item && _item->name##_prev) \
+ _item = _item->name##_prev; \
+ _item; \
+ })
/* Find the tail of the list */
-#define LIST_FIND_TAIL(name,item,tail) \
- do { \
+#define LIST_FIND_TAIL(name,item) \
+ ({ \
typeof(*(item)) *_item = (item); \
- if (!_item) \
- (tail) = NULL; \
- else { \
- while (_item->name##_next) \
- _item = _item->name##_next; \
- (tail) = _item; \
- } \
- } while (false)
+ while (_item && _item->name##_next) \
+ _item = _item->name##_next; \
+ _item; \
+ })
/* 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) { \
@@ -103,11 +95,12 @@
_b->name##_prev = _a; \
_a->name##_next = _b; \
} \
- } while (false)
+ _b; \
+ })
/* 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) { \
@@ -131,7 +124,8 @@
_b->name##_next = _a; \
_a->name##_prev = _b; \
} \
- } while (false)
+ _b; \
+ })
#define LIST_JUST_US(name,item) \
(!(item)->name##_prev && !(item)->name##_next)
@@ -172,18 +166,19 @@
/* 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 = LIST_FIND_TAIL(name, (a)); \
_tail->name##_next = _head; \
_head->name##_prev = _tail; \
} \
(b) = NULL; \
- } while (false)
+ a; \
+ })
#define LIST_POP(name, a) \
({ \
@@ -193,3 +188,7 @@
LIST_REMOVE(name, *_a, _p); \
_p; \
})
+
+/* Now include "macro.h", because we want our definition of assert() which the macros above use. We include
+ * it down here instead of up top, since macro.h pulls in log.h which in turn needs our own definitions. */
+#include "macro.h"
diff --git a/src/libnm-systemd-shared/src/basic/locale-util.c b/src/libnm-systemd-shared/src/basic/locale-util.c
index d8518ec06a..d94fbcff4b 100644
--- a/src/libnm-systemd-shared/src/basic/locale-util.c
+++ b/src/libnm-systemd-shared/src/basic/locale-util.c
@@ -10,7 +10,7 @@
#include <sys/mman.h>
#include <sys/stat.h>
-#include "def.h"
+#include "constants.h"
#include "dirent-util.h"
#include "env-util.h"
#include "fd-util.h"
@@ -95,7 +95,7 @@ static int add_locales_from_archive(Set *locales) {
const struct locarhead *h;
const struct namehashent *e;
const void *p = MAP_FAILED;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
size_t sz = 0;
struct stat st;
int r;
@@ -286,8 +286,9 @@ void init_gettext(void) {
}
bool is_locale_utf8(void) {
- const char *set;
static int cached_answer = -1;
+ const char *set;
+ int r;
/* Note that we default to 'true' here, since today UTF8 is
* pretty much supported everywhere. */
@@ -295,6 +296,13 @@ bool is_locale_utf8(void) {
if (cached_answer >= 0)
goto out;
+ r = getenv_bool_secure("SYSTEMD_UTF8");
+ if (r >= 0) {
+ cached_answer = r;
+ goto out;
+ } else if (r != -ENXIO)
+ log_debug_errno(r, "Failed to parse $SYSTEMD_UTF8, ignoring: %m");
+
if (!setlocale(LC_ALL, "")) {
cached_answer = true;
goto out;
diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h
index c51941c141..f73d4c4154 100644
--- a/src/libnm-systemd-shared/src/basic/log.h
+++ b/src/libnm-systemd-shared/src/basic/log.h
@@ -7,8 +7,10 @@
#include <string.h>
#include <syslog.h>
+#include "list.h"
#include "macro.h"
#include "ratelimit.h"
+#include "stdio-util.h"
/* Some structures we reference but don't want to pull in headers for */
struct iovec;
@@ -296,6 +298,7 @@ int log_emergency_level(void);
#define log_oom() log_oom_internal(LOG_ERR, PROJECT_FILE, __LINE__, __func__)
#define log_oom_debug() log_oom_internal(LOG_DEBUG, PROJECT_FILE, __LINE__, __func__)
+#define log_oom_warning() log_oom_internal(LOG_WARNING, PROJECT_FILE, __LINE__, __func__)
bool log_on_console(void) _pure_;
@@ -375,15 +378,12 @@ typedef struct LogRateLimit {
RateLimit ratelimit;
} LogRateLimit;
-#define log_ratelimit_internal(_level, _error, _format, _file, _line, _func, ...) \
+#define log_ratelimit_internal(_level, _error, _ratelimit, _format, _file, _line, _func, ...) \
({ \
int _log_ratelimit_error = (_error); \
int _log_ratelimit_level = (_level); \
static LogRateLimit _log_ratelimit = { \
- .ratelimit = { \
- .interval = 1 * USEC_PER_SEC, \
- .burst = 1, \
- }, \
+ .ratelimit = (_ratelimit), \
}; \
unsigned _num_dropped_errors = ratelimit_num_dropped(&_log_ratelimit.ratelimit); \
if (_log_ratelimit_error != _log_ratelimit.error || _log_ratelimit_level != _log_ratelimit.level) { \
@@ -391,18 +391,115 @@ typedef struct LogRateLimit {
_log_ratelimit.error = _log_ratelimit_error; \
_log_ratelimit.level = _log_ratelimit_level; \
} \
- if (ratelimit_below(&_log_ratelimit.ratelimit)) \
+ if (log_get_max_level() == LOG_DEBUG || ratelimit_below(&_log_ratelimit.ratelimit)) \
_log_ratelimit_error = _num_dropped_errors > 0 \
- ? log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format " (Dropped %u similar message(s))", __VA_ARGS__, _num_dropped_errors) \
- : log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format, __VA_ARGS__); \
+ ? log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format " (Dropped %u similar message(s))", ##__VA_ARGS__, _num_dropped_errors) \
+ : log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format, ##__VA_ARGS__); \
_log_ratelimit_error; \
})
-#define log_ratelimit_full_errno(level, error, format, ...) \
+#define log_ratelimit_full_errno(level, error, _ratelimit, format, ...) \
({ \
int _level = (level), _e = (error); \
_e = (log_get_max_level() >= LOG_PRI(_level)) \
- ? log_ratelimit_internal(_level, _e, format, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
+ ? log_ratelimit_internal(_level, _e, _ratelimit, format, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__) \
: -ERRNO_VALUE(_e); \
_e < 0 ? _e : -ESTRPIPE; \
})
+
+#define log_ratelimit_full(level, _ratelimit, format, ...) \
+ log_ratelimit_full_errno(level, 0, _ratelimit, format, ##__VA_ARGS__)
+
+/* Normal logging */
+#define log_ratelimit_info(...) log_ratelimit_full(LOG_INFO, __VA_ARGS__)
+#define log_ratelimit_notice(...) log_ratelimit_full(LOG_NOTICE, __VA_ARGS__)
+#define log_ratelimit_warning(...) log_ratelimit_full(LOG_WARNING, __VA_ARGS__)
+#define log_ratelimit_error(...) log_ratelimit_full(LOG_ERR, __VA_ARGS__)
+#define log_ratelimit_emergency(...) log_ratelimit_full(log_emergency_level(), __VA_ARGS__)
+
+/* Logging triggered by an errno-like error */
+#define log_ratelimit_info_errno(error, ...) log_ratelimit_full_errno(LOG_INFO, error, __VA_ARGS__)
+#define log_ratelimit_notice_errno(error, ...) log_ratelimit_full_errno(LOG_NOTICE, error, __VA_ARGS__)
+#define log_ratelimit_warning_errno(error, ...) log_ratelimit_full_errno(LOG_WARNING, error, __VA_ARGS__)
+#define log_ratelimit_error_errno(error, ...) log_ratelimit_full_errno(LOG_ERR, error, __VA_ARGS__)
+#define log_ratelimit_emergency_errno(error, ...) log_ratelimit_full_errno(log_emergency_level(), error, __VA_ARGS__)
+
+/*
+ * The log context allows attaching extra metadata to log messages written to the journal via log.h. We keep
+ * track of a thread local log context onto which we can push extra metadata fields that should be logged.
+ *
+ * LOG_CONTEXT_PUSH() will add the provided field to the log context and will remove it again when the
+ * current block ends. LOG_CONTEXT_PUSH_STRV() will do the same but for all fields in the given strv.
+ * LOG_CONTEXT_PUSHF() is like LOG_CONTEXT_PUSH() but takes a format string and arguments.
+ *
+ * Using the macros is as simple as putting them anywhere inside a block to add a field to all following log
+ * messages logged from inside that block.
+ *
+ * void myfunction(...) {
+ * ...
+ *
+ * LOG_CONTEXT_PUSHF("MYMETADATA=%s", "abc");
+ *
+ * // Every journal message logged will now have the MYMETADATA=abc
+ * // field included.
+ * }
+ *
+ * One special case to note is async code, where we use callbacks that are invoked to continue processing
+ * when some event occurs. For async code, there's usually an associated "userdata" struct containing all the
+ * information associated with the async operation. In this "userdata" struct, we can store a log context
+ * allocated with log_context_new() and freed with log_context_free(). We can then add and remove fields to
+ * the `fields` member of the log context object and all those fields will be logged along with each log
+ * message.
+ */
+
+typedef struct LogContext LogContext;
+
+bool log_context_enabled(void);
+
+LogContext* log_context_attach(LogContext *c);
+LogContext* log_context_detach(LogContext *c);
+
+LogContext* log_context_new(char **fields, bool owned);
+LogContext* log_context_free(LogContext *c);
+
+/* Same as log_context_new(), but frees the given fields strv on failure. */
+LogContext* log_context_new_consume(char **fields);
+
+/* Returns the number of attached log context objects. */
+size_t log_context_num_contexts(void);
+/* Returns the number of fields in all attached log contexts. */
+size_t log_context_num_fields(void);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(LogContext*, log_context_detach);
+DEFINE_TRIVIAL_CLEANUP_FUNC(LogContext*, log_context_free);
+
+#define LOG_CONTEXT_PUSH(...) \
+ LOG_CONTEXT_PUSH_STRV(STRV_MAKE(__VA_ARGS__))
+
+#define LOG_CONTEXT_PUSHF(...) \
+ LOG_CONTEXT_PUSH(snprintf_ok((char[LINE_MAX]) {}, LINE_MAX, __VA_ARGS__))
+
+#define _LOG_CONTEXT_PUSH_STRV(strv, c) \
+ _unused_ _cleanup_(log_context_freep) LogContext *c = log_context_new(strv, /*owned=*/ false);
+
+#define LOG_CONTEXT_PUSH_STRV(strv) \
+ _LOG_CONTEXT_PUSH_STRV(strv, UNIQ_T(c, UNIQ))
+
+/* LOG_CONTEXT_CONSUME_STR()/LOG_CONTEXT_CONSUME_STRV() are identical to
+ * LOG_CONTEXT_PUSH_STR()/LOG_CONTEXT_PUSH_STRV() except they take ownership of the given str/strv argument.
+ */
+
+#define _LOG_CONTEXT_CONSUME_STR(s, c, strv) \
+ _unused_ _cleanup_strv_free_ strv = strv_new(s); \
+ if (!strv) \
+ free(s); \
+ _unused_ _cleanup_(log_context_freep) LogContext *c = log_context_new_consume(TAKE_PTR(strv))
+
+#define LOG_CONTEXT_CONSUME_STR(s) \
+ _LOG_CONTEXT_CONSUME_STR(s, UNIQ_T(c, UNIQ), UNIQ_T(sv, UNIQ))
+
+#define _LOG_CONTEXT_CONSUME_STRV(strv, c) \
+ _unused_ _cleanup_(log_context_freep) LogContext *c = log_context_new_consume(strv);
+
+#define LOG_CONTEXT_CONSUME_STRV(strv) \
+ _LOG_CONTEXT_CONSUME_STRV(strv, UNIQ_T(c, UNIQ))
diff --git a/src/libnm-systemd-shared/src/basic/util.h b/src/libnm-systemd-shared/src/basic/logarithm.h
index 68ae3b51e0..646f2d3613 100644
--- a/src/libnm-systemd-shared/src/basic/util.h
+++ b/src/libnm-systemd-shared/src/basic/logarithm.h
@@ -5,27 +5,6 @@
#include "macro.h"
-extern int saved_argc;
-extern char **saved_argv;
-
-static inline void save_argc_argv(int argc, char **argv) {
-
- /* Protect against CVE-2021-4034 style attacks */
- assert_se(argc > 0);
- assert_se(argv);
- assert_se(argv[0]);
-
- saved_argc = argc;
- saved_argv = argv;
-}
-
-bool kexec_loaded(void);
-
-int prot_from_flags(int flags) _const_;
-
-bool in_initrd(void);
-void in_initrd_force(bool value);
-
/* Note: log2(0) == log2(1) == 0 here and below. */
#define CONST_LOG2ULL(x) ((x) > 1 ? (unsigned) __builtin_clzll(x) ^ 63U : 0)
@@ -72,9 +51,3 @@ static inline unsigned log2u_round_up(unsigned x) {
return log2u(x - 1) + 1;
}
-
-int container_get_leader(const char *machine, pid_t *pid);
-
-int version(void);
-
-void disable_coredumps(void);
diff --git a/src/libnm-systemd-shared/src/basic/macro.h b/src/libnm-systemd-shared/src/basic/macro.h
index 237117db12..0d032866cf 100644
--- a/src/libnm-systemd-shared/src/basic/macro.h
+++ b/src/libnm-systemd-shared/src/basic/macro.h
@@ -9,32 +9,9 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
+#include "constants.h"
#include "macro-fundamental.h"
-#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
@@ -87,10 +64,14 @@
_Pragma("GCC diagnostic push")
#endif
-#define DISABLE_WARNING_TYPE_LIMITS \
+#define DISABLE_WARNING_TYPE_LIMITS \
_Pragma("GCC diagnostic push"); \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
+#define DISABLE_WARNING_ADDRESS \
+ _Pragma("GCC diagnostic push"); \
+ _Pragma("GCC diagnostic ignored \"-Waddress\"")
+
#define REENABLE_WARNING \
_Pragma("GCC diagnostic pop")
@@ -194,12 +175,12 @@ static inline int __coverity_check_and_return__(int condition) {
#define assert_message_se(expr, message) \
do { \
if (_unlikely_(!(expr))) \
- log_assert_failed(message, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__); \
+ log_assert_failed(message, PROJECT_FILE, __LINE__, __func__); \
} while (false)
#define assert_log(expr, message) ((_likely_(expr)) \
? (true) \
- : (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__), false))
+ : (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __func__), false))
#endif /* __COVERITY__ */
@@ -214,7 +195,7 @@ static inline int __coverity_check_and_return__(int condition) {
#endif
#define assert_not_reached() \
- log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__)
+ log_assert_failed_unreachable(PROJECT_FILE, __LINE__, __func__)
#define assert_return(expr, r) \
do { \
@@ -341,10 +322,14 @@ static inline int __coverity_check_and_return__(int condition) {
*p = func(*p); \
}
-/* When func() doesn't return the appropriate type, set variable to empty afterwards */
+/* When func() doesn't return the appropriate type, set variable to empty afterwards.
+ * The func() may be provided by a dynamically loaded shared library, hence add an assertion. */
#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \
static inline void func##p(type *p) { \
if (*p != (empty)) { \
+ DISABLE_WARNING_ADDRESS; \
+ assert(func); \
+ REENABLE_WARNING; \
func(*p); \
*p = (empty); \
} \
diff --git a/src/libnm-systemd-shared/src/basic/memory-util.c b/src/libnm-systemd-shared/src/basic/memory-util.c
index 2983762117..c4f54c7b4e 100644
--- a/src/libnm-systemd-shared/src/basic/memory-util.c
+++ b/src/libnm-systemd-shared/src/basic/memory-util.c
@@ -38,21 +38,3 @@ bool memeqbyte(uint8_t byte, const void *data, size_t length) {
/* Now we know first 16 bytes match, memcmp() with self. */
return memcmp(data, p + 16, 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/src/libnm-systemd-shared/src/basic/memory-util.h b/src/libnm-systemd-shared/src/basic/memory-util.h
index 6e3280b9df..428ccc210c 100644
--- a/src/libnm-systemd-shared/src/basic/memory-util.h
+++ b/src/libnm-systemd-shared/src/basic/memory-util.h
@@ -9,6 +9,7 @@
#include "alloc-util.h"
#include "macro.h"
+#include "memory-util-fundamental.h"
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
@@ -91,17 +92,6 @@ static inline void *mempmem_safe(const void *haystack, size_t haystacklen, const
return (uint8_t*) p + 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;
diff --git a/src/libnm-systemd-shared/src/basic/missing_syscall.h b/src/libnm-systemd-shared/src/basic/missing_syscall.h
index 793d111c55..98cd037962 100644
--- a/src/libnm-systemd-shared/src/basic/missing_syscall.h
+++ b/src/libnm-systemd-shared/src/basic/missing_syscall.h
@@ -363,6 +363,20 @@ static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info)
/* ======================================================================= */
+#if !HAVE_RT_TGSIGQUEUEINFO
+static inline int missing_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *info) {
+# if defined __NR_rt_tgsigqueueinfo && __NR_rt_tgsigqueueinfo >= 0
+ return syscall(__NR_rt_tgsigqueueinfo, tgid, tid, sig, info);
+# else
+# error "__NR_rt_tgsigqueueinfo not defined"
+# endif
+}
+
+# define rt_tgsigqueueinfo missing_rt_tgsigqueueinfo
+#endif
+
+/* ======================================================================= */
+
#if !HAVE_EXECVEAT
static inline int missing_execveat(int dirfd, const char *pathname,
char *const argv[], char *const envp[],
@@ -412,44 +426,6 @@ static inline int missing_close_range(int first_fd, int end_fd, unsigned flags)
/* ======================================================================= */
-#if !HAVE_EPOLL_PWAIT2
-
-/* Defined to be equivalent to the kernel's _NSIG_WORDS, i.e. the size of the array of longs that is
- * encapsulated by sigset_t. */
-#define KERNEL_NSIG_WORDS (64 / (sizeof(long) * 8))
-#define KERNEL_NSIG_BYTES (KERNEL_NSIG_WORDS * sizeof(long))
-
-struct epoll_event;
-
-static inline int missing_epoll_pwait2(
- int fd,
- struct epoll_event *events,
- int maxevents,
- const struct timespec *timeout,
- const sigset_t *sigset) {
-
-# if defined(__NR_epoll_pwait2) && HAVE_LINUX_TIME_TYPES_H
- if (timeout) {
- /* Convert from userspace timespec to kernel timespec */
- struct __kernel_timespec ts = {
- .tv_sec = timeout->tv_sec,
- .tv_nsec = timeout->tv_nsec,
- };
-
- return syscall(__NR_epoll_pwait2, fd, events, maxevents, &ts, sigset, sigset ? KERNEL_NSIG_BYTES : 0);
- } else
- return syscall(__NR_epoll_pwait2, fd, events, maxevents, NULL, sigset, sigset ? KERNEL_NSIG_BYTES : 0);
-# else
- errno = ENOSYS;
- return -1;
-# endif
-}
-
-# define epoll_pwait2 missing_epoll_pwait2
-#endif
-
-/* ======================================================================= */
-
#if !HAVE_MOUNT_SETATTR
#if !HAVE_STRUCT_MOUNT_ATTR
@@ -593,6 +569,46 @@ static inline int missing_move_mount(
/* ======================================================================= */
+#if !HAVE_FSOPEN
+
+#ifndef FSOPEN_CLOEXEC
+#define FSOPEN_CLOEXEC 0x00000001
+#endif
+
+static inline int missing_fsopen(const char *fsname, unsigned flags) {
+# if defined __NR_fsopen && __NR_fsopen >= 0
+ return syscall(__NR_fsopen, fsname, flags);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+
+# define fsopen missing_fsopen
+#endif
+
+/* ======================================================================= */
+
+#if !HAVE_FSCONFIG
+
+#ifndef FSCONFIG_SET_STRING
+#define FSCONFIG_SET_STRING 1 /* Set parameter, supplying a string value */
+#endif
+
+static inline int missing_fsconfig(int fd, unsigned cmd, const char *key, const void *value, int aux) {
+# if defined __NR_fsconfig && __NR_fsconfig >= 0
+ return syscall(__NR_fsconfig, fd, cmd, key, value, aux);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+
+# define fsconfig missing_fsconfig
+#endif
+
+/* ======================================================================= */
+
#if !HAVE_GETDENTS64
static inline ssize_t missing_getdents64(int fd, void *buffer, size_t length) {
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.c b/src/libnm-systemd-shared/src/basic/parse-util.c
index 3b3efb0ab8..3445d31307 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.c
+++ b/src/libnm-systemd-shared/src/basic/parse-util.c
@@ -256,6 +256,26 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
return 0;
}
+int parse_sector_size(const char *t, uint64_t *ret) {
+ int r;
+
+ assert(t);
+ assert(ret);
+
+ uint64_t ss;
+
+ r = safe_atou64(t, &ss);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse sector size parameter %s", t);
+ if (ss < 512 || ss > 4096) /* Allow up to 4K due to dm-crypt support and 4K alignment by the homed LUKS backend */
+ return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Sector size not between 512 and 4096: %s", t);
+ if (!ISPOWEROF2(ss))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Sector size not power of 2: %s", t);
+
+ *ret = ss;
+ return 0;
+}
+
int parse_range(const char *t, unsigned *lower, unsigned *upper) {
_cleanup_free_ char *word = NULL;
unsigned l, u;
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.h b/src/libnm-systemd-shared/src/basic/parse-util.h
index 8d8d52327b..877199529d 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.h
+++ b/src/libnm-systemd-shared/src/basic/parse-util.h
@@ -18,6 +18,7 @@ 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_sector_size(const char *t, uint64_t *ret);
int parse_range(const char *t, unsigned *lower, unsigned *upper);
int parse_errno(const char *t);
diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c
index bf93990fde..40a819d47d 100644
--- a/src/libnm-systemd-shared/src/basic/path-util.c
+++ b/src/libnm-systemd-shared/src/basic/path-util.c
@@ -519,17 +519,17 @@ char* path_extend_internal(char **x, ...) {
va_list ap;
bool slash;
- /* 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.
+ /* 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 the individual strings.
*
* The first argument may be an already allocated string that is extended via realloc() if
* non-NULL. path_extend() and path_join() are macro wrappers around this function, making use of the
* first parameter to distinguish the two operations.
*
- * Note: any listed empty string is simply skipped. This can be useful for concatenating strings of which some
- * are optional.
+ * Note: any listed empty string is simply skipped. This can be useful for concatenating strings of
+ * which some are optional.
*
* Examples:
*
@@ -587,7 +587,7 @@ char* path_extend_internal(char **x, ...) {
}
static int check_x_access(const char *path, int *ret_fd) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
int r;
/* We need to use O_PATH because there may be executables for which we have only exec
@@ -615,7 +615,7 @@ static int check_x_access(const char *path, int *ret_fd) {
}
static int find_executable_impl(const char *name, const char *root, char **ret_filename, int *ret_fd) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
_cleanup_free_ char *path_name = NULL;
int r;
@@ -1164,31 +1164,35 @@ bool path_is_normalized(const char *p) {
return true;
}
-char *file_in_same_dir(const char *path, const char *filename) {
- char *e, *ret;
- size_t k;
+int file_in_same_dir(const char *path, const char *filename, char **ret) {
+ _cleanup_free_ char *b = NULL;
+ int r;
assert(path);
assert(filename);
+ assert(ret);
- /* This removes the last component of path and appends
- * filename, unless the latter is absolute anyway or the
- * former isn't */
+ /* 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);
+ b = strdup(filename);
+ else {
+ _cleanup_free_ char *dn = NULL;
- k = strlen(filename);
- ret = new(char, (e + 1 - path) + k + 1);
- if (!ret)
- return NULL;
+ r = path_extract_directory(path, &dn);
+ if (r == -EDESTADDRREQ) /* no path prefix */
+ b = strdup(filename);
+ else if (r < 0)
+ return r;
+ else
+ b = path_join(dn, filename);
+ }
+ if (!b)
+ return -ENOMEM;
- memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
- return ret;
+ *ret = TAKE_PTR(b);
+ return 0;
}
bool hidden_or_backup_file(const char *filename) {
diff --git a/src/libnm-systemd-shared/src/basic/path-util.h b/src/libnm-systemd-shared/src/basic/path-util.h
index 22d3632e6e..56f01f41d8 100644
--- a/src/libnm-systemd-shared/src/basic/path-util.h
+++ b/src/libnm-systemd-shared/src/basic/path-util.h
@@ -130,6 +130,7 @@ int fsck_exists_for_fstype(const char *fstype);
/* 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. */
+/* DEPRECATED: use path_join() instead */
#define prefix_roota(root, path) \
({ \
const char* _path = (path), *_root = (root), *_ret; \
@@ -169,7 +170,7 @@ static inline bool path_is_safe(const char *p) {
}
bool path_is_normalized(const char *p) _pure_;
-char *file_in_same_dir(const char *path, const char *filename);
+int file_in_same_dir(const char *path, const char *filename, char **ret);
bool hidden_or_backup_file(const char *filename) _pure_;
diff --git a/src/libnm-systemd-shared/src/basic/prioq.c b/src/libnm-systemd-shared/src/basic/prioq.c
index c15dcb26af..7e33561688 100644
--- a/src/libnm-systemd-shared/src/basic/prioq.c
+++ b/src/libnm-systemd-shared/src/basic/prioq.c
@@ -253,7 +253,7 @@ int prioq_remove(Prioq *q, void *data, unsigned *idx) {
return 1;
}
-int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
+void prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
struct prioq_item *i;
unsigned k;
@@ -261,12 +261,11 @@ int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
i = find_item(q, data, idx);
if (!i)
- return 0;
+ return;
k = i - q->items;
k = shuffle_down(q, k);
shuffle_up(q, k);
- return 1;
}
void *prioq_peek_by_index(Prioq *q, unsigned idx) {
diff --git a/src/libnm-systemd-shared/src/basic/prioq.h b/src/libnm-systemd-shared/src/basic/prioq.h
index 508db88026..f66562f387 100644
--- a/src/libnm-systemd-shared/src/basic/prioq.h
+++ b/src/libnm-systemd-shared/src/basic/prioq.h
@@ -18,7 +18,7 @@ int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func);
int prioq_put(Prioq *q, void *data, unsigned *idx);
int prioq_ensure_put(Prioq **q, compare_func_t compare_func, void *data, unsigned *idx);
int prioq_remove(Prioq *q, void *data, unsigned *idx);
-int prioq_reshuffle(Prioq *q, void *data, unsigned *idx);
+void 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) {
diff --git a/src/libnm-systemd-shared/src/basic/process-util.c b/src/libnm-systemd-shared/src/basic/process-util.c
index fb0b38fa49..70aa15f060 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.c
+++ b/src/libnm-systemd-shared/src/basic/process-util.c
@@ -8,7 +8,6 @@
#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>
@@ -22,19 +21,25 @@
#include "alloc-util.h"
#include "architecture.h"
+#include "argv-util.h"
+#include "env-file.h"
#include "env-util.h"
#include "errno-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "hostname-util.h"
#include "locale-util.h"
#include "log.h"
#include "macro.h"
#include "memory-util.h"
#include "missing_sched.h"
#include "missing_syscall.h"
+#include "mountpoint-util.h"
#include "namespace-util.h"
+#include "nulstr-util.h"
+#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "raw-clone.h"
@@ -253,149 +258,45 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
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 container_get_leader(const char *machine, pid_t *pid) {
+ _cleanup_free_ char *s = NULL, *class = NULL;
+ const char *p;
+ pid_t leader;
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");
- }
+ assert(machine);
+ assert(pid);
- 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");
+ if (streq(machine, ".host")) {
+ *pid = 1;
+ return 0;
}
- 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;
- }
+ if (!hostname_is_valid(machine, 0))
+ return -EINVAL;
- /* 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;
- }
+ 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;
- for (int i = 1; i < saved_argc; i++) {
- if (!saved_argv[i])
- break;
+ if (!streq_ptr(class, "container"))
+ return -EIO;
- memzero(saved_argv[i], strlen(saved_argv[i]));
- }
- }
+ r = parse_pid(s, &leader);
+ if (r < 0)
+ return r;
+ if (leader <= 1)
+ return -EIO;
- return !truncated;
+ *pid = leader;
+ return 0;
}
int is_kernel_thread(pid_t pid) {
@@ -864,6 +765,23 @@ void sigterm_wait(pid_t pid) {
(void) wait_for_terminate(pid, NULL);
}
+void sigkill_nowait(pid_t pid) {
+ assert(pid > 1);
+
+ (void) kill(pid, SIGKILL);
+}
+
+void sigkill_nowaitp(pid_t *pid) {
+ PROTECT_ERRNO;
+
+ if (!pid)
+ return;
+ if (*pid <= 1)
+ return;
+
+ sigkill_nowait(*pid);
+}
+
int kill_and_sigcont(pid_t pid, int sig) {
int r;
@@ -1352,15 +1270,26 @@ int safe_fork_full(
}
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_SET(flags, FORK_PRIVATE_TMP)) {
+ assert(FLAGS_SET(flags, FORK_NEW_MOUNTNS));
+
+ /* Optionally, overmount new tmpfs instance on /tmp/. */
+ r = mount_nofollow("tmpfs", "/tmp", "tmpfs",
+ MS_NOSUID|MS_NODEV,
+ "mode=01777" TMPFS_LIMITS_RUN);
+ if (r < 0) {
+ log_full_errno(prio, r, "Failed to overmount /tmp/: %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();
@@ -1372,6 +1301,14 @@ int safe_fork_full(
}
}
+ if (flags & FORK_CLOEXEC_OFF) {
+ r = fd_cloexec_many(except_fds, n_except_fds, false);
+ if (r < 0) {
+ log_full_errno(prio, r, "Failed to turn off O_CLOEXEC on 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();
@@ -1519,6 +1456,20 @@ int pidfd_get_pid(int fd, pid_t *ret) {
return parse_pid(p, ret);
}
+int pidfd_verify_pid(int pidfd, pid_t pid) {
+ pid_t current_pid;
+ int r;
+
+ assert(pidfd >= 0);
+ assert(pid > 0);
+
+ r = pidfd_get_pid(pidfd, &current_pid);
+ if (r < 0)
+ return r;
+
+ return current_pid != pid ? -ESRCH : 0;
+}
+
static int rlimit_to_nice(rlim_t limit) {
if (limit <= 1)
return PRIO_MAX-1; /* i.e. 19 */
@@ -1575,40 +1526,6 @@ int setpriority_closest(int priority) {
return 0;
}
-bool invoked_as(char *argv[], const char *token) {
- if (!argv || isempty(argv[0]))
- return false;
-
- if (isempty(token))
- return false;
-
- return strstr(last_path_component(argv[0]), token);
-}
-
-bool invoked_by_systemd(void) {
- int r;
-
- /* If the process is directly executed by PID1 (e.g. ExecStart= or generator), systemd-importd,
- * or systemd-homed, then $SYSTEMD_EXEC_PID= is set, and read the command line. */
- const char *e = getenv("SYSTEMD_EXEC_PID");
- if (!e)
- return false;
-
- if (streq(e, "*"))
- /* For testing. */
- return true;
-
- pid_t p;
- r = parse_pid(e, &p);
- if (r < 0) {
- /* We know that systemd sets the variable correctly. Something else must have set it. */
- log_debug_errno(r, "Failed to parse \"SYSTEMD_EXEC_PID=%s\", ignoring: %m", e);
- return false;
- }
-
- return getpid_cached() == p;
-}
-
_noreturn_ void freeze(void) {
log_close();
@@ -1630,31 +1547,6 @@ _noreturn_ void freeze(void) {
pause();
}
-bool argv_looks_like_help(int argc, char **argv) {
- char **l;
-
- /* Scans the command line for indications the user asks for help. This is supposed to be called by
- * tools that do not implement getopt() style command line parsing because they are not primarily
- * user-facing. Detects four ways of asking for help:
- *
- * 1. Passing zero arguments
- * 2. Passing "help" as first argument
- * 3. Passing --help as any argument
- * 4. Passing -h as any argument
- */
-
- if (argc <= 1)
- return true;
-
- if (streq_ptr(argv[1], "help"))
- return true;
-
- l = strv_skip(argv, 1);
-
- return strv_contains(l, "--help") ||
- strv_contains(l, "-h");
-}
-
static const char *const sigchld_code_table[] = {
[CLD_EXITED] = "exited",
[CLD_KILLED] = "killed",
diff --git a/src/libnm-systemd-shared/src/basic/process-util.h b/src/libnm-systemd-shared/src/basic/process-util.h
index f8c374a310..96da0bb292 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.h
+++ b/src/libnm-systemd-shared/src/basic/process-util.h
@@ -50,6 +50,8 @@ int get_process_environ(pid_t pid, char **ret);
int get_process_ppid(pid_t pid, pid_t *ret);
int get_process_umask(pid_t pid, mode_t *ret);
+int container_get_leader(const char *machine, pid_t *pid);
+
int wait_for_terminate(pid_t pid, siginfo_t *status);
typedef enum WaitFlags {
@@ -66,10 +68,11 @@ 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);
+void sigkill_nowait(pid_t pid);
+void sigkill_nowaitp(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);
@@ -146,10 +149,12 @@ typedef enum ForkFlags {
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 */
- FORK_FLUSH_STDIO = 1 << 12, /* fflush() stdout (and stderr) before forking */
- FORK_NEW_USERNS = 1 << 13, /* Run child in its own user namespace */
+ FORK_PRIVATE_TMP = 1 << 10, /* Mount new /tmp/ in the child (combine with FORK_NEW_MOUNTNS!) */
+ FORK_RLIMIT_NOFILE_SAFE = 1 << 11, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
+ FORK_STDOUT_TO_STDERR = 1 << 12, /* Make stdout a copy of stderr */
+ FORK_FLUSH_STDIO = 1 << 13, /* fflush() stdout (and stderr) before forking */
+ FORK_NEW_USERNS = 1 << 14, /* Run child in its own user namespace */
+ FORK_CLOEXEC_OFF = 1 << 15, /* In the child: turn off O_CLOEXEC on all fds in except_fds[] */
} ForkFlags;
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
@@ -175,23 +180,12 @@ int get_oom_score_adjust(int *ret);
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 *_ppid_ = &(pid); \
- pid_t _pid_ = *_ppid_; \
- *_ppid_ = 0; \
- _pid_; \
- })
+/* Like TAKE_PTR() but for pid_t, resetting them to 0 */
+#define TAKE_PID(pid) TAKE_GENERIC(pid, pid_t, 0)
int pidfd_get_pid(int fd, pid_t *ret);
+int pidfd_verify_pid(int pidfd, pid_t pid);
int setpriority_closest(int priority);
-bool invoked_as(char *argv[], const char *token);
-
-bool invoked_by_systemd(void);
-
_noreturn_ void freeze(void);
-
-bool argv_looks_like_help(int argc, char **argv);
diff --git a/src/libnm-systemd-shared/src/basic/random-util.c b/src/libnm-systemd-shared/src/basic/random-util.c
index d8734cc7d0..28ace92f19 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.c
+++ b/src/libnm-systemd-shared/src/basic/random-util.c
@@ -75,7 +75,7 @@ static void fallback_random_bytes(void *p, size_t n) {
void random_bytes(void *p, size_t n) {
static bool have_getrandom = true, have_grndinsecure = true;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
if (n == 0)
return;
@@ -117,7 +117,7 @@ void random_bytes(void *p, size_t n) {
int crypto_random_bytes(void *p, size_t n) {
static bool have_getrandom = true, seen_initialized = false;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
if (n == 0)
return 0;
@@ -145,7 +145,7 @@ int crypto_random_bytes(void *p, size_t n) {
}
if (!seen_initialized) {
- _cleanup_close_ int ready_fd = -1;
+ _cleanup_close_ int ready_fd = -EBADF;
int r;
ready_fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
@@ -187,7 +187,7 @@ size_t random_pool_size(void) {
}
int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
- _cleanup_close_ int opened_fd = -1;
+ _cleanup_close_ int opened_fd = -EBADF;
int r;
assert(seed || size == 0);
diff --git a/src/libnm-systemd-shared/src/basic/random-util.h b/src/libnm-systemd-shared/src/basic/random-util.h
index 2d99807272..b1a4d10971 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.h
+++ b/src/libnm-systemd-shared/src/basic/random-util.h
@@ -23,6 +23,7 @@ static inline uint32_t random_u32(void) {
/* Some limits on the pool sizes when we deal with the kernel random pool */
#define RANDOM_POOL_SIZE_MIN 32U
#define RANDOM_POOL_SIZE_MAX (10U*1024U*1024U)
+#define RANDOM_EFI_SEED_SIZE 32U
size_t random_pool_size(void);
diff --git a/src/libnm-systemd-shared/src/basic/ratelimit.c b/src/libnm-systemd-shared/src/basic/ratelimit.c
index c16c8f7103..f90a63b1a9 100644
--- a/src/libnm-systemd-shared/src/basic/ratelimit.c
+++ b/src/libnm-systemd-shared/src/basic/ratelimit.c
@@ -10,6 +10,7 @@
bool ratelimit_below(RateLimit *r) {
usec_t ts;
+ bool good = false;
assert(r);
@@ -24,18 +25,12 @@ bool ratelimit_below(RateLimit *r) {
/* Reset counter */
r->num = 0;
- goto good;
- }
+ good = true;
+ } else if (r->num < r->burst)
+ good = true;
- if (r->num < r->burst)
- goto good;
-
- r->num++;
- return false;
-
-good:
r->num++;
- return true;
+ return good;
}
unsigned ratelimit_num_dropped(RateLimit *r) {
diff --git a/src/libnm-systemd-shared/src/basic/signal-util.c b/src/libnm-systemd-shared/src/basic/signal-util.c
index b61c18b2de..7875ca69bb 100644
--- a/src/libnm-systemd-shared/src/basic/signal-util.c
+++ b/src/libnm-systemd-shared/src/basic/signal-util.c
@@ -5,6 +5,7 @@
#include "errno-util.h"
#include "macro.h"
+#include "missing_syscall.h"
#include "parse-util.h"
#include "signal-util.h"
#include "stdio-util.h"
@@ -282,3 +283,20 @@ int pop_pending_signal_internal(int sig, ...) {
return r; /* Returns the signal popped */
}
+
+void propagate_signal(int sig, siginfo_t *siginfo) {
+ pid_t p;
+
+ /* To be called from a signal handler. Will raise the same signal again, in our process + in our threads.
+ *
+ * Note that we use raw_getpid() instead of getpid_cached(). We might have forked with raw_clone()
+ * earlier (see PID 1), and hence let's go to the raw syscall here. In particular as this is not
+ * performance sensitive code.
+ *
+ * Note that we use kill() rather than raise() as fallback, for similar reasons. */
+
+ p = raw_getpid();
+
+ if (rt_tgsigqueueinfo(p, gettid(), sig, siginfo) < 0)
+ assert_se(kill(p, sig) >= 0);
+}
diff --git a/src/libnm-systemd-shared/src/basic/signal-util.h b/src/libnm-systemd-shared/src/basic/signal-util.h
index 36372c19bd..ad2ba841c6 100644
--- a/src/libnm-systemd-shared/src/basic/signal-util.h
+++ b/src/libnm-systemd-shared/src/basic/signal-util.h
@@ -65,3 +65,5 @@ int signal_is_blocked(int sig);
int pop_pending_signal_internal(int sig, ...);
#define pop_pending_signal(...) pop_pending_signal_internal(__VA_ARGS__, -1)
+
+void propagate_signal(int sig, siginfo_t *siginfo);
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.c b/src/libnm-systemd-shared/src/basic/socket-util.c
index f39be19a59..d7946a3641 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.c
+++ b/src/libnm-systemd-shared/src/basic/socket-util.c
@@ -1049,7 +1049,7 @@ ssize_t receive_one_fd_iov(
if (found)
*ret_fd = *(int*) CMSG_DATA(found);
else
- *ret_fd = -1;
+ *ret_fd = -EBADF;
return k;
}
@@ -1426,7 +1426,7 @@ int socket_get_mtu(int fd, int af, size_t *ret) {
}
int connect_unix_path(int fd, int dir_fd, const char *path) {
- _cleanup_close_ int inode_fd = -1;
+ _cleanup_close_ int inode_fd = -EBADF;
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
@@ -1472,3 +1472,71 @@ int connect_unix_path(int fd, int dir_fd, const char *path) {
return RET_NERRNO(connect(fd, &sa.sa, salen));
}
+
+int socket_address_parse_unix(SocketAddress *ret_address, const char *s) {
+ struct sockaddr_un un;
+ int r;
+
+ assert(ret_address);
+ assert(s);
+
+ if (!IN_SET(*s, '/', '@'))
+ return -EPROTO;
+
+ r = sockaddr_un_set_path(&un, s);
+ if (r < 0)
+ return r;
+
+ *ret_address = (SocketAddress) {
+ .sockaddr.un = un,
+ .size = r,
+ };
+
+ return 0;
+}
+
+int socket_address_parse_vsock(SocketAddress *ret_address, const char *s) {
+ /* AF_VSOCK socket in vsock:cid:port notation */
+ _cleanup_free_ char *n = NULL;
+ char *e, *cid_start;
+ unsigned port, cid;
+ int r;
+
+ assert(ret_address);
+ assert(s);
+
+ cid_start = startswith(s, "vsock:");
+ if (!cid_start)
+ return -EPROTO;
+
+ e = strchr(cid_start, ':');
+ if (!e)
+ return -EINVAL;
+
+ r = safe_atou(e+1, &port);
+ if (r < 0)
+ return r;
+
+ n = strndup(cid_start, e - cid_start);
+ if (!n)
+ return -ENOMEM;
+
+ if (isempty(n))
+ cid = VMADDR_CID_ANY;
+ else {
+ r = safe_atou(n, &cid);
+ if (r < 0)
+ return r;
+ }
+
+ *ret_address = (SocketAddress) {
+ .sockaddr.vm = {
+ .svm_cid = cid,
+ .svm_family = AF_VSOCK,
+ .svm_port = port,
+ },
+ .size = sizeof(struct sockaddr_vm),
+ };
+
+ return 0;
+}
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.h b/src/libnm-systemd-shared/src/basic/socket-util.h
index 2e36e1a56b..5cb35f65fb 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.h
+++ b/src/libnm-systemd-shared/src/basic/socket-util.h
@@ -175,15 +175,17 @@ int flush_accept(int fd);
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
+#define CMSG_TYPED_DATA(cmsg, type) \
+ ({ \
+ struct cmsghdr *_cmsg = cmsg; \
+ _cmsg ? CAST_ALIGN_PTR(type, CMSG_DATA(_cmsg)) : (type*) NULL; \
+ })
+
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); \
- })
+#define CMSG_FIND_DATA(mh, level, type, ctype) \
+ CMSG_TYPED_DATA(cmsg_find(mh, level, type, CMSG_LEN(sizeof(ctype))), ctype)
/* 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"
@@ -334,3 +336,9 @@ int socket_get_mtu(int fd, int af, size_t *ret);
#define UCRED_INVALID { .pid = 0, .uid = UID_INVALID, .gid = GID_INVALID }
int connect_unix_path(int fd, int dir_fd, const char *path);
+
+/* Parses AF_UNIX and AF_VSOCK addresses. AF_INET[6] require some netlink calls, so it cannot be in
+ * src/basic/ and is done from 'socket_local_address from src/shared/. Return -EPROTO in case of
+ * protocol mismatch. */
+int socket_address_parse_unix(SocketAddress *ret_address, const char *s);
+int socket_address_parse_vsock(SocketAddress *ret_address, const char *s);
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c
index 51adaca9d0..700e28f2c2 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.c
+++ b/src/libnm-systemd-shared/src/basic/stat-util.c
@@ -15,6 +15,7 @@
#include "fileio.h"
#include "filesystems.h"
#include "fs-util.h"
+#include "hash-funcs.h"
#include "macro.h"
#include "missing_fs.h"
#include "missing_magic.h"
@@ -64,7 +65,7 @@ int is_device_node(const char *path) {
}
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
struct dirent *buf;
size_t m;
@@ -162,26 +163,37 @@ int null_or_empty_fd(int fd) {
return null_or_empty(&st);
}
-int path_is_read_only_fs(const char *path) {
+static int fd_is_read_only_fs(int fd) {
struct statvfs st;
- assert(path);
+ assert(fd >= 0);
- if (statvfs(path, &st) < 0)
+ if (fstatvfs(fd, &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)
+ /* On NFS, fstatvfs() 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_fd(fd, W_OK) == -EROFS)
return true;
return false;
}
+int path_is_read_only_fs(const char *path) {
+ _cleanup_close_ int fd = -EBADF;
+
+ assert(path);
+
+ fd = open(path, O_CLOEXEC | O_PATH);
+ if (fd < 0)
+ return -errno;
+
+ return fd_is_read_only_fs(fd);
+}
+
int files_same(const char *filea, const char *fileb, int flags) {
struct stat a, b;
@@ -441,3 +453,20 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
return 0;
}
+
+void inode_hash_func(const struct stat *q, struct siphash *state) {
+ siphash24_compress(&q->st_dev, sizeof(q->st_dev), state);
+ siphash24_compress(&q->st_ino, sizeof(q->st_ino), state);
+}
+
+int inode_compare_func(const struct stat *a, const struct stat *b) {
+ int r;
+
+ r = CMP(a->st_dev, b->st_dev);
+ if (r != 0)
+ return r;
+
+ return CMP(a->st_ino, b->st_ino);
+}
+
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops, struct stat, inode_hash_func, inode_compare_func, free);
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.h b/src/libnm-systemd-shared/src/basic/stat-util.h
index f9519d8cbd..de11c0cf7c 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.h
+++ b/src/libnm-systemd-shared/src/basic/stat-util.h
@@ -11,6 +11,7 @@
#include "macro.h"
#include "missing_stat.h"
+#include "siphash24.h"
int is_symlink(const char *path);
int is_dir_full(int atfd, const char *fname, bool follow);
@@ -96,3 +97,7 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
struct new_statx nsx; \
} var
#endif
+
+void inode_hash_func(const struct stat *q, struct siphash *state);
+int inode_compare_func(const struct stat *a, const struct stat *b);
+extern const struct hash_ops inode_hash_ops;
diff --git a/src/libnm-systemd-shared/src/basic/stdio-util.h b/src/libnm-systemd-shared/src/basic/stdio-util.h
index f647f125ac..4e93ac90c9 100644
--- a/src/libnm-systemd-shared/src/basic/stdio-util.h
+++ b/src/libnm-systemd-shared/src/basic/stdio-util.h
@@ -7,15 +7,20 @@
#include <sys/types.h>
#include "macro.h"
-#include "memory-util.h"
-#define snprintf_ok(buf, len, fmt, ...) \
- ({ \
- char *_buf = (buf); \
- size_t _len = (len); \
- int _snpf = snprintf(_buf, _len, (fmt), ##__VA_ARGS__); \
- _snpf >= 0 && (size_t) _snpf < _len ? _buf : NULL; \
- })
+_printf_(3, 4)
+static inline char *snprintf_ok(char *buf, size_t len, const char *format, ...) {
+ va_list ap;
+ int r;
+
+ va_start(ap, format);
+ DISABLE_WARNING_FORMAT_NONLITERAL;
+ r = vsnprintf(buf, len, format, ap);
+ REENABLE_WARNING;
+ va_end(ap);
+
+ return r >= 0 && (size_t) r < len ? buf : NULL;
+}
#define xsprintf(buf, fmt, ...) \
assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, ##__VA_ARGS__), "xsprintf: " #buf "[] must be big enough")
@@ -26,7 +31,7 @@ do { \
size_t _i, _k; \
/* See https://github.com/google/sanitizers/issues/992 */ \
if (HAS_FEATURE_MEMORY_SANITIZER) \
- zero(_argtypes); \
+ memset(_argtypes, 0, sizeof(_argtypes)); \
_k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
assert(_k < ELEMENTSOF(_argtypes)); \
for (_i = 0; _i < _k; _i++) { \
diff --git a/src/libnm-systemd-shared/src/basic/string-util.c b/src/libnm-systemd-shared/src/basic/string-util.c
index 17d35fe1a4..ad8c9863bd 100644
--- a/src/libnm-systemd-shared/src/basic/string-util.c
+++ b/src/libnm-systemd-shared/src/basic/string-util.c
@@ -18,7 +18,6 @@
#include "strv.h"
#include "terminal-util.h"
#include "utf8.h"
-#include "util.h"
char* first_word(const char *s, const char *word) {
size_t sl, wl;
@@ -1188,6 +1187,49 @@ char *string_replace_char(char *str, char old_char, char new_char) {
return str;
}
+int make_cstring(const char *s, size_t n, MakeCStringMode mode, char **ret) {
+ char *b;
+
+ assert(s || n == 0);
+ assert(mode >= 0);
+ assert(mode < _MAKE_CSTRING_MODE_MAX);
+
+ /* Converts a sized character buffer into a NUL-terminated NUL string, refusing if there are embedded
+ * NUL bytes. Whether to expect a trailing NUL byte can be specified via 'mode' */
+
+ if (n == 0) {
+ if (mode == MAKE_CSTRING_REQUIRE_TRAILING_NUL)
+ return -EINVAL;
+
+ if (!ret)
+ return 0;
+
+ b = new0(char, 1);
+ } else {
+ const char *nul;
+
+ nul = memchr(s, 0, n);
+ if (nul) {
+ if (nul < s + n - 1 || /* embedded NUL? */
+ mode == MAKE_CSTRING_REFUSE_TRAILING_NUL)
+ return -EINVAL;
+
+ n--;
+ } else if (mode == MAKE_CSTRING_REQUIRE_TRAILING_NUL)
+ return -EINVAL;
+
+ if (!ret)
+ return 0;
+
+ b = memdup_suffix0(s, n);
+ }
+ if (!b)
+ return -ENOMEM;
+
+ *ret = b;
+ return 0;
+}
+
size_t strspn_from_end(const char *str, const char *accept) {
size_t n = 0;
@@ -1202,3 +1244,19 @@ size_t strspn_from_end(const char *str, const char *accept) {
return n;
}
+
+char *strdupspn(const char *a, const char *accept) {
+ if (isempty(a) || isempty(accept))
+ return strdup("");
+
+ return strndup(a, strspn(a, accept));
+}
+
+char *strdupcspn(const char *a, const char *reject) {
+ if (isempty(a))
+ return strdup("");
+ if (isempty(reject))
+ return strdup(a);
+
+ return strndup(a, strcspn(a, reject));
+}
diff --git a/src/libnm-systemd-shared/src/basic/string-util.h b/src/libnm-systemd-shared/src/basic/string-util.h
index 46681ced99..e0a47a21a9 100644
--- a/src/libnm-systemd-shared/src/basic/string-util.h
+++ b/src/libnm-systemd-shared/src/basic/string-util.h
@@ -53,9 +53,13 @@ static inline const char* enable_disable(bool b) {
return b ? "enable" : "disable";
}
-static inline const char *empty_to_null(const char *p) {
- return isempty(p) ? NULL : p;
-}
+/* This macro's return pointer will have the "const" qualifier set or unset the same way as the input
+ * pointer. */
+#define empty_to_null(p) \
+ ({ \
+ const char *_p = (p); \
+ (typeof(p)) (isempty(_p) ? NULL : _p); \
+ })
static inline const char *empty_to_na(const char *p) {
return isempty(p) ? "n/a" : p;
@@ -74,6 +78,11 @@ static inline bool empty_or_dash(const char *str) {
static inline const char *empty_or_dash_to_null(const char *p) {
return empty_or_dash(p) ? NULL : p;
}
+#define empty_or_dash_to_null(p) \
+ ({ \
+ const char *_p = (p); \
+ (typeof(p)) (empty_or_dash(_p) ? NULL : _p); \
+ })
char *first_word(const char *s, const char *word) _pure_;
@@ -230,4 +239,17 @@ bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok);
char *string_replace_char(char *str, char old_char, char new_char);
+typedef enum MakeCStringMode {
+ MAKE_CSTRING_REFUSE_TRAILING_NUL,
+ MAKE_CSTRING_ALLOW_TRAILING_NUL,
+ MAKE_CSTRING_REQUIRE_TRAILING_NUL,
+ _MAKE_CSTRING_MODE_MAX,
+ _MAKE_CSTRING_MODE_INVALID = -1,
+} MakeCStringMode;
+
+int make_cstring(const char *s, size_t n, MakeCStringMode mode, char **ret);
+
size_t strspn_from_end(const char *str, const char *accept);
+
+char *strdupspn(const char *a, const char *accept);
+char *strdupcspn(const char *a, const char *reject);
diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c
index eea34ca68d..2b7a61d442 100644
--- a/src/libnm-systemd-shared/src/basic/strv.c
+++ b/src/libnm-systemd-shared/src/basic/strv.c
@@ -623,121 +623,6 @@ char** strv_remove(char **l, const char *s) {
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.
- */
-
- size_t c = 0, i = 0;
- char **v;
-
- assert(s || l <= 0);
-
- if (l <= 0)
- return new0(char*, 1);
-
- for (const char *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;
-
- for (const char *p = s; 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;
-}
-
-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;
-}
-
-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.
- */
-
- _cleanup_free_ char *m = NULL;
- size_t n = 0;
-
- assert(ret);
- assert(ret_size);
-
- STRV_FOREACH(i, l) {
- size_t z;
-
- z = strlen(*i);
-
- if (!GREEDY_REALLOC(m, 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) {
STRV_FOREACH(i, a)
if (strv_contains(b, *i))
@@ -904,6 +789,22 @@ rollback:
return -ENOMEM;
}
+int strv_extend_assignment(char ***l, const char *lhs, const char *rhs) {
+ char *j;
+
+ assert(l);
+ assert(lhs);
+
+ if (!rhs) /* value is optional, in which case we suppress the field */
+ return 0;
+
+ j = strjoin(lhs, "=", rhs);
+ if (!j)
+ return -ENOMEM;
+
+ return strv_consume(l, j);
+}
+
int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
bool b = false;
int r;
diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h
index d6f5ac6ba5..1f8da85fcc 100644
--- a/src/libnm-systemd-shared/src/basic/strv.h
+++ b/src/libnm-systemd-shared/src/basic/strv.h
@@ -45,7 +45,7 @@ static inline int strv_extend(char ***l, const char *value) {
return strv_extend_with_size(l, NULL, value);
}
-int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
+int strv_extendf(char ***l, const char *format, ...) _printf_(2,3);
int strv_extend_front(char ***l, const char *value);
int strv_push_with_size(char ***l, size_t *n, char *value);
@@ -124,20 +124,6 @@ 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_BACKWARDS(s, l, h, i) \
@@ -255,6 +241,8 @@ char** strv_skip(char **l, size_t n);
int strv_extend_n(char ***l, const char *value, size_t n);
+int strv_extend_assignment(char ***l, const char *lhs, const char *rhs);
+
int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
#define strv_free_and_replace(a, b) \
diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c
index 71b2f67350..b700f364ef 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.c
+++ b/src/libnm-systemd-shared/src/basic/time-util.c
@@ -308,54 +308,48 @@ char *format_timestamp_style(
};
struct tm tm;
+ bool utc, us;
time_t sec;
size_t n;
- bool utc = false, us = false;
- int r;
assert(buf);
+ assert(style >= 0);
+ assert(style < _TIMESTAMP_STYLE_MAX);
- switch (style) {
- case TIMESTAMP_PRETTY:
- case TIMESTAMP_UNIX:
- 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 (!timestamp_is_set(t))
return NULL; /* Timestamp is unset */
if (style == TIMESTAMP_UNIX) {
- r = snprintf(buf, l, "@" USEC_FMT, t / USEC_PER_SEC); /* round down µs → s */
- if (r < 0 || (size_t) r >= l)
- return NULL; /* Doesn't fit */
+ if (l < (size_t) (1 + 1 + 1))
+ return NULL; /* not enough space for even the shortest of forms */
- return buf;
+ return snprintf_ok(buf, l, "@" USEC_FMT, t / USEC_PER_SEC); /* round down µs → s */
}
+ utc = IN_SET(style, TIMESTAMP_UTC, TIMESTAMP_US_UTC, TIMESTAMP_DATE);
+ us = IN_SET(style, TIMESTAMP_US, TIMESTAMP_US_UTC);
+
+ if (l < (size_t) (3 + /* week day */
+ 1 + 10 + /* space and date */
+ style == TIMESTAMP_DATE ? 0 :
+ (1 + 8 + /* space and time */
+ (us ? 1 + 6 : 0) + /* "." and microsecond part */
+ 1 + (utc ? 3 : 1)) + /* space and shortest possible zone */
+ 1))
+ return NULL; /* Not enough space even for the shortest form. */
+
/* 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;
+ static const char* const xxx[_TIMESTAMP_STYLE_MAX] = {
+ [TIMESTAMP_PRETTY] = "--- XXXX-XX-XX XX:XX:XX",
+ [TIMESTAMP_US] = "--- XXXX-XX-XX XX:XX:XX.XXXXXX",
+ [TIMESTAMP_UTC] = "--- XXXX-XX-XX XX:XX:XX UTC",
+ [TIMESTAMP_US_UTC] = "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC",
+ [TIMESTAMP_DATE] = "--- XXXX-XX-XX",
+ };
+
+ assert(l >= strlen(xxx[style]) + 1);
+ return strcpy(buf, xxx[style]);
}
sec = (time_t) (t / USEC_PER_SEC); /* Round down */
@@ -367,6 +361,14 @@ char *format_timestamp_style(
assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays));
memcpy(buf, weekdays[tm.tm_wday], 4);
+ if (style == TIMESTAMP_DATE) {
+ /* Special format string if only date should be shown. */
+ if (strftime(buf + 3, l - 3, " %Y-%m-%d", &tm) <= 0)
+ return NULL; /* Doesn't fit */
+
+ return buf;
+ }
+
/* Add the main components */
if (strftime(buf + 3, l - 3, " %Y-%m-%d %H:%M:%S", &tm) <= 0)
return NULL; /* Doesn't fit */
@@ -1395,7 +1397,7 @@ int get_timezones(char ***ret) {
int verify_timezone(const char *name, int log_level) {
bool slash = false;
const char *p, *t;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
char buf[4];
int r;
@@ -1568,7 +1570,7 @@ int time_change_fd(void) {
.it_value.tv_sec = TIME_T_MAX,
};
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
diff --git a/src/libnm-systemd-shared/src/basic/time-util.h b/src/libnm-systemd-shared/src/basic/time-util.h
index c98f95a530..c5ae0c98d4 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.h
+++ b/src/libnm-systemd-shared/src/basic/time-util.h
@@ -35,6 +35,7 @@ typedef enum TimestampStyle {
TIMESTAMP_UTC,
TIMESTAMP_US_UTC,
TIMESTAMP_UNIX,
+ TIMESTAMP_DATE,
_TIMESTAMP_STYLE_MAX,
_TIMESTAMP_STYLE_INVALID = -EINVAL,
} TimestampStyle;
diff --git a/src/libnm-systemd-shared/src/basic/tmpfile-util.c b/src/libnm-systemd-shared/src/basic/tmpfile-util.c
index 34d3016ba9..95adf9d374 100644
--- a/src/libnm-systemd-shared/src/basic/tmpfile-util.c
+++ b/src/libnm-systemd-shared/src/basic/tmpfile-util.c
@@ -19,29 +19,15 @@
#include "tmpfile-util.h"
#include "umask-util.h"
-int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) {
+static int fopen_temporary_internal(int dir_fd, const char *path, FILE **ret_file) {
_cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *t = NULL;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
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;
- }
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+ assert(path);
- fd = mkostemp_safe(t);
+ fd = openat(dir_fd, path, O_CLOEXEC|O_NOCTTY|O_RDWR|O_CREAT|O_EXCL, 0600);
if (fd < 0)
return -errno;
@@ -50,15 +36,59 @@ int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) {
r = take_fdopen_unlocked(&fd, "w", &f);
if (r < 0) {
- (void) unlink(t);
+ (void) unlinkat(dir_fd, path, 0);
return r;
}
- if (ret_f)
- *ret_f = TAKE_PTR(f);
+ if (ret_file)
+ *ret_file = TAKE_PTR(f);
+
+ return 0;
+}
+
+int fopen_temporary_at(int dir_fd, const char *path, FILE **ret_file, char **ret_path) {
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+ assert(path);
+
+ r = tempfn_random(path, NULL, &t);
+ if (r < 0)
+ return r;
+
+ r = fopen_temporary_internal(dir_fd, t, ret_file);
+ if (r < 0)
+ return r;
+
+ if (ret_path)
+ *ret_path = TAKE_PTR(t);
+
+ return 0;
+}
+
+int fopen_temporary_child_at(int dir_fd, const char *path, FILE **ret_file, char **ret_path) {
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+
+ if (!path) {
+ r = tmp_dir(&path);
+ if (r < 0)
+ return r;
+ }
+
+ r = tempfn_random_child(path, NULL, &t);
+ if (r < 0)
+ return r;
+
+ r = fopen_temporary_internal(dir_fd, t, ret_file);
+ if (r < 0)
+ return r;
- if (ret_temp_path)
- *ret_temp_path = TAKE_PTR(t);
+ if (ret_path)
+ *ret_path = TAKE_PTR(t);
return 0;
}
@@ -71,7 +101,7 @@ int mkostemp_safe(char *pattern) {
}
int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
FILE *f;
fd = mkostemp_safe(pattern);
@@ -279,7 +309,7 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE **ret_file) {
_cleanup_free_ char *path = NULL;
_cleanup_fclose_ FILE *f = NULL;
- _cleanup_close_ int fd = -1;
+ _cleanup_close_ int fd = -EBADF;
assert(target);
assert(ret_file);
@@ -358,3 +388,23 @@ int mkdtemp_malloc(const char *template, char **ret) {
*ret = TAKE_PTR(p);
return 0;
}
+
+int mkdtemp_open(const char *template, int flags, char **ret) {
+ _cleanup_free_ char *p = NULL;
+ int fd, r;
+
+ r = mkdtemp_malloc(template, &p);
+ if (r < 0)
+ return r;
+
+ fd = RET_NERRNO(open(p, O_DIRECTORY|O_CLOEXEC|flags));
+ if (fd < 0) {
+ (void) rmdir(p);
+ return fd;
+ }
+
+ if (ret)
+ *ret = TAKE_PTR(p);
+
+ return fd;
+}
diff --git a/src/libnm-systemd-shared/src/basic/tmpfile-util.h b/src/libnm-systemd-shared/src/basic/tmpfile-util.h
index 610cbaf87e..e5b7709e3f 100644
--- a/src/libnm-systemd-shared/src/basic/tmpfile-util.h
+++ b/src/libnm-systemd-shared/src/basic/tmpfile-util.h
@@ -1,9 +1,19 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <fcntl.h>
#include <stdio.h>
-int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
+int fopen_temporary_at(int dir_fd, const char *path, FILE **ret_file, char **ret_path);
+static inline int fopen_temporary(const char *path, FILE **ret_file, char **ret_path) {
+ return fopen_temporary_at(AT_FDCWD, path, ret_file, ret_path);
+}
+
+int fopen_temporary_child_at(int dir_fd, const char *path, FILE **ret_file, char **ret_path);
+static inline int fopen_temporary_child(const char *path, FILE **ret_file, char **ret_path) {
+ return fopen_temporary_child_at(AT_FDCWD, path, ret_file, ret_path);
+}
+
int mkostemp_safe(char *pattern);
int fmkostemp_safe(char *pattern, const char *mode, FILE**_f);
@@ -19,3 +29,4 @@ int link_tmpfile(int fd, const char *path, const char *target);
int flink_tmpfile(FILE *f, const char *path, const char *target);
int mkdtemp_malloc(const char *template, char **ret);
+int mkdtemp_open(const char *template, int flags, char **ret);
diff --git a/src/libnm-systemd-shared/src/basic/umask-util.h b/src/libnm-systemd-shared/src/basic/umask-util.h
index 90d18f70ba..6f0e1cc2b2 100644
--- a/src/libnm-systemd-shared/src/basic/umask-util.h
+++ b/src/libnm-systemd-shared/src/basic/umask-util.h
@@ -15,12 +15,12 @@ static inline void umaskp(mode_t *u) {
/* 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. */
+ * distinguish the first and the second iteration of the 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) \
+#define 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/src/libnm-systemd-shared/src/basic/util.c b/src/libnm-systemd-shared/src/basic/util.c
deleted file mode 100644
index d7ef382737..0000000000
--- a/src/libnm-systemd-shared/src/basic/util.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#include "alloc-util.h"
-#include "build.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"
-
-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) {
- int r;
- const char *e;
- bool lenient = false;
-
- if (saved_in_initrd >= 0)
- return saved_in_initrd;
-
- /* We have 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.
- *
- * If env var $SYSTEMD_IN_INITRD is not set or set to "auto",
- * both checks are used. If it's set to "lenient", only check
- * 1 is used. If set to a boolean value, then the boolean
- * value is returned.
- */
-
- e = secure_getenv("SYSTEMD_IN_INITRD");
- if (e) {
- if (streq(e, "lenient"))
- lenient = true;
- else if (!streq(e, "auto")) {
- r = parse_boolean(e);
- if (r >= 0) {
- saved_in_initrd = r > 0;
- return saved_in_initrd;
- }
- log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
- }
- }
-
- if (!lenient) {
- r = path_is_temporary_fs("/");
- if (r < 0)
- log_debug_errno(r, "Couldn't determine if / is a temporary file system: %m");
-
- saved_in_initrd = r > 0;
- }
-
- r = access("/etc/initrd-release", F_OK);
- if (r >= 0) {
- if (saved_in_initrd == 0)
- log_debug("/etc/initrd-release exists, but it's not an initrd.");
- else
- saved_in_initrd = 1;
- } else {
- if (errno != ENOENT)
- log_debug_errno(errno, "Failed to test if /etc/initrd-release exists: %m");
- saved_in_initrd = 0;
- }
-
- return saved_in_initrd;
-}
-
-void in_initrd_force(bool value) {
- saved_in_initrd = value;
-}
-
-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;
-}
-
-/* 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");
-}
diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
index 2536c741c6..c4ad957588 100644
--- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
+++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#ifndef SD_BOOT
+#if !SD_BOOT
# include <assert.h>
#endif
@@ -20,6 +20,7 @@
#define _hidden_ __attribute__((__visibility__("hidden")))
#define _likely_(x) (__builtin_expect(!!(x), 1))
#define _malloc_ __attribute__((__malloc__))
+#define _noinline_ __attribute__((noinline))
#define _noreturn_ _Noreturn
#define _packed_ __attribute__((__packed__))
#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
@@ -66,18 +67,18 @@
#define XCONCATENATE(x, y) x ## y
#define CONCATENATE(x, y) XCONCATENATE(x, y)
-#ifdef SD_BOOT
+#if SD_BOOT
_noreturn_ void efi_assert(const char *expr, const char *file, unsigned line, const char *function);
#ifdef NDEBUG
#define assert(expr)
#define assert_not_reached() __builtin_unreachable()
#else
- #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
- #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); })
+ #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __func__)
#endif
#define static_assert _Static_assert
- #define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
+ #define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __func__); })
#endif
/* This passes the argument through after (if asserts are enabled) checking that it is not null. */
@@ -251,47 +252,44 @@
(UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \
})
-#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 CASE_F_1(X) case X:
+#define CASE_F_2(X, ...) case X: CASE_F_1( __VA_ARGS__)
+#define CASE_F_3(X, ...) case X: CASE_F_2( __VA_ARGS__)
+#define CASE_F_4(X, ...) case X: CASE_F_3( __VA_ARGS__)
+#define CASE_F_5(X, ...) case X: CASE_F_4( __VA_ARGS__)
+#define CASE_F_6(X, ...) case X: CASE_F_5( __VA_ARGS__)
+#define CASE_F_7(X, ...) case X: CASE_F_6( __VA_ARGS__)
+#define CASE_F_8(X, ...) case X: CASE_F_7( __VA_ARGS__)
+#define CASE_F_9(X, ...) case X: CASE_F_8( __VA_ARGS__)
+#define CASE_F_10(X, ...) case X: CASE_F_9( __VA_ARGS__)
+#define CASE_F_11(X, ...) case X: CASE_F_10( __VA_ARGS__)
+#define CASE_F_12(X, ...) case X: CASE_F_11( __VA_ARGS__)
+#define CASE_F_13(X, ...) case X: CASE_F_12( __VA_ARGS__)
+#define CASE_F_14(X, ...) case X: CASE_F_13( __VA_ARGS__)
+#define CASE_F_15(X, ...) case X: CASE_F_14( __VA_ARGS__)
+#define CASE_F_16(X, ...) case X: CASE_F_15( __VA_ARGS__)
+#define CASE_F_17(X, ...) case X: CASE_F_16( __VA_ARGS__)
+#define CASE_F_18(X, ...) case X: CASE_F_17( __VA_ARGS__)
+#define CASE_F_19(X, ...) case X: CASE_F_18( __VA_ARGS__)
+#define CASE_F_20(X, ...) case X: CASE_F_19( __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__)
+ (__VA_ARGS__)
-#define IN_SET(x, ...) \
+#define IN_SET(x, first, ...) \
({ \
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__ }; \
+ /* If the build breaks in the line below, you need to extend the case macros. We use typeof(+x) \
+ * here to widen the type of x if it is a bit-field as this would otherwise be illegal. */ \
+ static const typeof(+x) __assert_in_set[] _unused_ = { first, __VA_ARGS__ }; \
assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
switch (x) { \
- FOR_EACH_MAKE_CASE(__VA_ARGS__) \
+ FOR_EACH_MAKE_CASE(first, __VA_ARGS__) \
_found = true; \
- break; \
+ break; \
default: \
break; \
} \
@@ -300,13 +298,18 @@
/* 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) *_pptr_ = &(ptr); \
- typeof(ptr) _ptr_ = *_pptr_; \
- *_pptr_ = NULL; \
- _ptr_; \
+#define TAKE_GENERIC(var, type, nullvalue) \
+ ({ \
+ type *_pvar_ = &(var); \
+ type _var_ = *_pvar_; \
+ type _nullvalue_ = nullvalue; \
+ *_pvar_ = _nullvalue_; \
+ _var_; \
})
+#define TAKE_PTR_TYPE(ptr, type) TAKE_GENERIC(ptr, type, NULL)
+#define TAKE_PTR(ptr) TAKE_PTR_TYPE(ptr, typeof(ptr))
+#define TAKE_STRUCT_TYPE(s, type) TAKE_GENERIC(s, type, {})
+#define TAKE_STRUCT(s) TAKE_STRUCT_TYPE(s, typeof(s))
/*
* STRLEN - return the length of a string literal, minus the trailing NUL byte.
@@ -330,14 +333,23 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
return ((l + ali - 1) & ~(ali - 1));
}
+#define ALIGN2(l) ALIGN_TO(l, 2)
#define ALIGN4(l) ALIGN_TO(l, 4)
#define ALIGN8(l) ALIGN_TO(l, 8)
-#ifndef SD_BOOT
+#define ALIGN2_PTR(p) ((void*) ALIGN2((uintptr_t) p))
+#define ALIGN4_PTR(p) ((void*) ALIGN4((uintptr_t) p))
+#define ALIGN8_PTR(p) ((void*) ALIGN8((uintptr_t) p))
+#if !SD_BOOT
/* libefi also provides ALIGN, and we do not use them in sd-boot explicitly. */
#define ALIGN(l) ALIGN_TO(l, sizeof(void*))
#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p)))
#endif
+/* Checks if the specified pointer is aligned as appropriate for the specific type */
+#define IS_ALIGNED16(p) (((uintptr_t) p) % __alignof__(uint16_t) == 0)
+#define IS_ALIGNED32(p) (((uintptr_t) p) % __alignof__(uint32_t) == 0)
+#define IS_ALIGNED64(p) (((uintptr_t) p) % __alignof__(uint64_t) == 0)
+
/* Same as ALIGN_TO but callable in constant contexts. */
#define CONST_ALIGN_TO(l, ali) \
__builtin_choose_expr( \
@@ -348,9 +360,31 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
((l) + (ali) - 1) & ~((ali) - 1), \
VOID_0)
+/* Similar to ((t *) (void *) (p)) to cast a pointer. The macro asserts that the pointer has a suitable
+ * alignment for type "t". This exists for places where otherwise "-Wcast-align=strict" would issue a
+ * warning or if you want to assert that the cast gives a pointer of suitable alignment. */
+#define CAST_ALIGN_PTR(t, p) \
+ ({ \
+ const void *_p = (p); \
+ assert(((uintptr_t) _p) % __alignof__(t) == 0); \
+ (t *) _p; \
+ })
+
#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)
+
+/* Declare a flexible array usable in a union.
+ * This is essentially a work-around for a pointless constraint in C99
+ * and might go away in some future version of the standard.
+ *
+ * See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=3080ea5553cc909b000d1f1d964a9041962f2c5b
+ */
+#define DECLARE_FLEX_ARRAY(type, name) \
+ struct { \
+ dummy_t __empty__ ## name; \
+ type name[]; \
+ }
diff --git a/src/libnm-systemd-shared/src/fundamental/memory-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/memory-util-fundamental.h
new file mode 100644
index 0000000000..78e2dbec59
--- /dev/null
+++ b/src/libnm-systemd-shared/src/fundamental/memory-util-fundamental.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stddef.h>
+
+#if SD_BOOT
+# include "efi-string.h"
+#else
+# include <string.h>
+#endif
+
+#include "macro-fundamental.h"
+
+#if !SD_BOOT && HAVE_EXPLICIT_BZERO
+static inline void *explicit_bzero_safe(void *p, size_t l) {
+ if (p && l > 0)
+ explicit_bzero(p, l);
+
+ return p;
+}
+#else
+static inline void *explicit_bzero_safe(void *p, size_t l) {
+ if (p && l > 0) {
+ memset(p, 0, l);
+ __asm__ __volatile__("" : : "r"(p) : "memory");
+ }
+ return p;
+}
+#endif
+
+struct VarEraser {
+ /* NB: This is a pointer to memory to erase in case of CLEANUP_ERASE(). Pointer to pointer to memory
+ * to erase in case of CLEANUP_ERASE_PTR() */
+ void *p;
+ size_t size;
+};
+
+static inline void erase_var(struct VarEraser *e) {
+ explicit_bzero_safe(e->p, e->size);
+}
+
+/* Mark var to be erased when leaving scope. */
+#define CLEANUP_ERASE(var) \
+ _cleanup_(erase_var) _unused_ struct VarEraser CONCATENATE(_eraser_, UNIQ) = { \
+ .p = &(var), \
+ .size = sizeof(var), \
+ }
+
+static inline void erase_varp(struct VarEraser *e) {
+
+ /* Very similar to erase_var(), but assumes `p` is a pointer to a pointer whose memory shall be destructed. */
+ if (!e->p)
+ return;
+
+ explicit_bzero_safe(*(void**) e->p, e->size);
+}
+
+/* Mark pointer so that memory pointed to is erased when leaving scope. Note: this takes a pointer to the
+ * specified pointer, instead of just a copy of it. This is to allow callers to invalidate the pointer after
+ * use, if they like, disabling our automatic erasure (for example because they succeeded with whatever they
+ * wanted to do and now intend to return the allocated buffer to their caller without it being erased). */
+#define CLEANUP_ERASE_PTR(ptr, sz) \
+ _cleanup_(erase_varp) _unused_ struct VarEraser CONCATENATE(_eraser_, UNIQ) = { \
+ .p = (ptr), \
+ .size = (sz), \
+ }
diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.c b/src/libnm-systemd-shared/src/fundamental/sha256.c
index 9b717645b3..4389e9e37c 100644
--- a/src/libnm-systemd-shared/src/fundamental/sha256.c
+++ b/src/libnm-systemd-shared/src/fundamental/sha256.c
@@ -22,7 +22,7 @@
<https://www.gnu.org/licenses/>. */
#include <stdbool.h>
-#ifdef SD_BOOT
+#if SD_BOOT
# include "efi-string.h"
#else
# include <string.h>
@@ -30,6 +30,7 @@
#include "macro-fundamental.h"
#include "sha256.h"
+#include "unaligned-fundamental.h"
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define SWAP(n) \
@@ -48,14 +49,6 @@
# define SWAP64(n) (n)
#endif
-/* The condition below is from glibc's string/string-inline.c.
- * See definition of _STRING_INLINE_unaligned. */
-#if !defined(__mc68020__) && !defined(__s390__) && !defined(__i386__)
-# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__(uint32_t) != 0)
-#else
-# define UNALIGNED_P(p) false
-#endif
-
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (FIPS 180-2:5.1.1) */
static const uint8_t fillbuf[64] = {
@@ -128,11 +121,7 @@ uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_
/* Put result from CTX in first 32 bytes following RESBUF. */
for (size_t i = 0; i < 8; ++i)
- if (UNALIGNED_P(resbuf))
- memcpy(resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t));
- else
- ((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]);
-
+ unaligned_write_ne32(resbuf + i * sizeof(uint32_t), SWAP(ctx->H[i]));
return resbuf;
}
@@ -165,18 +154,17 @@ void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx
/* Process available complete blocks. */
if (len >= 64) {
- if (UNALIGNED_P(buffer))
+ if (IS_ALIGNED32(buffer)) {
+ sha256_process_block(buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ } else
while (len > 64) {
memcpy(ctx->buffer, buffer, 64);
sha256_process_block(ctx->buffer, 64, ctx);
buffer = (const char *) buffer + 64;
len -= 64;
}
- else {
- sha256_process_block(buffer, len & ~63, ctx);
- buffer = (const char *) buffer + (len & ~63);
- len &= 63;
- }
}
/* Move remaining bytes into internal buffer. */
diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.h b/src/libnm-systemd-shared/src/fundamental/sha256.h
index 31790c2ebd..dbb08e35e5 100644
--- a/src/libnm-systemd-shared/src/fundamental/sha256.h
+++ b/src/libnm-systemd-shared/src/fundamental/sha256.h
@@ -1,7 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#include "stdint.h"
+#include <stddef.h>
+#include <stdint.h>
#define SHA256_DIGEST_SIZE 32
@@ -28,6 +29,11 @@ void sha256_init_ctx(struct sha256_ctx *ctx);
uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]);
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx);
+static inline void sha256_process_bytes_and_size(const void *buffer, size_t len, struct sha256_ctx *ctx) {
+ sha256_process_bytes(&len, sizeof(len), ctx);
+ sha256_process_bytes(buffer, len, ctx);
+}
+
uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]);
#define SHA256_DIRECT(buffer, sz) sha256_direct(buffer, sz, (uint8_t[SHA256_DIGEST_SIZE]) {})
diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
index 11701ebe52..484131d72a 100644
--- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
+++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#ifndef SD_BOOT
+#if !SD_BOOT
# include <ctype.h>
#endif
@@ -20,7 +20,7 @@ sd_char *startswith(const sd_char *s, const sd_char *prefix) {
return (sd_char*) s + l;
}
-#ifndef SD_BOOT
+#if !SD_BOOT
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) {
size_t l;
diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
index ecf32e519f..c35ce5b88f 100644
--- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
+++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#ifdef SD_BOOT
+#if SD_BOOT
# include <efi.h>
# include <efilib.h>
# include "efi-string.h"
@@ -11,7 +11,7 @@
#include "macro-fundamental.h"
-#ifdef SD_BOOT
+#if SD_BOOT
# define strlen strlen16
# define strcmp strcmp16
# define strncmp strncmp16
@@ -59,7 +59,7 @@ static inline size_t strlen_ptr(const sd_char *s) {
}
sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_;
-#ifndef SD_BOOT
+#if !SD_BOOT
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_;
#endif
sd_char *endswith(const sd_char *s, const sd_char *postfix) _pure_;
@@ -110,6 +110,10 @@ static inline bool ascii_isdigit(sd_char a) {
return a >= '0' && a <= '9';
}
+static inline bool ascii_ishex(sd_char a) {
+ return ascii_isdigit(a) || (a >= 'a' && a <= 'f') || (a >= 'A' && a <= 'F');
+}
+
static inline bool ascii_isalpha(sd_char a) {
/* A pure ASCII, locale independent version of isalpha() */
return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.c b/src/libnm-systemd-shared/src/shared/dns-domain.c
index ebf86d2405..620b156563 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.c
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.c
@@ -297,7 +297,6 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) {
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;
@@ -314,7 +313,7 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
if (encoded_size <= 0)
return -EINVAL;
- for (p = encoded; p < encoded + encoded_size; p++)
+ for (const char *p = encoded; p < encoded + encoded_size; p++)
if ((uint8_t) *p > 127)
contains_8bit = true;
@@ -527,7 +526,18 @@ int dns_name_compare_func(const char *a, const char *b) {
}
}
-DEFINE_HASH_OPS(dns_name_hash_ops, char, dns_name_hash_func, dns_name_compare_func);
+DEFINE_HASH_OPS(
+ dns_name_hash_ops,
+ char,
+ dns_name_hash_func,
+ dns_name_compare_func);
+
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+ dns_name_hash_ops_free,
+ char,
+ dns_name_hash_func,
+ dns_name_compare_func,
+ free);
int dns_name_equal(const char *x, const char *y) {
int r, q;
@@ -745,9 +755,8 @@ int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_ad
return r;
if (r > 0) {
uint8_t a[4];
- unsigned i;
- for (i = 0; i < ELEMENTSOF(a); i++) {
+ for (size_t i = 0; i < ELEMENTSOF(a); i++) {
char label[DNS_LABEL_MAX+1];
r = dns_label_unescape(&p, label, sizeof label, 0);
@@ -781,9 +790,8 @@ int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_ad
return r;
if (r > 0) {
struct in6_addr a;
- unsigned i;
- for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
+ for (size_t i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
char label[DNS_LABEL_MAX+1];
int x, y;
@@ -824,7 +832,6 @@ int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_ad
}
bool dns_name_is_root(const char *name) {
-
assert(name);
/* There are exactly two ways to encode the root domain name:
@@ -895,8 +902,6 @@ int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, boo
}
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 */
@@ -910,12 +915,11 @@ static bool srv_type_label_is_valid(const char *label, size_t n) {
return false;
/* Third and further chars must be alphanumeric or a hyphen */
- for (k = 2; k < n; k++) {
+ for (size_t k = 2; k < n; k++)
if (!ascii_isalpha(label[k]) &&
!ascii_isdigit(label[k]) &&
label[k] != '-')
return false;
- }
return true;
}
@@ -1111,14 +1115,12 @@ finish:
}
static int dns_name_build_suffix_table(const char *name, const char *table[]) {
- const char *p;
+ const char *p = ASSERT_PTR(name);
unsigned n = 0;
int r;
- assert(name);
assert(table);
- p = name;
for (;;) {
if (n > DNS_N_LABELS_MAX)
return -EINVAL;
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.h b/src/libnm-systemd-shared/src/shared/dns-domain.h
index 5421c60ee7..331fb89637 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.h
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.h
@@ -60,13 +60,10 @@ static inline int dns_name_is_valid_ldh(const char *s) {
return 1;
}
-static inline bool dns_name_is_empty(const char *s) {
- return isempty(s) || streq(s, ".");
-}
-
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;
+extern const struct hash_ops dns_name_hash_ops_free;
int dns_name_between(const char *a, const char *b, const char *c);
int dns_name_equal(const char *x, const char *y);