summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-04-04 05:40:44 +0200
committerThomas Haller <thaller@redhat.com>2019-04-04 09:39:16 +0200
commitb6032223988616c7d5c6c5715521aff1c5a81e40 (patch)
tree82f821c11542897b303f7e3b13e4aa7c02d1a4a1
parent8372c0e9c0e6a035be1e6e046ceb8015e6f96782 (diff)
downloadNetworkManager-b6032223988616c7d5c6c5715521aff1c5a81e40.tar.gz
systemd: update code from upstream (2019-04-04)
This is a direct dump from systemd git. ====== SYSTEMD_DIR=../systemd COMMIT=6e79d2b5a414f49c05392cf5f52072c5f081442e ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files -z :/src/systemd/src/ \ :/shared/systemd/src/ \ :/shared/nm-utils/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_nmutils() { mkdir -p "./shared/nm-utils/" cp "$SYSTEMD_DIR/$1" "./shared/nm-utils/${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/shared/dns-domain.c" nm_copy_sd_core "src/shared/dns-domain.h" 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-dhcp6-client.h" nm_copy_sd_core "src/systemd/sd-dhcp6-lease.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_nmutils "src/basic/unaligned.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/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/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_socket.h" nm_copy_sd_shared "src/basic/missing_stat.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/set.h" 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/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/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"
-rw-r--r--shared/systemd/src/basic/alloc-util.c20
-rw-r--r--shared/systemd/src/basic/alloc-util.h14
-rw-r--r--shared/systemd/src/basic/env-file.c2
-rw-r--r--shared/systemd/src/basic/errno-util.h43
-rw-r--r--shared/systemd/src/basic/fd-util.c11
-rw-r--r--shared/systemd/src/basic/fd-util.h12
-rw-r--r--shared/systemd/src/basic/fileio.c4
-rw-r--r--shared/systemd/src/basic/fs-util.c104
-rw-r--r--shared/systemd/src/basic/fs-util.h4
-rw-r--r--shared/systemd/src/basic/hashmap.c15
-rw-r--r--shared/systemd/src/basic/hashmap.h2
-rw-r--r--shared/systemd/src/basic/hexdecoct.c9
-rw-r--r--shared/systemd/src/basic/in-addr-util.c138
-rw-r--r--shared/systemd/src/basic/in-addr-util.h4
-rw-r--r--shared/systemd/src/basic/log.h15
-rw-r--r--shared/systemd/src/basic/memory-util.c57
-rw-r--r--shared/systemd/src/basic/memory-util.h84
-rw-r--r--shared/systemd/src/basic/mempool.c1
-rw-r--r--shared/systemd/src/basic/missing_socket.h64
-rw-r--r--shared/systemd/src/basic/missing_stat.h51
-rw-r--r--shared/systemd/src/basic/path-util.c51
-rw-r--r--shared/systemd/src/basic/process-util.c53
-rw-r--r--shared/systemd/src/basic/process-util.h4
-rw-r--r--shared/systemd/src/basic/random-util.c11
-rw-r--r--shared/systemd/src/basic/refcnt.h54
-rw-r--r--shared/systemd/src/basic/socket-util.c59
-rw-r--r--shared/systemd/src/basic/socket-util.h3
-rw-r--r--shared/systemd/src/basic/sort-util.h70
-rw-r--r--shared/systemd/src/basic/stat-util.c46
-rw-r--r--shared/systemd/src/basic/stat-util.h3
-rw-r--r--shared/systemd/src/basic/stdio-util.h2
-rw-r--r--shared/systemd/src/basic/string-table.h8
-rw-r--r--shared/systemd/src/basic/string-util.c35
-rw-r--r--shared/systemd/src/basic/string-util.h33
-rw-r--r--shared/systemd/src/basic/strv.c3
-rw-r--r--shared/systemd/src/basic/strv.h2
-rw-r--r--shared/systemd/src/basic/time-util.c11
-rw-r--r--shared/systemd/src/basic/time-util.h1
-rw-r--r--shared/systemd/src/basic/utf8.c38
-rw-r--r--shared/systemd/src/basic/utf8.h2
-rw-r--r--shared/systemd/src/basic/util.c337
-rw-r--r--shared/systemd/src/basic/util.h172
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-identifier.c8
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-lease-internal.h4
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-network.c19
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-option.c6
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-option.c2
-rw-r--r--src/systemd/src/libsystemd-network/lldp-neighbor.c2
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.c97
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.h17
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-client.c26
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-lease.c78
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-client.c9
-rw-r--r--src/systemd/src/libsystemd-network/sd-ipv4acd.c2
-rw-r--r--src/systemd/src/libsystemd-network/sd-ipv4ll.c32
-rw-r--r--src/systemd/src/libsystemd-network/sd-lldp.c2
-rw-r--r--src/systemd/src/libsystemd/sd-event/sd-event.c4
-rw-r--r--src/systemd/src/libsystemd/sd-id128/sd-id128.c45
-rw-r--r--src/systemd/src/systemd/sd-dhcp-lease.h2
-rw-r--r--src/systemd/src/systemd/sd-event.h2
60 files changed, 1031 insertions, 978 deletions
diff --git a/shared/systemd/src/basic/alloc-util.c b/shared/systemd/src/basic/alloc-util.c
index ab7a42c4e2..1e4ee722f2 100644
--- a/shared/systemd/src/basic/alloc-util.c
+++ b/shared/systemd/src/basic/alloc-util.c
@@ -1,11 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <malloc.h>
#include <stdint.h>
#include <string.h>
#include "alloc-util.h"
#include "macro.h"
-#include "util.h"
+#include "memory-util.h"
void* memdup(const void *p, size_t l) {
void *ret;
@@ -27,6 +28,9 @@ void* memdup_suffix0(const void *p, size_t l) {
/* The same as memdup() but place a safety NUL byte after the allocated memory */
+ if (_unlikely_(l == SIZE_MAX)) /* prevent overflow */
+ return NULL;
+
ret = malloc(l + 1);
if (!ret)
return NULL;
@@ -45,19 +49,23 @@ void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
if (*allocated >= need)
return *p;
- newalloc = MAX(need * 2, 64u / size);
- a = newalloc * size;
+ if (_unlikely_(need > SIZE_MAX/2)) /* Overflow check */
+ return NULL;
- /* check for overflows */
- if (a < size * need)
+ newalloc = need * 2;
+ if (size_multiply_overflow(newalloc, size))
return NULL;
+ a = newalloc * size;
+ if (a < 64) /* Allocate at least 64 bytes */
+ a = 64;
+
q = realloc(*p, a);
if (!q)
return NULL;
*p = q;
- *allocated = newalloc;
+ *allocated = _unlikely_(size == 0) ? newalloc : malloc_usable_size(q) / size;
return q;
}
diff --git a/shared/systemd/src/basic/alloc-util.h b/shared/systemd/src/basic/alloc-util.h
index 893a1238ff..9b20be4773 100644
--- a/shared/systemd/src/basic/alloc-util.h
+++ b/shared/systemd/src/basic/alloc-util.h
@@ -8,6 +8,10 @@
#include "macro.h"
+#if HAS_FEATURE_MEMORY_SANITIZER
+# include <sanitizer/msan_interface.h>
+#endif
+
typedef void (*free_func_t)(void *p);
/* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than
@@ -152,11 +156,17 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
(void*)memset(_new_, 0, _xsize_); \
})
-/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to
- * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
+/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time
+ * resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
#define TAKE_PTR(ptr) \
({ \
typeof(ptr) _ptr_ = (ptr); \
(ptr) = NULL; \
_ptr_; \
})
+
+#if HAS_FEATURE_MEMORY_SANITIZER
+# define msan_unpoison(r, s) __msan_unpoison(r, s)
+#else
+# define msan_unpoison(r, s)
+#endif
diff --git a/shared/systemd/src/basic/env-file.c b/shared/systemd/src/basic/env-file.c
index 7f10f9ad39..a1f1308a54 100644
--- a/shared/systemd/src/basic/env-file.c
+++ b/shared/systemd/src/basic/env-file.c
@@ -559,6 +559,6 @@ int write_env_file(const char *fname, char **l) {
r = -errno;
}
- unlink(p);
+ (void) unlink(p);
return r;
}
diff --git a/shared/systemd/src/basic/errno-util.h b/shared/systemd/src/basic/errno-util.h
new file mode 100644
index 0000000000..615b6a806a
--- /dev/null
+++ b/shared/systemd/src/basic/errno-util.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "macro.h"
+
+static inline void _reset_errno_(int *saved_errno) {
+ if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
+ return;
+
+ errno = *saved_errno;
+}
+
+#define PROTECT_ERRNO \
+ _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
+
+#define UNPROTECT_ERRNO \
+ do { \
+ errno = _saved_errno_; \
+ _saved_errno_ = -1; \
+ } while (false)
+
+static inline int negative_errno(void) {
+ /* This helper should be used to shut up gcc if you know 'errno' is
+ * negative. Instead of "return -errno;", use "return negative_errno();"
+ * It will suppress bogus gcc warnings in case it assumes 'errno' might
+ * be 0 and thus the caller's error-handling might not be triggered. */
+ assert_return(errno > 0, -EINVAL);
+ return -errno;
+}
+
+/* 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 */
+#define ERRNO_IS_DISCONNECT(r) \
+ IN_SET(abs(r), \
+ ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, \
+ ENETUNREACH, EHOSTUNREACH, ENOPROTOOPT, EHOSTDOWN, \
+ ENONET, ESHUTDOWN)
+
+/* Resource exhaustion, could be our fault or general system trouble */
+#define ERRNO_IS_RESOURCE(r) \
+ IN_SET(abs(r), ENOMEM, EMFILE, ENFILE)
diff --git a/shared/systemd/src/basic/fd-util.c b/shared/systemd/src/basic/fd-util.c
index 3e6ef5a06a..b3b840145f 100644
--- a/shared/systemd/src/basic/fd-util.c
+++ b/shared/systemd/src/basic/fd-util.c
@@ -25,6 +25,10 @@
#include "util.h"
#include "tmpfile-util.h"
+/* The maximum number of iterations in the loop to close descriptors in the fallback case
+ * when /proc/self/fd/ is inaccessible. */
+#define MAX_FD_LOOP_LIMIT (1024*1024)
+
int close_nointr(int fd) {
assert(fd >= 0);
@@ -228,6 +232,13 @@ int close_all_fds(const int except[], size_t n_except) {
if (max_fd < 0)
return max_fd;
+ /* Refuse to do the loop over more too many elements. It's better to fail immediately than to
+ * spin the CPU for a long time. */
+ if (max_fd > MAX_FD_LOOP_LIMIT)
+ return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
+ "/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
+ max_fd);
+
for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
int q;
diff --git a/shared/systemd/src/basic/fd-util.h b/shared/systemd/src/basic/fd-util.h
index 4085a244d2..e490753caf 100644
--- a/shared/systemd/src/basic/fd-util.h
+++ b/shared/systemd/src/basic/fd-util.h
@@ -77,18 +77,6 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags);
int fd_duplicate_data_fd(int fd);
-/* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */
-/* 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 */
-#define ERRNO_IS_DISCONNECT(r) \
- IN_SET(r, \
- ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, \
- ENETUNREACH, EHOSTUNREACH, ENOPROTOOPT, EHOSTDOWN, ENONET)
-
-/* Resource exhaustion, could be our fault or general system trouble */
-#define ERRNO_IS_RESOURCE(r) \
- IN_SET(r, ENOMEM, EMFILE, ENFILE)
-
int fd_move_above_stdio(int fd);
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd);
diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c
index e18b842999..91e0c9ec8b 100644
--- a/shared/systemd/src/basic/fileio.c
+++ b/shared/systemd/src/basic/fileio.c
@@ -212,7 +212,6 @@ int write_string_filef(
int read_one_line_file(const char *fn, char **line) {
_cleanup_fclose_ FILE *f = NULL;
- int r;
assert(fn);
assert(line);
@@ -223,8 +222,7 @@ int read_one_line_file(const char *fn, char **line) {
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
- r = read_line(f, LONG_LINE_MAX, line);
- return r < 0 ? r : 0;
+ return read_line(f, LONG_LINE_MAX, line);
}
int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c
index f25bf2cbbc..d1c06cf12a 100644
--- a/shared/systemd/src/basic/fs-util.c
+++ b/shared/systemd/src/basic/fs-util.c
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <linux/falloc.h>
#include <linux/magic.h>
#include <time.h>
#include <unistd.h>
@@ -214,64 +215,109 @@ int readlink_and_make_absolute(const char *p, char **r) {
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
char fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
_cleanup_close_ int fd = -1;
+ bool st_valid = false;
+ struct stat st;
+ int r;
+
assert(path);
- /* Under the assumption that we are running privileged we first change the access mode and only then hand out
- * ownership to avoid a window where access is too open. */
+ /* Under the assumption that we are running privileged we first change the access mode and only then
+ * hand out ownership to avoid a window where access is too open. */
- fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change mode/owner
- * on the same file */
+ fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change
+ * mode/owner on the same file */
if (fd < 0)
return -errno;
xsprintf(fd_path, "/proc/self/fd/%i", fd);
if (mode != MODE_INVALID) {
-
if ((mode & S_IFMT) != 0) {
- struct stat st;
if (stat(fd_path, &st) < 0)
return -errno;
if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
return -EINVAL;
+
+ st_valid = true;
}
- if (chmod(fd_path, mode & 07777) < 0)
- return -errno;
+ if (chmod(fd_path, mode & 07777) < 0) {
+ r = -errno;
+
+ if (!st_valid && stat(fd_path, &st) < 0)
+ return -errno;
+
+ if ((mode & 07777) != (st.st_mode & 07777))
+ return r;
+
+ st_valid = true;
+ }
}
- if (uid != UID_INVALID || gid != GID_INVALID)
- if (chown(fd_path, uid, gid) < 0)
- return -errno;
+ if (uid != UID_INVALID || gid != GID_INVALID) {
+ if (chown(fd_path, uid, gid) < 0) {
+ r = -errno;
+
+ if (!st_valid && stat(fd_path, &st) < 0)
+ return -errno;
+
+ if (uid != UID_INVALID && st.st_uid != uid)
+ return r;
+ if (gid != GID_INVALID && st.st_gid != gid)
+ return r;
+ }
+ }
return 0;
}
int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
+ bool st_valid = false;
+ struct stat st;
+ int r;
+
/* Under the assumption that we are running privileged we first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
if (mode != MODE_INVALID) {
-
if ((mode & S_IFMT) != 0) {
- struct stat st;
if (fstat(fd, &st) < 0)
return -errno;
if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
return -EINVAL;
+
+ st_valid = true;
}
- if (fchmod(fd, mode & 0777) < 0)
- return -errno;
+ if (fchmod(fd, mode & 07777) < 0) {
+ r = -errno;
+
+ if (!st_valid && fstat(fd, &st) < 0)
+ return -errno;
+
+ if ((mode & 07777) != (st.st_mode & 07777))
+ return r;
+
+ st_valid = true;
+ }
}
if (uid != UID_INVALID || gid != GID_INVALID)
- if (fchown(fd, uid, gid) < 0)
- return -errno;
+ if (fchown(fd, uid, gid) < 0) {
+ r = -errno;
+
+ if (!st_valid && fstat(fd, &st) < 0)
+ return -errno;
+
+ if (uid != UID_INVALID && st.st_uid != uid)
+ return r;
+ if (gid != GID_INVALID && st.st_gid != gid)
+ return r;
+ }
return 0;
}
@@ -307,6 +353,10 @@ int fd_warn_permissions(const char *path, int fd) {
if (fstat(fd, &st) < 0)
return -errno;
+ /* Don't complain if we are reading something that is not a file, for example /dev/null */
+ if (!S_ISREG(st.st_mode))
+ return 0;
+
if (st.st_mode & 0111)
log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
@@ -925,6 +975,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (fstat(child, &st) < 0)
return -errno;
if ((flags & CHASE_SAFE) &&
+ (empty_or_root(root) || (size_t)(todo - buffer) > strlen(root)) &&
unsafe_transition(&previous_stat, &st))
return log_unsafe_transition(fd, child, path, flags);
@@ -1329,6 +1380,21 @@ int fsync_path_at(int at_fd, const char *path) {
return 0;
}
+int syncfs_path(int atfd, const char *path) {
+ _cleanup_close_ int fd = -1;
+
+ assert(path);
+
+ fd = openat(atfd, path, O_CLOEXEC|O_RDONLY|O_NONBLOCK);
+ if (fd < 0)
+ return -errno;
+
+ if (syncfs(fd) < 0)
+ return -errno;
+
+ return 0;
+}
+
int open_parent(const char *path, int flags, mode_t mode) {
_cleanup_free_ char *parent = NULL;
int fd;
@@ -1345,9 +1411,9 @@ int open_parent(const char *path, int flags, mode_t mode) {
/* Let's insist on O_DIRECTORY since the parent of a file or directory is a directory. Except if we open an
* O_TMPFILE file, because in that case we are actually create a regular file below the parent directory. */
- if ((flags & O_PATH) == O_PATH)
+ if (FLAGS_SET(flags, O_PATH))
flags |= O_DIRECTORY;
- else if ((flags & O_TMPFILE) != O_TMPFILE)
+ else if (!FLAGS_SET(flags, O_TMPFILE))
flags |= O_DIRECTORY|O_RDONLY;
fd = open(parent, flags, mode);
diff --git a/shared/systemd/src/basic/fs-util.h b/shared/systemd/src/basic/fs-util.h
index 7ad030be5d..b9651205e6 100644
--- a/shared/systemd/src/basic/fs-util.h
+++ b/shared/systemd/src/basic/fs-util.h
@@ -10,8 +10,8 @@
#include <sys/types.h>
#include <unistd.h>
+#include "errno-util.h"
#include "time-util.h"
-#include "util.h"
int unlink_noerrno(const char *path);
@@ -108,4 +108,6 @@ int unlinkat_deallocate(int fd, const char *name, int flags);
int fsync_directory_of_file(int fd);
int fsync_path_at(int at_fd, const char *path);
+int syncfs_path(int atfd, const char *path);
+
int open_parent(const char *path, int flags, mode_t mode);
diff --git a/shared/systemd/src/basic/hashmap.c b/shared/systemd/src/basic/hashmap.c
index f2e33d2265..c7bd7323a1 100644
--- a/shared/systemd/src/basic/hashmap.c
+++ b/shared/systemd/src/basic/hashmap.c
@@ -9,6 +9,7 @@
#include "fileio.h"
#include "hashmap.h"
#include "macro.h"
+#include "memory-util.h"
#include "mempool.h"
#include "process-util.h"
#include "random-util.h"
@@ -16,7 +17,6 @@
#include "siphash24.h"
#include "string-util.h"
#include "strv.h"
-#include "util.h"
#if ENABLE_DEBUG_HASHMAP
#include <pthread.h>
@@ -888,7 +888,8 @@ void internal_hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_f
* themselves from our hash table a second time, the entry is already gone. */
while (internal_hashmap_size(h) > 0) {
- void *v, *k;
+ void *k = NULL;
+ void *v;
v = internal_hashmap_first_key_and_value(h, true, &k);
@@ -1515,8 +1516,11 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r
unsigned idx;
idx = find_first_entry(h);
- if (idx == IDX_NIL)
+ if (idx == IDX_NIL) {
+ if (ret_key)
+ *ret_key = NULL;
return NULL;
+ }
e = bucket_at(h, idx);
key = (void*) e->key;
@@ -1532,7 +1536,6 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r
}
unsigned internal_hashmap_size(HashmapBase *h) {
-
if (!h)
return 0;
@@ -1540,7 +1543,6 @@ unsigned internal_hashmap_size(HashmapBase *h) {
}
unsigned internal_hashmap_buckets(HashmapBase *h) {
-
if (!h)
return 0;
@@ -1900,8 +1902,7 @@ IteratedCache *iterated_cache_free(IteratedCache *cache) {
if (cache) {
free(cache->keys.ptr);
free(cache->values.ptr);
- free(cache);
}
- return NULL;
+ return mfree(cache);
}
diff --git a/shared/systemd/src/basic/hashmap.h b/shared/systemd/src/basic/hashmap.h
index e16a9f9e30..41c8adb16b 100644
--- a/shared/systemd/src/basic/hashmap.h
+++ b/shared/systemd/src/basic/hashmap.h
@@ -412,9 +412,11 @@ static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_key);
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_key);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free);
#define _cleanup_hashmap_free_ _cleanup_(hashmap_freep)
diff --git a/shared/systemd/src/basic/hexdecoct.c b/shared/systemd/src/basic/hexdecoct.c
index c0f96409fd..a5660a0ff3 100644
--- a/shared/systemd/src/basic/hexdecoct.c
+++ b/shared/systemd/src/basic/hexdecoct.c
@@ -8,8 +8,8 @@
#include "alloc-util.h"
#include "hexdecoct.h"
#include "macro.h"
+#include "memory-util.h"
#include "string-util.h"
-#include "util.h"
char octchar(int x) {
return '0' + (x & 7);
@@ -601,10 +601,11 @@ static int base64_append_width(
lines = DIV_ROUND_UP(len, width);
slen = strlen_ptr(sep);
- if (lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1))
+ if (plen >= SSIZE_MAX - 1 - slen ||
+ lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1))
return -ENOMEM;
- t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
+ t = realloc(*prefix, (ssize_t) plen + 1 + slen + (indent + width + 1) * lines);
if (!t)
return -ENOMEM;
@@ -639,7 +640,7 @@ int base64_append(
return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
else
/* leave plen on the left, keep last column free */
- return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
+ return base64_append_width(prefix, plen, " ", plen, p, l, width - plen - 1);
}
static int unbase64_next(const char **p, size_t *l) {
diff --git a/shared/systemd/src/basic/in-addr-util.c b/shared/systemd/src/basic/in-addr-util.c
index 2bffe473ca..1d5c6412b5 100644
--- a/shared/systemd/src/basic/in-addr-util.c
+++ b/shared/systemd/src/basic/in-addr-util.c
@@ -5,12 +5,15 @@
#include <errno.h>
#include <net/if.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include "alloc-util.h"
#include "in-addr-util.h"
#include "macro.h"
#include "parse-util.h"
+#include "random-util.h"
+#include "strxcpyx.h"
#include "util.h"
bool in4_addr_is_null(const struct in_addr *a) {
@@ -68,6 +71,14 @@ bool in4_addr_is_localhost(const struct in_addr *a) {
return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
}
+bool in4_addr_is_non_local(const struct in_addr *a) {
+ /* Whether the address is not null and not localhost.
+ *
+ * As such, it is suitable to configure as DNS/NTP server from DHCP. */
+ return !in4_addr_is_null(a) &&
+ !in4_addr_is_localhost(a);
+}
+
int in_addr_is_localhost(int family, const union in_addr_union *u) {
assert(u);
@@ -207,8 +218,85 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen)
return -EAFNOSUPPORT;
}
+int in_addr_random_prefix(
+ int family,
+ union in_addr_union *u,
+ unsigned prefixlen_fixed_part,
+ unsigned prefixlen) {
+
+ assert(u);
+
+ /* Random network part of an address by one. */
+
+ if (prefixlen <= 0)
+ return 0;
+
+ if (family == AF_INET) {
+ uint32_t c, n;
+
+ if (prefixlen_fixed_part > 32)
+ prefixlen_fixed_part = 32;
+ if (prefixlen > 32)
+ prefixlen = 32;
+ if (prefixlen_fixed_part >= prefixlen)
+ return -EINVAL;
+
+ c = be32toh(u->in.s_addr);
+ c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
+
+ random_bytes(&n, sizeof(n));
+ n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
+
+ u->in.s_addr = htobe32(n | c);
+ return 1;
+ }
+
+ if (family == AF_INET6) {
+ struct in6_addr n;
+ unsigned i, j;
+
+ if (prefixlen_fixed_part > 128)
+ prefixlen_fixed_part = 128;
+ if (prefixlen > 128)
+ prefixlen = 128;
+ if (prefixlen_fixed_part >= prefixlen)
+ return -EINVAL;
+
+ random_bytes(&n, sizeof(n));
+
+ for (i = 0; i < 16; i++) {
+ uint8_t mask_fixed_part = 0, mask = 0;
+
+ if (i < (prefixlen_fixed_part + 7) / 8) {
+ if (i < prefixlen_fixed_part / 8)
+ mask_fixed_part = 0xffu;
+ else {
+ j = prefixlen_fixed_part % 8;
+ mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j);
+ }
+ }
+
+ if (i < (prefixlen + 7) / 8) {
+ if (i < prefixlen / 8)
+ mask = 0xffu ^ mask_fixed_part;
+ else {
+ j = prefixlen % 8;
+ mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part;
+ }
+ }
+
+ u->in6.s6_addr[i] &= mask_fixed_part;
+ u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
+ }
+
+ return 1;
+ }
+
+ return -EAFNOSUPPORT;
+}
+
int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
- char *x;
+ _cleanup_free_ char *x = NULL;
size_t l;
assert(u);
@@ -226,18 +314,50 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
return -ENOMEM;
errno = 0;
- if (!inet_ntop(family, u, x, l)) {
- free(x);
+ if (!inet_ntop(family, u, x, l))
return errno > 0 ? -errno : -EINVAL;
- }
- *ret = x;
+ *ret = TAKE_PTR(x);
+ return 0;
+}
+
+int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) {
+ _cleanup_free_ char *x = NULL;
+ char *p;
+ size_t l;
+
+ assert(u);
+ assert(ret);
+
+ if (family == AF_INET)
+ l = INET_ADDRSTRLEN + 3;
+ else if (family == AF_INET6)
+ l = INET6_ADDRSTRLEN + 4;
+ else
+ return -EAFNOSUPPORT;
+
+ if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
+ return -EINVAL;
+
+ x = new(char, l);
+ if (!x)
+ return -ENOMEM;
+
+ errno = 0;
+ if (!inet_ntop(family, u, x, l))
+ return errno > 0 ? -errno : -EINVAL;
+
+ p = x + strlen(x);
+ l -= strlen(x);
+ (void) strpcpyf(&p, l, "/%u", prefixlen);
+
+ *ret = TAKE_PTR(x);
return 0;
}
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
+ _cleanup_free_ char *x = NULL;
size_t l;
- char *x;
int r;
assert(u);
@@ -263,14 +383,12 @@ int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifin
return -ENOMEM;
errno = 0;
- if (!inet_ntop(family, u, x, l)) {
- free(x);
+ if (!inet_ntop(family, u, x, l))
return errno > 0 ? -errno : -EINVAL;
- }
sprintf(strchr(x, 0), "%%%i", ifindex);
- *ret = x;
+ *ret = TAKE_PTR(x);
return 0;
fallback:
diff --git a/shared/systemd/src/basic/in-addr-util.h b/shared/systemd/src/basic/in-addr-util.h
index 3069790519..a6a685b918 100644
--- a/shared/systemd/src/basic/in-addr-util.h
+++ b/shared/systemd/src/basic/in-addr-util.h
@@ -30,10 +30,14 @@ int in_addr_is_link_local(int family, const union in_addr_union *u);
bool in4_addr_is_localhost(const struct in_addr *a);
int in_addr_is_localhost(int family, const union in_addr_union *u);
+bool in4_addr_is_non_local(const struct in_addr *a);
+
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
+int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen);
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
+int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
diff --git a/shared/systemd/src/basic/log.h b/shared/systemd/src/basic/log.h
index 17438d7ff7..aa3d5b75f1 100644
--- a/shared/systemd/src/basic/log.h
+++ b/shared/systemd/src/basic/log.h
@@ -115,6 +115,19 @@ int log_internalv_realm(
log_internalv_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__)
/* Realm is fixed to LOG_REALM_SYSTEMD for those */
+int log_object_internalv(
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const char *object_field,
+ const char *object,
+ const char *extra_field,
+ const char *extra,
+ const char *format,
+ va_list ap) _printf_(10,0);
+
int log_object_internal(
int level,
int error,
@@ -308,7 +321,7 @@ int log_syntax_invalid_utf8_internal(
int _level = (level), _e = (error); \
(log_get_max_level() >= LOG_PRI(_level)) \
? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
- : -abs(_e); \
+ : -ERRNO_VALUE(_e); \
})
#define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \
diff --git a/shared/systemd/src/basic/memory-util.c b/shared/systemd/src/basic/memory-util.c
new file mode 100644
index 0000000000..5f327ef0d7
--- /dev/null
+++ b/shared/systemd/src/basic/memory-util.c
@@ -0,0 +1,57 @@
+#include <unistd.h>
+
+#include "memory-util.h"
+
+size_t page_size(void) {
+ static thread_local size_t pgsz = 0;
+ long r;
+
+ if (_likely_(pgsz > 0))
+ return pgsz;
+
+ r = sysconf(_SC_PAGESIZE);
+ assert(r > 0);
+
+ pgsz = (size_t) r;
+ return pgsz;
+}
+
+bool memeqzero(const void *data, size_t length) {
+ /* Does the buffer consist entirely of NULs?
+ * Copied from https://github.com/systemd/casync/, copied in turn from
+ * https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
+ * which is licensed CC-0.
+ */
+
+ const uint8_t *p = data;
+ size_t i;
+
+ /* Check first 16 bytes manually */
+ for (i = 0; i < 16; i++, length--) {
+ if (length == 0)
+ return true;
+ if (p[i])
+ return false;
+ }
+
+ /* Now we know first 16 bytes are NUL, memcmp with self. */
+ return memcmp(data, p + i, length) == 0;
+}
+
+#if !HAVE_EXPLICIT_BZERO
+/*
+ * The pointer to memset() is volatile so that compiler must de-reference the pointer and can't assume that
+ * it points to any function in particular (such as memset(), which it then might further "optimize"). This
+ * approach is inspired by openssl's crypto/mem_clr.c.
+ */
+typedef void *(*memset_t)(void *,int,size_t);
+
+static volatile memset_t memset_func = memset;
+
+void* explicit_bzero_safe(void *p, size_t l) {
+ if (l > 0)
+ memset_func(p, '\0', l);
+
+ return p;
+}
+#endif
diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h
new file mode 100644
index 0000000000..915c24a5dd
--- /dev/null
+++ b/shared/systemd/src/basic/memory-util.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "macro.h"
+
+size_t page_size(void) _pure_;
+#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
+
+/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
+static inline void memcpy_safe(void *dst, const void *src, size_t n) {
+ if (n == 0)
+ return;
+ assert(src);
+ memcpy(dst, src, n);
+}
+
+/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */
+static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
+ if (n == 0)
+ return 0;
+ assert(s1);
+ assert(s2);
+ return memcmp(s1, s2, n);
+}
+
+/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */
+static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) {
+ return memcmp_safe(s1, s2, MIN(n1, n2))
+ ?: CMP(n1, n2);
+}
+
+#define memzero(x,l) \
+ ({ \
+ size_t _l_ = (l); \
+ void *_x_ = (x); \
+ _l_ == 0 ? _x_ : memset(_x_, 0, _l_); \
+ })
+
+#define zero(x) (memzero(&(x), sizeof(x)))
+
+bool memeqzero(const void *data, size_t length);
+
+#define eqzero(x) memeqzero(x, sizeof(x))
+
+static inline void *mempset(void *s, int c, size_t n) {
+ memset(s, c, n);
+ return (uint8_t*)s + n;
+}
+
+/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
+static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
+
+ if (needlelen <= 0)
+ return (void*) haystack;
+
+ if (haystacklen < needlelen)
+ return NULL;
+
+ assert(haystack);
+ assert(needle);
+
+ return memmem(haystack, haystacklen, needle, needlelen);
+}
+
+#if HAVE_EXPLICIT_BZERO
+static inline void* explicit_bzero_safe(void *p, size_t l) {
+ if (l > 0)
+ explicit_bzero(p, l);
+
+ return p;
+}
+#else
+void *explicit_bzero_safe(void *p, size_t l);
+#endif
+
+/* Use with _cleanup_ to erase a single 'char' when leaving scope */
+static inline void erase_char(char *p) {
+ explicit_bzero_safe(p, sizeof(char));
+}
diff --git a/shared/systemd/src/basic/mempool.c b/shared/systemd/src/basic/mempool.c
index 159c963377..22df42105b 100644
--- a/shared/systemd/src/basic/mempool.c
+++ b/shared/systemd/src/basic/mempool.c
@@ -5,6 +5,7 @@
#include "env-util.h"
#include "macro.h"
+#include "memory-util.h"
#include "mempool.h"
#include "process-util.h"
#include "util.h"
diff --git a/shared/systemd/src/basic/missing_socket.h b/shared/systemd/src/basic/missing_socket.h
new file mode 100644
index 0000000000..276be366c3
--- /dev/null
+++ b/shared/systemd/src/basic/missing_socket.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <sys/socket.h>
+
+#if HAVE_LINUX_VM_SOCKETS_H
+#include <linux/vm_sockets.h>
+#else
+#define VMADDR_CID_ANY -1U
+struct sockaddr_vm {
+ unsigned short svm_family;
+ unsigned short svm_reserved1;
+ unsigned int svm_port;
+ unsigned int svm_cid;
+ unsigned char svm_zero[sizeof(struct sockaddr) -
+ sizeof(unsigned short) -
+ sizeof(unsigned short) -
+ sizeof(unsigned int) -
+ sizeof(unsigned int)];
+};
+#endif /* !HAVE_LINUX_VM_SOCKETS_H */
+
+#ifndef AF_VSOCK
+#define AF_VSOCK 40
+#endif
+
+#ifndef SO_REUSEPORT
+#define SO_REUSEPORT 15
+#endif
+
+#ifndef SO_PEERGROUPS
+#define SO_PEERGROUPS 59
+#endif
+
+#ifndef SO_BINDTOIFINDEX
+#define SO_BINDTOIFINDEX 62
+#endif
+
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
+/* Not exposed yet. Defined in include/linux/socket.h. */
+#ifndef SOL_SCTP
+#define SOL_SCTP 132
+#endif
+
+/* Not exposed yet. Defined in include/linux/socket.h */
+#ifndef SCM_SECURITY
+#define SCM_SECURITY 0x03
+#endif
+
+/* netinet/in.h */
+#ifndef IP_FREEBIND
+#define IP_FREEBIND 15
+#endif
+
+#ifndef IP_TRANSPARENT
+#define IP_TRANSPARENT 19
+#endif
diff --git a/shared/systemd/src/basic/missing_stat.h b/shared/systemd/src/basic/missing_stat.h
new file mode 100644
index 0000000000..5116206a2e
--- /dev/null
+++ b/shared/systemd/src/basic/missing_stat.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/types.h>
+#include <sys/stat.h>
+
+#if WANT_LINUX_STAT_H
+#include <linux/stat.h>
+#endif
+
+/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
+#if !HAVE_STRUCT_STATX
+struct statx_timestamp {
+ __s64 tv_sec;
+ __u32 tv_nsec;
+ __s32 __reserved;
+};
+struct statx {
+ __u32 stx_mask;
+ __u32 stx_blksize;
+ __u64 stx_attributes;
+ __u32 stx_nlink;
+ __u32 stx_uid;
+ __u32 stx_gid;
+ __u16 stx_mode;
+ __u16 __spare0[1];
+ __u64 stx_ino;
+ __u64 stx_size;
+ __u64 stx_blocks;
+ __u64 stx_attributes_mask;
+ struct statx_timestamp stx_atime;
+ struct statx_timestamp stx_btime;
+ struct statx_timestamp stx_ctime;
+ struct statx_timestamp stx_mtime;
+ __u32 stx_rdev_major;
+ __u32 stx_rdev_minor;
+ __u32 stx_dev_major;
+ __u32 stx_dev_minor;
+ __u64 __spare2[14];
+};
+#endif
+
+/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
+#ifndef STATX_BTIME
+#define STATX_BTIME 0x00000800U
+#endif
+
+/* a528d35e8bfcc521d7cb70aaf03e1bd296c8493f (4.11) */
+#ifndef AT_STATX_DONT_SYNC
+#define AT_STATX_DONT_SYNC 0x4000
+#endif
diff --git a/shared/systemd/src/basic/path-util.c b/shared/systemd/src/basic/path-util.c
index 221517303e..55cb140d87 100644
--- a/shared/systemd/src/basic/path-util.c
+++ b/shared/systemd/src/basic/path-util.c
@@ -21,6 +21,7 @@
#include "log.h"
#include "macro.h"
#include "missing.h"
+#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "stat-util.h"
@@ -1103,48 +1104,40 @@ int path_simplify_and_warn(
unsigned line,
const char *lvalue) {
- bool absolute, fatal = flag & PATH_CHECK_FATAL;
+ bool fatal = flag & PATH_CHECK_FATAL;
assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
- if (!utf8_is_valid(path)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
- return -EINVAL;
- }
+ if (!utf8_is_valid(path))
+ return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
+ bool absolute;
+
absolute = path_is_absolute(path);
- if (!absolute && (flag & PATH_CHECK_ABSOLUTE)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "%s= path is not absolute%s: %s",
- lvalue, fatal ? "" : ", ignoring", path);
- return -EINVAL;
- }
+ if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
+ return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+ "%s= path is not absolute%s: %s",
+ lvalue, fatal ? "" : ", ignoring", path);
- if (absolute && (flag & PATH_CHECK_RELATIVE)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "%s= path is absolute%s: %s",
- lvalue, fatal ? "" : ", ignoring", path);
- return -EINVAL;
- }
+ if (absolute && (flag & PATH_CHECK_RELATIVE))
+ return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+ "%s= path is absolute%s: %s",
+ lvalue, fatal ? "" : ", ignoring", path);
}
path_simplify(path, true);
- if (!path_is_normalized(path)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "%s= path is not normalized%s: %s",
- lvalue, fatal ? "" : ", ignoring", path);
- return -EINVAL;
- }
+ if (!path_is_valid(path))
+ return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+ "%s= path has invalid length (%zu bytes)%s.",
+ lvalue, strlen(path), fatal ? "" : ", ignoring");
- if (!path_is_valid(path)) {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "%s= path has invalid length (%zu bytes)%s.",
- lvalue, strlen(path), fatal ? "" : ", ignoring");
- return -EINVAL;
- }
+ if (!path_is_normalized(path))
+ return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+ "%s= path is not normalized%s: %s",
+ lvalue, fatal ? "" : ", ignoring", path);
return 0;
}
diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c
index 78ce43b944..f773eeaffd 100644
--- a/shared/systemd/src/basic/process-util.c
+++ b/shared/systemd/src/basic/process-util.c
@@ -32,7 +32,9 @@
#include "ioprio.h"
#include "log.h"
#include "macro.h"
+#include "memory-util.h"
#include "missing.h"
+#include "namespace-util.h"
#include "process-util.h"
#include "raw-clone.h"
#include "rlimit-util.h"
@@ -42,7 +44,6 @@
#include "string-util.h"
#include "terminal-util.h"
#include "user-util.h"
-#include "util.h"
int get_process_state(pid_t pid) {
const char *p;
@@ -933,6 +934,20 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) {
return 0;
}
+int pid_is_my_child(pid_t pid) {
+ pid_t ppid;
+ int r;
+
+ if (pid <= 1)
+ return false;
+
+ r = get_process_ppid(pid, &ppid);
+ if (r < 0)
+ return r;
+
+ return ppid == getpid_cached();
+}
+
bool pid_is_unwaited(pid_t pid) {
/* Checks whether a PID is still valid at all, including a zombie */
@@ -1000,7 +1015,7 @@ _noreturn_ void freeze(void) {
log_close();
/* Make sure nobody waits for us on a socket anymore */
- close_all_fds(NULL, 0);
+ (void) close_all_fds(NULL, 0);
sync();
@@ -1534,6 +1549,40 @@ int set_oom_score_adjust(int value) {
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
}
+int cpus_in_affinity_mask(void) {
+ size_t n = 16;
+ int r;
+
+ for (;;) {
+ cpu_set_t *c;
+
+ c = CPU_ALLOC(n);
+ if (!c)
+ return -ENOMEM;
+
+ if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) {
+ int k;
+
+ k = CPU_COUNT_S(CPU_ALLOC_SIZE(n), c);
+ CPU_FREE(c);
+
+ if (k <= 0)
+ return -EINVAL;
+
+ return k;
+ }
+
+ r = -errno;
+ CPU_FREE(c);
+
+ if (r != -EINVAL)
+ return r;
+ if (n > SIZE_MAX/2)
+ return -ENOMEM;
+ n *= 2;
+ }
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
diff --git a/shared/systemd/src/basic/process-util.h b/shared/systemd/src/basic/process-util.h
index c85ea30ecc..7e1d65a7bf 100644
--- a/shared/systemd/src/basic/process-util.h
+++ b/shared/systemd/src/basic/process-util.h
@@ -12,6 +12,7 @@
#include <sys/resource.h>
#include <sys/types.h>
+#include "alloc-util.h"
#include "format-util.h"
#include "ioprio.h"
#include "macro.h"
@@ -68,6 +69,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value);
bool pid_is_alive(pid_t pid);
bool pid_is_unwaited(pid_t pid);
+int pid_is_my_child(pid_t pid);
int pid_from_same_root_fs(pid_t pid);
bool is_main_thread(void);
@@ -192,3 +194,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX)
(pid) = 0; \
_pid_; \
})
+
+int cpus_in_affinity_mask(void);
diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c
index f7decf60b6..ca25fd2420 100644
--- a/shared/systemd/src/basic/random-util.c
+++ b/shared/systemd/src/basic/random-util.c
@@ -23,16 +23,13 @@
# include <linux/random.h>
#endif
+#include "alloc-util.h"
#include "fd-util.h"
#include "io-util.h"
#include "missing.h"
#include "random-util.h"
#include "time-util.h"
-#if HAS_FEATURE_MEMORY_SANITIZER
-#include <sanitizer/msan_interface.h>
-#endif
-
int rdrand(unsigned long *ret) {
#if defined(__i386__) || defined(__x86_64__)
@@ -58,11 +55,7 @@ int rdrand(unsigned long *ret) {
"setc %1"
: "=r" (*ret),
"=qm" (err));
-
-#if HAS_FEATURE_MEMORY_SANITIZER
- __msan_unpoison(&err, sizeof(err));
-#endif
-
+ msan_unpoison(&err, sizeof(err));
if (!err)
return -EAGAIN;
diff --git a/shared/systemd/src/basic/refcnt.h b/shared/systemd/src/basic/refcnt.h
deleted file mode 100644
index 40f9a84a22..0000000000
--- a/shared/systemd/src/basic/refcnt.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
-#pragma once
-
-/* A type-safe atomic refcounter.
- *
- * DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */
-
-typedef struct {
- volatile unsigned _value;
-} RefCount;
-
-#define REFCNT_GET(r) ((r)._value)
-#define REFCNT_INC(r) (__sync_add_and_fetch(&(r)._value, 1))
-#define REFCNT_DEC(r) (__sync_sub_and_fetch(&(r)._value, 1))
-
-#define REFCNT_INIT ((RefCount) { ._value = 1 })
-
-#define _DEFINE_ATOMIC_REF_FUNC(type, name, scope) \
- scope type *name##_ref(type *p) { \
- if (!p) \
- return NULL; \
- \
- assert_se(REFCNT_INC(p->n_ref) >= 2); \
- return p; \
- }
-
-#define _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, scope) \
- scope type *name##_unref(type *p) { \
- if (!p) \
- return NULL; \
- \
- if (REFCNT_DEC(p->n_ref) > 0) \
- return NULL; \
- \
- return free_func(p); \
- }
-
-#define DEFINE_ATOMIC_REF_FUNC(type, name) \
- _DEFINE_ATOMIC_REF_FUNC(type, name,)
-#define DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name) \
- _DEFINE_ATOMIC_REF_FUNC(type, name, _public_)
-
-#define DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func) \
- _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func,)
-#define DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func) \
- _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, _public_)
-
-#define DEFINE_ATOMIC_REF_UNREF_FUNC(type, name, free_func) \
- DEFINE_ATOMIC_REF_FUNC(type, name); \
- DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func);
-
-#define DEFINE_PUBLIC_ATOMIC_REF_UNREF_FUNC(type, name, free_func) \
- DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name); \
- DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func);
diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c
index 91bf801cdf..3d929f5418 100644
--- a/shared/systemd/src/basic/socket-util.c
+++ b/shared/systemd/src/basic/socket-util.c
@@ -21,6 +21,7 @@
#include "format-util.h"
#include "log.h"
#include "macro.h"
+#include "memory-util.h"
#include "missing.h"
#include "parse-util.h"
#include "path-util.h"
@@ -31,7 +32,6 @@
#include "strv.h"
#include "user-util.h"
#include "utf8.h"
-#include "util.h"
#if ENABLE_IDN
# define IDN_FLAGS NI_IDN
@@ -235,23 +235,32 @@ int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
}
int socket_address_parse_netlink(SocketAddress *a, const char *s) {
- int family;
+ _cleanup_free_ char *word = NULL;
unsigned group = 0;
- _cleanup_free_ char *sfamily = NULL;
+ int family, r;
+
assert(a);
assert(s);
zero(*a);
a->type = SOCK_RAW;
- errno = 0;
- if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
- return errno > 0 ? -errno : -EINVAL;
+ r = extract_first_word(&s, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EINVAL;
- family = netlink_family_from_string(sfamily);
+ family = netlink_family_from_string(word);
if (family < 0)
return -EINVAL;
+ if (!isempty(s)) {
+ r = safe_atou(s, &group);
+ if (r < 0)
+ return r;
+ }
+
a->sockaddr.nl.nl_family = AF_NETLINK;
a->sockaddr.nl.nl_groups = group;
@@ -1345,3 +1354,39 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
return (int) (offsetof(struct sockaddr_un, sun_path) + l + 1); /* include trailing NUL in size */
}
}
+
+int socket_bind_to_ifname(int fd, const char *ifname) {
+ assert(fd >= 0);
+
+ /* Call with NULL to drop binding */
+
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen_ptr(ifname)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int socket_bind_to_ifindex(int fd, int ifindex) {
+ char ifname[IFNAMSIZ] = "";
+
+ assert(fd >= 0);
+
+ if (ifindex <= 0) {
+ /* Drop binding */
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0) < 0)
+ return -errno;
+
+ return 0;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDTOIFINDEX, &ifindex, sizeof(ifindex)) >= 0)
+ return 0;
+ if (errno != ENOPROTOOPT)
+ return -errno;
+
+ /* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */
+ if (!if_indextoname(ifindex, ifname))
+ return -errno;
+
+ return socket_bind_to_ifname(fd, ifname);
+}
diff --git a/shared/systemd/src/basic/socket-util.h b/shared/systemd/src/basic/socket-util.h
index 574d2b73f5..6920fd99ba 100644
--- a/shared/systemd/src/basic/socket-util.h
+++ b/shared/systemd/src/basic/socket-util.h
@@ -198,3 +198,6 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) {
return 0;
}
+
+int socket_bind_to_ifname(int fd, const char *ifname);
+int socket_bind_to_ifindex(int fd, int ifindex);
diff --git a/shared/systemd/src/basic/sort-util.h b/shared/systemd/src/basic/sort-util.h
new file mode 100644
index 0000000000..e029f8646e
--- /dev/null
+++ b/shared/systemd/src/basic/sort-util.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdlib.h>
+
+#include "macro.h"
+
+void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
+ __compar_d_fn_t compar, void *arg);
+
+#define typesafe_bsearch_r(k, b, n, func, userdata) \
+ ({ \
+ const typeof(b[0]) *_k = k; \
+ int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
+ xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
+ })
+
+/**
+ * Normal bsearch requires base to be nonnull. Here were require
+ * that only if nmemb > 0.
+ */
+static inline void* bsearch_safe(const void *key, const void *base,
+ size_t nmemb, size_t size, __compar_fn_t compar) {
+ if (nmemb <= 0)
+ return NULL;
+
+ assert(base);
+ return bsearch(key, base, nmemb, size, compar);
+}
+
+#define typesafe_bsearch(k, b, n, func) \
+ ({ \
+ const typeof(b[0]) *_k = k; \
+ int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
+ bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
+ })
+
+/**
+ * Normal qsort requires base to be nonnull. Here were require
+ * that only if nmemb > 0.
+ */
+static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
+ if (nmemb <= 1)
+ return;
+
+ assert(base);
+ qsort(base, nmemb, size, compar);
+}
+
+/* A wrapper around the above, but that adds typesafety: the element size is automatically derived from the type and so
+ * is the prototype for the comparison function */
+#define typesafe_qsort(p, n, func) \
+ ({ \
+ int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
+ qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
+ })
+
+static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
+ if (nmemb <= 1)
+ return;
+
+ assert(base);
+ qsort_r(base, nmemb, size, compar, userdata);
+}
+
+#define typesafe_qsort_r(p, n, func, userdata) \
+ ({ \
+ int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
+ qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
+ })
diff --git a/shared/systemd/src/basic/stat-util.c b/shared/systemd/src/basic/stat-util.c
index ea2bbc368b..2cd722c106 100644
--- a/shared/systemd/src/basic/stat-util.c
+++ b/shared/systemd/src/basic/stat-util.c
@@ -223,52 +223,6 @@ int fd_is_network_fs(int fd) {
return is_network_fs(&s);
}
-int fd_is_network_ns(int fd) {
- struct statfs s;
- int r;
-
- /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
- * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
- * this somewhat nicely.
- *
- * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
- * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
-
- if (fstatfs(fd, &s) < 0)
- return -errno;
-
- if (!is_fs_type(&s, NSFS_MAGIC)) {
- /* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs
- * instead. Handle that in a somewhat smart way. */
-
- if (is_fs_type(&s, PROC_SUPER_MAGIC)) {
- struct statfs t;
-
- /* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the
- * passed fd might refer to a network namespace, but we can't know for sure. In that case,
- * return a recognizable error. */
-
- if (statfs("/proc/self/ns/net", &t) < 0)
- return -errno;
-
- if (s.f_type == t.f_type)
- return -EUCLEAN; /* It's possible, we simply don't know */
- }
-
- return 0; /* No! */
- }
-
- r = ioctl(fd, NS_GET_NSTYPE);
- if (r < 0) {
- if (errno == ENOTTY) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */
- return -EUCLEAN;
-
- return -errno;
- }
-
- return r == CLONE_NEWNET;
-}
-
int path_is_temporary_fs(const char *path) {
_cleanup_close_ int fd = -1;
diff --git a/shared/systemd/src/basic/stat-util.h b/shared/systemd/src/basic/stat-util.h
index 74fb7251b3..7824af3500 100644
--- a/shared/systemd/src/basic/stat-util.h
+++ b/shared/systemd/src/basic/stat-util.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/stat.h>
@@ -50,8 +51,6 @@ bool is_network_fs(const struct statfs *s) _pure_;
int fd_is_temporary_fs(int fd);
int fd_is_network_fs(int fd);
-int fd_is_network_ns(int fd);
-
int path_is_temporary_fs(const char *path);
/* Because statfs.t_type can be int on some architectures, we have to cast
diff --git a/shared/systemd/src/basic/stdio-util.h b/shared/systemd/src/basic/stdio-util.h
index dc67b6e761..c3b9448d4f 100644
--- a/shared/systemd/src/basic/stdio-util.h
+++ b/shared/systemd/src/basic/stdio-util.h
@@ -7,7 +7,7 @@
#include <sys/types.h>
#include "macro.h"
-#include "util.h"
+#include "memory-util.h"
#define snprintf_ok(buf, len, fmt, ...) \
((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len))
diff --git a/shared/systemd/src/basic/string-table.h b/shared/systemd/src/basic/string-table.h
index 228c12ad00..42fe4f4315 100644
--- a/shared/systemd/src/basic/string-table.h
+++ b/shared/systemd/src/basic/string-table.h
@@ -59,13 +59,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \
scope type name##_from_string(const char *s) { \
- type i; \
unsigned u = 0; \
+ type i; \
if (!s) \
return (type) -1; \
- for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \
- if (streq_ptr(name##_table[i], s)) \
- return i; \
+ i = (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
+ if (i >= 0) \
+ return i; \
if (safe_atou(s, &u) >= 0 && u <= max) \
return (type) u; \
return (type) -1; \
diff --git a/shared/systemd/src/basic/string-util.c b/shared/systemd/src/basic/string-util.c
index 93917bc0f0..5001a2be3a 100644
--- a/shared/systemd/src/basic/string-util.c
+++ b/shared/systemd/src/basic/string-util.c
@@ -10,14 +10,15 @@
#include "alloc-util.h"
#include "escape.h"
+#include "fileio.h"
#include "gunicode.h"
#include "locale-util.h"
#include "macro.h"
+#include "memory-util.h"
#include "string-util.h"
#include "terminal-util.h"
#include "utf8.h"
#include "util.h"
-#include "fileio.h"
int strcmp_ptr(const char *a, const char *b) {
@@ -675,19 +676,6 @@ char *cellescape(char *buf, size_t len, const char *s) {
return buf;
}
-bool nulstr_contains(const char *nulstr, const char *needle) {
- const char *i;
-
- if (!nulstr)
- return false;
-
- NULSTR_FOREACH(i, nulstr)
- if (streq(i, needle))
- return true;
-
- return false;
-}
-
char* strshorten(char *s, size_t l) {
assert(s);
@@ -1048,25 +1036,6 @@ int free_and_strndup(char **p, const char *s, size_t l) {
return 1;
}
-#if !HAVE_EXPLICIT_BZERO
-/*
- * Pointer to memset is volatile so that compiler must de-reference
- * the pointer and can't assume that it points to any function in
- * particular (such as memset, which it then might further "optimize")
- * This approach is inspired by openssl's crypto/mem_clr.c.
- */
-typedef void *(*memset_t)(void *,int,size_t);
-
-static volatile memset_t memset_func = memset;
-
-void* explicit_bzero_safe(void *p, size_t l) {
- if (l > 0)
- memset_func(p, '\0', l);
-
- return p;
-}
-#endif
-
char* string_erase(char *x) {
if (!x)
return NULL;
diff --git a/shared/systemd/src/basic/string-util.h b/shared/systemd/src/basic/string-util.h
index 38070abb22..9cf11198b1 100644
--- a/shared/systemd/src/basic/string-util.h
+++ b/shared/systemd/src/basic/string-util.h
@@ -165,8 +165,6 @@ char *cellescape(char *buf, size_t len, const char *s);
/* This limit is arbitrary, enough to give some idea what the string contains */
#define CELLESCAPE_DEFAULT_LENGTH 64
-bool nulstr_contains(const char *nulstr, const char *needle);
-
char* strshorten(char *s, size_t l);
char *strreplace(const char *text, const char *old_string, const char *new_string);
@@ -182,33 +180,12 @@ char *strrep(const char *s, unsigned n);
int split_pair(const char *s, const char *sep, char **l, char **r);
int free_and_strdup(char **p, const char *s);
-int free_and_strndup(char **p, const char *s, size_t l);
-
-/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
-static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
-
- if (needlelen <= 0)
- return (void*) haystack;
-
- if (haystacklen < needlelen)
- return NULL;
-
- assert(haystack);
- assert(needle);
-
- return memmem(haystack, haystacklen, needle, needlelen);
-}
-
-#if HAVE_EXPLICIT_BZERO
-static inline void* explicit_bzero_safe(void *p, size_t l) {
- if (l > 0)
- explicit_bzero(p, l);
-
- return p;
+static inline int free_and_strdup_warn(char **p, const char *s) {
+ if (free_and_strdup(p, s) < 0)
+ return log_oom();
+ return 0;
}
-#else
-void *explicit_bzero_safe(void *p, size_t l);
-#endif
+int free_and_strndup(char **p, const char *s, size_t l);
char *string_erase(char *x);
diff --git a/shared/systemd/src/basic/strv.c b/shared/systemd/src/basic/strv.c
index 3a62f25ded..21c106149b 100644
--- a/shared/systemd/src/basic/strv.c
+++ b/shared/systemd/src/basic/strv.c
@@ -11,9 +11,10 @@
#include "escape.h"
#include "extract-word.h"
#include "fileio.h"
+#include "nulstr-util.h"
+#include "sort-util.h"
#include "string-util.h"
#include "strv.h"
-#include "util.h"
char *strv_find(char **l, const char *name) {
char **i;
diff --git a/shared/systemd/src/basic/strv.h b/shared/systemd/src/basic/strv.h
index 392cab65be..aa5f95ab72 100644
--- a/shared/systemd/src/basic/strv.h
+++ b/shared/systemd/src/basic/strv.h
@@ -5,12 +5,12 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdio.h>
#include "alloc-util.h"
#include "extract-word.h"
#include "macro.h"
#include "string-util.h"
-#include "util.h"
char *strv_find(char **l, const char *name) _pure_;
char *strv_find_prefix(char **l, const char *name) _pure_;
diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c
index 62cdc305f9..daf952baa1 100644
--- a/shared/systemd/src/basic/time-util.c
+++ b/shared/systemd/src/basic/time-util.c
@@ -1031,6 +1031,15 @@ int parse_sec_fix_0(const char *t, usec_t *ret) {
return r;
}
+int parse_sec_def_infinity(const char *t, usec_t *ret) {
+ t += strspn(t, WHITESPACE);
+ if (isempty(t)) {
+ *ret = USEC_INFINITY;
+ return 0;
+ }
+ return parse_sec(t, ret);
+}
+
static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
static const struct {
const char *suffix;
@@ -1205,7 +1214,7 @@ int get_timezones(char ***ret) {
n_allocated = 2;
n_zones = 1;
- f = fopen("/usr/share/zoneinfo/zone.tab", "re");
+ f = fopen("/usr/share/zoneinfo/zone1970.tab", "re");
if (f) {
for (;;) {
_cleanup_free_ char *line = NULL;
diff --git a/shared/systemd/src/basic/time-util.h b/shared/systemd/src/basic/time-util.h
index 5316305062..a238f6914d 100644
--- a/shared/systemd/src/basic/time-util.h
+++ b/shared/systemd/src/basic/time-util.h
@@ -112,6 +112,7 @@ int parse_timestamp(const char *t, usec_t *usec);
int parse_sec(const char *t, usec_t *usec);
int parse_sec_fix_0(const char *t, usec_t *usec);
+int parse_sec_def_infinity(const char *t, usec_t *usec);
int parse_time(const char *t, usec_t *usec, usec_t default_unit);
int parse_nsec(const char *t, nsec_t *nsec);
diff --git a/shared/systemd/src/basic/utf8.c b/shared/systemd/src/basic/utf8.c
index e0d1949dc7..090c69d140 100644
--- a/shared/systemd/src/basic/utf8.c
+++ b/shared/systemd/src/basic/utf8.c
@@ -61,12 +61,7 @@ static bool unichar_is_control(char32_t ch) {
}
/* count of characters used to encode one unicode char */
-static size_t utf8_encoded_expected_len(const char *str) {
- uint8_t c;
-
- assert(str);
-
- c = (uint8_t) str[0];
+static size_t utf8_encoded_expected_len(uint8_t c) {
if (c < 0x80)
return 1;
if ((c & 0xe0) == 0xc0)
@@ -90,7 +85,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
assert(str);
- len = utf8_encoded_expected_len(str);
+ len = utf8_encoded_expected_len(str[0]);
switch (len) {
case 1:
@@ -133,14 +128,14 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
assert(str);
- for (p = str; length;) {
+ for (p = str; length > 0;) {
int encoded_len, r;
char32_t val;
- encoded_len = utf8_encoded_valid_unichar(p);
- if (encoded_len < 0 ||
- (size_t) encoded_len > length)
+ encoded_len = utf8_encoded_valid_unichar(p, length);
+ if (encoded_len < 0)
return false;
+ assert(encoded_len > 0 && (size_t) encoded_len <= length);
r = utf8_encoded_to_unichar(p, &val);
if (r < 0 ||
@@ -164,7 +159,7 @@ char *utf8_is_valid(const char *str) {
while (*p) {
int len;
- len = utf8_encoded_valid_unichar(p);
+ len = utf8_encoded_valid_unichar(p, (size_t) -1);
if (len < 0)
return NULL;
@@ -186,7 +181,7 @@ char *utf8_escape_invalid(const char *str) {
while (*str) {
int len;
- len = utf8_encoded_valid_unichar(str);
+ len = utf8_encoded_valid_unichar(str, (size_t) -1);
if (len > 0) {
s = mempcpy(s, str, len);
str += len;
@@ -213,7 +208,7 @@ char *utf8_escape_non_printable(const char *str) {
while (*str) {
int len;
- len = utf8_encoded_valid_unichar(str);
+ len = utf8_encoded_valid_unichar(str, (size_t) -1);
if (len > 0) {
if (utf8_is_printable(str, len)) {
s = mempcpy(s, str, len);
@@ -405,7 +400,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length) {
char32_t unichar;
size_t e;
- e = utf8_encoded_expected_len(s + i);
+ e = utf8_encoded_expected_len(s[i]);
if (e <= 1) /* Invalid and single byte characters are copied as they are */
goto copy;
@@ -457,17 +452,24 @@ static int utf8_unichar_to_encoded_len(char32_t unichar) {
}
/* validate one encoded unicode char and return its length */
-int utf8_encoded_valid_unichar(const char *str) {
+int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) {
char32_t unichar;
size_t len, i;
int r;
assert(str);
+ assert(length > 0);
- len = utf8_encoded_expected_len(str);
+ /* We read until NUL, at most length bytes. (size_t) -1 may be used to disable the length check. */
+
+ len = utf8_encoded_expected_len(str[0]);
if (len == 0)
return -EINVAL;
+ /* Do we have a truncated multi-byte character? */
+ if (len > length)
+ return -EINVAL;
+
/* ascii is valid */
if (len == 1)
return 1;
@@ -500,7 +502,7 @@ size_t utf8_n_codepoints(const char *str) {
while (*str != 0) {
int k;
- k = utf8_encoded_valid_unichar(str);
+ k = utf8_encoded_valid_unichar(str, (size_t) -1);
if (k < 0)
return (size_t) -1;
diff --git a/shared/systemd/src/basic/utf8.h b/shared/systemd/src/basic/utf8.h
index 628456936e..6df70921db 100644
--- a/shared/systemd/src/basic/utf8.h
+++ b/shared/systemd/src/basic/utf8.h
@@ -32,7 +32,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length);
size_t char16_strlen(const char16_t *s); /* returns the number of 16bit words in the string (not bytes!) */
-int utf8_encoded_valid_unichar(const char *str);
+int utf8_encoded_valid_unichar(const char *str, size_t length);
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar);
static inline bool utf16_is_surrogate(char16_t c) {
diff --git a/shared/systemd/src/basic/util.c b/shared/systemd/src/basic/util.c
index e577c93e60..93d610bc98 100644
--- a/shared/systemd/src/basic/util.c
+++ b/shared/systemd/src/basic/util.c
@@ -19,7 +19,6 @@
#include "alloc-util.h"
#include "btrfs-util.h"
#include "build.h"
-#include "cgroup-util.h"
#include "def.h"
#include "device-nodes.h"
#include "dirent-util.h"
@@ -52,33 +51,6 @@ int saved_argc = 0;
char **saved_argv = NULL;
static int saved_in_initrd = -1;
-size_t page_size(void) {
- static thread_local size_t pgsz = 0;
- long r;
-
- if (_likely_(pgsz > 0))
- return pgsz;
-
- r = sysconf(_SC_PAGESIZE);
- assert(r > 0);
-
- pgsz = (size_t) r;
- return pgsz;
-}
-
-bool plymouth_running(void) {
- return access("/run/plymouth/pid", F_OK) >= 0;
-}
-
-bool display_is_local(const char *display) {
- assert(display);
-
- return
- display[0] == ':' &&
- display[1] >= '0' &&
- display[1] <= '9';
-}
-
bool kexec_loaded(void) {
_cleanup_free_ char *s = NULL;
@@ -141,53 +113,6 @@ void in_initrd_force(bool value) {
saved_in_initrd = value;
}
-/* hey glibc, APIs with callbacks without a user pointer are so useless */
-void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
- __compar_d_fn_t compar, void *arg) {
- size_t l, u, idx;
- const void *p;
- int comparison;
-
- assert(!size_multiply_overflow(nmemb, size));
-
- l = 0;
- u = nmemb;
- while (l < u) {
- idx = (l + u) / 2;
- p = (const uint8_t*) base + idx * size;
- comparison = compar(key, p, arg);
- if (comparison < 0)
- u = idx;
- else if (comparison > 0)
- l = idx + 1;
- else
- return (void *)p;
- }
- return NULL;
-}
-
-bool memeqzero(const void *data, size_t length) {
- /* Does the buffer consist entirely of NULs?
- * Copied from https://github.com/systemd/casync/, copied in turn from
- * https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
- * which is licensed CC-0.
- */
-
- const uint8_t *p = data;
- size_t i;
-
- /* Check first 16 bytes manually */
- for (i = 0; i < 16; i++, length--) {
- if (length == 0)
- return true;
- if (p[i])
- return false;
- }
-
- /* Now we know first 16 bytes are NUL, memcmp with self. */
- return memcmp(data, p + i, length) == 0;
-}
-
int on_ac_power(void) {
bool found_offline = false, found_online = false;
_cleanup_closedir_ DIR *d = NULL;
@@ -294,268 +219,6 @@ int container_get_leader(const char *machine, pid_t *pid) {
return 0;
}
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
- int rfd = -1;
-
- assert(pid >= 0);
-
- if (mntns_fd) {
- const char *mntns;
-
- mntns = procfs_file_alloca(pid, "ns/mnt");
- mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
- if (mntnsfd < 0)
- return -errno;
- }
-
- if (pidns_fd) {
- const char *pidns;
-
- pidns = procfs_file_alloca(pid, "ns/pid");
- pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
- if (pidnsfd < 0)
- return -errno;
- }
-
- if (netns_fd) {
- const char *netns;
-
- netns = procfs_file_alloca(pid, "ns/net");
- netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
- if (netnsfd < 0)
- return -errno;
- }
-
- if (userns_fd) {
- const char *userns;
-
- userns = procfs_file_alloca(pid, "ns/user");
- usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
- if (usernsfd < 0 && errno != ENOENT)
- return -errno;
- }
-
- if (root_fd) {
- const char *root;
-
- root = procfs_file_alloca(pid, "root");
- rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
- if (rfd < 0)
- return -errno;
- }
-
- if (pidns_fd)
- *pidns_fd = pidnsfd;
-
- if (mntns_fd)
- *mntns_fd = mntnsfd;
-
- if (netns_fd)
- *netns_fd = netnsfd;
-
- if (userns_fd)
- *userns_fd = usernsfd;
-
- if (root_fd)
- *root_fd = rfd;
-
- pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
-
- return 0;
-}
-
-int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
- if (userns_fd >= 0) {
- /* Can't setns to your own userns, since then you could
- * escalate from non-root to root in your own namespace, so
- * check if namespaces equal before attempting to enter. */
- _cleanup_free_ char *userns_fd_path = NULL;
- int r;
- if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
- return -ENOMEM;
-
- r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
- if (r < 0)
- return r;
- if (r)
- userns_fd = -1;
- }
-
- if (pidns_fd >= 0)
- if (setns(pidns_fd, CLONE_NEWPID) < 0)
- return -errno;
-
- if (mntns_fd >= 0)
- if (setns(mntns_fd, CLONE_NEWNS) < 0)
- return -errno;
-
- if (netns_fd >= 0)
- if (setns(netns_fd, CLONE_NEWNET) < 0)
- return -errno;
-
- if (userns_fd >= 0)
- if (setns(userns_fd, CLONE_NEWUSER) < 0)
- return -errno;
-
- if (root_fd >= 0) {
- if (fchdir(root_fd) < 0)
- return -errno;
-
- if (chroot(".") < 0)
- return -errno;
- }
-
- return reset_uid_gid();
-}
-
-uint64_t physical_memory(void) {
- _cleanup_free_ char *root = NULL, *value = NULL;
- uint64_t mem, lim;
- size_t ps;
- long sc;
- int r;
-
- /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
- * memory.
- *
- * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
- * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
-
- sc = sysconf(_SC_PHYS_PAGES);
- assert(sc > 0);
-
- ps = page_size();
- mem = (uint64_t) sc * (uint64_t) ps;
-
- r = cg_get_root_path(&root);
- if (r < 0) {
- log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m");
- return mem;
- }
-
- r = cg_all_unified();
- if (r < 0) {
- log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m");
- return mem;
- }
- if (r > 0) {
- r = cg_get_attribute("memory", root, "memory.max", &value);
- if (r < 0) {
- log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m");
- return mem;
- }
-
- if (streq(value, "max"))
- return mem;
- } else {
- r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value);
- if (r < 0) {
- log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m");
- return mem;
- }
- }
-
- r = safe_atou64(value, &lim);
- if (r < 0) {
- log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value);
- return mem;
- }
- if (lim == UINT64_MAX)
- return mem;
-
- /* Make sure the limit is a multiple of our own page size */
- lim /= ps;
- lim *= ps;
-
- return MIN(mem, lim);
-}
-
-uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
- uint64_t p, m, ps, r;
-
- assert(max > 0);
-
- /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
- * the result is a multiple of the page size (rounds down). */
-
- ps = page_size();
- assert(ps > 0);
-
- p = physical_memory() / ps;
- assert(p > 0);
-
- m = p * v;
- if (m / p != v)
- return UINT64_MAX;
-
- m /= max;
-
- r = m * ps;
- if (r / ps != m)
- return UINT64_MAX;
-
- return r;
-}
-
-uint64_t system_tasks_max(void) {
-
- uint64_t a = TASKS_MAX, b = TASKS_MAX;
- _cleanup_free_ char *root = NULL;
- int r;
-
- /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
- * limit:
- *
- * a) the maximum tasks value the kernel allows on this architecture
- * b) the cgroups pids_max attribute for the system
- * c) the kernel's configured maximum PID value
- *
- * And then pick the smallest of the three */
-
- r = procfs_tasks_get_limit(&a);
- if (r < 0)
- log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m");
-
- r = cg_get_root_path(&root);
- if (r < 0)
- log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m");
- else {
- _cleanup_free_ char *value = NULL;
-
- r = cg_get_attribute("pids", root, "pids.max", &value);
- if (r < 0)
- log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m");
- else if (!streq(value, "max")) {
- r = safe_atou64(value, &b);
- if (r < 0)
- log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m");
- }
- }
-
- return MIN3(TASKS_MAX,
- a <= 0 ? TASKS_MAX : a,
- b <= 0 ? TASKS_MAX : b);
-}
-
-uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
- uint64_t t, m;
-
- assert(max > 0);
-
- /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
- * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
-
- t = system_tasks_max();
- assert(t > 0);
-
- m = t * v;
- if (m / t != v) /* overflow? */
- return UINT64_MAX;
-
- return m / max;
-}
-
int version(void) {
puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n"
SYSTEMD_FEATURES);
diff --git a/shared/systemd/src/basic/util.h b/shared/systemd/src/basic/util.h
index f009d37d4c..25e6ab8112 100644
--- a/shared/systemd/src/basic/util.h
+++ b/shared/systemd/src/basic/util.h
@@ -1,34 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-#include <alloca.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <locale.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stddef.h>
#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/inotify.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/sysmacros.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "format-util.h"
-#include "macro.h"
-#include "time-util.h"
-size_t page_size(void) _pure_;
-#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
+#include "macro.h"
static inline const char* yes_no(bool b) {
return b ? "yes" : "no";
@@ -46,19 +21,14 @@ static inline const char* enable_disable(bool b) {
return b ? "enable" : "disable";
}
-bool plymouth_running(void);
-
-bool display_is_local(const char *display) _pure_;
-
-#define NULSTR_FOREACH(i, l) \
- for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
-
-#define NULSTR_FOREACH_PAIR(i, j, l) \
- for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
-
extern int saved_argc;
extern char **saved_argv;
+static inline void save_argc_argv(int argc, char **argv) {
+ saved_argc = argc;
+ saved_argv = argv;
+}
+
bool kexec_loaded(void);
int prot_from_flags(int flags) _const_;
@@ -66,129 +36,8 @@ int prot_from_flags(int flags) _const_;
bool in_initrd(void);
void in_initrd_force(bool value);
-void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
- __compar_d_fn_t compar, void *arg);
-
-#define typesafe_bsearch_r(k, b, n, func, userdata) \
- ({ \
- const typeof(b[0]) *_k = k; \
- int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
- xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
- })
-
-/**
- * Normal bsearch requires base to be nonnull. Here were require
- * that only if nmemb > 0.
- */
-static inline void* bsearch_safe(const void *key, const void *base,
- size_t nmemb, size_t size, __compar_fn_t compar) {
- if (nmemb <= 0)
- return NULL;
-
- assert(base);
- return bsearch(key, base, nmemb, size, compar);
-}
-
-#define typesafe_bsearch(k, b, n, func) \
- ({ \
- const typeof(b[0]) *_k = k; \
- int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
- bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
- })
-
-/**
- * Normal qsort requires base to be nonnull. Here were require
- * that only if nmemb > 0.
- */
-static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
- if (nmemb <= 1)
- return;
-
- assert(base);
- qsort(base, nmemb, size, compar);
-}
-
-/* A wrapper around the above, but that adds typesafety: the element size is automatically derived from the type and so
- * is the prototype for the comparison function */
-#define typesafe_qsort(p, n, func) \
- ({ \
- int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
- qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
- })
-
-static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
- if (nmemb <= 1)
- return;
-
- assert(base);
- qsort_r(base, nmemb, size, compar, userdata);
-}
-
-#define typesafe_qsort_r(p, n, func, userdata) \
- ({ \
- int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
- qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
- })
-
-/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
-static inline void memcpy_safe(void *dst, const void *src, size_t n) {
- if (n == 0)
- return;
- assert(src);
- memcpy(dst, src, n);
-}
-
-/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */
-static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
- if (n == 0)
- return 0;
- assert(s1);
- assert(s2);
- return memcmp(s1, s2, n);
-}
-
-/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */
-static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) {
- return memcmp_safe(s1, s2, MIN(n1, n2))
- ?: CMP(n1, n2);
-}
-
int on_ac_power(void);
-#define memzero(x,l) \
- ({ \
- size_t _l_ = (l); \
- void *_x_ = (x); \
- _l_ == 0 ? _x_ : memset(_x_, 0, _l_); \
- })
-
-#define zero(x) (memzero(&(x), sizeof(x)))
-
-bool memeqzero(const void *data, size_t length);
-
-#define eqzero(x) memeqzero(x, sizeof(x))
-
-static inline void *mempset(void *s, int c, size_t n) {
- memset(s, c, n);
- return (uint8_t*)s + n;
-}
-
-static inline void _reset_errno_(int *saved_errno) {
- errno = *saved_errno;
-}
-
-#define PROTECT_ERRNO \
- _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
-
-static inline int negative_errno(void) {
- /* This helper should be used to shut up gcc if you know 'errno' is
- * negative. Instead of "return -errno;", use "return negative_errno();"
- * It will suppress bogus gcc warnings in case it assumes 'errno' might
- * be 0 and thus the caller's error-handling might not be triggered. */
- assert_return(errno > 0, -EINVAL);
- return -errno;
-}
-
static inline unsigned u64log2(uint64_t n) {
#if __SIZEOF_LONG_LONG__ == 8
return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
@@ -228,15 +77,6 @@ static inline unsigned log2u_round_up(unsigned x) {
int container_get_leader(const char *machine, pid_t *pid);
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
-int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
-
-uint64_t physical_memory(void);
-uint64_t physical_memory_scale(uint64_t v, uint64_t max);
-
-uint64_t system_tasks_max(void);
-uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
-
int version(void);
int str_verscmp(const char *s1, const char *s2);
diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c
index 04bf64cce5..0c1ff34e5d 100644
--- a/src/systemd/src/libsystemd-network/dhcp-identifier.c
+++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c
@@ -12,6 +12,7 @@
#include "siphash24.h"
#include "sparse-endian.h"
#include "stdio-util.h"
+#include "udev-util.h"
#include "virt.h"
#define SYSTEMD_PEN 43793
@@ -182,6 +183,13 @@ int dhcp_identifier_set_iaid(
/* not yet ready */
return -EBUSY;
+ r = device_is_renaming(device);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ /* device is under renaming */
+ return -EBUSY;
+
name = net_get_name(device);
}
}
diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
index 9d245a9059..122042ab58 100644
--- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
@@ -41,7 +41,6 @@ struct sd_dhcp_lease {
/* each 0 if unset */
be32_t address;
be32_t server_address;
- be32_t router;
be32_t next_server;
bool have_subnet_mask;
@@ -50,6 +49,9 @@ struct sd_dhcp_lease {
bool have_broadcast;
be32_t broadcast;
+ struct in_addr *router;
+ size_t router_size;
+
struct in_addr *dns;
size_t dns_size;
diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c
index 0e5b4147a9..94c10ed14c 100644
--- a/src/systemd/src/libsystemd-network/dhcp-network.c
+++ b/src/systemd/src/libsystemd-network/dhcp-network.c
@@ -50,12 +50,16 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)), /* A <- DHCP header type */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0), /* header type == arp_type ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+
+ /* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally
+ * compare chaddr for ETH_ALEN bytes. */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 12), /* A (the MAC address length) == ETH_ALEN ? */
BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(&eth_mac->ether_addr_octet[0])), /* A <- 4 bytes of client's MAC */
BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */
@@ -68,6 +72,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
@@ -148,7 +153,6 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
.in.sin_addr.s_addr = address,
};
_cleanup_close_ int s = -1;
- char ifname[IF_NAMESIZE] = "";
int r;
s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
@@ -164,12 +168,9 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
return r;
if (ifindex > 0) {
- if (if_indextoname(ifindex, ifname) == 0)
- return -errno;
-
- r = setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
+ r = socket_bind_to_ifindex(s, ifindex);
if (r < 0)
- return -errno;
+ return r;
}
if (address == INADDR_ANY) {
diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c
index ad3f92546d..a68de4ff98 100644
--- a/src/systemd/src/libsystemd-network/dhcp-option.c
+++ b/src/systemd/src/libsystemd-network/dhcp-option.c
@@ -9,10 +9,10 @@
#include <string.h>
#include "alloc-util.h"
-#include "utf8.h"
-#include "strv.h"
-
#include "dhcp-internal.h"
+#include "memory-util.h"
+#include "strv.h"
+#include "utf8.h"
static int option_append(uint8_t options[], size_t size, size_t *offset,
uint8_t code, size_t optlen, const void *optval) {
diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c
index a2aac9a793..017402c53b 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-option.c
+++ b/src/systemd/src/libsystemd-network/dhcp6-option.c
@@ -14,10 +14,10 @@
#include "dhcp6-lease-internal.h"
#include "dhcp6-protocol.h"
#include "dns-domain.h"
+#include "memory-util.h"
#include "sparse-endian.h"
#include "strv.h"
#include "unaligned.h"
-#include "util.h"
typedef struct DHCP6StatusOption {
struct DHCP6Option option;
diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c
index f6db62594d..9bae4a3c6e 100644
--- a/src/systemd/src/libsystemd-network/lldp-neighbor.c
+++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c
@@ -7,9 +7,9 @@
#include "in-addr-util.h"
#include "lldp-internal.h"
#include "lldp-neighbor.h"
+#include "memory-util.h"
#include "missing.h"
#include "unaligned.h"
-#include "util.h"
static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) {
siphash24_compress(id->chassis_id, id->chassis_id_size, state);
diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c
index 0348e7fa9d..2154cf7eac 100644
--- a/src/systemd/src/libsystemd-network/network-internal.c
+++ b/src/systemd/src/libsystemd-network/network-internal.c
@@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "condition.h"
#include "conf-parser.h"
+#include "device-util.h"
#include "dhcp-lease-internal.h"
#include "ether-addr-util.h"
#include "hexdecoct.h"
@@ -40,31 +41,35 @@ const char *net_get_name(sd_device *device) {
int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
size_t l, sz = 0;
- const char *name = NULL;
+ const char *name;
int r;
uint8_t *v;
assert(device);
+ /* net_get_name() 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 device name. */
name = net_get_name(device);
if (!name)
- return -ENOENT;
+ (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 */
+ /* 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. */
+ /* 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;
}
@@ -95,33 +100,12 @@ bool net_match_config(Set *match_mac,
char * const *match_drivers,
char * const *match_types,
char * const *match_names,
- Condition *match_host,
- Condition *match_virt,
- Condition *match_kernel_cmdline,
- Condition *match_kernel_version,
- Condition *match_arch,
const struct ether_addr *dev_mac,
const char *dev_path,
- const char *dev_parent_driver,
const char *dev_driver,
const char *dev_type,
const char *dev_name) {
- if (match_host && condition_test(match_host) <= 0)
- return false;
-
- if (match_virt && condition_test(match_virt) <= 0)
- return false;
-
- if (match_kernel_cmdline && condition_test(match_kernel_cmdline) <= 0)
- return false;
-
- if (match_kernel_version && condition_test(match_kernel_version) <= 0)
- return false;
-
- if (match_arch && condition_test(match_arch) <= 0)
- return false;
-
if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
return false;
@@ -152,32 +136,31 @@ int config_parse_net_condition(const char *unit,
void *userdata) {
ConditionType cond = ltype;
- Condition **ret = data;
+ Condition **list = data, *c;
bool negate;
- Condition *c;
- _cleanup_free_ char *s = NULL;
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++;
- s = strdup(rvalue);
- if (!s)
- return log_oom();
-
- c = condition_new(cond, s, false, negate);
+ c = condition_new(cond, rvalue, false, negate);
if (!c)
return log_oom();
- if (*ret)
- condition_free(*ret);
+ /* Drop previous assignment. */
+ *list = condition_free_list_type(*list, cond);
- *ret = c;
+ LIST_PREPEND(conditions, *list, c);
return 0;
}
@@ -409,16 +392,33 @@ int config_parse_bridge_port_priority(
return 0;
}
-void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
- unsigned i;
+size_t serialize_in_addrs(FILE *f,
+ const struct in_addr *addresses,
+ size_t size,
+ bool with_leading_space,
+ bool (*predicate)(const struct in_addr *addr)) {
+ size_t count;
+ size_t i;
assert(f);
assert(addresses);
- assert(size);
- for (i = 0; i < size; i++)
- fprintf(f, "%s%s", inet_ntoa(addresses[i]),
- (i < (size - 1)) ? " ": "");
+ count = 0;
+
+ for (i = 0; i < size; i++) {
+ char sbuf[INET_ADDRSTRLEN];
+
+ if (predicate && !predicate(&addresses[i]))
+ continue;
+ if (with_leading_space)
+ fputc(' ', f);
+ else
+ with_leading_space = true;
+ fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f);
+ count++;
+ }
+
+ return count;
}
int deserialize_in_addrs(struct in_addr **ret, const char *string) {
@@ -452,7 +452,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) {
size++;
}
- *ret = TAKE_PTR(addresses);
+ *ret = size > 0 ? TAKE_PTR(addresses) : NULL;
return size;
}
@@ -521,6 +521,7 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz
fprintf(f, "%s=", key);
for (i = 0; i < size; i++) {
+ char sbuf[INET_ADDRSTRLEN];
struct in_addr dest, gw;
uint8_t length;
@@ -528,8 +529,8 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz
assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
- fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length);
- fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": "");
+ fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof(sbuf)), length);
+ fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof(sbuf)), (i < (size - 1)) ? " ": "");
}
fputs("\n", f);
diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h
index 0c8da848c1..62f5a4a76c 100644
--- a/src/systemd/src/libsystemd-network/network-internal.h
+++ b/src/systemd/src/libsystemd-network/network-internal.h
@@ -6,9 +6,10 @@
#include "sd-device.h"
#include "sd-dhcp-lease.h"
-#include "condition.h"
#include "conf-parser.h"
+#include "def.h"
#include "set.h"
+#include "strv.h"
#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128
#define LINK_BRIDGE_PORT_PRIORITY_MAX 63
@@ -18,14 +19,8 @@ bool net_match_config(Set *match_mac,
char * const *match_driver,
char * const *match_type,
char * const *match_name,
- Condition *match_host,
- Condition *match_virt,
- Condition *match_kernel_cmdline,
- Condition *match_kernel_version,
- Condition *match_arch,
const struct ether_addr *dev_mac,
const char *dev_path,
- const char *dev_parent_driver,
const char *dev_driver,
const char *dev_type,
const char *dev_name);
@@ -40,7 +35,11 @@ CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority);
int net_get_unique_predictable_data(sd_device *device, uint64_t *result);
const char *net_get_name(sd_device *device);
-void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size);
+size_t serialize_in_addrs(FILE *f,
+ const struct in_addr *addresses,
+ size_t size,
+ bool with_leading_space,
+ bool (*predicate)(const struct in_addr *addr));
int deserialize_in_addrs(struct in_addr **addresses, const char *string);
void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
size_t size);
@@ -54,3 +53,5 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t
/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
+
+#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network"))
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
index 35fc88ef91..97e1dd3702 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
@@ -24,10 +24,10 @@
#include "event-util.h"
#include "hostname-util.h"
#include "io-util.h"
+#include "memory-util.h"
#include "random-util.h"
#include "string-util.h"
#include "strv.h"
-#include "util.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
@@ -1676,8 +1676,7 @@ static int client_receive_message_udp(
sd_dhcp_client *client = userdata;
_cleanup_free_ DHCPMessage *message = NULL;
- const struct ether_addr zero_mac = {};
- const struct ether_addr *expected_chaddr = NULL;
+ const uint8_t *expected_chaddr = NULL;
uint8_t expected_hlen = 0;
ssize_t len, buflen;
@@ -1685,6 +1684,12 @@ static int client_receive_message_udp(
assert(client);
buflen = next_datagram_size_fd(fd);
+ 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;
@@ -1694,7 +1699,8 @@ static int client_receive_message_udp(
len = recv(fd, message, buflen, 0);
if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ /* see comment above for why we shouldn't error out on ENETDOWN. */
+ if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
return 0;
return log_dhcp_client_errno(client, errno,
@@ -1722,11 +1728,7 @@ static int client_receive_message_udp(
if (client->arp_type == ARPHRD_ETHER) {
expected_hlen = ETH_ALEN;
- expected_chaddr = (const struct ether_addr *) &client->mac_addr;
- } else {
- /* Non-Ethernet links expect zero chaddr */
- expected_hlen = 0;
- expected_chaddr = &zero_mac;
+ expected_chaddr = &client->mac_addr[0];
}
if (message->hlen != expected_hlen) {
@@ -1734,7 +1736,7 @@ static int client_receive_message_udp(
return 0;
}
- if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
+ if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) {
log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
return 0;
}
@@ -1776,6 +1778,8 @@ static int client_receive_message_raw(
assert(client);
buflen = next_datagram_size_fd(fd);
+ if (buflen == -ENETDOWN)
+ return 0;
if (buflen < 0)
return buflen;
@@ -1787,7 +1791,7 @@ static int client_receive_message_raw(
len = recvmsg(fd, &msg, 0);
if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
return 0;
return log_dhcp_client_errno(client, errno,
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
index 13badbf0bf..a16314a9d3 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
@@ -9,6 +9,9 @@
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "sd-dhcp-lease.h"
@@ -151,15 +154,15 @@ int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
return 0;
}
-int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
+int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) {
assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL);
- if (lease->router == 0)
+ if (lease->router_size <= 0)
return -ENODATA;
- addr->s_addr = lease->router;
- return 0;
+ *addr = lease->router;
+ return (int) lease->router_size;
}
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
@@ -261,6 +264,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
}
free(lease->root_path);
+ free(lease->router);
free(lease->timezone);
free(lease->hostname);
free(lease->domainname);
@@ -370,23 +374,6 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
return 0;
}
-static void filter_bogus_addresses(struct in_addr *addresses, size_t *n) {
- size_t i, j;
-
- /* Silently filter DNS/NTP servers supplied to us that do not make outside of the local scope. */
-
- for (i = 0, j = 0; i < *n; i ++) {
-
- if (in4_addr_is_null(addresses+i) ||
- in4_addr_is_localhost(addresses+i))
- continue;
-
- addresses[j++] = addresses[i];
- }
-
- *n = j;
-}
-
static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
assert(option);
assert(ret);
@@ -408,8 +395,6 @@ static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_add
if (!addresses)
return -ENOMEM;
- filter_bogus_addresses(addresses, &n_addresses);
-
free(*ret);
*ret = addresses;
*n_ret = n_addresses;
@@ -554,11 +539,9 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
break;
case SD_DHCP_OPTION_ROUTER:
- if (len >= 4) {
- r = lease_parse_be32(option, 4, &lease->router);
- if (r < 0)
- log_debug_errno(r, "Failed to parse router address, ignoring: %m");
- }
+ r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse router addresses, ignoring: %m");
break;
case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
@@ -820,7 +803,6 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
if (!lease)
return -ENOMEM;
- lease->router = INADDR_ANY;
lease->n_ref = 1;
*ret = lease;
@@ -835,6 +817,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
const struct in_addr *addresses;
const void *client_id, *data;
size_t client_id_len, data_len;
+ char sbuf[INET_ADDRSTRLEN];
const char *string;
uint16_t mtu;
_cleanup_free_ sd_dhcp_route **routes = NULL;
@@ -857,27 +840,30 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = sd_dhcp_lease_get_address(lease, &address);
if (r >= 0)
- fprintf(f, "ADDRESS=%s\n", inet_ntoa(address));
+ fprintf(f, "ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
r = sd_dhcp_lease_get_netmask(lease, &address);
if (r >= 0)
- fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
+ fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
- r = sd_dhcp_lease_get_router(lease, &address);
- if (r >= 0)
- fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
+ r = sd_dhcp_lease_get_router(lease, &addresses);
+ if (r > 0) {
+ fputs("ROUTER=", f);
+ serialize_in_addrs(f, addresses, r, false, NULL);
+ fputc('\n', f);
+ }
r = sd_dhcp_lease_get_server_identifier(lease, &address);
if (r >= 0)
- fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address));
+ fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
r = sd_dhcp_lease_get_next_server(lease, &address);
if (r >= 0)
- fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
+ fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
r = sd_dhcp_lease_get_broadcast(lease, &address);
if (r >= 0)
- fprintf(f, "BROADCAST=%s\n", inet_ntoa(address));
+ fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
r = sd_dhcp_lease_get_mtu(lease, &mtu);
if (r >= 0)
@@ -898,15 +884,15 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = sd_dhcp_lease_get_dns(lease, &addresses);
if (r > 0) {
fputs("DNS=", f);
- serialize_in_addrs(f, addresses, r);
- fputs("\n", f);
+ serialize_in_addrs(f, addresses, r, false, NULL);
+ fputc('\n', f);
}
r = sd_dhcp_lease_get_ntp(lease, &addresses);
if (r > 0) {
fputs("NTP=", f);
- serialize_in_addrs(f, addresses, r);
- fputs("\n", f);
+ serialize_in_addrs(f, addresses, r, false, NULL);
+ fputc('\n', f);
}
r = sd_dhcp_lease_get_domainname(lease, &string);
@@ -917,7 +903,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
if (r > 0) {
fputs("DOMAIN_SEARCH_LIST=", f);
fputstrv(f, search_domains, NULL, NULL);
- fputs("\n", f);
+ fputc('\n', f);
}
r = sd_dhcp_lease_get_hostname(lease, &string);
@@ -1080,9 +1066,11 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
}
if (router) {
- r = inet_pton(AF_INET, router, &lease->router);
- if (r <= 0)
- log_debug("Failed to parse router %s, ignoring.", router);
+ r = deserialize_in_addrs(&lease->router, router);
+ if (r < 0)
+ log_debug_errno(r, "Failed to deserialize router addresses %s, ignoring: %m", router);
+ else
+ lease->router_size = r;
}
if (netmask) {
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
index 593ffd1b64..68b41dfb6c 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
@@ -1112,6 +1112,12 @@ static int client_receive_message(
assert(client->event);
buflen = next_datagram_size_fd(fd);
+ 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;
@@ -1121,7 +1127,8 @@ static int client_receive_message(
len = recv(fd, message, buflen, 0);
if (len < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ /* see comment above for why we shouldn't error out on ENETDOWN. */
+ if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
return 0;
return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c
index 59359aec79..c8e34497fd 100644
--- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c
@@ -21,7 +21,7 @@
#include "random-util.h"
#include "siphash24.h"
#include "string-util.h"
-#include "util.h"
+#include "time-util.h"
/* Constants from the RFC */
#define PROBE_WAIT_USEC (1U * USEC_PER_SEC)
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c
index e451dff744..a59a952326 100644
--- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c
@@ -218,28 +218,21 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) {
return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr });
}
-int sd_ipv4ll_restart(sd_ipv4ll *ll) {
- ll->address = 0;
-
- return sd_ipv4ll_start(ll);
-}
-
#define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
-int sd_ipv4ll_start(sd_ipv4ll *ll) {
+static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) {
int r;
bool picked_address = false;
assert_return(ll, -EINVAL);
assert_return(!ether_addr_is_null(&ll->mac), -EINVAL);
- assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
/* If no random seed is set, generate some from the MAC address */
if (!ll->seed_set)
ll->seed.value = htole64(siphash24(ll->mac.ether_addr_octet, ETH_ALEN, MAC_HASH_KEY.bytes));
- /* Restart the generation counter. */
- ll->seed.generation = 0;
+ if (reset_generation)
+ ll->seed.generation = 0;
if (ll->address == 0) {
r = ipv4ll_pick_address(ll);
@@ -263,6 +256,19 @@ int sd_ipv4ll_start(sd_ipv4ll *ll) {
return 0;
}
+int sd_ipv4ll_start(sd_ipv4ll *ll) {
+ assert_return(ll, -EINVAL);
+ assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
+
+ return ipv4ll_start_internal(ll, true);
+}
+
+int sd_ipv4ll_restart(sd_ipv4ll *ll) {
+ ll->address = 0;
+
+ return ipv4ll_start_internal(ll, false);
+}
+
static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
assert(ll);
@@ -298,11 +304,7 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
ll->claimed_address = 0;
} else {
- r = ipv4ll_pick_address(ll);
- if (r < 0)
- goto error;
-
- r = sd_ipv4acd_start(ll->acd);
+ r = sd_ipv4ll_restart(ll);
if (r < 0)
goto error;
}
diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c
index 969fc71051..1f28c5731f 100644
--- a/src/systemd/src/libsystemd-network/sd-lldp.c
+++ b/src/systemd/src/libsystemd-network/sd-lldp.c
@@ -13,7 +13,9 @@
#include "lldp-internal.h"
#include "lldp-neighbor.h"
#include "lldp-network.h"
+#include "memory-util.h"
#include "socket-util.h"
+#include "sort-util.h"
#include "string-table.h"
#define LLDP_DEFAULT_NEIGHBORS_MAX 128U
diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c
index 04ba7e2574..1987f279eb 100644
--- a/src/systemd/src/libsystemd/sd-event/sd-event.c
+++ b/src/systemd/src/libsystemd/sd-event/sd-event.c
@@ -15,6 +15,7 @@
#include "hashmap.h"
#include "list.h"
#include "macro.h"
+#include "memory-util.h"
#include "missing.h"
#include "prioq.h"
#include "process-util.h"
@@ -23,7 +24,6 @@
#include "string-table.h"
#include "string-util.h"
#include "time-util.h"
-#include "util.h"
#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
@@ -3116,7 +3116,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
timeout = 0;
m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
- timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC));
+ timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC));
if (m < 0) {
if (errno == EINTR) {
e->state = SD_EVENT_PENDING;
diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
index e72af1593c..e5f82b8863 100644
--- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
@@ -117,7 +117,6 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
}
static int get_invocation_from_keyring(sd_id128_t *ret) {
-
_cleanup_free_ char *description = NULL;
char *d, *p, *g, *u, *e;
unsigned long perms;
@@ -136,7 +135,7 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
if (key == -1) {
/* Keyring support not available? No invocation key stored? */
if (IN_SET(errno, ENOSYS, ENOKEY))
- return 0;
+ return -ENXIO;
return -errno;
}
@@ -212,7 +211,19 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
if (c != sizeof(sd_id128_t))
return -EIO;
- return 1;
+ return 0;
+}
+
+static int get_invocation_from_environment(sd_id128_t *ret) {
+ const char *e;
+
+ assert(ret);
+
+ e = secure_getenv("INVOCATION_ID");
+ if (!e)
+ return -ENXIO;
+
+ return sd_id128_from_string(e, ret);
}
_public_ int sd_id128_get_invocation(sd_id128_t *ret) {
@@ -222,31 +233,17 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
assert_return(ret, -EINVAL);
if (sd_id128_is_null(saved_invocation_id)) {
+ /* We first check the environment. The environment variable is primarily relevant for user
+ * services, and sufficiently safe as long as no privilege boundary is involved. */
+ r = get_invocation_from_environment(&saved_invocation_id);
+ if (r < 0 && r != -ENXIO)
+ return r;
- /* We first try to read the invocation ID from the kernel keyring. This has the benefit that it is not
- * fakeable by unprivileged code. If the information is not available in the keyring, we use
- * $INVOCATION_ID but ignore the data if our process was called by less privileged code
- * (i.e. secure_getenv() instead of getenv()).
- *
- * The kernel keyring is only relevant for system services (as for user services we don't store the
- * invocation ID in the keyring, as there'd be no trust benefit in that). The environment variable is
- * primarily relevant for user services, and sufficiently safe as no privilege boundary is involved. */
-
+ /* The kernel keyring is relevant for system services (as for user services we don't store
+ * the invocation ID in the keyring, as there'd be no trust benefit in that). */
r = get_invocation_from_keyring(&saved_invocation_id);
if (r < 0)
return r;
-
- if (r == 0) {
- const char *e;
-
- e = secure_getenv("INVOCATION_ID");
- if (!e)
- return -ENXIO;
-
- r = sd_id128_from_string(e, &saved_invocation_id);
- if (r < 0)
- return r;
- }
}
*ret = saved_invocation_id;
diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h
index 4875f10555..d299c79121 100644
--- a/src/systemd/src/systemd/sd-dhcp-lease.h
+++ b/src/systemd/src/systemd/sd-dhcp-lease.h
@@ -39,7 +39,7 @@ int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1);
int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2);
int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr);
+int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr);
int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h
index 787a12f241..7bb8609376 100644
--- a/src/systemd/src/systemd/sd-event.h
+++ b/src/systemd/src/systemd/sd-event.h
@@ -71,7 +71,7 @@ typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata);
typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata);
typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata);
typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata);
-#if defined _GNU_SOURCE || _POSIX_C_SOURCE >= 199309L
+#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L)
typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata);
#else
typedef void* sd_event_child_handler_t;