diff --git a/TODO b/TODO index 462db57a3a..b4e0cbb88a 100644 --- a/TODO +++ b/TODO @@ -825,6 +825,7 @@ Features: - man: document the very specific env the shutdown drop-in tools live in - man: add more examples to man pages - man: maybe sort directives in man pages, and take sections from --help and apply them to man too + - document root=gpt-auto properly * systemctl: - add systemctl switch to dump transaction without executing it diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 43dfc1073b..e39f108d8f 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -329,7 +329,7 @@ Configures the root file system and its file system type and mount options, as well as whether it shall be - mounted read-only or read-writable initially. For details, + mounted read-only or read-write initially. For details, see systemd-fstab-generator8. diff --git a/man/systemd-gpt-auto-generator.xml b/man/systemd-gpt-auto-generator.xml index d98ef2003f..5ae4343705 100644 --- a/man/systemd-gpt-auto-generator.xml +++ b/man/systemd-gpt-auto-generator.xml @@ -196,6 +196,45 @@ systemd.generator7. + + Kernel Command Line + + systemd-gpt-auto-generator understands the following kernel command line + parameters: + + + + + systemd.gpt_auto + rd.systemd.gpt_auto + + Those options take an optional boolean argument, and default to yes. + The generator is enabled by default, and a negative value may be used to disable it. + + + + + root= + + When used with the special value gpt-auto, automatic discovery of + the root parition based on the GPT partition type is enabled. Any other value disables this + generator. + + + + rw + ro + + Mount the root partition read-write or read-only initially. + + Note that unlike most kernel command line options these settings do not override configuration + in the file system, and the file system may be remounted later. See + systemd-remount-fs.service8. + + + + + See Also diff --git a/man/systemd-remount-fs.service.xml b/man/systemd-remount-fs.service.xml index 988a617406..46ab56eb0b 100644 --- a/man/systemd-remount-fs.service.xml +++ b/man/systemd-remount-fs.service.xml @@ -30,26 +30,31 @@ Description - systemd-remount-fs.service is an - early boot service that applies mount options listed in - fstab5 - to the root file system, the /usr file system, - and the kernel API file systems. This is required so that the - mount options of these file systems — which are pre-mounted by - the kernel, the initial RAM disk, container environments or system - manager code — are updated to those listed in - /etc/fstab. This service ignores normal file - systems and only changes the root file system (i.e. - /), /usr and the virtual - kernel API file systems such as /proc, - /sys or /dev. This - service executes no operation if /etc/fstab - does not exist or lists no entries for the mentioned file - systems. + systemd-remount-fs.service is an early boot service that applies mount options + listed in fstab5, or + gathered from the partition table (when + systemd-gpt-auto-generator8 + is active) to the root file system, the /usr file system, and the kernel API file + systems. This is required so that the mount options of these file systems — which are pre-mounted by the + kernel, the initial RAM disk, container environments or system manager code — are updated to those + configured in /etc/fstab and the other sources. This service ignores normal file + systems and only changes the root file system (i.e. /), /usr, + and the virtual kernel API file systems such as /proc, /sys or + /dev. This service executes no operation if no configuration is found + (/etc/fstab does not exist or lists no entries for the mentioned file systems, or + the partition table does not contain relevant entries). For a longer discussion of kernel API file systems see API File Systems. + + Note: systemd-remount-fs.service is usually pulled in by + systemd-fstab-generator8, + hence it is also affected by the kernel command line option fstab=, which may be used + to disable the generator. It may also pulled in by + systemd-gpt-auto-generator8, + which is affected by systemd.gpt_auto and other options. @@ -57,7 +62,9 @@ systemd1, fstab5, - mount8 + mount8, + systemd-fstab-generator8, + systemd-gpt-auto-generator8 diff --git a/src/basic/special.h b/src/basic/special.h index 379a3d7979..add1c1d507 100644 --- a/src/basic/special.h +++ b/src/basic/special.h @@ -76,9 +76,11 @@ /* Magic early boot services */ #define SPECIAL_FSCK_SERVICE "systemd-fsck@.service" +#define SPECIAL_FSCK_ROOT_SERVICE "systemd-fsck-root.service" #define SPECIAL_QUOTACHECK_SERVICE "systemd-quotacheck.service" #define SPECIAL_QUOTAON_SERVICE "quotaon.service" #define SPECIAL_REMOUNT_FS_SERVICE "systemd-remount-fs.service" +#define SPECIAL_VOLATILE_ROOT_SERVICE "systemd-volatile-root.service" /* Services systemd relies on */ #define SPECIAL_DBUS_SERVICE "dbus.service" diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index f3c223a270..30a6d356d0 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -518,6 +518,8 @@ static int parse_fstab(bool initrd) { int r = 0; fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab"; + log_debug("Parsing %s...", fstab_path); + f = setmntent(fstab_path, "re"); if (!f) { if (errno == ENOENT) @@ -720,23 +722,14 @@ static int add_sysroot_usr_mount(void) { } static int add_volatile_root(void) { - const char *from, *to; + /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is + * requested, leaving only /usr from the root mount inside. */ if (arg_volatile_mode != VOLATILE_YES) return 0; - /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is - * requested, leaving only /usr from the root mount inside. */ - - from = strjoina(SYSTEM_DATA_UNIT_PATH "/systemd-volatile-root.service"); - to = strjoina(arg_dest, "/" SPECIAL_INITRD_ROOT_FS_TARGET, ".requires/systemd-volatile-root.service"); - - (void) mkdir_parents(to, 0755); - - if (symlink(from, to) < 0) - return log_error_errno(errno, "Failed to hook in volatile remount service: %m"); - - return 0; + return generator_add_symlink(arg_dest, SPECIAL_INITRD_ROOT_FS_TARGET, "requires", + SYSTEM_DATA_UNIT_PATH "/" SPECIAL_VOLATILE_ROOT_SERVICE); } static int add_volatile_var(void) { @@ -868,7 +861,7 @@ static int determine_root(void) { } static int run(const char *dest, const char *dest_early, const char *dest_late) { - int r; + int r, r2 = 0, r3 = 0; assert_se(arg_dest = dest); assert_se(arg_dest_late = dest_late); @@ -881,42 +874,27 @@ static int run(const char *dest, const char *dest_early, const char *dest_late) /* Always honour root= and usr= in the kernel command line if we are in an initrd */ if (in_initrd()) { - int k; - r = add_sysroot_mount(); - k = add_sysroot_usr_mount(); - if (k < 0) - r = k; + r2 = add_sysroot_usr_mount(); - k = add_volatile_root(); - if (k < 0) - r = k; + r3 = add_volatile_root(); } else r = add_volatile_var(); /* Honour /etc/fstab only when that's enabled */ if (arg_fstab_enabled) { - int k; - - log_debug("Parsing /etc/fstab"); - /* Parse the local /etc/fstab, possibly from the initrd */ - k = parse_fstab(false); - if (k < 0) - r = k; + r2 = parse_fstab(false); /* If running in the initrd also parse the /etc/fstab from the host */ - if (in_initrd()) { - log_debug("Parsing /sysroot/etc/fstab"); - - k = parse_fstab(true); - if (k < 0) - r = k; - } + if (in_initrd()) + r3 = parse_fstab(true); + else + r3 = generator_enable_remount_fs_service(arg_dest); } - return r; + return r < 0 ? r : r2 < 0 ? r2 : r3; } DEFINE_MAIN_GENERATOR_FUNCTION(run); diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index d9e29c47f3..09c0bcba2d 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -467,13 +467,13 @@ static int add_root_rw(DissectedPartition *p) { return 0; } + (void) generator_enable_remount_fs_service(arg_dest); + path = strjoina(arg_dest, "/systemd-remount-fs.service.d/50-remount-rw.conf"); (void) mkdir_parents(path, 0755); r = write_string_file(path, "# Automatically generated by systemd-gpt-generator\n\n" - "[Unit]\n" - "ConditionPathExists=\n\n" /* We need to turn off the ConditionPathExist= in the main unit file */ "[Service]\n" "Environment=SYSTEMD_REMOUNT_ROOT_RW=1\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_NOFOLLOW); @@ -678,6 +678,9 @@ static int add_root_mount(void) { return r; } + /* Note that we do not need to enable systemd-remount-fs.service here. If + * /etc/fstab exists, systemd-fstab-generator will pull it in for us. */ + return add_mount( "root", "/dev/gpt-auto-root", diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c index 0bac355e0f..0df29aa69f 100644 --- a/src/remount-fs/remount-fs.c +++ b/src/remount-fs/remount-fs.c @@ -47,6 +47,31 @@ static int track_pid(Hashmap **h, const char *path, pid_t pid) { return 0; } +static int do_remount(const char *path, bool force_rw, Hashmap **pids) { + pid_t pid; + int r; + + log_debug("Remounting %s...", path); + + r = safe_fork(force_rw ? "(remount-rw)" : "(remount)", + FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid); + if (r < 0) + return r; + if (r == 0) { + /* Child */ + execv(MOUNT_PATH, + STRV_MAKE(MOUNT_PATH, + path, + "-o", + force_rw ? "remount,rw" : "remount")); + log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m"); + _exit(EXIT_FAILURE); + } + + /* Parent */ + return track_pid(pids, path, pid); +} + static int run(int argc, char *argv[]) { _cleanup_hashmap_free_free_ Hashmap *pids = NULL; _cleanup_endmntent_ FILE *f = NULL; @@ -66,36 +91,20 @@ static int run(int argc, char *argv[]) { if (!f) { if (errno != ENOENT) return log_error_errno(errno, "Failed to open /etc/fstab: %m"); - } else { + } else while ((me = getmntent(f))) { - pid_t pid; - - /* Remount the root fs, /usr and all API VFS */ + /* Remount the root fs, /usr, and all API VFSs */ if (!mount_point_is_api(me->mnt_dir) && !PATH_IN_SET(me->mnt_dir, "/", "/usr")) continue; - log_debug("Remounting %s...", me->mnt_dir); - if (path_equal(me->mnt_dir, "/")) has_root = true; - r = safe_fork("(remount)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid); - if (r < 0) - return r; - if (r == 0) { - /* Child */ - execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, me->mnt_dir, "-o", "remount")); - log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m"); - _exit(EXIT_FAILURE); - } - - /* Parent */ - r = track_pid(&pids, me->mnt_dir, pid); + r = do_remount(me->mnt_dir, false, &pids); if (r < 0) return r; } - } if (!has_root) { /* The $SYSTEMD_REMOUNT_ROOT_RW environment variable is set by systemd-gpt-auto-generator to tell us @@ -103,27 +112,14 @@ static int run(int argc, char *argv[]) { * which takes precedence. */ r = getenv_bool("SYSTEMD_REMOUNT_ROOT_RW"); - if (r > 0) { - pid_t pid; - - log_debug("Remounting / writable..."); - - r = safe_fork("(remount-rw)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid); - if (r < 0) - return r; - if (r == 0) { - /* Child */ - execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, "/", "-o", "remount,rw")); - log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m"); - _exit(EXIT_FAILURE); - } - - r = track_pid(&pids, "/", pid); - if (r < 0) - return r; - - } else if (r < 0 && r != -ENXIO) + if (r < 0 && r != -ENXIO) log_warning_errno(r, "Failed to parse $SYSTEMD_REMOUNT_ROOT_RW, ignoring: %m"); + + if (r > 0) { + r = do_remount("/", true, &pids); + if (r < 0) + return r; + } } r = 0; diff --git a/src/shared/generator.c b/src/shared/generator.c index 0adaaf2c56..b2085040f0 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -55,13 +55,14 @@ int generator_open_unit_file( return 0; } -int generator_add_symlink(const char *root, const char *dst, const char *dep_type, const char *src) { - /* Adds a symlink from ..d/ to ../ */ +int generator_add_symlink(const char *dir, const char *dst, const char *dep_type, const char *src) { + /* Adds a symlink from ./ to (if src is absolute) + * or ../ (otherwise). */ const char *from, *to; - from = strjoina("../", src); - to = strjoina(root, "/", dst, ".", dep_type, "/", src); + from = path_is_absolute(src) ? src : strjoina("../", src); + to = strjoina(dir, "/", dst, ".", dep_type, "/", basename(src)); mkdir_parents_label(to, 0755); if (symlink(from, to) < 0) @@ -85,7 +86,7 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) { if (!escaped2) return log_oom(); - unit = strjoina(dir, "/systemd-fsck-root.service"); + unit = strjoina(dir, "/"SPECIAL_FSCK_ROOT_SERVICE); log_debug("Creating %s", unit); r = unit_name_from_path(what, ".device", &device); @@ -157,10 +158,10 @@ int generator_write_fsck_deps( if (path_equal(where, "/")) { const char *lnk; - lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service"); + lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/"SPECIAL_FSCK_ROOT_SERVICE); mkdir_parents(lnk, 0755); - if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0) + if (symlink(SYSTEM_DATA_UNIT_PATH "/"SPECIAL_FSCK_ROOT_SERVICE, lnk) < 0) return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); } else { @@ -172,7 +173,7 @@ int generator_write_fsck_deps( if (r < 0) return r; - fsck = "systemd-fsck-root.service"; + fsck = SPECIAL_FSCK_ROOT_SERVICE; } else { r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck); if (r < 0) @@ -498,6 +499,12 @@ int generator_hook_up_growfs( return generator_add_symlink(dir, where_unit, "wants", unit); } +int generator_enable_remount_fs_service(const char *dir) { + /* Pull in systemd-remount-fs.service */ + return generator_add_symlink(dir, SPECIAL_LOCAL_FS_TARGET, "wants", + SYSTEM_DATA_UNIT_PATH "/" SPECIAL_REMOUNT_FS_SERVICE); +} + void log_setup_generator(void) { log_set_prohibit_ipc(true); log_setup_service(); diff --git a/src/shared/generator.h b/src/shared/generator.h index 5a1c1e32f7..fa002a9114 100644 --- a/src/shared/generator.h +++ b/src/shared/generator.h @@ -11,7 +11,7 @@ int generator_open_unit_file( const char *name, FILE **file); -int generator_add_symlink(const char *root, const char *dst, const char *dep_type, const char *src); +int generator_add_symlink(const char *dir, const char *dst, const char *dep_type, const char *src); int generator_write_fsck_deps( FILE *f, @@ -50,6 +50,8 @@ int generator_hook_up_growfs( const char *where, const char *target); +int generator_enable_remount_fs_service(const char *dir); + void log_setup_generator(void); /* Similar to DEFINE_MAIN_FUNCTION, but initializes logging and assigns positional arguments. */ diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index 0d3674cff8..959d6d4614 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -759,7 +759,7 @@ static void test_unit_name_from_dbus_path(void) { test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dcoredump_2esocket", 0, "systemd-coredump.socket"); test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dcoredump_400_2eservice", 0, "systemd-coredump@0.service"); test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dfirstboot_2eservice", 0, "systemd-firstboot.service"); - test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dfsck_2droot_2eservice", 0, "systemd-fsck-root.service"); + test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dfsck_2droot_2eservice", 0, SPECIAL_FSCK_ROOT_SERVICE); test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dhwdb_2dupdate_2eservice", 0, "systemd-hwdb-update.service"); test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dinitctl_2eservice", 0, "systemd-initctl.service"); test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dinitctl_2esocket", 0, "systemd-initctl.socket"); diff --git a/units/meson.build b/units/meson.build index d69508467f..3820585051 100644 --- a/units/meson.build +++ b/units/meson.build @@ -186,8 +186,7 @@ in_units = [ ['systemd-quotacheck.service', 'ENABLE_QUOTACHECK'], ['systemd-random-seed.service', 'ENABLE_RANDOMSEED', 'sysinit.target.wants/'], - ['systemd-remount-fs.service', '', - 'local-fs.target.wants/'], + ['systemd-remount-fs.service', ''], ['systemd-resolved.service', 'ENABLE_RESOLVE', join_paths(pkgsysconfdir, 'system/dbus-org.freedesktop.resolve1.service') + ' ' + join_paths(pkgsysconfdir, 'system/multi-user.target.wants/')], diff --git a/units/systemd-remount-fs.service.in b/units/systemd-remount-fs.service.in index 2e5b75ec03..4f4304d68e 100644 --- a/units/systemd-remount-fs.service.in +++ b/units/systemd-remount-fs.service.in @@ -16,7 +16,6 @@ Conflicts=shutdown.target After=systemd-fsck-root.service Before=local-fs-pre.target local-fs.target shutdown.target Wants=local-fs-pre.target -ConditionPathExists=/etc/fstab [Service] Type=oneshot