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