summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Boccassi <bluca@debian.org>2023-11-25 04:16:36 +0100
committerLuca Boccassi <bluca@debian.org>2023-11-29 12:04:59 +0100
commit9e615fa3aa9710f530a4242dd79e4c7a4f96256e (patch)
treedde29aca0f048952f5228c2d84efd72d6296eeb3
parentmkosi: Install integritysetup on CentOS/Fedora (diff)
downloadsystemd-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.xml7
-rw-r--r--man/systemd.mount.xml9
-rw-r--r--man/systemd.unit.xml10
-rw-r--r--src/core/automount.c2
-rw-r--r--src/core/dbus-unit.c11
-rw-r--r--src/core/load-fragment-gperf.gperf.in3
-rw-r--r--src/core/load-fragment.c10
-rw-r--r--src/core/load-fragment.h2
-rw-r--r--src/core/manager.c11
-rw-r--r--src/core/manager.h10
-rw-r--r--src/core/mount.c51
-rw-r--r--src/core/path.c2
-rw-r--r--src/core/socket.c2
-rw-r--r--src/core/swap.c2
-rw-r--r--src/core/timer.c2
-rw-r--r--src/core/unit-serialize.c25
-rw-r--r--src/core/unit.c156
-rw-r--r--src/core/unit.h21
-rw-r--r--src/fstab-generator/fstab-generator.c13
-rw-r--r--src/shared/bus-unit-util.c1
-rw-r--r--test/fuzz/fuzz-unit-file/directives-all.service1
-rw-r--r--test/test-path/basic.target2
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