diff options
author | Luca Boccassi <bluca@debian.org> | 2023-11-25 04:16:36 +0100 |
---|---|---|
committer | Luca Boccassi <bluca@debian.org> | 2023-11-29 12:04:59 +0100 |
commit | 9e615fa3aa9710f530a4242dd79e4c7a4f96256e (patch) | |
tree | dde29aca0f048952f5228c2d84efd72d6296eeb3 | |
parent | mkosi: Install integritysetup on CentOS/Fedora (diff) | |
download | systemd-9e615fa3aa9710f530a4242dd79e4c7a4f96256e.tar.xz systemd-9e615fa3aa9710f530a4242dd79e4c7a4f96256e.zip |
core: add WantsMountsFor=
This is the equivalent of RequiresMountsFor=, but adds Wants= instead
of Requires=. It will be useful for example for the autogenerated
systemd-cryptsetup units.
Fixes https://github.com/systemd/systemd/issues/11646
-rw-r--r-- | man/org.freedesktop.systemd1.xml | 7 | ||||
-rw-r--r-- | man/systemd.mount.xml | 9 | ||||
-rw-r--r-- | man/systemd.unit.xml | 10 | ||||
-rw-r--r-- | src/core/automount.c | 2 | ||||
-rw-r--r-- | src/core/dbus-unit.c | 11 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.in | 3 | ||||
-rw-r--r-- | src/core/load-fragment.c | 10 | ||||
-rw-r--r-- | src/core/load-fragment.h | 2 | ||||
-rw-r--r-- | src/core/manager.c | 11 | ||||
-rw-r--r-- | src/core/manager.h | 10 | ||||
-rw-r--r-- | src/core/mount.c | 51 | ||||
-rw-r--r-- | src/core/path.c | 2 | ||||
-rw-r--r-- | src/core/socket.c | 2 | ||||
-rw-r--r-- | src/core/swap.c | 2 | ||||
-rw-r--r-- | src/core/timer.c | 2 | ||||
-rw-r--r-- | src/core/unit-serialize.c | 25 | ||||
-rw-r--r-- | src/core/unit.c | 156 | ||||
-rw-r--r-- | src/core/unit.h | 21 | ||||
-rw-r--r-- | src/fstab-generator/fstab-generator.c | 13 | ||||
-rw-r--r-- | src/shared/bus-unit-util.c | 1 | ||||
-rw-r--r-- | test/fuzz/fuzz-unit-file/directives-all.service | 1 | ||||
-rw-r--r-- | test/test-path/basic.target | 2 |
22 files changed, 230 insertions, 123 deletions
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 9d37e44d28..014a5cc883 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -1979,6 +1979,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as RequiresMountsFor = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly as WantsMountsFor = ['...', ...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as Documentation = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s Description = '...'; @@ -2135,6 +2137,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { <!--property SliceOf is not documented!--> + <!--property WantsMountsFor is not documented!--> + <!--property FreezerState is not documented!--> <!--property DropInPaths is not documented!--> @@ -2295,6 +2299,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { <variablelist class="dbus-property" generated="True" extra-ref="RequiresMountsFor"/> + <variablelist class="dbus-property" generated="True" extra-ref="WantsMountsFor"/> + <variablelist class="dbus-property" generated="True" extra-ref="Documentation"/> <variablelist class="dbus-property" generated="True" extra-ref="Description"/> @@ -11829,6 +11835,7 @@ $ gdbus introspect --system --dest org.freedesktop.systemd1 \ <varname>ActivationDetails</varname> were added in version 252.</para> <para><function>QueueSignal()</function> was added in version 254.</para> <para><varname>SurviveFinalKillSignal</varname> was added in version 255.</para> + <para><varname>WantsMountsFor</varname> was added in version 256.</para> </refsect2> <refsect2> <title>Service Unit Objects</title> diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml index c2e470e7dc..7900221935 100644 --- a/man/systemd.mount.xml +++ b/man/systemd.mount.xml @@ -255,13 +255,14 @@ </varlistentry> <varlistentry> + <term><option>x-systemd.wants-mounts-for=</option></term> <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 + <varname>RequiresMountsFor=</varname> or <varname>WantsMountsFor=</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> or <varname>WantsMountsFor=</varname> in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details.</para> diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 301fe77ce9..190d4c1d2f 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -920,6 +920,16 @@ </varlistentry> <varlistentry> + <term><varname>WantsMountsFor=</varname></term> + + <listitem><para>Same as <varname>RequiresMountsFor=</varname>, + but adds dependencies of type <varname>Wants=</varname> instead + of <varname>Requires=</varname>.</para> + + <xi:include href="version-info.xml" xpointer="v256"/></listitem> + </varlistentry> + + <varlistentry> <term><varname>OnSuccessJobMode=</varname></term> <term><varname>OnFailureJobMode=</varname></term> diff --git a/src/core/automount.c b/src/core/automount.c index 14bf7e6998..4cbb3727e5 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -126,7 +126,7 @@ static int automount_add_mount_dependencies(Automount *a) { if (r < 0) return r; - return unit_require_mounts_for(UNIT(a), parent, UNIT_DEPENDENCY_IMPLICIT); + return unit_add_mounts_for(UNIT(a), parent, UNIT_DEPENDENCY_IMPLICIT, UNIT_MOUNT_REQUIRES); } static int automount_add_default_dependencies(Automount *a) { diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 1a037b7035..48b7e10ea5 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -177,7 +177,7 @@ static int property_get_dependencies( return sd_bus_message_close_container(reply); } -static int property_get_requires_mounts_for( +static int property_get_mounts_for( sd_bus *bus, const char *path, const char *interface, @@ -879,7 +879,8 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("StopPropagatedFrom", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SliceOf", "as", property_get_dependencies, 0, SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("RequiresMountsFor", "as", property_get_requires_mounts_for, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RequiresMountsFor", "as", property_get_mounts_for, offsetof(Unit, mounts_for[UNIT_MOUNT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WantsMountsFor", "as", property_get_mounts_for, offsetof(Unit, mounts_for[UNIT_MOUNT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("AccessSELinuxContext", "s", NULL, offsetof(Unit, access_selinux_context), SD_BUS_VTABLE_PROPERTY_CONST), @@ -2308,7 +2309,7 @@ static int bus_unit_set_transient_property( return 1; - } else if (streq(name, "RequiresMountsFor")) { + } else if (STR_IN_SET(name, "RequiresMountsFor", "WantsMountsFor")) { _cleanup_strv_free_ char **l = NULL; r = sd_bus_message_read_strv(message, &l); @@ -2328,9 +2329,9 @@ static int bus_unit_set_transient_property( return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path specified in %s is not normalized: %s", name, *p); if (!UNIT_WRITE_FLAGS_NOOP(flags)) { - r = unit_require_mounts_for(u, *p, UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(u, *p, UNIT_DEPENDENCY_FILE, unit_mount_dependency_type_from_string(name)); if (r < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to add required mount \"%s\": %m", *p); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to add requested mount \"%s\": %m", *p); unit_write_settingf(u, flags, name, "%s=%s", name, *p); } diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index 45f9ab03c4..ed19c84697 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -309,7 +309,8 @@ Unit.PartOf, config_parse_unit_deps, Unit.JoinsNamespaceOf, config_parse_unit_deps, UNIT_JOINS_NAMESPACE_OF, 0 Unit.RequiresOverridable, config_parse_obsolete_unit_deps, UNIT_REQUIRES, 0 Unit.RequisiteOverridable, config_parse_obsolete_unit_deps, UNIT_REQUISITE, 0 -Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, 0 +Unit.RequiresMountsFor, config_parse_unit_mounts_for, 0, 0 +Unit.WantsMountsFor, config_parse_unit_mounts_for, 0, 0 Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 6e3a22bc16..d8ce2d6260 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3152,7 +3152,7 @@ int config_parse_unit_condition_string( return 0; } -int config_parse_unit_requires_mounts_for( +int config_parse_unit_mounts_for( const char *unit, const char *filename, unsigned line, @@ -3171,6 +3171,7 @@ int config_parse_unit_requires_mounts_for( assert(lvalue); assert(rvalue); assert(data); + assert(STR_IN_SET(lvalue, "RequiresMountsFor", "WantsMountsFor")); for (const char *p = rvalue;;) { _cleanup_free_ char *word = NULL, *resolved = NULL; @@ -3196,9 +3197,9 @@ int config_parse_unit_requires_mounts_for( if (r < 0) continue; - r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE, unit_mount_dependency_type_from_string(lvalue)); if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to add required mount '%s', ignoring: %m", resolved); + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to add requested mount '%s', ignoring: %m", resolved); continue; } } @@ -6301,8 +6302,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_nsec, "NANOSECONDS" }, { config_parse_namespace_path_strv, "PATH [...]" }, { config_parse_bind_paths, "PATH[:PATH[:OPTIONS]] [...]" }, - { config_parse_unit_requires_mounts_for, - "PATH [...]" }, + { config_parse_unit_mounts_for, "PATH [...]" }, { config_parse_exec_mount_propagation_flag, "MOUNTFLAG" }, { config_parse_unit_string_printf, "STRING" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 69198050ea..c001397ff2 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -71,7 +71,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_unit_condition_string); CONFIG_PARSER_PROTOTYPE(config_parse_kill_mode); CONFIG_PARSER_PROTOTYPE(config_parse_notify_access); CONFIG_PARSER_PROTOTYPE(config_parse_emergency_action); -CONFIG_PARSER_PROTOTYPE(config_parse_unit_requires_mounts_for); +CONFIG_PARSER_PROTOTYPE(config_parse_unit_mounts_for); CONFIG_PARSER_PROTOTYPE(config_parse_syscall_filter); CONFIG_PARSER_PROTOTYPE(config_parse_syscall_archs); CONFIG_PARSER_PROTOTYPE(config_parse_syscall_errno); diff --git a/src/core/manager.c b/src/core/manager.c index 37e4f70950..6ca643e693 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1691,8 +1691,10 @@ Manager* manager_free(Manager *m) { unit_defaults_done(&m->defaults); - assert(hashmap_isempty(m->units_requiring_mounts_for)); - hashmap_free(m->units_requiring_mounts_for); + FOREACH_ARRAY(map, m->units_needing_mounts_for, _UNIT_MOUNT_DEPENDENCY_TYPE_MAX) { + assert(hashmap_isempty(*map)); + hashmap_free(*map); + } hashmap_free(m->uid_refs); hashmap_free(m->gid_refs); @@ -4478,14 +4480,15 @@ void manager_status_printf(Manager *m, StatusType type, const char *status, cons va_end(ap); } -Set* manager_get_units_requiring_mounts_for(Manager *m, const char *path) { +Set* manager_get_units_needing_mounts_for(Manager *m, const char *path, UnitMountDependencyType t) { assert(m); assert(path); + assert(t >= 0 && t < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX); if (path_equal(path, "/")) path = ""; - return hashmap_get(m->units_requiring_mounts_for, path); + return hashmap_get(m->units_needing_mounts_for[t], path); } int manager_update_failed_units(Manager *m, Unit *u, bool failed) { diff --git a/src/core/manager.h b/src/core/manager.h index d96eb7b995..d7bc6e761d 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -137,6 +137,7 @@ typedef enum WatchdogType { #include "path-lookup.h" #include "show-status.h" #include "unit-name.h" +#include "unit.h" typedef enum ManagerTestRunFlags { MANAGER_TEST_NORMAL = 0, /* run normally */ @@ -438,10 +439,9 @@ struct Manager { /* This is true before and after switching root. */ bool switching_root; - /* This maps all possible path prefixes to the units needing - * them. It's a hashmap with a path string as key and a Set as - * value where Unit objects are contained. */ - Hashmap *units_requiring_mounts_for; + /* These map all possible path prefixes to the units needing them. They are hashmaps with a path + * string as key, and a Set as value where Unit objects are contained. */ + Hashmap *units_needing_mounts_for[_UNIT_MOUNT_DEPENDENCY_TYPE_MAX]; /* Used for processing polkit authorization responses */ Hashmap *polkit_registry; @@ -596,7 +596,7 @@ double manager_get_progress(Manager *m); void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5); -Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path); +Set* manager_get_units_needing_mounts_for(Manager *m, const char *path, UnitMountDependencyType t); ManagerState manager_state(Manager *m); diff --git a/src/core/mount.c b/src/core/mount.c index ded322d332..f364b2ab0b 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -281,8 +281,6 @@ static int update_parameters_proc_self_mountinfo( static int mount_add_mount_dependencies(Mount *m) { MountParameters *pm; - Unit *other; - Set *s; int r; assert(m); @@ -296,7 +294,7 @@ static int mount_add_mount_dependencies(Mount *m) { if (r < 0) return r; - r = unit_require_mounts_for(UNIT(m), parent, UNIT_DEPENDENCY_IMPLICIT); + r = unit_add_mounts_for(UNIT(m), parent, UNIT_DEPENDENCY_IMPLICIT, UNIT_MOUNT_REQUIRES); if (r < 0) return r; } @@ -308,30 +306,43 @@ static int mount_add_mount_dependencies(Mount *m) { path_is_absolute(pm->what) && (mount_is_bind(pm) || mount_is_loop(pm) || !mount_is_network(pm))) { - r = unit_require_mounts_for(UNIT(m), pm->what, UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(UNIT(m), pm->what, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); if (r < 0) return r; } /* Adds in dependencies to other units that use this path or paths further down in the hierarchy */ - s = manager_get_units_requiring_mounts_for(UNIT(m)->manager, m->where); - SET_FOREACH(other, s) { - - if (other->load_state != UNIT_LOADED) - continue; - - if (other == UNIT(m)) - continue; - - r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true, UNIT_DEPENDENCY_PATH); - if (r < 0) - return r; - - if (UNIT(m)->fragment_path) { - /* If we have fragment configuration, then make this dependency required */ - r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true, UNIT_DEPENDENCY_PATH); + for (UnitMountDependencyType t = 0; t < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX; ++t) { + Unit *other; + Set *s = manager_get_units_needing_mounts_for(UNIT(m)->manager, m->where, t); + + SET_FOREACH(other, s) { + if (other->load_state != UNIT_LOADED) + continue; + + if (other == UNIT(m)) + continue; + + r = unit_add_dependency( + other, + UNIT_AFTER, + UNIT(m), + /* add_reference= */ true, + UNIT_DEPENDENCY_PATH); if (r < 0) return r; + + if (UNIT(m)->fragment_path) { + /* If we have fragment configuration, then make this dependency required/wanted */ + r = unit_add_dependency( + other, + unit_mount_dependency_type_to_dependency_type(t), + UNIT(m), + /* add_reference= */ true, + UNIT_DEPENDENCY_PATH); + if (r < 0) + return r; + } } } diff --git a/src/core/path.c b/src/core/path.c index 44481a95d5..471d159d81 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -309,7 +309,7 @@ static int path_add_mount_dependencies(Path *p) { assert(p); LIST_FOREACH(spec, s, p->specs) { - r = unit_require_mounts_for(UNIT(p), s->path, UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(UNIT(p), s->path, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); if (r < 0) return r; } diff --git a/src/core/socket.c b/src/core/socket.c index 388be62318..c42a94d046 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -221,7 +221,7 @@ static int socket_add_mount_dependencies(Socket *s) { if (!path) continue; - r = unit_require_mounts_for(UNIT(s), path, UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(UNIT(s), path, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); if (r < 0) return r; } diff --git a/src/core/swap.c b/src/core/swap.c index 488b1719c5..ce35a5c441 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -321,7 +321,7 @@ static int swap_add_extras(Swap *s) { return r; } - r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT); + r = unit_add_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT, UNIT_MOUNT_REQUIRES); if (r < 0) return r; diff --git a/src/core/timer.c b/src/core/timer.c index 3c41a250b0..19358c7665 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -141,7 +141,7 @@ static int timer_setup_persistent(Timer *t) { if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) { - r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); if (r < 0) return r; diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c index fe4221ca46..40cdb615be 100644 --- a/src/core/unit-serialize.c +++ b/src/core/unit-serialize.c @@ -831,21 +831,26 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { } } - if (!hashmap_isempty(u->requires_mounts_for)) { - UnitDependencyInfo di; - const char *path; + for (UnitMountDependencyType type = 0; type < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX; type++) + if (!hashmap_isempty(u->mounts_for[type])) { + UnitDependencyInfo di; + const char *path; - HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) { - bool space = false; + HASHMAP_FOREACH_KEY(di.data, path, u->mounts_for[type]) { + bool space = false; - fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path); + fprintf(f, + "%s\t%s: %s (", + prefix, + unit_mount_dependency_type_to_string(type), + path); - print_unit_dependency_mask(f, "origin", di.origin_mask, &space); - print_unit_dependency_mask(f, "destination", di.destination_mask, &space); + print_unit_dependency_mask(f, "origin", di.origin_mask, &space); + print_unit_dependency_mask(f, "destination", di.destination_mask, &space); - fputs(")\n", f); + fputs(")\n", f); + } } - } if (u->load_state == UNIT_LOADED) { diff --git a/src/core/unit.c b/src/core/unit.c index 41f3bdb226..5b852bcc13 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -689,38 +689,39 @@ static void unit_remove_transient(Unit *u) { } } -static void unit_free_requires_mounts_for(Unit *u) { +static void unit_free_mounts_for(Unit *u) { assert(u); - for (;;) { - _cleanup_free_ char *path = NULL; + for (UnitMountDependencyType t = 0; t < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX; ++t) { + for (;;) { + _cleanup_free_ char *path = NULL; + + path = hashmap_steal_first_key(u->mounts_for[t]); + if (!path) + break; - path = hashmap_steal_first_key(u->requires_mounts_for); - if (!path) - break; - else { char s[strlen(path) + 1]; PATH_FOREACH_PREFIX_MORE(s, path) { char *y; Set *x; - x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y); + x = hashmap_get2(u->manager->units_needing_mounts_for[t], s, (void**) &y); if (!x) continue; (void) set_remove(x, u); if (set_isempty(x)) { - (void) hashmap_remove(u->manager->units_requiring_mounts_for, y); + assert_se(hashmap_remove(u->manager->units_needing_mounts_for[t], y)); free(y); set_free(x); } } } - } - u->requires_mounts_for = hashmap_free(u->requires_mounts_for); + u->mounts_for[t] = hashmap_free(u->mounts_for[t]); + } } static void unit_done(Unit *u) { @@ -769,7 +770,7 @@ Unit* unit_free(Unit *u) { u->deserialized_refs = strv_free(u->deserialized_refs); u->pending_freezer_invocation = sd_bus_message_unref(u->pending_freezer_invocation); - unit_free_requires_mounts_for(u); + unit_free_mounts_for(u); SET_FOREACH(t, u->aliases) hashmap_remove_value(u->manager->units, t, u); @@ -1278,19 +1279,19 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { /* Unlike unit_add_dependency() or friends, this always returns 0 on success. */ if (c->working_directory && !c->working_directory_missing_ok) { - r = unit_require_mounts_for(u, c->working_directory, UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(u, c->working_directory, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); if (r < 0) return r; } if (c->root_directory) { - r = unit_require_mounts_for(u, c->root_directory, UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(u, c->root_directory, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); if (r < 0) return r; } if (c->root_image) { - r = unit_require_mounts_for(u, c->root_image, UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(u, c->root_image, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); if (r < 0) return r; } @@ -1306,7 +1307,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { if (!p) return -ENOMEM; - r = unit_require_mounts_for(u, p, UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(u, p, UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); if (r < 0) return r; } @@ -1335,7 +1336,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { if (r < 0) return r; - r = unit_require_mounts_for(u, "/var/tmp", UNIT_DEPENDENCY_FILE); + r = unit_add_mounts_for(u, "/var/tmp", UNIT_DEPENDENCY_FILE, UNIT_MOUNT_REQUIRES); if (r < 0) return r; @@ -1536,51 +1537,72 @@ static int unit_add_slice_dependencies(Unit *u) { } static int unit_add_mount_dependencies(Unit *u) { - UnitDependencyInfo di; - const char *path; bool changed = false; int r; assert(u); - HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) { - char prefix[strlen(path) + 1]; + for (UnitMountDependencyType t = 0; t < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX; ++t) { + UnitDependencyInfo di; + const char *path; - PATH_FOREACH_PREFIX_MORE(prefix, path) { - _cleanup_free_ char *p = NULL; - Unit *m; + HASHMAP_FOREACH_KEY(di.data, path, u->mounts_for[t]) { - r = unit_name_from_path(prefix, ".mount", &p); - if (r == -EINVAL) - continue; /* If the path cannot be converted to a mount unit name, then it's - * not manageable as a unit by systemd, and hence we don't need a - * dependency on it. Let's thus silently ignore the issue. */ - if (r < 0) - return r; + char prefix[strlen(ASSERT_PTR(path)) + 1]; - m = manager_get_unit(u->manager, p); - if (!m) { - /* Make sure to load the mount unit if it exists. If so the dependencies on - * this unit will be added later during the loading of the mount unit. */ - (void) manager_load_unit_prepare(u->manager, p, NULL, NULL, &m); - continue; - } - if (m == u) - continue; + PATH_FOREACH_PREFIX_MORE(prefix, path) { + _cleanup_free_ char *p = NULL; + Unit *m; - if (m->load_state != UNIT_LOADED) - continue; + r = unit_name_from_path(prefix, ".mount", &p); + if (r == -EINVAL) + continue; /* If the path cannot be converted to a mount unit name, + * then it's not manageable as a unit by systemd, and + * hence we don't need a dependency on it. Let's thus + * silently ignore the issue. */ + if (r < 0) + return r; - r = unit_add_dependency(u, UNIT_AFTER, m, true, di.origin_mask); - if (r < 0) - return r; - changed = changed || r > 0; + m = manager_get_unit(u->manager, p); + if (!m) { + /* Make sure to load the mount unit if it exists. If so the + * dependencies on this unit will be added later during the loading + * of the mount unit. */ + (void) manager_load_unit_prepare( + u->manager, + p, + /* path= */NULL, + /* e= */NULL, + &m); + continue; + } + if (m == u) + continue; + + if (m->load_state != UNIT_LOADED) + continue; - if (m->fragment_path) { - r = unit_add_dependency(u, UNIT_REQUIRES, m, true, di.origin_mask); + r = unit_add_dependency( + u, + UNIT_AFTER, + m, + /* add_reference= */ true, + di.origin_mask); if (r < 0) return r; changed = changed || r > 0; + + if (m->fragment_path) { + r = unit_add_dependency( + u, + unit_mount_dependency_type_to_dependency_type(t), + m, + /* add_reference= */ true, + di.origin_mask); + if (r < 0) + return r; + changed = changed || r > 0; + } } } } @@ -4942,11 +4964,16 @@ int unit_kill_context( return wait_for_exit; } -int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) { +int unit_add_mounts_for(Unit *u, const char *path, UnitDependencyMask mask, UnitMountDependencyType type) { + Hashmap **unit_map, **manager_map; int r; assert(u); assert(path); + assert(type >= 0 && type < _UNIT_MOUNT_DEPENDENCY_TYPE_MAX); + + unit_map = &u->mounts_for[type]; + manager_map = &u->manager->units_needing_mounts_for[type]; /* Registers a unit for requiring a certain path and all its prefixes. We keep a hashtable of these * paths in the unit (from the path to the UnitDependencyInfo structure indicating how to the @@ -4956,7 +4983,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) if (!path_is_absolute(path)) return -EINVAL; - if (hashmap_contains(u->requires_mounts_for, path)) /* Exit quickly if the path is already covered. */ + if (hashmap_contains(*unit_map, path)) /* Exit quickly if the path is already covered. */ return 0; /* Use the canonical form of the path as the stored key. We call path_is_normalized() @@ -4975,7 +5002,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) .origin_mask = mask }; - r = hashmap_ensure_put(&u->requires_mounts_for, &path_hash_ops, p, di.data); + r = hashmap_ensure_put(unit_map, &path_hash_ops, p, di.data); if (r < 0) return r; assert(r > 0); @@ -4985,11 +5012,11 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) PATH_FOREACH_PREFIX_MORE(prefix, path) { Set *x; - x = hashmap_get(u->manager->units_requiring_mounts_for, prefix); + x = hashmap_get(*manager_map, prefix); if (!x) { _cleanup_free_ char *q = NULL; - r = hashmap_ensure_allocated(&u->manager->units_requiring_mounts_for, &path_hash_ops); + r = hashmap_ensure_allocated(manager_map, &path_hash_ops); if (r < 0) return r; @@ -5001,7 +5028,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask) if (!x) return -ENOMEM; - r = hashmap_put(u->manager->units_requiring_mounts_for, q, x); + r = hashmap_put(*manager_map, q, x); if (r < 0) { set_free(x); return r; @@ -6615,3 +6642,24 @@ int activation_details_append_pair(ActivationDetails *details, char ***strv) { } DEFINE_TRIVIAL_REF_UNREF_FUNC(ActivationDetails, activation_details, activation_details_free); + +static const char* const unit_mount_dependency_type_table[_UNIT_MOUNT_DEPENDENCY_TYPE_MAX] = { + [UNIT_MOUNT_WANTS] = "WantsMountsFor", + [UNIT_MOUNT_REQUIRES] = "RequiresMountsFor", +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_mount_dependency_type, UnitMountDependencyType); + +UnitDependency unit_mount_dependency_type_to_dependency_type(UnitMountDependencyType t) { + switch (t) { + + case UNIT_MOUNT_WANTS: + return UNIT_WANTS; + + case UNIT_MOUNT_REQUIRES: + return UNIT_REQUIRES; + + default: + assert_not_reached(); + } +} diff --git a/src/core/unit.h b/src/core/unit.h index 60bc2e3d35..fdaa3b8a8e 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include <errno.h> #include <stdbool.h> #include <stdlib.h> #include <sys/socket.h> @@ -8,6 +9,14 @@ #include "sd-id128.h" +/* Circular dependency with manager.h, needs to be defined before local includes */ +typedef enum UnitMountDependencyType { + UNIT_MOUNT_WANTS, + UNIT_MOUNT_REQUIRES, + _UNIT_MOUNT_DEPENDENCY_TYPE_MAX, + _UNIT_MOUNT_DEPENDENCY_TYPE_INVALID = -EINVAL, +} UnitMountDependencyType; + #include "bpf-program.h" #include "cgroup.h" #include "condition.h" @@ -216,9 +225,9 @@ typedef struct Unit { * Hashmap(UnitDependency → Hashmap(Unit* → UnitDependencyInfo)) */ Hashmap *dependencies; - /* Similar, for RequiresMountsFor= path dependencies. The key is the path, the value the - * UnitDependencyInfo type */ - Hashmap *requires_mounts_for; + /* Similar, for RequiresMountsFor= and WantsMountsFor= path dependencies. The key is the path, the + * value the UnitDependencyInfo type */ + Hashmap *mounts_for[_UNIT_MOUNT_DEPENDENCY_TYPE_MAX]; char *description; char **documentation; @@ -1001,7 +1010,7 @@ int unit_kill_context(Unit *u, KillContext *c, KillOperation k, PidRef *main_pid int unit_make_transient(Unit *u); -int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask); +int unit_add_mounts_for(Unit *u, const char *path, UnitDependencyMask mask, UnitMountDependencyType type); bool unit_type_supported(UnitType t); @@ -1101,6 +1110,10 @@ int unit_arm_timer(Unit *u, sd_event_source **source, bool relative, usec_t usec int unit_compare_priority(Unit *a, Unit *b); +UnitMountDependencyType unit_mount_dependency_type_from_string(const char *s) _const_; +const char* unit_mount_dependency_type_to_string(UnitMountDependencyType t) _const_; +UnitDependency unit_mount_dependency_type_to_dependency_type(UnitMountDependencyType t) _pure_; + /* Macros which append UNIT= or USER_UNIT= to the message */ #define log_unit_full_errno_zerook(unit, level, error, ...) \ diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 016f3baa7f..fd1a78aed2 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -416,15 +416,17 @@ static int write_before(FILE *f, const char *opts) { "x-systemd.before\0", "Before=%1$s\n"); } -static int write_requires_mounts_for(FILE *f, const char *opts) { +static int write_mounts_for(const char *x_opt, const char *unit_setting, FILE *f, const char *opts) { _cleanup_strv_free_ char **paths = NULL, **paths_escaped = NULL; _cleanup_free_ char *res = NULL; int r; + assert(x_opt); + assert(unit_setting); assert(f); assert(opts); - r = fstab_filter_options(opts, "x-systemd.requires-mounts-for\0", NULL, NULL, &paths, NULL); + r = fstab_filter_options(opts, x_opt, NULL, NULL, &paths, NULL); if (r < 0) return log_warning_errno(r, "Failed to parse options: %m"); if (r == 0) @@ -438,7 +440,7 @@ static int write_requires_mounts_for(FILE *f, const char *opts) { if (!res) return log_oom(); - fprintf(f, "RequiresMountsFor=%s\n", res); + fprintf(f, "%s=%s\n", unit_setting, res); return 0; } @@ -458,7 +460,10 @@ static int write_extra_dependencies(FILE *f, const char *opts) { r = write_before(f, opts); if (r < 0) return r; - r = write_requires_mounts_for(f, opts); + r = write_mounts_for("x-systemd.requires-mounts-for\0", "RequiresMountsFor", f, opts); + if (r < 0) + return r; + r = write_mounts_for("x-systemd.wants-mounts-for\0", "WantsMountsFor", f, opts); if (r < 0) return r; } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 4ee9706847..bba040112d 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -2643,6 +2643,7 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const if (unit_dependency_from_string(field) >= 0 || STR_IN_SET(field, "Documentation", "RequiresMountsFor", + "WantsMountsFor", "Markers")) return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE); diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service index 4bdc48a59b..d5877f930c 100644 --- a/test/fuzz/fuzz-unit-file/directives-all.service +++ b/test/fuzz/fuzz-unit-file/directives-all.service @@ -276,6 +276,7 @@ User= WakeSystem= WantedBy= Wants= +WantsMountsFor= WatchdogSec= What= Where= diff --git a/test/test-path/basic.target b/test/test-path/basic.target index 45f71aac98..c4b04c4da1 100644 --- a/test/test-path/basic.target +++ b/test/test-path/basic.target @@ -12,4 +12,4 @@ After=sysinit.target sockets.target paths.target slices.target tmp.mount # require /var and /var/tmp, but only add a Wants= type dependency on /tmp, as # we support that unit being masked, and this should not be considered an error. RequiresMountsFor=/var /var/tmp -Wants=tmp.mount +WantsMountsFor=/tmp |