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