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