X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Funit.c;h=e40e6f2068c682f58e135f254cf65202f84351d6;hb=7c52a17b1a31eedd40093a4fbb460cf492087d9b;hp=8a7df01284b64109015f931d4024eba9a8941f74;hpb=718880ba0d557a045e2f969e141cbd59e78c76f4;p=elogind.git diff --git a/src/core/unit.c b/src/core/unit.c index 8a7df0128..e40e6f206 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -553,29 +553,38 @@ const char* unit_sub_state_to_string(Unit *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; @@ -583,6 +592,29 @@ static void merge_names(Unit *u, Unit *other) { 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) { @@ -618,7 +650,8 @@ static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitD 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; @@ -627,6 +660,7 @@ static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitD int unit_merge(Unit *u, Unit *other) { UnitDependency d; const char *other_id = NULL; + int r; assert(u); assert(other); @@ -660,8 +694,21 @@ int unit_merge(Unit *u, Unit *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) @@ -3083,7 +3130,7 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, if (mode == UNIT_PERSISTENT && !transient) r = user_config_home(dir); else - r = user_runtime(dir); + r = user_runtime_dir(dir); if (r == 0) return -ENOENT; @@ -3232,7 +3279,7 @@ int unit_make_transient(Unit *u) { if (u->manager->running_as == SYSTEMD_USER) { _cleanup_free_ char *c = NULL; - r = user_runtime(&c); + r = user_runtime_dir(&c); if (r < 0) return r; if (r == 0) @@ -3457,32 +3504,3 @@ static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { }; 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);