core: add Ref()/Unref() bus calls for units

This adds two (privileged) bus calls Ref() and Unref() to the Unit interface.
The two calls may be used by clients to pin a unit into memory, so that various
runtime properties aren't flushed out by the automatic GC. This is necessary
to permit clients to race-freely acquire runtime results (such as process exit
status/code or accumulated CPU time) on successful service termination.

Ref() and Unref() are fully recursive, hence act like the usual reference
counting concept in C. Taking a reference is a privileged operation, as this
allows pinning units into memory which consumes resources.

Transient units may also gain a reference at the time of creation, via the new
AddRef property (that is only defined for transient units at the time of
creation).
This commit is contained in:
Lennart Poettering 2016-08-15 18:12:01 +02:00
parent ecddb2b586
commit 05a98afd3e
14 changed files with 342 additions and 85 deletions

View File

@ -642,13 +642,13 @@
<term><command>list-units <optional><replaceable>PATTERN</replaceable>...</optional></command></term>
<listitem>
<para>List units that <command>systemd</command> has loaded. This includes units that
are either referenced directly or through a dependency, or units that were active in the
past and have failed. By default only units which are active, have pending jobs, or have
<para>List units that <command>systemd</command> has loaded. This includes units that are either referenced
directly or through a dependency, units that are pinned by applications programmatically, or units that
were active in the past and have failed. By default only units which are active, have pending jobs, or have
failed are shown; this can be changed with option <option>--all</option>. If one or more
<replaceable>PATTERN</replaceable>s are specified, only units matching one of them are
shown. The units that are shown are additionally filtered by <option>--type=</option>
and <option>--state=</option> if those options are specified.</para>
<replaceable>PATTERN</replaceable>s are specified, only units matching one of them are shown. The units
that are shown are additionally filtered by <option>--type=</option> and <option>--state=</option> if those
options are specified.</para>
<para>This is the default command.</para>
</listitem>

View File

