79dacd0
From 9f103625b145a397e67c3714766775b615c8b587 Mon Sep 17 00:00:00 2001
79dacd0
From: Tobias Hunger <tobias.hunger@gmail.com>
79dacd0
Date: Thu, 9 Oct 2014 21:37:17 +0200
79dacd0
Subject: [PATCH] fstab-generator: Honor mount.usr*= on kernel command line
79dacd0
79dacd0
This allows to configure boot loader entries for systems where the
79dacd0
root and usr filesystems are in different subvolumes (or even on
79dacd0
different drives).
79dacd0
---
79dacd0
 man/systemd-fstab-generator.xml       | 76 ++++++++++++++++++++++++++++-
79dacd0
 src/fstab-generator/fstab-generator.c | 90 +++++++++++++++++++++++++++++++++--
79dacd0
 2 files changed, 160 insertions(+), 6 deletions(-)
79dacd0
79dacd0
diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml
79dacd0
index e3cf5d2bfb..65b48eea07 100644
79dacd0
--- a/man/systemd-fstab-generator.xml
79dacd0
+++ b/man/systemd-fstab-generator.xml
79dacd0
@@ -104,9 +104,83 @@
79dacd0
                                 (initrd) while
79dacd0
                                 <varname>fstab=</varname> is
79dacd0
                                 honored by both the main system and
79dacd0
-                                the initrd.  </para></listitem>
79dacd0
+                                the initrd.</para></listitem>
79dacd0
                         </varlistentry>
79dacd0
+                        <varlistentry>
79dacd0
+                                <term><varname>root=</varname></term>
79dacd0
+
79dacd0
+                                <listitem><para>Takes the root filesystem to mount
79dacd0
+                                in the initrd.
79dacd0
+                                <varname>root=</varname> is
79dacd0
+                                honored by the initrd.</para></listitem>
79dacd0
+                        </varlistentry>
79dacd0
+                        <varlistentry>
79dacd0
+                                <term><varname>rootfstype=</varname></term>
79dacd0
+
79dacd0
+                                <listitem><para>Takes the root filesystem type that
79dacd0
+                                will be passed to the mount command.
79dacd0
+                                <varname>rootfstype=</varname> is
79dacd0
+                                honored by the initrd.</para></listitem>
79dacd0
+                        </varlistentry>
79dacd0
+                        <varlistentry>
79dacd0
+                                <term><varname>rootflags=</varname></term>
79dacd0
+
79dacd0
+                                <listitem><para>Takes the root filesystem mount options
79dacd0
+                                to use. <varname>rootflags=</varname> is
79dacd0
+                                honored by the initrd.</para></listitem>
79dacd0
+                        </varlistentry>
79dacd0
+                        <varlistentry>
79dacd0
+                                <term><varname>mount.usr=</varname></term>
79dacd0
+
79dacd0
+                                <listitem><para>Takes the <filename>/usr</filename>
79dacd0
+                                filesystem to be mounted by the initrd. If
79dacd0
+                                <varname>mount.usrfstype=</varname> or
79dacd0
+                                <varname>mount.usrflags=</varname> is set, then
79dacd0
+                                <varname>mount.usr=</varname> will default to the value set in
79dacd0
+                                <varname>root=</varname>.</para>
79dacd0
+
79dacd0
+                                <para>Otherwise this parameter defaults to the
79dacd0
+                                <filename>/usr</filename> entry
79dacd0
+                                found in <filename>/etc/fstab</filename> on the root
79dacd0
+                                filesystem.</para>
79dacd0
+
79dacd0
+                                <para><varname>mount.usr=</varname> is honored by the initrd.
79dacd0
+                                </para></listitem>
79dacd0
+                        </varlistentry>
79dacd0
+                        <varlistentry>
79dacd0
+                                <term><varname>mount.usrfstype=</varname></term>
79dacd0
+
79dacd0
+                                <listitem><para>Takes the <filename>/usr</filename>
79dacd0
+                                filesystem type that will be passed to the mount
79dacd0
+                                command. If <varname>mount.usr=</varname> or
79dacd0
+                                <varname>mount.usrflags=</varname> is set, then
79dacd0
+                                <varname>mount.usrfstype=</varname> will default to the value set in
79dacd0
+                                <varname>rootfstype=</varname>.</para>
79dacd0
+
79dacd0
+                                <para>Otherwise this value will be read from the
79dacd0
+                                <filename>/usr</filename> entry in
79dacd0
+                                <filename>/etc/fstab</filename> on the root filesystem.</para>
79dacd0
+
79dacd0
+                                <para><varname>mount.usrfstype=</varname> is
79dacd0
+                                honored by the initrd.</para></listitem>
79dacd0
+                        </varlistentry>
79dacd0
+                        <varlistentry>
79dacd0
+                                <term><varname>mount.usrflags=</varname></term>
79dacd0
+
79dacd0
+                                <listitem><para>Takes the <filename>/usr</filename>
79dacd0
+                                filesystem mount options to use. If
79dacd0
+                                <varname>mount.usr=</varname> or
79dacd0
+                                <varname>mount.usrfstype=</varname> is set, then
79dacd0
+                                <varname>mount.usrflages=</varname> will default to the value set in
79dacd0
+                                <varname>rootflags=</varname>.</para>
79dacd0
 
