]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/cgroup-util.c
nspawn: introduce the new /machine/ tree in the cgroup tree and move containers there
[thirdparty/systemd.git] / src / shared / 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
22#include <errno.h>
23#include <unistd.h>
24#include <signal.h>
25#include <string.h>
26#include <stdlib.h>
35d2e7ec 27#include <dirent.h>
672c48cc
LP
28#include <sys/stat.h>
29#include <sys/types.h>
e27796a0 30#include <ftw.h>
8c6db833
LP
31
32#include "cgroup-util.h"
33#include "log.h"
34#include "set.h"
35#include "macro.h"
36#include "util.h"
9eb977db 37#include "path-util.h"
b59e2465 38#include "strv.h"
ef1673d1 39#include "unit-name.h"
a5c32cff 40#include "fileio.h"
8c6db833 41
c6c18be3 42int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
7027ff61 43 _cleanup_free_ char *fs = NULL;
c6c18be3 44 FILE *f;
7027ff61 45 int r;
c6c18be3 46
c6c18be3
LP
47 assert(_f);
48
c3175a7f
LP
49 r = cg_get_path(controller, path, "cgroup.procs", &fs);
50 if (r < 0)
c6c18be3
LP
51 return r;
52
53 f = fopen(fs, "re");
c6c18be3
LP
54 if (!f)
55 return -errno;
56
57 *_f = f;
58 return 0;
59}
60
61int cg_enumerate_tasks(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, "tasks", &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
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
95 return errno ? -errno : -EIO;
96 }
97
98 if (ul <= 0)
99 return -EIO;
100
101 *_pid = (pid_t) ul;
102 return 1;
103}
104
35d2e7ec 105int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
7027ff61 106 _cleanup_free_ char *fs = NULL;
35d2e7ec
LP
107 int r;
108 DIR *d;
109
35d2e7ec
LP
110 assert(_d);
111
112 /* This is not recursive! */
113
c3175a7f
LP
114 r = cg_get_path(controller, path, NULL, &fs);
115 if (r < 0)
35d2e7ec
LP
116 return r;
117
118 d = opendir(fs);
35d2e7ec
LP
119 if (!d)
120 return -errno;
121
122 *_d = d;
123 return 0;
124}
125
126int cg_read_subgroup(DIR *d, char **fn) {
127 struct dirent *de;
128
129 assert(d);
7027ff61 130 assert(fn);
35d2e7ec 131
7027ff61 132 FOREACH_DIRENT(de, d, return -errno) {
35d2e7ec
LP
133 char *b;
134
135 if (de->d_type != DT_DIR)
136 continue;
137
138 if (streq(de->d_name, ".") ||
139 streq(de->d_name, ".."))
140 continue;
141
7027ff61
LP
142 b = strdup(de->d_name);
143 if (!b)
35d2e7ec
LP
144 return -ENOMEM;
145
146 *fn = b;
147 return 1;
148 }
149
35d2e7ec
LP
150 return 0;
151}
152
ad293f5a 153int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
7027ff61 154 _cleanup_free_ char *p = NULL;
35d2e7ec
LP
155 int r;
156
ad293f5a
LP
157 r = cg_get_path(controller, path, NULL, &p);
158 if (r < 0)
35d2e7ec
LP
159 return r;
160
ad293f5a
LP
161 if (honour_sticky) {
162 char *tasks;
163
164 /* If the sticky bit is set don't remove the directory */
165
166 tasks = strappend(p, "/tasks");
7027ff61 167 if (!tasks)
ad293f5a 168 return -ENOMEM;
ad293f5a 169
8d53b453 170 r = file_is_priv_sticky(tasks);
ad293f5a
LP
171 free(tasks);
172
7027ff61 173 if (r > 0)
ad293f5a 174 return 0;
ad293f5a
LP
175 }
176
35d2e7ec 177 r = rmdir(p);
7027ff61
LP
178 if (r < 0 && errno != ENOENT)
179 return -errno;
35d2e7ec 180
7027ff61 181 return 0;
35d2e7ec
LP
182}
183
430c18ed 184int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
7027ff61 185 _cleanup_set_free_ Set *allocated_set = NULL;
35d2e7ec 186 bool done = false;
8c6db833 187 int r, ret = 0;
35d2e7ec 188 pid_t my_pid;
8c6db833 189
8c6db833
LP
190 assert(sig >= 0);
191
192 /* This goes through the tasks list and kills them all. This
193 * is repeated until no further processes are added to the
194 * tasks list, to properly handle forking processes */
195
7027ff61
LP
196 if (!s) {
197 s = allocated_set = set_new(trivial_hash_func, trivial_compare_func);
198 if (!s)
ca949c9d 199 return -ENOMEM;
7027ff61 200 }
8c6db833
LP
201
202 my_pid = getpid();
203
204 do {
7027ff61 205 _cleanup_fclose_ FILE *f = NULL;
0b172489 206 pid_t pid = 0;
8c6db833
LP
207 done = true;
208
7027ff61
LP
209 r = cg_enumerate_processes(controller, path, &f);
210 if (r < 0) {
4c633005 211 if (ret >= 0 && r != -ENOENT)
7027ff61 212 return r;
35d2e7ec 213
7027ff61 214 return ret;
35d2e7ec 215 }
c6c18be3
LP
216
217 while ((r = cg_read_pid(f, &pid)) > 0) {
8c6db833 218
7027ff61 219 if (ignore_self && pid == my_pid)
c6c18be3 220 continue;
8c6db833 221
c6c18be3
LP
222 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
223 continue;
8c6db833
LP
224
225 /* If we haven't killed this process yet, kill
226 * it */
4c633005
LP
227 if (kill(pid, sig) < 0) {
228 if (ret >= 0 && errno != ESRCH)
8c6db833 229 ret = -errno;
430c18ed
LP
230 } else if (ret == 0) {
231
232 if (sigcont)
233 kill(pid, SIGCONT);
234
35d2e7ec 235 ret = 1;
430c18ed 236 }
8c6db833 237
8c6db833
LP
238 done = false;
239
7027ff61
LP
240 r = set_put(s, LONG_TO_PTR(pid));
241 if (r < 0) {
35d2e7ec 242 if (ret >= 0)
7027ff61 243 return r;
35d2e7ec 244
7027ff61 245 return ret;
35d2e7ec
LP
246 }
247 }
248
249 if (r < 0) {
250 if (ret >= 0)
7027ff61 251 return r;
35d2e7ec 252
7027ff61 253 return ret;
8c6db833
LP
254 }
255
8c6db833
LP
256 /* To avoid racing against processes which fork
257 * quicker than we can kill them we repeat this until
258 * no new pids need to be killed. */
259
35d2e7ec 260 } while (!done);
8c6db833 261
35d2e7ec 262 return ret;
8c6db833
LP
263}
264
430c18ed 265int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
7027ff61
LP
266 _cleanup_set_free_ Set *allocated_set = NULL;
267 _cleanup_closedir_ DIR *d = NULL;
35d2e7ec 268 int r, ret = 0;
35d2e7ec 269 char *fn;
8c6db833
LP
270
271 assert(path);
8c6db833
LP
272 assert(sig >= 0);
273
7027ff61
LP
274 if (!s) {
275 s = allocated_set = set_new(trivial_hash_func, trivial_compare_func);
276 if (!s)
ca949c9d 277 return -ENOMEM;
7027ff61 278 }
ca949c9d 279
430c18ed 280 ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
8c6db833 281
7027ff61
LP
282 r = cg_enumerate_subgroups(controller, path, &d);
283 if (r < 0) {
4c633005 284 if (ret >= 0 && r != -ENOENT)
7027ff61 285 return r;
8c6db833 286
7027ff61 287 return ret;
35d2e7ec 288 }
8c6db833 289
35d2e7ec 290 while ((r = cg_read_subgroup(d, &fn)) > 0) {
7027ff61 291 _cleanup_free_ char *p = NULL;
8c6db833 292
7027ff61 293 p = strjoin(path, "/", fn, NULL);
35d2e7ec 294 free(fn);
7027ff61
LP
295 if (!p)
296 return -ENOMEM;
8c6db833 297
430c18ed 298 r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
7027ff61 299 if (ret >= 0 && r != 0)
35d2e7ec 300 ret = r;
8c6db833
LP
301 }
302
7027ff61 303 if (ret >= 0 && r < 0)
35d2e7ec
LP
304 ret = r;
305
7027ff61
LP
306 if (rem) {
307 r = cg_rmdir(controller, path, true);
308 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
309 return r;
310 }
ca949c9d 311
8c6db833
LP
312 return ret;
313}
314
35d2e7ec 315int cg_kill_recursive_and_wait(const char *controller, const char *path, bool rem) {
8c6db833
LP
316 unsigned i;
317
318 assert(path);
8c6db833
LP
319
320 /* This safely kills all processes; first it sends a SIGTERM,
9f452741
LP
321 * then checks 8 times after 200ms whether the group is now
322 * empty, then kills everything that is left with SIGKILL and
323 * finally checks 5 times after 200ms each whether the group
324 * is finally empty. */
8c6db833 325
9f452741 326 for (i = 0; i < 15; i++) {
1d0ae74a 327 int sig, r;
8c6db833
LP
328
329 if (i <= 0)
330 sig = SIGTERM;
9f452741 331 else if (i == 9)
8c6db833
LP
332 sig = SIGKILL;
333 else
334 sig = 0;
335
7027ff61
LP
336 r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL);
337 if (r <= 0)
8c6db833
LP
338 return r;
339
9f452741 340 usleep(200 * USEC_PER_MSEC);
8c6db833
LP
341 }
342
343 return 0;
344}
345
246aa6dd 346int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) {
35d2e7ec 347 bool done = false;
246aa6dd 348 _cleanup_set_free_ Set *s = NULL;
8c6db833
LP
349 int r, ret = 0;
350 pid_t my_pid;
351
246aa6dd
LP
352 assert(cfrom);
353 assert(pfrom);
354 assert(cto);
355 assert(pto);
8c6db833 356
246aa6dd
LP
357 s = set_new(trivial_hash_func, trivial_compare_func);
358 if (!s)
35d2e7ec
LP
359 return -ENOMEM;
360
8c6db833
LP
361 my_pid = getpid();
362
363 do {
7027ff61 364 _cleanup_fclose_ FILE *f = NULL;
0b172489 365 pid_t pid = 0;
8c6db833
LP
366 done = true;
367
246aa6dd
LP
368 r = cg_enumerate_tasks(cfrom, pfrom, &f);
369 if (r < 0) {
4c633005 370 if (ret >= 0 && r != -ENOENT)
7027ff61 371 return r;
35d2e7ec 372
246aa6dd 373 return ret;
35d2e7ec 374 }
c6c18be3
LP
375
376 while ((r = cg_read_pid(f, &pid)) > 0) {
8c6db833 377
35d2e7ec
LP
378 /* This might do weird stuff if we aren't a
379 * single-threaded program. However, we
380 * luckily know we are not */
7027ff61 381 if (ignore_self && pid == my_pid)
c6c18be3 382 continue;
8c6db833 383
35d2e7ec
LP
384 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
385 continue;
386
246aa6dd
LP
387 r = cg_attach(cto, pto, pid);
388 if (r < 0) {
4c633005 389 if (ret >= 0 && r != -ESRCH)
35d2e7ec
LP
390 ret = r;
391 } else if (ret == 0)
392 ret = 1;
8c6db833 393
8c6db833 394 done = false;
35d2e7ec 395
246aa6dd
LP
396 r = set_put(s, LONG_TO_PTR(pid));
397 if (r < 0) {
35d2e7ec 398 if (ret >= 0)
7027ff61 399 return r;
35d2e7ec 400
246aa6dd 401 return ret;
35d2e7ec
LP
402 }
403 }
404
405 if (r < 0) {
406 if (ret >= 0)
7027ff61 407 return r;
35d2e7ec 408
246aa6dd 409 return ret;
8c6db833 410 }
35d2e7ec 411 } while (!done);
8c6db833 412
35d2e7ec 413 return ret;
8c6db833
LP
414}
415
246aa6dd 416int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool rem) {
246aa6dd 417 _cleanup_closedir_ DIR *d = NULL;
7027ff61 418 int r, ret = 0;
35d2e7ec 419 char *fn;
8c6db833 420
246aa6dd
LP
421 assert(cfrom);
422 assert(pfrom);
423 assert(cto);
424 assert(pto);
8c6db833 425
246aa6dd 426 ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self);
8c6db833 427
246aa6dd
LP
428 r = cg_enumerate_subgroups(cfrom, pfrom, &d);
429 if (r < 0) {
4c633005 430 if (ret >= 0 && r != -ENOENT)
7027ff61
LP
431 return r;
432
246aa6dd 433 return ret;
35d2e7ec
LP
434 }
435
436 while ((r = cg_read_subgroup(d, &fn)) > 0) {
246aa6dd 437 _cleanup_free_ char *p = NULL;
8c6db833 438
246aa6dd 439 p = strjoin(pfrom, "/", fn, NULL);
35d2e7ec 440 free(fn);
246aa6dd 441 if (!p) {
35d2e7ec 442 if (ret >= 0)
7027ff61 443 return -ENOMEM;
35d2e7ec 444
246aa6dd 445 return ret;
8c6db833
LP
446 }
447
246aa6dd 448 r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem);
35d2e7ec
LP
449 if (r != 0 && ret >= 0)
450 ret = r;
8c6db833
LP
451 }
452
35d2e7ec
LP
453 if (r < 0 && ret >= 0)
454 ret = r;
455
246aa6dd
LP
456 if (rem) {
457 r = cg_rmdir(cfrom, pfrom, true);
458 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
459 return r;
460 }
8c6db833
LP
461
462 return ret;
463}
464
3474ae3c
LP
465static const char *normalize_controller(const char *controller) {
466
7027ff61
LP
467 assert(controller);
468
3474ae3c
LP
469 if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
470 return "systemd";
471 else if (startswith(controller, "name="))
472 return controller + 5;
473 else
474 return controller;
475}
476
477static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
018ef268 478 char *t = NULL;
3474ae3c 479
c3175a7f
LP
480 if (controller) {
481 if (path && suffix)
b7def684 482 t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
c3175a7f 483 else if (path)
b7def684 484 t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL);
c3175a7f 485 else if (suffix)
b7def684 486 t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL);
c3175a7f 487 else
7027ff61 488 t = strappend("/sys/fs/cgroup/", controller);
c3175a7f
LP
489 } else {
490 if (path && suffix)
b7def684 491 t = strjoin(path, "/", suffix, NULL);
c3175a7f
LP
492 else if (path)
493 t = strdup(path);
7027ff61
LP
494 else
495 return -EINVAL;
c3175a7f 496 }
3474ae3c
LP
497
498 if (!t)
499 return -ENOMEM;
500
501 path_kill_slashes(t);
502
503 *fs = t;
504 return 0;
505}
506
8c6db833 507int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
dbd821ac 508 const char *p;
0ac10822 509 static __thread bool good = false;
8c6db833 510
dbd821ac
LP
511 assert(fs);
512
3bfc7184 513 if (_unlikely_(!good)) {
70132bd0
LP
514 int r;
515
0c85a4f3 516 r = path_is_mount_point("/sys/fs/cgroup", false);
70132bd0
LP
517 if (r <= 0)
518 return r < 0 ? r : -ENOENT;
519
520 /* Cache this to save a few stat()s */
521 good = true;
522 }
523
c3175a7f 524 p = controller ? normalize_controller(controller) : NULL;
7027ff61 525
3474ae3c
LP
526 return join_path(p, path, suffix, fs);
527}
dbd821ac 528
7027ff61 529static int check_hierarchy(const char *p) {
37099707
LP
530 char *cc;
531
532 assert(p);
533
534 /* Check if this controller actually really exists */
535 cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(p));
536 strcpy(stpcpy(cc, "/sys/fs/cgroup/"), p);
537 if (access(cc, F_OK) < 0)
538 return -errno;
539
540 return 0;
541}
542
3474ae3c
LP
543int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
544 const char *p;
37099707 545 int r;
dbd821ac 546
3474ae3c 547 assert(fs);
70132bd0 548
3474ae3c
LP
549 if (isempty(controller))
550 return -EINVAL;
70132bd0 551
37099707 552 /* Normalize the controller syntax */
3474ae3c 553 p = normalize_controller(controller);
8c6db833 554
3474ae3c 555 /* Check if this controller actually really exists */
7027ff61 556 r = check_hierarchy(p);
37099707
LP
557 if (r < 0)
558 return r;
3474ae3c
LP
559
560 return join_path(p, path, suffix, fs);
8c6db833
LP
561}
562
e27796a0
LP
563static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
564 char *p;
565 bool is_sticky;
566
567 if (typeflag != FTW_DP)
568 return 0;
569
570 if (ftwbuf->level < 1)
571 return 0;
572
573 p = strappend(path, "/tasks");
574 if (!p) {
575 errno = ENOMEM;
576 return 1;
577 }
578
8d53b453 579 is_sticky = file_is_priv_sticky(p) > 0;
e27796a0
LP
580 free(p);
581
582 if (is_sticky)
583 return 0;
584
585 rmdir(path);
586 return 0;
587}
588
8c6db833 589int cg_trim(const char *controller, const char *path, bool delete_root) {
7027ff61 590 _cleanup_free_ char *fs = NULL;
e27796a0 591 int r = 0;
8c6db833 592
8c6db833
LP
593 assert(path);
594
e27796a0
LP
595 r = cg_get_path(controller, path, NULL, &fs);
596 if (r < 0)
8c6db833
LP
597 return r;
598
e27796a0 599 errno = 0;
7027ff61 600 if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0)
e27796a0
LP
601 r = errno ? -errno : -EIO;
602
603 if (delete_root) {
604 bool is_sticky;
605 char *p;
606
607 p = strappend(fs, "/tasks");
7027ff61 608 if (!p)
e27796a0 609 return -ENOMEM;
e27796a0 610
8d53b453 611 is_sticky = file_is_priv_sticky(p) > 0;
e27796a0
LP
612 free(p);
613
614 if (!is_sticky)
7027ff61
LP
615 if (rmdir(fs) < 0 && errno != ENOENT && r == 0)
616 return -errno;
e27796a0
LP
617 }
618
e27796a0 619 return r;
8c6db833
LP
620}
621
622int cg_delete(const char *controller, const char *path) {
7027ff61 623 _cleanup_free_ char *parent = NULL;
8c6db833
LP
624 int r;
625
8c6db833
LP
626 assert(path);
627
7027ff61
LP
628 r = path_get_parent(path, &parent);
629 if (r < 0)
35d2e7ec 630 return r;
8c6db833 631
246aa6dd 632 r = cg_migrate_recursive(controller, path, controller, parent, false, true);
4c633005 633 return r == -ENOENT ? 0 : r;
8c6db833
LP
634}
635
8c6db833 636int cg_attach(const char *controller, const char *path, pid_t pid) {
574d5f2d
LP
637 _cleanup_free_ char *fs = NULL;
638 char c[DECIMAL_STR_MAX(pid_t) + 2];
8c6db833
LP
639 int r;
640
8c6db833
LP
641 assert(path);
642 assert(pid >= 0);
643
3474ae3c
LP
644 r = cg_get_path_and_check(controller, path, "tasks", &fs);
645 if (r < 0)
c6c18be3 646 return r;
8c6db833
LP
647
648 if (pid == 0)
649 pid = getpid();
650
c6c18be3 651 snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid);
8c6db833 652
574d5f2d 653 return write_string_file(fs, c);
8c6db833
LP
654}
655
2d76d14e
LP
656int cg_set_group_access(
657 const char *controller,
658 const char *path,
659 mode_t mode,
660 uid_t uid,
661 gid_t gid) {
662
574d5f2d 663 _cleanup_free_ char *fs = NULL;
8c6db833
LP
664 int r;
665
8c6db833
LP
666 assert(path);
667
8d53b453
LP
668 if (mode != (mode_t) -1)
669 mode &= 0777;
670
671 r = cg_get_path(controller, path, NULL, &fs);
672 if (r < 0)
8c6db833
LP
673 return r;
674
574d5f2d 675 return chmod_and_chown(fs, mode, uid, gid);
8c6db833
LP
676}
677
974efc46
LP
678int cg_set_task_access(
679 const char *controller,
680 const char *path,
681 mode_t mode,
682 uid_t uid,
683 gid_t gid,
684 int sticky) {
685
686 _cleanup_free_ char *fs = NULL, *procs = NULL;
8c6db833
LP
687 int r;
688
8c6db833
LP
689 assert(path);
690
8d53b453
LP
691 if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1 && sticky < 0)
692 return 0;
693
694 if (mode != (mode_t) -1)
695 mode &= 0666;
696
697 r = cg_get_path(controller, path, "tasks", &fs);
698 if (r < 0)
8c6db833
LP
699 return r;
700
8d53b453
LP
701 if (sticky >= 0 && mode != (mode_t) -1)
702 /* Both mode and sticky param are passed */
703 mode |= (sticky ? S_ISVTX : 0);
704 else if ((sticky >= 0 && mode == (mode_t) -1) ||
705 (mode != (mode_t) -1 && sticky < 0)) {
706 struct stat st;
707
708 /* Only one param is passed, hence read the current
709 * mode from the file itself */
710
711 r = lstat(fs, &st);
974efc46 712 if (r < 0)
8d53b453 713 return -errno;
8d53b453
LP
714
715 if (mode == (mode_t) -1)
716 /* No mode set, we just shall set the sticky bit */
717 mode = (st.st_mode & ~S_ISVTX) | (sticky ? S_ISVTX : 0);
718 else
719 /* Only mode set, leave sticky bit untouched */
720 mode = (st.st_mode & ~0777) | mode;
721 }
722
8c6db833 723 r = chmod_and_chown(fs, mode, uid, gid);
974efc46
LP
724 if (r < 0)
725 return r;
8c6db833 726
974efc46
LP
727 /* Always keep values for "cgroup.procs" in sync with "tasks" */
728 r = cg_get_path(controller, path, "cgroup.procs", &procs);
729 if (r < 0)
730 return r;
731
732 return chmod_and_chown(procs, mode, uid, gid);
8c6db833
LP
733}
734
7027ff61
LP
735int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
736 char fs[sizeof("/proc/") - 1 + DECIMAL_STR_MAX(pid_t) + sizeof("/cgroup")];
737 _cleanup_fclose_ FILE *f = NULL;
738 char line[LINE_MAX];
c6c18be3 739 size_t cs;
8c6db833 740
8c6db833 741 assert(path);
c6c18be3 742 assert(pid >= 0);
8c6db833 743
7027ff61
LP
744 if (!controller)
745 controller = SYSTEMD_CGROUP_CONTROLLER;
746
c6c18be3
LP
747 if (pid == 0)
748 pid = getpid();
8c6db833 749
7027ff61 750 sprintf(fs, "/proc/%lu/cgroup", (unsigned long) pid);
c6c18be3 751 f = fopen(fs, "re");
4c633005
LP
752 if (!f)
753 return errno == ENOENT ? -ESRCH : -errno;
754
c6c18be3
LP
755 cs = strlen(controller);
756
7027ff61
LP
757 FOREACH_LINE(line, f, return -errno) {
758 char *l, *p;
c6c18be3
LP
759
760 truncate_nl(line);
761
7027ff61
LP
762 l = strchr(line, ':');
763 if (!l)
c6c18be3
LP
764 continue;
765
766 l++;
641906e9 767 if (!strneq(l, controller, cs))
c6c18be3
LP
768 continue;
769
770 if (l[cs] != ':')
771 continue;
772
7027ff61
LP
773 p = strdup(l + cs + 1);
774 if (!p)
775 return -ENOMEM;
c6c18be3
LP
776
777 *path = p;
7027ff61 778 return 0;
c6c18be3
LP
779 }
780
7027ff61 781 return -ENOENT;
8c6db833
LP
782}
783
784int cg_install_release_agent(const char *controller, const char *agent) {
7027ff61
LP
785 _cleanup_free_ char *fs = NULL, *contents = NULL;
786 char *sc;
8c6db833
LP
787 int r;
788
8c6db833
LP
789 assert(agent);
790
7027ff61
LP
791 r = cg_get_path(controller, NULL, "release_agent", &fs);
792 if (r < 0)
c6c18be3 793 return r;
8c6db833 794
7027ff61
LP
795 r = read_one_line_file(fs, &contents);
796 if (r < 0)
797 return r;
8c6db833
LP
798
799 sc = strstrip(contents);
8c6db833 800 if (sc[0] == 0) {
7027ff61 801 r = write_string_file(fs, agent);
574d5f2d 802 if (r < 0)
7027ff61
LP
803 return r;
804 } else if (!streq(sc, agent))
805 return -EEXIST;
8c6db833 806
c6c18be3
LP
807 free(fs);
808 fs = NULL;
7027ff61
LP
809 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
810 if (r < 0)
811 return r;
8c6db833
LP
812
813 free(contents);
814 contents = NULL;
7027ff61
LP
815 r = read_one_line_file(fs, &contents);
816 if (r < 0)
817 return r;
8c6db833
LP
818
819 sc = strstrip(contents);
8c6db833 820 if (streq(sc, "0")) {
7027ff61
LP
821 r = write_string_file(fs, "1");
822 if (r < 0)
823 return r;
c6c18be3 824
7027ff61
LP
825 return 1;
826 }
8c6db833 827
7027ff61
LP
828 if (!streq(sc, "1"))
829 return -EIO;
8c6db833 830
7027ff61 831 return 0;
8c6db833
LP
832}
833
834int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
7027ff61 835 _cleanup_fclose_ FILE *f = NULL;
c3175a7f 836 pid_t pid = 0, self_pid;
c6c18be3 837 bool found = false;
7027ff61 838 int r;
8c6db833 839
8c6db833
LP
840 assert(path);
841
c3175a7f
LP
842 r = cg_enumerate_tasks(controller, path, &f);
843 if (r < 0)
4c633005 844 return r == -ENOENT ? 1 : r;
8c6db833 845
c3175a7f
LP
846 self_pid = getpid();
847
c6c18be3 848 while ((r = cg_read_pid(f, &pid)) > 0) {
8c6db833 849
c3175a7f 850 if (ignore_self && pid == self_pid)
c6c18be3 851 continue;
8c6db833 852
c6c18be3
LP
853 found = true;
854 break;
8c6db833
LP
855 }
856
c6c18be3
LP
857 if (r < 0)
858 return r;
8c6db833 859
c6c18be3 860 return !found;
8c6db833
LP
861}
862
b08121d0 863int cg_is_empty_by_spec(const char *spec, bool ignore_self) {
b08121d0 864 _cleanup_free_ char *controller = NULL, *path = NULL;
7027ff61 865 int r;
b08121d0
LP
866
867 assert(spec);
868
869 r = cg_split_spec(spec, &controller, &path);
870 if (r < 0)
871 return r;
872
873 return cg_is_empty(controller, path, ignore_self);
874}
875
8c6db833 876int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
7027ff61 877 _cleanup_closedir_ DIR *d = NULL;
35d2e7ec 878 char *fn;
7027ff61 879 int r;
8c6db833 880
8c6db833
LP
881 assert(path);
882
c3175a7f
LP
883 r = cg_is_empty(controller, path, ignore_self);
884 if (r <= 0)
35d2e7ec
LP
885 return r;
886
c3175a7f
LP
887 r = cg_enumerate_subgroups(controller, path, &d);
888 if (r < 0)
4c633005 889 return r == -ENOENT ? 1 : r;
8c6db833 890
35d2e7ec 891 while ((r = cg_read_subgroup(d, &fn)) > 0) {
7027ff61 892 _cleanup_free_ char *p = NULL;
8c6db833 893
7027ff61 894 p = strjoin(path, "/", fn, NULL);
35d2e7ec 895 free(fn);
7027ff61
LP
896 if (!p)
897 return -ENOMEM;
8c6db833 898
35d2e7ec 899 r = cg_is_empty_recursive(controller, p, ignore_self);
35d2e7ec 900 if (r <= 0)
7027ff61 901 return r;
35d2e7ec
LP
902 }
903
7027ff61
LP
904 if (r < 0)
905 return r;
35d2e7ec 906
7027ff61 907 return 1;
35d2e7ec
LP
908}
909
910int cg_split_spec(const char *spec, char **controller, char **path) {
911 const char *e;
912 char *t = NULL, *u = NULL;
913
914 assert(spec);
35d2e7ec
LP
915
916 if (*spec == '/') {
e884315e
LP
917 if (!path_is_safe(spec))
918 return -EINVAL;
35d2e7ec
LP
919
920 if (path) {
246aa6dd
LP
921 t = strdup(spec);
922 if (!t)
35d2e7ec
LP
923 return -ENOMEM;
924
925 *path = t;
8c6db833
LP
926 }
927
35d2e7ec
LP
928 if (controller)
929 *controller = NULL;
930
931 return 0;
8c6db833
LP
932 }
933
246aa6dd
LP
934 e = strchr(spec, ':');
935 if (!e) {
e884315e 936 if (!filename_is_safe(spec))
35d2e7ec
LP
937 return -EINVAL;
938
939 if (controller) {
246aa6dd
LP
940 t = strdup(spec);
941 if (!t)
35d2e7ec
LP
942 return -ENOMEM;
943
944 *controller = t;
945 }
946
947 if (path)
948 *path = NULL;
949
950 return 0;
8c6db833
LP
951 }
952
e884315e
LP
953 t = strndup(spec, e-spec);
954 if (!t)
955 return -ENOMEM;
956 if (!filename_is_safe(t)) {
957 free(t);
35d2e7ec 958 return -EINVAL;
246aa6dd
LP
959 }
960
e884315e
LP
961 u = strdup(e+1);
962 if (!u) {
963 free(t);
964 return -ENOMEM;
965 }
966 if (!path_is_safe(u)) {
967 free(t);
968 free(u);
969 return -EINVAL;
246aa6dd 970 }
35d2e7ec
LP
971
972 if (controller)
973 *controller = t;
e884315e
LP
974 else
975 free(t);
35d2e7ec
LP
976
977 if (path)
978 *path = u;
e884315e
LP
979 else
980 free(u);
35d2e7ec
LP
981
982 return 0;
8c6db833 983}
c6c18be3 984
35d2e7ec 985int cg_join_spec(const char *controller, const char *path, char **spec) {
7027ff61
LP
986 char *s;
987
35d2e7ec 988 assert(path);
c6c18be3 989
7027ff61
LP
990 if (!controller)
991 controller = "systemd";
992 else if (controller[0] == 0 ||
993 strchr(controller, ':') ||
994 strchr(controller, '/'))
35d2e7ec
LP
995 return -EINVAL;
996
7027ff61
LP
997 if (!path_is_absolute(path))
998 return -EINVAL;
999
1000 controller = normalize_controller(controller);
1001
1002 s = strjoin(controller, ":", path, NULL);
1003 if (!s)
35d2e7ec 1004 return -ENOMEM;
c6c18be3 1005
7027ff61 1006 *spec = s;
c6c18be3
LP
1007 return 0;
1008}
35d2e7ec 1009
7027ff61 1010int cg_mangle_path(const char *path, char **result) {
35d2e7ec
LP
1011 char *t, *c, *p;
1012 int r;
1013
1014 assert(path);
1015 assert(result);
1016
1017 /* First check if it already is a filesystem path */
7027ff61 1018 if (path_startswith(path, "/sys/fs/cgroup")) {
35d2e7ec 1019
b69d29ce
LP
1020 t = strdup(path);
1021 if (!t)
35d2e7ec
LP
1022 return -ENOMEM;
1023
1024 *result = t;
1025 return 0;
1026 }
1027
1028 /* Otherwise treat it as cg spec */
b69d29ce
LP
1029 r = cg_split_spec(path, &c, &p);
1030 if (r < 0)
35d2e7ec
LP
1031 return r;
1032
1033 r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1034 free(c);
1035 free(p);
1036
1037 return r;
1038}
1f73f0f1 1039
7027ff61
LP
1040int cg_get_system_path(char **path) {
1041 char *p;
1042 int r;
1043
1044 assert(path);
1045
1046 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
1047 if (r < 0) {
1048 p = strdup("/system");
1049 if (!p)
1050 return -ENOMEM;
1051 }
1052
1053 if (endswith(p, "/system"))
1054 *path = p;
1055 else {
1056 char *q;
1057
1058 q = strappend(p, "/system");
1059 free(p);
1060 if (!q)
1061 return -ENOMEM;
1062
1063 *path = q;
1064 }
1065
1066 return 0;
1067}
1068
1069int cg_get_root_path(char **path) {
1070 char *root, *e;
1071 int r;
1072
1073 assert(path);
1074
1075 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &root);
1076 if (r < 0)
1077 return r;
1078
1079 e = endswith(root, "/system");
1080 if (e == root)
1081 e[1] = 0;
1082 else if (e)
1083 *e = 0;
1084
1085 *path = root;
1086 return 0;
1087}
1088
1f73f0f1 1089int cg_get_user_path(char **path) {
7027ff61
LP
1090 _cleanup_free_ char *root = NULL;
1091 char *p;
1f73f0f1
LP
1092
1093 assert(path);
1094
1095 /* Figure out the place to put user cgroups below. We use the
1096 * same as PID 1 has but with the "/system" suffix replaced by
1097 * "/user" */
1098
7027ff61 1099 if (cg_get_root_path(&root) < 0 || streq(root, "/"))
1f73f0f1 1100 p = strdup("/user");
7027ff61 1101 else
1f73f0f1 1102 p = strappend(root, "/user");
7027ff61
LP
1103
1104 if (!p)
1105 return -ENOMEM;
1106
1107 *path = p;
1108 return 0;
1109}
1110
1111int cg_get_machine_path(char **path) {
1112 _cleanup_free_ char *root = NULL;
1113 char *p;
1114
1115 assert(path);
1116
1117 if (cg_get_root_path(&root) < 0 || streq(root, "/"))
1118 p = strdup("/machine");
1119 else
1120 p = strappend(root, "/machine");
1f73f0f1
LP
1121
1122 if (!p)
1123 return -ENOMEM;
1124
1125 *path = p;
1126 return 0;
1127}
b59e2465
LP
1128
1129char **cg_shorten_controllers(char **controllers) {
1130 char **f, **t;
1131
b59e2465
LP
1132 if (!controllers)
1133 return controllers;
1134
1135 for (f = controllers, t = controllers; *f; f++) {
37099707 1136 const char *p;
7027ff61
LP
1137 int r;
1138
1139 p = normalize_controller(*f);
b59e2465 1140
7027ff61 1141 if (streq(*f, "systemd")) {
b59e2465
LP
1142 free(*f);
1143 continue;
1144 }
1145
7027ff61 1146 r = check_hierarchy(p);
37099707 1147 if (r < 0) {
b59e2465
LP
1148 log_debug("Controller %s is not available, removing from controllers list.", *f);
1149 free(*f);
1150 continue;
1151 }
1152
1153 *(t++) = *f;
1154 }
1155
1156 *t = NULL;
6c03089c 1157 return strv_uniq(controllers);
b59e2465 1158}
ba1261bc 1159
7027ff61
LP
1160int cg_pid_get_path_shifted(pid_t pid, char **root, char **cgroup) {
1161 _cleanup_free_ char *cg_root = NULL;
1162 char *cg_process, *p;
ba1261bc
LP
1163 int r;
1164
7027ff61 1165 r = cg_get_root_path(&cg_root);
ba1261bc
LP
1166 if (r < 0)
1167 return r;
1168
7027ff61
LP
1169 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process);
1170 if (r < 0)
ba1261bc 1171 return r;
ba1261bc 1172
7027ff61
LP
1173 p = path_startswith(cg_process, cg_root);
1174 if (p)
1175 p--;
1176 else
1177 p = cg_process;
ba1261bc
LP
1178
1179 if (cgroup) {
1180 char* c;
1181
1182 c = strdup(p);
1183 if (!c) {
1184 free(cg_process);
1185 return -ENOMEM;
1186 }
1187
1188 *cgroup = c;
1189 }
1190
1191 if (root) {
1192 cg_process[p-cg_process] = 0;
1193 *root = cg_process;
1194 } else
1195 free(cg_process);
1196
1197 return 0;
1198}
1199
6c03089c 1200/* non-static only for testing purposes */
7027ff61 1201int cg_path_decode_unit(const char *cgroup, char **unit){
6c03089c 1202 char *p, *e, *c, *s, *k;
ef1673d1
MT
1203
1204 assert(cgroup);
6c03089c 1205 assert(unit);
ef1673d1 1206
6c03089c
LP
1207 e = strchrnul(cgroup, '/');
1208 c = strndupa(cgroup, e - cgroup);
ef1673d1 1209
6c03089c
LP
1210 /* Could this be a valid unit name? */
1211 if (!unit_name_is_valid(c, true))
1212 return -EINVAL;
ef1673d1 1213
6c03089c
LP
1214 if (!unit_name_is_template(c))
1215 s = strdup(c);
1216 else {
1217 if (*e != '/')
96cde13a 1218 return -EINVAL;
ef1673d1 1219
6c03089c
LP
1220 e += strspn(e, "/");
1221 p = strchrnul(e, '/');
ef1673d1 1222
6c03089c
LP
1223 /* Don't allow empty instance strings */
1224 if (p == e)
1225 return -EINVAL;
1226
1227 k = strndupa(e, p - e);
1228
1229 s = unit_name_replace_instance(c, k);
ef1673d1
MT
1230 }
1231
6c03089c
LP
1232 if (!s)
1233 return -ENOMEM;
1234
1235 *unit = s;
ef1673d1
MT
1236 return 0;
1237}
1238
6c03089c
LP
1239int cg_path_get_unit(const char *path, char **unit) {
1240 const char *e;
1241
1242 assert(path);
1243 assert(unit);
1244
1245 e = path_startswith(path, "/system/");
1246 if (!e)
1247 return -ENOENT;
1248
7027ff61 1249 return cg_path_decode_unit(e, unit);
6c03089c
LP
1250}
1251
1252int cg_pid_get_unit(pid_t pid, char **unit) {
1253 char _cleanup_free_ *cgroup = NULL;
ba1261bc 1254 int r;
ba1261bc 1255
ef1673d1
MT
1256 assert(unit);
1257
7027ff61 1258 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
ef1673d1
MT
1259 if (r < 0)
1260 return r;
1261
6c03089c
LP
1262 return cg_path_get_unit(cgroup, unit);
1263}
ef1673d1 1264
6c03089c
LP
1265static const char *skip_label(const char *e) {
1266 assert(e);
ef1673d1 1267
6c03089c
LP
1268 e = strchr(e, '/');
1269 if (!e)
1270 return NULL;
ef1673d1 1271
6c03089c
LP
1272 e += strspn(e, "/");
1273 return e;
ef1673d1
MT
1274}
1275
6c03089c
LP
1276int cg_path_get_user_unit(const char *path, char **unit) {
1277 const char *e;
ef1673d1 1278
6c03089c 1279 assert(path);
ba1261bc
LP
1280 assert(unit);
1281
6c03089c
LP
1282 /* We always have to parse the path from the beginning as unit
1283 * cgroups might have arbitrary child cgroups and we shouldn't get
1284 * confused by those */
ba1261bc 1285
6c03089c
LP
1286 e = path_startswith(path, "/user/");
1287 if (!e)
ba1261bc 1288 return -ENOENT;
ba1261bc 1289
6c03089c
LP
1290 /* Skip the user name */
1291 e = skip_label(e);
1292 if (!e)
1293 return -ENOENT;
ba1261bc 1294
6c03089c
LP
1295 /* Skip the session ID */
1296 e = skip_label(e);
1297 if (!e)
1298 return -ENOENT;
1299
1300 /* Skip the systemd cgroup */
1301 e = skip_label(e);
1302 if (!e)
1303 return -ENOENT;
1304
7027ff61 1305 return cg_path_decode_unit(e, unit);
ef1673d1 1306}
ba1261bc 1307
ef1673d1 1308int cg_pid_get_user_unit(pid_t pid, char **unit) {
6c03089c
LP
1309 char _cleanup_free_ *cgroup = NULL;
1310 int r;
1311
1312 assert(unit);
1313
7027ff61 1314 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
6c03089c
LP
1315 if (r < 0)
1316 return r;
1317
1318 return cg_path_get_user_unit(cgroup, unit);
ba1261bc 1319}
e884315e 1320
7027ff61
LP
1321int cg_path_get_machine_name(const char *path, char **machine) {
1322 const char *e, *n;
1323 char *s;
1324
1325 assert(path);
1326 assert(machine);
1327
1328 e = path_startswith(path, "/machine/");
1329 if (!e)
1330 return -ENOENT;
1331
1332 n = strchrnul(e, '/');
1333 if (e == n)
1334 return -ENOENT;
1335
1336 s = strndup(e, n - e);
1337 if (!s)
1338 return -ENOMEM;
1339
1340 *machine = s;
1341 return 0;
1342}
1343
1344int cg_pid_get_machine_name(pid_t pid, char **machine) {
1345 char _cleanup_free_ *cgroup = NULL;
1346 int r;
1347
1348 assert(machine);
1349
1350 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1351 if (r < 0)
1352 return r;
1353
1354 return cg_path_get_machine_name(cgroup, machine);
1355}
1356
1357int cg_path_get_session(const char *path, char **session) {
1358 const char *e, *n;
1359 char *s;
1360
1361 assert(path);
1362 assert(session);
1363
1364 e = path_startswith(path, "/user/");
1365 if (!e)
1366 return -ENOENT;
1367
1368 /* Skip the user name */
1369 e = skip_label(e);
1370 if (!e)
1371 return -ENOENT;
1372
1373 n = strchrnul(e, '/');
1374 if (e == n)
1375 return -ENOENT;
1376
1377 if (n - e == 6 && memcmp(e, "shared", 6) == 0)
1378 return -ENOENT;
1379
1380 s = strndup(e, n - e);
1381 if (!s)
1382 return -ENOMEM;
1383
1384 *session = s;
1385 return 0;
1386}
1387
1388int cg_pid_get_session(pid_t pid, char **session) {
1389 char _cleanup_free_ *cgroup = NULL;
1390 int r;
1391
1392 assert(session);
1393
1394 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1395 if (r < 0)
1396 return r;
1397
1398 return cg_path_get_session(cgroup, session);
1399}
1400
e884315e
LP
1401int cg_controller_from_attr(const char *attr, char **controller) {
1402 const char *dot;
1403 char *c;
1404
1405 assert(attr);
1406 assert(controller);
1407
1408 if (!filename_is_safe(attr))
1409 return -EINVAL;
1410
1411 dot = strchr(attr, '.');
1412 if (!dot) {
1413 *controller = NULL;
1414 return 0;
1415 }
1416
1417 c = strndup(attr, dot - attr);
1418 if (!c)
1419 return -ENOMEM;
1420
1421 if (!filename_is_safe(c)) {
1422 free(c);
1423 return -EINVAL;
1424 }
1425
1426 *controller = c;
1427 return 1;
1428}