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"
37 #include "path-util.h"
39 #include "unit-name.h"
43 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
44 _cleanup_free_ char *fs = NULL;
50 r = cg_get_path(controller, path, "cgroup.procs", &fs);
62 int cg_read_pid(FILE *f, pid_t *_pid) {
65 /* Note that the cgroup.procs might contain duplicates! See
66 * cgroups.txt for details. */
72 if (fscanf(f, "%lu", &ul) != 1) {
77 return errno ? -errno : -EIO;
87 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
88 _cleanup_free_ char *fs = NULL;
94 /* This is not recursive! */
96 r = cg_get_path(controller, path, NULL, &fs);
108 int cg_read_subgroup(DIR *d, char **fn) {
114 FOREACH_DIRENT(de, d, return -errno) {
117 if (de->d_type != DT_DIR)
120 if (streq(de->d_name, ".") ||
121 streq(de->d_name, ".."))
124 b = strdup(de->d_name);
135 int cg_rmdir(const char *controller, const char *path) {
136 _cleanup_free_ char *p = NULL;
139 r = cg_get_path(controller, path, NULL, &p);
144 if (r < 0 && errno != ENOENT)
150 int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
151 _cleanup_set_free_ Set *allocated_set = NULL;
158 /* This goes through the tasks list and kills them all. This
159 * is repeated until no further processes are added to the
160 * tasks list, to properly handle forking processes */
163 s = allocated_set = set_new(trivial_hash_func, trivial_compare_func);
171 _cleanup_fclose_ FILE *f = NULL;
175 r = cg_enumerate_processes(controller, path, &f);
177 if (ret >= 0 && r != -ENOENT)
183 while ((r = cg_read_pid(f, &pid)) > 0) {
185 if (ignore_self && pid == my_pid)
188 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
191 /* If we haven't killed this process yet, kill
193 if (kill(pid, sig) < 0) {
194 if (ret >= 0 && errno != ESRCH)
196 } else if (ret == 0) {
206 r = set_put(s, LONG_TO_PTR(pid));
222 /* To avoid racing against processes which fork
223 * quicker than we can kill them we repeat this until
224 * no new pids need to be killed. */
231 int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
232 _cleanup_set_free_ Set *allocated_set = NULL;
233 _cleanup_closedir_ DIR *d = NULL;
241 s = allocated_set = set_new(trivial_hash_func, trivial_compare_func);
246 ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
248 r = cg_enumerate_subgroups(controller, path, &d);
250 if (ret >= 0 && r != -ENOENT)
256 while ((r = cg_read_subgroup(d, &fn)) > 0) {
257 _cleanup_free_ char *p = NULL;
259 p = strjoin(path, "/", fn, NULL);
264 r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
265 if (ret >= 0 && r != 0)
269 if (ret >= 0 && r < 0)
273 r = cg_rmdir(controller, path);
274 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
281 int cg_kill_recursive_and_wait(const char *controller, const char *path, bool rem) {
286 /* This safely kills all processes; first it sends a SIGTERM,
287 * then checks 8 times after 200ms whether the group is now
288 * empty, then kills everything that is left with SIGKILL and
289 * finally checks 5 times after 200ms each whether the group
290 * is finally empty. */
292 for (i = 0; i < 15; i++) {
302 r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL);
306 usleep(200 * USEC_PER_MSEC);
312 int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) {
314 _cleanup_set_free_ Set *s = NULL;
323 s = set_new(trivial_hash_func, trivial_compare_func);
330 _cleanup_fclose_ FILE *f = NULL;
334 r = cg_enumerate_processes(cfrom, pfrom, &f);
336 if (ret >= 0 && r != -ENOENT)
342 while ((r = cg_read_pid(f, &pid)) > 0) {
344 /* This might do weird stuff if we aren't a
345 * single-threaded program. However, we
346 * luckily know we are not */
347 if (ignore_self && pid == my_pid)
350 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
353 r = cg_attach(cto, pto, pid);
355 if (ret >= 0 && r != -ESRCH)
362 r = set_put(s, LONG_TO_PTR(pid));
382 int cg_migrate_recursive(
390 _cleanup_closedir_ DIR *d = NULL;
399 ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self);
401 r = cg_enumerate_subgroups(cfrom, pfrom, &d);
403 if (ret >= 0 && r != -ENOENT)
409 while ((r = cg_read_subgroup(d, &fn)) > 0) {
410 _cleanup_free_ char *p = NULL;
412 p = strjoin(pfrom, "/", fn, NULL);
421 r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem);
422 if (r != 0 && ret >= 0)
426 if (r < 0 && ret >= 0)
430 r = cg_rmdir(cfrom, pfrom);
431 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
438 int cg_migrate_recursive_fallback(
453 r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem);
455 char prefix[strlen(pto) + 1];
457 /* This didn't work? Then let's try all prefixes of the destination */
463 slash = strrchr(prefix, '/');
469 r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
478 static const char *normalize_controller(const char *controller) {
482 if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
484 else if (startswith(controller, "name="))
485 return controller + 5;
490 static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
493 if (!isempty(controller)) {
494 if (!isempty(path) && !isempty(suffix))
495 t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
496 else if (!isempty(path))
497 t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL);
498 else if (!isempty(suffix))
499 t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL);
501 t = strappend("/sys/fs/cgroup/", controller);
503 if (!isempty(path) && !isempty(suffix))
504 t = strjoin(path, "/", suffix, NULL);
505 else if (!isempty(path))
514 path_kill_slashes(t);
520 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
522 static __thread bool good = false;
526 if (controller && !cg_controller_is_valid(controller, true))
529 if (_unlikely_(!good)) {
532 r = path_is_mount_point("/sys/fs/cgroup", false);
534 return r < 0 ? r : -ENOENT;
536 /* Cache this to save a few stat()s */
540 p = controller ? normalize_controller(controller) : NULL;
542 return join_path(p, path, suffix, fs);
545 static int check_hierarchy(const char *p) {
550 /* Check if this controller actually really exists */
551 cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(p));
552 strcpy(stpcpy(cc, "/sys/fs/cgroup/"), p);
553 if (access(cc, F_OK) < 0)
559 int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
565 if (!cg_controller_is_valid(controller, true))
568 /* Normalize the controller syntax */
569 p = normalize_controller(controller);
571 /* Check if this controller actually really exists */
572 r = check_hierarchy(p);
576 return join_path(p, path, suffix, fs);
579 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
584 if (typeflag != FTW_DP)
587 if (ftwbuf->level < 1)
594 int cg_trim(const char *controller, const char *path, bool delete_root) {
595 _cleanup_free_ char *fs = NULL;
600 r = cg_get_path(controller, path, NULL, &fs);
605 if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0)
606 r = errno ? -errno : -EIO;
609 if (rmdir(fs) < 0 && errno != ENOENT)
616 int cg_delete(const char *controller, const char *path) {
617 _cleanup_free_ char *parent = NULL;
622 r = path_get_parent(path, &parent);
626 r = cg_migrate_recursive(controller, path, controller, parent, false, true);
627 return r == -ENOENT ? 0 : r;
630 int cg_attach(const char *controller, const char *path, pid_t pid) {
631 _cleanup_free_ char *fs = NULL;
632 char c[DECIMAL_STR_MAX(pid_t) + 2];
638 r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
645 snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid);
647 return write_string_file(fs, c);
650 int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
657 r = cg_attach(controller, path, pid);
659 char prefix[strlen(path) + 1];
661 /* This didn't work? Then let's try all prefixes of
664 strcpy(prefix, path);
668 slash = strrchr(prefix, '/');
674 r = cg_attach(controller, prefix, pid);
683 int cg_set_group_access(
684 const char *controller,
690 _cleanup_free_ char *fs = NULL;
695 if (mode != (mode_t) -1)
698 r = cg_get_path(controller, path, NULL, &fs);
702 return chmod_and_chown(fs, mode, uid, gid);
705 int cg_set_task_access(
706 const char *controller,
712 _cleanup_free_ char *fs = NULL, *procs = NULL;
717 if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1)
720 if (mode != (mode_t) -1)
723 r = cg_get_path(controller, path, "cgroup.procs", &fs);
727 r = chmod_and_chown(fs, mode, uid, gid);
731 /* Compatibility, Always keep values for "tasks" in sync with
733 r = cg_get_path(controller, path, "tasks", &procs);
737 return chmod_and_chown(procs, mode, uid, gid);
740 int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
741 _cleanup_fclose_ FILE *f = NULL;
750 if (!cg_controller_is_valid(controller, true))
753 controller = normalize_controller(controller);
755 controller = SYSTEMD_CGROUP_CONTROLLER;
758 fs = "/proc/self/cgroup";
760 fs = procfs_file_alloca(pid, "cgroup");
764 return errno == ENOENT ? -ESRCH : -errno;
766 cs = strlen(controller);
768 FOREACH_LINE(line, f, return -errno) {
776 l = strchr(line, ':');
787 FOREACH_WORD_SEPARATOR(w, k, l, ",", state) {
789 if (k == cs && memcmp(w, controller, cs) == 0) {
795 memcmp(w, "name=", 5) == 0 &&
796 memcmp(w+5, controller, cs) == 0) {
816 int cg_install_release_agent(const char *controller, const char *agent) {
817 _cleanup_free_ char *fs = NULL, *contents = NULL;
823 r = cg_get_path(controller, NULL, "release_agent", &fs);
827 r = read_one_line_file(fs, &contents);
831 sc = strstrip(contents);
833 r = write_string_file(fs, agent);
836 } else if (!streq(sc, agent))
841 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
847 r = read_one_line_file(fs, &contents);
851 sc = strstrip(contents);
852 if (streq(sc, "0")) {
853 r = write_string_file(fs, "1");
866 int cg_uninstall_release_agent(const char *controller) {
867 _cleanup_free_ char *fs = NULL;
870 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
874 r = write_string_file(fs, "0");
881 r = cg_get_path(controller, NULL, "release_agent", &fs);
885 r = write_string_file(fs, "");
892 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
893 _cleanup_fclose_ FILE *f = NULL;
894 pid_t pid = 0, self_pid;
900 r = cg_enumerate_processes(controller, path, &f);
902 return r == -ENOENT ? 1 : r;
906 while ((r = cg_read_pid(f, &pid)) > 0) {
908 if (ignore_self && pid == self_pid)
921 int cg_is_empty_by_spec(const char *spec, bool ignore_self) {
922 _cleanup_free_ char *controller = NULL, *path = NULL;
927 r = cg_split_spec(spec, &controller, &path);
931 return cg_is_empty(controller, path, ignore_self);
934 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
935 _cleanup_closedir_ DIR *d = NULL;
941 r = cg_is_empty(controller, path, ignore_self);
945 r = cg_enumerate_subgroups(controller, path, &d);
947 return r == -ENOENT ? 1 : r;
949 while ((r = cg_read_subgroup(d, &fn)) > 0) {
950 _cleanup_free_ char *p = NULL;
952 p = strjoin(path, "/", fn, NULL);
957 r = cg_is_empty_recursive(controller, p, ignore_self);
968 int cg_split_spec(const char *spec, char **controller, char **path) {
970 char *t = NULL, *u = NULL;
971 _cleanup_free_ char *v = NULL;
976 if (!path_is_safe(spec))
984 path_kill_slashes(t);
994 e = strchr(spec, ':');
996 if (!cg_controller_is_valid(spec, true))
1000 t = strdup(normalize_controller(spec));
1013 v = strndup(spec, e-spec);
1016 t = strdup(normalize_controller(v));
1019 if (!cg_controller_is_valid(t, true)) {
1029 if (!path_is_safe(u) ||
1030 !path_is_absolute(u)) {
1036 path_kill_slashes(u);
1051 int cg_join_spec(const char *controller, const char *path, char **spec) {
1057 controller = "systemd";
1059 if (!cg_controller_is_valid(controller, true))
1062 controller = normalize_controller(controller);
1065 if (!path_is_absolute(path))
1068 s = strjoin(controller, ":", path, NULL);
1072 path_kill_slashes(s + strlen(controller) + 1);
1078 int cg_mangle_path(const char *path, char **result) {
1079 _cleanup_free_ char *c = NULL, *p = NULL;
1086 /* First check if it already is a filesystem path */
1087 if (path_startswith(path, "/sys/fs/cgroup")) {
1093 path_kill_slashes(t);
1098 /* Otherwise treat it as cg spec */
1099 r = cg_split_spec(path, &c, &p);
1103 return cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1106 int cg_get_root_path(char **path) {
1112 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
1116 e = endswith(p, "/" SPECIAL_SYSTEM_SLICE);
1124 char **cg_shorten_controllers(char **controllers) {
1130 for (f = controllers, t = controllers; *f; f++) {
1134 p = normalize_controller(*f);
1136 if (streq(p, "systemd")) {
1141 if (!cg_controller_is_valid(p, true)) {
1142 log_warning("Controller %s is not valid, removing from controllers list.", p);
1147 r = check_hierarchy(p);
1149 log_debug("Controller %s is not available, removing from controllers list.", p);
1158 return strv_uniq(controllers);
1161 int cg_pid_get_path_shifted(pid_t pid, char **root, char **cgroup) {
1162 _cleanup_free_ char *cg_root = NULL;
1163 char *cg_process, *p;
1166 r = cg_get_root_path(&cg_root);
1170 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process);
1174 p = path_startswith(cg_process, cg_root);
1193 cg_process[p-cg_process] = 0;
1201 int cg_path_decode_unit(const char *cgroup, char **unit){
1207 e = strchrnul(cgroup, '/');
1208 c = strndupa(cgroup, e - cgroup);
1211 if (!unit_name_is_valid(c, false))
1222 static const char *skip_slices(const char *p) {
1223 /* Skips over all slice assignments */
1228 p += strspn(p, "/");
1230 n = strcspn(p, "/");
1231 if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0)
1238 int cg_path_get_unit(const char *path, char **unit) {
1244 e = skip_slices(path);
1246 return cg_path_decode_unit(e, unit);
1249 int cg_pid_get_unit(pid_t pid, char **unit) {
1250 _cleanup_free_ char *cgroup = NULL;
1255 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1259 return cg_path_get_unit(cgroup, unit);
1262 static const char *skip_session(const char *p) {
1267 p += strspn(p, "/");
1269 n = strcspn(p, "/");
1270 if (n <= 12 || memcmp(p, "session-", 8) != 0 || memcmp(p + n - 6, ".scope", 6) != 0)
1274 p += strspn(p, "/");
1279 int cg_path_get_user_unit(const char *path, char **unit) {
1285 /* We always have to parse the path from the beginning as unit
1286 * cgroups might have arbitrary child cgroups and we shouldn't get
1287 * confused by those */
1289 /* Skip slices, if there are any */
1290 e = skip_slices(path);
1292 /* Skip the session scope, require that there is one */
1293 e = skip_session(e);
1297 /* And skip more slices */
1300 return cg_path_decode_unit(e, unit);
1303 int cg_pid_get_user_unit(pid_t pid, char **unit) {
1304 _cleanup_free_ char *cgroup = NULL;
1309 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1313 return cg_path_get_user_unit(cgroup, unit);
1316 int cg_path_get_machine_name(const char *path, char **machine) {
1317 const char *e, *n, *x;
1324 /* Skip slices, if there are any */
1325 e = skip_slices(path);
1327 n = strchrnul(e, '/');
1331 s = strndupa(e, n - e);
1334 x = startswith(s, "machine-");
1337 if (!endswith(x, ".scope"))
1344 r = strndup(x, l - 6);
1352 int cg_pid_get_machine_name(pid_t pid, char **machine) {
1353 _cleanup_free_ char *cgroup = NULL;
1358 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1362 return cg_path_get_machine_name(cgroup, machine);
1365 int cg_path_get_session(const char *path, char **session) {
1366 const char *e, *n, *x;
1373 /* Skip slices, if there are any */
1374 e = skip_slices(path);
1376 n = strchrnul(e, '/');
1380 s = strndupa(e, n - e);
1383 x = startswith(s, "session-");
1386 if (!endswith(x, ".scope"))
1393 r = strndup(x, l - 6);
1401 int cg_pid_get_session(pid_t pid, char **session) {
1402 _cleanup_free_ char *cgroup = NULL;
1407 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1411 return cg_path_get_session(cgroup, session);
1414 int cg_path_get_owner_uid(const char *path, uid_t *uid) {
1415 _cleanup_free_ char *slice = NULL;
1423 r = cg_path_get_slice(path, &slice);
1427 e = startswith(slice, "user-");
1430 if (!endswith(slice, ".slice"))
1433 s = strndupa(e, strlen(e) - 6);
1437 return parse_uid(s, uid);
1440 int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
1441 _cleanup_free_ char *cgroup = NULL;
1446 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1450 return cg_path_get_owner_uid(cgroup, uid);
1453 int cg_path_get_slice(const char *p, char **slice) {
1454 const char *e = NULL;
1463 p += strspn(p, "/");
1465 n = strcspn(p, "/");
1466 if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0) {
1487 int cg_pid_get_slice(pid_t pid, char **slice) {
1488 _cleanup_free_ char *cgroup = NULL;
1493 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1497 return cg_path_get_slice(cgroup, slice);
1500 int cg_controller_from_attr(const char *attr, char **controller) {
1507 if (!filename_is_safe(attr))
1510 dot = strchr(attr, '.');
1516 c = strndup(attr, dot - attr);
1520 if (!cg_controller_is_valid(c, false)) {
1529 char *cg_escape(const char *p) {
1530 bool need_prefix = false;
1532 /* This implements very minimal escaping for names to be used
1533 * as file names in the cgroup tree: any name which might
1534 * conflict with a kernel name or is prefixed with '_' is
1535 * prefixed with a '_'. That way, when reading cgroup names it
1536 * is sufficient to remove a single prefixing underscore if
1539 /* The return value of this function (unlike cg_unescape())
1545 streq(p, "notify_on_release") ||
1546 streq(p, "release_agent") ||
1552 dot = strrchr(p, '.');
1555 if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0)
1560 n = strndupa(p, dot - p);
1562 if (check_hierarchy(n) >= 0)
1569 return strappend("_", p);
1574 char *cg_unescape(const char *p) {
1577 /* The return value of this function (unlike cg_escape())
1578 * doesn't need free()! */
1586 #define CONTROLLER_VALID \
1590 bool cg_controller_is_valid(const char *p, bool allow_named) {
1597 s = startswith(p, "name=");
1602 if (*p == 0 || *p == '_')
1605 for (t = p; *t; t++)
1606 if (!strchr(CONTROLLER_VALID, *t))
1609 if (t - p > FILENAME_MAX)
1615 int cg_slice_to_path(const char *unit, char **ret) {
1616 _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
1622 if (!unit_name_is_valid(unit, false))
1625 if (!endswith(unit, ".slice"))
1628 p = unit_name_to_prefix(unit);
1632 dash = strchr(p, '-');
1634 _cleanup_free_ char *escaped = NULL;
1635 char n[dash - p + sizeof(".slice")];
1637 strcpy(stpncpy(n, p, dash - p), ".slice");
1639 if (!unit_name_is_valid(n, false))
1642 escaped = cg_escape(n);
1646 if (!strextend(&s, escaped, "/", NULL))
1649 dash = strchr(dash+1, '-');
1652 e = cg_escape(unit);
1656 if (!strextend(&s, e, NULL))
1665 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
1666 _cleanup_free_ char *p = NULL;
1669 r = cg_get_path(controller, path, attribute, &p);
1673 return write_string_file(p, value);
1676 static const char mask_names[] =
1683 int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
1684 CGroupControllerMask bit = 1;
1688 /* This one will create a cgroup in our private tree, but also
1689 * duplicate it in the trees specified in mask, and remove it
1692 /* First create the cgroup in our own hierarchy. */
1693 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
1697 /* Then, do the same in the other hierarchies */
1698 NULSTR_FOREACH(n, mask_names) {
1701 else if (supported & bit)
1702 cg_trim(n, path, true);
1710 int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid) {
1711 CGroupControllerMask bit = 1;
1715 r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
1719 NULSTR_FOREACH(n, mask_names) {
1720 if (supported & bit)
1721 cg_attach_fallback(n, path, pid);
1729 int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids) {
1734 SET_FOREACH(pidp, pids, i) {
1735 pid_t pid = PTR_TO_LONG(pidp);
1738 q = cg_attach_everywhere(supported, path, pid);
1746 int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to) {
1747 CGroupControllerMask bit = 1;
1751 if (!path_equal(from, to)) {
1752 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
1757 NULSTR_FOREACH(n, mask_names) {
1758 if (supported & bit)
1759 cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, n, to, false, false);
1767 int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
1768 CGroupControllerMask bit = 1;
1772 r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
1776 NULSTR_FOREACH(n, mask_names) {
1777 if (supported & bit)
1778 cg_trim(n, path, delete_root);
1786 CGroupControllerMask cg_mask_supported(void) {
1787 CGroupControllerMask bit = 1, mask = 0;
1790 NULSTR_FOREACH(n, mask_names) {
1791 if (check_hierarchy(n) >= 0)