diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
index 120ffbc8ef..689ca3ec88 100644
--- a/man/org.freedesktop.systemd1.xml
+++ b/man/org.freedesktop.systemd1.xml
@@ -1898,6 +1898,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
readonly s CollectMode = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly as Refs = ['...', ...];
+ readonly a(ss) ActivationDetails = [...];
};
interface org.freedesktop.DBus.Peer { ... };
interface org.freedesktop.DBus.Introspectable { ... };
@@ -2229,6 +2230,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
+
+
@@ -2406,6 +2409,18 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
Transient contains a boolean that indicates whether the unit was created as a
transient unit (i.e. via CreateTransientUnit() on the manager object).
+
+ ActivationDetails contains a list of string pairs, key and value, that
+ describe the event that caused the unit to be activated, if any. The key describes the information
+ (e.g.: trigger_unit, with value foo.service). This is only filled
+ in if the unit was triggered by a Path or Timer unit, and it is
+ only provided in a best effort fashion: it is not guaranteed to be set, and it is not guaranteed to be
+ the only trigger. It is only guaranteed to be a valid trigger that caused the activation job to be
+ enqueued and complete successfully. The key value pairs correspond (in lowercase) to the environment
+ variables described in the Environment Variables Set on Triggered Units section in
+ systemd.exec1.
+ Note that new key value pair may be added at any time in future versions. Existing entries will not be
+ removed.
@@ -10650,6 +10665,8 @@ node /org/freedesktop/systemd1/job/666 {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s JobType = '...';
readonly s State = '...';
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly a(ss) ActivationDetails = [...];
};
interface org.freedesktop.DBus.Peer { ... };
interface org.freedesktop.DBus.Introspectable { ... };
@@ -10681,6 +10698,8 @@ node /org/freedesktop/systemd1/job/666 {
+
+
@@ -10709,6 +10728,9 @@ node /org/freedesktop/systemd1/job/666 {
State refers to the job's state and is one of waiting and
running. The former indicates that a job is currently queued but has not begun to
execute yet. The latter indicates that a job is currently being executed.
+
+ ActivationDetails has the same content as the property of the same name under
+ the org.freedesktop.systemd1.Unit interface.
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index de474e6d4e..7b1438266b 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -7,6 +7,7 @@
#include "bus-util.h"
#include "dbus-job.h"
#include "dbus-unit.h"
+#include "dbus-util.h"
#include "dbus.h"
#include "job.h"
#include "log.h"
@@ -136,6 +137,7 @@ const sd_bus_vtable bus_job_vtable[] = {
SD_BUS_PROPERTY("Unit", "(so)", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("JobType", "s", property_get_type, offsetof(Job, type), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("State", "s", property_get_state, offsetof(Job, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("ActivationDetails", "a(ss)", bus_property_get_activation_details, offsetof(Job, activation_details), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index ee013e1bc5..7a16471758 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -951,6 +951,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("CollectMode", "s", property_get_collect_mode, offsetof(Unit, collect_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Refs", "as", property_get_refs, 0, 0),
+ SD_BUS_PROPERTY("ActivationDetails", "a(ss)", bus_property_get_activation_details, offsetof(Unit, activation_details), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_METHOD_WITH_ARGS("Start",
SD_BUS_ARGS("s", mode),
diff --git a/src/core/dbus-util.c b/src/core/dbus-util.c
index 264a4f55b6..edfa0eb69a 100644
--- a/src/core/dbus-util.c
+++ b/src/core/dbus-util.c
@@ -228,3 +228,35 @@ int bus_read_mount_options(
return 0;
}
+
+int bus_property_get_activation_details(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ActivationDetails **details = ASSERT_PTR(userdata);
+ _cleanup_strv_free_ char **pairs = NULL;
+ int r;
+
+ assert(reply);
+
+ r = activation_details_append_pair(*details, &pairs);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(ss)");
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH_PAIR(key, value, pairs) {
+ r = sd_bus_message_append(reply, "(ss)", *key, *value);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
diff --git a/src/core/dbus-util.h b/src/core/dbus-util.h
index 799136737b..e12631a0e2 100644
--- a/src/core/dbus-util.h
+++ b/src/core/dbus-util.h
@@ -251,3 +251,5 @@ static inline int bus_set_transient_usec_fix_0(Unit *u, const char *name, usec_t
int bus_verify_manage_units_async_full(Unit *u, const char *verb, int capability, const char *polkit_message, bool interactive, sd_bus_message *call, sd_bus_error *error);
int bus_read_mount_options(sd_bus_message *message, sd_bus_error *error, MountOptions **ret_options, char **ret_format_str, const char *separator);
+
+int bus_property_get_activation_details(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
diff --git a/src/core/job.c b/src/core/job.c
index 6653dbde84..dd8d858bd2 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -104,6 +104,8 @@ Job* job_free(Job *j) {
sd_bus_track_unref(j->bus_track);
strv_free(j->deserialized_clients);
+ activation_details_unref(j->activation_details);
+
return mfree(j);
}
@@ -180,9 +182,13 @@ static void job_merge_into_installed(Job *j, Job *other) {
assert(j->installed);
assert(j->unit == other->unit);
- if (j->type != JOB_NOP)
+ if (j->type != JOB_NOP) {
assert_se(job_type_merge_and_collapse(&j->type, other->type, j->unit) == 0);
- else
+
+ /* Keep the oldest ActivationDetails, if any */
+ if (!j->activation_details)
+ j->activation_details = TAKE_PTR(other->activation_details);
+ } else
assert(other->type == JOB_NOP);
j->irreversible = j->irreversible || other->irreversible;
@@ -776,6 +782,7 @@ static void job_emit_done_message(Unit *u, uint32_t job_id, JobType t, JobResult
}
static int job_perform_on_unit(Job **j) {
+ ActivationDetails *a;
uint32_t id;
Manager *m;
JobType t;
@@ -795,10 +802,11 @@ static int job_perform_on_unit(Job **j) {
u = (*j)->unit;
t = (*j)->type;
id = (*j)->id;
+ a = (*j)->activation_details;
switch (t) {
case JOB_START:
- r = unit_start(u);
+ r = unit_start(u, a);
break;
case JOB_RESTART:
@@ -1160,6 +1168,8 @@ int job_serialize(Job *j, FILE *f) {
bus_track_serialize(j->bus_track, f, "subscribed");
+ activation_details_serialize(j->activation_details, f);
+
/* End marker */
fputc('\n', f);
return 0;
@@ -1257,6 +1267,11 @@ int job_deserialize(Job *j, FILE *f) {
else if (streq(l, "subscribed")) {
if (strv_extend(&j->deserialized_clients, v) < 0)
return log_oom();
+
+ } else if (startswith(l, "activation-details")) {
+ if (activation_details_deserialize(l, v, &j->activation_details) < 0)
+ log_debug("Failed to parse job ActivationDetails element: %s", v);
+
} else
log_debug("Unknown job serialization key: %s", l);
}
@@ -1636,3 +1651,11 @@ int job_compare(Job *a, Job *b, UnitDependencyAtom assume_dep) {
else
return -1;
}
+
+void job_set_activation_details(Job *j, ActivationDetails *info) {
+ /* Existing (older) ActivationDetails win, newer ones are discarded. */
+ if (!j || j->activation_details || !info)
+ return; /* Nothing to do. */
+
+ j->activation_details = activation_details_ref(info);
+}
diff --git a/src/core/job.h b/src/core/job.h
index c033c8a4fa..0305e0ea44 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -10,6 +10,7 @@
#include "unit-name.h"
#include "unit.h"
+typedef struct ActivationDetails ActivationDetails;
typedef struct Job Job;
typedef struct JobDependency JobDependency;
typedef enum JobType JobType;
@@ -151,6 +152,9 @@ struct Job {
unsigned run_queue_idx;
+ /* If the job had a specific trigger that needs to be advertised (eg: a path unit), store it. */
+ ActivationDetails *activation_details;
+
bool installed:1;
bool in_run_queue:1;
bool matters_to_anchor:1;
@@ -243,3 +247,5 @@ JobResult job_result_from_string(const char *s) _pure_;
const char* job_type_to_access_method(JobType t);
int job_compare(Job *a, Job *b, UnitDependencyAtom assume_dep);
+
+void job_set_activation_details(Job *j, ActivationDetails *info);
diff --git a/src/core/service.c b/src/core/service.c
index a715a1d1dc..fa37207dcc 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1641,6 +1641,16 @@ static int service_spawn_internal(
}
}
+ if (UNIT(s)->activation_details) {
+ r = activation_details_append_env(UNIT(s)->activation_details, &our_env);
+ if (r < 0)
+ return r;
+ /* The number of env vars added here can vary, rather than keeping the allocation block in
+ * sync manually, these functions simply use the strv methods to append to it, so we need
+ * to update n_env when we are done in case of future usage. */
+ n_env += r;
+ }
+
r = unit_set_exec_params(UNIT(s), &exec_params);
if (r < 0)
return r;
diff --git a/src/core/unit.c b/src/core/unit.c
index 6242f045b4..18d9ba85de 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -41,6 +41,7 @@
#include "path-util.h"
#include "process-util.h"
#include "rm-rf.h"
+#include "serialize.h"
#include "set.h"
#include "signal-util.h"
#include "sparse-endian.h"
@@ -807,6 +808,8 @@ Unit* unit_free(Unit *u) {
set_free_free(u->aliases);
free(u->id);
+ activation_details_unref(u->activation_details);
+
return mfree(u);
}
@@ -1188,6 +1191,9 @@ int unit_merge(Unit *u, Unit *other) {
other->load_state = UNIT_MERGED;
other->merged_into = u;
+ if (!u->activation_details)
+ u->activation_details = activation_details_ref(other->activation_details);
+
/* If there is still some data attached to the other node, we
* don't need it anymore, and can free it. */
if (other->load_state != UNIT_STUB)
@@ -1861,7 +1867,7 @@ static bool unit_verify_deps(Unit *u) {
* -ESTALE: This unit has been started before and can't be started a second time
* -ENOENT: This is a triggering unit and unit to trigger is not loaded
*/
-int unit_start(Unit *u) {
+int unit_start(Unit *u, ActivationDetails *details) {
UnitActiveState state;
Unit *following;
int r;
@@ -1918,7 +1924,7 @@ int unit_start(Unit *u) {
following = unit_following(u);
if (following) {
log_unit_debug(u, "Redirecting start request from %s to %s.", u->id, following->id);
- return unit_start(following);
+ return unit_start(following, details);
}
/* Check our ability to start early so that failure conditions don't cause us to enter a busy loop. */
@@ -1939,6 +1945,9 @@ int unit_start(Unit *u) {
unit_add_to_dbus_queue(u);
unit_cgroup_freezer_action(u, FREEZER_THAW);
+ if (!u->activation_details) /* Older details object wins */
+ u->activation_details = activation_details_ref(details);
+
return UNIT_VTABLE(u)->start(u);
}
@@ -5919,3 +5928,152 @@ int unit_get_dependency_array(const Unit *u, UnitDependencyAtom atom, Unit ***re
assert(n <= INT_MAX);
return (int) n;
}
+
+const ActivationDetailsVTable * const activation_details_vtable[_UNIT_TYPE_MAX] = {
+};
+
+ActivationDetails *activation_details_new(Unit *trigger_unit) {
+ _cleanup_free_ ActivationDetails *details = NULL;
+
+ assert(trigger_unit);
+ assert(trigger_unit->type != _UNIT_TYPE_INVALID);
+ assert(trigger_unit->id);
+
+ details = malloc0(activation_details_vtable[trigger_unit->type]->object_size);
+ if (!details)
+ return NULL;
+
+ *details = (ActivationDetails) {
+ .n_ref = 1,
+ .trigger_unit_type = trigger_unit->type,
+ };
+
+ details->trigger_unit_name = strdup(trigger_unit->id);
+ if (!details->trigger_unit_name)
+ return NULL;
+
+ if (ACTIVATION_DETAILS_VTABLE(details)->init)
+ ACTIVATION_DETAILS_VTABLE(details)->init(details, trigger_unit);
+
+ return TAKE_PTR(details);
+}
+
+static ActivationDetails *activation_details_free(ActivationDetails *details) {
+ if (!details)
+ return NULL;
+
+ if (ACTIVATION_DETAILS_VTABLE(details)->done)
+ ACTIVATION_DETAILS_VTABLE(details)->done(details);
+
+ free(details->trigger_unit_name);
+
+ return mfree(details);
+}
+
+void activation_details_serialize(ActivationDetails *details, FILE *f) {
+ if (!details || details->trigger_unit_type == _UNIT_TYPE_INVALID)
+ return;
+
+ (void) serialize_item(f, "activation-details-unit-type", unit_type_to_string(details->trigger_unit_type));
+ if (details->trigger_unit_name)
+ (void) serialize_item(f, "activation-details-unit-name", details->trigger_unit_name);
+ if (ACTIVATION_DETAILS_VTABLE(details)->serialize)
+ ACTIVATION_DETAILS_VTABLE(details)->serialize(details, f);
+}
+
+int activation_details_deserialize(const char *key, const char *value, ActivationDetails **details) {
+ assert(key);
+ assert(value);
+ assert(details);
+
+ if (!*details) {
+ UnitType t;
+
+ if (!streq(key, "activation-details-unit-type"))
+ return -EINVAL;
+
+ t = unit_type_from_string(value);
+ if (t == _UNIT_TYPE_INVALID)
+ return -EINVAL;
+
+ *details = malloc0(activation_details_vtable[t]->object_size);
+ if (!*details)
+ return -ENOMEM;
+
+ **details = (ActivationDetails) {
+ .n_ref = 1,
+ .trigger_unit_type = t,
+ };
+
+ return 0;
+ }
+
+ if (streq(key, "activation-details-unit-name")) {
+ (*details)->trigger_unit_name = strdup(value);
+ if (!(*details)->trigger_unit_name)
+ return -ENOMEM;
+
+ return 0;
+ }
+
+ if (ACTIVATION_DETAILS_VTABLE(*details)->deserialize)
+ return ACTIVATION_DETAILS_VTABLE(*details)->deserialize(key, value, details);
+
+ return -EINVAL;
+}
+
+int activation_details_append_env(ActivationDetails *details, char ***strv) {
+ int r = 0;
+
+ assert(strv);
+
+ if (!details)
+ return 0;
+
+ if (!isempty(details->trigger_unit_name)) {
+ char *s = strjoin("TRIGGER_UNIT=", details->trigger_unit_name);
+ if (!s)
+ return -ENOMEM;
+
+ r = strv_consume(strv, TAKE_PTR(s));
+ if (r < 0)
+ return r;
+ }
+
+ if (ACTIVATION_DETAILS_VTABLE(details)->append_env) {
+ r = ACTIVATION_DETAILS_VTABLE(details)->append_env(details, strv);
+ if (r < 0)
+ return r;
+ }
+
+ return r + !isempty(details->trigger_unit_name); /* Return the number of variables added to the env block */
+}
+
+int activation_details_append_pair(ActivationDetails *details, char ***strv) {
+ int r = 0;
+
+ assert(strv);
+
+ if (!details)
+ return 0;
+
+ if (!isempty(details->trigger_unit_name)) {
+ r = strv_extend(strv, "trigger_unit");
+ if (r < 0)
+ return r;
+
+ r = strv_extend(strv, details->trigger_unit_name);
+ if (r < 0)
+ return r;
+ }
+
+ if (ACTIVATION_DETAILS_VTABLE(details)->append_env) {
+ r = ACTIVATION_DETAILS_VTABLE(details)->append_pair(details, strv);
+ if (r < 0)
+ return r;
+ }
+
+ return r + !isempty(details->trigger_unit_name); /* Return the number of pairs added to the strv */
+}
+
+DEFINE_TRIVIAL_REF_UNREF_FUNC(ActivationDetails, activation_details, activation_details_free);
diff --git a/src/core/unit.h b/src/core/unit.h
index 4dabbb9a3c..fc8edaade5 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -110,6 +110,75 @@ typedef union UnitDependencyInfo {
} _packed_;
} UnitDependencyInfo;
+/* Store information about why a unit was activated.
+ * We start with trigger units (.path/.timer), eventually it will be expanded to include more metadata. */
+typedef struct ActivationDetails {
+ unsigned n_ref;
+ UnitType trigger_unit_type;
+ char *trigger_unit_name;
+} ActivationDetails;
+
+/* For casting an activation event into the various unit-specific types */
+#define DEFINE_ACTIVATION_DETAILS_CAST(UPPERCASE, MixedCase, UNIT_TYPE) \
+ static inline MixedCase* UPPERCASE(ActivationDetails *a) { \
+ if (_unlikely_(!a || a->trigger_unit_type != UNIT_##UNIT_TYPE)) \
+ return NULL; \
+ \
+ return (MixedCase*) a; \
+ }
+
+/* For casting the various unit types into a unit */
+#define ACTIVATION_DETAILS(u) \
+ ({ \
+ typeof(u) _u_ = (u); \
+ ActivationDetails *_w_ = _u_ ? &(_u_)->meta : NULL; \
+ _w_; \
+ })
+
+ActivationDetails *activation_details_new(Unit *trigger_unit);
+ActivationDetails *activation_details_ref(ActivationDetails *p);
+ActivationDetails *activation_details_unref(ActivationDetails *p);
+void activation_details_serialize(ActivationDetails *p, FILE *f);
+int activation_details_deserialize(const char *key, const char *value, ActivationDetails **info);
+int activation_details_append_env(ActivationDetails *info, char ***strv);
+int activation_details_append_pair(ActivationDetails *info, char ***strv);
+DEFINE_TRIVIAL_CLEANUP_FUNC(ActivationDetails*, activation_details_unref);
+
+typedef struct ActivationDetailsVTable {
+ /* How much memory does an object of this activation type need */
+ size_t object_size;
+
+ /* This should reset all type-specific variables. This should not allocate memory, and is called
+ * with zero-initialized data. It should hence only initialize variables that need to be set != 0. */
+ void (*init)(ActivationDetails *info, Unit *trigger_unit);
+
+ /* This should free all type-specific variables. It should be idempotent. */
+ void (*done)(ActivationDetails *info);
+
+ /* This should serialize all type-specific variables. */
+ void (*serialize)(ActivationDetails *info, FILE *f);
+
+ /* This should deserialize all type-specific variables, one at a time. */
+ int (*deserialize)(const char *key, const char *value, ActivationDetails **info);
+
+ /* This should format the type-specific variables for the env block of the spawned service,
+ * and return the number of added items. */
+ int (*append_env)(ActivationDetails *info, char ***strv);
+
+ /* This should append type-specific variables as key/value pairs for the D-Bus property of the job,
+ * and return the number of added pairs. */
+ int (*append_pair)(ActivationDetails *info, char ***strv);
+} ActivationDetailsVTable;
+
+extern const ActivationDetailsVTable * const activation_details_vtable[_UNIT_TYPE_MAX];
+
+static inline const ActivationDetailsVTable* ACTIVATION_DETAILS_VTABLE(const ActivationDetails *a) {
+ assert(a);
+ assert(a->trigger_unit_type < _UNIT_TYPE_MAX);
+
+ return activation_details_vtable[a->trigger_unit_type];
+}
+
/* Newer LLVM versions don't like implicit casts from large pointer types to smaller enums, hence let's add
* explicit type-safe helpers for that. */
static inline UnitDependency UNIT_DEPENDENCY_FROM_PTR(const void *p) {
@@ -363,6 +432,9 @@ typedef struct Unit {
JobMode on_success_job_mode;
JobMode on_failure_job_mode;
+ /* If the job had a specific trigger that needs to be advertised (eg: a path unit), store it. */
+ ActivationDetails *activation_details;
+
/* Tweaking the GC logic */
CollectMode collect_mode;
@@ -813,7 +885,7 @@ bool unit_can_start(Unit *u) _pure_;
bool unit_can_stop(Unit *u) _pure_;
bool unit_can_isolate(Unit *u) _pure_;
-int unit_start(Unit *u);
+int unit_start(Unit *u, ActivationDetails *details);
int unit_stop(Unit *u);
int unit_reload(Unit *u);
diff --git a/src/test/test-bpf-firewall.c b/src/test/test-bpf-firewall.c
index 3b99c5aaec..d655058d3d 100644
--- a/src/test/test-bpf-firewall.c
+++ b/src/test/test-bpf-firewall.c
@@ -176,7 +176,7 @@ int main(int argc, char *argv[]) {
assert_se(r >= 0);
- assert_se(unit_start(u) >= 0);
+ assert_se(unit_start(u, NULL) >= 0);
while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED))
assert_se(sd_event_run(m->event, UINT64_MAX) >= 0);
@@ -201,7 +201,7 @@ int main(int argc, char *argv[]) {
SERVICE(u)->type = SERVICE_ONESHOT;
u->load_state = UNIT_LOADED;
- assert_se(unit_start(u) >= 0);
+ assert_se(unit_start(u, NULL) >= 0);
while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED))
assert_se(sd_event_run(m->event, UINT64_MAX) >= 0);
diff --git a/src/test/test-bpf-foreign-programs.c b/src/test/test-bpf-foreign-programs.c
index 061426f287..0445c39855 100644
--- a/src/test/test-bpf-foreign-programs.c
+++ b/src/test/test-bpf-foreign-programs.c
@@ -246,7 +246,7 @@ static int test_bpf_cgroup_programs(Manager *m, const char *unit_name, const Tes
SERVICE(u)->type = SERVICE_ONESHOT;
u->load_state = UNIT_LOADED;
- r = unit_start(u);
+ r = unit_start(u, NULL);
if (r < 0)
return log_error_errno(r, "Unit start failed %m");
diff --git a/src/test/test-bpf-lsm.c b/src/test/test-bpf-lsm.c
index 9709053d0a..e1df62f1a6 100644
--- a/src/test/test-bpf-lsm.c
+++ b/src/test/test-bpf-lsm.c
@@ -39,7 +39,7 @@ static int test_restrict_filesystems(Manager *m, const char *unit_name, const ch
SERVICE(u)->type = SERVICE_ONESHOT;
u->load_state = UNIT_LOADED;
- r = unit_start(u);
+ r = unit_start(u, NULL);
if (r < 0)
return log_error_errno(r, "Unit start failed %m");
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 82e4cf5e54..0283caeca6 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -210,7 +210,7 @@ static void _test(const char *file, unsigned line, const char *func,
assert_se(unit_name);
assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
- assert_se(unit_start(unit) >= 0);
+ assert_se(unit_start(unit, NULL) >= 0);
check_main_result(file, line, func, m, unit, status_expected, code_expected);
}
#define test(m, unit_name, status_expected, code_expected) \
@@ -223,7 +223,7 @@ static void _test_service(const char *file, unsigned line, const char *func,
assert_se(unit_name);
assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
- assert_se(unit_start(unit) >= 0);
+ assert_se(unit_start(unit, NULL) >= 0);
check_service_result(file, line, func, m, unit, result_expected);
}
#define test_service(m, unit_name, result_expected) \
diff --git a/src/test/test-path.c b/src/test/test-path.c
index 7fb1f7363c..a440ca08b4 100644
--- a/src/test/test-path.c
+++ b/src/test/test-path.c
@@ -136,7 +136,7 @@ static void test_path_exists(Manager *m) {
path = PATH(unit);
service = service_for_path(m, path, NULL);
- assert_se(unit_start(unit) >= 0);
+ assert_se(unit_start(unit, NULL) >= 0);
if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
return;
@@ -170,7 +170,7 @@ static void test_path_existsglob(Manager *m) {
path = PATH(unit);
service = service_for_path(m, path, NULL);
- assert_se(unit_start(unit) >= 0);
+ assert_se(unit_start(unit, NULL) >= 0);
if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
return;
@@ -205,7 +205,7 @@ static void test_path_changed(Manager *m) {
path = PATH(unit);
service = service_for_path(m, path, NULL);
- assert_se(unit_start(unit) >= 0);
+ assert_se(unit_start(unit, NULL) >= 0);
if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
return;
@@ -247,7 +247,7 @@ static void test_path_modified(Manager *m) {
path = PATH(unit);
service = service_for_path(m, path, NULL);
- assert_se(unit_start(unit) >= 0);
+ assert_se(unit_start(unit, NULL) >= 0);
if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
return;
@@ -288,7 +288,7 @@ static void test_path_unit(Manager *m) {
path = PATH(unit);
service = service_for_path(m, path, "path-mycustomunit.service");
- assert_se(unit_start(unit) >= 0);
+ assert_se(unit_start(unit, NULL) >= 0);
if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
return;
@@ -319,7 +319,7 @@ static void test_path_directorynotempty(Manager *m) {
assert_se(access(test_path, F_OK) < 0);
- assert_se(unit_start(unit) >= 0);
+ assert_se(unit_start(unit, NULL) >= 0);
if (check_states(m, path, service, PATH_WAITING, SERVICE_DEAD) < 0)
return;
@@ -356,7 +356,7 @@ static void test_path_makedirectory_directorymode(Manager *m) {
assert_se(access(test_path, F_OK) < 0);
- assert_se(unit_start(unit) >= 0);
+ assert_se(unit_start(unit, NULL) >= 0);
/* Check if the directory has been created */
assert_se(access(test_path, F_OK) >= 0);
diff --git a/src/test/test-socket-bind.c b/src/test/test-socket-bind.c
index dadd2c0dff..d7d9110343 100644
--- a/src/test/test-socket-bind.c
+++ b/src/test/test-socket-bind.c
@@ -78,7 +78,7 @@ static int test_socket_bind(
SERVICE(u)->type = SERVICE_ONESHOT;
u->load_state = UNIT_LOADED;
- r = unit_start(u);
+ r = unit_start(u, NULL);
if (r < 0)
return log_error_errno(r, "Unit start failed %m");