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