From a3460730f27ebba85710d7f085619dce78ff481c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 4 Oct 2022 12:33:50 +0200 Subject: [PATCH] systemd: update code from upstream (2022-10-04) This is a direct dump from systemd git. $ git clean -fdx && \ git cat-file -p HEAD | sed '1,/^======$/ d' | bash - && \ git add . ====== SYSTEMD_DIR=../systemd COMMIT=f77c0840d505825f14ff30921752cb26778bf53e ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files -z :/src/libnm-systemd-core/src/ \ :/src/libnm-systemd-shared/src/ \ :/src/libnm-std-aux/unaligned.h | \ xargs -0 rm -f nm_copy_sd_shared() { mkdir -p "./src/libnm-systemd-shared/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-shared/$1" } nm_copy_sd_core() { mkdir -p "./src/libnm-systemd-core/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-core/$1" } nm_copy_sd_stdaux() { mkdir -p "./src/libnm-std-aux/" cp "$SYSTEMD_DIR/$1" "./src/libnm-std-aux/${1##*/}" } nm_copy_sd_core "src/libsystemd-network/arp-util.c" nm_copy_sd_core "src/libsystemd-network/arp-util.h" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.c" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.h" nm_copy_sd_core "src/libsystemd-network/dhcp-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.c" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.h" nm_copy_sd_core "src/libsystemd-network/lldp-network.c" nm_copy_sd_core "src/libsystemd-network/lldp-network.h" nm_copy_sd_core "src/libsystemd-network/lldp-rx-internal.h" nm_copy_sd_core "src/libsystemd-network/network-common.c" nm_copy_sd_core "src/libsystemd-network/network-common.h" nm_copy_sd_core "src/libsystemd-network/network-internal.h" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c" nm_copy_sd_core "src/libsystemd-network/sd-lldp-rx.c" nm_copy_sd_core "src/libsystemd/sd-event/event-source.h" nm_copy_sd_core "src/libsystemd/sd-event/event-util.c" nm_copy_sd_core "src/libsystemd/sd-event/event-util.h" nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h" nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c" nm_copy_sd_core "src/systemd/_sd-common.h" nm_copy_sd_core "src/systemd/sd-dhcp6-client.h" nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h" nm_copy_sd_core "src/systemd/sd-dhcp6-option.h" nm_copy_sd_core "src/systemd/sd-event.h" nm_copy_sd_core "src/systemd/sd-id128.h" nm_copy_sd_core "src/systemd/sd-lldp-rx.h" nm_copy_sd_core "src/systemd/sd-lldp.h" nm_copy_sd_core "src/systemd/sd-ndisc.h" nm_copy_sd_shared "src/basic/alloc-util.c" nm_copy_sd_shared "src/basic/alloc-util.h" nm_copy_sd_shared "src/basic/async.h" nm_copy_sd_shared "src/basic/cgroup-util.h" nm_copy_sd_shared "src/basic/dns-def.h" nm_copy_sd_shared "src/basic/env-file.c" nm_copy_sd_shared "src/basic/env-file.h" nm_copy_sd_shared "src/basic/env-util.c" nm_copy_sd_shared "src/basic/env-util.h" nm_copy_sd_shared "src/basic/errno-util.h" nm_copy_sd_shared "src/basic/escape.c" nm_copy_sd_shared "src/basic/escape.h" nm_copy_sd_shared "src/basic/ether-addr-util.c" nm_copy_sd_shared "src/basic/ether-addr-util.h" nm_copy_sd_shared "src/basic/extract-word.c" nm_copy_sd_shared "src/basic/extract-word.h" nm_copy_sd_shared "src/basic/fd-util.c" nm_copy_sd_shared "src/basic/fd-util.h" nm_copy_sd_shared "src/basic/fileio.c" nm_copy_sd_shared "src/basic/fileio.h" nm_copy_sd_shared "src/basic/format-util.c" nm_copy_sd_shared "src/basic/format-util.h" nm_copy_sd_shared "src/basic/fs-util.c" nm_copy_sd_shared "src/basic/fs-util.h" nm_copy_sd_shared "src/basic/glyph-util.c" nm_copy_sd_shared "src/basic/glyph-util.h" nm_copy_sd_shared "src/basic/hash-funcs.c" nm_copy_sd_shared "src/basic/hash-funcs.h" nm_copy_sd_shared "src/basic/hashmap.c" nm_copy_sd_shared "src/basic/hashmap.h" nm_copy_sd_shared "src/basic/hexdecoct.c" nm_copy_sd_shared "src/basic/hexdecoct.h" nm_copy_sd_shared "src/basic/hostname-util.c" nm_copy_sd_shared "src/basic/hostname-util.h" nm_copy_sd_shared "src/basic/in-addr-util.c" nm_copy_sd_shared "src/basic/in-addr-util.h" nm_copy_sd_shared "src/basic/inotify-util.c" nm_copy_sd_shared "src/basic/inotify-util.h" nm_copy_sd_shared "src/basic/io-util.c" nm_copy_sd_shared "src/basic/io-util.h" nm_copy_sd_shared "src/basic/list.h" nm_copy_sd_shared "src/basic/locale-util.c" nm_copy_sd_shared "src/basic/locale-util.h" nm_copy_sd_shared "src/basic/log.h" nm_copy_sd_shared "src/basic/macro.h" nm_copy_sd_shared "src/basic/memory-util.c" nm_copy_sd_shared "src/basic/memory-util.h" nm_copy_sd_shared "src/basic/mempool.c" nm_copy_sd_shared "src/basic/mempool.h" nm_copy_sd_shared "src/basic/missing_fcntl.h" nm_copy_sd_shared "src/basic/missing_random.h" nm_copy_sd_shared "src/basic/missing_socket.h" nm_copy_sd_shared "src/basic/missing_stat.h" nm_copy_sd_shared "src/basic/missing_syscall.h" nm_copy_sd_shared "src/basic/missing_type.h" nm_copy_sd_shared "src/basic/ordered-set.c" nm_copy_sd_shared "src/basic/ordered-set.h" nm_copy_sd_shared "src/basic/parse-util.c" nm_copy_sd_shared "src/basic/parse-util.h" nm_copy_sd_shared "src/basic/path-util.c" nm_copy_sd_shared "src/basic/path-util.h" nm_copy_sd_shared "src/basic/prioq.c" nm_copy_sd_shared "src/basic/prioq.h" nm_copy_sd_shared "src/basic/process-util.c" nm_copy_sd_shared "src/basic/process-util.h" nm_copy_sd_shared "src/basic/random-util.c" nm_copy_sd_shared "src/basic/random-util.h" nm_copy_sd_shared "src/basic/ratelimit.c" nm_copy_sd_shared "src/basic/ratelimit.h" nm_copy_sd_shared "src/basic/set.h" nm_copy_sd_shared "src/basic/signal-util.c" nm_copy_sd_shared "src/basic/signal-util.h" nm_copy_sd_shared "src/basic/siphash24.h" nm_copy_sd_shared "src/basic/socket-util.c" nm_copy_sd_shared "src/basic/socket-util.h" nm_copy_sd_shared "src/basic/sort-util.h" nm_copy_sd_shared "src/basic/sparse-endian.h" nm_copy_sd_shared "src/basic/stat-util.c" nm_copy_sd_shared "src/basic/stat-util.h" nm_copy_sd_shared "src/basic/stdio-util.h" nm_copy_sd_shared "src/basic/string-table.c" nm_copy_sd_shared "src/basic/string-table.h" nm_copy_sd_shared "src/basic/string-util.c" nm_copy_sd_shared "src/basic/string-util.h" nm_copy_sd_shared "src/basic/strv.c" nm_copy_sd_shared "src/basic/strv.h" nm_copy_sd_shared "src/basic/strxcpyx.c" nm_copy_sd_shared "src/basic/strxcpyx.h" nm_copy_sd_shared "src/basic/time-util.c" nm_copy_sd_shared "src/basic/time-util.h" nm_copy_sd_shared "src/basic/tmpfile-util.c" nm_copy_sd_shared "src/basic/tmpfile-util.h" nm_copy_sd_shared "src/basic/umask-util.h" nm_copy_sd_shared "src/basic/user-util.h" nm_copy_sd_shared "src/basic/utf8.c" nm_copy_sd_shared "src/basic/utf8.h" nm_copy_sd_shared "src/basic/util.c" nm_copy_sd_shared "src/basic/util.h" nm_copy_sd_shared "src/fundamental/macro-fundamental.h" nm_copy_sd_shared "src/fundamental/sha256.c" nm_copy_sd_shared "src/fundamental/sha256.h" nm_copy_sd_shared "src/fundamental/string-util-fundamental.c" nm_copy_sd_shared "src/fundamental/string-util-fundamental.h" nm_copy_sd_shared "src/shared/dns-domain.c" nm_copy_sd_shared "src/shared/dns-domain.h" nm_copy_sd_shared "src/shared/log-link.h" nm_copy_sd_shared "src/shared/web-util.c" nm_copy_sd_shared "src/shared/web-util.h" nm_copy_sd_stdaux "src/basic/unaligned.h" --- .../src/libsystemd-network/dhcp6-protocol.c | 11 ++ .../src/libsystemd-network/dhcp6-protocol.h | 1 + .../src/libsystemd-network/sd-dhcp6-client.c | 35 ++++- .../src/libsystemd-network/sd-dhcp6-lease.c | 2 +- .../src/libsystemd-network/sd-lldp-rx.c | 3 +- .../src/libsystemd/sd-event/event-source.h | 1 + .../src/libsystemd/sd-event/sd-event.c | 134 ++++++++++++++-- src/libnm-systemd-core/src/systemd/sd-event.h | 3 + .../src/basic/cgroup-util.h | 1 + src/libnm-systemd-shared/src/basic/env-file.c | 4 +- src/libnm-systemd-shared/src/basic/env-util.c | 12 ++ src/libnm-systemd-shared/src/basic/env-util.h | 2 + src/libnm-systemd-shared/src/basic/fd-util.c | 2 +- src/libnm-systemd-shared/src/basic/fd-util.h | 2 +- src/libnm-systemd-shared/src/basic/fs-util.c | 79 ++++------ src/libnm-systemd-shared/src/basic/fs-util.h | 22 ++- .../src/basic/glyph-util.c | 2 + .../src/basic/glyph-util.h | 1 + src/libnm-systemd-shared/src/basic/hashmap.c | 7 +- .../src/basic/in-addr-util.c | 42 +++++ .../src/basic/in-addr-util.h | 2 + src/libnm-systemd-shared/src/basic/io-util.c | 6 +- src/libnm-systemd-shared/src/basic/log.h | 39 +++++ .../src/basic/parse-util.c | 68 ++------ .../src/basic/parse-util.h | 6 +- .../src/basic/path-util.c | 135 ++++++++++++---- .../src/basic/path-util.h | 7 +- .../src/basic/random-util.c | 15 +- .../src/basic/ratelimit.c | 7 + .../src/basic/ratelimit.h | 3 +- .../src/basic/stat-util.c | 26 ++++ .../src/basic/stat-util.h | 3 + .../src/basic/string-util.c | 13 ++ .../src/basic/string-util.h | 2 + src/libnm-systemd-shared/src/basic/strv.c | 27 +++- src/libnm-systemd-shared/src/basic/strv.h | 2 +- .../src/basic/time-util.c | 3 +- .../src/basic/time-util.h | 9 +- .../src/basic/tmpfile-util.c | 147 +++++++++--------- .../src/basic/user-util.h | 17 +- .../src/fundamental/macro-fundamental.h | 19 +-- .../src/fundamental/sha256.c | 14 +- .../src/fundamental/sha256.h | 6 +- 43 files changed, 647 insertions(+), 295 deletions(-) diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c index c399a7ac50..f965ea40fe 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c @@ -82,3 +82,14 @@ static const char * const dhcp6_message_status_table[_DHCP6_STATUS_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, DHCP6Status); + +int dhcp6_message_status_to_errno(DHCP6Status s) { + switch (s) { + case DHCP6_STATUS_SUCCESS: + return 0; + case DHCP6_STATUS_NO_BINDING: + return -EADDRNOTAVAIL; + default: + return -EINVAL; + } +} diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h index f4e47857e3..18217691b7 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h @@ -154,3 +154,4 @@ const char *dhcp6_message_type_to_string(DHCP6MessageType s) _const_; DHCP6MessageType dhcp6_message_type_from_string(const char *s) _pure_; const char *dhcp6_message_status_to_string(DHCP6Status s) _const_; DHCP6Status dhcp6_message_status_from_string(const char *s) _pure_; +int dhcp6_message_status_to_errno(DHCP6Status s); diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c index 273dd35e04..606e48ce6f 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c @@ -207,7 +207,7 @@ static int dhcp6_client_set_duid_internal( if (r < 0) return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m"); - log_dhcp6_client(client, "Using DUID of type %u of incorrect length, proceeding.", duid_type); + log_dhcp6_client(client, "Using DUID of type %i of incorrect length, proceeding.", duid_type); } client->duid.type = htobe16(duid_type); @@ -543,13 +543,9 @@ static void client_notify(sd_dhcp6_client *client, int event) { client->callback(client, event, client->userdata); } -static void client_stop(sd_dhcp6_client *client, int error) { - DHCP6_CLIENT_DONT_DESTROY(client); - +static void client_cleanup(sd_dhcp6_client *client) { assert(client); - client_notify(client, error); - client->lease = sd_dhcp6_lease_unref(client->lease); /* Reset IRT here. Otherwise, we cannot restart the client in the information requesting mode, @@ -566,6 +562,16 @@ static void client_stop(sd_dhcp6_client *client, int error) { client_set_state(client, DHCP6_STATE_STOPPED); } +static void client_stop(sd_dhcp6_client *client, int error) { + DHCP6_CLIENT_DONT_DESTROY(client); + + assert(client); + + client_notify(client, error); + + client_cleanup(client); +} + static int client_append_common_options_in_managed_mode( sd_dhcp6_client *client, uint8_t **opt, @@ -684,6 +690,9 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **opt, size_t *opt req_opts = client->req_opts; } + if (n == 0) + return 0; + return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts); } @@ -1133,6 +1142,20 @@ static int client_process_reply( return log_invalid_message_type(client, message); r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease); + if (r == -EADDRNOTAVAIL) { + + /* If NoBinding status code is received, we cannot request the address anymore. + * Let's restart transaction from the beginning. */ + + if (client->state == DHCP6_STATE_REQUEST) + /* The lease is not acquired yet, hence it is not necessary to notify the restart. */ + client_cleanup(client); + else + /* We need to notify the previous lease was expired. */ + client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE); + + return client_start_transaction(client, DHCP6_STATE_SOLICITATION); + } if (r < 0) return log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m"); diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c index f588514cb6..57c23965ed 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c @@ -512,7 +512,7 @@ static int dhcp6_lease_parse_message( return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m"); if (r > 0) - return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), + return log_dhcp6_client_errno(client, dhcp6_message_status_to_errno(r), "Received %s message with non-zero status: %s%s%s", dhcp6_message_type_to_string(message->type), strempty(msg), isempty(msg) ? "" : ": ", diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c b/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c index d4762bf097..0479cff5f5 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c +++ b/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c @@ -192,11 +192,10 @@ static int lldp_rx_handle_datagram(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) { static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) { _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; ssize_t space, length; - sd_lldp_rx *lldp_rx = userdata; + sd_lldp_rx *lldp_rx = ASSERT_PTR(userdata); struct timespec ts; assert(fd >= 0); - assert(lldp_rx); space = next_datagram_size_fd(fd); if (space < 0) { diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h b/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h index 74cbc26962..6092652d0f 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h @@ -99,6 +99,7 @@ struct sd_event_source { sd_event_signal_handler_t callback; struct signalfd_siginfo siginfo; int sig; + bool unblock; } signal; struct { sd_event_child_handler_t callback; 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 027a8dffa1..778070a5fb 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 @@ -153,6 +153,8 @@ struct sd_event { LIST_HEAD(sd_event_source, sources); + sd_event_source *sigint_event_source, *sigterm_event_source; + usec_t last_run_usec, last_log_usec; unsigned delays[sizeof(usec_t) * 8]; }; @@ -323,6 +325,9 @@ static sd_event *event_free(sd_event *e) { assert(e); + e->sigterm_event_source = sd_event_source_unref(e->sigterm_event_source); + e->sigint_event_source = sd_event_source_unref(e->sigint_event_source); + while ((s = e->sources)) { assert(s->floating); source_disconnect(s); @@ -813,6 +818,7 @@ static void event_source_time_prioq_remove( static void source_disconnect(sd_event_source *s) { sd_event *event; + int r; assert(s); @@ -853,6 +859,20 @@ static void source_disconnect(sd_event_source *s) { s->event->signal_sources[s->signal.sig] = NULL; event_gc_signal_data(s->event, &s->priority, s->signal.sig); + + if (s->signal.unblock) { + sigset_t new_ss; + + if (sigemptyset(&new_ss) < 0) + log_debug_errno(errno, "Failed to reset signal set, ignoring: %m"); + else if (sigaddset(&new_ss, s->signal.sig) < 0) + log_debug_errno(errno, "Failed to add signal %i to signal mask, ignoring: %m", s->signal.sig); + else { + r = pthread_sigmask(SIG_UNBLOCK, &new_ss, NULL); + if (r != 0) + log_debug_errno(r, "Failed to unblock signal %i, ignoring: %m", s->signal.sig); + } + } } break; @@ -1328,23 +1348,38 @@ _public_ int sd_event_add_signal( _cleanup_(source_freep) sd_event_source *s = NULL; struct signal_data *d; + sigset_t new_ss; + bool block_it; int r; assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(SIGNAL_VALID(sig), -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + /* Let's make sure our special flag stays outside of the valid signal range */ + assert_cc(_NSIG < SD_EVENT_SIGNAL_PROCMASK); + + if (sig & SD_EVENT_SIGNAL_PROCMASK) { + sig &= ~SD_EVENT_SIGNAL_PROCMASK; + assert_return(SIGNAL_VALID(sig), -EINVAL); + + block_it = true; + } else { + assert_return(SIGNAL_VALID(sig), -EINVAL); + + r = signal_is_blocked(sig); + if (r < 0) + return r; + if (r == 0) + return -EBUSY; + + block_it = false; + } + if (!callback) callback = signal_exit_callback; - r = signal_is_blocked(sig); - if (r < 0) - return r; - if (r == 0) - return -EBUSY; - if (!e->signal_sources) { e->signal_sources = new0(sd_event_source*, _NSIG); if (!e->signal_sources) @@ -1363,9 +1398,34 @@ _public_ int sd_event_add_signal( e->signal_sources[sig] = s; + if (block_it) { + sigset_t old_ss; + + if (sigemptyset(&new_ss) < 0) + return -errno; + + if (sigaddset(&new_ss, sig) < 0) + return -errno; + + r = pthread_sigmask(SIG_BLOCK, &new_ss, &old_ss); + if (r != 0) + return -r; + + r = sigismember(&old_ss, sig); + if (r < 0) + return -errno; + + s->signal.unblock = !r; + } else + s->signal.unblock = false; + r = event_make_signal_data(e, sig, &d); - if (r < 0) + if (r < 0) { + if (s->signal.unblock) + (void) pthread_sigmask(SIG_UNBLOCK, &new_ss, NULL); + return r; + } /* Use the signal name as description for the event source by default */ (void) sd_event_source_set_description(s, signal_to_string(sig)); @@ -3823,7 +3883,7 @@ static void event_close_inode_data_fds(sd_event *e) { /* Close the fds pointing to the inodes to watch now. We need to close them as they might otherwise pin * filesystems. But we can't close them right-away as we need them as long as the user still wants to make - * adjustments to the even source, such as changing the priority (which requires us to remove and re-add a watch + * adjustments to the event source, such as changing the priority (which requires us to remove and re-add a watch * for the inode). Hence, let's close them when entering the first iteration after they were added, as a * compromise. */ @@ -4531,8 +4591,8 @@ _public_ int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, s _public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) { assert_return(s, -EINVAL); - /* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence - * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */ + /* Querying whether an event source has ratelimiting configured is not a loggable offense, hence + * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error. */ if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) return -EDOM; @@ -4558,3 +4618,55 @@ _public_ int sd_event_source_is_ratelimited(sd_event_source *s) { return s->ratelimited; } + +_public_ int sd_event_set_signal_exit(sd_event *e, int b) { + bool change = false; + int r; + + assert_return(e, -EINVAL); + + if (b) { + /* We want to maintain pointers to these event sources, so that we can destroy them when told + * so. But we also don't want them to pin the event loop itself. Hence we mark them as + * floating after creation (and undo this before deleting them again). */ + + if (!e->sigint_event_source) { + r = sd_event_add_signal(e, &e->sigint_event_source, SIGINT | SD_EVENT_SIGNAL_PROCMASK, NULL, NULL); + if (r < 0) + return r; + + assert(sd_event_source_set_floating(e->sigint_event_source, true) >= 0); + change = true; + } + + if (!e->sigterm_event_source) { + r = sd_event_add_signal(e, &e->sigterm_event_source, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, NULL, NULL); + if (r < 0) { + if (change) { + assert(sd_event_source_set_floating(e->sigint_event_source, false) >= 0); + e->sigint_event_source = sd_event_source_unref(e->sigint_event_source); + } + + return r; + } + + assert(sd_event_source_set_floating(e->sigterm_event_source, true) >= 0); + change = true; + } + + } else { + if (e->sigint_event_source) { + assert(sd_event_source_set_floating(e->sigint_event_source, false) >= 0); + e->sigint_event_source = sd_event_source_unref(e->sigint_event_source); + change = true; + } + + if (e->sigterm_event_source) { + assert(sd_event_source_set_floating(e->sigterm_event_source, false) >= 0); + e->sigterm_event_source = sd_event_source_unref(e->sigterm_event_source); + change = true; + } + } + + return change; +} diff --git a/src/libnm-systemd-core/src/systemd/sd-event.h b/src/libnm-systemd-core/src/systemd/sd-event.h index e782339c4a..cae4c8672a 100644 --- a/src/libnm-systemd-core/src/systemd/sd-event.h +++ b/src/libnm-systemd-core/src/systemd/sd-event.h @@ -68,6 +68,8 @@ enum { SD_EVENT_PRIORITY_IDLE = 100 }; +#define SD_EVENT_SIGNAL_PROCMASK (1 << 30) + typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); @@ -114,6 +116,7 @@ int sd_event_get_exit_code(sd_event *e, int *code); int sd_event_set_watchdog(sd_event *e, int b); int sd_event_get_watchdog(sd_event *e); int sd_event_get_iteration(sd_event *e, uint64_t *ret); +int sd_event_set_signal_exit(sd_event *e, int b); sd_event_source* sd_event_source_ref(sd_event_source *s); sd_event_source* sd_event_source_unref(sd_event_source *s); diff --git a/src/libnm-systemd-shared/src/basic/cgroup-util.h b/src/libnm-systemd-shared/src/basic/cgroup-util.h index 4c413a8d17..df6d5b7bbb 100644 --- a/src/libnm-systemd-shared/src/basic/cgroup-util.h +++ b/src/libnm-systemd-shared/src/basic/cgroup-util.h @@ -86,6 +86,7 @@ bool cpu_accounting_is_cheap(void); /* Special values for all weight knobs on unified hierarchy */ #define CGROUP_WEIGHT_INVALID UINT64_MAX +#define CGROUP_WEIGHT_IDLE UINT64_C(0) #define CGROUP_WEIGHT_MIN UINT64_C(1) #define CGROUP_WEIGHT_MAX UINT64_C(10000) #define CGROUP_WEIGHT_DEFAULT UINT64_C(100) diff --git a/src/libnm-systemd-shared/src/basic/env-file.c b/src/libnm-systemd-shared/src/basic/env-file.c index 2ab5c7bc0d..e363bc80bf 100644 --- a/src/libnm-systemd-shared/src/basic/env-file.c +++ b/src/libnm-systemd-shared/src/basic/env-file.c @@ -443,11 +443,9 @@ static int merge_env_file_push( const char *key, char *value, void *userdata) { - char ***env = userdata; + char ***env = ASSERT_PTR(userdata); char *expanded_value; - assert(env); - if (!value) { log_error("%s:%u: invalid syntax (around \"%s\"), ignoring.", strna(filename), line, key); return 0; diff --git a/src/libnm-systemd-shared/src/basic/env-util.c b/src/libnm-systemd-shared/src/basic/env-util.c index 62914f1587..55ac11a512 100644 --- a/src/libnm-systemd-shared/src/basic/env-util.c +++ b/src/libnm-systemd-shared/src/basic/env-util.c @@ -776,6 +776,18 @@ int getenv_bool_secure(const char *p) { return parse_boolean(e); } +int getenv_uint64_secure(const char *p, uint64_t *ret) { + const char *e; + + assert(p); + + e = secure_getenv(p); + if (!e) + return -ENXIO; + + return safe_atou64(e, ret); +} + int set_unset_env(const char *name, const char *value, bool overwrite) { assert(name); diff --git a/src/libnm-systemd-shared/src/basic/env-util.h b/src/libnm-systemd-shared/src/basic/env-util.h index 2bf0603f21..b927ac7a48 100644 --- a/src/libnm-systemd-shared/src/basic/env-util.h +++ b/src/libnm-systemd-shared/src/basic/env-util.h @@ -57,6 +57,8 @@ 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 getenv_uint64_secure(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); diff --git a/src/libnm-systemd-shared/src/basic/fd-util.c b/src/libnm-systemd-shared/src/basic/fd-util.c index 00591d6c2d..6c85a34896 100644 --- a/src/libnm-systemd-shared/src/basic/fd-util.c +++ b/src/libnm-systemd-shared/src/basic/fd-util.c @@ -654,7 +654,7 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_ goto finish; } - CLOSE_AND_REPLACE(null_fd, copy); + close_and_replace(null_fd, copy); } } diff --git a/src/libnm-systemd-shared/src/basic/fd-util.h b/src/libnm-systemd-shared/src/basic/fd-util.h index 808cac4d5d..8543d0d5ea 100644 --- a/src/libnm-systemd-shared/src/basic/fd-util.h +++ b/src/libnm-systemd-shared/src/basic/fd-util.h @@ -98,7 +98,7 @@ static inline int make_null_stdio(void) { }) /* Like free_and_replace(), but for file descriptors */ -#define CLOSE_AND_REPLACE(a, b) \ +#define close_and_replace(a, b) \ ({ \ int *_fdp_ = &(a); \ safe_close(*_fdp_); \ diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c index cc25222c32..6b757bd570 100644 --- a/src/libnm-systemd-shared/src/basic/fs-util.c +++ b/src/libnm-systemd-shared/src/basic/fs-util.c @@ -398,10 +398,6 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi return ret; } -int touch(const char *path) { - return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID); -} - int symlink_idempotent(const char *from, const char *to, bool make_relative) { _cleanup_free_ char *relpath = NULL; int r; @@ -410,13 +406,7 @@ int symlink_idempotent(const char *from, const char *to, bool make_relative) { assert(to); if (make_relative) { - _cleanup_free_ char *parent = NULL; - - r = path_extract_directory(to, &parent); - if (r < 0) - return r; - - r = path_make_relative(parent, from, &relpath); + r = path_make_relative_parent(to, from, &relpath); if (r < 0) return r; @@ -442,29 +432,38 @@ int symlink_idempotent(const char *from, const char *to, bool make_relative) { return 0; } -int symlink_atomic(const char *from, const char *to) { - _cleanup_free_ char *t = NULL; +int symlinkat_atomic_full(const char *from, int atfd, const char *to, bool make_relative) { + _cleanup_free_ char *relpath = NULL, *t = NULL; int r; assert(from); assert(to); + if (make_relative) { + r = path_make_relative_parent(to, from, &relpath); + if (r < 0) + return r; + + from = relpath; + } + r = tempfn_random(to, NULL, &t); if (r < 0) return r; - if (symlink(from, t) < 0) + if (symlinkat(from, atfd, t) < 0) return -errno; - if (rename(t, to) < 0) { - unlink_noerrno(t); - return -errno; + r = RET_NERRNO(renameat(atfd, t, atfd, to)); + if (r < 0) { + (void) unlinkat(atfd, t, 0); + return r; } return 0; } -int mknod_atomic(const char *path, mode_t mode, dev_t dev) { +int mknodat_atomic(int atfd, const char *path, mode_t mode, dev_t dev) { _cleanup_free_ char *t = NULL; int r; @@ -474,58 +473,36 @@ int mknod_atomic(const char *path, mode_t mode, dev_t dev) { if (r < 0) return r; - if (mknod(t, mode, dev) < 0) + if (mknodat(atfd, t, mode, dev) < 0) return -errno; - if (rename(t, path) < 0) { - unlink_noerrno(t); - return -errno; - } - - return 0; -} - -int mkfifo_atomic(const char *path, mode_t mode) { - _cleanup_free_ char *t = NULL; - int r; - - assert(path); - - r = tempfn_random(path, NULL, &t); - if (r < 0) + r = RET_NERRNO(renameat(atfd, t, atfd, path)); + if (r < 0) { + (void) unlinkat(atfd, t, 0); return r; - - if (mkfifo(t, mode) < 0) - return -errno; - - if (rename(t, path) < 0) { - unlink_noerrno(t); - return -errno; } return 0; } -int mkfifoat_atomic(int dirfd, const char *path, mode_t mode) { +int mkfifoat_atomic(int atfd, const char *path, mode_t mode) { _cleanup_free_ char *t = NULL; int r; assert(path); - if (path_is_absolute(path)) - return mkfifo_atomic(path, mode); - /* We're only interested in the (random) filename. */ - r = tempfn_random_child("", NULL, &t); + r = tempfn_random(path, NULL, &t); if (r < 0) return r; - if (mkfifoat(dirfd, t, mode) < 0) + if (mkfifoat(atfd, t, mode) < 0) return -errno; - if (renameat(dirfd, t, dirfd, path) < 0) { - unlink_noerrno(t); - return -errno; + r = RET_NERRNO(renameat(atfd, t, atfd, path)); + if (r < 0) { + (void) unlinkat(atfd, t, 0); + return r; } return 0; diff --git a/src/libnm-systemd-shared/src/basic/fs-util.h b/src/libnm-systemd-shared/src/basic/fs-util.h index e48cf6800f..c4dffc48f3 100644 --- a/src/libnm-systemd-shared/src/basic/fs-util.h +++ b/src/libnm-systemd-shared/src/basic/fs-util.h @@ -13,6 +13,7 @@ #include "alloc-util.h" #include "errno-util.h" #include "time-util.h" +#include "user-util.h" #define MODE_INVALID ((mode_t) -1) @@ -50,14 +51,27 @@ int stat_warn_permissions(const char *path, const struct stat *st); RET_NERRNO(faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)) int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode); -int touch(const char *path); + +static inline int touch(const char *path) { + return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID); +} int symlink_idempotent(const char *from, const char *to, bool make_relative); -int symlink_atomic(const char *from, const char *to); -int mknod_atomic(const char *path, mode_t mode, dev_t dev); -int mkfifo_atomic(const char *path, mode_t mode); +int symlinkat_atomic_full(const char *from, int atfd, const char *to, bool make_relative); +static inline int symlink_atomic(const char *from, const char *to) { + return symlinkat_atomic_full(from, AT_FDCWD, to, false); +} + +int mknodat_atomic(int atfd, const char *path, mode_t mode, dev_t dev); +static inline int mknod_atomic(const char *path, mode_t mode, dev_t dev) { + return mknodat_atomic(AT_FDCWD, path, mode, dev); +} + int mkfifoat_atomic(int dir_fd, const char *path, mode_t mode); +static inline int mkfifo_atomic(const char *path, mode_t mode) { + return mkfifoat_atomic(AT_FDCWD, path, mode); +} int get_files_in_directory(const char *path, char ***list); diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.c b/src/libnm-systemd-shared/src/basic/glyph-util.c index 1bba139bfc..67f2270daf 100644 --- a/src/libnm-systemd-shared/src/basic/glyph-util.c +++ b/src/libnm-systemd-shared/src/basic/glyph-util.c @@ -53,6 +53,7 @@ const char *special_glyph(SpecialGlyph code) { [SPECIAL_GLYPH_LIGHT_SHADE] = "-", [SPECIAL_GLYPH_DARK_SHADE] = "X", [SPECIAL_GLYPH_SIGMA] = "S", + [SPECIAL_GLYPH_ARROW_LEFT] = "<-", [SPECIAL_GLYPH_ARROW_RIGHT] = "->", [SPECIAL_GLYPH_ARROW_UP] = "^", [SPECIAL_GLYPH_ARROW_DOWN] = "v", @@ -99,6 +100,7 @@ const char *special_glyph(SpecialGlyph code) { [SPECIAL_GLYPH_ARROW_DOWN] = u8"↓", /* actually called: DOWNWARDS ARROW */ /* Single glyph in Unicode, two in ASCII */ + [SPECIAL_GLYPH_ARROW_LEFT] = u8"←", /* actually called: LEFTWARDS ARROW */ [SPECIAL_GLYPH_ARROW_RIGHT] = u8"→", /* actually called: RIGHTWARDS ARROW */ /* Single glyph in Unicode, three in ASCII */ diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.h b/src/libnm-systemd-shared/src/basic/glyph-util.h index 065dde8a62..621d7a85b7 100644 --- a/src/libnm-systemd-shared/src/basic/glyph-util.h +++ b/src/libnm-systemd-shared/src/basic/glyph-util.h @@ -22,6 +22,7 @@ typedef enum SpecialGlyph { SPECIAL_GLYPH_MU, SPECIAL_GLYPH_CHECK_MARK, SPECIAL_GLYPH_CROSS_MARK, + SPECIAL_GLYPH_ARROW_LEFT, SPECIAL_GLYPH_ARROW_RIGHT, SPECIAL_GLYPH_ARROW_UP, SPECIAL_GLYPH_ARROW_DOWN, diff --git a/src/libnm-systemd-shared/src/basic/hashmap.c b/src/libnm-systemd-shared/src/basic/hashmap.c index 1fadaad996..f68cd36bb7 100644 --- a/src/libnm-systemd-shared/src/basic/hashmap.c +++ b/src/libnm-systemd-shared/src/basic/hashmap.c @@ -1190,7 +1190,7 @@ static int resize_buckets(HashmapBase *h, unsigned entries_add) { } while (rehash_next); } - assert(n_rehashed == n_entries(h)); + assert_se(n_rehashed == n_entries(h)); return 1; } @@ -1882,11 +1882,10 @@ int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HA } int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) { - const char *p = v; + const char *p = ASSERT_PTR(v); int r; assert(s); - assert(v); for (;;) { char *word; @@ -2079,6 +2078,8 @@ static bool set_fnmatch_one(Set *patterns, const char *needle) { assert(needle); + /* Any failure of fnmatch() is treated as equivalent to FNM_NOMATCH, i.e. as non-matching pattern */ + SET_FOREACH(p, patterns) if (fnmatch(p, needle, 0) == 0) return true; 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 fe356c6d15..cefe3f7661 100644 --- a/src/libnm-systemd-shared/src/basic/in-addr-util.c +++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c @@ -586,6 +586,7 @@ unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) { return 32U - u32ctz(be32toh(addr->s_addr)); } +/* Calculate an IPv4 netmask from prefix length, for example /8 -> 255.0.0.0. */ struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) { assert(addr); assert(prefixlen <= 32); @@ -599,6 +600,47 @@ struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned cha return addr; } +/* Calculate an IPv6 netmask from prefix length, for example /16 -> ffff::. */ +struct in6_addr* in6_addr_prefixlen_to_netmask(struct in6_addr *addr, unsigned char prefixlen) { + assert(addr); + assert(prefixlen <= 128); + + for (unsigned i = 0; i < 16; i++) { + uint8_t mask; + + if (prefixlen >= 8) { + mask = 0xFF; + prefixlen -= 8; + } else if (prefixlen > 0) { + mask = 0xFF << (8 - prefixlen); + prefixlen = 0; + } else { + assert(prefixlen == 0); + mask = 0; + } + + addr->s6_addr[i] = mask; + } + + return addr; +} + +/* Calculate an IPv4 or IPv6 netmask from prefix length, for example /8 -> 255.0.0.0 or /16 -> ffff::. */ +int in_addr_prefixlen_to_netmask(int family, union in_addr_union *addr, unsigned char prefixlen) { + assert(addr); + + switch (family) { + case AF_INET: + in4_addr_prefixlen_to_netmask(&addr->in, prefixlen); + return 0; + case AF_INET6: + in6_addr_prefixlen_to_netmask(&addr->in6, prefixlen); + return 0; + default: + return -EAFNOSUPPORT; + } +} + int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) { uint8_t msb_octet = *(uint8_t*) addr; 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 fbc60436c7..19fa35f1d2 100644 --- a/src/libnm-systemd-shared/src/basic/in-addr-util.h +++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h @@ -138,6 +138,8 @@ int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr); struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen); +struct in6_addr* in6_addr_prefixlen_to_netmask(struct in6_addr *addr, unsigned char prefixlen); +int in_addr_prefixlen_to_netmask(int family, union in_addr_union *addr, unsigned char prefixlen); int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen); int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask); int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen); diff --git a/src/libnm-systemd-shared/src/basic/io-util.c b/src/libnm-systemd-shared/src/basic/io-util.c index a591a75c37..cdad939aa6 100644 --- a/src/libnm-systemd-shared/src/basic/io-util.c +++ b/src/libnm-systemd-shared/src/basic/io-util.c @@ -49,11 +49,10 @@ int flush_fd(int fd) { } ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { - uint8_t *p = buf; + uint8_t *p = ASSERT_PTR(buf); ssize_t n = 0; assert(fd >= 0); - assert(buf); /* If called with nbytes == 0, let's call read() at least * once, to validate the operation */ @@ -108,10 +107,9 @@ int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { } int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { - const uint8_t *p = buf; + const uint8_t *p = ASSERT_PTR(buf); assert(fd >= 0); - assert(buf); if (_unlikely_(nbytes > (size_t) SSIZE_MAX)) return -EINVAL; diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h index b7b0a42e49..c51941c141 100644 --- a/src/libnm-systemd-shared/src/basic/log.h +++ b/src/libnm-systemd-shared/src/basic/log.h @@ -8,6 +8,7 @@ #include #include "macro.h" +#include "ratelimit.h" /* Some structures we reference but don't want to pull in headers for */ struct iovec; @@ -367,3 +368,41 @@ int log_syntax_invalid_utf8_internal( #define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG) void log_setup(void); + +typedef struct LogRateLimit { + int error; + int level; + RateLimit ratelimit; +} LogRateLimit; + +#define log_ratelimit_internal(_level, _error, _format, _file, _line, _func, ...) \ +({ \ + int _log_ratelimit_error = (_error); \ + int _log_ratelimit_level = (_level); \ + static LogRateLimit _log_ratelimit = { \ + .ratelimit = { \ + .interval = 1 * USEC_PER_SEC, \ + .burst = 1, \ + }, \ + }; \ + unsigned _num_dropped_errors = ratelimit_num_dropped(&_log_ratelimit.ratelimit); \ + if (_log_ratelimit_error != _log_ratelimit.error || _log_ratelimit_level != _log_ratelimit.level) { \ + ratelimit_reset(&_log_ratelimit.ratelimit); \ + _log_ratelimit.error = _log_ratelimit_error; \ + _log_ratelimit.level = _log_ratelimit_level; \ + } \ + if (ratelimit_below(&_log_ratelimit.ratelimit)) \ + _log_ratelimit_error = _num_dropped_errors > 0 \ + ? log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format " (Dropped %u similar message(s))", __VA_ARGS__, _num_dropped_errors) \ + : log_internal(_log_ratelimit_level, _log_ratelimit_error, _file, _line, _func, _format, __VA_ARGS__); \ + _log_ratelimit_error; \ +}) + +#define log_ratelimit_full_errno(level, error, format, ...) \ + ({ \ + int _level = (level), _e = (error); \ + _e = (log_get_max_level() >= LOG_PRI(_level)) \ + ? log_ratelimit_internal(_level, _e, format, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ + : -ERRNO_VALUE(_e); \ + _e < 0 ? _e : -ESTRPIPE; \ + }) diff --git a/src/libnm-systemd-shared/src/basic/parse-util.c b/src/libnm-systemd-shared/src/basic/parse-util.c index 787a681870..3b3efb0ab8 100644 --- a/src/libnm-systemd-shared/src/basic/parse-util.c +++ b/src/libnm-systemd-shared/src/basic/parse-util.c @@ -476,69 +476,31 @@ int safe_atolli(const char *s, long long int *ret_lli) { return 0; } -int safe_atou8(const char *s, uint8_t *ret) { - unsigned base = 0; - unsigned long l; - char *x = NULL; +int safe_atou8_full(const char *s, unsigned base, uint8_t *ret) { + unsigned u; + int r; - assert(s); - - s += strspn(s, WHITESPACE); - s = mangle_base(s, &base); - - errno = 0; - l = strtoul(s, &x, base); - if (errno > 0) - return -errno; - if (!x || x == s || *x != 0) - return -EINVAL; - if (l != 0 && s[0] == '-') - return -ERANGE; - if ((unsigned long) (uint8_t) l != l) + r = safe_atou_full(s, base, &u); + if (r < 0) + return r; + if (u > UINT8_MAX) return -ERANGE; - if (ret) - *ret = (uint8_t) l; + *ret = (uint8_t) u; return 0; } int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) { - char *x = NULL; - unsigned long l; + unsigned u; + int r; - assert(s); - assert(SAFE_ATO_MASK_FLAGS(base) <= 16); - - if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) && - strchr(WHITESPACE, s[0])) - return -EINVAL; - - s += strspn(s, WHITESPACE); - - if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) && - IN_SET(s[0], '+', '-')) - return -EINVAL; - - if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) && - s[0] == '0' && s[1] != 0) - return -EINVAL; - - s = mangle_base(s, &base); - - errno = 0; - l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base)); - if (errno > 0) - return -errno; - if (!x || x == s || *x != 0) - return -EINVAL; - if (l != 0 && s[0] == '-') - return -ERANGE; - if ((unsigned long) (uint16_t) l != l) + r = safe_atou_full(s, base, &u); + if (r < 0) + return r; + if (u > UINT16_MAX) return -ERANGE; - if (ret) - *ret = (uint16_t) l; - + *ret = (uint16_t) u; return 0; } diff --git a/src/libnm-systemd-shared/src/basic/parse-util.h b/src/libnm-systemd-shared/src/basic/parse-util.h index f2222dcffb..8d8d52327b 100644 --- a/src/libnm-systemd-shared/src/basic/parse-util.h +++ b/src/libnm-systemd-shared/src/basic/parse-util.h @@ -36,7 +36,11 @@ static inline int safe_atou(const char *s, unsigned *ret_u) { int safe_atoi(const char *s, int *ret_i); int safe_atolli(const char *s, long long int *ret_i); -int safe_atou8(const char *s, uint8_t *ret); +int safe_atou8_full(const char *s, unsigned base, uint8_t *ret); + +static inline int safe_atou8(const char *s, uint8_t *ret) { + return safe_atou8_full(s, 0, ret); +} int safe_atou16_full(const char *s, unsigned base, uint16_t *ret); diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c index e40ab3f5b6..bf93990fde 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.c +++ b/src/libnm-systemd-shared/src/basic/path-util.c @@ -1,22 +1,18 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #include #include #include -/* When we include libgen.h because we need dirname() we immediately - * undefine basename() since libgen.h defines it as a macro to the - * POSIX version which is really broken. We prefer GNU basename(). */ -#include -#undef basename - #include "alloc-util.h" #include "chase-symlinks.h" #include "extract-word.h" #include "fd-util.h" #include "fs-util.h" +#include "glob-util.h" #include "log.h" #include "macro.h" #include "path-util.h" @@ -197,6 +193,34 @@ int path_make_relative(const char *from, const char *to, char **ret) { return 0; } +int path_make_relative_parent(const char *from_child, const char *to, char **ret) { + _cleanup_free_ char *from = NULL; + int r; + + assert(from_child); + assert(to); + assert(ret); + + /* Similar to path_make_relative(), but provides the relative path from the parent directory of + * 'from_child'. This may be useful when creating relative symlink. + * + * E.g. + * - from = "/path/to/aaa", to = "/path/to/bbb" + * path_make_relative(from, to) = "../bbb" + * path_make_relative_parent(from, to) = "bbb" + * + * - from = "/path/to/aaa/bbb", to = "/path/to/ccc/ddd" + * path_make_relative(from, to) = "../../ccc/ddd" + * path_make_relative_parent(from, to) = "../ccc/ddd" + */ + + r = path_extract_directory(from_child, &from); + if (r < 0) + return r; + + return path_make_relative(from, to, ret); +} + char* path_startswith_strv(const char *p, char **set) { STRV_FOREACH(s, set) { char *t; @@ -324,11 +348,9 @@ char **path_strv_resolve_uniq(char **l, const char *root) { char *path_simplify(char *path) { bool add_slash = false; - char *f = path; + char *f = ASSERT_PTR(path); int r; - assert(path); - /* Removes redundant inner and trailing slashes. Also removes unnecessary dots. * Modifies the passed string in-place. * @@ -760,39 +782,27 @@ static int executable_is_good(const char *executable) { "/dev/null"); } -int fsck_exists(const char *fstype) { +int fsck_exists(void) { + return executable_is_good("fsck"); +} + +int fsck_exists_for_fstype(const char *fstype) { const char *checker; + int r; assert(fstype); if (streq(fstype, "auto")) return -EINVAL; + r = fsck_exists(); + if (r <= 0) + return r; + checker = strjoina("fsck.", fstype); return executable_is_good(checker); } -char* dirname_malloc(const char *path) { - char *d, *dir, *dir2; - - assert(path); - - d = strdup(path); - if (!d) - return NULL; - - dir = dirname(d); - assert(dir); - - if (dir == d) - return d; - - dir2 = strdup(dir); - free(d); - - return dir2; -} - static const char *skip_slash_or_dot(const char *p) { for (; !isempty(p); p++) { if (*p == '/') @@ -1310,3 +1320,66 @@ bool prefixed_path_strv_contains(char **l, const char *path) { return false; } + +int path_glob_can_match(const char *pattern, const char *prefix, char **ret) { + assert(pattern); + assert(prefix); + + for (const char *a = pattern, *b = prefix;;) { + _cleanup_free_ char *g = NULL, *h = NULL; + const char *p, *q; + int r, s; + + r = path_find_first_component(&a, /* accept_dot_dot = */ false, &p); + if (r < 0) + return r; + + s = path_find_first_component(&b, /* accept_dot_dot = */ false, &q); + if (s < 0) + return s; + + if (s == 0) { + /* The pattern matches the prefix. */ + if (ret) { + char *t; + + t = path_join(prefix, p); + if (!t) + return -ENOMEM; + + *ret = t; + } + return true; + } + + if (r == 0) + break; + + if (r == s && strneq(p, q, r)) + continue; /* common component. Check next. */ + + g = strndup(p, r); + if (!g) + return -ENOMEM; + + if (!string_is_glob(g)) + break; + + /* We found a glob component. Check if the glob pattern matches the prefix component. */ + + h = strndup(q, s); + if (!h) + return -ENOMEM; + + r = fnmatch(g, h, 0); + if (r == FNM_NOMATCH) + break; + if (r != 0) /* Failure to process pattern? */ + return -EINVAL; + } + + /* The pattern does not match the prefix. */ + if (ret) + *ret = NULL; + return false; +} diff --git a/src/libnm-systemd-shared/src/basic/path-util.h b/src/libnm-systemd-shared/src/basic/path-util.h index bb20087221..22d3632e6e 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.h +++ b/src/libnm-systemd-shared/src/basic/path-util.h @@ -61,6 +61,7 @@ char* path_make_absolute(const char *p, const char *prefix); int safe_getcwd(char **ret); int path_make_absolute_cwd(const char *p, char **ret); int path_make_relative(const char *from, const char *to, char **ret); +int path_make_relative_parent(const char *from_child, const char *to, char **ret); char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_; static inline char* path_startswith(const char *path, const char *prefix) { return path_startswith_full(path, prefix, true); @@ -102,7 +103,8 @@ static inline int find_executable(const char *name, char **ret_filename) { bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); -int fsck_exists(const char *fstype); +int fsck_exists(void); +int fsck_exists_for_fstype(const char *fstype); /* Iterates through the path prefixes of the specified path, going up * the tree, to root. Also returns "" (and not "/"!) for the root @@ -151,7 +153,6 @@ int fsck_exists(const char *fstype); _ret; \ }) -char* dirname_malloc(const char *path); int path_find_first_component(const char **p, bool accept_dot_dot, const char **ret); int path_find_last_component(const char *path, bool accept_dot_dot, const char **next, const char **ret); const char *last_path_component(const char *path); @@ -196,3 +197,5 @@ static inline const char *empty_to_root(const char *path) { bool path_strv_contains(char **l, const char *path); bool prefixed_path_strv_contains(char **l, const char *path); + +int path_glob_can_match(const char *pattern, const char *prefix, char **ret); diff --git a/src/libnm-systemd-shared/src/basic/random-util.c b/src/libnm-systemd-shared/src/basic/random-util.c index 9423a0805d..d8734cc7d0 100644 --- a/src/libnm-systemd-shared/src/basic/random-util.c +++ b/src/libnm-systemd-shared/src/basic/random-util.c @@ -1,9 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#if defined(__i386__) || defined(__x86_64__) -#include -#endif - #include #include #include @@ -33,11 +29,10 @@ #include "sha256.h" #include "time-util.h" -/* This is a "best effort" kind of thing, but has no real security value. - * So, this should only be used by random_bytes(), which is not meant for - * crypto. This could be made better, but we're *not* trying to roll a - * userspace prng here, or even have forward secrecy, but rather just do - * the shortest thing that is at least better than libc rand(). */ +/* This is a "best effort" kind of thing, but has no real security value. So, this should only be used by + * random_bytes(), which is not meant for crypto. This could be made better, but we're *not* trying to roll a + * userspace prng here, or even have forward secrecy, but rather just do the shortest thing that is at least + * better than libc rand(). */ static void fallback_random_bytes(void *p, size_t n) { static thread_local uint64_t fallback_counter = 0; struct { @@ -53,7 +48,7 @@ static void fallback_random_bytes(void *p, size_t n) { .stamp_mono = now(CLOCK_MONOTONIC), .stamp_real = now(CLOCK_REALTIME), .pid = getpid(), - .tid = gettid() + .tid = gettid(), }; #if HAVE_SYS_AUXV_H diff --git a/src/libnm-systemd-shared/src/basic/ratelimit.c b/src/libnm-systemd-shared/src/basic/ratelimit.c index 005bf31dc7..c16c8f7103 100644 --- a/src/libnm-systemd-shared/src/basic/ratelimit.c +++ b/src/libnm-systemd-shared/src/basic/ratelimit.c @@ -30,9 +30,16 @@ bool ratelimit_below(RateLimit *r) { if (r->num < r->burst) goto good; + r->num++; return false; good: r->num++; return true; } + +unsigned ratelimit_num_dropped(RateLimit *r) { + assert(r); + + return r->num > r->burst ? r->num - r->burst : 0; +} diff --git a/src/libnm-systemd-shared/src/basic/ratelimit.h b/src/libnm-systemd-shared/src/basic/ratelimit.h index ee1d17c0e7..2236189851 100644 --- a/src/libnm-systemd-shared/src/basic/ratelimit.h +++ b/src/libnm-systemd-shared/src/basic/ratelimit.h @@ -4,7 +4,6 @@ #include #include "time-util.h" -#include "util.h" typedef struct RateLimit { usec_t interval; /* Keep those two fields first so they can be initialized easily: */ @@ -22,3 +21,5 @@ static inline bool ratelimit_configured(RateLimit *rl) { } bool ratelimit_below(RateLimit *r); + +unsigned ratelimit_num_dropped(RateLimit *r); diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c index c31b4d89d0..51adaca9d0 100644 --- a/src/libnm-systemd-shared/src/basic/stat-util.c +++ b/src/libnm-systemd-shared/src/basic/stat-util.c @@ -360,6 +360,32 @@ bool stat_inode_unmodified(const struct stat *a, const struct stat *b) { (!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */ } +bool statx_inode_same(const struct statx *a, const struct statx *b) { + + /* Same as stat_inode_same() but for struct statx */ + + return a && b && + FLAGS_SET(a->stx_mask, STATX_TYPE|STATX_INO) && FLAGS_SET(b->stx_mask, STATX_TYPE|STATX_INO) && + (a->stx_mode & S_IFMT) != 0 && + ((a->stx_mode ^ b->stx_mode) & S_IFMT) == 0 && + a->stx_dev_major == b->stx_dev_major && + a->stx_dev_minor == b->stx_dev_minor && + a->stx_ino == b->stx_ino; +} + +bool statx_mount_same(const struct new_statx *a, const struct new_statx *b) { + if (!a || !b) + return false; + + /* if we have the mount ID, that's all we need */ + if (FLAGS_SET(a->stx_mask, STATX_MNT_ID) && FLAGS_SET(b->stx_mask, STATX_MNT_ID)) + return a->stx_mnt_id == b->stx_mnt_id; + + /* Otherwise, major/minor of backing device must match */ + return a->stx_dev_major == b->stx_dev_major && + a->stx_dev_minor == b->stx_dev_minor; +} + int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) { static bool avoid_statx = false; struct stat st; diff --git a/src/libnm-systemd-shared/src/basic/stat-util.h b/src/libnm-systemd-shared/src/basic/stat-util.h index 56f15534aa..f9519d8cbd 100644 --- a/src/libnm-systemd-shared/src/basic/stat-util.h +++ b/src/libnm-systemd-shared/src/basic/stat-util.h @@ -73,6 +73,9 @@ int proc_mounted(void); bool stat_inode_same(const struct stat *a, const struct stat *b); bool stat_inode_unmodified(const struct stat *a, const struct stat *b); +bool statx_inode_same(const struct statx *a, const struct statx *b); +bool statx_mount_same(const struct new_statx *a, const struct new_statx *b); + int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx); #if HAS_FEATURE_MEMORY_SANITIZER diff --git a/src/libnm-systemd-shared/src/basic/string-util.c b/src/libnm-systemd-shared/src/basic/string-util.c index 128aea99c0..17d35fe1a4 100644 --- a/src/libnm-systemd-shared/src/basic/string-util.c +++ b/src/libnm-systemd-shared/src/basic/string-util.c @@ -521,6 +521,19 @@ char* strshorten(char *s, size_t l) { return s; } +int strgrowpad0(char **s, size_t l) { + assert(s); + + char *q = realloc(*s, l); + if (!q) + return -ENOMEM; + *s = q; + + size_t sz = strlen(*s); + memzero(*s + sz, l - sz); + return 0; +} + char *strreplace(const char *text, const char *old_string, const char *new_string) { size_t l, old_len, new_len; char *t, *ret = NULL; diff --git a/src/libnm-systemd-shared/src/basic/string-util.h b/src/libnm-systemd-shared/src/basic/string-util.h index 1dd46f7f20..0703c848f0 100644 --- a/src/libnm-systemd-shared/src/basic/string-util.h +++ b/src/libnm-systemd-shared/src/basic/string-util.h @@ -152,6 +152,8 @@ char *cellescape(char *buf, size_t len, const char *s); char* strshorten(char *s, size_t l); +int strgrowpad0(char **s, size_t l); + char *strreplace(const char *text, const char *old_string, const char *new_string); char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]); diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c index b2fe8d9d4e..eea34ca68d 100644 --- a/src/libnm-systemd-shared/src/basic/strv.c +++ b/src/libnm-systemd-shared/src/basic/strv.c @@ -828,13 +828,26 @@ char** strv_shell_escape(char **l, const char *bad) { return l; } -bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos) { - for (size_t i = 0; patterns && patterns[i]; i++) - if (fnmatch(patterns[i], s, flags) == 0) { - if (matched_pos) - *matched_pos = i; - return true; - } +bool strv_fnmatch_full( + char* const* patterns, + const char *s, + int flags, + size_t *ret_matched_pos) { + + assert(s); + + if (patterns) + for (size_t i = 0; patterns[i]; i++) + /* NB: We treat all fnmatch() errors as equivalent to FNM_NOMATCH, i.e. if fnmatch() fails to + * process the pattern for some reason we'll consider this equivalent to non-matching. */ + if (fnmatch(patterns[i], s, flags) == 0) { + if (ret_matched_pos) + *ret_matched_pos = i; + return true; + } + + if (ret_matched_pos) + *ret_matched_pos = SIZE_MAX; return false; } diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h index 87ec6337bd..d6f5ac6ba5 100644 --- a/src/libnm-systemd-shared/src/basic/strv.h +++ b/src/libnm-systemd-shared/src/basic/strv.h @@ -240,7 +240,7 @@ void strv_print(char * const *l); char** strv_reverse(char **l); char** strv_shell_escape(char **l, const char *bad); -bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos); +bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *ret_matched_pos); static inline bool strv_fnmatch(char* const* patterns, const char *s) { return strv_fnmatch_full(patterns, s, 0, NULL); } diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c index 26d59de123..71b2f67350 100644 --- a/src/libnm-systemd-shared/src/basic/time-util.c +++ b/src/libnm-systemd-shared/src/basic/time-util.c @@ -513,10 +513,9 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { { "us", 1 }, }; - char *p = buf; + char *p = ASSERT_PTR(buf); bool something = false; - assert(buf); assert(l > 0); if (t == USEC_INFINITY) { diff --git a/src/libnm-systemd-shared/src/basic/time-util.h b/src/libnm-systemd-shared/src/basic/time-util.h index bf312442b0..c98f95a530 100644 --- a/src/libnm-systemd-shared/src/basic/time-util.h +++ b/src/libnm-systemd-shared/src/basic/time-util.h @@ -189,10 +189,15 @@ static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) { } static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) { + if (delta == INT64_MIN) { /* prevent overflow */ + assert_cc(-(INT64_MIN + 1) == INT64_MAX); + assert_cc(USEC_INFINITY > INT64_MAX); + return usec_add(timestamp, (usec_t) INT64_MAX + 1); + } if (delta < 0) return usec_add(timestamp, (usec_t) (-delta)); - else - return usec_sub_unsigned(timestamp, (usec_t) delta); + + return usec_sub_unsigned(timestamp, (usec_t) delta); } #if SIZEOF_TIME_T == 8 diff --git a/src/libnm-systemd-shared/src/basic/tmpfile-util.c b/src/libnm-systemd-shared/src/basic/tmpfile-util.c index e0a338c163..34d3016ba9 100644 --- a/src/libnm-systemd-shared/src/basic/tmpfile-util.c +++ b/src/libnm-systemd-shared/src/basic/tmpfile-util.c @@ -86,12 +86,76 @@ int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) { return 0; } -int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { - _cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL; +static int tempfn_build(const char *p, const char *pre, const char *post, bool child, char **ret) { + _cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL, *result = NULL; + size_t len_pre, len_post, len_add; int r; + assert(p); assert(ret); + /* + * Turns this: + * /foo/bar/waldo + * + * Into this : + * /foo/bar/waldo/.#
 (child == true)
+         *         /foo/bar/.#
waldo (child == false)
+         */
+
+        if (pre && strchr(pre, '/'))
+                return -EINVAL;
+
+        if (post && strchr(post, '/'))
+                return -EINVAL;
+
+        len_pre = strlen_ptr(pre);
+        len_post = strlen_ptr(post);
+        /* NAME_MAX is counted *without* the trailing NUL byte. */
+        if (len_pre > NAME_MAX - STRLEN(".#") ||
+            len_post > NAME_MAX - STRLEN(".#") - len_pre)
+                return -EINVAL;
+
+        len_add = len_pre + len_post + STRLEN(".#");
+
+        if (child) {
+                d = strdup(p);
+                if (!d)
+                        return -ENOMEM;
+        } else {
+                r = path_extract_directory(p, &d);
+                if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */
+                        return r;
+
+                r = path_extract_filename(p, &fn);
+                if (r < 0)
+                        return r;
+
+                if (strlen(fn) > NAME_MAX - len_add)
+                        /* We cannot simply prepend and append strings to the filename. Let's truncate the filename. */
+                        fn[NAME_MAX - len_add] = '\0';
+        }
+
+        nf = strjoin(".#", strempty(pre), strempty(fn), strempty(post));
+        if (!nf)
+                return -ENOMEM;
+
+        if (d) {
+                if (!path_extend(&d, nf))
+                        return -ENOMEM;
+
+                result = path_simplify(TAKE_PTR(d));
+        } else
+                result = TAKE_PTR(nf);
+
+        if (!path_is_valid(result)) /* New path is not valid? (Maybe because too long?) Refuse. */
+                return -EINVAL;
+
+        *ret = TAKE_PTR(result);
+        return 0;
+}
+
+int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
         /*
          * Turns this:
          *         /foo/bar/waldo
@@ -100,36 +164,13 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
          *         /foo/bar/.#waldoXXXXXX
          */
 
-        r = path_extract_directory(p, &d);
-        if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */
-                return r;
-
-        r = path_extract_filename(p, &fn);
-        if (r < 0)
-                return r;
-
-        nf = strjoin(".#", strempty(extra), fn, "XXXXXX");
-        if (!nf)
-                return -ENOMEM;
-
-        if (!filename_is_valid(nf)) /* New name is not valid? (Maybe because too long?) Refuse. */
-                return -EINVAL;
-
-        if (d)  {
-                if (!path_extend(&d, nf))
-                        return -ENOMEM;
-
-                *ret = path_simplify(TAKE_PTR(d));
-        } else
-                *ret = TAKE_PTR(nf);
-
-        return 0;
+        return tempfn_build(p, extra, "XXXXXX", /* child = */ false, ret);
 }
 
 int tempfn_random(const char *p, const char *extra, char **ret) {
-        _cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL;
-        int r;
+        _cleanup_free_ char *s = NULL;
 
+        assert(p);
         assert(ret);
 
         /*
@@ -140,37 +181,14 @@ int tempfn_random(const char *p, const char *extra, char **ret) {
          *         /foo/bar/.#waldobaa2a261115984a9
          */
 
-        r = path_extract_directory(p, &d);
-        if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */
-                return r;
-
-        r = path_extract_filename(p, &fn);
-        if (r < 0)
-                return r;
-
-        if (asprintf(&nf, ".#%s%s%016" PRIx64,
-                     strempty(extra),
-                     fn,
-                     random_u64()) < 0)
+        if (asprintf(&s, "%016" PRIx64, random_u64()) < 0)
                 return -ENOMEM;
 
-        if (!filename_is_valid(nf)) /* Not valid? (maybe because too long now?) — refuse early */
-                return -EINVAL;
-
-        if (d) {
-                if (!path_extend(&d, nf))
-                        return -ENOMEM;
-
-                *ret = path_simplify(TAKE_PTR(d));
-        } else
-                *ret = TAKE_PTR(nf);
-
-        return 0;
+        return tempfn_build(p, extra, s, /* child = */ false, ret);
 }
 
 int tempfn_random_child(const char *p, const char *extra, char **ret) {
-        char *t, *x;
-        uint64_t u;
+        _cleanup_free_ char *s = NULL;
         int r;
 
         assert(ret);
@@ -187,27 +205,10 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
                         return r;
         }
 
-        extra = strempty(extra);
-
-        t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
-        if (!t)
+        if (asprintf(&s, "%016" PRIx64, random_u64()) < 0)
                 return -ENOMEM;
 
-        if (isempty(p))
-                x = stpcpy(stpcpy(t, ".#"), extra);
-        else
-                x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
-
-        u = random_u64();
-        for (unsigned i = 0; i < 16; i++) {
-                *(x++) = hexchar(u & 0xF);
-                u >>= 4;
-        }
-
-        *x = 0;
-
-        *ret = path_simplify(t);
-        return 0;
+        return tempfn_build(p, extra, s, /* child = */ true, ret);
 }
 
 int open_tmpfile_unlinkable(const char *directory, int flags) {
diff --git a/src/libnm-systemd-shared/src/basic/user-util.h b/src/libnm-systemd-shared/src/basic/user-util.h
index e1692c4f66..a08683bcea 100644
--- a/src/libnm-systemd-shared/src/basic/user-util.h
+++ b/src/libnm-systemd-shared/src/basic/user-util.h
@@ -13,12 +13,12 @@
 #include 
 
 /* Users managed by systemd-homed. See https://systemd.io/UIDS-GIDS for details how this range fits into the rest of the world */
-#define HOME_UID_MIN 60001
-#define HOME_UID_MAX 60513
+#define HOME_UID_MIN ((uid_t) 60001)
+#define HOME_UID_MAX ((uid_t) 60513)
 
 /* Users mapped from host into a container */
-#define MAP_UID_MIN 60514
-#define MAP_UID_MAX 60577
+#define MAP_UID_MIN ((uid_t) 60514)
+#define MAP_UID_MAX ((uid_t) 60577)
 
 bool uid_is_valid(uid_t uid);
 
@@ -55,7 +55,7 @@ int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t
 int getgroups_alloc(gid_t** gids);
 
 int get_home_dir(char **ret);
-int get_shell(char **_ret);
+int get_shell(char **ret);
 
 int reset_uid_gid(void);
 
@@ -67,9 +67,9 @@ int take_etc_passwd_lock(const char *root);
 #define UID_NOBODY ((uid_t) 65534U)
 #define GID_NOBODY ((gid_t) 65534U)
 
-/* If REMOUNT_IDMAP_HOST_ROOT is set for remount_idmap() we'll include a mapping here that maps the host root
- * user accessing the idmapped mount to the this user ID on the backing fs. This is the last valid UID in the
- * *signed* 32bit range. You might wonder why precisely use this specific UID for this purpose? Well, we
+/* If REMOUNT_IDMAPPING_HOST_ROOT is set for remount_idmap() we'll include a mapping here that maps the host
+ * root user accessing the idmapped mount to the this user ID on the backing fs. This is the last valid UID in
+ * the *signed* 32bit range. You might wonder why precisely use this specific UID for this purpose? Well, we
  * definitely cannot use the first 0…65536 UIDs for that, since in most cases that's precisely the file range
  * we intend to map to some high UID range, and since UID mappings have to be bijective we thus cannot use
  * them at all. Furthermore the UID range beyond INT32_MAX (i.e. the range above the signed 32bit range) is
@@ -130,6 +130,7 @@ int putsgent_sane(const struct sgrp *sg, FILE *stream);
 #endif
 
 bool is_nologin_shell(const char *shell);
+const char* default_root_shell(const char *root);
 
 int is_this_me(const char *username);
 
diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
index 8b483f0b50..2536c741c6 100644
--- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
+++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
@@ -81,18 +81,13 @@
 #endif
 
 /* This passes the argument through after (if asserts are enabled) checking that it is not null. */
-#define ASSERT_PTR(expr)                        \
-        ({                                      \
-                typeof(expr) _expr_ = (expr);   \
-                assert(_expr_);                 \
-                _expr_;                         \
-        })
-
-#define ASSERT_SE_PTR(expr)                     \
-        ({                                      \
-                typeof(expr) _expr_ = (expr);   \
-                assert_se(_expr_);              \
-                _expr_;                         \
+#define ASSERT_PTR(expr) _ASSERT_PTR(expr, UNIQ_T(_expr_, UNIQ), assert)
+#define ASSERT_SE_PTR(expr) _ASSERT_PTR(expr, UNIQ_T(_expr_, UNIQ), assert_se)
+#define _ASSERT_PTR(expr, var, check)      \
+        ({                                 \
+                typeof(expr) var = (expr); \
+                check(var);                \
+                var;                       \
         })
 
 #define ASSERT_NONNEG(expr)                              \
diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.c b/src/libnm-systemd-shared/src/fundamental/sha256.c
index 31d9674d09..9b717645b3 100644
--- a/src/libnm-systemd-shared/src/fundamental/sha256.c
+++ b/src/libnm-systemd-shared/src/fundamental/sha256.c
@@ -104,7 +104,7 @@ void sha256_init_ctx(struct sha256_ctx *ctx) {
 
 /* Process the remaining bytes in the internal buffer and the usual
    prolog according to the standard and write the result to RESBUF. */
-void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
+uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]) {
         /* Take yet unprocessed bytes into account.  */
         uint32_t bytes = ctx->buflen;
         size_t pad;
@@ -129,7 +129,7 @@ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
         /* Put result from CTX in first 32 bytes following RESBUF.  */
         for (size_t i = 0; i < 8; ++i)
                 if (UNALIGNED_P(resbuf))
-                        memcpy((uint8_t*) resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t));
+                        memcpy(resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t));
                 else
                         ((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]);
 
@@ -197,10 +197,9 @@ void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx
 /* Process LEN bytes of BUFFER, accumulating context into CTX.
    It is assumed that LEN % 64 == 0.  */
 static void sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx) {
-        const uint32_t *words = buffer;
+        const uint32_t *words = ASSERT_PTR(buffer);
         size_t nwords = len / sizeof(uint32_t);
 
-        assert(buffer);
         assert(ctx);
 
         uint32_t a = ctx->H[0];
@@ -289,3 +288,10 @@ static void sha256_process_block(const void *buffer, size_t len, struct sha256_c
         ctx->H[6] = g;
         ctx->H[7] = h;
 }
+
+uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]) {
+        struct sha256_ctx ctx;
+        sha256_init_ctx(&ctx);
+        sha256_process_bytes(buffer, sz, &ctx);
+        return sha256_finish_ctx(&ctx, result);
+}
diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.h b/src/libnm-systemd-shared/src/fundamental/sha256.h
index f296f76ae8..31790c2ebd 100644
--- a/src/libnm-systemd-shared/src/fundamental/sha256.h
+++ b/src/libnm-systemd-shared/src/fundamental/sha256.h
@@ -25,5 +25,9 @@ struct sha256_ctx {
 };
 
 void sha256_init_ctx(struct sha256_ctx *ctx);
-void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf);
+uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]);
 void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx);
+
+uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]);
+
+#define SHA256_DIRECT(buffer, sz) sha256_direct(buffer, sz, (uint8_t[SHA256_DIGEST_SIZE]) {})