summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-12-22 21:04:52 +0100
committerThomas Haller <thaller@redhat.com>2020-12-23 17:13:47 +0100
commit0d3f8ded9d97586238bbc1f98174158a3f30c391 (patch)
treee3dd9573cb0e828bc40960bf303fcba1ec673a0a
parent8258ff91c9ee3a321f671a6427c032eec016949c (diff)
downloadNetworkManager-0d3f8ded9d97586238bbc1f98174158a3f30c391.tar.gz
systemd: update code from upstream (2020-12-23)
This is a direct dump from systemd git. ====== SYSTEMD_DIR=../systemd COMMIT=227acf0009bde2cd7f8bc371615b05e84137847d ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files -z :/src/systemd/src/ \ :/shared/systemd/src/ \ :/shared/nm-std-aux/unaligned.h | \ xargs -0 rm -f nm_copy_sd_shared() { mkdir -p "./shared/systemd/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./shared/systemd/$1" } nm_copy_sd_core() { mkdir -p "./src/systemd/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/systemd/$1" } nm_copy_sd_stdaux() { mkdir -p "./shared/nm-std-aux/" cp "$SYSTEMD_DIR/$1" "./shared/nm-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/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/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/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--shared/nm-std-aux/unaligned.h2
-rw-r--r--shared/systemd/src/basic/alloc-util.c2
-rw-r--r--shared/systemd/src/basic/alloc-util.h14
-rw-r--r--shared/systemd/src/basic/async.h8
-rw-r--r--shared/systemd/src/basic/cgroup-util.h15
-rw-r--r--shared/systemd/src/basic/env-file.c2
-rw-r--r--shared/systemd/src/basic/env-file.h2
-rw-r--r--shared/systemd/src/basic/env-util.c28
-rw-r--r--shared/systemd/src/basic/env-util.h5
-rw-r--r--shared/systemd/src/basic/errno-util.h10
-rw-r--r--shared/systemd/src/basic/escape.c2
-rw-r--r--shared/systemd/src/basic/escape.h4
-rw-r--r--shared/systemd/src/basic/ether-addr-util.c17
-rw-r--r--shared/systemd/src/basic/ether-addr-util.h26
-rw-r--r--shared/systemd/src/basic/extract-word.c2
-rw-r--r--shared/systemd/src/basic/extract-word.h2
-rw-r--r--shared/systemd/src/basic/fd-util.c88
-rw-r--r--shared/systemd/src/basic/fd-util.h2
-rw-r--r--shared/systemd/src/basic/fileio.c93
-rw-r--r--shared/systemd/src/basic/fileio.h35
-rw-r--r--shared/systemd/src/basic/format-util.c2
-rw-r--r--shared/systemd/src/basic/format-util.h7
-rw-r--r--shared/systemd/src/basic/fs-util.c81
-rw-r--r--shared/systemd/src/basic/fs-util.h4
-rw-r--r--shared/systemd/src/basic/hash-funcs.c15
-rw-r--r--shared/systemd/src/basic/hash-funcs.h4
-rw-r--r--shared/systemd/src/basic/hashmap.c64
-rw-r--r--shared/systemd/src/basic/hashmap.h7
-rw-r--r--shared/systemd/src/basic/hexdecoct.c2
-rw-r--r--shared/systemd/src/basic/hexdecoct.h2
-rw-r--r--shared/systemd/src/basic/hostname-util.c171
-rw-r--r--shared/systemd/src/basic/hostname-util.h26
-rw-r--r--shared/systemd/src/basic/in-addr-util.c2
-rw-r--r--shared/systemd/src/basic/in-addr-util.h2
-rw-r--r--shared/systemd/src/basic/io-util.c6
-rw-r--r--shared/systemd/src/basic/io-util.h2
-rw-r--r--shared/systemd/src/basic/list.h2
-rw-r--r--shared/systemd/src/basic/log.h14
-rw-r--r--shared/systemd/src/basic/macro.h30
-rw-r--r--shared/systemd/src/basic/memory-util.c2
-rw-r--r--shared/systemd/src/basic/memory-util.h2
-rw-r--r--shared/systemd/src/basic/mempool.c2
-rw-r--r--shared/systemd/src/basic/mempool.h2
-rw-r--r--shared/systemd/src/basic/missing_fcntl.h2
-rw-r--r--shared/systemd/src/basic/missing_random.h2
-rw-r--r--shared/systemd/src/basic/missing_socket.h10
-rw-r--r--shared/systemd/src/basic/missing_stat.h2
-rw-r--r--shared/systemd/src/basic/missing_syscall.h493
-rw-r--r--shared/systemd/src/basic/missing_type.h2
-rw-r--r--shared/systemd/src/basic/parse-util.c44
-rw-r--r--shared/systemd/src/basic/parse-util.h22
-rw-r--r--shared/systemd/src/basic/path-util.c58
-rw-r--r--shared/systemd/src/basic/path-util.h10
-rw-r--r--shared/systemd/src/basic/prioq.c2
-rw-r--r--shared/systemd/src/basic/prioq.h2
-rw-r--r--shared/systemd/src/basic/process-util.c2
-rw-r--r--shared/systemd/src/basic/process-util.h2
-rw-r--r--shared/systemd/src/basic/random-util.c19
-rw-r--r--shared/systemd/src/basic/random-util.h2
-rw-r--r--shared/systemd/src/basic/ratelimit.c38
-rw-r--r--shared/systemd/src/basic/ratelimit.h24
-rw-r--r--shared/systemd/src/basic/set.h14
-rw-r--r--shared/systemd/src/basic/signal-util.c13
-rw-r--r--shared/systemd/src/basic/signal-util.h2
-rw-r--r--shared/systemd/src/basic/siphash24.h2
-rw-r--r--shared/systemd/src/basic/socket-util.c117
-rw-r--r--shared/systemd/src/basic/socket-util.h44
-rw-r--r--shared/systemd/src/basic/sort-util.h4
-rw-r--r--shared/systemd/src/basic/stat-util.c5
-rw-r--r--shared/systemd/src/basic/stat-util.h2
-rw-r--r--shared/systemd/src/basic/stdio-util.h2
-rw-r--r--shared/systemd/src/basic/string-table.c2
-rw-r--r--shared/systemd/src/basic/string-table.h9
-rw-r--r--shared/systemd/src/basic/string-util.c57
-rw-r--r--shared/systemd/src/basic/string-util.h12
-rw-r--r--shared/systemd/src/basic/strv.c57
-rw-r--r--shared/systemd/src/basic/strv.h5
-rw-r--r--shared/systemd/src/basic/strxcpyx.c2
-rw-r--r--shared/systemd/src/basic/strxcpyx.h2
-rw-r--r--shared/systemd/src/basic/time-util.c4
-rw-r--r--shared/systemd/src/basic/time-util.h10
-rw-r--r--shared/systemd/src/basic/tmpfile-util.c2
-rw-r--r--shared/systemd/src/basic/tmpfile-util.h2
-rw-r--r--shared/systemd/src/basic/umask-util.h2
-rw-r--r--shared/systemd/src/basic/user-util.h2
-rw-r--r--shared/systemd/src/basic/utf8.c2
-rw-r--r--shared/systemd/src/basic/utf8.h2
-rw-r--r--shared/systemd/src/basic/util.c8
-rw-r--r--shared/systemd/src/basic/util.h2
-rw-r--r--shared/systemd/src/shared/dns-domain.c88
-rw-r--r--shared/systemd/src/shared/dns-domain.h2
-rw-r--r--shared/systemd/src/shared/log-link.h45
-rw-r--r--shared/systemd/src/shared/web-util.c2
-rw-r--r--shared/systemd/src/shared/web-util.h2
-rw-r--r--src/systemd/src/libsystemd-network/arp-util.c2
-rw-r--r--src/systemd/src/libsystemd-network/arp-util.h2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-identifier.c8
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-identifier.h2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-internal.h10
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-lease-internal.h2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-network.c42
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-option.c2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-packet.c2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-protocol.h2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-internal.h2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-lease-internal.h2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-network.c2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-option.c2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-protocol.h2
-rw-r--r--src/systemd/src/libsystemd-network/lldp-internal.h2
-rw-r--r--src/systemd/src/libsystemd-network/lldp-neighbor.c2
-rw-r--r--src/systemd/src/libsystemd-network/lldp-neighbor.h2
-rw-r--r--src/systemd/src/libsystemd-network/lldp-network.c2
-rw-r--r--src/systemd/src/libsystemd-network/lldp-network.h2
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.c647
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.h46
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-client.c305
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-lease.c8
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-client.c25
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-lease.c2
-rw-r--r--src/systemd/src/libsystemd-network/sd-ipv4acd.c51
-rw-r--r--src/systemd/src/libsystemd-network/sd-ipv4ll.c27
-rw-r--r--src/systemd/src/libsystemd-network/sd-lldp.c5
-rw-r--r--src/systemd/src/libsystemd/sd-event/event-source.h13
-rw-r--r--src/systemd/src/libsystemd/sd-event/event-util.c2
-rw-r--r--src/systemd/src/libsystemd/sd-event/event-util.h2
-rw-r--r--src/systemd/src/libsystemd/sd-event/sd-event.c892
-rw-r--r--src/systemd/src/libsystemd/sd-id128/id128-util.c10
-rw-r--r--src/systemd/src/libsystemd/sd-id128/id128-util.h6
-rw-r--r--src/systemd/src/libsystemd/sd-id128/sd-id128.c2
-rw-r--r--src/systemd/src/systemd/_sd-common.h2
-rw-r--r--src/systemd/src/systemd/sd-dhcp-client.h5
-rw-r--r--src/systemd/src/systemd/sd-dhcp-lease.h2
-rw-r--r--src/systemd/src/systemd/sd-dhcp-option.h2
-rw-r--r--src/systemd/src/systemd/sd-dhcp6-client.h2
-rw-r--r--src/systemd/src/systemd/sd-dhcp6-lease.h2
-rw-r--r--src/systemd/src/systemd/sd-dhcp6-option.h2
-rw-r--r--src/systemd/src/systemd/sd-event.h5
-rw-r--r--src/systemd/src/systemd/sd-id128.h2
-rw-r--r--src/systemd/src/systemd/sd-ipv4acd.h4
-rw-r--r--src/systemd/src/systemd/sd-ipv4ll.h4
-rw-r--r--src/systemd/src/systemd/sd-lldp.h2
-rw-r--r--src/systemd/src/systemd/sd-ndisc.h2
143 files changed, 2286 insertions, 1959 deletions
diff --git a/shared/nm-std-aux/unaligned.h b/shared/nm-std-aux/unaligned.h
index 00c17f8769..4100be0803 100644
--- a/shared/nm-std-aux/unaligned.h
+++ b/shared/nm-std-aux/unaligned.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <endian.h>
diff --git a/shared/systemd/src/basic/alloc-util.c b/shared/systemd/src/basic/alloc-util.c
index 5951e8c3d5..bad15cc204 100644
--- a/shared/systemd/src/basic/alloc-util.c
+++ b/shared/systemd/src/basic/alloc-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <malloc.h>
#include <stdint.h>
diff --git a/shared/systemd/src/basic/alloc-util.h b/shared/systemd/src/basic/alloc-util.h
index 64d9e00315..f3e192ddaf 100644
--- a/shared/systemd/src/basic/alloc-util.h
+++ b/shared/systemd/src/basic/alloc-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <alloca.h>
@@ -27,7 +27,7 @@ typedef void (*free_func_t)(void *p);
size_t _n_ = n; \
assert(!size_multiply_overflow(sizeof(t), _n_)); \
assert(sizeof(t)*_n_ <= ALLOCA_MAX); \
- (t*) alloca(sizeof(t)*_n_); \
+ (t*) alloca((sizeof(t)*_n_) ?: 1); \
})
#define newa0(t, n) \
@@ -35,14 +35,14 @@ typedef void (*free_func_t)(void *p);
size_t _n_ = n; \
assert(!size_multiply_overflow(sizeof(t), _n_)); \
assert(sizeof(t)*_n_ <= ALLOCA_MAX); \
- (t*) alloca0(sizeof(t)*_n_); \
+ (t*) alloca0((sizeof(t)*_n_) ?: 1); \
})
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
#define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
-#define malloc0(n) (calloc(1, (n)))
+#define malloc0(n) (calloc(1, (n) ?: 1))
static inline void *mfree(void *memory) {
free(memory);
@@ -65,7 +65,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
void *_q_; \
size_t _l_ = l; \
assert(_l_ <= ALLOCA_MAX); \
- _q_ = alloca(_l_); \
+ _q_ = alloca(_l_ ?: 1); \
memcpy(_q_, p, _l_); \
})
@@ -135,7 +135,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
char *_new_; \
size_t _len_ = n; \
assert(_len_ <= ALLOCA_MAX); \
- _new_ = alloca(_len_); \
+ _new_ = alloca(_len_ ?: 1); \
(void *) memset(_new_, 0, _len_); \
})
@@ -146,7 +146,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
size_t _mask_ = (align) - 1; \
size_t _size_ = size; \
assert(_size_ <= ALLOCA_MAX); \
- _ptr_ = alloca(_size_ + _mask_); \
+ _ptr_ = alloca((_size_ + _mask_) ?: 1); \
(void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
})
diff --git a/shared/systemd/src/basic/async.h b/shared/systemd/src/basic/async.h
index 3160613184..e0bbaa5658 100644
--- a/shared/systemd/src/basic/async.h
+++ b/shared/systemd/src/basic/async.h
@@ -1,7 +1,13 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <sys/types.h>
+
+#include "macro.h"
+
int asynchronous_job(void* (*func)(void *p), void *arg);
int asynchronous_sync(pid_t *ret_pid);
int asynchronous_close(int fd);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(int, asynchronous_close);
diff --git a/shared/systemd/src/basic/cgroup-util.h b/shared/systemd/src/basic/cgroup-util.h
index 2b88571bc1..bdc0d0d086 100644
--- a/shared/systemd/src/basic/cgroup-util.h
+++ b/shared/systemd/src/basic/cgroup-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <dirent.h>
@@ -208,6 +208,9 @@ static inline int cg_get_keyed_attribute_graceful(
int cg_get_attribute_as_uint64(const char *controller, const char *path, const char *attribute, uint64_t *ret);
+/* Does a parse_boolean() on the attribute contents and sets ret accordingly */
+int cg_get_attribute_as_bool(const char *controller, const char *path, const char *attribute, bool *ret);
+
int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid);
int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags);
@@ -275,3 +278,13 @@ CGroupController cgroup_controller_from_string(const char *s) _pure_;
bool is_cgroup_fs(const struct statfs *s);
bool fd_is_cgroup_fs(int fd);
+
+typedef enum ManagedOOMMode {
+ MANAGED_OOM_AUTO,
+ MANAGED_OOM_KILL,
+ _MANAGED_OOM_MODE_MAX,
+ _MANAGED_OOM_MODE_INVALID = -1,
+} ManagedOOMMode;
+
+const char* managed_oom_mode_to_string(ManagedOOMMode m) _const_;
+ManagedOOMMode managed_oom_mode_from_string(const char *s) _pure_;
diff --git a/shared/systemd/src/basic/env-file.c b/shared/systemd/src/basic/env-file.c
index dc92b13a6f..99c3e3f4a3 100644
--- a/shared/systemd/src/basic/env-file.c
+++ b/shared/systemd/src/basic/env-file.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "env-file.h"
diff --git a/shared/systemd/src/basic/env-file.h b/shared/systemd/src/basic/env-file.h
index e1ca195ff0..de475885ac 100644
--- a/shared/systemd/src/basic/env-file.h
+++ b/shared/systemd/src/basic/env-file.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdarg.h>
diff --git a/shared/systemd/src/basic/env-util.c b/shared/systemd/src/basic/env-util.c
index 179408c399..a84863ff22 100644
--- a/shared/systemd/src/basic/env-util.c
+++ b/shared/systemd/src/basic/env-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <limits.h>
@@ -16,7 +16,8 @@
#include "strv.h"
#include "utf8.h"
-#define VALID_CHARS_ENV_NAME \
+/* We follow bash for the character set. Different shells have different rules. */
+#define VALID_BASH_ENV_NAME_CHARS \
DIGITS LETTERS \
"_"
@@ -41,17 +42,14 @@ static bool env_name_is_valid_n(const char *e, size_t n) {
return false;
for (p = e; p < e + n; p++)
- if (!strchr(VALID_CHARS_ENV_NAME, *p))
+ if (!strchr(VALID_BASH_ENV_NAME_CHARS, *p))
return false;
return true;
}
bool env_name_is_valid(const char *e) {
- if (!e)
- return false;
-
- return env_name_is_valid_n(e, strlen(e));
+ return env_name_is_valid_n(e, strlen_ptr(e));
}
bool env_value_is_valid(const char *e) {
@@ -546,7 +544,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
word = e+1;
state = WORD;
- } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) {
+ } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
k = strnappend(r, word, e-word-1);
if (!k)
return NULL;
@@ -636,7 +634,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
case VARIABLE_RAW:
assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
- if (!strchr(VALID_CHARS_ENV_NAME, *e)) {
+ if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
const char *t;
t = strv_env_get_n(env, word+1, e-word-1, flags);
@@ -749,3 +747,15 @@ int getenv_bool_secure(const char *p) {
return parse_boolean(e);
}
+
+int set_unset_env(const char *name, const char *value, bool overwrite) {
+ int r;
+
+ if (value)
+ r = setenv(name, value, overwrite);
+ else
+ r = unsetenv(name);
+ if (r < 0)
+ return -errno;
+ return 0;
+}
diff --git a/shared/systemd/src/basic/env-util.h b/shared/systemd/src/basic/env-util.h
index 92802ed774..6684b3350f 100644
--- a/shared/systemd/src/basic/env-util.h
+++ b/shared/systemd/src/basic/env-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
@@ -52,3 +52,6 @@ char *strv_env_get(char **x, const char *n) _pure_;
int getenv_bool(const char *p);
int getenv_bool_secure(const char *p);
+
+/* Like setenv, but calls unsetenv if value == NULL. */
+int set_unset_env(const char *name, const char *value, bool overwrite);
diff --git a/shared/systemd/src/basic/errno-util.h b/shared/systemd/src/basic/errno-util.h
index 0ca650f48f..5609820b88 100644
--- a/shared/systemd/src/basic/errno-util.h
+++ b/shared/systemd/src/basic/errno-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdlib.h>
@@ -50,7 +50,10 @@ static inline int errno_or_else(int fallback) {
/* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5.
*
* Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases. See the
- * icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */
+ * icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources.
+ *
+ * Hint #3: When asynchronous connect() on TCP fails because the host never acknowledges a single packet,
+ * kernel tells us that with ETIMEDOUT, see tcp(7). */
static inline bool ERRNO_IS_DISCONNECT(int r) {
return IN_SET(abs(r),
ECONNABORTED,
@@ -66,7 +69,8 @@ static inline bool ERRNO_IS_DISCONNECT(int r) {
ENOTCONN,
EPIPE,
EPROTO,
- ESHUTDOWN);
+ ESHUTDOWN,
+ ETIMEDOUT);
}
/* Transient errors we might get on accept() that we should ignore. As per error handling comment in
diff --git a/shared/systemd/src/basic/escape.c b/shared/systemd/src/basic/escape.c
index 7589d597a2..31f3cda472 100644
--- a/shared/systemd/src/basic/escape.c
+++ b/shared/systemd/src/basic/escape.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <stdlib.h>
diff --git a/shared/systemd/src/basic/escape.h b/shared/systemd/src/basic/escape.h
index fa267813b3..691b6d802c 100644
--- a/shared/systemd/src/basic/escape.h
+++ b/shared/systemd/src/basic/escape.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
@@ -16,7 +16,7 @@
/* Those that can be escaped or double-quoted.
*
- * Stricly speaking, ! does not need to be escaped, except in interactive
+ * Strictly speaking, ! does not need to be escaped, except in interactive
* mode, but let's be extra nice to the user and quote ! in case this
* output is ever used in interactive mode. */
#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;!"
diff --git a/shared/systemd/src/basic/ether-addr-util.c b/shared/systemd/src/basic/ether-addr-util.c
index e875696a1a..c8094b6e45 100644
--- a/shared/systemd/src/basic/ether-addr-util.c
+++ b/shared/systemd/src/basic/ether-addr-util.c
@@ -1,6 +1,7 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
+#include <inttypes.h>
#include <net/ethernet.h>
#include <stdio.h>
#include <sys/types.h>
@@ -9,6 +10,20 @@
#include "macro.h"
#include "string-util.h"
+char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) {
+ assert(addr);
+ assert(buffer);
+ assert(addr->length <= HW_ADDR_MAX_SIZE);
+
+ for (size_t i = 0; i < addr->length; i++) {
+ sprintf(&buffer[3*i], "%02"PRIx8, addr->addr.bytes[i]);
+ if (i < addr->length - 1)
+ buffer[3*i + 2] = ':';
+ }
+
+ return buffer;
+}
+
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
assert(addr);
assert(buffer);
diff --git a/shared/systemd/src/basic/ether-addr-util.h b/shared/systemd/src/basic/ether-addr-util.h
index 4e44b30be9..942ce55621 100644
--- a/shared/systemd/src/basic/ether-addr-util.h
+++ b/shared/systemd/src/basic/ether-addr-util.h
@@ -1,11 +1,35 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <linux/if_infiniband.h>
#include <net/ethernet.h>
#include <stdbool.h>
#include "hash-funcs.h"
+/* This is MAX_ADDR_LEN as defined in linux/netdevice.h, but net/if_arp.h
+ * defines a macro of the same name with a much lower size. */
+#define HW_ADDR_MAX_SIZE 32
+
+union hw_addr_union {
+ struct ether_addr ether;
+ uint8_t infiniband[INFINIBAND_ALEN];
+ uint8_t bytes[HW_ADDR_MAX_SIZE];
+};
+
+typedef struct hw_addr_data {
+ union hw_addr_union addr;
+ size_t length;
+} hw_addr_data;
+
+#define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE)
+char* hw_addr_to_string(const hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]);
+
+/* Use only as function argument, never stand-alone! */
+#define HW_ADDR_TO_STR(hw_addr) hw_addr_to_string((hw_addr), (char[HW_ADDR_TO_STRING_MAX]){})
+
+#define HW_ADDR_NULL ((const hw_addr_data){})
+
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
diff --git a/shared/systemd/src/basic/extract-word.c b/shared/systemd/src/basic/extract-word.c
index d64dddd641..76b3fe12e3 100644
--- a/shared/systemd/src/basic/extract-word.c
+++ b/shared/systemd/src/basic/extract-word.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <stdarg.h>
diff --git a/shared/systemd/src/basic/extract-word.h b/shared/systemd/src/basic/extract-word.h
index f028577c40..d1de32e580 100644
--- a/shared/systemd/src/basic/extract-word.h
+++ b/shared/systemd/src/basic/extract-word.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "macro.h"
diff --git a/shared/systemd/src/basic/fd-util.c b/shared/systemd/src/basic/fd-util.c
index db869cbd54..a03ba83e19 100644
--- a/shared/systemd/src/basic/fd-util.c
+++ b/shared/systemd/src/basic/fd-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <fcntl.h>
@@ -21,6 +21,7 @@
#include "path-util.h"
#include "process-util.h"
#include "socket-util.h"
+#include "sort-util.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "tmpfile-util.h"
@@ -211,12 +212,97 @@ static int get_max_fd(void) {
}
int close_all_fds(const int except[], size_t n_except) {
+ static bool have_close_range = true; /* Assume we live in the future */
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r = 0;
assert(n_except == 0 || except);
+ if (have_close_range) {
+ /* In the best case we have close_range() to close all fds between a start and an end fd,
+ * which we can use on the "inverted" exception array, i.e. all intervals between all
+ * adjacent pairs from the sorted exception array. This changes loop complexity from O(n)
+ * where n is number of open fds to O(m⋅log(m)) where m is the number of fds to keep
+ * open. Given that we assume n ≫ m that's preferable to us. */
+
+ if (n_except == 0) {
+ /* Close everything. Yay! */
+
+ if (close_range(3, -1, 0) >= 0)
+ return 1;
+
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+ return -errno;
+
+ have_close_range = false;
+ } else {
+ _cleanup_free_ int *sorted_malloc = NULL;
+ size_t n_sorted;
+ int *sorted;
+
+ assert(n_except < SIZE_MAX);
+ n_sorted = n_except + 1;
+
+ if (n_sorted > 64) /* Use heap for large numbers of fds, stack otherwise */
+ sorted = sorted_malloc = new(int, n_sorted);
+ else
+ sorted = newa(int, n_sorted);
+
+ if (sorted) {
+ int c = 0;
+
+ memcpy(sorted, except, n_except * sizeof(int));
+
+ /* Let's add fd 2 to the list of fds, to simplify the loop below, as this
+ * allows us to cover the head of the array the same way as the body */
+ sorted[n_sorted-1] = 2;
+
+ typesafe_qsort(sorted, n_sorted, cmp_int);
+
+ for (size_t i = 0; i < n_sorted-1; i++) {
+ int start, end;
+
+ start = MAX(sorted[i], 2); /* The first three fds shall always remain open */
+ end = MAX(sorted[i+1], 2);
+
+ assert(end >= start);
+
+ if (end - start <= 1)
+ continue;
+
+ /* Close everything between the start and end fds (both of which shall stay open) */
+ if (close_range(start + 1, end - 1, 0) < 0) {
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+ return -errno;
+
+ have_close_range = false;
+ break;
+ }
+
+ c += end - start - 1;
+ }
+
+ if (have_close_range) {
+ /* The loop succeeded. Let's now close everything beyond the end */
+
+ if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
+ return c;
+
+ if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
+ return c + 1;
+
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+ return -errno;
+
+ have_close_range = false;
+ }
+ }
+ }
+
+ /* Fallback on OOM or if close_range() is not supported */
+ }
+
d = opendir("/proc/self/fd");
if (!d) {
int fd, max_fd;
diff --git a/shared/systemd/src/basic/fd-util.h b/shared/systemd/src/basic/fd-util.h
index 93ce95cd03..2162537b80 100644
--- a/shared/systemd/src/basic/fd-util.h
+++ b/shared/systemd/src/basic/fd-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <dirent.h>
diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c
index c5a093a857..f4708bc05f 100644
--- a/shared/systemd/src/basic/fileio.c
+++ b/shared/systemd/src/basic/fileio.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <ctype.h>
#include <errno.h>
@@ -117,7 +117,7 @@ int write_string_stream_ts(
FILE *f,
const char *line,
WriteStringFileFlags flags,
- struct timespec *ts) {
+ const struct timespec *ts) {
bool needs_nl;
int r, fd;
@@ -161,7 +161,7 @@ int write_string_stream_ts(
return r;
if (ts) {
- struct timespec twice[2] = {*ts, *ts};
+ const struct timespec twice[2] = {*ts, *ts};
if (futimens(fd, twice) < 0)
return -errno;
@@ -174,7 +174,7 @@ static int write_string_file_atomic(
const char *fn,
const char *line,
WriteStringFileFlags flags,
- struct timespec *ts) {
+ const struct timespec *ts) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
@@ -221,7 +221,7 @@ int write_string_file_ts(
const char *fn,
const char *line,
WriteStringFileFlags flags,
- struct timespec *ts) {
+ const struct timespec *ts) {
_cleanup_fclose_ FILE *f = NULL;
int q, r, fd;
@@ -252,7 +252,8 @@ int write_string_file_ts(
/* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY |
(FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
- (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0),
+ (FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
+ (FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0),
(FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
if (fd < 0) {
r = -errno;
@@ -471,12 +472,13 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
int read_full_stream_full(
FILE *f,
const char *filename,
+ uint64_t offset,
+ size_t size,
ReadFullFileFlags flags,
char **ret_contents,
size_t *ret_size) {
_cleanup_free_ char *buf = NULL;
- struct stat st;
size_t n, n_next, l;
int fd, r;
@@ -484,32 +486,45 @@ int read_full_stream_full(
assert(ret_contents);
assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
- n_next = LINE_MAX; /* Start size */
+ if (offset != UINT64_MAX && offset > LONG_MAX)
+ return -ERANGE;
+
+ n_next = size != SIZE_MAX ? size : LINE_MAX; /* Start size */
fd = fileno(f);
- if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's
- * optimize our buffering */
+ if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see
+ * fmemopen()), let's optimize our buffering */
+ struct stat st;
if (fstat(fd, &st) < 0)
return -errno;
if (S_ISREG(st.st_mode)) {
-
- /* Safety check */
- if (st.st_size > READ_FULL_BYTES_MAX)
- return -E2BIG;
-
- /* Start with the right file size. Note that we increase the size
- * to read here by one, so that the first read attempt already
- * makes us notice the EOF. */
- if (st.st_size > 0)
- n_next = st.st_size + 1;
+ if (size == SIZE_MAX) {
+ uint64_t rsize =
+ LESS_BY((uint64_t) st.st_size, offset == UINT64_MAX ? 0 : offset);
+
+ /* Safety check */
+ if (rsize > READ_FULL_BYTES_MAX)
+ return -E2BIG;
+
+ /* Start with the right file size. Note that we increase the size to read
+ * here by one, so that the first read attempt already makes us notice the
+ * EOF. If the reported size of the file is zero, we avoid this logic
+ * however, since quite likely it might be a virtual file in procfs that all
+ * report a zero file size. */
+ if (st.st_size > 0)
+ n_next = rsize + 1;
+ }
if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
(void) warn_file_is_world_accessible(filename, &st, NULL, 0);
}
}
+ if (offset != UINT64_MAX && fseek(f, offset, SEEK_SET) < 0)
+ return -errno;
+
n = l = 0;
for (;;) {
char *t;
@@ -546,6 +561,11 @@ int read_full_stream_full(
if (feof(f))
break;
+ if (size != SIZE_MAX) { /* If we got asked to read some specific size, we already sized the buffer right, hence leave */
+ assert(l == size);
+ break;
+ }
+
assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
/* Safety check */
@@ -601,12 +621,21 @@ finalize:
return r;
}
-int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
+int read_full_file_full(
+ int dir_fd,
+ const char *filename,
+ uint64_t offset,
+ size_t size,
+ ReadFullFileFlags flags,
+ const char *bind_name,
+ char **ret_contents,
+ size_t *ret_size) {
+
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(filename);
- assert(contents);
+ assert(ret_contents);
r = xfopenat(dir_fd, filename, "re", 0, &f);
if (r < 0) {
@@ -621,6 +650,10 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag
if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
return -ENXIO;
+ /* Seeking is not supported on AF_UNIX sockets */
+ if (offset != UINT64_MAX)
+ return -ESPIPE;
+
if (dir_fd == AT_FDCWD)
r = sockaddr_un_set_path(&sa.un, filename);
else {
@@ -644,6 +677,20 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag
if (sk < 0)
return -errno;
+ if (bind_name) {
+ /* If the caller specified a socket name to bind to, do so before connecting. This is
+ * useful to communicate some minor, short meta-information token from the client to
+ * the server. */
+ union sockaddr_union bsa;
+
+ r = sockaddr_un_set_path(&bsa.un, bind_name);
+ if (r < 0)
+ return r;
+
+ if (bind(sk, &bsa.sa, r) < 0)
+ return r;
+ }
+
if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is
* not a socket after all */
@@ -660,7 +707,7 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
- return read_full_stream_full(f, filename, flags, contents, size);
+ return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
}
int executable_is_script(const char *path, char **interpreter) {
diff --git a/shared/systemd/src/basic/fileio.h b/shared/systemd/src/basic/fileio.h
index 9cba5a90e3..498e880354 100644
--- a/shared/systemd/src/basic/fileio.h
+++ b/shared/systemd/src/basic/fileio.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <dirent.h>
@@ -16,14 +16,15 @@
typedef enum {
WRITE_STRING_FILE_CREATE = 1 << 0,
- WRITE_STRING_FILE_ATOMIC = 1 << 1,
- WRITE_STRING_FILE_AVOID_NEWLINE = 1 << 2,
- WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 3,
- WRITE_STRING_FILE_SYNC = 1 << 4,
- WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5,
- WRITE_STRING_FILE_NOFOLLOW = 1 << 6,
- WRITE_STRING_FILE_MKDIR_0755 = 1 << 7,
- WRITE_STRING_FILE_MODE_0600 = 1 << 8,
+ WRITE_STRING_FILE_TRUNCATE = 1 << 1,
+ WRITE_STRING_FILE_ATOMIC = 1 << 2,
+ WRITE_STRING_FILE_AVOID_NEWLINE = 1 << 3,
+ WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 4,
+ WRITE_STRING_FILE_SYNC = 1 << 5,
+ WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 6,
+ WRITE_STRING_FILE_NOFOLLOW = 1 << 7,
+ WRITE_STRING_FILE_MKDIR_0755 = 1 << 8,
+ WRITE_STRING_FILE_MODE_0600 = 1 << 9,
/* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one
more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file()
@@ -47,11 +48,11 @@ DIR* take_fdopendir(int *dfd);
FILE* open_memstream_unlocked(char **ptr, size_t *sizeloc);
FILE* fmemopen_unlocked(void *buf, size_t size, const char *mode);
-int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts);
+int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
return write_string_stream_ts(f, line, flags, NULL);
}
-int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, struct timespec *ts);
+int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, const struct timespec *ts);
static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
return write_string_file_ts(fn, line, flags, NULL);
}
@@ -59,14 +60,14 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
int read_one_line_file(const char *filename, char **line);
-int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
-static inline int read_full_file(const char *filename, char **contents, size_t *size) {
- return read_full_file_full(AT_FDCWD, filename, 0, contents, size);
+int read_full_file_full(int dir_fd, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, const char *bind_name, char **ret_contents, size_t *ret_size);
+static inline int read_full_file(const char *filename, char **ret_contents, size_t *ret_size) {
+ return read_full_file_full(AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size);
}
int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size);
-int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
-static inline int read_full_stream(FILE *f, char **contents, size_t *size) {
- return read_full_stream_full(f, NULL, 0, contents, size);
+int read_full_stream_full(FILE *f, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, char **ret_contents, size_t *ret_size);
+static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_size) {
+ return read_full_stream_full(f, NULL, UINT64_MAX, SIZE_MAX, 0, ret_contents, ret_size);
}
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
diff --git a/shared/systemd/src/basic/format-util.c b/shared/systemd/src/basic/format-util.c
index b4144e0352..bf23037792 100644
--- a/shared/systemd/src/basic/format-util.c
+++ b/shared/systemd/src/basic/format-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "format-util.h"
#include "memory-util.h"
diff --git a/shared/systemd/src/basic/format-util.h b/shared/systemd/src/basic/format-util.h
index c47fa76ea8..b7e18768e3 100644
--- a/shared/systemd/src/basic/format-util.h
+++ b/shared/systemd/src/basic/format-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
@@ -72,11 +72,14 @@ typedef enum {
FORMAT_BYTES_TRAILING_B = 1 << 2,
} FormatBytesFlag;
-#define FORMAT_BYTES_MAX 16
+#define FORMAT_BYTES_MAX 16U
+
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag);
+
static inline char *format_bytes(char *buf, size_t l, uint64_t t) {
return format_bytes_full(buf, l, t, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | FORMAT_BYTES_TRAILING_B);
}
+
static inline char *format_bytes_cgroup_protection(char *buf, size_t l, uint64_t t) {
if (t == CGROUP_LIMIT_MAX) {
(void) snprintf(buf, l, "%s", "infinity");
diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c
index 587b3504ee..f240f84322 100644
--- a/shared/systemd/src/basic/fs-util.c
+++ b/shared/systemd/src/basic/fs-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <stddef.h>
@@ -810,7 +810,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
*
* 3. With CHASE_STEP: in this case only a single step of the normalization is executed, i.e. only the first
* symlink or ".." component of the path is resolved, and the resulting path is returned. This is useful if
- * a caller wants to trace the a path through the file system verbosely. Returns < 0 on error, > 0 if the
+ * a caller wants to trace the path through the file system verbosely. Returns < 0 on error, > 0 if the
* path is fully normalized, and == 0 for each normalization step. This may be combined with
* CHASE_NONEXISTENT, in which case 1 is returned when a component is not found.
*
@@ -1613,3 +1613,80 @@ int path_is_encrypted(const char *path) {
return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */);
}
+
+int conservative_rename(
+ int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath) {
+
+ _cleanup_close_ int old_fd = -1, new_fd = -1;
+ struct stat old_stat, new_stat;
+
+ /* Renames the old path to thew new path, much like renameat() — except if both are regular files and
+ * have the exact same contents and basic file attributes already. In that case remove the new file
+ * instead. This call is useful for reducing inotify wakeups on files that are updated but don't
+ * actually change. This function is written in a style that we rather rename too often than suppress
+ * too much. i.e. whenever we are in doubt we rather rename than fail. After all reducing inotify
+ * events is an optimization only, not more. */
+
+ old_fd = openat(olddirfd, oldpath, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_NOFOLLOW);
+ if (old_fd < 0)
+ goto do_rename;
+
+ new_fd = openat(newdirfd, newpath, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_NOFOLLOW);
+ if (new_fd < 0)
+ goto do_rename;
+
+ if (fstat(old_fd, &old_stat) < 0)
+ goto do_rename;
+
+ if (!S_ISREG(old_stat.st_mode))
+ goto do_rename;
+
+ if (fstat(new_fd, &new_stat) < 0)
+ goto do_rename;
+
+ if (new_stat.st_ino == old_stat.st_ino &&
+ new_stat.st_dev == old_stat.st_dev)
+ goto is_same;
+
+ if (old_stat.st_mode != new_stat.st_mode ||
+ old_stat.st_size != new_stat.st_size ||
+ old_stat.st_uid != new_stat.st_uid ||
+ old_stat.st_gid != new_stat.st_gid)
+ goto do_rename;
+
+ for (;;) {
+ char buf1[16*1024];
+ char buf2[sizeof(buf1) + 1];
+ ssize_t l1, l2;
+
+ l1 = read(old_fd, buf1, sizeof(buf1));
+ if (l1 < 0)
+ goto do_rename;
+
+ l2 = read(new_fd, buf2, l1 + 1);
+ if (l1 != l2)
+ goto do_rename;
+
+ if (l1 == 0) /* EOF on both! And everything's the same so far, yay! */
+ break;
+
+ if (memcmp(buf1, buf2, l1) != 0)
+ goto do_rename;
+ }
+
+is_same:
+ /* Everything matches? Then don't rename, instead remove the source file, and leave the existing
+ * destination in place */
+
+ if (unlinkat(olddirfd, oldpath, 0) < 0)
+ goto do_rename;
+
+ return 0;
+
+do_rename:
+ if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
+ return -errno;
+
+ return 1;
+}
diff --git a/shared/systemd/src/basic/fs-util.h b/shared/systemd/src/basic/fs-util.h
index 241cc6ef62..9a39473567 100644
--- a/shared/systemd/src/basic/fs-util.h
+++ b/shared/systemd/src/basic/fs-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <dirent.h>
@@ -132,3 +132,5 @@ int syncfs_path(int atfd, const char *path);
int open_parent(const char *path, int flags, mode_t mode);
int path_is_encrypted(const char *path);
+
+int conservative_rename(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
diff --git a/shared/systemd/src/basic/hash-funcs.c b/shared/systemd/src/basic/hash-funcs.c
index cf279e5cbe..e033de1ae1 100644
--- a/shared/systemd/src/basic/hash-funcs.c
+++ b/shared/systemd/src/basic/hash-funcs.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <string.h>
@@ -71,6 +71,19 @@ const struct hash_ops trivial_hash_ops = {
.compare = trivial_compare_func,
};
+const struct hash_ops trivial_hash_ops_free = {
+ .hash = trivial_hash_func,
+ .compare = trivial_compare_func,
+ .free_key = free,
+};
+
+const struct hash_ops trivial_hash_ops_free_free = {
+ .hash = trivial_hash_func,
+ .compare = trivial_compare_func,
+ .free_key = free,
+ .free_value = free,
+};
+
void uint64_hash_func(const uint64_t *p, struct siphash *state) {
siphash24_compress(p, sizeof(uint64_t), state);
}
diff --git a/shared/systemd/src/basic/hash-funcs.h b/shared/systemd/src/basic/hash-funcs.h
index 005d1b21d2..5672df1da4 100644
--- a/shared/systemd/src/basic/hash-funcs.h
+++ b/shared/systemd/src/basic/hash-funcs.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "alloc-util.h"
@@ -88,6 +88,8 @@ extern const struct hash_ops path_hash_ops_free;
void trivial_hash_func(const void *p, struct siphash *state);
int trivial_compare_func(const void *a, const void *b) _const_;
extern const struct hash_ops trivial_hash_ops;
+extern const struct hash_ops trivial_hash_ops_free;
+extern const struct hash_ops trivial_hash_ops_free_free;
/* 32bit values we can always just embed in the pointer itself, but in order to support 32bit archs we need store 64bit
* values indirectly, since they don't fit in a pointer. */
diff --git a/shared/systemd/src/basic/hashmap.c b/shared/systemd/src/basic/hashmap.c
index 77cebd9f15..cdc6847edf 100644
--- a/shared/systemd/src/basic/hashmap.c
+++ b/shared/systemd/src/basic/hashmap.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <pthread.h>
@@ -1794,10 +1794,10 @@ int set_consume(Set *s, void *value) {
return r;
}
-int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS) {
+int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v HASHMAP_DEBUG_PARAMS) {
int r;
- r = _hashmap_ensure_allocated(h, &string_hash_ops_free_free HASHMAP_DEBUG_PASS_ARGS);
+ r = _hashmap_ensure_allocated(h, hash_ops HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
@@ -1828,14 +1828,14 @@ int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG
return r;
}
-int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS) {
+int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS) {
char *c;
int r;
assert(s);
assert(p);
- r = _set_ensure_allocated(s, &string_hash_ops_free HASHMAP_DEBUG_PASS_ARGS);
+ r = _set_ensure_allocated(s, hash_ops HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
@@ -1849,14 +1849,14 @@ int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS) {
return set_consume(*s, c);
}
-int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS) {
+int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS) {
int n = 0, r;
char **i;
assert(s);
STRV_FOREACH(i, l) {
- r = _set_put_strdup(s, *i HASHMAP_DEBUG_PASS_ARGS);
+ r = _set_put_strdup_full(s, hash_ops, *i HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
@@ -1976,3 +1976,53 @@ IteratedCache* iterated_cache_free(IteratedCache *cache) {
return mfree(cache);
}
+
+int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret) {
+ size_t separator_len, allocated = 0, len = 0;
+ _cleanup_free_ char *str = NULL;
+ const char *value;
+ bool first;
+
+ assert(ret);
+
+ if (set_isempty(s)) {
+ *ret = NULL;
+ return 0;
+ }
+
+ separator_len = strlen_ptr(separator);
+
+ if (separator_len == 0)
+ wrap_with_separator = false;
+
+ first = !wrap_with_separator;
+
+ SET_FOREACH(value, s) {
+ size_t l = strlen_ptr(value);
+
+ if (l == 0)
+ continue;
+
+ if (!GREEDY_REALLOC(str, allocated, len + l + (first ? 0 : separator_len) + (wrap_with_separator ? separator_len : 0) + 1))
+ return -ENOMEM;
+
+ if (separator_len > 0 && !first) {
+ memcpy(str + len, separator, separator_len);
+ len += separator_len;
+ }
+
+ memcpy(str + len, value, l);
+ len += l;
+ first = false;
+ }
+
+ if (wrap_with_separator) {
+ memcpy(str + len, separator, separator_len);
+ len += separator_len;
+ }
+
+ str[len] = '\0';
+
+ *ret = TAKE_PTR(str);
+ return 0;
+}
diff --git a/shared/systemd/src/basic/hashmap.h b/shared/systemd/src/basic/hashmap.h
index 890f90a9d1..e99448375e 100644
--- a/shared/systemd/src/basic/hashmap.h
+++ b/shared/systemd/src/basic/hashmap.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <limits.h>
@@ -153,8 +153,9 @@ static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *
return hashmap_put(PLAIN_HASHMAP(h), key, value);
}
-int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS);
-#define hashmap_put_strdup(h, k, v) _hashmap_put_strdup(h, k, v HASHMAP_DEBUG_SRC_ARGS)
+int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v HASHMAP_DEBUG_PARAMS);
+#define hashmap_put_strdup_full(h, hash_ops, k, v) _hashmap_put_strdup_full(h, hash_ops, k, v HASHMAP_DEBUG_SRC_ARGS)
+#define hashmap_put_strdup(h, k, v) hashmap_put_strdup_full(h, &string_hash_ops_free_free, k, v)
int hashmap_update(Hashmap *h, const void *key, void *value);
static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
diff --git a/shared/systemd/src/basic/hexdecoct.c b/shared/systemd/src/basic/hexdecoct.c
index 96f7b9ed0f..da60202e57 100644
--- a/shared/systemd/src/basic/hexdecoct.c
+++ b/shared/systemd/src/basic/hexdecoct.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <ctype.h>
#include <errno.h>
diff --git a/shared/systemd/src/basic/hexdecoct.h b/shared/systemd/src/basic/hexdecoct.h
index dfdff1e9bb..7e2a6892c0 100644
--- a/shared/systemd/src/basic/hexdecoct.h
+++ b/shared/systemd/src/basic/hexdecoct.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
diff --git a/shared/systemd/src/basic/hostname-util.c b/shared/systemd/src/basic/hostname-util.c
index 90a3dfc864..d7aba2c263 100644
--- a/shared/systemd/src/basic/hostname-util.c
+++ b/shared/systemd/src/basic/hostname-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <limits.h>
@@ -7,28 +7,10 @@
#include <unistd.h>
#include "alloc-util.h"
-#include "fd-util.h"
-#include "fileio.h"
#include "hostname-util.h"
-#include "macro.h"
#include "string-util.h"
#include "strv.h"
-bool hostname_is_set(void) {
- struct utsname u;
-
- assert_se(uname(&u) >= 0);
-
- if (isempty(u.nodename))
- return false;
-
- /* This is the built-in kernel default hostname */
- if (streq(u.nodename, "(none)"))
- return false;
-
- return true;
-}
-
char* gethostname_malloc(void) {
struct utsname u;
const char *s;
@@ -89,6 +71,8 @@ int gethostname_strict(char **ret) {
}
bool valid_ldh_char(char c) {
+ /* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */
+
return
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
@@ -96,28 +80,24 @@ bool valid_ldh_char(char c) {
c == '-';
}
-/**
- * Check if s looks like a valid hostname or FQDN. This does not do
- * full DNS validation, but only checks if the name is composed of
- * allowed characters and the length is not above the maximum allowed
- * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
- * allow_trailing_dot is true and at least two components are present
- * in the name. Note that due to the restricted charset and length
- * this call is substantially more conservative than
- * dns_name_is_valid().
- */
-bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
+bool hostname_is_valid(const char *s, ValidHostnameFlags flags) {
unsigned n_dots = 0;
const char *p;
bool dot, hyphen;
+ /* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only
+ * checks if the name is composed of allowed characters and the length is not above the maximum
+ * allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if
+ * VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note
+ * that due to the restricted charset and length this call is substantially more conservative than
+ * dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames
+ * with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */
+
if (isempty(s))
return false;
- /* Doesn't accept empty hostnames, hostnames with
- * leading dots, and hostnames with multiple dots in a
- * sequence. Also ensures that the length stays below
- * HOST_NAME_MAX. */
+ if (streq(s, ".host")) /* Used by the container logic to denote the "root container" */
+ return FLAGS_SET(flags, VALID_HOSTNAME_DOT_HOST);
for (p = s, dot = hyphen = true; *p; p++)
if (*p == '.') {
@@ -143,14 +123,13 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
hyphen = false;
}
- if (dot && (n_dots < 2 || !allow_trailing_dot))
+ if (dot && (n_dots < 2 || !FLAGS_SET(flags, VALID_HOSTNAME_TRAILING_DOT)))
return false;
if (hyphen)
return false;
- if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
- * Linux, but DNS allows domain names
- * up to 255 characters */
+ if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to
+ * 255 characters */
return false;
return true;
@@ -211,119 +190,3 @@ bool is_localhost(const char *hostname) {
endswith_no_case(hostname, ".localhost.localdomain") ||
endswith_no_case(hostname, ".localhost.localdomain.");
}
-
-bool is_gateway_hostname(const char *hostname) {
- assert(hostname);
-
- /* This tries to identify the valid syntaxes for the our
- * synthetic "gateway" host. */
-
- return
- strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.")
-#if ENABLE_COMPAT_GATEWAY_HOSTNAME
- || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.")
-#endif
- ;
-}
-
-int sethostname_idempotent(const char *s) {
- char buf[HOST_NAME_MAX + 1] = {};
-
- assert(s);
-
- if (gethostname(buf, sizeof(buf)) < 0)
- return -errno;
-
- if (streq(buf, s))
- return 0;
-
- if (sethostname(s, strlen(s)) < 0)
- return -errno;
-
- return 1;
-}
-
-int shorten_overlong(const char *s, char **ret) {
- char *h, *p;
-
- /* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
- * whatever comes earlier. */
-
- assert(s);
-
- h = strdup(s);
- if (!h)
- return -ENOMEM;
-
- if (hostname_is_valid(h, false)) {
- *ret = h;
- return 0;
- }
-
- p = strchr(h, '.');
- if (p)
- *p = 0;
-
- strshorten(h, HOST_NAME_MAX);
-
- if (!hostname_is_valid(h, false)) {
- free(h);
- return -EDOM;
- }
-
- *ret = h;
- return 1;
-}
-
-int read_etc_hostname_stream(FILE *f, char **ret) {
- int r;
-
- assert(f);
- assert(ret);
-
- for (;;) {
- _cleanup_free_ char *line = NULL;
- char *p;
-
- r = read_line(f, LONG_LINE_MAX, &line);
- if (r < 0)
- return r;
- if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
- return -ENOENT;
-
- p = strstrip(line);
-
- /* File may have empty lines or comments, ignore them */
- if (!IN_SET(*p, '\0', '#')) {
- char *copy;
-
- hostname_cleanup(p); /* normalize the hostname */
-
- if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */
- return -EBADMSG;
-
- copy = strdup(p);
- if (!copy)
- return -ENOMEM;
-
- *ret = copy;
- return 0;
- }
- }
-}
-
-int read_etc_hostname(const char *path, char **ret) {
- _cleanup_fclose_ FILE *f = NULL;
-
- assert(ret);
-
- if (!path)
- path = "/etc/hostname";
-
- f = fopen(path, "re");
- if (!f)
- return -errno;
-
- return read_etc_hostname_stream(f, ret);
-
-}
diff --git a/shared/systemd/src/basic/hostname-util.h b/shared/systemd/src/basic/hostname-util.h
index cafd6f020b..6cff9c1d4c 100644
--- a/shared/systemd/src/basic/hostname-util.h
+++ b/shared/systemd/src/basic/hostname-util.h
@@ -1,29 +1,29 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
#include <stdio.h>
#include "macro.h"
-
-bool hostname_is_set(void);
+#include "strv.h"
char* gethostname_malloc(void);
char* gethostname_short_malloc(void);
int gethostname_strict(char **ret);
bool valid_ldh_char(char c) _const_;
-bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_;
-char* hostname_cleanup(char *s);
-
-#define machine_name_is_valid(s) hostname_is_valid(s, false)
-bool is_localhost(const char *hostname);
-bool is_gateway_hostname(const char *hostname);
+typedef enum ValidHostnameFlags {
+ VALID_HOSTNAME_TRAILING_DOT = 1 << 0, /* Accept trailing dot on multi-label names */
+ VALID_HOSTNAME_DOT_HOST = 1 << 1, /* Accept ".host" as valid hostname */
+} ValidHostnameFlags;
-int sethostname_idempotent(const char *s);
+bool hostname_is_valid(const char *s, ValidHostnameFlags flags) _pure_;
+char* hostname_cleanup(char *s);
-int shorten_overlong(const char *s, char **ret);
+bool is_localhost(const char *hostname);
-int read_etc_hostname_stream(FILE *f, char **ret);
-int read_etc_hostname(const char *path, char **ret);
+static inline bool is_gateway_hostname(const char *hostname) {
+ /* This tries to identify the valid syntaxes for the our synthetic "gateway" host. */
+ return STRCASE_IN_SET(hostname, "_gateway", "_gateway.");
+}
diff --git a/shared/systemd/src/basic/in-addr-util.c b/shared/systemd/src/basic/in-addr-util.c
index c102504fdd..a4f13b620a 100644
--- a/shared/systemd/src/basic/in-addr-util.c
+++ b/shared/systemd/src/basic/in-addr-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <arpa/inet.h>
#include <endian.h>
diff --git a/shared/systemd/src/basic/in-addr-util.h b/shared/systemd/src/basic/in-addr-util.h
index 45c93a0056..24308b702e 100644
--- a/shared/systemd/src/basic/in-addr-util.h
+++ b/shared/systemd/src/basic/in-addr-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <netinet/in.h>
diff --git a/shared/systemd/src/basic/io-util.c b/shared/systemd/src/basic/io-util.c
index 460649deda..4d7405296b 100644
--- a/shared/systemd/src/basic/io-util.c
+++ b/shared/systemd/src/basic/io-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <limits.h>
@@ -291,7 +291,7 @@ int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len) {
return -E2BIG;
if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
- return log_oom();
+ return -ENOMEM;
iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len);
return 0;
@@ -303,7 +303,7 @@ int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const c
x = strjoin(field, value);
if (!x)
- return log_oom();
+ return -ENOMEM;
r = iovw_put(iovw, x, strlen(x));
if (r >= 0)
diff --git a/shared/systemd/src/basic/io-util.h b/shared/systemd/src/basic/io-util.h
index 719e19e85d..d817714b05 100644
--- a/shared/systemd/src/basic/io-util.h
+++ b/shared/systemd/src/basic/io-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
diff --git a/shared/systemd/src/basic/list.h b/shared/systemd/src/basic/list.h
index b62c374985..256b7187c2 100644
--- a/shared/systemd/src/basic/list.h
+++ b/shared/systemd/src/basic/list.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "macro.h"
diff --git a/shared/systemd/src/basic/log.h b/shared/systemd/src/basic/log.h
index ce8bb42ea1..41d828fd98 100644
--- a/shared/systemd/src/basic/log.h
+++ b/shared/systemd/src/basic/log.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdarg.h>
@@ -44,10 +44,17 @@ typedef enum LogTarget{
#define ERRNO_VALUE(val) (abs(val) & 255)
void log_set_target(LogTarget target);
+
void log_set_max_level_realm(LogRealm realm, int level);
+
#define log_set_max_level(level) \
log_set_max_level_realm(LOG_REALM, (level))
+static inline void log_set_max_level_all_realms(int level) {
+ for (LogRealm realm = 0; realm < _LOG_REALM_MAX; realm++)
+ log_set_max_level_realm(realm, level);
+}
+
void log_set_facility(int facility);
int log_set_target_from_string(const char *e);
@@ -161,7 +168,7 @@ int log_struct_internal(
const char *format, ...) _printf_(6,0) _sentinel_;
int log_oom_internal(
- LogRealm realm,
+ int level,
const char *file,
int line,
const char *func);
@@ -279,7 +286,8 @@ int log_emergency_level(void);
log_dump_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
0, PROJECT_FILE, __LINE__, __func__, buffer)
-#define log_oom() log_oom_internal(LOG_REALM, PROJECT_FILE, __LINE__, __func__)
+#define log_oom() log_oom_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, LOG_ERR), PROJECT_FILE, __LINE__, __func__)
+#define log_oom_debug() log_oom_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, LOG_DEBUG), PROJECT_FILE, __LINE__, __func__)
bool log_on_console(void) _pure_;
diff --git a/shared/systemd/src/basic/macro.h b/shared/systemd/src/basic/macro.h
index 41c2c3289e..2782553756 100644
--- a/shared/systemd/src/basic/macro.h
+++ b/shared/systemd/src/basic/macro.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <assert.h>
@@ -93,6 +93,10 @@
#endif
/* Temporarily disable some warnings */
+#define DISABLE_WARNING_DEPRECATED_DECLARATIONS \
+ _Pragma("GCC diagnostic push"); \
+ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+
#define DISABLE_WARNING_FORMAT_NONLITERAL \
_Pragma("GCC diagnostic push"); \
_Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"")
@@ -277,6 +281,12 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
MAX(_c, z); \
})
+#define MAX4(x, y, z, a) \
+ ({ \
+ const typeof(x) _d = MAX3(x, y, z); \
+ MAX(_d, a); \
+ })
+
#undef MIN
#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b))
#define __MIN(aq, a, bq, b) \
@@ -440,6 +450,9 @@ static inline int __coverity_check_and_return__(int condition) {
#define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p)))
#define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u)))
+#define PTR_TO_UINT8(p) ((uint8_t) ((uintptr_t) (p)))
+#define UINT8_TO_PTR(u) ((void *) ((uintptr_t) (u)))
+
#define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p)))
#define INT32_TO_PTR(u) ((void *) ((intptr_t) (u)))
#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p)))
@@ -541,10 +554,13 @@ static inline int __coverity_check_and_return__(int condition) {
#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
#define STRV_MAKE_EMPTY ((char*[1]) { NULL })
-/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses (void*) -1 as internal marker for EOL. */
-#define FOREACH_POINTER(p, x, ...) \
- for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, (void*) -1 }; \
- p != (typeof(p)) (void*) -1; \
+/* Pointers range from NULL to POINTER_MAX */
+#define POINTER_MAX ((void*) UINTPTR_MAX)
+
+/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses POINTER_MAX as internal marker for EOL. */
+#define FOREACH_POINTER(p, x, ...) \
+ for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, POINTER_MAX }; \
+ p != (typeof(p)) POINTER_MAX; \
p = *(++_l))
/* Define C11 thread_local attribute even on older gcc compiler
@@ -634,4 +650,8 @@ static inline int __coverity_check_and_return__(int condition) {
_copy; \
})
+static inline size_t size_add(size_t x, size_t y) {
+ return y >= SIZE_MAX - x ? SIZE_MAX : x + y;
+}
+
#include "log.h"
diff --git a/shared/systemd/src/basic/memory-util.c b/shared/systemd/src/basic/memory-util.c
index 5f327ef0d7..3338e355f7 100644
--- a/shared/systemd/src/basic/memory-util.c
+++ b/shared/systemd/src/basic/memory-util.c
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
#include <unistd.h>
#include "memory-util.h"
diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h
index 4f596cffb7..179edd247b 100644
--- a/shared/systemd/src/basic/memory-util.h
+++ b/shared/systemd/src/basic/memory-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
diff --git a/shared/systemd/src/basic/mempool.c b/shared/systemd/src/basic/mempool.c
index 22df42105b..9eedc20c4f 100644
--- a/shared/systemd/src/basic/mempool.c
+++ b/shared/systemd/src/basic/mempool.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdint.h>
#include <stdlib.h>
diff --git a/shared/systemd/src/basic/mempool.h b/shared/systemd/src/basic/mempool.h
index 0eecca0f92..0fe2f2789c 100644
--- a/shared/systemd/src/basic/mempool.h
+++ b/shared/systemd/src/basic/mempool.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
diff --git a/shared/systemd/src/basic/missing_fcntl.h b/shared/systemd/src/basic/missing_fcntl.h
index 5d1c6352f4..00937d2af0 100644
--- a/shared/systemd/src/basic/missing_fcntl.h
+++ b/shared/systemd/src/basic/missing_fcntl.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <fcntl.h>
diff --git a/shared/systemd/src/basic/missing_random.h b/shared/systemd/src/basic/missing_random.h
index 17af87a3ae..443b913685 100644
--- a/shared/systemd/src/basic/missing_random.h
+++ b/shared/systemd/src/basic/missing_random.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#if USE_SYS_RANDOM_H
diff --git a/shared/systemd/src/basic/missing_socket.h b/shared/systemd/src/basic/missing_socket.h
index c4f33449a3..30ac297e17 100644
--- a/shared/systemd/src/basic/missing_socket.h
+++ b/shared/systemd/src/basic/missing_socket.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <sys/socket.h>
@@ -67,6 +67,14 @@ struct sockaddr_vm {
#define IPV6_FREEBIND 78
#endif
+#ifndef IP_RECVFRAGSIZE
+#define IP_RECVFRAGSIZE 25
+#endif
+
+#ifndef IPV6_RECVFRAGSIZE
+#define IPV6_RECVFRAGSIZE 77
+#endif
+
/* linux/sockios.h */
#ifndef SIOCGSKNS
#define SIOCGSKNS 0x894C
diff --git a/shared/systemd/src/basic/missing_stat.h b/shared/systemd/src/basic/missing_stat.h
index 7bdc8a7efa..372fdf90bd 100644
--- a/shared/systemd/src/basic/missing_stat.h
+++ b/shared/systemd/src/basic/missing_stat.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <linux/types.h>
diff --git a/shared/systemd/src/basic/missing_syscall.h b/shared/systemd/src/basic/missing_syscall.h
index 7427b632ac..06166b3fb3 100644
--- a/shared/systemd/src/basic/missing_syscall.h
+++ b/shared/systemd/src/basic/missing_syscall.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/* Missing glibc definitions to access certain kernel APIs */
@@ -15,6 +15,26 @@
#include <asm/sgidefs.h>
#endif
+#if defined(__alpha__)
+# define systemd_SC_arch_bias(x) (110 + (x))
+#elif defined(__ia64__)
+# define systemd_SC_arch_bias(x) (1024 + (x))
+#elif defined(_MIPS_SIM)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define systemd_SC_arch_bias(x) (4000 + (x))
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define systemd_SC_arch_bias(x) (6000 + (x))
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define systemd_SC_arch_bias(x) (5000 + (x))
+# else
+# error "Unknown MIPS ABI"
+# endif
+#elif defined(__x86_64__) && defined(__ILP32__)
+# define systemd_SC_arch_bias(x) ((x) | /* __X32_SYSCALL_BIT */ 0x40000000)
+#else
+# define systemd_SC_arch_bias(x) (x)
+#endif
+
#include "missing_keyctl.h"
#include "missing_stat.h"
@@ -33,32 +53,38 @@ static inline int missing_pivot_root(const char *new_root, const char *put_old)
/* ======================================================================= */
-#if defined __x86_64__
-# define systemd_NR_memfd_create 319
-#elif defined __arm__
-# define systemd_NR_memfd_create 385
-#elif defined __aarch64__
+#if defined(__aarch64__)
# define systemd_NR_memfd_create 279
+#elif defined(__alpha__)
+# define systemd_NR_memfd_create 512
+#elif defined(__arc__) || defined(__tilegx__)
+# define systemd_NR_memfd_create 279
+#elif defined(__arm__)
+# define systemd_NR_memfd_create 385
+#elif defined(__i386__)
+# define systemd_NR_memfd_create 356
+#elif defined(__ia64__)
+# define systemd_NR_memfd_create systemd_SC_arch_bias(316)
+#elif defined(__m68k__)
+# define systemd_NR_memfd_create 353
+#elif defined(_MIPS_SIM)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define systemd_NR_memfd_create systemd_SC_arch_bias(354)
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define systemd_NR_memfd_create systemd_SC_arch_bias(318)
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define systemd_NR_memfd_create systemd_SC_arch_bias(314)
+# endif
#elif defined(__powerpc__)
# define systemd_NR_memfd_create 360
-#elif defined __s390__
+#elif defined(__s390__)
# define systemd_NR_memfd_create 350
-#elif defined _MIPS_SIM
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_memfd_create 4354
-# endif
-# if _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_memfd_create 6318
-# endif
-# if _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_memfd_create 5314
-# endif
-#elif defined __i386__
-# define systemd_NR_memfd_create 356
-#elif defined __arc__
-# define systemd_NR_memfd_create 279
+#elif defined(__sparc__)
+# define systemd_NR_memfd_create 348
+#elif defined(__x86_64__)
+# define systemd_NR_memfd_create systemd_SC_arch_bias(319)
#else
-# warning "memfd_create() syscall number unknown for your architecture"
+# warning "memfd_create() syscall number is unknown for your architecture"
#endif
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -90,36 +116,38 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) {
/* ======================================================================= */
-#if defined __x86_64__
-# define systemd_NR_getrandom 318
-#elif defined(__i386__)
-# define systemd_NR_getrandom 355
+#if defined(__aarch64__)
+# define systemd_NR_getrandom 278
+#elif defined(__alpha__)
+# define systemd_NR_getrandom 511
+#elif defined(__arc__) || defined(__tilegx__)
+# define systemd_NR_getrandom 278
#elif defined(__arm__)
# define systemd_NR_getrandom 384
-#elif defined(__aarch64__)
-# define systemd_NR_getrandom 278
+#elif defined(__i386__)
+# define systemd_NR_getrandom 355
#elif defined(__ia64__)
-# define systemd_NR_getrandom 1339
+# define systemd_NR_getrandom systemd_SC_arch_bias(318)
#elif defined(__m68k__)
# define systemd_NR_getrandom 352
-#elif defined(__s390x__)
-# define systemd_NR_getrandom 349
-#elif defined(__powerpc__)
-# define systemd_NR_getrandom 359
-#elif defined _MIPS_SIM
+#elif defined(_MIPS_SIM)
# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_getrandom 4353
-# endif
-# if _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_getrandom 6317
+# define systemd_NR_getrandom systemd_SC_arch_bias(353)
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define systemd_NR_getrandom systemd_SC_arch_bias(317)
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define systemd_NR_getrandom systemd_SC_arch_bias(313)
# endif
-# if _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_getrandom 5313
-# endif
-#elif defined(__arc__)
-# define systemd_NR_getrandom 278
+#elif defined(__powerpc__)
+# define systemd_NR_getrandom 359
+#elif defined(__s390__)
+# define systemd_NR_getrandom 349
+#elif defined(__sparc__)
+# define systemd_NR_getrandom 347
+#elif defined(__x86_64__)
+# define systemd_NR_getrandom systemd_SC_arch_bias(318)
#else
-# warning "getrandom() syscall number unknown for your architecture"
+# warning "getrandom() syscall number is unknown for your architecture"
#endif
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -166,22 +194,38 @@ static inline pid_t missing_gettid(void) {
/* ======================================================================= */
-#if defined(__x86_64__)
-# define systemd_NR_name_to_handle_at 303
-#elif defined(__i386__)
-# define systemd_NR_name_to_handle_at 341
+#if defined(__aarch64__)
+# define systemd_NR_name_to_handle_at 264
+#elif defined(__alpha__)
+# define systemd_NR_name_to_handle_at 497
+#elif defined(__arc__) || defined(__tilegx__)
+# define systemd_NR_name_to_handle_at 264
#elif defined(__arm__)
# define systemd_NR_name_to_handle_at 370
-#elif defined __aarch64__
-# define systemd_NR_name_to_handle_at 264
+#elif defined(__i386__)
+# define systemd_NR_name_to_handle_at 341
+#elif defined(__ia64__)
+# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(302)
+#elif defined(__m68k__)
+# define systemd_NR_name_to_handle_at 340
+#elif defined(_MIPS_SIM)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(339)
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303)
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(298)
+# endif
#elif defined(__powerpc__)
# define systemd_NR_name_to_handle_at 345
-#elif defined __s390__ || defined __s390x__
+#elif defined(__s390__)
# define systemd_NR_name_to_handle_at 335
-#elif defined(__arc__)
-# define systemd_NR_name_to_handle_at 264
+#elif defined(__sparc__)
+# define systemd_NR_name_to_handle_at 332
+#elif defined(__x86_64__)
+# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303)
#else
-# warning "name_to_handle_at number is not defined"
+# warning "name_to_handle_at() syscall number is unknown for your architecture"
#endif
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -219,22 +263,38 @@ static inline int missing_name_to_handle_at(int fd, const char *name, struct fil
/* ======================================================================= */
-#if defined __aarch64__
+#if defined(__aarch64__)
+# define systemd_NR_setns 268
+#elif defined(__alpha__)
+# define systemd_NR_setns 501
+#elif defined(__arc__) || defined(__tilegx__)
# define systemd_NR_setns 268
-#elif defined __arm__
+#elif defined(__arm__)
# define systemd_NR_setns 375
-#elif defined(__x86_64__)
-# define systemd_NR_setns 308
#elif defined(__i386__)
# define systemd_NR_setns 346
+#elif defined(__ia64__)
+# define systemd_NR_setns systemd_SC_arch_bias(306)
+#elif defined(__m68k__)
+# define systemd_NR_setns 344
+#elif defined(_MIPS_SIM)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define systemd_NR_setns systemd_SC_arch_bias(344)
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define systemd_NR_setns systemd_SC_arch_bias(308)
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define systemd_NR_setns systemd_SC_arch_bias(303)
+# endif
#elif defined(__powerpc__)
# define systemd_NR_setns 350
-#elif defined __s390__ || defined __s390x__
+#elif defined(__s390__)
# define systemd_NR_setns 339
-#elif defined(__arc__)
-# define systemd_NR_setns 268
+#elif defined(__sparc__)
+# define systemd_NR_setns 337
+#elif defined(__x86_64__)
+# define systemd_NR_setns systemd_SC_arch_bias(308)
#else
-# warning "setns() syscall number unknown for your architecture"
+# warning "setns() syscall number is unknown for your architecture"
#endif
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -276,32 +336,38 @@ static inline pid_t raw_getpid(void) {
/* ======================================================================= */
-#if defined __x86_64__
-# define systemd_NR_renameat2 316
-#elif defined __arm__
-# define systemd_NR_renameat2 382
-#elif defined __aarch64__
+#if defined(__aarch64__)
+# define systemd_NR_renameat2 276
+#elif defined(__alpha__)
+# define systemd_NR_renameat2 510
+#elif defined(__arc__) || defined(__tilegx__)
# define systemd_NR_renameat2 276
-#elif defined _MIPS_SIM
+#elif defined(__arm__)
+# define systemd_NR_renameat2 382
+#elif defined(__i386__)
+# define systemd_NR_renameat2 353
+#elif defined(__ia64__)
+# define systemd_NR_renameat2 systemd_SC_arch_bias(314)
+#elif defined(__m68k__)
+# define systemd_NR_renameat2 351
+#elif defined(_MIPS_SIM)
# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_renameat2 4351
-# endif
-# if _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_renameat2 6315
-# endif
-# if _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_renameat2 5311
+# 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 __i386__
-# define systemd_NR_renameat2 353
-#elif defined __powerpc64__
+#elif defined(__powerpc__)
# define systemd_NR_renameat2 357
-#elif defined __s390__ || defined __s390x__
+#elif defined(__s390__)
# define systemd_NR_renameat2 347
-#elif defined __arc__
-# define systemd_NR_renameat2 276
+#elif defined(__sparc__)
+# define systemd_NR_renameat2 345
+#elif defined(__x86_64__)
+# define systemd_NR_renameat2 systemd_SC_arch_bias(316)
#else
-# warning "renameat2() syscall number unknown for your architecture"
+# warning "renameat2() syscall number is unknown for your architecture"
#endif
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -385,22 +451,38 @@ static inline key_serial_t missing_request_key(const char *type, const char *des
/* ======================================================================= */
-#if defined(__x86_64__)
-# define systemd_NR_copy_file_range 326
+#if defined(__aarch64__)
+# define systemd_NR_copy_file_range 285
+#elif defined(__alpha__)
+# define systemd_NR_copy_file_range 519
+#elif defined(__arc__) || defined(__tilegx__)
+# define systemd_NR_copy_file_range 285
+#elif defined(__arm__)
+# define systemd_NR_copy_file_range 391
#elif defined(__i386__)
# define systemd_NR_copy_file_range 377
-#elif defined __s390__
-# define systemd_NR_copy_file_range 375
-#elif defined __arm__
-# define systemd_NR_copy_file_range 391
-#elif defined __aarch64__
-# define systemd_NR_copy_file_range 285
-#elif defined __powerpc__
+#elif defined(__ia64__)
+# define systemd_NR_copy_file_range systemd_SC_arch_bias(323)
+#elif defined(__m68k__)
+# define systemd_NR_copy_file_range 376
+#elif defined(_MIPS_SIM)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define systemd_NR_copy_file_range systemd_SC_arch_bias(360)
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define systemd_NR_copy_file_range systemd_SC_arch_bias(324)
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define systemd_NR_copy_file_range systemd_SC_arch_bias(320)
+# endif
+#elif defined(__powerpc__)
# define systemd_NR_copy_file_range 379
-#elif defined __arc__
-# define systemd_NR_copy_file_range 285
+#elif defined(__s390__)
+# define systemd_NR_copy_file_range 375
+#elif defined(__sparc__)
+# define systemd_NR_copy_file_range 357
+#elif defined(__x86_64__)
+# define systemd_NR_copy_file_range systemd_SC_arch_bias(326)
#else
-# warning "copy_file_range() syscall number unknown for your architecture"
+# warning "copy_file_range() syscall number is unknown for your architecture"
#endif
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -435,24 +517,38 @@ static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in,
/* ======================================================================= */
-#if defined __i386__
-# define systemd_NR_bpf 357
-#elif defined __x86_64__
-# define systemd_NR_bpf 321
-#elif defined __aarch64__
+#if defined(__aarch64__)
+# define systemd_NR_bpf 280
+#elif defined(__alpha__)
+# define systemd_NR_bpf 515
+#elif defined(__arc__) || defined(__tilegx__)
# define systemd_NR_bpf 280
-#elif defined __arm__
+#elif defined(__arm__)
# define systemd_NR_bpf 386
+#elif defined(__i386__)
+# define systemd_NR_bpf 357
+#elif defined(__ia64__)
+# define systemd_NR_bpf systemd_SC_arch_bias(317)
+#elif defined(__m68k__)
+# define systemd_NR_bpf 354
+#elif defined(_MIPS_SIM)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define systemd_NR_bpf systemd_SC_arch_bias(355)
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define systemd_NR_bpf systemd_SC_arch_bias(319)
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define systemd_NR_bpf systemd_SC_arch_bias(315)
+# endif
#elif defined(__powerpc__)
# define systemd_NR_bpf 361
-#elif defined __sparc__
-# define systemd_NR_bpf 349
-#elif defined __s390__
+#elif defined(__s390__)
# define systemd_NR_bpf 351
-#elif defined __tilegx__
-# define systemd_NR_bpf 280
+#elif defined(__sparc__)
+# define systemd_NR_bpf 349
+#elif defined(__x86_64__)
+# define systemd_NR_bpf systemd_SC_arch_bias(321)
#else
-# warning "bpf() syscall number unknown for your architecture"
+# warning "bpf() syscall number is unknown for your architecture"
#endif
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -487,30 +583,38 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) {
/* ======================================================================= */
#ifndef __IGNORE_pkey_mprotect
-# if defined __i386__
-# define systemd_NR_pkey_mprotect 380
-# elif defined __x86_64__
-# define systemd_NR_pkey_mprotect 329
-# elif defined __aarch64__
+# if defined(__aarch64__)
# define systemd_NR_pkey_mprotect 288
-# elif defined __arm__
+# elif defined(__alpha__)
+# define systemd_NR_pkey_mprotect 524
+# elif defined(__arc__) || defined(__tilegx__)
+# define systemd_NR_pkey_mprotect 226
+# elif defined(__arm__)
# define systemd_NR_pkey_mprotect 394
-# elif defined __powerpc__
-# define systemd_NR_pkey_mprotect 386
-# elif defined __s390__
-# define systemd_NR_pkey_mprotect 384
-# elif defined _MIPS_SIM
+# elif defined(__i386__)
+# define systemd_NR_pkey_mprotect 380
+# elif defined(__ia64__)
+# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(330)
+# elif defined(__m68k__)
+# define systemd_NR_pkey_mprotect 381
+# elif defined(_MIPS_SIM)
# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define systemd_NR_pkey_mprotect 4363
-# endif
-# if _MIPS_SIM == _MIPS_SIM_NABI32
-# define systemd_NR_pkey_mprotect 6327
-# endif
-# if _MIPS_SIM == _MIPS_SIM_ABI64
-# define systemd_NR_pkey_mprotect 5323
+# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(363)
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(327)
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(323)
# endif
+# elif defined(__powerpc__)
+# define systemd_NR_pkey_mprotect 386
+# elif defined(__s390__)
+# define systemd_NR_pkey_mprotect 384
+# elif defined(__sparc__)
+# define systemd_NR_pkey_mprotect 362
+# elif defined(__x86_64__)
+# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(329)
# else
-# warning "pkey_mprotect() syscall number unknown for your architecture"
+# warning "pkey_mprotect() syscall number is unknown for your architecture"
# endif
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -530,22 +634,38 @@ assert_cc(__NR_pkey_mprotect == systemd_NR_pkey_mprotect);
/* ======================================================================= */
-#if defined __aarch64__
+#if defined(__aarch64__)
# define systemd_NR_statx 291
-#elif defined __arm__
-# define systemd_NR_statx 397
-#elif defined __alpha__
+#elif defined(__alpha__)
# define systemd_NR_statx 522
-#elif defined __i386__ || defined __powerpc64__
+#elif defined(__arc__) || defined(__tilegx__)
+# define systemd_NR_statx 291
+#elif defined(__arm__)
+# define systemd_NR_statx 397
+#elif defined(__i386__)
# define systemd_NR_statx 383
-#elif defined __s390__ || defined __s390x__
+#elif defined(__ia64__)
+# define systemd_NR_statx systemd_SC_arch_bias(326)
+#elif defined(__m68k__)
# define systemd_NR_statx 379
-#elif defined __sparc__
+#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 332
+#elif defined(__x86_64__)
+# define systemd_NR_statx systemd_SC_arch_bias(332)
#else
-# warning "statx() syscall number unknown for your architecture"
+# warning "statx() syscall number is unknown for your architecture"
#endif
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
@@ -628,23 +748,7 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask,
/* ======================================================================= */
/* should be always defined, see kernel 39036cd2727395c3369b1051005da74059a85317 */
-#if defined __alpha__
-# define systemd_NR_pidfd_send_signal 534
-#elif defined _MIPS_SIM
-# if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
-# define systemd_NR_pidfd_send_signal (424 + 4000)
-# endif
-# if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
-# define systemd_NR_pidfd_send_signal (424 + 6000)
-# endif
-# if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
-# define systemd_NR_pidfd_send_signal (424 + 5000)
-# endif
-#elif defined __ia64__
-# define systemd_NR_pidfd_send_signal (424 + 1024)
-#else
-# define systemd_NR_pidfd_send_signal 424
-#endif
+#define systemd_NR_pidfd_send_signal systemd_SC_arch_bias(424)
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
#if defined __NR_pidfd_send_signal && __NR_pidfd_send_signal >= 0
@@ -660,7 +764,7 @@ assert_cc(__NR_pidfd_send_signal == systemd_NR_pidfd_send_signal);
#if !HAVE_PIDFD_SEND_SIGNAL
static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) {
-# ifdef __NR_pidfd_open
+# ifdef __NR_pidfd_send_signal
return syscall(__NR_pidfd_send_signal, fd, sig, info, flags);
# else
errno = ENOSYS;
@@ -672,23 +776,7 @@ static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, un
#endif
/* should be always defined, see kernel 7615d9e1780e26e0178c93c55b73309a5dc093d7 */
-#if defined __alpha__
-# define systemd_NR_pidfd_open 544
-#elif defined _MIPS_SIM
-# if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */
-# define systemd_NR_pidfd_open (434 + 4000)
-# endif
-# if _MIPS_SIM == _MIPS_SIM_NABI32 /* n32 */
-# define systemd_NR_pidfd_open (434 + 6000)
-# endif
-# if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */
-# define systemd_NR_pidfd_open (434 + 5000)
-# endif
-#elif defined __ia64__
-# define systemd_NR_pidfd_open (434 + 1024)
-#else
-# define systemd_NR_pidfd_open 434
-#endif
+#define systemd_NR_pidfd_open systemd_SC_arch_bias(434)
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
#if defined __NR_pidfd_open && __NR_pidfd_open >= 0
@@ -728,3 +816,68 @@ static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info)
# define rt_sigqueueinfo missing_rt_sigqueueinfo
#endif
+
+/* ======================================================================= */
+
+#if !HAVE_EXECVEAT
+static inline int missing_execveat(int dirfd, const char *pathname,
+ char *const argv[], char *const envp[],
+ int flags) {
+# if defined __NR_execveat && __NR_execveat >= 0
+ return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+
+# undef AT_EMPTY_PATH
+# define AT_EMPTY_PATH 0x1000
+# define execveat missing_execveat
+#endif
+
+/* ======================================================================= */
+
+#define systemd_NR_close_range systemd_SC_arch_bias(436)
+
+/* may be (invalid) negative number due to libseccomp, see PR 13319 */
+#if defined __NR_close_range && __NR_close_range >= 0
+# if defined systemd_NR_close_range
+assert_cc(__NR_close_range == systemd_NR_close_range);
+# endif
+#else
+# if defined __NR_close_range
+# undef __NR_close_range
+# endif
+# if defined systemd_NR_close_range
+# define __NR_close_range systemd_NR_close_range
+# endif
+#endif
+
+#if !HAVE_CLOSE_RANGE
+static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) {
+# ifdef __NR_close_range
+ /* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
+ * userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to
+ * wrap this syscall, but let's assume it's going to be similar to what they do for close(),
+ * i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the
+ * userspace wrapper. There's only one caveat for this: unlike for close() there's the special
+ * UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse
+ * any other negative values. */
+ if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) {
+ errno = -EBADF;
+ return -1;
+ }
+
+ return syscall(__NR_close_range,
+ (unsigned) first_fd,
+ end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */
+ flags);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+
+# define close_range missing_close_range
+#endif
diff --git a/shared/systemd/src/basic/missing_type.h b/shared/systemd/src/basic/missing_type.h
index bf8a6caa1b..f6233090a9 100644
--- a/shared/systemd/src/basic/missing_type.h
+++ b/shared/systemd/src/basic/missing_type.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <uchar.h>
diff --git a/shared/systemd/src/basic/parse-util.c b/shared/systemd/src/basic/parse-util.c
index 818c9054d6..5d4dafe3a5 100644
--- a/shared/systemd/src/basic/parse-util.c
+++ b/shared/systemd/src/basic/parse-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <inttypes.h>
@@ -862,3 +862,45 @@ int parse_oom_score_adjust(const char *s, int *ret) {
*ret = v;
return 0;
}
+
+int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret) {
+ assert(ret);
+
+ if (i >= (~0UL << FSHIFT))
+ return -ERANGE;
+
+ i = i << FSHIFT;
+ f = DIV_ROUND_UP((f << FSHIFT), 100);
+
+ if (f >= FIXED_1)
+ return -ERANGE;
+
+ *ret = i | f;
+ return 0;
+}
+
+int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) {
+ const char *d, *f_str, *i_str;
+ unsigned long i, f;
+ int r;
+
+ assert(s);
+ assert(ret);
+
+ d = strchr(s, '.');
+ if (!d)
+ return -EINVAL;
+
+ i_str = strndupa(s, d - s);
+ f_str = d + 1;
+
+ r = safe_atolu_full(i_str, 10, &i);
+ if (r < 0)
+ return r;
+
+ r = safe_atolu_full(f_str, 10, &f);
+ if (r < 0)
+ return r;
+
+ return store_loadavg_fixed_point(i, f, ret);
+}
diff --git a/shared/systemd/src/basic/parse-util.h b/shared/systemd/src/basic/parse-util.h
index 2cee65c49a..81478ed059 100644
--- a/shared/systemd/src/basic/parse-util.h
+++ b/shared/systemd/src/basic/parse-util.h
@@ -1,14 +1,17 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
#include <limits.h>
+#include <linux/loadavg.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include "macro.h"
+typedef unsigned long loadavg_t;
+
int parse_boolean(const char *v) _pure_;
int parse_dev(const char *s, dev_t *ret);
int parse_pid(const char *s, pid_t* ret_pid);
@@ -88,18 +91,18 @@ static inline int safe_atoux64(const char *s, uint64_t *ret) {
}
#if LONG_MAX == INT_MAX
-static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+static inline int safe_atolu_full(const char *s, unsigned base, long unsigned *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned));
- return safe_atou(s, (unsigned*) ret_u);
+ return safe_atou_full(s, base, (unsigned*) ret_u);
}
static inline int safe_atoli(const char *s, long int *ret_u) {
assert_cc(sizeof(long int) == sizeof(int));
return safe_atoi(s, (int*) ret_u);
}
#else
-static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+static inline int safe_atolu_full(const char *s, unsigned base, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
- return safe_atollu(s, (unsigned long long*) ret_u);
+ return safe_atollu_full(s, base, (unsigned long long*) ret_u);
}
static inline int safe_atoli(const char *s, long int *ret_u) {
assert_cc(sizeof(long int) == sizeof(long long int));
@@ -107,6 +110,10 @@ static inline int safe_atoli(const char *s, long int *ret_u) {
}
#endif
+static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+ return safe_atolu_full(s, 0, ret_u);
+}
+
#if SIZE_MAX == UINT_MAX
static inline int safe_atozu(const char *s, size_t *ret_u) {
assert_cc(sizeof(size_t) == sizeof(unsigned));
@@ -137,3 +144,8 @@ int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high);
int parse_ip_prefix_length(const char *s, int *ret);
int parse_oom_score_adjust(const char *s, int *ret);
+
+/* Given a Linux load average (e.g. decimal number 34.89 where 34 is passed as i and 89 is passed as f), convert it
+ * to a loadavg_t. */
+int store_loadavg_fixed_point(unsigned long i, unsigned long f, loadavg_t *ret);
+int parse_loadavg_fixed_point(const char *s, loadavg_t *ret);
diff --git a/shared/systemd/src/basic/path-util.c b/shared/systemd/src/basic/path-util.c
index a36cf8332c..dae8b7341a 100644
--- a/shared/systemd/src/basic/path-util.c
+++ b/shared/systemd/src/basic/path-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <limits.h>
@@ -550,7 +550,7 @@ char* path_join_internal(const char *first, ...) {
sz = strlen_ptr(first);
va_start(ap, first);
- while ((p = va_arg(ap, char*)) != (const char*) -1)
+ while ((p = va_arg(ap, char*)) != POINTER_MAX)
if (!isempty(p))
sz += 1 + strlen(p);
va_end(ap);
@@ -570,7 +570,7 @@ char* path_join_internal(const char *first, ...) {
}
va_start(ap, first);
- while ((p = va_arg(ap, char*)) != (const char*) -1) {
+ while ((p = va_arg(ap, char*)) != POINTER_MAX) {
if (isempty(p))
continue;
@@ -585,22 +585,53 @@ char* path_join_internal(const char *first, ...) {
return joined;
}
-int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
+static int check_x_access(const char *path, int *ret_fd) {
+ if (ret_fd) {
+ _cleanup_close_ int fd = -1;
+ int r;
+
+ /* We need to use O_PATH because there may be executables for which we have only exec
+ * permissions, but not read (usually suid executables). */
+ fd = open(path, O_PATH|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ r = access_fd(fd, X_OK);
+ if (r < 0)
+ return r;
+
+ *ret_fd = TAKE_FD(fd);
+ } else {
+ /* Let's optimize things a bit by not opening the file if we don't need the fd. */
+ if (access(path, X_OK) < 0)
+ return -errno;
+ }
+
+ return 0;
+}
+
+int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd) {
int last_error, r;
const char *p = NULL;
assert(name);
if (is_path(name)) {
- if (access(name, X_OK) < 0)
- return -errno;
+ _cleanup_close_ int fd = -1;
- if (ret) {
- r = path_make_absolute_cwd(name, ret);
+ r = check_x_access(name, ret_fd ? &fd : NULL);
+ if (r < 0)
+ return r;
+
+ if (ret_filename) {
+ r = path_make_absolute_cwd(name, ret_filename);
if (r < 0)
return r;
}
+ if (ret_fd)
+ *ret_fd = TAKE_FD(fd);
+
return 0;
}
@@ -613,8 +644,10 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
last_error = -ENOENT;
+ /* Resolve a single-component name to a full path */
for (;;) {
_cleanup_free_ char *j = NULL, *element = NULL;
+ _cleanup_close_ int fd = -1;
r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
@@ -629,7 +662,8 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
if (!j)
return -ENOMEM;
- if (access(j, X_OK) >= 0) {
+ r = check_x_access(j, ret_fd ? &fd : NULL);
+ if (r >= 0) {
_cleanup_free_ char *with_dash;
with_dash = strjoin(j, "/");
@@ -643,8 +677,10 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) {
/* We can't just `continue` inverting this case, since we need to update last_error. */
if (errno == ENOTDIR) {
/* Found it! */
- if (ret)
- *ret = path_simplify(TAKE_PTR(j), false);
+ if (ret_filename)
+ *ret_filename = path_simplify(TAKE_PTR(j), false);
+ if (ret_fd)
+ *ret_fd = TAKE_FD(fd);
return 0;
}
diff --git a/shared/systemd/src/basic/path-util.h b/shared/systemd/src/basic/path-util.h
index bd8c14903e..e7a26c9a84 100644
--- a/shared/systemd/src/basic/path-util.h
+++ b/shared/systemd/src/basic/path-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <alloca.h>
@@ -62,7 +62,7 @@ int path_compare(const char *a, const char *b) _pure_;
bool path_equal(const char *a, const char *b) _pure_;
bool path_equal_or_files_same(const char *a, const char *b, int flags);
char* path_join_internal(const char *first, ...);
-#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, (const char*) -1)
+#define path_join(x, ...) path_join_internal(x, __VA_ARGS__, POINTER_MAX)
char* path_simplify(char *path, bool kill_dots);
@@ -88,9 +88,9 @@ int path_strv_make_absolute_cwd(char **l);
char** path_strv_resolve(char **l, const char *root);
char** path_strv_resolve_uniq(char **l, const char *root);
-int find_executable_full(const char *name, bool use_path_envvar, char **ret);
-static inline int find_executable(const char *name, char **ret) {
- return find_executable_full(name, true, ret);
+int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd);
+static inline int find_executable(const char *name, char **ret_filename) {
+ return find_executable_full(name, true, ret_filename, NULL);
}
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
diff --git a/shared/systemd/src/basic/prioq.c b/shared/systemd/src/basic/prioq.c
index 76b27fa0a8..559e5d124d 100644
--- a/shared/systemd/src/basic/prioq.c
+++ b/shared/systemd/src/basic/prioq.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Priority Queue
diff --git a/shared/systemd/src/basic/prioq.h b/shared/systemd/src/basic/prioq.h
index 1fb57bfa4c..951576c021 100644
--- a/shared/systemd/src/basic/prioq.h
+++ b/shared/systemd/src/basic/prioq.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c
index 80f13048c1..0851613fc9 100644
--- a/shared/systemd/src/basic/process-util.c
+++ b/shared/systemd/src/basic/process-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <ctype.h>
#include <errno.h>
diff --git a/shared/systemd/src/basic/process-util.h b/shared/systemd/src/basic/process-util.h
index 49bb74ac0f..6144f142c4 100644
--- a/shared/systemd/src/basic/process-util.h
+++ b/shared/systemd/src/basic/process-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <errno.h>
diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c
index 2031262389..c831f06dac 100644
--- a/shared/systemd/src/basic/random-util.c
+++ b/shared/systemd/src/basic/random-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#if defined(__i386__) || defined(__x86_64__)
#include <cpuid.h>
@@ -452,10 +452,21 @@ size_t random_pool_size(void) {
}
int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
+ _cleanup_close_ int opened_fd = -1;
int r;
- assert(fd >= 0);
- assert(seed && size > 0);
+ assert(seed || size == 0);
+
+ if (size == 0)
+ return 0;
+
+ if (fd < 0) {
+ opened_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
+ if (opened_fd < 0)
+ return -errno;
+
+ fd = opened_fd;
+ }
if (credit) {
_cleanup_free_ struct rand_pool_info *info = NULL;
@@ -481,5 +492,5 @@ int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
return r;
}
- return 0;
+ return 1;
}
diff --git a/shared/systemd/src/basic/random-util.h b/shared/systemd/src/basic/random-util.h
index 7824ffaceb..f661fc093a 100644
--- a/shared/systemd/src/basic/random-util.h
+++ b/shared/systemd/src/basic/random-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
diff --git a/shared/systemd/src/basic/ratelimit.c b/shared/systemd/src/basic/ratelimit.c
new file mode 100644
index 0000000000..bae2ec3ffc
--- /dev/null
+++ b/shared/systemd/src/basic/ratelimit.c
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <sys/time.h>
+
+#include "macro.h"
+#include "ratelimit.h"
+
+/* Modelled after Linux' lib/ratelimit.c by Dave Young
+ * <hidave.darkstar@gmail.com>, which is licensed GPLv2. */
+
+bool ratelimit_below(RateLimit *r) {
+ usec_t ts;
+
+ assert(r);
+
+ if (!ratelimit_configured(r))
+ return true;
+
+ ts = now(CLOCK_MONOTONIC);
+
+ if (r->begin <= 0 ||
+ ts - r->begin > r->interval) {
+ r->begin = ts;
+
+ /* Reset counter */
+ r->num = 0;
+ goto good;
+ }
+
+ if (r->num < r->burst)
+ goto good;
+
+ return false;
+
+good:
+ r->num++;
+ return true;
+}
diff --git a/shared/systemd/src/basic/ratelimit.h b/shared/systemd/src/basic/ratelimit.h
new file mode 100644
index 0000000000..ee1d17c0e7
--- /dev/null
+++ b/shared/systemd/src/basic/ratelimit.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdbool.h>
+
+#include "time-util.h"
+#include "util.h"
+
+typedef struct RateLimit {
+ usec_t interval; /* Keep those two fields first so they can be initialized easily: */
+ unsigned burst; /* RateLimit rl = { INTERVAL, BURST }; */
+ unsigned num;
+ usec_t begin;
+} RateLimit;
+
+static inline void ratelimit_reset(RateLimit *rl) {
+ rl->num = rl->begin = 0;
+}
+
+static inline bool ratelimit_configured(RateLimit *rl) {
+ return rl->interval > 0 && rl->burst > 0;
+}
+
+bool ratelimit_below(RateLimit *r);
diff --git a/shared/systemd/src/basic/set.h b/shared/systemd/src/basic/set.h
index 7170eea84c..57ff713039 100644
--- a/shared/systemd/src/basic/set.h
+++ b/shared/systemd/src/basic/set.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "extract-word.h"
@@ -128,10 +128,12 @@ int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HAS
int set_consume(Set *s, void *value);
-int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS);
-#define set_put_strdup(s, p) _set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS)
-int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS);
-#define set_put_strdupv(s, l) _set_put_strdupv(s, l HASHMAP_DEBUG_SRC_ARGS)
+int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS);
+#define set_put_strdup_full(s, hash_ops, p) _set_put_strdup_full(s, hash_ops, p HASHMAP_DEBUG_SRC_ARGS)
+#define set_put_strdup(s, p) set_put_strdup_full(s, &string_hash_ops_free, p)
+int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS);
+#define set_put_strdupv_full(s, hash_ops, l) _set_put_strdupv_full(s, hash_ops, l HASHMAP_DEBUG_SRC_ARGS)
+#define set_put_strdupv(s, l) set_put_strdupv_full(s, &string_hash_ops_free, l)
int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags);
@@ -148,3 +150,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
#define _cleanup_set_free_ _cleanup_(set_freep)
#define _cleanup_set_free_free_ _cleanup_(set_free_freep)
+
+int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret);
diff --git a/shared/systemd/src/basic/signal-util.c b/shared/systemd/src/basic/signal-util.c
index cb59f6ca0f..63b833b218 100644
--- a/shared/systemd/src/basic/signal-util.c
+++ b/shared/systemd/src/basic/signal-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <stdarg.h>
@@ -49,16 +49,7 @@ static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
int r = 0;
/* negative signal ends the list. 0 signal is skipped. */
-
- if (sig < 0)
- return 0;
-
- if (sig > 0) {
- if (sigaction(sig, sa, NULL) < 0)
- r = -errno;
- }
-
- while ((sig = va_arg(ap, int)) >= 0) {
+ for (; sig >= 0; sig = va_arg(ap, int)) {
if (sig == 0)
continue;
diff --git a/shared/systemd/src/basic/signal-util.h b/shared/systemd/src/basic/signal-util.h
index 3909ee341d..bdd39d429d 100644
--- a/shared/systemd/src/basic/signal-util.h
+++ b/shared/systemd/src/basic/signal-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <signal.h>
diff --git a/shared/systemd/src/basic/siphash24.h b/shared/systemd/src/basic/siphash24.h
index fe43256882..90a6de00e4 100644
--- a/shared/systemd/src/basic/siphash24.h
+++ b/shared/systemd/src/basic/siphash24.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: CC0-1.0 */
+
#pragma once
#include <inttypes.h>
diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c
index f2e1148e87..59039bea4f 100644
--- a/shared/systemd/src/basic/socket-util.c
+++ b/shared/systemd/src/basic/socket-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <arpa/inet.h>
#include <errno.h>
@@ -23,10 +23,7 @@
#include "format-util.h"
#include "io-util.h"
#include "log.h"
-#include "macro.h"
#include "memory-util.h"
-#include "missing_socket.h"
-#include "missing_network.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
@@ -320,7 +317,7 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) {
}
int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
- union sockaddr_union *sa = (union sockaddr_union*) _sa;
+ const union sockaddr_union *sa = (const union sockaddr_union*) _sa;
/* Note, this returns the port as 'unsigned' rather than 'uint16_t', as AF_VSOCK knows larger ports */
@@ -345,6 +342,25 @@ int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
}
}
+const union in_addr_union *sockaddr_in_addr(const struct sockaddr *_sa) {
+ const union sockaddr_union *sa = (const union sockaddr_union*) _sa;
+
+ if (!sa)
+ return NULL;
+
+ switch (sa->sa.sa_family) {
+
+ case AF_INET:
+ return (const union in_addr_union*) &sa->in.sin_addr;
+
+ case AF_INET6:
+ return (const union in_addr_union*) &sa->in6.sin6_addr;
+
+ default:
+ return NULL;
+ }
+}
+
int sockaddr_pretty(
const struct sockaddr *_sa,
socklen_t salen,
@@ -1240,71 +1256,8 @@ int socket_set_recvpktinfo(int fd, int af, bool b) {
case AF_NETLINK:
return setsockopt_int(fd, SOL_NETLINK, NETLINK_PKTINFO, b);
- default:
- return -EAFNOSUPPORT;
- }
-}
-
-int socket_set_recverr(int fd, int af, bool b) {
- int r;
-
- if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
- }
-
- switch (af) {
-
- case AF_INET:
- return setsockopt_int(fd, IPPROTO_IP, IP_RECVERR, b);
-
- case AF_INET6:
- return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVERR, b);
-
- default:
- return -EAFNOSUPPORT;
- }
-}
-
-int socket_set_recvttl(int fd, int af, bool b) {
- int r;
-
- if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
- }
-
- switch (af) {
-
- case AF_INET:
- return setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, b);
-
- case AF_INET6:
- return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, b);
-
- default:
- return -EAFNOSUPPORT;
- }
-}
-
-int socket_set_ttl(int fd, int af, int ttl) {
- int r;
-
- if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
- }
-
- switch (af) {
-
- case AF_INET:
- return setsockopt_int(fd, IPPROTO_IP, IP_TTL, ttl);
-
- case AF_INET6:
- return setsockopt_int(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, ttl);
+ case AF_PACKET:
+ return setsockopt_int(fd, SOL_PACKET, PACKET_AUXDATA, b);
default:
return -EAFNOSUPPORT;
@@ -1340,7 +1293,7 @@ int socket_set_unicast_if(int fd, int af, int ifi) {
}
}
-int socket_set_freebind(int fd, int af, bool b) {
+int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val) {
int r;
if (af == AF_UNSPEC) {
@@ -1352,18 +1305,18 @@ int socket_set_freebind(int fd, int af, bool b) {
switch (af) {
case AF_INET:
- return setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, b);
+ return setsockopt_int(fd, IPPROTO_IP, opt_ipv4, val);
case AF_INET6:
- return setsockopt_int(fd, IPPROTO_IPV6, IPV6_FREEBIND, b);
+ return setsockopt_int(fd, IPPROTO_IPV6, opt_ipv6, val);
default:
return -EAFNOSUPPORT;
}
}
-int socket_set_transparent(int fd, int af, bool b) {
- int r;
+int socket_get_mtu(int fd, int af, size_t *ret) {
+ int mtu, r;
if (af == AF_UNSPEC) {
r = socket_get_family(fd, &af);
@@ -1374,12 +1327,22 @@ int socket_set_transparent(int fd, int af, bool b) {
switch (af) {
case AF_INET:
- return setsockopt_int(fd, IPPROTO_IP, IP_TRANSPARENT, b);
+ r = getsockopt_int(fd, IPPROTO_IP, IP_MTU, &mtu);
+ break;
case AF_INET6:
- return setsockopt_int(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, b);
+ r = getsockopt_int(fd, IPPROTO_IPV6, IPV6_MTU, &mtu);
+ break;
default:
return -EAFNOSUPPORT;
}
+
+ if (r < 0)
+ return r;
+ if (mtu <= 0)
+ return -EINVAL;
+
+ *ret = (size_t) mtu;
+ return 0;
}
diff --git a/shared/systemd/src/basic/socket-util.h b/shared/systemd/src/basic/socket-util.h
index c36f90f75f..240d209c14 100644
--- a/shared/systemd/src/basic/socket-util.h
+++ b/shared/systemd/src/basic/socket-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
@@ -15,6 +15,7 @@
#include <sys/un.h>
#include "macro.h"
+#include "missing_network.h"
#include "missing_socket.h"
#include "sparse-endian.h"
@@ -102,6 +103,7 @@ const char* socket_address_get_path(const SocketAddress *a);
bool socket_ipv6_is_supported(void);
int sockaddr_port(const struct sockaddr *_sa, unsigned *port);
+const union in_addr_union *sockaddr_in_addr(const struct sockaddr *sa);
int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret);
int getpeername_pretty(int fd, bool include_port, char **ret);
@@ -256,6 +258,19 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) {
return 0;
}
+static inline int getsockopt_int(int fd, int level, int optname, int *ret) {
+ int v;
+ socklen_t sl = sizeof(v);
+
+ if (getsockopt(fd, level, optname, &v, &sl) < 0)
+ return -errno;
+ if (sl != sizeof(v))
+ return -EIO;
+
+ *ret = v;
+ return 0;
+}
+
int socket_bind_to_ifname(int fd, const char *ifname);
int socket_bind_to_ifindex(int fd, int ifindex);
@@ -263,9 +278,26 @@ ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags);
int socket_get_family(int fd, int *ret);
int socket_set_recvpktinfo(int fd, int af, bool b);
-int socket_set_recverr(int fd, int af, bool b);
-int socket_set_recvttl(int fd, int af, bool b);
-int socket_set_ttl(int fd, int af, int ttl);
int socket_set_unicast_if(int fd, int af, int ifi);
-int socket_set_freebind(int fd, int af, bool b);
-int socket_set_transparent(int fd, int af, bool b);
+
+int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val);
+static inline int socket_set_recverr(int fd, int af, bool b) {
+ return socket_set_option(fd, af, IP_RECVERR, IPV6_RECVERR, b);
+}
+static inline int socket_set_recvttl(int fd, int af, bool b) {
+ return socket_set_option(fd, af, IP_RECVTTL, IPV6_RECVHOPLIMIT, b);
+}
+static inline int socket_set_ttl(int fd, int af, int ttl) {
+ return socket_set_option(fd, af, IP_TTL, IPV6_UNICAST_HOPS, ttl);
+}
+static inline int socket_set_freebind(int fd, int af, bool b) {
+ return socket_set_option(fd, af, IP_FREEBIND, IPV6_FREEBIND, b);
+}
+static inline int socket_set_transparent(int fd, int af, bool b) {
+ return socket_set_option(fd, af, IP_TRANSPARENT, IPV6_TRANSPARENT, b);
+}
+static inline int socket_set_recvfragsize(int fd, int af, bool b) {
+ return socket_set_option(fd, af, IP_RECVFRAGSIZE, IPV6_RECVFRAGSIZE, b);
+}
+
+int socket_get_mtu(int fd, int af, size_t *ret);
diff --git a/shared/systemd/src/basic/sort-util.h b/shared/systemd/src/basic/sort-util.h
index a8dc3bb6ed..49586a4a24 100644
--- a/shared/systemd/src/basic/sort-util.h
+++ b/shared/systemd/src/basic/sort-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdlib.h>
@@ -68,3 +68,5 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
})
+
+int cmp_int(const int *a, const int *b);
diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c
index 574815bc43..41c92e69de 100644
--- a/shared/systemd/src/basic/stat-util.c
+++ b/shared/systemd/src/basic/stat-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <fcntl.h>
@@ -408,7 +408,8 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
return a && b &&
(a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
((a->st_mode ^ b->st_mode) & S_IFMT) == 0 && /* same inode type */
- a->st_mtime == b->st_mtime &&
+ a->st_mtim.tv_sec == b->st_mtim.tv_sec &&
+ a->st_mtim.tv_nsec == b->st_mtim.tv_nsec &&
(!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
a->st_dev == b->st_dev &&
a->st_ino == b->st_ino &&
diff --git a/shared/systemd/src/basic/stat-util.h b/shared/systemd/src/basic/stat-util.h
index 26ecd635f1..a566114f7c 100644
--- a/shared/systemd/src/basic/stat-util.h
+++ b/shared/systemd/src/basic/stat-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <fcntl.h>
diff --git a/shared/systemd/src/basic/stdio-util.h b/shared/systemd/src/basic/stdio-util.h
index c3b9448d4f..6dc1e72312 100644
--- a/shared/systemd/src/basic/stdio-util.h
+++ b/shared/systemd/src/basic/stdio-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <printf.h>
diff --git a/shared/systemd/src/basic/string-table.c b/shared/systemd/src/basic/string-table.c
index 0168cff886..116021df82 100644
--- a/shared/systemd/src/basic/string-table.c
+++ b/shared/systemd/src/basic/string-table.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "string-table.h"
#include "string-util.h"
diff --git a/shared/systemd/src/basic/string-table.h b/shared/systemd/src/basic/string-table.h
index 96924778f5..ae4ea145d3 100644
--- a/shared/systemd/src/basic/string-table.h
+++ b/shared/systemd/src/basic/string-table.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
@@ -28,13 +28,12 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
scope type name##_from_string(const char *s) { \
- int b; \
if (!s) \
return -1; \
- b = parse_boolean(s); \
+ int b = parse_boolean(s); \
if (b == 0) \
return (type) 0; \
- else if (b > 0) \
+ if (b > 0) \
return yes; \
return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
}
@@ -79,11 +78,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
_DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope)
#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
+#define DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,static)
/* For string conversions where numbers are also acceptable */
#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c
index ab725d0dab..7ab460faa5 100644
--- a/shared/systemd/src/basic/string-util.c
+++ b/shared/systemd/src/basic/string-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <stdarg.h>
@@ -145,57 +145,32 @@ char *strnappend(const char *s, const char *suffix, size_t b) {
char *strjoin_real(const char *x, ...) {
va_list ap;
- size_t l;
+ size_t l = 1;
char *r, *p;
va_start(ap, x);
+ for (const char *t = x; t; t = va_arg(ap, const char *)) {
+ size_t n;
- if (x) {
- l = strlen(x);
-
- for (;;) {
- const char *t;
- size_t n;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- n = strlen(t);
- if (n > ((size_t) -1) - l) {
- va_end(ap);
- return NULL;
- }
-
- l += n;
+ n = strlen(t);
+ if (n > SIZE_MAX - l) {
+ va_end(ap);
+ return NULL;
}
- } else
- l = 0;
-
+ l += n;
+ }
va_end(ap);
- r = new(char, l+1);
+ p = r = new(char, l);
if (!r)
return NULL;
- if (x) {
- p = stpcpy(r, x);
-
- va_start(ap, x);
-
- for (;;) {
- const char *t;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- p = stpcpy(p, t);
- }
+ va_start(ap, x);
+ for (const char *t = x; t; t = va_arg(ap, const char *))
+ p = stpcpy(p, t);
+ va_end(ap);
- va_end(ap);
- } else
- r[0] = 0;
+ *p = 0;
return r;
}
diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h
index cefbda3577..fdd3ce7363 100644
--- a/shared/systemd/src/basic/string-util.h
+++ b/shared/systemd/src/basic/string-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
@@ -33,6 +33,12 @@ static inline bool streq_ptr(const char *a, const char *b) {
return strcmp_ptr(a, b) == 0;
}
+static inline char* strstr_ptr(const char *haystack, const char *needle) {
+ if (!haystack || !needle)
+ return NULL;
+ return strstr(haystack, needle);
+}
+
static inline const char* strempty(const char *s) {
return s ?: "";
}
@@ -53,6 +59,10 @@ static inline const char* true_false(bool b) {
return b ? "true" : "false";
}
+static inline const char* plus_minus(bool b) {
+ return b ? "+" : "-";
+}
+
static inline const char* one_zero(bool b) {
return b ? "1" : "0";
}
diff --git a/shared/systemd/src/basic/strv.c b/shared/systemd/src/basic/strv.c
index b2b6de388a..492dfe4002 100644
--- a/shared/systemd/src/basic/strv.c
+++ b/shared/systemd/src/basic/strv.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <fnmatch.h>
@@ -123,7 +123,6 @@ size_t strv_length(char * const *l) {
}
char **strv_new_ap(const char *x, va_list ap) {
- const char *s;
_cleanup_strv_free_ char **a = NULL;
size_t n = 0, i = 0;
va_list aq;
@@ -133,43 +132,28 @@ char **strv_new_ap(const char *x, va_list ap) {
* STRV_IFNOTNULL() macro to include possibly NULL strings in
* the string list. */
- if (x) {
- n = x == STRV_IGNORE ? 0 : 1;
-
- va_copy(aq, ap);
- while ((s = va_arg(aq, const char*))) {
- if (s == STRV_IGNORE)
- continue;
-
- n++;
- }
+ va_copy(aq, ap);
+ for (const char *s = x; s; s = va_arg(aq, const char*)) {
+ if (s == STRV_IGNORE)
+ continue;
- va_end(aq);
+ n++;
}
+ va_end(aq);
a = new(char*, n+1);
if (!a)
return NULL;
- if (x) {
- if (x != STRV_IGNORE) {
- a[i] = strdup(x);
- if (!a[i])
- return NULL;
- i++;
- }
-
- while ((s = va_arg(ap, const char*))) {
-
- if (s == STRV_IGNORE)
- continue;
+ for (const char *s = x; s; s = va_arg(ap, const char*)) {
+ if (s == STRV_IGNORE)
+ continue;
- a[i] = strdup(s);
- if (!a[i])
- return NULL;
+ a[i] = strdup(s);
+ if (!a[i])
+ return NULL;
- i++;
- }
+ i++;
}
a[i] = NULL;
@@ -537,6 +521,19 @@ int strv_consume_prepend(char ***l, char *value) {
return r;
}
+int strv_prepend(char ***l, const char *value) {
+ char *v;
+
+ if (!value)
+ return 0;
+
+ v = strdup(value);
+ if (!v)
+ return -ENOMEM;
+
+ return strv_consume_prepend(l, v);
+}
+
int strv_extend(char ***l, const char *value) {
char *v;
diff --git a/shared/systemd/src/basic/strv.h b/shared/systemd/src/basic/strv.h
index 919fabf75a..6b3e8e7f86 100644
--- a/shared/systemd/src/basic/strv.h
+++ b/shared/systemd/src/basic/strv.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <fnmatch.h>
@@ -34,6 +34,7 @@ size_t strv_length(char * const *l) _pure_;
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix);
+int strv_prepend(char ***l, const char *value);
int strv_extend(char ***l, const char *value);
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
int strv_extend_front(char ***l, const char *value);
@@ -62,7 +63,7 @@ char **strv_new_internal(const char *x, ...) _sentinel_;
char **strv_new_ap(const char *x, va_list ap);
#define strv_new(...) strv_new_internal(__VA_ARGS__, NULL)
-#define STRV_IGNORE ((const char *) -1)
+#define STRV_IGNORE ((const char *) POINTER_MAX)
static inline const char* STRV_IFNOTNULL(const char *x) {
return x ? x : STRV_IGNORE;
diff --git a/shared/systemd/src/basic/strxcpyx.c b/shared/systemd/src/basic/strxcpyx.c
index ef6d3fa324..dbbf7d08d2 100644
--- a/shared/systemd/src/basic/strxcpyx.c
+++ b/shared/systemd/src/basic/strxcpyx.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Concatenates/copies strings. In any case, terminates in all cases
diff --git a/shared/systemd/src/basic/strxcpyx.h b/shared/systemd/src/basic/strxcpyx.h
index 9b66841246..cdef492db1 100644
--- a/shared/systemd/src/basic/strxcpyx.h
+++ b/shared/systemd/src/basic/strxcpyx.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stddef.h>
diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c
index 7fa3b48623..52c564a68d 100644
--- a/shared/systemd/src/basic/time-util.c
+++ b/shared/systemd/src/basic/time-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <ctype.h>
#include <errno.h>
@@ -1606,7 +1606,7 @@ TimestampStyle timestamp_style_from_string(const char *s) {
return t;
if (streq_ptr(s, "µs"))
return TIMESTAMP_US;
- if (streq_ptr(s, "µs+uts"))
+ if (streq_ptr(s, "µs+utc"))
return TIMESTAMP_US_UTC;
return t;
}
diff --git a/shared/systemd/src/basic/time-util.h b/shared/systemd/src/basic/time-util.h
index cecd5efa60..89ee8b4a96 100644
--- a/shared/systemd/src/basic/time-util.h
+++ b/shared/systemd/src/basic/time-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
@@ -63,10 +63,10 @@ typedef enum TimestampStyle {
/* We assume a maximum timezone length of 6. TZNAME_MAX is not defined on Linux, but glibc internally initializes this
* to 6. Let's rely on that. */
-#define FORMAT_TIMESTAMP_MAX (3+1+10+1+8+1+6+1+6+1)
-#define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */
-#define FORMAT_TIMESTAMP_RELATIVE_MAX 256
-#define FORMAT_TIMESPAN_MAX 64
+#define FORMAT_TIMESTAMP_MAX (3U+1U+10U+1U+8U+1U+6U+1U+6U+1U)
+#define FORMAT_TIMESTAMP_WIDTH 28U /* when outputting, assume this width */
+#define FORMAT_TIMESTAMP_RELATIVE_MAX 256U
+#define FORMAT_TIMESPAN_MAX 64U
#define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
diff --git a/shared/systemd/src/basic/tmpfile-util.c b/shared/systemd/src/basic/tmpfile-util.c
index a49f7eee70..49c343773c 100644
--- a/shared/systemd/src/basic/tmpfile-util.c
+++ b/shared/systemd/src/basic/tmpfile-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/mman.h>
diff --git a/shared/systemd/src/basic/tmpfile-util.h b/shared/systemd/src/basic/tmpfile-util.h
index 802c85d6d9..45255fc062 100644
--- a/shared/systemd/src/basic/tmpfile-util.h
+++ b/shared/systemd/src/basic/tmpfile-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdio.h>
diff --git a/shared/systemd/src/basic/umask-util.h b/shared/systemd/src/basic/umask-util.h
index cad745170e..bd7c2bdb8c 100644
--- a/shared/systemd/src/basic/umask-util.h
+++ b/shared/systemd/src/basic/umask-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
diff --git a/shared/systemd/src/basic/user-util.h b/shared/systemd/src/basic/user-util.h
index 13e2c99e6c..20ff415e2e 100644
--- a/shared/systemd/src/basic/user-util.h
+++ b/shared/systemd/src/basic/user-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <grp.h>
diff --git a/shared/systemd/src/basic/utf8.c b/shared/systemd/src/basic/utf8.c
index f0233397ef..59663c0350 100644
--- a/shared/systemd/src/basic/utf8.c
+++ b/shared/systemd/src/basic/utf8.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/* Parts of this file are based on the GLIB utf8 validation functions. The
* original license text follows. */
diff --git a/shared/systemd/src/basic/utf8.h b/shared/systemd/src/basic/utf8.h
index f315ea0f1e..a6ea942c62 100644
--- a/shared/systemd/src/basic/utf8.h
+++ b/shared/systemd/src/basic/utf8.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
diff --git a/shared/systemd/src/basic/util.c b/shared/systemd/src/basic/util.c
index 2b3b3918a3..7c708eb3be 100644
--- a/shared/systemd/src/basic/util.c
+++ b/shared/systemd/src/basic/util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <fcntl.h>
@@ -165,7 +165,7 @@ int container_get_leader(const char *machine, pid_t *pid) {
return 0;
}
- if (!machine_name_is_valid(machine))
+ if (!hostname_is_valid(machine, 0))
return -EINVAL;
p = strjoina("/run/systemd/machines/", machine);
@@ -193,8 +193,8 @@ int container_get_leader(const char *machine, pid_t *pid) {
}
int version(void) {
- puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n"
- SYSTEMD_FEATURES);
+ printf("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n%s\n",
+ systemd_features);
return 0;
}
diff --git a/shared/systemd/src/basic/util.h b/shared/systemd/src/basic/util.h
index 6fc7480fcb..942d773ff1 100644
--- a/shared/systemd/src/basic/util.h
+++ b/shared/systemd/src/basic/util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdint.h>
diff --git a/shared/systemd/src/shared/dns-domain.c b/shared/systemd/src/shared/dns-domain.c
index 00e12e681f..cc5ad582db 100644
--- a/shared/systemd/src/shared/dns-domain.c
+++ b/shared/systemd/src/shared/dns-domain.c
@@ -1,11 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
-
-#if HAVE_LIBIDN2
-# include <idn2.h>
-#elif HAVE_LIBIDN
-# include <idna.h>
-# include <stringprep.h>
-#endif
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <endian.h>
#include <netinet/in.h>
@@ -17,6 +10,7 @@
#include "hashmap.h"
#include "hexdecoct.h"
#include "hostname-util.h"
+#include "idn-util.h"
#include "in-addr-util.h"
#include "macro.h"
#include "parse-util.h"
@@ -312,12 +306,17 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
const char *p;
bool contains_8bit = false;
char buffer[DNS_LABEL_MAX+1];
+ int r;
assert(encoded);
assert(decoded);
/* Converts an U-label into an A-label */
+ r = dlopen_idn();
+ if (r < 0)
+ return r;
+
if (encoded_size <= 0)
return -EINVAL;
@@ -332,11 +331,11 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
return 0;
}
- input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
+ input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
if (!input)
return -ENOMEM;
- if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
+ if (sym_idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
return -EINVAL;
l = strlen(buffer);
@@ -362,28 +361,33 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
_cleanup_free_ char *result = NULL;
uint32_t *output = NULL;
size_t w;
+ int r;
/* To be invoked after unescaping. Converts an A-label into an U-label. */
assert(encoded);
assert(decoded);
+ r = dlopen_idn();
+ if (r < 0)
+ return r;
+
if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX)
return -EINVAL;
if (!memory_startswith(encoded, encoded_size, IDNA_ACE_PREFIX))
return 0;
- input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
+ input = sym_stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
if (!input)
return -ENOMEM;
output_size = input_size;
output = newa(uint32_t, output_size);
- idna_to_unicode_44i(input, input_size, output, &output_size, 0);
+ sym_idna_to_unicode_44i(input, input_size, output, &output_size, 0);
- result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
+ result = sym_stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
if (!result)
return -ENOMEM;
if (w <= 0)
@@ -739,12 +743,12 @@ int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
return 0;
}
-int dns_name_address(const char *p, int *family, union in_addr_union *address) {
+int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_address) {
int r;
assert(p);
- assert(family);
- assert(address);
+ assert(ret_family);
+ assert(ret_address);
r = dns_name_endswith(p, "in-addr.arpa");
if (r < 0)
@@ -773,11 +777,11 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
if (r <= 0)
return r;
- *family = AF_INET;
- address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
- ((uint32_t) a[2] << 16) |
- ((uint32_t) a[1] << 8) |
- (uint32_t) a[0]);
+ *ret_family = AF_INET;
+ ret_address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
+ ((uint32_t) a[2] << 16) |
+ ((uint32_t) a[1] << 8) |
+ (uint32_t) a[0]);
return 1;
}
@@ -818,11 +822,14 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
if (r <= 0)
return r;
- *family = AF_INET6;
- address->in6 = a;
+ *ret_family = AF_INET6;
+ ret_address->in6 = a;
return 1;
}
+ *ret_family = AF_UNSPEC;
+ *ret_address = IN_ADDR_NULL;
+
return 0;
}
@@ -1266,47 +1273,67 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
}
int dns_name_apply_idna(const char *name, char **ret) {
+
/* Return negative on error, 0 if not implemented, positive on success. */
-#if HAVE_LIBIDN2
+#if HAVE_LIBIDN2 || HAVE_LIBIDN2
int r;
+
+ r = dlopen_idn();
+ if (r == EOPNOTSUPP) {
+ *ret = NULL;
+ return 0;
+ }
+ if (r < 0)
+ return r;
+#endif
+
+#if HAVE_LIBIDN2
_cleanup_free_ char *t = NULL;
assert(name);
assert(ret);
- r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
- IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
+ /* First, try non-transitional mode (i.e. IDN2008 rules) */
+ r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
+ IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
+ if (r == IDN2_DISALLOWED) /* If that failed, because of disallowed characters, try transitional mode.
+ * (i.e. IDN2003 rules which supports some unicode chars IDN2008 doesn't allow). */
+ r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
+ IDN2_NFC_INPUT | IDN2_TRANSITIONAL);
+
log_debug("idn2_lookup_u8: %s → %s", name, t);
if (r == IDN2_OK) {
if (!startswith(name, "xn--")) {
_cleanup_free_ char *s = NULL;
- r = idn2_to_unicode_8z8z(t, &s, 0);
+ r = sym_idn2_to_unicode_8z8z(t, &s, 0);
if (r != IDN2_OK) {
log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
- t, r, idn2_strerror(r));
+ t, r, sym_idn2_strerror(r));
+ *ret = NULL;
return 0;
}
if (!streq_ptr(name, s)) {
log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.",
name, t, s);
+ *ret = NULL;
return 0;
}
}
*ret = TAKE_PTR(t);
-
return 1; /* *ret has been written */
}
- log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r));
+ log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, sym_idn2_strerror(r));
if (r == IDN2_2HYPHEN)
/* The name has two hyphens — forbidden by IDNA2008 in some cases */
return 0;
if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL))
return -ENOSPC;
+
return -EINVAL;
#elif HAVE_LIBIDN
_cleanup_free_ char *buf = NULL;
@@ -1358,6 +1385,7 @@ int dns_name_apply_idna(const char *name, char **ret) {
return 1;
#else
+ *ret = NULL;
return 0;
#endif
}
diff --git a/shared/systemd/src/shared/dns-domain.h b/shared/systemd/src/shared/dns-domain.h
index 60de7af227..77f596294d 100644
--- a/shared/systemd/src/shared/dns-domain.h
+++ b/shared/systemd/src/shared/dns-domain.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <errno.h>
diff --git a/shared/systemd/src/shared/log-link.h b/shared/systemd/src/shared/log-link.h
new file mode 100644
index 0000000000..3a4dcaa267
--- /dev/null
+++ b/shared/systemd/src/shared/log-link.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "log.h"
+
+#define log_interface_full_errno(ifname, level, error, ...) \
+ ({ \
+ const char *_ifname = (ifname); \
+ _ifname ? log_object_internal(level, error, PROJECT_FILE, __LINE__, __func__, "INTERFACE=", _ifname, NULL, NULL, ##__VA_ARGS__) : \
+ log_internal(level, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \
+ })
+
+/*
+ * The following macros append INTERFACE= to the message.
+ * The macros require a struct named 'Link' which contains 'char *ifname':
+ *
+ * typedef struct Link {
+ * char *ifname;
+ * } Link;
+ *
+ * See, network/networkd-link.h for example.
+ */
+
+#define log_link_full_errno(link, level, error, ...) \
+ ({ \
+ const Link *_l = (link); \
+ log_interface_full_errno(_l ? _l->ifname : NULL, level, error, ##__VA_ARGS__); \
+ })
+
+#define log_link_full(link, level, ...) (void) log_link_full_errno(link, level, 0, __VA_ARGS__)
+
+#define log_link_debug(link, ...) log_link_full_errno(link, LOG_DEBUG, 0, __VA_ARGS__)
+#define log_link_info(link, ...) log_link_full(link, LOG_INFO, __VA_ARGS__)
+#define log_link_notice(link, ...) log_link_full(link, LOG_NOTICE, __VA_ARGS__)
+#define log_link_warning(link, ...) log_link_full(link, LOG_WARNING, __VA_ARGS__)
+#define log_link_error(link, ...) log_link_full(link, LOG_ERR, __VA_ARGS__)
+
+#define log_link_debug_errno(link, error, ...) log_link_full_errno(link, LOG_DEBUG, error, __VA_ARGS__)
+#define log_link_info_errno(link, error, ...) log_link_full_errno(link, LOG_INFO, error, __VA_ARGS__)
+#define log_link_notice_errno(link, error, ...) log_link_full_errno(link, LOG_NOTICE, error, __VA_ARGS__)
+#define log_link_warning_errno(link, error, ...) log_link_full_errno(link, LOG_WARNING, error, __VA_ARGS__)
+#define log_link_error_errno(link, error, ...) log_link_full_errno(link, LOG_ERR, error, __VA_ARGS__)
+
+#define LOG_LINK_MESSAGE(link, fmt, ...) "MESSAGE=%s: " fmt, (link)->ifname, ##__VA_ARGS__
+#define LOG_LINK_INTERFACE(link) "INTERFACE=%s", (link)->ifname
diff --git a/shared/systemd/src/shared/web-util.c b/shared/systemd/src/shared/web-util.c
index edf650d200..82cd5fbd6b 100644
--- a/shared/systemd/src/shared/web-util.c
+++ b/shared/systemd/src/shared/web-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdbool.h>
diff --git a/shared/systemd/src/shared/web-util.h b/shared/systemd/src/shared/web-util.h
index c9e67e5c0a..ec54669f50 100644
--- a/shared/systemd/src/shared/web-util.h
+++ b/shared/systemd/src/shared/web-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
diff --git a/src/systemd/src/libsystemd-network/arp-util.c b/src/systemd/src/libsystemd-network/arp-util.c
index 4fbf2bbc96..327fb2ff3e 100644
--- a/src/systemd/src/libsystemd-network/arp-util.c
+++ b/src/systemd/src/libsystemd-network/arp-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2014 Axis Communications AB. All rights reserved.
***/
diff --git a/src/systemd/src/libsystemd-network/arp-util.h b/src/systemd/src/libsystemd-network/arp-util.h
index 9a4427e831..2dac8cfbaa 100644
--- a/src/systemd/src/libsystemd-network/arp-util.h
+++ b/src/systemd/src/libsystemd-network/arp-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/***
diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c
index d0610a32e2..953fef19fa 100644
--- a/src/systemd/src/libsystemd-network/dhcp-identifier.c
+++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c
@@ -1,6 +1,7 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/if_infiniband.h>
+#include <net/ethernet.h>
#include <net/if_arp.h>
#include "sd-device.h"
@@ -8,7 +9,7 @@
#include "dhcp-identifier.h"
#include "dhcp6-protocol.h"
-#include "network-internal.h"
+#include "network-util.h"
#include "siphash24.h"
#include "sparse-endian.h"
#include "stdio-util.h"
@@ -26,11 +27,10 @@ int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict) {
if (duid_len > MAX_DUID_LEN)
return -EINVAL;
- if (!strict) {
+ if (!strict)
/* Strict validation is not requested. We only ensure that the
* DUID is not too long. */
return 0;
- }
switch (duid_type) {
case DUID_TYPE_LLT:
diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.h b/src/systemd/src/libsystemd-network/dhcp-identifier.h
index 76abd6583e..e9f2ea7e95 100644
--- a/src/systemd/src/libsystemd-network/dhcp-identifier.h
+++ b/src/systemd/src/libsystemd-network/dhcp-identifier.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-id128.h"
diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h
index 7e8149487a..40e6b1f26f 100644
--- a/src/systemd/src/libsystemd-network/dhcp-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp-internal.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/***
@@ -29,10 +29,10 @@ typedef struct DHCPServerData {
extern const struct hash_ops dhcp_option_hash_ops;
-int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
- uint32_t xid, const uint8_t *mac_addr,
- size_t mac_addr_len, uint16_t arp_type,
- uint16_t port);
+int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
+ const uint8_t *mac_addr, size_t mac_addr_len,
+ const uint8_t *bcast_addr, size_t bcast_addr_len,
+ uint16_t arp_type, uint16_t port);
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
const void *packet, size_t len);
diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
index 66222eaddb..49392d1bea 100644
--- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/***
diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c
index f48e7c3490..656482bf83 100644
--- a/src/systemd/src/libsystemd-network/dhcp-network.c
+++ b/src/systemd/src/libsystemd-network/dhcp-network.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2013 Intel Corporation. All rights reserved.
***/
@@ -19,9 +19,9 @@
#include "unaligned.h"
static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
- uint32_t xid, const uint8_t *mac_addr,
- size_t mac_addr_len,
+ uint32_t xid,
const uint8_t *bcast_addr,
+ size_t bcast_addr_len,
const struct ether_addr *eth_mac,
uint16_t arp_type, uint8_t dhcp_hlen,
uint16_t port) {
@@ -104,9 +104,9 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
.sll_protocol = htobe16(ETH_P_IP),
.sll_ifindex = ifindex,
.sll_hatype = htobe16(arp_type),
- .sll_halen = mac_addr_len,
+ .sll_halen = bcast_addr_len,
};
- memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
+ memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len); /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */
r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
if (r < 0)
@@ -115,34 +115,44 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
return TAKE_FD(s);
}
-int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
- uint32_t xid, const uint8_t *mac_addr,
- size_t mac_addr_len, uint16_t arp_type,
- uint16_t port) {
+int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid,
+ const uint8_t *mac_addr, size_t mac_addr_len,
+ const uint8_t *bcast_addr, size_t bcast_addr_len,
+ uint16_t arp_type, uint16_t port) {
static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
/* Default broadcast address for IPoIB */
static const uint8_t ib_bcast[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff
- };
+ };
struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } };
- const uint8_t *bcast_addr = NULL;
+ const uint8_t *default_bcast_addr;
+ size_t expected_bcast_addr_len;
uint8_t dhcp_hlen = 0;
if (arp_type == ARPHRD_ETHER) {
assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
memcpy(&eth_mac, mac_addr, ETH_ALEN);
- bcast_addr = eth_bcast;
dhcp_hlen = ETH_ALEN;
+
+ default_bcast_addr = eth_bcast;
+ expected_bcast_addr_len = ETH_ALEN;
} else if (arp_type == ARPHRD_INFINIBAND) {
- assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL);
- bcast_addr = ib_bcast;
+ default_bcast_addr = ib_bcast;
+ expected_bcast_addr_len = INFINIBAND_ALEN;
} else
return -EINVAL;
- return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len,
- bcast_addr, &eth_mac, arp_type, dhcp_hlen, port);
+ if (bcast_addr && bcast_addr_len > 0)
+ assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL);
+ else {
+ bcast_addr = default_bcast_addr;
+ bcast_addr_len = expected_bcast_addr_len;
+ }
+
+ return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len,
+ &eth_mac, arp_type, dhcp_hlen, port);
}
int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c
index 6fe8a3779d..70753c68d8 100644
--- a/src/systemd/src/libsystemd-network/dhcp-option.c
+++ b/src/systemd/src/libsystemd-network/dhcp-option.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2013 Intel Corporation. All rights reserved.
***/
diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c
index fe7d51703b..cace916f44 100644
--- a/src/systemd/src/libsystemd-network/dhcp-packet.c
+++ b/src/systemd/src/libsystemd-network/dhcp-packet.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2013 Intel Corporation. All rights reserved.
***/
diff --git a/src/systemd/src/libsystemd-network/dhcp-protocol.h b/src/systemd/src/libsystemd-network/dhcp-protocol.h
index f03663248a..11f4201ab2 100644
--- a/src/systemd/src/libsystemd-network/dhcp-protocol.h
+++ b/src/systemd/src/libsystemd-network/dhcp-protocol.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/***
diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h
index 9ce6dcd02c..24d8a314a4 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/***
diff --git a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h
index df6c95e0b3..e9e2362d6f 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/***
diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c
index e2efa8bbe3..4f7bd53de4 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-network.c
+++ b/src/systemd/src/libsystemd-network/dhcp6-network.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2014 Intel Corporation. All rights reserved.
***/
diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c
index 030173a58a..e2bf4f7e36 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-option.c
+++ b/src/systemd/src/libsystemd-network/dhcp6-option.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2014-2015 Intel Corporation. All rights reserved.
***/
diff --git a/src/systemd/src/libsystemd-network/dhcp6-protocol.h b/src/systemd/src/libsystemd-network/dhcp6-protocol.h
index f7a2702860..c700363803 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/systemd/src/libsystemd-network/dhcp6-protocol.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/***
diff --git a/src/systemd/src/libsystemd-network/lldp-internal.h b/src/systemd/src/libsystemd-network/lldp-internal.h
index 9598438dba..f23695f974 100644
--- a/src/systemd/src/libsystemd-network/lldp-internal.h
+++ b/src/systemd/src/libsystemd-network/lldp-internal.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-event.h"
diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c
index 02645b2bcd..546ae1c980 100644
--- a/src/systemd/src/libsystemd-network/lldp-neighbor.c
+++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "escape.h"
diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.h b/src/systemd/src/libsystemd-network/lldp-neighbor.h
index 74175edf54..a5718c8c31 100644
--- a/src/systemd/src/libsystemd-network/lldp-neighbor.h
+++ b/src/systemd/src/libsystemd-network/lldp-neighbor.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c
index de7e2bf847..9616cb6250 100644
--- a/src/systemd/src/libsystemd-network/lldp-network.c
+++ b/src/systemd/src/libsystemd-network/lldp-network.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/filter.h>
#include <netinet/if_ether.h>
diff --git a/src/systemd/src/libsystemd-network/lldp-network.h b/src/systemd/src/libsystemd-network/lldp-network.h
index e4ed2898a5..bc69b324c2 100644
--- a/src/systemd/src/libsystemd-network/lldp-network.h
+++ b/src/systemd/src/libsystemd-network/lldp-network.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-event.h"
diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c
index 459d13ad7d..12b73cd50d 100644
--- a/src/systemd/src/libsystemd-network/network-internal.c
+++ b/src/systemd/src/libsystemd-network/network-internal.c
@@ -1,661 +1,18 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <arpa/inet.h>
#include <linux/if.h>
#include <netinet/ether.h>
-#include "sd-id128.h"
#include "sd-ndisc.h"
#include "alloc-util.h"
-#include "arphrd-list.h"
-#include "condition.h"
-#include "conf-parser.h"
-#include "device-util.h"
#include "dhcp-lease-internal.h"
-#include "env-util.h"
-#include "ether-addr-util.h"
+#include "extract-word.h"
#include "hexdecoct.h"
#include "log.h"
#include "network-internal.h"
#include "parse-util.h"
-#include "siphash24.h"
-#include "socket-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "utf8.h"
-#include "util.h"
-
-const char *net_get_name_persistent(sd_device *device) {
- const char *name, *field;
-
- assert(device);
-
- /* fetch some persistent data unique (on this machine) to this device */
- FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC")
- if (sd_device_get_property_value(device, field, &name) >= 0)
- return name;
-
- return NULL;
-}
-
-#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
-
-int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) {
- size_t l, sz = 0;
- const char *name;
- int r;
- uint8_t *v;
-
- assert(device);
-
- /* net_get_name_persistent() will return one of the device names based on stable information about
- * the device. If this is not available, we fall back to using the actual device name. */
- name = net_get_name_persistent(device);
- if (!name && use_sysname)
- (void) sd_device_get_sysname(device, &name);
- if (!name)
- return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA),
- "No stable identifying information found");
-
- log_device_debug(device, "Using \"%s\" as stable identifying information", name);
- l = strlen(name);
- sz = sizeof(sd_id128_t) + l;
- v = newa(uint8_t, sz);
-
- /* Fetch some persistent data unique to this machine */
- r = sd_id128_get_machine((sd_id128_t*) v);
- if (r < 0)
- return r;
- memcpy(v + sizeof(sd_id128_t), name, l);
-
- /* Let's hash the machine ID plus the device name. We use
- * a fixed, but originally randomly created hash key here. */
- *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
- return 0;
-}
-
-static bool net_condition_test_strv(char * const *patterns, const char *string) {
- char * const *p;
- bool match = false, has_positive_rule = false;
-
- if (strv_isempty(patterns))
- return true;
-
- STRV_FOREACH(p, patterns) {
- const char *q = *p;
- bool invert;
-
- invert = *q == '!';
- q += invert;
-
- if (!invert)
- has_positive_rule = true;
-
- if (string && fnmatch(q, string, 0) == 0) {
- if (invert)
- return false;
- else
- match = true;
- }
- }
-
- return has_positive_rule ? match : true;
-}
-
-static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) {
- if (net_condition_test_strv(patterns, ifname))
- return true;
-
- char * const *p;
- STRV_FOREACH(p, alternative_names)
- if (net_condition_test_strv(patterns, *p))
- return true;
-
- return false;
-}
-
-static int net_condition_test_property(char * const *match_property, sd_device *device) {
- char * const *p;
-
- if (strv_isempty(match_property))
- return true;
-
- STRV_FOREACH(p, match_property) {
- _cleanup_free_ char *key = NULL;
- const char *val, *dev_val;
- bool invert, v;
-
- invert = **p == '!';
-
- val = strchr(*p + invert, '=');
- if (!val)
- return -EINVAL;
-
- key = strndup(*p + invert, val - *p - invert);
- if (!key)
- return -ENOMEM;
-
- val++;
-
- v = device &&
- sd_device_get_property_value(device, key, &dev_val) >= 0 &&
- fnmatch(val, dev_val, 0) == 0;
-
- if (invert ? v : !v)
- return false;
- }
-
- return true;
-}
-
-static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = {
- [NL80211_IFTYPE_ADHOC] = "ad-hoc",
- [NL80211_IFTYPE_STATION] = "station",
- [NL80211_IFTYPE_AP] = "ap",
- [NL80211_IFTYPE_AP_VLAN] = "ap-vlan",
- [NL80211_IFTYPE_WDS] = "wds",
- [NL80211_IFTYPE_MONITOR] = "monitor",
- [NL80211_IFTYPE_MESH_POINT] = "mesh-point",
- [NL80211_IFTYPE_P2P_CLIENT] = "p2p-client",
- [NL80211_IFTYPE_P2P_GO] = "p2p-go",
- [NL80211_IFTYPE_P2P_DEVICE] = "p2p-device",
- [NL80211_IFTYPE_OCB] = "ocb",
- [NL80211_IFTYPE_NAN] = "nan",
-};
-
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype);
-
-char *link_get_type_string(unsigned short iftype, sd_device *device) {
- const char *t, *devtype;
- char *p;
-
- if (device &&
- sd_device_get_devtype(device, &devtype) >= 0 &&
- !isempty(devtype))
- return strdup(devtype);
-
- t = arphrd_to_name(iftype);
- if (!t)
- return NULL;
-
- p = strdup(t);
- if (!p)
- return NULL;
-
- ascii_strlower(p);
- return p;
-}
-
-bool net_match_config(Set *match_mac,
- Set *match_permanent_mac,
- char * const *match_paths,
- char * const *match_drivers,
- char * const *match_iftypes,
- char * const *match_names,
- char * const *match_property,
- char * const *match_wifi_iftype,
- char * const *match_ssid,
- Set *match_bssid,
- sd_device *device,
- const struct ether_addr *dev_mac,
- const struct ether_addr *dev_permanent_mac,
- const char *dev_driver,
- unsigned short dev_iftype,
- const char *dev_name,
- char * const *alternative_names,
- enum nl80211_iftype dev_wifi_iftype,
- const char *dev_ssid,
- const struct ether_addr *dev_bssid) {
-
- _cleanup_free_ char *dev_iftype_str;
- const char *dev_path = NULL;
-
- dev_iftype_str = link_get_type_string(dev_iftype, device);
-
- if (device) {
- const char *mac_str;
-
- (void) sd_device_get_property_value(device, "ID_PATH", &dev_path);
- if (!dev_driver)
- (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver);
- if (!dev_name)
- (void) sd_device_get_sysname(device, &dev_name);
- if (!dev_mac &&
- sd_device_get_sysattr_value(device, "address", &mac_str) >= 0)
- dev_mac = ether_aton(mac_str);
- }
-
- if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
- return false;
-
- if (match_permanent_mac &&
- (!dev_permanent_mac ||
- ether_addr_is_null(dev_permanent_mac) ||
- !set_contains(match_permanent_mac, dev_permanent_mac)))
- return false;
-
- if (!net_condition_test_strv(match_paths, dev_path))
- return false;
-
- if (!net_condition_test_strv(match_drivers, dev_driver))
- return false;
-
- if (!net_condition_test_strv(match_iftypes, dev_iftype_str))
- return false;
-
- if (!net_condition_test_ifname(match_names, dev_name, alternative_names))
- return false;
-
- if (!net_condition_test_property(match_property, device))
- return false;
-
- if (!net_condition_test_strv(match_wifi_iftype, wifi_iftype_to_string(dev_wifi_iftype)))
- return false;
-
- if (!net_condition_test_strv(match_ssid, dev_ssid))
- return false;
-
- if (match_bssid && (!dev_bssid || !set_contains(match_bssid, dev_bssid)))
- return false;
-
- return true;
-}
-
-int config_parse_net_condition(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ConditionType cond = ltype;
- Condition **list = data, *c;
- bool negate;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- *list = condition_free_list_type(*list, cond);
- return 0;
- }
-
- negate = rvalue[0] == '!';
- if (negate)
- rvalue++;
-
- c = condition_new(cond, rvalue, false, negate);
- if (!c)
- return log_oom();
-
- /* Drop previous assignment. */
- *list = condition_free_list_type(*list, cond);
-
- LIST_PREPEND(conditions, *list, c);
- return 0;
-}
-
-int config_parse_match_strv(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- const char *p = rvalue;
- char ***sv = data;
- bool invert;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- *sv = strv_free(*sv);
- return 0;
- }
-
- invert = *p == '!';
- p += invert;
-
- for (;;) {
- _cleanup_free_ char *word = NULL, *k = NULL;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
- if (r == 0)
- return 0;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
- return 0;
- }
-
- if (invert) {
- k = strjoin("!", word);
- if (!k)
- return log_oom();
- } else
- k = TAKE_PTR(word);
-
- r = strv_consume(sv, TAKE_PTR(k));
- if (r < 0)
- return log_oom();
- }
-}
-
-int config_parse_match_ifnames(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- const char *p = rvalue;
- char ***sv = data;
- bool invert;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- invert = *p == '!';
- p += invert;
-
- for (;;) {
- _cleanup_free_ char *word = NULL, *k = NULL;
-
- r = extract_first_word(&p, &word, NULL, 0);
- if (r == 0)
- return 0;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Failed to parse interface name list: %s", rvalue);
- return 0;
- }
-
- if (!ifname_valid_full(word, ltype)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Interface name is not valid or too long, ignoring assignment: %s", word);
- continue;
- }
-
- if (invert) {
- k = strjoin("!", word);
- if (!k)
- return log_oom();
- } else
- k = TAKE_PTR(word);
-
- r = strv_consume(sv, TAKE_PTR(k));
- if (r < 0)
- return log_oom();
- }
-}
-
-int config_parse_match_property(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- const char *p = rvalue;
- char ***sv = data;
- bool invert;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- invert = *p == '!';
- p += invert;
-
- for (;;) {
- _cleanup_free_ char *word = NULL, *k = NULL;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
- if (r == 0)
- return 0;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Invalid syntax, ignoring: %s", rvalue);
- return 0;
- }
-
- if (!env_assignment_is_valid(word)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Invalid property or value, ignoring assignment: %s", word);
- continue;
- }
-
- if (invert) {
- k = strjoin("!", word);
- if (!k)
- return log_oom();
- } else
- k = TAKE_PTR(word);
-
- r = strv_consume(sv, TAKE_PTR(k));
- if (r < 0)
- return log_oom();
- }
-}
-
-int config_parse_ifalias(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- char **s = data;
- _cleanup_free_ char *n = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- n = strdup(rvalue);
- if (!n)
- return log_oom();
-
- if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
- return 0;
- }
-
- if (isempty(n))
- *s = mfree(*s);
- else
- free_and_replace(*s, n);
-
- return 0;
-}
-
-int config_parse_hwaddr(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- _cleanup_free_ struct ether_addr *n = NULL;
- struct ether_addr **hwaddr = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- n = new0(struct ether_addr, 1);
- if (!n)
- return log_oom();
-
- r = ether_addr_from_string(rvalue, n);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue);
- return 0;
- }
-
- free_and_replace(*hwaddr, n);
-
- return 0;
-}
-
-int config_parse_hwaddrs(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- _cleanup_set_free_free_ Set *s = NULL;
- const char *p = rvalue;
- Set **hwaddrs = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- *hwaddrs = set_free_free(*hwaddrs);
- return 0;
- }
-
- s = set_new(&ether_addr_hash_ops);
- if (!s)
- return log_oom();
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
- _cleanup_free_ struct ether_addr *n = NULL;
-
- r = extract_first_word(&p, &word, NULL, 0);
- if (r == 0)
- break;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
- return 0;
- }
-
- n = new(struct ether_addr, 1);
- if (!n)
- return log_oom();
-
- r = ether_addr_from_string(word, n);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring: %s", word);
- continue;
- }
-
- r = set_put(s, n);
- if (r < 0)
- return log_oom();
- if (r > 0)
- n = NULL; /* avoid cleanup */
- }
-
- r = set_ensure_allocated(hwaddrs, &ether_addr_hash_ops);
- if (r < 0)
- return log_oom();
-
- r = set_move(*hwaddrs, s);
- if (r < 0)
- return log_oom();
-
- return 0;
-}
-
-int config_parse_bridge_port_priority(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- uint16_t i;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = safe_atou16(rvalue, &i);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse bridge port priority, ignoring: %s", rvalue);
- return 0;
- }
-
- if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue);
- return 0;
- }
-
- *((uint16_t *)data) = i;
-
- return 0;
-}
size_t serialize_in_addrs(FILE *f,
const struct in_addr *addresses,
diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h
index e4c11235b6..e5b853c0cd 100644
--- a/src/systemd/src/libsystemd-network/network-internal.h
+++ b/src/systemd/src/libsystemd-network/network-internal.h
@@ -1,53 +1,11 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
-#include <linux/nl80211.h>
#include <stdbool.h>
+#include <stdio.h>
-#include "sd-device.h"
#include "sd-dhcp-lease.h"
-#include "conf-parser.h"
-#include "set.h"
-#include "strv.h"
-
-#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128
-#define LINK_BRIDGE_PORT_PRIORITY_MAX 63
-
-char *link_get_type_string(unsigned short iftype, sd_device *device);
-bool net_match_config(Set *match_mac,
- Set *match_permanent_mac,
- char * const *match_paths,
- char * const *match_drivers,
- char * const *match_iftypes,
- char * const *match_names,
- char * const *match_property,
- char * const *match_wifi_iftype,
- char * const *match_ssid,
- Set *match_bssid,
- sd_device *device,
- const struct ether_addr *dev_mac,
- const struct ether_addr *dev_permanent_mac,
- const char *dev_driver,
- unsigned short dev_iftype,
- const char *dev_name,
- char * const *alternative_names,
- enum nl80211_iftype dev_wifi_iftype,
- const char *dev_ssid,
- const struct ether_addr *dev_bssid);
-
-CONFIG_PARSER_PROTOTYPE(config_parse_net_condition);
-CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr);
-CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs);
-CONFIG_PARSER_PROTOTYPE(config_parse_match_strv);
-CONFIG_PARSER_PROTOTYPE(config_parse_match_ifnames);
-CONFIG_PARSER_PROTOTYPE(config_parse_match_property);
-CONFIG_PARSER_PROTOTYPE(config_parse_ifalias);
-CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority);
-
-int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result);
-const char *net_get_name_persistent(sd_device *device);
-
size_t serialize_in_addrs(FILE *f,
const struct in_addr *addresses,
size_t size,
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
index 265b6eab44..939dbac5bb 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2013 Intel Corporation. All rights reserved.
***/
@@ -14,19 +14,22 @@
#include "sd-dhcp-client.h"
#include "alloc-util.h"
-#include "async.h"
#include "dhcp-identifier.h"
#include "dhcp-internal.h"
#include "dhcp-lease-internal.h"
#include "dhcp-protocol.h"
#include "dns-domain.h"
#include "event-util.h"
+#include "fd-util.h"
#include "hostname-util.h"
#include "io-util.h"
#include "memory-util.h"
#include "random-util.h"
+#include "set.h"
+#include "sort-util.h"
#include "string-util.h"
#include "strv.h"
+#include "time-util.h"
#include "utf8.h"
#include "web-util.h"
@@ -36,6 +39,9 @@
#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
+#define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report
+ * transient failure. */
+
typedef struct sd_dhcp_client_id {
uint8_t type;
union {
@@ -75,13 +81,13 @@ struct sd_dhcp_client {
union sockaddr_union link;
sd_event_source *receive_message;
bool request_broadcast;
- uint8_t *req_opts;
- size_t req_opts_allocated;
- size_t req_opts_size;
+ Set *req_opts;
bool anonymize;
be32_t last_addr;
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
size_t mac_addr_len;
+ uint8_t bcast_addr[MAX_MAC_ADDR_LEN];
+ size_t bcast_addr_len;
uint16_t arp_type;
sd_dhcp_client_id client_id;
size_t client_id_len;
@@ -93,6 +99,9 @@ struct sd_dhcp_client {
uint32_t fallback_lease_lifetime;
uint32_t xid;
usec_t start_time;
+ usec_t t1_time;
+ usec_t t2_time;
+ usec_t expire_time;
uint64_t attempt;
uint64_t max_attempts;
OrderedHashmap *extra_options;
@@ -230,8 +239,6 @@ int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast)
}
int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
- size_t i;
-
assert_return(client, -EINVAL);
assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
@@ -248,17 +255,7 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
break;
}
- for (i = 0; i < client->req_opts_size; i++)
- if (client->req_opts[i] == option)
- return -EEXIST;
-
- if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated,
- client->req_opts_size + 1))
- return -ENOMEM;
-
- client->req_opts[client->req_opts_size++] = option;
-
- return 0;
+ return set_ensure_put(&client->req_opts, NULL, UINT8_TO_PTR(option));
}
int sd_dhcp_client_set_request_address(
@@ -289,6 +286,7 @@ int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
int sd_dhcp_client_set_mac(
sd_dhcp_client *client,
const uint8_t *addr,
+ const uint8_t *bcast_addr,
size_t addr_len,
uint16_t arp_type) {
@@ -309,7 +307,9 @@ int sd_dhcp_client_set_mac(
return -EINVAL;
if (client->mac_addr_len == addr_len &&
- memcmp(&client->mac_addr, addr, addr_len) == 0)
+ memcmp(&client->mac_addr, addr, addr_len) == 0 &&
+ (client->bcast_addr_len > 0) == !!bcast_addr &&
+ (!bcast_addr || memcmp(&client->bcast_addr, bcast_addr, addr_len) == 0))
return 0;
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
@@ -321,6 +321,12 @@ int sd_dhcp_client_set_mac(
memcpy(&client->mac_addr, addr, addr_len);
client->mac_addr_len = addr_len;
client->arp_type = arp_type;
+ client->bcast_addr_len = 0;
+
+ if (bcast_addr) {
+ memcpy(&client->bcast_addr, bcast_addr, addr_len);
+ client->bcast_addr_len = addr_len;
+ }
if (need_restart && client->state != DHCP_STATE_STOPPED) {
r = sd_dhcp_client_start(client);
@@ -538,7 +544,7 @@ int sd_dhcp_client_set_hostname(
/* Make sure hostnames qualify as DNS and as Linux hostnames */
if (hostname &&
- !(hostname_is_valid(hostname, false) && dns_name_is_valid(hostname) > 0))
+ !(hostname_is_valid(hostname, 0) && dns_name_is_valid(hostname) > 0))
return -EINVAL;
return free_and_strdup(&client->hostname, hostname);
@@ -693,7 +699,7 @@ static int client_initialize(sd_dhcp_client *client) {
client->receive_message = sd_event_source_unref(client->receive_message);
- client->fd = asynchronous_close(client->fd);
+ client->fd = safe_close(client->fd);
(void) event_source_disable(client->timeout_resend);
(void) event_source_disable(client->timeout_t1);
@@ -725,6 +731,41 @@ static void client_stop(sd_dhcp_client *client, int error) {
client_initialize(client);
}
+/* RFC2131 section 4.1:
+ * retransmission delays should include -1 to +1 sec of random 'fuzz'. */
+#define RFC2131_RANDOM_FUZZ \
+ ((int64_t)(random_u64() % (2 * USEC_PER_SEC)) - (int64_t)USEC_PER_SEC)
+
+/* RFC2131 section 4.1:
+ * for retransmission delays, timeout should start at 4s then double
+ * each attempt with max of 64s, with -1 to +1 sec of random 'fuzz' added.
+ * This assumes the first call will be using attempt 1. */
+static usec_t client_compute_request_timeout(usec_t now, uint64_t attempt) {
+ usec_t timeout = (UINT64_C(1) << MIN(attempt + 1, UINT64_C(6))) * USEC_PER_SEC;
+
+ return usec_sub_signed(usec_add(now, timeout), RFC2131_RANDOM_FUZZ);
+}
+
+/* RFC2131 section 4.4.5:
+ * T1 defaults to (0.5 * duration_of_lease).
+ * T2 defaults to (0.875 * duration_of_lease). */
+#define T1_DEFAULT(lifetime) ((lifetime) / 2)
+#define T2_DEFAULT(lifetime) (((lifetime) * 7) / 8)
+
+/* RFC2131 section 4.4.5:
+ * the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state)
+ * and one-half of the remaining lease time (in REBINDING state), down to a minimum
+ * of 60 seconds.
+ * Note that while the default T1/T2 initial times do have random 'fuzz' applied,
+ * the RFC sec 4.4.5 does not mention adding any fuzz to retries. */
+static usec_t client_compute_reacquisition_timeout(usec_t now, usec_t expire) {
+ return now + MAX(usec_sub_unsigned(expire, now) / 2, 60 * USEC_PER_SEC);
+}
+
+static int cmp_uint8(const uint8_t *a, const uint8_t *b) {
+ return CMP(*a, *b);
+}
+
static int client_message_init(
sd_dhcp_client *client,
DHCPPacket **ret,
@@ -835,10 +876,26 @@ static int client_message_init(
MAY contain the Parameter Request List option. */
/* NOTE: in case that there would be an option to do not send
* any PRL at all, the size should be checked before sending */
- if (client->req_opts_size > 0 && type != DHCP_RELEASE) {
+ if (!set_isempty(client->req_opts) && type != DHCP_RELEASE) {
+ _cleanup_free_ uint8_t *opts = NULL;
+ size_t n_opts, i = 0;
+ void *val;
+
+ n_opts = set_size(client->req_opts);
+ opts = new(uint8_t, n_opts);
+ if (!opts)
+ return -ENOMEM;
+
+ SET_FOREACH(val, client->req_opts)
+ opts[i++] = PTR_TO_UINT8(val);
+ assert(i == n_opts);
+
+ /* For anonymizing the request, let's sort the options. */
+ typesafe_qsort(opts, n_opts, cmp_uint8);
+
r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
- client->req_opts_size, client->req_opts);
+ n_opts, opts);
if (r < 0)
return r;
}
@@ -1168,9 +1225,8 @@ static int client_timeout_resend(
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
- usec_t next_timeout = 0;
+ usec_t next_timeout;
uint64_t time_now;
- uint32_t time_left;
int r;
assert(s);
@@ -1184,22 +1240,11 @@ static int client_timeout_resend(
switch (client->state) {
case DHCP_STATE_RENEWING:
-
- time_left = (client->lease->t2 - client->lease->t1) / 2;
- if (time_left < 60)
- time_left = 60;
-
- next_timeout = time_now + time_left * USEC_PER_SEC;
-
+ next_timeout = client_compute_reacquisition_timeout(time_now, client->t2_time);
break;
case DHCP_STATE_REBINDING:
-
- time_left = (client->lease->lifetime - client->lease->t2) / 2;
- if (time_left < 60)
- time_left = 60;
-
- next_timeout = time_now + time_left * USEC_PER_SEC;
+ next_timeout = client_compute_reacquisition_timeout(time_now, client->expire_time);
break;
case DHCP_STATE_REBOOTING:
@@ -1211,24 +1256,20 @@ static int client_timeout_resend(
r = client_start(client);
if (r < 0)
goto error;
- else {
- log_dhcp_client(client, "REBOOTED");
- return 0;
- }
+
+ log_dhcp_client(client, "REBOOTED");
+ return 0;
case DHCP_STATE_INIT:
case DHCP_STATE_INIT_REBOOT:
case DHCP_STATE_SELECTING:
case DHCP_STATE_REQUESTING:
case DHCP_STATE_BOUND:
-
- if (client->attempt < client->max_attempts)
- client->attempt++;
- else
+ if (client->attempt >= client->max_attempts)
goto error;
- next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
-
+ client->attempt++;
+ next_timeout = client_compute_request_timeout(time_now, client->attempt);
break;
case DHCP_STATE_STOPPED:
@@ -1236,8 +1277,6 @@ static int client_timeout_resend(
goto error;
}
- next_timeout += (random_u32() & 0x1fffff);
-
r = event_reset_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
next_timeout, 10 * USEC_PER_MSEC,
@@ -1276,12 +1315,10 @@ static int client_timeout_resend(
client->state = DHCP_STATE_REBOOTING;
client->request_sent = time_now;
-
break;
case DHCP_STATE_REBOOTING:
case DHCP_STATE_BOUND:
-
break;
case DHCP_STATE_STOPPED:
@@ -1289,6 +1326,9 @@ static int client_timeout_resend(
goto error;
}
+ if (client->attempt >= TRANSIENT_FAILURE_ATTEMPTS)
+ client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE);
+
return 0;
error:
@@ -1373,9 +1413,10 @@ static int client_start_delayed(sd_dhcp_client *client) {
client->xid = random_u32();
- r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
- client->xid, client->mac_addr,
- client->mac_addr_len, client->arp_type, client->port);
+ r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
+ client->mac_addr, client->mac_addr_len,
+ client->bcast_addr, client->bcast_addr_len,
+ client->arp_type, client->port);
if (r < 0) {
client_stop(client, r);
return r;
@@ -1418,15 +1459,15 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
assert(client);
client->receive_message = sd_event_source_unref(client->receive_message);
- client->fd = asynchronous_close(client->fd);
+ client->fd = safe_close(client->fd);
client->state = DHCP_STATE_REBINDING;
client->attempt = 0;
- r = dhcp_network_bind_raw_socket(client->ifindex, &client->link,
- client->xid, client->mac_addr,
- client->mac_addr_len, client->arp_type,
- client->port);
+ r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
+ client->mac_addr, client->mac_addr_len,
+ client->bcast_addr, client->bcast_addr_len,
+ client->arp_type, client->port);
if (r < 0) {
client_stop(client, r);
return 0;
@@ -1601,25 +1642,8 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t le
return r;
}
-static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
- assert(client);
- assert(client->request_sent);
- assert(lifetime > 0);
-
- if (lifetime > 3)
- lifetime -= 3;
- else
- lifetime = 0;
-
- return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
- + (random_u32() & 0x1fffff);
-}
-
static int client_set_lease_timeouts(sd_dhcp_client *client) {
usec_t time_now;
- uint64_t lifetime_timeout;
- uint64_t t2_timeout;
- uint64_t t1_timeout;
char time_string[FORMAT_TIMESPAN_MAX];
int r;
@@ -1642,93 +1666,76 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
assert(client->request_sent <= time_now);
- /* convert the various timeouts from relative (secs) to absolute (usecs) */
- lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
- if (client->lease->t1 > 0 && client->lease->t2 > 0) {
- /* both T1 and T2 are given */
- if (client->lease->t1 < client->lease->t2 &&
- client->lease->t2 < client->lease->lifetime) {
- /* they are both valid */
- t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
- t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
- } else {
- /* discard both */
- t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
- client->lease->t2 = (client->lease->lifetime * 7) / 8;
- t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
- client->lease->t1 = client->lease->lifetime / 2;
- }
- } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
- /* only T2 is given, and it is valid */
- t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
- t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
- client->lease->t1 = client->lease->lifetime / 2;
- if (t2_timeout <= t1_timeout) {
- /* the computed T1 would be invalid, so discard T2 */
- t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
- client->lease->t2 = (client->lease->lifetime * 7) / 8;
- }
- } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
- /* only T1 is given, and it is valid */
- t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
- t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
- client->lease->t2 = (client->lease->lifetime * 7) / 8;
- if (t2_timeout <= t1_timeout) {
- /* the computed T2 would be invalid, so discard T1 */
- t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
- client->lease->t2 = client->lease->lifetime / 2;
- }
- } else {
- /* fall back to the default timeouts */
- t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
- client->lease->t1 = client->lease->lifetime / 2;
- t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
- client->lease->t2 = (client->lease->lifetime * 7) / 8;
- }
+ /* verify that 0 < t2 < lifetime */
+ if (client->lease->t2 == 0 || client->lease->t2 >= client->lease->lifetime)
+ client->lease->t2 = T2_DEFAULT(client->lease->lifetime);
+ /* verify that 0 < t1 < lifetime */
+ if (client->lease->t1 == 0 || client->lease->t1 >= client->lease->t2)
+ client->lease->t1 = T1_DEFAULT(client->lease->lifetime);
+ /* now, if t1 >= t2, t1 *must* be T1_DEFAULT, since the previous check
+ * could not evalate to false if t1 >= t2; so setting t2 to T2_DEFAULT
+ * guarantees t1 < t2. */
+ if (client->lease->t1 >= client->lease->t2)
+ client->lease->t2 = T2_DEFAULT(client->lease->lifetime);
+
+ client->expire_time = client->request_sent + client->lease->lifetime * USEC_PER_SEC;
+ client->t1_time = client->request_sent + client->lease->t1 * USEC_PER_SEC;
+ client->t2_time = client->request_sent + client->lease->t2 * USEC_PER_SEC;
+
+ /* RFC2131 section 4.4.5:
+ * Times T1 and T2 SHOULD be chosen with some random "fuzz".
+ * Since the RFC doesn't specify here the exact 'fuzz' to use,
+ * we use the range from section 4.1: -1 to +1 sec. */
+ client->t1_time = usec_sub_signed(client->t1_time, RFC2131_RANDOM_FUZZ);
+ client->t2_time = usec_sub_signed(client->t2_time, RFC2131_RANDOM_FUZZ);
+
+ /* after fuzzing, ensure t2 is still >= t1 */
+ client->t2_time = MAX(client->t1_time, client->t2_time);
/* arm lifetime timeout */
r = event_reset_time(client->event, &client->timeout_expire,
clock_boottime_or_monotonic(),
- lifetime_timeout, 10 * USEC_PER_MSEC,
+ client->expire_time, 10 * USEC_PER_MSEC,
client_timeout_expire, client,
client->event_priority, "dhcp4-lifetime", true);
if (r < 0)
return r;
- log_dhcp_client(client, "lease expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
-
/* don't arm earlier timeouts if this has already expired */
- if (lifetime_timeout <= time_now)
+ if (client->expire_time <= time_now)
return 0;
+ log_dhcp_client(client, "lease expires in %s",
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->expire_time - time_now, USEC_PER_SEC));
+
/* arm T2 timeout */
r = event_reset_time(client->event, &client->timeout_t2,
clock_boottime_or_monotonic(),
- t2_timeout, 10 * USEC_PER_MSEC,
+ client->t2_time, 10 * USEC_PER_MSEC,
client_timeout_t2, client,
client->event_priority, "dhcp4-t2-timeout", true);
if (r < 0)
return r;
- log_dhcp_client(client, "T2 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
-
/* don't arm earlier timeout if this has already expired */
- if (t2_timeout <= time_now)
+ if (client->t2_time <= time_now)
return 0;
+ log_dhcp_client(client, "T2 expires in %s",
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t2_time - time_now, USEC_PER_SEC));
+
/* arm T1 timeout */
r = event_reset_time(client->event, &client->timeout_t1,
clock_boottime_or_monotonic(),
- t1_timeout, 10 * USEC_PER_MSEC,
+ client->t1_time, 10 * USEC_PER_MSEC,
client_timeout_t1, client,
client->event_priority, "dhcp4-t1-timer", true);
if (r < 0)
return r;
- log_dhcp_client(client, "T1 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
+ if (client->t1_time > time_now)
+ log_dhcp_client(client, "T1 expires in %s",
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t1_time - time_now, USEC_PER_SEC));
return 0;
}
@@ -1775,7 +1782,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
(void) event_source_disable(client->timeout_resend);
client->receive_message =
sd_event_source_unref(client->receive_message);
- client->fd = asynchronous_close(client->fd);
+ client->fd = safe_close(client->fd);
if (IN_SET(client->state, DHCP_STATE_REQUESTING,
DHCP_STATE_REBOOTING))
@@ -1880,12 +1887,11 @@ static int client_receive_message_udp(
assert(client);
buflen = next_datagram_size_fd(fd);
- if (buflen == -ENETDOWN) {
+ if (buflen == -ENETDOWN)
/* the link is down. Don't return an error or the I/O event
source will be disconnected and we won't be able to receive
packets again when the link comes back. */
return 0;
- }
if (buflen < 0)
return buflen;
@@ -2128,9 +2134,10 @@ int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
}
int sd_dhcp_client_stop(sd_dhcp_client *client) {
- DHCP_CLIENT_DONT_DESTROY(client);
+ if (!client)
+ return 0;
- assert_return(client, -EINVAL);
+ DHCP_CLIENT_DONT_DESTROY(client);
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
client->state = DHCP_STATE_STOPPED;
@@ -2188,7 +2195,7 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
sd_dhcp_lease_unref(client->lease);
- free(client->req_opts);
+ set_free(client->req_opts);
free(client->hostname);
free(client->vendor_class_identifier);
free(client->mudurl);
@@ -2201,6 +2208,10 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
+ const uint8_t *opts;
+ size_t n_opts;
+ int r;
+
assert_return(ret, -EINVAL);
_cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = new(sd_dhcp_client, 1);
@@ -2220,14 +2231,18 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
};
/* NOTE: this could be moved to a function. */
if (anonymize) {
- client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
- client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
+ n_opts = ELEMENTSOF(default_req_opts_anonymize);
+ opts = default_req_opts_anonymize;
} else {
- client->req_opts_size = ELEMENTSOF(default_req_opts);
- client->req_opts = memdup(default_req_opts, client->req_opts_size);
+ n_opts = ELEMENTSOF(default_req_opts);
+ opts = default_req_opts;
+ }
+
+ for (size_t i = 0; i < n_opts; i++) {
+ r = sd_dhcp_client_set_request_option(client, opts[i]);
+ if (r < 0)
+ return r;
}
- if (!client->req_opts)
- return -ENOMEM;
*ret = TAKE_PTR(client);
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
index 83e1b90291..8a138ff4b6 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2013 Intel Corporation. All rights reserved.
***/
@@ -1233,10 +1233,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
if (!a)
return -ENOMEM;
- if (!strv_isempty(a)) {
- lease->search_domains = a;
- a = NULL;
- }
+ if (!strv_isempty(a))
+ lease->search_domains = TAKE_PTR(a);
}
if (routes) {
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
index 38025b63d9..e068e0dc91 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2014-2015 Intel Corporation. All rights reserved.
***/
@@ -21,10 +21,10 @@
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
-#include "network-internal.h"
#include "random-util.h"
#include "socket-util.h"
#include "string-table.h"
+#include "strv.h"
#include "util.h"
#include "web-util.h"
@@ -188,8 +188,7 @@ int sd_dhcp6_client_set_mac(
assert_return(client, -EINVAL);
assert_return(addr, -EINVAL);
- assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
- assert_return(arp_type > 0, -EINVAL);
+ assert_return(addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
@@ -197,8 +196,11 @@ int sd_dhcp6_client_set_mac(
assert_return(addr_len == ETH_ALEN, -EINVAL);
else if (arp_type == ARPHRD_INFINIBAND)
assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
- else
- return -EINVAL;
+ else {
+ client->arp_type = ARPHRD_NONE;
+ client->mac_addr_len = 0;
+ return 0;
+ }
if (client->mac_addr_len == addr_len &&
memcmp(&client->mac_addr, addr, addr_len) == 0)
@@ -405,7 +407,7 @@ int sd_dhcp6_client_set_fqdn(
/* Make sure FQDN qualifies as DNS and as Linux hostname */
if (fqdn &&
- !(hostname_is_valid(fqdn, false) && dns_name_is_valid(fqdn) > 0))
+ !(hostname_is_valid(fqdn, 0) && dns_name_is_valid(fqdn) > 0))
return -EINVAL;
return free_and_strdup(&client->fqdn, fqdn);
@@ -1420,12 +1422,11 @@ static int client_receive_message(
assert(client->event);
buflen = next_datagram_size_fd(fd);
- if (buflen == -ENETDOWN) {
+ if (buflen == -ENETDOWN)
/* the link is down. Don't return an error or the I/O event
source will be disconnected and we won't be able to receive
packets again when the link comes back. */
return 0;
- }
if (buflen < 0)
return buflen;
@@ -1677,7 +1678,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
}
int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
- assert_return(client, -EINVAL);
+ if (!client)
+ return 0;
client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
@@ -1743,8 +1745,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
}
log_dhcp6_client(client, "Started in %s mode",
- client->information_request? "Information request":
- "Managed");
+ client->information_request ? "Information request" : "Managed");
return client_start(client, state);
}
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c
index 9aad22124d..d6f0708c94 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2014-2015 Intel Corporation. All rights reserved.
***/
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c
index ecd91cd927..9426b65324 100644
--- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2014 Axis Communications AB. All rights reserved.
***/
@@ -16,10 +16,12 @@
#include "ether-addr-util.h"
#include "event-util.h"
#include "fd-util.h"
+#include "format-util.h"
#include "in-addr-util.h"
-#include "list.h"
+#include "log-link.h"
#include "random-util.h"
#include "siphash24.h"
+#include "string-table.h"
#include "string-util.h"
#include "time-util.h"
@@ -54,6 +56,7 @@ struct sd_ipv4acd {
int ifindex;
int fd;
+ char ifname[IF_NAMESIZE + 1];
unsigned n_iteration;
unsigned n_conflict;
@@ -72,13 +75,30 @@ struct sd_ipv4acd {
void* userdata;
};
-#define log_ipv4acd_errno(acd, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__)
-#define log_ipv4acd(acd, fmt, ...) log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__)
+#define log_ipv4acd_errno(acd, error, fmt, ...) \
+ log_interface_full_errno(sd_ipv4acd_get_ifname(acd), LOG_DEBUG, error, "IPV4ACD: " fmt, ##__VA_ARGS__)
+#define log_ipv4acd(acd, fmt, ...) \
+ log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__)
+
+static const char * const ipv4acd_state_table[_IPV4ACD_STATE_MAX] = {
+ [IPV4ACD_STATE_INIT] = "init",
+ [IPV4ACD_STATE_STARTED] = "started",
+ [IPV4ACD_STATE_WAITING_PROBE] = "waiting-probe",
+ [IPV4ACD_STATE_PROBING] = "probing",
+ [IPV4ACD_STATE_WAITING_ANNOUNCE] = "waiting-announce",
+ [IPV4ACD_STATE_ANNOUNCING] = "announcing",
+ [IPV4ACD_STATE_RUNNING] = "running",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(ipv4acd_state, IPv4ACDState);
static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_counter) {
assert(acd);
assert(st < _IPV4ACD_STATE_MAX);
+ if (st != acd->state)
+ log_ipv4acd(acd, "%s -> %s", ipv4acd_state_to_string(acd->state), ipv4acd_state_to_string(st));
+
if (st == acd->state && !reset_counter)
acd->n_iteration++;
else {
@@ -144,7 +164,8 @@ static void ipv4acd_client_notify(sd_ipv4acd *acd, int event) {
int sd_ipv4acd_stop(sd_ipv4acd *acd) {
IPv4ACDState old_state;
- assert_return(acd, -EINVAL);
+ if (!acd)
+ return 0;
old_state = acd->state;
@@ -377,15 +398,35 @@ fail:
}
int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) {
+ char ifname[IF_NAMESIZE + 1];
+
assert_return(acd, -EINVAL);
assert_return(ifindex > 0, -EINVAL);
assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY);
+ if (!format_ifname(ifindex, ifname))
+ return -ENODEV;
+
+ strcpy(acd->ifname, ifname);
acd->ifindex = ifindex;
return 0;
}
+int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd) {
+ if (!acd)
+ return -EINVAL;
+
+ return acd->ifindex;
+}
+
+const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd) {
+ if (!acd)
+ return NULL;
+
+ return empty_to_null(acd->ifname);
+}
+
int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) {
assert_return(acd, -EINVAL);
assert_return(addr, -EINVAL);
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c
index 4f4d9ebe87..3af7d89bf0 100644
--- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2014 Axis Communications AB. All rights reserved.
***/
@@ -15,7 +15,7 @@
#include "alloc-util.h"
#include "ether-addr-util.h"
#include "in-addr-util.h"
-#include "list.h"
+#include "log-link.h"
#include "random-util.h"
#include "siphash24.h"
#include "sparse-endian.h"
@@ -49,8 +49,10 @@ struct sd_ipv4ll {
void* userdata;
};
-#define log_ipv4ll_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "IPV4LL: " fmt, ##__VA_ARGS__)
-#define log_ipv4ll(ll, fmt, ...) log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__)
+#define log_ipv4ll_errno(ll, error, fmt, ...) \
+ log_interface_full_errno(sd_ipv4ll_get_ifname(ll), LOG_DEBUG, error, "IPV4LL: " fmt, ##__VA_ARGS__)
+#define log_ipv4ll(ll, fmt, ...) \
+ log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__)
static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata);
@@ -89,7 +91,8 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) {
}
int sd_ipv4ll_stop(sd_ipv4ll *ll) {
- assert_return(ll, -EINVAL);
+ if (!ll)
+ return 0;
return sd_ipv4acd_stop(ll->acd);
}
@@ -102,6 +105,20 @@ int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int ifindex) {
return sd_ipv4acd_set_ifindex(ll->acd, ifindex);
}
+int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll) {
+ if (!ll)
+ return -EINVAL;
+
+ return sd_ipv4acd_get_ifindex(ll->acd);
+}
+
+const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll) {
+ if (!ll)
+ return NULL;
+
+ return sd_ipv4acd_get_ifname(ll->acd);
+}
+
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
int r;
diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c
index b0a11fe20b..8b666522cb 100644
--- a/src/systemd/src/libsystemd-network/sd-lldp.c
+++ b/src/systemd/src/libsystemd-network/sd-lldp.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <arpa/inet.h>
#include <linux/sockios.h>
@@ -276,7 +276,8 @@ fail:
}
_public_ int sd_lldp_stop(sd_lldp *lldp) {
- assert_return(lldp, -EINVAL);
+ if (!lldp)
+ return 0;
if (lldp->fd < 0)
return 0;
diff --git a/src/systemd/src/libsystemd/sd-event/event-source.h b/src/systemd/src/libsystemd/sd-event/event-source.h
index a8a30d825e..f0d2a1b9e6 100644
--- a/src/systemd/src/libsystemd/sd-event/event-source.h
+++ b/src/systemd/src/libsystemd/sd-event/event-source.h
@@ -1,5 +1,5 @@
#pragma once
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/epoll.h>
#include <sys/timerfd.h>
@@ -11,6 +11,7 @@
#include "hashmap.h"
#include "list.h"
#include "prioq.h"
+#include "ratelimit.h"
typedef enum EventSourceType {
SOURCE_IO,
@@ -61,6 +62,7 @@ struct sd_event_source {
bool dispatching:1;
bool floating:1;
bool exit_on_failure:1;
+ bool ratelimited:1;
int64_t priority;
unsigned pending_index;
@@ -72,6 +74,13 @@ struct sd_event_source {
LIST_FIELDS(sd_event_source, sources);
+ RateLimit rate_limit;
+
+ /* These are primarily fields relevant for time event sources, but since any event source can
+ * effectively become one when rate-limited, this is part of the common fields. */
+ unsigned earliest_index;
+ unsigned latest_index;
+
union {
struct {
sd_event_io_handler_t callback;
@@ -84,8 +93,6 @@ struct sd_event_source {
struct {
sd_event_time_handler_t callback;
usec_t next, accuracy;
- unsigned earliest_index;
- unsigned latest_index;
} time;
struct {
sd_event_signal_handler_t callback;
diff --git a/src/systemd/src/libsystemd/sd-event/event-util.c b/src/systemd/src/libsystemd/sd-event/event-util.c
index 43e73d55e1..132796fc6c 100644
--- a/src/systemd/src/libsystemd/sd-event/event-util.c
+++ b/src/systemd/src/libsystemd/sd-event/event-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
diff --git a/src/systemd/src/libsystemd/sd-event/event-util.h b/src/systemd/src/libsystemd/sd-event/event-util.h
index 00180955f9..c8f97bc8d6 100644
--- a/src/systemd/src/libsystemd/sd-event/event-util.h
+++ b/src/systemd/src/libsystemd/sd-event/event-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c
index d3df2e1309..3f1a6776fe 100644
--- a/src/systemd/src/libsystemd/sd-event/sd-event.c
+++ b/src/systemd/src/libsystemd/sd-event/sd-event.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/epoll.h>
#include <sys/timerfd.h>
@@ -37,6 +37,16 @@ static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) {
s->child.options == WEXITED;
}
+static bool event_source_is_online(sd_event_source *s) {
+ assert(s);
+ return s->enabled != SD_EVENT_OFF && !s->ratelimited;
+}
+
+static bool event_source_is_offline(sd_event_source *s) {
+ assert(s);
+ return s->enabled == SD_EVENT_OFF || s->ratelimited;
+}
+
static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
[SOURCE_IO] = "io",
[SOURCE_TIME_REALTIME] = "realtime",
@@ -55,7 +65,25 @@ static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX]
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int);
-#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM)
+#define EVENT_SOURCE_IS_TIME(t) \
+ IN_SET((t), \
+ SOURCE_TIME_REALTIME, \
+ SOURCE_TIME_BOOTTIME, \
+ SOURCE_TIME_MONOTONIC, \
+ SOURCE_TIME_REALTIME_ALARM, \
+ SOURCE_TIME_BOOTTIME_ALARM)
+
+#define EVENT_SOURCE_CAN_RATE_LIMIT(t) \
+ IN_SET((t), \
+ SOURCE_IO, \
+ SOURCE_TIME_REALTIME, \
+ SOURCE_TIME_BOOTTIME, \
+ SOURCE_TIME_MONOTONIC, \
+ SOURCE_TIME_REALTIME_ALARM, \
+ SOURCE_TIME_BOOTTIME_ALARM, \
+ SOURCE_SIGNAL, \
+ SOURCE_DEFER, \
+ SOURCE_INOTIFY)
struct sd_event {
unsigned n_ref;
@@ -81,7 +109,7 @@ struct sd_event {
Hashmap *signal_data; /* indexed by priority */
Hashmap *child_sources;
- unsigned n_enabled_child_sources;
+ unsigned n_online_child_sources;
Set *post_sources;
@@ -120,7 +148,7 @@ struct sd_event {
LIST_HEAD(sd_event_source, sources);
- usec_t last_run, last_log;
+ usec_t last_run_usec, last_log_usec;
unsigned delays[sizeof(usec_t) * 8];
};
@@ -146,6 +174,11 @@ static int pending_prioq_compare(const void *a, const void *b) {
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
+ /* Non rate-limited ones first. */
+ r = CMP(!!x->ratelimited, !!y->ratelimited);
+ if (r != 0)
+ return r;
+
/* Lower priority values first */
r = CMP(x->priority, y->priority);
if (r != 0)
@@ -168,6 +201,11 @@ static int prepare_prioq_compare(const void *a, const void *b) {
if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
return 1;
+ /* Non rate-limited ones first. */
+ r = CMP(!!x->ratelimited, !!y->ratelimited);
+ if (r != 0)
+ return r;
+
/* Move most recently prepared ones last, so that we can stop
* preparing as soon as we hit one that has already been
* prepared in the current iteration */
@@ -179,12 +217,30 @@ static int prepare_prioq_compare(const void *a, const void *b) {
return CMP(x->priority, y->priority);
}
+static usec_t time_event_source_next(const sd_event_source *s) {
+ assert(s);
+
+ /* We have two kinds of event sources that have elapsation times associated with them: the actual
+ * time based ones and the ones for which a ratelimit can be in effect (where we want to be notified
+ * once the ratelimit time window ends). Let's return the next elapsing time depending on what we are
+ * looking at here. */
+
+ if (s->ratelimited) { /* If rate-limited the next elapsation is when the ratelimit time window ends */
+ assert(s->rate_limit.begin != 0);
+ assert(s->rate_limit.interval != 0);
+ return usec_add(s->rate_limit.begin, s->rate_limit.interval);
+ }
+
+ /* Otherwise this must be a time event source, if not ratelimited */
+ if (EVENT_SOURCE_IS_TIME(s->type))
+ return s->time.next;
+
+ return USEC_INFINITY;
+}
+
static int earliest_time_prioq_compare(const void *a, const void *b) {
const sd_event_source *x = a, *y = b;
- assert(EVENT_SOURCE_IS_TIME(x->type));
- assert(x->type == y->type);
-
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
return -1;
@@ -198,19 +254,30 @@ static int earliest_time_prioq_compare(const void *a, const void *b) {
return 1;
/* Order by time */
- return CMP(x->time.next, y->time.next);
+ return CMP(time_event_source_next(x), time_event_source_next(y));
}
static usec_t time_event_source_latest(const sd_event_source *s) {
- return usec_add(s->time.next, s->time.accuracy);
+ assert(s);
+
+ if (s->ratelimited) { /* For ratelimited stuff the earliest and the latest time shall actually be the
+ * same, as we should avoid adding additional inaccuracy on an inaccuracy time
+ * window */
+ assert(s->rate_limit.begin != 0);
+ assert(s->rate_limit.interval != 0);
+ return usec_add(s->rate_limit.begin, s->rate_limit.interval);
+ }
+
+ /* Must be a time event source, if not ratelimited */
+ if (EVENT_SOURCE_IS_TIME(s->type))
+ return usec_add(s->time.next, s->time.accuracy);
+
+ return USEC_INFINITY;
}
static int latest_time_prioq_compare(const void *a, const void *b) {
const sd_event_source *x = a, *y = b;
- assert(EVENT_SOURCE_IS_TIME(x->type));
- assert(x->type == y->type);
-
/* Enabled ones first */
if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
return -1;
@@ -380,7 +447,7 @@ static void source_io_unregister(sd_event_source *s) {
return;
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0)
- log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
+ log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m",
strna(s->description), event_source_type_to_string(s->type));
s->io.registered = false;
@@ -399,13 +466,10 @@ static int source_io_register(
.events = events | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0),
.data.ptr = s,
};
- int r;
- r = epoll_ctl(s->event->epoll_fd,
+ if (epoll_ctl(s->event->epoll_fd,
s->io.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD,
- s->io.fd,
- &ev);
- if (r < 0)
+ s->io.fd, &ev) < 0)
return -errno;
s->io.registered = true;
@@ -425,15 +489,13 @@ static void source_child_pidfd_unregister(sd_event_source *s) {
if (EVENT_SOURCE_WATCH_PIDFD(s))
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0)
- log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
+ log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m",
strna(s->description), event_source_type_to_string(s->type));
s->child.registered = false;
}
static int source_child_pidfd_register(sd_event_source *s, int enabled) {
- int r;
-
assert(s);
assert(s->type == SOURCE_CHILD);
assert(enabled != SD_EVENT_OFF);
@@ -444,11 +506,9 @@ static int source_child_pidfd_register(sd_event_source *s, int enabled) {
.data.ptr = s,
};
- if (s->child.registered)
- r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->child.pidfd, &ev);
- else
- r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->child.pidfd, &ev);
- if (r < 0)
+ if (epoll_ctl(s->event->epoll_fd,
+ s->child.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD,
+ s->child.pidfd, &ev) < 0)
return -errno;
}
@@ -616,8 +676,7 @@ static int event_make_signal_data(
.data.ptr = d,
};
- r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev);
- if (r < 0) {
+ if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev) < 0) {
r = -errno;
goto fail;
}
@@ -669,12 +728,12 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig)
* and possibly drop the signalfd for it. */
if (sig == SIGCHLD &&
- e->n_enabled_child_sources > 0)
+ e->n_online_child_sources > 0)
return;
if (e->signal_sources &&
e->signal_sources[sig] &&
- e->signal_sources[sig]->enabled != SD_EVENT_OFF)
+ event_source_is_online(e->signal_sources[sig]))
return;
/*
@@ -704,6 +763,52 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig)
event_unmask_signal_data(e, d, sig);
}
+static void event_source_pp_prioq_reshuffle(sd_event_source *s) {
+ assert(s);
+
+ /* Reshuffles the pending + prepare prioqs. Called whenever the dispatch order changes, i.e. when
+ * they are enabled/disabled or marked pending and such. */
+
+ if (s->pending)
+ prioq_reshuffle(s->event->pending, s, &s->pending_index);
+
+ if (s->prepare)
+ prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
+}
+
+static void event_source_time_prioq_reshuffle(sd_event_source *s) {
+ struct clock_data *d;
+
+ assert(s);
+
+ /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy,
+ * pending, enable state. Makes sure the two prioq's are ordered properly again. */
+
+ if (s->ratelimited)
+ d = &s->event->monotonic;
+ else {
+ assert(EVENT_SOURCE_IS_TIME(s->type));
+ assert_se(d = event_get_clock_data(s->event, s->type));
+ }
+
+ prioq_reshuffle(d->earliest, s, &s->earliest_index);
+ prioq_reshuffle(d->latest, s, &s->latest_index);
+ d->needs_rearm = true;
+}
+
+static void event_source_time_prioq_remove(
+ sd_event_source *s,
+ struct clock_data *d) {
+
+ assert(s);
+ assert(d);
+
+ prioq_remove(d->earliest, s, &s->earliest_index);
+ prioq_remove(d->latest, s, &s->latest_index);
+ s->earliest_index = s->latest_index = PRIOQ_IDX_NULL;
+ d->needs_rearm = true;
+}
+
static void source_disconnect(sd_event_source *s) {
sd_event *event;
@@ -726,17 +831,18 @@ static void source_disconnect(sd_event_source *s) {
case SOURCE_TIME_BOOTTIME:
case SOURCE_TIME_MONOTONIC:
case SOURCE_TIME_REALTIME_ALARM:
- case SOURCE_TIME_BOOTTIME_ALARM: {
- struct clock_data *d;
+ case SOURCE_TIME_BOOTTIME_ALARM:
+ /* Only remove this event source from the time event source here if it is not ratelimited. If
+ * it is ratelimited, we'll remove it below, separately. Why? Because the clock used might
+ * differ: ratelimiting always uses CLOCK_MONOTONIC, but timer events might use any clock */
- d = event_get_clock_data(s->event, s->type);
- assert(d);
+ if (!s->ratelimited) {
+ struct clock_data *d;
+ assert_se(d = event_get_clock_data(s->event, s->type));
+ event_source_time_prioq_remove(s, d);
+ }
- prioq_remove(d->earliest, s, &s->time.earliest_index);
- prioq_remove(d->latest, s, &s->time.latest_index);
- d->needs_rearm = true;
break;
- }
case SOURCE_SIGNAL:
if (s->signal.sig > 0) {
@@ -751,9 +857,9 @@ static void source_disconnect(sd_event_source *s) {
case SOURCE_CHILD:
if (s->child.pid > 0) {
- if (s->enabled != SD_EVENT_OFF) {
- assert(s->event->n_enabled_child_sources > 0);
- s->event->n_enabled_child_sources--;
+ if (event_source_is_online(s)) {
+ assert(s->event->n_online_child_sources > 0);
+ s->event->n_online_child_sources--;
}
(void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid));
@@ -823,6 +929,9 @@ static void source_disconnect(sd_event_source *s) {
if (s->prepare)
prioq_remove(s->event->prepare, s, &s->prepare_index);
+ if (s->ratelimited)
+ event_source_time_prioq_remove(s, &s->event->monotonic);
+
event = TAKE_PTR(s->event);
LIST_REMOVE(sources, event->sources, s);
event->n_sources--;
@@ -910,16 +1019,8 @@ static int source_set_pending(sd_event_source *s, bool b) {
} else
assert_se(prioq_remove(s->event->pending, s, &s->pending_index));
- if (EVENT_SOURCE_IS_TIME(s->type)) {
- struct clock_data *d;
-
- d = event_get_clock_data(s->event, s->type);
- assert(d);
-
- prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
- prioq_reshuffle(d->latest, s, &s->time.latest_index);
- d->needs_rearm = true;
- }
+ if (EVENT_SOURCE_IS_TIME(s->type))
+ event_source_time_prioq_reshuffle(s);
if (s->type == SOURCE_SIGNAL && !b) {
struct signal_data *d;
@@ -1052,7 +1153,6 @@ static int event_setup_timer_fd(
return 0;
_cleanup_close_ int fd = -1;
- int r;
fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC);
if (fd < 0)
@@ -1065,8 +1165,7 @@ static int event_setup_timer_fd(
.data.ptr = d,
};
- r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
- if (r < 0)
+ if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
return -errno;
d->fd = TAKE_FD(fd);
@@ -1079,6 +1178,52 @@ static int time_exit_callback(sd_event_source *s, uint64_t usec, void *userdata)
return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
}
+static int setup_clock_data(sd_event *e, struct clock_data *d, clockid_t clock) {
+ int r;
+
+ assert(d);
+
+ if (d->fd < 0) {
+ r = event_setup_timer_fd(e, d, clock);
+ if (r < 0)
+ return r;
+ }
+
+ r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare);
+ if (r < 0)
+ return r;
+
+ r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int event_source_time_prioq_put(
+ sd_event_source *s,
+ struct clock_data *d) {
+
+ int r;
+
+ assert(s);
+ assert(d);
+
+ r = prioq_put(d->earliest, s, &s->earliest_index);
+ if (r < 0)
+ return r;
+
+ r = prioq_put(d->latest, s, &s->latest_index);
+ if (r < 0) {
+ assert_se(prioq_remove(d->earliest, s, &s->earliest_index) > 0);
+ s->earliest_index = PRIOQ_IDX_NULL;
+ return r;
+ }
+
+ d->needs_rearm = true;
+ return 0;
+}
+
_public_ int sd_event_add_time(
sd_event *e,
sd_event_source **ret,
@@ -1109,23 +1254,12 @@ _public_ int sd_event_add_time(
if (!callback)
callback = time_exit_callback;
- d = event_get_clock_data(e, type);
- assert(d);
-
- r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare);
- if (r < 0)
- return r;
+ assert_se(d = event_get_clock_data(e, type));
- r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare);
+ r = setup_clock_data(e, d, clock);
if (r < 0)
return r;
- if (d->fd < 0) {
- r = event_setup_timer_fd(e, d, clock);
- if (r < 0)
- return r;
- }
-
s = source_new(e, !ret, type);
if (!s)
return -ENOMEM;
@@ -1133,17 +1267,11 @@ _public_ int sd_event_add_time(
s->time.next = usec;
s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy;
s->time.callback = callback;
- s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL;
+ s->earliest_index = s->latest_index = PRIOQ_IDX_NULL;
s->userdata = userdata;
s->enabled = SD_EVENT_ONESHOT;
- d->needs_rearm = true;
-
- r = prioq_put(d->earliest, s, &s->time.earliest_index);
- if (r < 0)
- return r;
-
- r = prioq_put(d->latest, s, &s->time.latest_index);
+ r = event_source_time_prioq_put(s, d);
if (r < 0)
return r;
@@ -1276,7 +1404,7 @@ _public_ int sd_event_add_child(
if (!callback)
callback = child_exit_callback;
- if (e->n_enabled_child_sources == 0) {
+ if (e->n_online_child_sources == 0) {
/* Caller must block SIGCHLD before using us to watch children, even if pidfd is available,
* for compatibility with pre-pidfd and because we don't want the reap the child processes
* ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to
@@ -1326,31 +1454,25 @@ _public_ int sd_event_add_child(
if (r < 0)
return r;
- e->n_enabled_child_sources++;
-
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
/* We have a pidfd and we only want to watch for exit */
-
r = source_child_pidfd_register(s, s->enabled);
- if (r < 0) {
- e->n_enabled_child_sources--;
+ if (r < 0)
return r;
- }
+
} else {
/* We have no pidfd or we shall wait for some other event than WEXITED */
-
r = event_make_signal_data(e, SIGCHLD, NULL);
- if (r < 0) {
- e->n_enabled_child_sources--;
+ if (r < 0)
return r;
- }
e->need_process_child = true;
}
+ e->n_online_child_sources++;
+
if (ret)
*ret = s;
-
TAKE_PTR(s);
return 0;
}
@@ -1379,7 +1501,7 @@ _public_ int sd_event_add_child_pidfd(
if (!callback)
callback = child_exit_callback;
- if (e->n_enabled_child_sources == 0) {
+ if (e->n_online_child_sources == 0) {
r = signal_is_blocked(SIGCHLD);
if (r < 0)
return r;
@@ -1415,31 +1537,24 @@ _public_ int sd_event_add_child_pidfd(
if (r < 0)
return r;
- e->n_enabled_child_sources++;
-
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
/* We only want to watch for WEXITED */
-
r = source_child_pidfd_register(s, s->enabled);
- if (r < 0) {
- e->n_enabled_child_sources--;
+ if (r < 0)
return r;
- }
} else {
/* We shall wait for some other event than WEXITED */
-
r = event_make_signal_data(e, SIGCHLD, NULL);
- if (r < 0) {
- e->n_enabled_child_sources--;
+ if (r < 0)
return r;
- }
e->need_process_child = true;
}
+ e->n_online_child_sources++;
+
if (ret)
*ret = s;
-
TAKE_PTR(s);
return 0;
}
@@ -2022,7 +2137,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
if (s->io.fd == fd)
return 0;
- if (s->enabled == SD_EVENT_OFF) {
+ if (event_source_is_offline(s)) {
s->io.fd = fd;
s->io.registered = false;
} else {
@@ -2089,7 +2204,7 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events)
if (r < 0)
return r;
- if (s->enabled != SD_EVENT_OFF) {
+ if (event_source_is_online(s)) {
r = source_io_register(s, s->enabled, events);
if (r < 0)
return r;
@@ -2192,7 +2307,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority)
event_gc_inode_data(s->event, old_inode_data);
- } else if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) {
+ } else if (s->type == SOURCE_SIGNAL && event_source_is_online(s)) {
struct signal_data *old, *d;
/* Move us from the signalfd belonging to the old
@@ -2212,11 +2327,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority)
} else
s->priority = priority;
- if (s->pending)
- prioq_reshuffle(s->event->pending, s, &s->pending_index);
-
- if (s->prepare)
- prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
+ event_source_pp_prioq_reshuffle(s);
if (s->type == SOURCE_EXIT)
prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
@@ -2233,198 +2344,222 @@ fail:
return r;
}
-_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
+_public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) {
assert_return(s, -EINVAL);
assert_return(!event_pid_changed(s->event), -ECHILD);
- if (m)
- *m = s->enabled;
+ if (ret)
+ *ret = s->enabled;
+
return s->enabled != SD_EVENT_OFF;
}
-_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
+static int event_source_offline(
+ sd_event_source *s,
+ int enabled,
+ bool ratelimited) {
+
+ bool was_offline;
int r;
- assert_return(s, -EINVAL);
- assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL);
- assert_return(!event_pid_changed(s->event), -ECHILD);
+ assert(s);
+ assert(enabled == SD_EVENT_OFF || ratelimited);
- /* If we are dead anyway, we are fine with turning off
- * sources, but everything else needs to fail. */
- if (s->event->state == SD_EVENT_FINISHED)
- return m == SD_EVENT_OFF ? 0 : -ESTALE;
+ /* Unset the pending flag when this event source is disabled */
+ if (s->enabled != SD_EVENT_OFF &&
+ enabled == SD_EVENT_OFF &&
+ !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
+ r = source_set_pending(s, false);
+ if (r < 0)
+ return r;
+ }
- if (s->enabled == m)
- return 0;
+ was_offline = event_source_is_offline(s);
+ s->enabled = enabled;
+ s->ratelimited = ratelimited;
- if (m == SD_EVENT_OFF) {
+ switch (s->type) {
- /* Unset the pending flag when this event source is disabled */
- if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
- r = source_set_pending(s, false);
- if (r < 0)
- return r;
- }
+ case SOURCE_IO:
+ source_io_unregister(s);
+ break;
- switch (s->type) {
+ case SOURCE_TIME_REALTIME:
+ case SOURCE_TIME_BOOTTIME:
+ case SOURCE_TIME_MONOTONIC:
+ case SOURCE_TIME_REALTIME_ALARM:
+ case SOURCE_TIME_BOOTTIME_ALARM:
+ event_source_time_prioq_reshuffle(s);
+ break;
- case SOURCE_IO:
- source_io_unregister(s);
- s->enabled = m;
- break;
+ case SOURCE_SIGNAL:
+ event_gc_signal_data(s->event, &s->priority, s->signal.sig);
+ break;
- case SOURCE_TIME_REALTIME:
- case SOURCE_TIME_BOOTTIME:
- case SOURCE_TIME_MONOTONIC:
- case SOURCE_TIME_REALTIME_ALARM:
- case SOURCE_TIME_BOOTTIME_ALARM: {
- struct clock_data *d;
+ case SOURCE_CHILD:
+ if (!was_offline) {
+ assert(s->event->n_online_child_sources > 0);
+ s->event->n_online_child_sources--;
+ }
- s->enabled = m;
- d = event_get_clock_data(s->event, s->type);
- assert(d);
+ if (EVENT_SOURCE_WATCH_PIDFD(s))
+ source_child_pidfd_unregister(s);
+ else
+ event_gc_signal_data(s->event, &s->priority, SIGCHLD);
+ break;
- prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
- prioq_reshuffle(d->latest, s, &s->time.latest_index);
- d->needs_rearm = true;
- break;
- }
+ case SOURCE_EXIT:
+ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
+ break;
- case SOURCE_SIGNAL:
- s->enabled = m;
+ case SOURCE_DEFER:
+ case SOURCE_POST:
+ case SOURCE_INOTIFY:
+ break;
- event_gc_signal_data(s->event, &s->priority, s->signal.sig);
- break;
+ default:
+ assert_not_reached("Wut? I shouldn't exist.");
+ }
- case SOURCE_CHILD:
- s->enabled = m;
+ return 1;
+}
- assert(s->event->n_enabled_child_sources > 0);
- s->event->n_enabled_child_sources--;
+static int event_source_online(
+ sd_event_source *s,
+ int enabled,
+ bool ratelimited) {
- if (EVENT_SOURCE_WATCH_PIDFD(s))
- source_child_pidfd_unregister(s);
- else
- event_gc_signal_data(s->event, &s->priority, SIGCHLD);
+ bool was_online;
+ int r;
- break;
+ assert(s);
+ assert(enabled != SD_EVENT_OFF || !ratelimited);
- case SOURCE_EXIT:
- s->enabled = m;
- prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
- break;
+ /* Unset the pending flag when this event source is enabled */
+ if (s->enabled == SD_EVENT_OFF &&
+ enabled != SD_EVENT_OFF &&
+ !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
+ r = source_set_pending(s, false);
+ if (r < 0)
+ return r;
+ }
- case SOURCE_DEFER:
- case SOURCE_POST:
- case SOURCE_INOTIFY:
- s->enabled = m;
- break;
+ /* Are we really ready for onlining? */
+ if (enabled == SD_EVENT_OFF || ratelimited) {
+ /* Nope, we are not ready for onlining, then just update the precise state and exit */
+ s->enabled = enabled;
+ s->ratelimited = ratelimited;
+ return 0;
+ }
- default:
- assert_not_reached("Wut? I shouldn't exist.");
- }
+ was_online = event_source_is_online(s);
- } else {
+ switch (s->type) {
+ case SOURCE_IO:
+ r = source_io_register(s, enabled, s->io.events);
+ if (r < 0)
+ return r;
+ break;
- /* Unset the pending flag when this event source is enabled */
- if (s->enabled == SD_EVENT_OFF && !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
- r = source_set_pending(s, false);
- if (r < 0)
- return r;
+ case SOURCE_SIGNAL:
+ r = event_make_signal_data(s->event, s->signal.sig, NULL);
+ if (r < 0) {
+ event_gc_signal_data(s->event, &s->priority, s->signal.sig);
+ return r;
}
- switch (s->type) {
+ break;
+
+ case SOURCE_CHILD:
+ if (EVENT_SOURCE_WATCH_PIDFD(s)) {
+ /* yes, we have pidfd */
- case SOURCE_IO:
- r = source_io_register(s, m, s->io.events);
+ r = source_child_pidfd_register(s, enabled);
if (r < 0)
return r;
+ } else {
+ /* no pidfd, or something other to watch for than WEXITED */
- s->enabled = m;
- break;
-
- case SOURCE_TIME_REALTIME:
- case SOURCE_TIME_BOOTTIME:
- case SOURCE_TIME_MONOTONIC:
- case SOURCE_TIME_REALTIME_ALARM:
- case SOURCE_TIME_BOOTTIME_ALARM: {
- struct clock_data *d;
-
- s->enabled = m;
- d = event_get_clock_data(s->event, s->type);
- assert(d);
-
- prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
- prioq_reshuffle(d->latest, s, &s->time.latest_index);
- d->needs_rearm = true;
- break;
+ r = event_make_signal_data(s->event, SIGCHLD, NULL);
+ if (r < 0) {
+ event_gc_signal_data(s->event, &s->priority, SIGCHLD);
+ return r;
+ }
}
- case SOURCE_SIGNAL:
+ if (!was_online)
+ s->event->n_online_child_sources++;
+ break;
- s->enabled = m;
+ case SOURCE_TIME_REALTIME:
+ case SOURCE_TIME_BOOTTIME:
+ case SOURCE_TIME_MONOTONIC:
+ case SOURCE_TIME_REALTIME_ALARM:
+ case SOURCE_TIME_BOOTTIME_ALARM:
+ case SOURCE_EXIT:
+ case SOURCE_DEFER:
+ case SOURCE_POST:
+ case SOURCE_INOTIFY:
+ break;
- r = event_make_signal_data(s->event, s->signal.sig, NULL);
- if (r < 0) {
- s->enabled = SD_EVENT_OFF;
- event_gc_signal_data(s->event, &s->priority, s->signal.sig);
- return r;
- }
+ default:
+ assert_not_reached("Wut? I shouldn't exist.");
+ }
- break;
+ s->enabled = enabled;
+ s->ratelimited = ratelimited;
- case SOURCE_CHILD:
+ /* Non-failing operations below */
+ switch (s->type) {
+ case SOURCE_TIME_REALTIME:
+ case SOURCE_TIME_BOOTTIME:
+ case SOURCE_TIME_MONOTONIC:
+ case SOURCE_TIME_REALTIME_ALARM:
+ case SOURCE_TIME_BOOTTIME_ALARM:
+ event_source_time_prioq_reshuffle(s);
+ break;
- if (s->enabled == SD_EVENT_OFF)
- s->event->n_enabled_child_sources++;
+ case SOURCE_EXIT:
+ prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
+ break;
- s->enabled = m;
+ default:
+ break;
+ }
- if (EVENT_SOURCE_WATCH_PIDFD(s)) {
- /* yes, we have pidfd */
+ return 1;
+}
- r = source_child_pidfd_register(s, s->enabled);
- if (r < 0) {
- s->enabled = SD_EVENT_OFF;
- s->event->n_enabled_child_sources--;
- return r;
- }
- } else {
- /* no pidfd, or something other to watch for than WEXITED */
+_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
+ int r;
- r = event_make_signal_data(s->event, SIGCHLD, NULL);
- if (r < 0) {
- s->enabled = SD_EVENT_OFF;
- s->event->n_enabled_child_sources--;
- event_gc_signal_data(s->event, &s->priority, SIGCHLD);
- return r;
- }
- }
+ assert_return(s, -EINVAL);
+ assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL);
+ assert_return(!event_pid_changed(s->event), -ECHILD);
- break;
+ /* If we are dead anyway, we are fine with turning off sources, but everything else needs to fail. */
+ if (s->event->state == SD_EVENT_FINISHED)
+ return m == SD_EVENT_OFF ? 0 : -ESTALE;
- case SOURCE_EXIT:
- s->enabled = m;
- prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index);
- break;
+ if (s->enabled == m) /* No change? */
+ return 0;
- case SOURCE_DEFER:
- case SOURCE_POST:
- case SOURCE_INOTIFY:
+ if (m == SD_EVENT_OFF)
+ r = event_source_offline(s, m, s->ratelimited);
+ else {
+ if (s->enabled != SD_EVENT_OFF) {
+ /* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the
+ * event source is already enabled after all. */
s->enabled = m;
- break;
-
- default:
- assert_not_reached("Wut? I shouldn't exist.");
+ return 0;
}
- }
- if (s->pending)
- prioq_reshuffle(s->event->pending, s, &s->pending_index);
-
- if (s->prepare)
- prioq_reshuffle(s->event->prepare, s, &s->prepare_index);
+ r = event_source_online(s, m, s->ratelimited);
+ }
+ if (r < 0)
+ return r;
+ event_source_pp_prioq_reshuffle(s);
return 0;
}
@@ -2439,7 +2574,6 @@ _public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) {
}
_public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) {
- struct clock_data *d;
int r;
assert_return(s, -EINVAL);
@@ -2453,13 +2587,7 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) {
s->time.next = usec;
- d = event_get_clock_data(s->event, s->type);
- assert(d);
-
- prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
- prioq_reshuffle(d->latest, s, &s->time.latest_index);
- d->needs_rearm = true;
-
+ event_source_time_prioq_reshuffle(s);
return 0;
}
@@ -2491,7 +2619,6 @@ _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *use
}
_public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) {
- struct clock_data *d;
int r;
assert_return(s, -EINVAL);
@@ -2509,12 +2636,7 @@ _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec
s->time.accuracy = usec;
- d = event_get_clock_data(s->event, s->type);
- assert(d);
-
- prioq_reshuffle(d->latest, s, &s->time.latest_index);
- d->needs_rearm = true;
-
+ event_source_time_prioq_reshuffle(s);
return 0;
}
@@ -2689,6 +2811,96 @@ _public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata)
return ret;
}
+static int event_source_enter_ratelimited(sd_event_source *s) {
+ int r;
+
+ assert(s);
+
+ /* When an event source becomes ratelimited, we place it in the CLOCK_MONOTONIC priority queue, with
+ * the end of the rate limit time window, much as if it was a timer event source. */
+
+ if (s->ratelimited)
+ return 0; /* Already ratelimited, this is a NOP hence */
+
+ /* Make sure we can install a CLOCK_MONOTONIC event further down. */
+ r = setup_clock_data(s->event, &s->event->monotonic, CLOCK_MONOTONIC);
+ if (r < 0)
+ return r;
+
+ /* Timer event sources are already using the earliest/latest queues for the timer scheduling. Let's
+ * first remove them from the prioq appropriate for their own clock, so that we can use the prioq
+ * fields of the event source then for adding it to the CLOCK_MONOTONIC prioq instead. */
+ if (EVENT_SOURCE_IS_TIME(s->type))
+ event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type));
+
+ /* Now, let's add the event source to the monotonic clock instead */
+ r = event_source_time_prioq_put(s, &s->event->monotonic);
+ if (r < 0)
+ goto fail;
+
+ /* And let's take the event source officially offline */
+ r = event_source_offline(s, s->enabled, /* ratelimited= */ true);
+ if (r < 0) {
+ event_source_time_prioq_remove(s, &s->event->monotonic);
+ goto fail;
+ }
+
+ event_source_pp_prioq_reshuffle(s);
+
+ log_debug("Event source %p (%s) entered rate limit state.", s, strna(s->description));
+ return 0;
+
+fail:
+ /* Reinstall time event sources in the priority queue as before. This shouldn't fail, since the queue
+ * space for it should already be allocated. */
+ if (EVENT_SOURCE_IS_TIME(s->type))
+ assert_se(event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)) >= 0);
+
+ return r;
+}
+
+static int event_source_leave_ratelimit(sd_event_source *s) {
+ int r;
+
+ assert(s);
+
+ if (!s->ratelimited)
+ return 0;
+
+ /* Let's take the event source out of the monotonic prioq first. */
+ event_source_time_prioq_remove(s, &s->event->monotonic);
+
+ /* Let's then add the event source to its native clock prioq again — if this is a timer event source */
+ if (EVENT_SOURCE_IS_TIME(s->type)) {
+ r = event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type));
+ if (r < 0)
+ goto fail;
+ }
+
+ /* Let's try to take it online again. */
+ r = event_source_online(s, s->enabled, /* ratelimited= */ false);
+ if (r < 0) {
+ /* Do something roughly sensible when this failed: undo the two prioq ops above */
+ if (EVENT_SOURCE_IS_TIME(s->type))
+ event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type));
+
+ goto fail;
+ }
+
+ event_source_pp_prioq_reshuffle(s);
+ ratelimit_reset(&s->rate_limit);
+
+ log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description));
+ return 0;
+
+fail:
+ /* Do something somewhat reasonable when we cannot move an event sources out of ratelimited mode:
+ * simply put it back in it, maybe we can then process it more successfully next iteration. */
+ assert_se(event_source_time_prioq_put(s, &s->event->monotonic) >= 0);
+
+ return r;
+}
+
static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) {
usec_t c;
assert(e);
@@ -2776,7 +2988,6 @@ static int event_arm_timer(
struct itimerspec its = {};
sd_event_source *a, *b;
usec_t t;
- int r;
assert(e);
assert(d);
@@ -2787,7 +2998,7 @@ static int event_arm_timer(
d->needs_rearm = false;
a = prioq_peek(d->earliest);
- if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) {
+ if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) {
if (d->fd < 0)
return 0;
@@ -2796,9 +3007,8 @@ static int event_arm_timer(
return 0;
/* disarm */
- r = timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL);
- if (r < 0)
- return r;
+ if (timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL) < 0)
+ return -errno;
d->next = USEC_INFINITY;
return 0;
@@ -2807,7 +3017,7 @@ static int event_arm_timer(
b = prioq_peek(d->latest);
assert_se(b && b->enabled != SD_EVENT_OFF);
- t = sleep_between(e, a->time.next, time_event_source_latest(b));
+ t = sleep_between(e, time_event_source_next(a), time_event_source_latest(b));
if (d->next == t)
return 0;
@@ -2820,8 +3030,7 @@ static int event_arm_timer(
} else
timespec_store(&its.it_value, t);
- r = timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL);
- if (r < 0)
+ if (timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL) < 0)
return -errno;
d->next = t;
@@ -2886,19 +3095,29 @@ static int process_timer(
for (;;) {
s = prioq_peek(d->earliest);
- if (!s ||
- s->time.next > n ||
- s->enabled == SD_EVENT_OFF ||
- s->pending)
+ if (!s || time_event_source_next(s) > n)
+ break;
+
+ if (s->ratelimited) {
+ /* This is an event sources whose ratelimit window has ended. Let's turn it on
+ * again. */
+ assert(s->ratelimited);
+
+ r = event_source_leave_ratelimit(s);
+ if (r < 0)
+ return r;
+
+ continue;
+ }
+
+ if (s->enabled == SD_EVENT_OFF || s->pending)
break;
r = source_set_pending(s, true);
if (r < 0)
return r;
- prioq_reshuffle(d->earliest, s, &s->time.earliest_index);
- prioq_reshuffle(d->latest, s, &s->time.latest_index);
- d->needs_rearm = true;
+ event_source_time_prioq_reshuffle(s);
}
return 0;
@@ -2936,7 +3155,7 @@ static int process_child(sd_event *e) {
if (s->pending)
continue;
- if (s->enabled == SD_EVENT_OFF)
+ if (event_source_is_offline(s))
continue;
if (s->child.exited)
@@ -2946,9 +3165,8 @@ static int process_child(sd_event *e) {
continue;
zero(s->child.siginfo);
- r = waitid(P_PID, s->child.pid, &s->child.siginfo,
- WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options);
- if (r < 0)
+ if (waitid(P_PID, s->child.pid, &s->child.siginfo,
+ WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options) < 0)
return -errno;
if (s->child.siginfo.si_pid != 0) {
@@ -2984,7 +3202,7 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
if (s->pending)
return 0;
- if (s->enabled == SD_EVENT_OFF)
+ if (event_source_is_offline(s))
return 0;
if (!EVENT_SOURCE_WATCH_PIDFD(s))
@@ -3144,7 +3362,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) {
LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) {
- if (s->enabled == SD_EVENT_OFF)
+ if (event_source_is_offline(s))
continue;
r = source_set_pending(s, true);
@@ -3180,7 +3398,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) {
* sources if IN_IGNORED or IN_UNMOUNT is set. */
LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) {
- if (s->enabled == SD_EVENT_OFF)
+ if (event_source_is_offline(s))
continue;
if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 &&
@@ -3234,6 +3452,16 @@ static int source_dispatch(sd_event_source *s) {
* callback might have invalidated/disconnected the event source. */
saved_event = sd_event_ref(s->event);
+ /* Check if we hit the ratelimit for this event source, if so, let's disable it. */
+ assert(!s->ratelimited);
+ if (!ratelimit_below(&s->rate_limit)) {
+ r = event_source_enter_ratelimited(s);
+ if (r < 0)
+ return r;
+
+ return 1;
+ }
+
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
r = source_set_pending(s, false);
if (r < 0)
@@ -3247,7 +3475,7 @@ static int source_dispatch(sd_event_source *s) {
* post sources as pending */
SET_FOREACH(z, s->event->post_sources) {
- if (z->enabled == SD_EVENT_OFF)
+ if (event_source_is_offline(z))
continue;
r = source_set_pending(z, true);
@@ -3367,7 +3595,7 @@ static int event_prepare(sd_event *e) {
sd_event_source *s;
s = prioq_peek(e->prepare);
- if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF)
+ if (!s || s->prepare_iteration == e->iteration || event_source_is_offline(s))
break;
s->prepare_iteration = e->iteration;
@@ -3402,18 +3630,17 @@ static int event_prepare(sd_event *e) {
static int dispatch_exit(sd_event *e) {
sd_event_source *p;
- _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
int r;
assert(e);
p = prioq_peek(e->exit);
- if (!p || p->enabled == SD_EVENT_OFF) {
+ if (!p || event_source_is_offline(p)) {
e->state = SD_EVENT_FINISHED;
return 0;
}
- ref = sd_event_ref(e);
+ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
e->iteration++;
e->state = SD_EVENT_EXITING;
r = source_dispatch(p);
@@ -3430,7 +3657,7 @@ static sd_event_source* event_next_pending(sd_event *e) {
if (!p)
return NULL;
- if (p->enabled == SD_EVENT_OFF)
+ if (event_source_is_offline(p))
return NULL;
return p;
@@ -3439,7 +3666,6 @@ static sd_event_source* event_next_pending(sd_event *e) {
static int arm_watchdog(sd_event *e) {
struct itimerspec its = {};
usec_t t;
- int r;
assert(e);
assert(e->watchdog_fd >= 0);
@@ -3455,8 +3681,7 @@ static int arm_watchdog(sd_event *e) {
if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0)
its.it_value.tv_nsec = 1;
- r = timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL);
- if (r < 0)
+ if (timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL) < 0)
return -errno;
return 0;
@@ -3511,6 +3736,9 @@ _public_ int sd_event_prepare(sd_event *e) {
* syscalls */
assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO);
+ /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */
+ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
+
if (e->exit_requested)
goto pending;
@@ -3716,9 +3944,8 @@ _public_ int sd_event_dispatch(sd_event *e) {
p = event_next_pending(e);
if (p) {
- _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
+ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
- ref = sd_event_ref(e);
e->state = SD_EVENT_RUNNING;
r = source_dispatch(p);
e->state = SD_EVENT_INITIAL;
@@ -3752,29 +3979,32 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
- if (e->profile_delays && e->last_run) {
+ if (e->profile_delays && e->last_run_usec != 0) {
usec_t this_run;
unsigned l;
this_run = now(CLOCK_MONOTONIC);
- l = u64log2(this_run - e->last_run);
- assert(l < sizeof(e->delays));
+ l = u64log2(this_run - e->last_run_usec);
+ assert(l < ELEMENTSOF(e->delays));
e->delays[l]++;
- if (this_run - e->last_log >= 5*USEC_PER_SEC) {
+ if (this_run - e->last_log_usec >= 5*USEC_PER_SEC) {
event_log_delays(e);
- e->last_log = this_run;
+ e->last_log_usec = this_run;
}
}
+ /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */
+ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e);
+
r = sd_event_prepare(e);
if (r == 0)
/* There was nothing? Then wait... */
r = sd_event_wait(e, timeout);
if (e->profile_delays)
- e->last_run = now(CLOCK_MONOTONIC);
+ e->last_run_usec = now(CLOCK_MONOTONIC);
if (r > 0) {
/* There's something now, then let's dispatch it */
@@ -3789,7 +4019,6 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
}
_public_ int sd_event_loop(sd_event *e) {
- _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
int r;
assert_return(e, -EINVAL);
@@ -3797,7 +4026,7 @@ _public_ int sd_event_loop(sd_event *e) {
assert_return(!event_pid_changed(e), -ECHILD);
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
- ref = sd_event_ref(e);
+ _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL;
while (e->state != SD_EVENT_FINISHED) {
r = sd_event_run(e, (uint64_t) -1);
@@ -3809,7 +4038,6 @@ _public_ int sd_event_loop(sd_event *e) {
}
_public_ int sd_event_get_fd(sd_event *e) {
-
assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
assert_return(!event_pid_changed(e), -ECHILD);
@@ -3866,8 +4094,7 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) {
return -EOPNOTSUPP;
if (!triple_timestamp_is_set(&e->timestamp)) {
- /* Implicitly fall back to now() if we never ran
- * before and thus have no cached time. */
+ /* Implicitly fall back to now() if we never ran before and thus have no cached time. */
*usec = now(clock);
return 1;
}
@@ -3946,8 +4173,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
.data.ptr = INT_TO_PTR(SOURCE_WATCHDOG),
};
- r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev);
- if (r < 0) {
+ if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev) < 0) {
r = -errno;
goto fail;
}
@@ -4045,3 +4271,53 @@ _public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) {
s->exit_on_failure = b;
return 1;
}
+
+_public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval, unsigned burst) {
+ int r;
+
+ assert_return(s, -EINVAL);
+
+ /* Turning on ratelimiting on event source types that don't support it, is a loggable offense. Doing
+ * so is a programming error. */
+ assert_return(EVENT_SOURCE_CAN_RATE_LIMIT(s->type), -EDOM);
+
+ /* When ratelimiting is configured we'll always reset the rate limit state first and start fresh,
+ * non-ratelimited. */
+ r = event_source_leave_ratelimit(s);
+ if (r < 0)
+ return r;
+
+ s->rate_limit = (RateLimit) { interval, burst };
+ return 0;
+}
+
+_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) {
+ assert_return(s, -EINVAL);
+
+ /* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence
+ * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */
+ if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type))
+ return -EDOM;
+
+ if (!ratelimit_configured(&s->rate_limit))
+ return -ENOEXEC;
+
+ if (ret_interval)
+ *ret_interval = s->rate_limit.interval;
+ if (ret_burst)
+ *ret_burst = s->rate_limit.burst;
+
+ return 0;
+}
+
+_public_ int sd_event_source_is_ratelimited(sd_event_source *s) {
+ assert_return(s, -EINVAL);
+
+ if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type))
+ return false;
+
+ if (!ratelimit_configured(&s->rate_limit))
+ return false;
+
+ return s->ratelimited;
+}
diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c
index 335f22b920..a3f6da6381 100644
--- a/src/systemd/src/libsystemd/sd-id128/id128-util.c
+++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <fcntl.h>
@@ -10,6 +10,7 @@
#include "id128-util.h"
#include "io-util.h"
#include "stdio-util.h"
+#include "string-util.h"
char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]) {
unsigned n, k = 0;
@@ -97,6 +98,11 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
switch (l) {
+ case 13:
+ case 14:
+ /* Treat an "uninitialized" id file like an empty one */
+ return f == ID128_PLAIN_OR_UNINIT && strneq(buffer, "uninitialized\n", l) ? -ENOMEDIUM : -EINVAL;
+
case 33: /* plain UUID with trailing newline */
if (buffer[32] != '\n')
return -EINVAL;
@@ -115,7 +121,7 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
_fallthrough_;
case 36: /* RFC UUID without trailing newline */
- if (f == ID128_PLAIN)
+ if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT))
return -EINVAL;
buffer[36] = 0;
diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h
index 1901bf119f..6b09bcd96a 100644
--- a/src/systemd/src/libsystemd/sd-id128/id128-util.h
+++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
@@ -17,6 +17,10 @@ bool id128_is_valid(const char *s) _pure_;
typedef enum Id128Format {
ID128_ANY,
ID128_PLAIN, /* formatted as 32 hex chars as-is */
+ ID128_PLAIN_OR_UNINIT, /* formatted as 32 hex chars as-is; allow special "uninitialized"
+ * value when reading from file (id128_read() and id128_read_fd()).
+ *
+ * This format should be used when reading a machine-id file. */
ID128_UUID, /* formatted as 36 character uuid string */
_ID128_FORMAT_MAX,
} Id128Format;
diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
index 9b38ef0c56..d5de935c77 100644
--- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <fcntl.h>
diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h
index 1055b00d07..e3de2ae562 100644
--- a/src/systemd/src/systemd/_sd-common.h
+++ b/src/systemd/src/systemd/_sd-common.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosdcommonhfoo
#define foosdcommonhfoo
diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h
index ac3b5b369c..c35328a9a6 100644
--- a/src/systemd/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/src/systemd/sd-dhcp-client.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosddhcpclienthfoo
#define foosddhcpclienthfoo
@@ -40,6 +40,8 @@ enum {
SD_DHCP_CLIENT_EVENT_EXPIRED = 3,
SD_DHCP_CLIENT_EVENT_RENEW = 4,
SD_DHCP_CLIENT_EVENT_SELECTING = 5,
+ SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts.
+ * The client may want to start acquiring link-local addresses. */
};
enum {
@@ -126,6 +128,7 @@ int sd_dhcp_client_set_ifindex(
int sd_dhcp_client_set_mac(
sd_dhcp_client *client,
const uint8_t *addr,
+ const uint8_t *bcast_addr,
size_t addr_len,
uint16_t arp_type);
int sd_dhcp_client_set_client_id(
diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h
index 17bd491819..c255a1f912 100644
--- a/src/systemd/src/systemd/sd-dhcp-lease.h
+++ b/src/systemd/src/systemd/sd-dhcp-lease.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosddhcpleasehfoo
#define foosddhcpleasehfoo
diff --git a/src/systemd/src/systemd/sd-dhcp-option.h b/src/systemd/src/systemd/sd-dhcp-option.h
index 45dbd27985..71aa479b5e 100644
--- a/src/systemd/src/systemd/sd-dhcp-option.h
+++ b/src/systemd/src/systemd/sd-dhcp-option.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosddhcpoptionhfoo
#define foosddhcpoptionhfoo
diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h
index 2b0d63a527..75ee27d68b 100644
--- a/src/systemd/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/src/systemd/sd-dhcp6-client.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosddhcp6clienthfoo
#define foosddhcp6clienthfoo
diff --git a/src/systemd/src/systemd/sd-dhcp6-lease.h b/src/systemd/src/systemd/sd-dhcp6-lease.h
index 240df74af8..f77b31acf9 100644
--- a/src/systemd/src/systemd/sd-dhcp6-lease.h
+++ b/src/systemd/src/systemd/sd-dhcp6-lease.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosddhcp6leasehfoo
#define foosddhcp6leasehfoo
diff --git a/src/systemd/src/systemd/sd-dhcp6-option.h b/src/systemd/src/systemd/sd-dhcp6-option.h
index 88a4986315..ddb2c7cecd 100644
--- a/src/systemd/src/systemd/sd-dhcp6-option.h
+++ b/src/systemd/src/systemd/sd-dhcp6-option.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosddhcp6optionhfoo
#define foosddhcp6optionhfoo
diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h
index 3a53c3d27d..2ae2a0da48 100644
--- a/src/systemd/src/systemd/sd-event.h
+++ b/src/systemd/src/systemd/sd-event.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosdeventhfoo
#define foosdeventhfoo
@@ -162,6 +162,9 @@ int sd_event_source_get_floating(sd_event_source *s);
int sd_event_source_set_floating(sd_event_source *s, int b);
int sd_event_source_get_exit_on_failure(sd_event_source *s);
int sd_event_source_set_exit_on_failure(sd_event_source *s, int b);
+int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst);
+int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst);
+int sd_event_source_is_ratelimited(sd_event_source *s);
/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);
diff --git a/src/systemd/src/systemd/sd-id128.h b/src/systemd/src/systemd/sd-id128.h
index 9b00b76ea6..02aa318a06 100644
--- a/src/systemd/src/systemd/sd-id128.h
+++ b/src/systemd/src/systemd/sd-id128.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosdid128hfoo
#define foosdid128hfoo
diff --git a/src/systemd/src/systemd/sd-ipv4acd.h b/src/systemd/src/systemd/sd-ipv4acd.h
index ebf723fc22..2809d8748b 100644
--- a/src/systemd/src/systemd/sd-ipv4acd.h
+++ b/src/systemd/src/systemd/sd-ipv4acd.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosdipv4acdfoo
#define foosdipv4acdfoo
@@ -43,6 +43,8 @@ int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address);
int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata);
int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr);
int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index);
+int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd);
+const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd);
int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address);
int sd_ipv4acd_is_running(sd_ipv4acd *acd);
int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts);
diff --git a/src/systemd/src/systemd/sd-ipv4ll.h b/src/systemd/src/systemd/sd-ipv4ll.h
index 71bd4cfe48..aa4d174e4b 100644
--- a/src/systemd/src/systemd/sd-ipv4ll.h
+++ b/src/systemd/src/systemd/sd-ipv4ll.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosdipv4llfoo
#define foosdipv4llfoo
@@ -43,6 +43,8 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata);
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index);
+int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll);
+const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll);
int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address);
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed);
int sd_ipv4ll_is_running(sd_ipv4ll *ll);
diff --git a/src/systemd/src/systemd/sd-lldp.h b/src/systemd/src/systemd/sd-lldp.h
index c2abc20121..f551f6b4fa 100644
--- a/src/systemd/src/systemd/sd-lldp.h
+++ b/src/systemd/src/systemd/sd-lldp.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosdlldphfoo
#define foosdlldphfoo
diff --git a/src/systemd/src/systemd/sd-ndisc.h b/src/systemd/src/systemd/sd-ndisc.h
index 3ddfc8cb6d..c0e37899a7 100644
--- a/src/systemd/src/systemd/sd-ndisc.h
+++ b/src/systemd/src/systemd/sd-ndisc.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef foosdndiscfoo
#define foosdndiscfoo