X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Funit.c;h=7f463f311ba5b189a1f27b363c66f5c04bcd9dce;hp=27119b0cd72880797ed770d762b6dc30dc827c36;hb=16ed0233a5b7ae38ed4f544d6fcd5827cde695dc;hpb=68eda4bd168306f51c90e5d22824c494d709289e diff --git a/src/core/unit.c b/src/core/unit.c index 27119b0cd..7f463f311 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -127,7 +127,8 @@ int unit_add_name(Unit *u, const char *text) { goto fail; } - if ((r = unit_name_to_instance(s, &i)) < 0) + r = unit_name_to_instance(s, &i); + if (r < 0) goto fail; if (i && unit_vtable[t]->no_instances) { @@ -154,13 +155,15 @@ int unit_add_name(Unit *u, const char *text) { goto fail; } - if ((r = set_put(u->names, s)) < 0) { + r = set_put(u->names, s); + if (r < 0) { if (r == -EEXIST) r = 0; goto fail; } - if ((r = hashmap_put(u->manager->units, s, u)) < 0) { + r = hashmap_put(u->manager->units, s, u); + if (r < 0) { set_remove(u->names, s); goto fail; } @@ -171,7 +174,7 @@ int unit_add_name(Unit *u, const char *text) { u->id = s; u->instance = i; - LIST_PREPEND(Unit, units_by_type, u->manager->units_by_type[t], u); + LIST_PREPEND(units_by_type, u->manager->units_by_type[t], u); if (UNIT_VTABLE(u)->init) UNIT_VTABLE(u)->init(u); @@ -201,7 +204,8 @@ int unit_choose_id(Unit *u, const char *name) { if (!u->instance) return -EINVAL; - if (!(t = unit_name_replace_instance(name, u->instance))) + t = unit_name_replace_instance(name, u->instance); + if (!t) return -ENOMEM; name = t; @@ -213,7 +217,8 @@ int unit_choose_id(Unit *u, const char *name) { if (!s) return -ENOENT; - if ((r = unit_name_to_instance(s, &i)) < 0) + r = unit_name_to_instance(s, &i); + if (r < 0) return r; u->id = s; @@ -284,7 +289,7 @@ void unit_add_to_load_queue(Unit *u) { if (u->load_state != UNIT_STUB || u->in_load_queue) return; - LIST_PREPEND(Unit, load_queue, u->manager->load_queue, u); + LIST_PREPEND(load_queue, u->manager->load_queue, u); u->in_load_queue = true; } @@ -294,7 +299,7 @@ void unit_add_to_cleanup_queue(Unit *u) { if (u->in_cleanup_queue) return; - LIST_PREPEND(Unit, cleanup_queue, u->manager->cleanup_queue, u); + LIST_PREPEND(cleanup_queue, u->manager->cleanup_queue, u); u->in_cleanup_queue = true; } @@ -307,7 +312,7 @@ void unit_add_to_gc_queue(Unit *u) { if (unit_check_gc(u)) return; - LIST_PREPEND(Unit, gc_queue, u->manager->gc_queue, u); + LIST_PREPEND(gc_queue, u->manager->gc_queue, u); u->in_gc_queue = true; u->manager->n_in_gc_queue ++; @@ -326,7 +331,7 @@ void unit_add_to_dbus_queue(Unit *u) { return; } - LIST_PREPEND(Unit, dbus_queue, u->manager->dbus_unit_queue, u); + LIST_PREPEND(dbus_queue, u->manager->dbus_unit_queue, u); u->in_dbus_queue = true; } @@ -374,6 +379,34 @@ static void unit_remove_transient(Unit *u) { } } +static void unit_free_requires_mounts_for(Unit *u) { + char **j; + + STRV_FOREACH(j, u->requires_mounts_for) { + char s[strlen(*j) + 1]; + + PATH_FOREACH_PREFIX_MORE(s, *j) { + char *y; + Set *x; + + x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y); + if (!x) + continue; + + set_remove(x, u); + + if (set_isempty(x)) { + hashmap_remove(u->manager->units_requiring_mounts_for, y); + free(y); + set_free(x); + } + } + } + + strv_free(u->requires_mounts_for); + u->requires_mounts_for = NULL; +} + void unit_free(Unit *u) { UnitDependency d; Iterator i; @@ -390,6 +423,8 @@ void unit_free(Unit *u) { if (UNIT_VTABLE(u)->done) UNIT_VTABLE(u)->done(u); + unit_free_requires_mounts_for(u); + SET_FOREACH(t, u->names, i) hashmap_remove_value(u->manager->units, t, u); @@ -408,30 +443,25 @@ void unit_free(Unit *u) { for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) bidi_set_free(u, u->dependencies[d]); - if (u->requires_mounts_for) { - LIST_REMOVE(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u); - strv_free(u->requires_mounts_for); - } - if (u->type != _UNIT_TYPE_INVALID) - LIST_REMOVE(Unit, units_by_type, u->manager->units_by_type[u->type], u); + LIST_REMOVE(units_by_type, u->manager->units_by_type[u->type], u); if (u->in_load_queue) - LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u); + LIST_REMOVE(load_queue, u->manager->load_queue, u); if (u->in_dbus_queue) - LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u); + LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u); if (u->in_cleanup_queue) - LIST_REMOVE(Unit, cleanup_queue, u->manager->cleanup_queue, u); + LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u); if (u->in_gc_queue) { - LIST_REMOVE(Unit, gc_queue, u->manager->gc_queue, u); + LIST_REMOVE(gc_queue, u->manager->gc_queue, u); u->manager->n_in_gc_queue--; } if (u->in_cgroup_queue) - LIST_REMOVE(Unit, cgroup_queue, u->manager->cgroup_queue, u); + LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u); if (u->cgroup_path) { hashmap_remove(u->manager->cgroup_unit, u->cgroup_path); @@ -521,14 +551,13 @@ static void merge_dependencies(Unit *u, Unit *other, UnitDependency d) { SET_FOREACH(back, other->dependencies[d], i) { UnitDependency k; - for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++) - if ((r = set_remove_and_put(back->dependencies[k], other, u)) < 0) { - - if (r == -EEXIST) - set_remove(back->dependencies[k], other); - else - assert(r == -ENOENT); - } + for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++) { + r = set_remove_and_put(back->dependencies[k], other, u); + if (r == -EEXIST) + set_remove(back->dependencies[k], other); + else + assert(r >= 0 || r == -ENOENT); + } } complete_move(&u->dependencies[d], &other->dependencies[d]); @@ -607,7 +636,8 @@ int unit_merge_by_name(Unit *u, const char *name) { if (!u->instance) return -EINVAL; - if (!(s = unit_name_replace_instance(name, u->instance))) + s = unit_name_replace_instance(name, u->instance); + if (!s) return -ENOMEM; name = s; @@ -818,7 +848,7 @@ int unit_load_fragment_and_dropin(Unit *u) { assert(u); - /* Load a .service file */ + /* Load a .{service,socket,...} file */ r = unit_load_fragment(u); if (r < 0) return r; @@ -921,13 +951,51 @@ static int unit_add_default_dependencies(Unit *u) { return 0; } +static int unit_add_mount_links(Unit *u) { + char **i; + int r; + + assert(u); + + STRV_FOREACH(i, u->requires_mounts_for) { + char prefix[strlen(*i) + 1]; + + PATH_FOREACH_PREFIX_MORE(prefix, *i) { + Unit *m; + + r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m); + if (r < 0) + return r; + if (r == 0) + continue; + if (m == u) + continue; + + if (m->load_state != UNIT_LOADED) + continue; + + r = unit_add_dependency(u, UNIT_AFTER, m, true); + if (r < 0) + return r; + + if (m->fragment_path) { + r = unit_add_dependency(u, UNIT_REQUIRES, m, true); + if (r < 0) + return r; + } + } + } + + return 0; +} + int unit_load(Unit *u) { int r; assert(u); if (u->in_load_queue) { - LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u); + LIST_REMOVE(load_queue, u->manager->load_queue, u); u->in_load_queue = false; } @@ -990,7 +1058,7 @@ fail: return r; } -bool unit_condition_test(Unit *u) { +static bool unit_condition_test(Unit *u) { assert(u); dual_timestamp_get(&u->condition_timestamp); @@ -1217,7 +1285,8 @@ int unit_reload(Unit *u) { if (state != UNIT_ACTIVE) return -ENOEXEC; - if ((following = unit_following(u))) { + following = unit_following(u); + if (following) { log_debug_unit(u->id, "Redirecting reload request from %s to %s.", u->id, following->id); return unit_reload(following); @@ -1421,6 +1490,9 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su if (UNIT_IS_INACTIVE_OR_FAILED(ns)) unit_destroy_cgroup(u); + /* Note that this doesn't apply to RemainAfterExit services exiting + * sucessfully, since there's no change of state in that case. Which is + * why it is handled in service_set_state() */ if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) { ExecContext *ec = unit_get_exec_context(u); if (ec && exec_context_may_touch_console(ec)) { @@ -1429,7 +1501,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su if (m->n_on_console == 0) /* unset no_console_output flag, since the console is free */ - m->no_console_output = 0; + m->no_console_output = false; } else m->n_on_console ++; } @@ -2093,28 +2165,6 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) { return r; } -int unit_get_related_unit(Unit *u, const char *type, Unit **_found) { - _cleanup_free_ char *t = NULL; - Unit *found; - - assert(u); - assert(type); - assert(_found); - - t = unit_name_change_suffix(u->id, type); - if (!t) - return -ENOMEM; - - assert(!unit_has_name(u, t)); - - found = manager_get_unit(u->manager, t); - if (!found) - return -ENOENT; - - *_found = found; - return 0; -} - int unit_watch_bus_name(Unit *u, const char *name) { assert(u); assert(name); @@ -2329,7 +2379,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { free(u->cgroup_path); u->cgroup_path = s; - hashmap_put(u->manager->cgroup_unit, s, u); + assert(hashmap_put(u->manager->cgroup_unit, s, u) == 1); continue; } @@ -2645,7 +2695,7 @@ Unit* unit_ref_set(UnitRef *ref, Unit *u) { unit_ref_unset(ref); ref->unit = u; - LIST_PREPEND(UnitRef, refs, u->refs, ref); + LIST_PREPEND(refs, u->refs, ref); return u; } @@ -2655,49 +2705,10 @@ void unit_ref_unset(UnitRef *ref) { if (!ref->unit) return; - LIST_REMOVE(UnitRef, refs, ref->unit->refs, ref); + LIST_REMOVE(refs, ref->unit->refs, ref); ref->unit = NULL; } -int unit_add_one_mount_link(Unit *u, Mount *m) { - char **i; - - assert(u); - assert(m); - - if (u->load_state != UNIT_LOADED || - UNIT(m)->load_state != UNIT_LOADED) - return 0; - - STRV_FOREACH(i, u->requires_mounts_for) { - - if (UNIT(m) == u) - continue; - - if (!path_startswith(*i, m->where)) - continue; - - return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true); - } - - return 0; -} - -int unit_add_mount_links(Unit *u) { - Unit *other; - int r; - - assert(u); - - LIST_FOREACH(units_by_type, other, u->manager->units_by_type[UNIT_MOUNT]) { - r = unit_add_one_mount_link(u, MOUNT(other)); - if (r < 0) - return r; - } - - return 0; -} - int unit_exec_context_defaults(Unit *u, ExecContext *c) { unsigned i; int r; @@ -2884,6 +2895,9 @@ int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) { return 0; r = drop_in_file(u, mode, name, &p, &q); + if (r < 0) + return r; + if (unlink(q) < 0) r = errno == ENOENT ? 0 : -errno; else @@ -3012,6 +3026,86 @@ int unit_kill_context( return wait_for_exit; } +int unit_require_mounts_for(Unit *u, const char *path) { + char prefix[strlen(path) + 1], *p; + int r; + + assert(u); + assert(path); + + /* Registers a unit for requiring a certain path and all its + * prefixes. We keep a simple array of these paths in the + * unit, since its usually short. However, we build a prefix + * table for all possible prefixes so that new appearing mount + * units can easily determine which units to make themselves a + * dependency of. */ + + p = strdup(path); + if (!p) + return -ENOMEM; + + path_kill_slashes(p); + + if (!path_is_absolute(p)) { + free(p); + return -EINVAL; + } + + if (!path_is_safe(p)) { + free(p); + return -EPERM; + } + + if (strv_contains(u->requires_mounts_for, p)) { + free(p); + return 0; + } + + r = strv_push(&u->requires_mounts_for, p); + if (r < 0) { + free(p); + return r; + } + + PATH_FOREACH_PREFIX_MORE(prefix, p) { + Set *x; + + x = hashmap_get(u->manager->units_requiring_mounts_for, prefix); + if (!x) { + char *q; + + if (!u->manager->units_requiring_mounts_for) { + u->manager->units_requiring_mounts_for = hashmap_new(string_hash_func, string_compare_func); + if (!u->manager->units_requiring_mounts_for) + return -ENOMEM; + } + + q = strdup(prefix); + if (!q) + return -ENOMEM; + + x = set_new(NULL, NULL); + if (!x) { + free(q); + return -ENOMEM; + } + + r = hashmap_put(u->manager->units_requiring_mounts_for, q, x); + if (r < 0) { + free(q); + set_free(x); + return r; + } + } + + r = set_put(x, u); + if (r < 0) + return r; + } + + return 0; +} + static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { [UNIT_ACTIVE] = "active", [UNIT_RELOADING] = "reloading",