summaryrefslogtreecommitdiff
path: root/src/shared/generator.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/generator.c')
-rw-r--r--src/shared/generator.c59
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)