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