1
0
mirror of https://github.com/systemd/systemd synced 2024-07-08 20:15:55 +00:00

Merge pull request #7186 from poettering/track-deps

rework unit dependency data structure to track why deps get created
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2017-11-12 16:14:41 +01:00 committed by GitHub
commit f886559e55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1029 additions and 475 deletions

View File

@ -74,3 +74,6 @@ BuildPackages=
Packages=
libidn2
BuildDirectory=mkosi.builddir
Cache=mkosi.cache

42
TODO
View File

@ -24,6 +24,48 @@ Janitorial Clean-ups:
Features:
* let's log the "tainted" string at boot
* Add NetworkNamespacePath= to specify a path to a network namespace
* Add StandardInputData= and StandardInputText= for putting together data to
pass to a service through stdin
* Add StandardInputPath=, StandardOutputPath=, StandardErrorPath= to connect a
service to a specific file. Be smart, and if the specified path refers to an
AF_UNIX socket, connect() to it.
* maybe use SOURCE_DATE_EPOCH (i.e. the env var the reproducible builds folks
introduced) as the RTC epoch, instead of the mtime of NEWS.
* Introduce GCMode= as unit file property or so, for tweaking the GC
logic. Specifically, there should be a way to tell systemd to collect
individual units even on failure. Then, make systemd-run --wait use this, so
that failed transient units in that case don't stick around.
* add a way to lock down cgroup migration: a boolean, which when set for a unit
makes sure the processes in it can never migrate out of it
* complain if a unit starts up and there are already processes in its cgroup
* blog about fd store and restartable services
* document Environment=SYSTEMD_LOG_LEVEL=debug drop-in in debugging document
* add a way to remove fds from the fdstore by name, and make logind use it
* in the long run: permit a system with /etc/machine-id linked to /dev/null, to
make it lose its identity, i.e. be anonymous. For this we'd have to patch
through the whole tree to make all code deal with the case where no machine
ID is available.
* optionally, collect cgroup resource data, and store it in per-unit RRD files,
suitable for processing with rrdtool. Add bus API to access this data, and
possibly implement a CPULoad property based on it.
* In journalctl add a way how "-o verbose" and suchlike can be tweaked to show
only a specific set of properties
* export UID ranges nspawns's --private-user and DynamicUser= uses in
the systemd.pc pkg-config file, the same way we already expose the system
user boundary there

View File

@ -73,6 +73,9 @@
special mode of escaping is applied instead, which assumes the
string is already escaped but will escape everything that
appears obviously non-escaped.</para>
<para>For details on the escaping and unescaping algorithms see the relevant section in
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</refsect1>
<refsect1>
@ -107,11 +110,12 @@
<term><option>--path</option></term>
<term><option>-p</option></term>
<listitem><para>When escaping or unescaping a string, assume
it refers to a file system path. This eliminates leading,
trailing or duplicate <literal>/</literal> characters
and rejects <literal>.</literal> and <literal>..</literal>
path components.</para></listitem>
<listitem><para>When escaping or unescaping a string, assume it refers to a file system path. This eliminates
leading, trailing or duplicate <literal>/</literal> characters and rejects <literal>.</literal> and
<literal>..</literal> path components. This is particularly useful for generating strings suitable for
unescaping with the <literal>%f</literal> specifier in unit files, see
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
<varlistentry>
@ -172,6 +176,7 @@ systemd-nspawn@My\x20Container\x201.service systemd-nspawn@containerb.service sy
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>

View File

@ -112,35 +112,36 @@
<refsect1>
<title>The udev Database</title>
<para>The settings of device units may either be configured via
unit files, or directly from the udev database (which is
recommended). The following udev device properties are understood
by systemd:</para>
<para>Unit settings of device units may either be configured via unit files, or directly from the udev
database. The following udev device properties are understood by the service manager:</para>
<variablelist class='udev-directives'>
<varlistentry>
<term><varname>SYSTEMD_WANTS=</varname></term>
<term><varname>SYSTEMD_USER_WANTS=</varname></term>
<listitem><para>Adds dependencies of type
<varname>Wants</varname> from the device unit to all listed
units. The first form is used by the system systemd instance,
the second by user systemd instances. Those settings may be
used to activate arbitrary units when a specific device
becomes available.</para>
<listitem><para>Adds dependencies of type <varname>Wants=</varname> from the device unit to the specified
units. <varname>SYSTEMD_WANTS=</varname> is read by the system service manager,
<varname>SYSTEMD_USER_WANTS=</varname> by user service manager instances. These properties may be used to
activate arbitrary units when a specific device becomes available.</para>
<para>Note that this and the other tags are not taken into
account unless the device is tagged with the
<literal>systemd</literal> string in the udev database,
because otherwise the device is not exposed as a systemd unit
(see above).</para>
<para>Note that this and the other udev device properties are not taken into account unless the device is
tagged with the <literal>systemd</literal> tag in the udev database, because otherwise the device is not
exposed as a systemd unit (see above).</para>
<para>Note that systemd will only act on
<varname>Wants</varname> dependencies when a device first
becomes active. It will not act on them if they are added to
devices that are already active. Use
<varname>SYSTEMD_READY=</varname> (see below) to influence on
which udev event to trigger the dependencies.
</para></listitem>
<para>Note that systemd will only act on <varname>Wants=</varname> dependencies when a device first becomes
active. It will not act on them if they are added to devices that are already active. Use
<varname>SYSTEMD_READY=</varname> (see below) to configure when a udev device shall be considered active, and
thus when to trigger the dependencies.</para>
<!-- Note that we don't document here that we actually apply unit_name_mangle() to all specified names, since
that's kinda ugly, and people should instead specify correctly escaped names -->
<para>The specified property value should be a space-separated list of valid unit names. If a unit template
name is specified (that is, a unit name containing an <literal>@</literal> character indicating a unit name to
use for multiple instantiation, but with an empty instance name following the <literal>@</literal>), it will be
automatically instantiated by the device's <literal>sysfs</literal> path (that is: the path is escaped and
inserted as instance name into the template unit name). This is useful in order to instantiate a specific
template unit once for each device that appears and matches specific properties.</para></listitem>
</varlistentry>
<varlistentry>
@ -152,20 +153,14 @@
<varlistentry>
<term><varname>SYSTEMD_READY=</varname></term>
<listitem><para>If set to 0, systemd will consider this device
unplugged even if it shows up in the udev tree. If this
property is unset or set to 1, the device will be considered
plugged if it is visible in the udev tree. This property has
no influence on the behavior when a device disappears from the
udev tree.</para>
<listitem><para>If set to 0, systemd will consider this device unplugged even if it shows up in the udev
tree. If this property is unset or set to 1, the device will be considered plugged if it is visible in the udev
tree.</para>
<para>This option is useful to support devices that initially
show up in an uninitialized state in the tree, and for which a
<literal>changed</literal> event is generated the moment they
are fully set up. Note that <varname>SYSTEMD_WANTS=</varname>
(see above) is not acted on as long as
<varname>SYSTEMD_READY=0</varname> is set for a
device.</para></listitem>
<para>This option is useful for devices that initially show up in an uninitialized state in the tree, and for
which a <literal>changed</literal> event is generated the moment they are fully set up. Note that
<varname>SYSTEMD_WANTS=</varname> (see above) is not acted on as long as <varname>SYSTEMD_READY=0</varname> is
set for a device.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -213,22 +213,6 @@
socket-based activation which make dependencies implicit,
resulting in a both simpler and more flexible system.</para>
<para>Some unit names reflect paths existing in the file system
namespace. Example: a device unit
<filename>dev-sda.device</filename> refers to a device with the
device node <filename noindex='true'>/dev/sda</filename> in the
file system namespace. If this applies, a special way to escape
the path name is used, so that the result is usable as part of a
filename. Basically, given a path, "/" is replaced by "-", and all
other characters which are not ASCII alphanumerics are replaced by
C-style "\x2d" escapes (except that "_" is never replaced and "."
is only replaced when it would be the first character in the
escaped path). The root directory "/" is encoded as single dash,
while otherwise the initial and ending "/" are removed from all
paths during transformation. This escaping is reversible. Properly
escaped paths can be generated using the
<citerefentry><refentrytitle>systemd-escape</refentrytitle><manvolnum>1</manvolnum></citerefentry>
command.</para>
<para>Optionally, units may be instantiated from a
template file at runtime. This allows creation of
@ -265,6 +249,32 @@
</refsect1>
<refsect1>
<title>String Escaping for Inclusion in Unit Names</title>
<para>Sometimes it is useful to convert arbitrary strings into unit names. To facilitate this, a method of string
escaping is used, in order to map strings containing arbitrary byte values (except NUL) into valid unit names and
their restricted character set. A common special case are unit names that reflect paths to objects in the file
system hierarchy. Example: a device unit <filename>dev-sda.device</filename> refers to a device with the device
node <filename noindex='true'>/dev/sda</filename> in the file system.</para>
<para>The escaping algorithm operates as follows: given a string, any <literal>/</literal> character is replaced by
<literal>-</literal>, and all other characters which are not ASCII alphanumerics or <literal>_</literal> are
replaced by C-style <literal>\x2d</literal> escapes. In addition, <literal>.</literal> is replaced with such a
C-style escape when it would appear as the first character in the escaped string.</para>
<para>When the input qualifies as absolute file system path, this algorithm is extended slightly: the path to the
root directory <literal>/</literal> is encoded as single dash <literal>-</literal>. In addition, any leading,
trailing or duplicate <literal>/</literal> characters are removed from the string before transformation. Example:
<filename>/foo//bar/baz/</filename> becomes <literal>foo-bar-baz</literal>.</para>
<para>This escaping is fully reversible, as long as it is known whether the escaped string was a path (the
unescaping results are different for paths and non-path strings). The
<citerefentry><refentrytitle>systemd-escape</refentrytitle><manvolnum>1</manvolnum></citerefentry> command may be
used to apply and reverse escaping on arbitrary strings. Use <command>systemd-escape --path</command> to escape
path strings, and <command>systemd-escape</command> without <option>--path</option> otherwise.</para>
</refsect1>
<refsect1>
<title>Implicit Dependencies</title>
@ -1241,7 +1251,7 @@
<row>
<entry><literal>%N</literal></entry>
<entry>Unescaped full unit name</entry>
<entry>Same as <literal>%n</literal>, but with escaping undone</entry>
<entry>Same as <literal>%n</literal>, but with escaping undone. This undoes the escaping used when generating unit names from arbitrary strings (see above). </entry>
</row>
<row>
<entry><literal>%p</literal></entry>
@ -1266,7 +1276,7 @@
<row>
<entry><literal>%f</literal></entry>
<entry>Unescaped filename</entry>
<entry>This is either the unescaped instance name (if applicable) with <filename>/</filename> prepended (if applicable), or the unescaped prefix name prepended with <filename>/</filename>.</entry>
<entry>This is either the unescaped instance name (if applicable) with <filename>/</filename> prepended (if applicable), or the unescaped prefix name prepended with <filename>/</filename>. This implements unescaping according to the rules for escaping absolute file system paths discussed above.</entry>
</row>
<row>
<entry><literal>%t</literal></entry>

