summaryrefslogtreecommitdiffstats
path: root/src/fstab-generator/fstab-generator.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fstab-generator/fstab-generator.c')
-rw-r--r--src/fstab-generator/fstab-generator.c253
1 files changed, 149 insertions, 104 deletions
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 016f3ba..b4df9d2 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -46,6 +46,7 @@ typedef enum MountPointFlags {
MOUNT_GROWFS = 1 << 4,
MOUNT_RW_ONLY = 1 << 5,
MOUNT_PCRFS = 1 << 6,
+ MOUNT_QUOTA = 1 << 7,
} MountPointFlags;
typedef struct Mount {
@@ -159,7 +160,7 @@ static int mount_array_add(bool for_initrd, const char *str) {
assert(str);
r = extract_many_words(&str, ":", EXTRACT_CUNESCAPE | EXTRACT_DONT_COALESCE_SEPARATORS,
- &what, &where, &fstype, &options, NULL);
+ &what, &where, &fstype, &options);
if (r < 0)
return r;
if (r < 2)
@@ -177,7 +178,7 @@ static int mount_array_add_swap(bool for_initrd, const char *str) {
assert(str);
r = extract_many_words(&str, ":", EXTRACT_CUNESCAPE | EXTRACT_DONT_COALESCE_SEPARATORS,
- &what, &options, NULL);
+ &what, &options);
if (r < 0)
return r;
if (r < 1)
@@ -191,6 +192,8 @@ static int mount_array_add_swap(bool for_initrd, const char *str) {
static int write_options(FILE *f, const char *options) {
_cleanup_free_ char *o = NULL;
+ assert(f);
+
if (isempty(options))
return 0;
@@ -208,6 +211,9 @@ static int write_options(FILE *f, const char *options) {
static int write_what(FILE *f, const char *what) {
_cleanup_free_ char *w = NULL;
+ assert(f);
+ assert(what);
+
w = specifier_escape(what);
if (!w)
return log_oom();
@@ -324,25 +330,30 @@ static int write_timeout(
const char *where,
const char *opts,
const char *filter,
- const char *variable) {
+ const char *unit_setting) {
_cleanup_free_ char *timeout = NULL;
usec_t u;
int r;
+ assert(f);
+ assert(where);
+ assert(filter);
+ assert(unit_setting);
+
r = fstab_filter_options(opts, filter, NULL, &timeout, NULL, NULL);
if (r < 0)
- return log_warning_errno(r, "Failed to parse options: %m");
+ return log_error_errno(r, "Failed to parse options for '%s': %m", where);
if (r == 0)
return 0;
r = parse_sec_fix_0(timeout, &u);
if (r < 0) {
- log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
+ log_warning_errno(r, "Failed to parse timeout '%s' for '%s', ignoring: %m", timeout, where);
return 0;
}
- fprintf(f, "%s=%s\n", variable, FORMAT_TIMESPAN(u, 0));
+ fprintf(f, "%s=%s\n", unit_setting, FORMAT_TIMESPAN(u, 0));
return 0;
}
@@ -359,109 +370,118 @@ static int write_mount_timeout(FILE *f, const char *where, const char *opts) {
static int write_dependency(
FILE *f,
+ const char *where,
const char *opts,
const char *filter,
- const char *format) {
+ const char* const *unit_settings) {
- _cleanup_strv_free_ char **names = NULL, **units = NULL;
- _cleanup_free_ char *res = NULL;
+ _cleanup_strv_free_ char **unit_names = NULL;
+ _cleanup_free_ char *units = NULL;
int r;
assert(f);
- assert(opts);
+ assert(filter);
+ assert(unit_settings);
- r = fstab_filter_options(opts, filter, NULL, NULL, &names, NULL);
+ r = fstab_filter_options(opts, filter, NULL, NULL, &unit_names, NULL);
if (r < 0)
- return log_warning_errno(r, "Failed to parse options: %m");
+ return log_error_errno(r, "Failed to parse options for '%s': %m", where);
if (r == 0)
return 0;
- STRV_FOREACH(s, names) {
- char *x;
+ STRV_FOREACH(s, unit_names) {
+ _cleanup_free_ char *mangled = NULL;
- r = unit_name_mangle_with_suffix(*s, "as dependency", 0, ".mount", &x);
+ r = unit_name_mangle_with_suffix(*s, "as dependency", 0, ".mount", &mangled);
if (r < 0)
- return log_error_errno(r, "Failed to generate unit name: %m");
+ return log_error_errno(r, "Failed to generate dependency unit name for '%s': %m", where);
- r = strv_consume(&units, x);
- if (r < 0)
+ if (!strextend_with_separator(&units, " ", mangled))
return log_oom();
}
- if (units) {
- res = strv_join(units, " ");
- if (!res)
- return log_oom();
-
- DISABLE_WARNING_FORMAT_NONLITERAL;
- fprintf(f, format, res);
- REENABLE_WARNING;
- }
+ STRV_FOREACH(setting, unit_settings)
+ fprintf(f, "%s=%s\n", *setting, units);
return 0;
}
-static int write_after(FILE *f, const char *opts) {
- return write_dependency(f, opts,
- "x-systemd.after\0", "After=%1$s\n");
+static int write_after(FILE *f, const char *where, const char *opts) {
+ return write_dependency(f, where, opts,
+ "x-systemd.after\0", STRV_MAKE_CONST("After"));
}
-static int write_requires_after(FILE *f, const char *opts) {
- return write_dependency(f, opts,
- "x-systemd.requires\0", "After=%1$s\nRequires=%1$s\n");
+static int write_requires_after(FILE *f, const char *where, const char *opts) {
+ return write_dependency(f, where, opts,
+ "x-systemd.requires\0", STRV_MAKE_CONST("Requires", "After"));
}
-static int write_before(FILE *f, const char *opts) {
- return write_dependency(f, opts,
- "x-systemd.before\0", "Before=%1$s\n");
+static int write_before(FILE *f, const char *where, const char *opts) {
+ return write_dependency(f, where, opts,
+ "x-systemd.before\0", STRV_MAKE_CONST("Before"));
}
-static int write_requires_mounts_for(FILE *f, const char *opts) {
+static int write_mounts_for(
+ FILE *f,
+ const char *where,
+ const char *opts,
+ const char *filter,
+ const char *unit_setting) {
+
_cleanup_strv_free_ char **paths = NULL, **paths_escaped = NULL;
- _cleanup_free_ char *res = NULL;
int r;
assert(f);
- assert(opts);
+ assert(where);
+ assert(filter);
+ assert(unit_setting);
- r = fstab_filter_options(opts, "x-systemd.requires-mounts-for\0", NULL, NULL, &paths, NULL);
+ r = fstab_filter_options(opts, filter, NULL, NULL, &paths, NULL);
if (r < 0)
- return log_warning_errno(r, "Failed to parse options: %m");
+ return log_error_errno(r, "Failed to parse options for '%s': %m", where);
if (r == 0)
return 0;
r = specifier_escape_strv(paths, &paths_escaped);
if (r < 0)
- return log_error_errno(r, "Failed to escape paths: %m");
-
- res = strv_join(paths_escaped, " ");
- if (!res)
- return log_oom();
+ return log_error_errno(r, "Failed to escape paths for '%s': %m", where);
- fprintf(f, "RequiresMountsFor=%s\n", res);
+ fprintf(f, "%s=", unit_setting);
+ fputstrv(f, paths_escaped, NULL, NULL);
+ fputc('\n', f);
return 0;
}
-static int write_extra_dependencies(FILE *f, const char *opts) {
+static int write_extra_dependencies(FILE *f, const char *where, const char *opts) {
int r;
assert(f);
- if (opts) {
- r = write_after(f, opts);
- if (r < 0)
- return r;
- r = write_requires_after(f, opts);
- if (r < 0)
- return r;
- r = write_before(f, opts);
- if (r < 0)
- return r;
- r = write_requires_mounts_for(f, opts);
- if (r < 0)
- return r;
- }
+ if (isempty(opts))
+ return 0;
+
+ r = write_after(f, where, opts);
+ if (r < 0)
+ return r;
+
+ r = write_requires_after(f, where, opts);
+ if (r < 0)
+ return r;
+
+ r = write_before(f, where, opts);
+ if (r < 0)
+ return r;
+
+ r = write_mounts_for(f, where, opts,
+ "x-systemd.requires-mounts-for\0", "RequiresMountsFor");
+ if (r < 0)
+ return r;
+
+ r = write_mounts_for(f, where, opts,
+ "x-systemd.wants-mounts-for\0", "WantsMountsFor");
+ if (r < 0)
+ return r;
return 0;
}
@@ -476,19 +496,10 @@ static int mandatory_mount_drop_unapplicable_options(
assert(flags);
assert(where);
- assert(options);
assert(ret_options);
- if (!(*flags & (MOUNT_NOAUTO|MOUNT_NOFAIL|MOUNT_AUTOMOUNT))) {
- _cleanup_free_ char *opts = NULL;
-
- opts = strdup(options);
- if (!opts)
- return -ENOMEM;
-
- *ret_options = TAKE_PTR(opts);
- return 0;
- }
+ if (!(*flags & (MOUNT_NOAUTO|MOUNT_NOFAIL|MOUNT_AUTOMOUNT)))
+ return strdup_to(ret_options, options);
log_debug("Mount '%s' is mandatory, ignoring 'noauto', 'nofail', and 'x-systemd.automount' options.",
where);
@@ -522,7 +533,6 @@ static int add_mount(
assert(what);
assert(where);
- assert(opts);
assert(target_unit);
assert(source);
@@ -551,16 +561,16 @@ static int add_mount(
if (r < 0)
return r;
- if (path_equal(where, "/")) {
+ if (PATH_IN_SET(where, "/", "/usr")) {
r = mandatory_mount_drop_unapplicable_options(&flags, where, opts, &opts_root_filtered);
if (r < 0)
return r;
opts = opts_root_filtered;
if (!strv_isempty(wanted_by))
- log_debug("Ignoring 'x-systemd.wanted-by=' option for root device.");
+ log_debug("Ignoring 'x-systemd.wanted-by=' option for root/usr device.");
if (!strv_isempty(required_by))
- log_debug("Ignoring 'x-systemd.required-by=' option for root device.");
+ log_debug("Ignoring 'x-systemd.required-by=' option for root/usr device.");
required_by = strv_free(required_by);
wanted_by = strv_free(wanted_by);
@@ -594,13 +604,25 @@ static int add_mount(
SET_FLAG(flags, MOUNT_NOFAIL, true);
}
- r = write_extra_dependencies(f, opts);
+ if (!strv_isempty(wanted_by) || !strv_isempty(required_by)) {
+ /* If x-systemd.{wanted,required}-by= is specified, target_unit is not used */
+ target_unit = NULL;
+
+ /* Don't set default ordering dependencies on local-fs.target or remote-fs.target, but we
+ * still need to conflict with umount.target. */
+ fputs("DefaultDependencies=no\n"
+ "Conflicts=umount.target\n"
+ "Before=umount.target\n",
+ f);
+ }
+
+ r = write_extra_dependencies(f, where, opts);
if (r < 0)
return r;
/* Order the mount unit we generate relative to target_unit, so that DefaultDependencies= on the
* target unit won't affect us. */
- if (!FLAGS_SET(flags, MOUNT_NOFAIL))
+ if (target_unit && !FLAGS_SET(flags, MOUNT_NOFAIL))
fprintf(f, "Before=%s\n", target_unit);
if (passno != 0) {
@@ -691,26 +713,19 @@ static int add_mount(
}
}
- if (!FLAGS_SET(flags, MOUNT_AUTOMOUNT)) {
- if (!FLAGS_SET(flags, MOUNT_NOAUTO) && strv_isempty(wanted_by) && strv_isempty(required_by)) {
- r = generator_add_symlink(dest, target_unit,
- (flags & MOUNT_NOFAIL) ? "wants" : "requires", name);
- if (r < 0)
+ if (flags & MOUNT_QUOTA) {
+ r = generator_hook_up_quotacheck(dest, what, where, target_unit, fstype);
+ if (r < 0) {
+ if (r != -EOPNOTSUPP)
return r;
} else {
- STRV_FOREACH(s, wanted_by) {
- r = generator_add_symlink(dest, *s, "wants", name);
- if (r < 0)
- return r;
- }
-
- STRV_FOREACH(s, required_by) {
- r = generator_add_symlink(dest, *s, "requires", name);
- if (r < 0)
- return r;
- }
+ r = generator_hook_up_quotaon(dest, where, target_unit);
+ if (r < 0)
+ return r;
}
- } else {
+ }
+
+ if (FLAGS_SET(flags, MOUNT_AUTOMOUNT)) {
r = unit_name_from_path(where, ".automount", &automount_name);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
@@ -740,11 +755,37 @@ static int add_mount(
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", automount_name);
+ }
- r = generator_add_symlink(dest, target_unit,
- (flags & MOUNT_NOFAIL) ? "wants" : "requires", automount_name);
- if (r < 0)
- return r;
+ if (target_unit) {
+ assert(strv_isempty(wanted_by));
+ assert(strv_isempty(required_by));
+
+ /* noauto has no effect if x-systemd.automount is used */
+ if (!FLAGS_SET(flags, MOUNT_NOAUTO) || automount_name) {
+ r = generator_add_symlink(dest, target_unit,
+ FLAGS_SET(flags, MOUNT_NOFAIL) ? "wants" : "requires",
+ automount_name ?: name);
+ if (r < 0)
+ return r;
+ }
+ } else {
+ const char *unit_name = automount_name ?: name;
+
+ STRV_FOREACH(s, wanted_by) {
+ r = generator_add_symlink(dest, *s, "wants", unit_name);
+ if (r < 0)
+ return r;
+ }
+
+ STRV_FOREACH(s, required_by) {
+ r = generator_add_symlink(dest, *s, "requires", unit_name);
+ if (r < 0)
+ return r;
+ }
+
+ if ((flags & (MOUNT_NOAUTO|MOUNT_NOFAIL)) != 0)
+ log_warning("x-systemd.wanted-by= and/or x-systemd.required-by= specified, 'noauto' and 'nofail' have no effect.");
}
return true;
@@ -791,7 +832,7 @@ static bool sysfs_check(void) {
int r;
if (cached < 0) {
- r = getenv_bool_secure("SYSTEMD_SYSFS_CHECK");
+ r = secure_getenv_bool("SYSTEMD_SYSFS_CHECK");
if (r < 0 && r != -ENXIO)
log_debug_errno(r, "Failed to parse $SYSTEMD_SYSFS_CHECK, ignoring: %m");
cached = r != 0;
@@ -816,12 +857,17 @@ static int add_sysusr_sysroot_usr_bind_mount(const char *source) {
static MountPointFlags fstab_options_to_flags(const char *options, bool is_swap) {
MountPointFlags flags = 0;
+ if (isempty(options))
+ return 0;
+
if (fstab_test_option(options, "x-systemd.makefs\0"))
flags |= MOUNT_MAKEFS;
if (fstab_test_option(options, "x-systemd.growfs\0"))
flags |= MOUNT_GROWFS;
if (fstab_test_option(options, "x-systemd.pcrfs\0"))
flags |= MOUNT_PCRFS;
+ if (fstab_test_option(options, "usrquota\0" "grpquota\0" "quota\0" "usrjquota\0" "grpjquota\0" "prjquota\0"))
+ flags |= MOUNT_QUOTA;
if (fstab_test_yes_no_option(options, "noauto\0" "auto\0"))
flags |= MOUNT_NOAUTO;
if (fstab_test_yes_no_option(options, "nofail\0" "fail\0"))
@@ -891,7 +937,6 @@ static int parse_fstab_one(
assert(what_original);
assert(fstype);
- assert(options);
if (prefix_sysroot && !mount_in_initrd(where_original, options, accept_root))
return 0;
@@ -1175,7 +1220,7 @@ static int add_sysroot_mount(void) {
fstype,
opts,
is_device_path(what) ? 1 : 0, /* passno */
- flags, /* makefs off, pcrfs off, noauto off, nofail off, automount off */
+ flags, /* makefs off, pcrfs off, quota off, noauto off, nofail off, automount off */
SPECIAL_INITRD_ROOT_FS_TARGET);
}
@@ -1563,7 +1608,7 @@ static int determine_usr(void) {
* with /sysroot/etc/fstab available, and then we can write additional units based
* on that file. */
static int run_generator(void) {
- int r = 0;
+ int r;
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
if (r < 0)