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