79dacd0
+                                <para>Otherwise this value will be read from the
79dacd0
+                                <filename>/usr</filename> entry in
79dacd0
+                                <filename>/etc/fstab</filename> on the root filesystem.</para>
79dacd0
+
79dacd0
+                                <para><varname>mount.usrflags=</varname> is
79dacd0
+                                honored by the initrd.</para></listitem>
79dacd0
+                        </varlistentry>
79dacd0
                 </variablelist>
79dacd0
         </refsect1>
79dacd0
 
79dacd0
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
79dacd0
index b75bbb7998..32a8f9bd51 100644
79dacd0
--- a/src/fstab-generator/fstab-generator.c
79dacd0
+++ b/src/fstab-generator/fstab-generator.c
79dacd0
@@ -43,6 +43,9 @@ static char *arg_root_what = NULL;
79dacd0
 static char *arg_root_fstype = NULL;
79dacd0
 static char *arg_root_options = NULL;
79dacd0
 static int arg_root_rw = -1;
79dacd0
+static char *arg_usr_what = NULL;
79dacd0
+static char *arg_usr_fstype = NULL;
79dacd0
+static char *arg_usr_options = NULL;
79dacd0
 
79dacd0
 
79dacd0
 static int mount_find_pri(struct mntent *me, int *ret) {
79dacd0
@@ -494,12 +497,64 @@ static int add_root_mount(void) {
79dacd0
                          "/proc/cmdline");
79dacd0
 }
79dacd0
 
