chiark / gitweb /
Prep v234: Eventually fix the cgroup stuff. elogind is not init.
[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 #if 0 /// UNNEEDED by elogind
1092 int cg_install_release_agent(const char *controller, const char *agent) {
1093         _cleanup_free_ char *fs = NULL, *contents = NULL;
1094         const char *sc;
1095         int r;
1096
1097         assert(agent);
1098
1099         r = cg_unified_controller(controller);
1100         if (r < 0)
1101                 return r;
1102         if (r > 0) /* doesn't apply to unified hierarchy */
1103                 return -EOPNOTSUPP;
1104
1105         r = cg_get_path(controller, NULL, "release_agent", &fs);
1106         if (r < 0)
1107                 return r;
1108
1109         r = read_one_line_file(fs, &contents);
1110         if (r < 0)
1111                 return r;
1112
1113         sc = strstrip(contents);
1114
1115         if (isempty(sc)) {
1116                 r = write_string_file(fs, agent, 0);
1117                 if (r < 0)
1118                         return r;
1119         } else if (!path_equal(sc, agent))
1120                 return -EEXIST;
1121
1122         fs = mfree(fs);
1123         r = cg_get_path(controller, NULL, "notify_on_release", &fs);
1124         if (r < 0)
1125                 return r;
1126
1127         contents = mfree(contents);
1128         r = read_one_line_file(fs, &contents);
1129         if (r < 0)
1130                 return r;
1131
1132         sc = strstrip(contents);
1133         if (streq(sc, "0")) {
1134                 r = write_string_file(fs, "1", 0);
1135                 if (r < 0)
1136                         return r;
1137
1138                 return 1;
1139         }
1140
1141         if (!streq(sc, "1"))
1142                 return -EIO;
1143
1144         return 0;
1145 }
1146
1147 int cg_uninstall_release_agent(const char *controller) {
1148         _cleanup_free_ char *fs = NULL;
1149         int r;
1150
1151         r = cg_unified_controller(controller);
1152         if (r < 0)
1153                 return r;
1154         if (r > 0) /* Doesn't apply to unified hierarchy */
1155                 return -EOPNOTSUPP;
1156
1157         r = cg_get_path(controller, NULL, "notify_on_release", &fs);
1158         if (r < 0)
1159                 return r;
1160
1161         r = write_string_file(fs, "0", 0);
1162         if (r < 0)
1163                 return r;
1164
1165         fs = mfree(fs);
1166
1167         r = cg_get_path(controller, NULL, "release_agent", &fs);
1168         if (r < 0)
1169                 return r;
1170
1171         r = write_string_file(fs, "", 0);
1172         if (r < 0)
1173                 return r;
1174
1175         return 0;
1176 }
1177 #endif // 0
1178
1179 int cg_is_empty(const char *controller, const char *path) {
1180         _cleanup_fclose_ FILE *f = NULL;
1181         pid_t pid;
1182         int r;
1183
1184         assert(path);
1185
1186         r = cg_enumerate_processes(controller, path, &f);
1187         if (r == -ENOENT)
1188                 return 1;
1189         if (r < 0)
1190                 return r;
1191
1192         r = cg_read_pid(f, &pid);
1193         if (r < 0)
1194                 return r;
1195
1196         return r == 0;
1197 }
1198
1199 int cg_is_empty_recursive(const char *controller, const char *path) {
1200         int r;
1201
1202         assert(path);
1203
1204         /* The root cgroup is always populated */
1205         if (controller && (isempty(path) || path_equal(path, "/")))
1206                 return false;
1207
1208         r = cg_unified_controller(controller);
1209         if (r < 0)
1210                 return r;
1211         if (r > 0) {
1212                 _cleanup_free_ char *t = NULL;
1213
1214                 /* On the unified hierarchy we can check empty state
1215                  * via the "populated" attribute of "cgroup.events". */
1216
1217                 r = cg_read_event(controller, path, "populated", &t);
1218                 if (r < 0)
1219                         return r;
1220
1221                 return streq(t, "0");
1222         } else {
1223                 _cleanup_closedir_ DIR *d = NULL;
1224                 char *fn;
1225
1226                 r = cg_is_empty(controller, path);
1227                 if (r <= 0)
1228                         return r;
1229
1230                 r = cg_enumerate_subgroups(controller, path, &d);
1231                 if (r == -ENOENT)
1232                         return 1;
1233                 if (r < 0)
1234                         return r;
1235
1236                 while ((r = cg_read_subgroup(d, &fn)) > 0) {
1237                         _cleanup_free_ char *p = NULL;
1238
1239                         p = strjoin(path, "/", fn);
1240                         free(fn);
1241                         if (!p)
1242                                 return -ENOMEM;
1243
1244                         r = cg_is_empty_recursive(controller, p);
1245                         if (r <= 0)
1246                                 return r;
1247                 }
1248                 if (r < 0)
1249                         return r;
1250
1251                 return true;
1252         }
1253 }
1254
1255 int cg_split_spec(const char *spec, char **controller, char **path) {
1256         char *t = NULL, *u = NULL;
1257         const char *e;
1258
1259         assert(spec);
1260
1261         if (*spec == '/') {
1262                 if (!path_is_safe(spec))
1263                         return -EINVAL;
1264
1265                 if (path) {
1266                         t = strdup(spec);
1267                         if (!t)
1268                                 return -ENOMEM;
1269
1270                         *path = path_kill_slashes(t);
1271                 }
1272
1273                 if (controller)
1274                         *controller = NULL;
1275
1276                 return 0;
1277         }
1278
1279         e = strchr(spec, ':');
1280         if (!e) {
1281                 if (!cg_controller_is_valid(spec))
1282                         return -EINVAL;
1283
1284                 if (controller) {
1285                         t = strdup(spec);
1286                         if (!t)
1287                                 return -ENOMEM;
1288
1289                         *controller = t;
1290                 }
1291
1292                 if (path)
1293                         *path = NULL;
1294
1295                 return 0;
1296         }
1297
1298         t = strndup(spec, e-spec);
1299         if (!t)
1300                 return -ENOMEM;
1301         if (!cg_controller_is_valid(t)) {
1302                 free(t);
1303                 return -EINVAL;
1304         }
1305
1306         if (isempty(e+1))
1307                 u = NULL;
1308         else {
1309                 u = strdup(e+1);
1310                 if (!u) {
1311                         free(t);
1312                         return -ENOMEM;
1313                 }
1314
1315                 if (!path_is_safe(u) ||
1316                     !path_is_absolute(u)) {
1317                         free(t);
1318                         free(u);
1319                         return -EINVAL;
1320                 }
1321
1322                 path_kill_slashes(u);
1323         }
1324
1325         if (controller)
1326                 *controller = t;
1327         else
1328                 free(t);
1329
1330         if (path)
1331                 *path = u;
1332         else
1333                 free(u);
1334
1335         return 0;
1336 }
1337
1338 int cg_mangle_path(const char *path, char **result) {
1339         _cleanup_free_ char *c = NULL, *p = NULL;
1340         char *t;
1341         int r;
1342
1343         assert(path);
1344         assert(result);
1345
1346         /* First, check if it already is a filesystem path */
1347         if (path_startswith(path, "/sys/fs/cgroup")) {
1348
1349                 t = strdup(path);
1350                 if (!t)
1351                         return -ENOMEM;
1352
1353                 *result = path_kill_slashes(t);
1354                 return 0;
1355         }
1356
1357         /* Otherwise, treat it as cg spec */
1358         r = cg_split_spec(path, &c, &p);
1359         if (r < 0)
1360                 return r;
1361
1362         return cg_get_path(c ?: SYSTEMD_CGROUP_CONTROLLER, p ?: "/", NULL, result);
1363 }
1364
1365 int cg_get_root_path(char **path) {
1366         char *p, *e;
1367         int r;
1368
1369         assert(path);
1370
1371         r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
1372         if (r < 0)
1373                 return r;
1374
1375 #if 0 /// elogind does not support systemd scopes and slices
1376         e = endswith(p, "/" SPECIAL_INIT_SCOPE);
1377         if (!e)
1378                 e = endswith(p, "/" SPECIAL_SYSTEM_SLICE); /* legacy */
1379         if (!e)
1380                 e = endswith(p, "/system"); /* even more legacy */
1381 #else
1382         e = endswith(p, "/elogind");
1383 #endif // 0
1384         if (e)
1385                 *e = 0;
1386
1387         *path = p;
1388         return 0;
1389 }
1390
1391 int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
1392         _cleanup_free_ char *rt = NULL;
1393         char *p;
1394         int r;
1395
1396         assert(cgroup);
1397         assert(shifted);
1398
1399         if (!root) {
1400                 /* If the root was specified let's use that, otherwise
1401                  * let's determine it from PID 1 */
1402
1403                 r = cg_get_root_path(&rt);
1404                 if (r < 0)
1405                         return r;
1406
1407                 root = rt;
1408                 log_debug_elogind("Determined root path: \"%s\"", root);
1409         }
1410
1411         p = path_startswith(cgroup, root);
1412 #if 0 /// With other controllers, elogind might end up in /elogind, and *p is 0
1413         if (p && p > cgroup)
1414 #else
1415         if (p && p[0] && (p > cgroup))
1416 #endif // 0
1417                 *shifted = p - 1;
1418         else
1419                 *shifted = cgroup;
1420
1421         return 0;
1422 }
1423
1424 int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
1425         _cleanup_free_ char *raw = NULL;
1426         const char *c;
1427         int r;
1428
1429         assert(pid >= 0);
1430         assert(cgroup);
1431
1432         r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &raw);
1433         if (r < 0)
1434                 return r;
1435
1436         log_debug_elogind("Shifting path: \"%s\" (PID %u, root: \"%s\")",
1437                           raw, pid, root ? root : "NULL");
1438         r = cg_shift_path(raw, root, &c);
1439         if (r < 0)
1440                 return r;
1441
1442         if (c == raw) {
1443                 *cgroup = raw;
1444                 raw = NULL;
1445         } else {
1446                 char *n;
1447
1448                 n = strdup(c);
1449                 if (!n)
1450                         return -ENOMEM;
1451
1452                 *cgroup = n;
1453         }
1454         log_debug_elogind("Resulting cgroup:\"%s\"", *cgroup);
1455
1456         return 0;
1457 }
1458
1459 #if 0 /// UNNEEDED by elogind
1460 int cg_path_decode_unit(const char *cgroup, char **unit) {
1461         char *c, *s;
1462         size_t n;
1463
1464         assert(cgroup);
1465         assert(unit);
1466
1467         n = strcspn(cgroup, "/");
1468         if (n < 3)
1469                 return -ENXIO;
1470
1471         c = strndupa(cgroup, n);
1472         c = cg_unescape(c);
1473
1474         if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
1475                 return -ENXIO;
1476
1477         s = strdup(c);
1478         if (!s)
1479                 return -ENOMEM;
1480
1481         *unit = s;
1482         return 0;
1483 }
1484
1485 static bool valid_slice_name(const char *p, size_t n) {
1486
1487         if (!p)
1488                 return false;
1489
1490         if (n < strlen("x.slice"))
1491                 return false;
1492
1493         if (memcmp(p + n - 6, ".slice", 6) == 0) {
1494                 char buf[n+1], *c;
1495
1496                 memcpy(buf, p, n);
1497                 buf[n] = 0;
1498
1499                 c = cg_unescape(buf);
1500
1501                 return unit_name_is_valid(c, UNIT_NAME_PLAIN);
1502         }
1503
1504         return false;
1505 }
1506
1507 static const char *skip_slices(const char *p) {
1508         assert(p);
1509
1510         /* Skips over all slice assignments */
1511
1512         for (;;) {
1513                 size_t n;
1514
1515                 p += strspn(p, "/");
1516
1517                 n = strcspn(p, "/");
1518                 if (!valid_slice_name(p, n))
1519                         return p;
1520
1521                 p += n;
1522         }
1523 }
1524
1525 int cg_path_get_unit(const char *path, char **ret) {
1526         const char *e;
1527         char *unit;
1528         int r;
1529
1530         assert(path);
1531         assert(ret);
1532
1533         e = skip_slices(path);
1534
1535         r = cg_path_decode_unit(e, &unit);
1536         if (r < 0)
1537                 return r;
1538
1539         /* We skipped over the slices, don't accept any now */
1540         if (endswith(unit, ".slice")) {
1541                 free(unit);
1542                 return -ENXIO;
1543         }
1544
1545         *ret = unit;
1546         return 0;
1547 }
1548
1549 int cg_pid_get_unit(pid_t pid, char **unit) {
1550         _cleanup_free_ char *cgroup = NULL;
1551         int r;
1552
1553         assert(unit);
1554
1555         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1556         if (r < 0)
1557                 return r;
1558
1559         return cg_path_get_unit(cgroup, unit);
1560 }
1561
1562 /**
1563  * Skip session-*.scope, but require it to be there.
1564  */
1565 static const char *skip_session(const char *p) {
1566         size_t n;
1567
1568         if (isempty(p))
1569                 return NULL;
1570
1571         p += strspn(p, "/");
1572
1573         n = strcspn(p, "/");
1574         if (n < strlen("session-x.scope"))
1575                 return NULL;
1576
1577         if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) {
1578                 char buf[n - 8 - 6 + 1];
1579
1580                 memcpy(buf, p + 8, n - 8 - 6);
1581                 buf[n - 8 - 6] = 0;
1582
1583                 /* Note that session scopes never need unescaping,
1584                  * since they cannot conflict with the kernel's own
1585                  * names, hence we don't need to call cg_unescape()
1586                  * here. */
1587
1588                 if (!session_id_valid(buf))
1589                         return false;
1590
1591                 p += n;
1592                 p += strspn(p, "/");
1593                 return p;
1594         }
1595
1596         return NULL;
1597 }
1598
1599 /**
1600  * Skip user@*.service, but require it to be there.
1601  */
1602 static const char *skip_user_manager(const char *p) {
1603         size_t n;
1604
1605         if (isempty(p))
1606                 return NULL;
1607
1608         p += strspn(p, "/");
1609
1610         n = strcspn(p, "/");
1611         if (n < strlen("user@x.service"))
1612                 return NULL;
1613
1614         if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
1615                 char buf[n - 5 - 8 + 1];
1616
1617                 memcpy(buf, p + 5, n - 5 - 8);
1618                 buf[n - 5 - 8] = 0;
1619
1620                 /* Note that user manager services never need unescaping,
1621                  * since they cannot conflict with the kernel's own
1622                  * names, hence we don't need to call cg_unescape()
1623                  * here. */
1624
1625                 if (parse_uid(buf, NULL) < 0)
1626                         return NULL;
1627
1628                 p += n;
1629                 p += strspn(p, "/");
1630
1631                 return p;
1632         }
1633
1634         return NULL;
1635 }
1636
1637 static const char *skip_user_prefix(const char *path) {
1638         const char *e, *t;
1639
1640         assert(path);
1641
1642         /* Skip slices, if there are any */
1643         e = skip_slices(path);
1644
1645         /* Skip the user manager, if it's in the path now... */
1646         t = skip_user_manager(e);
1647         if (t)
1648                 return t;
1649
1650         /* Alternatively skip the user session if it is in the path... */
1651         return skip_session(e);
1652 }
1653
1654 int cg_path_get_user_unit(const char *path, char **ret) {
1655         const char *t;
1656
1657         assert(path);
1658         assert(ret);
1659
1660         t = skip_user_prefix(path);
1661         if (!t)
1662                 return -ENXIO;
1663
1664         /* And from here on it looks pretty much the same as for a
1665          * system unit, hence let's use the same parser from here
1666          * on. */
1667         return cg_path_get_unit(t, ret);
1668 }
1669
1670 int cg_pid_get_user_unit(pid_t pid, char **unit) {
1671         _cleanup_free_ char *cgroup = NULL;
1672         int r;
1673
1674         assert(unit);
1675
1676         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1677         if (r < 0)
1678                 return r;
1679
1680         return cg_path_get_user_unit(cgroup, unit);
1681 }
1682
1683 int cg_path_get_machine_name(const char *path, char **machine) {
1684         _cleanup_free_ char *u = NULL;
1685         const char *sl;
1686         int r;
1687
1688         r = cg_path_get_unit(path, &u);
1689         if (r < 0)
1690                 return r;
1691
1692         sl = strjoina("/run/systemd/machines/unit:", u);
1693         return readlink_malloc(sl, machine);
1694 }
1695
1696 int cg_pid_get_machine_name(pid_t pid, char **machine) {
1697         _cleanup_free_ char *cgroup = NULL;
1698         int r;
1699
1700         assert(machine);
1701
1702         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1703         if (r < 0)
1704                 return r;
1705
1706         return cg_path_get_machine_name(cgroup, machine);
1707 }
1708 #endif // 0
1709
1710 int cg_path_get_session(const char *path, char **session) {
1711 #if 0 /// UNNEEDED by elogind
1712         _cleanup_free_ char *unit = NULL;
1713         char *start, *end;
1714         int r;
1715
1716         assert(path);
1717
1718         r = cg_path_get_unit(path, &unit);
1719         if (r < 0)
1720                 return r;
1721
1722         start = startswith(unit, "session-");
1723         if (!start)
1724                 return -ENXIO;
1725         end = endswith(start, ".scope");
1726         if (!end)
1727                 return -ENXIO;
1728
1729         *end = 0;
1730         if (!session_id_valid(start))
1731                 return -ENXIO;
1732 #else
1733         /* Elogind uses a flat hierarchy, just "/SESSION".  The only
1734            wrinkle is that SESSION might be escaped.  */
1735         const char *e, *n, *start;
1736
1737         assert(path);
1738         log_debug_elogind("path is \"%s\"", path);
1739         assert(path[0] == '/');
1740
1741         e = path + 1;
1742         n = strchrnul(e, '/');
1743         if (e == n)
1744                 return -ENOENT;
1745
1746         start = strndupa(e, n - e);
1747         start = cg_unescape(start);
1748
1749         if (!start[0])
1750                 return -ENOENT;
1751 #endif // 0
1752
1753         if (session) {
1754                 char *rr;
1755
1756                 log_debug_elogind("found session: \"%s\"", start);
1757                 rr = strdup(start);
1758                 if (!rr)
1759                         return -ENOMEM;
1760
1761                 *session = rr;
1762         }
1763
1764         return 0;
1765 }
1766
1767 int cg_pid_get_session(pid_t pid, char **session) {
1768         _cleanup_free_ char *cgroup = NULL;
1769         int r;
1770
1771         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1772         if (r < 0)
1773                 return r;
1774
1775         return cg_path_get_session(cgroup, session);
1776 }
1777
1778 #if 0 /// UNNEEDED by elogind
1779 int cg_path_get_owner_uid(const char *path, uid_t *uid) {
1780         _cleanup_free_ char *slice = NULL;
1781         char *start, *end;
1782         int r;
1783
1784         assert(path);
1785
1786         r = cg_path_get_slice(path, &slice);
1787         if (r < 0)
1788                 return r;
1789
1790         start = startswith(slice, "user-");
1791         if (!start)
1792                 return -ENXIO;
1793         end = endswith(start, ".slice");
1794         if (!end)
1795                 return -ENXIO;
1796
1797         *end = 0;
1798         if (parse_uid(start, uid) < 0)
1799                 return -ENXIO;
1800
1801         return 0;
1802 }
1803
1804 int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
1805         _cleanup_free_ char *cgroup = NULL;
1806         int r;
1807
1808         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1809         if (r < 0)
1810                 return r;
1811
1812         return cg_path_get_owner_uid(cgroup, uid);
1813 }
1814
1815 int cg_path_get_slice(const char *p, char **slice) {
1816         const char *e = NULL;
1817
1818         assert(p);
1819         assert(slice);
1820
1821         /* Finds the right-most slice unit from the beginning, but
1822          * stops before we come to the first non-slice unit. */
1823
1824         for (;;) {
1825                 size_t n;
1826
1827                 p += strspn(p, "/");
1828
1829                 n = strcspn(p, "/");
1830                 if (!valid_slice_name(p, n)) {
1831
1832                         if (!e) {
1833                                 char *s;
1834
1835                                 s = strdup(SPECIAL_ROOT_SLICE);
1836                                 if (!s)
1837                                         return -ENOMEM;
1838
1839                                 *slice = s;
1840                                 return 0;
1841                         }
1842
1843                         return cg_path_decode_unit(e, slice);
1844                 }
1845
1846                 e = p;
1847                 p += n;
1848         }
1849 }
1850
1851 int cg_pid_get_slice(pid_t pid, char **slice) {
1852         _cleanup_free_ char *cgroup = NULL;
1853         int r;
1854
1855         assert(slice);
1856
1857         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1858         if (r < 0)
1859                 return r;
1860
1861         return cg_path_get_slice(cgroup, slice);
1862 }
1863
1864 int cg_path_get_user_slice(const char *p, char **slice) {
1865         const char *t;
1866         assert(p);
1867         assert(slice);
1868
1869         t = skip_user_prefix(p);
1870         if (!t)
1871                 return -ENXIO;
1872
1873         /* And now it looks pretty much the same as for a system
1874          * slice, so let's just use the same parser from here on. */
1875         return cg_path_get_slice(t, slice);
1876 }
1877
1878 int cg_pid_get_user_slice(pid_t pid, char **slice) {
1879         _cleanup_free_ char *cgroup = NULL;
1880         int r;
1881
1882         assert(slice);
1883
1884         r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1885         if (r < 0)
1886                 return r;
1887
1888         return cg_path_get_user_slice(cgroup, slice);
1889 }
1890 #endif // 0
1891
1892 char *cg_escape(const char *p) {
1893         bool need_prefix = false;
1894
1895         /* This implements very minimal escaping for names to be used
1896          * as file names in the cgroup tree: any name which might
1897          * conflict with a kernel name or is prefixed with '_' is
1898          * prefixed with a '_'. That way, when reading cgroup names it
1899          * is sufficient to remove a single prefixing underscore if
1900          * there is one. */
1901
1902         /* The return value of this function (unlike cg_unescape())
1903          * needs free()! */
1904
1905         if (p[0] == 0 ||
1906             p[0] == '_' ||
1907             p[0] == '.' ||
1908             streq(p, "notify_on_release") ||
1909             streq(p, "release_agent") ||
1910             streq(p, "tasks") ||
1911             startswith(p, "cgroup."))
1912                 need_prefix = true;
1913         else {
1914                 const char *dot;
1915
1916                 dot = strrchr(p, '.');
1917                 if (dot) {
1918                         CGroupController c;
1919                         size_t l = dot - p;
1920
1921                         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
1922                                 const char *n;
1923
1924                                 n = cgroup_controller_to_string(c);
1925
1926                                 if (l != strlen(n))
1927                                         continue;
1928
1929                                 if (memcmp(p, n, l) != 0)
1930                                         continue;
1931
1932                                 need_prefix = true;
1933                                 break;
1934                         }
1935                 }
1936         }
1937
1938         if (need_prefix)
1939                 return strappend("_", p);
1940
1941         return strdup(p);
1942 }
1943
1944 char *cg_unescape(const char *p) {
1945         assert(p);
1946
1947         /* The return value of this function (unlike cg_escape())
1948          * doesn't need free()! */
1949
1950         if (p[0] == '_')
1951                 return (char*) p+1;
1952
1953         return (char*) p;
1954 }
1955
1956 #define CONTROLLER_VALID                        \
1957         DIGITS LETTERS                          \
1958         "_"
1959
1960 bool cg_controller_is_valid(const char *p) {
1961         const char *t, *s;
1962
1963         if (!p)
1964                 return false;
1965
1966         if (streq(p, SYSTEMD_CGROUP_CONTROLLER))
1967                 return true;
1968
1969         s = startswith(p, "name=");
1970         if (s)
1971                 p = s;
1972
1973         if (*p == 0 || *p == '_')
1974                 return false;
1975
1976         for (t = p; *t; t++)
1977                 if (!strchr(CONTROLLER_VALID, *t))
1978                         return false;
1979
1980         if (t - p > FILENAME_MAX)
1981                 return false;
1982
1983         return true;
1984 }
1985
1986 #if 0 /// UNNEEDED by elogind
1987 int cg_slice_to_path(const char *unit, char **ret) {
1988         _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
1989         const char *dash;
1990         int r;
1991
1992         assert(unit);
1993         assert(ret);
1994
1995         if (streq(unit, SPECIAL_ROOT_SLICE)) {
1996                 char *x;
1997
1998                 x = strdup("");
1999                 if (!x)
2000                         return -ENOMEM;
2001                 *ret = x;
2002                 return 0;
2003         }
2004
2005         if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
2006                 return -EINVAL;
2007
2008         if (!endswith(unit, ".slice"))
2009                 return -EINVAL;
2010
2011         r = unit_name_to_prefix(unit, &p);
2012         if (r < 0)
2013                 return r;
2014
2015         dash = strchr(p, '-');
2016
2017         /* Don't allow initial dashes */
2018         if (dash == p)
2019                 return -EINVAL;
2020
2021         while (dash) {
2022                 _cleanup_free_ char *escaped = NULL;
2023                 char n[dash - p + sizeof(".slice")];
2024
2025                 /* Don't allow trailing or double dashes */
2026                 if (dash[1] == 0 || dash[1] == '-')
2027                         return -EINVAL;
2028
2029                 strcpy(stpncpy(n, p, dash - p), ".slice");
2030                 if (!unit_name_is_valid(n, UNIT_NAME_PLAIN))
2031                         return -EINVAL;
2032
2033                 escaped = cg_escape(n);
2034                 if (!escaped)
2035                         return -ENOMEM;
2036
2037                 if (!strextend(&s, escaped, "/", NULL))
2038                         return -ENOMEM;
2039
2040                 dash = strchr(dash+1, '-');
2041         }
2042
2043         e = cg_escape(unit);
2044         if (!e)
2045                 return -ENOMEM;
2046
2047         if (!strextend(&s, e, NULL))
2048                 return -ENOMEM;
2049
2050         *ret = s;
2051         s = NULL;
2052
2053         return 0;
2054 }
2055 #endif // 0
2056
2057 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
2058         _cleanup_free_ char *p = NULL;
2059         int r;
2060
2061         r = cg_get_path(controller, path, attribute, &p);
2062         if (r < 0)
2063                 return r;
2064
2065         return write_string_file(p, value, 0);
2066 }
2067
2068 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) {
2069         _cleanup_free_ char *p = NULL;
2070         int r;
2071
2072         r = cg_get_path(controller, path, attribute, &p);
2073         if (r < 0)
2074                 return r;
2075
2076         return read_one_line_file(p, ret);
2077 }
2078
2079 #if 0 /// UNNEEDED by elogind
2080 int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, const char **keys, char **values) {
2081         _cleanup_free_ char *filename = NULL, *content = NULL;
2082         char *line, *p;
2083         int i, r;
2084
2085         for (i = 0; keys[i]; i++)
2086                 values[i] = NULL;
2087
2088         r = cg_get_path(controller, path, attribute, &filename);
2089         if (r < 0)
2090                 return r;
2091
2092         r = read_full_file(filename, &content, NULL);
2093         if (r < 0)
2094                 return r;
2095
2096         p = content;
2097         while ((line = strsep(&p, "\n"))) {
2098                 char *key;
2099
2100                 key = strsep(&line, " ");
2101
2102                 for (i = 0; keys[i]; i++) {
2103                         if (streq(key, keys[i])) {
2104                                 values[i] = strdup(line);
2105                                 break;
2106                         }
2107                 }
2108         }
2109
2110         for (i = 0; keys[i]; i++) {
2111                 if (!values[i]) {
2112                         for (i = 0; keys[i]; i++) {
2113                                 free(values[i]);
2114                                 values[i] = NULL;
2115                         }
2116                         return -ENOENT;
2117                 }
2118         }
2119
2120         return 0;
2121 }
2122
2123 int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {
2124         CGroupController c;
2125         int r;
2126
2127         /* This one will create a cgroup in our private tree, but also
2128          * duplicate it in the trees specified in mask, and remove it
2129          * in all others */
2130
2131         /* First create the cgroup in our own hierarchy. */
2132         r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
2133         if (r < 0)
2134                 return r;
2135
2136         /* If we are in the unified hierarchy, we are done now */
2137         r = cg_all_unified();
2138         if (r < 0)
2139                 return r;
2140         if (r > 0)
2141                 return 0;
2142
2143         /* Otherwise, do the same in the other hierarchies */
2144         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2145                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2146                 const char *n;
2147
2148                 n = cgroup_controller_to_string(c);
2149
2150                 if (mask & bit)
2151                         (void) cg_create(n, path);
2152                 else if (supported & bit)
2153                         (void) cg_trim(n, path, true);
2154         }
2155
2156         return 0;
2157 }
2158
2159 int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
2160         CGroupController c;
2161         int r;
2162
2163         r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
2164         if (r < 0)
2165                 return r;
2166
2167         r = cg_all_unified();
2168         if (r < 0)
2169                 return r;
2170         if (r > 0)
2171                 return 0;
2172
2173         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2174                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2175                 const char *p = NULL;
2176
2177                 if (!(supported & bit))
2178                         continue;
2179
2180                 if (path_callback)
2181                         p = path_callback(bit, userdata);
2182
2183                 if (!p)
2184                         p = path;
2185
2186                 (void) cg_attach_fallback(cgroup_controller_to_string(c), p, pid);
2187         }
2188
2189         return 0;
2190 }
2191
2192 int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
2193         Iterator i;
2194         void *pidp;
2195         int r = 0;
2196
2197         SET_FOREACH(pidp, pids, i) {
2198                 pid_t pid = PTR_TO_PID(pidp);
2199                 int q;
2200
2201                 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
2202                 if (q < 0 && r >= 0)
2203                         r = q;
2204         }
2205
2206         return r;
2207 }
2208
2209 int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
2210         CGroupController c;
2211         int r = 0, q;
2212
2213         if (!path_equal(from, to))  {
2214                 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, CGROUP_REMOVE);
2215                 if (r < 0)
2216                         return r;
2217         }
2218
2219         q = cg_all_unified();
2220         if (q < 0)
2221                 return q;
2222         if (q > 0)
2223                 return r;
2224
2225         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2226                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2227                 const char *p = NULL;
2228
2229                 if (!(supported & bit))
2230                         continue;
2231
2232                 if (to_callback)
2233                         p = to_callback(bit, userdata);
2234
2235                 if (!p)
2236                         p = to;
2237
2238                 (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, 0);
2239         }
2240
2241         return 0;
2242 }
2243
2244 int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
2245         CGroupController c;
2246         int r, q;
2247
2248         r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
2249         if (r < 0)
2250                 return r;
2251
2252         q = cg_all_unified();
2253         if (q < 0)
2254                 return q;
2255         if (q > 0)
2256                 return r;
2257
2258         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2259                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2260
2261                 if (!(supported & bit))
2262                         continue;
2263
2264                 (void) cg_trim(cgroup_controller_to_string(c), path, delete_root);
2265         }
2266
2267         return 0;
2268 }
2269 #endif // 0
2270
2271 int cg_mask_to_string(CGroupMask mask, char **ret) {
2272         const char *controllers[_CGROUP_CONTROLLER_MAX + 1];
2273         CGroupController c;
2274         int i = 0;
2275         char *s;
2276
2277         assert(ret);
2278
2279         if (mask == 0) {
2280                 *ret = NULL;
2281                 return 0;
2282         }
2283
2284         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2285
2286                 if (!(mask & CGROUP_CONTROLLER_TO_MASK(c)))
2287                         continue;
2288
2289                 controllers[i++] = cgroup_controller_to_string(c);
2290                 controllers[i] = NULL;
2291         }
2292
2293         s = strv_join((char **)controllers, NULL);
2294         if (!s)
2295                 return -ENOMEM;
2296
2297         *ret = s;
2298         return 0;
2299 }
2300
2301 int cg_mask_from_string(const char *value, CGroupMask *mask) {
2302         assert(mask);
2303         assert(value);
2304
2305         for (;;) {
2306                 _cleanup_free_ char *n = NULL;
2307                 CGroupController v;
2308                 int r;
2309
2310                 r = extract_first_word(&value, &n, NULL, 0);
2311                 if (r < 0)
2312                         return r;
2313                 if (r == 0)
2314                         break;
2315
2316                 v = cgroup_controller_from_string(n);
2317                 if (v < 0)
2318                         continue;
2319
2320                 *mask |= CGROUP_CONTROLLER_TO_MASK(v);
2321         }
2322         return 0;
2323 }
2324
2325 int cg_mask_supported(CGroupMask *ret) {
2326         CGroupMask mask = 0;
2327         int r;
2328
2329         /* Determines the mask of supported cgroup controllers. Only
2330          * includes controllers we can make sense of and that are
2331          * actually accessible. */
2332
2333         r = cg_all_unified();
2334         if (r < 0)
2335                 return r;
2336         if (r > 0) {
2337                 _cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
2338
2339                 /* In the unified hierarchy we can read the supported
2340                  * and accessible controllers from a the top-level
2341                  * cgroup attribute */
2342
2343                 r = cg_get_root_path(&root);
2344                 if (r < 0)
2345                         return r;
2346
2347                 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, "cgroup.controllers", &path);
2348                 if (r < 0)
2349                         return r;
2350
2351                 r = read_one_line_file(path, &controllers);
2352                 if (r < 0)
2353                         return r;
2354
2355                 r = cg_mask_from_string(controllers, &mask);
2356                 if (r < 0)
2357                         return r;
2358
2359                 /* Currently, we support the cpu, memory, io and pids
2360                  * controller in the unified hierarchy, mask
2361                  * everything else off. */
2362                 mask &= CGROUP_MASK_CPU | CGROUP_MASK_MEMORY | CGROUP_MASK_IO | CGROUP_MASK_PIDS;
2363
2364         } else {
2365                 CGroupController c;
2366
2367                 /* In the legacy hierarchy, we check whether which
2368                  * hierarchies are mounted. */
2369
2370                 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2371                         const char *n;
2372
2373                         n = cgroup_controller_to_string(c);
2374                         if (controller_is_accessible(n) >= 0)
2375                                 mask |= CGROUP_CONTROLLER_TO_MASK(c);
2376                 }
2377         }
2378
2379         *ret = mask;
2380         return 0;
2381 }
2382
2383 #if 0 /// UNNEEDED by elogind
2384 int cg_kernel_controllers(Set *controllers) {
2385         _cleanup_fclose_ FILE *f = NULL;
2386         char buf[LINE_MAX];
2387         int r;
2388
2389         assert(controllers);
2390
2391         /* Determines the full list of kernel-known controllers. Might
2392          * include controllers we don't actually support, arbitrary
2393          * named hierarchies and controllers that aren't currently
2394          * accessible (because not mounted). */
2395
2396         f = fopen("/proc/cgroups", "re");
2397         if (!f) {
2398                 if (errno == ENOENT)
2399                         return 0;
2400                 return -errno;
2401         }
2402
2403         /* Ignore the header line */
2404         (void) fgets(buf, sizeof(buf), f);
2405
2406         for (;;) {
2407                 char *controller;
2408                 int enabled = 0;
2409
2410                 errno = 0;
2411                 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
2412
2413                         if (feof(f))
2414                                 break;
2415
2416                         if (ferror(f) && errno > 0)
2417                                 return -errno;
2418
2419                         return -EBADMSG;
2420                 }
2421
2422                 if (!enabled) {
2423                         free(controller);
2424                         continue;
2425                 }
2426
2427                 if (!cg_controller_is_valid(controller)) {
2428                         free(controller);
2429                         return -EBADMSG;
2430                 }
2431
2432                 r = set_consume(controllers, controller);
2433                 if (r < 0)
2434                         return r;
2435         }
2436
2437         return 0;
2438 }
2439 #endif // 0
2440
2441 static thread_local CGroupUnified unified_cache = CGROUP_UNIFIED_UNKNOWN;
2442
2443 /* The hybrid mode was initially implemented in v232 and simply mounted cgroup v2 on /sys/fs/cgroup/systemd.  This
2444  * unfortunately broke other tools (such as docker) which expected the v1 "name=systemd" hierarchy on
2445  * /sys/fs/cgroup/systemd.  From v233 and on, the hybrid mode mountnbs v2 on /sys/fs/cgroup/unified and maintains
2446  * "name=systemd" hierarchy on /sys/fs/cgroup/systemd for compatibility with other tools.
2447  *
2448  * To keep live upgrade working, we detect and support v232 layout.  When v232 layout is detected, to keep cgroup v2
2449  * process management but disable the compat dual layout, we return %true on
2450  * cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) and %false on cg_hybrid_unified().
2451  */
2452 static thread_local bool unified_systemd_v232;
2453
2454 static int cg_unified_update(void) {
2455
2456         struct statfs fs;
2457
2458         /* Checks if we support the unified hierarchy. Returns an
2459          * error when the cgroup hierarchies aren't mounted yet or we
2460          * have any other trouble determining if the unified hierarchy
2461          * is supported. */
2462
2463         if (unified_cache >= CGROUP_UNIFIED_NONE)
2464                 return 0;
2465
2466         if (statfs("/sys/fs/cgroup/", &fs) < 0)
2467                 return -errno;
2468
2469 #if 0 /// UNNEEDED by elogind
2470         if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC))
2471                 unified_cache = CGROUP_UNIFIED_ALL;
2472         else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) {
2473                 if (statfs("/sys/fs/cgroup/unified/", &fs) == 0 &&
2474                     F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) {
2475                         unified_cache = CGROUP_UNIFIED_SYSTEMD;
2476                         unified_systemd_v232 = false;
2477                 } else if (statfs("/sys/fs/cgroup/systemd/", &fs) == 0 &&
2478                            F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) {
2479                         unified_cache = CGROUP_UNIFIED_SYSTEMD;
2480                         unified_systemd_v232 = true;
2481                 } else {
2482                         if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0)
2483                                 return -errno;
2484                         if (!F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC))
2485                                 return -ENOMEDIUM;
2486                         unified_cache = CGROUP_UNIFIED_NONE;
2487                 }
2488         } else
2489                 return -ENOMEDIUM;
2490 #else
2491         /* elogind can not support the unified hierarchy as a controller,
2492          * so always assume a classical hierarchy.
2493          * If, and only *if*, someone really wants to substitute systemd-login
2494          * in an environment managed by systemd with elogind, we might have to
2495          * add such a support. */
2496         unified_cache = CGROUP_UNIFIED_NONE;
2497 #endif // 0
2498
2499         return 0;
2500 }
2501
2502 int cg_unified_controller(const char *controller) {
2503         int r;
2504
2505         r = cg_unified_update();
2506         if (r < 0)
2507                 return r;
2508
2509         if (unified_cache == CGROUP_UNIFIED_NONE)
2510                 return false;
2511
2512         if (unified_cache >= CGROUP_UNIFIED_ALL)
2513                 return true;
2514
2515         return streq_ptr(controller, SYSTEMD_CGROUP_CONTROLLER);
2516 }
2517
2518 int cg_all_unified(void) {
2519         int r;
2520
2521         r = cg_unified_update();
2522         if (r < 0)
2523                 return r;
2524
2525         return unified_cache >= CGROUP_UNIFIED_ALL;
2526 }
2527
2528 int cg_hybrid_unified(void) {
2529         int r;
2530
2531         r = cg_unified_update();
2532         if (r < 0)
2533                 return r;
2534
2535         return unified_cache == CGROUP_UNIFIED_SYSTEMD && !unified_systemd_v232;
2536 }
2537
2538 int cg_unified_flush(void) {
2539         unified_cache = CGROUP_UNIFIED_UNKNOWN;
2540
2541         return cg_unified_update();
2542 }
2543
2544 #if 0 /// UNNEEDED by elogind
2545 int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
2546         _cleanup_free_ char *fs = NULL;
2547         CGroupController c;
2548         int r;
2549
2550         assert(p);
2551
2552         if (supported == 0)
2553                 return 0;
2554
2555         r = cg_all_unified();
2556         if (r < 0)
2557                 return r;
2558         if (r == 0) /* on the legacy hiearchy there's no joining of controllers defined */
2559                 return 0;
2560
2561         r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, p, "cgroup.subtree_control", &fs);
2562         if (r < 0)
2563                 return r;
2564
2565         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2566                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2567                 const char *n;
2568
2569                 if (!(supported & bit))
2570                         continue;
2571
2572                 n = cgroup_controller_to_string(c);
2573                 {
2574                         char s[1 + strlen(n) + 1];
2575
2576                         s[0] = mask & bit ? '+' : '-';
2577                         strcpy(s + 1, n);
2578
2579                         r = write_string_file(fs, s, 0);
2580                         if (r < 0)
2581                                 log_debug_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs);
2582                 }
2583         }
2584
2585         return 0;
2586 }
2587
2588 bool cg_is_unified_wanted(void) {
2589         static thread_local int wanted = -1;
2590         int r;
2591         bool b;
2592         const bool is_default = DEFAULT_HIERARCHY == CGROUP_UNIFIED_ALL;
2593
2594         /* If we have a cached value, return that. */
2595         if (wanted >= 0)
2596                 return wanted;
2597
2598         /* If the hierarchy is already mounted, then follow whatever
2599          * was chosen for it. */
2600         if (cg_unified_flush() >= 0)
2601                 return (wanted = unified_cache >= CGROUP_UNIFIED_ALL);
2602
2603         /* Otherwise, let's see what the kernel command line has to say.
2604          * Since checking is expensive, cache a non-error result. */
2605         r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", &b);
2606
2607         return (wanted = r > 0 ? b : is_default);
2608 }
2609
2610 bool cg_is_legacy_wanted(void) {
2611         static thread_local int wanted = -1;
2612
2613         /* If we have a cached value, return that. */
2614         if (wanted >= 0)
2615                 return wanted;
2616
2617         /* Check if we have cgroups2 already mounted. */
2618         if (cg_unified_flush() >= 0 &&
2619             unified_cache == CGROUP_UNIFIED_ALL)
2620                 return (wanted = false);
2621
2622         /* Otherwise, assume that at least partial legacy is wanted,
2623          * since cgroups2 should already be mounted at this point. */
2624         return (wanted = true);
2625 }
2626
2627 bool cg_is_hybrid_wanted(void) {
2628         static thread_local int wanted = -1;
2629         int r;
2630         bool b;
2631         const bool is_default = DEFAULT_HIERARCHY >= CGROUP_UNIFIED_SYSTEMD;
2632         /* We default to true if the default is "hybrid", obviously,
2633          * but also when the default is "unified", because if we get
2634          * called, it means that unified hierarchy was not mounted. */
2635
2636         /* If we have a cached value, return that. */
2637         if (wanted >= 0)
2638                 return wanted;
2639
2640         /* If the hierarchy is already mounted, then follow whatever
2641          * was chosen for it. */
2642         if (cg_unified_flush() >= 0 &&
2643             unified_cache == CGROUP_UNIFIED_ALL)
2644                 return (wanted = false);
2645
2646         /* Otherwise, let's see what the kernel command line has to say.
2647          * Since checking is expensive, cache a non-error result. */
2648         r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", &b);
2649
2650         /* The meaning of the kernel option is reversed wrt. to the return value
2651          * of this function, hence the negation. */
2652         return (wanted = r > 0 ? !b : is_default);
2653 }
2654 #else
2655 bool cg_is_unified_wanted(void) {
2656         return false;
2657 }
2658 bool cg_is_legacy_wanted(void) {
2659         return true;
2660 }
2661 bool cg_is_hybrid_wanted(void) {
2662         return false;
2663 }
2664 #endif // 0
2665
2666 #if 0 /// UNNEEDED by elogind
2667 int cg_weight_parse(const char *s, uint64_t *ret) {
2668         uint64_t u;
2669         int r;
2670
2671         if (isempty(s)) {
2672                 *ret = CGROUP_WEIGHT_INVALID;
2673                 return 0;
2674         }
2675
2676         r = safe_atou64(s, &u);
2677         if (r < 0)
2678                 return r;
2679
2680         if (u < CGROUP_WEIGHT_MIN || u > CGROUP_WEIGHT_MAX)
2681                 return -ERANGE;
2682
2683         *ret = u;
2684         return 0;
2685 }
2686
2687 const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX] = {
2688         [CGROUP_IO_RBPS_MAX]    = CGROUP_LIMIT_MAX,
2689         [CGROUP_IO_WBPS_MAX]    = CGROUP_LIMIT_MAX,
2690         [CGROUP_IO_RIOPS_MAX]   = CGROUP_LIMIT_MAX,
2691         [CGROUP_IO_WIOPS_MAX]   = CGROUP_LIMIT_MAX,
2692 };
2693
2694 static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] = {
2695         [CGROUP_IO_RBPS_MAX]    = "IOReadBandwidthMax",
2696         [CGROUP_IO_WBPS_MAX]    = "IOWriteBandwidthMax",
2697         [CGROUP_IO_RIOPS_MAX]   = "IOReadIOPSMax",
2698         [CGROUP_IO_WIOPS_MAX]   = "IOWriteIOPSMax",
2699 };
2700
2701 DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType);
2702
2703 int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
2704         uint64_t u;
2705         int r;
2706
2707         if (isempty(s)) {
2708                 *ret = CGROUP_CPU_SHARES_INVALID;
2709                 return 0;
2710         }
2711
2712         r = safe_atou64(s, &u);
2713         if (r < 0)
2714                 return r;
2715
2716         if (u < CGROUP_CPU_SHARES_MIN || u > CGROUP_CPU_SHARES_MAX)
2717                 return -ERANGE;
2718
2719         *ret = u;
2720         return 0;
2721 }
2722
2723 int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
2724         uint64_t u;
2725         int r;
2726
2727         if (isempty(s)) {
2728                 *ret = CGROUP_BLKIO_WEIGHT_INVALID;
2729                 return 0;
2730         }
2731
2732         r = safe_atou64(s, &u);
2733         if (r < 0)
2734                 return r;
2735
2736         if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX)
2737                 return -ERANGE;
2738
2739         *ret = u;
2740         return 0;
2741 }
2742 #endif // 0
2743
2744 bool is_cgroup_fs(const struct statfs *s) {
2745         return is_fs_type(s, CGROUP_SUPER_MAGIC) ||
2746                is_fs_type(s, CGROUP2_SUPER_MAGIC);
2747 }
2748
2749 bool fd_is_cgroup_fs(int fd) {
2750         struct statfs s;
2751
2752         if (fstatfs(fd, &s) < 0)
2753                 return -errno;
2754
2755         return is_cgroup_fs(&s);
2756 }
2757
2758 static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
2759         [CGROUP_CONTROLLER_CPU] = "cpu",
2760         [CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
2761         [CGROUP_CONTROLLER_IO] = "io",
2762         [CGROUP_CONTROLLER_BLKIO] = "blkio",
2763         [CGROUP_CONTROLLER_MEMORY] = "memory",
2764         [CGROUP_CONTROLLER_DEVICES] = "devices",
2765         [CGROUP_CONTROLLER_PIDS] = "pids",
2766 };
2767
2768 DEFINE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController);