mirror of
https://github.com/systemd/systemd.git
synced 2025-01-23 02:04:32 +03:00
fstab-generator: add x-systemd.requires and x-systemd.requires-mounts-for
Currently we have no way how to specify dependencies between fstab entries (or another units) in the /etc/fstab. It means that users are forced to bypass fstab and write .mount units manually. The patch introduces new systemd fstab options: x-systemd.requires=<PATH> - to specify dependence an another mount (PATH is translated to unit name) x-systemd.requires=<UNIT> - to specify dependence on arbitrary UNIT x-systemd.requires-mounts-for=<PATH ...> - to specify dependence on another paths, implemented by RequiresMountsFor=. The option may be specified more than once. For example two bind mounts where B depends on A: /mnt/test/A /mnt/test/A none bind,defaults /mnt/test/A /mnt/test/B none bind,x-systemd.requires=/mnt/test/A More complex example with overlay FS where one mount point depends on "low" and "upper" directories: /dev/sdc1 /mnt/low ext4 defaults /dev/sdc2 /mnt/high ext4 defaults 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 https://bugzilla.redhat.com/show_bug.cgi?id=812826 https://bugzilla.redhat.com/show_bug.cgi?id=1164334
This commit is contained in:
parent
06ee4910e4
commit
3519d230c8
@ -138,6 +138,36 @@
|
||||
|
||||
<variablelist class='fstab-options'>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>x-systemd.requires=</option></term>
|
||||
|
||||
<listitem><para>Configures a <varname>Requires=</varname> and
|
||||
an <varname>After=</varname> dependency between the created
|
||||
mount unit and another systemd unit, such as a device or mount
|
||||
unit. The argument should be a unit name, or an absolute path
|
||||
to a device node or mount point. This option may be specified
|
||||
more than once. This option is particularly useful for mount
|
||||
point declarations that need an additional device to be around
|
||||
(such as an external journal device for journal file systems)
|
||||
or an additional mount to be in place (such as an overlay file
|
||||
system that merges multiple mount points). See
|
||||
<varname>After=</varname> and <varname>Requires=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>x-systemd.requires-mounts-for=</option></term>
|
||||
|
||||
<listitem><para>Configures a
|
||||
<varname>RequiresMountsFor=</varname> dependency between the
|
||||
created mount unit and other mount units. The argument must be
|
||||
an absolute path. This option may be specified more than once.
|
||||
See <varname>RequiresMountsFor=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>x-systemd.automount</option></term>
|
||||
|
||||
|
@ -177,6 +177,65 @@ static int write_idle_timeout(FILE *f, const char *where, const char *opts) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_requires_after(FILE *f, const char *opts) {
|
||||
_cleanup_strv_free_ char **names = NULL, **units = NULL;
|
||||
_cleanup_free_ char *res = NULL;
|
||||
char **s;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
assert(opts);
|
||||
|
||||
r = fstab_extract_values(opts, "x-systemd.requires", &names);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to parse options: %m");
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
STRV_FOREACH(s, names) {
|
||||
char *x;
|
||||
|
||||
r = unit_name_mangle_with_suffix(*s, UNIT_NAME_NOGLOB, ".mount", &x);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate unit name: %m");
|
||||
r = strv_consume(&units, x);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (units) {
|
||||
res = strv_join(units, " ");
|
||||
if (!res)
|
||||
return log_oom();
|
||||
fprintf(f, "After=%1$s\nRequires=%1$s\n", res);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_requires_mounts_for(FILE *f, const char *opts) {
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
_cleanup_free_ char *res = NULL;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
assert(opts);
|
||||
|
||||
r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to parse options: %m");
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
res = strv_join(paths, " ");
|
||||
if (!res)
|
||||
return log_oom();
|
||||
|
||||
fprintf(f, "RequiresMountsFor=%s\n", res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_mount(
|
||||
const char *what,
|
||||
const char *where,
|
||||
@ -251,6 +310,15 @@ static int add_mount(
|
||||
if (post && !noauto && !nofail && !automount)
|
||||
fprintf(f, "Before=%s\n", post);
|
||||
|
||||
if (!automount && opts) {
|
||||
r = write_requires_after(f, opts);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = write_requires_mounts_for(f, opts);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (passno != 0) {
|
||||
r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
|
||||
if (r < 0)
|
||||
@ -315,6 +383,15 @@ static int add_mount(
|
||||
"Before=%s\n",
|
||||
post);
|
||||
|
||||
if (opts) {
|
||||
r = write_requires_after(f, opts);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = write_requires_mounts_for(f, opts);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
fprintf(f,
|
||||
"[Automount]\n"
|
||||
"Where=%s\n",
|
||||
|
@ -125,6 +125,36 @@ answer:
|
||||
return !!n;
|
||||
}
|
||||
|
||||
int fstab_extract_values(const char *opts, const char *name, char ***values) {
|
||||
_cleanup_strv_free_ char **optsv = NULL, **res = NULL;
|
||||
char **s;
|
||||
|
||||
assert(opts);
|
||||
assert(name);
|
||||
assert(values);
|
||||
|
||||
optsv = strv_split(opts, ",");
|
||||
if (!optsv)
|
||||
return -ENOMEM;
|
||||
|
||||
STRV_FOREACH(s, optsv) {
|
||||
char *arg;
|
||||
int r;
|
||||
|
||||
arg = startswith(*s, name);
|
||||
if (!arg || *arg != '=')
|
||||
continue;
|
||||
r = strv_extend(&res, arg + 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*values = res;
|
||||
res = NULL;
|
||||
|
||||
return !!*values;
|
||||
}
|
||||
|
||||
int fstab_find_pri(const char *options, int *ret) {
|
||||
_cleanup_free_ char *opt = NULL;
|
||||
int r;
|
||||
|
@ -28,6 +28,8 @@
|
||||
int fstab_filter_options(const char *opts, const char *names,
|
||||
const char **namefound, char **value, char **filtered);
|
||||
|
||||
int fstab_extract_values(const char *opts, const char *name, char ***values);
|
||||
|
||||
static inline bool fstab_test_option(const char *opts, const char *names) {
|
||||
return !!fstab_filter_options(opts, names, NULL, NULL, NULL);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user