From 129ef395a7f217565ef0a2685b45996f111e001d Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Wed, 2 Sep 2020 13:28:10 +0200 Subject: [PATCH] New upstream version 246.4 --- man/networkctl.xml | 6 +++ man/org.freedesktop.systemd1.xml | 20 +++++--- man/sd_bus_message_append.xml | 6 ++- man/sd_bus_message_read.xml | 14 ++++- man/sd_bus_message_read_basic.xml | 24 +++++---- man/sd_listen_fds.xml | 25 ++++----- man/systemctl.xml | 6 ++- man/systemd.service.xml | 30 ++++++----- man/systemd.socket.xml | 18 +++---- man/systemd.time.xml | 10 ++++ shell-completion/zsh/_networkctl | 36 ++++++++----- src/analyze/analyze.c | 2 +- src/basic/missing_capability.h | 8 +++ src/basic/path-util.c | 25 ++++++--- src/basic/siphash24.h | 6 +++ src/core/load-fragment.c | 2 +- src/core/main.c | 16 ++++++ src/core/manager.c | 21 ++++---- src/core/manager.h | 4 +- src/core/mount-setup.c | 13 ++++- src/core/transaction.c | 5 +- src/core/unit.c | 10 ++-- src/core/unit.h | 2 +- src/coredump/coredump.c | 14 +++-- src/firstboot/firstboot.c | 5 +- src/home/homed-home.c | 2 +- src/login/logind.h | 1 + src/login/user-runtime-dir.c | 5 +- src/network/networkctl.c | 2 +- src/network/networkd-dhcp6.c | 3 +- src/nspawn/nspawn.c | 2 +- src/partition/makefs.c | 1 + src/partition/test-repart.sh | 2 + src/resolve/resolved-dns-transaction.c | 29 ++++++----- src/shared/ask-password-api.c | 3 ++ src/shared/dev-setup.c | 29 +++++------ src/shared/dev-setup.h | 2 +- src/shared/dissect-image.c | 6 +-- src/shared/group-record-nss.c | 2 +- src/shared/libcrypt-util.c | 19 ++++--- src/shared/libcrypt-util.h | 2 +- src/shared/unit-file.c | 51 ++++++++++--------- src/shared/unit-file.h | 12 ++--- src/shared/user-record-nss.c | 2 +- src/shared/varlink.c | 12 +++-- src/test/test-dev-setup.c | 5 +- .../tty-ask-password-agent.c | 19 +++---- src/userdb/userdbctl.c | 3 +- units/meson.build | 1 + 49 files changed, 336 insertions(+), 207 deletions(-) diff --git a/man/networkctl.xml b/man/networkctl.xml index bd958fb1e..5a6ca5ab2 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -255,6 +255,7 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR) delete + DEVICE… Deletes virtual netdevs. Takes interface name or index number. @@ -262,6 +263,7 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR) up + DEVICE… Bring devices up. Takes interface name or index number. @@ -269,6 +271,7 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR) down + DEVICE… Bring devices down. Takes interface name or index number. @@ -276,6 +279,7 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR) renew + DEVICE… Renew dynamic configurations e.g. addresses received from DHCP server. Takes interface name or index number. @@ -284,6 +288,7 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR) forcerenew + DEVICE… Send a FORCERENEW message to all connected clients, triggering DHCP reconfiguration. Takes interface name or index number. @@ -292,6 +297,7 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR) reconfigure + DEVICE… Reconfigure network interfaces. Takes interface name or index number. diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 12e18109b..ef9dfb4f1 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -2698,12 +2698,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { - - - - - - @@ -3706,6 +3700,18 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { Most properties of the Service interface map directly to the corresponding settings in service unit files. For the sake of brevity, here's a list of all exceptions only: + TimeoutStartUSec, TimeoutStopUSec and + TimeoutAbortUSec contain the start, stop and abort timeouts, in microseconds. Note + the slight difference in naming when compared to the matching unit file settings (see + systemd.service7): + these bus properties strictly use microseconds (and thus are suffixed …USec) while + the unit file settings default to a time unit of seconds (and thus are suffixed + …Sec), unless a different unit is explicitly specified. This reflects that fact that + internally the service manager deals in microsecond units only, and the bus properties are a relatively + low-level (binary) concept exposing this. The unit file settings on the other hand are relatively + high-level (string-based) concepts and thus support more user friendly time specifications which + default to second time units but allow other units too, if specified. + WatchdogTimestamp and WatchdogTimestampMonotonic contain CLOCK_REALTIME/CLOCK_MONOTONIC microsecond timestamps of the last watchdog ping received from the service, or 0 if none was ever received. @@ -8968,8 +8974,6 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope { - - diff --git a/man/sd_bus_message_append.xml b/man/sd_bus_message_append.xml index 5faadd603..7f9235954 100644 --- a/man/sd_bus_message_append.xml +++ b/man/sd_bus_message_append.xml @@ -146,8 +146,10 @@ - For types "s" and "g" (unicode string or signature), the pointer may be - NULL, which is equivalent to an empty string. See + For types s and g (unicode string or signature), the pointer + may be NULL, which is equivalent to an empty string. For h (UNIX + file descriptor), the descriptor is duplicated by this call and the passed descriptor stays in possession + of the caller. See sd_bus_message_append_basic3 for the precise interpretation of those and other types. diff --git a/man/sd_bus_message_read.xml b/man/sd_bus_message_read.xml index 1b9f36cd8..2b5f1000b 100644 --- a/man/sd_bus_message_read.xml +++ b/man/sd_bus_message_read.xml @@ -73,7 +73,10 @@ should be read. See the table below for a complete list of allowed arguments and their types. Note that, if the basic type is a pointer (e.g., const char * in the case of a string), the argument is a pointer to a pointer, and also the pointer value that is written is only borrowed and the contents must - be copied if they are to be used after the end of the messages lifetime. + be copied if they are to be used after the end of the messages lifetime. If the type is + h (UNIX file descriptor), the descriptor is not duplicated by this call and the + returned descriptor remains in possession of the message object, and needs to be duplicated by the caller + in order to keep an open reference to it after the message object is freed. Each argument may also be NULL, in which case the value is read and ignored. @@ -228,6 +231,15 @@ const char *s, *t, *u; sd_bus_message_read(m, "a{is}", 3, &i, &s, &j, &t, &k, &u); + + Read a single file descriptor, and duplicate it in order to keep it open after the message is + freed. + + sd_bus_message *m; +int fd, fd_copy; + +sd_bus_message_read(m, "h", &fd); +fd_copy = fcntl(fd, FD_DUPFD_CLOEXEC, 3); diff --git a/man/sd_bus_message_read_basic.xml b/man/sd_bus_message_read_basic.xml index e1e993434..dc9f96061 100644 --- a/man/sd_bus_message_read_basic.xml +++ b/man/sd_bus_message_read_basic.xml @@ -52,17 +52,19 @@ - If p is not NULL, it should contain - a pointer to an appropriate object. For example, if type - is 'y', the object passed in p - should have type uint8_t *. If type is - 's', the object passed in p should - have type const char **. Note that, if the basic type is a pointer - (e.g., const char * in the case of a string), the pointer is only - borrowed and the contents must be copied if they are to be used after the end - of the messages lifetime. Similarly, during the lifetime of such a pointer, the - message must not be modified. See the table below for a complete list of allowed - types. + If p is not NULL, it should contain a pointer to an + appropriate object. For example, if type is 'y', the object + passed in p should have type uint8_t *. If + type is 's', the object passed in p + should have type const char **. Note that, if the basic type is a pointer (e.g., + const char * in the case of a string), the pointer is only borrowed and the contents must + be copied if they are to be used after the end of the messages lifetime. Similarly, during the lifetime + of such a pointer, the message must not be modified. If type is + 'h' (UNIX file descriptor), the descriptor is not duplicated by this call and the + returned descriptor remains in possession of the message object, and needs to be duplicated by the caller + in order to keep an open reference to it after the message object is freed (for example by calling + fcntl(fd, FD_DUPFD_CLOEXEC, 3)). See the table below for a complete list of + allowed types. diff --git a/man/sd_listen_fds.xml b/man/sd_listen_fds.xml index 9a66ee33b..4973718ef 100644 --- a/man/sd_listen_fds.xml +++ b/man/sd_listen_fds.xml @@ -54,24 +54,19 @@ (i.e. SD_LISTEN_FDS_START), the remaining descriptors follow at 4, 5, 6, …, if any. - If a daemon receives more than one file descriptor, they - will be passed in the same order as configured in the systemd - socket unit file (see - systemd.socket5 - for details). Nonetheless, it is recommended to verify the correct - socket types before using them. To simplify this checking, the - functions + If a daemon receives more than one file descriptor, they will be passed in the same order as + configured in the systemd socket unit file (see + systemd.socket5 for + details) — if there's only one such file (see below). Nonetheless, it is recommended to verify the + correct socket types before using them. To simplify this checking, the functions sd_is_fifo3, sd_is_socket3, sd_is_socket_inet3, - sd_is_socket_unix3 - are provided. In order to maximize flexibility, it is recommended - to make these checks as loose as possible without allowing - incorrect setups. i.e. often, the actual port number a socket is - bound to matters little for the service to work, hence it should - not be verified. On the other hand, whether a socket is a datagram - or stream socket matters a lot for the most common program logics - and should be checked. + sd_is_socket_unix3 are + provided. In order to maximize flexibility, it is recommended to make these checks as loose as possible + without allowing incorrect setups. i.e. often, the actual port number a socket is bound to matters little + for the service to work, hence it should not be verified. On the other hand, whether a socket is a + datagram or stream socket matters a lot for the most common program logics and should be checked.This function call will set the FD_CLOEXEC flag for all passed file descriptors to avoid further inheritance to children diff --git a/man/systemctl.xml b/man/systemctl.xml index 506f9ca68..1e2b6c16e 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -446,7 +446,11 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err current main process identifier as MainPID (which is runtime state), and time settings are always exposed as properties ending in the …USec suffix even if a matching configuration options end in …Sec, because microseconds is the normalized time unit used - by the system and service manager. + internally by the system and service manager. + + For details about many of these properties, see the documentation of the D-Bus interface + backing these properties, see + org.freedesktop.systemd15. diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 5aec51172..124fa383a 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -1028,20 +1028,24 @@ FileDescriptorStoreMax= - Configure how many file descriptors may be stored in the service manager for the service using + Configure how many file descriptors may be stored in the service manager for the + service using sd_pid_notify_with_fds3's - FDSTORE=1 messages. This is useful for implementing services that can restart after an - explicit request or a crash without losing state. Any open sockets and other file descriptors which should not - be closed during the restart may be stored this way. Application state can either be serialized to a file in - /run, or better, stored in a - memfd_create2 memory file - descriptor. Defaults to 0, i.e. no file descriptors may be stored in the service manager. All file descriptors - passed to the service manager from a specific service are passed back to the service's main process on the next - service restart. Any file descriptors passed to the service manager are automatically closed when - POLLHUP or POLLERR is seen on them, or when the service is fully - stopped and no job is queued or being executed for it. If this option is used, NotifyAccess= - (see above) should be set to open access to the notification socket provided by systemd. If - NotifyAccess= is not set, it will be implicitly set to + FDSTORE=1 messages. This is useful for implementing services that can restart + after an explicit request or a crash without losing state. Any open sockets and other file + descriptors which should not be closed during the restart may be stored this way. Application state + can either be serialized to a file in /run, or better, stored in a + memfd_create2 + memory file descriptor. Defaults to 0, i.e. no file descriptors may be stored in the service + manager. All file descriptors passed to the service manager from a specific service are passed back + to the service's main process on the next service restart (see + sd_listen_fds3 for + details about the precise protocol used and the order in which the file descriptors are passed). Any + file descriptors passed to the service manager are automatically closed when + POLLHUP or POLLERR is seen on them, or when the service is + fully stopped and no job is queued or being executed for it. If this option is used, + NotifyAccess= (see above) should be set to open access to the notification socket + provided by systemd. If NotifyAccess= is not set, it will be implicitly set to . diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index f989b99f9..29ce0b1c2 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -81,16 +81,14 @@ services, as well as parallelized starting of services. See the blog stories linked at the end for an introduction. - Note that the daemon software configured for socket - activation with socket units needs to be able to accept sockets - from systemd, either via systemd's native socket passing interface - (see - sd_listen_fds3 - for details) or via the traditional - inetd8-style - socket passing (i.e. sockets passed in via standard input and - output, using StandardInput=socket in the - service file). + Note that the daemon software configured for socket activation with socket units needs to be able + to accept sockets from systemd, either via systemd's native socket passing interface (see + sd_listen_fds3 for + details about the precise protocol used and the order in which the file descriptors are passed) or via + traditional inetd8-style + socket passing (i.e. sockets passed in via standard input and output, using + StandardInput=socket in the service file). All network sockets allocated through .socket units are allocated in the host's network namespace (see One can use the timespan command of systemd-analyze1 to normalise a textual time span for testing and validation purposes. + + Internally, systemd generally operates with microsecond time granularity, while the default time + unit in user-configurable time spans is usually seconds (see above). This disparity becomes visible when + comparing the same settings in the (high-level) unit file syntax with the matching (more low-level) D-Bus + properties (which are what + systemctl1's + show command displays). The former typically are suffixed with …Sec + to indicate the default unit of seconds, the latter are typically suffixed with …USec + to indicate the underlying low-level time unit, even if they both encapsulate the very same + settings. diff --git a/shell-completion/zsh/_networkctl b/shell-completion/zsh/_networkctl index 4995bd3d1..13c800988 100644 --- a/shell-completion/zsh/_networkctl +++ b/shell-completion/zsh/_networkctl @@ -6,9 +6,16 @@ local -a _networkctl_cmds _networkctl_cmds=( 'list:List existing links' - 'status:Show information about the specified links' - 'lldp:Show Link Layer Discovery Protocol status' - 'label:Show address labels' + 'status:Show information about the specified links' + 'lldp:Show Link Layer Discovery Protocol status' + 'label:Show address labels' + 'delete:Delete virtual netdevs' + 'up:Bring devices up' + 'down:Bring devices down' + 'renew:Renew dynamic configurations' + 'forcerenew:Trigger DHCP reconfiguration of all connected clients' + 'reconfigure:Reconfigure interfaces' + 'reload:Reload .network and .netdev files' ) if (( CURRENT == 1 )); then _describe -t commands 'networkctl command' _networkctl_cmds @@ -16,16 +23,19 @@ local curcontext="$curcontext" local -a _links cmd="${${_networkctl_cmds[(r)$words[1]:*]%%:*}}" - if [ $cmd = "status" ]; then - _links=( "${(foa)$(networkctl list --no-legend | awk 'BEGIN{OFS=":"} {sub(/[[ \t]+/, ""); print $2,$0}' 2>/dev/null)}" ) - if [[ -n "$_links" ]]; then - _describe -t links 'links' _links - else - _message "no links" - fi - else - _message "no more options" - fi + case $cmd in + (list|status|up|down|lldp|delete|renew|forcerenew|reconfigure) + _links=( "${(foa)$(networkctl list --no-legend | awk 'BEGIN{OFS=":"} {sub(/[[ \t]+/, ""); print $2,$0}' 2>/dev/null)}" ) + if [[ -n "$_links" ]]; then + _describe -t links 'links' _links + else + _message "no links" + fi + ;; + *) + _message "no more options" + ;; + esac fi } diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 9d64e3c76..f0473234d 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -1576,7 +1576,7 @@ static int dump_exit_status(int argc, char *argv[], void *userdata) { status = exit_status_from_string(argv[i]); if (status < 0) - return log_error_errno(r, "Invalid exit status \"%s\": %m", argv[i]); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid exit status \"%s\".", argv[i]); assert(status >= 0 && (size_t) status < ELEMENTSOF(exit_status_mappings)); r = table_add_many(table, diff --git a/src/basic/missing_capability.h b/src/basic/missing_capability.h index dd6bccd87..b31e73639 100644 --- a/src/basic/missing_capability.h +++ b/src/basic/missing_capability.h @@ -26,3 +26,11 @@ #undef CAP_LAST_CAP #define CAP_LAST_CAP CAP_BPF #endif + +/* 124ea650d3072b005457faed69909221c2905a1f (5.9) */ +#ifndef CAP_CHECKPOINT_RESTORE +#define CAP_CHECKPOINT_RESTORE 40 + +#undef CAP_LAST_CAP +#define CAP_LAST_CAP CAP_CHECKPOINT_RESTORE +#endif diff --git a/src/basic/path-util.c b/src/basic/path-util.c index d3b497823..7b0863f74 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -637,16 +637,27 @@ int find_binary(const char *name, char **ret) { if (!j) return -ENOMEM; - if (is_dir(j, true)) - continue; - if (access(j, X_OK) >= 0) { - /* Found it! */ + _cleanup_free_ char *with_dash; - if (ret) - *ret = path_simplify(TAKE_PTR(j), false); + with_dash = strjoin(j, "/"); + if (!with_dash) + return -ENOMEM; - return 0; + /* If this passes, it must be a directory, and so should be skipped. */ + if (access(with_dash, X_OK) >= 0) + continue; + + /** + * We can't just `continue` inverting this case, since we need to update last_error. + */ + if (errno == ENOTDIR) { + /* Found it! */ + if (ret) + *ret = path_simplify(TAKE_PTR(j), false); + + return 0; + } } /* PATH entries which we don't have access to are ignored, as per tradition. */ diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h index 7f799ede3..fe4325688 100644 --- a/src/basic/siphash24.h +++ b/src/basic/siphash24.h @@ -6,6 +6,8 @@ #include #include +#include "time-util.h" + struct siphash { uint64_t v0; uint64_t v1; @@ -25,6 +27,10 @@ static inline void siphash24_compress_boolean(bool in, struct siphash *state) { siphash24_compress(&i, sizeof i, state); } +static inline void siphash24_compress_usec_t(usec_t in, struct siphash *state) { + siphash24_compress(&in, sizeof in, state); +} + static inline void siphash24_compress_string(const char *in, struct siphash *state) { if (!in) return; diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index a1100d506..f32652633 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -4943,7 +4943,7 @@ int unit_load_fragment(Unit *u) { /* Possibly rebuild the fragment map to catch new units */ r = unit_file_build_name_map(&u->manager->lookup_paths, - &u->manager->unit_cache_mtime, + &u->manager->unit_cache_timestamp_hash, &u->manager->unit_id_map, &u->manager->unit_name_map, &u->manager->unit_path_cache); diff --git a/src/core/main.c b/src/core/main.c index 4a376976e..9a834a875 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -32,6 +32,7 @@ #include "dbus-manager.h" #include "dbus.h" #include "def.h" +#include "dev-setup.h" #include "efi-random.h" #include "efivars.h" #include "emergency-action.h" @@ -53,6 +54,7 @@ #include "loopback-setup.h" #include "machine-id-setup.h" #include "manager.h" +#include "mkdir.h" #include "mount-setup.h" #include "os-util.h" #include "pager.h" @@ -2073,6 +2075,20 @@ static int initialize_runtime( if (r < 0) log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", arg_watchdog_device); } + } else { + _cleanup_free_ char *p = NULL; + + /* Create the runtime directory and place the inaccessible device nodes there, if we run in + * user mode. In system mode mount_setup() already did that. */ + + r = xdg_user_runtime_dir(&p, "/systemd"); + if (r < 0) { + *ret_error_message = "$XDG_RUNTIME_DIR is not set"; + return log_emergency_errno(r, "Failed to determine $XDG_RUNTIME_DIR path: %m"); + } + + (void) mkdir_p(p, 0755); + (void) make_inaccessible_nodes(p, UID_INVALID, GID_INVALID); } if (arg_timer_slack_nsec != NSEC_INFINITY) diff --git a/src/core/manager.c b/src/core/manager.c index 41e0d7373..6b7908fc6 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -703,7 +703,7 @@ static void manager_free_unit_name_maps(Manager *m) { m->unit_id_map = hashmap_free(m->unit_id_map); m->unit_name_map = hashmap_free(m->unit_name_map); m->unit_path_cache = set_free(m->unit_path_cache); - m->unit_cache_mtime = 0; + m->unit_cache_timestamp_hash = 0; } static int manager_setup_run_queue(Manager *m) { @@ -1937,19 +1937,22 @@ unsigned manager_dispatch_load_queue(Manager *m) { return n; } -bool manager_unit_file_maybe_loadable_from_cache(Unit *u) { +bool manager_unit_cache_should_retry_load(Unit *u) { assert(u); + /* Automatic reloading from disk only applies to units which were not found sometime in the past, and + * the not-found stub is kept pinned in the unit graph by dependencies. For units that were + * previously loaded, we don't do automatic reloading, and daemon-reload is necessary to update. */ if (u->load_state != UNIT_NOT_FOUND) return false; - if (u->manager->unit_cache_mtime == 0) - return false; - - if (u->manager->unit_cache_mtime > u->fragment_loadtime) + /* The cache has been updated since the last time we tried to load the unit. There might be new + * fragment paths to read. */ + if (u->manager->unit_cache_timestamp_hash != u->fragment_not_found_timestamp_hash) return true; - return !lookup_paths_mtime_good(&u->manager->lookup_paths, u->manager->unit_cache_mtime); + /* The cache needs to be updated because there are modifications on disk. */ + return !lookup_paths_timestamp_hash_same(&u->manager->lookup_paths, u->manager->unit_cache_timestamp_hash, NULL); } int manager_load_unit_prepare( @@ -1998,10 +2001,10 @@ int manager_load_unit_prepare( * first if anything in the usual paths was modified since the last time * the cache was loaded. Also check if the last time an attempt to load the * unit was made was before the most recent cache refresh, so that we know - * we need to try again - even if the cache is current, it might have been + * we need to try again — even if the cache is current, it might have been * updated in a different context before we had a chance to retry loading * this particular unit. */ - if (manager_unit_file_maybe_loadable_from_cache(ret)) + if (manager_unit_cache_should_retry_load(ret)) ret->load_state = UNIT_STUB; else { *_ret = ret; diff --git a/src/core/manager.h b/src/core/manager.h index 81b0c13a9..6b29d48fa 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -233,7 +233,7 @@ struct Manager { Hashmap *unit_id_map; Hashmap *unit_name_map; Set *unit_path_cache; - usec_t unit_cache_mtime; + uint64_t unit_cache_timestamp_hash; char **transient_environment; /* The environment, as determined from config files, kernel cmdline and environment generators */ char **client_environment; /* Environment variables created by clients through the bus API */ @@ -463,7 +463,7 @@ Unit *manager_get_unit(Manager *m, const char *name); int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j); -bool manager_unit_file_maybe_loadable_from_cache(Unit *u); +bool manager_unit_cache_should_retry_load(Unit *u); int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret); int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret); int manager_load_startable_unit_or_warn(Manager *m, const char *name, const char *path, Unit **ret); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index feb88f3e6..39662ebb0 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -536,8 +536,17 @@ int mount_setup(bool loaded_policy, bool leave_propagation) { (void) mkdir_label("/run/systemd/system", 0755); /* Also create /run/systemd/inaccessible nodes, so that we always have something to mount - * inaccessible nodes from. */ - (void) make_inaccessible_nodes(NULL, UID_INVALID, GID_INVALID); + * inaccessible nodes from. If we run in a container the host might have created these for us already + * in /run/host/inaccessible/. Use those if we can, since tht way we likely get access to block/char + * device nodes that are inaccessible, and if userns is used to nodes that are on mounts owned by a + * userns outside the container and thus nicely read-only and not remountable. */ + if (access("/run/host/inaccessible/", F_OK) < 0) { + if (errno != ENOENT) + log_debug_errno(errno, "Failed to check if /run/host/inaccessible exists, ignoring: %m"); + + (void) make_inaccessible_nodes("/run/systemd", UID_INVALID, GID_INVALID); + } else + (void) symlink("../host/inaccessible", "/run/systemd/inaccessible"); return 0; } diff --git a/src/core/transaction.c b/src/core/transaction.c index 958243bc9..0fa419787 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -960,12 +960,13 @@ int transaction_add_job_and_dependencies( * first if anything in the usual paths was modified since the last time * the cache was loaded. Also check if the last time an attempt to load the * unit was made was before the most recent cache refresh, so that we know - * we need to try again - even if the cache is current, it might have been + * we need to try again — even if the cache is current, it might have been * updated in a different context before we had a chance to retry loading * this particular unit. + * * Given building up the transaction is a synchronous operation, attempt * to load the unit immediately. */ - if (r < 0 && manager_unit_file_maybe_loadable_from_cache(unit)) { + if (r < 0 && manager_unit_cache_should_retry_load(unit)) { sd_bus_error_free(e); unit->load_state = UNIT_STUB; r = unit_load(unit); diff --git a/src/core/unit.c b/src/core/unit.c index 2c09def06..1bda56856 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1674,18 +1674,18 @@ int unit_load(Unit *u) { return 0; fail: - /* We convert ENOEXEC errors to the UNIT_BAD_SETTING load state here. Configuration parsing code should hence - * return ENOEXEC to ensure units are placed in this state after loading */ + /* We convert ENOEXEC errors to the UNIT_BAD_SETTING load state here. Configuration parsing code + * should hence return ENOEXEC to ensure units are placed in this state after loading. */ u->load_state = u->load_state == UNIT_STUB ? UNIT_NOT_FOUND : r == -ENOEXEC ? UNIT_BAD_SETTING : UNIT_ERROR; u->load_error = r; - /* Record the last time we tried to load the unit, so that if the cache gets updated between now - * and the next time an attempt is made to load this unit, we know we need to check again */ + /* Record the timestamp on the cache, so that if the cache gets updated between now and the next time + * an attempt is made to load this unit, we know we need to check again. */ if (u->load_state == UNIT_NOT_FOUND) - u->fragment_loadtime = now(CLOCK_REALTIME); + u->fragment_not_found_timestamp_hash = u->manager->unit_cache_timestamp_hash; unit_add_to_dbus_queue(u); unit_add_to_gc_queue(u); diff --git a/src/core/unit.h b/src/core/unit.h index d5e4c6598..4130cd50a 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -136,7 +136,7 @@ typedef struct Unit { char *source_path; /* if converted, the source file */ char **dropin_paths; - usec_t fragment_loadtime; + usec_t fragment_not_found_timestamp_hash; usec_t fragment_mtime; usec_t source_mtime; usec_t dropin_mtime; diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 8b052dac2..10bbf1018 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -77,7 +77,7 @@ enum { META_ARGV_UID, /* %u: as seen in the initial user namespace */ META_ARGV_GID, /* %g: as seen in the initial user namespace */ META_ARGV_SIGNAL, /* %s: number of signal causing dump */ - META_ARGV_TIMESTAMP, /* %t: time of dump, expressed as seconds since the Epoch */ + META_ARGV_TIMESTAMP, /* %t: time of dump, expressed as seconds since the Epoch (we expand this to µs granularity) */ META_ARGV_RLIMIT, /* %c: core file size soft resource limit */ META_ARGV_HOSTNAME, /* %h: hostname */ _META_ARGV_MAX, @@ -311,7 +311,7 @@ static int make_filename(const Context *context, char **ret) { return -ENOMEM; if (asprintf(ret, - "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s000000", + "/var/lib/systemd/coredump/core.%s.%s." SD_ID128_FORMAT_STR ".%s.%s", c, u, SD_ID128_FORMAT_VAL(boot), @@ -1016,8 +1016,11 @@ static int send_iovec(const struct iovec_wrapper *iovw, int input_fd) { return 0; } -static int gather_pid_metadata_from_argv(struct iovec_wrapper *iovw, Context *context, - int argc, char **argv) { +static int gather_pid_metadata_from_argv( + struct iovec_wrapper *iovw, + Context *context, + int argc, char **argv) { + _cleanup_free_ char *free_timestamp = NULL; int i, r, signo; char *t; @@ -1035,6 +1038,7 @@ static int gather_pid_metadata_from_argv(struct iovec_wrapper *iovw, Context *co t = argv[i]; switch (i) { + case META_ARGV_TIMESTAMP: /* The journal fields contain the timestamp padded with six * zeroes, so that the kernel-supplied 1s granularity timestamps @@ -1044,12 +1048,14 @@ static int gather_pid_metadata_from_argv(struct iovec_wrapper *iovw, Context *co if (!t) return log_oom(); break; + case META_ARGV_SIGNAL: /* For signal, record its pretty name too */ if (safe_atoi(argv[i], &signo) >= 0 && SIGNAL_VALID(signo)) (void) iovw_put_string_field(iovw, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo)); break; + default: break; } diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index a3f442518..c9fc8dd5c 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -94,7 +94,7 @@ static bool press_any_key(void) { static void print_welcome(void) { _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL; static bool done = false; - const char *pn; + const char *pn, *ac; int r; if (!arg_welcome) @@ -113,9 +113,10 @@ static void print_welcome(void) { "Failed to read os-release file, ignoring: %m"); pn = isempty(pretty_name) ? "Linux" : pretty_name; + ac = isempty(ansi_color) ? "0" : ansi_color; if (colors_enabled()) - printf("\nWelcome to your new installation of \x1B[%sm%s\x1B[0m!\n", ansi_color, pn); + printf("\nWelcome to your new installation of \x1B[%sm%s\x1B[0m!\n", ac, pn); else printf("\nWelcome to your new installation of %s!\n", pn); diff --git a/src/home/homed-home.c b/src/home/homed-home.c index f0c157cb7..35b325413 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -1042,7 +1042,7 @@ static int home_start_work(Home *h, const char *verb, UserRecord *hr, UserRecord homework = getenv("SYSTEMD_HOMEWORK_PATH") ?: SYSTEMD_HOMEWORK_PATH; execl(homework, homework, verb, NULL); - log_error_errno(errno, "Failed to invoke " SYSTEMD_HOMEWORK_PATH ": %m"); + log_error_errno(errno, "Failed to invoke %s: %m", homework); _exit(EXIT_FAILURE); } diff --git a/src/login/logind.h b/src/login/logind.h index e64ecce8e..272fcfecd 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include "sd-bus.h" #include "sd-device.h" diff --git a/src/login/user-runtime-dir.c b/src/login/user-runtime-dir.c index 8ba916f05..03c60f90b 100644 --- a/src/login/user-runtime-dir.c +++ b/src/login/user-runtime-dir.c @@ -88,7 +88,8 @@ static int user_mkdir_runtime_path( goto fail; } - log_debug_errno(errno, "Failed to mount per-user tmpfs directory %s.\n" + log_debug_errno(errno, + "Failed to mount per-user tmpfs directory %s.\n" "Assuming containerized execution, ignoring: %m", runtime_path); r = chmod_and_chown(runtime_path, 0700, uid, gid); @@ -103,8 +104,6 @@ static int user_mkdir_runtime_path( log_warning_errno(r, "Failed to fix label of \"%s\", ignoring: %m", runtime_path); } - /* Set up inaccessible nodes now so they're available if we decide to use them with user namespaces. */ - (void) make_inaccessible_nodes(runtime_path, uid, gid); return 0; fail: diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 48182e61d..758b85d55 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -2794,7 +2794,7 @@ static int networkctl_main(int argc, char *argv[]) { { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links }, { "status", VERB_ANY, VERB_ANY, 0, link_status }, { "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status }, - { "label", VERB_ANY, VERB_ANY, 0, list_address_labels }, + { "label", 1, 1, 0, list_address_labels }, { "delete", 2, VERB_ANY, 0, link_delete }, { "up", 2, VERB_ANY, 0, link_up_down }, { "down", 2, VERB_ANY, 0, link_up_down }, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index d671284b0..d969995ea 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -992,7 +992,8 @@ static int dhcp6_update_address( addr->cinfo.ifa_valid = lifetime_valid; (void) in_addr_to_string(addr->family, &addr->in_addr, &buffer); - log_link_info(link, "DHCPv6 address %s/%u timeout preferred %d valid %d", + log_link_full(link, set_contains(link->dhcp6_addresses, addr) ? LOG_DEBUG : LOG_INFO, 0, + "DHCPv6 address %s/%u timeout preferred %d valid %d", strna(buffer), addr->prefixlen, lifetime_preferred, lifetime_valid); r = address_configure(addr, link, dhcp6_address_handler, true, &ret); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index eb7c3321a..43712565c 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3531,7 +3531,7 @@ static int outer_child( (void) dev_setup(directory, arg_uid_shift, arg_uid_shift); - p = prefix_roota(directory, "/run"); + p = prefix_roota(directory, "/run/host"); (void) make_inaccessible_nodes(p, arg_uid_shift, arg_uid_shift); r = setup_pts(directory); diff --git a/src/partition/makefs.c b/src/partition/makefs.c index 97f50c903..33ede22a6 100644 --- a/src/partition/makefs.c +++ b/src/partition/makefs.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include +#include #include #include #include diff --git a/src/partition/test-repart.sh b/src/partition/test-repart.sh index bfb9bcb4c..a0fd6aa0e 100755 --- a/src/partition/test-repart.sh +++ b/src/partition/test-repart.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -ex +[[ -f /dev/loop-control ]] || exit 77 + repart=$1 test -x $repart diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index e23ea273e..016ff0136 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -364,6 +364,14 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { dns_transaction_gc(t); } +static void dns_transaction_complete_errno(DnsTransaction *t, int error) { + assert(t); + assert(error != 0); + + t->answer_errno = abs(error); + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); +} + static int dns_transaction_pick_server(DnsTransaction *t) { DnsServer *server; @@ -415,10 +423,8 @@ static void dns_transaction_retry(DnsTransaction *t, bool next_server) { dns_scope_next_dns_server(t->scope); r = dns_transaction_go(t); - if (r < 0) { - t->answer_errno = -r; - dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); - } + if (r < 0) + dns_transaction_complete_errno(t, r); } static int dns_transaction_maybe_restart(DnsTransaction *t) { @@ -466,10 +472,8 @@ static void on_transaction_stream_error(DnsTransaction *t, int error) { dns_transaction_retry(t, true); return; } - if (error != 0) { - t->answer_errno = error; - dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); - } + if (error != 0) + dns_transaction_complete_errno(t, error); } static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) { @@ -836,8 +840,7 @@ static void dns_transaction_process_dnssec(DnsTransaction *t) { return; fail: - t->answer_errno = -r; - dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); + dns_transaction_complete_errno(t, r); } static int dns_transaction_has_positive_answer(DnsTransaction *t, DnsAnswerFlags *flags) { @@ -1169,8 +1172,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { return; fail: - t->answer_errno = -r; - dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); + dns_transaction_complete_errno(t, r); } static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { @@ -1196,8 +1198,7 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use return 0; } if (r < 0) { - dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); - t->answer_errno = -r; + dns_transaction_complete_errno(t, r); return 0; } if (r == 0) diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 3d0b93910..a727b98e7 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -237,6 +237,9 @@ int ask_password_plymouth( assert(ret); + if (!message) + message = "Password:"; + if (flag_file) { notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); if (notify < 0) diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c index 6e57e2a99..528440b82 100644 --- a/src/shared/dev-setup.c +++ b/src/shared/dev-setup.c @@ -57,7 +57,7 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid) { } int make_inaccessible_nodes( - const char *runtime_dir, + const char *parent_dir, uid_t uid, gid_t gid) { @@ -65,28 +65,26 @@ int make_inaccessible_nodes( const char *name; mode_t mode; } table[] = { - { "/systemd", S_IFDIR | 0755 }, - { "/systemd/inaccessible", S_IFDIR | 0000 }, - { "/systemd/inaccessible/reg", S_IFREG | 0000 }, - { "/systemd/inaccessible/dir", S_IFDIR | 0000 }, - { "/systemd/inaccessible/fifo", S_IFIFO | 0000 }, - { "/systemd/inaccessible/sock", S_IFSOCK | 0000 }, + { "inaccessible", S_IFDIR | 0755 }, + { "inaccessible/reg", S_IFREG | 0000 }, + { "inaccessible/dir", S_IFDIR | 0000 }, + { "inaccessible/fifo", S_IFIFO | 0000 }, + { "inaccessible/sock", S_IFSOCK | 0000 }, /* The following two are likely to fail if we lack the privs for it (for example in an userns * environment, if CAP_SYS_MKNOD is missing, or if a device node policy prohibit major/minor of 0 * device nodes to be created). But that's entirely fine. Consumers of these files should carry * fallback to use a different node then, for example /inaccessible/sock, which is close * enough in behaviour and semantics for most uses. */ - { "/systemd/inaccessible/chr", S_IFCHR | 0000 }, - { "/systemd/inaccessible/blk", S_IFBLK | 0000 }, + { "inaccessible/chr", S_IFCHR | 0000 }, + { "inaccessible/blk", S_IFBLK | 0000 }, }; _cleanup_umask_ mode_t u; - size_t i; int r; - if (!runtime_dir) - runtime_dir = "/run"; + if (!parent_dir) + parent_dir = "/run/systemd"; u = umask(0000); @@ -95,10 +93,10 @@ int make_inaccessible_nodes( * to lock down these nodes as much as we can, but otherwise try to match them as closely as possible with the * underlying file, i.e. in the best case we offer the same node type as the underlying node. */ - for (i = 0; i < ELEMENTSOF(table); i++) { + for (size_t i = 0; i < ELEMENTSOF(table); i++) { _cleanup_free_ char *path = NULL; - path = path_join(runtime_dir, table[i].name); + path = path_join(parent_dir, table[i].name); if (!path) return log_oom(); @@ -107,8 +105,7 @@ int make_inaccessible_nodes( else r = mknod_label(path, table[i].mode, makedev(0, 0)); if (r < 0) { - if (r != -EEXIST) - log_debug_errno(r, "Failed to create '%s', ignoring: %m", path); + log_debug_errno(r, "Failed to create '%s', ignoring: %m", path); continue; } diff --git a/src/shared/dev-setup.h b/src/shared/dev-setup.h index 72b90ec4d..437c0e96e 100644 --- a/src/shared/dev-setup.h +++ b/src/shared/dev-setup.h @@ -5,4 +5,4 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid); -int make_inaccessible_nodes(const char *root, uid_t uid, gid_t gid); +int make_inaccessible_nodes(const char *parent_dir, uid_t uid, gid_t gid); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 24be6de6c..d3f10b396 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -51,6 +51,9 @@ #include "user-util.h" #include "xattr-util.h" +/* how many times to wait for the device nodes to appear */ +#define N_DEVICE_NODE_LIST_ATTEMPTS 10 + int probe_filesystem(const char *node, char **ret_fstype) { /* Try to find device content type and return it in *ret_fstype. If nothing is found, * 0/NULL will be returned. -EUCLEAN will be returned for ambiguous results, and an @@ -151,9 +154,6 @@ static int enumerator_for_parent(sd_device *d, sd_device_enumerator **ret) { return 0; } -/* how many times to wait for the device nodes to appear */ -#define N_DEVICE_NODE_LIST_ATTEMPTS 10 - static int wait_for_partitions_to_appear( int fd, sd_device *d, diff --git a/src/shared/group-record-nss.c b/src/shared/group-record-nss.c index 5c4fae865..b018a46e1 100644 --- a/src/shared/group-record-nss.c +++ b/src/shared/group-record-nss.c @@ -37,7 +37,7 @@ int nss_group_to_group_record( g->gid = grp->gr_gid; if (sgrp) { - if (hashed_password_valid(sgrp->sg_passwd)) { + if (looks_like_hashed_password(sgrp->sg_passwd)) { g->hashed_password = strv_new(sgrp->sg_passwd); if (!g->hashed_password) return -ENOMEM; diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c index f41685ae4..bf6605508 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -74,13 +74,18 @@ int make_salt(char **ret) { #endif } -bool hashed_password_valid(const char *s) { - - /* Returns true if the specified string is a 'valid' hashed UNIX password, i.e. if starts with '$' or - * with '!$' (the latter being a valid, yet locked password). */ - - if (isempty(s)) +bool looks_like_hashed_password(const char *s) { + /* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists + * various hashing methods. We only reject (return false) strings which are documented to have + * different meanings. + * + * In particular, we allow locked passwords, i.e. strings starting with "!", including just "!", + * i.e. the locked empty password. See also fc58c0c7bf7e4f525b916e3e5be0de2307fef04e. + */ + if (!s) return false; - return STARTSWITH_SET(s, "$", "!$"); + s += strspn(s, "!"); /* Skip (possibly duplicated) locking prefix */ + + return !STR_IN_SET(s, "x", "*"); } diff --git a/src/shared/libcrypt-util.h b/src/shared/libcrypt-util.h index 93f0e13ff..8a860ceb0 100644 --- a/src/shared/libcrypt-util.h +++ b/src/shared/libcrypt-util.h @@ -19,4 +19,4 @@ int make_salt(char **ret); -bool hashed_password_valid(const char *s); +bool looks_like_hashed_password(const char *s); diff --git a/src/shared/unit-file.c b/src/shared/unit-file.c index ed4affd66..0f030ae43 100644 --- a/src/shared/unit-file.c +++ b/src/shared/unit-file.c @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include "sd-id128.h" + #include "dirent-util.h" #include "fd-util.h" #include "fs-util.h" @@ -199,9 +201,14 @@ static bool lookup_paths_mtime_exclude(const LookupPaths *lp, const char *path) streq_ptr(path, lp->runtime_control); } -bool lookup_paths_mtime_good(const LookupPaths *lp, usec_t mtime) { - char **dir; +#define HASH_KEY SD_ID128_MAKE(4e,86,1b,e3,39,b3,40,46,98,5d,b8,11,34,8f,c3,c1) +bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_hash, uint64_t *ret_new) { + struct siphash state; + + siphash24_init(&state, HASH_KEY.bytes); + + char **dir; STRV_FOREACH(dir, (char**) lp->search_path) { struct stat st; @@ -217,18 +224,20 @@ bool lookup_paths_mtime_good(const LookupPaths *lp, usec_t mtime) { continue; } - if (timespec_load(&st.st_mtim) > mtime) { - log_debug_errno(errno, "Unit dir %s has changed, need to update cache.", *dir); - return false; - } + siphash24_compress_usec_t(timespec_load(&st.st_mtim), &state); } - return true; + uint64_t updated = siphash24_finalize(&state); + if (ret_new) + *ret_new = updated; + if (updated != timestamp_hash) + log_debug("Modification times have changed, need to update cache."); + return updated == timestamp_hash; } int unit_file_build_name_map( const LookupPaths *lp, - usec_t *cache_mtime, + uint64_t *cache_timestamp_hash, Hashmap **unit_ids_map, Hashmap **unit_names_map, Set **path_cache) { @@ -245,14 +254,18 @@ int unit_file_build_name_map( _cleanup_hashmap_free_ Hashmap *ids = NULL, *names = NULL; _cleanup_set_free_free_ Set *paths = NULL; + uint64_t timestamp_hash; char **dir; int r; - usec_t mtime = 0; - /* Before doing anything, check if the mtime that was passed is still valid. If - * yes, do nothing. If *cache_time == 0, always build the cache. */ - if (cache_mtime && *cache_mtime > 0 && lookup_paths_mtime_good(lp, *cache_mtime)) - return 0; + /* Before doing anything, check if the timestamp hash that was passed is still valid. + * If yes, do nothing. */ + if (cache_timestamp_hash && + lookup_paths_timestamp_hash_same(lp, *cache_timestamp_hash, ×tamp_hash)) + return 0; + + /* The timestamp hash is now set based on the mtimes from before when we start reading files. + * If anything is modified concurrently, we'll consider the cache outdated. */ if (path_cache) { paths = set_new(&path_hash_ops_free); @@ -263,7 +276,6 @@ int unit_file_build_name_map( STRV_FOREACH(dir, (char**) lp->search_path) { struct dirent *de; _cleanup_closedir_ DIR *d = NULL; - struct stat st; d = opendir(*dir); if (!d) { @@ -272,13 +284,6 @@ int unit_file_build_name_map( continue; } - /* Determine the latest lookup path modification time */ - if (fstat(dirfd(d), &st) < 0) - return log_error_errno(errno, "Failed to fstat %s: %m", *dir); - - if (!lookup_paths_mtime_exclude(lp, *dir)) - mtime = MAX(mtime, timespec_load(&st.st_mtim)); - FOREACH_DIRENT_ALL(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) { char *filename; _cleanup_free_ char *_filename_free = NULL, *simplified = NULL; @@ -417,8 +422,8 @@ int unit_file_build_name_map( basename(dst), src); } - if (cache_mtime) - *cache_mtime = mtime; + if (cache_timestamp_hash) + *cache_timestamp_hash = timestamp_hash; hashmap_free_and_replace(*unit_ids_map, ids); hashmap_free_and_replace(*unit_names_map, names); diff --git a/src/shared/unit-file.h b/src/shared/unit-file.h index d6d041d71..d36bb07cc 100644 --- a/src/shared/unit-file.h +++ b/src/shared/unit-file.h @@ -43,19 +43,19 @@ bool unit_type_may_template(UnitType type) _const_; int unit_symlink_name_compatible(const char *symlink, const char *target, bool instance_propagation); int unit_validate_alias_symlink_and_warn(const char *filename, const char *target); -bool lookup_paths_mtime_good(const LookupPaths *lp, usec_t mtime); +bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_hash, uint64_t *ret_new); int unit_file_build_name_map( const LookupPaths *lp, - usec_t *ret_time, - Hashmap **ret_unit_ids_map, - Hashmap **ret_unit_names_map, - Set **ret_path_cache); + uint64_t *cache_timestamp_hash, + Hashmap **unit_ids_map, + Hashmap **unit_names_map, + Set **path_cache); int unit_file_find_fragment( Hashmap *unit_ids_map, Hashmap *unit_name_map, const char *unit_name, const char **ret_fragment_path, - Set **names); + Set **ret_names); const char* runlevel_to_target(const char *rl); diff --git a/src/shared/user-record-nss.c b/src/shared/user-record-nss.c index b27a12c55..b4c35b8a5 100644 --- a/src/shared/user-record-nss.c +++ b/src/shared/user-record-nss.c @@ -66,7 +66,7 @@ int nss_passwd_to_user_record( hr->uid = pwd->pw_uid; hr->gid = pwd->pw_gid; - if (spwd && hashed_password_valid(spwd->sp_pwdp)) { + if (spwd && looks_like_hashed_password(spwd->sp_pwdp)) { strv_free_erase(hr->hashed_password); hr->hashed_password = strv_new(spwd->sp_pwdp); if (!hr->hashed_password) diff --git a/src/shared/varlink.c b/src/shared/varlink.c index be3559dc1..0278591b1 100644 --- a/src/shared/varlink.c +++ b/src/shared/varlink.c @@ -579,11 +579,17 @@ static int varlink_parse_message(Varlink *v) { sz = e - begin + 1; - varlink_log(v, "New incoming message: %s", begin); + varlink_log(v, "New incoming message: %s", begin); /* FIXME: should we output the whole message here before validation? + * This may produce a non-printable journal entry if the message + * is invalid. We may also expose privileged information. */ r = json_parse(begin, 0, &v->current, NULL, NULL); - if (r < 0) - return r; + if (r < 0) { + /* If we encounter a parse failure flush all data. We cannot possibly recover from this, + * hence drop all buffered data now. */ + v->input_buffer_index = v->input_buffer_size = v->input_buffer_unscanned = 0; + return varlink_log_errno(v, r, "Failed to parse JSON: %m"); + } v->input_buffer_size -= sz; diff --git a/src/test/test-dev-setup.c b/src/test/test-dev-setup.c index 038484e47..11196cd4d 100644 --- a/src/test/test-dev-setup.c +++ b/src/test/test-dev-setup.c @@ -3,6 +3,7 @@ #include "capability-util.h" #include "dev-setup.h" #include "fs-util.h" +#include "mkdir.h" #include "path-util.h" #include "rm-rf.h" #include "tmpfile-util.h" @@ -17,8 +18,8 @@ int main(int argc, char *argv[]) { assert_se(mkdtemp_malloc("/tmp/test-dev-setupXXXXXX", &p) >= 0); - f = prefix_roota(p, "/run"); - assert_se(mkdir(f, 0755) >= 0); + f = prefix_roota(p, "/run/systemd"); + assert_se(mkdir_p(f, 0755) >= 0); assert_se(make_inaccessible_nodes(f, 1, 1) >= 0); diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 4371da478..87779a4dd 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -47,7 +47,7 @@ static enum { ACTION_LIST, ACTION_QUERY, ACTION_WATCH, - ACTION_WALL + ACTION_WALL, } arg_action = ACTION_QUERY; static bool arg_plymouth = false; @@ -143,8 +143,7 @@ static int agent_ask_password_tty( const char *flag_file, char ***ret) { - int tty_fd = -1; - int r; + int tty_fd = -1, r; if (arg_console) { const char *con = arg_device ?: "/dev/console"; @@ -166,7 +165,7 @@ static int agent_ask_password_tty( release_terminal(); } - return 0; + return r; } static int process_one_password_file(const char *filename) { @@ -210,7 +209,7 @@ static int process_one_password_file(const char *filename) { switch (arg_action) { case ACTION_LIST: - printf("'%s' (PID %u)\n", message, pid); + printf("'%s' (PID %u)\n", strna(message), pid); return 0; case ACTION_WALL: { @@ -219,7 +218,7 @@ static int process_one_password_file(const char *filename) { if (asprintf(&wall, "Password entry required for \'%s\' (PID %u).\r\n" "Please enter password with the systemd-tty-ask-password-agent tool.", - message, + strna(message), pid) < 0) return log_oom(); @@ -233,7 +232,7 @@ static int process_one_password_file(const char *filename) { if (access(socket_name, W_OK) < 0) { if (arg_action == ACTION_QUERY) - log_info("Not querying '%s' (PID %u), lacking privileges.", message, pid); + log_info("Not querying '%s' (PID %u), lacking privileges.", strna(message), pid); return 0; } @@ -246,7 +245,6 @@ static int process_one_password_file(const char *filename) { r = ask_password_plymouth(message, not_after, flags, filename, &passwords); else r = agent_ask_password_tty(message, not_after, flags, filename, &passwords); - if (r < 0) { /* If the query went away, that's OK */ if (IN_SET(r, -ETIME, -ENOENT)) @@ -262,8 +260,7 @@ static int process_one_password_file(const char *filename) { if (r < 0) return log_error_errno(r, "Failed to send: %m"); break; - } - } + }} return 0; } @@ -713,7 +710,7 @@ static int run(int argc, char *argv[]) { (void) release_terminal(); } - return process_and_watch_password_files(arg_action != ACTION_QUERY); + return process_and_watch_password_files(!IN_SET(arg_action, ACTION_QUERY, ACTION_LIST)); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index c973ee9c0..c6836cda0 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -685,7 +685,8 @@ static int parse_argv(int argc, char *argv[]) { else if (streq(optarg, "help")) { puts("classic\n" "friendly\n" - "json"); + "json\n" + "table"); return 0; } else return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid --output= mode: %s", optarg); diff --git a/units/meson.build b/units/meson.build index aa2ed115e..275daad3f 100644 --- a/units/meson.build +++ b/units/meson.build @@ -148,6 +148,7 @@ units = [ ['tmp.mount', '', 'local-fs.target.wants/'], ['umount.target', ''], + ['usb-gadget.target', ''], ['user.slice', ''], ['var-lib-machines.mount', 'ENABLE_MACHINED', 'remote-fs.target.wants/ machines.target.wants/'],