@ -643,6 +643,54 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s
return bus_unit_method_set_properties(message, u, error);
}
static int method_ref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
Unit *u;
int r;
assert(message);
assert(m);
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
r = manager_load_unit(m, name, NULL, error, &u);
if (r < 0)
return r;
r = bus_unit_check_load_state(u, error);
if (r < 0)
return r;
return bus_unit_method_ref(message, u, error);
}
static int method_unref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
Unit *u;
int r;
assert(message);
assert(m);
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
r = manager_load_unit(m, name, NULL, error, &u);
if (r < 0)
return r;
r = bus_unit_check_load_state(u, error);
if (r < 0)
return r;
return bus_unit_method_unref(message, u, error);
}
static int reply_unit_info(sd_bus_message *reply, Unit *u) {
_cleanup_free_ char *unit_path = NULL, *job_path = NULL;
Unit *following;
@ -781,6 +829,13 @@ static int transient_unit_from_message(
if (r < 0)
return r;
/* If the client asked for it, automatically add a reference to this unit. */
if (u->bus_track_add) {
r = bus_unit_track_add_sender(u, message);
if (r < 0)
return log_error_errno(r, "Failed to watch sender: %m");
}
/* Now load the missing bits of the unit we just created */
unit_add_to_load_queue(u);
manager_dispatch_load_queue(m);
@ -2211,6 +2266,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("RefUnit", "s", NULL, method_ref_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnrefUnit", "s", NULL, method_unref_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitProcesses", "s", "a(sus)", method_get_unit_processes, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED),

View File

@ -418,6 +418,7 @@ static int bus_verify_manage_units_async_full(
const char *verb,
int capability,
const char *polkit_message,
bool interactive,
sd_bus_message *call,
sd_bus_error *error) {
@ -433,7 +434,15 @@ static int bus_verify_manage_units_async_full(
details[7] = GETTEXT_PACKAGE;
}
return bus_verify_polkit_async(call, capability, "org.freedesktop.systemd1.manage-units", details, false, UID_INVALID, &u->manager->polkit_registry, error);
return bus_verify_polkit_async(
call,
capability,
"org.freedesktop.systemd1.manage-units",
details,
interactive,
UID_INVALID,
&u->manager->polkit_registry,
error);
}
int bus_unit_method_start_generic(
@ -486,6 +495,7 @@ int bus_unit_method_start_generic(
verb,
CAP_SYS_ADMIN,
job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL,
true,
message,
error);
if (r < 0)
@ -558,6 +568,7 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
"kill",
CAP_KILL,
N_("Authentication is required to kill '$(unit)'."),
true,
message,
error);
if (r < 0)
@ -588,6 +599,7 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus
"reset-failed",
CAP_SYS_ADMIN,
N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
true,
message,
error);
if (r < 0)
@ -620,6 +632,7 @@ int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_b
"set-property",
CAP_SYS_ADMIN,
N_("Authentication is required to set properties on '$(unit)'."),
true,
message,
error);
if (r < 0)
@ -634,6 +647,53 @@ int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_b
return sd_bus_reply_method_return(message, NULL);
}
int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Unit *u = userdata;
int r;
assert(message);
assert(u);
r = mac_selinux_unit_access_check(u, message, "start", error);
if (r < 0)
return r;
r = bus_verify_manage_units_async_full(
u,
"ref",
CAP_SYS_ADMIN,
NULL,
false,
message,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = bus_unit_track_add_sender(u, message);
if (r < 0)
return r;
return sd_bus_reply_method_return(message, NULL);
}
int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Unit *u = userdata;
int r;
assert(message);
assert(u);
r = bus_unit_track_remove_sender(u, message);
if (r == -EUNATCH)
return sd_bus_error_setf(error, BUS_ERROR_NOT_REFERENCED, "Unit has not been referenced yet.");
if (r < 0)
return r;
return sd_bus_reply_method_return(message, NULL);
}
const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_VTABLE_START(0),
@ -715,6 +775,8 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Ref", NULL, NULL, bus_unit_method_ref, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Unref", NULL, NULL, bus_unit_method_unref, SD_BUS_VTABLE_UNPRIVILEGED),
/* Obsolete properties or obsolete alias names */
SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
@ -1318,6 +1380,29 @@ static int bus_unit_set_transient_property(
return r;
return 1;
} else if (streq(name, "AddRef")) {
int b;
/* Why is this called "AddRef" rather than just "Ref", or "Reference"? There's already a "Ref()" method
* on the Unit interface, and it's probably not a good idea to expose a property and a method on the
* same interface (well, strictly speaking AddRef isn't exposed as full property, we just read it for
* transient units, but still). And "References" and "ReferencedBy" is already used as unit reference
* dependency type, hence let's not confuse things with that.
*
* Note that we don't acually add the reference to the bus track. We do that only after the setup of
* the transient unit is complete, so that setting this property multiple times in the same transient
* unit creation call doesn't count as individual references. */
r = sd_bus_message_read(message, "b", &b);
if (r < 0)
return r;
if (mode != UNIT_CHECK)
u->bus_track_add = b;
return 1;
}
return 0;
@ -1422,3 +1507,71 @@ int bus_unit_check_load_state(Unit *u, sd_bus_error *error) {
return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id);
}
static int bus_track_handler(sd_bus_track *t, void *userdata) {
Unit *u = userdata;
assert(t);
assert(u);
u->bus_track = sd_bus_track_unref(u->bus_track); /* make sure we aren't called again */
unit_add_to_gc_queue(u);
return 0;
}
static int allocate_bus_track(Unit *u) {
int r;
assert(u);
if (u->bus_track)
return 0;
r = sd_bus_track_new(u->manager->api_bus, &u->bus_track, bus_track_handler, u);
if (r < 0)
return r;
r = sd_bus_track_set_recursive(u->bus_track, true);
if (r < 0) {
u->bus_track = sd_bus_track_unref(u->bus_track);
return r;
}
return 0;
}
int bus_unit_track_add_name(Unit *u, const char *name) {
int r;
assert(u);
r = allocate_bus_track(u);
if (r < 0)
return r;
return sd_bus_track_add_name(u->bus_track, name);
}
int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) {
int r;
assert(u);
r = allocate_bus_track(u);
if (r < 0)
return r;
return sd_bus_track_add_sender(u->bus_track, m);
}
int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m) {
assert(u);
/* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an
* error */
if (!u->bus_track)
return -EUNATCH;
return sd_bus_track_remove_sender(u->bus_track, m);
}

