1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
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 Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include <sys/types.h>
32 #include "cgroup-util.h"
36 #include "formats-util.h"
37 #include "process-util.h"
38 #include "path-util.h"
39 #include "unit-name.h"
43 #include "login-util.h"
45 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
46 _cleanup_free_ char *fs = NULL;
52 r = cg_get_path(controller, path, "cgroup.procs", &fs);
64 int cg_read_pid(FILE *f, pid_t *_pid) {
67 /* Note that the cgroup.procs might contain duplicates! See
68 * cgroups.txt for details. */
74 if (fscanf(f, "%lu", &ul) != 1) {
79 return errno ? -errno : -EIO;
89 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
90 _cleanup_free_ char *fs = NULL;
96 /* This is not recursive! */
98 r = cg_get_path(controller, path, NULL, &fs);
110 int cg_read_subgroup(DIR *d, char **fn) {
116 FOREACH_DIRENT(de, d, return -errno) {
119 if (de->d_type != DT_DIR)
122 if (streq(de->d_name, ".") ||
123 streq(de->d_name, ".."))
126 b = strdup(de->d_name);
137 int cg_rmdir(const char *controller, const char *path) {
138 _cleanup_free_ char *p = NULL;
141 r = cg_get_path(controller, path, NULL, &p);
146 if (r < 0 && errno != ENOENT)
152 int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
153 _cleanup_set_free_ Set *allocated_set = NULL;
160 /* This goes through the tasks list and kills them all. This
161 * is repeated until no further processes are added to the
162 * tasks list, to properly handle forking processes */
165 s = allocated_set = set_new(NULL);
173 _cleanup_fclose_ FILE *f = NULL;
177 r = cg_enumerate_processes(controller, path, &f);
179 if (ret >= 0 && r != -ENOENT)
185 while ((r = cg_read_pid(f, &pid)) > 0) {
187 if (ignore_self && pid == my_pid)
190 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
193 /* If we haven't killed this process yet, kill
195 if (kill(pid, sig) < 0) {
196 if (ret >= 0 && errno != ESRCH)
199 if (sigcont && sig != SIGKILL)
208 r = set_put(s, LONG_TO_PTR(pid));
224 /* To avoid racing against processes which fork
225 * quicker than we can kill them we repeat this until
226 * no new pids need to be killed. */
233 int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
234 _cleanup_set_free_ Set *allocated_set = NULL;
235 _cleanup_closedir_ DIR *d = NULL;
243 s = allocated_set = set_new(NULL);
248 ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
250 r = cg_enumerate_subgroups(controller, path, &d);
252 if (ret >= 0 && r != -ENOENT)
258 while ((r = cg_read_subgroup(d, &fn)) > 0) {
259 _cleanup_free_ char *p = NULL;
261 p = strjoin(path, "/", fn, NULL);
266 r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
267 if (ret >= 0 && r != 0)
271 if (ret >= 0 && r < 0)
275 r = cg_rmdir(controller, path);
276 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
283 int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) {
285 _cleanup_set_free_ Set *s = NULL;
301 _cleanup_fclose_ FILE *f = NULL;
305 r = cg_enumerate_processes(cfrom, pfrom, &f);
307 if (ret >= 0 && r != -ENOENT)
313 while ((r = cg_read_pid(f, &pid)) > 0) {
315 /* This might do weird stuff if we aren't a
316 * single-threaded program. However, we
317 * luckily know we are not */
318 if (ignore_self && pid == my_pid)
321 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
324 /* Ignore kernel threads. Since they can only
325 * exist in the root cgroup, we only check for
328 (isempty(pfrom) || path_equal(pfrom, "/")) &&
329 is_kernel_thread(pid) > 0)
332 r = cg_attach(cto, pto, pid);
334 if (ret >= 0 && r != -ESRCH)
341 r = set_put(s, LONG_TO_PTR(pid));
361 int cg_migrate_recursive(
369 _cleanup_closedir_ DIR *d = NULL;
378 ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self);
380 r = cg_enumerate_subgroups(cfrom, pfrom, &d);
382 if (ret >= 0 && r != -ENOENT)
388 while ((r = cg_read_subgroup(d, &fn)) > 0) {
389 _cleanup_free_ char *p = NULL;
391 p = strjoin(pfrom, "/", fn, NULL);
400 r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem);
401 if (r != 0 && ret >= 0)
405 if (r < 0 && ret >= 0)
409 r = cg_rmdir(cfrom, pfrom);
410 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
417 int cg_migrate_recursive_fallback(
432 r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem);
434 char prefix[strlen(pto) + 1];
436 /* This didn't work? Then let's try all prefixes of the destination */
438 PATH_FOREACH_PREFIX(prefix, pto) {
439 r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
448 static const char *normalize_controller(const char *controller) {
452 if (startswith(controller, "name="))
453 return controller + 5;
458 static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
461 if (!isempty(controller)) {
462 if (!isempty(path) && !isempty(suffix))
463 t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
464 else if (!isempty(path))
465 t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL);
466 else if (!isempty(suffix))
467 t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL);
469 t = strappend("/sys/fs/cgroup/", controller);
471 if (!isempty(path) && !isempty(suffix))
472 t = strjoin(path, "/", suffix, NULL);
473 else if (!isempty(path))
482 *fs = path_kill_slashes(t);
486 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
488 static thread_local bool good = false;
492 if (controller && !cg_controller_is_valid(controller))
495 if (_unlikely_(!good)) {
498 r = path_is_mount_point("/sys/fs/cgroup", 0);
504 /* Cache this to save a few stat()s */
508 p = controller ? normalize_controller(controller) : NULL;
510 return join_path(p, path, suffix, fs);
513 static int check_hierarchy(const char *p) {
518 if (!filename_is_valid(p))
521 /* Check if this controller actually really exists */
522 cc = strjoina("/sys/fs/cgroup/", p);
523 if (laccess(cc, F_OK) < 0)
529 int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
535 if (!cg_controller_is_valid(controller))
538 /* Normalize the controller syntax */
539 p = normalize_controller(controller);
541 /* Check if this controller actually really exists */
542 r = check_hierarchy(p);
546 return join_path(p, path, suffix, fs);
549 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
554 if (typeflag != FTW_DP)
557 if (ftwbuf->level < 1)
564 int cg_trim(const char *controller, const char *path, bool delete_root) {
565 _cleanup_free_ char *fs = NULL;
570 r = cg_get_path(controller, path, NULL, &fs);
575 if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0)
576 r = errno ? -errno : -EIO;
579 if (rmdir(fs) < 0 && errno != ENOENT)
586 /// UNNEDED by elogind
588 int cg_delete(const char *controller, const char *path) {
589 _cleanup_free_ char *parent = NULL;
594 r = path_get_parent(path, &parent);
598 r = cg_migrate_recursive(controller, path, controller, parent, false, true);
599 return r == -ENOENT ? 0 : r;
603 int cg_create(const char *controller, const char *path) {
604 _cleanup_free_ char *fs = NULL;
607 r = cg_get_path_and_check(controller, path, NULL, &fs);
611 r = mkdir_parents(fs, 0755);
615 if (mkdir(fs, 0755) < 0) {
626 /// UNNEEDED by elogind
628 int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
633 r = cg_create(controller, path);
637 q = cg_attach(controller, path, pid);
641 /* This does not remove the cgroup on failure */
646 int cg_attach(const char *controller, const char *path, pid_t pid) {
647 _cleanup_free_ char *fs = NULL;
648 char c[DECIMAL_STR_MAX(pid_t) + 2];
654 r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
661 snprintf(c, sizeof(c), PID_FMT"\n", pid);
663 return write_string_file_no_create(fs, c);
666 int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
673 r = cg_attach(controller, path, pid);
675 char prefix[strlen(path) + 1];
677 /* This didn't work? Then let's try all prefixes of
680 PATH_FOREACH_PREFIX(prefix, path) {
681 r = cg_attach(controller, prefix, pid);
690 /// UNNEEDED by elogind
692 int cg_set_group_access(
693 const char *controller,
699 _cleanup_free_ char *fs = NULL;
704 if (mode != MODE_INVALID)
707 r = cg_get_path(controller, path, NULL, &fs);
711 return chmod_and_chown(fs, mode, uid, gid);
714 int cg_set_task_access(
715 const char *controller,
721 _cleanup_free_ char *fs = NULL, *procs = NULL;
726 if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
729 if (mode != MODE_INVALID)
732 r = cg_get_path(controller, path, "cgroup.procs", &fs);
736 r = chmod_and_chown(fs, mode, uid, gid);
740 /* Compatibility, Always keep values for "tasks" in sync with
742 r = cg_get_path(controller, path, "tasks", &procs);
746 return chmod_and_chown(procs, mode, uid, gid);
750 int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
751 _cleanup_fclose_ FILE *f = NULL;
760 if (!cg_controller_is_valid(controller))
763 controller = normalize_controller(controller);
765 controller = ELOGIND_CGROUP_CONTROLLER;
767 fs = procfs_file_alloca(pid, "cgroup");
771 return errno == ENOENT ? -ESRCH : -errno;
773 cs = strlen(controller);
775 FOREACH_LINE(line, f, return -errno) {
778 const char *word, *state;
783 l = strchr(line, ':');
794 FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
796 if (k == cs && memcmp(word, controller, cs) == 0) {
802 memcmp(word, "name=", 5) == 0 &&
803 memcmp(word+5, controller, cs) == 0) {
823 /// UNNEEDED by elogind
825 int cg_install_release_agent(const char *controller, const char *agent) {
826 _cleanup_free_ char *fs = NULL, *contents = NULL;
832 r = cg_get_path(controller, NULL, "release_agent", &fs);
836 r = read_one_line_file(fs, &contents);
840 sc = strstrip(contents);
842 r = write_string_file_no_create(fs, agent);
845 } else if (!streq(sc, agent))
849 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
853 contents = mfree(contents);
854 r = read_one_line_file(fs, &contents);
858 sc = strstrip(contents);
859 if (streq(sc, "0")) {
860 r = write_string_file_no_create(fs, "1");
873 int cg_uninstall_release_agent(const char *controller) {
874 _cleanup_free_ char *fs = NULL;
877 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
881 r = write_string_file_no_create(fs, "0");
887 r = cg_get_path(controller, NULL, "release_agent", &fs);
891 r = write_string_file_no_create(fs, "");
899 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
900 _cleanup_fclose_ FILE *f = NULL;
901 pid_t pid = 0, self_pid;
907 r = cg_enumerate_processes(controller, path, &f);
909 return r == -ENOENT ? 1 : r;
913 while ((r = cg_read_pid(f, &pid)) > 0) {
915 if (ignore_self && pid == self_pid)
928 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
929 _cleanup_closedir_ DIR *d = NULL;
935 r = cg_is_empty(controller, path, ignore_self);
939 r = cg_enumerate_subgroups(controller, path, &d);
941 return r == -ENOENT ? 1 : r;
943 while ((r = cg_read_subgroup(d, &fn)) > 0) {
944 _cleanup_free_ char *p = NULL;
946 p = strjoin(path, "/", fn, NULL);
951 r = cg_is_empty_recursive(controller, p, ignore_self);
962 int cg_split_spec(const char *spec, char **controller, char **path) {
964 char *t = NULL, *u = NULL;
965 _cleanup_free_ char *v = NULL;
970 if (!path_is_safe(spec))
978 *path = path_kill_slashes(t);
987 e = strchr(spec, ':');
989 if (!cg_controller_is_valid(spec))
993 t = strdup(normalize_controller(spec));
1006 v = strndup(spec, e-spec);
1009 t = strdup(normalize_controller(v));
1012 if (!cg_controller_is_valid(t)) {
1017 if (streq(e+1, "")) {
1030 if (!path_is_safe(u) ||
1031 !path_is_absolute(u)) {
1037 path_kill_slashes(u);
1053 int cg_mangle_path(const char *path, char **result) {
1054 _cleanup_free_ char *c = NULL, *p = NULL;
1061 /* First, check if it already is a filesystem path */
1062 if (path_startswith(path, "/sys/fs/cgroup")) {
1068 *result = path_kill_slashes(t);
1072 /* Otherwise, treat it as cg spec */
1073 r = cg_split_spec(path, &c, &p);
1077 return cg_get_path(c ? c : ELOGIND_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1080 int cg_get_root_path(char **path) {
1086 r = cg_pid_get_path(ELOGIND_CGROUP_CONTROLLER, 1, &p);
1090 e = endswith(p, "/" SPECIAL_SYSTEM_SLICE);
1098 int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
1099 _cleanup_free_ char *rt = NULL;
1107 /* If the root was specified let's use that, otherwise
1108 * let's determine it from PID 1 */
1110 r = cg_get_root_path(&rt);
1117 p = path_startswith(cgroup, root);
1126 int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
1127 _cleanup_free_ char *raw = NULL;
1134 r = cg_pid_get_path(ELOGIND_CGROUP_CONTROLLER, pid, &raw);
1138 r = cg_shift_path(raw, root, &c);
1158 int cg_path_decode_unit(const char *cgroup, char **unit){
1165 n = strcspn(cgroup, "/");
1169 c = strndupa(cgroup, n);
1172 if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
1183 static bool valid_slice_name(const char *p, size_t n) {
1188 if (n < strlen("x.slice"))
1191 if (memcmp(p + n - 6, ".slice", 6) == 0) {
1197 c = cg_unescape(buf);
1199 return unit_name_is_valid(c, UNIT_NAME_PLAIN);
1205 static const char *skip_slices(const char *p) {
1208 /* Skips over all slice assignments */
1213 p += strspn(p, "/");
1215 n = strcspn(p, "/");
1216 if (!valid_slice_name(p, n))
1223 int cg_path_get_unit(const char *path, char **ret) {
1231 e = skip_slices(path);
1233 r = cg_path_decode_unit(e, &unit);
1237 /* We skipped over the slices, don't accept any now */
1238 if (endswith(unit, ".slice")) {
1247 int cg_pid_get_unit(pid_t pid, char **unit) {
1248 _cleanup_free_ char *cgroup = NULL;
1253 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1257 return cg_path_get_unit(cgroup, unit);
1261 * Skip session-*.scope, but require it to be there.
1263 static const char *skip_session(const char *p) {
1269 p += strspn(p, "/");
1271 n = strcspn(p, "/");
1272 if (n < strlen("session-x.scope"))
1275 if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) {
1276 char buf[n - 8 - 6 + 1];
1278 memcpy(buf, p + 8, n - 8 - 6);
1281 /* Note that session scopes never need unescaping,
1282 * since they cannot conflict with the kernel's own
1283 * names, hence we don't need to call cg_unescape()
1286 if (!session_id_valid(buf))
1290 p += strspn(p, "/");
1298 * Skip user@*.service, but require it to be there.
1300 static const char *skip_user_manager(const char *p) {
1306 p += strspn(p, "/");
1308 n = strcspn(p, "/");
1309 if (n < strlen("user@x.service"))
1312 if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
1313 char buf[n - 5 - 8 + 1];
1315 memcpy(buf, p + 5, n - 5 - 8);
1318 /* Note that user manager services never need unescaping,
1319 * since they cannot conflict with the kernel's own
1320 * names, hence we don't need to call cg_unescape()
1323 if (parse_uid(buf, NULL) < 0)
1327 p += strspn(p, "/");
1335 static const char *skip_user_prefix(const char *path) {
1340 /* Skip slices, if there are any */
1341 e = skip_slices(path);
1343 /* Skip the user manager, if it's in the path now... */
1344 t = skip_user_manager(e);
1348 /* Alternatively skip the user session if it is in the path... */
1349 return skip_session(e);
1352 int cg_path_get_user_unit(const char *path, char **ret) {
1358 t = skip_user_prefix(path);
1362 /* And from here on it looks pretty much the same as for a
1363 * system unit, hence let's use the same parser from here
1365 return cg_path_get_unit(t, ret);
1368 int cg_pid_get_user_unit(pid_t pid, char **unit) {
1369 _cleanup_free_ char *cgroup = NULL;
1374 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1378 return cg_path_get_user_unit(cgroup, unit);
1381 int cg_path_get_machine_name(const char *path, char **machine) {
1382 _cleanup_free_ char *u = NULL, *sl = NULL;
1385 r = cg_path_get_unit(path, &u);
1389 sl = strjoin("/run/systemd/machines/unit:", u, NULL);
1393 return readlink_malloc(sl, machine);
1396 int cg_pid_get_machine_name(pid_t pid, char **machine) {
1397 _cleanup_free_ char *cgroup = NULL;
1402 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1406 return cg_path_get_machine_name(cgroup, machine);
1409 int cg_path_get_session(const char *path, char **session) {
1410 _cleanup_free_ char *unit = NULL;
1416 r = cg_path_get_unit(path, &unit);
1420 start = startswith(unit, "session-");
1423 end = endswith(start, ".scope");
1428 if (!session_id_valid(start))
1444 int cg_pid_get_session(pid_t pid, char **session) {
1445 _cleanup_free_ char *cgroup = NULL;
1448 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1452 return cg_path_get_session(cgroup, session);
1455 int cg_path_get_owner_uid(const char *path, uid_t *uid) {
1456 _cleanup_free_ char *slice = NULL;
1462 r = cg_path_get_slice(path, &slice);
1466 start = startswith(slice, "user-");
1469 end = endswith(start, ".slice");
1474 if (parse_uid(start, uid) < 0)
1480 int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
1481 _cleanup_free_ char *cgroup = NULL;
1484 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1488 return cg_path_get_owner_uid(cgroup, uid);
1491 int cg_path_get_slice(const char *p, char **slice) {
1492 const char *e = NULL;
1497 /* Finds the right-most slice unit from the beginning, but
1498 * stops before we come to the first non-slice unit. */
1503 p += strspn(p, "/");
1505 n = strcspn(p, "/");
1506 if (!valid_slice_name(p, n)) {
1511 s = strdup("-.slice");
1519 return cg_path_decode_unit(e, slice);
1527 int cg_pid_get_slice(pid_t pid, char **slice) {
1528 _cleanup_free_ char *cgroup = NULL;
1533 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1537 return cg_path_get_slice(cgroup, slice);
1540 int cg_path_get_user_slice(const char *p, char **slice) {
1545 t = skip_user_prefix(p);
1549 /* And now it looks pretty much the same as for a system
1550 * slice, so let's just use the same parser from here on. */
1551 return cg_path_get_slice(t, slice);
1554 int cg_pid_get_user_slice(pid_t pid, char **slice) {
1555 _cleanup_free_ char *cgroup = NULL;
1560 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1564 return cg_path_get_user_slice(cgroup, slice);
1567 char *cg_escape(const char *p) {
1568 bool need_prefix = false;
1570 /* This implements very minimal escaping for names to be used
1571 * as file names in the cgroup tree: any name which might
1572 * conflict with a kernel name or is prefixed with '_' is
1573 * prefixed with a '_'. That way, when reading cgroup names it
1574 * is sufficient to remove a single prefixing underscore if
1577 /* The return value of this function (unlike cg_unescape())
1583 streq(p, "notify_on_release") ||
1584 streq(p, "release_agent") ||
1590 dot = strrchr(p, '.');
1593 if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0)
1598 n = strndupa(p, dot - p);
1600 if (check_hierarchy(n) >= 0)
1607 return strappend("_", p);
1612 char *cg_unescape(const char *p) {
1615 /* The return value of this function (unlike cg_escape())
1616 * doesn't need free()! */
1624 #define CONTROLLER_VALID \
1628 bool cg_controller_is_valid(const char *p) {
1634 s = startswith(p, "name=");
1638 if (*p == 0 || *p == '_')
1641 for (t = p; *t; t++)
1642 if (!strchr(CONTROLLER_VALID, *t))
1645 if (t - p > FILENAME_MAX)
1651 /// UNNEEDED by elogind
1653 int cg_slice_to_path(const char *unit, char **ret) {
1654 _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
1661 if (streq(unit, "-.slice")) {
1671 if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
1674 if (!endswith(unit, ".slice"))
1677 r = unit_name_to_prefix(unit, &p);
1681 dash = strchr(p, '-');
1683 /* Don't allow initial dashes */
1688 _cleanup_free_ char *escaped = NULL;
1689 char n[dash - p + sizeof(".slice")];
1691 /* Don't allow trailing or double dashes */
1692 if (dash[1] == 0 || dash[1] == '-')
1695 strcpy(stpncpy(n, p, dash - p), ".slice");
1696 if (!unit_name_is_valid(n, UNIT_NAME_PLAIN))
1699 escaped = cg_escape(n);
1703 if (!strextend(&s, escaped, "/", NULL))
1706 dash = strchr(dash+1, '-');
1709 e = cg_escape(unit);
1713 if (!strextend(&s, e, NULL))
1722 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
1723 _cleanup_free_ char *p = NULL;
1726 r = cg_get_path(controller, path, attribute, &p);
1730 return write_string_file_no_create(p, value);
1733 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) {
1734 _cleanup_free_ char *p = NULL;
1737 r = cg_get_path(controller, path, attribute, &p);
1741 return read_one_line_file(p, ret);
1745 static const char mask_names[] =
1752 /// UNNEEDED by elogind
1754 int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
1755 CGroupControllerMask bit = 1;
1759 /* This one will create a cgroup in our private tree, but also
1760 * duplicate it in the trees specified in mask, and remove it
1763 /* First create the cgroup in our own hierarchy. */
1764 r = cg_create(ELOGIND_CGROUP_CONTROLLER, path);
1768 /* Then, do the same in the other hierarchies */
1769 NULSTR_FOREACH(n, mask_names) {
1772 else if (supported & bit)
1773 cg_trim(n, path, true);
1782 int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
1783 CGroupControllerMask bit = 1;
1787 r = cg_attach(ELOGIND_CGROUP_CONTROLLER, path, pid);
1791 NULSTR_FOREACH(n, mask_names) {
1793 if (supported & bit) {
1794 const char *p = NULL;
1797 p = path_callback(bit, userdata);
1802 cg_attach_fallback(n, p, pid);
1811 /// UNNEEDED by elogind
1813 int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
1818 SET_FOREACH(pidp, pids, i) {
1819 pid_t pid = PTR_TO_LONG(pidp);
1822 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
1830 int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
1831 CGroupControllerMask bit = 1;
1835 if (!path_equal(from, to)) {
1836 r = cg_migrate_recursive(ELOGIND_CGROUP_CONTROLLER, from, ELOGIND_CGROUP_CONTROLLER, to, false, true);
1841 NULSTR_FOREACH(n, mask_names) {
1842 if (supported & bit) {
1843 const char *p = NULL;
1846 p = to_callback(bit, userdata);
1851 cg_migrate_recursive_fallback(ELOGIND_CGROUP_CONTROLLER, to, n, p, false, false);
1860 int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
1861 CGroupControllerMask bit = 1;
1865 r = cg_trim(ELOGIND_CGROUP_CONTROLLER, path, delete_root);
1869 NULSTR_FOREACH(n, mask_names) {
1870 if (supported & bit)
1871 cg_trim(n, path, delete_root);
1879 CGroupControllerMask cg_mask_supported(void) {
1880 CGroupControllerMask bit = 1, mask = 0;
1883 NULSTR_FOREACH(n, mask_names) {
1884 if (check_hierarchy(n) >= 0)
1893 int cg_kernel_controllers(Set *controllers) {
1894 _cleanup_fclose_ FILE *f = NULL;
1898 assert(controllers);
1900 f = fopen("/proc/cgroups", "re");
1902 if (errno == ENOENT)
1907 /* Ignore the header line */
1908 (void) fgets(buf, sizeof(buf), f);
1915 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
1920 if (ferror(f) && errno)
1931 if (!filename_is_valid(controller)) {
1936 r = set_consume(controllers, controller);