diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 7caa951814..fc173289d9 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -51,6 +51,9 @@ All tools: * `$SYSTEMD_FSTAB` — if set, use this path instead of `/etc/fstab`. Only useful for debugging. +* `$SYSTEMD_SYSROOT_FSTAB` — if set, use this path instead of + `/sysroot/etc/fstab`. Only useful for debugging `systemd-fstab-generator`. + * `$SYSTEMD_CRYPTTAB` — if set, use this path instead of `/etc/crypttab`. Only useful for debugging. Currently only supported by `systemd-cryptsetup-generator`. diff --git a/man/sd_notify.xml b/man/sd_notify.xml index 4a0a7b34dc..31388b9c3d 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -272,13 +272,14 @@ BARRIER=1 - Tells the service manager that the client is explicitly requesting synchronization by means of - closing the file descriptor sent with this command. The service manager guarantees that the processing of a - BARRIER=1 command will only happen after all previous notification messages sent before this command - have been processed. Hence, this command accompanied with a single file descriptor can be used to synchronize - against reception of all previous status messages. Note that this command cannot be mixed with other notifications, - and has to be sent in a separate message to the service manager, otherwise all assignments will be ignored. Note that - sending 0 or more than 1 file descriptor with this command is a violation of the protocol. + Tells the service manager that the client is explicitly requesting synchronization by + means of closing the file descriptor sent with this command. The service manager guarantees that the + processing of a BARRIER=1 command will only happen after all previous notification + messages sent before this command have been processed. Hence, this command accompanied with a single + file descriptor can be used to synchronize against reception of all previous status messages. Note + that this command cannot be mixed with other notifications, and has to be sent in a separate message + to the service manager, otherwise all assignments will be ignored. Note that sending 0 or more than 1 + file descriptor with this command is a violation of the protocol. @@ -341,7 +342,7 @@ sd_notify_barrier() allows the caller to synchronize against reception of previously sent notification messages - and uses the BARRIER=1 command. It takes a relative + and uses the BARRIER=1 command. It takes a relative timeout value in microseconds which is passed to ppoll2 . A value of UINT64_MAX is interpreted as infinite timeout. diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml index 21fa85da7d..21c3ea94a7 100644 --- a/man/systemd-fstab-generator.xml +++ b/man/systemd-fstab-generator.xml @@ -46,7 +46,7 @@ for more information about special /etc/fstab mount options this generator understands. - One special topic is handling of symbolic links. Historical init + One special topic is handling of symbolic links. Historical init implementations supported symlinks in /etc/fstab. Because mount units will refuse mounts where the target is a symbolic link, this generator will resolve any symlinks as far as possible when processing @@ -251,8 +251,8 @@ systemd.swap5, systemd-cryptsetup-generator8, systemd-gpt-auto-generator8, - kernel-command-line7 + kernel-command-line7, + Known Environment Variables - diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml index 1f916ac65e..d837afb6f9 100644 --- a/man/systemd.generator.xml +++ b/man/systemd.generator.xml @@ -26,8 +26,8 @@ /path/to/generator normal-dir - early-dir - late-dir + early-dir + late-dir @@ -56,13 +56,13 @@ that they can extend the unit file hierarchy the service manager subsequently loads and operates on. - Each generator is called with three directory paths that are to be used for generator output. In - these three directories, generators may dynamically generate unit files (regular ones, instances, as well - as templates), unit file .d/ drop-ins, and create symbolic links to unit files to - add additional dependencies, create aliases, or instantiate existing templates. Those directories are - included in the unit load path of - systemd1, allowing - generated configuration to extend or override existing definitions. + systemd will call each generator with three directory paths that are to be used + for generator output. In these three directories, generators may dynamically generate unit files (regular + ones, instances, as well as templates), unit file .d/ drop-ins, and create symbolic + links to unit files to add additional dependencies, create aliases, or instantiate existing templates. + Those directories are included in the unit load path, allowing generated configuration to extend or + override existing definitions. For tests, generators may be called with just one argument; the generator + should assume that all three paths are the same in that case. Directory paths for generator output differ by priority: …/generator.early has priority higher than the admin configuration in /etc/, while @@ -96,7 +96,8 @@ Generators are invoked with three arguments: paths to directories where generators can place their generated unit files or symlinks. By default those paths are runtime directories that are included in the search path of systemd, but a generator may be called with different paths for - debugging purposes. + debugging purposes. If only one argument is provided, the generator should use the same directory as the + the three output paths. diff --git a/src/basic/log.c b/src/basic/log.c index 02fc2c6f92..cac17a76f4 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -1153,30 +1153,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat } static bool should_parse_proc_cmdline(void) { - const char *e; - pid_t p; - /* PID1 always reads the kernel command line. */ if (getpid_cached() == 1) return true; - /* If the process is directly executed by PID1 (e.g. ExecStart= or generator), systemd-importd, - * or systemd-homed, then $SYSTEMD_EXEC_PID= is set, and read the command line. */ - e = getenv("SYSTEMD_EXEC_PID"); - if (!e) - return false; - - if (streq(e, "*")) - /* For testing. */ - return true; - - if (parse_pid(e, &p) < 0) { - /* We know that systemd sets the variable correctly. Something else must have set it. */ - log_debug("Failed to parse \"$SYSTEMD_EXEC_PID=%s\". Ignoring.", e); - return false; - } - - return getpid_cached() == p; + /* Otherwise, parse the commandline if invoked directly by systemd. */ + return invoked_by_systemd(); } void log_parse_environment_variables(void) { diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 6980e0c4f6..d885d92dfb 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1579,6 +1579,30 @@ bool invoked_as(char *argv[], const char *token) { return strstr(last_path_component(argv[0]), token); } +bool invoked_by_systemd(void) { + int r; + + /* If the process is directly executed by PID1 (e.g. ExecStart= or generator), systemd-importd, + * or systemd-homed, then $SYSTEMD_EXEC_PID= is set, and read the command line. */ + const char *e = getenv("SYSTEMD_EXEC_PID"); + if (!e) + return false; + + if (streq(e, "*")) + /* For testing. */ + return true; + + pid_t p; + r = parse_pid(e, &p); + if (r < 0) { + /* We know that systemd sets the variable correctly. Something else must have set it. */ + log_debug_errno(r, "Failed to parse \"SYSTEMD_EXEC_PID=%s\", ignoring: %m", e); + return false; + } + + return getpid_cached() == p; +} + _noreturn_ void freeze(void) { log_close(); diff --git a/src/basic/process-util.h b/src/basic/process-util.h index c07575e580..f8c374a310 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -190,6 +190,8 @@ int setpriority_closest(int priority); bool invoked_as(char *argv[], const char *token); +bool invoked_by_systemd(void); + _noreturn_ void freeze(void); bool argv_looks_like_help(int argc, char **argv); diff --git a/src/boot/bless-boot-generator.c b/src/boot/bless-boot-generator.c index 7209b28e67..6adef5b3dc 100644 --- a/src/boot/bless-boot-generator.c +++ b/src/boot/bless-boot-generator.c @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include -#include #include #include "efi-loader.h" @@ -10,62 +9,47 @@ #include "mkdir.h" #include "special.h" #include "string-util.h" -#include "util.h" #include "virt.h" -/* This generator pulls systemd-bless-boot.service into the initial transaction if the "LoaderBootCountPath" EFI - * variable is set, i.e. the system boots up with boot counting in effect, which means we should mark the boot as - * "good" if we manage to boot up far enough. */ +/* This generator pulls systemd-bless-boot.service into the initial transaction if the "LoaderBootCountPath" + * EFI variable is set, i.e. the system boots up with boot counting in effect, which means we should mark the + * boot as "good" if we manage to boot up far enough. */ -static const char *arg_dest = "/tmp"; - -int main(int argc, char *argv[]) { - const char *p; - - log_setup_generator(); - - if (argc > 1 && argc != 4) { - log_error("This program takes three or no arguments."); - return EXIT_FAILURE; - } - - if (argc > 1) - arg_dest = argv[2]; +static int run(const char *dest, const char *dest_early, const char *dest_late) { if (in_initrd() > 0) { log_debug("Skipping generator, running in the initrd."); - return EXIT_SUCCESS; + return 0; } if (detect_container() > 0) { log_debug("Skipping generator, running in a container."); - return EXIT_SUCCESS; + return 0; } if (!is_efi_boot()) { log_debug("Skipping generator, not an EFI boot."); - return EXIT_SUCCESS; + return 0; } if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderBootCountPath)), F_OK) < 0) { if (errno == ENOENT) { log_debug_errno(errno, "Skipping generator, not booted with boot counting in effect."); - return EXIT_SUCCESS; + return 0; } - log_error_errno(errno, "Failed to check if LoaderBootCountPath EFI variable exists: %m"); - return EXIT_FAILURE; + return log_error_errno(errno, "Failed to check if LoaderBootCountPath EFI variable exists: %m"); } - /* We pull this in from basic.target so that it ends up in all "regular" boot ups, but not in rescue.target or - * even emergency.target. */ - p = strjoina(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/systemd-bless-boot.service"); + /* We pull this in from basic.target so that it ends up in all "regular" boot ups, but not in + * rescue.target or even emergency.target. */ + const char *p = strjoina(dest_early, "/" SPECIAL_BASIC_TARGET ".wants/systemd-bless-boot.service"); (void) mkdir_parents(p, 0755); - if (symlink(SYSTEM_DATA_UNIT_DIR "/systemd-bless-boot.service", p) < 0) { - log_error_errno(errno, "Failed to create symlink '%s': %m", p); - return EXIT_FAILURE; - } + if (symlink(SYSTEM_DATA_UNIT_DIR "/systemd-bless-boot.service", p) < 0) + return log_error_errno(errno, "Failed to create symlink '%s': %m", p); - return EXIT_SUCCESS; + return 0; } + +DEFINE_MAIN_GENERATOR_FUNCTION(run); diff --git a/src/core/manager.c b/src/core/manager.c index e7e077dcf0..45f6dccf4a 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2530,14 +2530,14 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t return 0; } - /* As extra safety check, let's make sure the string we get doesn't contain embedded NUL bytes. We permit one - * trailing NUL byte in the message, but don't expect it. */ + /* As extra safety check, let's make sure the string we get doesn't contain embedded NUL bytes. + * We permit one trailing NUL byte in the message, but don't expect it. */ if (n > 1 && memchr(buf, 0, n-1)) { log_warning("Received notify message with embedded NUL bytes. Ignoring."); return 0; } - /* Make sure it's NUL-terminated, then parse it to obtain the tags list */ + /* Make sure it's NUL-terminated, then parse it to obtain the tags list. */ buf[n] = 0; tags = strv_split_newlines(buf); if (!tags) { @@ -2545,7 +2545,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t return 0; } - /* possibly a barrier fd, let's see */ + /* Possibly a barrier fd, let's see. */ if (manager_process_barrier_fd(tags, fds)) return 0; @@ -2566,8 +2566,8 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t if (!array_copy) log_oom(); } - /* And now invoke the per-unit callbacks. Note that manager_invoke_notify_message() will handle duplicate units - * make sure we only invoke each unit's handler once. */ + /* And now invoke the per-unit callbacks. Note that manager_invoke_notify_message() will handle + * duplicate units make sure we only invoke each unit's handler once. */ if (u1) { manager_invoke_notify_message(m, u1, ucred, tags, fds); found = true; @@ -2620,8 +2620,8 @@ static int manager_dispatch_sigchld(sd_event_source *source, void *userdata) { assert(source); assert(m); - /* First we call waitid() for a PID and do not reap the zombie. That way we can still access /proc/$PID for it - * while it is a zombie. */ + /* First we call waitid() for a PID and do not reap the zombie. That way we can still access + * /proc/$PID for it while it is a zombie. */ if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) { @@ -2988,15 +2988,15 @@ static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32 assert(m); assert(m->idle_pipe[2] == fd); - /* There's at least one Type=idle child that just gave up on us waiting for the boot process to complete. Let's - * now turn off any further console output if there's at least one service that needs console access, so that - * from now on our own output should not spill into that service's output anymore. After all, we support - * Type=idle only to beautify console output and it generally is set on services that want to own the console - * exclusively without our interference. */ + /* There's at least one Type=idle child that just gave up on us waiting for the boot process to + * complete. Let's now turn off any further console output if there's at least one service that needs + * console access, so that from now on our own output should not spill into that service's output + * anymore. After all, we support Type=idle only to beautify console output and it generally is set + * on services that want to own the console exclusively without our interference. */ m->no_console_output = m->n_on_console > 0; - /* Acknowledge the child's request, and let all all other children know too that they shouldn't wait any longer - * by closing the pipes towards them, which is what they are waiting for. */ + /* Acknowledge the child's request, and let all all other children know too that they shouldn't wait + * any longer by closing the pipes towards them, which is what they are waiting for. */ manager_close_idle_pipe(m); return 0; @@ -3092,8 +3092,8 @@ int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, if (r < 0) return r; - /* Permit addressing units by invocation ID: if the passed bus path is suffixed by a 128bit ID then we use it - * as invocation ID. */ + /* Permit addressing units by invocation ID: if the passed bus path is suffixed by a 128bit ID then + * we use it as invocation ID. */ r = sd_id128_from_string(n, &invocation_id); if (r >= 0) { u = hashmap_get(m->units_by_invocation_id, &invocation_id); @@ -3915,10 +3915,10 @@ int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) { void manager_recheck_dbus(Manager *m) { assert(m); - /* Connects to the bus if the dbus service and socket are running. If we are running in user mode this is all - * it does. In system mode we'll also connect to the system bus (which will most likely just reuse the - * connection of the API bus). That's because the system bus after all runs as service of the system instance, - * while in the user instance we can assume it's already there. */ + /* Connects to the bus if the dbus service and socket are running. If we are running in user mode + * this is all it does. In system mode we'll also connect to the system bus (which will most likely + * just reuse the connection of the API bus). That's because the system bus after all runs as service + * of the system instance, while in the user instance we can assume it's already there. */ if (MANAGER_IS_RELOADING(m)) return; /* don't check while we are reloading… */ @@ -3990,9 +3990,9 @@ void manager_recheck_journal(Manager *m) { if (MANAGER_IS_RELOADING(m)) return; - /* The journal is fully and entirely up? If so, let's permit logging to it, if that's configured. If the - * journal is down, don't ever log to it, otherwise we might end up deadlocking ourselves as we might trigger - * an activation ourselves we can't fulfill. */ + /* The journal is fully and entirely up? If so, let's permit logging to it, if that's configured. If + * the journal is down, don't ever log to it, otherwise we might end up deadlocking ourselves as we + * might trigger an activation ourselves we can't fulfill. */ log_set_prohibit_ipc(!manager_journal_is_running(m)); log_open(); } @@ -4264,13 +4264,14 @@ static void manager_unref_uid_internal( assert(uid_is_valid(uid)); assert(_clean_ipc); - /* A generic implementation, covering both manager_unref_uid() and manager_unref_gid(), under the assumption - * that uid_t and gid_t are actually defined the same way, with the same validity rules. + /* A generic implementation, covering both manager_unref_uid() and manager_unref_gid(), under the + * assumption that uid_t and gid_t are actually defined the same way, with the same validity rules. * - * We store a hashmap where the key is the UID/GID and the value is a 32bit reference counter, whose highest - * bit is used as flag for marking UIDs/GIDs whose IPC objects to remove when the last reference to the UID/GID - * is dropped. The flag is set to on, once at least one reference from a unit where RemoveIPC= is set is added - * on a UID/GID. It is reset when the UID's/GID's reference counter drops to 0 again. */ + * We store a hashmap where the key is the UID/GID and the value is a 32bit reference counter, whose + * highest bit is used as flag for marking UIDs/GIDs whose IPC objects to remove when the last + * reference to the UID/GID is dropped. The flag is set to on, once at least one reference from a + * unit where RemoveIPC= is set is added on a UID/GID. It is reset when the UID's/GID's reference + * counter drops to 0 again. */ assert_cc(sizeof(uid_t) == sizeof(gid_t)); assert_cc(UID_INVALID == (uid_t) GID_INVALID); @@ -4318,8 +4319,9 @@ static int manager_ref_uid_internal( assert(uid_refs); assert(uid_is_valid(uid)); - /* A generic implementation, covering both manager_ref_uid() and manager_ref_gid(), under the assumption - * that uid_t and gid_t are actually defined the same way, with the same validity rules. */ + /* A generic implementation, covering both manager_ref_uid() and manager_ref_gid(), under the + * assumption that uid_t and gid_t are actually defined the same way, with the same validity + * rules. */ assert_cc(sizeof(uid_t) == sizeof(gid_t)); assert_cc(UID_INVALID == (uid_t) GID_INVALID); @@ -4419,9 +4421,10 @@ int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t re assert_se(source); assert_se(m); - /* Invoked whenever a child process succeeded resolving its user/group to use and sent us the resulting UID/GID - * in a datagram. We parse the datagram here and pass it off to the unit, so that it can add a reference to the - * UID/GID so that it can destroy the UID/GID's IPC objects when the reference counter drops to 0. */ + /* Invoked whenever a child process succeeded resolving its user/group to use and sent us the + * resulting UID/GID in a datagram. We parse the datagram here and pass it off to the unit, so that + * it can add a reference to the UID/GID so that it can destroy the UID/GID's IPC objects when the + * reference counter drops to 0. */ l = recv(fd, &buffer, sizeof(buffer), MSG_DONTWAIT); if (l < 0) { diff --git a/src/environment-d-generator/environment-d-generator.c b/src/environment-d-generator/environment-d-generator.c index 12aafbc7d9..e3fea1f2b0 100644 --- a/src/environment-d-generator/environment-d-generator.c +++ b/src/environment-d-generator/environment-d-generator.c @@ -8,6 +8,7 @@ #include "escape.h" #include "glyph-util.h" #include "log.h" +#include "main-func.h" #include "path-lookup.h" #include "strv.h" @@ -80,20 +81,19 @@ static int load_and_print(void) { return 0; } -int main(int argc, char *argv[]) { +static int run(int argc, char *argv[]) { int r; log_parse_environment(); log_open(); - if (argc > 1) { - log_error("This program takes no arguments."); - return EXIT_FAILURE; - } + if (argc > 1) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments."); r = load_and_print(); if (r < 0) - log_error_errno(r, "Failed to load environment.d: %m"); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + return log_error_errno(r, "Failed to load environment.d: %m"); + return 0; } + +DEFINE_MAIN_FUNCTION(run); diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index 46ccc9781f..b7fe729836 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -54,7 +54,7 @@ static void start_target(const char *target, const char *mode) { log_info("Running request %s/start/%s", target, mode); - /* Start these units only if we can replace base.target with it */ + /* Start this unit only if we can replace basic.target with it */ r = sd_bus_call_method(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 75523d0c07..da7ea627f1 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -92,6 +92,7 @@ static int write_what(FILE *f, const char *what) { } static int add_swap( + const char *source, const char *what, struct mntent *me, MountPointFlags flags) { @@ -122,7 +123,7 @@ static int add_swap( if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); - r = generator_open_unit_file(arg_dest, fstab_path(), name, &f); + r = generator_open_unit_file(arg_dest, source, name, &f); if (r < 0) return r; @@ -130,7 +131,7 @@ static int add_swap( "[Unit]\n" "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n" "SourcePath=%s\n", - fstab_path()); + source); r = generator_write_blockdev_dependency(f, what); if (r < 0) @@ -188,7 +189,7 @@ static bool mount_in_initrd(struct mntent *me) { assert(me); return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") || - streq(me->mnt_dir, "/usr"); + path_equal(me->mnt_dir, "/usr"); } static int write_timeout( @@ -339,6 +340,7 @@ static int write_extra_dependencies(FILE *f, const char *opts) { } static int add_mount( + const char *source, const char *dest, const char *what, const char *where, @@ -347,8 +349,7 @@ static int add_mount( const char *opts, int passno, MountPointFlags flags, - const char *post, - const char *source) { + const char *target_unit) { _cleanup_free_ char *name = NULL, @@ -362,7 +363,7 @@ static int add_mount( assert(what); assert(where); assert(opts); - assert(post); + assert(target_unit); assert(source); if (streq_ptr(fstype, "autofs")) @@ -406,7 +407,7 @@ static int add_mount( if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); - r = generator_open_unit_file(dest, fstab_path(), name, &f); + r = generator_open_unit_file(dest, source, name, &f); if (r < 0) return r; @@ -434,10 +435,10 @@ static int add_mount( if (r < 0) return r; - /* Order the mount unit we generate relative to the post unit, so that DefaultDependencies= on the + /* Order the mount unit we generate relative to target_unit, so that DefaultDependencies= on the * target unit won't affect us. */ - if (post && !FLAGS_SET(flags, MOUNT_NOFAIL)) - fprintf(f, "Before=%s\n", post); + if (!FLAGS_SET(flags, MOUNT_NOFAIL)) + fprintf(f, "Before=%s\n", target_unit); if (passno != 0) { r = generator_write_fsck_deps(f, dest, what, where, fstype); @@ -505,14 +506,14 @@ static int add_mount( } if (flags & MOUNT_GROWFS) { - r = generator_hook_up_growfs(dest, where, post); + r = generator_hook_up_growfs(dest, where, target_unit); if (r < 0) return r; } if (!FLAGS_SET(flags, MOUNT_AUTOMOUNT)) { if (!FLAGS_SET(flags, MOUNT_NOAUTO) && strv_isempty(wanted_by) && strv_isempty(required_by)) { - r = generator_add_symlink(dest, post, + r = generator_add_symlink(dest, target_unit, (flags & MOUNT_NOFAIL) ? "wants" : "requires", name); if (r < 0) return r; @@ -536,7 +537,7 @@ static int add_mount( f = safe_fclose(f); - r = generator_open_unit_file(dest, fstab_path(), automount_name, &f); + r = generator_open_unit_file(dest, source, automount_name, &f); if (r < 0) return r; @@ -560,7 +561,7 @@ static int add_mount( if (r < 0) return log_error_errno(r, "Failed to write unit file %s: %m", automount_name); - r = generator_add_symlink(dest, post, + r = generator_add_symlink(dest, target_unit, (flags & MOUNT_NOFAIL) ? "wants" : "requires", automount_name); if (r < 0) return r; @@ -569,13 +570,21 @@ static int add_mount( return 0; } +static const char* sysroot_fstab_path(void) { + return getenv("SYSTEMD_SYSROOT_FSTAB") ?: "/sysroot/etc/fstab"; +} + static int parse_fstab(bool initrd) { _cleanup_endmntent_ FILE *f = NULL; const char *fstab; struct mntent *me; int r = 0; - fstab = initrd ? "/sysroot/etc/fstab" : fstab_path(); + if (initrd) + fstab = sysroot_fstab_path(); + else + fstab = fstab_path(); + log_debug("Parsing %s...", fstab); f = setmntent(fstab, "re"); @@ -622,13 +631,25 @@ static int parse_fstab(bool initrd) { * mount units, but causes problems since it historically worked to have symlinks in e.g. * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case * where a symlink refers to another mount target; this works assuming the sub-mountpoint - * target is the final directory. */ + * target is the final directory. + * + * FIXME: when chase_symlinks() learns to chase non-existent paths, use this here and + * drop the prefixing with /sysroot on error below. + */ k = chase_symlinks(where, initrd ? "/sysroot" : NULL, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &canonical_where, NULL); - if (k < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */ - log_debug_errno(k, "Failed to read symlink target for %s, ignoring: %m", where); - else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */ + if (k < 0) { + /* If we can't canonicalize, continue as if it wasn't a symlink */ + log_debug_errno(k, "Failed to read symlink target for %s, using as-is: %m", where); + + if (initrd) { + canonical_where = path_join("/sysroot", where); + if (!canonical_where) + return log_oom(); + } + + } else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */ canonical_where = mfree(canonical_where); else log_debug("Canonicalized what=%s where=%s to %s", what, where, canonical_where); @@ -650,10 +671,9 @@ static int parse_fstab(bool initrd) { nofail * MOUNT_NOFAIL; if (streq(me->mnt_type, "swap")) - k = add_swap(what, me, flags); + k = add_swap(fstab, what, me, flags); else { bool rw_only, automount; - const char *post; rw_only = fstab_test_option(me->mnt_opts, "x-systemd.rw-only\0"); automount = fstab_test_option(me->mnt_opts, @@ -663,14 +683,13 @@ static int parse_fstab(bool initrd) { flags |= rw_only * MOUNT_RW_ONLY | automount * MOUNT_AUTOMOUNT; - if (initrd) - post = SPECIAL_INITRD_FS_TARGET; - else if (mount_is_network(me)) - post = SPECIAL_REMOTE_FS_TARGET; - else - post = SPECIAL_LOCAL_FS_TARGET; + const char *target_unit = + initrd ? SPECIAL_INITRD_FS_TARGET : + mount_is_network(me) ? SPECIAL_REMOTE_FS_TARGET : + SPECIAL_LOCAL_FS_TARGET; - k = add_mount(arg_dest, + k = add_mount(fstab, + arg_dest, what, canonical_where ?: where, canonical_where ? where: NULL, @@ -678,8 +697,7 @@ static int parse_fstab(bool initrd) { me->mnt_opts, me->mnt_passno, flags, - post, - fstab); + target_unit); } if (r >= 0 && k < 0) @@ -752,7 +770,7 @@ static int add_sysroot_mount(void) { } if (streq(arg_root_what, "gpt-auto")) { - /* This is handled by the gpt-auto generator */ + /* This is handled by gpt-auto-generator */ log_debug("Skipping root directory handling, as gpt-auto was requested."); return 0; } @@ -818,7 +836,8 @@ static int add_sysroot_mount(void) { return r; } - return add_mount(arg_dest, + return add_mount("/proc/cmdline", + arg_dest, what, "/sysroot", NULL, @@ -826,8 +845,7 @@ static int add_sysroot_mount(void) { opts, is_device_path(what) ? 1 : 0, /* passno */ 0, /* makefs off, growfs off, noauto off, nofail off, automount off */ - SPECIAL_INITRD_ROOT_FS_TARGET, - "/proc/cmdline"); + SPECIAL_INITRD_ROOT_FS_TARGET); } static int add_sysroot_usr_mount(void) { @@ -898,7 +916,8 @@ static int add_sysroot_usr_mount(void) { log_debug("Found entry what=%s where=/sysusr/usr type=%s opts=%s", what, strna(arg_usr_fstype), strempty(opts)); - r = add_mount(arg_dest, + r = add_mount("/proc/cmdline", + arg_dest, what, "/sysusr/usr", NULL, @@ -906,14 +925,14 @@ static int add_sysroot_usr_mount(void) { opts, is_device_path(what) ? 1 : 0, /* passno */ 0, - SPECIAL_INITRD_USR_FS_TARGET, - "/proc/cmdline"); + SPECIAL_INITRD_USR_FS_TARGET); if (r < 0) return r; log_debug("Synthesizing entry what=/sysusr/usr where=/sysrootr/usr opts=bind"); - r = add_mount(arg_dest, + r = add_mount("/proc/cmdline", + arg_dest, "/sysusr/usr", "/sysroot/usr", NULL, @@ -921,8 +940,7 @@ static int add_sysroot_usr_mount(void) { "bind", 0, 0, - SPECIAL_INITRD_FS_TARGET, - "/proc/cmdline"); + SPECIAL_INITRD_FS_TARGET); if (r < 0) return r; @@ -966,7 +984,8 @@ static int add_volatile_var(void) { /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */ - return add_mount(arg_dest_late, + return add_mount("/proc/cmdline", + arg_dest_late, "tmpfs", "/var", NULL, @@ -974,8 +993,7 @@ static int add_volatile_var(void) { "mode=0755" TMPFS_LIMITS_VAR, 0, 0, - SPECIAL_LOCAL_FS_TARGET, - "/proc/cmdline"); + SPECIAL_LOCAL_FS_TARGET); } static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c index ee320909ee..f591407f78 100644 --- a/src/hibernate-resume/hibernate-resume-generator.c +++ b/src/hibernate-resume/hibernate-resume-generator.c @@ -16,7 +16,7 @@ #include "string-util.h" #include "unit-name.h" -static const char *arg_dest = "/tmp"; +static const char *arg_dest = NULL; static char *arg_resume_device = NULL; static char *arg_resume_options = NULL; static char *arg_root_options = NULL; @@ -109,17 +109,10 @@ static int process_resume(void) { return 0; } -static int run(int argc, char *argv[]) { +static int run(const char *dest, const char *dest_early, const char *dest_late) { int r = 0; - log_setup_generator(); - - if (argc > 1 && argc != 4) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "This program takes three or no arguments."); - - if (argc > 1) - arg_dest = argv[1]; + arg_dest = ASSERT_PTR(dest); /* Don't even consider resuming outside of initramfs. */ if (!in_initrd()) { @@ -139,4 +132,4 @@ static int run(int argc, char *argv[]) { return process_resume(); } -DEFINE_MAIN_FUNCTION(run); +DEFINE_MAIN_GENERATOR_FUNCTION(run); diff --git a/src/shared/generator.c b/src/shared/generator.c index ca66673d84..12170d3642 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -15,6 +15,7 @@ #include "macro.h" #include "mkdir-label.h" #include "path-util.h" +#include "process-util.h" #include "special.h" #include "specifier.h" #include "string-util.h" @@ -737,11 +738,15 @@ int generator_write_veritysetup_service_section( } void log_setup_generator(void) { - /* Disable talking to syslog/journal (i.e. the two IPC-based loggers) if we run in system context. */ - if (cg_pid_get_owner_uid(0, NULL) == -ENXIO /* not running in a per-user slice */) - log_set_prohibit_ipc(true); + if (invoked_by_systemd()) { + /* Disable talking to syslog/journal (i.e. the two IPC-based loggers) if we run in system context. */ + if (cg_pid_get_owner_uid(0, NULL) == -ENXIO /* not running in a per-user slice */) + log_set_prohibit_ipc(true); + + /* This effectively means: journal for per-user generators, kmsg otherwise */ + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + } - log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); /* This effectively means: journal for per-user generators, kmsg otherwise */ log_parse_environment(); (void) log_open(); } diff --git a/src/shared/generator.h b/src/shared/generator.h index bd768daf49..1b4f36ac53 100644 --- a/src/shared/generator.h +++ b/src/shared/generator.h @@ -3,6 +3,7 @@ #include +#include "macro.h" #include "main-func.h" int generator_open_unit_file( @@ -86,11 +87,11 @@ void log_setup_generator(void); _DEFINE_MAIN_FUNCTION( \ ({ \ log_setup_generator(); \ - if (argc > 1 && argc != 4) \ + if (!IN_SET(argc, 2, 4)) \ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), \ - "This program takes zero or three arguments."); \ + "This program takes one or three arguments."); \ }), \ - impl(argc > 1 ? argv[1] : "/tmp", \ - argc > 1 ? argv[2] : "/tmp", \ - argc > 1 ? argv[3] : "/tmp"), \ + impl(argv[1], \ + argv[argc == 4 ? 2 : 1], \ + argv[argc == 4 ? 3 : 1]), \ r < 0 ? EXIT_FAILURE : EXIT_SUCCESS) diff --git a/src/sulogin-shell/sulogin-shell.c b/src/sulogin-shell/sulogin-shell.c index 0207e85b7e..148e8acd73 100644 --- a/src/sulogin-shell/sulogin-shell.c +++ b/src/sulogin-shell/sulogin-shell.c @@ -49,9 +49,9 @@ static int start_default_target(sd_bus *bus) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; - log_info("Starting default target"); + log_info("Starting "SPECIAL_DEFAULT_TARGET); - /* Start these units only if we can replace base.target with it */ + /* Start this unit only if we can replace basic.target with it */ r = sd_bus_call_method(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -62,7 +62,7 @@ static int start_default_target(sd_bus *bus) { "ss", SPECIAL_DEFAULT_TARGET, "isolate"); if (r < 0) - return log_error_errno(r, "Failed to start default target: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Failed to start "SPECIAL_DEFAULT_TARGET": %s", bus_error_message(&error, r)); return 0; }