X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=unit.c;h=b69b6e36201a6cb218bff5c3d51e95c68293cf28;hp=7f147537e30e418da1c2dc50e4fc1248f2d1af51;hb=b05a4429e0d7bc67a892e51df9ef8f752d76eadd;hpb=9e2f7c11fb6ba35ffec2274da3e2d08b10d23965 diff --git a/unit.c b/unit.c index 7f147537e..b69b6e362 100644 --- a/unit.c +++ b/unit.c @@ -37,6 +37,7 @@ #include "log.h" #include "unit-name.h" #include "specifier.h" +#include "dbus-unit.h" const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = &service_vtable, @@ -124,6 +125,11 @@ int unit_add_name(Unit *u, const char *text) { goto fail; } + if (hashmap_size(u->meta.manager->units) >= MANAGER_MAX_NAMES) { + r = -E2BIG; + goto fail; + } + if ((r = set_put(u->meta.names, s)) < 0) { if (r == -EEXIST) r = 0; @@ -203,6 +209,25 @@ int unit_set_description(Unit *u, const char *description) { return 0; } +bool unit_check_gc(Unit *u) { + assert(u); + + if (UNIT_VTABLE(u)->no_gc) + return true; + + if (u->meta.job) + return true; + + if (unit_active_state(u) != UNIT_INACTIVE) + return true; + + if (UNIT_VTABLE(u)->check_gc) + if (UNIT_VTABLE(u)->check_gc(u)) + return true; + + return false; +} + void unit_add_to_load_queue(Unit *u) { assert(u); assert(u->meta.type != _UNIT_TYPE_INVALID); @@ -224,6 +249,24 @@ void unit_add_to_cleanup_queue(Unit *u) { u->meta.in_cleanup_queue = true; } +void unit_add_to_gc_queue(Unit *u) { + assert(u); + + if (u->meta.in_gc_queue || u->meta.in_cleanup_queue) + return; + + if (unit_check_gc(u)) + return; + + LIST_PREPEND(Meta, gc_queue, u->meta.manager->gc_queue, &u->meta); + u->meta.in_gc_queue = true; + + u->meta.manager->n_in_gc_queue ++; + + if (u->meta.manager->gc_queue_timestamp <= 0) + u->meta.manager->gc_queue_timestamp = now(CLOCK_MONOTONIC); +} + void unit_add_to_dbus_queue(Unit *u) { assert(u); assert(u->meta.type != _UNIT_TYPE_INVALID); @@ -249,6 +292,8 @@ static void bidi_set_free(Unit *u, Set *s) { for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) set_remove(other->meta.dependencies[d], u); + + unit_add_to_gc_queue(other); } set_free(s); @@ -279,6 +324,11 @@ void unit_free(Unit *u) { if (u->meta.in_cleanup_queue) LIST_REMOVE(Meta, cleanup_queue, u->meta.manager->cleanup_queue, &u->meta); + if (u->meta.in_gc_queue) { + LIST_REMOVE(Meta, gc_queue, u->meta.manager->gc_queue, &u->meta); + u->meta.manager->n_in_gc_queue--; + } + /* Free data and next 'smaller' objects */ if (u->meta.job) job_free(u->meta.job); @@ -481,11 +531,11 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) { /* If syslog or kernel logging is requested, make sure our own * logging daemon is run first. */ - if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET, NULL)) < 0) + if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0) return r; if (u->meta.manager->running_as != MANAGER_SESSION) - if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET, NULL)) < 0) + if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET, NULL, true)) < 0) return r; return 0; @@ -518,20 +568,22 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { prefix2 = p2 ? p2 : prefix; fprintf(f, - "%s→ Unit %s:\n" + "%s-> Unit %s:\n" "%s\tDescription: %s\n" "%s\tInstance: %s\n" "%s\tUnit Load State: %s\n" "%s\tUnit Active State: %s\n" "%s\tActive Enter Timestamp: %s\n" - "%s\tActive Exit Timestamp: %s\n", + "%s\tActive Exit Timestamp: %s\n" + "%s\tGC Check Good: %s\n", prefix, u->meta.id, prefix, unit_description(u), prefix, strna(u->meta.instance), prefix, unit_load_state_to_string(u->meta.load_state), prefix, unit_active_state_to_string(unit_active_state(u)), prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->meta.active_enter_timestamp)), - prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->meta.active_exit_timestamp))); + prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->meta.active_exit_timestamp)), + prefix, yes_no(unit_check_gc(u))); SET_FOREACH(t, u->meta.names, i) fprintf(f, "%s\tName: %s\n", prefix, t); @@ -614,6 +666,16 @@ int unit_load_fragment_and_dropin_optional(Unit *u) { return 0; } +/* Common implementation for multiple backends */ +int unit_load_nop(Unit *u) { + assert(u); + + if (u->meta.load_state == UNIT_STUB) + u->meta.load_state = UNIT_LOADED; + + return 0; +} + int unit_load(Unit *u) { int r; @@ -642,6 +704,7 @@ int unit_load(Unit *u) { assert((u->meta.load_state != UNIT_MERGED) == !u->meta.merged_into); unit_add_to_dbus_queue(unit_follow_merge(u)); + unit_add_to_gc_queue(u); return 0; @@ -976,6 +1039,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { unit_check_uneeded(u); unit_add_to_dbus_queue(u); + unit_add_to_gc_queue(u); } int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) { @@ -1023,6 +1087,9 @@ int unit_watch_pid(Unit *u, pid_t pid) { assert(u); assert(pid >= 1); + /* Watch a specific PID. We only support one unit watching + * each PID for now. */ + return hashmap_put(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u); } @@ -1030,7 +1097,7 @@ void unit_unwatch_pid(Unit *u, pid_t pid) { assert(u); assert(pid >= 1); - hashmap_remove(u->meta.manager->watch_pids, UINT32_TO_PTR(pid)); + hashmap_remove_value(u->meta.manager->watch_pids, UINT32_TO_PTR(pid), u); } int unit_watch_timer(Unit *u, usec_t delay, Watch *w) { @@ -1105,7 +1172,7 @@ void unit_unwatch_timer(Unit *u, Watch *w) { assert(w->type == WATCH_TIMER && w->data.unit == u); assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0); - assert_se(close_nointr(w->fd) == 0); + close_nointr_nofail(w->fd); w->fd = -1; w->type = WATCH_INVALID; @@ -1138,7 +1205,7 @@ bool unit_job_is_applicable(Unit *u, JobType j) { } } -int unit_add_dependency(Unit *u, UnitDependency d, Unit *other) { +int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) { static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_REQUIRES] = UNIT_REQUIRED_BY, @@ -1151,9 +1218,11 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other) { [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID, [UNIT_CONFLICTS] = UNIT_CONFLICTS, [UNIT_BEFORE] = UNIT_AFTER, - [UNIT_AFTER] = UNIT_BEFORE + [UNIT_AFTER] = UNIT_BEFORE, + [UNIT_REFERENCES] = UNIT_REFERENCED_BY, + [UNIT_REFERENCED_BY] = UNIT_REFERENCES }; - int r; + int r, q = 0, v = 0, w = 0; assert(u); assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX); @@ -1173,22 +1242,47 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other) { return -EINVAL; } - if ((r = set_ensure_allocated(&u->meta.dependencies[d], trivial_hash_func, trivial_compare_func)) < 0) + if ((r = set_ensure_allocated(&u->meta.dependencies[d], trivial_hash_func, trivial_compare_func)) < 0 || + (r = set_ensure_allocated(&other->meta.dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0) return r; - if ((r = set_ensure_allocated(&other->meta.dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0) - return r; + if (add_reference) + if ((r = set_ensure_allocated(&u->meta.dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func)) < 0 || + (r = set_ensure_allocated(&other->meta.dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func)) < 0) + return r; - if ((r = set_put(u->meta.dependencies[d], other)) < 0) - return r; + if ((q = set_put(u->meta.dependencies[d], other)) < 0) + return q; - if ((r = set_put(other->meta.dependencies[inverse_table[d]], u)) < 0) { - set_remove(u->meta.dependencies[d], other); - return r; + if ((v = set_put(other->meta.dependencies[inverse_table[d]], u)) < 0) { + r = v; + goto fail; + } + + if (add_reference) { + if ((w = set_put(u->meta.dependencies[UNIT_REFERENCES], other)) < 0) { + r = w; + goto fail; + } + + if ((r = set_put(other->meta.dependencies[UNIT_REFERENCED_BY], u)) < 0) + goto fail; } unit_add_to_dbus_queue(u); return 0; + +fail: + if (q > 0) + set_remove(u->meta.dependencies[d], other); + + if (v > 0) + set_remove(other->meta.dependencies[inverse_table[d]], u); + + if (w > 0) + set_remove(u->meta.dependencies[UNIT_REFERENCES], other); + + return r; } static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) { @@ -1224,7 +1318,7 @@ static const char *resolve_template(Unit *u, const char *name, const char*path, return s; } -int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path) { +int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) { Unit *other; int r; char *s; @@ -1238,14 +1332,14 @@ int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, con if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0) goto finish; - r = unit_add_dependency(u, d, other); + r = unit_add_dependency(u, d, other, add_reference); finish: free(s); return r; } -int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path) { +int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) { Unit *other; int r; char *s; @@ -1259,7 +1353,7 @@ int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *n if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0) goto finish; - r = unit_add_dependency(other, d, u); + r = unit_add_dependency(other, d, u, add_reference); finish: free(s); @@ -1339,13 +1433,22 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) { static char *default_cgroup_path(Unit *u) { char *p; + int r; assert(u); - if (asprintf(&p, "%s/%s", u->meta.manager->cgroup_hierarchy, u->meta.id) < 0) - return NULL; + if (u->meta.instance) { + char *t; - return p; + if (!(t = unit_name_template(u->meta.id))) + return NULL; + + r = asprintf(&p, "%s/%s/%s", u->meta.manager->cgroup_hierarchy, t, u->meta.instance); + free(t); + } else + r = asprintf(&p, "%s/%s", u->meta.manager->cgroup_hierarchy, u->meta.id); + + return r < 0 ? NULL : p; } int unit_add_cgroup_from_text(Unit *u, const char *name) { @@ -1482,6 +1585,29 @@ 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) { + Unit *found; + char *t; + + assert(u); + assert(type); + assert(_found); + + if (!(t = unit_name_change_suffix(u->meta.id, type))) + return -ENOMEM; + + assert(!unit_has_name(u, t)); + + found = manager_get_unit(u->meta.manager, t); + free(t); + + if (!found) + return -ENOENT; + + *_found = found; + return 0; +} + static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) { Unit *u = userdata; assert(u); @@ -1597,6 +1723,114 @@ fail: return NULL; } +int unit_watch_bus_name(Unit *u, const char *name) { + assert(u); + assert(name); + + /* Watch a specific name on the bus. We only support one unit + * watching each name for now. */ + + return hashmap_put(u->meta.manager->watch_bus, name, u); +} + +void unit_unwatch_bus_name(Unit *u, const char *name) { + assert(u); + assert(name); + + hashmap_remove_value(u->meta.manager->watch_bus, name, u); +} + +bool unit_can_serialize(Unit *u) { + assert(u); + + return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item; +} + +int unit_serialize(Unit *u, FILE *f, FDSet *fds) { + int r; + + assert(u); + assert(f); + assert(fds); + + if (!unit_can_serialize(u)) + return 0; + + if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0) + return r; + + /* End marker */ + fputc('\n', f); + return 0; +} + +void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) { + va_list ap; + + assert(u); + assert(f); + assert(key); + assert(format); + + fputs(key, f); + fputc('=', f); + + va_start(ap, format); + vfprintf(f, format, ap); + va_end(ap); + + fputc('\n', f); +} + +void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) { + assert(u); + assert(f); + assert(key); + assert(value); + + fprintf(f, "%s=%s\n", key, value); +} + +int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + int r; + + assert(u); + assert(f); + assert(fds); + + if (!unit_can_serialize(u)) + return 0; + + for (;;) { + char line[1024], *l, *v; + size_t k; + + if (!fgets(line, sizeof(line), f)) { + if (feof(f)) + return 0; + return -errno; + } + + l = strstrip(line); + + /* End marker */ + if (l[0] == 0) + return 0; + + k = strcspn(l, "="); + + if (l[k] == '=') { + l[k] = 0; + v = l+k+1; + } else + v = l+k; + + if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0) + return r; + } +} + + static const char* const unit_type_table[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = "service", [UNIT_TIMER] = "timer", @@ -1640,6 +1874,8 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_CONFLICTS] = "Conflicts", [UNIT_BEFORE] = "Before", [UNIT_AFTER] = "After", + [UNIT_REFERENCES] = "References", + [UNIT_REFERENCED_BY] = "ReferencedBy" }; DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);