mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03: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:
commit
f886559e55
@ -74,3 +74,6 @@ BuildPackages=
|
||||
|
||||
Packages=
|
||||
libidn2
|
||||
|
||||
BuildDirectory=mkosi.builddir
|
||||
Cache=mkosi.cache
|
||||
|
42
TODO
42
TODO
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
100
src/core/mount.c
100
src/core/mount.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
565
src/core/unit.c
565
src/core/unit.c
File diff suppressed because it is too large
Load Diff
@ -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, ...) \
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
4
test/TEST-17-UDEV-WANTS/Makefile
Normal file
4
test/TEST-17-UDEV-WANTS/Makefile
Normal 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
49
test/TEST-17-UDEV-WANTS/test.sh
Executable 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 "$@"
|
76
test/TEST-17-UDEV-WANTS/testsuite.sh
Executable file
76
test/TEST-17-UDEV-WANTS/testsuite.sh
Executable 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
|
@ -13,6 +13,7 @@ ConditionPathIsSymbolicLink=!/tmp
|
||||
DefaultDependencies=no
|
||||
Conflicts=umount.target
|
||||
Before=local-fs.target umount.target
|
||||
After=swap.target
|
||||
|
||||
[Mount]
|
||||
What=tmpfs
|
||||
|
Loading…
Reference in New Issue
Block a user