summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFernando Fernandez Mancera <ffmancera@riseup.net>2024-04-19 18:16:17 +0200
committerFernando Fernandez Mancera <ffmancera@riseup.net>2024-04-19 18:16:22 +0200
commite59dce948839292050824620746321cf6300865a (patch)
tree36780aee66593dabb879459e0470514ebf2cba1e
parent0a3917e6a1836877ef1d43c9e680836cec8b2391 (diff)
parentcd87004dfbe6947a03f1aa7248c01fc9351c4bbd (diff)
merge: branch 'systemd' into ff/sync_systemdff/sync_systemd
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-device/sd-device.c2
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c6
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c4
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp-duid.h1
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-ndisc.h91
-rw-r--r--src/libnm-systemd-shared/src/basic/env-util.c33
-rw-r--r--src/libnm-systemd-shared/src/basic/env-util.h10
-rw-r--r--src/libnm-systemd-shared/src/basic/extract-word.c35
-rw-r--r--src/libnm-systemd-shared/src/basic/extract-word.h5
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.c83
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.h6
-rw-r--r--src/libnm-systemd-shared/src/basic/format-util.h8
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.c16
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.h10
-rw-r--r--src/libnm-systemd-shared/src/basic/glyph-util.c13
-rw-r--r--src/libnm-systemd-shared/src/basic/glyph-util.h6
-rw-r--r--src/libnm-systemd-shared/src/basic/hashmap.c53
-rw-r--r--src/libnm-systemd-shared/src/basic/hashmap.h10
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.c16
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/locale-util.c7
-rw-r--r--src/libnm-systemd-shared/src/basic/log.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_fcntl.h21
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_syscall.h19
-rw-r--r--src/libnm-systemd-shared/src/basic/namespace-util.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.c23
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.h27
-rw-r--r--src/libnm-systemd-shared/src/basic/signal-util.c28
-rw-r--r--src/libnm-systemd-shared/src/basic/signal-util.h9
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.c204
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.h29
-rw-r--r--src/libnm-systemd-shared/src/basic/string-util.c3
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.c2
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.c6
-rw-r--r--src/libnm-systemd-shared/src/fundamental/macro-fundamental.h26
35 files changed, 505 insertions, 315 deletions
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-device/sd-device.c b/src/libnm-systemd-core/src/libsystemd/sd-device/sd-device.c
index 2e7cdcb3d5..0ca871464f 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-device/sd-device.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-device/sd-device.c
@@ -223,7 +223,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
/* Only operate on sysfs, i.e. refuse going down into /sys/fs/cgroup/ or similar places where
* things are not arranged as kobjects in kernel, and hence don't necessarily have
* kobject/attribute structure. */
- r = getenv_bool_secure("SYSTEMD_DEVICE_VERIFY_SYSFS");
+ r = secure_getenv_bool("SYSTEMD_DEVICE_VERIFY_SYSFS");
if (r < 0 && r != -ENXIO)
log_debug_errno(r, "Failed to parse $SYSTEMD_DEVICE_VERIFY_SYSFS value: %m");
if (r != 0) {
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
index 33cf30800c..6449b85c50 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
@@ -1579,7 +1579,7 @@ static int child_exit_callback(sd_event_source *s, const siginfo_t *si, void *us
static bool shall_use_pidfd(void) {
/* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */
- return getenv_bool_secure("SYSTEMD_PIDFD") != 0;
+ return secure_getenv_bool("SYSTEMD_PIDFD") != 0;
}
_public_ int sd_event_add_child(
@@ -4923,13 +4923,13 @@ _public_ int sd_event_get_state(sd_event *e) {
_public_ int sd_event_get_exit_code(sd_event *e, int *code) {
assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
- assert_return(code, -EINVAL);
assert_return(!event_origin_changed(e), -ECHILD);
if (!e->exit_requested)
return -ENODATA;
- *code = e->exit_code;
+ if (code)
+ *code = e->exit_code;
return 0;
}
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
index 1fc011c7f3..5817305548 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
@@ -143,7 +143,7 @@ int id128_read_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t *ret) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
- fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0);
+ fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return fd;
@@ -190,7 +190,7 @@ int id128_write_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t id) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
- fd = xopenat(dir_fd, path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, /* xopen_flags = */ 0, 0444);
+ fd = xopenat_full(dir_fd, path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, /* xopen_flags = */ 0, 0444);
if (fd < 0)
return fd;
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-duid.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-duid.h
index b1d2772a3e..555b40e9d8 100644
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp-duid.h
+++ b/src/libnm-systemd-core/src/systemd/sd-dhcp-duid.h
@@ -3,7 +3,6 @@
#define foosddhcpduidhfoo
/***
- Copyright © 2013 Intel Corporation. All rights reserved.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
diff --git a/src/libnm-systemd-core/src/systemd/sd-ndisc.h b/src/libnm-systemd-core/src/systemd/sd-ndisc.h
index a5ccd5f644..5f4f6caf8d 100644
--- a/src/libnm-systemd-core/src/systemd/sd-ndisc.h
+++ b/src/libnm-systemd-core/src/systemd/sd-ndisc.h
@@ -26,35 +26,14 @@
#include <sys/types.h>
#include "sd-event.h"
+#include "sd-ndisc-protocol.h"
+#include "sd-ndisc-router.h"
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
-/* Neighbor Discovery Options, RFC 4861, Section 4.6 and
- * https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */
-enum {
- SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1,
- SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2,
- SD_NDISC_OPTION_PREFIX_INFORMATION = 3,
- SD_NDISC_OPTION_MTU = 5,
- SD_NDISC_OPTION_ROUTE_INFORMATION = 24,
- SD_NDISC_OPTION_RDNSS = 25,
- SD_NDISC_OPTION_FLAGS_EXTENSION = 26,
- SD_NDISC_OPTION_DNSSL = 31,
- SD_NDISC_OPTION_CAPTIVE_PORTAL = 37,
- SD_NDISC_OPTION_PREF64 = 38
-};
-
-/* Route preference, RFC 4191, Section 2.1 */
-enum {
- SD_NDISC_PREFERENCE_LOW = 3U,
- SD_NDISC_PREFERENCE_MEDIUM = 0U,
- SD_NDISC_PREFERENCE_HIGH = 1U
-};
-
typedef struct sd_ndisc sd_ndisc;
-typedef struct sd_ndisc_router sd_ndisc_router;
__extension__ typedef enum sd_ndisc_event_t {
SD_NDISC_EVENT_TIMEOUT,
@@ -64,14 +43,16 @@ __extension__ typedef enum sd_ndisc_event_t {
_SD_ENUM_FORCE_S64(NDISC_EVENT)
} sd_ndisc_event_t;
-typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata);
+typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata);
int sd_ndisc_new(sd_ndisc **ret);
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
sd_ndisc *sd_ndisc_unref(sd_ndisc *nd);
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
int sd_ndisc_start(sd_ndisc *nd);
int sd_ndisc_stop(sd_ndisc *nd);
+int sd_ndisc_is_running(sd_ndisc *nd);
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority);
int sd_ndisc_detach_event(sd_ndisc *nd);
@@ -81,69 +62,9 @@ int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb, void *userdata);
int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index);
int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name);
int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret);
+int sd_ndisc_set_link_local_address(sd_ndisc *nd, const struct in6_addr *addr);
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
-sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
-sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
-
-int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
-int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
-
-int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret);
-int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret);
-int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret);
-
-/* Generic option access */
-int sd_ndisc_router_option_rewind(sd_ndisc_router *rt);
-int sd_ndisc_router_option_next(sd_ndisc_router *rt);
-int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret);
-int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type);
-int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
-
-/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */
-int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_prefix_get_valid_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret);
-int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
-int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
-
-/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */
-int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_route_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
-int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
-int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret);
-
-/* Specific option access: SD_NDISC_OPTION_RDNSS */
-int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret);
-int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_rdnss_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-
-/* Specific option access: SD_NDISC_OPTION_DNSSL */
-int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret);
-int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_dnssl_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-
-/* Specific option access: SD_NDISC_OPTION_CAPTIVE_PORTAL */
-int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret, size_t *ret_size);
-
-/* Specific option access: SD_NDISC_OPTION_PREF64 */
-int sd_ndisc_router_prefix64_get_prefix(sd_ndisc_router *rt, struct in6_addr *ret);
-int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
-int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
-int sd_ndisc_router_prefix64_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
-
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref);
-
_SD_END_DECLARATIONS;
#endif
diff --git a/src/libnm-systemd-shared/src/basic/env-util.c b/src/libnm-systemd-shared/src/basic/env-util.c
index c12caa2e55..54509a559f 100644
--- a/src/libnm-systemd-shared/src/basic/env-util.c
+++ b/src/libnm-systemd-shared/src/basic/env-util.c
@@ -312,19 +312,17 @@ char **strv_env_delete(char **x, size_t n_lists, ...) {
return TAKE_PTR(t);
}
-char **strv_env_unset(char **l, const char *p) {
- char **f, **t;
+char** strv_env_unset(char **l, const char *p) {
+ assert(p);
if (!l)
return NULL;
- assert(p);
-
/* Drops every occurrence of the env var setting p in the
* string list. Edits in-place. */
+ char **f, **t;
for (f = t = l; *f; f++) {
-
if (env_match(*f, p)) {
free(*f);
continue;
@@ -337,14 +335,13 @@ char **strv_env_unset(char **l, const char *p) {
return l;
}
-char **strv_env_unset_many(char **l, ...) {
- char **f, **t;
-
+char** strv_env_unset_many_internal(char **l, ...) {
if (!l)
return NULL;
/* Like strv_env_unset() but applies many at once. Edits in-place. */
+ char **f, **t;
for (f = t = l; *f; f++) {
bool found = false;
const char *p;
@@ -352,12 +349,11 @@ char **strv_env_unset_many(char **l, ...) {
va_start(ap, l);
- while ((p = va_arg(ap, const char*))) {
+ while ((p = va_arg(ap, const char*)))
if (env_match(*f, p)) {
found = true;
break;
}
- }
va_end(ap);
@@ -972,7 +968,7 @@ int getenv_bool(const char *p) {
return parse_boolean(e);
}
-int getenv_bool_secure(const char *p) {
+int secure_getenv_bool(const char *p) {
const char *e;
e = secure_getenv(p);
@@ -982,8 +978,7 @@ int getenv_bool_secure(const char *p) {
return parse_boolean(e);
}
-#if 0 /* NM_IGNORED */
-int getenv_uint64_secure(const char *p, uint64_t *ret) {
+int secure_getenv_uint64(const char *p, uint64_t *ret) {
const char *e;
assert(p);
@@ -1017,6 +1012,7 @@ int putenv_dup(const char *assignment, bool override) {
return RET_NERRNO(setenv(n, e + 1, override));
}
+#if 0 /* NM_IGNORED */
int setenv_systemd_exec_pid(bool update_only) {
const char *e;
int r;
@@ -1037,6 +1033,17 @@ int setenv_systemd_exec_pid(bool update_only) {
return 1;
}
+int setenv_systemd_log_level(void) {
+ _cleanup_free_ char *val = NULL;
+ int r;
+
+ r = log_level_to_string_alloc(log_get_max_level(), &val);
+ if (r < 0)
+ return r;
+
+ return RET_NERRNO(setenv("SYSTEMD_LOG_LEVEL", val, /* overwrite= */ true));
+}
+
int getenv_path_list(const char *name, char ***ret_paths) {
_cleanup_strv_free_ char **l = NULL;
const char *e;
diff --git a/src/libnm-systemd-shared/src/basic/env-util.h b/src/libnm-systemd-shared/src/basic/env-util.h
index ad127de39f..6610ca8ca1 100644
--- a/src/libnm-systemd-shared/src/basic/env-util.h
+++ b/src/libnm-systemd-shared/src/basic/env-util.h
@@ -43,8 +43,9 @@ char** _strv_env_merge(char **first, ...);
#define strv_env_merge(first, ...) _strv_env_merge(first, __VA_ARGS__, POINTER_MAX)
char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
-char **strv_env_unset(char **l, const char *p); /* In place ... */
-char **strv_env_unset_many(char **l, ...) _sentinel_;
+char** strv_env_unset(char **l, const char *p); /* In place ... */
+char** strv_env_unset_many_internal(char **l, ...) _sentinel_;
+#define strv_env_unset_many(l, ...) strv_env_unset_many_internal(l, __VA_ARGS__, NULL)
int strv_env_replace_consume(char ***l, char *p); /* In place ... */
int strv_env_replace_strdup(char ***l, const char *assignment);
int strv_env_replace_strdup_passthrough(char ***l, const char *assignment);
@@ -61,9 +62,9 @@ static inline char* strv_env_get(char * const *x, const char *n) {
char *strv_env_pairs_get(char **l, const char *name) _pure_;
int getenv_bool(const char *p);
-int getenv_bool_secure(const char *p);
+int secure_getenv_bool(const char *p);
-int getenv_uint64_secure(const char *p, uint64_t *ret);
+int secure_getenv_uint64(const char *p, uint64_t *ret);
/* Like setenv, but calls unsetenv if value == NULL. */
int set_unset_env(const char *name, const char *value, bool overwrite);
@@ -72,6 +73,7 @@ int set_unset_env(const char *name, const char *value, bool overwrite);
int putenv_dup(const char *assignment, bool override);
int setenv_systemd_exec_pid(bool update_only);
+int setenv_systemd_log_level(void);
/* Parses and does sanity checks on an environment variable containing
* PATH-like colon-separated absolute paths */
diff --git a/src/libnm-systemd-shared/src/basic/extract-word.c b/src/libnm-systemd-shared/src/basic/extract-word.c
index 2910a4cb60..bf7bc44fb6 100644
--- a/src/libnm-systemd-shared/src/basic/extract-word.c
+++ b/src/libnm-systemd-shared/src/basic/extract-word.c
@@ -247,52 +247,43 @@ int extract_first_word_and_warn(
* Let's make sure that ExtractFlags fits into an unsigned int. */
assert_cc(sizeof(enum ExtractFlags) <= sizeof(unsigned));
-int extract_many_words(const char **p, const char *separators, unsigned flags, ...) {
+int extract_many_words_internal(const char **p, const char *separators, unsigned flags, ...) {
va_list ap;
- char **l;
- int n = 0, i, c, r;
+ unsigned n = 0;
+ int r;
- /* Parses a number of words from a string, stripping any
- * quotes if necessary. */
+ /* Parses a number of words from a string, stripping any quotes if necessary. */
assert(p);
/* Count how many words are expected */
va_start(ap, flags);
- for (;;) {
- if (!va_arg(ap, char **))
- break;
+ while (va_arg(ap, char**))
n++;
- }
va_end(ap);
- if (n <= 0)
+ if (n == 0)
return 0;
/* Read all words into a temporary array */
- l = newa0(char*, n);
- for (c = 0; c < n; c++) {
+ char **l = newa0(char*, n);
+ unsigned c;
+ for (c = 0; c < n; c++) {
r = extract_first_word(p, &l[c], separators, flags);
if (r < 0) {
free_many_charp(l, c);
return r;
}
-
if (r == 0)
break;
}
- /* If we managed to parse all words, return them in the passed
- * in parameters */
+ /* If we managed to parse all words, return them in the passed in parameters */
va_start(ap, flags);
- for (i = 0; i < n; i++) {
- char **v;
-
- v = va_arg(ap, char **);
- assert(v);
-
- *v = l[i];
+ FOREACH_ARRAY(i, l, n) {
+ char **v = ASSERT_PTR(va_arg(ap, char**));
+ *v = *i;
}
va_end(ap);
diff --git a/src/libnm-systemd-shared/src/basic/extract-word.h b/src/libnm-systemd-shared/src/basic/extract-word.h
index c82ad761ef..da4f6ae674 100644
--- a/src/libnm-systemd-shared/src/basic/extract-word.h
+++ b/src/libnm-systemd-shared/src/basic/extract-word.h
@@ -19,4 +19,7 @@ typedef enum ExtractFlags {
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
-int extract_many_words(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
+
+int extract_many_words_internal(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
+#define extract_many_words(p, separators, flags, ...) \
+ extract_many_words_internal(p, separators, flags, ##__VA_ARGS__, NULL)
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.c b/src/libnm-systemd-shared/src/basic/fd-util.c
index afdc05f2ab..584d02f05b 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.c
+++ b/src/libnm-systemd-shared/src/basic/fd-util.c
@@ -311,7 +311,7 @@ static int close_all_fds_special_case(const int except[], size_t n_except) {
case 0:
/* Close everything. Yay! */
- if (close_range(3, -1, 0) >= 0)
+ if (close_range(3, INT_MAX, 0) >= 0)
return 1;
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
@@ -422,7 +422,7 @@ int close_all_fds(const int except[], size_t n_except) {
if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
return 0;
- if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
+ if (close_range(sorted[n_sorted-1] + 1, INT_MAX, 0) >= 0)
return 0;
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
@@ -467,6 +467,53 @@ int close_all_fds(const int except[], size_t n_except) {
return r;
}
+int pack_fds(int fds[], size_t n_fds) {
+ if (n_fds <= 0)
+ return 0;
+
+ /* Shifts around the fds in the provided array such that they
+ * all end up packed next to each-other, in order, starting
+ * from SD_LISTEN_FDS_START. This must be called after close_all_fds();
+ * it is likely to freeze up otherwise. You should probably use safe_fork_full
+ * with FORK_CLOSE_ALL_FDS|FORK_PACK_FDS set, to ensure that this is done correctly.
+ * The fds array is modified in place with the new FD numbers. */
+
+ assert(fds);
+
+ for (int start = 0;;) {
+ int restart_from = -1;
+
+ for (int i = start; i < (int) n_fds; i++) {
+ int nfd;
+
+ /* Already at right index? */
+ if (fds[i] == i + 3)
+ continue;
+
+ nfd = fcntl(fds[i], F_DUPFD, i + 3);
+ if (nfd < 0)
+ return -errno;
+
+ safe_close(fds[i]);
+ fds[i] = nfd;
+
+ /* Hmm, the fd we wanted isn't free? Then
+ * let's remember that and try again from here */
+ if (nfd != i + 3 && restart_from < 0)
+ restart_from = i;
+ }
+
+ if (restart_from < 0)
+ break;
+
+ start = restart_from;
+ }
+
+ assert(fds[0] == 3);
+
+ return 0;
+}
+
int same_fd(int a, int b) {
struct stat sta, stb;
pid_t pid;
@@ -875,6 +922,38 @@ int fd_is_opath(int fd) {
return FLAGS_SET(r, O_PATH);
}
+int fd_verify_safe_flags(int fd) {
+ int flags, unexpected_flags;
+
+ /* Check if an extrinsic fd is safe to work on (by a privileged service). This ensures that clients
+ * can't trick a privileged service into giving access to a file the client doesn't already have
+ * access to (especially via something like O_PATH).
+ *
+ * O_NOFOLLOW: For some reason the kernel will return this flag from fcntl; it doesn't go away
+ * immediately after open(). It should have no effect whatsoever to an already-opened FD,
+ * and since we refuse O_PATH it should be safe.
+ *
+ * RAW_O_LARGEFILE: glibc secretly sets this and neglects to hide it from us if we call fcntl.
+ * See comment in missing_fcntl.h for more details about this.
+ *
+ * O_DIRECTORY: this is set for directories, which are totally fine
+ */
+
+ assert(fd >= 0);
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags < 0)
+ return -errno;
+
+ unexpected_flags = flags & ~(O_ACCMODE|O_NOFOLLOW|RAW_O_LARGEFILE|O_DIRECTORY);
+ if (unexpected_flags != 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
+ "Unexpected flags set for extrinsic fd: 0%o",
+ (unsigned) unexpected_flags);
+
+ return 0;
+}
+
int read_nr_open(void) {
_cleanup_free_ char *nr_open = NULL;
int r;
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.h b/src/libnm-systemd-shared/src/basic/fd-util.h
index 183266513a..f549831090 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.h
+++ b/src/libnm-systemd-shared/src/basic/fd-util.h
@@ -8,6 +8,7 @@
#include <sys/socket.h>
#include "macro.h"
+#include "missing_fcntl.h"
#include "stdio-util.h"
/* maximum length of fdname */
@@ -77,6 +78,8 @@ int get_max_fd(void);
int close_all_fds(const int except[], size_t n_except);
int close_all_fds_without_malloc(const int except[], size_t n_except);
+int pack_fds(int fds[], size_t n);
+
int same_fd(int a, int b);
void cmsg_close_all(struct msghdr *mh);
@@ -109,7 +112,10 @@ static inline int make_null_stdio(void) {
int fd_reopen(int fd, int flags);
int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
+
int fd_is_opath(int fd);
+int fd_verify_safe_flags(int fd);
+
int read_nr_open(void);
int fd_get_diskseq(int fd, uint64_t *ret);
diff --git a/src/libnm-systemd-shared/src/basic/format-util.h b/src/libnm-systemd-shared/src/basic/format-util.h
index 7db8b61d89..8a80eb3339 100644
--- a/src/libnm-systemd-shared/src/basic/format-util.h
+++ b/src/libnm-systemd-shared/src/basic/format-util.h
@@ -18,6 +18,14 @@ assert_cc(sizeof(uid_t) == sizeof(uint32_t));
assert_cc(sizeof(gid_t) == sizeof(uint32_t));
#define GID_FMT "%" PRIu32
+/* Note: the lifetime of the compound literal is the immediately surrounding block,
+ * see C11 §6.5.2.5, and
+ * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
+#define FORMAT_UID(uid) \
+ snprintf_ok((char[DECIMAL_STR_MAX(uid_t)]){}, DECIMAL_STR_MAX(uid_t), UID_FMT, uid)
+#define FORMAT_GID(gid) \
+ snprintf_ok((char[DECIMAL_STR_MAX(gid_t)]){}, DECIMAL_STR_MAX(gid_t), GID_FMT, gid)
+
#if SIZEOF_TIME_T == 8
# define PRI_TIME PRIi64
#elif SIZEOF_TIME_T == 4
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c
index 0210d3cdf9..3f414794ba 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.c
+++ b/src/libnm-systemd-shared/src/basic/fs-util.c
@@ -120,7 +120,11 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
int readlinkat_malloc(int fd, const char *p, char **ret) {
size_t l = PATH_MAX;
- assert(p);
+ assert(fd >= 0 || fd == AT_FDCWD);
+
+ if (fd < 0 && isempty(p))
+ return -EISDIR; /* In this case, the fd points to the current working directory, and is
+ * definitely not a symlink. Let's return earlier. */
for (;;) {
_cleanup_free_ char *c = NULL;
@@ -130,7 +134,7 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
if (!c)
return -ENOMEM;
- n = readlinkat(fd, p, c, l);
+ n = readlinkat(fd, strempty(p), c, l);
if (n < 0)
return -errno;
@@ -1060,7 +1064,7 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
path = fname;
}
- fd = xopenat(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, /* xopen_flags = */ 0, mode);
+ fd = xopenat_full(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, /* xopen_flags = */ 0, mode);
if (IN_SET(fd, -ELOOP, -ENOTDIR))
return -EEXIST;
if (fd < 0)
@@ -1116,7 +1120,7 @@ int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, b
}
}
-int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
+int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
_cleanup_close_ int fd = -EBADF;
bool made = false;
int r;
@@ -1198,7 +1202,7 @@ int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags
}
#if 0 /* NM_IGNORED */
-int xopenat_lock(
+int xopenat_lock_full(
int dir_fd,
const char *path,
int open_flags,
@@ -1221,7 +1225,7 @@ int xopenat_lock(
for (;;) {
struct stat st;
- fd = xopenat(dir_fd, path, open_flags, xopen_flags, mode);
+ fd = xopenat_full(dir_fd, path, open_flags, xopen_flags, mode);
if (fd < 0)
return fd;
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.h b/src/libnm-systemd-shared/src/basic/fs-util.h
index 1023ab73ca..6a1e2e76d1 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.h
+++ b/src/libnm-systemd-shared/src/basic/fs-util.h
@@ -137,6 +137,12 @@ typedef enum XOpenFlags {
XO_SUBVOLUME = 1 << 1,
} XOpenFlags;
-int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
+int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
+static inline int xopenat(int dir_fd, const char *path, int open_flags) {
+ return xopenat_full(dir_fd, path, open_flags, 0, 0);
+}
-int xopenat_lock(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation);
+int xopenat_lock_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation);
+static inline int xopenat_lock(int dir_fd, const char *path, int open_flags, LockType locktype, int operation) {
+ return xopenat_lock_full(dir_fd, path, open_flags, 0, 0, locktype, operation);
+}
diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.c b/src/libnm-systemd-shared/src/basic/glyph-util.c
index 1de60e105b..58d64a0303 100644
--- a/src/libnm-systemd-shared/src/basic/glyph-util.c
+++ b/src/libnm-systemd-shared/src/basic/glyph-util.c
@@ -43,6 +43,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_TREE_SPACE] = " ",
[SPECIAL_GLYPH_TREE_TOP] = ",-",
[SPECIAL_GLYPH_VERTICAL_DOTTED] = ":",
+ [SPECIAL_GLYPH_HORIZONTAL_DOTTED] = "-",
+ [SPECIAL_GLYPH_HORIZONTAL_FAT] = "=",
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">",
[SPECIAL_GLYPH_BLACK_CIRCLE] = "*",
[SPECIAL_GLYPH_WHITE_CIRCLE] = "*",
@@ -76,6 +78,10 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_SPARKLES] = "*",
[SPECIAL_GLYPH_LOW_BATTERY] = "!",
[SPECIAL_GLYPH_WARNING_SIGN] = "!",
+ [SPECIAL_GLYPH_RED_CIRCLE] = "o",
+ [SPECIAL_GLYPH_YELLOW_CIRCLE] = "o",
+ [SPECIAL_GLYPH_BLUE_CIRCLE] = "o",
+ [SPECIAL_GLYPH_GREEN_CIRCLE] = "o",
},
/* UTF-8 */
@@ -89,6 +95,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
/* Single glyphs in both cases */
[SPECIAL_GLYPH_VERTICAL_DOTTED] = u8"┆",
+ [SPECIAL_GLYPH_HORIZONTAL_DOTTED] = u8"┄",
+ [SPECIAL_GLYPH_HORIZONTAL_FAT] = u8"━",
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = u8"‣",
[SPECIAL_GLYPH_BLACK_CIRCLE] = u8"●",
[SPECIAL_GLYPH_WHITE_CIRCLE] = u8"○",
@@ -138,6 +146,11 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_WARNING_SIGN] = u8"⚠️",
[SPECIAL_GLYPH_COMPUTER_DISK] = u8"💽",
[SPECIAL_GLYPH_WORLD] = u8"🌍",
+
+ [SPECIAL_GLYPH_RED_CIRCLE] = u8"🔴",
+ [SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡",
+ [SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵",
+ [SPECIAL_GLYPH_GREEN_CIRCLE] = u8"🟢",
},
};
diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.h b/src/libnm-systemd-shared/src/basic/glyph-util.h
index a7709976e1..db8dbbff26 100644
--- a/src/libnm-systemd-shared/src/basic/glyph-util.h
+++ b/src/libnm-systemd-shared/src/basic/glyph-util.h
@@ -13,6 +13,8 @@ typedef enum SpecialGlyph {
SPECIAL_GLYPH_TREE_SPACE,
SPECIAL_GLYPH_TREE_TOP,
SPECIAL_GLYPH_VERTICAL_DOTTED,
+ SPECIAL_GLYPH_HORIZONTAL_DOTTED,
+ SPECIAL_GLYPH_HORIZONTAL_FAT,
SPECIAL_GLYPH_TRIANGULAR_BULLET,
SPECIAL_GLYPH_BLACK_CIRCLE,
SPECIAL_GLYPH_WHITE_CIRCLE,
@@ -49,6 +51,10 @@ typedef enum SpecialGlyph {
SPECIAL_GLYPH_WARNING_SIGN,
SPECIAL_GLYPH_COMPUTER_DISK,
SPECIAL_GLYPH_WORLD,
+ SPECIAL_GLYPH_RED_CIRCLE,
+ SPECIAL_GLYPH_YELLOW_CIRCLE,
+ SPECIAL_GLYPH_BLUE_CIRCLE,
+ SPECIAL_GLYPH_GREEN_CIRCLE,
_SPECIAL_GLYPH_MAX,
_SPECIAL_GLYPH_INVALID = -EINVAL,
} SpecialGlyph;
diff --git a/src/libnm-systemd-shared/src/basic/hashmap.c b/src/libnm-systemd-shared/src/basic/hashmap.c
index 28d2efa0e2..9686af0d93 100644
--- a/src/libnm-systemd-shared/src/basic/hashmap.c
+++ b/src/libnm-systemd-shared/src/basic/hashmap.c
@@ -2126,24 +2126,27 @@ static int hashmap_entry_compare(
return compare((*a)->key, (*b)->key);
}
-int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
- _cleanup_free_ struct hashmap_base_entry **entries = NULL;
+static int _hashmap_dump_entries_sorted(
+ HashmapBase *h,
+ void ***ret,
+ size_t *ret_n) {
+ _cleanup_free_ void **entries = NULL;
Iterator iter;
unsigned idx;
size_t n = 0;
assert(ret);
+ assert(ret_n);
if (_hashmap_size(h) == 0) {
*ret = NULL;
- if (ret_n)
- *ret_n = 0;
+ *ret_n = 0;
return 0;
}
/* We append one more element than needed so that the resulting array can be used as a strv. We
* don't count this entry in the returned size. */
- entries = new(struct hashmap_base_entry*, _hashmap_size(h) + 1);
+ entries = new(void*, _hashmap_size(h) + 1);
if (!entries)
return -ENOMEM;
@@ -2153,13 +2156,47 @@ int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
assert(n == _hashmap_size(h));
entries[n] = NULL;
- typesafe_qsort_r(entries, n, hashmap_entry_compare, h->hash_ops->compare);
+ typesafe_qsort_r((struct hashmap_base_entry**) entries, n,
+ hashmap_entry_compare, h->hash_ops->compare);
+
+ *ret = TAKE_PTR(entries);
+ *ret_n = n;
+ return 0;
+}
+
+int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
+ _cleanup_free_ void **entries = NULL;
+ size_t n;
+ int r;
+
+ r = _hashmap_dump_entries_sorted(h, &entries, &n);
+ if (r < 0)
+ return r;
+
+ /* Reuse the array. */
+ FOREACH_ARRAY(e, entries, n)
+ *e = (void*) (*(struct hashmap_base_entry**) e)->key;
+
+ *ret = TAKE_PTR(entries);
+ if (ret_n)
+ *ret_n = n;
+ return 0;
+}
+
+int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
+ _cleanup_free_ void **entries = NULL;
+ size_t n;
+ int r;
+
+ r = _hashmap_dump_entries_sorted(h, &entries, &n);
+ if (r < 0)
+ return r;
/* Reuse the array. */
FOREACH_ARRAY(e, entries, n)
- *e = entry_value(h, *e);
+ *e = entry_value(h, *(struct hashmap_base_entry**) e);
- *ret = (void**) TAKE_PTR(entries);
+ *ret = TAKE_PTR(entries);
if (ret_n)
*ret_n = n;
return 0;
diff --git a/src/libnm-systemd-shared/src/basic/hashmap.h b/src/libnm-systemd-shared/src/basic/hashmap.h
index 233f1d7a1e..49d9d118cc 100644
--- a/src/libnm-systemd-shared/src/basic/hashmap.h
+++ b/src/libnm-systemd-shared/src/basic/hashmap.h
@@ -39,8 +39,8 @@ typedef struct IteratedCache IteratedCache; /* Caches the iterated order of on
* by hashmap users, so the definition has to be here. Do not use its fields
* directly. */
typedef struct {
- unsigned idx; /* index of an entry to be iterated next */
const void *next_key; /* expected value of that entry's key pointer */
+ unsigned idx; /* index of an entry to be iterated next */
#if ENABLE_DEBUG_HASHMAP
unsigned put_count; /* hashmap's put_count recorded at start of iteration */
unsigned rem_count; /* hashmap's rem_count in previous iteration */
@@ -409,6 +409,14 @@ static inline int set_dump_sorted(Set *h, void ***ret, size_t *ret_n) {
return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
}
+int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n);
+static inline int hashmap_dump_keys_sorted(Hashmap *h, void ***ret, size_t *ret_n) {
+ return _hashmap_dump_keys_sorted(HASHMAP_BASE(h), ret, ret_n);
+}
+static inline int ordered_hashmap_dump_keys_sorted(OrderedHashmap *h, void ***ret, size_t *ret_n) {
+ return _hashmap_dump_keys_sorted(HASHMAP_BASE(h), ret, ret_n);
+}
+
/*
* Hashmaps are iterated in unpredictable order.
* OrderedHashmaps are an exception to this. They are iterated in the order
diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.c b/src/libnm-systemd-shared/src/basic/in-addr-util.c
index 0c3923b0ef..310e057a25 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.c
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c
@@ -93,14 +93,26 @@ bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) {
be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001);
}
+bool in4_addr_is_multicast(const struct in_addr *a) {
+ assert(a);
+
+ return IN_MULTICAST(be32toh(a->s_addr));
+}
+
+bool in6_addr_is_multicast(const struct in6_addr *a) {
+ assert(a);
+
+ return IN6_IS_ADDR_MULTICAST(a);
+}
+
int in_addr_is_multicast(int family, const union in_addr_union *u) {
assert(u);
if (family == AF_INET)
- return IN_MULTICAST(be32toh(u->in.s_addr));
+ return in4_addr_is_multicast(&u->in);
if (family == AF_INET6)
- return IN6_IS_ADDR_MULTICAST(&u->in6);
+ return in6_addr_is_multicast(&u->in6);
return -EAFNOSUPPORT;
}
diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.h b/src/libnm-systemd-shared/src/basic/in-addr-util.h
index 9fae3cae45..5c820c6ec6 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.h
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h
@@ -40,6 +40,8 @@ static inline bool in_addr_data_is_set(const struct in_addr_data *a) {
return in_addr_data_is_null(a);
}
+bool in4_addr_is_multicast(const struct in_addr *a);
+bool in6_addr_is_multicast(const struct in6_addr *a);
int in_addr_is_multicast(int family, const union in_addr_union *u);
bool in4_addr_is_link_local(const struct in_addr *a);
diff --git a/src/libnm-systemd-shared/src/basic/locale-util.c b/src/libnm-systemd-shared/src/basic/locale-util.c
index 78564a74a0..95648775ec 100644
--- a/src/libnm-systemd-shared/src/basic/locale-util.c
+++ b/src/libnm-systemd-shared/src/basic/locale-util.c
@@ -263,7 +263,10 @@ bool locale_is_valid(const char *name) {
if (!filename_is_valid(name))
return false;
- if (!string_is_safe(name))
+ /* Locales look like: ll_CC.ENC@variant, where ll and CC are alphabetic, ENC is alphanumeric with
+ * dashes, and variant seems to be alphabetic.
+ * See: https://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html */
+ if (!in_charset(name, ALPHANUMERICAL "_.-@"))
return false;
return true;
@@ -296,7 +299,7 @@ bool is_locale_utf8(void) {
if (cached_answer >= 0)
goto out;
- r = getenv_bool_secure("SYSTEMD_UTF8");
+ r = secure_getenv_bool("SYSTEMD_UTF8");
if (r >= 0) {
cached_answer = r;
goto out;
diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h
index cc59b0775c..1b5bc655f8 100644
--- a/src/libnm-systemd-shared/src/basic/log.h
+++ b/src/libnm-systemd-shared/src/basic/log.h
@@ -524,7 +524,7 @@ typedef struct LogRateLimit {
RateLimit ratelimit;
} LogRateLimit;
-#define log_ratelimit_internal(_level, _error, _ratelimit, _format, _file, _line, _func, ...) \
+#define log_ratelimit_internal(_level, _error, _ratelimit, _file, _line, _func, _format, ...) \
({ \
int _log_ratelimit_error = (_error); \
int _log_ratelimit_level = (_level); \
@@ -548,7 +548,7 @@ typedef struct LogRateLimit {
({ \
int _level = (level), _e = (error); \
_e = (log_get_max_level() >= LOG_PRI(_level)) \
- ? log_ratelimit_internal(_level, _e, _ratelimit, format, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__) \
+ ? log_ratelimit_internal(_level, _e, _ratelimit, PROJECT_FILE, __LINE__, __func__, format, ##__VA_ARGS__) \
: -ERRNO_VALUE(_e); \
_e < 0 ? _e : -ESTRPIPE; \
})
diff --git a/src/libnm-systemd-shared/src/basic/missing_fcntl.h b/src/libnm-systemd-shared/src/basic/missing_fcntl.h
index 24b2dc3119..3c85befda9 100644
--- a/src/libnm-systemd-shared/src/basic/missing_fcntl.h
+++ b/src/libnm-systemd-shared/src/basic/missing_fcntl.h
@@ -69,9 +69,26 @@
/* So O_LARGEFILE is generally implied by glibc, and defined to zero hence, because we only build in LFS
* mode. However, when invoking fcntl(F_GETFL) the flag is ORed into the result anyway — glibc does not mask
- * it away. Which sucks. Let's define the actual value here, so that we can mask it ourselves. */
+ * it away. Which sucks. Let's define the actual value here, so that we can mask it ourselves.
+ *
+ * The precise definition is arch specific, so we use the values defined in the kernel (note that some
+ * are hexa and others are octal; duplicated as-is from the kernel definitions):
+ * - alpha, arm, arm64, m68k, mips, parisc, powerpc, sparc: each has a specific value;
+ * - others: they use the "generic" value (defined in include/uapi/asm-generic/fcntl.h) */
#if O_LARGEFILE != 0
#define RAW_O_LARGEFILE O_LARGEFILE
#else
-#define RAW_O_LARGEFILE 0100000
+#if defined(__alpha__) || defined(__arm__) || defined(__aarch64__) || defined(__m68k__)
+#define RAW_O_LARGEFILE 0400000
+#elif defined(__mips__)
+#define RAW_O_LARGEFILE 0x2000
+#elif defined(__parisc__) || defined(__hppa__)
+#define RAW_O_LARGEFILE 000004000
+#elif defined(__powerpc__)
+#define RAW_O_LARGEFILE 0200000
+#elif defined(__sparc__)
+#define RAW_O_LARGEFILE 0x40000
+#else
+#define RAW_O_LARGEFILE 00100000
+#endif
#endif
diff --git a/src/libnm-systemd-shared/src/basic/missing_syscall.h b/src/libnm-systemd-shared/src/basic/missing_syscall.h
index a04633510d..149c5b4884 100644
--- a/src/libnm-systemd-shared/src/basic/missing_syscall.h
+++ b/src/libnm-systemd-shared/src/basic/missing_syscall.h
@@ -419,23 +419,14 @@ static inline int missing_execveat(int dirfd, const char *pathname,
/* ======================================================================= */
#if !HAVE_CLOSE_RANGE
-static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) {
+static inline int missing_close_range(unsigned first_fd, unsigned end_fd, unsigned flags) {
# ifdef __NR_close_range
/* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
- * userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to
- * wrap this syscall, but let's assume it's going to be similar to what they do for close(),
- * i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the
- * userspace wrapper. There's only one caveat for this: unlike for close() there's the special
- * UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse
- * any other negative values. */
- if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) {
- errno = -EBADF;
- return -1;
- }
-
+ * userspace exclusively uses signed integers for fds. glibc chose to expose it 1:1 however, hence we
+ * do so here too, even if we end up passing signed fds to it most of the time. */
return syscall(__NR_close_range,
- (unsigned) first_fd,
- end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */
+ first_fd,
+ end_fd,
flags);
# else
errno = ENOSYS;
diff --git a/src/libnm-systemd-shared/src/basic/namespace-util.h b/src/libnm-systemd-shared/src/basic/namespace-util.h
index d1d015612f..34cbec3f6e 100644
--- a/src/libnm-systemd-shared/src/basic/namespace-util.h
+++ b/src/libnm-systemd-shared/src/basic/namespace-util.h
@@ -53,3 +53,5 @@ static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
int userns_acquire(const char *uid_map, const char *gid_map);
int netns_acquire(void);
int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type);
+
+int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_range);
diff --git a/src/libnm-systemd-shared/src/basic/process-util.c b/src/libnm-systemd-shared/src/basic/process-util.c
index 0f1894b3af..5dd9003d5d 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.c
+++ b/src/libnm-systemd-shared/src/basic/process-util.c
@@ -514,7 +514,7 @@ static int get_process_link_contents(pid_t pid, const char *proc_file, char **re
p = procfs_file_alloca(pid, proc_file);
r = readlink_malloc(p, ret);
- return r == -ENOENT ? -ESRCH : r;
+ return (r == -ENOENT && proc_mounted() > 0) ? -ESRCH : r;
}
int get_process_exe(pid_t pid, char **ret) {
@@ -1309,7 +1309,7 @@ int opinionated_personality(unsigned long *ret) {
if (current < 0)
return current;
- if (((unsigned long) current & 0xffff) == PER_LINUX32)
+ if (((unsigned long) current & OPINIONATED_PERSONALITY_MASK) == PER_LINUX32)
*ret = PER_LINUX32;
else
*ret = PER_LINUX;
@@ -1476,7 +1476,7 @@ static int fork_flags_to_signal(ForkFlags flags) {
int safe_fork_full(
const char *name,
const int stdio_fds[3],
- const int except_fds[],
+ int except_fds[],
size_t n_except_fds,
ForkFlags flags,
pid_t *ret_pid) {
@@ -1705,6 +1705,19 @@ int safe_fork_full(
}
}
+ if (flags & FORK_PACK_FDS) {
+ /* FORK_CLOSE_ALL_FDS ensures that except_fds are the only FDs >= 3 that are
+ * open, this is including the log. This is required by pack_fds, which will
+ * get stuck in an infinite loop of any FDs other than except_fds are open. */
+ assert(FLAGS_SET(flags, FORK_CLOSE_ALL_FDS));
+
+ r = pack_fds(except_fds, n_except_fds);
+ if (r < 0) {
+ log_full_errno(prio, r, "Failed to pack file descriptors: %m");
+ _exit(EXIT_FAILURE);
+ }
+ }
+
if (flags & FORK_CLOEXEC_OFF) {
r = fd_cloexec_many(except_fds, n_except_fds, false);
if (r < 0) {
@@ -1744,7 +1757,7 @@ int safe_fork_full(
int pidref_safe_fork_full(
const char *name,
const int stdio_fds[3],
- const int except_fds[],
+ int except_fds[],
size_t n_except_fds,
ForkFlags flags,
PidRef *ret_pid) {
@@ -1768,7 +1781,7 @@ int pidref_safe_fork_full(
int namespace_fork(
const char *outer_name,
const char *inner_name,
- const int except_fds[],
+ int except_fds[],
size_t n_except_fds,
ForkFlags flags,
int pidns_fd,
diff --git a/src/libnm-systemd-shared/src/basic/process-util.h b/src/libnm-systemd-shared/src/basic/process-util.h
index a75c44cfad..49350065fb 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.h
+++ b/src/libnm-systemd-shared/src/basic/process-util.h
@@ -101,12 +101,17 @@ bool is_main_thread(void);
bool oom_score_adjust_is_valid(int oa);
#ifndef PERSONALITY_INVALID
-/* personality(7) documents that 0xffffffffUL is used for querying the
+/* personality(2) documents that 0xFFFFFFFFUL is used for querying the
* current personality, hence let's use that here as error
* indicator. */
-#define PERSONALITY_INVALID 0xffffffffLU
+#define PERSONALITY_INVALID 0xFFFFFFFFUL
#endif
+/* The personality() syscall returns a 32-bit value where the top three bytes are reserved for flags that
+ * emulate historical or architectural quirks, and only the least significant byte reflects the actual
+ * personality we're interested in. */
+#define OPINIONATED_PERSONALITY_MASK 0xFFUL
+
unsigned long personality_from_string(const char *p);
const char *personality_to_string(unsigned long);
@@ -182,12 +187,13 @@ typedef enum ForkFlags {
FORK_KEEP_NOTIFY_SOCKET = 1 << 17, /* Unless this specified, $NOTIFY_SOCKET will be unset. */
FORK_DETACH = 1 << 18, /* Double fork if needed to ensure PID1/subreaper is parent */
FORK_NEW_NETNS = 1 << 19, /* Run child in its own network namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
+ FORK_PACK_FDS = 1 << 20, /* Rearrange the passed FDs to be FD 3,4,5,etc. Updates the array in place (combine with FORK_CLOSE_ALL_FDS!) */
} ForkFlags;
int safe_fork_full(
const char *name,
const int stdio_fds[3],
- const int except_fds[],
+ int except_fds[],
size_t n_except_fds,
ForkFlags flags,
pid_t *ret_pid);
@@ -199,7 +205,7 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
int pidref_safe_fork_full(
const char *name,
const int stdio_fds[3],
- const int except_fds[],
+ int except_fds[],
size_t n_except_fds,
ForkFlags flags,
PidRef *ret_pid);
@@ -208,7 +214,18 @@ static inline int pidref_safe_fork(const char *name, ForkFlags flags, PidRef *re
return pidref_safe_fork_full(name, NULL, NULL, 0, flags, ret_pid);
}
-int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
+int namespace_fork(
+ const char *outer_name,
+ const char *inner_name,
+ int except_fds[],
+ size_t n_except_fds,
+ ForkFlags flags,
+ int pidns_fd,
+ int mntns_fd,
+ int netns_fd,
+ int userns_fd,
+ int root_fd,
+ pid_t *ret_pid);
int set_oom_score_adjust(int value);
int get_oom_score_adjust(int *ret);
diff --git a/src/libnm-systemd-shared/src/basic/signal-util.c b/src/libnm-systemd-shared/src/basic/signal-util.c
index 4354edca7e..95c86584e9 100644
--- a/src/libnm-systemd-shared/src/basic/signal-util.c
+++ b/src/libnm-systemd-shared/src/basic/signal-util.c
@@ -21,7 +21,7 @@ int reset_all_signal_handlers(void) {
.sa_handler = SIG_DFL,
.sa_flags = SA_RESTART,
};
- int r = 0;
+ int ret = 0, r;
for (int sig = 1; sig < _NSIG; sig++) {
@@ -29,14 +29,14 @@ int reset_all_signal_handlers(void) {
if (IN_SET(sig, SIGKILL, SIGSTOP))
continue;
- /* On Linux the first two RT signals are reserved by
- * glibc, and sigaction() will return EINVAL for them. */
- if (sigaction(sig, &sa, NULL) < 0)
- if (errno != EINVAL && r >= 0)
- r = -errno;
+ /* On Linux the first two RT signals are reserved by glibc, and sigaction() will return
+ * EINVAL for them. */
+ r = RET_NERRNO(sigaction(sig, &sa, NULL));
+ if (r != -EINVAL)
+ RET_GATHER(ret, r);
}
- return r;
+ return ret;
}
int reset_signal_mask(void) {
@@ -60,10 +60,7 @@ int sigaction_many_internal(const struct sigaction *sa, ...) {
if (sig == 0)
continue;
- if (sigaction(sig, sa, NULL) < 0) {
- if (r >= 0)
- r = -errno;
- }
+ RET_GATHER(r, RET_NERRNO(sigaction(sig, sa, NULL)));
}
va_end(ap);
@@ -90,7 +87,7 @@ static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
return r;
}
-int sigset_add_many(sigset_t *ss, ...) {
+int sigset_add_many_internal(sigset_t *ss, ...) {
va_list ap;
int r;
@@ -101,7 +98,7 @@ int sigset_add_many(sigset_t *ss, ...) {
return r;
}
-int sigprocmask_many(int how, sigset_t *old, ...) {
+int sigprocmask_many_internal(int how, sigset_t *old, ...) {
va_list ap;
sigset_t ss;
int r;
@@ -116,10 +113,7 @@ int sigprocmask_many(int how, sigset_t *old, ...) {
if (r < 0)
return r;
- if (sigprocmask(how, &ss, old) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(sigprocmask(how, &ss, old));
}
static const char *const static_signal_table[] = {
diff --git a/src/libnm-systemd-shared/src/basic/signal-util.h b/src/libnm-systemd-shared/src/basic/signal-util.h
index ad2ba841c6..8826fbeb7b 100644
--- a/src/libnm-systemd-shared/src/basic/signal-util.h
+++ b/src/libnm-systemd-shared/src/basic/signal-util.h
@@ -31,8 +31,11 @@ int sigaction_many_internal(const struct sigaction *sa, ...);
#define sigaction_many(sa, ...) \
sigaction_many_internal(sa, __VA_ARGS__, -1)
-int sigset_add_many(sigset_t *ss, ...);
-int sigprocmask_many(int how, sigset_t *old, ...);
+int sigset_add_many_internal(sigset_t *ss, ...);
+#define sigset_add_many(...) sigset_add_many_internal(__VA_ARGS__, -1)
+
+int sigprocmask_many_internal(int how, sigset_t *old, ...);
+#define sigprocmask_many(...) sigprocmask_many_internal(__VA_ARGS__, -1)
const char *signal_to_string(int i) _const_;
int signal_from_string(const char *s) _pure_;
@@ -46,7 +49,7 @@ static inline void block_signals_reset(sigset_t *ss) {
#define BLOCK_SIGNALS(...) \
_cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \
sigset_t _t; \
- assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__, -1) >= 0); \
+ assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__) >= 0); \
_t; \
})
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c
index b50544c9f3..4da3845be8 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.c
+++ b/src/libnm-systemd-shared/src/basic/stat-util.c
@@ -27,46 +27,130 @@
#include "stat-util.h"
#include "string-util.h"
-#if 0 /* NM_IGNORED */
-int is_symlink(const char *path) {
- struct stat info;
+static int verify_stat_at(
+ int fd,
+ const char *path,
+ bool follow,
+ int (*verify_func)(const struct stat *st),
+ bool verify) {
+ struct stat st;
+ int r;
- assert(path);
+ assert(fd >= 0 || fd == AT_FDCWD);
+ assert(!isempty(path) || !follow);
+ assert(verify_func);
- if (lstat(path, &info) < 0)
+ if (fstatat(fd, strempty(path), &st,
+ (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
return -errno;
- return !!S_ISLNK(info.st_mode);
+ r = verify_func(&st);
+ return verify ? r : r >= 0;
}
-#endif /* NM_IGNORED */
-int is_dir_full(int atfd, const char* path, bool follow) {
- struct stat st;
- int r;
+int stat_verify_regular(const struct stat *st) {
+ assert(st);
- assert(atfd >= 0 || atfd == AT_FDCWD);
- assert(atfd >= 0 || path);
+ /* Checks whether the specified stat() structure refers to a regular file. If not returns an
+ * appropriate error code. */
- if (path)
- r = fstatat(atfd, path, &st, follow ? 0 : AT_SYMLINK_NOFOLLOW);
- else
- r = fstat(atfd, &st);
- if (r < 0)
- return -errno;
+ if (S_ISDIR(st->st_mode))
+ return -EISDIR;
- return !!S_ISDIR(st.st_mode);
+ if (S_ISLNK(st->st_mode))
+ return -ELOOP;
+
+ if (!S_ISREG(st->st_mode))
+ return -EBADFD;
+
+ return 0;
}
-#if 0 /* NM_IGNORED */
-int is_device_node(const char *path) {
- struct stat info;
+int verify_regular_at(int fd, const char *path, bool follow) {
+ return verify_stat_at(fd, path, follow, stat_verify_regular, true);
+}
- assert(path);
+int fd_verify_regular(int fd) {
+ assert(fd >= 0);
+ return verify_regular_at(fd, NULL, false);
+}
- if (lstat(path, &info) < 0)
- return -errno;
+int stat_verify_directory(const struct stat *st) {
+ assert(st);
+
+ if (S_ISLNK(st->st_mode))
+ return -ELOOP;
+
+ if (!S_ISDIR(st->st_mode))
+ return -ENOTDIR;
+
+ return 0;
+}
+
+int fd_verify_directory(int fd) {
+ assert(fd >= 0);
+ return verify_stat_at(fd, NULL, false, stat_verify_directory, true);
+}
+
+int is_dir_at(int fd, const char *path, bool follow) {
+ return verify_stat_at(fd, path, follow, stat_verify_directory, false);
+}
+
+int is_dir(const char *path, bool follow) {
+ assert(!isempty(path));
+ return is_dir_at(AT_FDCWD, path, follow);
+}
+
+int stat_verify_symlink(const struct stat *st) {
+ assert(st);
+
+ if (S_ISDIR(st->st_mode))
+ return -EISDIR;
+
+ if (!S_ISLNK(st->st_mode))
+ return -ENOLINK;
+
+ return 0;
+}
+
+int is_symlink(const char *path) {
+ assert(!isempty(path));
+ return verify_stat_at(AT_FDCWD, path, false, stat_verify_symlink, false);
+}
+
+int stat_verify_linked(const struct stat *st) {
+ assert(st);
+
+ if (st->st_nlink <= 0)
+ return -EIDRM; /* recognizable error. */
+
+ return 0;
+}
+
+int fd_verify_linked(int fd) {
+ assert(fd >= 0);
+ return verify_stat_at(fd, NULL, false, stat_verify_linked, true);
+}
+
+int stat_verify_device_node(const struct stat *st) {
+ assert(st);
+
+ if (S_ISLNK(st->st_mode))
+ return -ELOOP;
+
+ if (S_ISDIR(st->st_mode))
+ return -EISDIR;
+
+ if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
+ return -ENOTTY;
+
+ return 0;
+}
- return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
+#if 0 /* NM_IGNORED */
+int is_device_node(const char *path) {
+ assert(!isempty(path));
+ return verify_stat_at(AT_FDCWD, path, false, stat_verify_device_node, false);
}
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
@@ -268,72 +352,6 @@ int path_is_network_fs(const char *path) {
}
#endif /* NM_IGNORED */
-int stat_verify_regular(const struct stat *st) {
- assert(st);
-
- /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
- * code. */
-
- if (S_ISDIR(st->st_mode))
- return -EISDIR;
-
- if (S_ISLNK(st->st_mode))
- return -ELOOP;
-
- if (!S_ISREG(st->st_mode))
- return -EBADFD;
-
- return 0;
-}
-
-int fd_verify_regular(int fd) {
- struct stat st;
-
- assert(fd >= 0);
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- return stat_verify_regular(&st);
-}
-
-#if 0 /* NM_IGNORED */
-int verify_regular_at(int dir_fd, const char *path, bool follow) {
- struct stat st;
-
- assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
- assert(path);
-
- if (fstatat(dir_fd, path, &st, (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
- return -errno;
-
- return stat_verify_regular(&st);
-}
-
-int stat_verify_directory(const struct stat *st) {
- assert(st);
-
- if (S_ISLNK(st->st_mode))
- return -ELOOP;
-
- if (!S_ISDIR(st->st_mode))
- return -ENOTDIR;
-
- return 0;
-}
-
-int fd_verify_directory(int fd) {
- struct stat st;
-
- assert(fd >= 0);
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- return stat_verify_directory(&st);
-}
-#endif /* NM_IGNORED */
-
int proc_mounted(void) {
int r;
@@ -480,7 +498,7 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(ret);
- fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0);
+ fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return fd;
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.h b/src/libnm-systemd-shared/src/basic/stat-util.h
index 65a14a44cb..7eb951a7a4 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.h
+++ b/src/libnm-systemd-shared/src/basic/stat-util.h
@@ -14,14 +14,22 @@
#include "siphash24.h"
#include "time-util.h"
+int stat_verify_regular(const struct stat *st);
+int verify_regular_at(int fd, const char *path, bool follow);
+int fd_verify_regular(int fd);
+
+int stat_verify_directory(const struct stat *st);
+int fd_verify_directory(int fd);
+int is_dir_at(int fd, const char *path, bool follow);
+int is_dir(const char *path, bool follow);
+
+int stat_verify_symlink(const struct stat *st);
int is_symlink(const char *path);
-int is_dir_full(int atfd, const char *fname, bool follow);
-static inline int is_dir(const char *path, bool follow) {
- return is_dir_full(AT_FDCWD, path, follow);
-}
-static inline int is_dir_fd(int fd) {
- return is_dir_full(fd, NULL, false);
-}
+
+int stat_verify_linked(const struct stat *st);
+int fd_verify_linked(int fd);
+
+int stat_verify_device_node(const struct stat *st);
int is_device_node(const char *path);
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup);
@@ -72,13 +80,6 @@ int path_is_network_fs(const char *path);
*/
#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
-int stat_verify_regular(const struct stat *st);
-int fd_verify_regular(int fd);
-int verify_regular_at(int dir_fd, const char *path, bool follow);
-
-int stat_verify_directory(const struct stat *st);
-int fd_verify_directory(int fd);
-
int proc_mounted(void);
bool stat_inode_same(const struct stat *a, const struct stat *b);
diff --git a/src/libnm-systemd-shared/src/basic/string-util.c b/src/libnm-systemd-shared/src/basic/string-util.c
index b48e25c7bf..59e659187c 100644
--- a/src/libnm-systemd-shared/src/basic/string-util.c
+++ b/src/libnm-systemd-shared/src/basic/string-util.c
@@ -625,6 +625,9 @@ char *cellescape(char *buf, size_t len, const char *s) {
char* strshorten(char *s, size_t l) {
assert(s);
+ if (l >= SIZE_MAX-1) /* Would not change anything */
+ return s;
+
if (strnlen(s, l+1) > l)
s[l] = 0;
diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c
index 7c6de915b2..ed02b4818f 100644
--- a/src/libnm-systemd-shared/src/basic/strv.c
+++ b/src/libnm-systemd-shared/src/basic/strv.c
@@ -363,7 +363,7 @@ int strv_split_colon_pairs(char ***t, const char *s) {
const char *p = tuple;
r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
- &first, &second, NULL);
+ &first, &second);
if (r < 0)
return r;
if (r == 0)
diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c
index 2147156e55..47f5bb5a61 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.c
+++ b/src/libnm-systemd-shared/src/basic/time-util.c
@@ -1434,7 +1434,7 @@ static int get_timezones_from_zone1970_tab(char ***ret) {
/* Line format is:
* 'country codes' 'coordinates' 'timezone' 'comments' */
- r = extract_many_words(&p, NULL, 0, &cc, &co, &tz, NULL);
+ r = extract_many_words(&p, NULL, 0, &cc, &co, &tz);
if (r < 0)
continue;
@@ -1479,7 +1479,7 @@ static int get_timezones_from_tzdata_zi(char ***ret) {
* Link line format is:
* 'Link' 'target' 'alias'
* See 'man zic' for more detail. */
- r = extract_many_words(&p, NULL, 0, &type, &f1, &f2, NULL);
+ r = extract_many_words(&p, NULL, 0, &type, &f1, &f2);
if (r < 0)
continue;
@@ -1579,7 +1579,7 @@ int verify_timezone(const char *name, int log_level) {
r = fd_verify_regular(fd);
if (r < 0)
- return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
+ return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
r = loop_read_exact(fd, buf, 4, false);
if (r < 0)
diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
index c810261308..00f2a2b9a1 100644
--- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
+++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
@@ -264,6 +264,30 @@
})
#endif /* NM_IGNORED */
+#define ADD_SAFE(ret, a, b) (!__builtin_add_overflow(a, b, ret))
+#define INC_SAFE(a, b) __INC_SAFE(UNIQ, a, b)
+#define __INC_SAFE(q, a, b) \
+ ({ \
+ const typeof(a) UNIQ_T(A, q) = (a); \
+ ADD_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
+ })
+
+#define SUB_SAFE(ret, a, b) (!__builtin_sub_overflow(a, b, ret))
+#define DEC_SAFE(a, b) __DEC_SAFE(UNIQ, a, b)
+#define __DEC_SAFE(q, a, b) \
+ ({ \
+ const typeof(a) UNIQ_T(A, q) = (a); \
+ SUB_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
+ })
+
+#define MUL_SAFE(ret, a, b) (!__builtin_mul_overflow(a, b, ret))
+#define MUL_ASSIGN_SAFE(a, b) __MUL_ASSIGN_SAFE(UNIQ, a, b)
+#define __MUL_ASSIGN_SAFE(q, a, b) \
+ ({ \
+ const typeof(a) UNIQ_T(A, q) = (a); \
+ MUL_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
+ })
+
#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
#define __LESS_BY(aq, a, bq, b) \
({ \
@@ -313,7 +337,7 @@
const typeof(y) UNIQ_T(A, q) = (y); \
const typeof(x) UNIQ_T(B, q) = DIV_ROUND_UP((x), UNIQ_T(A, q)); \
typeof(x) UNIQ_T(C, q); \
- __builtin_mul_overflow(UNIQ_T(B, q), UNIQ_T(A, q), &UNIQ_T(C, q)) ? (typeof(x)) -1 : UNIQ_T(C, q); \
+ MUL_SAFE(&UNIQ_T(C, q), UNIQ_T(B, q), UNIQ_T(A, q)) ? UNIQ_T(C, q) : (typeof(x)) -1; \
})
#define ROUND_UP(x, y) __ROUND_UP(UNIQ, (x), (y))