]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/cgroup-util.c
util-lib: split out fd-related operations into fd-util.[ch]
[thirdparty/systemd.git] / src / basic / cgroup-util.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
8c6db833
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
8c6db833
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
8c6db833 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
8c6db833
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
84ac7bea 22#include <dirent.h>
8c6db833 23#include <errno.h>
84ac7bea 24#include <ftw.h>
8c6db833 25#include <signal.h>
8c6db833 26#include <stdlib.h>
84ac7bea 27#include <string.h>
672c48cc
LP
28#include <sys/stat.h>
29#include <sys/types.h>
84ac7bea 30#include <unistd.h>
8c6db833 31
3ffd4af2 32#include "cgroup-util.h"
84ac7bea 33#include "extract-word.h"
3ffd4af2 34#include "fd-util.h"
84ac7bea 35#include "fileio.h"
6482f626 36#include "formats-util.h"
84ac7bea
LP
37#include "login-util.h"
38#include "macro.h"
39#include "mkdir.h"
9eb977db 40#include "path-util.h"
84ac7bea
LP
41#include "process-util.h"
42#include "set.h"
9444b1f2 43#include "special.h"
07630cea 44#include "string-util.h"
84ac7bea
LP
45#include "unit-name.h"
46#include "util.h"
8c6db833 47
c6c18be3 48int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
7027ff61 49 _cleanup_free_ char *fs = NULL;
c6c18be3 50 FILE *f;
7027ff61 51 int r;
c6c18be3 52
c6c18be3
LP
53 assert(_f);
54
c3175a7f
LP
55 r = cg_get_path(controller, path, "cgroup.procs", &fs);
56 if (r < 0)
c6c18be3
LP
57 return r;
58
59 f = fopen(fs, "re");
c6c18be3
LP
60 if (!f)
61 return -errno;
62
63 *_f = f;
64 return 0;
65}
66
c6c18be3
LP
67int cg_read_pid(FILE *f, pid_t *_pid) {
68 unsigned long ul;
69
70 /* Note that the cgroup.procs might contain duplicates! See
71 * cgroups.txt for details. */
72
7027ff61
LP
73 assert(f);
74 assert(_pid);
75
c6c18be3
LP
76 errno = 0;
77 if (fscanf(f, "%lu", &ul) != 1) {
78
79 if (feof(f))
80 return 0;
81
82 return errno ? -errno : -EIO;
83 }
84
85 if (ul <= 0)
86 return -EIO;
87
88 *_pid = (pid_t) ul;
89 return 1;
90}
91
35d2e7ec 92int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
7027ff61 93 _cleanup_free_ char *fs = NULL;
35d2e7ec
LP
94 int r;
95 DIR *d;
96
35d2e7ec
LP
97 assert(_d);
98
99 /* This is not recursive! */
100
c3175a7f
LP
101 r = cg_get_path(controller, path, NULL, &fs);
102 if (r < 0)
35d2e7ec
LP
103 return r;
104
105 d = opendir(fs);
35d2e7ec
LP
106 if (!d)
107 return -errno;
108
109 *_d = d;
110 return 0;
111}
112
113int cg_read_subgroup(DIR *d, char **fn) {
114 struct dirent *de;
115
116 assert(d);
7027ff61 117 assert(fn);
35d2e7ec 118
f01327ad 119 FOREACH_DIRENT_ALL(de, d, return -errno) {
35d2e7ec
LP
120 char *b;
121
122 if (de->d_type != DT_DIR)
123 continue;
124
125 if (streq(de->d_name, ".") ||
126 streq(de->d_name, ".."))
127 continue;
128
7027ff61
LP
129 b = strdup(de->d_name);
130 if (!b)
35d2e7ec
LP
131 return -ENOMEM;
132
133 *fn = b;
134 return 1;
135 }
136
35d2e7ec
LP
137 return 0;
138}
139
4ad49000 140int cg_rmdir(const char *controller, const char *path) {
7027ff61 141 _cleanup_free_ char *p = NULL;
35d2e7ec
LP
142 int r;
143
ad293f5a
LP
144 r = cg_get_path(controller, path, NULL, &p);
145 if (r < 0)
35d2e7ec
LP
146 return r;
147
148 r = rmdir(p);
7027ff61
LP
149 if (r < 0 && errno != ENOENT)
150 return -errno;
35d2e7ec 151
7027ff61 152 return 0;
35d2e7ec
LP
153}
154
430c18ed 155int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
7027ff61 156 _cleanup_set_free_ Set *allocated_set = NULL;
35d2e7ec 157 bool done = false;
8c6db833 158 int r, ret = 0;
35d2e7ec 159 pid_t my_pid;
8c6db833 160
8c6db833
LP
161 assert(sig >= 0);
162
163 /* This goes through the tasks list and kills them all. This
164 * is repeated until no further processes are added to the
165 * tasks list, to properly handle forking processes */
166
7027ff61 167 if (!s) {
d5099efc 168 s = allocated_set = set_new(NULL);
7027ff61 169 if (!s)
ca949c9d 170 return -ENOMEM;
7027ff61 171 }
8c6db833
LP
172
173 my_pid = getpid();
174
175 do {
7027ff61 176 _cleanup_fclose_ FILE *f = NULL;
0b172489 177 pid_t pid = 0;
8c6db833
LP
178 done = true;
179
7027ff61
LP
180 r = cg_enumerate_processes(controller, path, &f);
181 if (r < 0) {
4c633005 182 if (ret >= 0 && r != -ENOENT)
7027ff61 183 return r;
35d2e7ec 184
7027ff61 185 return ret;
35d2e7ec 186 }
c6c18be3
LP
187
188 while ((r = cg_read_pid(f, &pid)) > 0) {
8c6db833 189
7027ff61 190 if (ignore_self && pid == my_pid)
c6c18be3 191 continue;
8c6db833 192
fea72cc0 193 if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
c6c18be3 194 continue;
8c6db833
LP
195
196 /* If we haven't killed this process yet, kill
197 * it */
4c633005
LP
198 if (kill(pid, sig) < 0) {
199 if (ret >= 0 && errno != ESRCH)
8c6db833 200 ret = -errno;
6e8314c4 201 } else {
dc8962da 202 if (sigcont && sig != SIGKILL)
e155a0aa 203 (void) kill(pid, SIGCONT);
430c18ed 204
6e8314c4
LP
205 if (ret == 0)
206 ret = 1;
430c18ed 207 }
8c6db833 208
8c6db833
LP
209 done = false;
210
fea72cc0 211 r = set_put(s, PID_TO_PTR(pid));
7027ff61 212 if (r < 0) {
35d2e7ec 213 if (ret >= 0)
7027ff61 214 return r;
35d2e7ec 215
7027ff61 216 return ret;
35d2e7ec
LP
217 }
218 }
219
220 if (r < 0) {
221 if (ret >= 0)
7027ff61 222 return r;
35d2e7ec 223
7027ff61 224 return ret;
8c6db833
LP
225 }
226
8c6db833
LP
227 /* To avoid racing against processes which fork
228 * quicker than we can kill them we repeat this until
229 * no new pids need to be killed. */
230
35d2e7ec 231 } while (!done);
8c6db833 232
35d2e7ec 233 return ret;
8c6db833
LP
234}
235
430c18ed 236int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
7027ff61
LP
237 _cleanup_set_free_ Set *allocated_set = NULL;
238 _cleanup_closedir_ DIR *d = NULL;
e155a0aa 239 int r, ret;
35d2e7ec 240 char *fn;
8c6db833
LP
241
242 assert(path);
8c6db833
LP
243 assert(sig >= 0);
244
7027ff61 245 if (!s) {
d5099efc 246 s = allocated_set = set_new(NULL);
7027ff61 247 if (!s)
ca949c9d 248 return -ENOMEM;
7027ff61 249 }
ca949c9d 250
430c18ed 251 ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
8c6db833 252
7027ff61
LP
253 r = cg_enumerate_subgroups(controller, path, &d);
254 if (r < 0) {
4c633005 255 if (ret >= 0 && r != -ENOENT)
7027ff61 256 return r;
8c6db833 257
7027ff61 258 return ret;
35d2e7ec 259 }
8c6db833 260
35d2e7ec 261 while ((r = cg_read_subgroup(d, &fn)) > 0) {
7027ff61 262 _cleanup_free_ char *p = NULL;
8c6db833 263
7027ff61 264 p = strjoin(path, "/", fn, NULL);
35d2e7ec 265 free(fn);
7027ff61
LP
266 if (!p)
267 return -ENOMEM;
8c6db833 268
430c18ed 269 r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
e155a0aa 270 if (r != 0 && ret >= 0)
35d2e7ec 271 ret = r;
8c6db833
LP
272 }
273
7027ff61 274 if (ret >= 0 && r < 0)
35d2e7ec
LP
275 ret = r;
276
7027ff61 277 if (rem) {
4ad49000 278 r = cg_rmdir(controller, path);
7027ff61
LP
279 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
280 return r;
281 }
ca949c9d 282
8c6db833
LP
283 return ret;
284}
285
246aa6dd 286int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) {
35d2e7ec 287 bool done = false;
246aa6dd 288 _cleanup_set_free_ Set *s = NULL;
8c6db833
LP
289 int r, ret = 0;
290 pid_t my_pid;
291
246aa6dd
LP
292 assert(cfrom);
293 assert(pfrom);
294 assert(cto);
295 assert(pto);
8c6db833 296
d5099efc 297 s = set_new(NULL);
246aa6dd 298 if (!s)
35d2e7ec
LP
299 return -ENOMEM;
300
8c6db833
LP
301 my_pid = getpid();
302
303 do {
7027ff61 304 _cleanup_fclose_ FILE *f = NULL;
0b172489 305 pid_t pid = 0;
8c6db833
LP
306 done = true;
307
b043cd0b 308 r = cg_enumerate_processes(cfrom, pfrom, &f);
246aa6dd 309 if (r < 0) {
4c633005 310 if (ret >= 0 && r != -ENOENT)
7027ff61 311 return r;
35d2e7ec 312
246aa6dd 313 return ret;
35d2e7ec 314 }
c6c18be3
LP
315
316 while ((r = cg_read_pid(f, &pid)) > 0) {
8c6db833 317
35d2e7ec
LP
318 /* This might do weird stuff if we aren't a
319 * single-threaded program. However, we
320 * luckily know we are not */
7027ff61 321 if (ignore_self && pid == my_pid)
c6c18be3 322 continue;
8c6db833 323
fea72cc0 324 if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
35d2e7ec
LP
325 continue;
326
9b84c7f9
LP
327 /* Ignore kernel threads. Since they can only
328 * exist in the root cgroup, we only check for
329 * them there. */
330 if (cfrom &&
331 (isempty(pfrom) || path_equal(pfrom, "/")) &&
332 is_kernel_thread(pid) > 0)
333 continue;
334
246aa6dd
LP
335 r = cg_attach(cto, pto, pid);
336 if (r < 0) {
4c633005 337 if (ret >= 0 && r != -ESRCH)
35d2e7ec
LP
338 ret = r;
339 } else if (ret == 0)
340 ret = 1;
8c6db833 341
8c6db833 342 done = false;
35d2e7ec 343
fea72cc0 344 r = set_put(s, PID_TO_PTR(pid));
246aa6dd 345 if (r < 0) {
35d2e7ec 346 if (ret >= 0)
7027ff61 347 return r;
35d2e7ec 348
246aa6dd 349 return ret;
35d2e7ec
LP
350 }
351 }
352
353 if (r < 0) {
354 if (ret >= 0)
7027ff61 355 return r;
35d2e7ec 356
246aa6dd 357 return ret;
8c6db833 358 }
35d2e7ec 359 } while (!done);
8c6db833 360
35d2e7ec 361 return ret;
8c6db833
LP
362}
363
4ad49000
LP
364int cg_migrate_recursive(
365 const char *cfrom,
366 const char *pfrom,
367 const char *cto,
368 const char *pto,
369 bool ignore_self,
370 bool rem) {
371
246aa6dd 372 _cleanup_closedir_ DIR *d = NULL;
7027ff61 373 int r, ret = 0;
35d2e7ec 374 char *fn;
8c6db833 375
246aa6dd
LP
376 assert(cfrom);
377 assert(pfrom);
378 assert(cto);
379 assert(pto);
8c6db833 380
246aa6dd 381 ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self);
8c6db833 382
246aa6dd
LP
383 r = cg_enumerate_subgroups(cfrom, pfrom, &d);
384 if (r < 0) {
4c633005 385 if (ret >= 0 && r != -ENOENT)
7027ff61
LP
386 return r;
387
246aa6dd 388 return ret;
35d2e7ec
LP
389 }
390
391 while ((r = cg_read_subgroup(d, &fn)) > 0) {
246aa6dd 392 _cleanup_free_ char *p = NULL;
8c6db833 393
246aa6dd 394 p = strjoin(pfrom, "/", fn, NULL);
35d2e7ec 395 free(fn);
e155a0aa
LP
396 if (!p)
397 return -ENOMEM;
8c6db833 398
246aa6dd 399 r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem);
35d2e7ec
LP
400 if (r != 0 && ret >= 0)
401 ret = r;
8c6db833
LP
402 }
403
35d2e7ec
LP
404 if (r < 0 && ret >= 0)
405 ret = r;
406
246aa6dd 407 if (rem) {
4ad49000 408 r = cg_rmdir(cfrom, pfrom);
246aa6dd
LP
409 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
410 return r;
411 }
8c6db833
LP
412
413 return ret;
414}
415
13b84ec7
LP
416int cg_migrate_recursive_fallback(
417 const char *cfrom,
418 const char *pfrom,
419 const char *cto,
420 const char *pto,
421 bool ignore_self,
422 bool rem) {
423
424 int r;
425
426 assert(cfrom);
427 assert(pfrom);
428 assert(cto);
429 assert(pto);
430
431 r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem);
432 if (r < 0) {
433 char prefix[strlen(pto) + 1];
434
435 /* This didn't work? Then let's try all prefixes of the destination */
436
fecffe5d 437 PATH_FOREACH_PREFIX(prefix, pto) {
e155a0aa
LP
438 int q;
439
440 q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
441 if (q >= 0)
442 return q;
13b84ec7
LP
443 }
444 }
445
e155a0aa 446 return r;
13b84ec7
LP
447}
448
efdb0237
LP
449static const char *controller_to_dirname(const char *controller) {
450 const char *e;
3474ae3c 451
7027ff61
LP
452 assert(controller);
453
efdb0237
LP
454 /* Converts a controller name to the directory name below
455 * /sys/fs/cgroup/ we want to mount it to. Effectively, this
456 * just cuts off the name= prefixed used for named
457 * hierarchies, if it is specified. */
458
459 e = startswith(controller, "name=");
460 if (e)
461 return e;
462
463 return controller;
3474ae3c
LP
464}
465
569b19d8
LP
466static int join_path_legacy(const char *controller, const char *path, const char *suffix, char **fs) {
467 const char *dn;
018ef268 468 char *t = NULL;
3474ae3c 469
efdb0237 470 assert(fs);
569b19d8
LP
471 assert(controller);
472
473 dn = controller_to_dirname(controller);
efdb0237
LP
474
475 if (isempty(path) && isempty(suffix))
569b19d8 476 t = strappend("/sys/fs/cgroup/", dn);
efdb0237 477 else if (isempty(path))
569b19d8 478 t = strjoin("/sys/fs/cgroup/", dn, "/", suffix, NULL);
efdb0237 479 else if (isempty(suffix))
569b19d8 480 t = strjoin("/sys/fs/cgroup/", dn, "/", path, NULL);
efdb0237 481 else
569b19d8 482 t = strjoin("/sys/fs/cgroup/", dn, "/", path, "/", suffix, NULL);
efdb0237
LP
483 if (!t)
484 return -ENOMEM;
3474ae3c 485
efdb0237
LP
486 *fs = t;
487 return 0;
488}
489
490static int join_path_unified(const char *path, const char *suffix, char **fs) {
491 char *t;
492
493 assert(fs);
494
495 if (isempty(path) && isempty(suffix))
496 t = strdup("/sys/fs/cgroup");
497 else if (isempty(path))
498 t = strappend("/sys/fs/cgroup/", suffix);
499 else if (isempty(suffix))
500 t = strappend("/sys/fs/cgroup/", path);
501 else
502 t = strjoin("/sys/fs/cgroup/", path, "/", suffix, NULL);
3474ae3c
LP
503 if (!t)
504 return -ENOMEM;
505
efdb0237 506 *fs = t;
3474ae3c
LP
507 return 0;
508}
509
8c6db833 510int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
efdb0237 511 int unified, r;
8c6db833 512
dbd821ac
LP
513 assert(fs);
514
efdb0237
LP
515 if (!controller) {
516 char *t;
517
569b19d8
LP
518 /* If no controller is specified, we return the path
519 * *below* the controllers, without any prefix. */
efdb0237
LP
520
521 if (!path && !suffix)
522 return -EINVAL;
523
989189ea 524 if (!suffix)
efdb0237 525 t = strdup(path);
989189ea 526 else if (!path)
efdb0237
LP
527 t = strdup(suffix);
528 else
529 t = strjoin(path, "/", suffix, NULL);
530 if (!t)
531 return -ENOMEM;
532
533 *fs = path_kill_slashes(t);
534 return 0;
535 }
536
537 if (!cg_controller_is_valid(controller))
78edb35a
LP
538 return -EINVAL;
539
efdb0237
LP
540 unified = cg_unified();
541 if (unified < 0)
542 return unified;
70132bd0 543
efdb0237
LP
544 if (unified > 0)
545 r = join_path_unified(path, suffix, fs);
569b19d8
LP
546 else
547 r = join_path_legacy(controller, path, suffix, fs);
efdb0237
LP
548 if (r < 0)
549 return r;
7027ff61 550
efdb0237
LP
551 path_kill_slashes(*fs);
552 return 0;
3474ae3c 553}
dbd821ac 554
efdb0237
LP
555static int controller_is_accessible(const char *controller) {
556 int unified;
37099707 557
efdb0237 558 assert(controller);
37099707 559
efdb0237
LP
560 /* Checks whether a specific controller is accessible,
561 * i.e. its hierarchy mounted. In the unified hierarchy all
562 * controllers are considered accessible, except for the named
563 * hierarchies */
b12afc8c 564
efdb0237
LP
565 if (!cg_controller_is_valid(controller))
566 return -EINVAL;
567
568 unified = cg_unified();
569 if (unified < 0)
570 return unified;
571 if (unified > 0) {
572 /* We don't support named hierarchies if we are using
573 * the unified hierarchy. */
574
575 if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
576 return 0;
577
578 if (startswith(controller, "name="))
579 return -EOPNOTSUPP;
580
581 } else {
582 const char *cc, *dn;
583
584 dn = controller_to_dirname(controller);
585 cc = strjoina("/sys/fs/cgroup/", dn);
586
587 if (laccess(cc, F_OK) < 0)
588 return -errno;
589 }
37099707
LP
590
591 return 0;
592}
593
3474ae3c 594int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
37099707 595 int r;
dbd821ac 596
efdb0237 597 assert(controller);
3474ae3c 598 assert(fs);
70132bd0 599
efdb0237
LP
600 /* Check if the specified controller is actually accessible */
601 r = controller_is_accessible(controller);
37099707
LP
602 if (r < 0)
603 return r;
3474ae3c 604
efdb0237 605 return cg_get_path(controller, path, suffix, fs);
8c6db833
LP
606}
607
e27796a0 608static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
4ad49000
LP
609 assert(path);
610 assert(sb);
611 assert(ftwbuf);
e27796a0
LP
612
613 if (typeflag != FTW_DP)
614 return 0;
615
616 if (ftwbuf->level < 1)
617 return 0;
618
e155a0aa 619 (void) rmdir(path);
e27796a0
LP
620 return 0;
621}
622
8c6db833 623int cg_trim(const char *controller, const char *path, bool delete_root) {
7027ff61 624 _cleanup_free_ char *fs = NULL;
e27796a0 625 int r = 0;
8c6db833 626
8c6db833
LP
627 assert(path);
628
e27796a0
LP
629 r = cg_get_path(controller, path, NULL, &fs);
630 if (r < 0)
8c6db833
LP
631 return r;
632
e27796a0 633 errno = 0;
e155a0aa
LP
634 if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) {
635 if (errno == ENOENT)
636 r = 0;
637 else if (errno != 0)
638 r = -errno;
639 else
640 r = -EIO;
641 }
e27796a0
LP
642
643 if (delete_root) {
4ad49000
LP
644 if (rmdir(fs) < 0 && errno != ENOENT)
645 return -errno;
e27796a0
LP
646 }
647
e27796a0 648 return r;
8c6db833
LP
649}
650
1434ae6f
LP
651int cg_create(const char *controller, const char *path) {
652 _cleanup_free_ char *fs = NULL;
653 int r;
654
655 r = cg_get_path_and_check(controller, path, NULL, &fs);
656 if (r < 0)
657 return r;
658
659 r = mkdir_parents(fs, 0755);
660 if (r < 0)
661 return r;
662
663 if (mkdir(fs, 0755) < 0) {
664
665 if (errno == EEXIST)
666 return 0;
667
668 return -errno;
669 }
670
671 return 1;
672}
673
674int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
675 int r, q;
676
677 assert(pid >= 0);
678
679 r = cg_create(controller, path);
680 if (r < 0)
681 return r;
682
683 q = cg_attach(controller, path, pid);
684 if (q < 0)
685 return q;
686
687 /* This does not remove the cgroup on failure */
688 return r;
689}
690
8c6db833 691int cg_attach(const char *controller, const char *path, pid_t pid) {
574d5f2d
LP
692 _cleanup_free_ char *fs = NULL;
693 char c[DECIMAL_STR_MAX(pid_t) + 2];
8c6db833
LP
694 int r;
695
8c6db833
LP
696 assert(path);
697 assert(pid >= 0);
698
b043cd0b 699 r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
3474ae3c 700 if (r < 0)
c6c18be3 701 return r;
8c6db833
LP
702
703 if (pid == 0)
704 pid = getpid();
705
de0671ee 706 snprintf(c, sizeof(c), PID_FMT"\n", pid);
8c6db833 707
4c1fc3e4 708 return write_string_file(fs, c, 0);
8c6db833
LP
709}
710
13b84ec7
LP
711int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
712 int r;
713
714 assert(controller);
715 assert(path);
716 assert(pid >= 0);
717
718 r = cg_attach(controller, path, pid);
719 if (r < 0) {
720 char prefix[strlen(path) + 1];
721
722 /* This didn't work? Then let's try all prefixes of
723 * the destination */
724
fecffe5d 725 PATH_FOREACH_PREFIX(prefix, path) {
e155a0aa
LP
726 int q;
727
728 q = cg_attach(controller, prefix, pid);
729 if (q >= 0)
730 return q;
13b84ec7
LP
731 }
732 }
733
e155a0aa 734 return r;
13b84ec7
LP
735}
736
2d76d14e
LP
737int cg_set_group_access(
738 const char *controller,
739 const char *path,
740 mode_t mode,
741 uid_t uid,
742 gid_t gid) {
743
574d5f2d 744 _cleanup_free_ char *fs = NULL;
8c6db833
LP
745 int r;
746
e155a0aa
LP
747 if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
748 return 0;
8c6db833 749
fed1e721 750 if (mode != MODE_INVALID)
8d53b453
LP
751 mode &= 0777;
752
753 r = cg_get_path(controller, path, NULL, &fs);
754 if (r < 0)
8c6db833
LP
755 return r;
756
574d5f2d 757 return chmod_and_chown(fs, mode, uid, gid);
8c6db833
LP
758}
759
974efc46
LP
760int cg_set_task_access(
761 const char *controller,
762 const char *path,
763 mode_t mode,
764 uid_t uid,
4ad49000 765 gid_t gid) {
974efc46
LP
766
767 _cleanup_free_ char *fs = NULL, *procs = NULL;
efdb0237 768 int r, unified;
8c6db833 769
8c6db833
LP
770 assert(path);
771
fed1e721 772 if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
8d53b453
LP
773 return 0;
774
fed1e721 775 if (mode != MODE_INVALID)
8d53b453
LP
776 mode &= 0666;
777
b043cd0b 778 r = cg_get_path(controller, path, "cgroup.procs", &fs);
8d53b453 779 if (r < 0)
8c6db833
LP
780 return r;
781
782 r = chmod_and_chown(fs, mode, uid, gid);
974efc46
LP
783 if (r < 0)
784 return r;
8c6db833 785
efdb0237
LP
786 unified = cg_unified();
787 if (unified < 0)
788 return unified;
789 if (unified)
790 return 0;
791
b043cd0b
LP
792 /* Compatibility, Always keep values for "tasks" in sync with
793 * "cgroup.procs" */
efdb0237
LP
794 if (cg_get_path(controller, path, "tasks", &procs) >= 0)
795 (void) chmod_and_chown(procs, mode, uid, gid);
974efc46 796
efdb0237 797 return 0;
8c6db833
LP
798}
799
7027ff61 800int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
7027ff61
LP
801 _cleanup_fclose_ FILE *f = NULL;
802 char line[LINE_MAX];
8af8afd6 803 const char *fs;
efdb0237
LP
804 size_t cs = 0;
805 int unified;
8c6db833 806
8c6db833 807 assert(path);
c6c18be3 808 assert(pid >= 0);
8c6db833 809
efdb0237
LP
810 unified = cg_unified();
811 if (unified < 0)
812 return unified;
813 if (unified == 0) {
814 if (controller) {
815 if (!cg_controller_is_valid(controller))
816 return -EINVAL;
817 } else
818 controller = SYSTEMD_CGROUP_CONTROLLER;
78edb35a 819
efdb0237
LP
820 cs = strlen(controller);
821 }
7027ff61 822
b68fa010 823 fs = procfs_file_alloca(pid, "cgroup");
c6c18be3 824 f = fopen(fs, "re");
4c633005
LP
825 if (!f)
826 return errno == ENOENT ? -ESRCH : -errno;
827
7027ff61 828 FOREACH_LINE(line, f, return -errno) {
efdb0237 829 char *e, *p;
c6c18be3
LP
830
831 truncate_nl(line);
832
efdb0237
LP
833 if (unified) {
834 e = startswith(line, "0:");
835 if (!e)
836 continue;
c6c18be3 837
efdb0237
LP
838 e = strchr(e, ':');
839 if (!e)
840 continue;
841 } else {
842 char *l;
843 size_t k;
844 const char *word, *state;
845 bool found = false;
846
847 l = strchr(line, ':');
848 if (!l)
849 continue;
8af8afd6 850
efdb0237
LP
851 l++;
852 e = strchr(l, ':');
853 if (!e)
854 continue;
8af8afd6 855
efdb0237
LP
856 *e = 0;
857 FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
858 if (k == cs && memcmp(word, controller, cs) == 0) {
859 found = true;
860 break;
861 }
8af8afd6
LP
862 }
863
efdb0237
LP
864 if (!found)
865 continue;
8af8afd6
LP
866 }
867
8af8afd6 868 p = strdup(e + 1);
7027ff61
LP
869 if (!p)
870 return -ENOMEM;
c6c18be3
LP
871
872 *path = p;
7027ff61 873 return 0;
c6c18be3
LP
874 }
875
1c80e425 876 return -ENODATA;
8c6db833
LP
877}
878
879int cg_install_release_agent(const char *controller, const char *agent) {
7027ff61 880 _cleanup_free_ char *fs = NULL, *contents = NULL;
efdb0237
LP
881 const char *sc;
882 int r, unified;
8c6db833 883
8c6db833
LP
884 assert(agent);
885
efdb0237
LP
886 unified = cg_unified();
887 if (unified < 0)
888 return unified;
889 if (unified) /* doesn't apply to unified hierarchy */
890 return -EOPNOTSUPP;
891
7027ff61
LP
892 r = cg_get_path(controller, NULL, "release_agent", &fs);
893 if (r < 0)
c6c18be3 894 return r;
8c6db833 895
7027ff61
LP
896 r = read_one_line_file(fs, &contents);
897 if (r < 0)
898 return r;
8c6db833
LP
899
900 sc = strstrip(contents);
e155a0aa 901 if (isempty(sc)) {
4c1fc3e4 902 r = write_string_file(fs, agent, 0);
574d5f2d 903 if (r < 0)
7027ff61 904 return r;
b8725df8 905 } else if (!path_equal(sc, agent))
7027ff61 906 return -EEXIST;
8c6db833 907
0da16248 908 fs = mfree(fs);
7027ff61
LP
909 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
910 if (r < 0)
911 return r;
8c6db833 912
0da16248 913 contents = mfree(contents);
7027ff61
LP
914 r = read_one_line_file(fs, &contents);
915 if (r < 0)
916 return r;
8c6db833
LP
917
918 sc = strstrip(contents);
8c6db833 919 if (streq(sc, "0")) {
4c1fc3e4 920 r = write_string_file(fs, "1", 0);
7027ff61
LP
921 if (r < 0)
922 return r;
c6c18be3 923
7027ff61
LP
924 return 1;
925 }
8c6db833 926
7027ff61
LP
927 if (!streq(sc, "1"))
928 return -EIO;
8c6db833 929
7027ff61 930 return 0;
8c6db833
LP
931}
932
ad929bcc
KS
933int cg_uninstall_release_agent(const char *controller) {
934 _cleanup_free_ char *fs = NULL;
efdb0237
LP
935 int r, unified;
936
937 unified = cg_unified();
938 if (unified < 0)
939 return unified;
940 if (unified) /* Doesn't apply to unified hierarchy */
941 return -EOPNOTSUPP;
ad929bcc 942
ac9ef333
LP
943 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
944 if (r < 0)
945 return r;
946
4c1fc3e4 947 r = write_string_file(fs, "0", 0);
ac9ef333
LP
948 if (r < 0)
949 return r;
950
0da16248 951 fs = mfree(fs);
ac9ef333 952
ad929bcc
KS
953 r = cg_get_path(controller, NULL, "release_agent", &fs);
954 if (r < 0)
955 return r;
956
4c1fc3e4 957 r = write_string_file(fs, "", 0);
ad929bcc
KS
958 if (r < 0)
959 return r;
960
ac9ef333 961 return 0;
ad929bcc
KS
962}
963
6f883237 964int cg_is_empty(const char *controller, const char *path) {
7027ff61 965 _cleanup_fclose_ FILE *f = NULL;
efdb0237 966 pid_t pid;
7027ff61 967 int r;
8c6db833 968
8c6db833
LP
969 assert(path);
970
b043cd0b 971 r = cg_enumerate_processes(controller, path, &f);
6f883237
LP
972 if (r == -ENOENT)
973 return 1;
c3175a7f 974 if (r < 0)
6f883237 975 return r;
8c6db833 976
6f883237 977 r = cg_read_pid(f, &pid);
c6c18be3
LP
978 if (r < 0)
979 return r;
8c6db833 980
6f883237 981 return r == 0;
8c6db833
LP
982}
983
6f883237 984int cg_is_empty_recursive(const char *controller, const char *path) {
efdb0237 985 int unified, r;
8c6db833 986
8c6db833
LP
987 assert(path);
988
6fd66507
LP
989 /* The root cgroup is always populated */
990 if (controller && (isempty(path) || path_equal(path, "/")))
efdb0237 991 return false;
6fd66507 992
efdb0237
LP
993 unified = cg_unified();
994 if (unified < 0)
995 return unified;
35d2e7ec 996
efdb0237
LP
997 if (unified > 0) {
998 _cleanup_free_ char *populated = NULL, *t = NULL;
8c6db833 999
efdb0237
LP
1000 /* On the unified hierarchy we can check empty state
1001 * via the "cgroup.populated" attribute. */
8c6db833 1002
efdb0237
LP
1003 r = cg_get_path(controller, path, "cgroup.populated", &populated);
1004 if (r < 0)
1005 return r;
1006
1007 r = read_one_line_file(populated, &t);
9a66c87a
LP
1008 if (r == -ENOENT)
1009 return 1;
efdb0237
LP
1010 if (r < 0)
1011 return r;
1012
1013 return streq(t, "0");
1014 } else {
1015 _cleanup_closedir_ DIR *d = NULL;
1016 char *fn;
8c6db833 1017
efdb0237 1018 r = cg_is_empty(controller, path);
35d2e7ec 1019 if (r <= 0)
7027ff61 1020 return r;
35d2e7ec 1021
efdb0237
LP
1022 r = cg_enumerate_subgroups(controller, path, &d);
1023 if (r == -ENOENT)
1024 return 1;
1025 if (r < 0)
1026 return r;
35d2e7ec 1027
efdb0237
LP
1028 while ((r = cg_read_subgroup(d, &fn)) > 0) {
1029 _cleanup_free_ char *p = NULL;
1030
1031 p = strjoin(path, "/", fn, NULL);
1032 free(fn);
1033 if (!p)
1034 return -ENOMEM;
1035
1036 r = cg_is_empty_recursive(controller, p);
1037 if (r <= 0)
1038 return r;
1039 }
1040 if (r < 0)
1041 return r;
1042
1043 return true;
1044 }
35d2e7ec
LP
1045}
1046
1047int cg_split_spec(const char *spec, char **controller, char **path) {
35d2e7ec 1048 char *t = NULL, *u = NULL;
efdb0237 1049 const char *e;
35d2e7ec
LP
1050
1051 assert(spec);
35d2e7ec
LP
1052
1053 if (*spec == '/') {
e884315e
LP
1054 if (!path_is_safe(spec))
1055 return -EINVAL;
35d2e7ec
LP
1056
1057 if (path) {
246aa6dd
LP
1058 t = strdup(spec);
1059 if (!t)
35d2e7ec
LP
1060 return -ENOMEM;
1061
dbb9401d 1062 *path = path_kill_slashes(t);
8c6db833
LP
1063 }
1064
35d2e7ec
LP
1065 if (controller)
1066 *controller = NULL;
1067
1068 return 0;
8c6db833
LP
1069 }
1070
246aa6dd
LP
1071 e = strchr(spec, ':');
1072 if (!e) {
185a0874 1073 if (!cg_controller_is_valid(spec))
35d2e7ec
LP
1074 return -EINVAL;
1075
1076 if (controller) {
efdb0237 1077 t = strdup(spec);
246aa6dd 1078 if (!t)
35d2e7ec
LP
1079 return -ENOMEM;
1080
1081 *controller = t;
1082 }
1083
1084 if (path)
1085 *path = NULL;
1086
1087 return 0;
8c6db833
LP
1088 }
1089
efdb0237 1090 t = strndup(spec, e-spec);
e884315e
LP
1091 if (!t)
1092 return -ENOMEM;
185a0874 1093 if (!cg_controller_is_valid(t)) {
e884315e 1094 free(t);
35d2e7ec 1095 return -EINVAL;
246aa6dd
LP
1096 }
1097
efdb0237
LP
1098 if (isempty(e+1))
1099 u = NULL;
1100 else {
baa89da4
LP
1101 u = strdup(e+1);
1102 if (!u) {
1103 free(t);
1104 return -ENOMEM;
1105 }
35d2e7ec 1106
baa89da4
LP
1107 if (!path_is_safe(u) ||
1108 !path_is_absolute(u)) {
1109 free(t);
1110 free(u);
1111 return -EINVAL;
1112 }
1113
1114 path_kill_slashes(u);
1115 }
5954c074 1116
35d2e7ec
LP
1117 if (controller)
1118 *controller = t;
e884315e
LP
1119 else
1120 free(t);
35d2e7ec
LP
1121
1122 if (path)
1123 *path = u;
e884315e
LP
1124 else
1125 free(u);
35d2e7ec
LP
1126
1127 return 0;
8c6db833 1128}
c6c18be3 1129
7027ff61 1130int cg_mangle_path(const char *path, char **result) {
78edb35a
LP
1131 _cleanup_free_ char *c = NULL, *p = NULL;
1132 char *t;
35d2e7ec
LP
1133 int r;
1134
1135 assert(path);
1136 assert(result);
1137
73e231ab 1138 /* First, check if it already is a filesystem path */
7027ff61 1139 if (path_startswith(path, "/sys/fs/cgroup")) {
35d2e7ec 1140
b69d29ce
LP
1141 t = strdup(path);
1142 if (!t)
35d2e7ec
LP
1143 return -ENOMEM;
1144
dbb9401d 1145 *result = path_kill_slashes(t);
35d2e7ec
LP
1146 return 0;
1147 }
1148
73e231ab 1149 /* Otherwise, treat it as cg spec */
b69d29ce
LP
1150 r = cg_split_spec(path, &c, &p);
1151 if (r < 0)
35d2e7ec
LP
1152 return r;
1153
efdb0237 1154 return cg_get_path(c ?: SYSTEMD_CGROUP_CONTROLLER, p ?: "/", NULL, result);
35d2e7ec 1155}
1f73f0f1 1156
7027ff61 1157int cg_get_root_path(char **path) {
9444b1f2 1158 char *p, *e;
7027ff61
LP
1159 int r;
1160
1161 assert(path);
1162
9444b1f2 1163 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
7027ff61
LP
1164 if (r < 0)
1165 return r;
1166
efdb0237
LP
1167 e = endswith(p, "/" SPECIAL_INIT_SCOPE);
1168 if (!e)
1169 e = endswith(p, "/" SPECIAL_SYSTEM_SLICE); /* legacy */
1170 if (!e)
1171 e = endswith(p, "/system"); /* even more legacy */
9444b1f2 1172 if (e)
7027ff61
LP
1173 *e = 0;
1174
1f73f0f1
LP
1175 *path = p;
1176 return 0;
1177}
b59e2465 1178
751bc6ac
LP
1179int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
1180 _cleanup_free_ char *rt = NULL;
1181 char *p;
ba1261bc
LP
1182 int r;
1183
e9174f29 1184 assert(cgroup);
751bc6ac 1185 assert(shifted);
e9174f29
LP
1186
1187 if (!root) {
1188 /* If the root was specified let's use that, otherwise
1189 * let's determine it from PID 1 */
1190
751bc6ac 1191 r = cg_get_root_path(&rt);
e9174f29
LP
1192 if (r < 0)
1193 return r;
1194
751bc6ac 1195 root = rt;
e9174f29 1196 }
ba1261bc 1197
751bc6ac 1198 p = path_startswith(cgroup, root);
efdb0237 1199 if (p && p > cgroup)
751bc6ac
LP
1200 *shifted = p - 1;
1201 else
1202 *shifted = cgroup;
1203
1204 return 0;
1205}
1206
1207int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
1208 _cleanup_free_ char *raw = NULL;
1209 const char *c;
1210 int r;
1211
1212 assert(pid >= 0);
1213 assert(cgroup);
1214
1215 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &raw);
7027ff61 1216 if (r < 0)
ba1261bc 1217 return r;
ba1261bc 1218
751bc6ac
LP
1219 r = cg_shift_path(raw, root, &c);
1220 if (r < 0)
1221 return r;
ba1261bc 1222
751bc6ac
LP
1223 if (c == raw) {
1224 *cgroup = raw;
1225 raw = NULL;
1226 } else {
1227 char *n;
ba1261bc 1228
751bc6ac
LP
1229 n = strdup(c);
1230 if (!n)
ba1261bc 1231 return -ENOMEM;
ba1261bc 1232
751bc6ac
LP
1233 *cgroup = n;
1234 }
ba1261bc
LP
1235
1236 return 0;
1237}
1238
7027ff61 1239int cg_path_decode_unit(const char *cgroup, char **unit){
8b0849e9
LP
1240 char *c, *s;
1241 size_t n;
ef1673d1
MT
1242
1243 assert(cgroup);
6c03089c 1244 assert(unit);
ef1673d1 1245
8b0849e9
LP
1246 n = strcspn(cgroup, "/");
1247 if (n < 3)
1248 return -ENXIO;
1249
1250 c = strndupa(cgroup, n);
ae018d9b 1251 c = cg_unescape(c);
ef1673d1 1252
7410616c 1253 if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
cfeaa44a 1254 return -ENXIO;
ef1673d1 1255
d7bd3de0 1256 s = strdup(c);
6c03089c
LP
1257 if (!s)
1258 return -ENOMEM;
1259
1260 *unit = s;
ef1673d1
MT
1261 return 0;
1262}
1263
8b0849e9
LP
1264static bool valid_slice_name(const char *p, size_t n) {
1265
1266 if (!p)
1267 return false;
1268
1269 if (n < strlen("x.slice"))
1270 return false;
1271
1272 if (memcmp(p + n - 6, ".slice", 6) == 0) {
1273 char buf[n+1], *c;
1274
1275 memcpy(buf, p, n);
1276 buf[n] = 0;
1277
1278 c = cg_unescape(buf);
1279
7410616c 1280 return unit_name_is_valid(c, UNIT_NAME_PLAIN);
8b0849e9
LP
1281 }
1282
1283 return false;
1284}
1285
9444b1f2 1286static const char *skip_slices(const char *p) {
8b0849e9
LP
1287 assert(p);
1288
9444b1f2
LP
1289 /* Skips over all slice assignments */
1290
1291 for (;;) {
1021b21b
LP
1292 size_t n;
1293
9444b1f2
LP
1294 p += strspn(p, "/");
1295
1296 n = strcspn(p, "/");
8b0849e9 1297 if (!valid_slice_name(p, n))
9444b1f2
LP
1298 return p;
1299
1300 p += n;
1301 }
1302}
1303
8b0849e9 1304int cg_path_get_unit(const char *path, char **ret) {
6c03089c 1305 const char *e;
8b0849e9
LP
1306 char *unit;
1307 int r;
6c03089c
LP
1308
1309 assert(path);
8b0849e9 1310 assert(ret);
6c03089c 1311
9444b1f2 1312 e = skip_slices(path);
6c03089c 1313
8b0849e9
LP
1314 r = cg_path_decode_unit(e, &unit);
1315 if (r < 0)
1316 return r;
1317
1318 /* We skipped over the slices, don't accept any now */
1319 if (endswith(unit, ".slice")) {
1320 free(unit);
1321 return -ENXIO;
1322 }
1323
1324 *ret = unit;
1325 return 0;
6c03089c
LP
1326}
1327
1328int cg_pid_get_unit(pid_t pid, char **unit) {
7fd1b19b 1329 _cleanup_free_ char *cgroup = NULL;
ba1261bc 1330 int r;
ba1261bc 1331
ef1673d1
MT
1332 assert(unit);
1333
7027ff61 1334 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
ef1673d1
MT
1335 if (r < 0)
1336 return r;
1337
6c03089c
LP
1338 return cg_path_get_unit(cgroup, unit);
1339}
ef1673d1 1340
d4fffc4b
ZJS
1341/**
1342 * Skip session-*.scope, but require it to be there.
1343 */
9444b1f2
LP
1344static const char *skip_session(const char *p) {
1345 size_t n;
1346
8b0849e9
LP
1347 if (isempty(p))
1348 return NULL;
9444b1f2
LP
1349
1350 p += strspn(p, "/");
1351
1352 n = strcspn(p, "/");
8b0849e9 1353 if (n < strlen("session-x.scope"))
d4fffc4b
ZJS
1354 return NULL;
1355
8b0849e9
LP
1356 if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) {
1357 char buf[n - 8 - 6 + 1];
1358
1359 memcpy(buf, p + 8, n - 8 - 6);
1360 buf[n - 8 - 6] = 0;
d4fffc4b 1361
8b0849e9
LP
1362 /* Note that session scopes never need unescaping,
1363 * since they cannot conflict with the kernel's own
1364 * names, hence we don't need to call cg_unescape()
1365 * here. */
1366
1367 if (!session_id_valid(buf))
1368 return false;
1369
1370 p += n;
1371 p += strspn(p, "/");
1372 return p;
1373 }
1374
1375 return NULL;
d4fffc4b
ZJS
1376}
1377
1378/**
1379 * Skip user@*.service, but require it to be there.
1380 */
1381static const char *skip_user_manager(const char *p) {
1382 size_t n;
1383
8b0849e9
LP
1384 if (isempty(p))
1385 return NULL;
d4fffc4b
ZJS
1386
1387 p += strspn(p, "/");
1388
1389 n = strcspn(p, "/");
8b0849e9 1390 if (n < strlen("user@x.service"))
6c03089c 1391 return NULL;
ef1673d1 1392
8b0849e9
LP
1393 if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) {
1394 char buf[n - 5 - 8 + 1];
9444b1f2 1395
8b0849e9
LP
1396 memcpy(buf, p + 5, n - 5 - 8);
1397 buf[n - 5 - 8] = 0;
1398
1399 /* Note that user manager services never need unescaping,
1400 * since they cannot conflict with the kernel's own
1401 * names, hence we don't need to call cg_unescape()
1402 * here. */
1403
1404 if (parse_uid(buf, NULL) < 0)
1405 return NULL;
1406
1407 p += n;
1408 p += strspn(p, "/");
1409
1410 return p;
1411 }
1412
1413 return NULL;
9444b1f2
LP
1414}
1415
329ac4bc 1416static const char *skip_user_prefix(const char *path) {
d4fffc4b 1417 const char *e, *t;
ef1673d1 1418
6c03089c 1419 assert(path);
ba1261bc 1420
9444b1f2
LP
1421 /* Skip slices, if there are any */
1422 e = skip_slices(path);
ba1261bc 1423
329ac4bc 1424 /* Skip the user manager, if it's in the path now... */
8b0849e9 1425 t = skip_user_manager(e);
329ac4bc
LP
1426 if (t)
1427 return t;
8b0849e9 1428
329ac4bc
LP
1429 /* Alternatively skip the user session if it is in the path... */
1430 return skip_session(e);
1431}
32081481 1432
329ac4bc
LP
1433int cg_path_get_user_unit(const char *path, char **ret) {
1434 const char *t;
6c03089c 1435
329ac4bc
LP
1436 assert(path);
1437 assert(ret);
8b0849e9 1438
329ac4bc
LP
1439 t = skip_user_prefix(path);
1440 if (!t)
8b0849e9 1441 return -ENXIO;
8b0849e9 1442
329ac4bc
LP
1443 /* And from here on it looks pretty much the same as for a
1444 * system unit, hence let's use the same parser from here
1445 * on. */
1446 return cg_path_get_unit(t, ret);
ef1673d1 1447}
ba1261bc 1448
ef1673d1 1449int cg_pid_get_user_unit(pid_t pid, char **unit) {
7fd1b19b 1450 _cleanup_free_ char *cgroup = NULL;
6c03089c
LP
1451 int r;
1452
1453 assert(unit);
1454
7027ff61 1455 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
6c03089c
LP
1456 if (r < 0)
1457 return r;
1458
1459 return cg_path_get_user_unit(cgroup, unit);
ba1261bc 1460}
e884315e 1461
7027ff61 1462int cg_path_get_machine_name(const char *path, char **machine) {
efdb0237
LP
1463 _cleanup_free_ char *u = NULL;
1464 const char *sl;
89f7c846 1465 int r;
374ec6ab 1466
89f7c846
LP
1467 r = cg_path_get_unit(path, &u);
1468 if (r < 0)
1469 return r;
7027ff61 1470
efdb0237 1471 sl = strjoina("/run/systemd/machines/unit:", u);
89f7c846 1472 return readlink_malloc(sl, machine);
7027ff61
LP
1473}
1474
1475int cg_pid_get_machine_name(pid_t pid, char **machine) {
7fd1b19b 1476 _cleanup_free_ char *cgroup = NULL;
7027ff61
LP
1477 int r;
1478
1479 assert(machine);
1480
1481 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1482 if (r < 0)
1483 return r;
1484
1485 return cg_path_get_machine_name(cgroup, machine);
1486}
1487
1488int cg_path_get_session(const char *path, char **session) {
8b0849e9
LP
1489 _cleanup_free_ char *unit = NULL;
1490 char *start, *end;
1491 int r;
7027ff61
LP
1492
1493 assert(path);
7027ff61 1494
8b0849e9
LP
1495 r = cg_path_get_unit(path, &unit);
1496 if (r < 0)
1497 return r;
7027ff61 1498
8b0849e9
LP
1499 start = startswith(unit, "session-");
1500 if (!start)
cfeaa44a 1501 return -ENXIO;
8b0849e9
LP
1502 end = endswith(start, ".scope");
1503 if (!end)
cfeaa44a 1504 return -ENXIO;
8b0849e9
LP
1505
1506 *end = 0;
1507 if (!session_id_valid(start))
cfeaa44a 1508 return -ENXIO;
374ec6ab 1509
af08d2f9 1510 if (session) {
8b0849e9 1511 char *rr;
af08d2f9 1512
8b0849e9
LP
1513 rr = strdup(start);
1514 if (!rr)
af08d2f9
LP
1515 return -ENOMEM;
1516
8b0849e9 1517 *session = rr;
af08d2f9 1518 }
7027ff61 1519
7027ff61
LP
1520 return 0;
1521}
1522
1523int cg_pid_get_session(pid_t pid, char **session) {
7fd1b19b 1524 _cleanup_free_ char *cgroup = NULL;
7027ff61
LP
1525 int r;
1526
7027ff61
LP
1527 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1528 if (r < 0)
1529 return r;
1530
1531 return cg_path_get_session(cgroup, session);
1532}
1533
ae018d9b 1534int cg_path_get_owner_uid(const char *path, uid_t *uid) {
374ec6ab 1535 _cleanup_free_ char *slice = NULL;
8b0849e9 1536 char *start, *end;
374ec6ab 1537 int r;
ae018d9b
LP
1538
1539 assert(path);
ae018d9b 1540
374ec6ab
LP
1541 r = cg_path_get_slice(path, &slice);
1542 if (r < 0)
1543 return r;
ae018d9b 1544
674eb685
LP
1545 start = startswith(slice, "user-");
1546 if (!start)
cfeaa44a 1547 return -ENXIO;
8b0849e9 1548 end = endswith(start, ".slice");
674eb685 1549 if (!end)
cfeaa44a 1550 return -ENXIO;
ae018d9b 1551
8b0849e9
LP
1552 *end = 0;
1553 if (parse_uid(start, uid) < 0)
cfeaa44a 1554 return -ENXIO;
674eb685 1555
674eb685 1556 return 0;
ae018d9b
LP
1557}
1558
1559int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
1560 _cleanup_free_ char *cgroup = NULL;
1561 int r;
1562
ae018d9b
LP
1563 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1564 if (r < 0)
1565 return r;
1566
1567 return cg_path_get_owner_uid(cgroup, uid);
1568}
1569
1021b21b
LP
1570int cg_path_get_slice(const char *p, char **slice) {
1571 const char *e = NULL;
1021b21b
LP
1572
1573 assert(p);
1574 assert(slice);
1575
329ac4bc
LP
1576 /* Finds the right-most slice unit from the beginning, but
1577 * stops before we come to the first non-slice unit. */
1578
1021b21b
LP
1579 for (;;) {
1580 size_t n;
1581
1582 p += strspn(p, "/");
1583
1584 n = strcspn(p, "/");
8b0849e9 1585 if (!valid_slice_name(p, n)) {
1021b21b 1586
8b0849e9
LP
1587 if (!e) {
1588 char *s;
1021b21b 1589
8b0849e9
LP
1590 s = strdup("-.slice");
1591 if (!s)
1592 return -ENOMEM;
1021b21b 1593
8b0849e9
LP
1594 *slice = s;
1595 return 0;
1596 }
1597
1598 return cg_path_decode_unit(e, slice);
1021b21b
LP
1599 }
1600
1601 e = p;
1021b21b
LP
1602 p += n;
1603 }
1604}
1605
1606int cg_pid_get_slice(pid_t pid, char **slice) {
1607 _cleanup_free_ char *cgroup = NULL;
1608 int r;
1609
1610 assert(slice);
1611
1612 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1613 if (r < 0)
1614 return r;
1615
1616 return cg_path_get_slice(cgroup, slice);
1617}
1618
329ac4bc
LP
1619int cg_path_get_user_slice(const char *p, char **slice) {
1620 const char *t;
1621 assert(p);
1622 assert(slice);
1623
1624 t = skip_user_prefix(p);
1625 if (!t)
1626 return -ENXIO;
1627
1628 /* And now it looks pretty much the same as for a system
1629 * slice, so let's just use the same parser from here on. */
1630 return cg_path_get_slice(t, slice);
1631}
1632
1633int cg_pid_get_user_slice(pid_t pid, char **slice) {
1634 _cleanup_free_ char *cgroup = NULL;
1635 int r;
1636
1637 assert(slice);
1638
1639 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1640 if (r < 0)
1641 return r;
1642
1643 return cg_path_get_user_slice(cgroup, slice);
1644}
1645
ae018d9b
LP
1646char *cg_escape(const char *p) {
1647 bool need_prefix = false;
1648
1649 /* This implements very minimal escaping for names to be used
1650 * as file names in the cgroup tree: any name which might
1651 * conflict with a kernel name or is prefixed with '_' is
1652 * prefixed with a '_'. That way, when reading cgroup names it
1653 * is sufficient to remove a single prefixing underscore if
1654 * there is one. */
1655
1656 /* The return value of this function (unlike cg_unescape())
1657 * needs free()! */
1658
a0ab5665
LP
1659 if (p[0] == 0 ||
1660 p[0] == '_' ||
1661 p[0] == '.' ||
1662 streq(p, "notify_on_release") ||
1663 streq(p, "release_agent") ||
efdb0237
LP
1664 streq(p, "tasks") ||
1665 startswith(p, "cgroup."))
ae018d9b
LP
1666 need_prefix = true;
1667 else {
1668 const char *dot;
1669
1670 dot = strrchr(p, '.');
1671 if (dot) {
efdb0237
LP
1672 CGroupController c;
1673 size_t l = dot - p;
ae018d9b 1674
efdb0237
LP
1675 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
1676 const char *n;
1677
1678 n = cgroup_controller_to_string(c);
ae018d9b 1679
efdb0237
LP
1680 if (l != strlen(n))
1681 continue;
ae018d9b 1682
efdb0237
LP
1683 if (memcmp(p, n, l) != 0)
1684 continue;
1685
1686 need_prefix = true;
1687 break;
ae018d9b
LP
1688 }
1689 }
1690 }
1691
1692 if (need_prefix)
1693 return strappend("_", p);
efdb0237
LP
1694
1695 return strdup(p);
ae018d9b
LP
1696}
1697
1698char *cg_unescape(const char *p) {
1699 assert(p);
1700
1701 /* The return value of this function (unlike cg_escape())
1702 * doesn't need free()! */
1703
1704 if (p[0] == '_')
1705 return (char*) p+1;
1706
1707 return (char*) p;
1708}
78edb35a
LP
1709
1710#define CONTROLLER_VALID \
4b549144 1711 DIGITS LETTERS \
78edb35a
LP
1712 "_"
1713
185a0874 1714bool cg_controller_is_valid(const char *p) {
78edb35a
LP
1715 const char *t, *s;
1716
1717 if (!p)
1718 return false;
1719
185a0874
DJL
1720 s = startswith(p, "name=");
1721 if (s)
1722 p = s;
78edb35a
LP
1723
1724 if (*p == 0 || *p == '_')
1725 return false;
1726
1727 for (t = p; *t; t++)
1728 if (!strchr(CONTROLLER_VALID, *t))
1729 return false;
1730
1731 if (t - p > FILENAME_MAX)
1732 return false;
1733
1734 return true;
1735}
a016b922
LP
1736
1737int cg_slice_to_path(const char *unit, char **ret) {
1738 _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
1739 const char *dash;
7410616c 1740 int r;
a016b922
LP
1741
1742 assert(unit);
1743 assert(ret);
1744
c96cc582
LP
1745 if (streq(unit, "-.slice")) {
1746 char *x;
1747
1748 x = strdup("");
1749 if (!x)
1750 return -ENOMEM;
1751 *ret = x;
1752 return 0;
1753 }
1754
7410616c 1755 if (!unit_name_is_valid(unit, UNIT_NAME_PLAIN))
a016b922
LP
1756 return -EINVAL;
1757
1758 if (!endswith(unit, ".slice"))
1759 return -EINVAL;
1760
7410616c
LP
1761 r = unit_name_to_prefix(unit, &p);
1762 if (r < 0)
1763 return r;
a016b922
LP
1764
1765 dash = strchr(p, '-');
e66e5b61
LP
1766
1767 /* Don't allow initial dashes */
1768 if (dash == p)
1769 return -EINVAL;
1770
a016b922
LP
1771 while (dash) {
1772 _cleanup_free_ char *escaped = NULL;
1773 char n[dash - p + sizeof(".slice")];
1774
e66e5b61
LP
1775 /* Don't allow trailing or double dashes */
1776 if (dash[1] == 0 || dash[1] == '-')
c96cc582 1777 return -EINVAL;
a016b922 1778
c96cc582 1779 strcpy(stpncpy(n, p, dash - p), ".slice");
7410616c 1780 if (!unit_name_is_valid(n, UNIT_NAME_PLAIN))
a016b922
LP
1781 return -EINVAL;
1782
1783 escaped = cg_escape(n);
1784 if (!escaped)
1785 return -ENOMEM;
1786
1787 if (!strextend(&s, escaped, "/", NULL))
1788 return -ENOMEM;
1789
1790 dash = strchr(dash+1, '-');
1791 }
1792
1793 e = cg_escape(unit);
1794 if (!e)
1795 return -ENOMEM;
1796
1797 if (!strextend(&s, e, NULL))
1798 return -ENOMEM;
1799
1800 *ret = s;
1801 s = NULL;
1802
1803 return 0;
1804}
4ad49000
LP
1805
1806int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
1807 _cleanup_free_ char *p = NULL;
1808 int r;
1809
1810 r = cg_get_path(controller, path, attribute, &p);
1811 if (r < 0)
1812 return r;
1813
4c1fc3e4 1814 return write_string_file(p, value, 0);
4ad49000
LP
1815}
1816
934277fe
LP
1817int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) {
1818 _cleanup_free_ char *p = NULL;
1819 int r;
1820
1821 r = cg_get_path(controller, path, attribute, &p);
1822 if (r < 0)
1823 return r;
1824
1825 return read_one_line_file(p, ret);
1826}
1827
efdb0237
LP
1828int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {
1829 CGroupController c;
1830 int r, unified;
4ad49000
LP
1831
1832 /* This one will create a cgroup in our private tree, but also
1833 * duplicate it in the trees specified in mask, and remove it
1834 * in all others */
1835
1836 /* First create the cgroup in our own hierarchy. */
1837 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
1838 if (r < 0)
1839 return r;
1840
efdb0237
LP
1841 /* If we are in the unified hierarchy, we are done now */
1842 unified = cg_unified();
1843 if (unified < 0)
1844 return unified;
1845 if (unified > 0)
1846 return 0;
1847
1848 /* Otherwise, do the same in the other hierarchies */
1849 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
1850 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
1851 const char *n;
1852
1853 n = cgroup_controller_to_string(c);
1854
13b84ec7 1855 if (mask & bit)
efdb0237 1856 (void) cg_create(n, path);
13b84ec7 1857 else if (supported & bit)
efdb0237 1858 (void) cg_trim(n, path, true);
4ad49000
LP
1859 }
1860
13b84ec7 1861 return 0;
4ad49000
LP
1862}
1863
efdb0237
LP
1864int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
1865 CGroupController c;
1866 int r, unified;
4ad49000
LP
1867
1868 r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
13b84ec7
LP
1869 if (r < 0)
1870 return r;
4ad49000 1871
efdb0237
LP
1872 unified = cg_unified();
1873 if (unified < 0)
1874 return unified;
1875 if (unified > 0)
1876 return 0;
7b3fd631 1877
efdb0237
LP
1878 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
1879 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
1880 const char *p = NULL;
7b3fd631 1881
efdb0237
LP
1882 if (!(supported & bit))
1883 continue;
7b3fd631 1884
efdb0237
LP
1885 if (path_callback)
1886 p = path_callback(bit, userdata);
7b3fd631 1887
efdb0237
LP
1888 if (!p)
1889 p = path;
4ad49000 1890
efdb0237 1891 (void) cg_attach_fallback(cgroup_controller_to_string(c), p, pid);
4ad49000
LP
1892 }
1893
13b84ec7 1894 return 0;
4ad49000
LP
1895}
1896
efdb0237 1897int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
6c12b52e
LP
1898 Iterator i;
1899 void *pidp;
1900 int r = 0;
1901
1902 SET_FOREACH(pidp, pids, i) {
fea72cc0 1903 pid_t pid = PTR_TO_PID(pidp);
13b84ec7 1904 int q;
6c12b52e 1905
7b3fd631 1906 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
efdb0237 1907 if (q < 0 && r >= 0)
13b84ec7 1908 r = q;
6c12b52e
LP
1909 }
1910
1911 return r;
1912}
1913
efdb0237 1914int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
b3c5bad3 1915 CGroupController c;
ba09d9c6 1916 int r = 0, unified;
4ad49000 1917
13b84ec7
LP
1918 if (!path_equal(from, to)) {
1919 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
1920 if (r < 0)
1921 return r;
1922 }
4ad49000 1923
efdb0237
LP
1924 unified = cg_unified();
1925 if (unified < 0)
1926 return unified;
1927 if (unified > 0)
1928 return r;
03b90d4b 1929
efdb0237
LP
1930 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
1931 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
1932 const char *p = NULL;
03b90d4b 1933
efdb0237
LP
1934 if (!(supported & bit))
1935 continue;
03b90d4b 1936
efdb0237
LP
1937 if (to_callback)
1938 p = to_callback(bit, userdata);
4ad49000 1939
efdb0237
LP
1940 if (!p)
1941 p = to;
1942
1943 (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, false, false);
4ad49000
LP
1944 }
1945
13b84ec7 1946 return 0;
4ad49000
LP
1947}
1948
efdb0237
LP
1949int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
1950 CGroupController c;
1951 int r, unified;
4ad49000
LP
1952
1953 r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
1954 if (r < 0)
1955 return r;
1956
efdb0237
LP
1957 unified = cg_unified();
1958 if (unified < 0)
1959 return unified;
1960 if (unified > 0)
1961 return r;
1962
1963 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
1964 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
1965
1966 if (!(supported & bit))
1967 continue;
4ad49000 1968
efdb0237 1969 (void) cg_trim(cgroup_controller_to_string(c), path, delete_root);
4ad49000
LP
1970 }
1971
13b84ec7 1972 return 0;
4ad49000
LP
1973}
1974
efdb0237
LP
1975int cg_mask_supported(CGroupMask *ret) {
1976 CGroupMask mask = 0;
1977 int r, unified;
1978
1979 /* Determines the mask of supported cgroup controllers. Only
1980 * includes controllers we can make sense of and that are
1981 * actually accessible. */
4ad49000 1982
efdb0237
LP
1983 unified = cg_unified();
1984 if (unified < 0)
1985 return unified;
1986 if (unified > 0) {
5f4c5fef 1987 _cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
efdb0237
LP
1988 const char *c;
1989
1990 /* In the unified hierarchy we can read the supported
1991 * and accessible controllers from a the top-level
1992 * cgroup attribute */
1993
5f4c5fef
LP
1994 r = cg_get_root_path(&root);
1995 if (r < 0)
1996 return r;
1997
1998 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, "cgroup.controllers", &path);
1999 if (r < 0)
2000 return r;
2001
2002 r = read_one_line_file(path, &controllers);
efdb0237
LP
2003 if (r < 0)
2004 return r;
4ad49000 2005
efdb0237
LP
2006 c = controllers;
2007 for (;;) {
2008 _cleanup_free_ char *n = NULL;
2009 CGroupController v;
2010
2011 r = extract_first_word(&c, &n, NULL, 0);
2012 if (r < 0)
2013 return r;
2014 if (r == 0)
2015 break;
2016
2017 v = cgroup_controller_from_string(n);
2018 if (v < 0)
2019 continue;
2020
2021 mask |= CGROUP_CONTROLLER_TO_MASK(v);
2022 }
2023
03a7b521
LP
2024 /* Currently, we only support the memory and pids
2025 * controller in the unified hierarchy, mask
2026 * everything else off. */
2027 mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_PIDS;
efdb0237
LP
2028
2029 } else {
2030 CGroupController c;
2031
2032 /* In the legacy hierarchy, we check whether which
2033 * hierarchies are mounted. */
2034
2035 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2036 const char *n;
2037
2038 n = cgroup_controller_to_string(c);
2039 if (controller_is_accessible(n) >= 0)
2040 mask |= CGROUP_CONTROLLER_TO_MASK(c);
2041 }
4ad49000
LP
2042 }
2043
efdb0237
LP
2044 *ret = mask;
2045 return 0;
4ad49000 2046}
b12afc8c
LP
2047
2048int cg_kernel_controllers(Set *controllers) {
2049 _cleanup_fclose_ FILE *f = NULL;
2050 char buf[LINE_MAX];
2051 int r;
2052
2053 assert(controllers);
2054
e155a0aa
LP
2055 /* Determines the full list of kernel-known controllers. Might
2056 * include controllers we don't actually support, arbitrary
2057 * named hierarchies and controllers that aren't currently
2058 * accessible (because not mounted). */
2059
b12afc8c
LP
2060 f = fopen("/proc/cgroups", "re");
2061 if (!f) {
2062 if (errno == ENOENT)
2063 return 0;
2064 return -errno;
2065 }
2066
2067 /* Ignore the header line */
2068 (void) fgets(buf, sizeof(buf), f);
2069
2070 for (;;) {
2071 char *controller;
2072 int enabled = 0;
2073
2074 errno = 0;
2075 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
2076
2077 if (feof(f))
2078 break;
2079
e155a0aa 2080 if (ferror(f) && errno != 0)
b12afc8c
LP
2081 return -errno;
2082
2083 return -EBADMSG;
2084 }
2085
2086 if (!enabled) {
2087 free(controller);
2088 continue;
2089 }
2090
efdb0237 2091 if (!cg_controller_is_valid(controller)) {
b12afc8c
LP
2092 free(controller);
2093 return -EBADMSG;
2094 }
2095
2096 r = set_consume(controllers, controller);
2097 if (r < 0)
2098 return r;
2099 }
2100
2101 return 0;
2102}
efdb0237
LP
2103
2104static thread_local int unified_cache = -1;
2105
2106int cg_unified(void) {
2107 struct statfs fs;
2108
2109 /* Checks if we support the unified hierarchy. Returns an
2110 * error when the cgroup hierarchies aren't mounted yet or we
2111 * have any other trouble determining if the unified hierarchy
2112 * is supported. */
2113
2114 if (unified_cache >= 0)
2115 return unified_cache;
2116
2117 if (statfs("/sys/fs/cgroup/", &fs) < 0)
2118 return -errno;
2119
2120 if (F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC))
2121 unified_cache = true;
2122 else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC))
2123 unified_cache = false;
2124 else
2125 return -ENOEXEC;
2126
2127 return unified_cache;
2128}
2129
2130void cg_unified_flush(void) {
2131 unified_cache = -1;
2132}
2133
2134int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
2135 _cleanup_free_ char *fs = NULL;
2136 CGroupController c;
2137 int r, unified;
2138
2139 assert(p);
2140
2141 if (supported == 0)
2142 return 0;
2143
2144 unified = cg_unified();
2145 if (unified < 0)
2146 return unified;
2147 if (!unified) /* on the legacy hiearchy there's no joining of controllers defined */
2148 return 0;
2149
2150 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, p, "cgroup.subtree_control", &fs);
2151 if (r < 0)
2152 return r;
2153
2154 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
2155 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
2156 const char *n;
2157
2158 if (!(supported & bit))
2159 continue;
2160
2161 n = cgroup_controller_to_string(c);
2162 {
2163 char s[1 + strlen(n) + 1];
2164
2165 s[0] = mask & bit ? '+' : '-';
2166 strcpy(s + 1, n);
2167
2168 r = write_string_file(fs, s, 0);
2169 if (r < 0)
98e4d8d7 2170 log_debug_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs);
efdb0237
LP
2171 }
2172 }
2173
2174 return 0;
2175}
2176
2177bool cg_is_unified_wanted(void) {
2178 static thread_local int wanted = -1;
2179 int r, unified;
2180
2181 /* If the hierarchy is already mounted, then follow whatever
2182 * was chosen for it. */
2183 unified = cg_unified();
2184 if (unified >= 0)
2185 return unified;
2186
2187 /* Otherwise, let's see what the kernel command line has to
2188 * say. Since checking that is expensive, let's cache the
2189 * result. */
2190 if (wanted >= 0)
2191 return wanted;
2192
2193 r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy", NULL);
2194 if (r > 0)
2195 return (wanted = true);
2196 else {
2197 _cleanup_free_ char *value = NULL;
2198
2199 r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy=", &value);
2200 if (r < 0)
2201 return false;
2202 if (r == 0)
2203 return (wanted = false);
2204
2205 return (wanted = parse_boolean(value) > 0);
2206 }
2207}
2208
2209bool cg_is_legacy_wanted(void) {
2210 return !cg_is_unified_wanted();
2211}
2212
d53d9474
LP
2213int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
2214 uint64_t u;
2215 int r;
2216
2217 if (isempty(s)) {
2218 *ret = CGROUP_CPU_SHARES_INVALID;
2219 return 0;
2220 }
2221
2222 r = safe_atou64(s, &u);
2223 if (r < 0)
2224 return r;
2225
2226 if (u < CGROUP_CPU_SHARES_MIN || u > CGROUP_CPU_SHARES_MAX)
2227 return -ERANGE;
2228
2229 *ret = u;
2230 return 0;
2231}
2232
2233int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
2234 uint64_t u;
2235 int r;
2236
2237 if (isempty(s)) {
2238 *ret = CGROUP_BLKIO_WEIGHT_INVALID;
2239 return 0;
2240 }
2241
2242 r = safe_atou64(s, &u);
2243 if (r < 0)
2244 return r;
2245
2246 if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX)
2247 return -ERANGE;
2248
2249 *ret = u;
2250 return 0;
2251}
2252
efdb0237
LP
2253static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
2254 [CGROUP_CONTROLLER_CPU] = "cpu",
2255 [CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
2256 [CGROUP_CONTROLLER_BLKIO] = "blkio",
2257 [CGROUP_CONTROLLER_MEMORY] = "memory",
3905f127 2258 [CGROUP_CONTROLLER_DEVICES] = "devices",
03a7b521 2259 [CGROUP_CONTROLLER_PIDS] = "pids",
32ee7d33 2260 [CGROUP_CONTROLLER_NET_CLS] = "net_cls",
efdb0237
LP
2261};
2262
2263DEFINE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController);