X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=unit.c;h=036c01648c6e017ee4d832e67d74a20e1c359fe9;hb=24e61ac49db6add10ffa448f42202245fb883b96;hp=bdbcb45c506fcce282696e3926ade9e6ceee2e9a;hpb=a7334b0952ab66c17ee787e36e6d2c5ceb387de6;p=elogind.git diff --git a/unit.c b/unit.c index bdbcb45c5..036c01648 100644 --- a/unit.c +++ b/unit.c @@ -174,6 +174,7 @@ int unit_add_name(Unit *u, const char *text) { if (!u->meta.id) u->meta.id = s; + unit_add_to_dbus_queue(u); return 0; } @@ -189,6 +190,8 @@ int unit_choose_id(Unit *u, const char *name) { return -ENOENT; u->meta.id = s; + + unit_add_to_dbus_queue(u); return 0; } @@ -202,6 +205,8 @@ int unit_set_description(Unit *u, const char *description) { free(u->meta.description); u->meta.description = s; + + unit_add_to_dbus_queue(u); return 0; } @@ -215,6 +220,16 @@ void unit_add_to_load_queue(Unit *u) { u->meta.in_load_queue = true; } +void unit_add_to_dbus_queue(Unit *u) { + assert(u); + + if (u->meta.load_state == UNIT_STUB || u->meta.in_dbus_queue || set_isempty(u->meta.manager->subscribed)) + return; + + LIST_PREPEND(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta); + u->meta.in_dbus_queue = true; +} + static void bidi_set_free(Unit *u, Set *s) { Iterator i; Unit *other; @@ -241,8 +256,12 @@ void unit_free(Unit *u) { assert(u); + bus_unit_send_removed_signal(u); + /* Detach from next 'bigger' objects */ + cgroup_bonding_free_list(u->meta.cgroup_bondings); + SET_FOREACH(t, u->meta.names, i) hashmap_remove_value(u->meta.manager->units, t, u); @@ -252,6 +271,9 @@ void unit_free(Unit *u) { if (u->meta.in_load_queue) LIST_REMOVE(Meta, load_queue, u->meta.manager->load_queue, &u->meta); + if (u->meta.in_dbus_queue) + LIST_REMOVE(Meta, dbus_queue, u->meta.manager->dbus_unit_queue, &u->meta); + if (u->meta.load_state == UNIT_LOADED) if (UNIT_VTABLE(u)->done) UNIT_VTABLE(u)->done(u); @@ -264,7 +286,7 @@ void unit_free(Unit *u) { bidi_set_free(u, u->meta.dependencies[d]); free(u->meta.description); - free(u->meta.load_path); + free(u->meta.fragment_path); while ((t = set_steal_first(u->meta.names))) free(t); @@ -325,6 +347,8 @@ int unit_merge(Unit *u, Unit *other) { if ((r = ensure_merge(&u->meta.dependencies[d], other->meta.dependencies[d])) < 0) return r; + unit_add_to_dbus_queue(u); + return 0; } @@ -347,19 +371,19 @@ const char *unit_description(Unit *u) { } void unit_dump(Unit *u, FILE *f, const char *prefix) { - char *t; UnitDependency d; Iterator i; - char *prefix2; + char *p2; + const char *prefix2; + CGroupBonding *b; assert(u); if (!prefix) prefix = ""; - prefix2 = strappend(prefix, "\t"); - if (!prefix2) - prefix2 = ""; + p2 = strappend(prefix, "\t"); + prefix2 = p2 ? p2 : prefix; fprintf(f, "%s→ Unit %s:\n" @@ -375,8 +399,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(u->meta.recursive_stop), prefix, yes_no(u->meta.stop_when_unneeded)); - if (u->meta.load_path) - fprintf(f, "%s\tLoad Path: %s\n", prefix, u->meta.load_path); + if (u->meta.fragment_path) + fprintf(f, "%s\tFragment Path: %s\n", prefix, u->meta.fragment_path); SET_FOREACH(t, u->meta.names, i) fprintf(f, "%s\tName: %s\n", prefix, t); @@ -391,13 +415,17 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), unit_id(other)); } + LIST_FOREACH(by_unit, b, u->meta.cgroup_bondings) + fprintf(f, "%s\tControlGroup: %s:%s\n", + prefix, b->controller, b->path); + if (UNIT_VTABLE(u)->dump) UNIT_VTABLE(u)->dump(u, f, prefix2); if (u->meta.job) job_dump(u->meta.job, f, prefix2); - free(prefix2); + free(p2); } /* Common implementation for multiple backends */ @@ -437,10 +465,12 @@ int unit_load(Unit *u) { goto fail; u->meta.load_state = UNIT_LOADED; + unit_add_to_dbus_queue(u); return 0; fail: u->meta.load_state = UNIT_FAILED; + unit_add_to_dbus_queue(u); return r; } @@ -454,19 +484,25 @@ int unit_start(Unit *u) { assert(u); - if (!UNIT_VTABLE(u)->start) - return -EBADR; - + /* If this is already (being) started, then this will + * succeed. Note that this will even succeed if this unit is + * not startable by the user. This is relied on to detect when + * we need to wait for units and when waiting is finished. */ state = unit_active_state(u); if (UNIT_IS_ACTIVE_OR_RELOADING(state)) return -EALREADY; + /* If it is stopped, but we cannot start it, then fail */ + if (!UNIT_VTABLE(u)->start) + return -EBADR; + /* We don't suppress calls to ->start() here when we are * already starting, to allow this request to be used as a * "hurry up" call, for example when the unit is in some "auto * restart" state where it waits for a holdoff timer to elapse * before it will start again. */ + unit_add_to_dbus_queue(u); return UNIT_VTABLE(u)->start(u); } @@ -486,16 +522,17 @@ int unit_stop(Unit *u) { assert(u); - if (!UNIT_VTABLE(u)->stop) - return -EBADR; - state = unit_active_state(u); if (state == UNIT_INACTIVE) return -EALREADY; + if (!UNIT_VTABLE(u)->stop) + return -EBADR; + if (state == UNIT_DEACTIVATING) return 0; + unit_add_to_dbus_queue(u); return UNIT_VTABLE(u)->stop(u); } @@ -519,6 +556,7 @@ int unit_reload(Unit *u) { if (unit_active_state(u) != UNIT_ACTIVE) return -ENOEXEC; + unit_add_to_dbus_queue(u); return UNIT_VTABLE(u)->reload(u); } @@ -649,7 +687,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { /* So we reached a different state for this * job. Let's see if we can run it now if it * failed previously due to EAGAIN. */ - job_schedule_run(u->meta.job); + job_add_to_run_queue(u->meta.job); else { assert(u->meta.job->state == JOB_RUNNING); @@ -718,6 +756,8 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) { /* Maybe we finished startup and are now ready for being * stopped because unneeded? */ unit_check_uneeded(u); + + unit_add_to_dbus_queue(u); } int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) { @@ -921,6 +961,7 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other) { return r; } + unit_add_to_dbus_queue(u); return 0; } @@ -937,14 +978,17 @@ int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name) { return 0; } -const char *unit_path(void) { - char *e; +int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name) { + Unit *other; + int r; + + if ((r = manager_load_unit(u->meta.manager, name, &other)) < 0) + return r; - if ((e = getenv("UNIT_PATH"))) - if (path_is_absolute(e)) - return e; + if ((r = unit_add_dependency(other, d, u)) < 0) + return r; - return UNIT_PATH; + return 0; } int set_unit_path(const char *p) { @@ -967,7 +1011,7 @@ int set_unit_path(const char *p) { return -ENOMEM; } - if (setenv("UNIT_PATH", c, 0) < 0) { + if (setenv("SYSTEMD_UNIT_PATH", c, 0) < 0) { r = -errno; free(c); return r; @@ -976,10 +1020,10 @@ int set_unit_path(const char *p) { return 0; } -char *unit_name_escape_path(const char *prefix, const char *path, const char *suffix) { +char *unit_name_escape_path(const char *path, const char *suffix) { char *r, *t; const char *f; - size_t a, b, c; + size_t a, b; assert(path); @@ -992,22 +1036,16 @@ char *unit_name_escape_path(const char *prefix, const char *path, const char *su * escaping is hence reversible. */ - if (!prefix) - prefix = ""; - if (!suffix) suffix = ""; - a = strlen(prefix); - b = strlen(path); - c = strlen(suffix); + a = strlen(path); + b = strlen(suffix); - if (!(r = new(char, a+b*4+c+1))) + if (!(r = new(char, a*4+b+1))) return NULL; - memcpy(r, prefix, a); - - for (f = path, t = r+a; *f; f++) { + for (f = path, t = r; *f; f++) { if (*f == '/') *(t++) = '.'; else if (*f == '.' || *f == '\\' || !strchr(VALID_CHARS, *f)) { @@ -1019,7 +1057,7 @@ char *unit_name_escape_path(const char *prefix, const char *path, const char *su *(t++) = *f; } - memcpy(t, suffix, c+1); + memcpy(t, suffix, b+1); return r; } @@ -1041,6 +1079,138 @@ char *unit_dbus_path(Unit *u) { return p; } +int unit_add_cgroup(Unit *u, CGroupBonding *b) { + CGroupBonding *l; + int r; + + assert(u); + assert(b); + assert(b->path); + + /* Ensure this hasn't been added yet */ + assert(!b->unit); + + l = hashmap_get(u->meta.manager->cgroup_bondings, b->path); + LIST_PREPEND(CGroupBonding, by_path, l, b); + + if ((r = hashmap_replace(u->meta.manager->cgroup_bondings, b->path, l)) < 0) { + LIST_REMOVE(CGroupBonding, by_path, l, b); + return r; + } + + LIST_PREPEND(CGroupBonding, by_unit, u->meta.cgroup_bondings, b); + b->unit = u; + + return 0; +} + +int unit_add_cgroup_from_text(Unit *u, const char *name) { + size_t n; + const char *p; + char *controller; + CGroupBonding *b; + int r; + + assert(u); + assert(name); + + /* Detect controller name */ + n = strcspn(name, ":/"); + + /* Only controller name, no path? No path? */ + if (name[n] == 0) + return -EINVAL; + + if (n > 0) { + if (name[n] != ':') + return -EINVAL; + + p = name+n+1; + } else + p = name; + + /* Insist in absolute paths */ + if (p[0] != '/') + return -EINVAL; + + if (!(controller = strndup(name, n))) + return -ENOMEM; + + if (cgroup_bonding_find_list(u->meta.cgroup_bondings, controller)) { + free(controller); + return -EEXIST; + } + + if (!(b = new0(CGroupBonding, 1))) { + free(controller); + return -ENOMEM; + } + + b->controller = controller; + + if (!(b->path = strdup(p))) { + r = -ENOMEM; + goto fail; + } + + b->only_us = false; + b->clean_up = false; + + if ((r = unit_add_cgroup(u, b)) < 0) + goto fail; + + return 0; + +fail: + free(b->path); + free(b->controller); + free(b); + + return r; +} + +int unit_add_default_cgroup(Unit *u) { + CGroupBonding *b; + int r = -ENOMEM; + + assert(u); + + /* Adds in the default cgroup data, if it wasn't specified yet */ + + if (unit_get_default_cgroup(u)) + return 0; + + if (!(b = new0(CGroupBonding, 1))) + return -ENOMEM; + + if (!(b->controller = strdup(u->meta.manager->cgroup_controller))) + goto fail; + + if (asprintf(&b->path, "%s/%s", u->meta.manager->cgroup_hierarchy, unit_id(u)) < 0) + goto fail; + + b->clean_up = true; + b->only_us = true; + + if ((r = unit_add_cgroup(u, b)) < 0) + goto fail; + + return 0; + +fail: + free(b->path); + free(b->controller); + free(b); + + return r; +} + +CGroupBonding* unit_get_default_cgroup(Unit *u) { + assert(u); + + return cgroup_bonding_find_list(u->meta.cgroup_bondings, u->meta.manager->cgroup_controller); +} + static const char* const unit_type_table[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = "service", [UNIT_TIMER] = "timer",