From 752ce62315bb38bd1267bd49dccc4dad2e9d05ee Mon Sep 17 00:00:00 2001 From: Yu Watanabe 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 /etc/fstab. Defaults to enabled. + + + systemd.mount-extra=WHAT:WHERE[:FSTYPE[:OPTIONS]] + + + Specifies the mount unit. Takes at least two and at most four fields separated with a colon + (:). Each field is handled as the corresponding fstab field. This option can be + specified multiple times. + Example: + +systemd.mount-extra=/dev/sda1:/mount-point:ext4:rw,noatime + + + + + + systemd.swap-extra=WHAT[:OPTIONS] + + + Specifies the swap unit. Takes the block device to be used as a swap device, and optionally + takes mount options followed by a colon (:). + Example: + +systemd.swap=/dev/sda2:x-systemd.makefs + + + 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; }