chiark / gitweb /
Rename formats-util.h to format-util.h
[elogind.git] / src / basic / cgroup-util.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2010 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <dirent.h>
21 #include <errno.h>
22 #include <ftw.h>
23 //#include <limits.h>
24 #include <signal.h>
25 //#include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 //#include <sys/statfs.h>
30 #include <sys/types.h>
31 #include <sys/xattr.h>
32 #include <unistd.h>
33
34 #include "alloc-util.h"
35 #include "cgroup-util.h"
36 //#include "def.h"
37 #include "dirent-util.h"
38 #include "extract-word.h"
39 #include "fd-util.h"
40 #include "fileio.h"
41 #include "format-util.h"
42 #include "fs-util.h"
43 //#include "log.h"
44 #include "login-util.h"
45 #include "macro.h"
46 //#include "missing.h"
47 #include "mkdir.h"
48 #include "parse-util.h"
49 #include "path-util.h"
50 #include "proc-cmdline.h"
51 #include "process-util.h"
52 #include "set.h"
53 //#include "special.h"
54 #include "stat-util.h"
55 #include "stdio-util.h"
56 #include "string-table.h"
57 #include "string-util.h"
58 #include "unit-name.h"
59 #include "user-util.h"
60
61 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
62         _cleanup_free_ char *fs = NULL;
63         FILE *f;
64         int r;
65
66         assert(_f);
67
68         r = cg_get_path(controller, path, "cgroup.procs", &fs);
69         if (r < 0)
70                 return r;
71
72         f = fopen(fs, "re");
73         if (!f)
74                 return -errno;
75
76         *_f = f;
77         return 0;
78 }
79
80 int cg_read_pid(FILE *f, pid_t *_pid) {
81         unsigned long ul;
82
83         /* Note that the cgroup.procs might contain duplicates! See
84          * cgroups.txt for details. */
85
86         assert(f);
87         assert(_pid);
88
89         errno = 0;
90         if (fscanf(f, "%lu", &ul) != 1) {
91
92                 if (feof(f))
93                         return 0;
94
95                 return errno > 0 ? -errno : -EIO;
96         }
97
98         if (ul <= 0)
99                 return -EIO;
100
101         *_pid = (pid_t) ul;
102         return 1;
103 }
104
105 int cg_read_event(const char *controller, const char *path, const char *event,
106                   char **val)
107 {
108         _cleanup_free_ char *events = NULL, *content = NULL;
109         char *p, *line;
110         int r;
111
112         r = cg_get_path(controller, path, "cgroup.events", &events);
113         if (r < 0)
114                 return r;
115
116         r = read_full_file(events, &content, NULL);
117         if (r < 0)
118                 return r;
119
120         p = content;
121         while ((line = strsep(&p, "\n"))) {
122                 char *key;
123
124                 key = strsep(&line, " ");
125                 if (!key || !line)
126                         return -EINVAL;
127
128                 if (strcmp(key, event))
129                         continue;
130
131                 *val = strdup(line);
132                 return 0;
133         }
134
135         return -ENOENT;
136 }
137
138 #if 0 /// UNNEEDED by elogind
139 bool cg_ns_supported(void) {
140         static thread_local int enabled = -1;
141
142         if (enabled >= 0)
143                 return enabled;
144
145         if (access("/proc/self/ns/cgroup", F_OK) == 0)
146                 enabled = 1;
147         else
148                 enabled = 0;
149
150         return enabled;
151 }
152 #endif //0
153
154 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
155         _cleanup_free_ char *fs = NULL;
156         int r;
157         DIR *d;
158
159         assert(_d);
160
161         /* This is not recursive! */
162
163         r = cg_get_path(controller, path, NULL, &fs);
164         if (r < 0)
165                 return r;
166
167         d = opendir(fs);
168         if (!d)
169                 return -errno;
170
171         *_d = d;
172         return 0;
173 }
174
175 int cg_read_subgroup(DIR *d, char **fn) {
176         struct dirent *de;
177
178         assert(d);
179         assert(fn);
180
181         FOREACH_DIRENT_ALL(de, d, return -errno) {
182                 char *b;
183
184                 if (de->d_type != DT_DIR)
185                         continue;
186
187                 if (streq(de->d_name, ".") ||
188                     streq(de->d_name, ".."))
189                         continue;
190
191                 b = strdup(de->d_name);
192                 if (!b)
193                         return -ENOMEM;
194
195                 *fn = b;
196                 return 1;
197         }
198
199         return 0;
200 }
201
202 int cg_rmdir(const char *controller, const char *path) {
203         _cleanup_free_ char *p = NULL;
204         int r;
205
206         r = cg_get_path(controller, path, NULL, &p);
207         if (r < 0)
208                 return r;
209
210         r = rmdir(p);
211         if (r < 0 && errno != ENOENT)
212                 return -errno;
213
214         return 0;
215 }
216
217 int cg_kill(
218                 const char *controller,
219                 const char *path,
220                 int sig,
221                 CGroupFlags flags,
222                 Set *s,
223                 cg_kill_log_func_t log_kill,
224                 void *userdata) {
225
226         _cleanup_set_free_ Set *allocated_set = NULL;
227         bool done = false;
228         int r, ret = 0;
229         pid_t my_pid;
230
231         assert(sig >= 0);
232
233          /* Don't send SIGCONT twice. Also, SIGKILL always works even when process is suspended, hence don't send
234           * SIGCONT on SIGKILL. */
235         if (IN_SET(sig, SIGCONT, SIGKILL))
236                 flags &= ~CGROUP_SIGCONT;
237
238         /* This goes through the tasks list and kills them all. This
239          * is repeated until no further processes are added to the
240          * tasks list, to properly handle forking processes */
241
242         if (!s) {
243                 s = allocated_set = set_new(NULL);
244                 if (!s)
245                         return -ENOMEM;
246         }
247
248         my_pid = getpid();
249
250         do {
251                 _cleanup_fclose_ FILE *f = NULL;
252                 pid_t pid = 0;
253                 done = true;
254
255                 r = cg_enumerate_processes(controller, path, &f);
256                 if (r < 0) {
257                         if (ret >= 0 && r != -ENOENT)
258                                 return r;
259
260                         return ret;
261                 }
262
263                 while ((r = cg_read_pid(f, &pid)) > 0) {
264
265                         if ((flags & CGROUP_IGNORE_SELF) && pid == my_pid)
266                                 continue;
267
268                         if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
269                                 continue;
270
271                         if (log_kill)
272                                 log_kill(pid, sig, userdata);
273
274                         /* If we haven't killed this process yet, kill
275                          * it */
276                         if (kill(pid, sig) < 0) {
277                                 if (ret >= 0 && errno != ESRCH)
278                                         ret = -errno;
279                         } else {
280                                 if (flags & CGROUP_SIGCONT)
281                                         (void) kill(pid, SIGCONT);
282
283                                 if (ret == 0)
284                                         ret = 1;
285                         }
286
287                         done = false;
288
289                         r = set_put(s, PID_TO_PTR(pid));
290                         if (r < 0) {
291                                 if (ret >= 0)
292                                         return r;
293
294                                 return ret;
295                         }
296                 }
297
298                 if (r < 0) {
299                         if (ret >= 0)
300                                 return r;
301
302                         return ret;
303                 }
304
305                 /* To avoid racing against processes which fork
306                  * quicker than we can kill them we repeat this until
307                  * no new pids need to be killed. */
308
309         } while (!done);
310
311         return ret;
312 }
313
314 int cg_kill_recursive(
315                 const char *controller,
316                 const char *path,
317                 int sig,
318                 CGroupFlags flags,
319                 Set *s,
320                 cg_kill_log_func_t log_kill,
321                 void *userdata) {
322
323         _cleanup_set_free_ Set *allocated_set = NULL;
324         _cleanup_closedir_ DIR *d = NULL;
325         int r, ret;
326         char *fn;
327
328         assert(path);
329         assert(sig >= 0);
330
331         if (!s) {
332                 s = allocated_set = set_new(NULL);
333                 if (!s)
334                         return -ENOMEM;
335         }
336
337         ret = cg_kill(controller, path, sig, flags, s, log_kill, userdata);
338
339         r = cg_enumerate_subgroups(controller, path, &d);
340         if (r < 0) {
341                 if (ret >= 0 && r != -ENOENT)
342                         return r;
343
344                 return ret;
345         }
346
347         while ((r = cg_read_subgroup(d, &fn)) > 0) {
348                 _cleanup_free_ char *p = NULL;
349
350                 p = strjoin(path, "/", fn);
351                 free(fn);
352                 if (!p)
353                         return -ENOMEM;
354
355                 r = cg_kill_recursive(controller, p, sig, flags, s, log_kill, userdata);
356                 if (r != 0 && ret >= 0)
357                         ret = r;
358         }
359         if (ret >= 0 && r < 0)
360                 ret = r;
361
362         if (flags & CGROUP_REMOVE) {
363                 r = cg_rmdir(controller, path);
364                 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
365                         return r;
366         }
367
368         return ret;
369 }
370
371 int cg_migrate(
372                 const char *cfrom,
373                 const char *pfrom,
374                 const char *cto,
375                 const char *pto,
376                 CGroupFlags flags) {
377
378         bool done = false;
379         _cleanup_set_free_ Set *s = NULL;
380         int r, ret = 0;
381         pid_t my_pid;
382
383         assert(cfrom);
384         assert(pfrom);
385         assert(cto);
386         assert(pto);
387
388         s = set_new(NULL);
389         if (!s)
390                 return -ENOMEM;
391
392         my_pid = getpid();
393
394         log_debug_elogind("Migrating \"%s\"/\"%s\" to \"%s\"/\"%s\" (%s)",
395                           cfrom, pfrom, cto, pto,
396                           (flags & CGROUP_IGNORE_SELF)
397                           ? "ignoring self" : "watching self");
398         do {
399                 _cleanup_fclose_ FILE *f = NULL;
400                 pid_t pid = 0;
401                 done = true;
402
403                 r = cg_enumerate_processes(cfrom, pfrom, &f);
404                 if (r < 0) {
405                         if (ret >= 0 && r != -ENOENT)
406                                 return r;
407
408                         return ret;
409                 }
410
411                 while ((r = cg_read_pid(f, &pid)) > 0) {
412
413                         /* This might do weird stuff if we aren't a
414                          * single-threaded program. However, we
415                          * luckily know we are not */
416                         if ((flags & CGROUP_IGNORE_SELF) && pid == my_pid)
417                                 continue;
418
419                         if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
420                                 continue;
421
422                         /* Ignore kernel threads. Since they can only
423                          * exist in the root cgroup, we only check for
424                          * them there. */
425                         if (cfrom &&
426                             (isempty(pfrom) || path_equal(pfrom, "/")) &&
427                             is_kernel_thread(pid) > 0)
428                                 continue;
429
430                         r = cg_attach(cto, pto, pid);
431                         if (r < 0) {
432                                 if (ret >= 0 && r != -ESRCH)
433                                         ret = r;
434                         } else if (ret == 0)
435                                 ret = 1;
436
437                         done = false;
438
439                         r = set_put(s, PID_TO_PTR(pid));
440                         if (r < 0) {
441                                 if (ret >= 0)
442                                         return r;
443
444                                 return ret;
445                         }
446                 }
447
448                 if (r < 0) {
449                         if (ret >= 0)
450                                 return r;
451
452                         return ret;
453                 }
454         } while (!done);
455
456         return ret;
457 }
458
459 int cg_migrate_recursive(
460                 const char *cfrom,
461                 const char *pfrom,
462                 const char *cto,
463                 const char *pto,
464                 CGroupFlags flags) {
465
466         _cleanup_closedir_ DIR *d = NULL;
467         int r, ret = 0;
468         char *fn;
469
470         assert(cfrom);
471         assert(pfrom);
472         assert(cto);
473         assert(pto);
474
475         ret = cg_migrate(cfrom, pfrom, cto, pto, flags);
476
477         r = cg_enumerate_subgroups(cfrom, pfrom, &d);
478         if (r < 0) {
479                 if (ret >= 0 && r != -ENOENT)
480                         return r;
481
482                 return ret;
483         }
484
485         while ((r = cg_read_subgroup(d, &fn)) > 0) {
486                 _cleanup_free_ char *p = NULL;
487
488                 p = strjoin(pfrom, "/", fn);
489                 free(fn);
490                 if (!p)
491                         return -ENOMEM;
492
493                 r = cg_migrate_recursive(cfrom, p, cto, pto, flags);
494                 if (r != 0 && ret >= 0)
495                         ret = r;
496         }
497
498         if (r < 0 && ret >= 0)
499                 ret = r;
500
501         if (flags & CGROUP_REMOVE) {
502                 r = cg_rmdir(cfrom, pfrom);
503                 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
504                         return r;
505         }
506
507         return ret;
508 }
509
510 int cg_migrate_recursive_fallback(
511                 const char *cfrom,
512                 const char *pfrom,
513                 const char *cto,
514                 const char *pto,
515                 CGroupFlags flags) {
516
517         int r;
518
519         assert(cfrom);
520         assert(pfrom);
521         assert(cto);
522         assert(pto);
523
524         r = cg_migrate_recursive(cfrom, pfrom, cto, pto, flags);
525         if (r < 0) {
526                 char prefix[strlen(pto) + 1];
527
528                 /* This didn't work? Then let's try all prefixes of the destination */
529
530                 PATH_FOREACH_PREFIX(prefix, pto) {
531                         int q;
532
533                         q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, flags);
534                         if (q >= 0)
535                                 return q;
536                 }
537         }
538
539         return r;
540 }
541
542 static const char *controller_to_dirname(const char *controller) {
543         const char *e;
544
545         assert(controller);
546
547         /* Converts a controller name to the directory name below
548          * /sys/fs/cgroup/ we want to mount it to. Effectively, this
549          * just cuts off the name= prefixed used for named
550          * hierarchies, if it is specified. */
551
552         e = startswith(controller, "name=");
553         if (e)
554                 return e;
555
556         return controller;
557 }
558
559 static int join_path_legacy(const char *controller, const char *path, const char *suffix, char **fs) {
560         const char *dn;
561         char *t = NULL;
562
563         assert(fs);
564         assert(controller);
565
566         dn = controller_to_dirname(controller);
567
568         if (isempty(path) && isempty(suffix))
569                 t = strappend("/sys/fs/cgroup/", dn);
570         else if (isempty(path))
571                 t = strjoin("/sys/fs/cgroup/", dn, "/", suffix);
572         else if (isempty(suffix))
573                 t = strjoin("/sys/fs/cgroup/", dn, "/", path);
574         else
575                 t = strjoin("/sys/fs/cgroup/", dn, "/", path, "/", suffix);
576         if (!t)
577                 return -ENOMEM;
578
579         *fs = t;
580         return 0;
581 }
582
583 static int join_path_unified(const char *path, const char *suffix, char **fs) {
584         char *t;
585
586         assert(fs);
587
588         if (isempty(path) && isempty(suffix))
589                 t = strdup("/sys/fs/cgroup");
590         else if (isempty(path))
591                 t = strappend("/sys/fs/cgroup/", suffix);
592         else if (isempty(suffix))
593                 t = strappend("/sys/fs/cgroup/", path);
594         else
595                 t = strjoin("/sys/fs/cgroup/", path, "/", suffix);
596         if (!t)
597                 return -ENOMEM;
598
599         *fs = t;
600         return 0;
601 }
602
603 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
604         int unified, r;
605
606         assert(fs);
607
608         if (!controller) {
609                 char *t;
610
611                 /* If no controller is specified, we return the path
612                  * *below* the controllers, without any prefix. */
613
614                 if (!path && !suffix)
615                         return -EINVAL;
616
617                 if (!suffix)
618                         t = strdup(path);
619                 else if (!path)
620                         t = strdup(suffix);
621                 else
622                         t = strjoin(path, "/", suffix);
623                 if (!t)
624                         return -ENOMEM;
625
626                 *fs = path_kill_slashes(t);
627                 return 0;
628         }
629
630         if (!cg_controller_is_valid(controller))
631                 return -EINVAL;
632
633         unified = cg_all_unified();
634         if (unified < 0)
635                 return unified;
636
637         if (unified > 0)
638                 r = join_path_unified(path, suffix, fs);
639         else
640                 r = join_path_legacy(controller, path, suffix, fs);
641         if (r < 0)
642                 return r;
643
644         path_kill_slashes(*fs);
645         return 0;
646 }
647
648 static int controller_is_accessible(const char *controller) {
649         int unified;
650
651         assert(controller);
652
653         /* Checks whether a specific controller is accessible,
654          * i.e. its hierarchy mounted. In the unified hierarchy all
655          * controllers are considered accessible, except for the named
656          * hierarchies */
657
658         if (!cg_controller_is_valid(controller))
659                 return -EINVAL;
660
661         unified = cg_all_unified();
662         if (unified < 0)
663                 return unified;
664         if (unified > 0) {
665                 /* We don't support named hierarchies if we are using
666                  * the unified hierarchy. */
667
668                 if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
669                         return 0;
670
671                 if (startswith(controller, "name="))
672                         return -EOPNOTSUPP;
673
674         } else {
675                 const char *cc, *dn;
676
677                 dn = controller_to_dirname(controller);
678                 cc = strjoina("/sys/fs/cgroup/", dn);
679
680                 if (laccess(cc, F_OK) < 0)
681                         return -errno;
682         }
683
684         return 0;
685 }
686
687 int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
688         int r;
689
690         assert(controller);
691         assert(fs);
692
693         /* Check if the specified controller is actually accessible */
694         r = controller_is_accessible(controller);
695         if (r < 0)
696                 return r;
697
698         return cg_get_path(controller, path, suffix, fs);
699 }
700
701 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
702         assert(path);
703         assert(sb);
704         assert(ftwbuf);
705
706         if (typeflag != FTW_DP)
707                 return 0;
708
709         if (ftwbuf->level < 1)
710                 return 0;
711
712         (void) rmdir(path);
713         return 0;
714 }
715
716 int cg_trim(const char *controller, const char *path, bool delete_root) {
717         _cleanup_free_ char *fs = NULL;
718         int r = 0;
719
720         assert(path);
721
722         r = cg_get_path(controller, path, NULL, &fs);
723         if (r < 0)
724                 return r;
725
726         errno = 0;
727         if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) {
728                 if (errno == ENOENT)
729                         r = 0;
730                 else if (errno > 0)
731                         r = -errno;
732                 else
733                         r = -EIO;
734         }
735
736         if (delete_root) {
737                 if (rmdir(fs) < 0 && errno != ENOENT)
738                         return -errno;
739         }
740
741         return r;
742 }
743
744 int cg_create(const char *controller, const char *path) {
745         _cleanup_free_ char *fs = NULL;
746         int r;
747
748         r = cg_get_path_and_check(controller, path, NULL, &fs);
749         if (r < 0)
750                 return r;
751
752         r = mkdir_parents(fs, 0755);
753         if (r < 0)
754                 return r;
755
756         if (mkdir(fs, 0755) < 0) {
757
758                 if (errno == EEXIST)
759                         return 0;
760
761                 return -errno;
762         }
763
764         return 1;
765 }
766
767 int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
768         int r, q;
769
770         assert(pid >= 0);
771
772         r = cg_create(controller, path);
773         if (r < 0)
774                 return r;
775
776         q = cg_attach(controller, path, pid);
777         if (q < 0)
778                 return q;
779
780         /* This does not remove the cgroup on failure */
781         return r;
782 }
783
784 int cg_attach(const char *controller, const char *path, pid_t pid) {
785         _cleanup_free_ char *fs = NULL;
786         char c[DECIMAL_STR_MAX(pid_t) + 2];
787         int r;
788
789         assert(path);
790         assert(pid >= 0);
791
792         r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
793         if (r < 0)
794                 return r;
795
796         if (pid == 0)
797                 pid = getpid();
798
799         xsprintf(c, PID_FMT "\n", pid);
800
801         return write_string_file(fs, c, 0);
802 }
803
804 int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
805         int r;
806
807         assert(controller);
808         assert(path);
809         assert(pid >= 0);
810
811         r = cg_attach(controller, path, pid);
812         if (r < 0) {
813                 char prefix[strlen(path) + 1];
814
815                 /* This didn't work? Then let's try all prefixes of
816                  * the destination */
817
818                 PATH_FOREACH_PREFIX(prefix, path) {
819                         int q;
820
821                         q = cg_attach(controller, prefix, pid);
822                         if (q >= 0)
823                                 return q;
824                 }
825         }
826
827         return r;
828 }
829
830 #if 0 /// UNNEEDED by elogind
831 int cg_set_group_access(
832                 const char *controller,
833                 const char *path,
834                 mode_t mode,
835                 uid_t uid,
836                 gid_t gid) {
837
838         _cleanup_free_ char *fs = NULL;
839         int r;
840
841         if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
842                 return 0;
843
844         if (mode != MODE_INVALID)
845                 mode &= 0777;
846
847         r = cg_get_path(controller, path, NULL, &fs);
848         if (r < 0)
849                 return r;
850
851         return chmod_and_chown(fs, mode, uid, gid);
852 }
853
854 int cg_set_task_access(
855                 const char *controller,
856                 const char *path,
857                 mode_t mode,
858                 uid_t uid,
859                 gid_t gid) {
860
861         _cleanup_free_ char *fs = NULL, *procs = NULL;
862         int r, unified;
863
864         assert(path);
865
866         if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
867                 return 0;
868
869         if (mode != MODE_INVALID)
870                 mode &= 0666;
871
872         r = cg_get_path(controller, path, "cgroup.procs", &fs);
873         if (r < 0)
874                 return r;
875
876         r = chmod_and_chown(fs, mode, uid, gid);
877         if (r < 0)
878                 return r;
879
880         unified = cg_unified(controller);
881         if (unified < 0)
882                 return unified;
883         if (unified)
884                 return 0;
885
886         /* Compatibility, Always keep values for "tasks" in sync with
887          * "cgroup.procs" */
888         if (cg_get_path(controller, path, "tasks", &procs) >= 0)
889                 (void) chmod_and_chown(procs, mode, uid, gid);
890
891         return 0;
892 }
893
894 int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags) {
895         _cleanup_free_ char *fs = NULL;
896         int r;
897
898         assert(path);
899         assert(name);
900         assert(value || size <= 0);
901
902         r = cg_get_path(controller, path, NULL, &fs);
903         if (r < 0)
904                 return r;
905
906         if (setxattr(fs, name, value, size, flags) < 0)
907                 return -errno;
908
909         return 0;
910 }
911
912 int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size) {
913         _cleanup_free_ char *fs = NULL;
914         ssize_t n;
915         int r;
916
917         assert(path);
918         assert(name);
919
920         r = cg_get_path(controller, path, NULL, &fs);
921         if (r < 0)
922                 return r;
923
924         n = getxattr(fs, name, value, size);
925         if (n < 0)
926                 return -errno;
927
928         return (int) n;
929 }
930 #endif // 0
931
932 int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
933         _cleanup_fclose_ FILE *f = NULL;
934         char line[LINE_MAX];
935         const char *fs;
936         size_t cs = 0;
937         int unified;
938
939         assert(path);
940         assert(pid >= 0);
941
942         if (controller) {
943                 if (!cg_controller_is_valid(controller))
944                         return -EINVAL;
945         } else
946                 controller = SYSTEMD_CGROUP_CONTROLLER;
947
948         unified = cg_unified(controller);
949         if (unified < 0)
950                 return unified;
951         if (unified == 0)
952                 cs = strlen(controller);
953
954         fs = procfs_file_alloca(pid, "cgroup");
955         log_debug_elogind("Searching for PID %u in \"%s\" (controller \"%s\")",
956                           pid, fs, controller);
957         f = fopen(fs, "re");
958         if (!f)
959                 return errno == ENOENT ? -ESRCH : -errno;
960
961         FOREACH_LINE(line, f, return -errno) {
962                 char *e, *p;
963
964                 truncate_nl(line);
965
966                 if (unified) {
967                         e = startswith(line, "0:");
968                         if (!e)
969                                 continue;
970
971                         e = strchr(e, ':');
972                         if (!e)
973                                 continue;
974                 } else {
975                         char *l;
976                         size_t k;
977                         const char *word, *state;
978                         bool found = false;
979
980                         l = strchr(line, ':');
981                         if (!l)
982                                 continue;
983
984                         l++;
985                         e = strchr(l, ':');
986                         if (!e)
987                                 continue;
988
989                         *e = 0;
990                         FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
991                                 if (k == cs && memcmp(word, controller, cs) == 0) {
992                                         found = true;
993                                         break;
994                                 }
995                         }
996
997                         if (!found)
998                                 continue;
999                 }
1000
1001                 log_debug_elogind("Found %s:%s", line, e+1);
1002                 p = strdup(e + 1);
1003                 if (!p)
1004                         return -ENOMEM;
1005
1006                 *path = p;
1007                 return 0;
1008         }
1009
1010         return -ENODATA;
1011 }
1012
1013 int cg_install_release_agent(const char *controller, const char *agent) {
1014         _cleanup_free_ char *fs = NULL, *contents = NULL;
1015         const char *sc;
1016         int r, unified;
1017
1018         assert(agent);
1019
1020         unified = cg_unified(controller);
1021         if (unified < 0)
1022                 return unified;
1023         if (unified) /* doesn't apply to unified hierarchy */
1024                 return -EOPNOTSUPP;
1025
1026         r = cg_get_path(controller, NULL, "release_agent", &fs);
1027         if (r < 0)
1028                 return r;
1029
1030         r = read_one_line_file(fs, &contents);
1031         if (r < 0)
1032                 return r;
1033
1034         sc = strstrip(contents);
1035         if (isempty(sc)) {
1036                 r = write_string_file(fs, agent, 0);
1037                 if (r < 0)
1038                         return r;
1039         } else if (!path_equal(sc, agent))
1040                 return -EEXIST;
1041
1042         fs = mfree(fs);
1043         r = cg_get_path(controller, NULL, "notify_on_release", &fs);
1044         if (r < 0)
1045                 return r;
1046
1047         contents = mfree(contents);
1048         r = read_one_line_file(fs, &contents);
1049         if (r < 0)
1050                 return r;
1051
1052         sc = strstrip(contents);
1053         if (streq(sc, "0")) {
1054                 r = write_string_file(fs, "1", 0);
1055                 if (r < 0)
1056                         return r;
1057
1058                 return 1;
1059         }
1060
1061         if (!streq(sc, "1"))
1062                 return -EIO;
1063
1064         return 0;
1065 }
1066
1067 int cg_uninstall_release_agent(const char *controller) {
1068         _cleanup_free_ char *fs = NULL;
1069         int r, unified;
1070
1071         unified = cg_unified(controller);
1072         if (unified < 0)
1073                 return unified;
1074         if (unified) /* Doesn't apply to unified hierarchy */
1075                 return -EOPNOTSUPP;
1076
1077         r = cg_get_path(controller, NULL, "notify_on_release", &fs);
1078         if (r < 0)
1079                 return r;
1080
1081         r = write_string_file(fs, "0", 0);
1082         if (r < 0)
1083                 return r;
1084
1085         fs = mfree(fs);
1086
1087         r = cg_get_path(controller, NULL, "release_agent", &fs);
1088         if (r < 0)
1089                 return r;
1090
1091         r = write_string_file(fs, "", 0);
1092         if (r < 0)
1093                 return r;
1094
1095         return 0;
1096 }
1097
1098 int cg_is_empty(const char *controller, const char *path) {
1099         _cleanup_fclose_ FILE *f = NULL;
1100         pid_t pid;
1101         int r;
1102
1103         assert(path);
1104
1105         r = cg_enumerate_processes(controller, path, &f);
1106         if (r == -ENOENT)
1107                 return 1;
1108         if (r < 0)
1109                 return r;
1110
1111         r = cg_read_pid(f, &pid);
1112         if (r < 0)
1113                 return r;
1114
1115         return r == 0;
1116 }
1117
1118 int cg_is_empty_recursive(const char *controller, const char *path) {
1119         int unified, r;
1120
1121         assert(path);
1122
1123         /* The root cgroup is always populated */
1124         if (controller && (isempty(path) || path_equal(path, "/")))
1125                 return false;
1126
1127         unified = cg_unified(controller);
1128         if (unified < 0)
1129                 return unified;
1130
1131         if (unified > 0) {
1132                 _cleanup_free_ char *t = NULL;
1133
1134                 /* On the unified hierarchy we can check empty state
1135                  * via the "populated" attribute of "cgroup.events". */
1136
1137                 r = cg_read_event(controller, path, "populated", &t);
1138                 if (r < 0)
1139                         return r;
1140
1141                 return streq(t, "0");
1142         } else {
1143                 _cleanup_closedir_ DIR *d = NULL;
1144                 char *fn;
1145
1146                 r = cg_is_empty(controller, path);
1147                 if (r <= 0)
1148                         return r;
1149
1150                 r = cg_enumerate_subgroups(controller, path, &d);
1151                 if (r == -ENOENT)
1152                         return 1;
1153                 if (r < 0)
1154                         return r;
1155
1156                 while ((r = cg_read_subgroup(d, &fn)) > 0) {
1157                         _cleanup_free_ char *p = NULL;
1158
1159                         p = strjoin(path, "/", fn);
1160                         free(fn);
1161                         if (!p)
1162                                 return -ENOMEM;
1163
1164                         r = cg_is_empty_recursive(controller, p);
1165                         if (r <= 0)
1166                                 return r;
1167                 }
1168                 if (r < 0)
1169                         return r;
1170
1171                 return true;
1172         }
1173 }
1174
1175 int cg_split_spec(const char *spec, char **controller, char **path) {
1176         char *t = NULL, *u = NULL;
1177         const char *e;
1178
1179         assert(spec);
1180
1181         if (*spec == '/') {
1182                 if (!path_is_safe(spec))
1183                         return -EINVAL;
1184
1185                 if (path) {
1186                         t = strdup(spec);
1187                         if (!t)
1188                                 return -ENOMEM;
1189
1190                         *path = path_kill_slashes(t);
1191                 }
1192
1193                 if (controller)
1194                         *controller = NULL;
1195
1196                 return 0;
1197         }
1198
1199         e = strchr(spec, ':');
1200         if (!e) {
1201                 if (!cg_controller_is_valid(spec))
1202                         return -EINVAL;
1203
1204                 if (controller) {
1205                         t = strdup(spec);
1206                         if (!t)
1207                                 return -ENOMEM;
1208
1209                         *controller = t;
1210                 }
1211
1212                 if (path)
1213                         *path = NULL;
1214
1215                 return 0;
1216         }
1217
1218         t = strndup(spec, e-spec);
1219         if (!t)
1220                 return -ENOMEM;
1221         if (!cg_controller_is_valid(t)) {
1222                 free(t);
1223                 return -EINVAL;
1224         }
1225
1226         if (isempty(e+1))
1227                 u = NULL;
1228         else {
1229                 u = strdup(e+1);
1230                 if (!u) {
1231                         free(t);
1232                         return -ENOMEM;
1233                 }
1234
1235                 if (!path_is_safe(u) ||
1236                     !path_is_absolute(u)) {
1237                         free(t);
1238                         free(u);
1239                         return -EINVAL;
1240                 }
1241
1242                 path_kill_slashes(u);
1243         }
1244
1245         if (controller)
1246                 *controller = t;
1247         else
1248                 free(t);
1249
1250         if (path)
1251                 *path = u;
1252         else
1253                 free(u);
1254
1255         return 0;
1256 }
1257
1258 int cg_mangle_path(const char *path, char **result) {
1259         _cleanup_free_ char *c = NULL, *p = NULL;
1260         char *t;
1261         int r;
1262
1263         assert(path);
1264         assert(result);
1265
1266         /* First, check if it already is a filesystem path */
1267         if (path_startswith(path, "/sys/fs/cgroup")) {
1268
1269                 t = strdup(path);
1270                 if (!t)
1271                         return -ENOMEM;
1272
1273                 *result = path_kill_slashes(t);
1274                 return 0;
1275         }
1276
1277         /* Otherwise, treat it as cg spec */
1278         r = cg_split_spec(path, &c, &p);
1279         if (r < 0)
1280                 return r;
1281
1282         return cg_get_path(c ?: SYSTEMD_CGROUP_CONTROLLER, p ?: "/", NULL, result);
1283 }
1284
1285 int cg_get_root_path(char **path) {
1286 #if 0 /// elogind does not support systemd scopes and slices
1287         char *p, *e;
1288         int r;
1289
1290         assert(path);
1291
1292         r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
1293         if (r < 0)
1294                 return r;
1295
1296         e = endswith(p, "/" SPECIAL_INIT_SCOPE);
1297         if (!e)
1298                 e = endswith(p, "/" SPECIAL_SYSTEM_SLICE); /* legacy */
1299         if (!e)
1300                 e = endswith(p, "/system"); /* even more legacy */
1301         if (e)
1302                 *e = 0;
1303
1304         *path = p;
1305         return 0;
1306 #else
1307         assert(path);
1308         return cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, path);
1309 #endif // 0
1310 }
1311
1312 int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
1313         _cleanup_free_ char *rt = NULL;
1314         char *p;
1315         int r;
1316
1317         assert(cgroup);
1318         assert(shifted);
1319
1320         if (!root) {
1321                 /* If the root was specified let's use that, otherwise
1322                  * let's determine it from PID 1 */
1323
1324                 r = cg_get_root_path(&rt);
1325                 if (r < 0)
1326                         return r;
1327
1328                 root = rt;
1329                 log_debug_elogind("Determined root path: \"%s\"", root);
1330         }
1331
1332         p = path_startswith(cgroup, root);
1333 #if 0 /// With other controllers, elogind might end up in /elogind, and *p is 0
1334         if (p && p > cgroup)
1335 #else
1336         if (p && p[0] && (p > cgroup))
1337 #endif // 0
1338                 *shifted = p - 1;
1339         else
1340                 *shifted = cgroup;
1341
1342         return 0;
1343 }
1344
1345 int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
1346         _cleanup_free_ char *raw = NULL;
1347         const char *c;
1348         int r;
1349
1350         assert(pid >= 0);
1351         assert(cgroup);
1352
1353         r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &raw);
1354         if (r < 0)
1355                 return r;
1356
1357         log_debug_elogind("Shifting path: \"%s\" (PID %u, root: \"%s\")",
1358                           raw, pid, root ? root : "NULL");
1359         r = cg_shift_path(raw, root, &c);
1360         if (r < 0)
1361                 return r;
1362
1363         if (c == raw) {
1364                 *cgroup = raw;
1365                 raw = NULL;
1366         } else {
1367                 char *n;
1368
1369                 n = strdup(c);
1370                 if (!n)
1371                         return -ENOMEM;
1372
1373                 *cgroup = n;
1374         }
1375         log_debug_elogind("Resulting cgroup:\"%s\"", *cgroup);
1376
1377         return 0;
1378 }
1379
1380 #if 0 /// UNNEEDED by elogind
1381 int cg_path_decode_unit(const char *cgroup, char **unit) {
1382         char *c, *s;
1383         size_t n;
1384
1385         assert(cgroup);
1386         assert(unit);
1387
1388         n = strcspn(cgroup, "/");
1389         if (n < 3)
1390                 return -ENXIO;
1391
1392         c = strndupa(cgroup, n);
1393         c = cg_unescape(c);
1394
1395         if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
1396                 return -ENXIO;
1397
1398         s = strdup(c);
1399         if (!s)
1400                 return -ENOMEM;
1401
1402         *unit = s;
1403         return 0;
1404 }
1405
1406 static bool valid_slice_name(const char *p, size_t n) {
1407
1408         if (!p)
1409                 return false;
1410
1411         if (n < strlen("x.slice"))
1412                 return false;
1413
1414         if (memcmp(p + n - 6, ".slice", 6) == 0) {
1415                 char buf[n+1], *c;
1416
1417                 memcpy(buf, p, n);
1418                 buf[n] = 0;
1419
1420                 c = cg_unescape(buf);
1421
1422                 return unit_name_is_valid(c, UNIT_NAME_PLAIN);
1423         }
1424
1425         return false;
1426 }
1427
1428 static const char *skip_slices(const char *p) {
1429         assert(p);
1430
1431         /* Skips over all slice assignments */
1432
1433         for (;;) {
1434                 size_t n;
1435
1436                 p += strspn(p, "/");
1437
1438                 n = strcspn(p, "/");
1439                 if (!valid_slice_name(p, n))
1440                         return p;
1441
1442                 p += n;
1443         }
1444 }
1445
1446 int cg_path_get_unit(const char *path, char **ret) {
1447         const char *e;
1448         char *unit;
1449         int r;
1450
1451         assert(path);
1452         assert(ret);
1453
1454         e = skip_slices(path);
1455
1456         r = cg_path_decode_unit(e, &unit);
1457         if (r < 0)
1458                 return r;
1459
1460         /* We skipped over the slices, don't accept any now */
1461         if (endswith(unit, ".slice")) {
1462                 free(unit);
1463                 return -ENXIO;
1464         }
1465
1466         *ret = unit;
1467         return 0;
1468 }
1469
1470 int cg_pid_get_unit(pid_t pid, char **unit) {
1471         _cleanup_free_ char *cgroup = NULL;
1472         int r;
1473
1474         assert(unit);
1475
1476         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1477         if (r < 0)
1478                 return r;
1479
1480         return cg_path_get_unit(cgroup, unit);
1481 }
1482
1483 /**
1484  * Skip session-*.scope, but require it to be there.
1485  */
1486 static const char *skip_session(const char *p) {
1487         size_t n;
1488
1489         if (isempty(p))
1490                 return NULL;
1491
1492         p += strspn(p, "/");
1493
1494         n = strcspn(p, "/");
1495         if (n < strlen("session-x.scope"))
1496                 return NULL;
1497
1498         if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) {
1499                 char buf[n - 8 - 6 + 1];
1500
1501                 memcpy(buf, p + 8, n - 8 - 6);
1502                 buf[n - 8 - 6] = 0;
1503
1504                 /* Note that session scopes never need unescaping,
1505                  * since they cannot conflict with the kernel's own
1506                  * names, hence we don't need to call cg_unescape()
1507                  * here. */
1508
1509                 if (!session_id_valid(buf))
1510                         return false;
1511
1512                 p += n;
1513                 p += strspn(p, "/");
1514                 return p;
1515         }
1516
1517         return NULL;
1518 }
1519
1520 /**
1521  * Skip user@*.service, but require it to be there.
1522  */
1523 static const char *skip_user_manager(const char *p) {
1524         size_t n;
1525
1526         if (isempty(p))
1527                 return NULL;
1528
1529         p += strspn(p, "/");
1530
1531         n = strcspn(p, "/");
1532         if (n < strlen("user@x.service"))
1533                 return NULL;
1534
1535         if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
1536                 char buf[n - 5 - 8 + 1];
1537
1538                 memcpy(buf, p + 5, n - 5 - 8);
1539                 buf[n - 5 - 8] = 0;
1540
1541                 /* Note that user manager services never need unescaping,
1542                  * since they cannot conflict with the kernel's own
1543                  * names, hence we don't need to call cg_unescape()
1544                  * here. */
1545
1546                 if (parse_uid(buf, NULL) < 0)
1547                         return NULL;
1548
1549                 p += n;
1550                 p += strspn(p, "/");
1551
1552                 return p;
1553         }
1554
1555         return NULL;
1556 }
1557
1558 static const char *skip_user_prefix(const char *path) {
1559         const char *e, *t;
1560
1561         assert(path);
1562
1563         /* Skip slices, if there are any */
1564         e = skip_slices(path);
1565
1566         /* Skip the user manager, if it's in the path now... */
1567         t = skip_user_manager(e);
1568         if (t)
1569                 return t;
1570
1571         /* Alternatively skip the user session if it is in the path... */
1572         return skip_session(e);
1573 }
1574
1575 int cg_path_get_user_unit(const char *path, char **ret) {
1576         const char *t;
1577
1578         assert(path);
1579         assert(ret);
1580
1581         t = skip_user_prefix(path);
1582         if (!t)
1583                 return -ENXIO;
1584
1585         /* And from here on it looks pretty much the same as for a
1586          * system unit, hence let's use the same parser from here
1587          * on. */
1588         return cg_path_get_unit(t, ret);
1589 }
1590
1591 int cg_pid_get_user_unit(pid_t pid, char **unit) {
1592         _cleanup_free_ char *cgroup = NULL;
1593         int r;
1594
1595         assert(unit);
1596
1597         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1598         if (r < 0)
1599                 return r;
1600
1601         return cg_path_get_user_unit(cgroup, unit);
1602 }
1603
1604 int cg_path_get_machine_name(const char *path, char **machine) {
1605         _cleanup_free_ char *u = NULL;
1606         const char *sl;
1607         int r;
1608
1609         r = cg_path_get_unit(path, &u);
1610         if (r < 0)
1611                 return r;
1612
1613         sl = strjoina("/run/systemd/machines/unit:", u);
1614         return readlink_malloc(sl, machine);
1615 }
1616
1617 int cg_pid_get_machine_name(pid_t pid, char **machine) {
1618         _cleanup_free_ char *cgroup = NULL;
1619         int r;
1620
1621         assert(machine);
1622
1623         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1624         if (r < 0)
1625                 return r;
1626
1627         return cg_path_get_machine_name(cgroup, machine);
1628 }
1629 #endif // 0
1630
1631 int cg_path_get_session(const char *path, char **session) {
1632 #if 0 /// UNNEEDED by elogind
1633         _cleanup_free_ char *unit = NULL;
1634         char *start, *end;
1635         int r;
1636
1637         assert(path);
1638
1639         r = cg_path_get_unit(path, &unit);
1640         if (r < 0)
1641                 return r;
1642
1643         start = startswith(unit, "session-");
1644         if (!start)
1645                 return -ENXIO;
1646         end = endswith(start, ".scope");
1647         if (!end)
1648                 return -ENXIO;
1649
1650         *end = 0;
1651         if (!session_id_valid(start))
1652                 return -ENXIO;
1653 #else
1654         /* Elogind uses a flat hierarchy, just "/SESSION".  The only
1655            wrinkle is that SESSION might be escaped.  */
1656         const char *e, *n, *start;
1657
1658         assert(path);
1659         log_debug_elogind("path is \"%s\"", path);
1660         assert(path[0] == '/');
1661
1662         e = path + 1;
1663         n = strchrnul(e, '/');
1664         if (e == n)
1665                 return -ENOENT;
1666
1667         start = strndupa(e, n - e);
1668         start = cg_unescape(start);
1669
1670         if (!start[0])
1671                 return -ENOENT;
1672 #endif // 0
1673
1674         if (session) {
1675                 char *rr;
1676
1677                 log_debug_elogind("found session: \"%s\"", start);
1678                 rr = strdup(start);
1679                 if (!rr)
1680                         return -ENOMEM;
1681
1682                 *session = rr;
1683         }
1684
1685         return 0;
1686 }
1687
1688 int cg_pid_get_session(pid_t pid, char **session) {
1689         _cleanup_free_ char *cgroup = NULL;
1690         int r;
1691
1692         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1693         if (r < 0)
1694                 return r;
1695
1696         return cg_path_get_session(cgroup, session);
1697 }
1698
1699 #if 0 /// UNNEEDED by elogind
1700 int cg_path_get_owner_uid(const char *path, uid_t *uid) {
1701         _cleanup_free_ char *slice = NULL;
1702         char *start, *end;
1703         int r;
1704
1705         assert(path);
1706
1707         r = cg_path_get_slice(path, &slice);
1708         if (r < 0)
1709                 return r;
1710
1711         start = startswith(slice, "user-");
1712         if (!start)
1713                 return -ENXIO;
1714         end = endswith(start, ".slice");
1715         if (!end)
1716                 return -ENXIO;
1717
1718         *end = 0;
1719         if (parse_uid(start, uid) < 0)
1720                 return -ENXIO;
1721
1722         return 0;
1723 }
1724
1725 int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
1726         _cleanup_free_ char *cgroup = NULL;
1727         int r;
1728
1729         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1730         if (r < 0)
1731                 return r;
1732
1733         return cg_path_get_owner_uid(cgroup, uid);
1734 }
1735
1736 int cg_path_get_slice(const char *p, char **slice) {
1737         const char *e = NULL;
1738
1739         assert(p);
1740         assert(slice);
1741
1742         /* Finds the right-most slice unit from the beginning, but
1743          * stops before we come to the first non-slice unit. */
1744
1745         for (;;) {
1746                 size_t n;
1747
1748                 p += strspn(p, "/");
1749
1750                 n = strcspn(p, "/");
1751                 if (!valid_slice_name(p, n)) {
1752
1753                         if (!e) {
1754                                 char *s;
1755
1756                                 s = strdup(SPECIAL_ROOT_SLICE);
1757                                 if (!s)
1758                                         return -ENOMEM;
1759
1760                                 *slice = s;
1761                                 return 0;
1762                         }
1763
1764                         return cg_path_decode_unit(e, slice);
1765                 }
1766
1767                 e = p;
1768                 p += n;
1769         }
1770 }
1771
1772 int cg_pid_get_slice(pid_t pid, char **slice) {
1773         _cleanup_free_ char *cgroup = NULL;
1774         int r;
1775
1776         assert(slice);
1777
1778         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1779         if (r < 0)
1780                 return r;
1781
1782         return cg_path_get_slice(cgroup, slice);
1783 }
1784
1785 int cg_path_get_user_slice(const char *p, char **slice) {
1786         const char *t;
1787         assert(p);
1788         assert(slice);
1789
1790         t = skip_user_prefix(p);
1791         if (!t)
1792                 return -ENXIO;
1793
1794         /* And now it looks pretty much the same as for a system
1795          * slice, so let's just use the same parser from here on. */
1796         return cg_path_get_slice(t, slice);
1797 }
1798
1799 int cg_pid_get_user_slice(pid_t pid, char **slice) {
1800         _cleanup_free_ char *cgroup = NULL;
1801         int r;
1802
1803         assert(slice);
1804
1805         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1806         if (r < 0)
1807                 return r;
1808
1809         return cg_path_get_user_slice(cgroup, slice);
1810 }
1811 #endif // 0
1812
1813 char *cg_escape(const char *p) {
1814         bool need_prefix = false;
1815
1816         /* This implements very minimal escaping for names to be used
1817          * as file names in the cgroup tree: any name which might
1818          * conflict with a kernel name or is prefixed with '_' is
1819          * prefixed with a '_'. That way, when reading cgroup names it
1820          * is sufficient to remove a single prefixing underscore if
1821          * there is one. */
1822
1823         /* The return value of this function (unlike cg_unescape())
1824          * needs free()! */
1825
1826         if (p[0] == 0 ||
1827             p[0] == '_' ||
1828             p[0] == '.' ||
1829             streq(p, "notify_on_release") ||
1830             streq(p, "release_agent") ||
1831             streq(p, "tasks") ||
1832             startswith(p, "cgroup."))
1833                 need_prefix = true;
1834         else {
1835                 const char *dot;
1836
1837                 dot = strrchr(p, '.');
1838                 if (dot) {
1839                         CGroupController c;
1840                         size_t l = dot - p;
1841
1842                         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
1843                                 const char *n;
1844
1845                                 n = cgroup_controller_to_string(c);
1846
1847                                 if (l != strlen(n))
1848                                         continue;
1849
1850                                 if (memcmp(p, n, l) != 0)
1851                                         continue;
1852
1853                                 need_prefix = true;
1854                                 break;
1855                         }
1856                 }
1857         }
1858
1859         if (need_prefix)
1860                 return strappend("_", p);
1861
1862         return strdup(p);
1863 }
1864
1865 char *cg_unescape(const char *p) {
1866         assert(p);
1867
1868         /* The return value of this function (unlike cg_escape())
1869          * doesn't need free()! */
1870
1871         if (p[0] == '_')
1872                 return (char*) p+1;
1873
1874         return (char*) p;
1875 }
1876
1877 #define CONTROLLER_VALID                        \
1878         DIGITS LETTERS                          \
1879         "_"
1880
1881 bool cg_controller_is_valid(const char *p) {
1882         const char *t, *s;
1883
1884         if (!p)
1885                 return false;
1886
1887         s = startswith(p, "name=");
1888         if (s)
1889                 p = s;
1890
1891         if (*p == 0 || *p == '_')
1892                 return false;
1893
1894         for (t = p; *t; t++)
1895                 if (!strchr(CONTROLLER_VALID, *t))
1896                         return false;
1897
1898         if (t - p > FILENAME_MAX)
1899                 return false;
1900
1901         return true;
1902 }
1903
1904 #if 0 /// UNNEEDED by elogind
1905 int cg_slice_to_path(const char *unit, char **ret) {
1906         _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
1907         const char *dash;
1908         int r;
1909
1910         assert(unit);
1911         assert(ret);
1912
1913         if (streq(unit, SPECIAL_ROOT_SLICE)) {
1914                 char *x;
1915
1916                 x = strdup("");
1917                 if (!x)
1918                         return -ENOMEM;
1919                 *ret = x;
1920                 return 0;
1921         }
1922
1923         if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
1924                 return -EINVAL;
1925
1926         if (!endswith(unit, ".slice"))
1927                 return -EINVAL;
1928
1929         r = unit_name_to_prefix(unit, &p);
1930         if (r < 0)
1931                 return r;
1932
1933         dash = strchr(p, '-');
1934
1935         /* Don't allow initial dashes */
1936         if (dash == p)
1937                 return -EINVAL;
1938
1939         while (dash) {
1940                 _cleanup_free_ char *escaped = NULL;
1941                 char n[dash - p + sizeof(".slice")];
1942
1943                 /* Don't allow trailing or double dashes */
1944                 if (dash[1] == 0 || dash[1] == '-')
1945                         return -EINVAL;
1946
1947                 strcpy(stpncpy(n, p, dash - p), ".slice");
1948                 if (!unit_name_is_valid(n, UNIT_NAME_PLAIN))
1949                         return -EINVAL;
1950
1951                 escaped = cg_escape(n);
1952                 if (!escaped)
1953                         return -ENOMEM;
1954
1955                 if (!strextend(&s, escaped, "/", NULL))
1956                         return -ENOMEM;
1957
1958                 dash = strchr(dash+1, '-');
1959         }
1960
1961         e = cg_escape(unit);
1962         if (!e)
1963                 return -ENOMEM;
1964
1965         if (!strextend(&s, e, NULL))
1966                 return -ENOMEM;
1967
1968         *ret = s;
1969         s = NULL;
1970
1971         return 0;
1972 }
1973 #endif // 0
1974
1975 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
1976         _cleanup_free_ char *p = NULL;
1977         int r;
1978
1979         r = cg_get_path(controller, path, attribute, &p);
1980         if (r < 0)
1981                 return r;
1982
1983         return write_string_file(p, value, 0);
1984 }
1985
1986 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) {
1987         _cleanup_free_ char *p = NULL;
1988         int r;
1989
1990         r = cg_get_path(controller, path, attribute, &p);
1991         if (r < 0)
1992                 return r;
1993
1994         return read_one_line_file(p, ret);
1995 }
1996
1997 #if 0 /// UNNEEDED by elogind
1998 int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, const char **keys, char **values) {
1999         _cleanup_free_ char *filename = NULL, *content = NULL;
2000         char *line, *p;
2001         int i, r;
2002
2003         for (i = 0; keys[i]; i++)
2004                 values[i] = NULL;
2005
2006         r = cg_get_path(controller, path, attribute, &filename);
2007         if (r < 0)
2008                 return r;
2009
2010         r = read_full_file(filename, &content, NULL);
2011         if (r < 0)
2012                 return r;
2013
2014         p = content;
2015         while ((line = strsep(&p, "\n"))) {
2016                 char *key;
2017
2018                 key = strsep(&line, " ");
2019
2020                 for (i = 0; keys[i]; i++) {
2021                         if (streq(key, keys[i])) {
2022                                 values[i] = strdup(line);
2023                                 break;
2024                         }
2025                 }
2026         }
2027
2028         for (i = 0; keys[i]; i++) {
2029                 if (!values[i]) {
2030                         for (i = 0; keys[i]; i++) {
2031                                 free(values[i]);
2032                                 values[i] = NULL;
2033                         }
2034                         return -ENOENT;
2035                 }
2036         }
2037
2038         return 0;
2039 }
2040
2041 int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {
2042         CGroupController c;
2043         int r, unified;
2044
2045         /* This one will create a cgroup in our private tree, but also
2046          * duplicate it in the trees specified in mask, and remove it
2047          * in all others */
2048
2049         /* First create the cgroup in our own hierarchy. */
2050         r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
2051         if (r < 0)
2052                 return r;
2053
2054         /* If we are in the unified hierarchy, we are done now */
2055         unified = cg_all_unified();
2056         if (unified < 0)
2057                 return unified;
2058         if (unified > 0)
2059                 return 0;
2060
2061         /* Otherwise, do the same in the other hierarchies */
2062         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2063                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2064                 const char *n;
2065
2066                 n = cgroup_controller_to_string(c);
2067
2068                 if (mask & bit)
2069                         (void) cg_create(n, path);
2070                 else if (supported & bit)
2071                         (void) cg_trim(n, path, true);
2072         }
2073
2074         return 0;
2075 }
2076
2077 int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
2078         CGroupController c;
2079         int r, unified;
2080
2081         r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
2082         if (r < 0)
2083                 return r;
2084
2085         unified = cg_all_unified();
2086         if (unified < 0)
2087                 return unified;
2088         if (unified > 0)
2089                 return 0;
2090
2091         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2092                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2093                 const char *p = NULL;
2094
2095                 if (!(supported & bit))
2096                         continue;
2097
2098                 if (path_callback)
2099                         p = path_callback(bit, userdata);
2100
2101                 if (!p)
2102                         p = path;
2103
2104                 (void) cg_attach_fallback(cgroup_controller_to_string(c), p, pid);
2105         }
2106
2107         return 0;
2108 }
2109
2110 int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
2111         Iterator i;
2112         void *pidp;
2113         int r = 0;
2114
2115         SET_FOREACH(pidp, pids, i) {
2116                 pid_t pid = PTR_TO_PID(pidp);
2117                 int q;
2118
2119                 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
2120                 if (q < 0 && r >= 0)
2121                         r = q;
2122         }
2123
2124         return r;
2125 }
2126
2127 int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
2128         CGroupController c;
2129         int r = 0, unified;
2130
2131         if (!path_equal(from, to))  {
2132                 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, CGROUP_REMOVE);
2133                 if (r < 0)
2134                         return r;
2135         }
2136
2137         unified = cg_all_unified();
2138         if (unified < 0)
2139                 return unified;
2140         if (unified > 0)
2141                 return r;
2142
2143         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2144                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2145                 const char *p = NULL;
2146
2147                 if (!(supported & bit))
2148                         continue;
2149
2150                 if (to_callback)
2151                         p = to_callback(bit, userdata);
2152
2153                 if (!p)
2154                         p = to;
2155
2156                 (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, 0);
2157         }
2158
2159         return 0;
2160 }
2161
2162 int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
2163         CGroupController c;
2164         int r, unified;
2165
2166         r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
2167         if (r < 0)
2168                 return r;
2169
2170         unified = cg_all_unified();
2171         if (unified < 0)
2172                 return unified;
2173         if (unified > 0)
2174                 return r;
2175
2176         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2177                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2178
2179                 if (!(supported & bit))
2180                         continue;
2181
2182                 (void) cg_trim(cgroup_controller_to_string(c), path, delete_root);
2183         }
2184
2185         return 0;
2186 }
2187 #endif // 0
2188
2189 int cg_mask_supported(CGroupMask *ret) {
2190         CGroupMask mask = 0;
2191         int r, unified;
2192
2193         /* Determines the mask of supported cgroup controllers. Only
2194          * includes controllers we can make sense of and that are
2195          * actually accessible. */
2196
2197         unified = cg_all_unified();
2198         if (unified < 0)
2199                 return unified;
2200         if (unified > 0) {
2201                 _cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
2202                 const char *c;
2203
2204                 /* In the unified hierarchy we can read the supported
2205                  * and accessible controllers from a the top-level
2206                  * cgroup attribute */
2207
2208                 r = cg_get_root_path(&root);
2209                 if (r < 0)
2210                         return r;
2211
2212                 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, "cgroup.controllers", &path);
2213                 if (r < 0)
2214                         return r;
2215
2216                 r = read_one_line_file(path, &controllers);
2217                 if (r < 0)
2218                         return r;
2219
2220                 c = controllers;
2221                 for (;;) {
2222                         _cleanup_free_ char *n = NULL;
2223                         CGroupController v;
2224
2225                         r = extract_first_word(&c, &n, NULL, 0);
2226                         if (r < 0)
2227                                 return r;
2228                         if (r == 0)
2229                                 break;
2230
2231                         v = cgroup_controller_from_string(n);
2232                         if (v < 0)
2233                                 continue;
2234
2235                         mask |= CGROUP_CONTROLLER_TO_MASK(v);
2236                 }
2237
2238                 /* Currently, we support the cpu, memory, io and pids
2239                  * controller in the unified hierarchy, mask
2240                  * everything else off. */
2241                 mask &= CGROUP_MASK_CPU | CGROUP_MASK_MEMORY | CGROUP_MASK_IO | CGROUP_MASK_PIDS;
2242
2243         } else {
2244                 CGroupController c;
2245
2246                 /* In the legacy hierarchy, we check whether which
2247                  * hierarchies are mounted. */
2248
2249                 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2250                         const char *n;
2251
2252                         n = cgroup_controller_to_string(c);
2253                         if (controller_is_accessible(n) >= 0)
2254                                 mask |= CGROUP_CONTROLLER_TO_MASK(c);
2255                 }
2256         }
2257
2258         *ret = mask;
2259         return 0;
2260 }
2261
2262 #if 0 /// UNNEEDED by elogind
2263 int cg_kernel_controllers(Set *controllers) {
2264         _cleanup_fclose_ FILE *f = NULL;
2265         char buf[LINE_MAX];
2266         int r;
2267
2268         assert(controllers);
2269
2270         /* Determines the full list of kernel-known controllers. Might
2271          * include controllers we don't actually support, arbitrary
2272          * named hierarchies and controllers that aren't currently
2273          * accessible (because not mounted). */
2274
2275         f = fopen("/proc/cgroups", "re");
2276         if (!f) {
2277                 if (errno == ENOENT)
2278                         return 0;
2279                 return -errno;
2280         }
2281
2282         /* Ignore the header line */
2283         (void) fgets(buf, sizeof(buf), f);
2284
2285         for (;;) {
2286                 char *controller;
2287                 int enabled = 0;
2288
2289                 errno = 0;
2290                 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
2291
2292                         if (feof(f))
2293                                 break;
2294
2295                         if (ferror(f) && errno > 0)
2296                                 return -errno;
2297
2298                         return -EBADMSG;
2299                 }
2300
2301                 if (!enabled) {
2302                         free(controller);
2303                         continue;
2304                 }
2305
2306                 if (!cg_controller_is_valid(controller)) {
2307                         free(controller);
2308                         return -EBADMSG;
2309                 }
2310
2311                 r = set_consume(controllers, controller);
2312                 if (r < 0)
2313                         return r;
2314         }
2315
2316         return 0;
2317 }
2318 #endif // 0
2319
2320 static thread_local CGroupUnified unified_cache = CGROUP_UNIFIED_UNKNOWN;
2321
2322 static int cg_update_unified(void) {
2323
2324         struct statfs fs;
2325
2326         /* Checks if we support the unified hierarchy. Returns an
2327          * error when the cgroup hierarchies aren't mounted yet or we
2328          * have any other trouble determining if the unified hierarchy
2329          * is supported. */
2330
2331         if (unified_cache >= CGROUP_UNIFIED_NONE)
2332                 return 0;
2333
2334         if (statfs("/sys/fs/cgroup/", &fs) < 0)
2335                 return -errno;
2336
2337 #if 0 /// UNNEEDED by elogind
2338         if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC))
2339                 unified_cache = CGROUP_UNIFIED_ALL;
2340         else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) {
2341                 if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0)
2342                         return -errno;
2343
2344                 unified_cache = F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC) ?
2345                         CGROUP_UNIFIED_SYSTEMD : CGROUP_UNIFIED_NONE;
2346         } else
2347                 return -ENOMEDIUM;
2348 #else
2349         /* elogind can not support the unified hierarchy as a controller,
2350          * so always assume a classical hierarchy.
2351          * If, and only *if*, someone really wants to substitute systemd-login
2352          * in an environment managed by systemd with elogind, we might have to
2353          * add such a support. */
2354         unified_cache = CGROUP_UNIFIED_NONE;
2355 #endif // 0
2356
2357         return 0;
2358 }
2359
2360 int cg_unified(const char *controller) {
2361
2362         int r;
2363
2364         r = cg_update_unified();
2365         if (r < 0)
2366                 return r;
2367
2368         if (streq_ptr(controller, SYSTEMD_CGROUP_CONTROLLER))
2369                 return unified_cache >= CGROUP_UNIFIED_SYSTEMD;
2370         else
2371                 return unified_cache >= CGROUP_UNIFIED_ALL;
2372 }
2373
2374 int cg_all_unified(void) {
2375
2376         return cg_unified(NULL);
2377 }
2378
2379 #if 0 /// UNNEEDED by elogind
2380 void cg_unified_flush(void) {
2381         unified_cache = CGROUP_UNIFIED_UNKNOWN;
2382 }
2383
2384 int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
2385         _cleanup_free_ char *fs = NULL;
2386         CGroupController c;
2387         int r, unified;
2388
2389         assert(p);
2390
2391         if (supported == 0)
2392                 return 0;
2393
2394         unified = cg_all_unified();
2395         if (unified < 0)
2396                 return unified;
2397         if (!unified) /* on the legacy hiearchy there's no joining of controllers defined */
2398                 return 0;
2399
2400         r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, p, "cgroup.subtree_control", &fs);
2401         if (r < 0)
2402                 return r;
2403
2404         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2405                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2406                 const char *n;
2407
2408                 if (!(supported & bit))
2409                         continue;
2410
2411                 n = cgroup_controller_to_string(c);
2412                 {
2413                         char s[1 + strlen(n) + 1];
2414
2415                         s[0] = mask & bit ? '+' : '-';
2416                         strcpy(s + 1, n);
2417
2418                         r = write_string_file(fs, s, 0);
2419                         if (r < 0)
2420                                 log_debug_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs);
2421                 }
2422         }
2423
2424         return 0;
2425 }
2426
2427 bool cg_is_unified_wanted(void) {
2428         static thread_local int wanted = -1;
2429         int r, unified;
2430
2431         /* If the hierarchy is already mounted, then follow whatever
2432          * was chosen for it. */
2433         unified = cg_all_unified();
2434         if (unified >= 0)
2435                 return unified;
2436
2437         /* Otherwise, let's see what the kernel command line has to
2438          * say. Since checking that is expensive, let's cache the
2439          * result. */
2440         if (wanted >= 0)
2441                 return wanted;
2442
2443         r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy", NULL);
2444         if (r > 0)
2445                 return (wanted = true);
2446         else {
2447                 _cleanup_free_ char *value = NULL;
2448
2449                 r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy=", &value);
2450                 if (r < 0)
2451                         return false;
2452                 if (r == 0)
2453                         return (wanted = false);
2454
2455                 return (wanted = parse_boolean(value) > 0);
2456         }
2457 }
2458
2459 bool cg_is_legacy_wanted(void) {
2460         return !cg_is_unified_wanted();
2461 }
2462
2463 bool cg_is_unified_systemd_controller_wanted(void) {
2464         static thread_local int wanted = -1;
2465         int r, unified;
2466
2467         /* If the unified hierarchy is requested in full, no need to
2468          * bother with this. */
2469         if (cg_is_unified_wanted())
2470                 return 0;
2471
2472         /* If the hierarchy is already mounted, then follow whatever
2473          * was chosen for it. */
2474         unified = cg_unified(SYSTEMD_CGROUP_CONTROLLER);
2475         if (unified >= 0)
2476                 return unified;
2477
2478         /* Otherwise, let's see what the kernel command line has to
2479          * say. Since checking that is expensive, let's cache the
2480          * result. */
2481         if (wanted >= 0)
2482                 return wanted;
2483
2484         r = get_proc_cmdline_key("systemd.legacy_systemd_cgroup_controller", NULL);
2485         if (r > 0)
2486                 wanted = false;
2487         else {
2488                 _cleanup_free_ char *value = NULL;
2489
2490                 r = get_proc_cmdline_key("systemd.legacy_systemd_cgroup_controller=", &value);
2491                 if (r < 0)
2492                         return true;
2493
2494                 if (r == 0)
2495                         wanted = true;
2496                 else
2497                         wanted = parse_boolean(value) <= 0;
2498         }
2499
2500         return wanted;
2501 }
2502
2503 bool cg_is_legacy_systemd_controller_wanted(void) {
2504         return cg_is_legacy_wanted() && !cg_is_unified_systemd_controller_wanted();
2505 }
2506 #else
2507 bool cg_is_legacy_wanted(void) {
2508         return true;
2509 }
2510 #endif // 0
2511
2512 #if 0 /// UNNEEDED by elogind
2513 int cg_weight_parse(const char *s, uint64_t *ret) {
2514         uint64_t u;
2515         int r;
2516
2517         if (isempty(s)) {
2518                 *ret = CGROUP_WEIGHT_INVALID;
2519                 return 0;
2520         }
2521
2522         r = safe_atou64(s, &u);
2523         if (r < 0)
2524                 return r;
2525
2526         if (u < CGROUP_WEIGHT_MIN || u > CGROUP_WEIGHT_MAX)
2527                 return -ERANGE;
2528
2529         *ret = u;
2530         return 0;
2531 }
2532
2533 const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX] = {
2534         [CGROUP_IO_RBPS_MAX]    = CGROUP_LIMIT_MAX,
2535         [CGROUP_IO_WBPS_MAX]    = CGROUP_LIMIT_MAX,
2536         [CGROUP_IO_RIOPS_MAX]   = CGROUP_LIMIT_MAX,
2537         [CGROUP_IO_WIOPS_MAX]   = CGROUP_LIMIT_MAX,
2538 };
2539
2540 static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] = {
2541         [CGROUP_IO_RBPS_MAX]    = "IOReadBandwidthMax",
2542         [CGROUP_IO_WBPS_MAX]    = "IOWriteBandwidthMax",
2543         [CGROUP_IO_RIOPS_MAX]   = "IOReadIOPSMax",
2544         [CGROUP_IO_WIOPS_MAX]   = "IOWriteIOPSMax",
2545 };
2546
2547 DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType);
2548
2549 int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
2550         uint64_t u;
2551         int r;
2552
2553         if (isempty(s)) {
2554                 *ret = CGROUP_CPU_SHARES_INVALID;
2555                 return 0;
2556         }
2557
2558         r = safe_atou64(s, &u);
2559         if (r < 0)
2560                 return r;
2561
2562         if (u < CGROUP_CPU_SHARES_MIN || u > CGROUP_CPU_SHARES_MAX)
2563                 return -ERANGE;
2564
2565         *ret = u;
2566         return 0;
2567 }
2568
2569 int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
2570         uint64_t u;
2571         int r;
2572
2573         if (isempty(s)) {
2574                 *ret = CGROUP_BLKIO_WEIGHT_INVALID;
2575                 return 0;
2576         }
2577
2578         r = safe_atou64(s, &u);
2579         if (r < 0)
2580                 return r;
2581
2582         if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX)
2583                 return -ERANGE;
2584
2585         *ret = u;
2586         return 0;
2587 }
2588 #endif // 0
2589
2590 bool is_cgroup_fs(const struct statfs *s) {
2591         return is_fs_type(s, CGROUP_SUPER_MAGIC) ||
2592                is_fs_type(s, CGROUP2_SUPER_MAGIC);
2593 }
2594
2595 bool fd_is_cgroup_fs(int fd) {
2596         struct statfs s;
2597
2598         if (fstatfs(fd, &s) < 0)
2599                 return -errno;
2600
2601         return is_cgroup_fs(&s);
2602 }
2603
2604 static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
2605         [CGROUP_CONTROLLER_CPU] = "cpu",
2606         [CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
2607         [CGROUP_CONTROLLER_IO] = "io",
2608         [CGROUP_CONTROLLER_BLKIO] = "blkio",
2609         [CGROUP_CONTROLLER_MEMORY] = "memory",
2610         [CGROUP_CONTROLLER_DEVICES] = "devices",
2611         [CGROUP_CONTROLLER_PIDS] = "pids",
2612 };
2613
2614 DEFINE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController);