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