]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/cgroup-util.c
Merge branch 'hostnamectl-dot-v2'
[thirdparty/systemd.git] / src / basic / cgroup-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <errno.h>
23 #include <unistd.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <dirent.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <ftw.h>
31
32 #include "cgroup-util.h"
33 #include "set.h"
34 #include "macro.h"
35 #include "util.h"
36 #include "formats-util.h"
37 #include "process-util.h"
38 #include "path-util.h"
39 #include "unit-name.h"
40 #include "fileio.h"
41 #include "special.h"
42 #include "mkdir.h"
43 #include "login-util.h"
44
45 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
46 _cleanup_free_ char *fs = NULL;
47 FILE *f;
48 int r;
49
50 assert(_f);
51
52 r = cg_get_path(controller, path, "cgroup.procs", &fs);
53 if (r < 0)
54 return r;
55
56 f = fopen(fs, "re");
57 if (!f)
58 return -errno;
59
60 *_f = f;
61 return 0;
62 }
63
64 int cg_read_pid(FILE *f, pid_t *_pid) {
65 unsigned long ul;
66
67 /* Note that the cgroup.procs might contain duplicates! See
68 * cgroups.txt for details. */
69
70 assert(f);
71 assert(_pid);
72
73 errno = 0;
74 if (fscanf(f, "%lu", &ul) != 1) {
75
76 if (feof(f))
77 return 0;
78
79 return errno ? -errno : -EIO;
80 }
81
82 if (ul <= 0)
83 return -EIO;
84
85 *_pid = (pid_t) ul;
86 return 1;
87 }
88
89 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
90 _cleanup_free_ char *fs = NULL;
91 int r;
92 DIR *d;
93
94 assert(_d);
95
96 /* This is not recursive! */
97
98 r = cg_get_path(controller, path, NULL, &fs);
99 if (r < 0)
100 return r;
101
102 d = opendir(fs);
103 if (!d)
104 return -errno;
105
106 *_d = d;
107 return 0;
108 }
109
110 int cg_read_subgroup(DIR *d, char **fn) {
111 struct dirent *de;
112
113 assert(d);
114 assert(fn);
115
116 FOREACH_DIRENT(de, d, return -errno) {
117 char *b;
118
119 if (de->d_type != DT_DIR)
120 continue;
121
122 if (streq(de->d_name, ".") ||
123 streq(de->d_name, ".."))
124 continue;
125
126 b = strdup(de->d_name);
127 if (!b)
128 return -ENOMEM;
129
130 *fn = b;
131 return 1;
132 }
133
134 return 0;
135 }
136
137 int cg_rmdir(const char *controller, const char *path) {
138 _cleanup_free_ char *p = NULL;
139 int r;
140
141 r = cg_get_path(controller, path, NULL, &p);
142 if (r < 0)
143 return r;
144
145 r = rmdir(p);
146 if (r < 0 && errno != ENOENT)
147 return -errno;
148
149 return 0;
150 }
151
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;
154 bool done = false;
155 int r, ret = 0;
156 pid_t my_pid;
157
158 assert(sig >= 0);
159
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 */
163
164 if (!s) {
165 s = allocated_set = set_new(NULL);
166 if (!s)
167 return -ENOMEM;
168 }
169
170 my_pid = getpid();
171
172 do {
173 _cleanup_fclose_ FILE *f = NULL;
174 pid_t pid = 0;
175 done = true;
176
177 r = cg_enumerate_processes(controller, path, &f);
178 if (r < 0) {
179 if (ret >= 0 && r != -ENOENT)
180 return r;
181
182 return ret;
183 }
184
185 while ((r = cg_read_pid(f, &pid)) > 0) {
186
187 if (ignore_self && pid == my_pid)
188 continue;
189
190 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
191 continue;
192
193 /* If we haven't killed this process yet, kill
194 * it */
195 if (kill(pid, sig) < 0) {
196 if (ret >= 0 && errno != ESRCH)
197 ret = -errno;
198 } else {
199 if (sigcont && sig != SIGKILL)
200 kill(pid, SIGCONT);
201
202 if (ret == 0)
203 ret = 1;
204 }
205
206 done = false;
207
208 r = set_put(s, LONG_TO_PTR(pid));
209 if (r < 0) {
210 if (ret >= 0)
211 return r;
212
213 return ret;
214 }
215 }
216
217 if (r < 0) {
218 if (ret >= 0)
219 return r;
220
221 return ret;
222 }
223
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. */
227
228 } while (!done);
229
230 return ret;
231 }
232
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;
236 int r, ret = 0;
237 char *fn;
238
239 assert(path);
240 assert(sig >= 0);
241
242 if (!s) {
243 s = allocated_set = set_new(NULL);
244 if (!s)
245 return -ENOMEM;
246 }
247
248 ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
249
250 r = cg_enumerate_subgroups(controller, path, &d);
251 if (r < 0) {
252 if (ret >= 0 && r != -ENOENT)
253 return r;
254
255 return ret;
256 }
257
258 while ((r = cg_read_subgroup(d, &fn)) > 0) {
259 _cleanup_free_ char *p = NULL;
260
261 p = strjoin(path, "/", fn, NULL);
262 free(fn);
263 if (!p)
264 return -ENOMEM;
265
266 r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
267 if (ret >= 0 && r != 0)
268 ret = r;
269 }
270
271 if (ret >= 0 && r < 0)
272 ret = r;
273
274 if (rem) {
275 r = cg_rmdir(controller, path);
276 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
277 return r;
278 }
279
280 return ret;
281 }
282
283 int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) {
284 bool done = false;
285 _cleanup_set_free_ Set *s = NULL;
286 int r, ret = 0;
287 pid_t my_pid;
288
289 assert(cfrom);
290 assert(pfrom);
291 assert(cto);
292 assert(pto);
293
294 s = set_new(NULL);
295 if (!s)
296 return -ENOMEM;
297
298 my_pid = getpid();
299
300 do {
301 _cleanup_fclose_ FILE *f = NULL;
302 pid_t pid = 0;
303 done = true;
304
305 r = cg_enumerate_processes(cfrom, pfrom, &f);
306 if (r < 0) {
307 if (ret >= 0 && r != -ENOENT)
308 return r;
309
310 return ret;
311 }
312
313 while ((r = cg_read_pid(f, &pid)) > 0) {
314
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)
319 continue;
320
321 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
322 continue;
323
324 r = cg_attach(cto, pto, pid);
325 if (r < 0) {
326 if (ret >= 0 && r != -ESRCH)
327 ret = r;
328 } else if (ret == 0)
329 ret = 1;
330
331 done = false;
332
333 r = set_put(s, LONG_TO_PTR(pid));
334 if (r < 0) {
335 if (ret >= 0)
336 return r;
337
338 return ret;
339 }
340 }
341
342 if (r < 0) {
343 if (ret >= 0)
344 return r;
345
346 return ret;
347 }
348 } while (!done);
349
350 return ret;
351 }
352
353 int cg_migrate_recursive(
354 const char *cfrom,
355 const char *pfrom,
356 const char *cto,
357 const char *pto,
358 bool ignore_self,
359 bool rem) {
360
361 _cleanup_closedir_ DIR *d = NULL;
362 int r, ret = 0;
363 char *fn;
364
365 assert(cfrom);
366 assert(pfrom);
367 assert(cto);
368 assert(pto);
369
370 ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self);
371
372 r = cg_enumerate_subgroups(cfrom, pfrom, &d);
373 if (r < 0) {
374 if (ret >= 0 && r != -ENOENT)
375 return r;
376
377 return ret;
378 }
379
380 while ((r = cg_read_subgroup(d, &fn)) > 0) {
381 _cleanup_free_ char *p = NULL;
382
383 p = strjoin(pfrom, "/", fn, NULL);
384 free(fn);
385 if (!p) {
386 if (ret >= 0)
387 return -ENOMEM;
388
389 return ret;
390 }
391
392 r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem);
393 if (r != 0 && ret >= 0)
394 ret = r;
395 }
396
397 if (r < 0 && ret >= 0)
398 ret = r;
399
400 if (rem) {
401 r = cg_rmdir(cfrom, pfrom);
402 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
403 return r;
404 }
405
406 return ret;
407 }
408
409 int cg_migrate_recursive_fallback(
410 const char *cfrom,
411 const char *pfrom,
412 const char *cto,
413 const char *pto,
414 bool ignore_self,
415 bool rem) {
416
417 int r;
418
419 assert(cfrom);
420 assert(pfrom);
421 assert(cto);
422 assert(pto);
423
424 r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem);
425 if (r < 0) {
426 char prefix[strlen(pto) + 1];
427
428 /* This didn't work? Then let's try all prefixes of the destination */
429
430 PATH_FOREACH_PREFIX(prefix, pto) {
431 r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
432 if (r >= 0)
433 break;
434 }
435 }
436
437 return 0;
438 }
439
440 static const char *normalize_controller(const char *controller) {
441
442 assert(controller);
443
444 if (startswith(controller, "name="))
445 return controller + 5;
446 else
447 return controller;
448 }
449
450 static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
451 char *t = NULL;
452
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);
460 else
461 t = strappend("/sys/fs/cgroup/", controller);
462 } else {
463 if (!isempty(path) && !isempty(suffix))
464 t = strjoin(path, "/", suffix, NULL);
465 else if (!isempty(path))
466 t = strdup(path);
467 else
468 return -EINVAL;
469 }
470
471 if (!t)
472 return -ENOMEM;
473
474 *fs = path_kill_slashes(t);
475 return 0;
476 }
477
478 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
479 const char *p;
480 static thread_local bool good = false;
481
482 assert(fs);
483
484 if (controller && !cg_controller_is_valid(controller))
485 return -EINVAL;
486
487 if (_unlikely_(!good)) {
488 int r;
489
490 r = path_is_mount_point("/sys/fs/cgroup", 0);
491 if (r < 0)
492 return r;
493 if (r == 0)
494 return -ENOENT;
495
496 /* Cache this to save a few stat()s */
497 good = true;
498 }
499
500 p = controller ? normalize_controller(controller) : NULL;
501
502 return join_path(p, path, suffix, fs);
503 }
504
505 static int check_hierarchy(const char *p) {
506 const char *cc;
507
508 assert(p);
509
510 if (!filename_is_valid(p))
511 return 0;
512
513 /* Check if this controller actually really exists */
514 cc = strjoina("/sys/fs/cgroup/", p);
515 if (laccess(cc, F_OK) < 0)
516 return -errno;
517
518 return 0;
519 }
520
521 int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
522 const char *p;
523 int r;
524
525 assert(fs);
526
527 if (!cg_controller_is_valid(controller))
528 return -EINVAL;
529
530 /* Normalize the controller syntax */
531 p = normalize_controller(controller);
532
533 /* Check if this controller actually really exists */
534 r = check_hierarchy(p);
535 if (r < 0)
536 return r;
537
538 return join_path(p, path, suffix, fs);
539 }
540
541 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
542 assert(path);
543 assert(sb);
544 assert(ftwbuf);
545
546 if (typeflag != FTW_DP)
547 return 0;
548
549 if (ftwbuf->level < 1)
550 return 0;
551
552 rmdir(path);
553 return 0;
554 }
555
556 int cg_trim(const char *controller, const char *path, bool delete_root) {
557 _cleanup_free_ char *fs = NULL;
558 int r = 0;
559
560 assert(path);
561
562 r = cg_get_path(controller, path, NULL, &fs);
563 if (r < 0)
564 return r;
565
566 errno = 0;
567 if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0)
568 r = errno ? -errno : -EIO;
569
570 if (delete_root) {
571 if (rmdir(fs) < 0 && errno != ENOENT)
572 return -errno;
573 }
574
575 return r;
576 }
577
578 int cg_delete(const char *controller, const char *path) {
579 _cleanup_free_ char *parent = NULL;
580 int r;
581
582 assert(path);
583
584 r = path_get_parent(path, &parent);
585 if (r < 0)
586 return r;
587
588 r = cg_migrate_recursive(controller, path, controller, parent, false, true);
589 return r == -ENOENT ? 0 : r;
590 }
591
592 int cg_create(const char *controller, const char *path) {
593 _cleanup_free_ char *fs = NULL;
594 int r;
595
596 r = cg_get_path_and_check(controller, path, NULL, &fs);
597 if (r < 0)
598 return r;
599
600 r = mkdir_parents(fs, 0755);
601 if (r < 0)
602 return r;
603
604 if (mkdir(fs, 0755) < 0) {
605
606 if (errno == EEXIST)
607 return 0;
608
609 return -errno;
610 }
611
612 return 1;
613 }
614
615 int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
616 int r, q;
617
618 assert(pid >= 0);
619
620 r = cg_create(controller, path);
621 if (r < 0)
622 return r;
623
624 q = cg_attach(controller, path, pid);
625 if (q < 0)
626 return q;
627
628 /* This does not remove the cgroup on failure */
629 return r;
630 }
631
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];
635 int r;
636
637 assert(path);
638 assert(pid >= 0);
639
640 r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
641 if (r < 0)
642 return r;
643
644 if (pid == 0)
645 pid = getpid();
646
647 snprintf(c, sizeof(c), PID_FMT"\n", pid);
648
649 return write_string_file(fs, c, 0);
650 }
651
652 int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
653 int r;
654
655 assert(controller);
656 assert(path);
657 assert(pid >= 0);
658
659 r = cg_attach(controller, path, pid);
660 if (r < 0) {
661 char prefix[strlen(path) + 1];
662
663 /* This didn't work? Then let's try all prefixes of
664 * the destination */
665
666 PATH_FOREACH_PREFIX(prefix, path) {
667 r = cg_attach(controller, prefix, pid);
668 if (r >= 0)
669 break;
670 }
671 }
672
673 return 0;
674 }
675
676 int cg_set_group_access(
677 const char *controller,
678 const char *path,
679 mode_t mode,
680 uid_t uid,
681 gid_t gid) {
682
683 _cleanup_free_ char *fs = NULL;
684 int r;
685
686 assert(path);
687
688 if (mode != MODE_INVALID)
689 mode &= 0777;
690
691 r = cg_get_path(controller, path, NULL, &fs);
692 if (r < 0)
693 return r;
694
695 return chmod_and_chown(fs, mode, uid, gid);
696 }
697
698 int cg_set_task_access(
699 const char *controller,
700 const char *path,
701 mode_t mode,
702 uid_t uid,
703 gid_t gid) {
704
705 _cleanup_free_ char *fs = NULL, *procs = NULL;
706 int r;
707
708 assert(path);
709
710 if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
711 return 0;
712
713 if (mode != MODE_INVALID)
714 mode &= 0666;
715
716 r = cg_get_path(controller, path, "cgroup.procs", &fs);
717 if (r < 0)
718 return r;
719
720 r = chmod_and_chown(fs, mode, uid, gid);
721 if (r < 0)
722 return r;
723
724 /* Compatibility, Always keep values for "tasks" in sync with
725 * "cgroup.procs" */
726 r = cg_get_path(controller, path, "tasks", &procs);
727 if (r < 0)
728 return r;
729
730 return chmod_and_chown(procs, mode, uid, gid);
731 }
732
733 int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
734 _cleanup_fclose_ FILE *f = NULL;
735 char line[LINE_MAX];
736 const char *fs;
737 size_t cs;
738
739 assert(path);
740 assert(pid >= 0);
741
742 if (controller) {
743 if (!cg_controller_is_valid(controller))
744 return -EINVAL;
745
746 controller = normalize_controller(controller);
747 } else
748 controller = SYSTEMD_CGROUP_CONTROLLER;
749
750 fs = procfs_file_alloca(pid, "cgroup");
751
752 f = fopen(fs, "re");
753 if (!f)
754 return errno == ENOENT ? -ESRCH : -errno;
755
756 cs = strlen(controller);
757
758 FOREACH_LINE(line, f, return -errno) {
759 char *l, *p, *e;
760 size_t k;
761 const char *word, *state;
762 bool found = false;
763
764 truncate_nl(line);
765
766 l = strchr(line, ':');
767 if (!l)
768 continue;
769
770 l++;
771 e = strchr(l, ':');
772 if (!e)
773 continue;
774
775 *e = 0;
776
777 FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
778
779 if (k == cs && memcmp(word, controller, cs) == 0) {
780 found = true;
781 break;
782 }
783
784 if (k == 5 + cs &&
785 memcmp(word, "name=", 5) == 0 &&
786 memcmp(word+5, controller, cs) == 0) {
787 found = true;
788 break;
789 }
790 }
791
792 if (!found)
793 continue;
794
795 p = strdup(e + 1);
796 if (!p)
797 return -ENOMEM;
798
799 *path = p;
800 return 0;
801 }
802
803 return -ENOENT;
804 }
805
806 int cg_install_release_agent(const char *controller, const char *agent) {
807 _cleanup_free_ char *fs = NULL, *contents = NULL;
808 char *sc;
809 int r;
810
811 assert(agent);
812
813 r = cg_get_path(controller, NULL, "release_agent", &fs);
814 if (r < 0)
815 return r;
816
817 r = read_one_line_file(fs, &contents);
818 if (r < 0)
819 return r;
820
821 sc = strstrip(contents);
822 if (sc[0] == 0) {
823 r = write_string_file(fs, agent, 0);
824 if (r < 0)
825 return r;
826 } else if (!streq(sc, agent))
827 return -EEXIST;
828
829 fs = mfree(fs);
830 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
831 if (r < 0)
832 return r;
833
834 contents = mfree(contents);
835 r = read_one_line_file(fs, &contents);
836 if (r < 0)
837 return r;
838
839 sc = strstrip(contents);
840 if (streq(sc, "0")) {
841 r = write_string_file(fs, "1", 0);
842 if (r < 0)
843 return r;
844
845 return 1;
846 }
847
848 if (!streq(sc, "1"))
849 return -EIO;
850
851 return 0;
852 }
853
854 int cg_uninstall_release_agent(const char *controller) {
855 _cleanup_free_ char *fs = NULL;
856 int r;
857
858 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
859 if (r < 0)
860 return r;
861
862 r = write_string_file(fs, "0", 0);
863 if (r < 0)
864 return r;
865
866 fs = mfree(fs);
867
868 r = cg_get_path(controller, NULL, "release_agent", &fs);
869 if (r < 0)
870 return r;
871
872 r = write_string_file(fs, "", 0);
873 if (r < 0)
874 return r;
875
876 return 0;
877 }
878
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;
882 bool found = false;
883 int r;
884
885 assert(path);
886
887 r = cg_enumerate_processes(controller, path, &f);
888 if (r < 0)
889 return r == -ENOENT ? 1 : r;
890
891 self_pid = getpid();
892
893 while ((r = cg_read_pid(f, &pid)) > 0) {
894
895 if (ignore_self && pid == self_pid)
896 continue;
897
898 found = true;
899 break;
900 }
901
902 if (r < 0)
903 return r;
904
905 return !found;
906 }
907
908 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
909 _cleanup_closedir_ DIR *d = NULL;
910 char *fn;
911 int r;
912
913 assert(path);
914
915 r = cg_is_empty(controller, path, ignore_self);
916 if (r <= 0)
917 return r;
918
919 r = cg_enumerate_subgroups(controller, path, &d);
920 if (r < 0)
921 return r == -ENOENT ? 1 : r;
922
923 while ((r = cg_read_subgroup(d, &fn)) > 0) {
924 _cleanup_free_ char *p = NULL;
925
926 p = strjoin(path, "/", fn, NULL);
927 free(fn);
928 if (!p)
929 return -ENOMEM;
930
931 r = cg_is_empty_recursive(controller, p, ignore_self);
932 if (r <= 0)
933 return r;
934 }
935
936 if (r < 0)
937 return r;
938
939 return 1;
940 }
941
942 int cg_split_spec(const char *spec, char **controller, char **path) {
943 const char *e;
944 char *t = NULL, *u = NULL;
945 _cleanup_free_ char *v = NULL;
946
947 assert(spec);
948
949 if (*spec == '/') {
950 if (!path_is_safe(spec))
951 return -EINVAL;
952
953 if (path) {
954 t = strdup(spec);
955 if (!t)
956 return -ENOMEM;
957
958 *path = path_kill_slashes(t);
959 }
960
961 if (controller)
962 *controller = NULL;
963
964 return 0;
965 }
966
967 e = strchr(spec, ':');
968 if (!e) {
969 if (!cg_controller_is_valid(spec))
970 return -EINVAL;
971
972 if (controller) {
973 t = strdup(normalize_controller(spec));
974 if (!t)
975 return -ENOMEM;
976
977 *controller = t;
978 }
979
980 if (path)
981 *path = NULL;
982
983 return 0;
984 }
985
986 v = strndup(spec, e-spec);
987 if (!v)
988 return -ENOMEM;
989 t = strdup(normalize_controller(v));
990 if (!t)
991 return -ENOMEM;
992 if (!cg_controller_is_valid(t)) {
993 free(t);
994 return -EINVAL;
995 }
996
997 if (streq(e+1, "")) {
998 u = strdup("/");
999 if (!u) {
1000 free(t);
1001 return -ENOMEM;
1002 }
1003 } else {
1004 u = strdup(e+1);
1005 if (!u) {
1006 free(t);
1007 return -ENOMEM;
1008 }
1009
1010 if (!path_is_safe(u) ||
1011 !path_is_absolute(u)) {
1012 free(t);
1013 free(u);
1014 return -EINVAL;
1015 }
1016
1017 path_kill_slashes(u);
1018 }
1019
1020 if (controller)
1021 *controller = t;
1022 else
1023 free(t);
1024
1025 if (path)
1026 *path = u;
1027 else
1028 free(u);
1029
1030 return 0;
1031 }
1032
1033 int cg_mangle_path(const char *path, char **result) {
1034 _cleanup_free_ char *c = NULL, *p = NULL;
1035 char *t;
1036 int r;
1037
1038 assert(path);
1039 assert(result);
1040
1041 /* First, check if it already is a filesystem path */
1042 if (path_startswith(path, "/sys/fs/cgroup")) {
1043
1044 t = strdup(path);
1045 if (!t)
1046 return -ENOMEM;
1047
1048 *result = path_kill_slashes(t);
1049 return 0;
1050 }
1051
1052 /* Otherwise, treat it as cg spec */
1053 r = cg_split_spec(path, &c, &p);
1054 if (r < 0)
1055 return r;
1056
1057 return cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1058 }
1059
1060 int cg_get_root_path(char **path) {
1061 char *p, *e;
1062 int r;
1063
1064 assert(path);
1065
1066 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
1067 if (r < 0)
1068 return r;
1069
1070 e = endswith(p, "/" SPECIAL_SYSTEM_SLICE);
1071 if (e)
1072 *e = 0;
1073
1074 *path = p;
1075 return 0;
1076 }
1077
1078 int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
1079 _cleanup_free_ char *rt = NULL;
1080 char *p;
1081 int r;
1082
1083 assert(cgroup);
1084 assert(shifted);
1085
1086 if (!root) {
1087 /* If the root was specified let's use that, otherwise
1088 * let's determine it from PID 1 */
1089
1090 r = cg_get_root_path(&rt);
1091 if (r < 0)
1092 return r;
1093
1094 root = rt;
1095 }
1096
1097 p = path_startswith(cgroup, root);
1098 if (p)
1099 *shifted = p - 1;
1100 else
1101 *shifted = cgroup;
1102
1103 return 0;
1104 }
1105
1106 int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
1107 _cleanup_free_ char *raw = NULL;
1108 const char *c;
1109 int r;
1110
1111 assert(pid >= 0);
1112 assert(cgroup);
1113
1114 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &raw);
1115 if (r < 0)
1116 return r;
1117
1118 r = cg_shift_path(raw, root, &c);
1119 if (r < 0)
1120 return r;
1121
1122 if (c == raw) {
1123 *cgroup = raw;
1124 raw = NULL;
1125 } else {
1126 char *n;
1127
1128 n = strdup(c);
1129 if (!n)
1130 return -ENOMEM;
1131
1132 *cgroup = n;
1133 }
1134
1135 return 0;
1136 }
1137
1138 int cg_path_decode_unit(const char *cgroup, char **unit){
1139 char *c, *s;
1140 size_t n;
1141
1142 assert(cgroup);
1143 assert(unit);
1144
1145 n = strcspn(cgroup, "/");
1146 if (n < 3)
1147 return -ENXIO;
1148
1149 c = strndupa(cgroup, n);
1150 c = cg_unescape(c);
1151
1152 if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
1153 return -ENXIO;
1154
1155 s = strdup(c);
1156 if (!s)
1157 return -ENOMEM;
1158
1159 *unit = s;
1160 return 0;
1161 }
1162
1163 static bool valid_slice_name(const char *p, size_t n) {
1164
1165 if (!p)
1166 return false;
1167
1168 if (n < strlen("x.slice"))
1169 return false;
1170
1171 if (memcmp(p + n - 6, ".slice", 6) == 0) {
1172 char buf[n+1], *c;
1173
1174 memcpy(buf, p, n);
1175 buf[n] = 0;
1176
1177 c = cg_unescape(buf);
1178
1179 return unit_name_is_valid(c, UNIT_NAME_PLAIN);
1180 }
1181
1182 return false;
1183 }
1184
1185 static const char *skip_slices(const char *p) {
1186 assert(p);
1187
1188 /* Skips over all slice assignments */
1189
1190 for (;;) {
1191 size_t n;
1192
1193 p += strspn(p, "/");
1194
1195 n = strcspn(p, "/");
1196 if (!valid_slice_name(p, n))
1197 return p;
1198
1199 p += n;
1200 }
1201 }
1202
1203 int cg_path_get_unit(const char *path, char **ret) {
1204 const char *e;
1205 char *unit;
1206 int r;
1207
1208 assert(path);
1209 assert(ret);
1210
1211 e = skip_slices(path);
1212
1213 r = cg_path_decode_unit(e, &unit);
1214 if (r < 0)
1215 return r;
1216
1217 /* We skipped over the slices, don't accept any now */
1218 if (endswith(unit, ".slice")) {
1219 free(unit);
1220 return -ENXIO;
1221 }
1222
1223 *ret = unit;
1224 return 0;
1225 }
1226
1227 int cg_pid_get_unit(pid_t pid, char **unit) {
1228 _cleanup_free_ char *cgroup = NULL;
1229 int r;
1230
1231 assert(unit);
1232
1233 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1234 if (r < 0)
1235 return r;
1236
1237 return cg_path_get_unit(cgroup, unit);
1238 }
1239
1240 /**
1241 * Skip session-*.scope, but require it to be there.
1242 */
1243 static const char *skip_session(const char *p) {
1244 size_t n;
1245
1246 if (isempty(p))
1247 return NULL;
1248
1249 p += strspn(p, "/");
1250
1251 n = strcspn(p, "/");
1252 if (n < strlen("session-x.scope"))
1253 return NULL;
1254
1255 if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) {
1256 char buf[n - 8 - 6 + 1];
1257
1258 memcpy(buf, p + 8, n - 8 - 6);
1259 buf[n - 8 - 6] = 0;
1260
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()
1264 * here. */
1265
1266 if (!session_id_valid(buf))
1267 return false;
1268
1269 p += n;
1270 p += strspn(p, "/");
1271 return p;
1272 }
1273
1274 return NULL;
1275 }
1276
1277 /**
1278 * Skip user@*.service, but require it to be there.
1279 */
1280 static const char *skip_user_manager(const char *p) {
1281 size_t n;
1282
1283 if (isempty(p))
1284 return NULL;
1285
1286 p += strspn(p, "/");
1287
1288 n = strcspn(p, "/");
1289 if (n < strlen("user@x.service"))
1290 return NULL;
1291
1292 if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
1293 char buf[n - 5 - 8 + 1];
1294
1295 memcpy(buf, p + 5, n - 5 - 8);
1296 buf[n - 5 - 8] = 0;
1297
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()
1301 * here. */
1302
1303 if (parse_uid(buf, NULL) < 0)
1304 return NULL;
1305
1306 p += n;
1307 p += strspn(p, "/");
1308
1309 return p;
1310 }
1311
1312 return NULL;
1313 }
1314
1315 static const char *skip_user_prefix(const char *path) {
1316 const char *e, *t;
1317
1318 assert(path);
1319
1320 /* Skip slices, if there are any */
1321 e = skip_slices(path);
1322
1323 /* Skip the user manager, if it's in the path now... */
1324 t = skip_user_manager(e);
1325 if (t)
1326 return t;
1327
1328 /* Alternatively skip the user session if it is in the path... */
1329 return skip_session(e);
1330 }
1331
1332 int cg_path_get_user_unit(const char *path, char **ret) {
1333 const char *t;
1334
1335 assert(path);
1336 assert(ret);
1337
1338 t = skip_user_prefix(path);
1339 if (!t)
1340 return -ENXIO;
1341
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
1344 * on. */
1345 return cg_path_get_unit(t, ret);
1346 }
1347
1348 int cg_pid_get_user_unit(pid_t pid, char **unit) {
1349 _cleanup_free_ char *cgroup = NULL;
1350 int r;
1351
1352 assert(unit);
1353
1354 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1355 if (r < 0)
1356 return r;
1357
1358 return cg_path_get_user_unit(cgroup, unit);
1359 }
1360
1361 int cg_path_get_machine_name(const char *path, char **machine) {
1362 _cleanup_free_ char *u = NULL, *sl = NULL;
1363 int r;
1364
1365 r = cg_path_get_unit(path, &u);
1366 if (r < 0)
1367 return r;
1368
1369 sl = strjoin("/run/systemd/machines/unit:", u, NULL);
1370 if (!sl)
1371 return -ENOMEM;
1372
1373 return readlink_malloc(sl, machine);
1374 }
1375
1376 int cg_pid_get_machine_name(pid_t pid, char **machine) {
1377 _cleanup_free_ char *cgroup = NULL;
1378 int r;
1379
1380 assert(machine);
1381
1382 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1383 if (r < 0)
1384 return r;
1385
1386 return cg_path_get_machine_name(cgroup, machine);
1387 }
1388
1389 int cg_path_get_session(const char *path, char **session) {
1390 _cleanup_free_ char *unit = NULL;
1391 char *start, *end;
1392 int r;
1393
1394 assert(path);
1395
1396 r = cg_path_get_unit(path, &unit);
1397 if (r < 0)
1398 return r;
1399
1400 start = startswith(unit, "session-");
1401 if (!start)
1402 return -ENXIO;
1403 end = endswith(start, ".scope");
1404 if (!end)
1405 return -ENXIO;
1406
1407 *end = 0;
1408 if (!session_id_valid(start))
1409 return -ENXIO;
1410
1411 if (session) {
1412 char *rr;
1413
1414 rr = strdup(start);
1415 if (!rr)
1416 return -ENOMEM;
1417
1418 *session = rr;
1419 }
1420
1421 return 0;
1422 }
1423
1424 int cg_pid_get_session(pid_t pid, char **session) {
1425 _cleanup_free_ char *cgroup = NULL;
1426 int r;
1427
1428 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1429 if (r < 0)
1430 return r;
1431
1432 return cg_path_get_session(cgroup, session);
1433 }
1434
1435 int cg_path_get_owner_uid(const char *path, uid_t *uid) {
1436 _cleanup_free_ char *slice = NULL;
1437 char *start, *end;
1438 int r;
1439
1440 assert(path);
1441
1442 r = cg_path_get_slice(path, &slice);
1443 if (r < 0)
1444 return r;
1445
1446 start = startswith(slice, "user-");
1447 if (!start)
1448 return -ENXIO;
1449 end = endswith(start, ".slice");
1450 if (!end)
1451 return -ENXIO;
1452
1453 *end = 0;
1454 if (parse_uid(start, uid) < 0)
1455 return -ENXIO;
1456
1457 return 0;
1458 }
1459
1460 int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
1461 _cleanup_free_ char *cgroup = NULL;
1462 int r;
1463
1464 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1465 if (r < 0)
1466 return r;
1467
1468 return cg_path_get_owner_uid(cgroup, uid);
1469 }
1470
1471 int cg_path_get_slice(const char *p, char **slice) {
1472 const char *e = NULL;
1473
1474 assert(p);
1475 assert(slice);
1476
1477 /* Finds the right-most slice unit from the beginning, but
1478 * stops before we come to the first non-slice unit. */
1479
1480 for (;;) {
1481 size_t n;
1482
1483 p += strspn(p, "/");
1484
1485 n = strcspn(p, "/");
1486 if (!valid_slice_name(p, n)) {
1487
1488 if (!e) {
1489 char *s;
1490
1491 s = strdup("-.slice");
1492 if (!s)
1493 return -ENOMEM;
1494
1495 *slice = s;
1496 return 0;
1497 }
1498
1499 return cg_path_decode_unit(e, slice);
1500 }
1501
1502 e = p;
1503 p += n;
1504 }
1505 }
1506
1507 int cg_pid_get_slice(pid_t pid, char **slice) {
1508 _cleanup_free_ char *cgroup = NULL;
1509 int r;
1510
1511 assert(slice);
1512
1513 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1514 if (r < 0)
1515 return r;
1516
1517 return cg_path_get_slice(cgroup, slice);
1518 }
1519
1520 int cg_path_get_user_slice(const char *p, char **slice) {
1521 const char *t;
1522 assert(p);
1523 assert(slice);
1524
1525 t = skip_user_prefix(p);
1526 if (!t)
1527 return -ENXIO;
1528
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);
1532 }
1533
1534 int cg_pid_get_user_slice(pid_t pid, char **slice) {
1535 _cleanup_free_ char *cgroup = NULL;
1536 int r;
1537
1538 assert(slice);
1539
1540 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1541 if (r < 0)
1542 return r;
1543
1544 return cg_path_get_user_slice(cgroup, slice);
1545 }
1546
1547 char *cg_escape(const char *p) {
1548 bool need_prefix = false;
1549
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
1555 * there is one. */
1556
1557 /* The return value of this function (unlike cg_unescape())
1558 * needs free()! */
1559
1560 if (p[0] == 0 ||
1561 p[0] == '_' ||
1562 p[0] == '.' ||
1563 streq(p, "notify_on_release") ||
1564 streq(p, "release_agent") ||
1565 streq(p, "tasks"))
1566 need_prefix = true;
1567 else {
1568 const char *dot;
1569
1570 dot = strrchr(p, '.');
1571 if (dot) {
1572
1573 if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0)
1574 need_prefix = true;
1575 else {
1576 char *n;
1577
1578 n = strndupa(p, dot - p);
1579
1580 if (check_hierarchy(n) >= 0)
1581 need_prefix = true;
1582 }
1583 }
1584 }
1585
1586 if (need_prefix)
1587 return strappend("_", p);
1588 else
1589 return strdup(p);
1590 }
1591
1592 char *cg_unescape(const char *p) {
1593 assert(p);
1594
1595 /* The return value of this function (unlike cg_escape())
1596 * doesn't need free()! */
1597
1598 if (p[0] == '_')
1599 return (char*) p+1;
1600
1601 return (char*) p;
1602 }
1603
1604 #define CONTROLLER_VALID \
1605 DIGITS LETTERS \
1606 "_"
1607
1608 bool cg_controller_is_valid(const char *p) {
1609 const char *t, *s;
1610
1611 if (!p)
1612 return false;
1613
1614 s = startswith(p, "name=");
1615 if (s)
1616 p = s;
1617
1618 if (*p == 0 || *p == '_')
1619 return false;
1620
1621 for (t = p; *t; t++)
1622 if (!strchr(CONTROLLER_VALID, *t))
1623 return false;
1624
1625 if (t - p > FILENAME_MAX)
1626 return false;
1627
1628 return true;
1629 }
1630
1631 int cg_slice_to_path(const char *unit, char **ret) {
1632 _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
1633 const char *dash;
1634 int r;
1635
1636 assert(unit);
1637 assert(ret);
1638
1639 if (streq(unit, "-.slice")) {
1640 char *x;
1641
1642 x = strdup("");
1643 if (!x)
1644 return -ENOMEM;
1645 *ret = x;
1646 return 0;
1647 }
1648
1649 if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
1650 return -EINVAL;
1651
1652 if (!endswith(unit, ".slice"))
1653 return -EINVAL;
1654
1655 r = unit_name_to_prefix(unit, &p);
1656 if (r < 0)
1657 return r;
1658
1659 dash = strchr(p, '-');
1660
1661 /* Don't allow initial dashes */
1662 if (dash == p)
1663 return -EINVAL;
1664
1665 while (dash) {
1666 _cleanup_free_ char *escaped = NULL;
1667 char n[dash - p + sizeof(".slice")];
1668
1669 /* Don't allow trailing or double dashes */
1670 if (dash[1] == 0 || dash[1] == '-')
1671 return -EINVAL;
1672
1673 strcpy(stpncpy(n, p, dash - p), ".slice");
1674 if (!unit_name_is_valid(n, UNIT_NAME_PLAIN))
1675 return -EINVAL;
1676
1677 escaped = cg_escape(n);
1678 if (!escaped)
1679 return -ENOMEM;
1680
1681 if (!strextend(&s, escaped, "/", NULL))
1682 return -ENOMEM;
1683
1684 dash = strchr(dash+1, '-');
1685 }
1686
1687 e = cg_escape(unit);
1688 if (!e)
1689 return -ENOMEM;
1690
1691 if (!strextend(&s, e, NULL))
1692 return -ENOMEM;
1693
1694 *ret = s;
1695 s = NULL;
1696
1697 return 0;
1698 }
1699
1700 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
1701 _cleanup_free_ char *p = NULL;
1702 int r;
1703
1704 r = cg_get_path(controller, path, attribute, &p);
1705 if (r < 0)
1706 return r;
1707
1708 return write_string_file(p, value, 0);
1709 }
1710
1711 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) {
1712 _cleanup_free_ char *p = NULL;
1713 int r;
1714
1715 r = cg_get_path(controller, path, attribute, &p);
1716 if (r < 0)
1717 return r;
1718
1719 return read_one_line_file(p, ret);
1720 }
1721
1722 static const char mask_names[] =
1723 "cpu\0"
1724 "cpuacct\0"
1725 "blkio\0"
1726 "memory\0"
1727 "devices\0";
1728
1729 int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
1730 CGroupControllerMask bit = 1;
1731 const char *n;
1732 int r;
1733
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
1736 * in all others */
1737
1738 /* First create the cgroup in our own hierarchy. */
1739 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
1740 if (r < 0)
1741 return r;
1742
1743 /* Then, do the same in the other hierarchies */
1744 NULSTR_FOREACH(n, mask_names) {
1745 if (mask & bit)
1746 cg_create(n, path);
1747 else if (supported & bit)
1748 cg_trim(n, path, true);
1749
1750 bit <<= 1;
1751 }
1752
1753 return 0;
1754 }
1755
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;
1758 const char *n;
1759 int r;
1760
1761 r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
1762 if (r < 0)
1763 return r;
1764
1765 NULSTR_FOREACH(n, mask_names) {
1766
1767 if (supported & bit) {
1768 const char *p = NULL;
1769
1770 if (path_callback)
1771 p = path_callback(bit, userdata);
1772
1773 if (!p)
1774 p = path;
1775
1776 cg_attach_fallback(n, p, pid);
1777 }
1778
1779 bit <<= 1;
1780 }
1781
1782 return 0;
1783 }
1784
1785 int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
1786 Iterator i;
1787 void *pidp;
1788 int r = 0;
1789
1790 SET_FOREACH(pidp, pids, i) {
1791 pid_t pid = PTR_TO_LONG(pidp);
1792 int q;
1793
1794 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
1795 if (q < 0)
1796 r = q;
1797 }
1798
1799 return r;
1800 }
1801
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;
1804 const char *n;
1805 int r;
1806
1807 if (!path_equal(from, to)) {
1808 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
1809 if (r < 0)
1810 return r;
1811 }
1812
1813 NULSTR_FOREACH(n, mask_names) {
1814 if (supported & bit) {
1815 const char *p = NULL;
1816
1817 if (to_callback)
1818 p = to_callback(bit, userdata);
1819
1820 if (!p)
1821 p = to;
1822
1823 cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, n, p, false, false);
1824 }
1825
1826 bit <<= 1;
1827 }
1828
1829 return 0;
1830 }
1831
1832 int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
1833 CGroupControllerMask bit = 1;
1834 const char *n;
1835 int r;
1836
1837 r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
1838 if (r < 0)
1839 return r;
1840
1841 NULSTR_FOREACH(n, mask_names) {
1842 if (supported & bit)
1843 cg_trim(n, path, delete_root);
1844
1845 bit <<= 1;
1846 }
1847
1848 return 0;
1849 }
1850
1851 CGroupControllerMask cg_mask_supported(void) {
1852 CGroupControllerMask bit = 1, mask = 0;
1853 const char *n;
1854
1855 NULSTR_FOREACH(n, mask_names) {
1856 if (check_hierarchy(n) >= 0)
1857 mask |= bit;
1858
1859 bit <<= 1;
1860 }
1861
1862 return mask;
1863 }
1864
1865 int cg_kernel_controllers(Set *controllers) {
1866 _cleanup_fclose_ FILE *f = NULL;
1867 char buf[LINE_MAX];
1868 int r;
1869
1870 assert(controllers);
1871
1872 f = fopen("/proc/cgroups", "re");
1873 if (!f) {
1874 if (errno == ENOENT)
1875 return 0;
1876 return -errno;
1877 }
1878
1879 /* Ignore the header line */
1880 (void) fgets(buf, sizeof(buf), f);
1881
1882 for (;;) {
1883 char *controller;
1884 int enabled = 0;
1885
1886 errno = 0;
1887 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
1888
1889 if (feof(f))
1890 break;
1891
1892 if (ferror(f) && errno)
1893 return -errno;
1894
1895 return -EBADMSG;
1896 }
1897
1898 if (!enabled) {
1899 free(controller);
1900 continue;
1901 }
1902
1903 if (!filename_is_valid(controller)) {
1904 free(controller);
1905 return -EBADMSG;
1906 }
1907
1908 r = set_consume(controllers, controller);
1909 if (r < 0)
1910 return r;
1911 }
1912
1913 return 0;
1914 }