1ff636
From 8f149756435998d009a8edc7206c5de038e5cbf1 Mon Sep 17 00:00:00 2001
1ff636
From: Karel Zak <kzak@redhat.com>
1ff636
Date: Mon, 18 May 2015 12:30:37 +0200
1ff636
Subject: [PATCH] fstab-generator: add x-systemd.requires and
1ff636
 x-systemd.requires-mounts-for
1ff636
1ff636
Currently we have no way how to specify dependencies between fstab
1ff636
entries (or another units) in the /etc/fstab. It means that users are
1ff636
forced to bypass fstab and write .mount units manually.
1ff636
1ff636
The patch introduces new systemd fstab options:
1ff636
1ff636
x-systemd.requires=<PATH>
1ff636
1ff636
 - to specify dependence an another mount (PATH is translated to unit name)
1ff636
1ff636
x-systemd.requires=<UNIT>
1ff636
1ff636
 - to specify dependence on arbitrary UNIT
1ff636
1ff636
x-systemd.requires-mounts-for=<PATH ...>
1ff636
1ff636
 - to specify dependence on another paths, implemented by
1ff636
   RequiresMountsFor=. The option may be specified more than once.
1ff636
1ff636
For example two bind mounts where B depends on A:
1ff636
1ff636
 /mnt/test/A    /mnt/test/A     none    bind,defaults
1ff636
 /mnt/test/A    /mnt/test/B     none    bind,x-systemd.requires=/mnt/test/A
1ff636
1ff636
More complex example with overlay FS where one mount point depends on
1ff636
"low" and "upper" directories:
1ff636
1ff636
 /dev/sdc1   /mnt/low    ext4     defaults
1ff636
 /dev/sdc2   /mnt/high   ext4     defaults
1ff636
 overlay     /mnt/merged overlay  lowerdir=/mnt/low,upperdir=/mnt/high/data,workdir=/mnt/high/work,x-systemd.requires-mounts-for=/mnt/low,x-systemd.requires-mounts-for=mnt/high
1ff636
1ff636
https://bugzilla.redhat.com/show_bug.cgi?id=812826
1ff636
https://bugzilla.redhat.com/show_bug.cgi?id=1164334
1ff636
1ff636
Conflicts:
1ff636
	src/fstab-generator/fstab-generator.c
1ff636
1ff636
Cherry-picked from: 3519d230c8bafe834b2dac26ace49fcfba139823
1ff636
Resolves: #1164334
1ff636
---
23b3cf
 man/systemd.mount.xml                 | 30 +++++++++++
23b3cf
 src/fstab-generator/fstab-generator.c | 76 +++++++++++++++++++++++++++
23b3cf
 src/shared/fstab-util.c               | 30 +++++++++++
1ff636
 src/shared/fstab-util.h               |  2 +
1ff636
 4 files changed, 138 insertions(+)
1ff636
1ff636
diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
Pablo Greco 48fc63
index fcb9a44161..8e652e1332 100644
1ff636
--- a/man/systemd.mount.xml
1ff636
+++ b/man/systemd.mount.xml
181b3f
@@ -138,6 +138,36 @@
181b3f
 
1ff636
     <variablelist class='fstab-options'>
1ff636
 
181b3f
+      <varlistentry>
1ff636
+        <term><option>x-systemd.requires=</option></term>
1ff636
+
1ff636
+        <listitem><para>Configures a <varname>Requires=</varname> and
1ff636
+        an <varname>After=</varname> dependency between the created
1ff636
+        mount unit and another systemd unit, such as a device or mount
1ff636
+        unit. The argument should be a unit name, or an absolute path
1ff636
+        to a device node or mount point.  This option may be specified
1ff636
+        more than once. This option is particularly useful for mount
1ff636
+        point declarations that need an additional device to be around
1ff636
+        (such as an external journal device for journal file systems)
1ff636
+        or an additional mount to be in place (such as an overlay file
1ff636
+        system that merges multiple mount points). See
1ff636
+        <varname>After=</varname> and <varname>Requires=</varname> in
1ff636
+        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
1ff636
+        for details.</para></listitem>
1ff636
+      </varlistentry>
1ff636
+
1ff636
+      <varlistentry>
1ff636
+        <term><option>x-systemd.requires-mounts-for=</option></term>
1ff636
+
1ff636
+        <listitem><para>Configures a
1ff636
+        <varname>RequiresMountsFor=</varname> dependency between the
1ff636
+        created mount unit and other mount units. The argument must be
1ff636
+        an absolute path. This option may be specified more than once.
1ff636
+        See <varname>RequiresMountsFor=</varname> in
1ff636
+        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
1ff636
+        for details.</para></listitem>
1ff636
+       </varlistentry>
1ff636
+
181b3f
       <varlistentry>
1ff636
         <term><option>x-systemd.automount</option></term>
1ff636
 
1ff636
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
Pablo Greco 48fc63
index 8e2f522bd0..65ed205799 100644
1ff636
--- a/src/fstab-generator/fstab-generator.c
1ff636
+++ b/src/fstab-generator/fstab-generator.c
1ff636
@@ -155,6 +155,64 @@ static bool mount_in_initrd(struct mntent *me) {
1ff636
                streq(me->mnt_dir, "/usr");
1ff636
 }
1ff636
 
