diff options
Diffstat (limited to 'src/fstab-generator/fstab-generator.c')
-rw-r--r-- | src/fstab-generator/fstab-generator.c | 253 |
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) |