diff --git a/man/sd_bus_message_open_container.xml b/man/sd_bus_message_open_container.xml
index 5a6551871..64fda41b1 100644
--- a/man/sd_bus_message_open_container.xml
+++ b/man/sd_bus_message_open_container.xml
@@ -80,7 +80,7 @@
m itself if there is no parent container.
sd_bus_message_enter_container() enters the next container of the message
- m. It behaves mostly the same as
+ m for reading. It behaves mostly the same as
sd_bus_message_open_container(). Entering a container allows reading its contents
with
sd_bus_message_read3
@@ -89,7 +89,12 @@
sd_bus_message_exit_container() exits the scope of the last container entered
with sd_bus_message_enter_container(). It behaves mostly the same as
- sd_bus_message_close_container().
+ sd_bus_message_close_container(). Note that
+ sd_bus_message_exit_container() may only be called after iterating through all
+ members of the container, i.e. reading or skipping them. Use
+ sd_bus_message_skip3
+ to skip over felds of a container in order to be able to exit the container with
+ sd_bus_message_exit_container() without reading all members.
@@ -128,6 +133,13 @@
Memory allocation failed.
+
+
+ -EBUSY
+
+ sd_bus_message_exit_container() was called but there are
+ unread members left in the container.
+
@@ -158,6 +170,7 @@
sd-bus3,
sd_bus_message_append3,
sd_bus_message_read3,
+ sd_bus_message_skip3,
The D-Bus specification
diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml
index 582240271..32ddb1c6e 100644
--- a/man/systemd.timer.xml
+++ b/man/systemd.timer.xml
@@ -297,9 +297,10 @@
Takes a boolean argument. If true, the time when the service unit was last triggered
is stored on disk. When the timer is activated, the service unit is triggered immediately if it
- would have been triggered at least once during the time when the timer was inactive. This is useful
- to catch up on missed runs of the service when the system was powered down. Note that this setting
- only has an effect on timers configured with OnCalendar=. Defaults to
+ would have been triggered at least once during the time when the timer was inactive. Such triggering
+ is nonetheless subject to the delay imposed by RandomizedDelaySec=.
+ This is useful to catch up on missed runs of the service when the system was powered down. Note that
+ this setting only has an effect on timers configured with OnCalendar=. Defaults to
false.
Use systemctl clean --what=state … on the timer unit to remove the timestamp
diff --git a/man/sysusers.d.xml b/man/sysusers.d.xml
index 38a95d6e1..2d5023dc9 100644
--- a/man/sysusers.d.xml
+++ b/man/sysusers.d.xml
@@ -27,12 +27,12 @@
/usr/lib/sysusers.d/*.conf
-#Type Name ID GECOS Home directory Shell
-u user_name uid "User Description" /path/to/shell
-u user_name uid:gid - -
-u user_name /file/owned/by/user - -
-g group_name gid "Group Description"
-g group_name /file/owned/by/group -
+#Type Name ID GECOS Home directory Shell
+u user_name uid "User Description" /home/dir /path/to/shell
+u user_name uid:gid "User Description" /home/dir /path/to/shell
+u user_name /file/owned/by/user "User Description" /home/dir /path/to/shell
+g group_name gid
+g group_name /file/owned/by/group
m user_name group_name
r - lowest-highest
diff --git a/meson.build b/meson.build
index ba9e7afe5..e928b10be 100644
--- a/meson.build
+++ b/meson.build
@@ -227,6 +227,7 @@ conf.set_quoted('SYSTEMCTL_BINARY_PATH', join_paths(rootbin
conf.set_quoted('SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH', join_paths(rootbindir, 'systemd-tty-ask-password-agent'))
conf.set_quoted('SYSTEMD_STDIO_BRIDGE_BINARY_PATH', join_paths(bindir, 'systemd-stdio-bridge'))
conf.set_quoted('ROOTPREFIX', rootprefixdir)
+conf.set_quoted('ROOTPREFIX_NOSLASH', rootprefixdir_noslash)
conf.set_quoted('RANDOM_SEED_DIR', randomseeddir)
conf.set_quoted('RANDOM_SEED', join_paths(randomseeddir, 'random-seed'))
conf.set_quoted('SYSTEMD_CRYPTSETUP_PATH', join_paths(rootlibexecdir, 'systemd-cryptsetup'))
diff --git a/shell-completion/bash/resolvectl b/shell-completion/bash/resolvectl
index d4ac33903..54b241ce9 100644
--- a/shell-completion/bash/resolvectl
+++ b/shell-completion/bash/resolvectl
@@ -48,6 +48,7 @@ _resolvectl() {
[DNSSEC]='dnssec'
[DNSOVERTLS]='dnsovertls'
[STANDALONE]='statistics reset-statistics flush-caches reset-server-features'
+ [LOG_LEVEL]='log-level'
)
local -A ARGS=(
[FAMILY]='tcp udp sctp'
@@ -95,6 +96,9 @@ _resolvectl() {
elif __contains_word "$verb" ${VERBS[STATUS]}; then
comps="$interfaces"
+ elif __contains_word "$verb" ${VERBS[LOG_LEVEL]}; then
+ comps='debug info notice warning err crit alert emerg'
+
elif __contains_word "$verb" ${VERBS[FAMILY]}; then
for ((i++; i < COMP_CWORD; i++)); do
if __contains_word "${COMP_WORDS[i]}" ${ARGS[FAMILY]} &&
diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c
index 3a644363e..388bd0367 100644
--- a/src/backlight/backlight.c
+++ b/src/backlight/backlight.c
@@ -284,7 +284,8 @@ static bool shall_clamp(sd_device *d) {
r = sd_device_get_property_value(d, "ID_BACKLIGHT_CLAMP", &s);
if (r < 0) {
- log_device_debug_errno(d, r, "Failed to get ID_BACKLIGHT_CLAMP property, ignoring: %m");
+ if (r != -ENOENT)
+ log_device_debug_errno(d, r, "Failed to get ID_BACKLIGHT_CLAMP property, ignoring: %m");
return true;
}
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index 71e1bc92e..7de777073 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -315,6 +315,15 @@ int btrfs_get_block_device_fd(int fd, dev_t *dev) {
return -errno;
}
+ /* For the root fs — when no initrd is involved — btrfs returns /dev/root on any kernels from
+ * the past few years. That sucks, as we have no API to determine the actual root then. let's
+ * return an recognizable error for this case, so that the caller can maybe print a nice
+ * message about this.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=89721 */
+ if (path_equal((char*) di.path, "/dev/root"))
+ return -EUCLEAN;
+
if (stat((char*) di.path, &st) < 0)
return -errno;
diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h
index c1bbb42ca..d9cb95af0 100644
--- a/src/basic/btrfs-util.h
+++ b/src/basic/btrfs-util.h
@@ -121,3 +121,9 @@ int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret);
int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *quota);
int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *quota);
+
+static inline int btrfs_log_dev_root(int level, int ret, const char *p) {
+ return log_full_errno(level, ret,
+ "File system behind %s is reported by btrfs to be backed by pseudo-device /dev/root, which is not a valid userspace accessible device node. "
+ "Cannot determine correct backing block device.", p);
+}
diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c
index 5a4d020f5..ae269e8a8 100644
--- a/src/basic/capability-util.c
+++ b/src/basic/capability-util.c
@@ -161,28 +161,21 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
return 0;
}
-int capability_bounding_set_drop(uint64_t keep, bool right_now) {
- _cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
+int capability_gain_cap_setpcap(cap_t *ret_before_caps) {
+ _cleanup_cap_free_ cap_t caps = NULL;
cap_flag_value_t fv;
- int r;
-
- /* If we are run as PID 1 we will lack CAP_SETPCAP by default
- * in the effective set (yes, the kernel drops that when
- * executing init!), so get it back temporarily so that we can
- * call PR_CAPBSET_DROP. */
-
- before_cap = cap_get_proc();
- if (!before_cap)
+ caps = cap_get_proc();
+ if (!caps)
return -errno;
- if (cap_get_flag(before_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
+ if (cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
return -errno;
if (fv != CAP_SET) {
_cleanup_cap_free_ cap_t temp_cap = NULL;
static const cap_value_t v = CAP_SETPCAP;
- temp_cap = cap_dup(before_cap);
+ temp_cap = cap_dup(caps);
if (!temp_cap)
return -errno;
@@ -193,8 +186,27 @@ int capability_bounding_set_drop(uint64_t keep, bool right_now) {
log_debug_errno(errno, "Can't acquire effective CAP_SETPCAP bit, ignoring: %m");
/* If we didn't manage to acquire the CAP_SETPCAP bit, we continue anyway, after all this just means
- * we'll fail later, when we actually intend to drop some capabilities. */
+ * we'll fail later, when we actually intend to drop some capabilities or try to set securebits. */
}
+ if (ret_before_caps)
+ /* Return the capabilities as they have been before setting CAP_SETPCAP */
+ *ret_before_caps = TAKE_PTR(caps);
+
+ return 0;
+}
+
+int capability_bounding_set_drop(uint64_t keep, bool right_now) {
+ _cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
+ int r;
+
+ /* If we are run as PID 1 we will lack CAP_SETPCAP by default
+ * in the effective set (yes, the kernel drops that when
+ * executing init!), so get it back temporarily so that we can
+ * call PR_CAPBSET_DROP. */
+
+ r = capability_gain_cap_setpcap(&before_cap);
+ if (r < 0)
+ return r;
after_cap = cap_dup(before_cap);
if (!after_cap)
diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h
index fcc59daed..fdf6ef846 100644
--- a/src/basic/capability-util.h
+++ b/src/basic/capability-util.h
@@ -14,6 +14,7 @@
unsigned cap_last_cap(void);
int have_effective_cap(int value);
+int capability_gain_cap_setpcap(cap_t *return_caps);
int capability_bounding_set_drop(uint64_t keep, bool right_now);
int capability_bounding_set_drop_usermode(uint64_t keep);
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 34a226078..461bc04e5 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -229,6 +229,7 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
bool do_chown, do_chmod;
struct stat st;
+ int r;
/* Change ownership and access mode of the specified fd. Tries to do so safely, ensuring that at no
* point in time the access mode is above the old access mode under the old ownership or the new
@@ -259,18 +260,22 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
if (do_chown && do_chmod) {
mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */
- if (((minimal ^ st.st_mode) & 07777) != 0)
- if (fchmod_opath(fd, minimal & 07777) < 0)
- return -errno;
+ if (((minimal ^ st.st_mode) & 07777) != 0) {
+ r = fchmod_opath(fd, minimal & 07777);
+ if (r < 0)
+ return r;
+ }
}
if (do_chown)
if (fchownat(fd, "", uid, gid, AT_EMPTY_PATH) < 0)
return -errno;
- if (do_chmod)
- if (fchmod_opath(fd, mode & 07777) < 0)
- return -errno;
+ if (do_chmod) {
+ r = fchmod_opath(fd, mode & 07777);
+ if (r < 0)
+ return r;
+ }
return do_chown || do_chmod;
}
diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c
index 67c439123..a4eeb110e 100644
--- a/src/basic/hashmap.c
+++ b/src/basic/hashmap.c
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include
+#include
#include
#include
@@ -19,7 +20,6 @@
#include "strv.h"
#if ENABLE_DEBUG_HASHMAP
-#include
#include "list.h"
#endif
@@ -189,7 +189,6 @@ assert_cc(DIRECT_BUCKETS(struct set_entry) < (1 << 3));
* a handful of directly stored entries in a hashmap. When a hashmap
* outgrows direct storage, it gets its own key for indirect storage. */
static uint8_t shared_hash_key[HASH_KEY_SIZE];
-static bool shared_hash_key_initialized;
/* Fields that all hashmap/set types must have */
struct HashmapBase {
@@ -768,6 +767,10 @@ static void reset_direct_storage(HashmapBase *h) {
memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets);
}
+static void shared_hash_key_initialize(void) {
+ random_bytes(shared_hash_key, sizeof(shared_hash_key));
+}
+
static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
HashmapBase *h;
const struct hashmap_type_info *hi = &hashmap_type_info[type];
@@ -790,10 +793,8 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
reset_direct_storage(h);
- if (!shared_hash_key_initialized) {
- random_bytes(shared_hash_key, sizeof(shared_hash_key));
- shared_hash_key_initialized= true;
- }
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ assert_se(pthread_once(&once, shared_hash_key_initialize) == 0);
#if ENABLE_DEBUG_HASHMAP
h->debug.func = func;
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c
index ea50e2619..15307f6f1 100644
--- a/src/basic/in-addr-util.c
+++ b/src/basic/in-addr-util.c
@@ -795,13 +795,13 @@ static int in_addr_data_compare_func(const struct in_addr_data *x, const struct
DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
-static void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
+void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
assert(addr);
siphash24_compress(addr, sizeof(*addr), state);
}
-static int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
+int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
return memcmp(a, b, sizeof(*a));
}
diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h
index dc3f575bc..0d038399d 100644
--- a/src/basic/in-addr-util.h
+++ b/src/basic/in-addr-util.h
@@ -74,5 +74,8 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
* See also oss-fuzz#11344. */
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
+void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state);
+int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b);
+
extern const struct hash_ops in_addr_data_hash_ops;
extern const struct hash_ops in6_addr_hash_ops;
diff --git a/src/basic/log.h b/src/basic/log.h
index 15807d302..137d21005 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -234,12 +234,12 @@ void log_assert_failed_return_realm(
#define log_full_errno(level, error, ...) \
log_full_errno_realm(LOG_REALM, (level), (error), __VA_ARGS__)
-#define log_full(level, ...) log_full_errno((level), 0, __VA_ARGS__)
+#define log_full(level, ...) (void) log_full_errno((level), 0, __VA_ARGS__)
int log_emergency_level(void);
/* Normal logging */
-#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__)
+#define log_debug(...) log_full_errno(LOG_DEBUG, 0, __VA_ARGS__)
#define log_info(...) log_full(LOG_INFO, __VA_ARGS__)
#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__)
#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__)
diff --git a/src/basic/quota-util.c b/src/basic/quota-util.c
index e048f5571..96ea9ee36 100644
--- a/src/basic/quota-util.c
+++ b/src/basic/quota-util.c
@@ -34,7 +34,7 @@ int quotactl_path(int cmd, const char *path, int id, void *addr) {
r = get_block_device(path, &devno);
if (r < 0)
return r;
- if (devno == 0)
+ if (devno == 0) /* Doesn't have a block device */
return -ENODEV;
return quotactl_devno(cmd, devno, id, addr);
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index fb1265985..4b3a4f206 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -617,40 +617,62 @@ bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b
return false;
}
-int fd_inc_sndbuf(int fd, size_t n) {
+int fd_set_sndbuf(int fd, size_t n, bool increase) {
int r, value;
socklen_t l = sizeof(value);
+ if (n > INT_MAX)
+ return -ERANGE;
+
r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
- if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
+ if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
return 0;
- /* If we have the privileges we will ignore the kernel limit. */
+ /* First, try to set the buffer size with SO_SNDBUF. */
+ r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, n);
+ if (r < 0)
+ return r;
- if (setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, n) < 0) {
- r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, n);
- if (r < 0)
- return r;
- }
+ /* SO_SNDBUF above may set to the kernel limit, instead of the requested size.
+ * So, we need to check the actual buffer size here. */
+ r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
+ if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
+ return 1;
+
+ /* If we have the privileges we will ignore the kernel limit. */
+ r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, n);
+ if (r < 0)
+ return r;
return 1;
}
-int fd_inc_rcvbuf(int fd, size_t n) {
+int fd_set_rcvbuf(int fd, size_t n, bool increase) {
int r, value;
socklen_t l = sizeof(value);
+ if (n > INT_MAX)
+ return -ERANGE;
+
r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
- if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
+ if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
return 0;
- /* If we have the privileges we will ignore the kernel limit. */
+ /* First, try to set the buffer size with SO_RCVBUF. */
+ r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, n);
+ if (r < 0)
+ return r;
- if (setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, n) < 0) {
- r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUFFORCE, n);
- if (r < 0)
- return r;
- }
+ /* SO_RCVBUF above may set to the kernel limit, instead of the requested size.
+ * So, we need to check the actual buffer size here. */
+ r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
+ if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2)
+ return 1;
+
+ /* If we have the privileges we will ignore the kernel limit. */
+ r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUFFORCE, n);
+ if (r < 0)
+ return r;
return 1;
}
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 9e02e3988..1177ac1d8 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -118,8 +118,14 @@ int netlink_family_from_string(const char *s) _pure_;
bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b);
-int fd_inc_sndbuf(int fd, size_t n);
-int fd_inc_rcvbuf(int fd, size_t n);
+int fd_set_sndbuf(int fd, size_t n, bool increase);
+static inline int fd_inc_sndbuf(int fd, size_t n) {
+ return fd_set_sndbuf(fd, n, true);
+}
+int fd_set_rcvbuf(int fd, size_t n, bool increase);
+static inline int fd_inc_rcvbuf(int fd, size_t n) {
+ return fd_set_rcvbuf(fd, n, true);
+}
int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index a663fc5c2..3a80aafcc 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -1249,15 +1249,15 @@ static int verb_status(int argc, char *argv[], void *userdata) {
printf(" Secure Boot: %sd\n", enable_disable(is_efi_secure_boot()));
printf(" Setup Mode: %s\n", is_efi_secure_boot_setup_mode() ? "setup" : "user");
- r = efi_get_reboot_to_firmware();
- if (r > 0)
+ k = efi_get_reboot_to_firmware();
+ if (k > 0)
printf(" Boot into FW: %sactive%s\n", ansi_highlight_yellow(), ansi_normal());
- else if (r == 0)
+ else if (k == 0)
printf(" Boot into FW: supported\n");
- else if (r == -EOPNOTSUPP)
+ else if (k == -EOPNOTSUPP)
printf(" Boot into FW: not supported\n");
else {
- errno = -r;
+ errno = -k;
printf(" Boot into FW: %sfailed%s (%m)\n", ansi_highlight_red(), ansi_normal());
}
printf("\n");
diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c
index bceb049b5..303751858 100644
--- a/src/core/bpf-firewall.c
+++ b/src/core/bpf-firewall.c
@@ -900,11 +900,11 @@ void emit_bpf_firewall_warning(Unit *u) {
if (!warned) {
bool quiet = bpf_firewall_unsupported_reason == -EPERM && detect_container();
- log_unit_full(u, quiet ? LOG_DEBUG : LOG_WARNING, bpf_firewall_unsupported_reason,
- "unit configures an IP firewall, but %s.\n"
- "(This warning is only shown for the first unit using IP firewalling.)",
- getuid() != 0 ? "not running as root" :
- "the local system does not support BPF/cgroup firewalling");
+ log_unit_full_errno(u, quiet ? LOG_DEBUG : LOG_WARNING, bpf_firewall_unsupported_reason,
+ "unit configures an IP firewall, but %s.\n"
+ "(This warning is only shown for the first unit using IP firewalling.)",
+ getuid() != 0 ? "not running as root" :
+ "the local system does not support BPF/cgroup firewalling");
warned = true;
}
}
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 031b28a68..1f9ba6ca8 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -78,8 +78,8 @@ static int set_attribute_and_warn(Unit *u, const char *controller, const char *a
r = cg_set_attribute(controller, u->cgroup_path, attribute, value);
if (r < 0)
- log_unit_full(u, LOG_LEVEL_CGROUP_WRITE(r), r, "Failed to set '%s' attribute on '%s' to '%.*s': %m",
- strna(attribute), isempty(u->cgroup_path) ? "/" : u->cgroup_path, (int) strcspn(value, NEWLINE), value);
+ log_unit_full_errno(u, LOG_LEVEL_CGROUP_WRITE(r), r, "Failed to set '%s' attribute on '%s' to '%.*s': %m",
+ strna(attribute), isempty(u->cgroup_path) ? "/" : u->cgroup_path, (int) strcspn(value, NEWLINE), value);
return r;
}
@@ -724,7 +724,7 @@ static usec_t cgroup_cpu_adjust_period_and_log(Unit *u, usec_t period, usec_t qu
if (new_period != period) {
char v[FORMAT_TIMESPAN_MAX];
- log_unit_full(u, u->warned_clamping_cpu_quota_period ? LOG_DEBUG : LOG_WARNING, 0,
+ log_unit_full(u, u->warned_clamping_cpu_quota_period ? LOG_DEBUG : LOG_WARNING,
"Clamping CPU interval for cpu.max: period is now %s",
format_timespan(v, sizeof(v), new_period, 1));
u->warned_clamping_cpu_quota_period = true;
@@ -986,8 +986,8 @@ static int cgroup_apply_devices(Unit *u) {
else
r = cg_set_attribute("devices", path, "devices.allow", "a");
if (r < 0)
- log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES, -EPERM) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to reset devices.allow/devices.deny: %m");
+ log_unit_full_errno(u, IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES, -EPERM) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to reset devices.allow/devices.deny: %m");
}
bool allow_list_static = policy == CGROUP_DEVICE_POLICY_CLOSED ||
@@ -1351,8 +1351,8 @@ static void cgroup_context_apply(
else
r = 0;
if (r < 0)
- log_unit_full(u, LOG_LEVEL_CGROUP_WRITE(r), r,
- "Failed to write to tasks limit sysctls: %m");
+ log_unit_full_errno(u, LOG_LEVEL_CGROUP_WRITE(r), r,
+ "Failed to write to tasks limit sysctls: %m");
}
/* The attribute itself is not available on the host root cgroup, and in the container case we want to
@@ -2436,7 +2436,7 @@ void unit_prune_cgroup(Unit *u) {
* the containing slice is stopped. So even if we failed now, this unit shouldn't assume
* that the cgroup is still realized the next time it is started. Do not return early
* on error, continue cleanup. */
- log_unit_full(u, r == -EBUSY ? LOG_DEBUG : LOG_WARNING, r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path);
+ log_unit_full_errno(u, r == -EBUSY ? LOG_DEBUG : LOG_WARNING, r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path);
if (is_root_slice)
return;
diff --git a/src/core/execute.c b/src/core/execute.c
index 2a4840a3a..7b3de2576 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1072,26 +1072,42 @@ static int enforce_groups(gid_t gid, const gid_t *supplementary_gids, int ngids)
return 0;
}
+static int set_securebits(int bits, int mask) {
+ int current, applied;
+ current = prctl(PR_GET_SECUREBITS);
+ if (current < 0)
+ return -errno;
+ /* Clear all securebits defined in mask and set bits */
+ applied = (current & ~mask) | bits;
+ if (current == applied)
+ return 0;
+ if (prctl(PR_SET_SECUREBITS, applied) < 0)
+ return -errno;
+ return 1;
+}
+
static int enforce_user(const ExecContext *context, uid_t uid) {
assert(context);
+ int r;
if (!uid_is_valid(uid))
return 0;
/* Sets (but doesn't look up) the uid and make sure we keep the
- * capabilities while doing so. */
+ * capabilities while doing so. For setting secure bits the capability CAP_SETPCAP is
+ * required, so we also need keep-caps in this case.
+ */
- if (context->capability_ambient_set != 0) {
+ if (context->capability_ambient_set != 0 || context->secure_bits != 0) {
/* First step: If we need to keep capabilities but
* drop privileges we need to make sure we keep our
* caps, while we drop privileges. */
if (uid != 0) {
- int sb = context->secure_bits | 1<capability_ambient_set, true);
if (r < 0) {
@@ -3806,21 +3830,12 @@ static int exec_child(
if (!needs_ambient_hack &&
context->capability_ambient_set != 0) {
- /* Fix the ambient capabilities after user change. */
+ /* Raise the ambient capabilities after user change. */
r = capability_ambient_set_apply(context->capability_ambient_set, false);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
return log_unit_error_errno(unit, r, "Failed to apply ambient capabilities (after UID change): %m");
}
-
- /* If we were asked to change user and ambient capabilities
- * were requested, we had to add keep-caps to the securebits
- * so that we would maintain the inherited capability set
- * through the setresuid(). Make sure that the bit is added
- * also to the context secure_bits so that we don't try to
- * drop the bit away next. */
-
- secure_bits |= 1<control_pid) {
- log_unit_full(UNIT(s), prio, 0, "New main PID "PID_FMT" is the control process, refusing.", pid);
+ log_unit_full(UNIT(s), prio, "New main PID "PID_FMT" is the control process, refusing.", pid);
return -EPERM;
}
if (!pid_is_alive(pid)) {
- log_unit_full(UNIT(s), prio, 0, "New main PID "PID_FMT" does not exist or is a zombie.", pid);
+ log_unit_full(UNIT(s), prio, "New main PID "PID_FMT" does not exist or is a zombie.", pid);
return -ESRCH;
}
@@ -958,16 +958,16 @@ static int service_load_pid_file(Service *s, bool may_warn) {
r = chase_symlinks(s->pid_file, NULL, CHASE_SAFE, NULL, &fd);
if (r == -ENOLINK) {
- log_unit_full(UNIT(s), LOG_DEBUG, r,
- "Potentially unsafe symlink chain, will now retry with relaxed checks: %s", s->pid_file);
+ log_unit_debug_errno(UNIT(s), r,
+ "Potentially unsafe symlink chain, will now retry with relaxed checks: %s", s->pid_file);
questionable_pid_file = true;
r = chase_symlinks(s->pid_file, NULL, 0, NULL, &fd);
}
if (r < 0)
- return log_unit_full(UNIT(s), prio, fd,
- "Can't open PID file %s (yet?) after %s: %m", s->pid_file, service_state_to_string(s->state));
+ return log_unit_full_errno(UNIT(s), prio, fd,
+ "Can't open PID file %s (yet?) after %s: %m", s->pid_file, service_state_to_string(s->state));
/* Let's read the PID file now that we chased it down. But we need to convert the O_PATH fd
* chase_symlinks() returned us into a proper fd first. */
@@ -980,7 +980,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
r = parse_pid(k, &pid);
if (r < 0)
- return log_unit_full(UNIT(s), prio, r, "Failed to parse PID from file %s: %m", s->pid_file);
+ return log_unit_full_errno(UNIT(s), prio, r, "Failed to parse PID from file %s: %m", s->pid_file);
if (s->main_pid_known && pid == s->main_pid)
return 0;
diff --git a/src/core/slice.c b/src/core/slice.c
index f4f63fcb5..c6884d8c3 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -383,8 +383,10 @@ static int slice_freezer_action(Unit *s, FreezerAction action) {
assert(s);
assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
- if (!slice_freezer_action_supported_by_children(s))
- return log_unit_warning(s, "Requested freezer operation is not supported by all children of the slice");
+ if (!slice_freezer_action_supported_by_children(s)) {
+ log_unit_warning(s, "Requested freezer operation is not supported by all children of the slice");
+ return 0;
+ }
HASHMAP_FOREACH_KEY(v, member, s->dependencies[UNIT_BEFORE], i) {
if (UNIT_DEREF(member->slice) != s)
diff --git a/src/core/socket.c b/src/core/socket.c
index 127195c9f..809cac68a 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -18,6 +18,7 @@
#include "dbus-socket.h"
#include "dbus-unit.h"
#include "def.h"
+#include "errno-list.h"
#include "exit-status.h"
#include "fd-util.h"
#include "format-util.h"
@@ -1072,20 +1073,17 @@ static void socket_apply_socket_options(Socket *s, int fd) {
}
if (s->receive_buffer > 0) {
- /* We first try with SO_RCVBUFFORCE, in case we have the perms for that */
- if (setsockopt_int(fd, SOL_SOCKET, SO_RCVBUFFORCE, s->receive_buffer) < 0) {
- r = setsockopt_int(fd, SOL_SOCKET, SO_RCVBUF, s->receive_buffer);
- if (r < 0)
- log_unit_warning_errno(UNIT(s), r, "SO_RCVBUF failed: %m");
- }
+ r = fd_set_rcvbuf(fd, s->receive_buffer, false);
+ if (r < 0)
+ log_unit_full_errno(UNIT(s), ERRNO_IS_PRIVILEGE(r) ? LOG_DEBUG : LOG_WARNING, r,
+ "SO_RCVBUF/SO_RCVBUFFORCE failed: %m");
}
if (s->send_buffer > 0) {
- if (setsockopt_int(fd, SOL_SOCKET, SO_SNDBUFFORCE, s->send_buffer) < 0) {
- r = setsockopt_int(fd, SOL_SOCKET, SO_SNDBUF, s->send_buffer);
- if (r < 0)
- log_unit_warning_errno(UNIT(s), r, "SO_SNDBUF failed: %m");
- }
+ r = fd_set_sndbuf(fd, s->send_buffer, false);
+ if (r < 0)
+ log_unit_full_errno(UNIT(s), ERRNO_IS_PRIVILEGE(r) ? LOG_DEBUG : LOG_WARNING, r,
+ "SO_SNDBUF/SO_SNDBUFFORCE failed: %m");
}
if (s->mark >= 0) {
@@ -1418,11 +1416,12 @@ int socket_load_service_unit(Socket *s, int cfd, Unit **ret) {
if (cfd >= 0) {
r = instance_from_socket(cfd, s->n_accepted, &instance);
- if (r == -ENOTCONN)
- /* ENOTCONN is legitimate if TCP RST was received.
- * This connection is over, but the socket unit lives on. */
+ if (ERRNO_IS_DISCONNECT(r))
+ /* ENOTCONN is legitimate if TCP RST was received. Other socket families might return
+ * different errors. This connection is over, but the socket unit lives on. */
return log_unit_debug_errno(UNIT(s), r,
- "Got ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring.");
+ "Got %s on incoming socket, assuming aborted connection attempt, ignoring.",
+ errno_to_name(r));
if (r < 0)
return r;
}
@@ -2359,8 +2358,8 @@ static void socket_enter_running(Socket *s, int cfd) {
if (!pending) {
if (!UNIT_ISSET(s->service)) {
- log_unit_error(UNIT(s), "Service to activate vanished, refusing activation.");
- r = -ENOENT;
+ r = log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOENT),
+ "Service to activate vanished, refusing activation.");
goto fail;
}
@@ -2382,8 +2381,10 @@ static void socket_enter_running(Socket *s, int cfd) {
if (s->max_connections_per_source > 0) {
r = socket_acquire_peer(s, cfd, &p);
- if (r < 0)
- goto refuse;
+ if (ERRNO_IS_DISCONNECT(r))
+ goto notconn;
+ if (r < 0) /* We didn't have enough resources to acquire peer information, let's fail. */
+ goto fail;
if (r > 0 && p->n_ref > s->max_connections_per_source) {
_cleanup_free_ char *t = NULL;
@@ -2397,6 +2398,8 @@ static void socket_enter_running(Socket *s, int cfd) {
}
r = socket_instantiate_service(s, cfd);
+ if (ERRNO_IS_DISCONNECT(r))
+ goto notconn;
if (r < 0)
goto fail;
@@ -2406,6 +2409,8 @@ static void socket_enter_running(Socket *s, int cfd) {
s->n_accepted++;
r = service_set_socket_fd(service, cfd, s, s->selinux_context_from_net);
+ if (ERRNO_IS_DISCONNECT(r))
+ goto notconn;
if (r < 0)
goto fail;
@@ -2430,13 +2435,18 @@ static void socket_enter_running(Socket *s, int cfd) {
refuse:
s->n_refused++;
+notconn:
safe_close(cfd);
return;
fail:
- log_unit_warning(UNIT(s), "Failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
- cfd >= 0 ? "template" : "non-template",
- bus_error_message(&error, r));
+ if (ERRNO_IS_RESOURCE(r))
+ log_unit_warning(UNIT(s), "Failed to queue service startup job: %s",
+ bus_error_message(&error, r));
+ else
+ log_unit_warning(UNIT(s), "Failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
+ cfd >= 0 ? "template" : "non-template",
+ bus_error_message(&error, r));
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
safe_close(cfd);
diff --git a/src/core/swap.c b/src/core/swap.c
index 20179de2d..f2a1eb460 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -284,8 +284,8 @@ static int swap_load_devnode(Swap *s) {
r = device_new_from_stat_rdev(&d, &st);
if (r < 0) {
- log_unit_full(UNIT(s), r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to allocate device for swap %s: %m", s->what);
+ log_unit_full_errno(UNIT(s), r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to allocate device for swap %s: %m", s->what);
return 0;
}
diff --git a/src/core/transaction.c b/src/core/transaction.c
index 0fa419787..402577298 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -1009,10 +1009,9 @@ int transaction_add_job_and_dependencies(
SET_FOREACH(dep, following, i) {
r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
- log_unit_full(dep,
- r == -ERFKILL ? LOG_INFO : LOG_WARNING,
- r, "Cannot add dependency job, ignoring: %s",
- bus_error_message(e, r));
+ log_unit_full_errno(dep, r == -ERFKILL ? LOG_INFO : LOG_WARNING, r,
+ "Cannot add dependency job, ignoring: %s",
+ bus_error_message(e, r));
sd_bus_error_free(e);
}
}
@@ -1046,10 +1045,10 @@ int transaction_add_job_and_dependencies(
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
/* unit masked, job type not applicable and unit not found are not considered as errors. */
- log_unit_full(dep,
- IN_SET(r, -ERFKILL, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING,
- r, "Cannot add dependency job, ignoring: %s",
- bus_error_message(e, r));
+ log_unit_full_errno(dep,
+ IN_SET(r, -ERFKILL, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING,
+ r, "Cannot add dependency job, ignoring: %s",
+ bus_error_message(e, r));
sd_bus_error_free(e);
}
}
diff --git a/src/core/unit.h b/src/core/unit.h
index 4130cd50a..4fdd2e28d 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -896,7 +896,7 @@ int unit_thaw_vtable_common(Unit *u);
/* Macros which append UNIT= or USER_UNIT= to the message */
-#define log_unit_full(unit, level, error, ...) \
+#define log_unit_full_errno(unit, level, error, ...) \
({ \
const Unit *_u = (unit); \
(log_get_max_level() < LOG_PRI(level)) ? -ERRNO_VALUE(error) : \
@@ -904,17 +904,19 @@ int unit_thaw_vtable_common(Unit *u);
log_internal(level, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \
})
-#define log_unit_debug(unit, ...) log_unit_full(unit, LOG_DEBUG, 0, ##__VA_ARGS__)
-#define log_unit_info(unit, ...) log_unit_full(unit, LOG_INFO, 0, ##__VA_ARGS__)
-#define log_unit_notice(unit, ...) log_unit_full(unit, LOG_NOTICE, 0, ##__VA_ARGS__)
-#define log_unit_warning(unit, ...) log_unit_full(unit, LOG_WARNING, 0, ##__VA_ARGS__)
-#define log_unit_error(unit, ...) log_unit_full(unit, LOG_ERR, 0, ##__VA_ARGS__)
+#define log_unit_full(unit, level, ...) (void) log_unit_full_errno(unit, level, 0, __VA_ARGS__)
-#define log_unit_debug_errno(unit, error, ...) log_unit_full(unit, LOG_DEBUG, error, ##__VA_ARGS__)
-#define log_unit_info_errno(unit, error, ...) log_unit_full(unit, LOG_INFO, error, ##__VA_ARGS__)
-#define log_unit_notice_errno(unit, error, ...) log_unit_full(unit, LOG_NOTICE, error, ##__VA_ARGS__)
-#define log_unit_warning_errno(unit, error, ...) log_unit_full(unit, LOG_WARNING, error, ##__VA_ARGS__)
-#define log_unit_error_errno(unit, error, ...) log_unit_full(unit, LOG_ERR, error, ##__VA_ARGS__)
+#define log_unit_debug(unit, ...) log_unit_full_errno(unit, LOG_DEBUG, 0, __VA_ARGS__)
+#define log_unit_info(unit, ...) log_unit_full(unit, LOG_INFO, __VA_ARGS__)
+#define log_unit_notice(unit, ...) log_unit_full(unit, LOG_NOTICE, __VA_ARGS__)
+#define log_unit_warning(unit, ...) log_unit_full(unit, LOG_WARNING, __VA_ARGS__)
+#define log_unit_error(unit, ...) log_unit_full(unit, LOG_ERR, __VA_ARGS__)
+
+#define log_unit_debug_errno(unit, error, ...) log_unit_full_errno(unit, LOG_DEBUG, error, __VA_ARGS__)
+#define log_unit_info_errno(unit, error, ...) log_unit_full_errno(unit, LOG_INFO, error, __VA_ARGS__)
+#define log_unit_notice_errno(unit, error, ...) log_unit_full_errno(unit, LOG_NOTICE, error, __VA_ARGS__)
+#define log_unit_warning_errno(unit, error, ...) log_unit_full_errno(unit, LOG_WARNING, error, __VA_ARGS__)
+#define log_unit_error_errno(unit, error, ...) log_unit_full_errno(unit, LOG_ERR, error, __VA_ARGS__)
#define LOG_UNIT_MESSAGE(unit, fmt, ...) "MESSAGE=%s: " fmt, (unit)->id, ##__VA_ARGS__
#define LOG_UNIT_ID(unit) (unit)->manager->unit_log_format_string, (unit)->id
diff --git a/src/escape/escape.c b/src/escape/escape.c
index 0c543a90f..3f3dc0a89 100644
--- a/src/escape/escape.c
+++ b/src/escape/escape.c
@@ -211,14 +211,16 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to extract instance: %m");
if (isempty(name))
- return log_error("Unit %s is missing the instance name.", *i);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Unit %s is missing the instance name.", *i);
r = unit_name_template(*i, &template);
if (r < 0)
return log_error_errno(r, "Failed to extract template: %m");
if (arg_template && !streq(arg_template, template))
- return log_error("Unit %s template %s does not match specified template %s.",
- *i, template, arg_template);
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Unit %s template %s does not match specified template %s.",
+ *i, template, arg_template);
} else {
name = strdup(*i);
if (!name)
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index a9478b9db..24d28afc2 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -729,10 +729,14 @@ static int add_mounts(void) {
int r;
r = get_block_device_harder("/", &devno);
+ if (r == -EUCLEAN)
+ return btrfs_log_dev_root(LOG_ERR, r, "root file system");
if (r < 0)
return log_error_errno(r, "Failed to determine block device of root file system: %m");
- if (r == 0) {
+ if (r == 0) { /* Not backed by block device */
r = get_block_device_harder("/usr", &devno);
+ if (r == -EUCLEAN)
+ return btrfs_log_dev_root(LOG_ERR, r, "/usr");
if (r < 0)
return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
if (r == 0) {
diff --git a/src/home/homed-home.c b/src/home/homed-home.c
index 35b325413..a87fd9a5d 100644
--- a/src/home/homed-home.c
+++ b/src/home/homed-home.c
@@ -1112,7 +1112,7 @@ static int home_fixate_internal(
if (r < 0)
return r;
- if (for_state == HOME_FIXATING_FOR_ACTIVATION) {
+ if (IN_SET(for_state, HOME_FIXATING_FOR_ACTIVATION, HOME_FIXATING_FOR_ACQUIRE)) {
/* Remember the secret data, since we need it for the activation again, later on. */
user_record_unref(h->secret);
h->secret = user_record_ref(secret);
diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c
index bed45da8e..1d24af069 100644
--- a/src/libsystemd/sd-device/device-monitor.c
+++ b/src/libsystemd/sd-device/device-monitor.c
@@ -91,18 +91,9 @@ int device_monitor_allow_unicast_sender(sd_device_monitor *m, sd_device_monitor
}
_public_ int sd_device_monitor_set_receive_buffer_size(sd_device_monitor *m, size_t size) {
- int r, n = (int) size;
-
assert_return(m, -EINVAL);
- assert_return((size_t) n == size, -EINVAL);
- if (setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUFFORCE, n) < 0) {
- r = setsockopt_int(m->sock, SOL_SOCKET, SO_RCVBUF, n);
- if (r < 0)
- return r;
- }
-
- return 0;
+ return fd_set_rcvbuf(m->sock, size, false);
}
int device_monitor_disconnect(sd_device_monitor *m) {
diff --git a/src/libsystemd/sd-device/device-util.h b/src/libsystemd/sd-device/device-util.h
index 1a1795d97..431d4a1b4 100644
--- a/src/libsystemd/sd-device/device-util.h
+++ b/src/libsystemd/sd-device/device-util.h
@@ -31,7 +31,7 @@
device; \
device = sd_device_enumerator_get_subsystem_next(enumerator))
-#define log_device_full(device, level, error, ...) \
+#define log_device_full_errno(device, level, error, ...) \
({ \
const char *_sysname = NULL; \
sd_device *_d = (device); \
@@ -41,17 +41,19 @@
(void) sd_device_get_sysname(_d, &_sysname); \
log_object_internal(_level, _error, PROJECT_FILE, __LINE__, __func__, \
_sysname ? "DEVICE=" : NULL, _sysname, \
- NULL, NULL, ##__VA_ARGS__); \
+ NULL, NULL, __VA_ARGS__); \
})
-#define log_device_debug(device, ...) log_device_full(device, LOG_DEBUG, 0, ##__VA_ARGS__)
-#define log_device_info(device, ...) log_device_full(device, LOG_INFO, 0, ##__VA_ARGS__)
-#define log_device_notice(device, ...) log_device_full(device, LOG_NOTICE, 0, ##__VA_ARGS__)
-#define log_device_warning(device, ...) log_device_full(device, LOG_WARNING, 0, ##__VA_ARGS__)
-#define log_device_error(device, ...) log_device_full(device, LOG_ERR, 0, ##__VA_ARGS__)
+#define log_device_full(device, level, ...) (void) log_device_full_errno(device, level, 0, __VA_ARGS__)
-#define log_device_debug_errno(device, error, ...) log_device_full(device, LOG_DEBUG, error, ##__VA_ARGS__)
-#define log_device_info_errno(device, error, ...) log_device_full(device, LOG_INFO, error, ##__VA_ARGS__)
-#define log_device_notice_errno(device, error, ...) log_device_full(device, LOG_NOTICE, error, ##__VA_ARGS__)
-#define log_device_warning_errno(device, error, ...) log_device_full(device, LOG_WARNING, error, ##__VA_ARGS__)
-#define log_device_error_errno(device, error, ...) log_device_full(device, LOG_ERR, error, ##__VA_ARGS__)
+#define log_device_debug(device, ...) log_device_full_errno(device, LOG_DEBUG, 0, __VA_ARGS__)
+#define log_device_info(device, ...) log_device_full(device, LOG_INFO, __VA_ARGS__)
+#define log_device_notice(device, ...) log_device_full(device, LOG_NOTICE, __VA_ARGS__)
+#define log_device_warning(device, ...) log_device_full(device, LOG_WARNING, __VA_ARGS__)
+#define log_device_error(device, ...) log_device_full(device, LOG_ERR, __VA_ARGS__)
+
+#define log_device_debug_errno(device, error, ...) log_device_full_errno(device, LOG_DEBUG, error, __VA_ARGS__)
+#define log_device_info_errno(device, error, ...) log_device_full_errno(device, LOG_INFO, error, __VA_ARGS__)
+#define log_device_notice_errno(device, error, ...) log_device_full_errno(device, LOG_NOTICE, error, __VA_ARGS__)
+#define log_device_warning_errno(device, error, ...) log_device_full_errno(device, LOG_WARNING, error, __VA_ARGS__)
+#define log_device_error_errno(device, error, ...) log_device_full_errno(device, LOG_ERR, error, __VA_ARGS__)
diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c
index 736795d1d..3f6e70d09 100644
--- a/src/libsystemd/sd-path/sd-path.c
+++ b/src/libsystemd/sd-path/sd-path.c
@@ -321,7 +321,7 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
return from_user_dir("XDG_DESKTOP_DIR", buffer, ret);
case SD_PATH_SYSTEMD_UTIL:
- *ret = ROOTPREFIX "/lib/systemd";
+ *ret = ROOTPREFIX_NOSLASH "/lib/systemd";
return 0;
case SD_PATH_SYSTEMD_SYSTEM_UNIT:
@@ -329,7 +329,7 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
return 0;
case SD_PATH_SYSTEMD_SYSTEM_PRESET:
- *ret = ROOTPREFIX "/lib/systemd/system-preset";
+ *ret = ROOTPREFIX_NOSLASH "/lib/systemd/system-preset";
return 0;
case SD_PATH_SYSTEMD_USER_UNIT:
@@ -337,7 +337,7 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
return 0;
case SD_PATH_SYSTEMD_USER_PRESET:
- *ret = ROOTPREFIX "/lib/systemd/user-preset";
+ *ret = ROOTPREFIX_NOSLASH "/lib/systemd/user-preset";
return 0;
case SD_PATH_SYSTEMD_SYSTEM_CONF:
@@ -357,11 +357,11 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
return 0;
case SD_PATH_SYSTEMD_SLEEP:
- *ret = ROOTPREFIX "/lib/systemd/system-sleep";
+ *ret = ROOTPREFIX_NOSLASH "/lib/systemd/system-sleep";
return 0;
case SD_PATH_SYSTEMD_SHUTDOWN:
- *ret = ROOTPREFIX "/lib/systemd/system-shutdown";
+ *ret = ROOTPREFIX_NOSLASH "/lib/systemd/system-shutdown";
return 0;
/* FIXME: systemd.pc uses ${prefix}, but CONF_PATHS_NULSTR doesn't.
@@ -371,19 +371,19 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
return 0;
case SD_PATH_SYSUSERS:
- *ret = ROOTPREFIX "/lib/sysusers.d";
+ *ret = ROOTPREFIX_NOSLASH "/lib/sysusers.d";
return 0;
case SD_PATH_SYSCTL:
- *ret = ROOTPREFIX "/lib/sysctl.d";
+ *ret = ROOTPREFIX_NOSLASH "/lib/sysctl.d";
return 0;
case SD_PATH_BINFMT:
- *ret = ROOTPREFIX "/lib/binfmt.d";
+ *ret = ROOTPREFIX_NOSLASH "/lib/binfmt.d";
return 0;
case SD_PATH_MODULES_LOAD:
- *ret = ROOTPREFIX "/lib/modules-load.d";
+ *ret = ROOTPREFIX_NOSLASH "/lib/modules-load.d";
return 0;
case SD_PATH_CATALOG:
diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c
index 2ffa5ec8c..de21ecece 100644
--- a/src/network/netdev/macsec.c
+++ b/src/network/netdev/macsec.c
@@ -852,10 +852,12 @@ int config_parse_macsec_key_id(
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse KeyId \"%s\": %m", rvalue);
return 0;
}
- if (l > MACSEC_KEYID_LEN)
- return log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Specified KeyId is larger then the allowed maximum (%zu > %u), ignoring: %s",
- l, MACSEC_KEYID_LEN, rvalue);
+ if (l > MACSEC_KEYID_LEN) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Specified KeyId is larger then the allowed maximum (%zu > %u), ignoring: %s",
+ l, MACSEC_KEYID_LEN, rvalue);
+ return 0;
+ }
dest = a ? a->sa.key_id : b->sa.key_id;
memcpy_safe(dest, p, l);
diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c
index 6812b07bf..df6d9feae 100644
--- a/src/network/netdev/wireguard.c
+++ b/src/network/netdev/wireguard.c
@@ -493,13 +493,17 @@ static int wireguard_decode_key_and_warn(
(void) warn_file_is_world_accessible(filename, NULL, unit, line);
r = unbase64mem_full(rvalue, strlen(rvalue), true, &key, &len);
- if (r < 0)
- return log_syntax(unit, LOG_WARNING, filename, line, r,
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to decode wireguard key provided by %s=, ignoring assignment: %m", lvalue);
- if (len != WG_KEY_LEN)
- return log_syntax(unit, LOG_WARNING, filename, line, SYNTHETIC_ERRNO(EINVAL),
+ return 0;
+ }
+ if (len != WG_KEY_LEN) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
"Wireguard key provided by %s= has invalid length (%zu bytes), ignoring assignment.",
lvalue, len);
+ return 0;
+ }
memcpy(ret, key, WG_KEY_LEN);
return 0;
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 0349ca6f9..b193a8f00 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -10,6 +10,7 @@
#include "netlink-util.h"
#include "networkd-address.h"
#include "networkd-manager.h"
+#include "networkd-ndisc.h"
#include "parse-util.h"
#include "set.h"
#include "socket-util.h"
@@ -123,6 +124,9 @@ void address_free(Address *address) {
}
if (address->link && !address->acd) {
+ NDiscAddress *n;
+ Iterator i;
+
set_remove(address->link->addresses, address);
set_remove(address->link->addresses_foreign, address);
set_remove(address->link->static_addresses, address);
@@ -134,8 +138,9 @@ void address_free(Address *address) {
set_remove(address->link->dhcp6_addresses_old, address);
set_remove(address->link->dhcp6_pd_addresses, address);
set_remove(address->link->dhcp6_pd_addresses_old, address);
- set_remove(address->link->ndisc_addresses, address);
- set_remove(address->link->ndisc_addresses_old, address);
+ SET_FOREACH(n, address->link->ndisc_addresses, i)
+ if (n->address == address)
+ free(set_remove(address->link->ndisc_addresses, n));
if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
@@ -162,7 +167,7 @@ static uint32_t address_prefix(const Address *a) {
return be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
}
-static void address_hash_func(const Address *a, struct siphash *state) {
+void address_hash_func(const Address *a, struct siphash *state) {
assert(a);
siphash24_compress(&a->family, sizeof(a->family), state);
@@ -187,7 +192,7 @@ static void address_hash_func(const Address *a, struct siphash *state) {
}
}
-static int address_compare_func(const Address *a1, const Address *a2) {
+int address_compare_func(const Address *a1, const Address *a2) {
int r;
r = CMP(a1->family, a2->family);
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 3fc9935d1..1378901b8 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -75,6 +75,8 @@ int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret);
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
+void address_hash_func(const Address *a, struct siphash *state);
+int address_compare_func(const Address *a1, const Address *a2);
extern const struct hash_ops address_hash_ops;
CONFIG_PARSER_PROTOTYPE(config_parse_address);
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index d28c3e380..ba03d36f2 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -251,11 +251,10 @@ static int dhcp_prefix_route_from_lease(
static int link_set_dhcp_routes(Link *link) {
_cleanup_free_ sd_dhcp_route **static_routes = NULL;
bool classless_route = false, static_route = false;
- const struct in_addr *router;
struct in_addr address;
- int r, n, i;
uint32_t table;
Route *rt;
+ int r, n;
assert(link);
@@ -298,9 +297,9 @@ static int link_set_dhcp_routes(Link *link) {
if (n == -ENODATA)
log_link_debug_errno(link, n, "DHCP: No routes received from DHCP server: %m");
else if (n < 0)
- log_link_debug_errno(link, n, "DHCP: could not get routes: %m");
+ return log_link_error_errno(link, n, "DHCP: could not get routes: %m");
- for (i = 0; i < n; i++) {
+ for (int i = 0; i < n; i++) {
switch (sd_dhcp_route_get_option(static_routes[i])) {
case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
classless_route = true;
@@ -312,11 +311,14 @@ static int link_set_dhcp_routes(Link *link) {
}
if (link->network->dhcp_use_routes) {
- for (i = 0; i < n; i++) {
+ /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
+ * the DHCP client MUST ignore the Static Routes option. */
+ if (classless_route && static_route)
+ log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option");
+
+ for (int i = 0; i < n; i++) {
_cleanup_(route_freep) Route *route = NULL;
- /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
- the DHCP client MUST ignore the Static Routes option. */
if (classless_route &&
sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
continue;
@@ -347,20 +349,20 @@ static int link_set_dhcp_routes(Link *link) {
}
if (link->network->dhcp_use_gateway) {
+ const struct in_addr *router;
+
r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
if (IN_SET(r, 0, -ENODATA))
log_link_info(link, "DHCP: No gateway received from DHCP server.");
else if (r < 0)
- log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
+ return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m");
else if (in4_addr_is_null(&router[0]))
log_link_info(link, "DHCP: Received gateway is null.");
-
- /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
- a Router option, the DHCP client MUST ignore the Router option. */
- if (classless_route && static_route)
- log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option");
-
- if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) {
+ else if (classless_route)
+ /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
+ * a Router option, the DHCP client MUST ignore the Router option. */
+ log_link_warning(link, "Classless static routes received from DHCP server: ignoring router option");
+ else {
_cleanup_(route_freep) Route *route = NULL, *route_gw = NULL;
r = route_new(&route_gw);
@@ -399,20 +401,20 @@ static int link_set_dhcp_routes(Link *link) {
r = dhcp_route_configure(route, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not set router: %m");
- }
- LIST_FOREACH(routes, rt, link->network->static_routes) {
- if (!rt->gateway_from_dhcp)
- continue;
+ LIST_FOREACH(routes, rt, link->network->static_routes) {
+ if (!rt->gateway_from_dhcp)
+ continue;
- if (rt->family != AF_INET)
- continue;
+ if (rt->family != AF_INET)
+ continue;
- rt->gw.in = router[0];
+ rt->gw.in = router[0];
- r = dhcp_route_configure(rt, link);
- if (r < 0)
- return log_link_error_errno(link, r, "Could not set gateway: %m");
+ r = dhcp_route_configure(rt, link);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set gateway: %m");
+ }
}
}
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index d969995ea..675f19c92 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -160,7 +160,8 @@ static int dhcp6_pd_remove_old(Link *link, bool force) {
if (k < 0)
r = k;
- (void) sd_radv_remove_prefix(link->radv, &route->dst.in6, 64);
+ if (link->radv)
+ (void) sd_radv_remove_prefix(link->radv, &route->dst.in6, 64);
dhcp6_pd_free(hashmap_get(link->manager->dhcp6_prefixes, &route->dst.in6));
}
@@ -201,7 +202,8 @@ int dhcp6_pd_remove(Link *link) {
if (k < 0)
r = k;
- (void) sd_radv_remove_prefix(link->radv, &route->dst.in6, 64);
+ if (link->radv)
+ (void) sd_radv_remove_prefix(link->radv, &route->dst.in6, 64);
dhcp6_pd_free(hashmap_get(link->manager->dhcp6_prefixes, &route->dst.in6));
}
@@ -992,7 +994,7 @@ static int dhcp6_update_address(
addr->cinfo.ifa_valid = lifetime_valid;
(void) in_addr_to_string(addr->family, &addr->in_addr, &buffer);
- log_link_full(link, set_contains(link->dhcp6_addresses, addr) ? LOG_DEBUG : LOG_INFO, 0,
+ log_link_full(link, set_contains(link->dhcp6_addresses, addr) ? LOG_DEBUG : LOG_INFO,
"DHCPv6 address %s/%u timeout preferred %d valid %d",
strna(buffer), addr->prefixlen, lifetime_preferred, lifetime_valid);
diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c
index 833d13cf0..6a0afeac3 100644
--- a/src/network/networkd-fdb.c
+++ b/src/network/networkd-fdb.c
@@ -292,10 +292,12 @@ int config_parse_fdb_destination(
return log_oom();
r = in_addr_from_string_auto(rvalue, &fdb_entry->family, &fdb_entry->destination_addr);
- if (r < 0)
- return log_syntax(unit, LOG_WARNING, filename, line, r,
- "FDB destination IP address is invalid, ignoring assignment: %s",
- rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "FDB destination IP address is invalid, ignoring assignment: %s",
+ rvalue);
+ return 0;
+ }
fdb_entry = NULL;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 1597f1ed5..ea3ff55b4 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -720,7 +720,6 @@ static Link *link_free(Link *link) {
link->dhcp6_pd_routes = set_free(link->dhcp6_pd_routes);
link->dhcp6_pd_routes_old = set_free(link->dhcp6_pd_routes_old);
link->ndisc_routes = set_free(link->ndisc_routes);
- link->ndisc_routes_old = set_free(link->ndisc_routes_old);
link->nexthops = set_free(link->nexthops);
link->nexthops_foreign = set_free(link->nexthops_foreign);
@@ -736,7 +735,6 @@ static Link *link_free(Link *link) {
link->dhcp6_pd_addresses = set_free(link->dhcp6_pd_addresses);
link->dhcp6_pd_addresses_old = set_free(link->dhcp6_pd_addresses_old);
link->ndisc_addresses = set_free(link->ndisc_addresses);
- link->ndisc_addresses_old = set_free(link->ndisc_addresses_old);
while ((address = link->pool_addresses)) {
LIST_REMOVE(addresses, link->pool_addresses, address);
@@ -1163,6 +1161,8 @@ void link_check_ready(Link *link) {
}
if (link_has_carrier(link) || !link->network->configure_without_carrier) {
+ bool has_ndisc_address = false;
+ NDiscAddress *n;
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address_configured) {
log_link_debug(link, "%s(): IPv4LL is not configured.", __func__);
@@ -1175,8 +1175,14 @@ void link_check_ready(Link *link) {
return;
}
+ SET_FOREACH(n, link->ndisc_addresses, i)
+ if (!n->marked) {
+ has_ndisc_address = true;
+ break;
+ }
+
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) &&
- !link->dhcp_address && set_isempty(link->dhcp6_addresses) && set_isempty(link->ndisc_addresses) &&
+ !link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no dynamic address is assigned yet.", __func__);
return;
@@ -4674,10 +4680,10 @@ int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, in
const char *err_msg = NULL;
(void) sd_netlink_message_read_string(m, NLMSGERR_ATTR_MSG, &err_msg);
- return log_link_full(link, level, err,
- "%s: %s%s%s%m",
- msg,
- strempty(err_msg),
- err_msg && !endswith(err_msg, ".") ? "." : "",
- err_msg ? " " : "");
+ return log_link_full_errno(link, level, err,
+ "%s: %s%s%s%m",
+ msg,
+ strempty(err_msg),
+ err_msg && !endswith(err_msg, ".") ? "." : "",
+ err_msg ? " " : "");
}
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index ab5c3fd26..a0c566114 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -132,8 +132,8 @@ typedef struct Link {
sd_ndisc *ndisc;
Set *ndisc_rdnss;
Set *ndisc_dnssl;
- Set *ndisc_addresses, *ndisc_addresses_old;
- Set *ndisc_routes, *ndisc_routes_old;
+ Set *ndisc_addresses;
+ Set *ndisc_routes;
unsigned ndisc_addresses_messages;
unsigned ndisc_routes_messages;
bool ndisc_addresses_configured:1;
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index a6c1a39e2..b1c68dbfd 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -36,11 +36,11 @@
#include "path-util.h"
#include "set.h"
#include "signal-util.h"
+#include "stat-util.h"
#include "strv.h"
#include "sysctl-util.h"
#include "tmpfile-util.h"
#include "udev-util.h"
-#include "virt.h"
/* use 128 MB for receive socket kernel queue. */
#define RCVBUF_SIZE (128*1024*1024)
@@ -260,16 +260,19 @@ static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *devi
static int manager_connect_udev(Manager *m) {
int r;
- /* udev does not initialize devices inside containers,
- * so we rely on them being already initialized before
- * entering the container */
- if (detect_container() > 0)
+ /* udev does not initialize devices inside containers, so we rely on them being already
+ * initialized before entering the container. */
+ if (path_is_read_only_fs("/sys") > 0)
return 0;
r = sd_device_monitor_new(&m->device_monitor);
if (r < 0)
return log_error_errno(r, "Failed to initialize device monitor: %m");
+ r = sd_device_monitor_set_receive_buffer_size(m->device_monitor, RCVBUF_SIZE);
+ if (r < 0)
+ log_warning_errno(r, "Failed to increase buffer size for device monitor, ignoring: %m");
+
r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL);
if (r < 0)
return log_error_errno(r, "Could not add device monitor filter: %m");
@@ -1346,7 +1349,7 @@ static int manager_connect_genl(Manager *m) {
r = sd_netlink_inc_rcvbuf(m->genl, RCVBUF_SIZE);
if (r < 0)
- return r;
+ log_warning_errno(r, "Failed to increase receive buffer size for general netlink socket, ignoring: %m");
r = sd_netlink_attach_event(m->genl, m->event, 0);
if (r < 0)
@@ -1368,9 +1371,14 @@ static int manager_connect_rtnl(Manager *m) {
if (r < 0)
return r;
- r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
- if (r < 0)
- return r;
+ /* Bump receiver buffer, but only if we are not called via socket activation, as in that
+ * case systemd sets the receive buffer size for us, and the value in the .socket unit
+ * should take full effect. */
+ if (fd < 0) {
+ r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
+ if (r < 0)
+ log_warning_errno(r, "Failed to increase receive buffer size for rtnl socket, ignoring: %m");
+ }
r = sd_netlink_attach_event(m->rtnl, m->event, 0);
if (r < 0)
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index 349f0548a..bcea91c69 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -35,79 +35,218 @@
#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
-static int ndisc_remove_old(Link *link, bool force);
+static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force);
static int ndisc_address_callback(Address *address) {
- Address *a;
+ struct in6_addr router = {};
+ NDiscAddress *n;
Iterator i;
assert(address);
assert(address->link);
- /* Make this called only once */
- SET_FOREACH(a, address->link->ndisc_addresses, i)
- a->callback = NULL;
+ SET_FOREACH(n, address->link->ndisc_addresses, i)
+ if (n->address == address) {
+ router = n->router;
+ break;
+ }
- return ndisc_remove_old(address->link, true);
+ if (IN6_IS_ADDR_UNSPECIFIED(&router)) {
+ _cleanup_free_ char *buf = NULL;
+
+ (void) in_addr_to_string(address->family, &address->in_addr, &buf);
+ log_link_debug(address->link, "%s is called for %s/%u, but it is already removed, ignoring.",
+ __func__, strna(buf), address->prefixlen);
+ return 0;
+ }
+
+ /* Make this called only once */
+ SET_FOREACH(n, address->link->ndisc_addresses, i)
+ if (IN6_ARE_ADDR_EQUAL(&n->router, &router))
+ n->address->callback = NULL;
+
+ return ndisc_remove_old_one(address->link, &router, true);
}
-static int ndisc_remove_old(Link *link, bool force) {
- Address *address;
- Route *route;
+static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force) {
+ NDiscAddress *na;
+ NDiscRoute *nr;
NDiscDNSSL *dnssl;
NDiscRDNSS *rdnss;
Iterator i;
int k, r = 0;
assert(link);
+ assert(router);
if (!force) {
- bool set_callback = !set_isempty(link->ndisc_addresses);
+ bool set_callback = false;
if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured)
return 0;
- SET_FOREACH(address, link->ndisc_addresses, i)
- if (address_is_ready(address)) {
- set_callback = false;
+ SET_FOREACH(na, link->ndisc_addresses, i)
+ if (!na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router)) {
+ set_callback = true;
break;
}
+ if (set_callback)
+ SET_FOREACH(na, link->ndisc_addresses, i)
+ if (!na->marked && address_is_ready(na->address)) {
+ set_callback = false;
+ break;
+ }
+
if (set_callback) {
- SET_FOREACH(address, link->ndisc_addresses, i)
- address->callback = ndisc_address_callback;
+ SET_FOREACH(na, link->ndisc_addresses, i)
+ if (!na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router))
+ na->address->callback = ndisc_address_callback;
+
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *buf = NULL;
+
+ (void) in_addr_to_string(AF_INET6, (union in_addr_union *) router, &buf);
+ log_link_debug(link, "No SLAAC address obtained from %s is ready. "
+ "The old NDisc information will be removed later.",
+ strna(buf));
+ }
return 0;
}
}
- if (!set_isempty(link->ndisc_addresses_old) || !set_isempty(link->ndisc_routes_old))
- log_link_debug(link, "Removing old NDisc addresses and routes.");
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *buf = NULL;
+
+ (void) in_addr_to_string(AF_INET6, (union in_addr_union *) router, &buf);
+ log_link_debug(link, "Removing old NDisc information obtained from %s.", strna(buf));
+ }
link_dirty(link);
- SET_FOREACH(address, link->ndisc_addresses_old, i) {
- k = address_remove(address, link, NULL);
- if (k < 0)
- r = k;
- }
+ SET_FOREACH(na, link->ndisc_addresses, i)
+ if (na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router)) {
+ k = address_remove(na->address, link, NULL);
+ if (k < 0)
+ r = k;
+ }
- SET_FOREACH(route, link->ndisc_routes_old, i) {
- k = route_remove(route, link, NULL);
- if (k < 0)
- r = k;
- }
+ SET_FOREACH(nr, link->ndisc_routes, i)
+ if (nr->marked && IN6_ARE_ADDR_EQUAL(&nr->router, router)) {
+ k = route_remove(nr->route, link, NULL);
+ if (k < 0)
+ r = k;
+ }
SET_FOREACH(rdnss, link->ndisc_rdnss, i)
- if (rdnss->marked)
+ if (rdnss->marked && IN6_ARE_ADDR_EQUAL(&rdnss->router, router))
free(set_remove(link->ndisc_rdnss, rdnss));
SET_FOREACH(dnssl, link->ndisc_dnssl, i)
- if (dnssl->marked)
+ if (dnssl->marked && IN6_ARE_ADDR_EQUAL(&dnssl->router, router))
free(set_remove(link->ndisc_dnssl, dnssl));
return r;
}
+static int ndisc_remove_old(Link *link) {
+ _cleanup_set_free_free_ Set *routers = NULL;
+ _cleanup_free_ struct in6_addr *router = NULL;
+ struct in6_addr *a;
+ NDiscAddress *na;
+ NDiscRoute *nr;
+ NDiscDNSSL *dnssl;
+ NDiscRDNSS *rdnss;
+ Iterator i;
+ int k, r;
+
+ assert(link);
+
+ routers = set_new(&in6_addr_hash_ops);
+ if (!routers)
+ return -ENOMEM;
+
+ SET_FOREACH(na, link->ndisc_addresses, i)
+ if (!set_contains(routers, &na->router)) {
+ router = newdup(struct in6_addr, &na->router, 1);
+ if (!router)
+ return -ENOMEM;
+
+ r = set_put(routers, router);
+ if (r < 0)
+ return r;
+
+ assert(r > 0);
+ TAKE_PTR(router);
+ }
+
+ SET_FOREACH(nr, link->ndisc_routes, i)
+ if (!set_contains(routers, &nr->router)) {
+ router = newdup(struct in6_addr, &nr->router, 1);
+ if (!router)
+ return -ENOMEM;
+
+ r = set_put(routers, router);
+ if (r < 0)
+ return r;
+
+ assert(r > 0);
+ TAKE_PTR(router);
+ }
+
+ SET_FOREACH(rdnss, link->ndisc_rdnss, i)
+ if (!set_contains(routers, &rdnss->router)) {
+ router = newdup(struct in6_addr, &rdnss->router, 1);
+ if (!router)
+ return -ENOMEM;
+
+ r = set_put(routers, router);
+ if (r < 0)
+ return r;
+
+ assert(r > 0);
+ TAKE_PTR(router);
+ }
+
+ SET_FOREACH(dnssl, link->ndisc_dnssl, i)
+ if (!set_contains(routers, &dnssl->router)) {
+ router = newdup(struct in6_addr, &dnssl->router, 1);
+ if (!router)
+ return -ENOMEM;
+
+ r = set_put(routers, router);
+ if (r < 0)
+ return r;
+
+ assert(r > 0);
+ TAKE_PTR(router);
+ }
+
+ r = 0;
+ SET_FOREACH(a, routers, i) {
+ k = ndisc_remove_old_one(link, a, false);
+ if (k < 0)
+ r = k;
+ }
+
+ return r;
+}
+
+static void ndisc_route_hash_func(const NDiscRoute *x, struct siphash *state) {
+ route_hash_func(x->route, state);
+}
+
+static int ndisc_route_compare_func(const NDiscRoute *a, const NDiscRoute *b) {
+ return route_compare_func(a->route, b->route);
+}
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+ ndisc_route_hash_ops,
+ NDiscRoute,
+ ndisc_route_hash_func,
+ ndisc_route_compare_func,
+ free);
+
static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@@ -130,7 +269,7 @@ static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
log_link_debug(link, "NDisc routes set.");
link->ndisc_routes_configured = true;
- r = ndisc_remove_old(link, false);
+ r = ndisc_remove_old(link);
if (r < 0) {
link_enter_failed(link);
return 1;
@@ -142,6 +281,67 @@ static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
return 1;
}
+static int ndisc_route_configure(Route *route, Link *link, sd_ndisc_router *rt) {
+ _cleanup_free_ NDiscRoute *nr = NULL;
+ NDiscRoute *nr_exist;
+ struct in6_addr router;
+ Route *ret;
+ int r;
+
+ assert(route);
+ assert(link);
+ assert(rt);
+
+ r = route_configure(route, link, ndisc_route_handler, &ret);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to set NDisc route: %m");
+
+ link->ndisc_routes_messages++;
+
+ r = sd_ndisc_router_get_address(rt, &router);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
+
+ nr = new(NDiscRoute, 1);
+ if (!nr)
+ return log_oom();
+
+ *nr = (NDiscRoute) {
+ .router = router,
+ .route = ret,
+ };
+
+ nr_exist = set_get(link->ndisc_routes, nr);
+ if (nr_exist) {
+ nr_exist->marked = false;
+ nr_exist->router = router;
+ return 0;
+ }
+
+ r = set_ensure_put(&link->ndisc_routes, &ndisc_route_hash_ops, nr);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to store NDisc SLAAC route: %m");
+ assert(r > 0);
+ TAKE_PTR(nr);
+
+ return 0;
+}
+
+static void ndisc_address_hash_func(const NDiscAddress *x, struct siphash *state) {
+ address_hash_func(x->address, state);
+}
+
+static int ndisc_address_compare_func(const NDiscAddress *a, const NDiscAddress *b) {
+ return address_compare_func(a->address, b->address);
+}
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+ ndisc_address_hash_ops,
+ NDiscAddress,
+ ndisc_address_hash_func,
+ ndisc_address_compare_func,
+ free);
+
static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@@ -165,7 +365,7 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
log_link_debug(link, "NDisc SLAAC addresses set.");
link->ndisc_addresses_configured = true;
- r = ndisc_remove_old(link, false);
+ r = ndisc_remove_old(link);
if (r < 0) {
link_enter_failed(link);
return 1;
@@ -181,34 +381,16 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1;
}
-static int ndisc_route_configure(Route *route, Link *link) {
- Route *ret;
- int r;
-
- assert(route);
- assert(link);
-
- r = route_configure(route, link, ndisc_route_handler, &ret);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to set NDisc route: %m");
-
- link->ndisc_routes_messages++;
-
- r = set_ensure_put(&link->ndisc_routes, &route_hash_ops, ret);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store NDisc route: %m");
-
- (void) set_remove(link->ndisc_routes_old, ret);
-
- return 0;
-}
-
-static int ndisc_address_configure(Address *address, Link *link) {
+static int ndisc_address_configure(Address *address, Link *link, sd_ndisc_router *rt) {
+ _cleanup_free_ NDiscAddress *na = NULL;
+ NDiscAddress *na_exist;
+ struct in6_addr router;
Address *ret;
int r;
assert(address);
assert(link);
+ assert(rt);
r = address_configure(address, link, ndisc_address_handler, true, &ret);
if (r < 0)
@@ -216,11 +398,31 @@ static int ndisc_address_configure(Address *address, Link *link) {
link->ndisc_addresses_messages++;
- r = set_ensure_put(&link->ndisc_addresses, &address_hash_ops, ret);
+ r = sd_ndisc_router_get_address(rt, &router);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
+
+ na = new(NDiscAddress, 1);
+ if (!na)
+ return log_oom();
+
+ *na = (NDiscAddress) {
+ .router = router,
+ .address = ret,
+ };
+
+ na_exist = set_get(link->ndisc_addresses, na);
+ if (na_exist) {
+ na_exist->marked = false;
+ na_exist->router = router;
+ return 0;
+ }
+
+ r = set_ensure_put(&link->ndisc_addresses, &ndisc_address_hash_ops, na);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store NDisc SLAAC address: %m");
-
- (void) set_remove(link->ndisc_addresses_old, ret);
+ assert(r > 0);
+ TAKE_PTR(na);
return 0;
}
@@ -286,7 +488,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
route->lifetime = time_now + lifetime * USEC_PER_SEC;
route->mtu = mtu;
- r = ndisc_route_configure(route, link);
+ r = ndisc_route_configure(route, link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not set default route: %m");
@@ -300,7 +502,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
route_gw->gw = gateway;
- r = ndisc_route_configure(route_gw, link);
+ r = ndisc_route_configure(route_gw, link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not set gateway: %m");
}
@@ -514,7 +716,7 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
address->in_addr.in6 = *a;
- r = ndisc_address_configure(address, link);
+ r = ndisc_address_configure(address, link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
}
@@ -560,7 +762,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
- r = ndisc_route_configure(route, link);
+ r = ndisc_route_configure(route, link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not set prefix route: %m");;
@@ -617,7 +819,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return log_link_error_errno(link, r, "Failed to get route address: %m");
- r = ndisc_route_configure(route, link);
+ r = ndisc_route_configure(route, link, rt);
if (r < 0)
return log_link_error_errno(link, r, "Could not set additional route: %m");
@@ -642,6 +844,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
uint32_t lifetime;
const struct in6_addr *a;
+ struct in6_addr router;
NDiscRDNSS *rdnss;
usec_t time_now;
Iterator i;
@@ -650,6 +853,10 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
assert(link);
assert(rt);
+ r = sd_ndisc_router_get_address(rt, &router);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
+
r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
@@ -663,7 +870,8 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
SET_FOREACH(rdnss, link->ndisc_rdnss, i)
- rdnss->marked = true;
+ if (IN6_ARE_ADDR_EQUAL(&rdnss->router, &router))
+ rdnss->marked = true;
if (lifetime == 0)
return 0;
@@ -682,6 +890,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
rdnss = set_get(link->ndisc_rdnss, &d);
if (rdnss) {
rdnss->marked = false;
+ rdnss->router = router;
rdnss->valid_until = time_now + lifetime * USEC_PER_SEC;
continue;
}
@@ -692,6 +901,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
*x = (NDiscRDNSS) {
.address = a[j],
+ .router = router,
.valid_until = time_now + lifetime * USEC_PER_SEC,
};
@@ -721,6 +931,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
_cleanup_strv_free_ char **l = NULL;
+ struct in6_addr router;
uint32_t lifetime;
usec_t time_now;
NDiscDNSSL *dnssl;
@@ -731,6 +942,10 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
assert(link);
assert(rt);
+ r = sd_ndisc_router_get_address(rt, &router);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
+
r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
@@ -744,7 +959,8 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
SET_FOREACH(dnssl, link->ndisc_dnssl, i)
- dnssl->marked = true;
+ if (IN6_ARE_ADDR_EQUAL(&dnssl->router, &router))
+ dnssl->marked = true;
if (lifetime == 0)
return 0;
@@ -767,10 +983,12 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
dnssl = set_get(link->ndisc_dnssl, s);
if (dnssl) {
dnssl->marked = false;
+ dnssl->router = router;
dnssl->valid_until = time_now + lifetime * USEC_PER_SEC;
continue;
}
+ s->router = router;
s->valid_until = time_now + lifetime * USEC_PER_SEC;
r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
@@ -865,9 +1083,11 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
}
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
- Address *address;
- Route *route;
+ struct in6_addr router;
uint64_t flags;
+ NDiscAddress *na;
+ NDiscRoute *nr;
+ Iterator i;
int r;
assert(link);
@@ -880,17 +1100,17 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
link_dirty(link);
- while ((address = set_steal_first(link->ndisc_addresses))) {
- r = set_ensure_put(&link->ndisc_addresses_old, &address_hash_ops, address);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store old NDisc SLAAC address: %m");
- }
+ r = sd_ndisc_router_get_address(rt, &router);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
- while ((route = set_steal_first(link->ndisc_routes))) {
- r = set_ensure_put(&link->ndisc_routes_old, &route_hash_ops, route);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store old NDisc route: %m");
- }
+ SET_FOREACH(na, link->ndisc_addresses, i)
+ if (IN6_ARE_ADDR_EQUAL(&na->router, &router))
+ na->marked = true;
+
+ SET_FOREACH(nr, link->ndisc_routes, i)
+ if (IN6_ARE_ADDR_EQUAL(&nr->router, &router))
+ nr->marked = true;
r = sd_ndisc_router_get_flags(rt, &flags);
if (r < 0)
@@ -933,7 +1153,7 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
else
log_link_debug(link, "Setting NDisc routes.");
- r = ndisc_remove_old(link, false);
+ r = ndisc_remove_old(link);
if (r < 0)
return r;
diff --git a/src/network/networkd-ndisc.h b/src/network/networkd-ndisc.h
index c459f4245..927f555bc 100644
--- a/src/network/networkd-ndisc.h
+++ b/src/network/networkd-ndisc.h
@@ -2,7 +2,9 @@
#pragma once
#include "conf-parser.h"
+#include "networkd-address.h"
#include "networkd-link.h"
+#include "networkd-route.h"
#include "time-util.h"
typedef struct IPv6Token IPv6Token;
@@ -23,9 +25,24 @@ typedef enum IPv6AcceptRAStartDHCP6Client {
_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_INVALID = -1,
} IPv6AcceptRAStartDHCP6Client;
+typedef struct NDiscAddress {
+ /* Used when GC'ing old DNS servers when configuration changes. */
+ bool marked;
+ struct in6_addr router;
+ Address *address;
+} NDiscAddress;
+
+typedef struct NDiscRoute {
+ /* Used when GC'ing old DNS servers when configuration changes. */
+ bool marked;
+ struct in6_addr router;
+ Route *route;
+} NDiscRoute;
+
typedef struct NDiscRDNSS {
/* Used when GC'ing old DNS servers when configuration changes. */
bool marked;
+ struct in6_addr router;
usec_t valid_until;
struct in6_addr address;
} NDiscRDNSS;
@@ -33,6 +50,7 @@ typedef struct NDiscRDNSS {
typedef struct NDiscDNSSL {
/* Used when GC'ing old domains when configuration changes. */
bool marked;
+ struct in6_addr router;
usec_t valid_until;
/* The domain name follows immediately. */
} NDiscDNSSL;
diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c
index e0c490bab..003a50b68 100644
--- a/src/network/networkd-radv.c
+++ b/src/network/networkd-radv.c
@@ -681,7 +681,9 @@ int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_le
int r;
assert(link);
- assert(link->radv);
+
+ if (!link->radv)
+ return 0;
r = sd_radv_prefix_new(&p);
if (r < 0)
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 541bf1e79..28c0f3b89 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -9,6 +9,7 @@
#include "netlink-util.h"
#include "networkd-ipv4ll.h"
#include "networkd-manager.h"
+#include "networkd-ndisc.h"
#include "networkd-route.h"
#include "parse-util.h"
#include "set.h"
@@ -142,6 +143,9 @@ void route_free(Route *route) {
network_config_section_free(route->section);
if (route->link) {
+ NDiscRoute *n;
+ Iterator i;
+
set_remove(route->link->routes, route);
set_remove(route->link->routes_foreign, route);
set_remove(route->link->dhcp_routes, route);
@@ -150,8 +154,9 @@ void route_free(Route *route) {
set_remove(route->link->dhcp6_routes_old, route);
set_remove(route->link->dhcp6_pd_routes, route);
set_remove(route->link->dhcp6_pd_routes_old, route);
- set_remove(route->link->ndisc_routes, route);
- set_remove(route->link->ndisc_routes_old, route);
+ SET_FOREACH(n, route->link->ndisc_routes, i)
+ if (n->route == route)
+ free(set_remove(route->link->ndisc_routes, n));
}
ordered_set_free_free(route->multipath_routes);
@@ -161,7 +166,7 @@ void route_free(Route *route) {
free(route);
}
-static void route_hash_func(const Route *route, struct siphash *state) {
+void route_hash_func(const Route *route, struct siphash *state) {
assert(route);
siphash24_compress(&route->family, sizeof(route->family), state);
@@ -196,7 +201,7 @@ static void route_hash_func(const Route *route, struct siphash *state) {
}
}
-static int route_compare_func(const Route *a, const Route *b) {
+int route_compare_func(const Route *a, const Route *b) {
int r;
r = CMP(a->family, b->family);
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index 3beee9b03..75651fa51 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -62,6 +62,8 @@ struct Route {
LIST_FIELDS(Route, routes);
};
+void route_hash_func(const Route *route, struct siphash *state);
+int route_compare_func(const Route *a, const Route *b);
extern const struct hash_ops route_hash_ops;
int route_new(Route **ret);
diff --git a/src/partition/growfs.c b/src/partition/growfs.c
index 98a7e4d31..8f5448937 100644
--- a/src/partition/growfs.c
+++ b/src/partition/growfs.c
@@ -11,6 +11,7 @@
#include
#include "blockdev-util.h"
+#include "btrfs-util.h"
#include "crypt-util.h"
#include "device-nodes.h"
#include "dissect-image.h"
@@ -94,6 +95,8 @@ static int maybe_resize_underlying_device(const char *mountpath, dev_t main_devn
if (r < 0)
return log_error_errno(r, "Failed to determine underlying block device of \"%s\": %m",
mountpath);
+ if (devno == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" not backed by block device.", arg_target);
log_debug("Underlying device %d:%d, main dev %d:%d, %s",
major(devno), minor(devno),
@@ -210,8 +213,12 @@ static int run(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "\"%s\" is not a mount point: %m", arg_target);
r = get_block_device(arg_target, &devno);
+ if (r == -EUCLEAN)
+ return btrfs_log_dev_root(LOG_ERR, r, arg_target);
if (r < 0)
return log_error_errno(r, "Failed to determine block device of \"%s\": %m", arg_target);
+ if (devno == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" not backed by block device.", arg_target);
r = maybe_resize_underlying_device(arg_target, devno);
if (r < 0)
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 2e5f5d134..9a35e9b73 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -2734,6 +2734,8 @@ static int context_open_copy_block_paths(Context *context) {
/* Special support for btrfs */
r = btrfs_get_block_device_fd(source_fd, &devt);
+ if (r == -EUCLEAN)
+ return btrfs_log_dev_root(LOG_ERR, r, p->copy_blocks_path);
if (r < 0)
return log_error_errno(r, "Unable to determine backing block device of '%s': %m", p->copy_blocks_path);
@@ -3150,6 +3152,8 @@ static int find_root(char **ret, int *ret_fd) {
}
r = acquire_root_devno(arg_node, O_RDONLY|O_CLOEXEC, ret, ret_fd);
+ if (r == -EUCLEAN)
+ return btrfs_log_dev_root(LOG_ERR, r, arg_node);
if (r < 0)
return log_error_errno(r, "Failed to determine backing device of %s: %m", arg_node);
@@ -3177,6 +3181,8 @@ static int find_root(char **ret, int *ret_fd) {
r = acquire_root_devno(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC, ret, ret_fd);
if (r < 0) {
+ if (r == -EUCLEAN)
+ return btrfs_log_dev_root(LOG_ERR, r, p);
if (r != -ENODEV)
return log_error_errno(r, "Failed to determine backing device of %s: %m", p);
} else
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c
index 3072b984e..8378ff591 100644
--- a/src/resolve/resolvectl.c
+++ b/src/resolve/resolvectl.c
@@ -2545,6 +2545,7 @@ static int native_help(void) {
" dnssec [LINK [MODE]] Get/set per-interface DNSSEC mode\n"
" nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA\n"
" revert LINK Revert per-interface configuration\n"
+ " log-level [LEVEL] Get/set logging threshold for systemd-resolved\n"
"\nOptions:\n"
" -h --help Show this help\n"
" --version Show package version\n"
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 1da590b68..b1974579a 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -349,7 +349,8 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
#if HAVE_LIBIDN2
r = idn2_to_unicode_8z8z(label, &utf8, 0);
if (r != IDN2_OK)
- return log_error("Failed to undo IDNA: %s", idn2_strerror(r));
+ return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN),
+ "Failed to undo IDNA: %s", idn2_strerror(r));
assert(utf8_is_valid(utf8));
r = strlen(utf8);
diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c
index 3bb12f922..14e91e3e4 100644
--- a/src/shared/ethtool-util.c
+++ b/src/shared/ethtool-util.c
@@ -943,7 +943,7 @@ int config_parse_channel(const char *unit,
}
if (k < 1) {
- log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Invalid %s value, ignoring: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid %s value, ignoring: %s", lvalue, rvalue);
return 0;
}
diff --git a/src/shared/log-link.h b/src/shared/log-link.h
index 2d0380269..b844f9ef8 100644
--- a/src/shared/log-link.h
+++ b/src/shared/log-link.h
@@ -14,24 +14,26 @@
* See, network/networkd-link.h for example.
*/
-#define log_link_full(link, level, error, ...) \
+#define log_link_full_errno(link, level, error, ...) \
({ \
const Link *_l = (link); \
(_l && _l->ifname) ? log_object_internal(level, error, PROJECT_FILE, __LINE__, __func__, "INTERFACE=", _l->ifname, NULL, NULL, ##__VA_ARGS__) : \
log_internal(level, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \
}) \
-#define log_link_debug(link, ...) log_link_full(link, LOG_DEBUG, 0, ##__VA_ARGS__)
-#define log_link_info(link, ...) log_link_full(link, LOG_INFO, 0, ##__VA_ARGS__)
-#define log_link_notice(link, ...) log_link_full(link, LOG_NOTICE, 0, ##__VA_ARGS__)
-#define log_link_warning(link, ...) log_link_full(link, LOG_WARNING, 0, ##__VA_ARGS__)
-#define log_link_error(link, ...) log_link_full(link, LOG_ERR, 0, ##__VA_ARGS__)
+#define log_link_full(link, level, ...) (void) log_link_full_errno(link, level, 0, __VA_ARGS__)
-#define log_link_debug_errno(link, error, ...) log_link_full(link, LOG_DEBUG, error, ##__VA_ARGS__)
-#define log_link_info_errno(link, error, ...) log_link_full(link, LOG_INFO, error, ##__VA_ARGS__)
-#define log_link_notice_errno(link, error, ...) log_link_full(link, LOG_NOTICE, error, ##__VA_ARGS__)
-#define log_link_warning_errno(link, error, ...) log_link_full(link, LOG_WARNING, error, ##__VA_ARGS__)
-#define log_link_error_errno(link, error, ...) log_link_full(link, LOG_ERR, error, ##__VA_ARGS__)
+#define log_link_debug(link, ...) log_link_full_errno(link, LOG_DEBUG, 0, __VA_ARGS__)
+#define log_link_info(link, ...) log_link_full(link, LOG_INFO, __VA_ARGS__)
+#define log_link_notice(link, ...) log_link_full(link, LOG_NOTICE, __VA_ARGS__)
+#define log_link_warning(link, ...) log_link_full(link, LOG_WARNING, __VA_ARGS__)
+#define log_link_error(link, ...) log_link_full(link, LOG_ERR, __VA_ARGS__)
+
+#define log_link_debug_errno(link, error, ...) log_link_full_errno(link, LOG_DEBUG, error, __VA_ARGS__)
+#define log_link_info_errno(link, error, ...) log_link_full_errno(link, LOG_INFO, error, __VA_ARGS__)
+#define log_link_notice_errno(link, error, ...) log_link_full_errno(link, LOG_NOTICE, error, __VA_ARGS__)
+#define log_link_warning_errno(link, error, ...) log_link_full_errno(link, LOG_WARNING, error, __VA_ARGS__)
+#define log_link_error_errno(link, error, ...) log_link_full_errno(link, LOG_ERR, error, __VA_ARGS__)
#define LOG_LINK_MESSAGE(link, fmt, ...) "MESSAGE=%s: " fmt, (link)->ifname, ##__VA_ARGS__
#define LOG_LINK_INTERFACE(link) "INTERFACE=%s", (link)->ifname
diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c
index 632964df4..4088439f9 100644
--- a/src/shared/pkcs11-util.c
+++ b/src/shared/pkcs11-util.c
@@ -212,13 +212,15 @@ int pkcs11_token_login(
"Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
log_info("Successfully logged into security token '%s' via protected authentication path.", token_label);
- *ret_used_pin = NULL;
+ if (ret_used_pin)
+ *ret_used_pin = NULL;
return 0;
}
if (!FLAGS_SET(token_info->flags, CKF_LOGIN_REQUIRED)) {
log_info("No login into security token '%s' required.", token_label);
- *ret_used_pin = NULL;
+ if (ret_used_pin)
+ *ret_used_pin = NULL;
return 0;
}
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 0dccc8f97..96c125b99 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -403,6 +403,8 @@ int find_hibernate_location(HibernateLocation **ret_hibernate_location) {
r = swap_device_to_device_id(swap, &swap_device);
if (r < 0)
return log_debug_errno(r, "%s: failed to query device number: %m", swap->device);
+ if (swap_device == 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENODEV), "%s: not backed by block device.", swap->device);
hibernate_location = hibernate_location_free(hibernate_location);
hibernate_location = new(HibernateLocation, 1);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index eafae6e4f..ddcf3bb9a 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2085,8 +2085,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (streq(key, "systemd.unit")) {
if (proc_cmdline_value_missing(key, value))
return 0;
- if (!unit_name_is_valid(value, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
- return log_warning("Unit name specified on %s= is not valid, ignoring: %s", key, value);
+ if (!unit_name_is_valid(value, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
+ log_warning("Unit name specified on %s= is not valid, ignoring: %s", key, value);
+ return 0;
+ }
return free_and_strdup_warn(ret, key);
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 2404e36bf..2db3773fc 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -773,6 +773,7 @@ static int fd_set_perms(Item *i, int fd, const char *path, const struct stat *st
struct stat stbuf;
mode_t new_mode;
bool do_chown;
+ int r;
assert(i);
assert(fd);
@@ -818,8 +819,9 @@ static int fd_set_perms(Item *i, int fd, const char *path, const struct stat *st
log_debug("\"%s\" matches temporary mode %o already.", path, m);
else {
log_debug("Temporarily changing \"%s\" to mode %o.", path, m);
- if (fchmod_opath(fd, m) < 0)
- return log_error_errno(errno, "fchmod() of %s failed: %m", path);
+ r = fchmod_opath(fd, m);
+ if (r < 0)
+ return log_error_errno(r, "fchmod() of %s failed: %m", path);
}
}
}
@@ -850,8 +852,9 @@ static int fd_set_perms(Item *i, int fd, const char *path, const struct stat *st
log_debug("\"%s\" matches mode %o already.", path, new_mode);
else {
log_debug("Changing \"%s\" to mode %o.", path, new_mode);
- if (fchmod_opath(fd, new_mode) < 0)
- return log_error_errno(errno, "fchmod() of %s failed: %m", path);
+ r = fchmod_opath(fd, new_mode);
+ if (r < 0)
+ return log_error_errno(r, "fchmod() of %s failed: %m", path);
}
}
}
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 72ef0c56b..03fd429b2 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -320,7 +320,8 @@ static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr
case NET_ADDR_PERM:
break;
default:
- return log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
+ log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
+ return 0;
}
if (want_random == (addr_type == NET_ADDR_RANDOM))
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
index bb82e8ae9..eb980cb98 100644
--- a/src/udev/udev-builtin-keyboard.c
+++ b/src/udev/udev-builtin-keyboard.c
@@ -87,7 +87,7 @@ static int map_keycode(sd_device *dev, int fd, int scancode, const char *keycode
return 0;
}
-static char* parse_token(const char *current, int32_t *val_out) {
+static const char* parse_token(const char *current, int32_t *val_out) {
char *next;
int32_t val;
@@ -109,7 +109,7 @@ static char* parse_token(const char *current, int32_t *val_out) {
static int override_abs(sd_device *dev, int fd, unsigned evcode, const char *value) {
struct input_absinfo absinfo;
- char *next;
+ const char *next;
int r;
r = ioctl(fd, EVIOCGABS(evcode), &absinfo);
@@ -122,7 +122,7 @@ static int override_abs(sd_device *dev, int fd, unsigned evcode, const char *val
next = parse_token(next, &absinfo.fuzz);
next = parse_token(next, &absinfo.flat);
if (!next)
- return log_device_error(dev, "Failed to parse EV_ABS override '%s'", value);
+ return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Failed to parse EV_ABS override '%s'", value);
log_device_debug(dev, "keyboard: %x overridden with %"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32,
evcode, absinfo.minimum, absinfo.maximum, absinfo.resolution, absinfo.fuzz, absinfo.flat);
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
index 63401a570..d552316ee 100644
--- a/src/udev/udev-builtin-uaccess.c
+++ b/src/udev/udev-builtin-uaccess.c
@@ -50,7 +50,7 @@ static int builtin_uaccess(sd_device *dev, int argc, char *argv[], bool test) {
r = devnode_acl(path, true, false, 0, true, uid);
if (r < 0) {
- log_device_full(dev, r == -ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL: %m");
+ log_device_full_errno(dev, r == -ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL: %m");
goto finish;
}
@@ -64,7 +64,7 @@ finish:
/* Better be safe than sorry and reset ACL */
k = devnode_acl(path, true, false, 0, false, 0);
if (k < 0) {
- log_device_full(dev, k == -ENOENT ? LOG_DEBUG : LOG_ERR, k, "Failed to apply ACL: %m");
+ log_device_full_errno(dev, k == -ENOENT ? LOG_DEBUG : LOG_ERR, k, "Failed to apply ACL: %m");
if (r >= 0)
r = k;
}
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index e1c2baf7f..f27696430 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -633,7 +633,7 @@ static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userd
if (si->si_status == 0)
log_device_debug(spawn->device, "Process '%s' succeeded.", spawn->cmd);
else
- log_device_full(spawn->device, spawn->accept_failure ? LOG_DEBUG : LOG_WARNING, 0,
+ log_device_full(spawn->device, spawn->accept_failure ? LOG_DEBUG : LOG_WARNING,
"Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
ret = si->si_status;
break;
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index 31a340309..643d413ba 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -325,13 +325,13 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
r = chmod_and_chown(devnode, mode, uid, gid);
if (r < 0)
- log_device_full(dev, r == -ENOENT ? LOG_DEBUG : LOG_ERR, r,
- "Failed to set owner/mode of %s to uid=" UID_FMT
- ", gid=" GID_FMT ", mode=%#o: %m",
- devnode,
- uid_is_valid(uid) ? uid : stats.st_uid,
- gid_is_valid(gid) ? gid : stats.st_gid,
- mode != MODE_INVALID ? mode & 0777 : stats.st_mode & 0777);
+ log_device_full_errno(dev, r == -ENOENT ? LOG_DEBUG : LOG_ERR, r,
+ "Failed to set owner/mode of %s to uid=" UID_FMT
+ ", gid=" GID_FMT ", mode=%#o: %m",
+ devnode,
+ uid_is_valid(uid) ? uid : stats.st_uid,
+ gid_is_valid(gid) ? gid : stats.st_gid,
+ mode != MODE_INVALID ? mode & 0777 : stats.st_mode & 0777);
} else
log_device_debug(dev, "Preserve permissions of %s, uid=" UID_FMT ", gid=" GID_FMT ", mode=%#o",
devnode,
@@ -348,8 +348,8 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
q = mac_selinux_apply(devnode, label);
if (q < 0)
- log_device_full(dev, q == -ENOENT ? LOG_DEBUG : LOG_ERR, q,
- "SECLABEL: failed to set SELinux label '%s': %m", label);
+ log_device_full_errno(dev, q == -ENOENT ? LOG_DEBUG : LOG_ERR, q,
+ "SECLABEL: failed to set SELinux label '%s': %m", label);
else
log_device_debug(dev, "SECLABEL: set SELinux label '%s'", label);
@@ -358,8 +358,8 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
q = mac_smack_apply(devnode, SMACK_ATTR_ACCESS, label);
if (q < 0)
- log_device_full(dev, q == -ENOENT ? LOG_DEBUG : LOG_ERR, q,
- "SECLABEL: failed to set SMACK label '%s': %m", label);
+ log_device_full_errno(dev, q == -ENOENT ? LOG_DEBUG : LOG_ERR, q,
+ "SECLABEL: failed to set SMACK label '%s': %m", label);
else
log_device_debug(dev, "SECLABEL: set SMACK label '%s'", label);
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index c36f032f6..9d6dc4244 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -182,43 +182,46 @@ struct UdevRules {
/*** Logging helpers ***/
-#define log_rule_full(device, rules, level, error, fmt, ...) \
+#define log_rule_full_errno(device, rules, level, error, fmt, ...) \
({ \
UdevRules *_r = (rules); \
UdevRuleFile *_f = _r ? _r->current_file : NULL; \
UdevRuleLine *_l = _f ? _f->current_line : NULL; \
const char *_n = _f ? _f->filename : NULL; \
\
- log_device_full(device, level, error, "%s:%u " fmt, \
- strna(_n), _l ? _l->line_number : 0, \
- ##__VA_ARGS__); \
+ log_device_full_errno(device, level, error, "%s:%u " fmt, \
+ strna(_n), _l ? _l->line_number : 0, \
+ ##__VA_ARGS__); \
})
-#define log_rule_debug(device, rules, ...) log_rule_full(device, rules, LOG_DEBUG, 0, ##__VA_ARGS__)
-#define log_rule_info(device, rules, ...) log_rule_full(device, rules, LOG_INFO, 0, ##__VA_ARGS__)
-#define log_rule_notice(device, rules, ...) log_rule_full(device, rules, LOG_NOTICE, 0, ##__VA_ARGS__)
-#define log_rule_warning(device, rules, ...) log_rule_full(device, rules, LOG_WARNING, 0, ##__VA_ARGS__)
-#define log_rule_error(device, rules, ...) log_rule_full(device, rules, LOG_ERR, 0, ##__VA_ARGS__)
+#define log_rule_full(device, rules, level, ...) (void) log_rule_full_errno(device, rules, level, 0, __VA_ARGS__)
-#define log_rule_debug_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_DEBUG, error, ##__VA_ARGS__)
-#define log_rule_info_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_INFO, error, ##__VA_ARGS__)
-#define log_rule_notice_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_NOTICE, error, ##__VA_ARGS__)
-#define log_rule_warning_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_WARNING, error, ##__VA_ARGS__)
-#define log_rule_error_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_ERR, error, ##__VA_ARGS__)
+#define log_rule_debug(device, rules, ...) log_rule_full_errno(device, rules, LOG_DEBUG, 0, __VA_ARGS__)
+#define log_rule_info(device, rules, ...) log_rule_full(device, rules, LOG_INFO, __VA_ARGS__)
+#define log_rule_notice(device, rules, ...) log_rule_full(device, rules, LOG_NOTICE, __VA_ARGS__)
+#define log_rule_warning(device, rules, ...) log_rule_full(device, rules, LOG_WARNING, __VA_ARGS__)
+#define log_rule_error(device, rules, ...) log_rule_full(device, rules, LOG_ERR, __VA_ARGS__)
-#define log_token_full(rules, ...) log_rule_full(NULL, rules, ##__VA_ARGS__)
+#define log_rule_debug_errno(device, rules, error, ...) log_rule_full_errno(device, rules, LOG_DEBUG, error, __VA_ARGS__)
+#define log_rule_info_errno(device, rules, error, ...) log_rule_full_errno(device, rules, LOG_INFO, error, __VA_ARGS__)
+#define log_rule_notice_errno(device, rules, error, ...) log_rule_full_errno(device, rules, LOG_NOTICE, error, __VA_ARGS__)
+#define log_rule_warning_errno(device, rules, error, ...) log_rule_full_errno(device, rules, LOG_WARNING, error, __VA_ARGS__)
+#define log_rule_error_errno(device, rules, error, ...) log_rule_full_errno(device, rules, LOG_ERR, error, __VA_ARGS__)
-#define log_token_debug(rules, ...) log_token_full(rules, LOG_DEBUG, 0, ##__VA_ARGS__)
-#define log_token_info(rules, ...) log_token_full(rules, LOG_INFO, 0, ##__VA_ARGS__)
-#define log_token_notice(rules, ...) log_token_full(rules, LOG_NOTICE, 0, ##__VA_ARGS__)
-#define log_token_warning(rules, ...) log_token_full(rules, LOG_WARNING, 0, ##__VA_ARGS__)
-#define log_token_error(rules, ...) log_token_full(rules, LOG_ERR, 0, ##__VA_ARGS__)
+#define log_token_full_errno(rules, level, error, ...) log_rule_full_errno(NULL, rules, level, error, __VA_ARGS__)
+#define log_token_full(rules, level, ...) (void) log_token_full_errno(rules, level, 0, __VA_ARGS__)
-#define log_token_debug_errno(rules, error, ...) log_token_full(rules, LOG_DEBUG, error, ##__VA_ARGS__)
-#define log_token_info_errno(rules, error, ...) log_token_full(rules, LOG_INFO, error, ##__VA_ARGS__)
-#define log_token_notice_errno(rules, error, ...) log_token_full(rules, LOG_NOTICE, error, ##__VA_ARGS__)
-#define log_token_warning_errno(rules, error, ...) log_token_full(rules, LOG_WARNING, error, ##__VA_ARGS__)
-#define log_token_error_errno(rules, error, ...) log_token_full(rules, LOG_ERR, error, ##__VA_ARGS__)
+#define log_token_debug(rules, ...) log_token_full_errno(rules, LOG_DEBUG, 0, __VA_ARGS__)
+#define log_token_info(rules, ...) log_token_full(rules, LOG_INFO, __VA_ARGS__)
+#define log_token_notice(rules, ...) log_token_full(rules, LOG_NOTICE, __VA_ARGS__)
+#define log_token_warning(rules, ...) log_token_full(rules, LOG_WARNING, __VA_ARGS__)
+#define log_token_error(rules, ...) log_token_full(rules, LOG_ERR, __VA_ARGS__)
+
+#define log_token_debug_errno(rules, error, ...) log_token_full_errno(rules, LOG_DEBUG, error, __VA_ARGS__)
+#define log_token_info_errno(rules, error, ...) log_token_full_errno(rules, LOG_INFO, error, __VA_ARGS__)
+#define log_token_notice_errno(rules, error, ...) log_token_full_errno(rules, LOG_NOTICE, error, __VA_ARGS__)
+#define log_token_warning_errno(rules, error, ...) log_token_full_errno(rules, LOG_WARNING, error, __VA_ARGS__)
+#define log_token_error_errno(rules, error, ...) log_token_full_errno(rules, LOG_ERR, error, __VA_ARGS__)
#define _log_token_invalid(rules, key, type) \
log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \
diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c
index 96a25ddf7..d87a43537 100644
--- a/src/udev/udev-watch.c
+++ b/src/udev/udev-watch.c
@@ -97,10 +97,8 @@ int udev_watch_begin(sd_device *dev) {
log_device_debug(dev, "Adding watch on '%s'", devnode);
wd = inotify_add_watch(inotify_fd, devnode, IN_CLOSE_WRITE);
if (wd < 0)
- return log_device_full(dev,
- errno == ENOENT ? LOG_DEBUG : LOG_ERR,
- errno,
- "Failed to add device '%s' to watch: %m", devnode);
+ return log_device_full_errno(dev, errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
+ "Failed to add device '%s' to watch: %m", devnode);
device_set_watch_handle(dev, wd);
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index f3236dedf..0551d2738 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -1685,8 +1685,11 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
/* Bump receiver buffer, but only if we are not called via socket activation, as in that
* case systemd sets the receive buffer size for us, and the value in the .socket unit
* should take full effect. */
- if (fd_uevent < 0)
- (void) sd_device_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024);
+ if (fd_uevent < 0) {
+ r = sd_device_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set receive buffer size for device monitor, ignoring: %m");
+ }
r = device_monitor_enable_receiving(manager->monitor);
if (r < 0)
diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c
index c001802dc..e9d589e0e 100644
--- a/src/update-done/update-done.c
+++ b/src/update-done/update-done.c
@@ -31,7 +31,7 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
r = write_string_file_atomic_label_ts(path, message, ts);
if (r == -EROFS)
- return log_debug("Cannot create \"%s\", file system is read-only.", path);
+ return log_debug_errno(r, "Cannot create \"%s\", file system is read-only.", path);
if (r < 0)
return log_error_errno(r, "Failed to write \"%s\": %m", path);
return 0;
diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c
index 47354d501..4ab90a63e 100644
--- a/src/update-utmp/update-utmp.c
+++ b/src/update-utmp/update-utmp.c
@@ -187,8 +187,10 @@ static int on_runlevel(Context *c) {
runlevel = get_current_runlevel(c);
if (runlevel < 0)
return runlevel;
- if (runlevel == 0)
- return log_warning("Failed to get new runlevel, utmp update skipped.");
+ if (runlevel == 0) {
+ log_warning("Failed to get new runlevel, utmp update skipped.");
+ return 0;
+ }
if (previous == runlevel)
return 0;
diff --git a/src/volatile-root/volatile-root.c b/src/volatile-root/volatile-root.c
index e55864d6c..6a0846424 100644
--- a/src/volatile-root/volatile-root.c
+++ b/src/volatile-root/volatile-root.c
@@ -175,7 +175,7 @@ static int run(int argc, char *argv[]) {
r = get_block_device_harder(path, &devt);
if (r < 0)
return log_error_errno(r, "Failed to determine device major/minor of %s: %m", path);
- else if (r > 0) {
+ else if (r > 0) { /* backed by block device */
_cleanup_free_ char *dn = NULL;
r = device_path_make_major_minor(S_IFBLK, devt, &dn);
diff --git a/test/test-execute/exec-dynamicuser-statedir.service b/test/test-execute/exec-dynamicuser-statedir.service
index ca40934de..6103193ba 100644
--- a/test/test-execute/exec-dynamicuser-statedir.service
+++ b/test/test-execute/exec-dynamicuser-statedir.service
@@ -10,10 +10,10 @@ ExecStart=test -f /var/lib/waldo/yay
ExecStart=test -f /var/lib/quux/pief/yayyay
ExecStart=test -f /var/lib/private/waldo/yay
ExecStart=test -f /var/lib/private/quux/pief/yayyay
-ExecStart=/bin/sh -x -c 'test "$$STATE_DIRECTORY" = "%S/waldo:%S/quux/pief"'
+ExecStart=sh -x -c 'test "$$STATE_DIRECTORY" = "%S/waldo:%S/quux/pief"'
# Make sure that /var/lib/private/waldo is really the only writable directory besides the obvious candidates
-ExecStart=sh -x -c 'test $$(find / \( -path /var/tmp -o -path /tmp -o -path /proc -o -path /dev/mqueue -o -path /dev/shm -o -path /sys/fs/bpf -o -path /dev/.lxc \) -prune -o -type d -writable -print 2>/dev/null | sort -u | tr -d '\\\\n') = /var/lib/private/quux/pief/var/lib/private/waldo'
+ExecStart=sh -x -c 'test $$(find / \\( -path /var/tmp -o -path /tmp -o -path /proc -o -path /dev/mqueue -o -path /dev/shm -o -path /sys/fs/bpf -o -path /dev/.lxc \\) -prune -o -type d -writable -print 2>/dev/null | sort -u | tr -d "\\\\n") = /var/lib/private/quux/pief/var/lib/private/waldo'
Type=oneshot
DynamicUser=yes
diff --git a/test/test-network/conf/25-address-static.network b/test/test-network/conf/25-address-static.network
index e9780f2ee..f8119d13e 100644
--- a/test/test-network/conf/25-address-static.network
+++ b/test/test-network/conf/25-address-static.network
@@ -51,3 +51,261 @@ Peer=2001:db8:0:f103::10/128
[Address]
Address=::/64
+
+# test for ENOBUFS issue #17012
+[Network]
+Address=10.3.3.1/16
+Address=10.3.3.2/16
+Address=10.3.3.3/16
+Address=10.3.3.4/16
+Address=10.3.3.5/16
+Address=10.3.3.6/16
+Address=10.3.3.7/16
+Address=10.3.3.8/16
+Address=10.3.3.9/16
+Address=10.3.3.10/16
+Address=10.3.3.11/16
+Address=10.3.3.12/16
+Address=10.3.3.13/16
+Address=10.3.3.14/16
+Address=10.3.3.15/16
+Address=10.3.3.16/16
+Address=10.3.3.17/16
+Address=10.3.3.18/16
+Address=10.3.3.19/16
+Address=10.3.3.20/16
+Address=10.3.3.21/16
+Address=10.3.3.22/16
+Address=10.3.3.23/16
+Address=10.3.3.24/16
+Address=10.3.3.25/16
+Address=10.3.3.26/16
+Address=10.3.3.27/16
+Address=10.3.3.28/16
+Address=10.3.3.29/16
+Address=10.3.3.30/16
+Address=10.3.3.31/16
+Address=10.3.3.32/16
+Address=10.3.3.33/16
+Address=10.3.3.34/16
+Address=10.3.3.35/16
+Address=10.3.3.36/16
+Address=10.3.3.37/16
+Address=10.3.3.38/16
+Address=10.3.3.39/16
+Address=10.3.3.40/16
+Address=10.3.3.41/16
+Address=10.3.3.42/16
+Address=10.3.3.43/16
+Address=10.3.3.44/16
+Address=10.3.3.45/16
+Address=10.3.3.46/16
+Address=10.3.3.47/16
+Address=10.3.3.48/16
+Address=10.3.3.49/16
+Address=10.3.3.50/16
+Address=10.3.3.51/16
+Address=10.3.3.52/16
+Address=10.3.3.53/16
+Address=10.3.3.54/16
+Address=10.3.3.55/16
+Address=10.3.3.56/16
+Address=10.3.3.57/16
+Address=10.3.3.58/16
+Address=10.3.3.59/16
+Address=10.3.3.60/16
+Address=10.3.3.61/16
+Address=10.3.3.62/16
+Address=10.3.3.63/16
+Address=10.3.3.64/16
+Address=10.3.3.65/16
+Address=10.3.3.66/16
+Address=10.3.3.67/16
+Address=10.3.3.68/16
+Address=10.3.3.69/16
+Address=10.3.3.70/16
+Address=10.3.3.71/16
+Address=10.3.3.72/16
+Address=10.3.3.73/16
+Address=10.3.3.74/16
+Address=10.3.3.75/16
+Address=10.3.3.76/16
+Address=10.3.3.77/16
+Address=10.3.3.78/16
+Address=10.3.3.79/16
+Address=10.3.3.80/16
+Address=10.3.3.81/16
+Address=10.3.3.82/16
+Address=10.3.3.83/16
+Address=10.3.3.84/16
+Address=10.3.3.85/16
+Address=10.3.3.86/16
+Address=10.3.3.87/16
+Address=10.3.3.88/16
+Address=10.3.3.89/16
+Address=10.3.3.90/16
+Address=10.3.3.91/16
+Address=10.3.3.92/16
+Address=10.3.3.93/16
+Address=10.3.3.94/16
+Address=10.3.3.95/16
+Address=10.3.3.96/16
+Address=10.3.3.97/16
+Address=10.3.3.98/16
+Address=10.3.3.99/16
+Address=10.3.3.100/16
+Address=10.3.3.101/16
+Address=10.3.3.101/16
+Address=10.3.3.102/16
+Address=10.3.3.103/16
+Address=10.3.3.104/16
+Address=10.3.3.105/16
+Address=10.3.3.106/16
+Address=10.3.3.107/16
+Address=10.3.3.108/16
+Address=10.3.3.109/16
+Address=10.3.3.110/16
+Address=10.3.3.111/16
+Address=10.3.3.112/16
+Address=10.3.3.113/16
+Address=10.3.3.114/16
+Address=10.3.3.115/16
+Address=10.3.3.116/16
+Address=10.3.3.117/16
+Address=10.3.3.118/16
+Address=10.3.3.119/16
+Address=10.3.3.120/16
+Address=10.3.3.121/16
+Address=10.3.3.122/16
+Address=10.3.3.123/16
+Address=10.3.3.124/16
+Address=10.3.3.125/16
+Address=10.3.3.126/16
+Address=10.3.3.127/16
+Address=10.3.3.128/16
+Address=10.3.3.129/16
+Address=10.3.3.130/16
+Address=10.3.3.131/16
+Address=10.3.3.132/16
+Address=10.3.3.133/16
+Address=10.3.3.134/16
+Address=10.3.3.135/16
+Address=10.3.3.136/16
+Address=10.3.3.137/16
+Address=10.3.3.138/16
+Address=10.3.3.139/16
+Address=10.3.3.140/16
+Address=10.3.3.141/16
+Address=10.3.3.142/16
+Address=10.3.3.143/16
+Address=10.3.3.144/16
+Address=10.3.3.145/16
+Address=10.3.3.146/16
+Address=10.3.3.147/16
+Address=10.3.3.148/16
+Address=10.3.3.149/16
+Address=10.3.3.150/16
+Address=10.3.3.151/16
+Address=10.3.3.152/16
+Address=10.3.3.153/16
+Address=10.3.3.154/16
+Address=10.3.3.155/16
+Address=10.3.3.156/16
+Address=10.3.3.157/16
+Address=10.3.3.158/16
+Address=10.3.3.159/16
+Address=10.3.3.160/16
+Address=10.3.3.161/16
+Address=10.3.3.162/16
+Address=10.3.3.163/16
+Address=10.3.3.164/16
+Address=10.3.3.165/16
+Address=10.3.3.166/16
+Address=10.3.3.167/16
+Address=10.3.3.168/16
+Address=10.3.3.169/16
+Address=10.3.3.170/16
+Address=10.3.3.171/16
+Address=10.3.3.172/16
+Address=10.3.3.173/16
+Address=10.3.3.174/16
+Address=10.3.3.175/16
+Address=10.3.3.176/16
+Address=10.3.3.177/16
+Address=10.3.3.178/16
+Address=10.3.3.179/16
+Address=10.3.3.180/16
+Address=10.3.3.181/16
+Address=10.3.3.182/16
+Address=10.3.3.183/16
+Address=10.3.3.184/16
+Address=10.3.3.185/16
+Address=10.3.3.186/16
+Address=10.3.3.187/16
+Address=10.3.3.188/16
+Address=10.3.3.189/16
+Address=10.3.3.190/16
+Address=10.3.3.191/16
+Address=10.3.3.192/16
+Address=10.3.3.193/16
+Address=10.3.3.194/16
+Address=10.3.3.195/16
+Address=10.3.3.196/16
+Address=10.3.3.197/16
+Address=10.3.3.198/16
+Address=10.3.3.199/16
+Address=10.3.3.200/16
+Address=10.3.3.201/16
+Address=10.3.3.202/16
+Address=10.3.3.203/16
+Address=10.3.3.204/16
+Address=10.3.3.205/16
+Address=10.3.3.206/16
+Address=10.3.3.207/16
+Address=10.3.3.208/16
+Address=10.3.3.209/16
+Address=10.3.3.210/16
+Address=10.3.3.211/16
+Address=10.3.3.212/16
+Address=10.3.3.213/16
+Address=10.3.3.214/16
+Address=10.3.3.215/16
+Address=10.3.3.216/16
+Address=10.3.3.217/16
+Address=10.3.3.218/16
+Address=10.3.3.219/16
+Address=10.3.3.220/16
+Address=10.3.3.221/16
+Address=10.3.3.222/16
+Address=10.3.3.223/16
+Address=10.3.3.224/16
+Address=10.3.3.225/16
+Address=10.3.3.226/16
+Address=10.3.3.227/16
+Address=10.3.3.228/16
+Address=10.3.3.229/16
+Address=10.3.3.230/16
+Address=10.3.3.231/16
+Address=10.3.3.232/16
+Address=10.3.3.233/16
+Address=10.3.3.234/16
+Address=10.3.3.235/16
+Address=10.3.3.236/16
+Address=10.3.3.237/16
+Address=10.3.3.238/16
+Address=10.3.3.239/16
+Address=10.3.3.240/16
+Address=10.3.3.241/16
+Address=10.3.3.242/16
+Address=10.3.3.243/16
+Address=10.3.3.244/16
+Address=10.3.3.245/16
+Address=10.3.3.246/16
+Address=10.3.3.247/16
+Address=10.3.3.248/16
+Address=10.3.3.249/16
+Address=10.3.3.250/16
+Address=10.3.3.251/16
+Address=10.3.3.252/16
+Address=10.3.3.253/16
+Address=10.3.3.254/16
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 0ca1fb3bf..d528fa8ad 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -1764,6 +1764,10 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
+ # test for ENOBUFS issue #17012
+ for i in range(1,254):
+ self.assertRegex(output, f'inet 10.3.3.{i}/16 brd 10.3.255.255')
+
# invalid sections
self.assertNotRegex(output, '10.10.0.1/16')
self.assertNotRegex(output, '10.10.0.2/16')
@@ -1789,6 +1793,14 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global')
+ restart_networkd()
+ self.wait_online(['dummy98:routable'])
+
+ # test for ENOBUFS issue #17012
+ output = check_output('ip -4 address show dev dummy98')
+ for i in range(1,254):
+ self.assertRegex(output, f'inet 10.3.3.{i}/16 brd 10.3.255.255')
+
def test_address_preferred_lifetime_zero_ipv6(self):
copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev')
start_networkd(5)