if (!u)
return NULL;
- u->names = set_new(string_hash_func, string_compare_func);
+ u->names = set_new(&string_hash_ops);
if (!u->names) {
free(u);
return NULL;
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)
char *t, **j;
UnitDependency d;
Iterator i;
- _cleanup_free_ char *p2 = NULL;
const char *prefix2;
char
timestamp1[FORMAT_TIMESTAMP_MAX],
assert(u);
assert(u->type >= 0);
- if (!prefix)
- prefix = "";
- p2 = strappend(prefix, "\t");
- prefix2 = p2 ? p2 : prefix;
+ prefix = strempty(prefix);
+ prefix2 = strappenda(prefix, "\t");
fprintf(f,
"%s-> Unit %s:\n"
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))
/* Watch a specific PID. We only support one or two units
* watching each PID for now, not more. */
- r = set_ensure_allocated(&u->pids, trivial_hash_func, trivial_compare_func);
+ r = set_ensure_allocated(&u->pids, NULL);
if (r < 0)
return r;
- r = hashmap_ensure_allocated(&u->manager->watch_pids1, trivial_hash_func, trivial_compare_func);
+ r = hashmap_ensure_allocated(&u->manager->watch_pids1, NULL);
if (r < 0)
return r;
r = hashmap_put(u->manager->watch_pids1, LONG_TO_PTR(pid), u);
if (r == -EEXIST) {
- r = hashmap_ensure_allocated(&u->manager->watch_pids2, trivial_hash_func, trivial_compare_func);
+ r = hashmap_ensure_allocated(&u->manager->watch_pids2, NULL);
if (r < 0)
return r;
return 0;
}
- r = set_ensure_allocated(&u->dependencies[d], trivial_hash_func, trivial_compare_func);
+ r = set_ensure_allocated(&u->dependencies[d], NULL);
if (r < 0)
return r;
if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) {
- r = set_ensure_allocated(&other->dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func);
+ r = set_ensure_allocated(&other->dependencies[inverse_table[d]], NULL);
if (r < 0)
return r;
}
if (add_reference) {
- r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func);
+ r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], NULL);
if (r < 0)
return r;
- r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func);
+ r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], NULL);
if (r < 0)
return r;
}
Set *pid_set;
int r;
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
+ pid_set = set_new(NULL);
if (!pid_set)
return NULL;
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)
char *q;
if (!u->manager->units_requiring_mounts_for) {
- u->manager->units_requiring_mounts_for = hashmap_new(string_hash_func, string_compare_func);
+ u->manager->units_requiring_mounts_for = hashmap_new(&string_hash_ops);
if (!u->manager->units_requiring_mounts_for)
return -ENOMEM;
}
if (!q)
return -ENOMEM;
- x = set_new(NULL, NULL);
+ x = set_new(NULL);
if (!x) {
free(q);
return -ENOMEM;
offset = UNIT_VTABLE(u)->exec_runtime_offset;
assert(offset > 0);
- /* Check if ther already is an ExecRuntime for this unit? */
+ /* Check if there already is an ExecRuntime for this unit? */
rt = (ExecRuntime**) ((uint8_t*) u + offset);
if (*rt)
return 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);