]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/cgroup-util.c
Merge pull request #156 from filbranden/journal_leading_whitespace
[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_no_create(fs, c);
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_no_create(fs, agent);
824 if (r < 0)
825 return r;
826 } else if (!streq(sc, agent))
827 return -EEXIST;
828
829 free(fs);
830 fs = NULL;
831 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
832 if (r < 0)
833 return r;
834
835 free(contents);
836 contents = NULL;
837 r = read_one_line_file(fs, &contents);
838 if (r < 0)
839 return r;
840
841 sc = strstrip(contents);
842 if (streq(sc, "0")) {
843 r = write_string_file_no_create(fs, "1");
844 if (r < 0)
845 return r;
846
847 return 1;
848 }
849
850 if (!streq(sc, "1"))
851 return -EIO;
852
853 return 0;
854 }
855
856 int cg_uninstall_release_agent(const char *controller) {
857 _cleanup_free_ char *fs = NULL;
858 int r;
859
860 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
861 if (r < 0)
862 return r;
863
864 r = write_string_file_no_create(fs, "0");
865 if (r < 0)
866 return r;
867
868 free(fs);
869 fs = NULL;
870
871 r = cg_get_path(controller, NULL, "release_agent", &fs);
872 if (r < 0)
873 return r;
874
875 r = write_string_file_no_create(fs, "");
876 if (r < 0)
877 return r;
878
879 return 0;
880 }
881
882 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
883 _cleanup_fclose_ FILE *f = NULL;
884 pid_t pid = 0, self_pid;
885 bool found = false;
886 int r;
887
888 assert(path);
889
890 r = cg_enumerate_processes(controller, path, &f);
891 if (r < 0)
892 return r == -ENOENT ? 1 : r;
893
894 self_pid = getpid();
895
896 while ((r = cg_read_pid(f, &pid)) > 0) {
897
898 if (ignore_self && pid == self_pid)
899 continue;
900
901 found = true;
902 break;
903 }
904
905 if (r < 0)
906 return r;
907
908 return !found;
909 }
910
911 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
912 _cleanup_closedir_ DIR *d = NULL;
913 char *fn;
914 int r;
915
916 assert(path);
917
918 r = cg_is_empty(controller, path, ignore_self);
919 if (r <= 0)
920 return r;
921
922 r = cg_enumerate_subgroups(controller, path, &d);
923 if (r < 0)
924 return r == -ENOENT ? 1 : r;
925
926 while ((r = cg_read_subgroup(d, &fn)) > 0) {
927 _cleanup_free_ char *p = NULL;
928
929 p = strjoin(path, "/", fn, NULL);
930 free(fn);
931 if (!p)
932 return -ENOMEM;
933
934 r = cg_is_empty_recursive(controller, p, ignore_self);
935 if (r <= 0)
936 return r;
937 }
938
939 if (r < 0)
940 return r;
941
942 return 1;
943 }
944
945 int cg_split_spec(const char *spec, char **controller, char **path) {
946 const char *e;
947 char *t = NULL, *u = NULL;
948 _cleanup_free_ char *v = NULL;
949
950 assert(spec);
951
952 if (*spec == '/') {
953 if (!path_is_safe(spec))
954 return -EINVAL;
955
956 if (path) {
957 t = strdup(spec);
958 if (!t)
959 return -ENOMEM;
960
961 *path = path_kill_slashes(t);
962 }
963
964 if (controller)
965 *controller = NULL;
966
967 return 0;
968 }
969
970 e = strchr(spec, ':');
971 if (!e) {
972 if (!cg_controller_is_valid(spec))
973 return -EINVAL;
974
975 if (controller) {
976 t = strdup(normalize_controller(spec));
977 if (!t)
978 return -ENOMEM;
979
980 *controller = t;
981 }
982
983 if (path)
984 *path = NULL;
985
986 return 0;
987 }
988
989 v = strndup(spec, e-spec);
990 if (!v)
991 return -ENOMEM;
992 t = strdup(normalize_controller(v));
993 if (!t)
994 return -ENOMEM;
995 if (!cg_controller_is_valid(t)) {
996 free(t);
997 return -EINVAL;
998 }
999
1000 if (streq(e+1, "")) {
1001 u = strdup("/");
1002 if (!u) {
1003 free(t);
1004 return -ENOMEM;
1005 }
1006 } else {
1007 u = strdup(e+1);
1008 if (!u) {
1009 free(t);
1010 return -ENOMEM;
1011 }
1012
1013 if (!path_is_safe(u) ||
1014 !path_is_absolute(u)) {
1015 free(t);
1016 free(u);
1017 return -EINVAL;
1018 }
1019
1020 path_kill_slashes(u);
1021 }
1022
1023 if (controller)
1024 *controller = t;
1025 else
1026 free(t);
1027
1028 if (path)
1029 *path = u;
1030 else
1031 free(u);
1032
1033 return 0;
1034 }
1035
1036 int cg_mangle_path(const char *path, char **result) {
1037 _cleanup_free_ char *c = NULL, *p = NULL;
1038 char *t;
1039 int r;
1040
1041 assert(path);
1042 assert(result);
1043
1044 /* First, check if it already is a filesystem path */
1045 if (path_startswith(path, "/sys/fs/cgroup")) {
1046
1047 t = strdup(path);
1048 if (!t)
1049 return -ENOMEM;
1050
1051 *result = path_kill_slashes(t);
1052 return 0;
1053 }
1054
1055 /* Otherwise, treat it as cg spec */
1056 r = cg_split_spec(path, &c, &p);
1057 if (r < 0)
1058 return r;
1059
1060 return cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1061 }
1062
1063 int cg_get_root_path(char **path) {
1064 char *p, *e;
1065 int r;
1066
1067 assert(path);
1068
1069 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
1070 if (r < 0)
1071 return r;
1072
1073 e = endswith(p, "/" SPECIAL_SYSTEM_SLICE);
1074 if (e)
1075 *e = 0;
1076
1077 *path = p;
1078 return 0;
1079 }
1080
1081 int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
1082 _cleanup_free_ char *rt = NULL;
1083 char *p;
1084 int r;
1085
1086 assert(cgroup);
1087 assert(shifted);
1088
1089 if (!root) {
1090 /* If the root was specified let's use that, otherwise
1091 * let's determine it from PID 1 */
1092
1093 r = cg_get_root_path(&rt);
1094 if (r < 0)
1095 return r;
1096
1097 root = rt;
1098 }
1099
1100 p = path_startswith(cgroup, root);
1101 if (p)
1102 *shifted = p - 1;
1103 else
1104 *shifted = cgroup;
1105
1106 return 0;
1107 }
1108
1109 int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
1110 _cleanup_free_ char *raw = NULL;
1111 const char *c;
1112 int r;
1113
1114 assert(pid >= 0);
1115 assert(cgroup);
1116
1117 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &raw);
1118 if (r < 0)
1119 return r;
1120
1121 r = cg_shift_path(raw, root, &c);
1122 if (r < 0)
1123 return r;
1124
1125 if (c == raw) {
1126 *cgroup = raw;
1127 raw = NULL;
1128 } else {
1129 char *n;
1130
1131 n = strdup(c);
1132 if (!n)
1133 return -ENOMEM;
1134
1135 *cgroup = n;
1136 }
1137
1138 return 0;
1139 }
1140
1141 int cg_path_decode_unit(const char *cgroup, char **unit){
1142 char *c, *s;
1143 size_t n;
1144
1145 assert(cgroup);
1146 assert(unit);
1147
1148 n = strcspn(cgroup, "/");
1149 if (n < 3)
1150 return -ENXIO;
1151
1152 c = strndupa(cgroup, n);
1153 c = cg_unescape(c);
1154
1155 if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
1156 return -ENXIO;
1157
1158 s = strdup(c);
1159 if (!s)
1160 return -ENOMEM;
1161
1162 *unit = s;
1163 return 0;
1164 }
1165
1166 static bool valid_slice_name(const char *p, size_t n) {
1167
1168 if (!p)
1169 return false;
1170
1171 if (n < strlen("x.slice"))
1172 return false;
1173
1174 if (memcmp(p + n - 6, ".slice", 6) == 0) {
1175 char buf[n+1], *c;
1176
1177 memcpy(buf, p, n);
1178 buf[n] = 0;
1179
1180 c = cg_unescape(buf);
1181
1182 return unit_name_is_valid(c, UNIT_NAME_PLAIN);
1183 }
1184
1185 return false;
1186 }
1187
1188 static const char *skip_slices(const char *p) {
1189 assert(p);
1190
1191 /* Skips over all slice assignments */
1192
1193 for (;;) {
1194 size_t n;
1195
1196 p += strspn(p, "/");
1197
1198 n = strcspn(p, "/");
1199 if (!valid_slice_name(p, n))
1200 return p;
1201
1202 p += n;
1203 }
1204 }
1205
1206 int cg_path_get_unit(const char *path, char **ret) {
1207 const char *e;
1208 char *unit;
1209 int r;
1210
1211 assert(path);
1212 assert(ret);
1213
1214 e = skip_slices(path);
1215
1216 r = cg_path_decode_unit(e, &unit);
1217 if (r < 0)
1218 return r;
1219
1220 /* We skipped over the slices, don't accept any now */
1221 if (endswith(unit, ".slice")) {
1222 free(unit);
1223 return -ENXIO;
1224 }
1225
1226 *ret = unit;
1227 return 0;
1228 }
1229
1230 int cg_pid_get_unit(pid_t pid, char **unit) {
1231 _cleanup_free_ char *cgroup = NULL;
1232 int r;
1233
1234 assert(unit);
1235
1236 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1237 if (r < 0)
1238 return r;
1239
1240 return cg_path_get_unit(cgroup, unit);
1241 }
1242
1243 /**
1244 * Skip session-*.scope, but require it to be there.
1245 */
1246 static const char *skip_session(const char *p) {
1247 size_t n;
1248
1249 if (isempty(p))
1250 return NULL;
1251
1252 p += strspn(p, "/");
1253
1254 n = strcspn(p, "/");
1255 if (n < strlen("session-x.scope"))
1256 return NULL;
1257
1258 if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) {
1259 char buf[n - 8 - 6 + 1];
1260
1261 memcpy(buf, p + 8, n - 8 - 6);
1262 buf[n - 8 - 6] = 0;
1263
1264 /* Note that session scopes never need unescaping,
1265 * since they cannot conflict with the kernel's own
1266 * names, hence we don't need to call cg_unescape()
1267 * here. */
1268
1269 if (!session_id_valid(buf))
1270 return false;
1271
1272 p += n;
1273 p += strspn(p, "/");
1274 return p;
1275 }
1276
1277 return NULL;
1278 }
1279
1280 /**
1281 * Skip user@*.service, but require it to be there.
1282 */
1283 static const char *skip_user_manager(const char *p) {
1284 size_t n;
1285
1286 if (isempty(p))
1287 return NULL;
1288
1289 p += strspn(p, "/");
1290
1291 n = strcspn(p, "/");
1292 if (n < strlen("user@x.service"))
1293 return NULL;
1294
1295 if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
1296 char buf[n - 5 - 8 + 1];
1297
1298 memcpy(buf, p + 5, n - 5 - 8);
1299 buf[n - 5 - 8] = 0;
1300
1301 /* Note that user manager services never need unescaping,
1302 * since they cannot conflict with the kernel's own
1303 * names, hence we don't need to call cg_unescape()
1304 * here. */
1305
1306 if (parse_uid(buf, NULL) < 0)
1307 return NULL;
1308
1309 p += n;
1310 p += strspn(p, "/");
1311
1312 return p;
1313 }
1314
1315 return NULL;
1316 }
1317
1318 static const char *skip_user_prefix(const char *path) {
1319 const char *e, *t;
1320
1321 assert(path);
1322
1323 /* Skip slices, if there are any */
1324 e = skip_slices(path);
1325
1326 /* Skip the user manager, if it's in the path now... */
1327 t = skip_user_manager(e);
1328 if (t)
1329 return t;
1330
1331 /* Alternatively skip the user session if it is in the path... */
1332 return skip_session(e);
1333 }
1334
1335 int cg_path_get_user_unit(const char *path, char **ret) {
1336 const char *t;
1337
1338 assert(path);
1339 assert(ret);
1340
1341 t = skip_user_prefix(path);
1342 if (!t)
1343 return -ENXIO;
1344
1345 /* And from here on it looks pretty much the same as for a
1346 * system unit, hence let's use the same parser from here
1347 * on. */
1348 return cg_path_get_unit(t, ret);
1349 }
1350
1351 int cg_pid_get_user_unit(pid_t pid, char **unit) {
1352 _cleanup_free_ char *cgroup = NULL;
1353 int r;
1354
1355 assert(unit);
1356
1357 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1358 if (r < 0)
1359 return r;
1360
1361 return cg_path_get_user_unit(cgroup, unit);
1362 }
1363
1364 int cg_path_get_machine_name(const char *path, char **machine) {
1365 _cleanup_free_ char *u = NULL, *sl = NULL;
1366 int r;
1367
1368 r = cg_path_get_unit(path, &u);
1369 if (r < 0)
1370 return r;
1371
1372 sl = strjoin("/run/systemd/machines/unit:", u, NULL);
1373 if (!sl)
1374 return -ENOMEM;
1375
1376 return readlink_malloc(sl, machine);
1377 }
1378
1379 int cg_pid_get_machine_name(pid_t pid, char **machine) {
1380 _cleanup_free_ char *cgroup = NULL;
1381 int r;
1382
1383 assert(machine);
1384
1385 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1386 if (r < 0)
1387 return r;
1388
1389 return cg_path_get_machine_name(cgroup, machine);
1390 }
1391
1392 int cg_path_get_session(const char *path, char **session) {
1393 _cleanup_free_ char *unit = NULL;
1394 char *start, *end;
1395 int r;
1396
1397 assert(path);
1398
1399 r = cg_path_get_unit(path, &unit);
1400 if (r < 0)
1401 return r;
1402
1403 start = startswith(unit, "session-");
1404 if (!start)
1405 return -ENXIO;
1406 end = endswith(start, ".scope");
1407 if (!end)
1408 return -ENXIO;
1409
1410 *end = 0;
1411 if (!session_id_valid(start))
1412 return -ENXIO;
1413
1414 if (session) {
1415 char *rr;
1416
1417 rr = strdup(start);
1418 if (!rr)
1419 return -ENOMEM;
1420
1421 *session = rr;
1422 }
1423
1424 return 0;
1425 }
1426
1427 int cg_pid_get_session(pid_t pid, char **session) {
1428 _cleanup_free_ char *cgroup = NULL;
1429 int r;
1430
1431 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1432 if (r < 0)
1433 return r;
1434
1435 return cg_path_get_session(cgroup, session);
1436 }
1437
1438 int cg_path_get_owner_uid(const char *path, uid_t *uid) {
1439 _cleanup_free_ char *slice = NULL;
1440 char *start, *end;
1441 int r;
1442
1443 assert(path);
1444
1445 r = cg_path_get_slice(path, &slice);
1446 if (r < 0)
1447 return r;
1448
1449 start = startswith(slice, "user-");
1450 if (!start)
1451 return -ENXIO;
1452 end = endswith(start, ".slice");
1453 if (!end)
1454 return -ENXIO;
1455
1456 *end = 0;
1457 if (parse_uid(start, uid) < 0)
1458 return -ENXIO;
1459
1460 return 0;
1461 }
1462
1463 int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
1464 _cleanup_free_ char *cgroup = NULL;
1465 int r;
1466
1467 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1468 if (r < 0)
1469 return r;
1470
1471 return cg_path_get_owner_uid(cgroup, uid);
1472 }
1473
1474 int cg_path_get_slice(const char *p, char **slice) {
1475 const char *e = NULL;
1476
1477 assert(p);
1478 assert(slice);
1479
1480 /* Finds the right-most slice unit from the beginning, but
1481 * stops before we come to the first non-slice unit. */
1482
1483 for (;;) {
1484 size_t n;
1485
1486 p += strspn(p, "/");
1487
1488 n = strcspn(p, "/");
1489 if (!valid_slice_name(p, n)) {
1490
1491 if (!e) {
1492 char *s;
1493
1494 s = strdup("-.slice");
1495 if (!s)
1496 return -ENOMEM;
1497
1498 *slice = s;
1499 return 0;
1500 }
1501
1502 return cg_path_decode_unit(e, slice);
1503 }
1504
1505 e = p;
1506 p += n;
1507 }
1508 }
1509
1510 int cg_pid_get_slice(pid_t pid, char **slice) {
1511 _cleanup_free_ char *cgroup = NULL;
1512 int r;
1513
1514 assert(slice);
1515
1516 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1517 if (r < 0)
1518 return r;
1519
1520 return cg_path_get_slice(cgroup, slice);
1521 }
1522
1523 int cg_path_get_user_slice(const char *p, char **slice) {
1524 const char *t;
1525 assert(p);
1526 assert(slice);
1527
1528 t = skip_user_prefix(p);
1529 if (!t)
1530 return -ENXIO;
1531
1532 /* And now it looks pretty much the same as for a system
1533 * slice, so let's just use the same parser from here on. */
1534 return cg_path_get_slice(t, slice);
1535 }
1536
1537 int cg_pid_get_user_slice(pid_t pid, char **slice) {
1538 _cleanup_free_ char *cgroup = NULL;
1539 int r;
1540
1541 assert(slice);
1542
1543 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1544 if (r < 0)
1545 return r;
1546
1547 return cg_path_get_user_slice(cgroup, slice);
1548 }
1549
1550 char *cg_escape(const char *p) {
1551 bool need_prefix = false;
1552
1553 /* This implements very minimal escaping for names to be used
1554 * as file names in the cgroup tree: any name which might
1555 * conflict with a kernel name or is prefixed with '_' is
1556 * prefixed with a '_'. That way, when reading cgroup names it
1557 * is sufficient to remove a single prefixing underscore if
1558 * there is one. */
1559
1560 /* The return value of this function (unlike cg_unescape())
1561 * needs free()! */
1562
1563 if (p[0] == 0 ||
1564 p[0] == '_' ||
1565 p[0] == '.' ||
1566 streq(p, "notify_on_release") ||
1567 streq(p, "release_agent") ||
1568 streq(p, "tasks"))
1569 need_prefix = true;
1570 else {
1571 const char *dot;
1572
1573 dot = strrchr(p, '.');
1574 if (dot) {
1575
1576 if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0)
1577 need_prefix = true;
1578 else {
1579 char *n;
1580
1581 n = strndupa(p, dot - p);
1582
1583 if (check_hierarchy(n) >= 0)
1584 need_prefix = true;
1585 }
1586 }
1587 }
1588
1589 if (need_prefix)
1590 return strappend("_", p);
1591 else
1592 return strdup(p);
1593 }
1594
1595 char *cg_unescape(const char *p) {
1596 assert(p);
1597
1598 /* The return value of this function (unlike cg_escape())
1599 * doesn't need free()! */
1600
1601 if (p[0] == '_')
1602 return (char*) p+1;
1603
1604 return (char*) p;
1605 }
1606
1607 #define CONTROLLER_VALID \
1608 DIGITS LETTERS \
1609 "_"
1610
1611 bool cg_controller_is_valid(const char *p) {
1612 const char *t, *s;
1613
1614 if (!p)
1615 return false;
1616
1617 s = startswith(p, "name=");
1618 if (s)
1619 p = s;
1620
1621 if (*p == 0 || *p == '_')
1622 return false;
1623
1624 for (t = p; *t; t++)
1625 if (!strchr(CONTROLLER_VALID, *t))
1626 return false;
1627
1628 if (t - p > FILENAME_MAX)
1629 return false;
1630
1631 return true;
1632 }
1633
1634 int cg_slice_to_path(const char *unit, char **ret) {
1635 _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
1636 const char *dash;
1637 int r;
1638
1639 assert(unit);
1640 assert(ret);
1641
1642 if (streq(unit, "-.slice")) {
1643 char *x;
1644
1645 x = strdup("");
1646 if (!x)
1647 return -ENOMEM;
1648 *ret = x;
1649 return 0;
1650 }
1651
1652 if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
1653 return -EINVAL;
1654
1655 if (!endswith(unit, ".slice"))
1656 return -EINVAL;
1657
1658 r = unit_name_to_prefix(unit, &p);
1659 if (r < 0)
1660 return r;
1661
1662 dash = strchr(p, '-');
1663
1664 /* Don't allow initial dashes */
1665 if (dash == p)
1666 return -EINVAL;
1667
1668 while (dash) {
1669 _cleanup_free_ char *escaped = NULL;
1670 char n[dash - p + sizeof(".slice")];
1671
1672 /* Don't allow trailing or double dashes */
1673 if (dash[1] == 0 || dash[1] == '-')
1674 return -EINVAL;
1675
1676 strcpy(stpncpy(n, p, dash - p), ".slice");
1677 if (!unit_name_is_valid(n, UNIT_NAME_PLAIN))
1678 return -EINVAL;
1679
1680 escaped = cg_escape(n);
1681 if (!escaped)
1682 return -ENOMEM;
1683
1684 if (!strextend(&s, escaped, "/", NULL))
1685 return -ENOMEM;
1686
1687 dash = strchr(dash+1, '-');
1688 }
1689
1690 e = cg_escape(unit);
1691 if (!e)
1692 return -ENOMEM;
1693
1694 if (!strextend(&s, e, NULL))
1695 return -ENOMEM;
1696
1697 *ret = s;
1698 s = NULL;
1699
1700 return 0;
1701 }
1702
1703 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
1704 _cleanup_free_ char *p = NULL;
1705 int r;
1706
1707 r = cg_get_path(controller, path, attribute, &p);
1708 if (r < 0)
1709 return r;
1710
1711 return write_string_file_no_create(p, value);
1712 }
1713
1714 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) {
1715 _cleanup_free_ char *p = NULL;
1716 int r;
1717
1718 r = cg_get_path(controller, path, attribute, &p);
1719 if (r < 0)
1720 return r;
1721
1722 return read_one_line_file(p, ret);
1723 }
1724
1725 static const char mask_names[] =
1726 "cpu\0"
1727 "cpuacct\0"
1728 "blkio\0"
1729 "memory\0"
1730 "devices\0";
1731
1732 int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
1733 CGroupControllerMask bit = 1;
1734 const char *n;
1735 int r;
1736
1737 /* This one will create a cgroup in our private tree, but also
1738 * duplicate it in the trees specified in mask, and remove it
1739 * in all others */
1740
1741 /* First create the cgroup in our own hierarchy. */
1742 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
1743 if (r < 0)
1744 return r;
1745
1746 /* Then, do the same in the other hierarchies */
1747 NULSTR_FOREACH(n, mask_names) {
1748 if (mask & bit)
1749 cg_create(n, path);
1750 else if (supported & bit)
1751 cg_trim(n, path, true);
1752
1753 bit <<= 1;
1754 }
1755
1756 return 0;
1757 }
1758
1759 int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
1760 CGroupControllerMask bit = 1;
1761 const char *n;
1762 int r;
1763
1764 r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
1765 if (r < 0)
1766 return r;
1767
1768 NULSTR_FOREACH(n, mask_names) {
1769
1770 if (supported & bit) {
1771 const char *p = NULL;
1772
1773 if (path_callback)
1774 p = path_callback(bit, userdata);
1775
1776 if (!p)
1777 p = path;
1778
1779 cg_attach_fallback(n, path, pid);
1780 }
1781
1782 bit <<= 1;
1783 }
1784
1785 return 0;
1786 }
1787
1788 int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
1789 Iterator i;
1790 void *pidp;
1791 int r = 0;
1792
1793 SET_FOREACH(pidp, pids, i) {
1794 pid_t pid = PTR_TO_LONG(pidp);
1795 int q;
1796
1797 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
1798 if (q < 0)
1799 r = q;
1800 }
1801
1802 return r;
1803 }
1804
1805 int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
1806 CGroupControllerMask bit = 1;
1807 const char *n;
1808 int r;
1809
1810 if (!path_equal(from, to)) {
1811 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
1812 if (r < 0)
1813 return r;
1814 }
1815
1816 NULSTR_FOREACH(n, mask_names) {
1817 if (supported & bit) {
1818 const char *p = NULL;
1819
1820 if (to_callback)
1821 p = to_callback(bit, userdata);
1822
1823 if (!p)
1824 p = to;
1825
1826 cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, n, p, false, false);
1827 }
1828
1829 bit <<= 1;
1830 }
1831
1832 return 0;
1833 }
1834
1835 int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
1836 CGroupControllerMask bit = 1;
1837 const char *n;
1838 int r;
1839
1840 r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
1841 if (r < 0)
1842 return r;
1843
1844 NULSTR_FOREACH(n, mask_names) {
1845 if (supported & bit)
1846 cg_trim(n, path, delete_root);
1847
1848 bit <<= 1;
1849 }
1850
1851 return 0;
1852 }
1853
1854 CGroupControllerMask cg_mask_supported(void) {
1855 CGroupControllerMask bit = 1, mask = 0;
1856 const char *n;
1857
1858 NULSTR_FOREACH(n, mask_names) {
1859 if (check_hierarchy(n) >= 0)
1860 mask |= bit;
1861
1862 bit <<= 1;
1863 }
1864
1865 return mask;
1866 }
1867
1868 int cg_kernel_controllers(Set *controllers) {
1869 _cleanup_fclose_ FILE *f = NULL;
1870 char buf[LINE_MAX];
1871 int r;
1872
1873 assert(controllers);
1874
1875 f = fopen("/proc/cgroups", "re");
1876 if (!f) {
1877 if (errno == ENOENT)
1878 return 0;
1879 return -errno;
1880 }
1881
1882 /* Ignore the header line */
1883 (void) fgets(buf, sizeof(buf), f);
1884
1885 for (;;) {
1886 char *controller;
1887 int enabled = 0;
1888
1889 errno = 0;
1890 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
1891
1892 if (feof(f))
1893 break;
1894
1895 if (ferror(f) && errno)
1896 return -errno;
1897
1898 return -EBADMSG;
1899 }
1900
1901 if (!enabled) {
1902 free(controller);
1903 continue;
1904 }
1905
1906 if (!filename_is_valid(controller)) {
1907 free(controller);
1908 return -EBADMSG;
1909 }
1910
1911 r = set_consume(controllers, controller);
1912 if (r < 0)
1913 return r;
1914 }
1915
1916 return 0;
1917 }