X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Funit.c;h=3a88996eb7394bfe69c27145bd165f8a24cb07f9;hp=45453dce64a6464899721ad5f7c133fcac4e418f;hb=9d246da3c630559924a0262769c8493fa22c7acc;hpb=f274ece0f76b5709408821e317e87aef76123db6 diff --git a/src/core/unit.c b/src/core/unit.c index 45453dce6..3a88996eb 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -45,6 +45,9 @@ #include "cgroup-util.h" #include "missing.h" #include "cgroup-attr.h" +#include "mkdir.h" +#include "label.h" +#include "fileio-label.h" const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = &service_vtable, @@ -613,9 +616,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 (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) + if (u->manager->running_as == SYSTEMD_SYSTEM) { + r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true); + if (r < 0) return r; + } return 0; } @@ -1022,9 +1027,9 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { t == JOB_STOP ? SD_MESSAGE_UNIT_STOPPING : SD_MESSAGE_UNIT_RELOADING; - log_struct(LOG_INFO, + log_struct_unit(LOG_INFO, + u->id, MESSAGE_ID(mid), - "UNIT=%s", u->id, "MESSAGE=%s", buf, NULL); } @@ -1438,9 +1443,9 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su check_unneeded_dependencies(u); if (ns != os && ns == UNIT_FAILED) { - log_struct(LOG_NOTICE, + log_struct_unit(LOG_NOTICE, + u->id, "MESSAGE=Unit %s entered failed state", u->id, - "UNIT=%s", u->id, NULL); unit_trigger_on_failure(u); } @@ -1781,6 +1786,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); @@ -1795,7 +1801,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); @@ -1812,22 +1819,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) { @@ -1941,8 +1946,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; } @@ -1956,7 +1962,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; } @@ -1969,26 +1976,21 @@ int unit_add_cgroup(Unit *u, CGroupBonding *b) { } char *unit_default_cgroup_path(Unit *u) { - char *p; - 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; @@ -1997,7 +1999,8 @@ 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) { @@ -2013,16 +2016,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; } @@ -2032,10 +2061,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); @@ -2057,10 +2090,12 @@ 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->controller) goto fail; b->path = unit_default_cgroup_path(u); @@ -2070,7 +2105,8 @@ static int unit_add_one_default_cgroup(Unit *u, const char *controller) { 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; @@ -2096,7 +2132,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) @@ -2111,42 +2148,69 @@ 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; + int r; assert(u); assert(name); assert(value); if (!controller) { - const char *dot; + r = cg_controller_from_attr(name, &c); + if (r < 0) + return -EINVAL; - dot = strchr(name, '.'); - if (!dot) + controller = c; + } else { + if (!filename_is_safe(name)) + return -EINVAL; + + if (!filename_is_safe(controller)) return -EINVAL; + } + + if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER)) + return -EINVAL; - c = strndup(name, dot - name); - if (!c) + 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; - controller = c; - } + free(a->value); + a->value = v; - if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) { - r = -EINVAL; - goto finish; + 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; @@ -2167,14 +2231,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) { @@ -2699,6 +2763,130 @@ ExecContext *unit_get_exec_context(Unit *u) { return (ExecContext*) ((uint8_t*) u + offset); } +int unit_write_drop_in(Unit *u, bool runtime, const char *name, const char *data) { + _cleanup_free_ char *p = NULL, *q = NULL; + assert(u); + + if (u->manager->running_as != SYSTEMD_SYSTEM) + return -ENOTSUP; + + if (!filename_is_safe(name)) + return -EINVAL; + + p = strjoin(runtime ? "/run/systemd/system/" : "/etc/systemd/system/", u->id, ".d", NULL); + if (!p) + return -ENOMEM; + + q = strjoin(p, "/50-", name, ".conf", NULL); + if (!q) + return -ENOMEM; + + mkdir_p(p, 0755); + return write_one_line_file_atomic_label(q, data); +} + +int unit_remove_drop_in(Unit *u, bool runtime, const char *name) { + _cleanup_free_ char *p = NULL, *q = NULL; + + assert(u); + + if (u->manager->running_as != SYSTEMD_SYSTEM) + return -ENOTSUP; + + if (!filename_is_safe(name)) + return -EINVAL; + + p = strjoin(runtime ? "/run/systemd/system/" : "/etc/systemd/system/", u->id, ".d", NULL); + if (!p) + return -ENOMEM; + + q = strjoin(p, "/50-", name, ".conf", NULL); + if (!q) + return -ENOMEM; + + if (unlink(q) < 0) + return -errno; + + rmdir(p); + return 0; +} + +int unit_kill_context( + Unit *u, + KillContext *c, + bool sigkill, + pid_t main_pid, + pid_t control_pid, + bool main_pid_alien) { + + int sig, wait_for_exit = 0, r; + + assert(u); + assert(c); + + if (c->kill_mode == KILL_NONE) + return 0; + + sig = sigkill ? SIGKILL : c->kill_signal; + + if (main_pid > 0) { + r = kill_and_sigcont(main_pid, sig); + + if (r < 0 && r != -ESRCH) { + _cleanup_free_ char *comm = NULL; + get_process_comm(main_pid, &comm); + + log_warning_unit(u->id, "Failed to kill main process %li (%s): %s", + (long) main_pid, strna(comm), strerror(-r)); + } else + wait_for_exit = !main_pid_alien; + } + + if (control_pid > 0) { + r = kill_and_sigcont(control_pid, sig); + + if (r < 0 && r != -ESRCH) { + _cleanup_free_ char *comm = NULL; + get_process_comm(control_pid, &comm); + + log_warning_unit(u->id, + "Failed to kill control process %li (%s): %s", + (long) control_pid, strna(comm), strerror(-r)); + } else + wait_for_exit = true; + } + + if (c->kill_mode == KILL_CONTROL_GROUP) { + _cleanup_set_free_ Set *pid_set = NULL; + + pid_set = set_new(trivial_hash_func, trivial_compare_func); + if (!pid_set) + return -ENOMEM; + + /* Exclude the main/control pids from being killed via the cgroup */ + if (main_pid > 0) { + r = set_put(pid_set, LONG_TO_PTR(main_pid)); + if (r < 0) + return r; + } + + if (control_pid > 0) { + r = set_put(pid_set, LONG_TO_PTR(control_pid)); + if (r < 0) + return r; + } + + r = cgroup_bonding_kill_list(u->cgroup_bondings, sig, true, false, pid_set, NULL); + if (r < 0) { + if (r != -EAGAIN && r != -ESRCH && r != -ENOENT) + log_warning_unit(u->id, "Failed to kill control group: %s", strerror(-r)); + } else if (r > 0) + wait_for_exit = true; + } + + return wait_for_exit; +} + static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { [UNIT_ACTIVE] = "active", [UNIT_RELOADING] = "reloading",