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