79dacd0
+static int add_usr_mount(void) {
79dacd0
+        _cleanup_free_ char *what = NULL;
79dacd0
+        const char *opts;
79dacd0
+
79dacd0
+        if (!arg_usr_what && !arg_usr_fstype && !arg_usr_options)
79dacd0
+                return 0;
79dacd0
+
79dacd0
+        if (arg_root_what && !arg_usr_what) {
79dacd0
+                arg_usr_what = strdup(arg_root_what);
79dacd0
+
79dacd0
+                if (!arg_usr_what)
79dacd0
+                        return log_oom();
79dacd0
+        }
79dacd0
+
79dacd0
+        if (arg_root_fstype && !arg_usr_fstype) {
79dacd0
+                arg_usr_fstype = strdup(arg_root_fstype);
79dacd0
+
79dacd0
+                if (!arg_usr_fstype)
79dacd0
+                        return log_oom();
79dacd0
+        }
79dacd0
+
79dacd0
+        if (arg_root_options && !arg_usr_options) {
79dacd0
+                arg_usr_options = strdup(arg_root_options);
79dacd0
+
79dacd0
+                if (!arg_usr_options)
79dacd0
+                        return log_oom();
79dacd0
+        }
79dacd0
+
79dacd0
+        if (!arg_usr_what || !arg_usr_options)
79dacd0
+                return 0;
79dacd0
+
79dacd0
+        what = fstab_node_to_udev_node(arg_usr_what);
79dacd0
+        if (!path_is_absolute(what)) {
79dacd0
+                log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
79dacd0
+                return -1;
79dacd0
+        }
79dacd0
+
79dacd0
+        opts = arg_usr_options;
79dacd0
+
79dacd0
+        log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
79dacd0
+        return add_mount(what,
79dacd0
+                         "/sysroot/usr",
79dacd0
+                         arg_usr_fstype,
79dacd0
+                         opts,
79dacd0
+                         1,
79dacd0
+                         false,
79dacd0
+                         false,
79dacd0
+                         false,
79dacd0
+                         SPECIAL_INITRD_ROOT_FS_TARGET,
79dacd0
+                         "/proc/cmdline");
79dacd0
+}
79dacd0
+
79dacd0
 static int parse_proc_cmdline_item(const char *key, const char *value) {
79dacd0
         int r;
79dacd0
 
79dacd0
-        /* root= and roofstype= may occur more than once, the last
79dacd0
-         * instance should take precedence.  In the case of multiple
79dacd0
-         * rootflags= the arguments should be concatenated */
79dacd0
+        /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
79dacd0
+         * instance should take precedence.  In the case of multiple rootflags=
79dacd0
+         * or usrflags= the arguments should be concatenated */
79dacd0
 
79dacd0
         if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
79dacd0
 
79dacd0
@@ -531,6 +586,28 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
79dacd0
                 free(arg_root_options);
79dacd0
                 arg_root_options = o;
79dacd0
 
79dacd0
+        } else if (streq(key, "mount.usr") && value) {
79dacd0
+
79dacd0
+                if (free_and_strdup(&arg_usr_what, value) < 0)
79dacd0
+                        return log_oom();
79dacd0
+
79dacd0
+        } else if (streq(key, "mount.usrfstype") && value) {
79dacd0
+
79dacd0
+                if (free_and_strdup(&arg_usr_fstype, value) < 0)
79dacd0
+                        return log_oom();
79dacd0
+
79dacd0
+        } else if (streq(key, "mount.usrflags") && value) {
79dacd0
+                char *o;
79dacd0
+
79dacd0
+                o = arg_usr_options ?
79dacd0
+                        strjoin(arg_usr_options, ",", value, NULL) :
79dacd0
+                        strdup(value);
79dacd0
+                if (!o)
79dacd0
+                        return log_oom();
79dacd0
+
79dacd0
+                free(arg_usr_options);
79dacd0
+                arg_usr_options = o;
79dacd0
+
79dacd0
         } else if (streq(key, "rw") && !value)
79dacd0
                 arg_root_rw = true;
79dacd0
         else if (streq(key, "ro") && !value)
79dacd0
@@ -559,9 +636,12 @@ int main(int argc, char *argv[]) {
79dacd0
         if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
79dacd0
                 return EXIT_FAILURE;
79dacd0
 
79dacd0
-        /* Always honour root= in the kernel command line if we are in an initrd */
79dacd0
-        if (in_initrd())
79dacd0
+        /* Always honour root= and usr= in the kernel command line if we are in an initrd */
79dacd0
+        if (in_initrd()) {
79dacd0
                 r = add_root_mount();
79dacd0
+                if (r == 0)
79dacd0
+                        r = add_usr_mount();
79dacd0
+        }
79dacd0
 
79dacd0
         /* Honour /etc/fstab only when that's enabled */
79dacd0
         if (arg_fstab_enabled) {