diff --git a/TODO b/TODO index 58fdc45e1..63525e950 100644 --- a/TODO +++ b/TODO @@ -581,6 +581,9 @@ Features: * sd-bus: add vtable flag, that may be used to request client creds implicitly and asynchronously before dispatching the operation +* sd-bus: parse addresses given in sd_bus_set_addresses immediately and not + only when used. Add unit tests. + * make use of ethtool veth peer info in machined, for automatically finding out host-side interface pointing to the container. diff --git a/man/custom-entities.ent.in b/man/custom-entities.ent.in index 03fe05f1b..dc4b242fc 100644 --- a/man/custom-entities.ent.in +++ b/man/custom-entities.ent.in @@ -10,3 +10,4 @@ + diff --git a/man/homectl.xml b/man/homectl.xml index 0724749c0..78b36062e 100644 --- a/man/homectl.xml +++ b/man/homectl.xml @@ -556,10 +556,13 @@ Takes a file system path. Configures where to place the user's home directory. When LUKS2 storage is used refers to the path to the loopback file, otherwise to the path to the home - directory. When unspecified defaults to /home/$USER.home when LUKS storage is - used and /home/$USER.homedir for the other storage mechanisms. Not defined for - the cifs storage mechanism. To use LUKS2 storage on a regular block device (for - example a USB stick) pass the path to the block device here. + directory (which may be in /home/ or any other accessible filesystem). When + unspecified defaults to /home/$USER.home when LUKS storage is used and + /home/$USER.homedir for the other storage mechanisms. Not defined for the + cifs storage mechanism. To use LUKS2 storage on a regular block device (for + example a USB stick) pass the path to the block device here. Specifying the path to a directory here + when using LUKS2 storage is not allowed. Similar, specifying the path to a regular file or device + node is not allowed if any of the other storage backends are used. diff --git a/man/systemd-rc-local-generator.xml b/man/systemd-rc-local-generator.xml index 0e607d0bc..b51f50a1e 100644 --- a/man/systemd-rc-local-generator.xml +++ b/man/systemd-rc-local-generator.xml @@ -1,8 +1,11 @@ - - + + "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [ + +%entities; +]> + systemd-rc-local-generator @@ -16,7 +19,7 @@ systemd-rc-local-generator - Compatibility generator for starting /etc/rc.local during boot + Compatibility generator for starting &RC_LOCAL_PATH; during boot @@ -27,17 +30,17 @@ Description systemd-rc-local-generator is a generator that checks whether - /etc/rc.local exists and is executable, and if it is pulls the - rc-local.service unit into the boot process. This unit is responsible for running this script - during late boot. Note that the script will be run with slightly different semantics than the original System V - version, which was run "last" in the boot process, which is a concept that does not translate to systemd. The - script is run after network.target, but in parallel with most other regular system - services. + &RC_LOCAL_PATH; exists and is executable, and if it is pulls the + rc-local.service unit into the boot process. This unit is responsible for running + this script during late boot. Note that the script will be run with slightly different semantics than the + original System V version, which was run "last" in the boot process, which is a concept that does not + translate to systemd. The script is run after network.target, but in parallel with + most other regular system services. - Support for /etc/rc.local is provided - for compatibility with specific System V systems only. However, it is strongly recommended to avoid making use of - this script today, and instead provide proper unit files with appropriate dependencies for any scripts to run - during the boot process. + Support for &RC_LOCAL_PATH; is provided for compatibility with specific System + V systems only. However, it is strongly recommended to avoid making use of this script today, and instead + provide proper unit files with appropriate dependencies for any scripts to run during the boot process. + Note that the path to the script is set a compile time and varies between distributions. systemd-rc-local-generator implements systemd.generator7. diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml index 32ddb1c6e..32f7814f8 100644 --- a/man/systemd.timer.xml +++ b/man/systemd.timer.xml @@ -335,18 +335,14 @@ RemainAfterElapse= - Takes a boolean argument. If true, an elapsed - timer will stay loaded, and its state remains queryable. If - false, an elapsed timer unit that cannot elapse anymore is - unloaded. Turning this off is particularly useful for - transient timer units that shall disappear after they first - elapse. Note that this setting has an effect on repeatedly - starting a timer unit that only elapses once: if - RemainAfterElapse= is on, it will not be - started again, and is guaranteed to elapse only once. However, - if RemainAfterElapse= is off, it might be - started again if it is already elapsed, and thus be triggered - multiple times. Defaults to + Takes a boolean argument. If true, a timer will stay loaded, and its state remains + queryable even after it elapsed and the associated unit (as configured with Unit=, + see above) deactivated again. If false, an elapsed timer unit that cannot elapse anymore is unloaded + once its associated unit deactivated again. Turning this off is particularly useful for transient + timer units. Note that this setting has an effect when repeatedly starting a timer unit: if + RemainAfterElapse= is on, starting the timer a second time has no effect. However, + if RemainAfterElapse= is off and the timer unit was already unloaded, it can be + started again, and thus the service can be triggered multiple times. Defaults to yes. diff --git a/meson.build b/meson.build index e928b10be..cfb9ffdb8 100644 --- a/meson.build +++ b/meson.build @@ -209,7 +209,7 @@ conf.set_quoted('SYSTEM_CONFIG_UNIT_DIR', join_paths(pkgsysc conf.set_quoted('SYSTEM_DATA_UNIT_PATH', systemunitdir) conf.set_quoted('SYSTEM_SYSVINIT_PATH', sysvinit_path) conf.set_quoted('SYSTEM_SYSVRCND_PATH', sysvrcnd_path) -conf.set_quoted('RC_LOCAL_SCRIPT_PATH_START', get_option('rc-local')) +conf.set_quoted('RC_LOCAL_PATH', get_option('rc-local')) conf.set('ANSI_OK_COLOR', 'ANSI_' + get_option('ok-color').underscorify().to_upper()) @@ -296,7 +296,7 @@ substs.set('CERTIFICATEROOT', get_option('certif substs.set('RANDOM_SEED', join_paths(randomseeddir, 'random-seed')) substs.set('SYSTEM_SYSVINIT_PATH', sysvinit_path) substs.set('SYSTEM_SYSVRCND_PATH', sysvrcnd_path) -substs.set('RC_LOCAL_SCRIPT_PATH_START', get_option('rc-local')) +substs.set('RC_LOCAL_PATH', get_option('rc-local')) substs.set('MEMORY_ACCOUNTING_DEFAULT', memory_accounting_default ? 'yes' : 'no') substs.set('STATUS_UNIT_FORMAT_DEFAULT', status_unit_format_default) substs.set('HIGH_RLIMIT_NOFILE', conf.get('HIGH_RLIMIT_NOFILE')) diff --git a/src/basic/env-file.c b/src/basic/env-file.c index 26470796e..dc92b13a6 100644 --- a/src/basic/env-file.c +++ b/src/basic/env-file.c @@ -209,17 +209,21 @@ static int parse_env_file_internal( case DOUBLE_QUOTE_VALUE_ESCAPE: state = DOUBLE_QUOTE_VALUE; - if (c == '"') { + if (strchr(SHELL_NEED_ESCAPE, c)) { + /* If this is a char that needs escaping, just unescape it. */ if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) return -ENOMEM; - value[n_value++] = '"'; - } else if (!strchr(NEWLINE, c)) { + value[n_value++] = c; + } else if (c != '\n') { + /* If other char than what needs escaping, keep the "\" in place, like the + * real shell does. */ if (!GREEDY_REALLOC(value, value_alloc, n_value+3)) return -ENOMEM; value[n_value++] = '\\'; value[n_value++] = c; } + /* Escaped newlines (aka "continuation lines") are eaten up entirely */ break; case COMMENT: diff --git a/src/basic/linux/update.sh b/src/basic/linux/update.sh index d272ffd29..b0b0cdc94 100755 --- a/src/basic/linux/update.sh +++ b/src/basic/linux/update.sh @@ -3,11 +3,7 @@ set -eu for i in *.h */*.h; do - if [[ $i == 'wireguard.h' ]]; then - curl https://raw.githubusercontent.com/WireGuard/WireGuard/master/src/uapi/$i -o $i - else - curl https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/$i -o $i - fi + curl https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/$i -o $i sed -i -e 's/__user //g' -e '/^#include / d' $i done diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 4b3a4f206..f0d64474c 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -635,6 +635,7 @@ int fd_set_sndbuf(int fd, size_t n, bool increase) { /* SO_SNDBUF above may set to the kernel limit, instead of the requested size. * So, we need to check the actual buffer size here. */ + l = sizeof(value); r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2) return 1; @@ -665,6 +666,7 @@ int fd_set_rcvbuf(int fd, size_t n, bool increase) { /* SO_RCVBUF above may set to the kernel limit, instead of the requested size. * So, we need to check the actual buffer size here. */ + l = sizeof(value); r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); if (r >= 0 && l == sizeof(value) && increase ? (size_t) value >= n*2 : (size_t) value == n*2) return 1; diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 3a80aafcc..1a085ffa6 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -1472,7 +1472,9 @@ static int install_random_seed(const char *esp) { } r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderSystemToken", NULL, NULL, &token_size); - if (r < 0) { + if (r == -ENODATA) + log_debug_errno(r, "LoaderSystemToken EFI variable is invalid (too short?), replacing."); + else if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to test system token validity: %m"); } else { diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index ccb22d5f8..3bb761cc9 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -2396,7 +2396,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hH:M:qj", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hH:M:qjl", options, NULL)) >= 0) switch (c) { diff --git a/src/core/automount.c b/src/core/automount.c index 1f0519876..73f0fb8c7 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -507,8 +507,8 @@ static void automount_trigger_notify(Unit *u, Unit *other) { assert(other); /* Filter out invocations with bogus state */ - if (other->load_state != UNIT_LOADED || other->type != UNIT_MOUNT) - return; + assert(UNIT_IS_LOAD_COMPLETE(other->load_state)); + assert(other->type == UNIT_MOUNT); /* Don't propagate state changes from the mount if we are already down */ if (!IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING)) diff --git a/src/core/path.c b/src/core/path.c index 1c3c28e34..4f4e7100c 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -748,10 +748,23 @@ static void path_trigger_notify(Unit *u, Unit *other) { assert(u); assert(other); - /* Invoked whenever the unit we trigger changes state or gains - * or loses a job */ + /* Invoked whenever the unit we trigger changes state or gains or loses a job */ - if (other->load_state != UNIT_LOADED) + /* Filter out invocations with bogus state */ + assert(UNIT_IS_LOAD_COMPLETE(other->load_state)); + + /* Don't propagate state changes from the triggered unit if we are already down */ + if (!IN_SET(p->state, PATH_WAITING, PATH_RUNNING)) + return; + + /* Propagate start limit hit state */ + if (other->start_limit_hit) { + path_enter_dead(p, PATH_FAILURE_UNIT_START_LIMIT_HIT); + return; + } + + /* Don't propagate anything if there's still a job queued */ + if (other->job) return; if (p->state == PATH_RUNNING && @@ -790,6 +803,7 @@ static const char* const path_result_table[_PATH_RESULT_MAX] = { [PATH_SUCCESS] = "success", [PATH_FAILURE_RESOURCES] = "resources", [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult); diff --git a/src/core/path.h b/src/core/path.h index 9e2836535..4043650fe 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -45,6 +45,7 @@ typedef enum PathResult { PATH_SUCCESS, PATH_FAILURE_RESOURCES, PATH_FAILURE_START_LIMIT_HIT, + PATH_FAILURE_UNIT_START_LIMIT_HIT, _PATH_RESULT_MAX, _PATH_RESULT_INVALID = -1 } PathResult; diff --git a/src/core/socket.c b/src/core/socket.c index 809cac68a..f2be28ff7 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -3284,13 +3284,8 @@ static void socket_trigger_notify(Unit *u, Unit *other) { assert(other); /* Filter out invocations with bogus state */ - if (!IN_SET(other->load_state, - UNIT_LOADED, - UNIT_NOT_FOUND, - UNIT_BAD_SETTING, - UNIT_ERROR, - UNIT_MASKED) || other->type != UNIT_SERVICE) - return; + assert(UNIT_IS_LOAD_COMPLETE(other->load_state)); + assert(other->type == UNIT_SERVICE); /* Don't propagate state changes from the service if we are already down */ if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING)) diff --git a/src/core/timer.c b/src/core/timer.c index 03a9c14f7..94388f072 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -746,8 +746,8 @@ static void timer_trigger_notify(Unit *u, Unit *other) { assert(u); assert(other); - if (other->load_state != UNIT_LOADED) - return; + /* Filter out invocations with bogus state */ + assert(UNIT_IS_LOAD_COMPLETE(other->load_state)); /* Reenable all timers that depend on unit state */ LIST_FOREACH(value, v, t->values) diff --git a/src/core/transaction.c b/src/core/transaction.c index 402577298..cbddfa5af 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -949,7 +949,7 @@ int transaction_add_job_and_dependencies( /* Safety check that the unit is a valid state, i.e. not in UNIT_STUB or UNIT_MERGED which should only be set * temporarily. */ - if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_MASKED)) + if (!UNIT_IS_LOAD_COMPLETE(unit->load_state)) return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id); if (type != JOB_STOP) { diff --git a/src/core/unit.h b/src/core/unit.h index 4fdd2e28d..5a2adf90f 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -49,6 +49,10 @@ static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) { return IN_SET(t, UNIT_INACTIVE, UNIT_FAILED); } +static inline bool UNIT_IS_LOAD_COMPLETE(UnitLoadState t) { + return t >= 0 && t < _UNIT_LOAD_STATE_MAX && t != UNIT_STUB && t != UNIT_MERGED; +} + /* Stores the 'reason' a dependency was created as a bit mask, i.e. due to which configuration source it came to be. We * use this so that we can selectively flush out parts of dependencies again. Note that the same dependency might be * created as a result of multiple "reasons", hence the bitmask. */ diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 91581aed3..6c560d547 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -425,7 +425,7 @@ static int add_mount( * the systemd mount-timeout doesn't interfere. * By placing these options first, they can be over-ridden by * settings in /etc/fstab. */ - opts = strjoina("x-systemd.mount-timeout=infinity,retry=10000,", opts, ",fg"); + opts = strjoina("x-systemd.mount-timeout=infinity,retry=10000,nofail,", opts, ",fg"); SET_FLAG(flags, NOFAIL, true); } diff --git a/src/home/homed-home.c b/src/home/homed-home.c index a87fd9a5d..3cdd1ef0e 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -1267,15 +1267,22 @@ int home_create(Home *h, UserRecord *secret, sd_bus_error *error) { assert(h); switch (home_get_state(h)) { - case HOME_INACTIVE: + case HOME_INACTIVE: { + int t; + if (h->record->storage < 0) break; /* if no storage is defined we don't know what precisely to look for, hence * HOME_INACTIVE is OK in that case too. */ - if (IN_SET(user_record_test_image_path(h->record), USER_TEST_MAYBE, USER_TEST_UNDEFINED)) + t = user_record_test_image_path(h->record); + if (IN_SET(t, USER_TEST_MAYBE, USER_TEST_UNDEFINED)) break; /* And if the image path test isn't conclusive, let's also go on */ - _fallthrough_; + if (IN_SET(t, -EBADFD, -ENOTDIR)) + return sd_bus_error_setf(error, BUS_ERROR_HOME_EXISTS, "Selected home image of user %s already exists or has wrong inode type.", h->user_name); + + return sd_bus_error_setf(error, BUS_ERROR_HOME_EXISTS, "Selected home image of user %s already exists.", h->user_name); + } case HOME_UNFIXATED: return sd_bus_error_setf(error, BUS_ERROR_HOME_EXISTS, "Home of user %s already exists.", h->user_name); case HOME_ABSENT: @@ -2709,6 +2716,19 @@ int home_set_current_message(Home *h, sd_bus_message *m) { return 1; } +int home_wait_for_worker(Home *h) { + assert(h); + + if (h->worker_pid <= 0) + return 0; + + log_info("Worker process for home %s is still running while exiting. Waiting for it to finish.", h->user_name); + (void) wait_for_terminate(h->worker_pid, NULL); + (void) hashmap_remove_value(h->manager->homes_by_worker_pid, PID_TO_PTR(h->worker_pid), h); + h->worker_pid = 0; + return 1; +} + static const char* const home_state_table[_HOME_STATE_MAX] = { [HOME_UNFIXATED] = "unfixated", [HOME_ABSENT] = "absent", diff --git a/src/home/homed-home.h b/src/home/homed-home.h index ec7966fb1..3bb455f33 100644 --- a/src/home/homed-home.h +++ b/src/home/homed-home.h @@ -164,5 +164,7 @@ int home_auto_login(Home *h, char ***ret_seats); int home_set_current_message(Home *h, sd_bus_message *m); +int home_wait_for_worker(Home *h); + const char *home_state_to_string(HomeState state); HomeState home_state_from_string(const char *s); diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index 54761175c..6c7c8ebcd 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -232,8 +232,14 @@ int manager_new(Manager **ret) { } Manager* manager_free(Manager *m) { + Home *h; + Iterator i; + assert(m); + HASHMAP_FOREACH(h, m->homes_by_worker_pid, i) + (void) home_wait_for_worker(h); + hashmap_free(m->homes_by_uid); hashmap_free(m->homes_by_name); hashmap_free(m->homes_by_worker_pid); diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index 6c0e27ba3..97fc3bcc3 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -18,8 +18,9 @@ fi MACHINE_ID=$KERNEL_INSTALL_MACHINE_ID -ENTRY_DIR="/$MACHINE_ID/$KERNEL_VERSION" -BOOT_ROOT=${ENTRY_DIR_ABS%$ENTRY_DIR} +BOOT_ROOT=${ENTRY_DIR_ABS%/$MACHINE_ID/$KERNEL_VERSION} +BOOT_MNT=$(stat -c %m $BOOT_ROOT) +ENTRY_DIR=/${ENTRY_DIR_ABS#$BOOT_MNT} if [[ $COMMAND == remove ]]; then rm -f "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 9de5e454a..39e23d978 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -783,7 +783,6 @@ static int parse_tcp_address(sd_bus *b, const char **p, char **guid) { int r; struct addrinfo *result, hints = { .ai_socktype = SOCK_STREAM, - .ai_flags = AI_ADDRCONFIG, }; assert(b); diff --git a/src/nspawn/nspawn-stub-pid1.c b/src/nspawn/nspawn-stub-pid1.c index d86dd2318..f785a3b24 100644 --- a/src/nspawn/nspawn-stub-pid1.c +++ b/src/nspawn/nspawn-stub-pid1.c @@ -66,7 +66,10 @@ int stub_pid1(sd_id128_t uuid) { if (pid == 0) { /* Return in the child */ assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) >= 0); - setsid(); + + if (setsid() < 0) + return log_error_errno(errno, "Failed to become session leader in payload process: %m"); + return 0; } diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 43712565c..8a1f74b93 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2172,7 +2172,7 @@ static int setup_pts(const char *dest) { } static int setup_stdio_as_dev_console(void) { - int terminal; + _cleanup_close_ int terminal = -1; int r; terminal = open_terminal("/dev/console", O_RDWR); @@ -2187,6 +2187,7 @@ static int setup_stdio_as_dev_console(void) { /* invalidates 'terminal' on success and failure */ r = rearrange_stdio(terminal, terminal, terminal); + TAKE_FD(terminal); if (r < 0) return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m"); diff --git a/src/partition/repart.c b/src/partition/repart.c index 9a35e9b73..c94b493d9 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -3142,7 +3142,7 @@ static int find_root(char **ret, int *ret_fd) { if (!s) return log_oom(); - fd = open(arg_node, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOFOLLOW, 0777); + fd = open(arg_node, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOFOLLOW, 0666); if (fd < 0) return log_error_errno(errno, "Failed to create '%s': %m", arg_node); diff --git a/src/rc-local-generator/rc-local-generator.c b/src/rc-local-generator/rc-local-generator.c index 908e6272a..75bb875b7 100644 --- a/src/rc-local-generator/rc-local-generator.c +++ b/src/rc-local-generator/rc-local-generator.c @@ -59,7 +59,7 @@ static int run(const char *dest, const char *dest_early, const char *dest_late) assert_se(arg_dest = dest); - if (check_executable(RC_LOCAL_SCRIPT_PATH_START) >= 0) { + if (check_executable(RC_LOCAL_PATH) >= 0) { log_debug("Automatically adding rc-local.service."); r = add_symlink("rc-local.service", "multi-user.target"); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index d3f10b396..6ac36e1f0 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -770,7 +770,12 @@ int dissect_image( } } - if (!m->partitions[PARTITION_ROOT].found) { + if (m->partitions[PARTITION_ROOT].found) { + /* If we found the primary arch, then invalidate the secondary arch to avoid any ambiguities, + * since we never want to mount the secondary arch in this case. */ + m->partitions[PARTITION_ROOT_SECONDARY].found = false; + m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found = false; + } else { /* No root partition found? Then let's see if ther's one for the secondary architecture. And if not * either, then check if there's a single generic one, and use that. */ @@ -815,12 +820,6 @@ int dissect_image( if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found) return -EADDRNOTAVAIL; - /* If we found the primary root with the hash, then we definitely want to suppress any secondary root - * (which would be weird, after all the root hash should only be assigned to one pair of - * partitions... */ - m->partitions[PARTITION_ROOT_SECONDARY].found = false; - m->partitions[PARTITION_ROOT_SECONDARY_VERITY].found = false; - /* If we found a verity setup, then the root partition is necessarily read-only. */ m->partitions[PARTITION_ROOT].rw = false; @@ -992,7 +991,7 @@ static int mount_partition( /* If requested, turn on discard support. */ if (fstype_can_discard(fstype) && ((flags & DISSECT_IMAGE_DISCARD) || - ((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node)))) { + ((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node) > 0))) { options = strdup("discard"); if (!options) return -ENOMEM; diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c index b461aead6..bf47436b8 100644 --- a/src/socket-proxy/socket-proxyd.c +++ b/src/socket-proxy/socket-proxyd.c @@ -418,7 +418,6 @@ static int resolve_remote(Connection *c) { static const struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM, - .ai_flags = AI_ADDRCONFIG }; const char *node, *service; diff --git a/src/test/test-env-file.c b/src/test/test-env-file.c index 47f86a567..23779b9b8 100644 --- a/src/test/test-env-file.c +++ b/src/test/test-env-file.c @@ -2,6 +2,7 @@ #include "env-file.h" #include "fd-util.h" +#include "fileio.h" #include "fs-util.h" #include "macro.h" #include "strv.h" @@ -132,6 +133,46 @@ static void test_load_env_file_5(void) { assert_se(data[2] == NULL); } +static void test_write_and_load_env_file(void) { + const char *v; + + /* Make sure that our writer, parser and the shell agree on what our env var files mean */ + + FOREACH_STRING(v, + "obbardc-laptop", + "obbardc\\-laptop", + "obbardc-lap\\top", + "obbardc-lap\\top", + "obbardc-lap\\\\top", + "double\"quote", + "single\'quote", + "dollar$dollar", + "newline\nnewline") { + _cleanup_(unlink_and_freep) char *p = NULL; + _cleanup_strv_free_ char **l = NULL; + _cleanup_free_ char *j = NULL, *w = NULL, *cmd = NULL, *from_shell = NULL; + _cleanup_pclose_ FILE *f = NULL; + size_t sz; + + assert_se(tempfn_random_child(NULL, NULL, &p) >= 0); + + assert_se(j = strjoin("TEST=", v)); + assert_se(write_env_file(p, STRV_MAKE(j)) >= 0); + + assert_se(cmd = strjoin(". ", p, " && /bin/echo -n \"$TEST\"")); + assert_se(f = popen(cmd, "re")); + assert_se(read_full_stream(f, &from_shell, &sz) >= 0); + assert_se(sz == strlen(v)); + assert_se(streq(from_shell, v)); + + assert_se(load_env_file(NULL, p, &l) >= 0); + assert_se(strv_equal(l, STRV_MAKE(j))); + + assert_se(parse_env_file(NULL, p, "TEST", &w) >= 0); + assert_se(streq_ptr(w, v)); + } +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_INFO); @@ -140,4 +181,8 @@ int main(int argc, char *argv[]) { test_load_env_file_3(); test_load_env_file_4(); test_load_env_file_5(); + + test_write_and_load_env_file(); + + return 0; } diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 95dcd4fdb..ce5af43db 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -151,6 +151,18 @@ static void test_parse_env_file(void) { assert_se(r >= 0); } +static void test_one_shell_var(const char *file, const char *variable, const char *value) { + _cleanup_free_ char *cmd = NULL, *from_shell = NULL; + _cleanup_pclose_ FILE *f = NULL; + size_t sz; + + assert_se(cmd = strjoin(". ", file, " && /bin/echo -n \"$", variable, "\"")); + assert_se(f = popen(cmd, "re")); + assert_se(read_full_stream(f, &from_shell, &sz) >= 0); + assert_se(sz == strlen(value)); + assert_se(streq(from_shell, value)); +} + static void test_parse_multiline_env_file(void) { _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-fileio-in-XXXXXX", @@ -162,8 +174,8 @@ static void test_parse_multiline_env_file(void) { assert_se(fmkostemp_safe(t, "w", &f) == 0); fputs("one=BAR\\\n" - " VAR\\\n" - "\tGAR\n" + "\\ \\ \\ \\ VAR\\\n" + "\\\tGAR\n" "#comment\n" "two=\"bar\\\n" " var\\\n" @@ -173,9 +185,13 @@ static void test_parse_multiline_env_file(void) { " var \\\n" "\tgar \"\n", f); - fflush(f); + assert_se(fflush_and_check(f) >= 0); fclose(f); + test_one_shell_var(t, "one", "BAR VAR\tGAR"); + test_one_shell_var(t, "two", "bar var\tgar"); + test_one_shell_var(t, "tri", "bar var \tgar "); + r = load_env_file(NULL, t, &a); assert_se(r >= 0); diff --git a/units/rc-local.service.in b/units/rc-local.service.in index 78ce69e0a..d4aaaf09d 100644 --- a/units/rc-local.service.in +++ b/units/rc-local.service.in @@ -8,16 +8,16 @@ # (at your option) any later version. # This unit gets pulled automatically into multi-user.target by -# systemd-rc-local-generator if @RC_LOCAL_SCRIPT_PATH_START@ is executable. +# systemd-rc-local-generator if @RC_LOCAL_PATH@ is executable. [Unit] -Description=@RC_LOCAL_SCRIPT_PATH_START@ Compatibility +Description=@RC_LOCAL_PATH@ Compatibility Documentation=man:systemd-rc-local-generator(8) -ConditionFileIsExecutable=@RC_LOCAL_SCRIPT_PATH_START@ +ConditionFileIsExecutable=@RC_LOCAL_PATH@ After=network.target [Service] Type=forking -ExecStart=@RC_LOCAL_SCRIPT_PATH_START@ start +ExecStart=@RC_LOCAL_PATH@ start TimeoutSec=0 RemainAfterExit=yes GuessMainPID=no