View File

@ -33,9 +33,15 @@ int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_
int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error);
int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
int bus_unit_check_load_state(Unit *u, sd_bus_error *error);
int bus_unit_track_add_name(Unit *u, const char *name);
int bus_unit_track_add_sender(Unit *u, sd_bus_message *m);
int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m);

View File

@ -1168,60 +1168,57 @@ int bus_foreach_bus(
return ret;
}
void bus_track_serialize(sd_bus_track *t, FILE *f) {
void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix) {
const char *n;
assert(f);
assert(prefix);
for (n = sd_bus_track_first(t); n; n = sd_bus_track_next(t))
fprintf(f, "subscribed=%s\n", n);
for (n = sd_bus_track_first(t); n; n = sd_bus_track_next(t)) {
int c, j;
c = sd_bus_track_count_name(t, n);
for (j = 0; j < c; j++) {
fputs(prefix, f);
fputc('=', f);
fputs(n, f);
fputc('\n', f);
}
}
}
int bus_track_deserialize_item(char ***l, const char *line) {
const char *e;
int r;
assert(l);
assert(line);
e = startswith(line, "subscribed=");
if (!e)
return 0;
r = strv_extend(l, e);
if (r < 0)
return r;
return 1;
}
int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) {
int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l) {
char **i;
int r = 0;
assert(m);
assert(t);
assert(l);
if (!strv_isempty(*l) && m->api_bus) {
char **i;
if (strv_isempty(l))
return 0;
if (!*t) {
r = sd_bus_track_new(m->api_bus, t, NULL, NULL);
if (r < 0)
return r;
}
if (!m->api_bus)
return 0;
r = 0;
STRV_FOREACH(i, *l) {
int k;
k = sd_bus_track_add_name(*t, *i);
if (k < 0)
r = k;
}
if (!*t) {
r = sd_bus_track_new(m->api_bus, t, NULL, NULL);
if (r < 0)
return r;
}
*l = strv_free(*l);
r = sd_bus_track_set_recursive(*t, recursive);
if (r < 0)
return r;
r = 0;
STRV_FOREACH(i, l) {
int k;
k = sd_bus_track_add_name(*t, *i);
if (k < 0)
r = k;
}
return r;
}

View File

@ -28,9 +28,8 @@ void bus_done(Manager *m);
int bus_fdset_add_all(Manager *m, FDSet *fds);
void bus_track_serialize(sd_bus_track *t, FILE *f);
int bus_track_deserialize_item(char ***l, const char *line);
int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l);
void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix);
int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l);
int manager_sync_bus_names(Manager *m, sd_bus *bus);

View File