View File

@ -26,7 +26,9 @@
export LC_CTYPE=en_US.UTF-8
[ -f "$BUILDDIR"/build.ninja ] || meson "$BUILDDIR"
sysvinit_path=`realpath /etc/init.d`
[ -f "$BUILDDIR"/build.ninja ] || meson "$BUILDDIR" -D "sysvinit-path=$sysvinit_path"
ninja -C "$BUILDDIR" all
[ "$WITH_TESTS" = 0 ] || ninja -C "$BUILDDIR" test || ( RET="$?" ; cat "$BUILDDIR"/meson-logs/testlog.txt ; exit "$RET" )
ninja -C "$BUILDDIR" install

View File

@ -216,6 +216,7 @@ static int detect_vm_dmi(void) {
}
static int detect_vm_xen(void) {
/* Check for Dom0 will be executed later in detect_vm_xen_dom0
Thats why we dont check the content of /proc/xen/capabilities here. */
if (access("/proc/xen/capabilities", F_OK) < 0) {
@ -224,8 +225,7 @@ static int detect_vm_xen(void) {
}
log_debug("Virtualization XEN found (/proc/xen/capabilities exists)");
return VIRTUALIZATION_XEN;
return VIRTUALIZATION_XEN;
}
static bool detect_vm_xen_dom0(void) {

View File

@ -130,7 +130,20 @@ static void automount_done(Unit *u) {
a->expire_event_source = sd_event_source_unref(a->expire_event_source);
}
static int automount_add_mount_links(Automount *a) {
static int automount_add_trigger_dependencies(Automount *a) {
Unit *x;
int r;
assert(a);
r = unit_load_related_unit(UNIT(a), ".mount", &x);
if (r < 0)
return r;
return unit_add_two_dependencies(UNIT(a), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
}
static int automount_add_mount_dependencies(Automount *a) {
_cleanup_free_ char *parent = NULL;
assert(a);
@ -139,7 +152,7 @@ static int automount_add_mount_links(Automount *a) {
if (!parent)
return -ENOMEM;
return unit_require_mounts_for(UNIT(a), parent);
return unit_require_mounts_for(UNIT(a), parent, UNIT_DEPENDENCY_IMPLICIT);
}
static int automount_add_default_dependencies(Automount *a) {
@ -153,7 +166,7 @@ static int automount_add_default_dependencies(Automount *a) {
if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
return 0;
r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
@ -215,21 +228,15 @@ static int automount_load(Unit *u) {
return r;
if (u->load_state == UNIT_LOADED) {
Unit *x;
r = automount_set_where(a);
if (r < 0)
return r;
r = unit_load_related_unit(u, ".mount", &x);
r = automount_add_trigger_dependencies(a);
if (r < 0)
return r;
r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
if (r < 0)
return r;
r = automount_add_mount_links(a);
r = automount_add_mount_dependencies(a);
if (r < 0)
return r;

View File

@ -1095,10 +1095,11 @@ CGroupMask unit_get_members_mask(Unit *u) {
u->cgroup_members_mask = 0;
if (u->type == UNIT_SLICE) {
void *v;
Unit *member;
Iterator i;
SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) {
HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i) {
if (member == u)
continue;
@ -1575,8 +1576,9 @@ static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) {
while ((slice = UNIT_DEREF(u->slice))) {
Iterator i;
Unit *m;
void *v;
SET_FOREACH(m, slice->dependencies[UNIT_BEFORE], i) {
HASHMAP_FOREACH_KEY(v, m, u->dependencies[UNIT_BEFORE], i) {
if (m == u)
continue;
@ -2426,8 +2428,9 @@ void unit_invalidate_cgroup_bpf(Unit *u) {
if (u->type == UNIT_SLICE) {
Unit *member;
Iterator i;
void *v;
SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) {
HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i) {
if (member == u)
continue;

View File

@ -139,8 +139,10 @@ static int property_get_tainted(
void *userdata,
sd_bus_error *error) {
char buf[sizeof("split-usr:cgroups-missing:local-hwclock:")] = "", *e = buf;
char buf[sizeof("split-usr:cgroups-missing:local-hwclock:var-run-bad:")] = "", *e = buf;
_cleanup_free_ char *destination = NULL;
Manager *m = userdata;
int r;
assert(bus);
assert(reply);
@ -155,6 +157,10 @@ static int property_get_tainted(
if (clock_is_localtime(NULL) > 0)
e = stpcpy(e, "local-hwclock:");
r = readlink_malloc("/var/run", &destination);
if (r < 0 || !PATH_IN_SET(destination, "../run", "/run"))
e = stpcpy(e, "var-run-bad:");
/* remove the last ':' */
if (e != buf)
e[-1] = 0;

View File

@ -36,7 +36,7 @@ static int property_get_what(
sd_bus_error *error) {
Mount *m = userdata;
const char *d;
const char *d = NULL;
assert(bus);
assert(reply);
@ -46,8 +46,6 @@ static int property_get_what(
d = m->parameters_proc_self_mountinfo.what;
else if (m->from_fragment && m->parameters_fragment.what)
d = m->parameters_fragment.what;
else
d = "";
return sd_bus_message_append(reply, "s", d);
}
@ -62,7 +60,7 @@ static int property_get_options(
sd_bus_error *error) {
Mount *m = userdata;
const char *d;
const char *d = NULL;
assert(bus);
assert(reply);
@ -72,8 +70,6 @@ static int property_get_options(
d = m->parameters_proc_self_mountinfo.options;
else if (m->from_fragment && m->parameters_fragment.options)
d = m->parameters_fragment.options;
else
d = "";
return sd_bus_message_append(reply, "s", d);
}
@ -87,13 +83,19 @@ static int property_get_type(
void *userdata,
sd_bus_error *error) {
const char *fstype = NULL;
Mount *m = userdata;
assert(bus);
assert(reply);
assert(m);
return sd_bus_message_append(reply, "s", mount_get_fstype(m));
if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype)
fstype = m->parameters_proc_self_mountinfo.fstype;
else if (m->from_fragment && m->parameters_fragment.fstype)
fstype = m->parameters_fragment.fstype;
return sd_bus_message_append(reply, "s", fstype);
}
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, mount_result, MountResult);

View File

@ -100,9 +100,10 @@ static int property_get_dependencies(
void *userdata,
sd_bus_error *error) {
Set *s = *(Set**) userdata;
Hashmap *h = *(Hashmap**) userdata;
Iterator j;
Unit *u;
void *v;
int r;
assert(bus);
@ -112,7 +113,7 @@ static int property_get_dependencies(
if (r < 0)
return r;
SET_FOREACH(u, s, j) {
HASHMAP_FOREACH_KEY(v, u, h, j) {
r = sd_bus_message_append(reply, "s", u->id);
if (r < 0)
return r;
@ -1395,7 +1396,7 @@ static int bus_unit_set_transient_property(
if (mode != UNIT_CHECK) {
_cleanup_free_ char *label = NULL;
r = unit_add_dependency_by_name(u, d, other, NULL, true);
r = unit_add_dependency_by_name(u, d, other, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;

View File

@ -256,60 +256,89 @@ static int device_update_description(Unit *u, struct udev_device *dev, const cha
}
static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
const char *wants, *property, *p;
const char *wants, *property;
int r;
assert(u);
assert(dev);
property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
wants = udev_device_get_property_value(dev, property);
for (p = wants;;) {
if (!wants)
return 0;
for (;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
r = extract_first_word(&wants, &word, NULL, EXTRACT_QUOTES);
if (r == 0)
return 0;
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_unit_error_errno(u, r, "Failed to add parse %s: %m", property);
return log_unit_error_errno(u, r, "Failed to parse property %s with value %s: %m", property, wants);
r = unit_name_mangle(word, UNIT_NAME_NOGLOB, &k);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word);
if (unit_name_is_valid(word, UNIT_NAME_TEMPLATE) && DEVICE(u)->sysfs) {
_cleanup_free_ char *escaped = NULL;
r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true);
/* If the unit name is specified as template, then automatically fill in the sysfs path of the
* device as instance name, properly escaped. */
r = unit_name_path_escape(DEVICE(u)->sysfs, &escaped);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to escape %s: %m", DEVICE(u)->sysfs);
r = unit_name_replace_instance(word, escaped, &k);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to build %s instance of template %s: %m", escaped, word);
} else {
/* If this is not a template, then let's mangle it so, that it becomes a valid unit name. */
r = unit_name_mangle(word, UNIT_NAME_NOGLOB, &k);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word);
}
r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true, UNIT_DEPENDENCY_UDEV);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to add wants dependency: %m");
return log_unit_error_errno(u, r, "Failed to add Wants= dependency: %m");
}
}
static bool device_is_bound_by_mounts(Unit *d, struct udev_device *dev) {
static bool device_is_bound_by_mounts(Device *d, struct udev_device *dev) {
const char *bound_by;
int r = false;
int r;
assert(d);
assert(dev);
bound_by = udev_device_get_property_value(dev, "SYSTEMD_MOUNT_DEVICE_BOUND");
if (bound_by)
r = parse_boolean(bound_by) > 0;
if (bound_by) {
r = parse_boolean(bound_by);
if (r < 0)
log_warning_errno(r, "Failed to parse SYSTEMD_MOUNT_DEVICE_BOUND='%s' udev property of %s, ignoring: %m", bound_by, strna(d->sysfs));
DEVICE(d)->bind_mounts = r;
return r;
d->bind_mounts = r > 0;
} else
d->bind_mounts = false;
return d->bind_mounts;
}
static int device_upgrade_mount_deps(Unit *u) {
Unit *other;
Iterator i;
void *v;
int r;
SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i) {
/* Let's upgrade Requires= to BindsTo= on us. (Used when SYSTEMD_MOUNT_DEVICE_BOUND is set) */
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRED_BY], i) {
if (other->type != UNIT_MOUNT)
continue;
r = unit_add_dependency(other, UNIT_BINDS_TO, u, true);
r = unit_add_dependency(other, UNIT_BINDS_TO, u, true, UNIT_DEPENDENCY_UDEV);
if (r < 0)
return r;
}
@ -337,23 +366,26 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
return log_error_errno(r, "Failed to generate unit name from device path: %m");
u = manager_get_unit(m, e);
if (u) {
/* The device unit can still be present even if the device was unplugged: a mount unit can reference it hence
* preventing the GC to have garbaged it. That's desired since the device unit may have a dependency on the
* mount unit which was added during the loading of the later. */
if (dev && DEVICE(u)->state == DEVICE_PLUGGED) {
/* The device unit can still be present even if the device was
* unplugged: a mount unit can reference it hence preventing
* the GC to have garbaged it. That's desired since the device
* unit may have a dependency on the mount unit which was
* added during the loading of the later. */
if (dev && u && DEVICE(u)->state == DEVICE_PLUGGED) {
/* This unit is in plugged state: we're sure it's
* attached to a device. */
if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
log_unit_debug(u, "Dev %s appeared twice with different sysfs paths %s and %s",
e, DEVICE(u)->sysfs, sysfs);
return -EEXIST;
/* This unit is in plugged state: we're sure it's attached to a device. */
if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
log_unit_debug(u, "Dev %s appeared twice with different sysfs paths %s and %s",
e, DEVICE(u)->sysfs, sysfs);
return -EEXIST;
}
}
}
if (!u) {
delete = false;
/* Let's remove all dependencies generated due to udev properties. We'll readd whatever is configured
* now below. */
unit_remove_dependencies(u, UNIT_DEPENDENCY_UDEV);
} else {
delete = true;
r = unit_new_for_name(m, sizeof(Device), e, &u);
@ -361,8 +393,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
goto fail;
unit_add_to_load_queue(u);
} else
delete = false;
}
/* If this was created via some dependency and has not
* actually been seen yet ->sysfs will not be
@ -380,16 +411,13 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
(void) device_add_udev_wants(u, dev);
}
/* So the user wants the mount units to be bound to the device but a
* mount unit might has been seen by systemd before the device appears
* on its radar. In this case the device unit is partially initialized
* and includes the deps on the mount unit but at that time the "bind
* mounts" flag wasn't not present. Fix this up now. */
if (dev && device_is_bound_by_mounts(u, dev))
/* So the user wants the mount units to be bound to the device but a mount unit might has been seen by systemd
* before the device appears on its radar. In this case the device unit is partially initialized and includes
* the deps on the mount unit but at that time the "bind mounts" flag wasn't not present. Fix this up now. */
if (dev && device_is_bound_by_mounts(DEVICE(u), dev))
device_upgrade_mount_deps(u);
/* Note that this won't dispatch the load queue, the caller
* has to do that if needed and appropriate */
/* Note that this won't dispatch the load queue, the caller has to do that if needed and appropriate */
unit_add_to_dbus_queue(u);
return 0;

View File

@ -437,6 +437,7 @@ int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
static bool job_is_runnable(Job *j) {
Iterator i;
Unit *other;
void *v;
assert(j);
assert(j->installed);
@ -459,13 +460,12 @@ static bool job_is_runnable(Job *j) {
return true;
if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) {
/* Immediate result is that the job is or might be
* started. In this case let's wait for the
* dependencies, regardless whether they are
* starting or stopping something. */
SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i)
if (other->job)
return false;
}
@ -473,7 +473,7 @@ static bool job_is_runnable(Job *j) {
/* Also, if something else is being stopped and we should
* change state after it, then let's wait. */
SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i)
if (other->job &&
IN_SET(other->job->type, JOB_STOP, JOB_RESTART))
return false;
@ -832,10 +832,11 @@ static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
static void job_fail_dependencies(Unit *u, UnitDependency d) {
Unit *other;
Iterator i;
void *v;
assert(u);
SET_FOREACH(other, u->dependencies[d], i) {
HASHMAP_FOREACH_KEY(v, other, u->dependencies[d], i) {
Job *j = other->job;
if (!j)
@ -852,6 +853,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
Unit *other;
JobType t;
Iterator i;
void *v;
assert(j);
assert(j->installed);
@ -919,12 +921,12 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
finish:
/* Try to start the next jobs that can be started */
SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_AFTER], i)
if (other->job) {
job_add_to_run_queue(other->job);
job_add_to_gc_queue(other->job);
}
SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BEFORE], i)
if (other->job) {
job_add_to_run_queue(other->job);
job_add_to_gc_queue(other->job);
@ -1273,6 +1275,7 @@ int job_get_timeout(Job *j, usec_t *timeout) {
bool job_check_gc(Job *j) {
Unit *other;
Iterator i;
void *v;
assert(j);
@ -1301,7 +1304,7 @@ bool job_check_gc(Job *j) {
/* If a job is ordered after ours, and is to be started, then it needs to wait for us, regardless if we stop or
* start, hence let's not GC in that case. */
SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
if (!other->job)
continue;
@ -1314,7 +1317,7 @@ bool job_check_gc(Job *j) {
/* If we are going down, but something else is ordered After= us, then it needs to wait for us */
if (IN_SET(j->type, JOB_STOP, JOB_RESTART))
SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
if (!other->job)
continue;
@ -1392,6 +1395,7 @@ int job_get_before(Job *j, Job*** ret) {
size_t n = 0, n_allocated = 0;
Unit *other = NULL;
Iterator i;
void *v;
/* Returns a list of all pending jobs that need to finish before this job may be started. */
@ -1405,7 +1409,7 @@ int job_get_before(Job *j, Job*** ret) {
if (IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE, JOB_RELOAD)) {
SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
if (!other->job)
continue;
@ -1415,7 +1419,7 @@ int job_get_before(Job *j, Job*** ret) {
}
}
SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
if (!other->job)
continue;
@ -1439,6 +1443,7 @@ int job_get_after(Job *j, Job*** ret) {
_cleanup_free_ Job** list = NULL;
size_t n = 0, n_allocated = 0;
Unit *other = NULL;
void *v;
Iterator i;
assert(j);
@ -1446,7 +1451,7 @@ int job_get_after(Job *j, Job*** ret) {
/* Returns a list of all pending jobs that are waiting for this job to finish. */
SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) {
HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE], i) {
if (!other->job)
continue;
@ -1463,7 +1468,7 @@ int job_get_after(Job *j, Job*** ret) {
if (IN_SET(j->type, JOB_STOP, JOB_RESTART)) {
SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i) {
HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER], i) {
if (!other->job)
continue;

View File

@ -115,7 +115,7 @@ static int process_deps(Unit *u, UnitDependency dependency, const char *dir_suff
log_unit_warning(u, "%s dependency dropin %s target %s has different name",
unit_dependency_to_string(dependency), *p, target);
r = unit_add_dependency_by_name(u, dependency, entry, *p, true);
r = unit_add_dependency_by_name(u, dependency, entry, *p, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_unit_error_errno(u, r, "cannot add %s dependency on %s, ignoring: %m",
unit_dependency_to_string(dependency), entry);

View File

@ -142,7 +142,7 @@ int config_parse_unit_deps(
continue;
}
r = unit_add_dependency_by_name(u, d, k, NULL, true);
r = unit_add_dependency_by_name(u, d, k, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
@ -1538,7 +1538,7 @@ int config_parse_trigger_unit(
assert(rvalue);
assert(data);
if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
if (!hashmap_isempty(u->dependencies[UNIT_TRIGGERS])) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
return 0;
}
@ -1560,7 +1560,7 @@ int config_parse_trigger_unit(
return 0;
}
r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
return 0;
@ -1760,11 +1760,11 @@ int config_parse_service_sockets(
continue;
}
r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
@ -2569,7 +2569,7 @@ int config_parse_unit_requires_mounts_for(
continue;
}
r = unit_require_mounts_for(u, resolved);
r = unit_require_mounts_for(u, resolved, UNIT_DEPENDENCY_FILE);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount \"%s\", ignoring: %m", resolved);
continue;

View File

@ -967,21 +967,23 @@ enum {
};
static void unit_gc_mark_good(Unit *u, unsigned gc_marker) {
Iterator i;
Unit *other;
Iterator i;
void *v;
u->gc_marker = gc_marker + GC_OFFSET_GOOD;
/* Recursively mark referenced units as GOOD as well */
SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i)
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REFERENCES], i)
if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE)
unit_gc_mark_good(other, gc_marker);
}
static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
Iterator i;
Unit *other;
bool is_bad;
Iterator i;
void *v;
assert(u);
@ -999,7 +1001,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
is_bad = true;
SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REFERENCED_BY], i) {
unit_gc_sweep(other, gc_marker);
if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)

View File

@ -156,21 +156,6 @@ static bool needs_quota(const MountParameters *p) {
"usrquota\0" "grpquota\0" "quota\0" "usrjquota\0" "grpjquota\0");
}
const char *mount_get_fstype(const Mount *m) {
const char *type = NULL;
assert(m);
if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype)
type = m->parameters_proc_self_mountinfo.fstype;
else if (m->from_fragment && m->parameters_fragment.fstype)
type = m->parameters_fragment.fstype;
else
type = "";
return type;
}
static void mount_init(Unit *u) {
Mount *m = MOUNT(u);
@ -280,9 +265,7 @@ _pure_ static MountParameters* get_mount_parameters(Mount *m) {
return get_mount_parameters_fragment(m);
}
static int mount_add_mount_links(Mount *m) {
_cleanup_free_ char *parent = NULL;
const char *fstype;
static int mount_add_mount_dependencies(Mount *m) {
MountParameters *pm;
Unit *other;
Iterator i;
@ -292,33 +275,32 @@ static int mount_add_mount_links(Mount *m) {
assert(m);
if (!path_equal(m->where, "/")) {
/* Adds in links to other mount points that might lie further
* up in the hierarchy */
_cleanup_free_ char *parent = NULL;
/* Adds in links to other mount points that might lie further up in the hierarchy */
parent = dirname_malloc(m->where);
if (!parent)
return -ENOMEM;
r = unit_require_mounts_for(UNIT(m), parent);
r = unit_require_mounts_for(UNIT(m), parent, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;
}
/* Adds in links to other mount points that might be needed
* for the source path (if this is a bind mount or a loop mount) to be
* available. */
/* Adds in dependencies to other mount points that might be needed for the source path (if this is a bind mount
* or a loop mount) to be available. */
pm = get_mount_parameters_fragment(m);
if (pm && pm->what &&
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);
r = unit_require_mounts_for(UNIT(m), pm->what, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
/* Adds in links to other units that use this path or paths
* further down in the hierarchy */
/* 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, i) {
@ -328,32 +310,25 @@ static int mount_add_mount_links(Mount *m) {
if (other == UNIT(m))
continue;
r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true);
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);
r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true, UNIT_DEPENDENCY_PATH);
if (r < 0)
return r;
}
}
/* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */
fstype = mount_get_fstype(m);
if (streq(fstype, "tmpfs")) {
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, NULL, true);
if (r < 0)
return r;
}
return 0;
}
static int mount_add_device_links(Mount *m) {
MountParameters *p;
static int mount_add_device_dependencies(Mount *m) {
bool device_wants_mount = false;
UnitDependencyMask mask;
MountParameters *p;
UnitDependency dep;
int r;
@ -391,16 +366,19 @@ static int mount_add_device_links(Mount *m) {
* automatically stopped when the device disappears suddenly. */
dep = mount_is_bound_to_device(m) ? UNIT_BINDS_TO : UNIT_REQUIRES;
r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, dep);
mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT;
r = unit_add_node_dependency(UNIT(m), p->what, device_wants_mount, dep, mask);
if (r < 0)
return r;
return 0;
}
static int mount_add_quota_links(Mount *m) {
int r;
static int mount_add_quota_dependencies(Mount *m) {
UnitDependencyMask mask;
MountParameters *p;
int r;
assert(m);
@ -414,11 +392,13 @@ static int mount_add_quota_links(Mount *m) {
if (!needs_quota(p))
return 0;
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true);
mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT;
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true, mask);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true);
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true, mask);
if (r < 0)
return r;
@ -457,9 +437,10 @@ static bool mount_is_extrinsic(Mount *m) {
}
static int mount_add_default_dependencies(Mount *m) {
UnitDependencyMask mask;
int r;
MountParameters *p;
const char *after;
int r;
assert(m);
@ -476,6 +457,8 @@ static int mount_add_default_dependencies(Mount *m) {
if (!p)
return 0;
mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_DEFAULT;
if (mount_is_network(p)) {
/* We order ourselves after network.target. This is
* primarily useful at shutdown: services that take
@ -483,7 +466,7 @@ static int mount_add_default_dependencies(Mount *m) {
* network.target, so that they are shut down only
* after this mount unit is stopped. */
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true);
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true, mask);
if (r < 0)
return r;
@ -494,7 +477,7 @@ static int mount_add_default_dependencies(Mount *m) {
* whose purpose it is to delay this until the network
* is "up". */
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true);
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true, mask);
if (r < 0)
return r;
@ -502,14 +485,21 @@ static int mount_add_default_dependencies(Mount *m) {
} else
after = SPECIAL_LOCAL_FS_PRE_TARGET;
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true);
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true, mask);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, mask);
if (r < 0)
return r;
/* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */
if (streq_ptr(p->fstype, "tmpfs")) {
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, NULL, true, mask);
if (r < 0)
return r;
}
return 0;
}
@ -577,15 +567,15 @@ static int mount_add_extras(Mount *m) {
return r;
}
r = mount_add_device_links(m);
r = mount_add_device_dependencies(m);
if (r < 0)
return r;
r = mount_add_mount_links(m);
r = mount_add_mount_dependencies(m);
if (r < 0)
return r;
r = mount_add_quota_links(m);
r = mount_add_quota_dependencies(m);
if (r < 0)
return r;
@ -1453,11 +1443,11 @@ static int mount_setup_new_unit(
int r;
target = mount_is_network(p) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true);
r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
if (r < 0)
return r;
r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
if (r < 0)
return r;
}
@ -1515,7 +1505,7 @@ static int mount_setup_existing_unit(
* in the dependency "Set*" objects who created a
* dependency), we can only add deps, never lose them,
* until the next full daemon-reload. */
unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true);
unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true, UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT);
load_extras = true;
}

View File

@ -110,5 +110,3 @@ MountExecCommand mount_exec_command_from_string(const char *s) _pure_;
const char* mount_result_to_string(MountResult i) _const_;
MountResult mount_result_from_string(const char *s) _pure_;
const char *mount_get_fstype(const Mount *m);

View File

@ -277,14 +277,14 @@ static void path_done(Unit *u) {
path_free_specs(p);
}
static int path_add_mount_links(Path *p) {
static int path_add_mount_dependencies(Path *p) {
PathSpec *s;
int r;
assert(p);
LIST_FOREACH(spec, s, p->specs) {
r = unit_require_mounts_for(UNIT(p), s->path);
r = unit_require_mounts_for(UNIT(p), s->path, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
@ -314,17 +314,33 @@ static int path_add_default_dependencies(Path *p) {
if (!UNIT(p)->default_dependencies)
return 0;
r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, NULL, true);
r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
}
static int path_add_trigger_dependencies(Path *p) {
Unit *x;
int r;
assert(p);
if (!hashmap_isempty(UNIT(p)->dependencies[UNIT_TRIGGERS]))
return 0;
r = unit_load_related_unit(UNIT(p), ".service", &x);
if (r < 0)
return r;
return unit_add_two_dependencies(UNIT(p), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
}
static int path_load(Unit *u) {
@ -340,19 +356,11 @@ static int path_load(Unit *u) {
if (u->load_state == UNIT_LOADED) {
if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
Unit *x;
r = path_add_trigger_dependencies(p);
if (r < 0)
return r;
r = unit_load_related_unit(u, ".service", &x);
if (r < 0)
return r;
r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
if (r < 0)
return r;
}
r = path_add_mount_links(p);
r = path_add_mount_dependencies(p);
if (r < 0)
return r;

View File

@ -124,7 +124,8 @@ static int scope_add_default_dependencies(Scope *s) {
r = unit_add_two_dependencies_by_name(
UNIT(s),
UNIT_BEFORE, UNIT_CONFLICTS,
SPECIAL_SHUTDOWN_TARGET, NULL, true);
SPECIAL_SHUTDOWN_TARGET, NULL, true,
UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;

View File

@ -562,7 +562,7 @@ static int service_add_default_dependencies(Service *s) {
* require it, so that we fail if we can't acquire
* it. */
r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
} else {
@ -570,7 +570,7 @@ static int service_add_default_dependencies(Service *s) {
/* In the --user instance there's no sysinit.target,
* in that case require basic.target instead. */
r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true);
r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
@ -578,12 +578,12 @@ static int service_add_default_dependencies(Service *s) {
/* Second, if the rest of the base system is in the same
* transaction, order us after it, but do not pull it in or
* even require it. */
r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true);
r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
/* Third, add us in for normal shutdown. */
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
}
static void service_fix_output(Service *s) {
@ -612,12 +612,12 @@ static int service_setup_bus_name(Service *s) {
if (!s->bus_name)
return 0;
r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true);
r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
/* We always want to be ordered against dbus.socket if both are in the transaction. */
r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true);
r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
@ -1103,11 +1103,12 @@ static int service_collect_fds(Service *s,
rn_socket_fds = 1;
} else {
Iterator i;
void *v;
Unit *u;
/* Pass all our configured sockets for singleton services */
SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
HASHMAP_FOREACH_KEY(v, u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
_cleanup_free_ int *cfds = NULL;
Socket *sock;
int cn_fds;
@ -3617,7 +3618,7 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context
return r;
}
r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;

View File

@ -97,7 +97,7 @@ static int slice_add_default_dependencies(Slice *s) {
r = unit_add_two_dependencies_by_name(
UNIT(s),
UNIT_BEFORE, UNIT_CONFLICTS,
SPECIAL_SHUTDOWN_TARGET, NULL, true);
SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;

View File

@ -250,7 +250,7 @@ int socket_instantiate_service(Socket *s) {
unit_ref_set(&s->service, u);
return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false);
return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false, UNIT_DEPENDENCY_IMPLICIT);
}
static bool have_non_accept_socket(Socket *s) {
@ -273,7 +273,7 @@ static bool have_non_accept_socket(Socket *s) {
return false;
}
static int socket_add_mount_links(Socket *s) {
static int socket_add_mount_dependencies(Socket *s) {
SocketPort *p;
int r;
@ -290,7 +290,7 @@ static int socket_add_mount_links(Socket *s) {
if (!path)
continue;
r = unit_require_mounts_for(UNIT(s), path);
r = unit_require_mounts_for(UNIT(s), path, UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
}
@ -298,7 +298,7 @@ static int socket_add_mount_links(Socket *s) {
return 0;
}
static int socket_add_device_link(Socket *s) {
static int socket_add_device_dependencies(Socket *s) {
char *t;
assert(s);
@ -307,7 +307,7 @@ static int socket_add_device_link(Socket *s) {
return 0;
t = strjoina("/sys/subsystem/net/devices/", s->bind_to_device);
return unit_add_node_link(UNIT(s), t, false, UNIT_BINDS_TO);
return unit_add_node_dependency(UNIT(s), t, false, UNIT_BINDS_TO, UNIT_DEPENDENCY_FILE);
}
static int socket_add_default_dependencies(Socket *s) {
@ -317,17 +317,17 @@ static int socket_add_default_dependencies(Socket *s) {
if (!UNIT(s)->default_dependencies)
return 0;
r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true);
r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
}
_pure_ static bool socket_has_exec(Socket *s) {
@ -378,16 +378,16 @@ static int socket_add_extras(Socket *s) {
unit_ref_set(&s->service, x);
}
r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true);
r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;
}
r = socket_add_mount_links(s);
r = socket_add_mount_dependencies(s);
if (r < 0)
return r;
r = socket_add_device_link(s);
r = socket_add_device_dependencies(s);
if (r < 0)
return r;
@ -2261,13 +2261,14 @@ static void socket_enter_running(Socket *s, int cfd) {
}
if (cfd < 0) {
Iterator i;
Unit *other;
bool pending = false;
Unit *other;
Iterator i;
void *v;
/* If there's already a start pending don't bother to
* do anything */
SET_FOREACH(other, UNIT(s)->dependencies[UNIT_TRIGGERS], i)
HASHMAP_FOREACH_KEY(v, other, UNIT(s)->dependencies[UNIT_TRIGGERS], i)
if (unit_active_or_pending(other)) {
pending = true;
break;

View File

@ -197,7 +197,7 @@ static int swap_arm_timer(Swap *s, usec_t usec) {
return 0;
}
static int swap_add_device_links(Swap *s) {
static int swap_add_device_dependencies(Swap *s) {
assert(s);
if (!s->what)
@ -207,12 +207,12 @@ static int swap_add_device_links(Swap *s) {
return 0;
if (is_device_path(s->what))
return unit_add_node_link(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO);
return unit_add_node_dependency(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO, UNIT_DEPENDENCY_FILE);
else
/* File based swap devices need to be ordered after
* systemd-remount-fs.service, since they might need a
* writable file system. */
return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true);
return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true, UNIT_DEPENDENCY_FILE);
}
static int swap_add_default_dependencies(Swap *s) {
@ -231,11 +231,11 @@ static int swap_add_default_dependencies(Swap *s) {
/* swap units generated for the swap dev links are missing the
* ordering dep against the swap target. */
r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true);
r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
}
static int swap_verify(Swap *s) {
@ -323,11 +323,11 @@ static int swap_load(Unit *u) {
return r;
}
r = unit_require_mounts_for(UNIT(s), s->what);
r = unit_require_mounts_for(UNIT(s), s->what, UNIT_DEPENDENCY_IMPLICIT);
if (r < 0)
return r;
r = swap_add_device_links(s);
r = swap_add_device_dependencies(s);
if (r < 0)
return r;

View File

@ -56,8 +56,6 @@ static int target_add_default_dependencies(Target *t) {
UNIT_PART_OF
};
Iterator i;
Unit *other;
int r;
unsigned k;
@ -66,23 +64,26 @@ static int target_add_default_dependencies(Target *t) {
if (!UNIT(t)->default_dependencies)
return 0;
/* Imply ordering for requirement dependencies on target
* units. Note that when the user created a contradicting
* ordering manually we won't add anything in here to make
* sure we don't create a loop. */
/* Imply ordering for requirement dependencies on target units. Note that when the user created a contradicting
* ordering manually we won't add anything in here to make sure we don't create a loop. */
for (k = 0; k < ELEMENTSOF(deps); k++)
SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i) {
for (k = 0; k < ELEMENTSOF(deps); k++) {
Unit *other;
Iterator i;
void *v;
HASHMAP_FOREACH_KEY(v, other, UNIT(t)->dependencies[deps[k]], i) {
r = unit_add_default_target_dependency(other, UNIT(t));
if (r < 0)
return r;
}
}
if (unit_has_name(UNIT(t), SPECIAL_SHUTDOWN_TARGET))
return 0;
/* Make sure targets are unloaded on shutdown */
return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
}
static int target_load(Unit *u) {

View File

@ -105,18 +105,18 @@ static int timer_add_default_dependencies(Timer *t) {
if (!UNIT(t)->default_dependencies)
return 0;
r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
LIST_FOREACH(value, v, t->values) {
if (v->base == TIMER_CALENDAR) {
r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true);
r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
break;
@ -124,7 +124,23 @@ static int timer_add_default_dependencies(Timer *t) {
}
}
return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT);
}
static int timer_add_trigger_dependencies(Timer *t) {
Unit *x;
int r;
assert(t);
if (!hashmap_isempty(UNIT(t)->dependencies[UNIT_TRIGGERS]))
return 0;
r = unit_load_related_unit(UNIT(t), ".service", &x);
if (r < 0)
return r;
return unit_add_two_dependencies(UNIT(t), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
}
static int timer_setup_persistent(Timer *t) {
@ -137,7 +153,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");
r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers", UNIT_DEPENDENCY_FILE);
if (r < 0)
return r;
@ -179,17 +195,9 @@ static int timer_load(Unit *u) {
if (u->load_state == UNIT_LOADED) {
if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
Unit *x;
r = unit_load_related_unit(u, ".service", &x);
if (r < 0)
return r;
r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
if (r < 0)
return r;
}
r = timer_add_trigger_dependencies(t);
if (r < 0)
return r;
r = timer_setup_persistent(t);
if (r < 0)

View File

@ -361,6 +361,7 @@ static char* merge_unit_ids(const char* unit_log_field, char **pairs) {
static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
Iterator i;
Unit *u;
void *v;
int r;
assert(tr);
@ -452,7 +453,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
/* We assume that the dependencies are bidirectional, and
* hence can ignore UNIT_AFTER */
SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) {
HASHMAP_FOREACH_KEY(v, u, j->unit->dependencies[UNIT_BEFORE], i) {
Job *o;
/* Is there a job for this unit? */
@ -860,14 +861,15 @@ static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependen
void transaction_add_propagate_reload_jobs(Transaction *tr, Unit *unit, Job *by, bool ignore_order, sd_bus_error *e) {
Iterator i;
Unit *dep;
JobType nt;
Unit *dep;
void *v;
int r;
assert(tr);
assert(unit);
SET_FOREACH(dep, unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
HASHMAP_FOREACH_KEY(v, dep, unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
nt = job_type_collapse(JOB_TRY_RELOAD, dep);
if (nt == JOB_NOP)
continue;
@ -892,11 +894,13 @@ int transaction_add_job_and_dependencies(
bool ignore_requirements,
bool ignore_order,
sd_bus_error *e) {
Job *ret;
bool is_new;
Iterator i;
Unit *dep;
Job *ret;
void *v;
int r;
bool is_new;
assert(tr);
assert(type < _JOB_TYPE_MAX);
@ -969,7 +973,7 @@ int transaction_add_job_and_dependencies(
/* Finally, recursively add in all dependencies. */
if (IN_SET(type, JOB_START, JOB_RESTART)) {
SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR) /* job type not applicable */
@ -979,7 +983,7 @@ int transaction_add_job_and_dependencies(
}
}
SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR) /* job type not applicable */
@ -989,7 +993,7 @@ int transaction_add_job_and_dependencies(
}
}
SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_WANTS], i) {
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
/* unit masked, job type not applicable and unit not found are not considered as errors. */
@ -1001,7 +1005,7 @@ int transaction_add_job_and_dependencies(
}
}
SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR) /* job type not applicable */
@ -1011,7 +1015,7 @@ int transaction_add_job_and_dependencies(
}
}
SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, true, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR) /* job type not applicable */
@ -1021,7 +1025,7 @@ int transaction_add_job_and_dependencies(
}
}
SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
log_unit_warning(dep,
@ -1050,7 +1054,7 @@ int transaction_add_job_and_dependencies(
ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type;
for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
HASHMAP_FOREACH_KEY(v, dep, ret->unit->dependencies[propagate_deps[j]], i) {
JobType nt;
nt = job_type_collapse(ptype, dep);

File diff suppressed because it is too large Load Diff

View File

@ -61,6 +61,53 @@ static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) {
return IN_SET(t, UNIT_INACTIVE, UNIT_FAILED);
}
/* Stores the 'reason' a dependency was created as a bit mask, i.e. due to which configuration source it came to be. We
* use this so that we can selectively flush out parts of dependencies again. Note that the same dependency might be
* created as a result of multiple "reasons", hence the bitmask. */
typedef enum UnitDependencyMask {
/* Configured directly by the unit file, .wants/.requries symlink or drop-in, or as an immediate result of a
* non-dependency option configured that way. */
UNIT_DEPENDENCY_FILE = 1 << 0,
/* As unconditional implicit dependency (not affected by unit configuration — except by the unit name and
* type) */
UNIT_DEPENDENCY_IMPLICIT = 1 << 1,
/* A dependency effected by DefaultDependencies=yes. Note that dependencies marked this way are conceptually
* just a subset of UNIT_DEPENDENCY_FILE, as DefaultDependencies= is itself a unit file setting that can only
* be set in unit files. We make this two separate bits only to help debugging how dependencies came to be. */
UNIT_DEPENDENCY_DEFAULT = 1 << 2,
/* A dependency created from udev rules */
UNIT_DEPENDENCY_UDEV = 1 << 3,
/* A dependency created because of some unit's RequiresMountsFor= setting */
UNIT_DEPENDENCY_PATH = 1 << 4,
/* A dependency created because of data read from /proc/self/mountinfo and no other configuration source */
UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT = 1 << 5,
/* A dependency created because of data read from /proc/self/mountinfo, but conditionalized by
* DefaultDependencies= and thus also involving configuration from UNIT_DEPENDENCY_FILE sources */
UNIT_DEPENDENCY_MOUNTINFO_DEFAULT = 1 << 6,
/* A dependency created because of data read from /proc/swaps and no other configuration source */
UNIT_DEPENDENCY_PROC_SWAP = 1 << 7,
_UNIT_DEPENDENCY_MASK_FULL = (1 << 8) - 1,
} UnitDependencyMask;
/* The Unit's dependencies[] hashmaps use this structure as value. It has the same size as a void pointer, and thus can
* be stored directly as hashmap value, without any indirection. Note that this stores two masks, as both the origin
* and the destination of a dependency might have created it. */
typedef union UnitDependencyInfo {
void *data;
struct {
UnitDependencyMask origin_mask:16;
UnitDependencyMask destination_mask:16;
} _packed_;
} UnitDependencyInfo;
#include "job.h"
struct UnitRef {
@ -89,9 +136,13 @@ struct Unit {
char *instance;
Set *names;
Set *dependencies[_UNIT_DEPENDENCY_MAX];
char **requires_mounts_for;
/* For each dependency type we maintain a Hashmap whose key is the Unit* object, and the value encodes why the
* dependency exists, using the UnitDependencyInfo type */
Hashmap *dependencies[_UNIT_DEPENDENCY_MAX];
/* Similar, for RequiresMountsFor= path dependencies. The key is the path, the value the UnitDependencyInfo type */
Hashmap *requires_mounts_for;
char *description;
char **documentation;
@ -492,7 +543,7 @@ extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
#define UNIT_HAS_CGROUP_CONTEXT(u) (UNIT_VTABLE(u)->cgroup_context_offset > 0)
#define UNIT_HAS_KILL_CONTEXT(u) (UNIT_VTABLE(u)->kill_context_offset > 0)
#define UNIT_TRIGGER(u) ((Unit*) set_first((u)->dependencies[UNIT_TRIGGERS]))
#define UNIT_TRIGGER(u) ((Unit*) hashmap_first_key((u)->dependencies[UNIT_TRIGGERS]))
DEFINE_CAST(SERVICE, Service);
DEFINE_CAST(SOCKET, Socket);
@ -512,11 +563,11 @@ void unit_free(Unit *u);
int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret);
int unit_add_name(Unit *u, const char *name);
int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference);
int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference);
int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference, UnitDependencyMask mask);
int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference, UnitDependencyMask mask);
int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference, UnitDependencyMask mask);
int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference, UnitDependencyMask mask);
int unit_add_exec_dependencies(Unit *u, ExecContext *c);
@ -596,7 +647,7 @@ int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *v
int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd);
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency d);
int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency d, UnitDependencyMask mask);
int unit_coldplug(Unit *u);
@ -651,7 +702,7 @@ int unit_kill_context(Unit *u, KillContext *c, KillOperation k, pid_t main_pid,
int unit_make_transient(Unit *u);
int unit_require_mounts_for(Unit *u, const char *path);
int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask);
bool unit_type_supported(UnitType t);
@ -689,6 +740,8 @@ void unit_set_exec_params(Unit *s, ExecParameters *p);
int unit_fork_helper_process(Unit *u, pid_t *ret);
void unit_remove_dependencies(Unit *u, UnitDependencyMask mask);
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \

View File

@ -688,7 +688,7 @@ static int add_mounts(void) {
}
int main(int argc, char *argv[]) {
int r = 0, k;
int r, k;
if (argc > 1 && argc != 4) {
log_error("This program takes three or no arguments.");
@ -720,6 +720,8 @@ int main(int argc, char *argv[]) {
if (arg_root_enabled)
r = add_root_mount();
else
r = 0;
if (!in_initrd()) {
k = add_mounts();

View File

@ -115,6 +115,33 @@ int main(int argc, char *argv[]) {
assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, &j) == 0);
manager_dump_jobs(m, stdout, "\t");
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
assert_se(!hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c));
assert_se(!hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
assert_se(unit_add_dependency(a, UNIT_PROPAGATES_RELOAD_TO, b, true, UNIT_DEPENDENCY_UDEV) == 0);
assert_se(unit_add_dependency(a, UNIT_PROPAGATES_RELOAD_TO, c, true, UNIT_DEPENDENCY_PROC_SWAP) == 0);
assert_se(hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
assert_se(hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
assert_se(hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c));
assert_se(hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
unit_remove_dependencies(a, UNIT_DEPENDENCY_UDEV);
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
assert_se(!hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
assert_se(hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c));
assert_se(hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
unit_remove_dependencies(a, UNIT_DEPENDENCY_PROC_SWAP);
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
assert_se(!hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c));
assert_se(!hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a));
manager_free(m);
return 0;

View File

@ -0,0 +1,4 @@
include ../Makefile.guess
all setup clean run:
@basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@

49
test/TEST-17-UDEV-WANTS/test.sh Executable file
View File

@ -0,0 +1,49 @@
#!/bin/bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh
set -e
TEST_DESCRIPTION="UDEV SYSTEMD_WANTS property"
TEST_NO_NSPAWN=1
. $TEST_BASE_DIR/test-functions
QEMU_TIMEOUT=180
test_setup() {
create_empty_image
mkdir -p $TESTDIR/root
mount ${LOOPDEV}p1 $TESTDIR/root
(
LOG_LEVEL=5
eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
setup_basic_environment
# mask some services that we do not want to run in these tests
ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
# setup the testsuite service
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
[Unit]
Description=Testsuite service
[Service]
ExecStart=/bin/sh -x /testsuite.sh
Type=oneshot
StandardOutput=tty
StandardError=tty
EOF
cp testsuite.sh $initdir/
setup_testsuite
) || return 1
ddebug "umount $TESTDIR/root"
umount $TESTDIR/root
}
do_test "$@"

View File

@ -0,0 +1,76 @@
#!/bin/bash
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh
set -ex
set -o pipefail
mkdir -p /run/udev/rules.d/
rm -f /run/udev/rules.d/50-testsuite.rules
udevadm control --reload
udevadm trigger /dev/sda
while : ; do
(
udevadm info /dev/sda | grep -q -v SYSTEMD_WANTS=foobar.service
udevadm info /dev/sda | grep -q -v SYSTEMD_WANTS=waldo.service
systemctl show -p WantedBy foobar.service | grep -q -v sda
systemctl show -p WantedBy waldo.service | grep -q -v sda
) && break
sleep .5
done
cat > /run/udev/rules.d/50-testsuite.rules <<EOF
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="sda", ENV{SYSTEMD_WANTS}="foobar.service"
EOF
udevadm control --reload
udevadm trigger /dev/sda
while : ; do
(
udevadm info /dev/sda | grep -q SYSTEMD_WANTS=foobar.service
udevadm info /dev/sda | grep -q -v SYSTEMD_WANTS=waldo.service
systemctl show -p WantedBy foobar.service | grep -q sda
systemctl show -p WantedBy waldo.service | grep -q -v sda
) && break
sleep .5
done
cat > /run/udev/rules.d/50-testsuite.rules <<EOF
ACTION!="remove", SUBSYSTEM=="block", KERNEL=="sda", ENV{SYSTEMD_WANTS}="waldo.service"
EOF
udevadm control --reload
udevadm trigger /dev/sda
while : ; do
(
udevadm info /dev/sda | grep -q -v SYSTEMD_WANTS=foobar.service
udevadm info /dev/sda | grep -q SYSTEMD_WANTS=waldo.service
systemctl show -p WantedBy foobar.service | grep -q -v sda
systemctl show -p WantedBy waldo.service | grep -q sda
) && break
sleep .5
done
rm /run/udev/rules.d/50-testsuite.rules
udevadm control --reload
udevadm trigger /dev/sda
while : ; do
(
udevadm info /dev/sda | grep -q -v SYSTEMD_WANTS=foobar.service
udevadm info /dev/sda | grep -q -v SYSTEMD_WANTS=waldo.service
systemctl show -p WantedBy foobar.service | grep -q -v sda
systemctl show -p WantedBy waldo.service | grep -q -v sda
) && break
sleep .5
done
echo OK > /testok
exit 0

View File

@ -13,6 +13,7 @@ ConditionPathIsSymbolicLink=!/tmp
DefaultDependencies=no
Conflicts=umount.target
Before=local-fs.target umount.target
After=swap.target
[Mount]
What=tmpfs