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