diff options
Diffstat (limited to 'src/shared/generator.c')
-rw-r--r-- | src/shared/generator.c | 59 |
1 files changed, 46 insertions, 13 deletions
diff --git a/src/shared/generator.c b/src/shared/generator.c index 5b9c432527..0bb3efa700 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -71,12 +71,22 @@ int generator_add_symlink(const char *dir, const char *dst, const char *dep_type return 0; } -static int write_fsck_sysroot_service(const char *dir, const char *what) { +static int write_fsck_sysroot_service( + const char *unit, /* Either SPECIAL_FSCK_ROOT_SERVICE or SPECIAL_FSCK_USR_SERVICE */ + const char *dir, + const char *what, + const char *extra_after) { + _cleanup_free_ char *device = NULL, *escaped = NULL, *escaped2 = NULL; _cleanup_fclose_ FILE *f = NULL; - const char *unit; + const char *fn; int r; + /* Writes out special versions of systemd-root-fsck.service and systemd-usr-fsck.service for use in + * the initrd. The regular statically shipped versions of these unit files use / and /usr for as + * paths, which doesn't match what we need for the initrd (where the dirs are /sysroot + + * /sysusr/usr), hence we overwrite those versions here. */ + escaped = specifier_escape(what); if (!escaped) return log_oom(); @@ -85,41 +95,44 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) { if (!escaped2) return log_oom(); - unit = strjoina(dir, "/"SPECIAL_FSCK_ROOT_SERVICE); - log_debug("Creating %s", unit); + fn = strjoina(dir, "/", unit); + log_debug("Creating %s", fn); r = unit_name_from_path(what, ".device", &device); if (r < 0) return log_error_errno(r, "Failed to convert device \"%s\" to unit name: %m", what); - f = fopen(unit, "wxe"); + f = fopen(fn, "wxe"); if (!f) - return log_error_errno(errno, "Failed to create unit file %s: %m", unit); + return log_error_errno(errno, "Failed to create unit file %s: %m", fn); fprintf(f, "# Automatically generated by %1$s\n\n" "[Unit]\n" "Description=File System Check on %2$s\n" - "Documentation=man:systemd-fsck-root.service(8)\n" + "Documentation=man:%3$s(8)\n" "DefaultDependencies=no\n" - "BindsTo=%3$s\n" + "BindsTo=%4$s\n" "Conflicts=shutdown.target\n" - "After=initrd-root-device.target local-fs-pre.target %3$s\n" + "After=%5$s%6$slocal-fs-pre.target %4$s\n" "Before=shutdown.target\n" "\n" "[Service]\n" "Type=oneshot\n" "RemainAfterExit=yes\n" - "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n" + "ExecStart=" SYSTEMD_FSCK_PATH " %7$s\n" "TimeoutSec=0\n", program_invocation_short_name, escaped, + unit, device, + strempty(extra_after), + isempty(extra_after) ? "" : " ", escaped2); r = fflush_and_check(f); if (r < 0) - return log_error_errno(r, "Failed to write unit file %s: %m", unit); + return log_error_errno(r, "Failed to write unit file %s: %m", fn); return 0; } @@ -138,6 +151,13 @@ int generator_write_fsck_deps( assert(what); assert(where); + /* Let's do an early exit if we are invoked for the root and /usr/ trees in the initrd, to avoid + * generating confusing log messages */ + if (in_initrd() && PATH_IN_SET(where, "/", "/usr")) { + log_debug("Skipping fsck for %s in initrd.", where); + return 0; + } + if (!is_device_path(what)) { log_warning("Checking was requested for \"%s\", but it is not a device.", what); return 0; @@ -157,6 +177,11 @@ int generator_write_fsck_deps( if (path_equal(where, "/")) { const char *lnk; + /* We support running the fsck instance for the root fs while it is already mounted, for + * compatibility with non-initrd boots. It's ugly, but it is how it is. Since – unlike for + * regular file systems – this means the ordering is reversed (i.e. mount *before* fsck) we + * have a separate fsck unit for this, independent of systemd-fsck@.service. */ + lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/" SPECIAL_FSCK_ROOT_SERVICE); (void) mkdir_parents(lnk, 0755); @@ -168,19 +193,27 @@ int generator_write_fsck_deps( const char *fsck, *dep; if (in_initrd() && path_equal(where, "/sysroot")) { - r = write_fsck_sysroot_service(dir, what); + r = write_fsck_sysroot_service(SPECIAL_FSCK_ROOT_SERVICE, dir, what, SPECIAL_INITRD_ROOT_DEVICE_TARGET); if (r < 0) return r; fsck = SPECIAL_FSCK_ROOT_SERVICE; dep = "Requires"; + + } else if (in_initrd() && path_equal(where, "/sysusr/usr")) { + r = write_fsck_sysroot_service(SPECIAL_FSCK_USR_SERVICE, dir, what, NULL); + if (r < 0) + return r; + + fsck = SPECIAL_FSCK_USR_SERVICE; + dep = "Requires"; } else { /* When this is /usr, then let's add a Wants= dependency, otherwise a Requires= * dependency. Why? We can't possibly unmount /usr during shutdown, but if we have a * Requires= from /usr onto a fsck@.service unit and that unit is shut down, then * we'd have to unmount /usr too. */ - dep = !in_initrd() && path_equal(where, "/usr") ? "Wants" : "Requires"; + dep = path_equal(where, "/usr") ? "Wants" : "Requires"; r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck); if (r < 0) |