@ -997,7 +997,10 @@ char *job_dbus_path(Job *j) {
return p;
}
int job_serialize(Job *j, FILE *f, FDSet *fds) {
int job_serialize(Job *j, FILE *f) {
assert(j);
assert(f);
fprintf(f, "job-id=%u\n", j->id);
fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
@ -1008,15 +1011,16 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) {
if (j->begin_usec > 0)
fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec);
bus_track_serialize(j->clients, f);
bus_track_serialize(j->clients, f, "subscribed");
/* End marker */
fputc('\n', f);
return 0;
}
int job_deserialize(Job *j, FILE *f, FDSet *fds) {
int job_deserialize(Job *j, FILE *f) {
assert(j);
assert(f);
for (;;) {
char line[LINE_MAX], *l, *v;
@ -1106,7 +1110,7 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) {
} else if (streq(l, "subscribed")) {
if (strv_extend(&j->deserialized_clients, v) < 0)
return log_oom();
log_oom();
}
}
}
@ -1118,9 +1122,8 @@ int job_coldplug(Job *j) {
/* After deserialization is complete and the bus connection
* set up again, let's start watching our subscribers again */
r = bus_track_coldplug(j->manager, &j->clients, &j->deserialized_clients);
if (r < 0)
return r;
(void) bus_track_coldplug(j->manager, &j->clients, false, j->deserialized_clients);
j->deserialized_clients = strv_free(j->deserialized_clients);
if (j->state == JOB_WAITING)
job_add_to_run_queue(j);

View File

@ -177,8 +177,8 @@ Job* job_install(Job *j);
int job_install_deserialized(Job *j);
void job_uninstall(Job *j);
void job_dump(Job *j, FILE*f, const char *prefix);
int job_serialize(Job *j, FILE *f, FDSet *fds);
int job_deserialize(Job *j, FILE *f, FDSet *fds);
int job_serialize(Job *j, FILE *f);
int job_deserialize(Job *j, FILE *f);
int job_coldplug(Job *j);
JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts);

View File

