chiark / gitweb /
Prep v225: Added needed udev support and re-enabled some masked cgroup functions.
[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 int cg_pid_get_user_unit(pid_t pid, char **unit) {
1361         _cleanup_free_ char *cgroup = NULL;
1362         int r;
1363
1364         assert(unit);
1365
1366         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1367         if (r < 0)
1368                 return r;
1369
1370         return cg_path_get_user_unit(cgroup, unit);
1371 }
1372
1373 int cg_path_get_machine_name(const char *path, char **machine) {
1374         _cleanup_free_ char *u = NULL, *sl = NULL;
1375         int r;
1376
1377         r = cg_path_get_unit(path, &u);
1378         if (r < 0)
1379                 return r;
1380
1381         sl = strjoin("/run/systemd/machines/unit:", u, NULL);
1382         if (!sl)
1383                 return -ENOMEM;
1384
1385         return readlink_malloc(sl, machine);
1386 }
1387
1388 int cg_pid_get_machine_name(pid_t pid, char **machine) {
1389         _cleanup_free_ char *cgroup = NULL;
1390         int r;
1391
1392         assert(machine);
1393
1394         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1395         if (r < 0)
1396                 return r;
1397
1398         return cg_path_get_machine_name(cgroup, machine);
1399 }
1400
1401 int cg_path_get_session(const char *path, char **session) {
1402         _cleanup_free_ char *unit = NULL;
1403         char *start, *end;
1404         int r;
1405
1406         assert(path);
1407
1408         r = cg_path_get_unit(path, &unit);
1409         if (r < 0)
1410                 return r;
1411
1412         start = startswith(unit, "session-");
1413         if (!start)
1414                 return -ENXIO;
1415         end = endswith(start, ".scope");
1416         if (!end)
1417                 return -ENXIO;
1418
1419         *end = 0;
1420         if (!session_id_valid(start))
1421                 return -ENXIO;
1422
1423         if (session) {
1424                 char *rr;
1425
1426                 rr = strdup(start);
1427                 if (!rr)
1428                         return -ENOMEM;
1429
1430                 *session = rr;
1431         }
1432
1433         return 0;
1434 }
1435
1436 int cg_pid_get_session(pid_t pid, char **session) {
1437         _cleanup_free_ char *cgroup = NULL;
1438         int r;
1439
1440         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1441         if (r < 0)
1442                 return r;
1443
1444         return cg_path_get_session(cgroup, session);
1445 }
1446
1447 int cg_path_get_owner_uid(const char *path, uid_t *uid) {
1448         _cleanup_free_ char *slice = NULL;
1449         char *start, *end;
1450         int r;
1451
1452         assert(path);
1453
1454         r = cg_path_get_slice(path, &slice);
1455         if (r < 0)
1456                 return r;
1457
1458         start = startswith(slice, "user-");
1459         if (!start)
1460                 return -ENXIO;
1461         end = endswith(start, ".slice");
1462         if (!end)
1463                 return -ENXIO;
1464
1465         *end = 0;
1466         if (parse_uid(start, uid) < 0)
1467                 return -ENXIO;
1468
1469         return 0;
1470 }
1471
1472 int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
1473         _cleanup_free_ char *cgroup = NULL;
1474         int r;
1475
1476         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1477         if (r < 0)
1478                 return r;
1479
1480         return cg_path_get_owner_uid(cgroup, uid);
1481 }
1482
1483 int cg_path_get_slice(const char *p, char **slice) {
1484         const char *e = NULL;
1485
1486         assert(p);
1487         assert(slice);
1488
1489         /* Finds the right-most slice unit from the beginning, but
1490          * stops before we come to the first non-slice unit. */
1491
1492         for (;;) {
1493                 size_t n;
1494
1495                 p += strspn(p, "/");
1496
1497                 n = strcspn(p, "/");
1498                 if (!valid_slice_name(p, n)) {
1499
1500                         if (!e) {
1501                                 char *s;
1502
1503                                 s = strdup("-.slice");
1504                                 if (!s)
1505                                         return -ENOMEM;
1506
1507                                 *slice = s;
1508                                 return 0;
1509                         }
1510
1511                         return cg_path_decode_unit(e, slice);
1512                 }
1513
1514                 e = p;
1515                 p += n;
1516         }
1517 }
1518
1519 int cg_pid_get_slice(pid_t pid, char **slice) {
1520         _cleanup_free_ char *cgroup = NULL;
1521         int r;
1522
1523         assert(slice);
1524
1525         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1526         if (r < 0)
1527                 return r;
1528
1529         return cg_path_get_slice(cgroup, slice);
1530 }
1531
1532 int cg_path_get_user_slice(const char *p, char **slice) {
1533         const char *t;
1534         assert(p);
1535         assert(slice);
1536
1537         t = skip_user_prefix(p);
1538         if (!t)
1539                 return -ENXIO;
1540
1541         /* And now it looks pretty much the same as for a system
1542          * slice, so let's just use the same parser from here on. */
1543         return cg_path_get_slice(t, slice);
1544 }
1545
1546 int cg_pid_get_user_slice(pid_t pid, char **slice) {
1547         _cleanup_free_ char *cgroup = NULL;
1548         int r;
1549
1550         assert(slice);
1551
1552         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1553         if (r < 0)
1554                 return r;
1555
1556         return cg_path_get_user_slice(cgroup, slice);
1557 }
1558
1559 char *cg_escape(const char *p) {
1560         bool need_prefix = false;
1561
1562         /* This implements very minimal escaping for names to be used
1563          * as file names in the cgroup tree: any name which might
1564          * conflict with a kernel name or is prefixed with '_' is
1565          * prefixed with a '_'. That way, when reading cgroup names it
1566          * is sufficient to remove a single prefixing underscore if
1567          * there is one. */
1568
1569         /* The return value of this function (unlike cg_unescape())
1570          * needs free()! */
1571
1572         if (p[0] == 0 ||
1573             p[0] == '_' ||
1574             p[0] == '.' ||
1575             streq(p, "notify_on_release") ||
1576             streq(p, "release_agent") ||
1577             streq(p, "tasks"))
1578                 need_prefix = true;
1579         else {
1580                 const char *dot;
1581
1582                 dot = strrchr(p, '.');
1583                 if (dot) {
1584
1585                         if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0)
1586                                 need_prefix = true;
1587                         else {
1588                                 char *n;
1589
1590                                 n = strndupa(p, dot - p);
1591
1592                                 if (check_hierarchy(n) >= 0)
1593                                         need_prefix = true;
1594                         }
1595                 }
1596         }
1597
1598         if (need_prefix)
1599                 return strappend("_", p);
1600         else
1601                 return strdup(p);
1602 }
1603
1604 char *cg_unescape(const char *p) {
1605         assert(p);
1606
1607         /* The return value of this function (unlike cg_escape())
1608          * doesn't need free()! */
1609
1610         if (p[0] == '_')
1611                 return (char*) p+1;
1612
1613         return (char*) p;
1614 }
1615
1616 #define CONTROLLER_VALID                        \
1617         DIGITS LETTERS                          \
1618         "_"
1619
1620 bool cg_controller_is_valid(const char *p) {
1621         const char *t, *s;
1622
1623         if (!p)
1624                 return false;
1625
1626         s = startswith(p, "name=");
1627         if (s)
1628                 p = s;
1629
1630         if (*p == 0 || *p == '_')
1631                 return false;
1632
1633         for (t = p; *t; t++)
1634                 if (!strchr(CONTROLLER_VALID, *t))
1635                         return false;
1636
1637         if (t - p > FILENAME_MAX)
1638                 return false;
1639
1640         return true;
1641 }
1642
1643 /// UNNEEDED by elogind
1644 #if 0
1645 int cg_slice_to_path(const char *unit, char **ret) {
1646         _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
1647         const char *dash;
1648         int r;
1649
1650         assert(unit);
1651         assert(ret);
1652
1653         if (streq(unit, "-.slice")) {
1654                 char *x;
1655
1656                 x = strdup("");
1657                 if (!x)
1658                         return -ENOMEM;
1659                 *ret = x;
1660                 return 0;
1661         }
1662
1663         if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
1664                 return -EINVAL;
1665
1666         if (!endswith(unit, ".slice"))
1667                 return -EINVAL;
1668
1669         r = unit_name_to_prefix(unit, &p);
1670         if (r < 0)
1671                 return r;
1672
1673         dash = strchr(p, '-');
1674
1675         /* Don't allow initial dashes */
1676         if (dash == p)
1677                 return -EINVAL;
1678
1679         while (dash) {
1680                 _cleanup_free_ char *escaped = NULL;
1681                 char n[dash - p + sizeof(".slice")];
1682
1683                 /* Don't allow trailing or double dashes */
1684                 if (dash[1] == 0 || dash[1] == '-')
1685                         return -EINVAL;
1686
1687                 strcpy(stpncpy(n, p, dash - p), ".slice");
1688                 if (!unit_name_is_valid(n, UNIT_NAME_PLAIN))
1689                         return -EINVAL;
1690
1691                 escaped = cg_escape(n);
1692                 if (!escaped)
1693                         return -ENOMEM;
1694
1695                 if (!strextend(&s, escaped, "/", NULL))
1696                         return -ENOMEM;
1697
1698                 dash = strchr(dash+1, '-');
1699         }
1700
1701         e = cg_escape(unit);
1702         if (!e)
1703                 return -ENOMEM;
1704
1705         if (!strextend(&s, e, NULL))
1706                 return -ENOMEM;
1707
1708         *ret = s;
1709         s = NULL;
1710
1711         return 0;
1712 }
1713
1714 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
1715         _cleanup_free_ char *p = NULL;
1716         int r;
1717
1718         r = cg_get_path(controller, path, attribute, &p);
1719         if (r < 0)
1720                 return r;
1721
1722         return write_string_file_no_create(p, value);
1723 }
1724
1725 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) {
1726         _cleanup_free_ char *p = NULL;
1727         int r;
1728
1729         r = cg_get_path(controller, path, attribute, &p);
1730         if (r < 0)
1731                 return r;
1732
1733         return read_one_line_file(p, ret);
1734 }
1735 #endif // 0
1736
1737 static const char mask_names[] =
1738         "cpu\0"
1739         "cpuacct\0"
1740         "blkio\0"
1741         "memory\0"
1742         "devices\0";
1743
1744 /// UNNEEDED by elogind
1745 #if 0
1746 int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
1747         CGroupControllerMask bit = 1;
1748         const char *n;
1749         int r;
1750
1751         /* This one will create a cgroup in our private tree, but also
1752          * duplicate it in the trees specified in mask, and remove it
1753          * in all others */
1754
1755         /* First create the cgroup in our own hierarchy. */
1756         r = cg_create(ELOGIND_CGROUP_CONTROLLER, path);
1757         if (r < 0)
1758                 return r;
1759
1760         /* Then, do the same in the other hierarchies */
1761         NULSTR_FOREACH(n, mask_names) {
1762                 if (mask & bit)
1763                         cg_create(n, path);
1764                 else if (supported & bit)
1765                         cg_trim(n, path, true);
1766
1767                 bit <<= 1;
1768         }
1769
1770         return 0;
1771 }
1772 #endif // 0
1773
1774 int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
1775         CGroupControllerMask bit = 1;
1776         const char *n;
1777         int r;
1778
1779         r = cg_attach(ELOGIND_CGROUP_CONTROLLER, path, pid);
1780         if (r < 0)
1781                 return r;
1782
1783         NULSTR_FOREACH(n, mask_names) {
1784
1785                 if (supported & bit) {
1786                         const char *p = NULL;
1787
1788                         if (path_callback)
1789                                 p = path_callback(bit, userdata);
1790
1791                         if (!p)
1792                                 p = path;
1793
1794                         cg_attach_fallback(n, p, pid);
1795                 }
1796
1797                 bit <<= 1;
1798         }
1799
1800         return 0;
1801 }
1802
1803 /// UNNEEDED by elogind
1804 #if 0
1805 int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
1806         Iterator i;
1807         void *pidp;
1808         int r = 0;
1809
1810         SET_FOREACH(pidp, pids, i) {
1811                 pid_t pid = PTR_TO_LONG(pidp);
1812                 int q;
1813
1814                 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
1815                 if (q < 0)
1816                         r = q;
1817         }
1818
1819         return r;
1820 }
1821
1822 int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
1823         CGroupControllerMask bit = 1;
1824         const char *n;
1825         int r;
1826
1827         if (!path_equal(from, to))  {
1828                 r = cg_migrate_recursive(ELOGIND_CGROUP_CONTROLLER, from, ELOGIND_CGROUP_CONTROLLER, to, false, true);
1829                 if (r < 0)
1830                         return r;
1831         }
1832
1833         NULSTR_FOREACH(n, mask_names) {
1834                 if (supported & bit) {
1835                         const char *p = NULL;
1836
1837                         if (to_callback)
1838                                 p = to_callback(bit, userdata);
1839
1840                         if (!p)
1841                                 p = to;
1842
1843                         cg_migrate_recursive_fallback(ELOGIND_CGROUP_CONTROLLER, to, n, p, false, false);
1844                 }
1845
1846                 bit <<= 1;
1847         }
1848
1849         return 0;
1850 }
1851
1852 int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
1853         CGroupControllerMask bit = 1;
1854         const char *n;
1855         int r;
1856
1857         r = cg_trim(ELOGIND_CGROUP_CONTROLLER, path, delete_root);
1858         if (r < 0)
1859                 return r;
1860
1861         NULSTR_FOREACH(n, mask_names) {
1862                 if (supported & bit)
1863                         cg_trim(n, path, delete_root);
1864
1865                 bit <<= 1;
1866         }
1867
1868         return 0;
1869 }
1870
1871 CGroupControllerMask cg_mask_supported(void) {
1872         CGroupControllerMask bit = 1, mask = 0;
1873         const char *n;
1874
1875         NULSTR_FOREACH(n, mask_names) {
1876                 if (check_hierarchy(n) >= 0)
1877                         mask |= bit;
1878
1879                 bit <<= 1;
1880         }
1881
1882         return mask;
1883 }
1884
1885 int cg_kernel_controllers(Set *controllers) {
1886         _cleanup_fclose_ FILE *f = NULL;
1887         char buf[LINE_MAX];
1888         int r;
1889
1890         assert(controllers);
1891
1892         f = fopen("/proc/cgroups", "re");
1893         if (!f) {
1894                 if (errno == ENOENT)
1895                         return 0;
1896                 return -errno;
1897         }
1898
1899         /* Ignore the header line */
1900         (void) fgets(buf, sizeof(buf), f);
1901
1902         for (;;) {
1903                 char *controller;
1904                 int enabled = 0;
1905
1906                 errno = 0;
1907                 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
1908
1909                         if (feof(f))
1910                                 break;
1911
1912                         if (ferror(f) && errno)
1913                                 return -errno;
1914
1915                         return -EBADMSG;
1916                 }
1917
1918                 if (!enabled) {
1919                         free(controller);
1920                         continue;
1921                 }
1922
1923                 if (!filename_is_valid(controller)) {
1924                         free(controller);
1925                         return -EBADMSG;
1926                 }
1927
1928                 r = set_consume(controllers, controller);
1929                 if (r < 0)
1930                         return r;
1931         }
1932
1933         return 0;
1934 }
1935 #endif // 0