]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cgroup-util.c
journalctl: properly honour -n when -f is passed, too
[thirdparty/systemd.git] / src / 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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
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
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
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"
37
c6c18be3
LP
38int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
39 char *fs;
40 int r;
41 FILE *f;
42
43 assert(controller);
44 assert(path);
45 assert(_f);
46
47 if ((r = cg_get_path(controller, path, "cgroup.procs", &fs)) < 0)
48 return r;
49
50 f = fopen(fs, "re");
51 free(fs);
52
53 if (!f)
54 return -errno;
55
56 *_f = f;
57 return 0;
58}
59
60int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
61 char *fs;
62 int r;
63 FILE *f;
64
65 assert(controller);
66 assert(path);
67 assert(_f);
68
69 if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
70 return r;
71
72 f = fopen(fs, "re");
73 free(fs);
74
75 if (!f)
76 return -errno;
77
78 *_f = f;
79 return 0;
80}
81
82int cg_read_pid(FILE *f, pid_t *_pid) {
83 unsigned long ul;
84
85 /* Note that the cgroup.procs might contain duplicates! See
86 * cgroups.txt for details. */
87
88 errno = 0;
89 if (fscanf(f, "%lu", &ul) != 1) {
90
91 if (feof(f))
92 return 0;
93
94 return errno ? -errno : -EIO;
95 }
96
97 if (ul <= 0)
98 return -EIO;
99
100 *_pid = (pid_t) ul;
101 return 1;
102}
103
35d2e7ec
LP
104int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
105 char *fs;
106 int r;
107 DIR *d;
108
109 assert(controller);
110 assert(path);
111 assert(_d);
112
113 /* This is not recursive! */
114
115 if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
116 return r;
117
118 d = opendir(fs);
119 free(fs);
120
121 if (!d)
122 return -errno;
123
124 *_d = d;
125 return 0;
126}
127
128int cg_read_subgroup(DIR *d, char **fn) {
129 struct dirent *de;
130
131 assert(d);
132
133 errno = 0;
134 while ((de = readdir(d))) {
135 char *b;
136
137 if (de->d_type != DT_DIR)
138 continue;
139
140 if (streq(de->d_name, ".") ||
141 streq(de->d_name, ".."))
142 continue;
143
144 if (!(b = strdup(de->d_name)))
145 return -ENOMEM;
146
147 *fn = b;
148 return 1;
149 }
150
151 if (errno)
152 return -errno;
153
154 return 0;
155}
156
ad293f5a 157int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
35d2e7ec
LP
158 char *p;
159 int r;
160
ad293f5a
LP
161 r = cg_get_path(controller, path, NULL, &p);
162 if (r < 0)
35d2e7ec
LP
163 return r;
164
ad293f5a
LP
165 if (honour_sticky) {
166 char *tasks;
167
168 /* If the sticky bit is set don't remove the directory */
169
170 tasks = strappend(p, "/tasks");
171 if (!tasks) {
172 free(p);
173 return -ENOMEM;
174 }
175
176 r = file_is_sticky(tasks);
177 free(tasks);
178
179 if (r > 0) {
180 free(p);
181 return 0;
182 }
183 }
184
35d2e7ec
LP
185 r = rmdir(p);
186 free(p);
187
ad293f5a 188 return (r < 0 && errno != ENOENT) ? -errno : 0;
35d2e7ec
LP
189}
190
430c18ed 191int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
35d2e7ec 192 bool done = false;
8c6db833 193 int r, ret = 0;
35d2e7ec 194 pid_t my_pid;
c6c18be3 195 FILE *f = NULL;
ca949c9d 196 Set *allocated_set = NULL;
8c6db833
LP
197
198 assert(controller);
199 assert(path);
200 assert(sig >= 0);
201
202 /* This goes through the tasks list and kills them all. This
203 * is repeated until no further processes are added to the
204 * tasks list, to properly handle forking processes */
205
ca949c9d
LP
206 if (!s)
207 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
208 return -ENOMEM;
8c6db833
LP
209
210 my_pid = getpid();
211
212 do {
0b172489 213 pid_t pid = 0;
8c6db833
LP
214 done = true;
215
35d2e7ec 216 if ((r = cg_enumerate_processes(controller, path, &f)) < 0) {
4c633005 217 if (ret >= 0 && r != -ENOENT)
35d2e7ec
LP
218 ret = r;
219
c6c18be3 220 goto finish;
35d2e7ec 221 }
c6c18be3
LP
222
223 while ((r = cg_read_pid(f, &pid)) > 0) {
8c6db833
LP
224
225 if (pid == my_pid && ignore_self)
c6c18be3 226 continue;
8c6db833 227
c6c18be3
LP
228 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
229 continue;
8c6db833
LP
230
231 /* If we haven't killed this process yet, kill
232 * it */
4c633005
LP
233 if (kill(pid, sig) < 0) {
234 if (ret >= 0 && errno != ESRCH)
8c6db833 235 ret = -errno;
430c18ed
LP
236 } else if (ret == 0) {
237
238 if (sigcont)
239 kill(pid, SIGCONT);
240
35d2e7ec 241 ret = 1;
430c18ed 242 }
8c6db833 243
8c6db833
LP
244 done = false;
245
35d2e7ec
LP
246 if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) {
247 if (ret >= 0)
248 ret = r;
249
250 goto finish;
251 }
252 }
253
254 if (r < 0) {
255 if (ret >= 0)
256 ret = r;
257
258 goto finish;
8c6db833
LP
259 }
260
c6c18be3
LP
261 fclose(f);
262 f = NULL;
8c6db833
LP
263
264 /* To avoid racing against processes which fork
265 * quicker than we can kill them we repeat this until
266 * no new pids need to be killed. */
267
35d2e7ec 268 } while (!done);
8c6db833 269
c6c18be3 270finish:
ca949c9d
LP
271 if (allocated_set)
272 set_free(allocated_set);
8c6db833 273
c6c18be3
LP
274 if (f)
275 fclose(f);
8c6db833 276
35d2e7ec 277 return ret;
8c6db833
LP
278}
279
430c18ed 280int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
35d2e7ec
LP
281 int r, ret = 0;
282 DIR *d = NULL;
283 char *fn;
ca949c9d 284 Set *allocated_set = NULL;
8c6db833
LP
285
286 assert(path);
287 assert(controller);
288 assert(sig >= 0);
289
ca949c9d
LP
290 if (!s)
291 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
292 return -ENOMEM;
293
430c18ed 294 ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
8c6db833 295
35d2e7ec 296 if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0) {
4c633005 297 if (ret >= 0 && r != -ENOENT)
35d2e7ec 298 ret = r;
8c6db833 299
35d2e7ec
LP
300 goto finish;
301 }
8c6db833 302
35d2e7ec
LP
303 while ((r = cg_read_subgroup(d, &fn)) > 0) {
304 char *p = NULL;
8c6db833 305
35d2e7ec
LP
306 r = asprintf(&p, "%s/%s", path, fn);
307 free(fn);
308
309 if (r < 0) {
310 if (ret >= 0)
311 ret = -ENOMEM;
8c6db833 312
35d2e7ec
LP
313 goto finish;
314 }
8c6db833 315
430c18ed 316 r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
35d2e7ec 317 free(p);
8c6db833 318
35d2e7ec
LP
319 if (r != 0 && ret >= 0)
320 ret = r;
8c6db833
LP
321 }
322
35d2e7ec
LP
323 if (r < 0 && ret >= 0)
324 ret = r;
325
326 if (rem)
ad293f5a 327 if ((r = cg_rmdir(controller, path, true)) < 0) {
2db9ecac
LP
328 if (ret >= 0 &&
329 r != -ENOENT &&
330 r != -EBUSY)
35d2e7ec
LP
331 ret = r;
332 }
8c6db833 333
35d2e7ec
LP
334finish:
335 if (d)
336 closedir(d);
8c6db833 337
ca949c9d
LP
338 if (allocated_set)
339 set_free(allocated_set);
340
8c6db833
LP
341 return ret;
342}
343
35d2e7ec 344int cg_kill_recursive_and_wait(const char *controller, const char *path, bool rem) {
8c6db833
LP
345 unsigned i;
346
347 assert(path);
348 assert(controller);
349
350 /* This safely kills all processes; first it sends a SIGTERM,
9f452741
LP
351 * then checks 8 times after 200ms whether the group is now
352 * empty, then kills everything that is left with SIGKILL and
353 * finally checks 5 times after 200ms each whether the group
354 * is finally empty. */
8c6db833 355
9f452741 356 for (i = 0; i < 15; i++) {
1d0ae74a 357 int sig, r;
8c6db833
LP
358
359 if (i <= 0)
360 sig = SIGTERM;
9f452741 361 else if (i == 9)
8c6db833
LP
362 sig = SIGKILL;
363 else
364 sig = 0;
365
430c18ed 366 if ((r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL)) <= 0)
8c6db833
LP
367 return r;
368
9f452741 369 usleep(200 * USEC_PER_MSEC);
8c6db833
LP
370 }
371
372 return 0;
373}
374
375int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self) {
35d2e7ec
LP
376 bool done = false;
377 Set *s;
8c6db833
LP
378 int r, ret = 0;
379 pid_t my_pid;
c6c18be3 380 FILE *f = NULL;
8c6db833
LP
381
382 assert(controller);
383 assert(from);
384 assert(to);
385
35d2e7ec
LP
386 if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
387 return -ENOMEM;
388
8c6db833
LP
389 my_pid = getpid();
390
391 do {
0b172489 392 pid_t pid = 0;
8c6db833
LP
393 done = true;
394
35d2e7ec 395 if ((r = cg_enumerate_tasks(controller, from, &f)) < 0) {
4c633005 396 if (ret >= 0 && r != -ENOENT)
35d2e7ec
LP
397 ret = r;
398
c6c18be3 399 goto finish;
35d2e7ec 400 }
c6c18be3
LP
401
402 while ((r = cg_read_pid(f, &pid)) > 0) {
8c6db833 403
35d2e7ec
LP
404 /* This might do weird stuff if we aren't a
405 * single-threaded program. However, we
406 * luckily know we are not */
8c6db833 407 if (pid == my_pid && ignore_self)
c6c18be3 408 continue;
8c6db833 409
35d2e7ec
LP
410 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
411 continue;
412
c6c18be3 413 if ((r = cg_attach(controller, to, pid)) < 0) {
4c633005 414 if (ret >= 0 && r != -ESRCH)
35d2e7ec
LP
415 ret = r;
416 } else if (ret == 0)
417 ret = 1;
8c6db833 418
8c6db833 419 done = false;
35d2e7ec
LP
420
421 if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) {
422 if (ret >= 0)
423 ret = r;
424
425 goto finish;
426 }
427 }
428
429 if (r < 0) {
430 if (ret >= 0)
431 ret = r;
432
433 goto finish;
8c6db833
LP
434 }
435
c6c18be3
LP
436 fclose(f);
437 f = NULL;
8c6db833 438
35d2e7ec 439 } while (!done);
8c6db833 440
c6c18be3 441finish:
35d2e7ec 442 set_free(s);
8c6db833 443
c6c18be3
LP
444 if (f)
445 fclose(f);
8c6db833 446
35d2e7ec 447 return ret;
8c6db833
LP
448}
449
35d2e7ec
LP
450int cg_migrate_recursive(const char *controller, const char *from, const char *to, bool ignore_self, bool rem) {
451 int r, ret = 0;
452 DIR *d = NULL;
453 char *fn;
8c6db833
LP
454
455 assert(controller);
456 assert(from);
457 assert(to);
458
35d2e7ec 459 ret = cg_migrate(controller, from, to, ignore_self);
8c6db833 460
35d2e7ec 461 if ((r = cg_enumerate_subgroups(controller, from, &d)) < 0) {
4c633005 462 if (ret >= 0 && r != -ENOENT)
35d2e7ec
LP
463 ret = r;
464 goto finish;
465 }
466
467 while ((r = cg_read_subgroup(d, &fn)) > 0) {
468 char *p = NULL;
8c6db833 469
35d2e7ec
LP
470 r = asprintf(&p, "%s/%s", from, fn);
471 free(fn);
8c6db833 472
35d2e7ec
LP
473 if (r < 0) {
474 if (ret >= 0)
475 ret = -ENOMEM;
476
477 goto finish;
8c6db833
LP
478 }
479
35d2e7ec 480 r = cg_migrate_recursive(controller, p, to, ignore_self, rem);
8c6db833
LP
481 free(p);
482
35d2e7ec
LP
483 if (r != 0 && ret >= 0)
484 ret = r;
8c6db833
LP
485 }
486
35d2e7ec
LP
487 if (r < 0 && ret >= 0)
488 ret = r;
489
490 if (rem)
ad293f5a 491 if ((r = cg_rmdir(controller, from, true)) < 0) {
2db9ecac
LP
492 if (ret >= 0 &&
493 r != -ENOENT &&
494 r != -EBUSY)
35d2e7ec
LP
495 ret = r;
496 }
8c6db833 497
35d2e7ec
LP
498finish:
499 if (d)
500 closedir(d);
8c6db833
LP
501
502 return ret;
503}
504
505int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
dbd821ac 506 const char *p;
70132bd0 507 char *t;
0ac10822 508 static __thread bool good = false;
8c6db833
LP
509
510 assert(controller);
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
524 if (isempty(controller))
525 return -EINVAL;
526
dbd821ac
LP
527 /* This is a very minimal lookup from controller names to
528 * paths. Since we have mounted most hierarchies ourselves
529 * should be kinda safe, but eventually we might want to
530 * extend this to have a fallback to actually check
531 * /proc/mounts. Might need caching then. */
532
533 if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
534 p = "systemd";
535 else if (startswith(controller, "name="))
536 p = controller + 5;
537 else
538 p = controller;
539
c6c18be3 540 if (path && suffix)
70132bd0 541 t = join("/sys/fs/cgroup/", p, "/", path, "/", suffix, NULL);
c6c18be3 542 else if (path)
70132bd0 543 t = join("/sys/fs/cgroup/", p, "/", path, NULL);
c6c18be3 544 else if (suffix)
70132bd0
LP
545 t = join("/sys/fs/cgroup/", p, "/", suffix, NULL);
546 else
547 t = join("/sys/fs/cgroup/", p, NULL);
548
549 if (!t)
550 return -ENOMEM;
551
552 path_kill_slashes(t);
8c6db833 553
70132bd0
LP
554 *fs = t;
555 return 0;
8c6db833
LP
556}
557
e27796a0
LP
558static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
559 char *p;
560 bool is_sticky;
561
562 if (typeflag != FTW_DP)
563 return 0;
564
565 if (ftwbuf->level < 1)
566 return 0;
567
568 p = strappend(path, "/tasks");
569 if (!p) {
570 errno = ENOMEM;
571 return 1;
572 }
573
574 is_sticky = file_is_sticky(p) > 0;
575 free(p);
576
577 if (is_sticky)
578 return 0;
579
580 rmdir(path);
581 return 0;
582}
583
8c6db833
LP
584int cg_trim(const char *controller, const char *path, bool delete_root) {
585 char *fs;
e27796a0 586 int r = 0;
8c6db833
LP
587
588 assert(controller);
589 assert(path);
590
e27796a0
LP
591 r = cg_get_path(controller, path, NULL, &fs);
592 if (r < 0)
8c6db833
LP
593 return r;
594
e27796a0
LP
595 errno = 0;
596 if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
597 r = errno ? -errno : -EIO;
598
599 if (delete_root) {
600 bool is_sticky;
601 char *p;
602
603 p = strappend(fs, "/tasks");
604 if (!p) {
605 free(fs);
606 return -ENOMEM;
607 }
608
609 is_sticky = file_is_sticky(p) > 0;
610 free(p);
611
612 if (!is_sticky)
613 if (rmdir(fs) < 0 && errno != ENOENT) {
614 if (r == 0)
615 r = -errno;
616 }
617 }
618
8c6db833
LP
619 free(fs);
620
e27796a0 621 return r;
8c6db833
LP
622}
623
624int cg_delete(const char *controller, const char *path) {
35d2e7ec 625 char *parent;
8c6db833
LP
626 int r;
627
628 assert(controller);
629 assert(path);
630
35d2e7ec
LP
631 if ((r = parent_of_path(path, &parent)) < 0)
632 return r;
8c6db833 633
35d2e7ec
LP
634 r = cg_migrate_recursive(controller, path, parent, false, true);
635 free(parent);
8c6db833 636
4c633005 637 return r == -ENOENT ? 0 : r;
8c6db833
LP
638}
639
640int cg_create(const char *controller, const char *path) {
c6c18be3 641 char *fs;
8c6db833
LP
642 int r;
643
644 assert(controller);
645 assert(path);
646
c6c18be3
LP
647 if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
648 return r;
8c6db833 649
672c48cc
LP
650 r = mkdir_parents(fs, 0755);
651
652 if (r >= 0) {
653 if (mkdir(fs, 0755) >= 0)
654 r = 1;
655 else if (errno == EEXIST)
656 r = 0;
657 else
658 r = -errno;
659 }
660
c6c18be3 661 free(fs);
8c6db833
LP
662
663 return r;
664}
665
666int cg_attach(const char *controller, const char *path, pid_t pid) {
c6c18be3 667 char *fs;
8c6db833 668 int r;
c6c18be3 669 char c[32];
8c6db833
LP
670
671 assert(controller);
672 assert(path);
673 assert(pid >= 0);
674
c6c18be3
LP
675 if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
676 return r;
8c6db833
LP
677
678 if (pid == 0)
679 pid = getpid();
680
c6c18be3
LP
681 snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid);
682 char_array_0(c);
8c6db833 683
c6c18be3
LP
684 r = write_one_line_file(fs, c);
685 free(fs);
8c6db833
LP
686
687 return r;
688}
689
690int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
672c48cc 691 int r, q;
8c6db833
LP
692
693 assert(controller);
694 assert(path);
695 assert(pid >= 0);
696
c6c18be3
LP
697 if ((r = cg_create(controller, path)) < 0)
698 return r;
8c6db833 699
672c48cc
LP
700 if ((q = cg_attach(controller, path, pid)) < 0)
701 return q;
8c6db833 702
c6c18be3 703 /* This does not remove the cgroup on failure */
8c6db833
LP
704
705 return r;
706}
707
708int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
709 char *fs;
710 int r;
711
712 assert(controller);
713 assert(path);
714
715 if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
716 return r;
717
718 r = chmod_and_chown(fs, mode, uid, gid);
719 free(fs);
720
721 return r;
722}
723
724int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
725 char *fs;
726 int r;
727
728 assert(controller);
729 assert(path);
730
731 if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
732 return r;
733
734 r = chmod_and_chown(fs, mode, uid, gid);
735 free(fs);
736
737 return r;
738}
739
740int cg_get_by_pid(const char *controller, pid_t pid, char **path) {
741 int r;
742 char *p = NULL;
c6c18be3
LP
743 FILE *f;
744 char *fs;
745 size_t cs;
8c6db833
LP
746
747 assert(controller);
8c6db833 748 assert(path);
c6c18be3 749 assert(pid >= 0);
8c6db833 750
c6c18be3
LP
751 if (pid == 0)
752 pid = getpid();
8c6db833 753
c6c18be3
LP
754 if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0)
755 return -ENOMEM;
8c6db833 756
c6c18be3
LP
757 f = fopen(fs, "re");
758 free(fs);
759
4c633005
LP
760 if (!f)
761 return errno == ENOENT ? -ESRCH : -errno;
762
c6c18be3
LP
763 cs = strlen(controller);
764
765 while (!feof(f)) {
766 char line[LINE_MAX];
767 char *l;
768
769 errno = 0;
770 if (!(fgets(line, sizeof(line), f))) {
771 if (feof(f))
772 break;
773
774 r = errno ? -errno : -EIO;
775 goto finish;
776 }
777
778 truncate_nl(line);
779
780 if (!(l = strchr(line, ':')))
781 continue;
782
783 l++;
784 if (strncmp(l, controller, cs) != 0)
785 continue;
786
787 if (l[cs] != ':')
788 continue;
789
790 if (!(p = strdup(l + cs + 1))) {
791 r = -ENOMEM;
792 goto finish;
793 }
794
795 *path = p;
796 r = 0;
797 goto finish;
798 }
799
800 r = -ENOENT;
801
802finish:
803 fclose(f);
804
805 return r;
8c6db833
LP
806}
807
808int cg_install_release_agent(const char *controller, const char *agent) {
c6c18be3 809 char *fs = NULL, *contents = NULL, *line = NULL, *sc;
8c6db833
LP
810 int r;
811
812 assert(controller);
813 assert(agent);
814
c6c18be3
LP
815 if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0)
816 return r;
8c6db833 817
c6c18be3 818 if ((r = read_one_line_file(fs, &contents)) < 0)
8c6db833
LP
819 goto finish;
820
821 sc = strstrip(contents);
8c6db833
LP
822 if (sc[0] == 0) {
823
824 if (asprintf(&line, "%s\n", agent) < 0) {
825 r = -ENOMEM;
826 goto finish;
827 }
828
c6c18be3 829 if ((r = write_one_line_file(fs, line)) < 0)
8c6db833
LP
830 goto finish;
831
832 } else if (!streq(sc, agent)) {
833 r = -EEXIST;
834 goto finish;
835 }
836
c6c18be3
LP
837 free(fs);
838 fs = NULL;
e364ad06 839 if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0)
8c6db833 840 goto finish;
8c6db833
LP
841
842 free(contents);
843 contents = NULL;
c6c18be3 844 if ((r = read_one_line_file(fs, &contents)) < 0)
8c6db833
LP
845 goto finish;
846
847 sc = strstrip(contents);
848
849 if (streq(sc, "0")) {
c6c18be3 850 if ((r = write_one_line_file(fs, "1\n")) < 0)
8c6db833 851 goto finish;
c6c18be3
LP
852
853 r = 1;
8c6db833
LP
854 } else if (!streq(sc, "1")) {
855 r = -EIO;
856 goto finish;
c6c18be3
LP
857 } else
858 r = 0;
8c6db833
LP
859
860finish:
c6c18be3 861 free(fs);
8c6db833
LP
862 free(contents);
863 free(line);
864
865 return r;
866}
867
868int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
0b172489 869 pid_t pid = 0;
8c6db833 870 int r;
0b172489 871 FILE *f = NULL;
c6c18be3 872 bool found = false;
8c6db833
LP
873
874 assert(controller);
875 assert(path);
876
c6c18be3 877 if ((r = cg_enumerate_tasks(controller, path, &f)) < 0)
4c633005 878 return r == -ENOENT ? 1 : r;
8c6db833 879
c6c18be3 880 while ((r = cg_read_pid(f, &pid)) > 0) {
8c6db833 881
c6c18be3
LP
882 if (ignore_self && pid == getpid())
883 continue;
8c6db833 884
c6c18be3
LP
885 found = true;
886 break;
8c6db833
LP
887 }
888
c6c18be3 889 fclose(f);
8c6db833 890
c6c18be3
LP
891 if (r < 0)
892 return r;
8c6db833 893
c6c18be3 894 return !found;
8c6db833
LP
895}
896
897int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
35d2e7ec
LP
898 int r;
899 DIR *d = NULL;
900 char *fn;
8c6db833
LP
901
902 assert(controller);
903 assert(path);
904
35d2e7ec
LP
905 if ((r = cg_is_empty(controller, path, ignore_self)) <= 0)
906 return r;
907
908 if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0)
4c633005 909 return r == -ENOENT ? 1 : r;
8c6db833 910
35d2e7ec
LP
911 while ((r = cg_read_subgroup(d, &fn)) > 0) {
912 char *p = NULL;
8c6db833 913
35d2e7ec
LP
914 r = asprintf(&p, "%s/%s", path, fn);
915 free(fn);
8c6db833 916
35d2e7ec
LP
917 if (r < 0) {
918 r = -ENOMEM;
919 goto finish;
8c6db833
LP
920 }
921
35d2e7ec 922 r = cg_is_empty_recursive(controller, p, ignore_self);
8c6db833
LP
923 free(p);
924
35d2e7ec
LP
925 if (r <= 0)
926 goto finish;
927 }
928
929 if (r >= 0)
930 r = 1;
931
932finish:
933
934 if (d)
935 closedir(d);
936
937 return r;
938}
939
940int cg_split_spec(const char *spec, char **controller, char **path) {
941 const char *e;
942 char *t = NULL, *u = NULL;
943
944 assert(spec);
945 assert(controller || path);
946
947 if (*spec == '/') {
948
949 if (path) {
950 if (!(t = strdup(spec)))
951 return -ENOMEM;
952
953 *path = t;
8c6db833
LP
954 }
955
35d2e7ec
LP
956 if (controller)
957 *controller = NULL;
958
959 return 0;
8c6db833
LP
960 }
961
35d2e7ec
LP
962 if (!(e = strchr(spec, ':'))) {
963
964 if (strchr(spec, '/') || spec[0] == 0)
965 return -EINVAL;
966
967 if (controller) {
968 if (!(t = strdup(spec)))
969 return -ENOMEM;
970
971 *controller = t;
972 }
973
974 if (path)
975 *path = NULL;
976
977 return 0;
8c6db833
LP
978 }
979
35d2e7ec
LP
980 if (e[1] != '/' ||
981 e == spec ||
982 memchr(spec, '/', e-spec))
983 return -EINVAL;
8c6db833 984
35d2e7ec
LP
985 if (controller)
986 if (!(t = strndup(spec, e-spec)))
987 return -ENOMEM;
988
989 if (path)
990 if (!(u = strdup(e+1))) {
991 free(t);
992 return -ENOMEM;
993 }
994
995 if (controller)
996 *controller = t;
997
998 if (path)
999 *path = u;
1000
1001 return 0;
8c6db833 1002}
c6c18be3 1003
35d2e7ec
LP
1004int cg_join_spec(const char *controller, const char *path, char **spec) {
1005 assert(controller);
1006 assert(path);
c6c18be3 1007
35d2e7ec
LP
1008 if (!path_is_absolute(path) ||
1009 controller[0] == 0 ||
1010 strchr(controller, ':') ||
1011 strchr(controller, '/'))
1012 return -EINVAL;
1013
1014 if (asprintf(spec, "%s:%s", controller, path) < 0)
1015 return -ENOMEM;
c6c18be3
LP
1016
1017 return 0;
1018}
35d2e7ec
LP
1019
1020int cg_fix_path(const char *path, char **result) {
1021 char *t, *c, *p;
1022 int r;
1023
1024 assert(path);
1025 assert(result);
1026
1027 /* First check if it already is a filesystem path */
1028 if (path_is_absolute(path) &&
77d5f105 1029 path_startswith(path, "/sys/fs/cgroup") &&
35d2e7ec
LP
1030 access(path, F_OK) >= 0) {
1031
1032 if (!(t = strdup(path)))
1033 return -ENOMEM;
1034
1035 *result = t;
1036 return 0;
1037 }
1038
1039 /* Otherwise treat it as cg spec */
1040 if ((r = cg_split_spec(path, &c, &p)) < 0)
1041 return r;
1042
1043 r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1044 free(c);
1045 free(p);
1046
1047 return r;
1048}
1f73f0f1
LP
1049
1050int cg_get_user_path(char **path) {
1051 char *root, *p;
1052
1053 assert(path);
1054
1055 /* Figure out the place to put user cgroups below. We use the
1056 * same as PID 1 has but with the "/system" suffix replaced by
1057 * "/user" */
1058
1059 if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0)
1060 p = strdup("/user");
1061 else {
1062 if (endswith(root, "/system"))
1063 root[strlen(root) - 7] = 0;
1064 else if (streq(root, "/"))
1065 root[0] = 0;
1066
1067 p = strappend(root, "/user");
1068 free(root);
1069 }
1070
1071 if (!p)
1072 return -ENOMEM;
1073
1074 *path = p;
1075 return 0;
1076}