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 r
= cg_attach(cto
, pto
, pid
);
326 if (ret
>= 0 && r
!= -ESRCH
)
333 r
= set_put(s
, LONG_TO_PTR(pid
));
353 int cg_migrate_recursive(
361 _cleanup_closedir_
DIR *d
= NULL
;
370 ret
= cg_migrate(cfrom
, pfrom
, cto
, pto
, ignore_self
);
372 r
= cg_enumerate_subgroups(cfrom
, pfrom
, &d
);
374 if (ret
>= 0 && r
!= -ENOENT
)
380 while ((r
= cg_read_subgroup(d
, &fn
)) > 0) {
381 _cleanup_free_
char *p
= NULL
;
383 p
= strjoin(pfrom
, "/", fn
, NULL
);
392 r
= cg_migrate_recursive(cfrom
, p
, cto
, pto
, ignore_self
, rem
);
393 if (r
!= 0 && ret
>= 0)
397 if (r
< 0 && ret
>= 0)
401 r
= cg_rmdir(cfrom
, pfrom
);
402 if (r
< 0 && ret
>= 0 && r
!= -ENOENT
&& r
!= -EBUSY
)
409 int cg_migrate_recursive_fallback(
424 r
= cg_migrate_recursive(cfrom
, pfrom
, cto
, pto
, ignore_self
, rem
);
426 char prefix
[strlen(pto
) + 1];
428 /* This didn't work? Then let's try all prefixes of the destination */
430 PATH_FOREACH_PREFIX(prefix
, pto
) {
431 r
= cg_migrate_recursive(cfrom
, pfrom
, cto
, prefix
, ignore_self
, rem
);
440 static const char *normalize_controller(const char *controller
) {
444 if (startswith(controller
, "name="))
445 return controller
+ 5;
450 static int join_path(const char *controller
, const char *path
, const char *suffix
, char **fs
) {
453 if (!isempty(controller
)) {
454 if (!isempty(path
) && !isempty(suffix
))
455 t
= strjoin("/sys/fs/cgroup/", controller
, "/", path
, "/", suffix
, NULL
);
456 else if (!isempty(path
))
457 t
= strjoin("/sys/fs/cgroup/", controller
, "/", path
, NULL
);
458 else if (!isempty(suffix
))
459 t
= strjoin("/sys/fs/cgroup/", controller
, "/", suffix
, NULL
);
461 t
= strappend("/sys/fs/cgroup/", controller
);
463 if (!isempty(path
) && !isempty(suffix
))
464 t
= strjoin(path
, "/", suffix
, NULL
);
465 else if (!isempty(path
))
474 *fs
= path_kill_slashes(t
);
478 int cg_get_path(const char *controller
, const char *path
, const char *suffix
, char **fs
) {
480 static thread_local
bool good
= false;
484 if (controller
&& !cg_controller_is_valid(controller
))
487 if (_unlikely_(!good
)) {
490 r
= path_is_mount_point("/sys/fs/cgroup", 0);
496 /* Cache this to save a few stat()s */
500 p
= controller
? normalize_controller(controller
) : NULL
;
502 return join_path(p
, path
, suffix
, fs
);
505 static int check_hierarchy(const char *p
) {
510 if (!filename_is_valid(p
))
513 /* Check if this controller actually really exists */
514 cc
= strjoina("/sys/fs/cgroup/", p
);
515 if (laccess(cc
, F_OK
) < 0)
521 int cg_get_path_and_check(const char *controller
, const char *path
, const char *suffix
, char **fs
) {
527 if (!cg_controller_is_valid(controller
))
530 /* Normalize the controller syntax */
531 p
= normalize_controller(controller
);
533 /* Check if this controller actually really exists */
534 r
= check_hierarchy(p
);
538 return join_path(p
, path
, suffix
, fs
);
541 static int trim_cb(const char *path
, const struct stat
*sb
, int typeflag
, struct FTW
*ftwbuf
) {
546 if (typeflag
!= FTW_DP
)
549 if (ftwbuf
->level
< 1)
556 int cg_trim(const char *controller
, const char *path
, bool delete_root
) {
557 _cleanup_free_
char *fs
= NULL
;
562 r
= cg_get_path(controller
, path
, NULL
, &fs
);
567 if (nftw(fs
, trim_cb
, 64, FTW_DEPTH
|FTW_MOUNT
|FTW_PHYS
) != 0)
568 r
= errno
? -errno
: -EIO
;
571 if (rmdir(fs
) < 0 && errno
!= ENOENT
)
578 int cg_delete(const char *controller
, const char *path
) {
579 _cleanup_free_
char *parent
= NULL
;
584 r
= path_get_parent(path
, &parent
);
588 r
= cg_migrate_recursive(controller
, path
, controller
, parent
, false, true);
589 return r
== -ENOENT
? 0 : r
;
592 int cg_create(const char *controller
, const char *path
) {
593 _cleanup_free_
char *fs
= NULL
;
596 r
= cg_get_path_and_check(controller
, path
, NULL
, &fs
);
600 r
= mkdir_parents(fs
, 0755);
604 if (mkdir(fs
, 0755) < 0) {
615 int cg_create_and_attach(const char *controller
, const char *path
, pid_t pid
) {
620 r
= cg_create(controller
, path
);
624 q
= cg_attach(controller
, path
, pid
);
628 /* This does not remove the cgroup on failure */
632 int cg_attach(const char *controller
, const char *path
, pid_t pid
) {
633 _cleanup_free_
char *fs
= NULL
;
634 char c
[DECIMAL_STR_MAX(pid_t
) + 2];
640 r
= cg_get_path_and_check(controller
, path
, "cgroup.procs", &fs
);
647 snprintf(c
, sizeof(c
), PID_FMT
"\n", pid
);
649 return write_string_file(fs
, c
, 0);
652 int cg_attach_fallback(const char *controller
, const char *path
, pid_t pid
) {
659 r
= cg_attach(controller
, path
, pid
);
661 char prefix
[strlen(path
) + 1];
663 /* This didn't work? Then let's try all prefixes of
666 PATH_FOREACH_PREFIX(prefix
, path
) {
667 r
= cg_attach(controller
, prefix
, pid
);
676 int cg_set_group_access(
677 const char *controller
,
683 _cleanup_free_
char *fs
= NULL
;
688 if (mode
!= MODE_INVALID
)
691 r
= cg_get_path(controller
, path
, NULL
, &fs
);
695 return chmod_and_chown(fs
, mode
, uid
, gid
);
698 int cg_set_task_access(
699 const char *controller
,
705 _cleanup_free_
char *fs
= NULL
, *procs
= NULL
;
710 if (mode
== MODE_INVALID
&& uid
== UID_INVALID
&& gid
== GID_INVALID
)
713 if (mode
!= MODE_INVALID
)
716 r
= cg_get_path(controller
, path
, "cgroup.procs", &fs
);
720 r
= chmod_and_chown(fs
, mode
, uid
, gid
);
724 /* Compatibility, Always keep values for "tasks" in sync with
726 r
= cg_get_path(controller
, path
, "tasks", &procs
);
730 return chmod_and_chown(procs
, mode
, uid
, gid
);
733 int cg_pid_get_path(const char *controller
, pid_t pid
, char **path
) {
734 _cleanup_fclose_
FILE *f
= NULL
;
743 if (!cg_controller_is_valid(controller
))
746 controller
= normalize_controller(controller
);
748 controller
= SYSTEMD_CGROUP_CONTROLLER
;
750 fs
= procfs_file_alloca(pid
, "cgroup");
754 return errno
== ENOENT
? -ESRCH
: -errno
;
756 cs
= strlen(controller
);
758 FOREACH_LINE(line
, f
, return -errno
) {
761 const char *word
, *state
;
766 l
= strchr(line
, ':');
777 FOREACH_WORD_SEPARATOR(word
, k
, l
, ",", state
) {
779 if (k
== cs
&& memcmp(word
, controller
, cs
) == 0) {
785 memcmp(word
, "name=", 5) == 0 &&
786 memcmp(word
+5, controller
, cs
) == 0) {
806 int cg_install_release_agent(const char *controller
, const char *agent
) {
807 _cleanup_free_
char *fs
= NULL
, *contents
= NULL
;
813 r
= cg_get_path(controller
, NULL
, "release_agent", &fs
);
817 r
= read_one_line_file(fs
, &contents
);
821 sc
= strstrip(contents
);
823 r
= write_string_file(fs
, agent
, 0);
826 } else if (!streq(sc
, agent
))
830 r
= cg_get_path(controller
, NULL
, "notify_on_release", &fs
);
834 contents
= mfree(contents
);
835 r
= read_one_line_file(fs
, &contents
);
839 sc
= strstrip(contents
);
840 if (streq(sc
, "0")) {
841 r
= write_string_file(fs
, "1", 0);
854 int cg_uninstall_release_agent(const char *controller
) {
855 _cleanup_free_
char *fs
= NULL
;
858 r
= cg_get_path(controller
, NULL
, "notify_on_release", &fs
);
862 r
= write_string_file(fs
, "0", 0);
868 r
= cg_get_path(controller
, NULL
, "release_agent", &fs
);
872 r
= write_string_file(fs
, "", 0);
879 int cg_is_empty(const char *controller
, const char *path
, bool ignore_self
) {
880 _cleanup_fclose_
FILE *f
= NULL
;
881 pid_t pid
= 0, self_pid
;
887 r
= cg_enumerate_processes(controller
, path
, &f
);
889 return r
== -ENOENT
? 1 : r
;
893 while ((r
= cg_read_pid(f
, &pid
)) > 0) {
895 if (ignore_self
&& pid
== self_pid
)
908 int cg_is_empty_recursive(const char *controller
, const char *path
, bool ignore_self
) {
909 _cleanup_closedir_
DIR *d
= NULL
;
915 r
= cg_is_empty(controller
, path
, ignore_self
);
919 r
= cg_enumerate_subgroups(controller
, path
, &d
);
921 return r
== -ENOENT
? 1 : r
;
923 while ((r
= cg_read_subgroup(d
, &fn
)) > 0) {
924 _cleanup_free_
char *p
= NULL
;
926 p
= strjoin(path
, "/", fn
, NULL
);
931 r
= cg_is_empty_recursive(controller
, p
, ignore_self
);
942 int cg_split_spec(const char *spec
, char **controller
, char **path
) {
944 char *t
= NULL
, *u
= NULL
;
945 _cleanup_free_
char *v
= NULL
;
950 if (!path_is_safe(spec
))
958 *path
= path_kill_slashes(t
);
967 e
= strchr(spec
, ':');
969 if (!cg_controller_is_valid(spec
))
973 t
= strdup(normalize_controller(spec
));
986 v
= strndup(spec
, e
-spec
);
989 t
= strdup(normalize_controller(v
));
992 if (!cg_controller_is_valid(t
)) {
997 if (streq(e
+1, "")) {
1010 if (!path_is_safe(u
) ||
1011 !path_is_absolute(u
)) {
1017 path_kill_slashes(u
);
1033 int cg_mangle_path(const char *path
, char **result
) {
1034 _cleanup_free_
char *c
= NULL
, *p
= NULL
;
1041 /* First, check if it already is a filesystem path */
1042 if (path_startswith(path
, "/sys/fs/cgroup")) {
1048 *result
= path_kill_slashes(t
);
1052 /* Otherwise, treat it as cg spec */
1053 r
= cg_split_spec(path
, &c
, &p
);
1057 return cg_get_path(c
? c
: SYSTEMD_CGROUP_CONTROLLER
, p
? p
: "/", NULL
, result
);
1060 int cg_get_root_path(char **path
) {
1066 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, 1, &p
);
1070 e
= endswith(p
, "/" SPECIAL_SYSTEM_SLICE
);
1078 int cg_shift_path(const char *cgroup
, const char *root
, const char **shifted
) {
1079 _cleanup_free_
char *rt
= NULL
;
1087 /* If the root was specified let's use that, otherwise
1088 * let's determine it from PID 1 */
1090 r
= cg_get_root_path(&rt
);
1097 p
= path_startswith(cgroup
, root
);
1106 int cg_pid_get_path_shifted(pid_t pid
, const char *root
, char **cgroup
) {
1107 _cleanup_free_
char *raw
= NULL
;
1114 r
= cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &raw
);
1118 r
= cg_shift_path(raw
, root
, &c
);
1138 int cg_path_decode_unit(const char *cgroup
, char **unit
){
1145 n
= strcspn(cgroup
, "/");
1149 c
= strndupa(cgroup
, n
);
1152 if (!unit_name_is_valid(c
, UNIT_NAME_PLAIN
|UNIT_NAME_INSTANCE
))
1163 static bool valid_slice_name(const char *p
, size_t n
) {
1168 if (n
< strlen("x.slice"))
1171 if (memcmp(p
+ n
- 6, ".slice", 6) == 0) {
1177 c
= cg_unescape(buf
);
1179 return unit_name_is_valid(c
, UNIT_NAME_PLAIN
);
1185 static const char *skip_slices(const char *p
) {
1188 /* Skips over all slice assignments */
1193 p
+= strspn(p
, "/");
1195 n
= strcspn(p
, "/");
1196 if (!valid_slice_name(p
, n
))
1203 int cg_path_get_unit(const char *path
, char **ret
) {
1211 e
= skip_slices(path
);
1213 r
= cg_path_decode_unit(e
, &unit
);
1217 /* We skipped over the slices, don't accept any now */
1218 if (endswith(unit
, ".slice")) {
1227 int cg_pid_get_unit(pid_t pid
, char **unit
) {
1228 _cleanup_free_
char *cgroup
= NULL
;
1233 r
= cg_pid_get_path_shifted(pid
, NULL
, &cgroup
);
1237 return cg_path_get_unit(cgroup
, unit
);
1241 * Skip session-*.scope, but require it to be there.
1243 static const char *skip_session(const char *p
) {
1249 p
+= strspn(p
, "/");
1251 n
= strcspn(p
, "/");
1252 if (n
< strlen("session-x.scope"))
1255 if (memcmp(p
, "session-", 8) == 0 && memcmp(p
+ n
- 6, ".scope", 6) == 0) {
1256 char buf
[n
- 8 - 6 + 1];
1258 memcpy(buf
, p
+ 8, n
- 8 - 6);
1261 /* Note that session scopes never need unescaping,
1262 * since they cannot conflict with the kernel's own
1263 * names, hence we don't need to call cg_unescape()
1266 if (!session_id_valid(buf
))
1270 p
+= strspn(p
, "/");
1278 * Skip user@*.service, but require it to be there.
1280 static const char *skip_user_manager(const char *p
) {
1286 p
+= strspn(p
, "/");
1288 n
= strcspn(p
, "/");
1289 if (n
< strlen("user@x.service"))
1292 if (memcmp(p
, "user@", 5) == 0 && memcmp(p
+ n
- 8, ".service", 8) == 0) {
1293 char buf
[n
- 5 - 8 + 1];
1295 memcpy(buf
, p
+ 5, n
- 5 - 8);
1298 /* Note that user manager services never need unescaping,
1299 * since they cannot conflict with the kernel's own
1300 * names, hence we don't need to call cg_unescape()
1303 if (parse_uid(buf
, NULL
) < 0)
1307 p
+= strspn(p
, "/");
1315 static const char *skip_user_prefix(const char *path
) {
1320 /* Skip slices, if there are any */
1321 e
= skip_slices(path
);
1323 /* Skip the user manager, if it's in the path now... */
1324 t
= skip_user_manager(e
);
1328 /* Alternatively skip the user session if it is in the path... */
1329 return skip_session(e
);
1332 int cg_path_get_user_unit(const char *path
, char **ret
) {
1338 t
= skip_user_prefix(path
);
1342 /* And from here on it looks pretty much the same as for a
1343 * system unit, hence let's use the same parser from here
1345 return cg_path_get_unit(t
, ret
);
1348 int cg_pid_get_user_unit(pid_t pid
, char **unit
) {
1349 _cleanup_free_
char *cgroup
= NULL
;
1354 r
= cg_pid_get_path_shifted(pid
, NULL
, &cgroup
);
1358 return cg_path_get_user_unit(cgroup
, unit
);
1361 int cg_path_get_machine_name(const char *path
, char **machine
) {
1362 _cleanup_free_
char *u
= NULL
, *sl
= NULL
;
1365 r
= cg_path_get_unit(path
, &u
);
1369 sl
= strjoin("/run/systemd/machines/unit:", u
, NULL
);
1373 return readlink_malloc(sl
, machine
);
1376 int cg_pid_get_machine_name(pid_t pid
, char **machine
) {
1377 _cleanup_free_
char *cgroup
= NULL
;
1382 r
= cg_pid_get_path_shifted(pid
, NULL
, &cgroup
);
1386 return cg_path_get_machine_name(cgroup
, machine
);
1389 int cg_path_get_session(const char *path
, char **session
) {
1390 _cleanup_free_
char *unit
= NULL
;
1396 r
= cg_path_get_unit(path
, &unit
);
1400 start
= startswith(unit
, "session-");
1403 end
= endswith(start
, ".scope");
1408 if (!session_id_valid(start
))
1424 int cg_pid_get_session(pid_t pid
, char **session
) {
1425 _cleanup_free_
char *cgroup
= NULL
;
1428 r
= cg_pid_get_path_shifted(pid
, NULL
, &cgroup
);
1432 return cg_path_get_session(cgroup
, session
);
1435 int cg_path_get_owner_uid(const char *path
, uid_t
*uid
) {
1436 _cleanup_free_
char *slice
= NULL
;
1442 r
= cg_path_get_slice(path
, &slice
);
1446 start
= startswith(slice
, "user-");
1449 end
= endswith(start
, ".slice");
1454 if (parse_uid(start
, uid
) < 0)
1460 int cg_pid_get_owner_uid(pid_t pid
, uid_t
*uid
) {
1461 _cleanup_free_
char *cgroup
= NULL
;
1464 r
= cg_pid_get_path_shifted(pid
, NULL
, &cgroup
);
1468 return cg_path_get_owner_uid(cgroup
, uid
);
1471 int cg_path_get_slice(const char *p
, char **slice
) {
1472 const char *e
= NULL
;
1477 /* Finds the right-most slice unit from the beginning, but
1478 * stops before we come to the first non-slice unit. */
1483 p
+= strspn(p
, "/");
1485 n
= strcspn(p
, "/");
1486 if (!valid_slice_name(p
, n
)) {
1491 s
= strdup("-.slice");
1499 return cg_path_decode_unit(e
, slice
);
1507 int cg_pid_get_slice(pid_t pid
, char **slice
) {
1508 _cleanup_free_
char *cgroup
= NULL
;
1513 r
= cg_pid_get_path_shifted(pid
, NULL
, &cgroup
);
1517 return cg_path_get_slice(cgroup
, slice
);
1520 int cg_path_get_user_slice(const char *p
, char **slice
) {
1525 t
= skip_user_prefix(p
);
1529 /* And now it looks pretty much the same as for a system
1530 * slice, so let's just use the same parser from here on. */
1531 return cg_path_get_slice(t
, slice
);
1534 int cg_pid_get_user_slice(pid_t pid
, char **slice
) {
1535 _cleanup_free_
char *cgroup
= NULL
;
1540 r
= cg_pid_get_path_shifted(pid
, NULL
, &cgroup
);
1544 return cg_path_get_user_slice(cgroup
, slice
);
1547 char *cg_escape(const char *p
) {
1548 bool need_prefix
= false;
1550 /* This implements very minimal escaping for names to be used
1551 * as file names in the cgroup tree: any name which might
1552 * conflict with a kernel name or is prefixed with '_' is
1553 * prefixed with a '_'. That way, when reading cgroup names it
1554 * is sufficient to remove a single prefixing underscore if
1557 /* The return value of this function (unlike cg_unescape())
1563 streq(p
, "notify_on_release") ||
1564 streq(p
, "release_agent") ||
1570 dot
= strrchr(p
, '.');
1573 if (dot
- p
== 6 && memcmp(p
, "cgroup", 6) == 0)
1578 n
= strndupa(p
, dot
- p
);
1580 if (check_hierarchy(n
) >= 0)
1587 return strappend("_", p
);
1592 char *cg_unescape(const char *p
) {
1595 /* The return value of this function (unlike cg_escape())
1596 * doesn't need free()! */
1604 #define CONTROLLER_VALID \
1608 bool cg_controller_is_valid(const char *p
) {
1614 s
= startswith(p
, "name=");
1618 if (*p
== 0 || *p
== '_')
1621 for (t
= p
; *t
; t
++)
1622 if (!strchr(CONTROLLER_VALID
, *t
))
1625 if (t
- p
> FILENAME_MAX
)
1631 int cg_slice_to_path(const char *unit
, char **ret
) {
1632 _cleanup_free_
char *p
= NULL
, *s
= NULL
, *e
= NULL
;
1639 if (streq(unit
, "-.slice")) {
1649 if (!unit_name_is_valid(unit
, UNIT_NAME_PLAIN
))
1652 if (!endswith(unit
, ".slice"))
1655 r
= unit_name_to_prefix(unit
, &p
);
1659 dash
= strchr(p
, '-');
1661 /* Don't allow initial dashes */
1666 _cleanup_free_
char *escaped
= NULL
;
1667 char n
[dash
- p
+ sizeof(".slice")];
1669 /* Don't allow trailing or double dashes */
1670 if (dash
[1] == 0 || dash
[1] == '-')
1673 strcpy(stpncpy(n
, p
, dash
- p
), ".slice");
1674 if (!unit_name_is_valid(n
, UNIT_NAME_PLAIN
))
1677 escaped
= cg_escape(n
);
1681 if (!strextend(&s
, escaped
, "/", NULL
))
1684 dash
= strchr(dash
+1, '-');
1687 e
= cg_escape(unit
);
1691 if (!strextend(&s
, e
, NULL
))
1700 int cg_set_attribute(const char *controller
, const char *path
, const char *attribute
, const char *value
) {
1701 _cleanup_free_
char *p
= NULL
;
1704 r
= cg_get_path(controller
, path
, attribute
, &p
);
1708 return write_string_file(p
, value
, 0);
1711 int cg_get_attribute(const char *controller
, const char *path
, const char *attribute
, char **ret
) {
1712 _cleanup_free_
char *p
= NULL
;
1715 r
= cg_get_path(controller
, path
, attribute
, &p
);
1719 return read_one_line_file(p
, ret
);
1722 static const char mask_names
[] =
1729 int cg_create_everywhere(CGroupControllerMask supported
, CGroupControllerMask mask
, const char *path
) {
1730 CGroupControllerMask bit
= 1;
1734 /* This one will create a cgroup in our private tree, but also
1735 * duplicate it in the trees specified in mask, and remove it
1738 /* First create the cgroup in our own hierarchy. */
1739 r
= cg_create(SYSTEMD_CGROUP_CONTROLLER
, path
);
1743 /* Then, do the same in the other hierarchies */
1744 NULSTR_FOREACH(n
, mask_names
) {
1747 else if (supported
& bit
)
1748 cg_trim(n
, path
, true);
1756 int cg_attach_everywhere(CGroupControllerMask supported
, const char *path
, pid_t pid
, cg_migrate_callback_t path_callback
, void *userdata
) {
1757 CGroupControllerMask bit
= 1;
1761 r
= cg_attach(SYSTEMD_CGROUP_CONTROLLER
, path
, pid
);
1765 NULSTR_FOREACH(n
, mask_names
) {
1767 if (supported
& bit
) {
1768 const char *p
= NULL
;
1771 p
= path_callback(bit
, userdata
);
1776 cg_attach_fallback(n
, p
, pid
);
1785 int cg_attach_many_everywhere(CGroupControllerMask supported
, const char *path
, Set
* pids
, cg_migrate_callback_t path_callback
, void *userdata
) {
1790 SET_FOREACH(pidp
, pids
, i
) {
1791 pid_t pid
= PTR_TO_LONG(pidp
);
1794 q
= cg_attach_everywhere(supported
, path
, pid
, path_callback
, userdata
);
1802 int cg_migrate_everywhere(CGroupControllerMask supported
, const char *from
, const char *to
, cg_migrate_callback_t to_callback
, void *userdata
) {
1803 CGroupControllerMask bit
= 1;
1807 if (!path_equal(from
, to
)) {
1808 r
= cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER
, from
, SYSTEMD_CGROUP_CONTROLLER
, to
, false, true);
1813 NULSTR_FOREACH(n
, mask_names
) {
1814 if (supported
& bit
) {
1815 const char *p
= NULL
;
1818 p
= to_callback(bit
, userdata
);
1823 cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER
, to
, n
, p
, false, false);
1832 int cg_trim_everywhere(CGroupControllerMask supported
, const char *path
, bool delete_root
) {
1833 CGroupControllerMask bit
= 1;
1837 r
= cg_trim(SYSTEMD_CGROUP_CONTROLLER
, path
, delete_root
);
1841 NULSTR_FOREACH(n
, mask_names
) {
1842 if (supported
& bit
)
1843 cg_trim(n
, path
, delete_root
);
1851 CGroupControllerMask
cg_mask_supported(void) {
1852 CGroupControllerMask bit
= 1, mask
= 0;
1855 NULSTR_FOREACH(n
, mask_names
) {
1856 if (check_hierarchy(n
) >= 0)
1865 int cg_kernel_controllers(Set
*controllers
) {
1866 _cleanup_fclose_
FILE *f
= NULL
;
1870 assert(controllers
);
1872 f
= fopen("/proc/cgroups", "re");
1874 if (errno
== ENOENT
)
1879 /* Ignore the header line */
1880 (void) fgets(buf
, sizeof(buf
), f
);
1887 if (fscanf(f
, "%ms %*i %*i %i", &controller
, &enabled
) != 2) {
1892 if (ferror(f
) && errno
)
1903 if (!filename_is_valid(controller
)) {
1908 r
= set_consume(controllers
, controller
);