X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Funit.c;h=f7d00b6030d2f9a690c8367da86506447347e3e7;hb=7850b3b83791ba0e2377ba40383c5abc258b839d;hp=83359e126b52a88318a103c7bd30ed888da81be0;hpb=bbc9006e6b5665073149331d75c104a33224dc19;p=elogind.git diff --git a/src/core/unit.c b/src/core/unit.c index 83359e126..f7d00b603 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -45,6 +45,7 @@ #include "cgroup-util.h" #include "missing.h" #include "cgroup-attr.h" +#include "mkdir.h" const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = &service_vtable, @@ -2156,26 +2157,27 @@ int unit_add_cgroup_attribute( _cleanup_free_ char *c = NULL; CGroupAttribute *a; + int r; assert(u); assert(name); assert(value); if (!controller) { - const char *dot; - - dot = strchr(name, '.'); - if (!dot) + r = cg_controller_from_attr(name, &c); + if (r < 0) return -EINVAL; - c = strndup(name, dot - name); - if (!c) - return -ENOMEM; - controller = c; + } else { + if (!filename_is_safe(name)) + return -EINVAL; + + if (!filename_is_safe(controller)) + return -EINVAL; } - if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) + if (!controller || streq(controller, SYSTEMD_CGROUP_CONTROLLER)) return -EINVAL; a = cgroup_attribute_find_list(u->cgroup_attributes, controller, name); @@ -2757,6 +2759,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(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",