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