strv_free(u->dropin_paths);
free(u->instance);
+ free(u->job_timeout_reboot_arg);
+
set_free_free(u->names);
unit_unwatch_all_pids(u);
return UNIT_VTABLE(u)->sub_state_to_string(u);
}
-static void complete_move(Set **s, Set **other) {
+static int complete_move(Set **s, Set **other) {
+ int r;
+
assert(s);
assert(other);
if (!*other)
- return;
+ return 0;
- if (*s)
- set_move(*s, *other);
- else {
+ if (*s) {
+ r = set_move(*s, *other);
+ if (r < 0)
+ return r;
+ } else {
*s = *other;
*other = NULL;
}
+
+ return 0;
}
-static void merge_names(Unit *u, Unit *other) {
+static int merge_names(Unit *u, Unit *other) {
char *t;
Iterator i;
+ int r;
assert(u);
assert(other);
- complete_move(&u->names, &other->names);
+ r = complete_move(&u->names, &other->names);
+ if (r < 0)
+ return r;
set_free_free(other->names);
other->names = NULL;
SET_FOREACH(t, u->names, i)
assert_se(hashmap_replace(u->manager->units, t, u) == 0);
+
+ return 0;
+}
+
+static int reserve_dependencies(Unit *u, Unit *other, UnitDependency d) {
+ unsigned n_reserve;
+
+ assert(u);
+ assert(other);
+ assert(d < _UNIT_DEPENDENCY_MAX);
+
+ /*
+ * If u does not have this dependency set allocated, there is no need
+ * to reserve anything. In that case other's set will be transfered
+ * as a whole to u by complete_move().
+ */
+ if (!u->dependencies[d])
+ return 0;
+
+ /* merge_dependencies() will skip a u-on-u dependency */
+ n_reserve = set_size(other->dependencies[d]) - !!set_get(other->dependencies[d], u);
+
+ return set_reserve(u->dependencies[d], n_reserve);
}
static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitDependency d) {
if (back)
maybe_warn_about_dependency(u->id, other_id, d);
- complete_move(&u->dependencies[d], &other->dependencies[d]);
+ /* The move cannot fail. The caller must have performed a reservation. */
+ assert_se(complete_move(&u->dependencies[d], &other->dependencies[d]) == 0);
set_free(other->dependencies[d]);
other->dependencies[d] = NULL;
int unit_merge(Unit *u, Unit *other) {
UnitDependency d;
const char *other_id = NULL;
+ int r;
assert(u);
assert(other);
if (other->id)
other_id = strdupa(other->id);
+ /* Make reservations to ensure merge_dependencies() won't fail */
+ for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
+ r = reserve_dependencies(u, other, d);
+ /*
+ * We don't rollback reservations if we fail. We don't have
+ * a way to undo reservations. A reservation is not a leak.
+ */
+ if (r < 0)
+ return r;
+ }
+
/* Merge names */
- merge_names(u, other);
+ r = merge_names(u, other);
+ if (r < 0)
+ return r;
/* Redirect all references */
while (other->refs)
if (u->job_timeout > 0)
fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
+ if (u->job_timeout_action != FAILURE_ACTION_NONE)
+ fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, failure_action_to_string(u->job_timeout_action));
+
+ if (u->job_timeout_reboot_arg)
+ fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
+
condition_dump_list(u->conditions, f, prefix);
if (dual_timestamp_is_set(&u->condition_timestamp))
if (u->manager->running_as == SYSTEMD_USER) {
int r;
- r = user_config_home(dir);
+ if (mode == UNIT_PERSISTENT && !transient)
+ r = user_config_home(dir);
+ else
+ r = user_runtime_dir(dir);
+
if (r == 0)
return -ENOENT;
return r;
if (u->manager->running_as == SYSTEMD_USER) {
_cleanup_free_ char *c = NULL;
- r = user_config_home(&c);
+ r = user_runtime_dir(&c);
if (r < 0)
return r;
if (r == 0)
};
DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
-
-static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
- [UNIT_REQUIRES] = "Requires",
- [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
- [UNIT_REQUISITE] = "Requisite",
- [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable",
- [UNIT_WANTS] = "Wants",
- [UNIT_BINDS_TO] = "BindsTo",
- [UNIT_PART_OF] = "PartOf",
- [UNIT_REQUIRED_BY] = "RequiredBy",
- [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable",
- [UNIT_WANTED_BY] = "WantedBy",
- [UNIT_BOUND_BY] = "BoundBy",
- [UNIT_CONSISTS_OF] = "ConsistsOf",
- [UNIT_CONFLICTS] = "Conflicts",
- [UNIT_CONFLICTED_BY] = "ConflictedBy",
- [UNIT_BEFORE] = "Before",
- [UNIT_AFTER] = "After",
- [UNIT_ON_FAILURE] = "OnFailure",
- [UNIT_TRIGGERS] = "Triggers",
- [UNIT_TRIGGERED_BY] = "TriggeredBy",
- [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo",
- [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom",
- [UNIT_JOINS_NAMESPACE_OF] = "JoinsNamespaceOf",
- [UNIT_REFERENCES] = "References",
- [UNIT_REFERENCED_BY] = "ReferencedBy",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);