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