summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-03-29 19:11:27 +0200
committerThomas Haller <thaller@redhat.com>2021-03-30 14:20:06 +0200
commit7935c1104455f444890ac35caede2c14c8fba485 (patch)
treec147dd1c9233ceecbd4837f51794579ec9ffda65
parentbd7a21e09900914c9f1b59f5e27821450d0c7369 (diff)
downloadNetworkManager-7935c1104455f444890ac35caede2c14c8fba485.tar.gz
systemd: update code from upstream (2021-03-30)
This is a direct dump from systemd git. ====== SYSTEMD_DIR=../systemd COMMIT=119063d2b149667a91e0e08e4bdf82a0eb6a7efd ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files -z :/src/core/systemd/src/ \ :/src/libnm-systemd-shared/src/ \ :/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/core/systemd/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/core/systemd/$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/arp-util.c" nm_copy_sd_core "src/libsystemd-network/arp-util.h" 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/dhcp-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp-option.c" nm_copy_sd_core "src/libsystemd-network/dhcp-packet.c" nm_copy_sd_core "src/libsystemd-network/dhcp-protocol.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-protocol.h" nm_copy_sd_core "src/libsystemd-network/lldp-internal.h" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.c" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.h" nm_copy_sd_core "src/libsystemd-network/lldp-network.c" nm_copy_sd_core "src/libsystemd-network/lldp-network.h" nm_copy_sd_core "src/libsystemd-network/network-internal.c" nm_copy_sd_core "src/libsystemd-network/network-internal.h" nm_copy_sd_core "src/libsystemd-network/sd-dhcp-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp-lease.c" 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-network/sd-ipv4acd.c" nm_copy_sd_core "src/libsystemd-network/sd-ipv4ll.c" nm_copy_sd_core "src/libsystemd-network/sd-lldp.c" 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-dhcp-client.h" nm_copy_sd_core "src/systemd/sd-dhcp-lease.h" nm_copy_sd_core "src/systemd/sd-dhcp-option.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-ipv4acd.h" nm_copy_sd_core "src/systemd/sd-ipv4ll.h" nm_copy_sd_core "src/systemd/sd-lldp.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/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/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/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/log.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/basic/util.c" nm_copy_sd_shared "src/basic/util.h" nm_copy_sd_shared "src/fundamental/macro-fundamental.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/fundamental/type.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"
-rw-r--r--src/core/systemd/src/libsystemd-network/dhcp-identifier.h2
-rw-r--r--src/core/systemd/src/libsystemd-network/dhcp-option.c16
-rw-r--r--src/core/systemd/src/libsystemd-network/dhcp6-internal.h6
-rw-r--r--src/core/systemd/src/libsystemd-network/dhcp6-option.c262
-rw-r--r--src/core/systemd/src/libsystemd-network/lldp-internal.h4
-rw-r--r--src/core/systemd/src/libsystemd-network/lldp-network.c2
-rw-r--r--src/core/systemd/src/libsystemd-network/sd-dhcp-client.c40
-rw-r--r--src/core/systemd/src/libsystemd-network/sd-dhcp-lease.c47
-rw-r--r--src/core/systemd/src/libsystemd-network/sd-dhcp6-client.c75
-rw-r--r--src/core/systemd/src/libsystemd-network/sd-ipv4acd.c2
-rw-r--r--src/core/systemd/src/libsystemd-network/sd-ipv4ll.c2
-rw-r--r--src/core/systemd/src/libsystemd-network/sd-lldp.c10
-rw-r--r--src/core/systemd/src/libsystemd/sd-event/event-source.h6
-rw-r--r--src/core/systemd/src/libsystemd/sd-event/sd-event.c249
-rw-r--r--src/core/systemd/src/systemd/_sd-common.h6
-rw-r--r--src/core/systemd/src/systemd/sd-dhcp-client.h2
-rw-r--r--src/core/systemd/src/systemd/sd-dhcp-lease.h10
-rw-r--r--src/core/systemd/src/systemd/sd-dhcp6-client.h4
-rw-r--r--src/core/systemd/src/systemd/sd-lldp.h12
-rw-r--r--src/core/systemd/src/systemd/sd-ndisc.h10
-rw-r--r--src/libnm-systemd-shared/src/basic/alloc-util.h11
-rw-r--r--src/libnm-systemd-shared/src/basic/cgroup-util.h29
-rw-r--r--src/libnm-systemd-shared/src/basic/dns-def.h17
-rw-r--r--src/libnm-systemd-shared/src/basic/env-file.c32
-rw-r--r--src/libnm-systemd-shared/src/basic/env-util.c179
-rw-r--r--src/libnm-systemd-shared/src/basic/env-util.h15
-rw-r--r--src/libnm-systemd-shared/src/basic/escape.c10
-rw-r--r--src/libnm-systemd-shared/src/basic/extract-word.c31
-rw-r--r--src/libnm-systemd-shared/src/basic/extract-word.h16
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.c8
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.c72
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/format-util.c6
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.c143
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.h24
-rw-r--r--src/libnm-systemd-shared/src/basic/hashmap.c42
-rw-r--r--src/libnm-systemd-shared/src/basic/hashmap.h3
-rw-r--r--src/libnm-systemd-shared/src/basic/hexdecoct.c6
-rw-r--r--src/libnm-systemd-shared/src/basic/hostname-util.c33
-rw-r--r--src/libnm-systemd-shared/src/basic/hostname-util.h1
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.c128
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.h25
-rw-r--r--src/libnm-systemd-shared/src/basic/io-util.c47
-rw-r--r--src/libnm-systemd-shared/src/basic/io-util.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/log.h111
-rw-r--r--src/libnm-systemd-shared/src/basic/macro.h192
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_syscall.h548
-rw-r--r--src/libnm-systemd-shared/src/basic/ordered-set.c101
-rw-r--r--src/libnm-systemd-shared/src/basic/ordered-set.h76
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.c127
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.h9
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.c196
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.h3
-rw-r--r--src/libnm-systemd-shared/src/basic/prioq.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.c53
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.h3
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.c19
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/ratelimit.c2
-rw-r--r--src/libnm-systemd-shared/src/basic/set.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/signal-util.c58
-rw-r--r--src/libnm-systemd-shared/src/basic/signal-util.h25
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.c69
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.h9
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.c15
-rw-r--r--src/libnm-systemd-shared/src/basic/string-table.c4
-rw-r--r--src/libnm-systemd-shared/src/basic/string-table.h20
-rw-r--r--src/libnm-systemd-shared/src/basic/string-util.c69
-rw-r--r--src/libnm-systemd-shared/src/basic/string-util.h44
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.c25
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.h16
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.c6
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.h8
-rw-r--r--src/libnm-systemd-shared/src/basic/tmpfile-util.c87
-rw-r--r--src/libnm-systemd-shared/src/basic/utf8.c35
-rw-r--r--src/libnm-systemd-shared/src/basic/utf8.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/util.c111
-rw-r--r--src/libnm-systemd-shared/src/basic/util.h2
-rw-r--r--src/libnm-systemd-shared/src/fundamental/macro-fundamental.h201
-rw-r--r--src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c234
-rw-r--r--src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h67
-rw-r--r--src/libnm-systemd-shared/src/fundamental/type.h22
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.h16
84 files changed, 2287 insertions, 1961 deletions
diff --git a/src/core/systemd/src/libsystemd-network/dhcp-identifier.h b/src/core/systemd/src/libsystemd-network/dhcp-identifier.h
index e9f2ea7e95..1d9a9c55ba 100644
--- a/src/core/systemd/src/libsystemd-network/dhcp-identifier.h
+++ b/src/core/systemd/src/libsystemd-network/dhcp-identifier.h
@@ -16,7 +16,7 @@ typedef enum DUIDType {
DUID_TYPE_LL = 3,
DUID_TYPE_UUID = 4,
_DUID_TYPE_MAX,
- _DUID_TYPE_INVALID = -1,
+ _DUID_TYPE_INVALID = -EINVAL,
} DUIDType;
/* RFC 3315 section 9.1:
diff --git a/src/core/systemd/src/libsystemd-network/dhcp-option.c b/src/core/systemd/src/libsystemd-network/dhcp-option.c
index 70753c68d8..faa075cbd7 100644
--- a/src/core/systemd/src/libsystemd-network/dhcp-option.c
+++ b/src/core/systemd/src/libsystemd-network/dhcp-option.c
@@ -38,11 +38,14 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
size_t total = 0;
char **s;
+ if (strv_isempty((char **) optval))
+ return -EINVAL;
+
STRV_FOREACH(s, (char **) optval) {
size_t len = strlen(*s);
- if (len > 255)
- return -ENAMETOOLONG;
+ if (len > 255 || len == 0)
+ return -EINVAL;
total += 1 + len;
}
@@ -51,14 +54,13 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
return -ENOBUFS;
options[*offset] = code;
- options[*offset + 1] = total;
+ options[*offset + 1] = total;
*offset += 2;
STRV_FOREACH(s, (char **) optval) {
size_t len = strlen(*s);
options[*offset] = len;
-
memcpy(&options[*offset + 1], *s, len);
*offset += 1 + len;
}
@@ -78,11 +80,11 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
break;
case SD_DHCP_OPTION_VENDOR_SPECIFIC: {
- OrderedHashmap *s = (OrderedHashmap *) optval;
+ OrderedSet *s = (OrderedSet *) optval;
struct sd_dhcp_option *p;
size_t l = 0;
- ORDERED_HASHMAP_FOREACH(p, s)
+ ORDERED_SET_FOREACH(p, s)
l += p->length + 2;
if (*offset + l + 2 > size)
@@ -93,7 +95,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
*offset += 2;
- ORDERED_HASHMAP_FOREACH(p, s) {
+ ORDERED_SET_FOREACH(p, s) {
options[*offset] = p->option;
options[*offset + 1] = p->length;
memcpy(&options[*offset + 2], p->data, p->length);
diff --git a/src/core/systemd/src/libsystemd-network/dhcp6-internal.h b/src/core/systemd/src/libsystemd-network/dhcp6-internal.h
index 24d8a314a4..681c462315 100644
--- a/src/core/systemd/src/libsystemd-network/dhcp6-internal.h
+++ b/src/core/systemd/src/libsystemd-network/dhcp6-internal.h
@@ -97,10 +97,10 @@ typedef struct DHCP6IA DHCP6IA;
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
size_t optlen, const void *optval);
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
-int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix);
+int dhcp6_option_append_pd(uint8_t **buf, size_t *buflen, const DHCP6IA *pd, const DHCP6Address *hint_pd_prefix);
int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
-int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class);
-int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **user_class);
+int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class);
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *user_class);
int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHashmap *vendor_options);
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
size_t *optlen, uint8_t **optvalue);
diff --git a/src/core/systemd/src/libsystemd-network/dhcp6-option.c b/src/core/systemd/src/libsystemd-network/dhcp6-option.c
index e2bf4f7e36..91162d636b 100644
--- a/src/core/systemd/src/libsystemd-network/dhcp6-option.c
+++ b/src/core/systemd/src/libsystemd-network/dhcp6-option.c
@@ -41,14 +41,15 @@ typedef struct DHCP6PDPrefixOption {
#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd))
#define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta))
-static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode,
- size_t optlen) {
- DHCP6Option *option = (DHCP6Option*) *buf;
+static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, size_t optlen) {
+ DHCP6Option *option;
assert_return(buf, -EINVAL);
assert_return(*buf, -EINVAL);
assert_return(buflen, -EINVAL);
+ option = (DHCP6Option*) *buf;
+
if (optlen > 0xffff || *buflen < optlen + offsetof(DHCP6Option, data))
return -ENOBUFS;
@@ -112,10 +113,13 @@ int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHash
}
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) {
- uint16_t len;
- uint8_t *ia_hdr;
- size_t iaid_offset, ia_buflen, ia_addrlen = 0;
+ size_t ia_buflen, ia_addrlen = 0;
+ struct ia_na ia_na;
+ struct ia_ta ia_ta;
DHCP6Address *addr;
+ uint8_t *ia_hdr;
+ uint16_t len;
+ void *p;
int r;
assert_return(buf, -EINVAL);
@@ -123,15 +127,23 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) {
assert_return(buflen, -EINVAL);
assert_return(ia, -EINVAL);
+ /* client should not send set T1 and T2. See, RFC 8415, and issue #18090. */
+
switch (ia->type) {
case SD_DHCP6_OPTION_IA_NA:
len = DHCP6_OPTION_IA_NA_LEN;
- iaid_offset = offsetof(DHCP6IA, ia_na);
+ ia_na = (struct ia_na) {
+ .id = ia->ia_na.id,
+ };
+ p = &ia_na;
break;
case SD_DHCP6_OPTION_IA_TA:
len = DHCP6_OPTION_IA_TA_LEN;
- iaid_offset = offsetof(DHCP6IA, ia_ta);
+ ia_ta = (struct ia_ta) {
+ .id = ia->ia_ta.id,
+ };
+ p = &ia_ta;
break;
default:
@@ -147,30 +159,113 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) {
*buf += offsetof(DHCP6Option, data);
*buflen -= offsetof(DHCP6Option, data);
- memcpy(*buf, (char*) ia + iaid_offset, len);
+ memcpy(*buf, p, len);
*buf += len;
*buflen -= len;
LIST_FOREACH(addresses, addr, ia->addresses) {
- r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IAADDR,
- sizeof(addr->iaaddr));
+ struct iaaddr a = {
+ .address = addr->iaaddr.address,
+ };
+
+ r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IAADDR, sizeof(struct iaaddr));
if (r < 0)
return r;
- memcpy(*buf, &addr->iaaddr, sizeof(addr->iaaddr));
+ memcpy(*buf, &a, sizeof(struct iaaddr));
- *buf += sizeof(addr->iaaddr);
- *buflen -= sizeof(addr->iaaddr);
+ *buf += sizeof(struct iaaddr);
+ *buflen -= sizeof(struct iaaddr);
- ia_addrlen += offsetof(DHCP6Option, data) + sizeof(addr->iaaddr);
+ ia_addrlen += offsetof(DHCP6Option, data) + sizeof(struct iaaddr);
}
- r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen);
+ return option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen);
+}
+
+static int option_append_pd_prefix(uint8_t **buf, size_t *buflen, const DHCP6Address *prefix) {
+ struct iapdprefix p;
+ int r;
+
+ assert(buf);
+ assert(*buf);
+ assert(buflen);
+ assert(prefix);
+
+ if (prefix->iapdprefix.prefixlen == 0)
+ return -EINVAL;
+
+ /* Do not append T1 and T2. */
+
+ p = (struct iapdprefix) {
+ .prefixlen = prefix->iapdprefix.prefixlen,
+ .address = prefix->iapdprefix.address,
+ };
+
+ r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IA_PD_PREFIX, sizeof(struct iapdprefix));
if (r < 0)
return r;
- return 0;
+ memcpy(*buf, &p, sizeof(struct iapdprefix));
+
+ *buf += sizeof(struct iapdprefix);
+ *buflen -= sizeof(struct iapdprefix);
+
+ return offsetof(DHCP6Option, data) + sizeof(struct iapdprefix);
+}
+
+int dhcp6_option_append_pd(uint8_t **buf, size_t *buflen, const DHCP6IA *pd, const DHCP6Address *hint_pd_prefix) {
+ struct ia_pd ia_pd;
+ size_t len, pd_buflen;
+ uint8_t *pd_hdr;
+ int r;
+
+ assert_return(buf, -EINVAL);
+ assert_return(*buf, -EINVAL);
+ assert_return(buflen, -EINVAL);
+ assert_return(pd, -EINVAL);
+ assert_return(pd->type == SD_DHCP6_OPTION_IA_PD, -EINVAL);
+
+ /* Do not set T1 and T2. */
+ ia_pd = (struct ia_pd) {
+ .id = pd->ia_pd.id,
+ };
+ len = sizeof(struct ia_pd);
+
+ if (*buflen < offsetof(DHCP6Option, data) + len)
+ return -ENOBUFS;
+
+ pd_hdr = *buf;
+ pd_buflen = *buflen;
+
+ /* The header will be written at the end of this function. */
+ *buf += offsetof(DHCP6Option, data);
+ *buflen -= offsetof(DHCP6Option, data);
+
+ memcpy(*buf, &ia_pd, len);
+
+ *buf += sizeof(struct ia_pd);
+ *buflen -= sizeof(struct ia_pd);
+
+ DHCP6Address *prefix;
+ LIST_FOREACH(addresses, prefix, pd->addresses) {
+ r = option_append_pd_prefix(buf, buflen, prefix);
+ if (r < 0)
+ return r;
+
+ len += r;
+ }
+
+ if (hint_pd_prefix && hint_pd_prefix->iapdprefix.prefixlen > 0) {
+ r = option_append_pd_prefix(buf, buflen, hint_pd_prefix);
+ if (r < 0)
+ return r;
+
+ len += r;
+ }
+
+ return option_append_hdr(&pd_hdr, &pd_buflen, pd->type, len);
}
int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
@@ -200,19 +295,22 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
return r;
}
-int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class) {
+int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class) {
_cleanup_free_ uint8_t *p = NULL;
size_t total = 0, offset = 0;
- char **s;
+ char * const *s;
- assert_return(buf && *buf && buflen && user_class, -EINVAL);
+ assert(buf);
+ assert(*buf);
+ assert(buflen);
+ assert(!strv_isempty(user_class));
STRV_FOREACH(s, user_class) {
size_t len = strlen(*s);
uint8_t *q;
- if (len > 0xffff)
- return -ENAMETOOLONG;
+ if (len > 0xffff || len == 0)
+ return -EINVAL;
q = realloc(p, total + len + 2);
if (!q)
return -ENOMEM;
@@ -229,16 +327,16 @@ int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_cl
return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, total, p);
}
-int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendor_class) {
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *vendor_class) {
_cleanup_free_ uint8_t *p = NULL;
uint32_t enterprise_identifier;
size_t total, offset;
- char **s;
+ char * const *s;
assert(buf);
assert(*buf);
assert(buflen);
- assert(vendor_class);
+ assert(!strv_isempty(vendor_class));
enterprise_identifier = htobe32(SYSTEMD_PEN);
@@ -253,6 +351,9 @@ int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendo
size_t len = strlen(*s);
uint8_t *q;
+ if (len > UINT16_MAX || len == 0)
+ return -EINVAL;
+
q = realloc(p, total + len + 2);
if (!q)
return -ENOMEM;
@@ -269,51 +370,6 @@ int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendo
return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p);
}
-int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) {
- DHCP6Option *option = (DHCP6Option *)buf;
- size_t i = sizeof(*option) + sizeof(pd->ia_pd);
- DHCP6PDPrefixOption *prefix_opt;
- DHCP6Address *prefix;
-
- assert_return(buf, -EINVAL);
- assert_return(pd, -EINVAL);
- assert_return(pd->type == SD_DHCP6_OPTION_IA_PD, -EINVAL);
-
- if (len < i)
- return -ENOBUFS;
-
- option->code = htobe16(SD_DHCP6_OPTION_IA_PD);
-
- memcpy(&option->data, &pd->ia_pd, sizeof(pd->ia_pd));
- LIST_FOREACH(addresses, prefix, pd->addresses) {
- if (len < i + sizeof(*prefix_opt))
- return -ENOBUFS;
-
- prefix_opt = (DHCP6PDPrefixOption *)&buf[i];
- prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX);
- prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix));
-
- memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, sizeof(struct iapdprefix));
- i += sizeof(*prefix_opt);
- }
-
- if (hint_pd_prefix && hint_pd_prefix->iapdprefix.prefixlen > 0) {
- if (len < i + sizeof(*prefix_opt))
- return -ENOBUFS;
-
- prefix_opt = (DHCP6PDPrefixOption *)&buf[i];
- prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX);
- prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix));
-
- memcpy(&prefix_opt->iapdprefix, &hint_pd_prefix->iapdprefix, sizeof(struct iapdprefix));
- i += sizeof(*prefix_opt);
- }
-
- option->len = htobe16(i - sizeof(*option));
-
- return i;
-}
-
static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) {
DHCP6Option *option = (DHCP6Option*) *buf;
uint16_t len;
@@ -369,8 +425,7 @@ int dhcp6_option_parse_status(DHCP6Option *option, size_t len) {
return be16toh(statusopt->status);
}
-static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia,
- uint32_t *lifetime_valid) {
+static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, uint32_t *ret_lifetime_valid) {
DHCP6AddressOption *addr_option = (DHCP6AddressOption *)option;
DHCP6Address *addr;
uint32_t lt_valid, lt_pref;
@@ -383,16 +438,22 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia,
lt_pref = be32toh(addr_option->iaaddr.lifetime_preferred);
if (lt_valid == 0 || lt_pref > lt_valid) {
- log_dhcp6_client(client, "Valid lifetime of an IA address is zero or preferred lifetime %d > valid lifetime %d",
+ log_dhcp6_client(client,
+ "Valid lifetime of an IA address is zero or "
+ "preferred lifetime %"PRIu32" > valid lifetime %"PRIu32,
lt_pref, lt_valid);
-
- return 0;
+ return -EINVAL;
}
if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*addr_option)) {
r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*addr_option));
- if (r != 0)
- return r < 0 ? r: 0;
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ log_dhcp6_client(client, "Non-zero status code '%s' for address is received",
+ dhcp6_message_status_to_string(r));
+ return -EINVAL;
+ }
}
addr = new0(DHCP6Address, 1);
@@ -404,13 +465,12 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia,
LIST_PREPEND(addresses, ia->addresses, addr);
- *lifetime_valid = be32toh(addr->iaaddr.lifetime_valid);
+ *ret_lifetime_valid = be32toh(addr->iaaddr.lifetime_valid);
return 0;
}
-static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia,
- uint32_t *lifetime_valid) {
+static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, uint32_t *ret_lifetime_valid) {
DHCP6PDPrefixOption *pdprefix_option = (DHCP6PDPrefixOption *)option;
DHCP6Address *prefix;
uint32_t lt_valid, lt_pref;
@@ -423,16 +483,22 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia,
lt_pref = be32toh(pdprefix_option->iapdprefix.lifetime_preferred);
if (lt_valid == 0 || lt_pref > lt_valid) {
- log_dhcp6_client(client, "Valid lifetieme of a PD prefix is zero or preferred lifetime %d > valid lifetime %d",
+ log_dhcp6_client(client,
+ "Valid lifetieme of a PD prefix is zero or "
+ "preferred lifetime %"PRIu32" > valid lifetime %"PRIu32,
lt_pref, lt_valid);
-
- return 0;
+ return -EINVAL;
}
if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*pdprefix_option)) {
r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*pdprefix_option));
- if (r != 0)
- return r < 0 ? r: 0;
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ log_dhcp6_client(client, "Non-zero status code '%s' for PD prefix is received",
+ dhcp6_message_status_to_string(r));
+ return -EINVAL;
+ }
}
prefix = new0(DHCP6Address, 1);
@@ -444,7 +510,7 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia,
LIST_PREPEND(addresses, ia->addresses, prefix);
- *lifetime_valid = be32toh(prefix->iapdprefix.lifetime_valid);
+ *ret_lifetime_valid = be32toh(prefix->iapdprefix.lifetime_valid);
return 0;
}
@@ -476,8 +542,7 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
lt_t2 = be32toh(ia->ia_na.lifetime_t2);
if (lt_t1 && lt_t2 && lt_t1 > lt_t2) {
- log_dhcp6_client(client, "IA NA T1 %ds > T2 %ds",
- lt_t1, lt_t2);
+ log_dhcp6_client(client, "IA NA T1 %"PRIu32"sec > T2 %"PRIu32"sec", lt_t1, lt_t2);
return -EINVAL;
}
@@ -495,8 +560,7 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
lt_t2 = be32toh(ia->ia_pd.lifetime_t2);
if (lt_t1 && lt_t2 && lt_t1 > lt_t2) {
- log_dhcp6_client(client, "IA PD T1 %ds > T2 %ds",
- lt_t1, lt_t2);
+ log_dhcp6_client(client, "IA PD T1 %"PRIu32"sec > T2 %"PRIu32"sec", lt_t1, lt_t2);
return -EINVAL;
}
@@ -536,10 +600,9 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
}
r = dhcp6_option_parse_address(option, ia, &lt_valid);
- if (r < 0)
+ if (r < 0 && r != -EINVAL)
return r;
-
- if (lt_valid < lt_min)
+ if (r >= 0 && lt_valid < lt_min)
lt_min = lt_valid;
break;
@@ -552,10 +615,9 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
}
r = dhcp6_option_parse_pdprefix(option, ia, &lt_valid);
- if (r < 0)
+ if (r < 0 && r != -EINVAL)
return r;
-
- if (lt_valid < lt_min)
+ if (r >= 0 && lt_valid < lt_min)
lt_min = lt_valid;
break;
@@ -588,26 +650,26 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
switch(iatype) {
case SD_DHCP6_OPTION_IA_NA:
- if (!ia->ia_na.lifetime_t1 && !ia->ia_na.lifetime_t2) {
+ if (!ia->ia_na.lifetime_t1 && !ia->ia_na.lifetime_t2 && lt_min != UINT32_MAX) {
lt_t1 = lt_min / 2;
lt_t2 = lt_min / 10 * 8;
ia->ia_na.lifetime_t1 = htobe32(lt_t1);
ia->ia_na.lifetime_t2 = htobe32(lt_t2);
- log_dhcp6_client(client, "Computed IA NA T1 %ds and T2 %ds as both were zero",
+ log_dhcp6_client(client, "Computed IA NA T1 %"PRIu32"sec and T2 %"PRIu32"sec as both were zero",
lt_t1, lt_t2);
}
break;
case SD_DHCP6_OPTION_IA_PD:
- if (!ia->ia_pd.lifetime_t1 && !ia->ia_pd.lifetime_t2) {
+ if (!ia->ia_pd.lifetime_t1 && !ia->ia_pd.lifetime_t2 && lt_min != UINT32_MAX) {
lt_t1 = lt_min / 2;
lt_t2 = lt_min / 10 * 8;
ia->ia_pd.lifetime_t1 = htobe32(lt_t1);
ia->ia_pd.lifetime_t2 = htobe32(lt_t2);
- log_dhcp6_client(client, "Computed IA PD T1 %ds and T2 %ds as both were zero",
+ log_dhcp6_client(client, "Computed IA PD T1 %"PRIu32"sec and T2 %"PRIu32"sec as both were zero",
lt_t1, lt_t2);
}
diff --git a/src/core/systemd/src/libsystemd-network/lldp-internal.h b/src/core/systemd/src/libsystemd-network/lldp-internal.h
index f23695f974..daedbb088f 100644
--- a/src/core/systemd/src/libsystemd-network/lldp-internal.h
+++ b/src/core/systemd/src/libsystemd-network/lldp-internal.h
@@ -35,5 +35,5 @@ struct sd_lldp {
#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__)
-const char* lldp_event_to_string(sd_lldp_event e) _const_;
-sd_lldp_event lldp_event_from_string(const char *s) _pure_;
+const char* lldp_event_to_string(sd_lldp_event_t e) _const_;
+sd_lldp_event_t lldp_event_from_string(const char *s) _pure_;
diff --git a/src/core/systemd/src/libsystemd-network/lldp-network.c b/src/core/systemd/src/libsystemd-network/lldp-network.c
index 9616cb6250..43141b2d79 100644
--- a/src/core/systemd/src/libsystemd-network/lldp-network.c
+++ b/src/core/systemd/src/libsystemd-network/lldp-network.c
@@ -22,7 +22,7 @@ int lldp_network_bind_raw_socket(int ifindex) {
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_proto)), /* A <- protocol */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
- BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */
+ BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept packet */
};
static const struct sock_fprog fprog = {
diff --git a/src/core/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/core/systemd/src/libsystemd-network/sd-dhcp-client.c
index 7604aafd6f..fb94fdc882 100644
--- a/src/core/systemd/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/core/systemd/src/libsystemd-network/sd-dhcp-client.c
@@ -274,7 +274,6 @@ int sd_dhcp_client_set_request_address(
}
int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
-
assert_return(client, -EINVAL);
assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
assert_return(ifindex > 0, -EINVAL);
@@ -348,13 +347,14 @@ int sd_dhcp_client_get_client_id(
assert_return(data, -EINVAL);
assert_return(data_len, -EINVAL);
- *type = 0;
- *data = NULL;
- *data_len = 0;
if (client->client_id_len) {
*type = client->client_id.type;
*data = client->client_id.raw.data;
*data_len = client->client_id_len - sizeof(client->client_id.type);
+ } else {
+ *type = 0;
+ *data = NULL;
+ *data_len = 0;
}
return 0;
@@ -573,22 +573,26 @@ int sd_dhcp_client_set_mud_url(
int sd_dhcp_client_set_user_class(
sd_dhcp_client *client,
- const char* const* user_class) {
+ char * const *user_class) {
+
+ char * const *p;
+ char **s = NULL;
- _cleanup_strv_free_ char **s = NULL;
- char **p;
+ assert_return(client, -EINVAL);
+ assert_return(!strv_isempty(user_class), -EINVAL);
+
+ STRV_FOREACH(p, user_class) {
+ size_t n = strlen(*p);
- STRV_FOREACH(p, (char **) user_class)
- if (strlen(*p) > 255)
- return -ENAMETOOLONG;
+ if (n > 255 || n == 0)
+ return -EINVAL;
+ }
- s = strv_copy((char **) user_class);
+ s = strv_copy(user_class);
if (!s)
return -ENOMEM;
- client->user_class = TAKE_PTR(s);
-
- return 0;
+ return strv_free_and_replace(client->user_class, s);
}
int sd_dhcp_client_set_client_port(
@@ -625,11 +629,7 @@ int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) {
assert_return(client, -EINVAL);
assert_return(v, -EINVAL);
- r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp_option_hash_ops);
- if (r < 0)
- return r;
-
- r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v);
+ r = ordered_hashmap_ensure_put(&client->extra_options, &dhcp_option_hash_ops, UINT_TO_PTR(v->option), v);
if (r < 0)
return r;
@@ -2229,7 +2229,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
.mtu = DHCP_DEFAULT_MIN_SIZE,
.port = DHCP_PORT_CLIENT,
.anonymize = !!anonymize,
- .max_attempts = (uint64_t) -1,
+ .max_attempts = UINT64_MAX,
.ip_service_type = -1,
};
/* NOTE: this could be moved to a function. */
diff --git a/src/core/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/core/systemd/src/libsystemd-network/sd-dhcp-lease.c
index 8a138ff4b6..6d88c88e6b 100644
--- a/src/core/systemd/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/core/systemd/src/libsystemd-network/sd-dhcp-lease.c
@@ -19,6 +19,7 @@
#include "env-file.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
@@ -98,7 +99,7 @@ int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
int sd_dhcp_lease_get_servers(
sd_dhcp_lease *lease,
- sd_dhcp_lease_server_type what,
+ sd_dhcp_lease_server_type_t what,
const struct in_addr **addr) {
assert_return(lease, -EINVAL);
@@ -280,7 +281,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
free(lease->hostname);
free(lease->domainname);
- for (sd_dhcp_lease_server_type i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++)
+ for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++)
free(lease->servers[i].addr);
free(lease->static_route);
@@ -868,7 +869,7 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
}
int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
- _cleanup_free_ char *temp_path = NULL;
+ _cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
struct sd_dhcp_raw_option *option;
struct in_addr address;
@@ -888,7 +889,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = fopen_temporary(lease_file, &f, &temp_path);
if (r < 0)
- goto fail;
+ return r;
(void) fchmod(fileno(f), 0644);
@@ -991,10 +992,8 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
_cleanup_free_ char *client_id_hex = NULL;
client_id_hex = hexmem(client_id, client_id_len);
- if (!client_id_hex) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!client_id_hex)
+ return -ENOMEM;
fprintf(f, "CLIENTID=%s\n", client_id_hex);
}
@@ -1003,10 +1002,8 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
_cleanup_free_ char *option_hex = NULL;
option_hex = hexmem(data, data_len);
- if (!option_hex) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!option_hex)
+ return -ENOMEM;
fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
}
@@ -1016,29 +1013,23 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
xsprintf(key, "OPTION_%" PRIu8, option->tag);
r = serialize_dhcp_option(f, key, option->data, option->length);
if (r < 0)
- goto fail;
+ return r;
}
r = fflush_and_check(f);
if (r < 0)
- goto fail;
-
- if (rename(temp_path, lease_file) < 0) {
- r = -errno;
- goto fail;
- }
+ return r;
- return 0;
+ r = conservative_rename(temp_path, lease_file);
+ if (r < 0)
+ return r;
-fail:
- if (temp_path)
- (void) unlink(temp_path);
+ temp_path = mfree(temp_path);
- return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
+ return 0;
}
int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
-
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
_cleanup_free_ char
*address = NULL,
@@ -1266,13 +1257,13 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
}
if (client_id_hex) {
- r = unhexmem(client_id_hex, (size_t) -1, &lease->client_id, &lease->client_id_len);
+ r = unhexmem(client_id_hex, SIZE_MAX, &lease->client_id, &lease->client_id_len);
if (r < 0)
log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex);
}
if (vendor_specific_hex) {
- r = unhexmem(vendor_specific_hex, (size_t) -1, &lease->vendor_specific, &lease->vendor_specific_len);
+ r = unhexmem(vendor_specific_hex, SIZE_MAX, &lease->vendor_specific, &lease->vendor_specific_len);
if (r < 0)
log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex);
}
@@ -1284,7 +1275,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
if (!options[i])
continue;
- r = unhexmem(options[i], (size_t) -1, &data, &len);
+ r = unhexmem(options[i], SIZE_MAX, &data, &len);
if (r < 0) {
log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]);
continue;
diff --git a/src/core/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/core/systemd/src/libsystemd-network/sd-dhcp6-client.c
index e068e0dc91..410bfda10e 100644
--- a/src/core/systemd/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/core/systemd/src/libsystemd-network/sd-dhcp6-client.c
@@ -157,7 +157,6 @@ int sd_dhcp6_client_set_callback(
}
int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) {
-
assert_return(client, -EINVAL);
assert_return(ifindex > 0, -EINVAL);
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
@@ -172,7 +171,7 @@ int sd_dhcp6_client_set_local_address(
assert_return(client, -EINVAL);
assert_return(local_address, -EINVAL);
- assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL);
+ assert_return(in6_addr_is_link_local(local_address) > 0, -EINVAL);
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
@@ -235,11 +234,7 @@ int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client, sd_dhcp6_option *
assert_return(client, -EINVAL);
assert_return(v, -EINVAL);
- r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp6_option_hash_ops);
- if (r < 0)
- return r;
-
- r = ordered_hashmap_put(client->vendor_options, v, v);
+ r = ordered_hashmap_ensure_put(&client->vendor_options, &dhcp6_option_hash_ops, v, v);
if (r < 0)
return r;
@@ -351,6 +346,7 @@ int sd_dhcp6_client_duid_as_string(
assert_return(client, -EINVAL);
assert_return(client->duid_len > 0, -ENODATA);
+ assert_return(duid, -EINVAL);
v = dhcp6_duid_type_to_string(be16toh(client->duid.type));
if (v) {
@@ -454,7 +450,6 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
}
int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mudurl) {
-
assert_return(client, -EINVAL);
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
assert_return(mudurl, -EINVAL);
@@ -464,47 +459,48 @@ int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mud
return free_and_strdup(&client->mudurl, mudurl);
}
-int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_class) {
- _cleanup_strv_free_ char **s = NULL;
- char **p;
+int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char * const *user_class) {
+ char * const *p;
+ char **s;
assert_return(client, -EINVAL);
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
+ assert_return(!strv_isempty(user_class), -EINVAL);
- assert_return(user_class, -EINVAL);
+ STRV_FOREACH(p, user_class) {
+ size_t len = strlen(*p);
- STRV_FOREACH(p, user_class)
- if (strlen(*p) > UINT16_MAX)
- return -ENAMETOOLONG;
+ if (len > UINT16_MAX || len == 0)
+ return -EINVAL;
+ }
s = strv_copy(user_class);
if (!s)
return -ENOMEM;
- client->user_class = TAKE_PTR(s);
-
- return 0;
+ return strv_free_and_replace(client->user_class, s);
}
-int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char **vendor_class) {
- _cleanup_strv_free_ char **s = NULL;
- char **p;
+int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char * const *vendor_class) {
+ char * const *p;
+ char **s;
assert_return(client, -EINVAL);
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
- assert_return(vendor_class, -EINVAL);
+ assert_return(!strv_isempty(vendor_class), -EINVAL);
+
+ STRV_FOREACH(p, vendor_class) {
+ size_t len = strlen(*p);
- STRV_FOREACH(p, vendor_class)
- if (strlen(*p) > UINT8_MAX)
- return -ENAMETOOLONG;
+ if (len > UINT16_MAX || len == 0)
+ return -EINVAL;
+ }
s = strv_copy(vendor_class);
if (!s)
return -ENOMEM;
- client->vendor_class = TAKE_PTR(s);
-
- return 0;
+ return strv_free_and_replace(client->vendor_class, s);
}
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
@@ -567,11 +563,7 @@ int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v) {
assert_return(client, -EINVAL);
assert_return(v, -EINVAL);
- r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp6_option_hash_ops);
- if (r < 0)
- return r;
-
- r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v);
+ r = ordered_hashmap_ensure_put(&client->extra_options, &dhcp6_option_hash_ops, UINT_TO_PTR(v->option), v);
if (r < 0)
return r;
@@ -706,12 +698,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
}
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
- r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
+ r = dhcp6_option_append_pd(&opt, &optlen, &client->ia_pd, &client->hint_pd_prefix);
if (r < 0)
return r;
-
- opt += r;
- optlen -= r;
}
break;
@@ -770,12 +759,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
}
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
- r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
+ r = dhcp6_option_append_pd(&opt, &optlen, &client->lease->pd, NULL);
if (r < 0)
return r;
-
- opt += r;
- optlen -= r;
}
break;
@@ -822,12 +808,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
}
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
- r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
+ r = dhcp6_option_append_pd(&opt, &optlen, &client->lease->pd, NULL);
if (r < 0)
return r;
-
- opt += r;
- optlen -= r;
}
break;
@@ -1701,7 +1684,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL);
assert_return(client->ifindex > 0, -EINVAL);
- assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL);
+ assert_return(in6_addr_is_link_local(&client->local_address) > 0, -EINVAL);
if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
return -EBUSY;
diff --git a/src/core/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/core/systemd/src/libsystemd-network/sd-ipv4acd.c
index 9426b65324..defd23d85a 100644
--- a/src/core/systemd/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/core/systemd/src/libsystemd-network/sd-ipv4acd.c
@@ -46,7 +46,7 @@ typedef enum IPv4ACDState {
IPV4ACD_STATE_ANNOUNCING,
IPV4ACD_STATE_RUNNING,
_IPV4ACD_STATE_MAX,
- _IPV4ACD_STATE_INVALID = -1
+ _IPV4ACD_STATE_INVALID = -EINVAL,
} IPv4ACDState;
struct sd_ipv4acd {
diff --git a/src/core/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/core/systemd/src/libsystemd-network/sd-ipv4ll.c
index 3af7d89bf0..a83c9b06de 100644
--- a/src/core/systemd/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/core/systemd/src/libsystemd-network/sd-ipv4ll.c
@@ -186,7 +186,7 @@ int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
static bool ipv4ll_address_is_valid(const struct in_addr *address) {
assert(address);
- if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address))
+ if (!in4_addr_is_link_local(address))
return false;
return !IN_SET(be32toh(address->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U);
diff --git a/src/core/systemd/src/libsystemd-network/sd-lldp.c b/src/core/systemd/src/libsystemd-network/sd-lldp.c
index 8b666522cb..3c0285df4e 100644
--- a/src/core/systemd/src/libsystemd-network/sd-lldp.c
+++ b/src/core/systemd/src/libsystemd-network/sd-lldp.c
@@ -21,13 +21,13 @@
#define LLDP_DEFAULT_NEIGHBORS_MAX 128U
static const char * const lldp_event_table[_SD_LLDP_EVENT_MAX] = {
- [SD_LLDP_EVENT_ADDED] = "added",
- [SD_LLDP_EVENT_REMOVED] = "removed",
+ [SD_LLDP_EVENT_ADDED] = "added",
+ [SD_LLDP_EVENT_REMOVED] = "removed",
[SD_LLDP_EVENT_UPDATED] = "updated",
[SD_LLDP_EVENT_REFRESHED] = "refreshed",
};
-DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event);
+DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event_t);
static void lldp_flush_neighbors(sd_lldp *lldp) {
assert(lldp);
@@ -35,7 +35,7 @@ static void lldp_flush_neighbors(sd_lldp *lldp) {
hashmap_clear(lldp->neighbor_by_id);
}
-static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) {
+static void lldp_callback(sd_lldp *lldp, sd_lldp_event_t event, sd_lldp_neighbor *n) {
assert(lldp);
assert(event >= 0 && event < _SD_LLDP_EVENT_MAX);
@@ -373,7 +373,7 @@ _public_ int sd_lldp_new(sd_lldp **ret) {
.n_ref = 1,
.fd = -1,
.neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX,
- .capability_mask = (uint16_t) -1,
+ .capability_mask = UINT16_MAX,
};
lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_hash_ops);
diff --git a/src/core/systemd/src/libsystemd/sd-event/event-source.h b/src/core/systemd/src/libsystemd/sd-event/event-source.h
index f0d2a1b9e6..d2dc21470e 100644
--- a/src/core/systemd/src/libsystemd/sd-event/event-source.h
+++ b/src/core/systemd/src/libsystemd/sd-event/event-source.h
@@ -28,7 +28,7 @@ typedef enum EventSourceType {
SOURCE_WATCHDOG,
SOURCE_INOTIFY,
_SOURCE_EVENT_SOURCE_TYPE_MAX,
- _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1
+ _SOURCE_EVENT_SOURCE_TYPE_INVALID = -EINVAL,
} EventSourceType;
/* All objects we use in epoll events start with this value, so that
@@ -40,7 +40,7 @@ typedef enum WakeupType {
WAKEUP_SIGNAL_DATA,
WAKEUP_INOTIFY_DATA,
_WAKEUP_TYPE_MAX,
- _WAKEUP_TYPE_INVALID = -1,
+ _WAKEUP_TYPE_INVALID = -EINVAL,
} WakeupType;
struct inode_data;
@@ -56,7 +56,7 @@ struct sd_event_source {
char *description;
- EventSourceType type:5;
+ EventSourceType type;
signed int enabled:3;
bool pending:1;
bool dispatching:1;
diff --git a/src/core/systemd/src/libsystemd/sd-event/sd-event.c b/src/core/systemd/src/libsystemd/sd-event/sd-event.c
index 3f1a6776fe..b76b0623fe 100644
--- a/src/core/systemd/src/libsystemd/sd-event/sd-event.c
+++ b/src/core/systemd/src/libsystemd/sd-event/sd-event.c
@@ -407,7 +407,7 @@ _public_ int sd_event_new(sd_event** ret) {
e->epoll_fd = fd_move_above_stdio(e->epoll_fd);
if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) {
- log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 ... 2^63 us will be logged every 5s.");
+ log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 … 2^63 us will be logged every 5s.");
e->profile_delays = true;
}
@@ -629,10 +629,6 @@ static int event_make_signal_data(
return 0;
}
} else {
- r = hashmap_ensure_allocated(&e->signal_data, &uint64_hash_ops);
- if (r < 0)
- return r;
-
d = new(struct signal_data, 1);
if (!d)
return -ENOMEM;
@@ -643,7 +639,7 @@ static int event_make_signal_data(
.priority = priority,
};
- r = hashmap_put(e->signal_data, &d->priority, d);
+ r = hashmap_ensure_put(&e->signal_data, &uint64_hash_ops, &d->priority, d);
if (r < 0) {
free(d);
return r;
@@ -943,7 +939,7 @@ static void source_disconnect(sd_event_source *s) {
sd_event_unref(event);
}
-static void source_free(sd_event_source *s) {
+static sd_event_source* source_free(sd_event_source *s) {
assert(s);
source_disconnect(s);
@@ -993,7 +989,7 @@ static void source_free(sd_event_source *s) {
s->destroy_callback(s->userdata);
free(s->description);
- free(s);
+ return mfree(s);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, source_free);
@@ -1043,7 +1039,7 @@ static int source_set_pending(sd_event_source *s, bool b) {
}
}
- return 0;
+ return 1;
}
static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType type) {
@@ -1240,7 +1236,7 @@ _public_ int sd_event_add_time(
assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
- assert_return(accuracy != (uint64_t) -1, -EINVAL);
+ assert_return(accuracy != UINT64_MAX, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
@@ -1727,10 +1723,6 @@ static int event_make_inotify_data(
fd = fd_move_above_stdio(fd);
- r = hashmap_ensure_allocated(&e->inotify_data, &uint64_hash_ops);
- if (r < 0)
- return r;
-
d = new(struct inotify_data, 1);
if (!d)
return -ENOMEM;
@@ -1741,7 +1733,7 @@ static int event_make_inotify_data(
.priority = priority,
};
- r = hashmap_put(e->inotify_data, &d->priority, d);
+ r = hashmap_ensure_put(&e->inotify_data, &uint64_hash_ops, &d->priority, d);
if (r < 0) {
d->fd = safe_close(d->fd);
free(d);
@@ -2602,10 +2594,11 @@ _public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec
if (r < 0)
return r;
- if (usec >= USEC_INFINITY - t)
+ usec = usec_add(t, usec);
+ if (usec == USEC_INFINITY)
return -EOVERFLOW;
- return sd_event_source_set_time(s, t + usec);
+ return sd_event_source_set_time(s, usec);
}
_public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) {
@@ -2622,7 +2615,7 @@ _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec
int r;
assert_return(s, -EINVAL);
- assert_return(usec != (uint64_t) -1, -EINVAL);
+ assert_return(usec != UINT64_MAX, -EINVAL);
assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM);
assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(s->event), -ECHILD);
@@ -3123,11 +3116,19 @@ static int process_timer(
return 0;
}
-static int process_child(sd_event *e) {
+static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priority) {
+ int64_t min_priority = threshold;
+ bool something_new = false;
sd_event_source *s;
int r;
assert(e);
+ assert(ret_min_priority);
+
+ if (!e->need_process_child) {
+ *ret_min_priority = min_priority;
+ return 0;
+ }
e->need_process_child = false;
@@ -3152,6 +3153,9 @@ static int process_child(sd_event *e) {
HASHMAP_FOREACH(s, e->child_sources) {
assert(s->type == SOURCE_CHILD);
+ if (s->priority > threshold)
+ continue;
+
if (s->pending)
continue;
@@ -3188,10 +3192,15 @@ static int process_child(sd_event *e) {
r = source_set_pending(s, true);
if (r < 0)
return r;
+ if (r > 0) {
+ something_new = true;
+ min_priority = MIN(min_priority, s->priority);
+ }
}
}
- return 0;
+ *ret_min_priority = min_priority;
+ return something_new;
}
static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
@@ -3221,13 +3230,13 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
return source_set_pending(s, true);
}
-static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
- bool read_one = false;
+static int process_signal(sd_event *e, struct signal_data *d, uint32_t events, int64_t *min_priority) {
int r;
assert(e);
assert(d);
assert_return(events == EPOLLIN, -EIO);
+ assert(min_priority);
/* If there's a signal queued on this priority and SIGCHLD is
on this priority too, then make sure to recheck the
@@ -3253,7 +3262,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
n = read(d->fd, &si, sizeof(si));
if (n < 0) {
if (IN_SET(errno, EAGAIN, EINTR))
- return read_one;
+ return 0;
return -errno;
}
@@ -3263,8 +3272,6 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
assert(SIGNAL_VALID(si.ssi_signo));
- read_one = true;
-
if (e->signal_sources)
s = e->signal_sources[si.ssi_signo];
if (!s)
@@ -3278,12 +3285,16 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
r = source_set_pending(s, true);
if (r < 0)
return r;
+ if (r > 0 && *min_priority >= s->priority) {
+ *min_priority = s->priority;
+ return 1; /* an event source with smaller priority is queued. */
+ }
- return 1;
+ return 0;
}
}
-static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t revents) {
+static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t revents, int64_t threshold) {
ssize_t n;
assert(e);
@@ -3299,6 +3310,9 @@ static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t
if (d->buffer_filled > 0)
return 0;
+ if (d->priority > threshold)
+ return 0;
+
n = read(d->fd, &d->buffer, sizeof(d->buffer));
if (n < 0) {
if (IN_SET(errno, EAGAIN, EINTR))
@@ -3788,44 +3802,103 @@ pending:
return r;
}
-_public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
- size_t event_queue_max;
- int r, m, i;
+static int epoll_wait_usec(
+ int fd,
+ struct epoll_event *events,
+ int maxevents,
+ usec_t timeout) {
- assert_return(e, -EINVAL);
- assert_return(e = event_resolve(e), -ENOPKG);
- assert_return(!event_pid_changed(e), -ECHILD);
- assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
- assert_return(e->state == SD_EVENT_ARMED, -EBUSY);
+ int r, msec;
+#if 0
+ static bool epoll_pwait2_absent = false;
- if (e->exit_requested) {
- e->state = SD_EVENT_PENDING;
- return 1;
+ /* 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. */
+
+ if (!epoll_pwait2_absent && timeout != USEC_INFINITY) {
+ struct timespec ts;
+
+ r = epoll_pwait2(fd,
+ events,
+ maxevents,
+ timespec_store(&ts, timeout),
+ NULL);
+ if (r >= 0)
+ return r;
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+ return -errno; /* Only fallback to old epoll_wait() if the syscall is masked or not
+ * supported. */
+
+ epoll_pwait2_absent = true;
}
+#endif
- event_queue_max = MAX(e->n_sources, 1u);
- if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, event_queue_max))
+ if (timeout == USEC_INFINITY)
+ msec = -1;
+ else {
+ usec_t k;
+
+ k = DIV_ROUND_UP(timeout, USEC_PER_MSEC);
+ if (k >= INT_MAX)
+ msec = INT_MAX; /* Saturate */
+ else
+ msec = (int) k;
+ }
+
+ r = epoll_wait(fd,
+ events,
+ maxevents,
+ msec);
+ if (r < 0)
+ return -errno;
+
+ return r;
+}
+
+static int process_epoll(sd_event *e, usec_t timeout, int64_t threshold, int64_t *ret_min_priority) {
+ int64_t min_priority = threshold;
+ bool something_new = false;
+ size_t n_event_queue, m;
+ int r;
+
+ assert(e);
+ assert(ret_min_priority);
+
+ n_event_queue = MAX(e->n_sources, 1u);
+ if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, n_event_queue))
return -ENOMEM;
/* If we still have inotify data buffered, then query the other fds, but don't wait on it */
if (e->inotify_data_buffered)
timeout = 0;
- m = epoll_wait(e->epoll_fd, e->event_queue, event_queue_max,
- timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC));
- if (m < 0) {
- if (errno == EINTR) {
- e->state = SD_EVENT_PENDING;
- return 1;
- }
+ for (;;) {
+ r = epoll_wait_usec(e->epoll_fd, e->event_queue, e->event_queue_allocated, timeout);
+ if (r < 0)
+ return r;
- r = -errno;
- goto finish;
+ m = (size_t) r;
+
+ if (m < e->event_queue_allocated)
+ break;
+
+ if (e->event_queue_allocated >= n_event_queue * 10)
+ break;
+
+ if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, e->event_queue_allocated + n_event_queue))
+ return -ENOMEM;
+
+ timeout = 0;
}
- triple_timestamp_get(&e->timestamp);
+ /* Set timestamp only when this is called first time. */
+ if (threshold == INT64_MAX)
+ triple_timestamp_get(&e->timestamp);
- for (i = 0; i < m; i++) {
+ for (size_t i = 0; i < m; i++) {
if (e->event_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
r = flush_timer(e, e->watchdog_fd, e->event_queue[i].events, NULL);
@@ -3839,6 +3912,11 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
assert(s);
+ if (s->priority > threshold)
+ continue;
+
+ min_priority = MIN(min_priority, s->priority);
+
switch (s->type) {
case SOURCE_IO:
@@ -3866,11 +3944,11 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
}
case WAKEUP_SIGNAL_DATA:
- r = process_signal(e, e->event_queue[i].data.ptr, e->event_queue[i].events);
+ r = process_signal(e, e->event_queue[i].data.ptr, e->event_queue[i].events, &min_priority);
break;
case WAKEUP_INOTIFY_DATA:
- r = event_inotify_data_read(e, e->event_queue[i].data.ptr, e->event_queue[i].events);
+ r = event_inotify_data_read(e, e->event_queue[i].data.ptr, e->event_queue[i].events, threshold);
break;
default:
@@ -3878,7 +3956,63 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
}
}
if (r < 0)
+ return r;
+ if (r > 0)
+ something_new = true;
+ }
+
+ *ret_min_priority = min_priority;
+ return something_new;
+}
+
+_public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
+ int r;
+
+ assert_return(e, -EINVAL);
+ assert_return(e = event_resolve(e), -ENOPKG);
+ assert_return(!event_pid_changed(e), -ECHILD);
+ assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
+ assert_return(e->state == SD_EVENT_ARMED, -EBUSY);
+
+ if (e->exit_requested) {
+ e->state = SD_EVENT_PENDING;
+ return 1;
+ }
+
+ for (int64_t threshold = INT64_MAX; ; threshold--) {
+ int64_t epoll_min_priority, child_min_priority;
+
+ /* There may be a possibility that new epoll (especially IO) and child events are
+ * triggered just after process_epoll() call but before process_child(), and the new IO
+ * events may have higher priority than the child events. To salvage these events,
+ * let's call epoll_wait() again, but accepts only events with higher priority than the
+ * previous. See issue https://github.com/systemd/systemd/issues/18190 and comments
+ * https://github.com/systemd/systemd/pull/18750#issuecomment-785801085
+ * https://github.com/systemd/systemd/pull/18922#issuecomment-792825226 */
+
+ r = process_epoll(e, timeout, threshold, &epoll_min_priority);
+ if (r == -EINTR) {
+ e->state = SD_EVENT_PENDING;
+ return 1;
+ }
+ if (r < 0)
goto finish;
+ if (r == 0 && threshold < INT64_MAX)
+ /* No new epoll event. */
+ break;
+
+ r = process_child(e, threshold, &child_min_priority);
+ if (r < 0)
+ goto finish;
+ if (r == 0)
+ /* No new child event. */
+ break;
+
+ threshold = MIN(epoll_min_priority, child_min_priority);
+ if (threshold == INT64_MIN)
+ break;
+
+ timeout = 0;
}
r = process_watchdog(e);
@@ -3905,19 +4039,12 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
if (r < 0)
goto finish;
- if (e->need_process_child) {
- r = process_child(e);
- if (r < 0)
- goto finish;
- }
-
r = process_inotify(e);
if (r < 0)
goto finish;
if (event_next_pending(e)) {
e->state = SD_EVENT_PENDING;
-
return 1;
}
@@ -4029,7 +4156,7 @@ _public_ int sd_event_loop(sd_event *e) {
_unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
while (e->state != SD_EVENT_FINISHED) {
- r = sd_event_run(e, (uint64_t) -1);
+ r = sd_event_run(e, UINT64_MAX);
if (r < 0)
return r;
}
diff --git a/src/core/systemd/src/systemd/_sd-common.h b/src/core/systemd/src/systemd/_sd-common.h
index e3de2ae562..e121429640 100644
--- a/src/core/systemd/src/systemd/_sd-common.h
+++ b/src/core/systemd/src/systemd/_sd-common.h
@@ -99,4 +99,10 @@ typedef void (*_sd_destroy_t)(void *userdata);
} \
struct _sd_useless_struct_to_allow_trailing_semicolon_
+/* The following macro should be used in all public enums, to force 64bit wideness on them, so that we can
+ * freely extend them later on, without breaking compatibility. */
+#define _SD_ENUM_FORCE_S64(id) \
+ _SD_##id##_INT64_MIN = INT64_MIN, \
+ _SD_##id##_INT64_MAX = INT64_MAX
+
#endif
diff --git a/src/core/systemd/src/systemd/sd-dhcp-client.h b/src/core/systemd/src/systemd/sd-dhcp-client.h
index c35328a9a6..822286919e 100644
--- a/src/core/systemd/src/systemd/sd-dhcp-client.h
+++ b/src/core/systemd/src/systemd/sd-dhcp-client.h
@@ -181,7 +181,7 @@ int sd_dhcp_client_set_mud_url(
const char *mudurl);
int sd_dhcp_client_set_user_class(
sd_dhcp_client *client,
- const char* const *user_class);
+ char * const *user_class);
int sd_dhcp_client_get_lease(
sd_dhcp_client *client,
sd_dhcp_lease **ret);
diff --git a/src/core/systemd/src/systemd/sd-dhcp-lease.h b/src/core/systemd/src/systemd/sd-dhcp-lease.h
index c255a1f912..5abf9a406c 100644
--- a/src/core/systemd/src/systemd/sd-dhcp-lease.h
+++ b/src/core/systemd/src/systemd/sd-dhcp-lease.h
@@ -18,6 +18,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <errno.h>
#include <inttypes.h>
#include <net/ethernet.h>
#include <netinet/in.h>
@@ -33,7 +34,7 @@ typedef struct sd_dhcp_route sd_dhcp_route;
sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease);
sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease);
-typedef enum sd_dhcp_lease_server_type {
+typedef enum sd_dhcp_lease_server_type_t {
SD_DHCP_LEASE_DNS,
SD_DHCP_LEASE_NTP,
SD_DHCP_LEASE_SIP,
@@ -41,8 +42,9 @@ typedef enum sd_dhcp_lease_server_type {
SD_DHCP_LEASE_SMTP,
SD_DHCP_LEASE_LPR,
_SD_DHCP_LEASE_SERVER_TYPE_MAX,
- _SD_DHCP_LEASE_SERVER_TYPE_INVALID = -1,
-} sd_dhcp_lease_server_type;
+ _SD_DHCP_LEASE_SERVER_TYPE_INVALID = -EINVAL,
+ _SD_ENUM_FORCE_S64(DHCP_LEASE_SERVER_TYPE),
+} sd_dhcp_lease_server_type_t;
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime);
@@ -53,7 +55,7 @@ int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type what, const struct in_addr **addr);
+int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr);
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr);
diff --git a/src/core/systemd/src/systemd/sd-dhcp6-client.h b/src/core/systemd/src/systemd/sd-dhcp6-client.h
index 75ee27d68b..84e3170130 100644
--- a/src/core/systemd/src/systemd/sd-dhcp6-client.h
+++ b/src/core/systemd/src/systemd/sd-dhcp6-client.h
@@ -133,10 +133,10 @@ int sd_dhcp6_client_set_request_mud_url(
const char *mudurl);
int sd_dhcp6_client_set_request_user_class(
sd_dhcp6_client *client,
- char** user_class);
+ char * const *user_class);
int sd_dhcp6_client_set_request_vendor_class(
sd_dhcp6_client *client,
- char** vendor_class);
+ char * const *vendor_class);
int sd_dhcp6_client_set_prefix_delegation_hint(
sd_dhcp6_client *client,
uint8_t prefixlen,
diff --git a/src/core/systemd/src/systemd/sd-lldp.h b/src/core/systemd/src/systemd/sd-lldp.h
index f551f6b4fa..e48e29fbc0 100644
--- a/src/core/systemd/src/systemd/sd-lldp.h
+++ b/src/core/systemd/src/systemd/sd-lldp.h
@@ -17,6 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <errno.h>
#include <inttypes.h>
#include <net/ethernet.h>
#include <sys/types.h>
@@ -80,7 +81,7 @@ enum {
SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10,
};
-#define SD_LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1)
+#define SD_LLDP_SYSTEM_CAPABILITIES_ALL UINT16_MAX
#define SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \
((uint16_t) \
@@ -121,16 +122,17 @@ enum {
typedef struct sd_lldp sd_lldp;
typedef struct sd_lldp_neighbor sd_lldp_neighbor;
-typedef enum sd_lldp_event {
+typedef enum sd_lldp_event_t {
SD_LLDP_EVENT_ADDED,
SD_LLDP_EVENT_REMOVED,
SD_LLDP_EVENT_UPDATED,
SD_LLDP_EVENT_REFRESHED,
_SD_LLDP_EVENT_MAX,
- _SD_LLDP_EVENT_INVALID = -1,
-} sd_lldp_event;
+ _SD_LLDP_EVENT_INVALID = -EINVAL,
+ _SD_ENUM_FORCE_S64(LLDP_EVENT),
+} sd_lldp_event_t;
-typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata);
+typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event_t event, sd_lldp_neighbor *n, void *userdata);
int sd_lldp_new(sd_lldp **ret);
sd_lldp* sd_lldp_ref(sd_lldp *lldp);
diff --git a/src/core/systemd/src/systemd/sd-ndisc.h b/src/core/systemd/src/systemd/sd-ndisc.h
index c0e37899a7..49b127c018 100644
--- a/src/core/systemd/src/systemd/sd-ndisc.h
+++ b/src/core/systemd/src/systemd/sd-ndisc.h
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <errno.h>
#include <inttypes.h>
#include <net/ethernet.h>
#include <netinet/in.h>
@@ -54,14 +55,15 @@ enum {
typedef struct sd_ndisc sd_ndisc;
typedef struct sd_ndisc_router sd_ndisc_router;
-typedef enum sd_ndisc_event {
+typedef enum sd_ndisc_event_t {
SD_NDISC_EVENT_TIMEOUT,
SD_NDISC_EVENT_ROUTER,
_SD_NDISC_EVENT_MAX,
- _SD_NDISC_EVENT_INVALID = -1,
-} sd_ndisc_event;
+ _SD_NDISC_EVENT_INVALID = -EINVAL,
+ _SD_ENUM_FORCE_S64(NDISC_EVENT),
+} sd_ndisc_event_t;
-typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata);
+typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata);
int sd_ndisc_new(sd_ndisc **ret);
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.h b/src/libnm-systemd-shared/src/basic/alloc-util.h
index f3e192ddaf..698a6583c5 100644
--- a/src/libnm-systemd-shared/src/basic/alloc-util.h
+++ b/src/libnm-systemd-shared/src/basic/alloc-util.h
@@ -80,7 +80,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
})
static inline void freep(void *p) {
- free(*(void**) p);
+ *(void**)p = mfree(*(void**) p);
}
#define _cleanup_free_ _cleanup_(freep)
@@ -158,15 +158,6 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
(void*)memset(_new_, 0, _xsize_); \
})
-/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time
- * resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
-#define TAKE_PTR(ptr) \
- ({ \
- typeof(ptr) _ptr_ = (ptr); \
- (ptr) = NULL; \
- _ptr_; \
- })
-
#if HAS_FEATURE_MEMORY_SANITIZER
# define msan_unpoison(r, s) __msan_unpoison(r, s)
#else
diff --git a/src/libnm-systemd-shared/src/basic/cgroup-util.h b/src/libnm-systemd-shared/src/basic/cgroup-util.h
index bdc0d0d086..f79e384147 100644
--- a/src/libnm-systemd-shared/src/basic/cgroup-util.h
+++ b/src/libnm-systemd-shared/src/basic/cgroup-util.h
@@ -32,7 +32,7 @@ typedef enum CGroupController {
CGROUP_CONTROLLER_BPF_DEVICES,
_CGROUP_CONTROLLER_MAX,
- _CGROUP_CONTROLLER_INVALID = -1,
+ _CGROUP_CONTROLLER_INVALID = -EINVAL,
} CGroupController;
#define CGROUP_CONTROLLER_TO_MASK(c) (1U << (c))
@@ -75,13 +75,13 @@ CGroupMask get_cpu_accounting_mask(void);
bool cpu_accounting_is_cheap(void);
/* Special values for all weight knobs on unified hierarchy */
-#define CGROUP_WEIGHT_INVALID ((uint64_t) -1)
+#define CGROUP_WEIGHT_INVALID UINT64_MAX
#define CGROUP_WEIGHT_MIN UINT64_C(1)
#define CGROUP_WEIGHT_MAX UINT64_C(10000)
#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
#define CGROUP_LIMIT_MIN UINT64_C(0)
-#define CGROUP_LIMIT_MAX ((uint64_t) -1)
+#define CGROUP_LIMIT_MAX UINT64_MAX
static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) {
return
@@ -97,7 +97,7 @@ typedef enum CGroupIOLimitType {
CGROUP_IO_WIOPS_MAX,
_CGROUP_IO_LIMIT_TYPE_MAX,
- _CGROUP_IO_LIMIT_TYPE_INVALID = -1
+ _CGROUP_IO_LIMIT_TYPE_INVALID = -EINVAL,
} CGroupIOLimitType;
extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX];
@@ -106,7 +106,7 @@ const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_;
CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_;
/* Special values for the cpu.shares attribute */
-#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1)
+#define CGROUP_CPU_SHARES_INVALID UINT64_MAX
#define CGROUP_CPU_SHARES_MIN UINT64_C(2)
#define CGROUP_CPU_SHARES_MAX UINT64_C(262144)
#define CGROUP_CPU_SHARES_DEFAULT UINT64_C(1024)
@@ -118,7 +118,7 @@ static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) {
}
/* Special values for the blkio.weight attribute */
-#define CGROUP_BLKIO_WEIGHT_INVALID ((uint64_t) -1)
+#define CGROUP_BLKIO_WEIGHT_INVALID UINT64_MAX
#define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10)
#define CGROUP_BLKIO_WEIGHT_MAX UINT64_C(1000)
#define CGROUP_BLKIO_WEIGHT_DEFAULT UINT64_C(500)
@@ -212,10 +212,13 @@ int cg_get_attribute_as_uint64(const char *controller, const char *path, const c
int cg_get_attribute_as_bool(const char *controller, const char *path, const char *attribute, bool *ret);
int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid);
+int cg_get_owner(const char *controller, const char *path, uid_t *ret_uid);
int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags);
int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size);
int cg_get_xattr_malloc(const char *controller, const char *path, const char *name, char **ret);
+/* Returns negative on error, and 0 or 1 on success for the bool value */
+int cg_get_xattr_bool(const char *controller, const char *path, const char *name);
int cg_remove_xattr(const char *controller, const char *path, const char *name);
int cg_install_release_agent(const char *controller, const char *agent);
@@ -257,6 +260,7 @@ int cg_slice_to_path(const char *unit, char **ret);
typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata);
int cg_mask_supported(CGroupMask *ret);
+int cg_mask_supported_subtree(const char *root, CGroupMask *ret);
int cg_mask_from_string(const char *s, CGroupMask *ret);
int cg_mask_to_string(CGroupMask mask, char **ret);
@@ -283,8 +287,19 @@ typedef enum ManagedOOMMode {
MANAGED_OOM_AUTO,
MANAGED_OOM_KILL,
_MANAGED_OOM_MODE_MAX,
- _MANAGED_OOM_MODE_INVALID = -1,
+ _MANAGED_OOM_MODE_INVALID = -EINVAL,
} ManagedOOMMode;
const char* managed_oom_mode_to_string(ManagedOOMMode m) _const_;
ManagedOOMMode managed_oom_mode_from_string(const char *s) _pure_;
+
+typedef enum ManagedOOMPreference {
+ MANAGED_OOM_PREFERENCE_NONE = 0,
+ MANAGED_OOM_PREFERENCE_AVOID = 1,
+ MANAGED_OOM_PREFERENCE_OMIT = 2,
+ _MANAGED_OOM_PREFERENCE_MAX,
+ _MANAGED_OOM_PREFERENCE_INVALID = -EINVAL,
+} ManagedOOMPreference;
+
+const char* managed_oom_preference_to_string(ManagedOOMPreference a) _const_;
+ManagedOOMPreference managed_oom_preference_from_string(const char *s) _pure_;
diff --git a/src/libnm-systemd-shared/src/basic/dns-def.h b/src/libnm-systemd-shared/src/basic/dns-def.h
new file mode 100644
index 0000000000..d70220bcc0
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/dns-def.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+/* Length of a single label, with all escaping removed, excluding any trailing dot or NUL byte */
+#define DNS_LABEL_MAX 63
+
+/* Worst case length of a single label, with all escaping applied and room for a trailing NUL byte. */
+#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1)
+
+/* Maximum length of a full hostname, consisting of a series of unescaped labels, and no trailing dot or NUL byte */
+#define DNS_HOSTNAME_MAX 253
+
+/* Maximum length of a full hostname, on the wire, including the final NUL byte */
+#define DNS_WIRE_FORMAT_HOSTNAME_MAX 255
+
+/* Maximum number of labels per valid hostname */
+#define DNS_N_LABELS_MAX 127
diff --git a/src/libnm-systemd-shared/src/basic/env-file.c b/src/libnm-systemd-shared/src/basic/env-file.c
index 99c3e3f4a3..a300909360 100644
--- a/src/libnm-systemd-shared/src/basic/env-file.c
+++ b/src/libnm-systemd-shared/src/basic/env-file.c
@@ -20,7 +20,7 @@ static int parse_env_file_internal(
void *userdata,
int *n_pushed) {
- size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
+ size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX;
_cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
unsigned line = 1;
char *p;
@@ -56,7 +56,7 @@ static int parse_env_file_internal(
state = COMMENT;
else if (!strchr(WHITESPACE, c)) {
state = KEY;
- last_key_whitespace = (size_t) -1;
+ last_key_whitespace = SIZE_MAX;
if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
return -ENOMEM;
@@ -72,11 +72,11 @@ static int parse_env_file_internal(
n_key = 0;
} else if (c == '=') {
state = PRE_VALUE;
- last_value_whitespace = (size_t) -1;
+ last_value_whitespace = SIZE_MAX;
} else {
if (!strchr(WHITESPACE, c))
- last_key_whitespace = (size_t) -1;
- else if (last_key_whitespace == (size_t) -1)
+ last_key_whitespace = SIZE_MAX;
+ else if (last_key_whitespace == SIZE_MAX)
last_key_whitespace = n_key;
if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
@@ -97,7 +97,7 @@ static int parse_env_file_internal(
value[n_value] = 0;
/* strip trailing whitespace from key */
- if (last_key_whitespace != (size_t) -1)
+ if (last_key_whitespace != SIZE_MAX)
key[last_key_whitespace] = 0;
r = push(fname, line, key, value, userdata, n_pushed);
@@ -136,11 +136,11 @@ static int parse_env_file_internal(
value[n_value] = 0;
/* Chomp off trailing whitespace from value */
- if (last_value_whitespace != (size_t) -1)
+ if (last_value_whitespace != SIZE_MAX)
value[last_value_whitespace] = 0;
/* strip trailing whitespace from key */
- if (last_key_whitespace != (size_t) -1)
+ if (last_key_whitespace != SIZE_MAX)
key[last_key_whitespace] = 0;
r = push(fname, line, key, value, userdata, n_pushed);
@@ -153,11 +153,11 @@ static int parse_env_file_internal(
} else if (c == '\\') {
state = VALUE_ESCAPE;
- last_value_whitespace = (size_t) -1;
+ last_value_whitespace = SIZE_MAX;
} else {
if (!strchr(WHITESPACE, c))
- last_value_whitespace = (size_t) -1;
- else if (last_value_whitespace == (size_t) -1)
+ last_value_whitespace = SIZE_MAX;
+ else if (last_value_whitespace == SIZE_MAX)
last_value_whitespace = n_value;
if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
@@ -255,11 +255,11 @@ static int parse_env_file_internal(
value[n_value] = 0;
if (state == VALUE)
- if (last_value_whitespace != (size_t) -1)
+ if (last_value_whitespace != SIZE_MAX)
value[last_value_whitespace] = 0;
/* strip trailing whitespace from key */
- if (last_key_whitespace != (size_t) -1)
+ if (last_key_whitespace != SIZE_MAX)
key[last_key_whitespace] = 0;
r = push(fname, line, key, value, userdata, n_pushed);
@@ -385,11 +385,9 @@ static int load_env_file_push(
if (!p)
return -ENOMEM;
- r = strv_env_replace(m, p);
- if (r < 0) {
- free(p);
+ r = strv_env_replace_consume(m, p);
+ if (r < 0)
return r;
- }
if (n_pushed)
(*n_pushed)++;
diff --git a/src/libnm-systemd-shared/src/basic/env-util.c b/src/libnm-systemd-shared/src/basic/env-util.c
index a84863ff22..c110a750a5 100644
--- a/src/libnm-systemd-shared/src/basic/env-util.c
+++ b/src/libnm-systemd-shared/src/basic/env-util.c
@@ -12,6 +12,9 @@
#include "extract-word.h"
#include "macro.h"
#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "utf8.h"
@@ -22,8 +25,6 @@
"_"
static bool env_name_is_valid_n(const char *e, size_t n) {
- const char *p;
-
if (!e)
return false;
@@ -41,7 +42,7 @@ static bool env_name_is_valid_n(const char *e, size_t n) {
if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
return false;
- for (p = e; p < e + n; p++)
+ for (const char *p = e; p < e + n; p++)
if (!strchr(VALID_BASH_ENV_NAME_CHARS, *p))
return false;
@@ -59,16 +60,13 @@ bool env_value_is_valid(const char *e) {
if (!utf8_is_valid(e))
return false;
- /* bash allows tabs and newlines in environment variables, and so
- * should we */
- if (string_has_cc(e, "\t\n"))
- return false;
+ /* Note that variable *values* may contain control characters, in particular NL, TAB, BS, DEL, ESC…
+ * When printing those variables with show-environment, we'll escape them. Make sure to print
+ * environment variables carefully! */
- /* POSIX says the overall size of the environment block cannot
- * be > ARG_MAX, an individual assignment hence cannot be
- * either. Discounting the shortest possible variable name of
- * length 1, the equal sign and trailing NUL this hence leaves
- * ARG_MAX-3 as longest possible variable value. */
+ /* POSIX says the overall size of the environment block cannot be > ARG_MAX, an individual assignment
+ * hence cannot be either. Discounting the shortest possible variable name of length 1, the equal
+ * sign and trailing NUL this hence leaves ARG_MAX-3 as longest possible variable value. */
if (strlen(e) > sc_arg_max() - 3)
return false;
@@ -88,10 +86,8 @@ bool env_assignment_is_valid(const char *e) {
if (!env_value_is_valid(eq + 1))
return false;
- /* POSIX says the overall size of the environment block cannot
- * be > ARG_MAX, hence the individual variable assignments
- * cannot be either, but let's leave room for one trailing NUL
- * byte. */
+ /* POSIX says the overall size of the environment block cannot be > ARG_MAX, hence the individual
+ * variable assignments cannot be either, but let's leave room for one trailing NUL byte. */
if (strlen(e) > sc_arg_max() - 1)
return false;
@@ -189,14 +185,14 @@ static int env_append(char **r, char ***k, char **a) {
char **strv_env_merge(size_t n_lists, ...) {
_cleanup_strv_free_ char **ret = NULL;
- size_t n = 0, i;
+ size_t n = 0;
char **l, **k;
va_list ap;
/* Merges an arbitrary number of environment sets */
va_start(ap, n_lists);
- for (i = 0; i < n_lists; i++) {
+ for (size_t i = 0; i < n_lists; i++) {
l = va_arg(ap, char**);
n += strv_length(l);
}
@@ -210,7 +206,7 @@ char **strv_env_merge(size_t n_lists, ...) {
k = ret;
va_start(ap, n_lists);
- for (i = 0; i < n_lists; i++) {
+ for (size_t i = 0; i < n_lists; i++) {
l = va_arg(ap, char**);
if (env_append(ret, &k, l) < 0) {
va_end(ap);
@@ -276,10 +272,8 @@ char **strv_env_delete(char **x, size_t n_lists, ...) {
return NULL;
STRV_FOREACH(k, x) {
- size_t v;
-
va_start(ap, n_lists);
- for (v = 0; v < n_lists; v++) {
+ for (size_t v = 0; v < n_lists; v++) {
char **l, **j;
l = va_arg(ap, char**);
@@ -310,7 +304,6 @@ char **strv_env_delete(char **x, size_t n_lists, ...) {
}
char **strv_env_unset(char **l, const char *p) {
-
char **f, **t;
if (!l)
@@ -371,20 +364,23 @@ char **strv_env_unset_many(char **l, ...) {
return l;
}
-int strv_env_replace(char ***l, char *p) {
+int strv_env_replace_consume(char ***l, char *p) {
const char *t, *name;
char **f;
int r;
assert(p);
- /* Replace first occurrence of the env var or add a new one in the string list. Drop other occurrences. Edits
- * in-place. Does not copy p. p must be a valid key=value assignment.
- */
+ /* Replace first occurrence of the env var or add a new one in the string list. Drop other
+ * occurrences. Edits in-place. Does not copy p and CONSUMES p EVEN ON FAILURE.
+ *
+ * p must be a valid key=value assignment. */
t = strchr(p, '=');
- if (!t)
+ if (!t) {
+ free(p);
return -EINVAL;
+ }
name = strndupa(p, t - p);
@@ -396,39 +392,39 @@ int strv_env_replace(char ***l, char *p) {
}
/* We didn't find a match, we need to append p or create a new strv */
- r = strv_push(l, p);
+ r = strv_consume(l, p);
if (r < 0)
return r;
return 1;
}
-char **strv_env_set(char **x, const char *p) {
- _cleanup_strv_free_ char **ret = NULL;
- size_t n, m;
- char **k;
+int strv_env_replace_strdup(char ***l, const char *assignment) {
+ /* Like strv_env_replace_consume(), but copies the argument. */
- /* Overrides the env var setting of p, returns a new copy */
+ char *p = strdup(assignment);
+ if (!p)
+ return -ENOMEM;
- n = strv_length(x);
- m = n + 2;
- if (m < n) /* overflow? */
- return NULL;
+ return strv_env_replace_consume(l, p);
+}
- ret = new(char*, m);
- if (!ret)
- return NULL;
+int strv_env_assign(char ***l, const char *key, const char *value) {
+ if (!env_name_is_valid(key))
+ return -EINVAL;
- *ret = NULL;
- k = ret;
+ /* NULL removes assignment, "" creates an empty assignment. */
- if (env_append(ret, &k, x) < 0)
- return NULL;
+ if (!value) {
+ strv_env_unset(*l, key);
+ return 0;
+ }
- if (env_append(ret, &k, STRV_MAKE(p)) < 0)
- return NULL;
+ char *p = strjoin(key, "=", value);
+ if (!p)
+ return -ENOMEM;
- return TAKE_PTR(ret);
+ return strv_env_replace_consume(l, p);
}
char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
@@ -460,6 +456,18 @@ char *strv_env_get(char **l, const char *name) {
return strv_env_get_n(l, name, strlen(name), 0);
}
+char *strv_env_pairs_get(char **l, const char *name) {
+ char **key, **value, *result = NULL;
+
+ assert(name);
+
+ STRV_FOREACH_PAIR(key, value, l)
+ if (streq(*key, name))
+ result = *value;
+
+ return result;
+}
+
char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
char **p, **q;
int k = 0;
@@ -759,3 +767,78 @@ int set_unset_env(const char *name, const char *value, bool overwrite) {
return -errno;
return 0;
}
+
+int putenv_dup(const char *assignment, bool override) {
+ const char *e, *n;
+
+ e = strchr(assignment, '=');
+ if (!e)
+ return -EINVAL;
+
+ n = strndupa(assignment, e - assignment);
+
+ /* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
+ if (setenv(n, e + 1, override) < 0)
+ return -errno;
+ return 0;
+}
+
+int setenv_systemd_exec_pid(bool update_only) {
+ char str[DECIMAL_STR_MAX(pid_t)];
+ const char *e;
+
+ /* Update $SYSTEMD_EXEC_PID=pid except when '*' is set for the variable. */
+
+ e = secure_getenv("SYSTEMD_EXEC_PID");
+ if (!e && update_only)
+ return 0;
+
+ if (streq_ptr(e, "*"))
+ return 0;
+
+ xsprintf(str, PID_FMT, getpid_cached());
+
+ if (setenv("SYSTEMD_EXEC_PID", str, 1) < 0)
+ return -errno;
+
+ return 1;
+}
+
+int getenv_path_list(const char *name, char ***ret_paths) {
+ _cleanup_strv_free_ char **l = NULL;
+ const char *e;
+ char **p;
+ int r;
+
+ assert(name);
+ assert(ret_paths);
+
+ e = secure_getenv(name);
+ if (!e)
+ return -ENXIO;
+
+ r = strv_split_full(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to parse $%s: %m", name);
+
+ STRV_FOREACH(p, l) {
+ if (!path_is_absolute(*p))
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Path '%s' is not absolute, refusing.", *p);
+
+ if (!path_is_normalized(*p))
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Path '%s' is not normalized, refusing.", *p);
+
+ if (path_equal(*p, "/"))
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Path '%s' is the root fs, refusing.", *p);
+ }
+
+ if (strv_isempty(l))
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+ "No paths specified, refusing.");
+
+ *ret_paths = TAKE_PTR(l);
+ return 1;
+}
diff --git a/src/libnm-systemd-shared/src/basic/env-util.h b/src/libnm-systemd-shared/src/basic/env-util.h
index 6684b3350f..1fbe7e4270 100644
--- a/src/libnm-systemd-shared/src/basic/env-util.h
+++ b/src/libnm-systemd-shared/src/basic/env-util.h
@@ -42,16 +42,27 @@ bool strv_env_name_or_assignment_is_valid(char **l);
char **strv_env_merge(size_t n_lists, ...);
char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
-char **strv_env_set(char **x, const char *p); /* New copy ... */
char **strv_env_unset(char **l, const char *p); /* In place ... */
char **strv_env_unset_many(char **l, ...) _sentinel_;
-int strv_env_replace(char ***l, char *p); /* In place ... */
+int strv_env_replace_consume(char ***l, char *p); /* In place ... */
+int strv_env_replace_strdup(char ***l, const char *assignment);
+int strv_env_assign(char ***l, const char *key, const char *value);
char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) _pure_;
char *strv_env_get(char **x, const char *n) _pure_;
+char *strv_env_pairs_get(char **l, const char *name) _pure_;
int getenv_bool(const char *p);
int getenv_bool_secure(const char *p);
/* Like setenv, but calls unsetenv if value == NULL. */
int set_unset_env(const char *name, const char *value, bool overwrite);
+
+/* Like putenv, but duplicates the memory like setenv. */
+int putenv_dup(const char *assignment, bool override);
+
+int setenv_systemd_exec_pid(bool update_only);
+
+/* Parses and does sanity checks on an environment variable containing
+ * PATH-like colon-separated absolute paths */
+int getenv_path_list(const char *name, char ***ret_paths);
diff --git a/src/libnm-systemd-shared/src/basic/escape.c b/src/libnm-systemd-shared/src/basic/escape.c
index 31f3cda472..af785ecfa4 100644
--- a/src/libnm-systemd-shared/src/basic/escape.c
+++ b/src/libnm-systemd-shared/src/basic/escape.c
@@ -114,7 +114,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit,
* instead be copied directly.
*/
- if (length != (size_t) -1 && length < 1)
+ if (length != SIZE_MAX && length < 1)
return -EINVAL;
switch (p[0]) {
@@ -159,7 +159,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit,
/* hexadecimal encoding */
int a, b;
- if (length != (size_t) -1 && length < 3)
+ if (length != SIZE_MAX && length < 3)
return -EINVAL;
a = unhexchar(p[1]);
@@ -187,7 +187,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit,
size_t i;
uint32_t c;
- if (length != (size_t) -1 && length < 5)
+ if (length != SIZE_MAX && length < 5)
return -EINVAL;
for (i = 0; i < 4; i++) {
@@ -214,7 +214,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit,
size_t i;
char32_t c;
- if (length != (size_t) -1 && length < 9)
+ if (length != SIZE_MAX && length < 9)
return -EINVAL;
for (i = 0; i < 8; i++) {
@@ -251,7 +251,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit,
int a, b, c;
char32_t m;
- if (length != (size_t) -1 && length < 3)
+ if (length != SIZE_MAX && length < 3)
return -EINVAL;
a = unoctchar(p[0]);
diff --git a/src/libnm-systemd-shared/src/basic/extract-word.c b/src/libnm-systemd-shared/src/basic/extract-word.c
index 76b3fe12e3..d1af11318a 100644
--- a/src/libnm-systemd-shared/src/basic/extract-word.c
+++ b/src/libnm-systemd-shared/src/basic/extract-word.c
@@ -20,11 +20,10 @@
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
_cleanup_free_ char *s = NULL;
size_t allocated = 0, sz = 0;
- char c;
- int r;
-
char quote = 0; /* 0 or ' or " */
bool backslash = false; /* whether we've just seen a backslash */
+ char c;
+ int r;
assert(p);
assert(ret);
@@ -70,14 +69,14 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
return -ENOMEM;
if (c == 0) {
- if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
- (!quote || flags & EXTRACT_RELAX)) {
+ if ((flags & EXTRACT_UNESCAPE_RELAX) &&
+ (quote == 0 || flags & EXTRACT_RELAX)) {
/* If we find an unquoted trailing backslash and we're in
- * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
+ * EXTRACT_UNESCAPE_RELAX mode, keep it verbatim in the
* output.
*
* Unbalanced quotes will only be allowed in EXTRACT_RELAX
- * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
+ * mode, EXTRACT_UNESCAPE_RELAX mode does not allow them.
*/
s[sz++] = '\\';
goto finish_force_terminate;
@@ -92,7 +91,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
char32_t u;
if ((flags & EXTRACT_CUNESCAPE) &&
- (r = cunescape_one(*p, (size_t) -1, &u, &eight_bit, false)) >= 0) {
+ (r = cunescape_one(*p, SIZE_MAX, &u, &eight_bit, false)) >= 0) {
/* A valid escaped sequence */
assert(r >= 1);
@@ -103,10 +102,10 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
else
sz += utf8_encode_unichar(s + sz, u);
} else if ((flags & EXTRACT_UNESCAPE_SEPARATORS) &&
- strchr(separators, **p))
- /* An escaped separator char */
+ (strchr(separators, **p) || **p == '\\'))
+ /* An escaped separator char or the escape char itself */
s[sz++] = c;
- else if (flags & EXTRACT_CUNESCAPE_RELAX) {
+ else if (flags & EXTRACT_UNESCAPE_RELAX) {
s[sz++] = '\\';
s[sz++] = c;
} else
@@ -116,7 +115,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
backslash = false;
- } else if (quote) { /* inside either single or double quotes */
+ } else if (quote != 0) { /* inside either single or double quotes */
for (;; (*p)++, c = **p) {
if (c == 0) {
if (flags & EXTRACT_RELAX)
@@ -197,7 +196,7 @@ int extract_first_word_and_warn(
const char *rvalue) {
/* Try to unquote it, if it fails, warn about it and try again
- * but this time using EXTRACT_CUNESCAPE_RELAX to keep the
+ * but this time using EXTRACT_UNESCAPE_RELAX to keep the
* backslashes verbatim in invalid escape sequences. */
const char *save;
@@ -208,11 +207,11 @@ int extract_first_word_and_warn(
if (r >= 0)
return r;
- if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
+ if (r == -EINVAL && !(flags & EXTRACT_UNESCAPE_RELAX)) {
- /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
+ /* Retry it with EXTRACT_UNESCAPE_RELAX. */
*p = save;
- r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
+ r = extract_first_word(p, ret, separators, flags|EXTRACT_UNESCAPE_RELAX);
if (r >= 0) {
/* It worked this time, hence it must have been an invalid escape sequence. */
log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Ignoring unknown escape sequences: \"%s\"", *ret);
diff --git a/src/libnm-systemd-shared/src/basic/extract-word.h b/src/libnm-systemd-shared/src/basic/extract-word.h
index d1de32e580..0e9e77e93d 100644
--- a/src/libnm-systemd-shared/src/basic/extract-word.h
+++ b/src/libnm-systemd-shared/src/basic/extract-word.h
@@ -4,13 +4,15 @@
#include "macro.h"
typedef enum ExtractFlags {
- EXTRACT_RELAX = 1 << 0,
- EXTRACT_CUNESCAPE = 1 << 1,
- EXTRACT_CUNESCAPE_RELAX = 1 << 2,
- EXTRACT_UNESCAPE_SEPARATORS = 1 << 3,
- EXTRACT_UNQUOTE = 1 << 4,
- EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5,
- EXTRACT_RETAIN_ESCAPE = 1 << 6,
+ EXTRACT_RELAX = 1 << 0, /* Allow unbalanced quote and eat up trailing backslash. */
+ EXTRACT_CUNESCAPE = 1 << 1, /* Unescape known escape sequences. */
+ EXTRACT_UNESCAPE_RELAX = 1 << 2, /* Allow and keep unknown escape sequences, allow and keep trailing backslash. */
+ EXTRACT_UNESCAPE_SEPARATORS = 1 << 3, /* Unescape separators (those specified, or whitespace by default). */
+ EXTRACT_UNQUOTE = 1 << 4, /* Remove quoting with "" and ''. */
+ EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5, /* Don't treat multiple adjacent separators as one */
+ EXTRACT_RETAIN_ESCAPE = 1 << 6, /* Treat escape character '\' as any other character without special meaning */
+
+ /* Note that if no flags are specified, escaped escape characters will be silently stripped. */
} ExtractFlags;
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.c b/src/libnm-systemd-shared/src/basic/fd-util.c
index a03ba83e19..d63f012ad5 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.c
+++ b/src/libnm-systemd-shared/src/basic/fd-util.c
@@ -91,11 +91,9 @@ void safe_close_pair(int p[static 2]) {
}
void close_many(const int fds[], size_t n_fd) {
- size_t i;
-
assert(fds || n_fd <= 0);
- for (i = 0; i < n_fd; i++)
+ for (size_t i = 0; i < n_fd; i++)
safe_close(fds[i]);
}
@@ -179,11 +177,9 @@ int fd_cloexec(int fd, bool cloexec) {
}
_pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {
- size_t i;
-
assert(n_fdset == 0 || fdset);
- for (i = 0; i < n_fdset; i++)
+ for (size_t i = 0; i < n_fdset; i++)
if (fdset[i] == fd)
return true;
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.h b/src/libnm-systemd-shared/src/basic/fd-util.h
index 2162537b80..f05c2b5a15 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.h
+++ b/src/libnm-systemd-shared/src/basic/fd-util.h
@@ -41,8 +41,8 @@ static inline void fclosep(FILE **f) {
safe_fclose(*f);
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);
-DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, pclose, NULL);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL);
#define _cleanup_close_ _cleanup_(closep)
#define _cleanup_fclose_ _cleanup_(fclosep)
diff --git a/src/libnm-systemd-shared/src/basic/fileio.c b/src/libnm-systemd-shared/src/basic/fileio.c
index f4708bc05f..a158ab080d 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.c
+++ b/src/libnm-systemd-shared/src/basic/fileio.c
@@ -27,7 +27,8 @@
#include "string-util.h"
#include "tmpfile-util.h"
-#define READ_FULL_BYTES_MAX (4U*1024U*1024U)
+/* The maximum size of the file we'll read in one go. */
+#define READ_FULL_BYTES_MAX (4U*1024U*1024U - 1)
int fopen_unlocked(const char *path, const char *options, FILE **ret) {
assert(ret);
@@ -368,7 +369,6 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
struct stat st;
size_t n, size;
int n_retries;
- char *p;
assert(ret_contents);
@@ -385,8 +385,12 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
if (fd < 0)
return -errno;
- /* Start size for files in /proc which usually report a file size of 0. */
- size = LINE_MAX / 2;
+ /* Start size for files in /proc/ which usually report a file size of 0. (Files in /sys/ report a
+ * file size of 4K, which is probably OK for sizing our initial buffer, and sysfs attributes can't be
+ * larger anyway.)
+ *
+ * It's one less than 4k, so that the malloc() below allocates exactly 4k. */
+ size = 4095;
/* Limit the number of attempts to read the number of bytes returned by fstat(). */
n_retries = 3;
@@ -402,19 +406,27 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
return -EBADF;
/* Be prepared for files from /proc which generally report a file size of 0. */
+ assert_cc(READ_FULL_BYTES_MAX < SSIZE_MAX);
if (st.st_size > 0) {
+ if (st.st_size > READ_FULL_BYTES_MAX)
+ return -E2BIG;
+
size = st.st_size;
n_retries--;
- } else
- size = size * 2;
-
- if (size > READ_FULL_BYTES_MAX)
- return -E2BIG;
+ } else {
+ /* Double the buffer size */
+ if (size >= READ_FULL_BYTES_MAX)
+ return -E2BIG;
+ if (size > READ_FULL_BYTES_MAX / 2 - 1)
+ size = READ_FULL_BYTES_MAX; /* clamp to max */
+ else
+ size = size * 2 + 1; /* Stay always one less than page size, so we malloc evenly */
+ }
- p = realloc(buf, size + 1);
- if (!p)
+ buf = malloc(size + 1);
+ if (!buf)
return -ENOMEM;
- buf = TAKE_PTR(p);
+ size = malloc_usable_size(buf) - 1; /* Use a bigger allocation if we got it anyway */
for (;;) {
ssize_t k;
@@ -443,25 +455,28 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
if (lseek(fd, 0, SEEK_SET) < 0)
return -errno;
+
+ buf = mfree(buf);
}
if (n < size) {
+ char *p;
+
+ /* Return rest of the buffer to libc */
p = realloc(buf, n + 1);
if (!p)
return -ENOMEM;
+
buf = TAKE_PTR(p);
}
- if (!ret_size) {
- /* Safety check: if the caller doesn't want to know the size of what we
- * just read it will rely on the trailing NUL byte. But if there's an
- * embedded NUL byte, then we should refuse operation as otherwise
- * there'd be ambiguity about what we just read. */
-
- if (memchr(buf, 0, n))
- return -EBADMSG;
- } else
+ if (ret_size)
*ret_size = n;
+ else if (memchr(buf, 0, n))
+ /* Safety check: if the caller doesn't want to know the size of what we just read it will
+ * rely on the trailing NUL byte. But if there's an embedded NUL byte, then we should refuse
+ * operation as otherwise there'd be ambiguity about what we just read. */
+ return -EBADMSG;
buf[n] = 0;
*ret_contents = TAKE_PTR(buf);
@@ -546,7 +561,9 @@ int read_full_stream_full(
}
buf = t;
- n = n_next;
+ /* Unless a size has been explicitly specified, try to read as much as fits into the memory
+ * we allocated (minus 1, to leave one byte for the safety NUL byte) */
+ n = size == SIZE_MAX ? malloc_usable_size(buf) - 1 : n_next;
errno = 0;
k = fread(buf + l, 1, n - l, f);
@@ -1146,7 +1163,7 @@ static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) {
return EOL_NONE;
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, funlockfile, NULL);
int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
size_t n = 0, allocated = 0, count = 0;
@@ -1323,15 +1340,6 @@ int warn_file_is_world_accessible(const char *filename, struct stat *st, const c
return 0;
}
-int sync_rights(int from, int to) {
- struct stat st;
-
- if (fstat(from, &st) < 0)
- return -errno;
-
- return fchmod_and_chown(to, st.st_mode & 07777, st.st_uid, st.st_gid);
-}
-
int rename_and_apply_smack_floor_label(const char *from, const char *to) {
int r = 0;
if (rename(from, to) < 0)
diff --git a/src/libnm-systemd-shared/src/basic/fileio.h b/src/libnm-systemd-shared/src/basic/fileio.h
index 498e880354..64a30ab7bb 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.h
+++ b/src/libnm-systemd-shared/src/basic/fileio.h
@@ -118,6 +118,4 @@ int safe_fgetc(FILE *f, char *ret);
int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line);
-int sync_rights(int from, int to);
-
int rename_and_apply_smack_floor_label(const char *temp_path, const char *dest_path);
diff --git a/src/libnm-systemd-shared/src/basic/format-util.c b/src/libnm-systemd-shared/src/basic/format-util.c
index bf23037792..9920604f3a 100644
--- a/src/libnm-systemd-shared/src/basic/format-util.c
+++ b/src/libnm-systemd-shared/src/basic/format-util.c
@@ -43,17 +43,17 @@ char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {
{ "K", UINT64_C(1000) },
};
const suffix_table *table;
- size_t n, i;
+ size_t n;
assert_cc(ELEMENTSOF(table_iec) == ELEMENTSOF(table_si));
- if (t == (uint64_t) -1)
+ if (t == UINT64_MAX)
return NULL;
table = flag & FORMAT_BYTES_USE_IEC ? table_iec : table_si;
n = ELEMENTSOF(table_iec);
- for (i = 0; i < n; i++)
+ for (size_t i = 0; i < n; i++)
if (t >= table[i].factor) {
if (flag & FORMAT_BYTES_BELOW_POINT) {
snprintf(buf, l,
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c
index 7f44b93726..b2a4e8036f 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.c
+++ b/src/libnm-systemd-shared/src/basic/fs-util.c
@@ -100,7 +100,7 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
/* renameat2() exists since Linux 3.15, btrfs and FAT added support for it later. If it is not implemented,
* fall back to a different method. */
- if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY))
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL)
return -errno;
/* Let's try to use linkat()+unlinkat() as fallback. This doesn't work on directories and on some file systems
@@ -117,7 +117,7 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
return 0;
}
- if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)) /* FAT returns EPERM on link()… */
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !IN_SET(errno, EINVAL, EPERM)) /* FAT returns EPERM on link()… */
return -errno;
/* OK, neither RENAME_NOREPLACE nor linkat()+unlinkat() worked. Let's then fall back to the racy TOCTOU
@@ -135,34 +135,34 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
}
int readlinkat_malloc(int fd, const char *p, char **ret) {
- size_t l = FILENAME_MAX+1;
- int r;
+ size_t l = PATH_MAX;
assert(p);
assert(ret);
for (;;) {
- char *c;
+ _cleanup_free_ char *c = NULL;
ssize_t n;
- c = new(char, l);
+ c = new(char, l+1);
if (!c)
return -ENOMEM;
- n = readlinkat(fd, p, c, l-1);
- if (n < 0) {
- r = -errno;
- free(c);
- return r;
- }
+ n = readlinkat(fd, p, c, l);
+ if (n < 0)
+ return -errno;
- if ((size_t) n < l-1) {
+ if ((size_t) n < l) {
c[n] = 0;
- *ret = c;
+ *ret = TAKE_PTR(c);
return 0;
}
- free(c);
+ if (l > (SSIZE_MAX-1)/2) /* readlinkat() returns an ssize_t, and we want an extra byte for a
+ * trailing NUL, hence do an overflow check relative to SSIZE_MAX-1
+ * here */
+ return -EFBIG;
+
l *= 2;
}
}
@@ -428,9 +428,9 @@ int symlink_idempotent(const char *from, const char *to, bool make_relative) {
if (make_relative) {
_cleanup_free_ char *parent = NULL;
- parent = dirname_malloc(to);
- if (!parent)
- return -ENOMEM;
+ r = path_extract_directory(to, &parent);
+ if (r < 0)
+ return r;
r = path_make_relative(parent, from, &relpath);
if (r < 0)
@@ -1413,33 +1413,45 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
int fsync_directory_of_file(int fd) {
_cleanup_free_ char *path = NULL;
_cleanup_close_ int dfd = -1;
+ struct stat st;
int r;
- r = fd_verify_regular(fd);
- if (r < 0)
- return r;
+ assert(fd >= 0);
- r = fd_get_path(fd, &path);
- if (r < 0) {
- log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m",
- fd,
- r == -ENOSYS ? ", ignoring" : "");
+ /* We only reasonably can do this for regular files and directories, hence check for that */
+ if (fstat(fd, &st) < 0)
+ return -errno;
- if (r == -ENOSYS)
- /* If /proc is not available, we're most likely running in some
- * chroot environment, and syncing the directory is not very
- * important in that case. Let's just silently do nothing. */
- return 0;
+ if (S_ISREG(st.st_mode)) {
- return r;
- }
+ r = fd_get_path(fd, &path);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m",
+ fd,
+ r == -ENOSYS ? ", ignoring" : "");
- if (!path_is_absolute(path))
- return -EINVAL;
+ if (r == -ENOSYS)
+ /* If /proc is not available, we're most likely running in some
+ * chroot environment, and syncing the directory is not very
+ * important in that case. Let's just silently do nothing. */
+ return 0;
+
+ return r;
+ }
+
+ if (!path_is_absolute(path))
+ return -EINVAL;
+
+ dfd = open_parent(path, O_CLOEXEC|O_NOFOLLOW, 0);
+ if (dfd < 0)
+ return dfd;
- dfd = open_parent(path, O_CLOEXEC, 0);
- if (dfd < 0)
- return dfd;
+ } else if (S_ISDIR(st.st_mode)) {
+ dfd = openat(fd, "..", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0);
+ if (dfd < 0)
+ return -errno;
+ } else
+ return -ENOTTY;
if (fsync(dfd) < 0)
return -errno;
@@ -1453,9 +1465,14 @@ int fsync_full(int fd) {
/* Sync both the file and the directory */
r = fsync(fd) < 0 ? -errno : 0;
- q = fsync_directory_of_file(fd);
- return r < 0 ? r : q;
+ q = fsync_directory_of_file(fd);
+ if (r < 0) /* Return earlier error */
+ return r;
+ if (q == -ENOTTY) /* Ignore if the 'fd' refers to a block device or so which doesn't really have a
+ * parent dir */
+ return 0;
+ return q;
}
int fsync_path_at(int at_fd, const char *path) {
@@ -1472,8 +1489,7 @@ int fsync_path_at(int at_fd, const char *path) {
} else
fd = at_fd;
} else {
-
- opened_fd = openat(at_fd, path, O_RDONLY|O_CLOEXEC);
+ opened_fd = openat(at_fd, path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (opened_fd < 0)
return -errno;
@@ -1503,16 +1519,11 @@ int syncfs_path(int atfd, const char *path) {
int open_parent(const char *path, int flags, mode_t mode) {
_cleanup_free_ char *parent = NULL;
- int fd;
-
- if (isempty(path))
- return -EINVAL;
- if (path_equal(path, "/")) /* requesting the parent of the root dir is fishy, let's prohibit that */
- return -EINVAL;
+ int fd, r;
- parent = dirname_malloc(path);
- if (!parent)
- return -ENOMEM;
+ r = path_extract_directory(path, &parent);
+ if (r < 0)
+ return r;
/* Let's insist on O_DIRECTORY since the parent of a file or directory is a directory. Except if we open an
* O_TMPFILE file, because in that case we are actually create a regular file below the parent directory. */
@@ -1614,7 +1625,7 @@ int path_is_encrypted(const char *path) {
return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
}
-int conservative_rename(
+int conservative_renameat(
int olddirfd, const char *oldpath,
int newdirfd, const char *newpath) {
@@ -1656,23 +1667,37 @@ int conservative_rename(
goto do_rename;
for (;;) {
- char buf1[16*1024];
- char buf2[sizeof(buf1) + 1];
+ uint8_t buf1[16*1024];
+ uint8_t buf2[sizeof(buf1)];
ssize_t l1, l2;
l1 = read(old_fd, buf1, sizeof(buf1));
if (l1 < 0)
goto do_rename;
- l2 = read(new_fd, buf2, l1 + 1);
- if (l1 != l2)
- goto do_rename;
+ if (l1 == sizeof(buf1))
+ /* Read the full block, hence read a full block in the other file too */
- if (l1 == 0) /* EOF on both! And everything's the same so far, yay! */
- break;
+ l2 = read(new_fd, buf2, l1);
+ else {
+ assert((size_t) l1 < sizeof(buf1));
+
+ /* Short read. This hence was the last block in the first file, and then came
+ * EOF. Read one byte more in the second file, so that we can verify we hit EOF there
+ * too. */
+
+ assert((size_t) (l1 + 1) <= sizeof(buf2));
+ l2 = read(new_fd, buf2, l1 + 1);
+ }
+ if (l2 != l1)
+ goto do_rename;
if (memcmp(buf1, buf2, l1) != 0)
goto do_rename;
+
+ if ((size_t) l1 < sizeof(buf1)) /* We hit EOF on the first file, and the second file too, hence exit
+ * now. */
+ break;
}
is_same:
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.h b/src/libnm-systemd-shared/src/basic/fs-util.h
index 9a39473567..45115fd3db 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.h
+++ b/src/libnm-systemd-shared/src/basic/fs-util.h
@@ -11,6 +11,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include "alloc-util.h"
#include "errno-util.h"
#include "time-util.h"
@@ -43,7 +44,8 @@ int futimens_opath(int fd, const struct timespec ts[2]);
int fd_warn_permissions(const char *path, int fd);
int stat_warn_permissions(const char *path, const struct stat *st);
-#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
+#define laccess(path, mode) \
+ (faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) < 0 ? -errno : 0)
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
int touch(const char *path);
@@ -99,16 +101,23 @@ int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chas
int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd);
/* Useful for usage with _cleanup_(), removes a directory and frees the pointer */
-static inline void rmdir_and_free(char *p) {
+static inline char *rmdir_and_free(char *p) {
PROTECT_ERRNO;
+
+ if (!p)
+ return NULL;
+
(void) rmdir(p);
- free(p);
+ return mfree(p);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rmdir_and_free);
-static inline void unlink_and_free(char *p) {
+static inline char* unlink_and_free(char *p) {
+ if (!p)
+ return NULL;
+
(void) unlink_noerrno(p);
- free(p);
+ return mfree(p);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free);
@@ -133,4 +142,7 @@ int open_parent(const char *path, int flags, mode_t mode);
int path_is_encrypted(const char *path);
-int conservative_rename(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
+int conservative_renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
+static inline int conservative_rename(const char *oldpath, const char *newpath) {
+ return conservative_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath);
+}
diff --git a/src/libnm-systemd-shared/src/basic/hashmap.c b/src/libnm-systemd-shared/src/basic/hashmap.c
index cdc6847edf..e354c67adc 100644
--- a/src/libnm-systemd-shared/src/basic/hashmap.c
+++ b/src/libnm-systemd-shared/src/basic/hashmap.c
@@ -845,6 +845,16 @@ int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBU
return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
}
+int _hashmap_ensure_put(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS) {
+ int r;
+
+ r = _hashmap_ensure_allocated(h, hash_ops HASHMAP_DEBUG_PASS_ARGS);
+ if (r < 0)
+ return r;
+
+ return hashmap_put(*h, key, value);
+}
+
int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS) {
int r;
@@ -2026,3 +2036,35 @@ int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **
*ret = TAKE_PTR(str);
return 0;
}
+
+bool set_equal(Set *a, Set *b) {
+ void *p;
+
+ /* Checks whether each entry of 'a' is also in 'b' and vice versa, i.e. the two sets contain the same
+ * entries */
+
+ if (a == b)
+ return true;
+
+ if (set_isempty(a) && set_isempty(b))
+ return true;
+
+ if (set_size(a) != set_size(b)) /* Cheap check that hopefully catches a lot of inequality cases
+ * already */
+ return false;
+
+ SET_FOREACH(p, a)
+ if (!set_contains(b, p))
+ return false;
+
+ /* If we have the same hashops, then we don't need to check things backwards given we compared the
+ * size and that all of a is in b. */
+ if (a->b.hash_ops == b->b.hash_ops)
+ return true;
+
+ SET_FOREACH(p, b)
+ if (!set_contains(a, p))
+ return false;
+
+ return true;
+}
diff --git a/src/libnm-systemd-shared/src/basic/hashmap.h b/src/libnm-systemd-shared/src/basic/hashmap.h
index e99448375e..c20ee8eb4b 100644
--- a/src/libnm-systemd-shared/src/basic/hashmap.h
+++ b/src/libnm-systemd-shared/src/basic/hashmap.h
@@ -133,8 +133,11 @@ HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS);
#define ordered_hashmap_copy(h) ((OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS))
int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+int _hashmap_ensure_put(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS);
int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+
#define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+#define hashmap_ensure_put(s, ops, key, value) _hashmap_ensure_put(s, ops, key, value HASHMAP_DEBUG_SRC_ARGS)
#define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS);
diff --git a/src/libnm-systemd-shared/src/basic/hexdecoct.c b/src/libnm-systemd-shared/src/basic/hexdecoct.c
index da60202e57..cb0104670f 100644
--- a/src/libnm-systemd-shared/src/basic/hexdecoct.c
+++ b/src/libnm-systemd-shared/src/basic/hexdecoct.c
@@ -119,7 +119,7 @@ int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_
assert(ret_len);
assert(p || l == 0);
- if (l == (size_t) -1)
+ if (l == SIZE_MAX)
l = strlen(p);
/* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
@@ -309,7 +309,7 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l
assert(mem);
assert(_len);
- if (l == (size_t) -1)
+ if (l == SIZE_MAX)
l = strlen(p);
/* padding ensures any base32hex input has input divisible by 8 */
@@ -708,7 +708,7 @@ int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *r
assert(ret);
assert(ret_size);
- if (l == (size_t) -1)
+ if (l == SIZE_MAX)
l = strlen(p);
/* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.c b/src/libnm-systemd-shared/src/basic/hostname-util.c
index d7aba2c263..29d69910d2 100644
--- a/src/libnm-systemd-shared/src/basic/hostname-util.c
+++ b/src/libnm-systemd-shared/src/basic/hostname-util.c
@@ -3,14 +3,39 @@
#include <errno.h>
#include <limits.h>
#include <stdio.h>
+#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>
#include "alloc-util.h"
#include "hostname-util.h"
+#include "os-util.h"
#include "string-util.h"
#include "strv.h"
+char* get_default_hostname(void) {
+ int r;
+
+ const char *e = secure_getenv("SYSTEMD_DEFAULT_HOSTNAME");
+ if (e) {
+ if (hostname_is_valid(e, 0))
+ return strdup(e);
+ log_debug("Invalid hostname in $SYSTEMD_DEFAULT_HOSTNAME, ignoring: %s", e);
+ }
+
+ _cleanup_free_ char *f = NULL;
+ r = parse_os_release(NULL, "DEFAULT_HOSTNAME", &f);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse os-release, ignoring: %m");
+ else if (f) {
+ if (hostname_is_valid(f, 0))
+ return TAKE_PTR(f);
+ log_debug("Invalid hostname in os-release, ignoring: %s", f);
+ }
+
+ return strdup(FALLBACK_HOSTNAME);
+}
+
char* gethostname_malloc(void) {
struct utsname u;
const char *s;
@@ -23,7 +48,7 @@ char* gethostname_malloc(void) {
s = u.nodename;
if (isempty(s) || streq(s, "(none)"))
- s = FALLBACK_HOSTNAME;
+ return get_default_hostname();
return strdup(s);
}
@@ -31,6 +56,7 @@ char* gethostname_malloc(void) {
char* gethostname_short_malloc(void) {
struct utsname u;
const char *s;
+ _cleanup_free_ char *f = NULL;
/* Like above, but kills the FQDN part if present. */
@@ -38,7 +64,10 @@ char* gethostname_short_malloc(void) {
s = u.nodename;
if (isempty(s) || streq(s, "(none)") || s[0] == '.') {
- s = FALLBACK_HOSTNAME;
+ s = f = get_default_hostname();
+ if (!s)
+ return NULL;
+
assert(s[0] != '.');
}
diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.h b/src/libnm-systemd-shared/src/basic/hostname-util.h
index 6cff9c1d4c..576ca083e0 100644
--- a/src/libnm-systemd-shared/src/basic/hostname-util.h
+++ b/src/libnm-systemd-shared/src/basic/hostname-util.h
@@ -7,6 +7,7 @@
#include "macro.h"
#include "strv.h"
+char* get_default_hostname(void);
char* gethostname_malloc(void);
char* gethostname_short_malloc(void);
int gethostname_strict(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 a4f13b620a..f7a7252f1a 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.c
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c
@@ -24,6 +24,12 @@ bool in4_addr_is_null(const struct in_addr *a) {
return a->s_addr == 0;
}
+bool in6_addr_is_null(const struct in6_addr *a) {
+ assert(a);
+
+ return IN6_IS_ADDR_UNSPECIFIED(a);
+}
+
int in_addr_is_null(int family, const union in_addr_union *u) {
assert(u);
@@ -31,7 +37,7 @@ int in_addr_is_null(int family, const union in_addr_union *u) {
return in4_addr_is_null(&u->in);
if (family == AF_INET6)
- return IN6_IS_ADDR_UNSPECIFIED(&u->in6);
+ return in6_addr_is_null(&u->in6);
return -EAFNOSUPPORT;
}
@@ -42,6 +48,12 @@ bool in4_addr_is_link_local(const struct in_addr *a) {
return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
}
+bool in6_addr_is_link_local(const struct in6_addr *a) {
+ assert(a);
+
+ return IN6_IS_ADDR_LINKLOCAL(a);
+}
+
int in_addr_is_link_local(int family, const union in_addr_union *u) {
assert(u);
@@ -49,7 +61,7 @@ int in_addr_is_link_local(int family, const union in_addr_union *u) {
return in4_addr_is_link_local(&u->in);
if (family == AF_INET6)
- return IN6_IS_ADDR_LINKLOCAL(&u->in6);
+ return in6_addr_is_link_local(&u->in6);
return -EAFNOSUPPORT;
}
@@ -116,6 +128,13 @@ bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) {
return a->s_addr == b->s_addr;
}
+bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b) {
+ assert(a);
+ assert(b);
+
+ return IN6_ARE_ADDR_EQUAL(a, b);
+}
+
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) {
assert(a);
assert(b);
@@ -124,7 +143,7 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_
return in4_addr_equal(&a->in, &b->in);
if (family == AF_INET6)
- return IN6_ARE_ADDR_EQUAL(&a->in6, &b->in6);
+ return in6_addr_equal(&a->in6, &b->in6);
return -EAFNOSUPPORT;
}
@@ -189,8 +208,8 @@ int in_addr_prefix_intersect(
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) {
assert(u);
- /* Increases the network part of an address by one. Returns
- * positive if that succeeds, or -ERANGE if this overflows. */
+ /* Increases the network part of an address by one. Returns 0 if that succeeds, or -ERANGE if
+ * this overflows. */
return in_addr_prefix_nth(family, u, prefixlen, 1);
}
@@ -198,19 +217,17 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen)
/*
* Calculates the nth prefix of size prefixlen starting from the address denoted by u.
*
- * On success 1 will be returned and the calculated prefix will be available in
- * u. In the case nth == 0 the input will be left unchanged and 1 will be returned.
- * In case the calculation cannot be performed (invalid prefix length,
+ * On success 0 will be returned and the calculated prefix will be available in
+ * u. In case the calculation cannot be performed (invalid prefix length,
* overflows would occur) -ERANGE is returned. If the address family given isn't
* supported -EAFNOSUPPORT will be returned.
*
- *
* Examples:
- * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 2), returns 1, writes 192.168.2.0 to u
- * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 0), returns 1, no data written
+ * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 2), returns 0, writes 192.168.2.0 to u
+ * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 0), returns 0, no data written
* - in_addr_prefix_nth(AF_INET, 255.255.255.0, 24, 1), returns -ERANGE, no data written
* - in_addr_prefix_nth(AF_INET, 255.255.255.0, 0, 1), returns -ERANGE, no data written
- * - in_addr_prefix_nth(AF_INET6, 2001:db8, 64, 0xff00) returns 1, writes 2001:0db8:0000:ff00:: to u
+ * - in_addr_prefix_nth(AF_INET6, 2001:db8, 64, 0xff00) returns 0, writes 2001:0db8:0000:ff00:: to u
*/
int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth) {
assert(u);
@@ -218,13 +235,11 @@ int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, u
if (prefixlen <= 0)
return -ERANGE;
- if (nth == 0)
- return 1;
-
if (family == AF_INET) {
uint32_t c, n, t;
+
if (prefixlen > 32)
- prefixlen = 32;
+ return -ERANGE;
c = be32toh(u->in.s_addr);
@@ -238,44 +253,40 @@ int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, u
n &= UINT32_C(0xFFFFFFFF) << (32 - prefixlen);
u->in.s_addr = htobe32(n);
- return 1;
+ return 0;
}
if (family == AF_INET6) {
- struct in6_addr result = {};
- uint8_t overflow = 0;
- uint64_t delta; /* this assumes that we only ever have to up to 1<<64 subnets */
- unsigned start_byte = (prefixlen - 1) / 8;
+ bool overflow = false;
if (prefixlen > 128)
- prefixlen = 128;
-
- /* First calculate what we have to add */
- delta = nth << ((128 - prefixlen) % 8);
+ return -ERANGE;
for (unsigned i = 16; i > 0; i--) {
- unsigned j = i - 1;
- unsigned d = 0;
-
- if (j <= start_byte) {
- int16_t t;
+ unsigned t, j = i - 1, p = j * 8;
- d = delta & 0xFF;
- delta >>= 8;
+ if (p >= prefixlen) {
+ u->in6.s6_addr[j] = 0;
+ continue;
+ }
- t = u->in6.s6_addr[j] + d + overflow;
- overflow = t > UINT8_MAX ? t - UINT8_MAX : 0;
+ if (prefixlen - p < 8) {
+ u->in6.s6_addr[j] &= 0xff << (8 - (prefixlen - p));
+ t = u->in6.s6_addr[j] + ((nth & 0xff) << (8 - (prefixlen - p)));
+ nth >>= prefixlen - p;
+ } else {
+ t = u->in6.s6_addr[j] + (nth & 0xff) + overflow;
+ nth >>= 8;
+ }
- result.s6_addr[j] = (uint8_t)t;
- } else
- result.s6_addr[j] = u->in6.s6_addr[j];
+ overflow = t > UINT8_MAX;
+ u->in6.s6_addr[j] = (uint8_t) (t & 0xff);
}
- if (overflow || delta != 0)
+ if (overflow || nth != 0)
return -ERANGE;
- u->in6 = result;
- return 1;
+ return 0;
}
return -EAFNOSUPPORT;
@@ -358,6 +369,43 @@ int in_addr_random_prefix(
return -EAFNOSUPPORT;
}
+int in_addr_prefix_range(
+ int family,
+ const union in_addr_union *in,
+ unsigned prefixlen,
+ union in_addr_union *ret_start,
+ union in_addr_union *ret_end) {
+
+ union in_addr_union start, end;
+ int r;
+
+ assert(in);
+
+ if (!IN_SET(family, AF_INET, AF_INET6))
+ return -EAFNOSUPPORT;
+
+ if (ret_start) {
+ start = *in;
+ r = in_addr_prefix_nth(family, &start, prefixlen, 0);
+ if (r < 0)
+ return r;
+ }
+
+ if (ret_end) {
+ end = *in;
+ r = in_addr_prefix_nth(family, &end, prefixlen, 1);
+ if (r < 0)
+ return r;
+ }
+
+ if (ret_start)
+ *ret_start = start;
+ if (ret_end)
+ *ret_end = end;
+
+ return 0;
+}
+
int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
_cleanup_free_ char *x = NULL;
size_t l;
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 24308b702e..519ee53b3a 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.h
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h
@@ -21,11 +21,29 @@ struct in_addr_data {
};
bool in4_addr_is_null(const struct in_addr *a);
+static inline bool in4_addr_is_set(const struct in_addr *a) {
+ return !in4_addr_is_null(a);
+}
+bool in6_addr_is_null(const struct in6_addr *a);
+static inline bool in6_addr_is_set(const struct in6_addr *a) {
+ return !in6_addr_is_null(a);
+}
int in_addr_is_null(int family, const union in_addr_union *u);
+static inline bool in_addr_is_set(int family, const union in_addr_union *u) {
+ return in_addr_is_null(family, u) == 0;
+}
+static inline int in_addr_data_is_null(const struct in_addr_data *a) {
+ assert(a);
+ return in_addr_is_null(a->family, &a->address);
+}
+static inline bool in_addr_data_is_set(const struct in_addr_data *a) {
+ return in_addr_data_is_null(a);
+}
int in_addr_is_multicast(int family, const union in_addr_union *u);
bool in4_addr_is_link_local(const struct in_addr *a);
+bool in6_addr_is_link_local(const struct in6_addr *a);
int in_addr_is_link_local(int family, const union in_addr_union *u);
bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a);
@@ -36,11 +54,18 @@ bool in4_addr_is_local_multicast(const struct in_addr *a);
bool in4_addr_is_non_local(const struct in_addr *a);
bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b);
+bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b);
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth);
int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen);
+int in_addr_prefix_range(
+ int family,
+ const union in_addr_union *in,
+ unsigned prefixlen,
+ union in_addr_union *ret_start,
+ union in_addr_union *ret_end);
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret);
diff --git a/src/libnm-systemd-shared/src/basic/io-util.c b/src/libnm-systemd-shared/src/basic/io-util.c
index 4d7405296b..f0a66da9bf 100644
--- a/src/libnm-systemd-shared/src/basic/io-util.c
+++ b/src/libnm-systemd-shared/src/basic/io-util.c
@@ -2,7 +2,6 @@
#include <errno.h>
#include <limits.h>
-#include <poll.h>
#include <stdio.h>
#include <unistd.h>
@@ -159,24 +158,42 @@ int pipe_eof(int fd) {
return !!(r & POLLHUP);
}
-int fd_wait_for_event(int fd, int event, usec_t t) {
-
- struct pollfd pollfd = {
- .fd = fd,
- .events = event,
- };
-
+int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) {
struct timespec ts;
int r;
- r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
+ assert(fds || nfds == 0);
+
+ if (nfds == 0)
+ return 0;
+
+ r = ppoll(fds, nfds, timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL);
if (r < 0)
return -errno;
if (r == 0)
return 0;
- if (pollfd.revents & POLLNVAL)
- return -EBADF;
+ for (size_t i = 0, n = r; i < nfds && n > 0; i++) {
+ if (fds[i].revents == 0)
+ continue;
+ if (fds[i].revents & POLLNVAL)
+ return -EBADF;
+ n--;
+ }
+
+ return r;
+}
+
+int fd_wait_for_event(int fd, int event, usec_t timeout) {
+ struct pollfd pollfd = {
+ .fd = fd,
+ .events = event,
+ };
+ int r;
+
+ r = ppoll_usec(&pollfd, 1, timeout);
+ if (r <= 0)
+ return r;
return pollfd.revents;
}
@@ -319,16 +336,14 @@ int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, ch
}
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) {
- size_t i;
-
- for (i = 0; i < iovw->count; i++)
+ for (size_t i = 0; i < iovw->count; i++)
iovw->iovec[i].iov_base = (char *)iovw->iovec[i].iov_base - old + new;
}
size_t iovw_size(struct iovec_wrapper *iovw) {
- size_t n = 0, i;
+ size_t n = 0;
- for (i = 0; i < iovw->count; i++)
+ for (size_t i = 0; i < iovw->count; i++)
n += iovw->iovec[i].iov_len;
return n;
diff --git a/src/libnm-systemd-shared/src/basic/io-util.h b/src/libnm-systemd-shared/src/basic/io-util.h
index d817714b05..d98817f760 100644
--- a/src/libnm-systemd-shared/src/basic/io-util.h
+++ b/src/libnm-systemd-shared/src/basic/io-util.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <poll.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -18,6 +19,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
int pipe_eof(int fd);
+int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout);
int fd_wait_for_event(int fd, int event, usec_t timeout);
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
@@ -60,7 +62,7 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
/* Same as above, but allows one extra value: -1 as indication for infinity. */
- if (l == (uint64_t) -1)
+ if (l == UINT64_MAX)
return true;
return FILE_SIZE_VALID(l);
diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h
index 41d828fd98..b3d32abfc8 100644
--- a/src/libnm-systemd-shared/src/basic/log.h
+++ b/src/libnm-systemd-shared/src/basic/log.h
@@ -12,16 +12,6 @@
struct iovec;
struct signalfd_siginfo;
-typedef enum LogRealm {
- LOG_REALM_SYSTEMD,
- LOG_REALM_UDEV,
- _LOG_REALM_MAX,
-} LogRealm;
-
-#ifndef LOG_REALM
-# define LOG_REALM LOG_REALM_SYSTEMD
-#endif
-
typedef enum LogTarget{
LOG_TARGET_CONSOLE,
LOG_TARGET_CONSOLE_PREFIXED,
@@ -33,35 +23,26 @@ typedef enum LogTarget{
LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */
LOG_TARGET_NULL,
_LOG_TARGET_MAX,
- _LOG_TARGET_INVALID = -1
+ _LOG_TARGET_INVALID = -EINVAL,
} LogTarget;
/* Note to readers: << and >> have lower precedence than & and | */
-#define LOG_REALM_PLUS_LEVEL(realm, level) ((realm) << 10 | (level))
-#define LOG_REALM_REMOVE_LEVEL(realm_level) ((realm_level) >> 10)
#define SYNTHETIC_ERRNO(num) (1 << 30 | (num))
#define IS_SYNTHETIC_ERRNO(val) ((val) >> 30 & 1)
#define ERRNO_VALUE(val) (abs(val) & 255)
+const char *log_target_to_string(LogTarget target) _const_;
+LogTarget log_target_from_string(const char *s) _pure_;
void log_set_target(LogTarget target);
+int log_set_target_from_string(const char *e);
+LogTarget log_get_target(void) _pure_;
-void log_set_max_level_realm(LogRealm realm, int level);
-
-#define log_set_max_level(level) \
- log_set_max_level_realm(LOG_REALM, (level))
-
-static inline void log_set_max_level_all_realms(int level) {
- for (LogRealm realm = 0; realm < _LOG_REALM_MAX; realm++)
- log_set_max_level_realm(realm, level);
-}
+void log_set_max_level(int level);
+int log_set_max_level_from_string(const char *e);
+int log_get_max_level(void) _pure_;
void log_set_facility(int facility);
-int log_set_target_from_string(const char *e);
-int log_set_max_level_from_string_realm(LogRealm realm, const char *e);
-#define log_set_max_level_from_string(e) \
- log_set_max_level_from_string_realm(LOG_REALM, (e))
-
void log_show_color(bool b);
bool log_get_show_color(void) _pure_;
void log_show_location(bool b);
@@ -76,15 +57,9 @@ int log_show_location_from_string(const char *e);
int log_show_time_from_string(const char *e);
int log_show_tid_from_string(const char *e);
-LogTarget log_get_target(void) _pure_;
-int log_get_max_level_realm(LogRealm realm) _pure_;
-#define log_get_max_level() \
- log_get_max_level_realm(LOG_REALM)
-
/* Functions below that open and close logs or configure logging based on the
* environment should not be called from library code — this is always a job
- * for the application itself.
- */
+ * for the application itself. */
assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1);
#define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1])
@@ -93,12 +68,7 @@ int log_open(void);
void log_close(void);
void log_forget_fds(void);
-void log_parse_environment_realm(LogRealm realm);
-void log_parse_environment_cli_realm(LogRealm realm);
-#define log_parse_environment() \
- log_parse_environment_realm(LOG_REALM)
-#define log_parse_environment_cli() \
- log_parse_environment_cli_realm(LOG_REALM)
+void log_parse_environment(void);
int log_dispatch_internal(
int level,
@@ -112,17 +82,15 @@ int log_dispatch_internal(
const char *extra_field,
char *buffer);
-int log_internal_realm(
+int log_internal(
int level,
int error,
const char *file,
int line,
const char *func,
const char *format, ...) _printf_(6,7);
-#define log_internal(level, ...) \
- log_internal_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__)
-int log_internalv_realm(
+int log_internalv(
int level,
int error,
const char *file,
@@ -130,10 +98,7 @@ int log_internalv_realm(
const char *func,
const char *format,
va_list ap) _printf_(6,0);
-#define log_internalv(level, ...) \
- log_internalv_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__)
-/* Realm is fixed to LOG_REALM_SYSTEMD for those */
int log_object_internalv(
int level,
int error,
@@ -201,49 +166,36 @@ int log_dump_internal(
char *buffer);
/* Logging for various assertions */
-_noreturn_ void log_assert_failed_realm(
- LogRealm realm,
+_noreturn_ void log_assert_failed(
const char *text,
const char *file,
int line,
const char *func);
-#define log_assert_failed(text, ...) \
- log_assert_failed_realm(LOG_REALM, (text), __VA_ARGS__)
-_noreturn_ void log_assert_failed_unreachable_realm(
- LogRealm realm,
+_noreturn_ void log_assert_failed_unreachable(
const char *text,
const char *file,
int line,
const char *func);
-#define log_assert_failed_unreachable(text, ...) \
- log_assert_failed_unreachable_realm(LOG_REALM, (text), __VA_ARGS__)
-void log_assert_failed_return_realm(
- LogRealm realm,
+void log_assert_failed_return(
const char *text,
const char *file,
int line,
const char *func);
-#define log_assert_failed_return(text, ...) \
- log_assert_failed_return_realm(LOG_REALM, (text), __VA_ARGS__)
#define log_dispatch(level, error, buffer) \
log_dispatch_internal(level, error, PROJECT_FILE, __LINE__, __func__, NULL, NULL, NULL, NULL, buffer)
/* Logging with level */
-#define log_full_errno_realm(realm, level, error, ...) \
+#define log_full_errno(level, error, ...) \
({ \
- int _level = (level), _e = (error), _realm = (realm); \
- (log_get_max_level_realm(_realm) >= LOG_PRI(_level)) \
- ? log_internal_realm(LOG_REALM_PLUS_LEVEL(_realm, _level), _e, \
- PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
+ int _level = (level), _e = (error); \
+ (log_get_max_level() >= LOG_PRI(_level)) \
+ ? log_internal(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
: -ERRNO_VALUE(_e); \
})
-#define log_full_errno(level, error, ...) \
- log_full_errno_realm(LOG_REALM, (level), (error), __VA_ARGS__)
-
#define log_full(level, ...) (void) log_full_errno((level), 0, __VA_ARGS__)
int log_emergency_level(void);
@@ -264,36 +216,30 @@ int log_emergency_level(void);
#define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__)
#define log_emergency_errno(error, ...) log_full_errno(log_emergency_level(), error, __VA_ARGS__)
-#ifdef LOG_TRACE
+#if LOG_TRACE
# define log_trace(...) log_debug(__VA_ARGS__)
#else
# define log_trace(...) do {} while (0)
#endif
/* Structured logging */
-#define log_struct_errno(level, error, ...) \
- log_struct_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
- error, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__, NULL)
+#define log_struct_errno(level, error, ...) \
+ log_struct_internal(level, error, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__, NULL)
#define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__)
#define log_struct_iovec_errno(level, error, iovec, n_iovec) \
- log_struct_iovec_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
- error, PROJECT_FILE, __LINE__, __func__, iovec, n_iovec)
+ log_struct_iovec_internal(level, error, PROJECT_FILE, __LINE__, __func__, iovec, n_iovec)
#define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec)
/* This modifies the buffer passed! */
-#define log_dump(level, buffer) \
- log_dump_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
- 0, PROJECT_FILE, __LINE__, __func__, buffer)
+#define log_dump(level, buffer) \
+ log_dump_internal(level, 0, PROJECT_FILE, __LINE__, __func__, buffer)
-#define log_oom() log_oom_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, LOG_ERR), PROJECT_FILE, __LINE__, __func__)
-#define log_oom_debug() log_oom_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, LOG_DEBUG), PROJECT_FILE, __LINE__, __func__)
+#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__)
bool log_on_console(void) _pure_;
-const char *log_target_to_string(LogTarget target) _const_;
-LogTarget log_target_from_string(const char *s) _pure_;
-
/* Helper to prepare various field for structured logging */
#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
@@ -354,5 +300,4 @@ int log_syntax_invalid_utf8_internal(
#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
-void log_setup_service(void);
-void log_setup_cli(void);
+void log_setup(void);
diff --git a/src/libnm-systemd-shared/src/basic/macro.h b/src/libnm-systemd-shared/src/basic/macro.h
index 2782553756..f1d5e0894e 100644
--- a/src/libnm-systemd-shared/src/basic/macro.h
+++ b/src/libnm-systemd-shared/src/basic/macro.h
@@ -9,6 +9,8 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
+#include "macro-fundamental.h"
+
#define _printf_(a, b) __attribute__((__format__(printf, a, b)))
#ifdef __clang__
# define _alloc_(...)
@@ -18,10 +20,7 @@
#define _sentinel_ __attribute__((__sentinel__))
#define _section_(x) __attribute__((__section__(x)))
#define _used_ __attribute__((__used__))
-#define _unused_ __attribute__((__unused__))
#define _destructor_ __attribute__((__destructor__))
-#define _pure_ __attribute__((__pure__))
-#define _const_ __attribute__((__const__))
#define _deprecated_ __attribute__((__deprecated__))
#define _packed_ __attribute__((__packed__))
#define _malloc_ __attribute__((__malloc__))
@@ -34,7 +33,6 @@
#define _align_(x) __attribute__((__aligned__(x)))
#define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
-#define _cleanup_(x) __attribute__((__cleanup__(x)))
#if __GNUC__ >= 7
#define _fallthrough_ __attribute__((__fallthrough__))
#else
@@ -143,12 +141,6 @@
#define XSTRINGIFY(x) #x
#define STRINGIFY(x) XSTRINGIFY(x)
-#define XCONCATENATE(x, y) x ## y
-#define CONCATENATE(x, y) XCONCATENATE(x, y)
-
-#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
-#define UNIQ __COUNTER__
-
/* builtins */
#if __SIZEOF_INT__ == 4
#define BUILTIN_FFS_U32(x) __builtin_ffs(x);
@@ -222,18 +214,6 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
return m;
}
-#ifndef __COVERITY__
-# define VOID_0 ((void)0)
-#else
-# define VOID_0 ((void*)0)
-#endif
-
-#define ELEMENTSOF(x) \
- (__builtin_choose_expr( \
- !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
- sizeof(x)/sizeof((x)[0]), \
- VOID_0))
-
/*
* STRLEN - return the length of a string literal, minus the trailing NUL byte.
* Contrary to strlen(), this is a constant expression.
@@ -254,106 +234,6 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
(type*)( (char *)UNIQ_T(A, uniq) - offsetof(type, member) ); \
})
-#undef MAX
-#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b))
-#define __MAX(aq, a, bq, b) \
- ({ \
- const typeof(a) UNIQ_T(A, aq) = (a); \
- const typeof(b) UNIQ_T(B, bq) = (b); \
- UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
- })
-
-/* evaluates to (void) if _A or _B are not constant or of different types */
-#define CONST_MAX(_A, _B) \
- (__builtin_choose_expr( \
- __builtin_constant_p(_A) && \
- __builtin_constant_p(_B) && \
- __builtin_types_compatible_p(typeof(_A), typeof(_B)), \
- ((_A) > (_B)) ? (_A) : (_B), \
- VOID_0))
-
-/* takes two types and returns the size of the larger one */
-#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; }))
-
-#define MAX3(x, y, z) \
- ({ \
- const typeof(x) _c = MAX(x, y); \
- MAX(_c, z); \
- })
-
-#define MAX4(x, y, z, a) \
- ({ \
- const typeof(x) _d = MAX3(x, y, z); \
- MAX(_d, a); \
- })
-
-#undef MIN
-#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
-#define __MIN(aq, a, bq, b) \
- ({ \
- const typeof(a) UNIQ_T(A, aq) = (a); \
- const typeof(b) UNIQ_T(B, bq) = (b); \
- UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
- })
-
-/* evaluates to (void) if _A or _B are not constant or of different types */
-#define CONST_MIN(_A, _B) \
- (__builtin_choose_expr( \
- __builtin_constant_p(_A) && \
- __builtin_constant_p(_B) && \
- __builtin_types_compatible_p(typeof(_A), typeof(_B)), \
- ((_A) < (_B)) ? (_A) : (_B), \
- VOID_0))
-
-#define MIN3(x, y, z) \
- ({ \
- const typeof(x) _c = MIN(x, y); \
- MIN(_c, z); \
- })
-
-#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
-#define __LESS_BY(aq, a, bq, b) \
- ({ \
- const typeof(a) UNIQ_T(A, aq) = (a); \
- const typeof(b) UNIQ_T(B, bq) = (b); \
- UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) - UNIQ_T(B, bq) : 0; \
- })
-
-#define CMP(a, b) __CMP(UNIQ, (a), UNIQ, (b))
-#define __CMP(aq, a, bq, b) \
- ({ \
- const typeof(a) UNIQ_T(A, aq) = (a); \
- const typeof(b) UNIQ_T(B, bq) = (b); \
- UNIQ_T(A, aq) < UNIQ_T(B, bq) ? -1 : \
- UNIQ_T(A, aq) > UNIQ_T(B, bq) ? 1 : 0; \
- })
-
-#undef CLAMP
-#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high))
-#define __CLAMP(xq, x, lowq, low, highq, high) \
- ({ \
- const typeof(x) UNIQ_T(X, xq) = (x); \
- const typeof(low) UNIQ_T(LOW, lowq) = (low); \
- const typeof(high) UNIQ_T(HIGH, highq) = (high); \
- UNIQ_T(X, xq) > UNIQ_T(HIGH, highq) ? \
- UNIQ_T(HIGH, highq) : \
- UNIQ_T(X, xq) < UNIQ_T(LOW, lowq) ? \
- UNIQ_T(LOW, lowq) : \
- UNIQ_T(X, xq); \
- })
-
-/* [(x + y - 1) / y] suffers from an integer overflow, even though the
- * computation should be possible in the given type. Therefore, we use
- * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the
- * quotient and the remainder, so both should be equally fast. */
-#define DIV_ROUND_UP(x, y) __DIV_ROUND_UP(UNIQ, (x), UNIQ, (y))
-#define __DIV_ROUND_UP(xq, x, yq, y) \
- ({ \
- const typeof(x) UNIQ_T(X, xq) = (x); \
- const typeof(y) UNIQ_T(Y, yq) = (y); \
- (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \
- })
-
#ifdef __COVERITY__
/* Use special definitions of assertion macros in order to prevent
@@ -410,16 +290,6 @@ static inline int __coverity_check_and_return__(int condition) {
#define assert_not_reached(t) \
log_assert_failed_unreachable(t, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__)
-#if defined(static_assert)
-#define assert_cc(expr) \
- static_assert(expr, #expr)
-#else
-#define assert_cc(expr) \
- struct CONCATENATE(_assert_struct_, __COUNTER__) { \
- char x[(expr) ? 0 : -1]; \
- }
-#endif
-
#define assert_return(expr, r) \
do { \
if (!assert_log(expr, #expr)) \
@@ -498,53 +368,6 @@ static inline int __coverity_check_and_return__(int condition) {
#define FLAGS_SET(v, flags) \
((~(v) & (flags)) == 0)
-#define CASE_F(X) case X:
-#define CASE_F_1(CASE, X) CASE_F(X)
-#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__)
-#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__)
-#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__)
-#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__)
-#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__)
-#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__)
-#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__)
-#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__)
-#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__)
-#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__)
-#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__)
-#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__)
-#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__)
-#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__)
-#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__)
-#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__)
-#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__)
-#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__)
-#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__)
-
-#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
-#define FOR_EACH_MAKE_CASE(...) \
- GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \
- CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
- (CASE_F,__VA_ARGS__)
-
-#define IN_SET(x, ...) \
- ({ \
- bool _found = false; \
- /* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \
- * type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
- * the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \
- * doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \
- static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \
- assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
- switch(x) { \
- FOR_EACH_MAKE_CASE(__VA_ARGS__) \
- _found = true; \
- break; \
- default: \
- break; \
- } \
- _found; \
- })
-
#define SWAP_TWO(x, y) do { \
typeof(x) _t = (x); \
(x) = (y); \
@@ -553,6 +376,7 @@ static inline int __coverity_check_and_return__(int condition) {
#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
#define STRV_MAKE_EMPTY ((char*[1]) { NULL })
+#define STRV_MAKE_CONST(...) ((const char* const*) ((const char*[]) { __VA_ARGS__, NULL }))
/* Pointers range from NULL to POINTER_MAX */
#define POINTER_MAX ((void*) UINTPTR_MAX)
@@ -582,10 +406,20 @@ static inline int __coverity_check_and_return__(int condition) {
func(p); \
}
+/* When func() returns the void value (NULL, -1, …) of the appropriate type */
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \
if (*p) \
+ *p = func(*p); \
+ }
+
+/* When func() doesn't return the appropriate type, set variable to empty afterwards */
+#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \
+ static inline void func##p(type *p) { \
+ if (*p != (empty)) { \
func(*p); \
+ *p = (empty); \
+ } \
}
#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \
diff --git a/src/libnm-systemd-shared/src/basic/missing_syscall.h b/src/libnm-systemd-shared/src/basic/missing_syscall.h
index 06166b3fb3..1384324804 100644
--- a/src/libnm-systemd-shared/src/basic/missing_syscall.h
+++ b/src/libnm-systemd-shared/src/basic/missing_syscall.h
@@ -5,6 +5,11 @@
#include <errno.h>
#include <fcntl.h>
+#if HAVE_LINUX_TIME_TYPES_H
+/* This header defines __kernel_timespec for us, but is only available since Linux 5.1, hence conditionally
+ * include this. */
+#include <linux/time_types.h>
+#endif
#include <signal.h>
#include <sys/syscall.h>
#include <sys/types.h>
@@ -15,34 +20,17 @@
#include <asm/sgidefs.h>
#endif
-#if defined(__alpha__)
-# define systemd_SC_arch_bias(x) (110 + (x))
-#elif defined(__ia64__)
-# define systemd_SC_arch_bias(x) (1024 + (x))
-#elif defined(_MIPS_SIM)
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_SC_arch_bias(x) (4000 + (x))
-# elif _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_SC_arch_bias(x) (6000 + (x))
-# elif _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_SC_arch_bias(x) (5000 + (x))
-# else
-# error "Unknown MIPS ABI"
-# endif
-#elif defined(__x86_64__) && defined(__ILP32__)
-# define systemd_SC_arch_bias(x) ((x) | /* __X32_SYSCALL_BIT */ 0x40000000)
-#else
-# define systemd_SC_arch_bias(x) (x)
-#endif
-
#include "missing_keyctl.h"
#include "missing_stat.h"
+#include "missing_syscall_def.h"
/* linux/kcmp.h */
#ifndef KCMP_FILE /* 3f4994cfc15f38a3159c6e3a4b3ab2e1481a6b02 (3.19) */
#define KCMP_FILE 0
#endif
+/* ======================================================================= */
+
#if !HAVE_PIVOT_ROOT
static inline int missing_pivot_root(const char *new_root, const char *put_old) {
return syscall(__NR_pivot_root, new_root, put_old);
@@ -53,54 +41,6 @@ static inline int missing_pivot_root(const char *new_root, const char *put_old)
/* ======================================================================= */
-#if defined(__aarch64__)
-# define systemd_NR_memfd_create 279
-#elif defined(__alpha__)
-# define systemd_NR_memfd_create 512
-#elif defined(__arc__) || defined(__tilegx__)
-# define systemd_NR_memfd_create 279
-#elif defined(__arm__)
-# define systemd_NR_memfd_create 385
-#elif defined(__i386__)
-# define systemd_NR_memfd_create 356
-#elif defined(__ia64__)
-# define systemd_NR_memfd_create systemd_SC_arch_bias(316)
-#elif defined(__m68k__)
-# define systemd_NR_memfd_create 353
-#elif defined(_MIPS_SIM)
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_memfd_create systemd_SC_arch_bias(354)
-# elif _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_memfd_create systemd_SC_arch_bias(318)
-# elif _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_memfd_create systemd_SC_arch_bias(314)
-# endif
-#elif defined(__powerpc__)
-# define systemd_NR_memfd_create 360
-#elif defined(__s390__)
-# define systemd_NR_memfd_create 350
-#elif defined(__sparc__)
-# define systemd_NR_memfd_create 348
-#elif defined(__x86_64__)
-# define systemd_NR_memfd_create systemd_SC_arch_bias(319)
-#else
-# warning "memfd_create() syscall number is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_memfd_create && __NR_memfd_create >= 0
-# if defined systemd_NR_memfd_create
-assert_cc(__NR_memfd_create == systemd_NR_memfd_create);
-# endif
-#else
-# if defined __NR_memfd_create
-# undef __NR_memfd_create
-# endif
-# if defined systemd_NR_memfd_create
-# define __NR_memfd_create systemd_NR_memfd_create
-# endif
-#endif
-
#if !HAVE_MEMFD_CREATE
static inline int missing_memfd_create(const char *name, unsigned int flags) {
# ifdef __NR_memfd_create
@@ -116,54 +56,6 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) {
/* ======================================================================= */
-#if defined(__aarch64__)
-# define systemd_NR_getrandom 278
-#elif defined(__alpha__)
-# define systemd_NR_getrandom 511
-#elif defined(__arc__) || defined(__tilegx__)
-# define systemd_NR_getrandom 278
-#elif defined(__arm__)
-# define systemd_NR_getrandom 384
-#elif defined(__i386__)
-# define systemd_NR_getrandom 355
-#elif defined(__ia64__)
-# define systemd_NR_getrandom systemd_SC_arch_bias(318)
-#elif defined(__m68k__)
-# define systemd_NR_getrandom 352
-#elif defined(_MIPS_SIM)
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_getrandom systemd_SC_arch_bias(353)
-# elif _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_getrandom systemd_SC_arch_bias(317)
-# elif _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_getrandom systemd_SC_arch_bias(313)
-# endif
-#elif defined(__powerpc__)
-# define systemd_NR_getrandom 359
-#elif defined(__s390__)
-# define systemd_NR_getrandom 349
-#elif defined(__sparc__)
-# define systemd_NR_getrandom 347
-#elif defined(__x86_64__)
-# define systemd_NR_getrandom systemd_SC_arch_bias(318)
-#else
-# warning "getrandom() syscall number is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_getrandom && __NR_getrandom >= 0
-# if defined systemd_NR_getrandom
-assert_cc(__NR_getrandom == systemd_NR_getrandom);
-# endif
-#else
-# if defined __NR_getrandom
-# undef __NR_getrandom
-# endif
-# if defined systemd_NR_getrandom
-# define __NR_getrandom systemd_NR_getrandom
-# endif
-#endif
-
#if !HAVE_GETRANDOM
static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) {
# ifdef __NR_getrandom
@@ -194,54 +86,6 @@ static inline pid_t missing_gettid(void) {
/* ======================================================================= */
-#if defined(__aarch64__)
-# define systemd_NR_name_to_handle_at 264
-#elif defined(__alpha__)
-# define systemd_NR_name_to_handle_at 497
-#elif defined(__arc__) || defined(__tilegx__)
-# define systemd_NR_name_to_handle_at 264
-#elif defined(__arm__)
-# define systemd_NR_name_to_handle_at 370
-#elif defined(__i386__)
-# define systemd_NR_name_to_handle_at 341
-#elif defined(__ia64__)
-# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(302)
-#elif defined(__m68k__)
-# define systemd_NR_name_to_handle_at 340
-#elif defined(_MIPS_SIM)
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(339)
-# elif _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303)
-# elif _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(298)
-# endif
-#elif defined(__powerpc__)
-# define systemd_NR_name_to_handle_at 345
-#elif defined(__s390__)
-# define systemd_NR_name_to_handle_at 335
-#elif defined(__sparc__)
-# define systemd_NR_name_to_handle_at 332
-#elif defined(__x86_64__)
-# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303)
-#else
-# warning "name_to_handle_at() syscall number is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_name_to_handle_at && __NR_name_to_handle_at >= 0
-# if defined systemd_NR_name_to_handle_at
-assert_cc(__NR_name_to_handle_at == systemd_NR_name_to_handle_at);
-# endif
-#else
-# if defined __NR_name_to_handle_at
-# undef __NR_name_to_handle_at
-# endif
-# if defined systemd_NR_name_to_handle_at
-# define __NR_name_to_handle_at systemd_NR_name_to_handle_at
-# endif
-#endif
-
#if !HAVE_NAME_TO_HANDLE_AT
struct file_handle {
unsigned int handle_bytes;
@@ -263,54 +107,6 @@ static inline int missing_name_to_handle_at(int fd, const char *name, struct fil
/* ======================================================================= */
-#if defined(__aarch64__)
-# define systemd_NR_setns 268
-#elif defined(__alpha__)
-# define systemd_NR_setns 501
-#elif defined(__arc__) || defined(__tilegx__)
-# define systemd_NR_setns 268
-#elif defined(__arm__)
-# define systemd_NR_setns 375
-#elif defined(__i386__)
-# define systemd_NR_setns 346
-#elif defined(__ia64__)
-# define systemd_NR_setns systemd_SC_arch_bias(306)
-#elif defined(__m68k__)
-# define systemd_NR_setns 344
-#elif defined(_MIPS_SIM)
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_setns systemd_SC_arch_bias(344)
-# elif _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_setns systemd_SC_arch_bias(308)
-# elif _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_setns systemd_SC_arch_bias(303)
-# endif
-#elif defined(__powerpc__)
-# define systemd_NR_setns 350
-#elif defined(__s390__)
-# define systemd_NR_setns 339
-#elif defined(__sparc__)
-# define systemd_NR_setns 337
-#elif defined(__x86_64__)
-# define systemd_NR_setns systemd_SC_arch_bias(308)
-#else
-# warning "setns() syscall number is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_setns && __NR_setns >= 0
-# if defined systemd_NR_setns
-assert_cc(__NR_setns == systemd_NR_setns);
-# endif
-#else
-# if defined __NR_setns
-# undef __NR_setns
-# endif
-# if defined systemd_NR_setns
-# define __NR_setns systemd_NR_setns
-# endif
-#endif
-
#if !HAVE_SETNS
static inline int missing_setns(int fd, int nstype) {
# ifdef __NR_setns
@@ -336,54 +132,6 @@ static inline pid_t raw_getpid(void) {
/* ======================================================================= */
-#if defined(__aarch64__)
-# define systemd_NR_renameat2 276
-#elif defined(__alpha__)
-# define systemd_NR_renameat2 510
-#elif defined(__arc__) || defined(__tilegx__)
-# define systemd_NR_renameat2 276
-#elif defined(__arm__)
-# define systemd_NR_renameat2 382
-#elif defined(__i386__)
-# define systemd_NR_renameat2 353
-#elif defined(__ia64__)
-# define systemd_NR_renameat2 systemd_SC_arch_bias(314)
-#elif defined(__m68k__)
-# define systemd_NR_renameat2 351
-#elif defined(_MIPS_SIM)
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_renameat2 systemd_SC_arch_bias(351)
-# elif _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_renameat2 systemd_SC_arch_bias(315)
-# elif _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_renameat2 systemd_SC_arch_bias(311)
-# endif
-#elif defined(__powerpc__)
-# define systemd_NR_renameat2 357
-#elif defined(__s390__)
-# define systemd_NR_renameat2 347
-#elif defined(__sparc__)
-# define systemd_NR_renameat2 345
-#elif defined(__x86_64__)
-# define systemd_NR_renameat2 systemd_SC_arch_bias(316)
-#else
-# warning "renameat2() syscall number is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_renameat2 && __NR_renameat2 >= 0
-# if defined systemd_NR_renameat2
-assert_cc(__NR_renameat2 == systemd_NR_renameat2);
-# endif
-#else
-# if defined __NR_renameat2
-# undef __NR_renameat2
-# endif
-# if defined systemd_NR_renameat2
-# define __NR_renameat2 systemd_NR_renameat2
-# endif
-#endif
-
#if !HAVE_RENAMEAT2
static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) {
# ifdef __NR_renameat2
@@ -451,54 +199,6 @@ static inline key_serial_t missing_request_key(const char *type, const char *des
/* ======================================================================= */
-#if defined(__aarch64__)
-# define systemd_NR_copy_file_range 285
-#elif defined(__alpha__)
-# define systemd_NR_copy_file_range 519
-#elif defined(__arc__) || defined(__tilegx__)
-# define systemd_NR_copy_file_range 285
-#elif defined(__arm__)
-# define systemd_NR_copy_file_range 391
-#elif defined(__i386__)
-# define systemd_NR_copy_file_range 377
-#elif defined(__ia64__)
-# define systemd_NR_copy_file_range systemd_SC_arch_bias(323)
-#elif defined(__m68k__)
-# define systemd_NR_copy_file_range 376
-#elif defined(_MIPS_SIM)
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_copy_file_range systemd_SC_arch_bias(360)
-# elif _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_copy_file_range systemd_SC_arch_bias(324)
-# elif _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_copy_file_range systemd_SC_arch_bias(320)
-# endif
-#elif defined(__powerpc__)
-# define systemd_NR_copy_file_range 379
-#elif defined(__s390__)
-# define systemd_NR_copy_file_range 375
-#elif defined(__sparc__)
-# define systemd_NR_copy_file_range 357
-#elif defined(__x86_64__)
-# define systemd_NR_copy_file_range systemd_SC_arch_bias(326)
-#else
-# warning "copy_file_range() syscall number is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_copy_file_range && __NR_copy_file_range >= 0
-# if defined systemd_NR_copy_file_range
-assert_cc(__NR_copy_file_range == systemd_NR_copy_file_range);
-# endif
-#else
-# if defined __NR_copy_file_range
-# undef __NR_copy_file_range
-# endif
-# if defined systemd_NR_copy_file_range
-# define __NR_copy_file_range systemd_NR_copy_file_range
-# endif
-#endif
-
#if !HAVE_COPY_FILE_RANGE
static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in,
int fd_out, loff_t *off_out,
@@ -517,54 +217,6 @@ static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in,
/* ======================================================================= */
-#if defined(__aarch64__)
-# define systemd_NR_bpf 280
-#elif defined(__alpha__)
-# define systemd_NR_bpf 515
-#elif defined(__arc__) || defined(__tilegx__)
-# define systemd_NR_bpf 280
-#elif defined(__arm__)
-# define systemd_NR_bpf 386
-#elif defined(__i386__)
-# define systemd_NR_bpf 357
-#elif defined(__ia64__)
-# define systemd_NR_bpf systemd_SC_arch_bias(317)
-#elif defined(__m68k__)
-# define systemd_NR_bpf 354
-#elif defined(_MIPS_SIM)
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_bpf systemd_SC_arch_bias(355)
-# elif _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_bpf systemd_SC_arch_bias(319)
-# elif _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_bpf systemd_SC_arch_bias(315)
-# endif
-#elif defined(__powerpc__)
-# define systemd_NR_bpf 361
-#elif defined(__s390__)
-# define systemd_NR_bpf 351
-#elif defined(__sparc__)
-# define systemd_NR_bpf 349
-#elif defined(__x86_64__)
-# define systemd_NR_bpf systemd_SC_arch_bias(321)
-#else
-# warning "bpf() syscall number is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_bpf && __NR_bpf >= 0
-# if defined systemd_NR_bpf
-assert_cc(__NR_bpf == systemd_NR_bpf);
-# endif
-#else
-# if defined __NR_bpf
-# undef __NR_bpf
-# endif
-# if defined systemd_NR_bpf
-# define __NR_bpf systemd_NR_bpf
-# endif
-#endif
-
#if !HAVE_BPF
union bpf_attr;
@@ -582,106 +234,6 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) {
/* ======================================================================= */
-#ifndef __IGNORE_pkey_mprotect
-# if defined(__aarch64__)
-# define systemd_NR_pkey_mprotect 288
-# elif defined(__alpha__)
-# define systemd_NR_pkey_mprotect 524
-# elif defined(__arc__) || defined(__tilegx__)
-# define systemd_NR_pkey_mprotect 226
-# elif defined(__arm__)
-# define systemd_NR_pkey_mprotect 394
-# elif defined(__i386__)
-# define systemd_NR_pkey_mprotect 380
-# elif defined(__ia64__)
-# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(330)
-# elif defined(__m68k__)
-# define systemd_NR_pkey_mprotect 381
-# elif defined(_MIPS_SIM)
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(363)
-# elif _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(327)
-# elif _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(323)
-# endif
-# elif defined(__powerpc__)
-# define systemd_NR_pkey_mprotect 386
-# elif defined(__s390__)
-# define systemd_NR_pkey_mprotect 384
-# elif defined(__sparc__)
-# define systemd_NR_pkey_mprotect 362
-# elif defined(__x86_64__)
-# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(329)
-# else
-# warning "pkey_mprotect() syscall number is unknown for your architecture"
-# endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-# if defined __NR_pkey_mprotect && __NR_pkey_mprotect >= 0
-# if defined systemd_NR_pkey_mprotect
-assert_cc(__NR_pkey_mprotect == systemd_NR_pkey_mprotect);
-# endif
-# else
-# if defined __NR_pkey_mprotect
-# undef __NR_pkey_mprotect
-# endif
-# if defined systemd_NR_pkey_mprotect
-# define __NR_pkey_mprotect systemd_NR_pkey_mprotect
-# endif
-# endif
-#endif
-
-/* ======================================================================= */
-
-#if defined(__aarch64__)
-# define systemd_NR_statx 291
-#elif defined(__alpha__)
-# define systemd_NR_statx 522
-#elif defined(__arc__) || defined(__tilegx__)
-# define systemd_NR_statx 291
-#elif defined(__arm__)
-# define systemd_NR_statx 397
-#elif defined(__i386__)
-# define systemd_NR_statx 383
-#elif defined(__ia64__)
-# define systemd_NR_statx systemd_SC_arch_bias(326)
-#elif defined(__m68k__)
-# define systemd_NR_statx 379
-#elif defined(_MIPS_SIM)
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_statx systemd_SC_arch_bias(366)
-# elif _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_statx systemd_SC_arch_bias(330)
-# elif _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_statx systemd_SC_arch_bias(326)
-# endif
-#elif defined(__powerpc__)
-# define systemd_NR_statx 383
-#elif defined(__s390__)
-# define systemd_NR_statx 379
-#elif defined(__sparc__)
-# define systemd_NR_statx 360
-#elif defined(__x86_64__)
-# define systemd_NR_statx systemd_SC_arch_bias(332)
-#else
-# warning "statx() syscall number is unknown for your architecture"
-#endif
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_statx && __NR_statx >= 0
-# if defined systemd_NR_statx
-assert_cc(__NR_statx == systemd_NR_statx);
-# endif
-#else
-# if defined __NR_statx
-# undef __NR_statx
-# endif
-# if defined systemd_NR_statx
-# define __NR_statx systemd_NR_statx
-# endif
-#endif
-
#if !HAVE_STATX
struct statx;
@@ -747,21 +299,6 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask,
/* ======================================================================= */
-/* should be always defined, see kernel 39036cd2727395c3369b1051005da74059a85317 */
-#define systemd_NR_pidfd_send_signal systemd_SC_arch_bias(424)
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_pidfd_send_signal && __NR_pidfd_send_signal >= 0
-# if defined systemd_NR_pidfd_send_signal
-assert_cc(__NR_pidfd_send_signal == systemd_NR_pidfd_send_signal);
-# endif
-#else
-# if defined __NR_pidfd_send_signal
-# undef __NR_pidfd_send_signal
-# endif
-# define __NR_pidfd_send_signal systemd_NR_pidfd_send_signal
-#endif
-
#if !HAVE_PIDFD_SEND_SIGNAL
static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) {
# ifdef __NR_pidfd_send_signal
@@ -775,21 +312,6 @@ static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, un
# define pidfd_send_signal missing_pidfd_send_signal
#endif
-/* should be always defined, see kernel 7615d9e1780e26e0178c93c55b73309a5dc093d7 */
-#define systemd_NR_pidfd_open systemd_SC_arch_bias(434)
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_pidfd_open && __NR_pidfd_open >= 0
-# if defined systemd_NR_pidfd_open
-assert_cc(__NR_pidfd_open == systemd_NR_pidfd_open);
-# endif
-#else
-# if defined __NR_pidfd_open
-# undef __NR_pidfd_open
-# endif
-# define __NR_pidfd_open systemd_NR_pidfd_open
-#endif
-
#if !HAVE_PIDFD_OPEN
static inline int missing_pidfd_open(pid_t pid, unsigned flags) {
# ifdef __NR_pidfd_open
@@ -838,22 +360,6 @@ static inline int missing_execveat(int dirfd, const char *pathname,
/* ======================================================================= */
-#define systemd_NR_close_range systemd_SC_arch_bias(436)
-
-/* may be (invalid) negative number due to libseccomp, see PR 13319 */
-#if defined __NR_close_range && __NR_close_range >= 0
-# if defined systemd_NR_close_range
-assert_cc(__NR_close_range == systemd_NR_close_range);
-# endif
-#else
-# if defined __NR_close_range
-# undef __NR_close_range
-# endif
-# if defined systemd_NR_close_range
-# define __NR_close_range systemd_NR_close_range
-# endif
-#endif
-
#if !HAVE_CLOSE_RANGE
static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) {
# ifdef __NR_close_range
@@ -881,3 +387,41 @@ static inline int missing_close_range(int first_fd, int end_fd, unsigned flags)
# define close_range missing_close_range
#endif
+
+/* ======================================================================= */
+
+#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
diff --git a/src/libnm-systemd-shared/src/basic/ordered-set.c b/src/libnm-systemd-shared/src/basic/ordered-set.c
new file mode 100644
index 0000000000..58fa8af1b7
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/ordered-set.c
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "fileio.h"
+#include "ordered-set.h"
+#include "strv.h"
+
+int _ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops HASHMAP_DEBUG_PARAMS) {
+ if (*s)
+ return 0;
+
+ *s = _ordered_set_new(ops HASHMAP_DEBUG_PASS_ARGS);
+ if (!*s)
+ return -ENOMEM;
+
+ return 0;
+}
+
+int _ordered_set_ensure_put(OrderedSet **s, const struct hash_ops *ops, void *p HASHMAP_DEBUG_PARAMS) {
+ int r;
+
+ r = _ordered_set_ensure_allocated(s, ops HASHMAP_DEBUG_PASS_ARGS);
+ if (r < 0)
+ return r;
+
+ return ordered_set_put(*s, p);
+}
+
+int ordered_set_consume(OrderedSet *s, void *p) {
+ int r;
+
+ r = ordered_set_put(s, p);
+ if (r <= 0)
+ free(p);
+
+ return r;
+}
+
+int ordered_set_put_strdup(OrderedSet *s, const char *p) {
+ char *c;
+ int r;
+
+ assert(s);
+ assert(p);
+
+ c = strdup(p);
+ if (!c)
+ return -ENOMEM;
+
+ r = ordered_set_consume(s, c);
+ if (r == -EEXIST)
+ return 0;
+
+ return r;
+}
+
+int ordered_set_put_strdupv(OrderedSet *s, char **l) {
+ int n = 0, r;
+ char **i;
+
+ STRV_FOREACH(i, l) {
+ r = ordered_set_put_strdup(s, *i);
+ if (r < 0)
+ return r;
+
+ n += r;
+ }
+
+ return n;
+}
+
+int ordered_set_put_string_set(OrderedSet *s, OrderedSet *l) {
+ int n = 0, r;
+ char *p;
+
+ /* Like ordered_set_put_strv, but for an OrderedSet of strings */
+
+ ORDERED_SET_FOREACH(p, l) {
+ r = ordered_set_put_strdup(s, p);
+ if (r < 0)
+ return r;
+
+ n += r;
+ }
+
+ return n;
+}
+
+void ordered_set_print(FILE *f, const char *field, OrderedSet *s) {
+ bool space = false;
+ char *p;
+
+ if (ordered_set_isempty(s))
+ return;
+
+ fputs(field, f);
+
+ ORDERED_SET_FOREACH(p, s)
+ fputs_with_space(f, p, NULL, &space);
+
+ fputc('\n', f);
+}
diff --git a/src/libnm-systemd-shared/src/basic/ordered-set.h b/src/libnm-systemd-shared/src/basic/ordered-set.h
new file mode 100644
index 0000000000..baf8202088
--- /dev/null
+++ b/src/libnm-systemd-shared/src/basic/ordered-set.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdio.h>
+
+#include "hashmap.h"
+
+typedef struct OrderedSet OrderedSet;
+
+static inline OrderedSet* _ordered_set_new(const struct hash_ops *ops HASHMAP_DEBUG_PARAMS) {
+ return (OrderedSet*) _ordered_hashmap_new(ops HASHMAP_DEBUG_PASS_ARGS);
+}
+#define ordered_set_new(ops) _ordered_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
+
+int _ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops HASHMAP_DEBUG_PARAMS);
+#define ordered_set_ensure_allocated(s, ops) _ordered_set_ensure_allocated(s, ops HASHMAP_DEBUG_SRC_ARGS)
+
+int _ordered_set_ensure_put(OrderedSet **s, const struct hash_ops *ops, void *p HASHMAP_DEBUG_PARAMS);
+#define ordered_set_ensure_put(s, hash_ops, key) _ordered_set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS)
+
+static inline OrderedSet* ordered_set_free(OrderedSet *s) {
+ return (OrderedSet*) ordered_hashmap_free((OrderedHashmap*) s);
+}
+
+static inline OrderedSet* ordered_set_free_free(OrderedSet *s) {
+ return (OrderedSet*) ordered_hashmap_free_free((OrderedHashmap*) s);
+}
+
+static inline int ordered_set_put(OrderedSet *s, void *p) {
+ return ordered_hashmap_put((OrderedHashmap*) s, p, p);
+}
+
+static inline unsigned ordered_set_size(OrderedSet *s) {
+ return ordered_hashmap_size((OrderedHashmap*) s);
+}
+
+static inline bool ordered_set_isempty(OrderedSet *s) {
+ return ordered_hashmap_isempty((OrderedHashmap*) s);
+}
+
+static inline bool ordered_set_iterate(OrderedSet *s, Iterator *i, void **value) {
+ return ordered_hashmap_iterate((OrderedHashmap*) s, i, value, NULL);
+}
+
+static inline void* ordered_set_remove(OrderedSet *s, void *p) {
+ return ordered_hashmap_remove((OrderedHashmap*) s, p);
+}
+
+static inline void* ordered_set_first(OrderedSet *s) {
+ return ordered_hashmap_first((OrderedHashmap*) s);
+}
+
+static inline void* ordered_set_steal_first(OrderedSet *s) {
+ return ordered_hashmap_steal_first((OrderedHashmap*) s);
+}
+
+static inline char** ordered_set_get_strv(OrderedSet *s) {
+ return _hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s));
+}
+
+int ordered_set_consume(OrderedSet *s, void *p);
+int ordered_set_put_strdup(OrderedSet *s, const char *p);
+int ordered_set_put_strdupv(OrderedSet *s, char **l);
+int ordered_set_put_string_set(OrderedSet *s, OrderedSet *l);
+void ordered_set_print(FILE *f, const char *field, OrderedSet *s);
+
+#define _ORDERED_SET_FOREACH(e, s, i) \
+ for (Iterator i = ITERATOR_FIRST; ordered_set_iterate((s), &i, (void**)&(e)); )
+#define ORDERED_SET_FOREACH(e, s) \
+ _ORDERED_SET_FOREACH(e, s, UNIQ_T(i, UNIQ))
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free_free);
+
+#define _cleanup_ordered_set_free_ _cleanup_(ordered_set_freep)
+#define _cleanup_ordered_set_free_free_ _cleanup_(ordered_set_free_freep)
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.c b/src/libnm-systemd-shared/src/basic/parse-util.c
index 5d4dafe3a5..b79c885dfd 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.c
+++ b/src/libnm-systemd-shared/src/basic/parse-util.c
@@ -16,9 +16,6 @@
#include "missing_network.h"
#include "parse-util.h"
#include "process-util.h"
-#if HAVE_SECCOMP
-#include "seccomp-util.h"
-#endif
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
@@ -317,46 +314,6 @@ int parse_errno(const char *t) {
return e;
}
-#if HAVE_SECCOMP
-int parse_syscall_and_errno(const char *in, char **name, int *error) {
- _cleanup_free_ char *n = NULL;
- char *p;
- int e = -1;
-
- assert(in);
- assert(name);
- assert(error);
-
- /*
- * This parse "syscall:errno" like "uname:EILSEQ", "@sync:255".
- * If errno is omitted, then error is set to -1.
- * Empty syscall name is not allowed.
- * Here, we do not check that the syscall name is valid or not.
- */
-
- p = strchr(in, ':');
- if (p) {
- e = seccomp_parse_errno_or_action(p + 1);
- if (e < 0)
- return e;
-
- n = strndup(in, p - in);
- } else
- n = strdup(in);
-
- if (!n)
- return -ENOMEM;
-
- if (isempty(n))
- return -EINVAL;
-
- *error = e;
- *name = TAKE_PTR(n);
-
- return 0;
-}
-#endif
-
static const char *mangle_base(const char *s, unsigned *base) {
const char *k;
@@ -636,14 +593,13 @@ int safe_atod(const char *s, double *ret_d) {
}
int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
- size_t i;
unsigned val = 0;
const char *s;
s = *p;
/* accept any number of digits, strtoull is limited to 19 */
- for (i=0; i < digits; i++,s++) {
+ for (size_t i = 0; i < digits; i++,s++) {
if (*s < '0' || *s > '9') {
if (i == 0)
return -EINVAL;
@@ -671,87 +627,6 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
return 0;
}
-int parse_percent_unbounded(const char *p) {
- const char *pc, *n;
- int r, v;
-
- pc = endswith(p, "%");
- if (!pc)
- return -EINVAL;
-
- n = strndupa(p, pc - p);
- r = safe_atoi(n, &v);
- if (r < 0)
- return r;
- if (v < 0)
- return -ERANGE;
-
- return v;
-}
-
-int parse_percent(const char *p) {
- int v;
-
- v = parse_percent_unbounded(p);
- if (v > 100)
- return -ERANGE;
-
- return v;
-}
-
-int parse_permille_unbounded(const char *p) {
- const char *pc, *pm, *dot, *n;
- int r, q, v;
-
- pm = endswith(p, "‰");
- if (pm) {
- n = strndupa(p, pm - p);
- r = safe_atoi(n, &v);
- if (r < 0)
- return r;
- if (v < 0)
- return -ERANGE;
- } else {
- pc = endswith(p, "%");
- if (!pc)
- return -EINVAL;
-
- dot = memchr(p, '.', pc - p);
- if (dot) {
- if (dot + 2 != pc)
- return -EINVAL;
- if (dot[1] < '0' || dot[1] > '9')
- return -EINVAL;
- q = dot[1] - '0';
- n = strndupa(p, dot - p);
- } else {
- q = 0;
- n = strndupa(p, pc - p);
- }
- r = safe_atoi(n, &v);
- if (r < 0)
- return r;
- if (v < 0)
- return -ERANGE;
- if (v > (INT_MAX - q) / 10)
- return -ERANGE;
-
- v = v * 10 + q;
- }
-
- return v;
-}
-
-int parse_permille(const char *p) {
- int v;
-
- v = parse_permille_unbounded(p);
- if (v > 1000)
- return -ERANGE;
-
- return v;
-}
-
int parse_nice(const char *p, int *ret) {
int n, r;
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.h b/src/libnm-systemd-shared/src/basic/parse-util.h
index 81478ed059..908202dafd 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.h
+++ b/src/libnm-systemd-shared/src/basic/parse-util.h
@@ -22,9 +22,6 @@ int parse_mtu(int family, const char *s, uint32_t *ret);
int parse_size(const char *t, uint64_t base, uint64_t *size);
int parse_range(const char *t, unsigned *lower, unsigned *upper);
int parse_errno(const char *t);
-#if HAVE_SECCOMP
-int parse_syscall_and_errno(const char *in, char **name, int *error);
-#endif
#define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
#define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)
@@ -130,12 +127,6 @@ int safe_atod(const char *s, double *ret_d);
int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
-int parse_percent_unbounded(const char *p);
-int parse_percent(const char *p);
-
-int parse_permille_unbounded(const char *p);
-int parse_permille(const char *p);
-
int parse_nice(const char *p, int *ret);
int parse_ip_port(const char *s, uint16_t *ret);
diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c
index dae8b7341a..50ba44492e 100644
--- a/src/libnm-systemd-shared/src/basic/path-util.c
+++ b/src/libnm-systemd-shared/src/basic/path-util.c
@@ -586,26 +586,25 @@ char* path_join_internal(const char *first, ...) {
}
static int check_x_access(const char *path, int *ret_fd) {
- if (ret_fd) {
- _cleanup_close_ int fd = -1;
- int r;
+ _cleanup_close_ int fd = -1;
+ int r;
- /* We need to use O_PATH because there may be executables for which we have only exec
- * permissions, but not read (usually suid executables). */
- fd = open(path, O_PATH|O_CLOEXEC);
- if (fd < 0)
- return -errno;
+ /* We need to use O_PATH because there may be executables for which we have only exec
+ * permissions, but not read (usually suid executables). */
+ fd = open(path, O_PATH|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
- r = access_fd(fd, X_OK);
- if (r < 0)
- return r;
+ r = fd_verify_regular(fd);
+ if (r < 0)
+ return r;
+ r = access_fd(fd, X_OK);
+ if (r < 0)
+ return r;
+
+ if (ret_fd)
*ret_fd = TAKE_FD(fd);
- } else {
- /* Let's optimize things a bit by not opening the file if we don't need the fd. */
- if (access(path, X_OK) < 0)
- return -errno;
- }
return 0;
}
@@ -663,32 +662,20 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret_file
return -ENOMEM;
r = check_x_access(j, ret_fd ? &fd : NULL);
- if (r >= 0) {
- _cleanup_free_ char *with_dash;
-
- with_dash = strjoin(j, "/");
- if (!with_dash)
- return -ENOMEM;
-
- /* If this passes, it must be a directory, and so should be skipped. */
- if (access(with_dash, X_OK) >= 0)
- continue;
-
- /* We can't just `continue` inverting this case, since we need to update last_error. */
- if (errno == ENOTDIR) {
- /* Found it! */
- if (ret_filename)
- *ret_filename = path_simplify(TAKE_PTR(j), false);
- if (ret_fd)
- *ret_fd = TAKE_FD(fd);
-
- return 0;
- }
+ if (r < 0) {
+ /* PATH entries which we don't have access to are ignored, as per tradition. */
+ if (r != -EACCES)
+ last_error = r;
+ continue;
}
- /* PATH entries which we don't have access to are ignored, as per tradition. */
- if (errno != EACCES)
- last_error = -errno;
+ /* Found it! */
+ if (ret_filename)
+ *ret_filename = path_simplify(TAKE_PTR(j), false);
+ if (ret_fd)
+ *ret_fd = TAKE_FD(fd);
+
+ return 0;
}
return last_error;
@@ -765,38 +752,6 @@ int fsck_exists(const char *fstype) {
return executable_is_good(checker);
}
-int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
- char *p;
- int r;
-
- /*
- * This function is intended to be used in command line
- * parsers, to handle paths that are passed in. It makes the
- * path absolute, and reduces it to NULL if omitted or
- * root (the latter optionally).
- *
- * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
- * SUCCESS! Hence, do not pass in uninitialized pointers.
- */
-
- if (isempty(path)) {
- *arg = mfree(*arg);
- return 0;
- }
-
- r = path_make_absolute_cwd(path, &p);
- if (r < 0)
- return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
-
- path_simplify(p, false);
- if (suppress_root && empty_or_root(p))
- p = mfree(p);
-
- free_and_replace(*arg, p);
-
- return 0;
-}
-
char* dirname_malloc(const char *path) {
char *d, *dir, *dir2;
@@ -836,6 +791,8 @@ const char *last_path_component(const char *path) {
* Also, the empty string is mapped to itself.
*
* This is different than basename(), which returns "" when a trailing slash is present.
+ *
+ * This always succeeds (except if you pass NULL in which case it returns NULL, too).
*/
unsigned l, k;
@@ -861,32 +818,84 @@ const char *last_path_component(const char *path) {
int path_extract_filename(const char *p, char **ret) {
_cleanup_free_ char *a = NULL;
- const char *c, *e = NULL, *q;
+ const char *c;
+ size_t n;
/* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes
- * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing slashes. */
+ * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing
+ * slashes. Returns:
+ *
+ * -EINVAL → if the passed in path is not a valid path
+ * -EADDRNOTAVAIL → if only a directory was specified, but no filename, i.e. the root dir itself is specified
+ * -ENOMEM → no memory
+ *
+ * Returns >= 0 on success. If the input path has a trailing slash, returns O_DIRECTORY, to indicate
+ * the referenced file must be a directory.
+ *
+ * This function guarantees to return a fully valid filename, i.e. one that passes
+ * filename_is_valid() – this means "." and ".." are not accepted. */
- if (!p)
+ if (!path_is_valid(p))
return -EINVAL;
+ /* Special case the root dir, because in that case we simply have no filename, but
+ * last_path_component() won't complain */
+ if (path_equal(p, "/"))
+ return -EADDRNOTAVAIL;
+
c = last_path_component(p);
+ n = strcspn(c, "/");
+
+ a = strndup(c, n);
+ if (!a)
+ return -ENOMEM;
+
+ if (!filename_is_valid(a))
+ return -EINVAL;
+
+ *ret = TAKE_PTR(a);
+ return c[n] == '/' ? O_DIRECTORY : 0;
+}
+
+int path_extract_directory(const char *p, char **ret) {
+ _cleanup_free_ char *a = NULL;
+ const char *c;
- for (q = c; *q != 0; q++)
- if (*q != '/')
- e = q + 1;
+ /* The inverse of path_extract_filename(), i.e. returns the directory path prefix. Returns:
+ *
+ * -EINVAL → if the passed in path is not a valid path
+ * -EDESTADDRREQ → if no directory was specified in the passed in path, i.e. only a filename was passed
+ * -EADDRNOTAVAIL → if the passed in parameter had no filename but did have a directory, i.e. the root dir itself was specified
+ * -ENOMEM → no memory (surprise!)
+ *
+ * This function guarantees to return a fully valid path, i.e. one that passes path_is_valid().
+ */
- if (!e) /* no valid character? */
+ if (!path_is_valid(p))
return -EINVAL;
- a = strndup(c, e - c);
+ /* Special case the root dir, because otherwise for an input of "///" last_path_component() returns
+ * the pointer to the last slash only, which might be seen as a valid path below. */
+ if (path_equal(p, "/"))
+ return -EADDRNOTAVAIL;
+
+ c = last_path_component(p);
+
+ /* Delete trailing slashes, but keep one */
+ while (c > p+1 && c[-1] == '/')
+ c--;
+
+ if (p == c) /* No path whatsoever? Then return a recognizable error */
+ return -EDESTADDRREQ;
+
+ a = strndup(p, c - p);
if (!a)
return -ENOMEM;
- if (!filename_is_valid(a))
+ if (!path_is_valid(a))
return -EINVAL;
*ret = TAKE_PTR(a);
-
return 0;
}
@@ -903,7 +912,7 @@ bool filename_is_valid(const char *p) {
if (*e != 0)
return false;
- if (e - p > FILENAME_MAX) /* FILENAME_MAX is counted *without* the trailing NUL byte */
+ if (e - p > NAME_MAX) /* NAME_MAX is counted *without* the trailing NUL byte */
return false;
return true;
@@ -914,10 +923,25 @@ bool path_is_valid(const char *p) {
if (isempty(p))
return false;
- if (strlen(p) >= PATH_MAX) /* PATH_MAX is counted *with* the trailing NUL byte */
- return false;
+ for (const char *e = p;;) {
+ size_t n;
- return true;
+ /* Skip over slashes */
+ e += strspn(e, "/");
+ if (e - p >= PATH_MAX) /* Already reached the maximum length for a path? (PATH_MAX is counted
+ * *with* the trailing NUL byte) */
+ return false;
+ if (*e == 0) /* End of string? Yay! */
+ return true;
+
+ /* Skip over one component */
+ n = strcspn(e, "/");
+ if (n > NAME_MAX) /* One component larger than NAME_MAX? (NAME_MAX is counted *without* the
+ * trailing NUL byte) */
+ return false;
+
+ e += n;
+ }
}
bool path_is_normalized(const char *p) {
diff --git a/src/libnm-systemd-shared/src/basic/path-util.h b/src/libnm-systemd-shared/src/basic/path-util.h
index e7a26c9a84..74ee6362ea 100644
--- a/src/libnm-systemd-shared/src/basic/path-util.h
+++ b/src/libnm-systemd-shared/src/basic/path-util.h
@@ -144,11 +144,10 @@ int fsck_exists(const char *fstype);
_ret; \
})
-int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg);
-
char* dirname_malloc(const char *path);
const char *last_path_component(const char *path);
int path_extract_filename(const char *p, char **ret);
+int path_extract_directory(const char *p, char **ret);
bool filename_is_valid(const char *p) _pure_;
bool path_is_valid(const char *p) _pure_;
diff --git a/src/libnm-systemd-shared/src/basic/prioq.h b/src/libnm-systemd-shared/src/basic/prioq.h
index 951576c021..7c76647611 100644
--- a/src/libnm-systemd-shared/src/basic/prioq.h
+++ b/src/libnm-systemd-shared/src/basic/prioq.h
@@ -8,7 +8,7 @@
typedef struct Prioq Prioq;
-#define PRIOQ_IDX_NULL ((unsigned) -1)
+#define PRIOQ_IDX_NULL (UINT_MAX)
Prioq *prioq_new(compare_func_t compare);
Prioq *prioq_free(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 0851613fc9..7d4301eadb 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.c
+++ b/src/libnm-systemd-shared/src/basic/process-util.c
@@ -124,14 +124,10 @@ int get_process_comm(pid_t pid, char **ret) {
}
int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line) {
- _cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *t = NULL, *ans = NULL;
const char *p;
- int r;
size_t k;
-
- /* This is supposed to be a safety guard against runaway command lines. */
- size_t max_length = sc_arg_max();
+ int r;
assert(line);
assert(pid >= 0);
@@ -147,36 +143,18 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
* comm_fallback is false). Returns 0 and sets *line otherwise. */
p = procfs_file_alloca(pid, "cmdline");
- r = fopen_unlocked(p, "re", &f);
+ r = read_full_virtual_file(p, &t, &k);
if (r == -ENOENT)
return -ESRCH;
if (r < 0)
return r;
- /* We assume that each four-byte character uses one or two columns. If we ever check for combining
- * characters, this assumption will need to be adjusted. */
- if ((size_t) 4 * max_columns + 1 < max_columns)
- max_length = MIN(max_length, (size_t) 4 * max_columns + 1);
-
- t = new(char, max_length);
- if (!t)
- return -ENOMEM;
-
- k = fread(t, 1, max_length, f);
if (k > 0) {
/* Arguments are separated by NULs. Let's replace those with spaces. */
for (size_t i = 0; i < k - 1; i++)
if (t[i] == '\0')
t[i] = ' ';
-
- t[k] = '\0'; /* Normally, t[k] is already NUL, so this is just a guard in case of short read */
} else {
- /* We only treat getting nothing as an error. We *could* also get an error after reading some
- * data, but we ignore that case, as such an error is rather unlikely and we prefer to get
- * some data rather than none. */
- if (ferror(f))
- return -errno;
-
if (!(flags & PROCESS_CMDLINE_COMM_FALLBACK))
return -ENOENT;
@@ -187,7 +165,7 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
if (r < 0)
return r;
- mfree(t);
+ free(t);
t = strjoin("[", t2, "]");
if (!t)
return -ENOMEM;
@@ -756,7 +734,7 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
/* Drop into a sigtimewait-based timeout. Waiting for the
* pid to exit. */
- until = now(CLOCK_MONOTONIC) + timeout;
+ until = usec_add(now(CLOCK_MONOTONIC), timeout);
for (;;) {
usec_t n;
siginfo_t status = {};
@@ -1230,6 +1208,11 @@ int safe_fork_full(
original_pid = getpid_cached();
+ if (flags & FORK_FLUSH_STDIO) {
+ fflush(stdout);
+ fflush(stderr); /* This one shouldn't be necessary, stderr should be unbuffered anyway, but let's better be safe than sorry */
+ }
+
if (flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG)) {
/* We temporarily block all signals, so that the new child has them blocked initially. This way, we can
* be sure that SIGTERMs are not lost we might send to the child. */
@@ -1462,7 +1445,11 @@ int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret
/* Spawns a temporary TTY agent, making sure it goes away when we go away */
- r = safe_fork_full(name, except, n_except, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, ret_pid);
+ r = safe_fork_full(name,
+ except,
+ n_except,
+ FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG,
+ ret_pid);
if (r < 0)
return r;
if (r > 0)
@@ -1543,7 +1530,7 @@ int pidfd_get_pid(int fd, pid_t *ret) {
xsprintf(path, "/proc/self/fdinfo/%i", fd);
- r = read_full_file(path, &fdinfo, NULL);
+ r = read_full_virtual_file(path, &fdinfo, NULL);
if (r == -ENOENT) /* if fdinfo doesn't exist we assume the process does not exist */
return -ESRCH;
if (r < 0)
@@ -1620,6 +1607,16 @@ 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);
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/libnm-systemd-shared/src/basic/process-util.h b/src/libnm-systemd-shared/src/basic/process-util.h
index 6144f142c4..ddce7bd272 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.h
+++ b/src/libnm-systemd-shared/src/basic/process-util.h
@@ -162,6 +162,7 @@ typedef enum ForkFlags {
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 */
} ForkFlags;
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
@@ -199,3 +200,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
int pidfd_get_pid(int fd, pid_t *ret);
int setpriority_closest(int priority);
+
+bool invoked_as(char *argv[], const char *token);
diff --git a/src/libnm-systemd-shared/src/basic/random-util.c b/src/libnm-systemd-shared/src/basic/random-util.c
index c831f06dac..a125e5228e 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.c
+++ b/src/libnm-systemd-shared/src/basic/random-util.c
@@ -494,3 +494,22 @@ int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
return 1;
}
+
+uint64_t random_u64_range(uint64_t m) {
+ uint64_t x, remainder;
+
+ /* Generates a random number in the range 0…m-1, unbiased. (Java's algorithm) */
+
+ if (m == 0) /* Let's take m == 0 as special case to return an integer from the full range */
+ return random_u64();
+ if (m == 1)
+ return 0;
+
+ remainder = UINT64_MAX % m;
+
+ do {
+ x = random_u64();
+ } while (x >= UINT64_MAX - remainder);
+
+ return x % m;
+}
diff --git a/src/libnm-systemd-shared/src/basic/random-util.h b/src/libnm-systemd-shared/src/basic/random-util.h
index f661fc093a..e6528ddc7f 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.h
+++ b/src/libnm-systemd-shared/src/basic/random-util.h
@@ -40,3 +40,5 @@ int rdrand(unsigned long *ret);
size_t random_pool_size(void);
int random_write_entropy(int fd, const void *seed, size_t size, bool credit);
+
+uint64_t random_u64_range(uint64_t max);
diff --git a/src/libnm-systemd-shared/src/basic/ratelimit.c b/src/libnm-systemd-shared/src/basic/ratelimit.c
index bae2ec3ffc..005bf31dc7 100644
--- a/src/libnm-systemd-shared/src/basic/ratelimit.c
+++ b/src/libnm-systemd-shared/src/basic/ratelimit.c
@@ -19,7 +19,7 @@ bool ratelimit_below(RateLimit *r) {
ts = now(CLOCK_MONOTONIC);
if (r->begin <= 0 ||
- ts - r->begin > r->interval) {
+ usec_sub_unsigned(ts, r->begin) > r->interval) {
r->begin = ts;
/* Reset counter */
diff --git a/src/libnm-systemd-shared/src/basic/set.h b/src/libnm-systemd-shared/src/basic/set.h
index 57ff713039..52b6f4984c 100644
--- a/src/libnm-systemd-shared/src/basic/set.h
+++ b/src/libnm-systemd-shared/src/basic/set.h
@@ -152,3 +152,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
#define _cleanup_set_free_free_ _cleanup_(set_free_freep)
int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret);
+
+bool set_equal(Set *a, Set *b);
diff --git a/src/libnm-systemd-shared/src/basic/signal-util.c b/src/libnm-systemd-shared/src/basic/signal-util.c
index 63b833b218..131fd3ba00 100644
--- a/src/libnm-systemd-shared/src/basic/signal-util.c
+++ b/src/libnm-systemd-shared/src/basic/signal-util.c
@@ -15,9 +15,9 @@ int reset_all_signal_handlers(void) {
.sa_handler = SIG_DFL,
.sa_flags = SA_RESTART,
};
- int sig, r = 0;
+ int r = 0;
- for (sig = 1; sig < _NSIG; sig++) {
+ for (int sig = 1; sig < _NSIG; sig++) {
/* These two cannot be caught... */
if (IN_SET(sig, SIGKILL, SIGSTOP))
@@ -45,11 +45,14 @@ int reset_signal_mask(void) {
return 0;
}
-static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
- int r = 0;
+int sigaction_many_internal(const struct sigaction *sa, ...) {
+ int sig, r = 0;
+ va_list ap;
+
+ va_start(ap, sa);
/* negative signal ends the list. 0 signal is skipped. */
- for (; sig >= 0; sig = va_arg(ap, int)) {
+ while ((sig = va_arg(ap, int)) >= 0) {
if (sig == 0)
continue;
@@ -60,49 +63,6 @@ static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
}
}
- return r;
-}
-
-int sigaction_many(const struct sigaction *sa, ...) {
- va_list ap;
- int r;
-
- va_start(ap, sa);
- r = sigaction_many_ap(sa, 0, ap);
- va_end(ap);
-
- return r;
-}
-
-int ignore_signals(int sig, ...) {
-
- static const struct sigaction sa = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_RESTART,
- };
-
- va_list ap;
- int r;
-
- va_start(ap, sig);
- r = sigaction_many_ap(&sa, sig, ap);
- va_end(ap);
-
- return r;
-}
-
-int default_signals(int sig, ...) {
-
- static const struct sigaction sa = {
- .sa_handler = SIG_DFL,
- .sa_flags = SA_RESTART,
- };
-
- va_list ap;
- int r;
-
- va_start(ap, sig);
- r = sigaction_many_ap(&sa, sig, ap);
va_end(ap);
return r;
@@ -198,7 +158,7 @@ static const char *const __signal_table[] = {
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
const char *signal_to_string(int signo) {
- static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int) + 1];
+ static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int)];
const char *name;
name = __signal_to_string(signo);
diff --git a/src/libnm-systemd-shared/src/basic/signal-util.h b/src/libnm-systemd-shared/src/basic/signal-util.h
index bdd39d429d..37271d7a68 100644
--- a/src/libnm-systemd-shared/src/basic/signal-util.h
+++ b/src/libnm-systemd-shared/src/basic/signal-util.h
@@ -8,9 +8,28 @@
int reset_all_signal_handlers(void);
int reset_signal_mask(void);
-int ignore_signals(int sig, ...);
-int default_signals(int sig, ...);
-int sigaction_many(const struct sigaction *sa, ...);
+int sigaction_many_internal(const struct sigaction *sa, ...);
+
+#define ignore_signals(...) \
+ sigaction_many_internal( \
+ &(const struct sigaction) { \
+ .sa_handler = SIG_IGN, \
+ .sa_flags = SA_RESTART \
+ }, \
+ __VA_ARGS__, \
+ -1)
+
+#define default_signals(...) \
+ sigaction_many_internal( \
+ &(const struct sigaction) { \
+ .sa_handler = SIG_DFL, \
+ .sa_flags = SA_RESTART \
+ }, \
+ __VA_ARGS__, \
+ -1)
+
+#define sigaction_many(sa, ...) \
+ sigaction_many_internal(sa, __VA_ARGS__, -1)
int sigset_add_many(sigset_t *ss, ...);
int sigprocmask_many(int how, sigset_t *old, ...);
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.c b/src/libnm-systemd-shared/src/basic/socket-util.c
index 59039bea4f..552ec053ff 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.c
+++ b/src/libnm-systemd-shared/src/basic/socket-util.c
@@ -31,6 +31,7 @@
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
+#include "sysctl-util.h"
#include "user-util.h"
#include "utf8.h"
@@ -277,10 +278,48 @@ const char* socket_address_get_path(const SocketAddress *a) {
}
bool socket_ipv6_is_supported(void) {
- if (access("/proc/net/if_inet6", F_OK) != 0)
+ static int cached = -1;
+
+ if (cached < 0) {
+
+ if (access("/proc/net/if_inet6", F_OK) < 0) {
+
+ if (errno != ENOENT) {
+ log_debug_errno(errno, "Unexpected error when checking whether /proc/net/if_inet6 exists: %m");
+ return false;
+ }
+
+ cached = false;
+ } else
+ cached = true;
+ }
+
+ return cached;
+}
+
+bool socket_ipv6_is_enabled(void) {
+ _cleanup_free_ char *v = NULL;
+ int r;
+
+ /* Much like socket_ipv6_is_supported(), but also checks that the sysctl that disables IPv6 on all
+ * interfaces isn't turned on */
+
+ if (!socket_ipv6_is_supported())
return false;
- return true;
+ r = sysctl_read_ip_property(AF_INET6, "all", "disable_ipv6", &v);
+ if (r < 0) {
+ log_debug_errno(r, "Unexpected error reading 'net.ipv6.conf.all.disable_ipv6' sysctl: %m");
+ return true;
+ }
+
+ r = parse_boolean(v);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to pare 'net.ipv6.conf.all.disable_ipv6' sysctl: %m");
+ return true;
+ }
+
+ return !r;
}
bool socket_address_matches_fd(const SocketAddress *a, int fd) {
@@ -721,6 +760,10 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
if (isempty(p))
return false;
+ /* A valid ifindex? If so, it's valid iff IFNAME_VALID_NUMERIC is set */
+ if (parse_ifindex(p) >= 0)
+ return flags & IFNAME_VALID_NUMERIC;
+
if (flags & IFNAME_VALID_ALTERNATIVE) {
if (strlen(p) >= ALTIFNAMSIZ)
return false;
@@ -732,6 +775,11 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
if (dot_or_dot_dot(p))
return false;
+ /* Let's refuse "all" and "default" as interface name, to avoid collisions with the special sysctl
+ * directories /proc/sys/net/{ipv4,ipv6}/conf/{all,default} */
+ if (STR_IN_SET(p, "all", "default"))
+ return false;
+
for (const char *t = p; *t; t++) {
if ((unsigned char) *t >= 127U)
return false;
@@ -739,20 +787,19 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
if ((unsigned char) *t <= 32U)
return false;
- if (IN_SET(*t, ':', '/'))
+ if (IN_SET(*t,
+ ':', /* colons are used by the legacy "alias" interface logic */
+ '/', /* slashes cannot work, since we need to use network interfaces in sysfs paths, and in paths slashes are separators */
+ '%')) /* %d is used in the kernel's weird foo%d format string naming feature which we really really don't want to ever run into by accident */
return false;
numeric = numeric && (*t >= '0' && *t <= '9');
}
- if (numeric) {
- if (!(flags & IFNAME_VALID_NUMERIC))
- return false;
-
- /* Verify that the number is well-formatted and in range. */
- if (parse_ifindex(p) < 0)
- return false;
- }
+ /* It's fully numeric but didn't parse as valid ifindex above? if so, it must be too large or zero or
+ * so, let's refuse that. */
+ if (numeric)
+ return false;
return true;
}
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.h b/src/libnm-systemd-shared/src/basic/socket-util.h
index 240d209c14..507a599d7c 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.h
+++ b/src/libnm-systemd-shared/src/basic/socket-util.h
@@ -63,7 +63,7 @@ typedef enum SocketAddressBindIPv6Only {
SOCKET_ADDRESS_BOTH,
SOCKET_ADDRESS_IPV6_ONLY,
_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX,
- _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -1
+ _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -EINVAL,
} SocketAddressBindIPv6Only;
#define socket_address_family(a) ((a)->sockaddr.sa.sa_family)
@@ -101,6 +101,7 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_
const char* socket_address_get_path(const SocketAddress *a);
bool socket_ipv6_is_supported(void);
+bool socket_ipv6_is_enabled(void);
int sockaddr_port(const struct sockaddr *_sa, unsigned *port);
const union in_addr_union *sockaddr_in_addr(const struct sockaddr *sa);
@@ -133,9 +134,9 @@ int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
typedef enum {
- IFNAME_VALID_ALTERNATIVE = 1 << 0,
- IFNAME_VALID_NUMERIC = 1 << 1,
- _IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC,
+ IFNAME_VALID_ALTERNATIVE = 1 << 0,
+ IFNAME_VALID_NUMERIC = 1 << 1,
+ _IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC,
} IfnameValidFlags;
bool ifname_valid_full(const char *p, IfnameValidFlags flags);
static inline bool ifname_valid(const char *p) {
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c
index f999681636..72a7e4a48b 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.c
+++ b/src/libnm-systemd-shared/src/basic/stat-util.c
@@ -72,12 +72,17 @@ int dir_is_empty_at(int dir_fd, const char *path) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
- if (path)
+ if (path) {
fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
- else
- fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
- if (fd < 0)
- return -errno;
+ if (fd < 0)
+ return -errno;
+ } else {
+ /* Note that DUPing is not enough, as the internal pointer
+ * would still be shared and moved by FOREACH_DIRENT. */
+ fd = fd_reopen(dir_fd, O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+ }
d = take_fdopendir(&fd);
if (!d)
diff --git a/src/libnm-systemd-shared/src/basic/string-table.c b/src/libnm-systemd-shared/src/basic/string-table.c
index 116021df82..3a6376714a 100644
--- a/src/libnm-systemd-shared/src/basic/string-table.c
+++ b/src/libnm-systemd-shared/src/basic/string-table.c
@@ -5,11 +5,11 @@
ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
if (!key)
- return -1;
+ return -EINVAL;
for (size_t i = 0; i < len; ++i)
if (streq_ptr(table[i], key))
return (ssize_t) i;
- return -1;
+ return -EINVAL;
}
diff --git a/src/libnm-systemd-shared/src/basic/string-table.h b/src/libnm-systemd-shared/src/basic/string-table.h
index ae4ea145d3..97c1adc07d 100644
--- a/src/libnm-systemd-shared/src/basic/string-table.h
+++ b/src/libnm-systemd-shared/src/basic/string-table.h
@@ -29,7 +29,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
scope type name##_from_string(const char *s) { \
if (!s) \
- return -1; \
+ return -EINVAL; \
int b = parse_boolean(s); \
if (b == 0) \
return (type) 0; \
@@ -60,14 +60,16 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
unsigned u = 0; \
type i; \
if (!s) \
- return (type) -1; \
+ return -EINVAL; \
i = (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
if (i >= 0) \
return i; \
- if (safe_atou(s, &u) >= 0 && u <= max) \
- return (type) u; \
- return (type) -1; \
- } \
+ if (safe_atou(s, &u) < 0) \
+ return -EINVAL; \
+ if (u > max) \
+ return -EINVAL; \
+ return (type) u; \
+ }
#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
@@ -79,12 +81,15 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
#define DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,)
+#define DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes) \
+ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,static)
/* For string conversions where numbers are also acceptable */
#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
@@ -98,9 +103,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
#define DUMP_STRING_TABLE(name,type,max) \
do { \
- type _k; \
flockfile(stdout); \
- for (_k = 0; _k < (max); _k++) { \
+ for (type _k = 0; _k < (max); _k++) { \
const char *_t; \
_t = name##_to_string(_k); \
if (!_t) \
diff --git a/src/libnm-systemd-shared/src/basic/string-util.c b/src/libnm-systemd-shared/src/basic/string-util.c
index be42d5c4f5..058eec54ff 100644
--- a/src/libnm-systemd-shared/src/basic/string-util.c
+++ b/src/libnm-systemd-shared/src/basic/string-util.c
@@ -20,64 +20,6 @@
#include "utf8.h"
#include "util.h"
-int strcmp_ptr(const char *a, const char *b) {
- /* Like strcmp(), but tries to make sense of NULL pointers */
-
- if (a && b)
- return strcmp(a, b);
- return CMP(a, b); /* Direct comparison of pointers, one of which is NULL */
-}
-
-int strcasecmp_ptr(const char *a, const char *b) {
- /* Like strcasecmp(), but tries to make sense of NULL pointers */
-
- if (a && b)
- return strcasecmp(a, b);
- return CMP(a, b); /* Direct comparison of pointers, one of which is NULL */
-}
-
-char* endswith(const char *s, const char *postfix) {
- size_t sl, pl;
-
- assert(s);
- assert(postfix);
-
- sl = strlen(s);
- pl = strlen(postfix);
-
- if (pl == 0)
- return (char*) s + sl;
-
- if (sl < pl)
- return NULL;
-
- if (memcmp(s + sl - pl, postfix, pl) != 0)
- return NULL;
-
- return (char*) s + sl - pl;
-}
-
-char* endswith_no_case(const char *s, const char *postfix) {
- size_t sl, pl;
-
- assert(s);
- assert(postfix);
-
- sl = strlen(s);
- pl = strlen(postfix);
-
- if (pl == 0)
- return (char*) s + sl;
-
- if (sl < pl)
- return NULL;
-
- if (strcasecmp(s + sl - pl, postfix) != 0)
- return NULL;
-
- return (char*) s + sl - pl;
-}
-
char* first_word(const char *s, const char *word) {
size_t sl, wl;
const char *p;
@@ -129,7 +71,7 @@ char *strnappend(const char *s, const char *suffix, size_t b) {
assert(suffix);
a = strlen(s);
- if (b > ((size_t) -1) - a)
+ if (b > SIZE_MAX - a)
return NULL;
r = new(char, a+b+1);
@@ -365,7 +307,7 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le
assert(s);
assert(percent <= 100);
- assert(new_length != (size_t) -1);
+ assert(new_length != SIZE_MAX);
if (old_length <= new_length)
return strndup(s, old_length);
@@ -436,7 +378,7 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
assert(s);
assert(percent <= 100);
- if (new_length == (size_t) -1)
+ if (new_length == SIZE_MAX)
return strndup(s, old_length);
if (new_length == 0)
@@ -862,9 +804,8 @@ char *strextend_with_separator_internal(char **x, const char *separator, ...) {
}
char *strrep(const char *s, unsigned n) {
- size_t l;
char *r, *p;
- unsigned i;
+ size_t l;
assert(s);
@@ -873,7 +814,7 @@ char *strrep(const char *s, unsigned n) {
if (!r)
return NULL;
- for (i = 0; i < n; i++)
+ for (unsigned i = 0; i < n; i++)
p = stpcpy(p, s);
*p = 0;
diff --git a/src/libnm-systemd-shared/src/basic/string-util.h b/src/libnm-systemd-shared/src/basic/string-util.h
index 593cf04ae1..cb2881b64d 100644
--- a/src/libnm-systemd-shared/src/basic/string-util.h
+++ b/src/libnm-systemd-shared/src/basic/string-util.h
@@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "macro.h"
+#include "string-util-fundamental.h"
/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n\r"
@@ -21,18 +22,6 @@
#define ALPHANUMERICAL LETTERS DIGITS
#define HEXDIGITS DIGITS "abcdefABCDEF"
-#define streq(a,b) (strcmp((a),(b)) == 0)
-#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
-#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
-#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
-
-int strcmp_ptr(const char *a, const char *b) _pure_;
-int strcasecmp_ptr(const char *a, const char *b) _pure_;
-
-static inline bool streq_ptr(const char *a, const char *b) {
- return strcmp_ptr(a, b) == 0;
-}
-
static inline char* strstr_ptr(const char *haystack, const char *needle) {
if (!haystack || !needle)
return NULL;
@@ -51,10 +40,6 @@ static inline const char *strna(const char *s) {
return s ?: "n/a";
}
-static inline const char* yes_no(bool b) {
- return b ? "yes" : "no";
-}
-
static inline const char* true_false(bool b) {
return b ? "true" : "false";
}
@@ -71,10 +56,6 @@ static inline const char* enable_disable(bool b) {
return b ? "enable" : "disable";
}
-static inline bool isempty(const char *p) {
- return !p || !p[0];
-}
-
static inline const char *empty_to_null(const char *p) {
return isempty(p) ? NULL : p;
}
@@ -93,29 +74,6 @@ static inline const char *empty_or_dash_to_null(const char *p) {
return empty_or_dash(p) ? NULL : p;
}
-static inline char *startswith(const char *s, const char *prefix) {
- size_t l;
-
- l = strlen(prefix);
- if (strncmp(s, prefix, l) == 0)
- return (char*) s + l;
-
- return NULL;
-}
-
-static inline char *startswith_no_case(const char *s, const char *prefix) {
- size_t l;
-
- l = strlen(prefix);
- if (strncasecmp(s, prefix, l) == 0)
- return (char*) s + l;
-
- return NULL;
-}
-
-char *endswith(const char *s, const char *postfix) _pure_;
-char *endswith_no_case(const char *s, const char *postfix) _pure_;
-
char *first_word(const char *s, const char *word) _pure_;
char *strnappend(const char *s, const char *suffix, size_t length);
diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c
index 492dfe4002..765da04a7b 100644
--- a/src/libnm-systemd-shared/src/basic/strv.c
+++ b/src/libnm-systemd-shared/src/basic/strv.c
@@ -240,27 +240,28 @@ int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) {
return 0;
}
-char **strv_split_newlines(const char *s) {
- char **l;
+int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags) {
+ _cleanup_strv_free_ char **l = NULL;
size_t n;
+ int r;
assert(s);
- /* Special version of strv_split() that splits on newlines and
- * suppresses an empty string at the end */
+ /* Special version of strv_split_full() that splits on newlines and
+ * suppresses an empty string at the end. */
- l = strv_split(s, NEWLINE);
- if (!l)
- return NULL;
+ r = strv_split_full(&l, s, NEWLINE, flags);
+ if (r < 0)
+ return r;
n = strv_length(l);
- if (n <= 0)
- return l;
-
- if (isempty(l[n - 1]))
+ if (n > 0 && isempty(l[n - 1])) {
l[n - 1] = mfree(l[n - 1]);
+ n--;
+ }
- return l;
+ *ret = TAKE_PTR(l);
+ return n;
}
int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags) {
diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h
index 6b3e8e7f86..911528fab4 100644
--- a/src/libnm-systemd-shared/src/basic/strv.h
+++ b/src/libnm-systemd-shared/src/basic/strv.h
@@ -73,15 +73,21 @@ static inline bool strv_isempty(char * const *l) {
return !l || !*l;
}
-char **strv_split_newlines(const char *s);
-
int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags);
static inline char **strv_split(const char *s, const char *separators) {
char **ret;
- int r;
- r = strv_split_full(&ret, s, separators, 0);
- if (r < 0)
+ if (strv_split_full(&ret, s, separators, 0) < 0)
+ return NULL;
+
+ return ret;
+}
+
+int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags);
+static inline char **strv_split_newlines(const char *s) {
+ char **ret;
+
+ if (strv_split_newlines_full(&ret, s, 0) < 0)
return NULL;
return ret;
diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c
index 52c564a68d..3c2b25bd2a 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.c
+++ b/src/libnm-systemd-shared/src/basic/time-util.c
@@ -493,7 +493,6 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
{ "us", 1 },
};
- size_t i;
char *p = buf;
bool something = false;
@@ -514,7 +513,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
/* The result of this function can be parsed with parse_sec */
- for (i = 0; i < ELEMENTSOF(table); i++) {
+ for (size_t i = 0; i < ELEMENTSOF(table); i++) {
int k = 0;
size_t n;
bool done = false;
@@ -962,9 +961,8 @@ static const char* extract_multiplier(const char *p, usec_t *multiplier) {
{ "us", 1ULL },
{ "µs", 1ULL },
};
- size_t i;
- for (i = 0; i < ELEMENTSOF(table); i++) {
+ for (size_t i = 0; i < ELEMENTSOF(table); i++) {
char *e;
e = startswith(p, table[i].suffix);
diff --git a/src/libnm-systemd-shared/src/basic/time-util.h b/src/libnm-systemd-shared/src/basic/time-util.h
index 89ee8b4a96..d716074fbe 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.h
+++ b/src/libnm-systemd-shared/src/basic/time-util.h
@@ -35,7 +35,7 @@ typedef enum TimestampStyle {
TIMESTAMP_UTC,
TIMESTAMP_US_UTC,
_TIMESTAMP_STYLE_MAX,
- _TIMESTAMP_STYLE_INVALID = -1,
+ _TIMESTAMP_STYLE_INVALID = -EINVAL,
} TimestampStyle;
#define USEC_INFINITY ((usec_t) UINT64_MAX)
@@ -155,16 +155,14 @@ usec_t jiffies_to_usec(uint32_t jiffies);
bool in_utc_timezone(void);
static inline usec_t usec_add(usec_t a, usec_t b) {
- usec_t c;
/* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output, and doesn't
* overflow. */
- c = a + b;
- if (c < a || c < b) /* overflow check */
+ if (a > USEC_INFINITY - b) /* overflow check */
return USEC_INFINITY;
- return c;
+ return a + b;
}
static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) {
diff --git a/src/libnm-systemd-shared/src/basic/tmpfile-util.c b/src/libnm-systemd-shared/src/basic/tmpfile-util.c
index 49c343773c..5ee71d0158 100644
--- a/src/libnm-systemd-shared/src/basic/tmpfile-util.c
+++ b/src/libnm-systemd-shared/src/basic/tmpfile-util.c
@@ -94,16 +94,11 @@ int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) {
}
int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
- const char *fn;
- char *t;
+ _cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL;
+ int r;
assert(ret);
- if (isempty(p))
- return -EINVAL;
- if (path_equal(p, "/"))
- return -EINVAL;
-
/*
* Turns this:
* /foo/bar/waldo
@@ -112,35 +107,41 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
* /foo/bar/.#<extra>waldoXXXXXX
*/
- fn = basename(p);
- if (!filename_is_valid(fn))
- return -EINVAL;
+ r = path_extract_directory(p, &d);
+ if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */
+ return r;
- extra = strempty(extra);
+ r = path_extract_filename(p, &fn);
+ if (r < 0)
+ return r;
- t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
- if (!t)
+ nf = strjoin(".#", strempty(extra), fn, "XXXXXX");
+ if (!nf)
return -ENOMEM;
- strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
+ if (!filename_is_valid(nf)) /* New name is not valid? (Maybe because too long?) Refuse. */
+ return -EINVAL;
+
+ if (d) {
+ char *j;
+
+ j = path_join(d, nf);
+ if (!j)
+ return -ENOMEM;
+
+ *ret = path_simplify(j, false);
+ } else
+ *ret = TAKE_PTR(nf);
- *ret = path_simplify(t, false);
return 0;
}
int tempfn_random(const char *p, const char *extra, char **ret) {
- const char *fn;
- char *t, *x;
- uint64_t u;
- unsigned i;
+ _cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL;
+ int r;
assert(ret);
- if (isempty(p))
- return -EINVAL;
- if (path_equal(p, "/"))
- return -EINVAL;
-
/*
* Turns this:
* /foo/bar/waldo
@@ -149,34 +150,40 @@ int tempfn_random(const char *p, const char *extra, char **ret) {
* /foo/bar/.#<extra>waldobaa2a261115984a9
*/
- fn = basename(p);
- if (!filename_is_valid(fn))
- return -EINVAL;
+ r = path_extract_directory(p, &d);
+ if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */
+ return r;
- extra = strempty(extra);
+ r = path_extract_filename(p, &fn);
+ if (r < 0)
+ return r;
- t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
- if (!t)
+ if (asprintf(&nf, ".#%s%s%016" PRIx64,
+ strempty(extra),
+ fn,
+ random_u64()) < 0)
return -ENOMEM;
- x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
+ if (!filename_is_valid(nf)) /* Not valid? (maybe because too long now?) — refuse early */
+ return -EINVAL;
- u = random_u64();
- for (i = 0; i < 16; i++) {
- *(x++) = hexchar(u & 0xF);
- u >>= 4;
- }
+ if (d) {
+ char *j;
- *x = 0;
+ j = path_join(d, nf);
+ if (!j)
+ return -ENOMEM;
+
+ *ret = path_simplify(j, false);
+ } else
+ *ret = TAKE_PTR(nf);
- *ret = path_simplify(t, false);
return 0;
}
int tempfn_random_child(const char *p, const char *extra, char **ret) {
char *t, *x;
uint64_t u;
- unsigned i;
int r;
assert(ret);
@@ -205,7 +212,7 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
u = random_u64();
- for (i = 0; i < 16; i++) {
+ for (unsigned i = 0; i < 16; i++) {
*(x++) = hexchar(u & 0xF);
u >>= 4;
}
diff --git a/src/libnm-systemd-shared/src/basic/utf8.c b/src/libnm-systemd-shared/src/basic/utf8.c
index 59663c0350..46c3a463b9 100644
--- a/src/libnm-systemd-shared/src/basic/utf8.c
+++ b/src/libnm-systemd-shared/src/basic/utf8.c
@@ -81,7 +81,7 @@ static size_t utf8_encoded_expected_len(uint8_t c) {
/* decode one unicode char */
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
char32_t unichar;
- size_t len, i;
+ size_t len;
assert(str);
@@ -110,7 +110,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
return -EINVAL;
}
- for (i = 1; i < len; i++) {
+ for (size_t i = 1; i < len; i++) {
if (((char32_t)str[i] & 0xc0) != 0x80)
return -EINVAL;
@@ -156,14 +156,14 @@ char *utf8_is_valid_n(const char *str, size_t len_bytes) {
assert(str);
- for (const char *p = str; len_bytes != (size_t) -1 ? (size_t) (p - str) < len_bytes : *p != '\0'; ) {
+ for (const char *p = str; len_bytes != SIZE_MAX ? (size_t) (p - str) < len_bytes : *p != '\0'; ) {
int len;
- if (_unlikely_(*p == '\0') && len_bytes != (size_t) -1)
+ if (_unlikely_(*p == '\0') && len_bytes != SIZE_MAX)
return NULL; /* embedded NUL */
len = utf8_encoded_valid_unichar(p,
- len_bytes != (size_t) -1 ? len_bytes - (p - str) : (size_t) -1);
+ len_bytes != SIZE_MAX ? len_bytes - (p - str) : SIZE_MAX);
if (_unlikely_(len < 0))
return NULL; /* invalid character */
@@ -185,7 +185,7 @@ char *utf8_escape_invalid(const char *str) {
while (*str) {
int len;
- len = utf8_encoded_valid_unichar(str, (size_t) -1);
+ len = utf8_encoded_valid_unichar(str, SIZE_MAX);
if (len > 0) {
s = mempcpy(s, str, len);
str += len;
@@ -233,7 +233,7 @@ char *utf8_escape_non_printable_full(const char *str, size_t console_width) {
if (!*str) /* done! */
goto finish;
- len = utf8_encoded_valid_unichar(str, (size_t) -1);
+ len = utf8_encoded_valid_unichar(str, SIZE_MAX);
if (len > 0) {
if (utf8_is_printable(str, len)) {
int w;
@@ -302,14 +302,12 @@ char *ascii_is_valid(const char *str) {
}
char *ascii_is_valid_n(const char *str, size_t len) {
- size_t i;
-
/* Very similar to ascii_is_valid(), but checks exactly len
* bytes and rejects any NULs in that range. */
assert(str);
- for (i = 0; i < len; i++)
+ for (size_t i = 0; i < len; i++)
if ((unsigned char) str[i] >= 128 || str[i] == 0)
return NULL;
@@ -436,7 +434,6 @@ size_t utf16_encode_unichar(char16_t *out, char32_t c) {
char16_t *utf8_to_utf16(const char *s, size_t length) {
char16_t *n, *p;
- size_t i;
int r;
assert(s);
@@ -447,7 +444,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length) {
p = n;
- for (i = 0; i < length;) {
+ for (size_t i = 0; i < length;) {
char32_t unichar;
size_t e;
@@ -505,13 +502,13 @@ static int utf8_unichar_to_encoded_len(char32_t unichar) {
/* validate one encoded unicode char and return its length */
int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) {
char32_t unichar;
- size_t len, i;
+ size_t len;
int r;
assert(str);
assert(length > 0);
- /* We read until NUL, at most length bytes. (size_t) -1 may be used to disable the length check. */
+ /* We read until NUL, at most length bytes. SIZE_MAX may be used to disable the length check. */
len = utf8_encoded_expected_len(str[0]);
if (len == 0)
@@ -526,7 +523,7 @@ int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) {
return 1;
/* check if expected encoded chars are available */
- for (i = 0; i < len; i++)
+ for (size_t i = 0; i < len; i++)
if ((str[i] & 0x80) != 0x80)
return -EINVAL;
@@ -548,14 +545,14 @@ int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) {
size_t utf8_n_codepoints(const char *str) {
size_t n = 0;
- /* Returns the number of UTF-8 codepoints in this string, or (size_t) -1 if the string is not valid UTF-8. */
+ /* Returns the number of UTF-8 codepoints in this string, or SIZE_MAX if the string is not valid UTF-8. */
while (*str != 0) {
int k;
- k = utf8_encoded_valid_unichar(str, (size_t) -1);
+ k = utf8_encoded_valid_unichar(str, SIZE_MAX);
if (k < 0)
- return (size_t) -1;
+ return SIZE_MAX;
str += k;
n++;
@@ -575,7 +572,7 @@ size_t utf8_console_width(const char *str) {
w = utf8_char_console_width(str);
if (w < 0)
- return (size_t) -1;
+ return SIZE_MAX;
n += w;
str = utf8_next_char(str);
diff --git a/src/libnm-systemd-shared/src/basic/utf8.h b/src/libnm-systemd-shared/src/basic/utf8.h
index a6ea942c62..219ca89184 100644
--- a/src/libnm-systemd-shared/src/basic/utf8.h
+++ b/src/libnm-systemd-shared/src/basic/utf8.h
@@ -16,7 +16,7 @@ bool unichar_is_valid(char32_t c);
char *utf8_is_valid_n(const char *str, size_t len_bytes) _pure_;
static inline char *utf8_is_valid(const char *s) {
- return utf8_is_valid_n(s, (size_t) -1);
+ return utf8_is_valid_n(s, SIZE_MAX);
}
char *ascii_is_valid(const char *s) _pure_;
char *ascii_is_valid_n(const char *str, size_t len);
@@ -27,7 +27,7 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newlin
char *utf8_escape_invalid(const char *s);
char *utf8_escape_non_printable_full(const char *str, size_t console_width);
static inline char *utf8_escape_non_printable(const char *str) {
- return utf8_escape_non_printable_full(str, (size_t) -1);
+ return utf8_escape_non_printable_full(str, SIZE_MAX);
}
size_t utf8_encode_unichar(char *out_utf8, char32_t g);
diff --git a/src/libnm-systemd-shared/src/basic/util.c b/src/libnm-systemd-shared/src/basic/util.c
index 7c708eb3be..955b18bd2a 100644
--- a/src/libnm-systemd-shared/src/basic/util.c
+++ b/src/libnm-systemd-shared/src/basic/util.c
@@ -52,13 +52,14 @@ int prot_from_flags(int flags) {
}
bool in_initrd(void) {
- struct statfs s;
int r;
+ const char *e;
+ bool lenient = false;
if (saved_in_initrd >= 0)
return saved_in_initrd;
- /* We make two checks here:
+ /* 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
@@ -66,18 +67,46 @@ bool in_initrd(void) {
* 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.
*/
- r = getenv_bool_secure("SYSTEMD_IN_INITRD");
- if (r < 0 && r != -ENXIO)
- log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m");
+ 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");
- if (r >= 0)
saved_in_initrd = r > 0;
- else
- saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
- statfs("/", &s) >= 0 &&
- is_temporary_fs(&s);
+ }
+
+ 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;
}
@@ -198,68 +227,6 @@ int version(void) {
return 0;
}
-/* This is a direct translation of str_verscmp from boot.c */
-static bool is_digit(int c) {
- return c >= '0' && c <= '9';
-}
-
-static int c_order(int c) {
- if (c == 0 || is_digit(c))
- return 0;
-
- if ((c >= 'a') && (c <= 'z'))
- return c;
-
- return c + 0x10000;
-}
-
-int str_verscmp(const char *s1, const char *s2) {
- const char *os1, *os2;
-
- assert(s1);
- assert(s2);
-
- os1 = s1;
- os2 = s2;
-
- while (*s1 || *s2) {
- int first;
-
- while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
- int order;
-
- order = c_order(*s1) - c_order(*s2);
- if (order != 0)
- return order;
- s1++;
- s2++;
- }
-
- while (*s1 == '0')
- s1++;
- while (*s2 == '0')
- s2++;
-
- first = 0;
- while (is_digit(*s1) && is_digit(*s2)) {
- if (first == 0)
- first = *s1 - *s2;
- s1++;
- s2++;
- }
-
- if (is_digit(*s1))
- return 1;
- if (is_digit(*s2))
- return -1;
-
- if (first != 0)
- return first;
- }
-
- return strcmp(os1, os2);
-}
-
/* Turn off core dumps but only if we're running outside of a container. */
void disable_coredumps(void) {
int r;
diff --git a/src/libnm-systemd-shared/src/basic/util.h b/src/libnm-systemd-shared/src/basic/util.h
index 942d773ff1..b6c51c036e 100644
--- a/src/libnm-systemd-shared/src/basic/util.h
+++ b/src/libnm-systemd-shared/src/basic/util.h
@@ -63,6 +63,4 @@ int container_get_leader(const char *machine, pid_t *pid);
int version(void);
-int str_verscmp(const char *s1, const char *s2);
-
void disable_coredumps(void);
diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
new file mode 100644
index 0000000000..790920eb23
--- /dev/null
+++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
@@ -0,0 +1,201 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#ifndef SD_BOOT
+#include <assert.h>
+#endif
+
+#include "type.h"
+
+#define _const_ __attribute__((__const__))
+#define _pure_ __attribute__((__pure__))
+#define _unused_ __attribute__((__unused__))
+#define _cleanup_(x) __attribute__((__cleanup__(x)))
+
+#ifndef __COVERITY__
+# define VOID_0 ((void)0)
+#else
+# define VOID_0 ((void*)0)
+#endif
+
+#define ELEMENTSOF(x) \
+ (__builtin_choose_expr( \
+ !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
+ sizeof(x)/sizeof((x)[0]), \
+ VOID_0))
+
+#define XCONCATENATE(x, y) x ## y
+#define CONCATENATE(x, y) XCONCATENATE(x, y)
+
+#ifdef SD_BOOT
+#define assert(expr) do {} while (false)
+#endif
+
+#if defined(static_assert)
+#define assert_cc(expr) \
+ static_assert(expr, #expr)
+#else
+#define assert_cc(expr) \
+ struct CONCATENATE(_assert_struct_, __COUNTER__) { \
+ char x[(expr) ? 0 : -1]; \
+ }
+#endif
+
+#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
+#define UNIQ __COUNTER__
+
+#undef MAX
+#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b))
+#define __MAX(aq, a, bq, b) \
+ ({ \
+ const typeof(a) UNIQ_T(A, aq) = (a); \
+ const typeof(b) UNIQ_T(B, bq) = (b); \
+ UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
+ })
+
+/* evaluates to (void) if _A or _B are not constant or of different types */
+#define CONST_MAX(_A, _B) \
+ (__builtin_choose_expr( \
+ __builtin_constant_p(_A) && \
+ __builtin_constant_p(_B) && \
+ __builtin_types_compatible_p(typeof(_A), typeof(_B)), \
+ ((_A) > (_B)) ? (_A) : (_B), \
+ VOID_0))
+
+/* takes two types and returns the size of the larger one */
+#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; }))
+
+#define MAX3(x, y, z) \
+ ({ \
+ const typeof(x) _c = MAX(x, y); \
+ MAX(_c, z); \
+ })
+
+#define MAX4(x, y, z, a) \
+ ({ \
+ const typeof(x) _d = MAX3(x, y, z); \
+ MAX(_d, a); \
+ })
+
+#undef MIN
+#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
+#define __MIN(aq, a, bq, b) \
+ ({ \
+ const typeof(a) UNIQ_T(A, aq) = (a); \
+ const typeof(b) UNIQ_T(B, bq) = (b); \
+ UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
+ })
+
+/* evaluates to (void) if _A or _B are not constant or of different types */
+#define CONST_MIN(_A, _B) \
+ (__builtin_choose_expr( \
+ __builtin_constant_p(_A) && \
+ __builtin_constant_p(_B) && \
+ __builtin_types_compatible_p(typeof(_A), typeof(_B)), \
+ ((_A) < (_B)) ? (_A) : (_B), \
+ VOID_0))
+
+#define MIN3(x, y, z) \
+ ({ \
+ const typeof(x) _c = MIN(x, y); \
+ MIN(_c, z); \
+ })
+
+#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
+#define __LESS_BY(aq, a, bq, b) \
+ ({ \
+ const typeof(a) UNIQ_T(A, aq) = (a); \
+ const typeof(b) UNIQ_T(B, bq) = (b); \
+ UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) - UNIQ_T(B, bq) : 0; \
+ })
+
+#define CMP(a, b) __CMP(UNIQ, (a), UNIQ, (b))
+#define __CMP(aq, a, bq, b) \
+ ({ \
+ const typeof(a) UNIQ_T(A, aq) = (a); \
+ const typeof(b) UNIQ_T(B, bq) = (b); \
+ UNIQ_T(A, aq) < UNIQ_T(B, bq) ? -1 : \
+ UNIQ_T(A, aq) > UNIQ_T(B, bq) ? 1 : 0; \
+ })
+
+#undef CLAMP
+#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high))
+#define __CLAMP(xq, x, lowq, low, highq, high) \
+ ({ \
+ const typeof(x) UNIQ_T(X, xq) = (x); \
+ const typeof(low) UNIQ_T(LOW, lowq) = (low); \
+ const typeof(high) UNIQ_T(HIGH, highq) = (high); \
+ UNIQ_T(X, xq) > UNIQ_T(HIGH, highq) ? \
+ UNIQ_T(HIGH, highq) : \
+ UNIQ_T(X, xq) < UNIQ_T(LOW, lowq) ? \
+ UNIQ_T(LOW, lowq) : \
+ UNIQ_T(X, xq); \
+ })
+
+/* [(x + y - 1) / y] suffers from an integer overflow, even though the
+ * computation should be possible in the given type. Therefore, we use
+ * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the
+ * quotient and the remainder, so both should be equally fast. */
+#define DIV_ROUND_UP(x, y) __DIV_ROUND_UP(UNIQ, (x), UNIQ, (y))
+#define __DIV_ROUND_UP(xq, x, yq, y) \
+ ({ \
+ const typeof(x) UNIQ_T(X, xq) = (x); \
+ const typeof(y) UNIQ_T(Y, yq) = (y); \
+ (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \
+ })
+
+#define CASE_F(X) case X:
+#define CASE_F_1(CASE, X) CASE_F(X)
+#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__)
+#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__)
+#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__)
+#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__)
+#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__)
+#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__)
+#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__)
+#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__)
+#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__)
+#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__)
+#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__)
+#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__)
+#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__)
+#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__)
+#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__)
+#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__)
+#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__)
+#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__)
+#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__)
+
+#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
+#define FOR_EACH_MAKE_CASE(...) \
+ GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \
+ CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
+ (CASE_F,__VA_ARGS__)
+
+#define IN_SET(x, ...) \
+ ({ \
+ sd_bool _found = false; \
+ /* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \
+ * type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
+ * the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \
+ * doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \
+ static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \
+ assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
+ switch(x) { \
+ FOR_EACH_MAKE_CASE(__VA_ARGS__) \
+ _found = true; \
+ break; \
+ default: \
+ break; \
+ } \
+ _found; \
+ })
+
+/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time
+ * resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
+#define TAKE_PTR(ptr) \
+ ({ \
+ typeof(ptr) _ptr_ = (ptr); \
+ (ptr) = NULL; \
+ _ptr_; \
+ })
diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
new file mode 100644
index 0000000000..9f14597fef
--- /dev/null
+++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
@@ -0,0 +1,234 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#ifndef SD_BOOT
+#include <ctype.h>
+
+#include "macro.h"
+#endif
+#include "string-util-fundamental.h"
+
+sd_char *startswith(const sd_char *s, const sd_char *prefix) {
+ sd_size_t l;
+
+ assert(s);
+ assert(prefix);
+
+ l = strlen(prefix);
+ if (!strneq(s, prefix, l))
+ return NULL;
+
+ return (sd_char*) s + l;
+}
+
+#ifndef SD_BOOT
+sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) {
+ sd_size_t l;
+
+ assert(s);
+ assert(prefix);
+
+ l = strlen(prefix);
+ if (!strncaseeq(s, prefix, l))
+ return NULL;
+
+ return (sd_char*) s + l;
+}
+#endif
+
+sd_char* endswith(const sd_char *s, const sd_char *postfix) {
+ sd_size_t sl, pl;
+
+ assert(s);
+ assert(postfix);
+
+ sl = strlen(s);
+ pl = strlen(postfix);
+
+ if (pl == 0)
+ return (sd_char*) s + sl;
+
+ if (sl < pl)
+ return NULL;
+
+ if (strcmp(s + sl - pl, postfix) != 0)
+ return NULL;
+
+ return (sd_char*) s + sl - pl;
+}
+
+sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) {
+ sd_size_t sl, pl;
+
+ assert(s);
+ assert(postfix);
+
+ sl = strlen(s);
+ pl = strlen(postfix);
+
+ if (pl == 0)
+ return (sd_char*) s + sl;
+
+ if (sl < pl)
+ return NULL;
+
+ if (strcasecmp(s + sl - pl, postfix) != 0)
+ return NULL;
+
+ return (sd_char*) s + sl - pl;
+}
+
+#ifdef SD_BOOT
+static sd_bool isdigit(sd_char a) {
+ return a >= '0' && a <= '9';
+}
+#endif
+
+static sd_bool is_alpha(sd_char a) {
+ /* Locale independent version of isalpha(). */
+ return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
+}
+
+static sd_bool is_valid_version_char(sd_char a) {
+ return isdigit(a) || is_alpha(a) || IN_SET(a, '~', '-', '^', '.');
+}
+
+sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
+
+ /* This is based on RPM's rpmvercmp(). But this explicitly handles '-' and '.', as we usually
+ * want to directly compare strings which contain both version and release; e.g.
+ * '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'.
+ * Unlike rpmvercmp(), this distiguishes e.g. 123a and 123.a, and 123a is newer.
+ *
+ * This splits the input strings into segments. Each segment is numeric or alpha, and may be
+ * prefixed with the following:
+ * '~' : used for pre-releases, a segment prefixed with this is the oldest,
+ * '-' : used for the separator between version and release,
+ * '^' : used for patched releases, a segment with this is newer than one with '-'.
+ * '.' : used for point releases.
+ * Note, no prefix segment is the newest. All non-supported characters are dropped, and
+ * handled as a separator of segments, e.g., 123_a is equivalent to 123a.
+ *
+ * By using this, version strings can be sorted like following:
+ * (older) 122.1
+ * ^ 123~rc1-1
+ * | 123
+ * | 123-a
+ * | 123-a.1
+ * | 123-1
+ * | 123-1.1
+ * | 123^post1
+ * | 123.a-1
+ * | 123.1-1
+ * v 123a-1
+ * (newer) 124-1
+ */
+
+ if (isempty(a) || isempty(b))
+ return strcmp_ptr(a, b);
+
+ for (;;) {
+ const sd_char *aa, *bb;
+ sd_int r;
+
+ /* Drop leading invalid characters. */
+ while (*a != '\0' && !is_valid_version_char(*a))
+ a++;
+ while (*b != '\0' && !is_valid_version_char(*b))
+ b++;
+
+ /* Handle '~'. Used for pre-releases, e.g. 123~rc1, or 4.5~alpha1 */
+ if (*a == '~' || *b == '~') {
+ /* The string prefixed with '~' is older. */
+ r = CMP(*a != '~', *b != '~');
+ if (r != 0)
+ return r;
+
+ /* Now both strings are prefixed with '~'. Compare remaining strings. */
+ a++;
+ b++;
+ }
+
+ /* If at least one string reaches the end, then longer is newer.
+ * Note that except for '~' prefixed segments, a string has more segments is newer.
+ * So, this check must be after the '~' check. */
+ if (*a == '\0' || *b == '\0')
+ return strcmp(a, b);
+
+ /* Handle '-', which separates version and release, e.g 123.4-3.1.fc33.x86_64 */
+ if (*a == '-' || *b == '-') {
+ /* The string prefixed with '-' is older (e.g., 123-9 vs 123.1-1) */
+ r = CMP(*a != '-', *b != '-');
+ if (r != 0)
+ return r;
+
+ a++;
+ b++;
+ }
+
+ /* Handle '^'. Used for patched release. */
+ if (*a == '^' || *b == '^') {
+ r = CMP(*a != '^', *b != '^');
+ if (r != 0)
+ return r;
+
+ a++;
+ b++;
+ }
+
+ /* Handle '.'. Used for point releases. */
+ if (*a == '.' || *b == '.') {
+ r = CMP(*a != '.', *b != '.');
+ if (r != 0)
+ return r;
+
+ a++;
+ b++;
+ }
+
+ if (isdigit(*a) || isdigit(*b)) {
+ /* Skip leading '0', to make 00123 equivalent to 123. */
+ while (*a == '0')
+ a++;
+ while (*b == '0')
+ b++;
+
+ /* Find the leading numeric segments. One may be an empty string. So,
+ * numeric segments are always newer than alpha segments. */
+ for (aa = a; *aa != '\0' && isdigit(*aa); aa++)
+ ;
+ for (bb = b; *bb != '\0' && isdigit(*bb); bb++)
+ ;
+
+ /* To compare numeric segments without parsing their values, first compare the
+ * lengths of the segments. Eg. 12345 vs 123, longer is newer. */
+ r = CMP(aa - a, bb - b);
+ if (r != 0)
+ return r;
+
+ /* Then, compare them as strings. */
+ r = strncmp(a, b, aa - a);
+ if (r != 0)
+ return r;
+ } else {
+ /* Find the leading non-numeric segments. */
+ for (aa = a; *aa != '\0' && is_alpha(*aa); aa++)
+ ;
+ for (bb = b; *bb != '\0' && is_alpha(*bb); bb++)
+ ;
+
+ /* Note that the segments are usually not NUL-terminated. */
+ r = strncmp(a, b, MIN(aa - a, bb - b));
+ if (r != 0)
+ return r;
+
+ /* Longer is newer, e.g. abc vs abcde. */
+ r = CMP(aa - a, bb - b);
+ if (r != 0)
+ return r;
+ }
+
+ /* The current segments are equivalent. Let's compare the next one. */
+ a = aa;
+ b = bb;
+ }
+}
diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
new file mode 100644
index 0000000000..407cede48d
--- /dev/null
+++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#ifdef SD_BOOT
+#include <efi.h>
+#include <efilib.h>
+#else
+#include <string.h>
+#endif
+
+#include "macro-fundamental.h"
+
+#ifdef SD_BOOT
+#define strlen(a) StrLen((a))
+#define strcmp(a, b) StrCmp((a), (b))
+#define strncmp(a, b, n) StrnCmp((a), (b), (n))
+#define strcasecmp(a, b) StriCmp((a), (b))
+#define STR_C(str) (L ## str)
+#else
+#define STR_C(str) (str)
+#endif
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
+#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
+#ifndef SD_BOOT
+#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
+#endif
+
+static inline sd_int strcmp_ptr(const sd_char *a, const sd_char *b) {
+ if (a && b)
+ return strcmp(a, b);
+
+ return CMP(a, b);
+}
+
+static inline sd_int strcasecmp_ptr(const sd_char *a, const sd_char *b) {
+ if (a && b)
+ return strcasecmp(a, b);
+
+ return CMP(a, b);
+}
+
+static inline sd_bool streq_ptr(const sd_char *a, const sd_char *b) {
+ return strcmp_ptr(a, b) == 0;
+}
+
+static inline sd_bool strcaseeq_ptr(const sd_char *a, const sd_char *b) {
+ return strcasecmp_ptr(a, b) == 0;
+}
+
+sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_;
+#ifndef 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_;
+sd_char *endswith_no_case(const sd_char *s, const sd_char *postfix) _pure_;
+
+static inline sd_bool isempty(const sd_char *a) {
+ return !a || a[0] == '\0';
+}
+
+static inline const sd_char *yes_no(sd_bool b) {
+ return b ? STR_C("yes") : STR_C("no");
+}
+
+sd_int strverscmp_improved(const sd_char *a, const sd_char *b);
diff --git a/src/libnm-systemd-shared/src/fundamental/type.h b/src/libnm-systemd-shared/src/fundamental/type.h
new file mode 100644
index 0000000000..f645d2de7f
--- /dev/null
+++ b/src/libnm-systemd-shared/src/fundamental/type.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#ifdef SD_BOOT
+#include <efi.h>
+
+typedef BOOLEAN sd_bool;
+typedef CHAR16 sd_char;
+typedef INTN sd_int;
+typedef UINTN sd_size_t;
+
+#define true TRUE
+#define false FALSE
+#else
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef bool sd_bool;
+typedef char sd_char;
+typedef int sd_int;
+typedef size_t sd_size_t;
+#endif
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.h b/src/libnm-systemd-shared/src/shared/dns-domain.h
index 77f596294d..c25fcaacc2 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.h
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.h
@@ -6,24 +6,10 @@
#include <stddef.h>
#include <stdint.h>
+#include "dns-def.h"
#include "hashmap.h"
#include "in-addr-util.h"
-/* Length of a single label, with all escaping removed, excluding any trailing dot or NUL byte */
-#define DNS_LABEL_MAX 63
-
-/* Worst case length of a single label, with all escaping applied and room for a trailing NUL byte. */
-#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1)
-
-/* Maximum length of a full hostname, consisting of a series of unescaped labels, and no trailing dot or NUL byte */
-#define DNS_HOSTNAME_MAX 253
-
-/* Maximum length of a full hostname, on the wire, including the final NUL byte */
-#define DNS_WIRE_FORMAT_HOSTNAME_MAX 255
-
-/* Maximum number of labels per valid hostname */
-#define DNS_N_LABELS_MAX 127
-
typedef enum DNSLabelFlags {
DNS_LABEL_LDH = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */
DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */