X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Funit.c;h=1194c524bfdc77f8fa2a840165fafdfe55fc0c2f;hb=3f141375cb4ff4f850b267258e776c90df594990;hp=be0d654bbc001bcfb94c9750c0700bece380236d;hpb=faa368e3376cb5e3e3c27550fdde652f1d3c9584;p=elogind.git diff --git a/src/core/unit.c b/src/core/unit.c index be0d654bb..1194c524b 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -40,7 +40,6 @@ #include "load-dropin.h" #include "log.h" #include "unit-name.h" -#include "specifier.h" #include "dbus-unit.h" #include "special.h" #include "cgroup-util.h" @@ -614,7 +613,7 @@ 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 (u->manager->running_as == MANAGER_SYSTEM) + if (u->manager->running_as == SYSTEMD_SYSTEM) if ((r = unit_add_two_dependencies_by_name(u, UNIT_REQUIRES, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true)) < 0) return r; @@ -1024,7 +1023,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { SD_MESSAGE_UNIT_RELOADING; log_struct(LOG_INFO, - "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(mid), + MESSAGE_ID(mid), "UNIT=%s", u->id, "MESSAGE=%s", buf, NULL); @@ -1439,7 +1438,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su check_unneeded_dependencies(u); if (ns != os && ns == UNIT_FAILED) { - log_notice("Unit %s entered failed state.", u->id); + log_struct(LOG_NOTICE, + "MESSAGE=Unit %s entered failed state", u->id, + "UNIT=%s", u->id, + NULL); unit_trigger_on_failure(u); } } @@ -1558,7 +1560,7 @@ void unit_unwatch_pid(Unit *u, pid_t pid) { hashmap_remove_value(u->manager->watch_pids, LONG_TO_PTR(pid), u); } -int unit_watch_timer(Unit *u, usec_t delay, Watch *w) { +int unit_watch_timer(Unit *u, clockid_t clock_id, bool relative, usec_t usec, Watch *w) { struct itimerspec its; int flags, fd; bool ours; @@ -1578,14 +1580,15 @@ int unit_watch_timer(Unit *u, usec_t delay, Watch *w) { } else if (w->type == WATCH_INVALID) { ours = true; - if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) + fd = timerfd_create(clock_id, TFD_NONBLOCK|TFD_CLOEXEC); + if (fd < 0) return -errno; } else assert_not_reached("Invalid watch type"); zero(its); - if (delay <= 0) { + if (usec <= 0) { /* Set absolute time in the past, but not 0, since we * don't want to disarm the timer */ its.it_value.tv_sec = 0; @@ -1593,8 +1596,8 @@ int unit_watch_timer(Unit *u, usec_t delay, Watch *w) { flags = TFD_TIMER_ABSTIME; } else { - timespec_store(&its.it_value, delay); - flags = 0; + timespec_store(&its.it_value, usec); + flags = relative ? 0 : TFD_TIMER_ABSTIME; } /* This will also flush the elapse counter */ @@ -1778,6 +1781,7 @@ static const char *resolve_template(Unit *u, const char *name, const char*path, assert(u); assert(name || path); + assert(p); if (!name) name = path_get_file_name(path); @@ -1792,7 +1796,8 @@ static const char *resolve_template(Unit *u, const char *name, const char*path, else { char *i; - if (!(i = unit_name_to_prefix(u->id))) + i = unit_name_to_prefix(u->id); + if (!i) return NULL; s = unit_name_replace_instance(name, i); @@ -1809,22 +1814,20 @@ static const char *resolve_template(Unit *u, 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; + _cleanup_free_ char *s = NULL; assert(u); assert(name || path); - if (!(name = resolve_template(u, name, path, &s))) + name = resolve_template(u, name, path, &s); + if (!name) return -ENOMEM; - if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0) - goto finish; - - r = unit_add_dependency(u, d, other, add_reference); + r = manager_load_unit(u->manager, name, path, NULL, &other); + if (r < 0) + return r; -finish: - free(s); - return r; + return unit_add_dependency(u, d, other, add_reference); } int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) { @@ -1938,8 +1941,9 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) { assert(b->path); if (!b->controller) { - if (!(b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER))) - return -ENOMEM; + b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER); + if (!b->controller) + return log_oom(); b->ours = true; } @@ -1953,7 +1957,8 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) { l = hashmap_get(u->manager->cgroup_bondings, b->path); LIST_PREPEND(CGroupBonding, by_path, l, b); - if ((r = hashmap_replace(u->manager->cgroup_bondings, b->path, l)) < 0) { + r = hashmap_replace(u->manager->cgroup_bondings, b->path, l); + if (r < 0) { LIST_REMOVE(CGroupBonding, by_path, l, b); return r; } @@ -1965,27 +1970,22 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) { return 0; } -static char *default_cgroup_path(Unit *u) { - char *p; - +char *unit_default_cgroup_path(Unit *u) { assert(u); if (u->instance) { - char *t; + _cleanup_free_ char *t = NULL; t = unit_name_template(u->id); if (!t) return NULL; - p = strjoin(u->manager->cgroup_hierarchy, "/", t, "/", u->instance, NULL); - free(t); + return strjoin(u->manager->cgroup_hierarchy, "/", t, "/", u->instance, NULL); } else - p = strjoin(u->manager->cgroup_hierarchy, "/", u->id, NULL); - - return p; + return strjoin(u->manager->cgroup_hierarchy, "/", u->id, NULL); } -int unit_add_cgroup_from_text(Unit *u, const char *name) { +int unit_add_cgroup_from_text(Unit *u, const char *name, bool overwrite, CGroupBonding **ret) { char *controller = NULL, *path = NULL; CGroupBonding *b = NULL; bool ours = false; @@ -1994,11 +1994,12 @@ int unit_add_cgroup_from_text(Unit *u, const char *name) { assert(u); assert(name); - if ((r = cg_split_spec(name, &controller, &path)) < 0) + r = cg_split_spec(name, &controller, &path); + if (r < 0) return r; if (!path) { - path = default_cgroup_path(u); + path = unit_default_cgroup_path(u); ours = true; } @@ -2010,16 +2011,42 @@ int unit_add_cgroup_from_text(Unit *u, const char *name) { if (!path || !controller) { free(path); free(controller); - - return -ENOMEM; + return log_oom(); } - if (cgroup_bonding_find_list(u->cgroup_bondings, controller)) { + b = cgroup_bonding_find_list(u->cgroup_bondings, controller); + if (b) { + if (streq(path, b->path)) { + free(path); + free(controller); + + if (ret) + *ret = b; + return 0; + } + + if (overwrite && !b->essential) { + free(controller); + + free(b->path); + b->path = path; + + b->ours = ours; + b->realized = false; + + if (ret) + *ret = b; + + return 1; + } + r = -EEXIST; + b = NULL; goto fail; } - if (!(b = new0(CGroupBonding, 1))) { + b = new0(CGroupBonding, 1); + if (!b) { r = -ENOMEM; goto fail; } @@ -2029,10 +2056,14 @@ int unit_add_cgroup_from_text(Unit *u, const char *name) { b->ours = ours; b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER); - if ((r = unit_add_cgroup(u, b)) < 0) + r = unit_add_cgroup(u, b); + if (r < 0) goto fail; - return 0; + if (ret) + *ret = b; + + return 1; fail: free(path); @@ -2054,19 +2085,23 @@ static int unit_add_one_default_cgroup(Unit *u, const char *controller) { if (cgroup_bonding_find_list(u->cgroup_bondings, controller)) return 0; - if (!(b = new0(CGroupBonding, 1))) + b = new0(CGroupBonding, 1); + if (!b) return -ENOMEM; - if (!(b->controller = strdup(controller))) + b->controller = strdup(controller); + if (!b) goto fail; - if (!(b->path = default_cgroup_path(u))) + b->path = unit_default_cgroup_path(u); + if (!b->path) goto fail; b->ours = true; b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER); - if ((r = unit_add_cgroup(u, b)) < 0) + r = unit_add_cgroup(u, b); + if (r < 0) goto fail; return 0; @@ -2092,7 +2127,8 @@ int unit_add_default_cgroups(Unit *u) { if (!u->manager->cgroup_hierarchy) return 0; - if ((r = unit_add_one_default_cgroup(u, NULL)) < 0) + r = unit_add_one_default_cgroup(u, NULL); + if (r < 0) return r; STRV_FOREACH(c, u->manager->default_controllers) @@ -2107,12 +2143,18 @@ int unit_add_default_cgroups(Unit *u) { CGroupBonding* unit_get_default_cgroup(Unit *u) { assert(u); - return cgroup_bonding_find_list(u->cgroup_bondings, SYSTEMD_CGROUP_CONTROLLER); + return cgroup_bonding_find_list(u->cgroup_bondings, NULL); } -int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, const char *value, CGroupAttributeMapCallback map_callback) { - int r; - char *c = NULL; +int unit_add_cgroup_attribute( + Unit *u, + const char *controller, + const char *name, + const char *value, + CGroupAttributeMapCallback map_callback, + CGroupAttribute **ret) { + + _cleanup_free_ char *c = NULL; CGroupAttribute *a; assert(u); @@ -2133,16 +2175,36 @@ int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, controller = c; } - if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) { - r = -EINVAL; - goto finish; + if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) + return -EINVAL; + + a = cgroup_attribute_find_list(u->cgroup_attributes, controller, name); + if (a) { + char *v; + + if (streq(value, a->value)) { + if (ret) + *ret = a; + + return 0; + } + + v = strdup(value); + if (!v) + return -ENOMEM; + + free(a->value); + a->value = v; + + if (ret) + *ret = a; + + return 1; } a = new0(CGroupAttribute, 1); - if (!a) { - r = -ENOMEM; - goto finish; - } + if (!a) + return -ENOMEM; if (c) { a->controller = c; @@ -2163,14 +2225,14 @@ int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, } a->map_callback = map_callback; + a->unit = u; LIST_PREPEND(CGroupAttribute, by_unit, u->cgroup_attributes, a); - r = 0; + if (ret) + *ret = a; -finish: - free(c); - return r; + return 1; } int unit_load_related_unit(Unit *u, const char *type, Unit **_found) { @@ -2217,253 +2279,6 @@ int unit_get_related_unit(Unit *u, const char *type, Unit **_found) { return 0; } -static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - return unit_name_to_prefix_and_instance(u->id); -} - -static char *specifier_prefix(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - return unit_name_to_prefix(u->id); -} - -static char *specifier_prefix_unescaped(char specifier, void *data, void *userdata) { - Unit *u = userdata; - char *p, *r; - - assert(u); - - if (!(p = unit_name_to_prefix(u->id))) - return NULL; - - r = unit_name_unescape(p); - free(p); - - return r; -} - -static char *specifier_instance_unescaped(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - if (u->instance) - return unit_name_unescape(u->instance); - - return strdup(""); -} - -static char *specifier_filename(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - if (u->instance) - return unit_name_path_unescape(u->instance); - - return unit_name_to_path(u->instance); -} - -static char *specifier_cgroup(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - return default_cgroup_path(u); -} - -static char *specifier_cgroup_root(char specifier, void *data, void *userdata) { - Unit *u = userdata; - char *p; - assert(u); - - if (specifier == 'r') - return strdup(u->manager->cgroup_hierarchy); - - if (path_get_parent(u->manager->cgroup_hierarchy, &p) < 0) - return strdup(""); - - if (streq(p, "/")) { - free(p); - return strdup(""); - } - - return p; -} - -static char *specifier_runtime(char specifier, void *data, void *userdata) { - Unit *u = userdata; - assert(u); - - if (u->manager->running_as == MANAGER_USER) { - const char *e; - - e = getenv("XDG_RUNTIME_DIR"); - if (e) - return strdup(e); - } - - return strdup("/run"); -} - -static char *specifier_user_name(char specifier, void *data, void *userdata) { - Service *s = userdata; - int r; - const char *username; - - /* get USER env from our own env if set */ - if (!s->exec_context.user) - return getusername_malloc(); - - /* fish username from passwd */ - username = s->exec_context.user; - r = get_user_creds(&username, NULL, NULL, NULL, NULL); - if (r < 0) - return NULL; - - return strdup(username); -} - -static char *specifier_user_home(char specifier, void *data, void *userdata) { - Service *s = userdata; - int r; - const char *username, *home; - - /* return HOME if set, otherwise from passwd */ - if (!s->exec_context.user) { - char *h; - - r = get_home_dir(&h); - if (r < 0) - return NULL; - - return h; - } - - username = s->exec_context.user; - r = get_user_creds(&username, NULL, NULL, &home, NULL); - if (r < 0) - return NULL; - - return strdup(home); -} - -static char *specifier_user_shell(char specifier, void *data, void *userdata) { - Service *s = userdata; - int r; - const char *username, *shell; - - /* return HOME if set, otherwise from passwd */ - if (!s->exec_context.user) { - char *sh; - - r = get_shell(&sh); - if (r < 0) - return strdup("/bin/sh"); - - return sh; - } - - username = s->exec_context.user; - r = get_user_creds(&username, NULL, NULL, NULL, &shell); - if (r < 0) - return strdup("/bin/sh"); - - return strdup(shell); -} - -char *unit_name_printf(Unit *u, const char* format) { - - /* - * This will use the passed string as format string and - * replace the following specifiers: - * - * %n: the full id of the unit (foo@bar.waldo) - * %N: the id of the unit without the suffix (foo@bar) - * %p: the prefix (foo) - * %i: the instance (bar) - */ - - const Specifier table[] = { - { 'n', specifier_string, u->id }, - { 'N', specifier_prefix_and_instance, NULL }, - { 'p', specifier_prefix, NULL }, - { 'i', specifier_string, u->instance }, - { 0, NULL, NULL } - }; - - assert(u); - assert(format); - - return specifier_printf(format, table, u); -} - -char *unit_full_printf(Unit *u, const char *format) { - - /* This is similar to unit_name_printf() but also supports - * unescaping. Also, adds a couple of additional codes: - * - * %c cgroup path of unit - * %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711") - * %R parent of root cgroup path (e.g. "/usr/lennart/shared") - * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR) - * %u the username of the configured User or running user - * %h the homedir of the configured User or running user - */ - - const Specifier table[] = { - { 'n', specifier_string, u->id }, - { 'N', specifier_prefix_and_instance, NULL }, - { 'p', specifier_prefix, NULL }, - { 'P', specifier_prefix_unescaped, NULL }, - { 'i', specifier_string, u->instance }, - { 'I', specifier_instance_unescaped, NULL }, - { 'f', specifier_filename, NULL }, - { 'c', specifier_cgroup, NULL }, - { 'r', specifier_cgroup_root, NULL }, - { 'R', specifier_cgroup_root, NULL }, - { 't', specifier_runtime, NULL }, - { 'u', specifier_user_name, NULL }, - { 'h', specifier_user_home, NULL }, - { 's', specifier_user_shell, NULL }, - { 0, NULL, NULL } - }; - - assert(u); - assert(format); - - return specifier_printf(format, table, u); -} - -char **unit_full_printf_strv(Unit *u, char **l) { - size_t n; - char **r, **i, **j; - - /* Applies unit_full_printf to every entry in l */ - - assert(u); - - n = strv_length(l); - if (!(r = new(char*, n+1))) - return NULL; - - for (i = l, j = r; *i; i++, j++) - if (!(*j = unit_full_printf(u, *i))) - goto fail; - - *j = NULL; - return r; - -fail: - for (j--; j >= r; j--) - free(*j); - - free(r); - - return NULL; -} - int unit_watch_bus_name(Unit *u, const char *name) { assert(u); assert(name); @@ -2837,7 +2652,7 @@ UnitFileState unit_get_unit_file_state(Unit *u) { if (u->unit_file_state < 0 && u->fragment_path) u->unit_file_state = unit_file_get_state( - u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, + u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, path_get_file_name(u->fragment_path)); return u->unit_file_state; @@ -2920,7 +2735,7 @@ int unit_exec_context_defaults(Unit *u, ExecContext *c) { return -ENOMEM; } - if (u->manager->running_as == MANAGER_USER && + if (u->manager->running_as == SYSTEMD_USER && !c->working_directory) { r = get_home_dir(&c->working_directory); @@ -2931,6 +2746,17 @@ int unit_exec_context_defaults(Unit *u, ExecContext *c) { return 0; } +ExecContext *unit_get_exec_context(Unit *u) { + size_t offset; + assert(u); + + offset = UNIT_VTABLE(u)->exec_context_offset; + if (offset <= 0) + return NULL; + + return (ExecContext*) ((uint8_t*) u + offset); +} + static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { [UNIT_ACTIVE] = "active", [UNIT_RELOADING] = "reloading",