308 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			308 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 752ce62315bb38bd1267bd49dccc4dad2e9d05ee Mon Sep 17 00:00:00 2001
 | |
| From: Yu Watanabe <watanabe.yu+github@gmail.com>
 | |
| Date: Mon, 8 May 2023 19:49:33 +0900
 | |
| Subject: [PATCH] fstab-generator: support defining mount units through kernel
 | |
|  command line
 | |
| 
 | |
| Now, the following kernel command line options are supported:
 | |
|   systemd.mount-extra=what:where:fstype:options
 | |
|   systemd.swap-extra=what:options
 | |
| 
 | |
| Closes #27260.
 | |
| 
 | |
| (cherry picked from commit 55365b0a233ae3024411fd0815ad930e20f6a3d6)
 | |
| 
 | |
| Resolves: #2190226
 | |
| ---
 | |
|  man/systemd-fstab-generator.xml       |  27 +++++
 | |
|  src/fstab-generator/fstab-generator.c | 164 +++++++++++++++++++++++++-
 | |
|  2 files changed, 186 insertions(+), 5 deletions(-)
 | |
| 
 | |
| diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml
 | |
| index 30204f5d8a..b29022fab7 100644
 | |
| --- a/man/systemd-fstab-generator.xml
 | |
| +++ b/man/systemd-fstab-generator.xml
 | |
| @@ -239,6 +239,33 @@
 | |
|          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>
 | |
|  
 | |
| diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
 | |
| index c53feb6154..910e29d26b 100644
 | |
| --- a/src/fstab-generator/fstab-generator.c
 | |
| +++ b/src/fstab-generator/fstab-generator.c
 | |
| @@ -20,6 +20,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"
 | |
| @@ -43,6 +44,15 @@ typedef enum MountPointFlags {
 | |
|          MOUNT_RW_ONLY   = 1 << 5,
 | |
|  } 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;
 | |
| @@ -58,6 +68,8 @@ static char *arg_usr_fstype = NULL;
 | |
|  static char *arg_usr_options = NULL;
 | |
|  static char *arg_usr_hash = NULL;
 | |
|  static VolatileMode arg_volatile_mode = _VOLATILE_MODE_INVALID;
 | |
| +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);
 | |
| @@ -67,6 +79,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;
 | |
| @@ -109,12 +216,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;
 | |
|          }
 | |
|  
 | |
| @@ -687,7 +794,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;
 | |
| @@ -702,7 +810,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;
 | |
|          }
 | |
| @@ -830,7 +938,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)
 | |
| @@ -1129,6 +1239,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;
 | |
|  
 | |
| @@ -1225,6 +1357,24 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 | |
|                          log_warning("Failed to parse systemd.swap switch %s. Ignoring.", value);
 | |
|                  else
 | |
|                          arg_swap_enabled = 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;
 | |
| @@ -1318,6 +1468,10 @@ static int run_generator(void) {
 | |
|                          ret = r;
 | |
|          }
 | |
|  
 | |
| +        r = add_mounts_from_cmdline();
 | |
| +        if (r < 0 && ret >= 0)
 | |
| +                ret = r;
 | |
| +
 | |
|          return ret;
 | |
|  }
 | |
|  
 |