]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fstab-generator: add mode to check /sysroot/etc/fstab and maybe do daemon-reload
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 14 Jul 2022 12:36:52 +0000 (14:36 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 23 Jul 2022 17:02:39 +0000 (19:02 +0200)
The idea is that we can peek into /sysroot/etc/fstab and figure out if there's
anything interesting there. We could use a separate binary for this, but we'd
need to duplicate most of the logic that in systemd-fstab-generator. Thus I
think it's nicer to make systemd-fstab-generator work as a multi-call binary.

If called as systemd-sysroot-fstab-check, we look for units that we'd mount and
call daemon-reload and initrd-fs.target/restart, similarly to what we did
before, but in the process itself.

meson.build
src/fstab-generator/fstab-generator.c

index 5d7c8699fe0d057855569f25ec1ceedf05a52e8a..e6e32050902ea7482aca47ea049a59fd26c359ca 100644 (file)
@@ -2298,6 +2298,10 @@ exe = executable(
         install : true,
         install_dir : systemgeneratordir)
 
+meson.add_install_script(meson_make_symlink,
+                         systemgeneratordir / 'systemd-fstab-generator',
+                         rootlibexecdir / 'systemd-sysroot-fstab-check')
+
 if want_tests != 'false'
         test('test-fstab-generator',
              test_fstab_generator_sh,
index da7ea627f1536c1aa5100e00ddb29f0d9cec9240..e76de45a0faaa6e2b360010188d159ff4e1684cd 100644 (file)
@@ -5,6 +5,8 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-locator.h"
 #include "chase-symlinks.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -20,6 +22,7 @@
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
+#include "process-util.h"
 #include "special.h"
 #include "specifier.h"
 #include "stat-util.h"
@@ -39,6 +42,7 @@ typedef enum MountPointFlags {
         MOUNT_RW_ONLY   = 1 << 5,
 } MountPointFlags;
 
+static bool arg_sysroot_check = false;
 static const char *arg_dest = NULL;
 static const char *arg_dest_late = NULL;
 static bool arg_fstab_enabled = true;
@@ -119,6 +123,11 @@ static int add_swap(
                 return 0;
         }
 
+        if (arg_sysroot_check) {
+                log_info("%s should be enabled in the initrd, will request daemon-reload.", what);
+                return true;
+        }
+
         r = unit_name_from_path(what, ".swap", &name);
         if (r < 0)
                 return log_error_errno(r, "Failed to generate unit name: %m");
@@ -175,7 +184,7 @@ static int add_swap(
                         return r;
         }
 
-        return 0;
+        return true;
 }
 
 static bool mount_is_network(struct mntent *me) {
@@ -378,6 +387,11 @@ static int add_mount(
             mount_point_ignore(where))
                 return 0;
 
+        if (arg_sysroot_check) {
+                log_info("%s should be mounted in the initrd, will request daemon-reload.", where);
+                return true;
+        }
+
         r = fstab_filter_options(opts, "x-systemd.wanted-by\0", NULL, NULL, &wanted_by, NULL);
         if (r < 0)
                 return r;
@@ -567,7 +581,52 @@ static int add_mount(
                         return r;
         }
 
-        return 0;
+        return true;
+}
+
+static int do_daemon_reload(void) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r, k;
+
+        log_debug("Calling org.freedesktop.systemd1.Manager.Reload()...");
+
+        r = bus_connect_system_systemd(&bus);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get D-Bus connection: %m");
+
+        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
+
+        /* We need to requeue the two targets so that any new units which previously were not part of the
+         * targets, and which we now added, will be started. */
+
+        r = 0;
+        FOREACH_STRING(unit, SPECIAL_INITRD_FS_TARGET, SPECIAL_SWAP_TARGET) {
+                log_info("Requesting %s/start/replace...", unit);
+
+                k = sd_bus_call_method(bus,
+                                       "org.freedesktop.systemd1",
+                                       "/org/freedesktop/systemd1",
+                                       "org.freedesktop.systemd1.Manager",
+                                       "StartUnit",
+                                       &error,
+                                       NULL,
+                                       "ss", unit, "replace");
+                if (k < 0) {
+                        log_error_errno(k, "Failed to (re)start %s: %s", unit, bus_error_message(&error, r));
+                        if (r == 0)
+                                r = k;
+                }
+        }
+
+        return r;
 }
 
 static const char* sysroot_fstab_path(void) {
@@ -582,8 +641,10 @@ static int parse_fstab(bool initrd) {
 
         if (initrd)
                 fstab = sysroot_fstab_path();
-        else
+        else {
                 fstab = fstab_path();
+                assert(!arg_sysroot_check);
+        }
 
         log_debug("Parsing %s...", fstab);
 
@@ -700,6 +761,8 @@ static int parse_fstab(bool initrd) {
                                       target_unit);
                 }
 
+                if (arg_sysroot_check && k > 0)
+                        return true;  /* We found a mount or swap that would be started… */
                 if (r >= 0 && k < 0)
                         r = k;
         }
@@ -1126,12 +1189,14 @@ static int determine_usr(void) {
         return determine_device(&arg_usr_what, arg_usr_hash, "usr");
 }
 
-static int run(const char *dest, const char *dest_early, const char *dest_late) {
+/* If arg_sysroot_check is false, run as generator in the usual fashion.
+ * If it is true, check /sysroot/etc/fstab for any units that we'd want to mount
+ * in the initrd, and call daemon-reload. We will get reinvoked as a generator,
+ * with /sysroot/etc/fstab available, and then we can write additional units based
+ * on that file. */
+static int run_generator(void) {
         int r, r2 = 0, r3 = 0;
 
-        assert_se(arg_dest = dest);
-        assert_se(arg_dest_late = dest_late);
-
         r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
@@ -1139,6 +1204,15 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
         (void) determine_root();
         (void) determine_usr();
 
+        if (arg_sysroot_check) {
+                r = parse_fstab(true);
+                if (r == 0)
+                        log_debug("Nothing interesting found, not doing daemon-reload.");
+                if (r > 0)
+                        r = do_daemon_reload();
+                return r;
+        }
+
         /* Always honour root= and usr= in the kernel command line if we are in an initrd */
         if (in_initrd()) {
                 r = add_sysroot_mount();
@@ -1164,4 +1238,32 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
         return r < 0 ? r : r2 < 0 ? r2 : r3;
 }
 
-DEFINE_MAIN_GENERATOR_FUNCTION(run);
+static int run(int argc, char **argv) {
+        arg_sysroot_check = invoked_as(argv, "systemd-sysroot-fstab-check");
+
+        if (arg_sysroot_check) {
+                /* Run as in systemd-sysroot-fstab-check mode */
+                log_setup();
+
+                if (strv_length(argv) > 1)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "This program takes no arguments.");
+                if (!in_initrd())
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "This program is only useful in the initrd.");
+        } else {
+                /* Run in generator mode */
+                log_setup_generator();
+
+                if (!IN_SET(strv_length(argv), 2, 4))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "This program takes one or three arguments.");
+
+                arg_dest = ASSERT_PTR(argv[1]);
+                arg_dest_late = ASSERT_PTR(argv[argc > 3 ? 3 : 1]);
+        }
+
+        return run_generator();
+}
+
+DEFINE_MAIN_FUNCTION(run);