1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include <libcgroup.h>
30 #include "cgroup-util.h"
37 Currently, the only remaining functionality from libcgroup we call
40 - cgroup_get_subsys_mount_point()
41 - cgroup_walk_tree_begin()/cgroup_walk_tree_next()
42 - cgroup_delete_cgroup_ext()
45 int cg_translate_error(int error, int _errno) {
49 case ECGROUPNOTCOMPILED:
50 case ECGROUPNOTMOUNTED:
52 case ECGROUPNOTCREATED:
58 case ECGROUPNOTALLOWED:
68 static struct cgroup* cg_new(const char *controller, const char *path) {
69 struct cgroup *cgroup;
74 if (!(cgroup = cgroup_new_cgroup(path)))
77 if (!cgroup_add_controller(cgroup, controller)) {
85 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
94 if ((r = cg_get_path(controller, path, "cgroup.procs", &fs)) < 0)
107 int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
116 if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
129 int cg_read_pid(FILE *f, pid_t *_pid) {
132 /* Note that the cgroup.procs might contain duplicates! See
133 * cgroups.txt for details. */
136 if (fscanf(f, "%lu", &ul) != 1) {
141 return errno ? -errno : -EIO;
151 int cg_kill(const char *controller, const char *path, int sig, bool ignore_self) {
152 bool killed = false, done = false;
162 /* This goes through the tasks list and kills them all. This
163 * is repeated until no further processes are added to the
164 * tasks list, to properly handle forking processes */
166 if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
175 if ((r = cg_enumerate_processes(controller, path, &f)) < 0)
178 while ((r = cg_read_pid(f, &pid)) > 0) {
180 if (pid == my_pid && ignore_self)
183 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
186 /* If we haven't killed this process yet, kill
188 if (kill(pid, sig) < 0 && errno != ESRCH) {
196 if ((r = set_put(s, LONG_TO_PTR(pid))) < 0)
203 /* To avoid racing against processes which fork
204 * quicker than we can kill them we repeat this until
205 * no new pids need to be killed. */
207 } while (!done && r >= 0);
224 int cg_kill_recursive(const char *controller, const char *path, int sig, bool ignore_self) {
225 struct cgroup_file_info info;
226 int level = 0, r, ret = 0;
227 void *iterator = NULL;
236 r = cgroup_walk_tree_begin(controller, path, 0, &iterator, &info, &level);
241 if (info.type != CGROUP_FILE_TYPE_DIR)
244 if (asprintf(&p, "%s/%s", path, info.path) < 0) {
249 k = cg_kill(controller, p, sig, ignore_self);
260 r = cgroup_walk_tree_next(0, &iterator, &info, level);
264 if (r == 0 || r == ECGEOF)
266 else if (r == ECGOTHER && errno == ENOENT)
269 ret = cg_translate_error(r, errno);
272 assert_se(cgroup_walk_tree_end(&iterator) == 0);
277 int cg_kill_recursive_and_wait(const char *controller, const char *path) {
283 /* This safely kills all processes; first it sends a SIGTERM,
284 * then checks 8 times after 50ms whether the group is
285 * now empty, and finally kills everything that is left with
288 for (i = 0; i < 10; i++) {
298 if ((r = cg_kill_recursive(controller, path, sig, true)) <= 0)
301 usleep(50 * USEC_PER_MSEC);
307 int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self) {
308 bool migrated = false, done = false;
323 if ((r = cg_enumerate_tasks(controller, from, &f)) < 0)
326 while ((r = cg_read_pid(f, &pid)) > 0) {
328 if (pid == my_pid && ignore_self)
331 if ((r = cg_attach(controller, to, pid)) < 0) {
343 } while (!done && r >= 0);
359 int cg_migrate_recursive(const char *controller, const char *from, const char *to, bool ignore_self) {
360 struct cgroup_file_info info;
361 int level = 0, r, ret = 0;
362 void *iterator = NULL;
363 bool migrated = false;
371 r = cgroup_walk_tree_begin(controller, from, 0, &iterator, &info, &level);
376 if (info.type != CGROUP_FILE_TYPE_DIR)
379 if (asprintf(&p, "%s/%s", from, info.path) < 0) {
384 k = cg_migrate(controller, p, to, ignore_self);
394 r = cgroup_walk_tree_next(0, &iterator, &info, level);
398 if (r == 0 || r == ECGEOF)
400 else if (r == ECGOTHER && errno == ENOENT)
403 r = cg_translate_error(r, errno);
406 assert_se(cgroup_walk_tree_end(&iterator) == 0);
411 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
417 if ((r = cgroup_get_subsys_mount_point(controller, &mp)) != 0)
418 return cg_translate_error(r, errno);
421 r = asprintf(fs, "%s/%s/%s", mp, path, suffix);
423 r = asprintf(fs, "%s/%s", mp, path);
425 r = asprintf(fs, "%s/%s", mp, suffix);
427 path_kill_slashes(mp);
433 path_kill_slashes(*fs);
434 return r < 0 ? -ENOMEM : 0;
437 int cg_trim(const char *controller, const char *path, bool delete_root) {
444 if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
447 r = rm_rf(fs, true, delete_root);
453 int cg_delete(const char *controller, const char *path) {
460 if (!(cg = cg_new(controller, path)))
463 if ((r = cgroup_delete_cgroup_ext(cg, CGFLAG_DELETE_RECURSIVE|CGFLAG_DELETE_IGNORE_MIGRATION)) != 0) {
464 r = cg_translate_error(r, errno);
476 int cg_create(const char *controller, const char *path) {
483 if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
486 r = mkdir_p(fs, 0755);
492 int cg_attach(const char *controller, const char *path, pid_t pid) {
501 if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
507 snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid);
510 r = write_one_line_file(fs, c);
516 int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
523 if ((r = cg_create(controller, path)) < 0)
526 if ((r = cg_attach(controller, path, pid)) < 0)
529 /* This does not remove the cgroup on failure */
534 int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
541 if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
544 r = chmod_and_chown(fs, mode, uid, gid);
550 int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
557 if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
560 r = chmod_and_chown(fs, mode, uid, gid);
566 int cg_get_by_pid(const char *controller, pid_t pid, char **path) {
580 if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0)
586 cs = strlen(controller);
593 if (!(fgets(line, sizeof(line), f))) {
597 r = errno ? -errno : -EIO;
603 if (!(l = strchr(line, ':')))
607 if (strncmp(l, controller, cs) != 0)
613 if (!(p = strdup(l + cs + 1))) {
631 int cg_install_release_agent(const char *controller, const char *agent) {
632 char *fs = NULL, *contents = NULL, *line = NULL, *sc;
638 if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0)
641 if ((r = read_one_line_file(fs, &contents)) < 0)
644 sc = strstrip(contents);
647 if (asprintf(&line, "%s\n", agent) < 0) {
652 if ((r = write_one_line_file(fs, line)) < 0)
655 } else if (!streq(sc, agent)) {
662 if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0) {
669 if ((r = read_one_line_file(fs, &contents)) < 0)
672 sc = strstrip(contents);
674 if (streq(sc, "0")) {
675 if ((r = write_one_line_file(fs, "1\n")) < 0)
679 } else if (!streq(sc, "1")) {
693 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
702 if ((r = cg_enumerate_tasks(controller, path, &f)) < 0)
705 while ((r = cg_read_pid(f, &pid)) > 0) {
707 if (ignore_self && pid == getpid())
722 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
723 struct cgroup_file_info info;
724 int level = 0, r, ret = 0;
725 void *iterator = NULL;
733 r = cgroup_walk_tree_begin(controller, path, 0, &iterator, &info, &level);
738 if (info.type != CGROUP_FILE_TYPE_DIR)
741 if (asprintf(&p, "%s/%s", path, info.path) < 0) {
746 k = cg_is_empty(controller, p, ignore_self);
758 r = cgroup_walk_tree_next(0, &iterator, &info, level);
762 if (r == 0 || r == ECGEOF)
764 else if (r == ECGOTHER && errno == ENOENT)
767 ret = cg_translate_error(r, errno);
770 assert_se(cgroup_walk_tree_end(&iterator) == 0);
778 if ((r = cgroup_init()) != 0)
779 return cg_translate_error(r, errno);