]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fstab-generator: support defining mount units through kernel command line
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 8 May 2023 10:49:33 +0000 (19:49 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 23 May 2023 23:23:22 +0000 (08:23 +0900)
Now, the following kernel command line options are supported:
  systemd.mount-extra=what:where:fstype:options
  systemd.swap-extra=what:options

Closes #27260.

man/systemd-fstab-generator.xml
src/fstab-generator/fstab-generator.c

index 30204f5d8aec4f5eb9235901184c5e614e8fe213..b29022fab75a1a6877a102808b58e75bf6209c96 100644 (file)
         any swap devices configured in <filename>/etc/fstab</filename>.
         Defaults to enabled.</para></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>systemd.mount-extra=<replaceable>WHAT</replaceable>:<replaceable>WHERE</replaceable>[:<replaceable>FSTYPE</replaceable>[:<replaceable>OPTIONS</replaceable>]]</varname></term>
+
+        <listitem>
+          <para>Specifies the mount unit. Takes at least two and at most four fields separated with a colon
+          (<literal>:</literal>). Each field is handled as the corresponding fstab field. This option can be
+          specified multiple times.</para>
+          <para>Example:
+          <programlisting>
+systemd.mount-extra=/dev/sda1:/mount-point:ext4:rw,noatime</programlisting>
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>systemd.swap-extra=<replaceable>WHAT</replaceable>[:<replaceable>OPTIONS</replaceable>]</varname></term>
+
+        <listitem>
+          <para>Specifies the swap unit. Takes the block device to be used as a swap device, and optionally
+          takes mount options followed by a colon (<literal>:</literal>).</para>
+          <para>Example:
+          <programlisting>
+systemd.swap=/dev/sda2:x-systemd.makefs</programlisting>
+          </para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index a2dc1a524d085cb67d9879d16caed89ac2ac6a8c..6337bc235f53cde937e940da992cc2969c49d43a 100644 (file)
@@ -22,6 +22,7 @@
 #include "mount-setup.h"
 #include "mount-util.h"
 #include "mountpoint-util.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
@@ -45,6 +46,15 @@ typedef enum MountPointFlags {
         MOUNT_PCRFS     = 1 << 6,
 } MountPointFlags;
 
+typedef struct Mount {
+        char *what;
+        char *where;
+        char *fstype;
+        char *options;
+} Mount;
+
+static void mount_array_free(Mount *mounts, size_t n);
+
 static bool arg_sysroot_check = false;
 static const char *arg_dest = NULL;
 static const char *arg_dest_late = NULL;
@@ -61,6 +71,8 @@ static char *arg_usr_options = NULL;
 static char *arg_usr_hash = NULL;
 static VolatileMode arg_volatile_mode = _VOLATILE_MODE_INVALID;
 static bool arg_verity = true;
+static Mount *arg_mounts = NULL;
+static size_t arg_n_mounts = 0;
 
 STATIC_DESTRUCTOR_REGISTER(arg_root_what, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_root_fstype, freep);
@@ -70,6 +82,101 @@ STATIC_DESTRUCTOR_REGISTER(arg_usr_what, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_usr_fstype, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_usr_options, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_usr_hash, freep);
+STATIC_ARRAY_DESTRUCTOR_REGISTER(arg_mounts, arg_n_mounts, mount_array_free);
+
+static void mount_done(Mount *m) {
+        assert(m);
+
+        free(m->what);
+        free(m->where);
+        free(m->fstype);
+        free(m->options);
+}
+
+static void mount_array_free(Mount *mounts, size_t n) {
+        FOREACH_ARRAY(m, mounts, n)
+                mount_done(m);
+
+        free(mounts);
+}
+
+static int mount_array_add_internal(char *in_what, char *in_where, const char *in_fstype, const char *in_options) {
+        _cleanup_free_ char *what = NULL, *where = NULL, *fstype = NULL, *options = NULL;
+        int r;
+
+        /* This takes what and where. */
+
+        what = ASSERT_PTR(in_what);
+        where = in_where;
+
+        fstype = strdup(isempty(in_fstype) ? "auto" : in_fstype);
+        if (!fstype)
+                return -ENOMEM;
+
+        if (streq(fstype, "swap"))
+                where = mfree(where);
+
+        if (!isempty(in_options)) {
+                _cleanup_strv_free_ char **options_strv = NULL;
+
+                r = strv_split_full(&options_strv, in_options, ",", 0);
+                if (r < 0)
+                        return r;
+
+                r = strv_make_nulstr(options_strv, &options, NULL);
+        } else
+                r = strv_make_nulstr(STRV_MAKE("defaults"), &options, NULL);
+        if (r < 0)
+                return r;
+
+        if (!GREEDY_REALLOC(arg_mounts, arg_n_mounts + 1))
+                return -ENOMEM;
+
+        arg_mounts[arg_n_mounts++] = (Mount) {
+                .what = TAKE_PTR(what),
+                .where = TAKE_PTR(where),
+                .fstype = TAKE_PTR(fstype),
+                .options = TAKE_PTR(options),
+        };
+
+        return 0;
+}
+
+static int mount_array_add(const char *str) {
+        _cleanup_free_ char *what = NULL, *where = NULL, *fstype = NULL, *options = NULL;
+        int r;
+
+        assert(str);
+
+        r = extract_many_words(&str, ":", EXTRACT_CUNESCAPE | EXTRACT_DONT_COALESCE_SEPARATORS,
+                               &what, &where, &fstype, &options, NULL);
+        if (r < 0)
+                return r;
+        if (r < 2)
+                return -EINVAL;
+        if (!isempty(str))
+                return -EINVAL;
+
+        return mount_array_add_internal(TAKE_PTR(what), TAKE_PTR(where), fstype, options);
+}
+
+static int mount_array_add_swap(const char *str) {
+        _cleanup_free_ char *what = NULL, *options = NULL;
+        int r;
+
+        assert(str);
+
+        r = extract_many_words(&str, ":", EXTRACT_CUNESCAPE | EXTRACT_DONT_COALESCE_SEPARATORS,
+                               &what, &options, NULL);
+        if (r < 0)
+                return r;
+        if (r < 1)
+                return -EINVAL;
+        if (!isempty(str))
+                return -EINVAL;
+
+        return mount_array_add_internal(TAKE_PTR(what), NULL, "swap", options);
+}
 
 static int write_options(FILE *f, const char *options) {
         _cleanup_free_ char *o = NULL;
@@ -112,12 +219,12 @@ static int add_swap(
         assert(what);
 
         if (access("/proc/swaps", F_OK) < 0) {
-                log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
+                log_info("Swap not supported, ignoring swap entry for %s.", what);
                 return 0;
         }
 
         if (detect_container() > 0) {
-                log_info("Running in a container, ignoring fstab swap entry for %s.", what);
+                log_info("Running in a container, ignoring swap entry for %s.", what);
                 return 0;
         }
 
@@ -698,7 +805,8 @@ static int parse_fstab_one(
                 const char *fstype,
                 const char *options,
                 int passno,
-                bool initrd) {
+                bool initrd,
+                bool use_swap_enabled) {
 
         _cleanup_free_ char *what = NULL, *where = NULL;
         MountPointFlags flags;
@@ -713,7 +821,7 @@ static int parse_fstab_one(
                 return 0;
 
         is_swap = streq_ptr(fstype, "swap");
-        if (is_swap && !arg_swap_enabled) {
+        if (is_swap && use_swap_enabled && !arg_swap_enabled) {
                 log_info("Swap unit generation disabled on kernel command line, ignoring swap entry for %s.", what);
                 return 0;
         }
@@ -841,7 +949,9 @@ static int parse_fstab(bool initrd) {
         }
 
         while ((me = getmntent(f))) {
-                r = parse_fstab_one(fstab, me->mnt_fsname, me->mnt_dir, me->mnt_type, me->mnt_opts, me->mnt_passno, initrd);
+                r = parse_fstab_one(fstab,
+                                    me->mnt_fsname, me->mnt_dir, me->mnt_type, me->mnt_opts, me->mnt_passno,
+                                    initrd, /* use_swap_enabled = */ true);
                 if (r < 0 && ret >= 0)
                         ret = r;
                 if (arg_sysroot_check && r > 0)
@@ -1149,6 +1259,28 @@ static int add_volatile_var(void) {
                          SPECIAL_LOCAL_FS_TARGET);
 }
 
+static int add_mounts_from_cmdline(void) {
+        int r, ret = 0;
+
+        /* Handle each entries found in cmdline as a fstab entry. */
+
+        FOREACH_ARRAY(m, arg_mounts, arg_n_mounts) {
+                r = parse_fstab_one(
+                              "/proc/cmdline",
+                              m->what,
+                              m->where,
+                              m->fstype,
+                              m->options,
+                              /* passno = */ 0,
+                              /* initrd = */ false,
+                              /* use_swap_enabled = */ false);
+                if (r < 0 && ret >= 0)
+                        ret = r;
+        }
+
+        return ret;
+}
+
 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
         int r;
 
@@ -1253,6 +1385,24 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                         log_warning("Failed to parse systemd.verity= kernel command line switch %s. Ignoring.", value);
                 else
                         arg_verity = r;
+
+        } else if (streq(key, "systemd.mount-extra")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                r = mount_array_add(value);
+                if (r < 0)
+                        log_warning("Failed to parse systemd.mount-extra= option, ignoring: %s", value);
+
+        } else if (streq(key, "systemd.swap-extra")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                r = mount_array_add_swap(value);
+                if (r < 0)
+                        log_warning("Failed to parse systemd.swap-extra= option, ignoring: %s", value);
         }
 
         return 0;
@@ -1349,6 +1499,10 @@ static int run_generator(void) {
                         ret = r;
         }
 
+        r = add_mounts_from_cmdline();
+        if (r < 0 && ret >= 0)
+                ret = r;
+
         return ret;
 }