1ff636
+static int write_requires_after(FILE *f, const char *opts) {
1ff636
+        _cleanup_strv_free_ char **names = NULL, **units = NULL;
1ff636
+        _cleanup_free_ char *res = NULL;
1ff636
+        char **s;
1ff636
+        int r;
1ff636
+
1ff636
+        assert(f);
1ff636
+        assert(opts);
1ff636
+
1ff636
+        r = fstab_extract_values(opts, "x-systemd.requires", &names);
1ff636
+        if (r < 0)
1ff636
+                return log_warning_errno(r, "Failed to parse options: %m");
1ff636
+        if (r == 0)
1ff636
+                return 0;
1ff636
+
1ff636
+        STRV_FOREACH(s, names) {
1ff636
+                char *x;
1ff636
+
1ff636
+                x = unit_name_mangle_with_suffix(*s, MANGLE_NOGLOB, ".mount");
1ff636
+                if (!x)
1ff636
+                        return log_error_errno(r, "Failed to generate unit name: %m");
1ff636
+                r = strv_consume(&units, x);
1ff636
+                if (r < 0)
1ff636
+                        return log_oom();
1ff636
+        }
1ff636
+
1ff636
+        if (units) {
1ff636
+                res = strv_join(units, " ");
1ff636
+                if (!res)
1ff636
+                        return log_oom();
1ff636
+                fprintf(f, "After=%1$s\nRequires=%1$s\n", res);
1ff636
+        }
1ff636
+
1ff636
+        return 0;
1ff636
+}
1ff636
+
1ff636
+static int write_requires_mounts_for(FILE *f, const char *opts) {
1ff636
+        _cleanup_strv_free_ char **paths = NULL;
1ff636
+        _cleanup_free_ char *res = NULL;
1ff636
+        int r;
1ff636
+
1ff636
+        assert(f);
1ff636
+        assert(opts);
1ff636
+
1ff636
+        r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths);
1ff636
+        if (r < 0)
1ff636
+                return log_warning_errno(r, "Failed to parse options: %m");
1ff636
+        if (r == 0)
1ff636
+                return 0;
1ff636
+
1ff636
+        res = strv_join(paths, " ");
1ff636
+        if (!res)
1ff636
+                return log_oom();
1ff636
+
1ff636
+        fprintf(f, "RequiresMountsFor=%s\n", res);
1ff636
+
1ff636
+        return 0;
1ff636
+}
1ff636
 static int add_mount(
1ff636
                 const char *what,
1ff636
                 const char *where,
1ff636
@@ -225,6 +283,15 @@ static int add_mount(
1ff636
         if (post && !noauto && !nofail && !automount)
1ff636
                 fprintf(f, "Before=%s\n", post);
1ff636
 
1ff636
+        if (!automount && opts) {
1ff636
+                 r = write_requires_after(f, opts);
1ff636
+                 if (r < 0)
1ff636
+                         return r;
1ff636
+                 r = write_requires_mounts_for(f, opts);
1ff636
+                 if (r < 0)
1ff636
+                         return r;
1ff636
+        }
1ff636
+
1ff636
         if (passno != 0) {
1ff636
                 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
1ff636
                 if (r < 0)
1ff636
@@ -289,6 +356,15 @@ static int add_mount(
1ff636
                                 "Before=%s\n",
1ff636
                                 post);
1ff636
 
1ff636
+                if (opts) {
1ff636
+                        r = write_requires_after(f, opts);
1ff636
+                        if (r < 0)
1ff636
+                                return r;
1ff636
+                        r = write_requires_mounts_for(f, opts);
1ff636
+                        if (r < 0)
1ff636
+                                return r;
1ff636
+                }
1ff636
+
1ff636
                 fprintf(f,
1ff636
                         "[Automount]\n"
1ff636
                         "Where=%s\n",
1ff636
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
Pablo Greco 48fc63
index cf317e17bd..e231a0ff80 100644
1ff636
--- a/src/shared/fstab-util.c
1ff636
+++ b/src/shared/fstab-util.c
1ff636
@@ -125,6 +125,36 @@ answer:
1ff636
         return !!n;
1ff636
 }
1ff636
 
1ff636
+int fstab_extract_values(const char *opts, const char *name, char ***values) {
1ff636
+        _cleanup_strv_free_ char **optsv = NULL, **res = NULL;
1ff636
+        char **s;
1ff636
+
1ff636
+        assert(opts);
1ff636
+        assert(name);
1ff636
+        assert(values);
1ff636
+
1ff636
+        optsv = strv_split(opts, ",");
1ff636
+        if (!optsv)
1ff636
+                return -ENOMEM;
1ff636
+
1ff636
+        STRV_FOREACH(s, optsv) {
1ff636
+                char *arg;
1ff636
+                int r;
1ff636
+
1ff636
+                arg = startswith(*s, name);
1ff636
+                if (!arg || *arg != '=')
1ff636
+                        continue;
1ff636
+                r = strv_extend(&res, arg + 1);
1ff636
+                if (r < 0)
1ff636
+                        return r;
1ff636
+        }
1ff636
+
1ff636
+        *values = res;
1ff636
+        res = NULL;
1ff636
+
1ff636
+        return !!*values;
1ff636
+}
1ff636
+
1ff636
 int fstab_find_pri(const char *options, int *ret) {
1ff636
         _cleanup_free_ char *opt = NULL;
1ff636
         int r;
1ff636
diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
Pablo Greco 48fc63
index 9f6b32eaf4..387c562a96 100644
1ff636
--- a/src/shared/fstab-util.h
1ff636
+++ b/src/shared/fstab-util.h
1ff636
@@ -28,6 +28,8 @@
1ff636
 int fstab_filter_options(const char *opts, const char *names,
1ff636
                          const char **namefound, char **value, char **filtered);
1ff636
 
1ff636
+int fstab_extract_values(const char *opts, const char *name, char ***values);
1ff636
+
1ff636
 static inline bool fstab_test_option(const char *opts, const char *names) {
1ff636
         return !!fstab_filter_options(opts, names, NULL, NULL, NULL);
1ff636
 }