@ -1287,10 +1287,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (q < 0 && r == 0)
r = q;
/* We might have deserialized the kdbus control fd, but if we
* didn't, then let's create the bus now. */
manager_connect_bus(m, !!serialization);
bus_track_coldplug(m, &m->subscribed, &m->deserialized_subscribed);
/* We might have deserialized the kdbus control fd, but if we didn't, then let's create the bus now. */
(void) manager_connect_bus(m, !!serialization);
(void) bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed);
m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
/* Third, fire things up! */
manager_coldplug(m);
@ -2490,7 +2491,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
fprintf(f, "kdbus-fd=%i\n", copy);
}
bus_track_serialize(m->subscribed, f);
bus_track_serialize(m->subscribed, f, "subscribed");
r = dynamic_user_serialize(m, f, fds);
if (r < 0)
@ -2693,15 +2694,13 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
manager_deserialize_uid_refs_one(m, l + 16);
else if (startswith(l, "destroy-ipc-gid="))
manager_deserialize_gid_refs_one(m, l + 16);
else {
int k;
else if (startswith(l, "subscribed=")) {
k = bus_track_deserialize_item(&m->deserialized_subscribed, l);
if (k < 0)
log_debug_errno(k, "Failed to deserialize bus tracker object: %m");
else if (k == 0)
log_debug("Unknown serialization item '%s'", l);
}
if (strv_extend(&m->deserialized_subscribed, l+11) < 0)
log_oom();
} else
log_debug("Unknown serialization item '%s'", l);
}
for (;;) {

View File

@ -182,6 +182,14 @@
send_interface="org.freedesktop.systemd1.Manager"
send_member="Reexecute"/>
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
send_member="RefUnit"/>
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
send_member="UnrefUnit"/>
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
send_member="EnableUnitFiles"/>

View File

@ -329,6 +329,9 @@ bool unit_check_gc(Unit *u) {
if (u->refs)
return true;
if (sd_bus_track_count(u->bus_track) > 0)
return true;
if (UNIT_VTABLE(u)->check_gc)
if (UNIT_VTABLE(u)->check_gc(u))
return true;
@ -509,6 +512,9 @@ void unit_free(Unit *u) {
sd_bus_slot_unref(u->match_bus_slot);
sd_bus_track_unref(u->bus_track);
u->deserialized_refs = strv_free(u->deserialized_refs);
unit_free_requires_mounts_for(u);
SET_FOREACH(t, u->names, i)
@ -897,6 +903,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
Unit *following;
_cleanup_set_free_ Set *following_set = NULL;
int r;
const char *n;
assert(u);
assert(u->type >= 0);
@ -1038,6 +1045,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
else if (u->load_state == UNIT_ERROR)
fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->load_error));
for (n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track))
fprintf(f, "%s\tBus Ref: %s\n", prefix, n);
if (u->job)
job_dump(u->job, f, prefix2);
@ -2622,15 +2631,17 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
if (gid_is_valid(u->ref_gid))
unit_serialize_item_format(u, f, "ref-gid", GID_FMT, u->ref_gid);
bus_track_serialize(u->bus_track, f, "ref");
if (serialize_jobs) {
if (u->job) {
fprintf(f, "job\n");
job_serialize(u->job, f, fds);
job_serialize(u->job, f);
}
if (u->nop_job) {
fprintf(f, "job\n");
job_serialize(u->nop_job, f, fds);
job_serialize(u->nop_job, f);
}
}
@ -2760,7 +2771,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
if (!j)
return log_oom();
r = job_deserialize(j, f, fds);
r = job_deserialize(j, f);
if (r < 0) {
job_free(j);
return r;
@ -2880,6 +2891,12 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
else
unit_ref_uid_gid(u, UID_INVALID, gid);
} else if (streq(l, "ref")) {
r = strv_extend(&u->deserialized_refs, v);
if (r < 0)
log_oom();
continue;
}
@ -2955,7 +2972,8 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep
}
int unit_coldplug(Unit *u) {
int r = 0, q = 0;
int r = 0, q;
char **i;
assert(u);
@ -2966,18 +2984,26 @@ int unit_coldplug(Unit *u) {
u->coldplugged = true;
if (UNIT_VTABLE(u)->coldplug)
r = UNIT_VTABLE(u)->coldplug(u);
STRV_FOREACH(i, u->deserialized_refs) {
q = bus_unit_track_add_name(u, *i);
if (q < 0 && r >= 0)
r = q;
}
u->deserialized_refs = strv_free(u->deserialized_refs);
if (u->job)
if (UNIT_VTABLE(u)->coldplug) {
q = UNIT_VTABLE(u)->coldplug(u);
if (q < 0 && r >= 0)
r = q;
}
if (u->job) {
q = job_coldplug(u->job);
if (q < 0 && r >= 0)
r = q;
}
if (r < 0)
return r;
if (q < 0)
return q;
return 0;
return r;
}
static bool fragment_mtime_newer(const char *path, usec_t mtime) {

View File

@ -108,6 +108,10 @@ struct Unit {
/* The slot used for watching NameOwnerChanged signals */
sd_bus_slot *match_bus_slot;
/* References to this unit from clients */
sd_bus_track *bus_track;
char **deserialized_refs;
/* Job timeout and action to take */
usec_t job_timeout;
FailureAction job_timeout_action;
@ -247,6 +251,9 @@ struct Unit {
/* Did we already invoke unit_coldplug() for this unit? */
bool coldplugged:1;
/* For transient units: whether to add a bus track reference after creating the unit */
bool bus_track_add:1;
};
struct UnitStatusMessageFormats {

View File

@ -45,6 +45,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN, ECANCELED),
SD_BUS_ERROR_MAP(BUS_ERROR_SCOPE_NOT_RUNNING, EHOSTDOWN),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DYNAMIC_USER, ESRCH),
SD_BUS_ERROR_MAP(BUS_ERROR_NOT_REFERENCED, EUNATCH),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_MACHINE, ENXIO),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_IMAGE, ENOENT),

View File

@ -41,6 +41,7 @@
#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown"
#define BUS_ERROR_SCOPE_NOT_RUNNING "org.freedesktop.systemd1.ScopeNotRunning"
#define BUS_ERROR_NO_SUCH_DYNAMIC_USER "org.freedesktop.systemd1.NoSuchDynamicUser"
#define BUS_ERROR_NOT_REFERENCED "org.freedesktop.systemd1.NotReferenced"
#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine"
#define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage"