]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-util.c
shared: add process-util.[ch]
[thirdparty/systemd.git] / src / shared / cgroup-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
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 Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser 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>
27 #include <dirent.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <ftw.h>
31
32 #include "cgroup-util.h"
33 #include "set.h"
34 #include "macro.h"
35 #include "util.h"
36 #include "formats-util.h"
37 #include "process-util.h"
38 #include "path-util.h"
39 #include "unit-name.h"
40 #include "fileio.h"
41 #include "special.h"
42 #include "mkdir.h"
43
44 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
45 _cleanup_free_ char *fs = NULL;
46 FILE *f;
47 int r;
48
49 assert(_f);
50
51 r = cg_get_path(controller, path, "cgroup.procs", &fs);
52 if (r < 0)
53 return r;
54
55 f = fopen(fs, "re");
56 if (!f)
57 return -errno;
58
59 *_f = f;
60 return 0;
61 }
62
63 int cg_read_pid(FILE *f, pid_t *_pid) {
64 unsigned long ul;
65
66 /* Note that the cgroup.procs might contain duplicates! See
67 * cgroups.txt for details. */
68
69 assert(f);
70 assert(_pid);
71
72 errno = 0;
73 if (fscanf(f, "%lu", &ul) != 1) {
74
75 if (feof(f))
76 return 0;
77
78 return errno ? -errno : -EIO;
79 }
80
81 if (ul <= 0)
82 return -EIO;
83
84 *_pid = (pid_t) ul;
85 return 1;
86 }
87
88 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
89 _cleanup_free_ char *fs = NULL;
90 int r;
91 DIR *d;
92
93 assert(_d);
94
95 /* This is not recursive! */
96
97 r = cg_get_path(controller, path, NULL, &fs);
98 if (r < 0)
99 return r;
100
101 d = opendir(fs);
102 if (!d)
103 return -errno;
104
105 *_d = d;
106 return 0;
107 }
108
109 int cg_read_subgroup(DIR *d, char **fn) {
110 struct dirent *de;
111
112 assert(d);
113 assert(fn);
114
115 FOREACH_DIRENT(de, d, return -errno) {
116 char *b;
117
118 if (de->d_type != DT_DIR)
119 continue;
120
121 if (streq(de->d_name, ".") ||
122 streq(de->d_name, ".."))
123 continue;
124
125 b = strdup(de->d_name);
126 if (!b)
127 return -ENOMEM;
128
129 *fn = b;
130 return 1;
131 }
132
133 return 0;
134 }
135
136 int cg_rmdir(const char *controller, const char *path) {
137 _cleanup_free_ char *p = NULL;
138 int r;
139
140 r = cg_get_path(controller, path, NULL, &p);
141 if (r < 0)
142 return r;
143
144 r = rmdir(p);
145 if (r < 0 && errno != ENOENT)
146 return -errno;
147
148 return 0;
149 }
150
151 int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
152 _cleanup_set_free_ Set *allocated_set = NULL;
153 bool done = false;
154 int r, ret = 0;
155 pid_t my_pid;
156
157 assert(sig >= 0);
158
159 /* This goes through the tasks list and kills them all. This
160 * is repeated until no further processes are added to the
161 * tasks list, to properly handle forking processes */
162
163 if (!s) {
164 s = allocated_set = set_new(NULL);
165 if (!s)
166 return -ENOMEM;
167 }
168
169 my_pid = getpid();
170
171 do {
172 _cleanup_fclose_ FILE *f = NULL;
173 pid_t pid = 0;
174 done = true;
175
176 r = cg_enumerate_processes(controller, path, &f);
177 if (r < 0) {
178 if (ret >= 0 && r != -ENOENT)
179 return r;
180
181 return ret;
182 }
183
184 while ((r = cg_read_pid(f, &pid)) > 0) {
185
186 if (ignore_self && pid == my_pid)
187 continue;
188
189 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
190 continue;
191
192 /* If we haven't killed this process yet, kill
193 * it */
194 if (kill(pid, sig) < 0) {
195 if (ret >= 0 && errno != ESRCH)
196 ret = -errno;
197 } else {
198 if (sigcont && sig != SIGKILL)
199 kill(pid, SIGCONT);
200
201 if (ret == 0)
202 ret = 1;
203 }
204
205 done = false;
206
207 r = set_put(s, LONG_TO_PTR(pid));
208 if (r < 0) {
209 if (ret >= 0)
210 return r;
211
212 return ret;
213 }
214 }
215
216 if (r < 0) {
217 if (ret >= 0)
218 return r;
219
220 return ret;
221 }
222
223 /* To avoid racing against processes which fork
224 * quicker than we can kill them we repeat this until
225 * no new pids need to be killed. */
226
227 } while (!done);
228
229 return ret;
230 }
231
232 int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
233 _cleanup_set_free_ Set *allocated_set = NULL;
234 _cleanup_closedir_ DIR *d = NULL;
235 int r, ret = 0;
236 char *fn;
237
238 assert(path);
239 assert(sig >= 0);
240
241 if (!s) {
242 s = allocated_set = set_new(NULL);
243 if (!s)
244 return -ENOMEM;
245 }
246
247 ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
248
249 r = cg_enumerate_subgroups(controller, path, &d);
250 if (r < 0) {
251 if (ret >= 0 && r != -ENOENT)
252 return r;
253
254 return ret;
255 }
256
257 while ((r = cg_read_subgroup(d, &fn)) > 0) {
258 _cleanup_free_ char *p = NULL;
259
260 p = strjoin(path, "/", fn, NULL);
261 free(fn);
262 if (!p)
263 return -ENOMEM;
264
265 r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
266 if (ret >= 0 && r != 0)
267 ret = r;
268 }
269
270 if (ret >= 0 && r < 0)
271 ret = r;
272
273 if (rem) {
274 r = cg_rmdir(controller, path);
275 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
276 return r;
277 }
278
279 return ret;
280 }
281
282 int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) {
283 bool done = false;
284 _cleanup_set_free_ Set *s = NULL;
285 int r, ret = 0;
286 pid_t my_pid;
287
288 assert(cfrom);
289 assert(pfrom);
290 assert(cto);
291 assert(pto);
292
293 s = set_new(NULL);
294 if (!s)
295 return -ENOMEM;
296
297 my_pid = getpid();
298
299 do {
300 _cleanup_fclose_ FILE *f = NULL;
301 pid_t pid = 0;
302 done = true;
303
304 r = cg_enumerate_processes(cfrom, pfrom, &f);
305 if (r < 0) {
306 if (ret >= 0 && r != -ENOENT)
307 return r;
308
309 return ret;
310 }
311
312 while ((r = cg_read_pid(f, &pid)) > 0) {
313
314 /* This might do weird stuff if we aren't a
315 * single-threaded program. However, we
316 * luckily know we are not */
317 if (ignore_self && pid == my_pid)
318 continue;
319
320 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
321 continue;
322
323 r = cg_attach(cto, pto, pid);
324 if (r < 0) {
325 if (ret >= 0 && r != -ESRCH)
326 ret = r;
327 } else if (ret == 0)
328 ret = 1;
329
330 done = false;
331
332 r = set_put(s, LONG_TO_PTR(pid));
333 if (r < 0) {
334 if (ret >= 0)
335 return r;
336
337 return ret;
338 }
339 }
340
341 if (r < 0) {
342 if (ret >= 0)
343 return r;
344
345 return ret;
346 }
347 } while (!done);
348
349 return ret;
350 }
351
352 int cg_migrate_recursive(
353 const char *cfrom,
354 const char *pfrom,
355 const char *cto,
356 const char *pto,
357 bool ignore_self,
358 bool rem) {
359
360 _cleanup_closedir_ DIR *d = NULL;
361 int r, ret = 0;
362 char *fn;
363
364 assert(cfrom);
365 assert(pfrom);
366 assert(cto);
367 assert(pto);
368
369 ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self);
370
371 r = cg_enumerate_subgroups(cfrom, pfrom, &d);
372 if (r < 0) {
373 if (ret >= 0 && r != -ENOENT)
374 return r;
375
376 return ret;
377 }
378
379 while ((r = cg_read_subgroup(d, &fn)) > 0) {
380 _cleanup_free_ char *p = NULL;
381
382 p = strjoin(pfrom, "/", fn, NULL);
383 free(fn);
384 if (!p) {
385 if (ret >= 0)
386 return -ENOMEM;
387
388 return ret;
389 }
390
391 r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem);
392 if (r != 0 && ret >= 0)
393 ret = r;
394 }
395
396 if (r < 0 && ret >= 0)
397 ret = r;
398
399 if (rem) {
400 r = cg_rmdir(cfrom, pfrom);
401 if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
402 return r;
403 }
404
405 return ret;
406 }
407
408 int cg_migrate_recursive_fallback(
409 const char *cfrom,
410 const char *pfrom,
411 const char *cto,
412 const char *pto,
413 bool ignore_self,
414 bool rem) {
415
416 int r;
417
418 assert(cfrom);
419 assert(pfrom);
420 assert(cto);
421 assert(pto);
422
423 r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem);
424 if (r < 0) {
425 char prefix[strlen(pto) + 1];
426
427 /* This didn't work? Then let's try all prefixes of the destination */
428
429 PATH_FOREACH_PREFIX(prefix, pto) {
430 r = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
431 if (r >= 0)
432 break;
433 }
434 }
435
436 return 0;
437 }
438
439 static const char *normalize_controller(const char *controller) {
440
441 assert(controller);
442
443 if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
444 return "systemd";
445 else if (startswith(controller, "name="))
446 return controller + 5;
447 else
448 return controller;
449 }
450
451 static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
452 char *t = NULL;
453
454 if (!isempty(controller)) {
455 if (!isempty(path) && !isempty(suffix))
456 t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
457 else if (!isempty(path))
458 t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL);
459 else if (!isempty(suffix))
460 t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL);
461 else
462 t = strappend("/sys/fs/cgroup/", controller);
463 } else {
464 if (!isempty(path) && !isempty(suffix))
465 t = strjoin(path, "/", suffix, NULL);
466 else if (!isempty(path))
467 t = strdup(path);
468 else
469 return -EINVAL;
470 }
471
472 if (!t)
473 return -ENOMEM;
474
475 *fs = path_kill_slashes(t);
476 return 0;
477 }
478
479 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
480 const char *p;
481 static thread_local bool good = false;
482
483 assert(fs);
484
485 if (controller && !cg_controller_is_valid(controller, true))
486 return -EINVAL;
487
488 if (_unlikely_(!good)) {
489 int r;
490
491 r = path_is_mount_point("/sys/fs/cgroup", false);
492 if (r < 0)
493 return r;
494 if (r == 0)
495 return -ENOENT;
496
497 /* Cache this to save a few stat()s */
498 good = true;
499 }
500
501 p = controller ? normalize_controller(controller) : NULL;
502
503 return join_path(p, path, suffix, fs);
504 }
505
506 static int check_hierarchy(const char *p) {
507 const char *cc;
508
509 assert(p);
510
511 if (!filename_is_valid(p))
512 return 0;
513
514 /* Check if this controller actually really exists */
515 cc = strjoina("/sys/fs/cgroup/", p);
516 if (laccess(cc, F_OK) < 0)
517 return -errno;
518
519 return 0;
520 }
521
522 int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
523 const char *p;
524 int r;
525
526 assert(fs);
527
528 if (!cg_controller_is_valid(controller, true))
529 return -EINVAL;
530
531 /* Normalize the controller syntax */
532 p = normalize_controller(controller);
533
534 /* Check if this controller actually really exists */
535 r = check_hierarchy(p);
536 if (r < 0)
537 return r;
538
539 return join_path(p, path, suffix, fs);
540 }
541
542 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
543 assert(path);
544 assert(sb);
545 assert(ftwbuf);
546
547 if (typeflag != FTW_DP)
548 return 0;
549
550 if (ftwbuf->level < 1)
551 return 0;
552
553 rmdir(path);
554 return 0;
555 }
556
557 int cg_trim(const char *controller, const char *path, bool delete_root) {
558 _cleanup_free_ char *fs = NULL;
559 int r = 0;
560
561 assert(path);
562
563 r = cg_get_path(controller, path, NULL, &fs);
564 if (r < 0)
565 return r;
566
567 errno = 0;
568 if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0)
569 r = errno ? -errno : -EIO;
570
571 if (delete_root) {
572 if (rmdir(fs) < 0 && errno != ENOENT)
573 return -errno;
574 }
575
576 return r;
577 }
578
579 int cg_delete(const char *controller, const char *path) {
580 _cleanup_free_ char *parent = NULL;
581 int r;
582
583 assert(path);
584
585 r = path_get_parent(path, &parent);
586 if (r < 0)
587 return r;
588
589 r = cg_migrate_recursive(controller, path, controller, parent, false, true);
590 return r == -ENOENT ? 0 : r;
591 }
592
593 int cg_create(const char *controller, const char *path) {
594 _cleanup_free_ char *fs = NULL;
595 int r;
596
597 r = cg_get_path_and_check(controller, path, NULL, &fs);
598 if (r < 0)
599 return r;
600
601 r = mkdir_parents(fs, 0755);
602 if (r < 0)
603 return r;
604
605 if (mkdir(fs, 0755) < 0) {
606
607 if (errno == EEXIST)
608 return 0;
609
610 return -errno;
611 }
612
613 return 1;
614 }
615
616 int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
617 int r, q;
618
619 assert(pid >= 0);
620
621 r = cg_create(controller, path);
622 if (r < 0)
623 return r;
624
625 q = cg_attach(controller, path, pid);
626 if (q < 0)
627 return q;
628
629 /* This does not remove the cgroup on failure */
630 return r;
631 }
632
633 int cg_attach(const char *controller, const char *path, pid_t pid) {
634 _cleanup_free_ char *fs = NULL;
635 char c[DECIMAL_STR_MAX(pid_t) + 2];
636 int r;
637
638 assert(path);
639 assert(pid >= 0);
640
641 r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
642 if (r < 0)
643 return r;
644
645 if (pid == 0)
646 pid = getpid();
647
648 snprintf(c, sizeof(c), PID_FMT"\n", pid);
649
650 return write_string_file_no_create(fs, c);
651 }
652
653 int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
654 int r;
655
656 assert(controller);
657 assert(path);
658 assert(pid >= 0);
659
660 r = cg_attach(controller, path, pid);
661 if (r < 0) {
662 char prefix[strlen(path) + 1];
663
664 /* This didn't work? Then let's try all prefixes of
665 * the destination */
666
667 PATH_FOREACH_PREFIX(prefix, path) {
668 r = cg_attach(controller, prefix, pid);
669 if (r >= 0)
670 break;
671 }
672 }
673
674 return 0;
675 }
676
677 int cg_set_group_access(
678 const char *controller,
679 const char *path,
680 mode_t mode,
681 uid_t uid,
682 gid_t gid) {
683
684 _cleanup_free_ char *fs = NULL;
685 int r;
686
687 assert(path);
688
689 if (mode != MODE_INVALID)
690 mode &= 0777;
691
692 r = cg_get_path(controller, path, NULL, &fs);
693 if (r < 0)
694 return r;
695
696 return chmod_and_chown(fs, mode, uid, gid);
697 }
698
699 int cg_set_task_access(
700 const char *controller,
701 const char *path,
702 mode_t mode,
703 uid_t uid,
704 gid_t gid) {
705
706 _cleanup_free_ char *fs = NULL, *procs = NULL;
707 int r;
708
709 assert(path);
710
711 if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
712 return 0;
713
714 if (mode != MODE_INVALID)
715 mode &= 0666;
716
717 r = cg_get_path(controller, path, "cgroup.procs", &fs);
718 if (r < 0)
719 return r;
720
721 r = chmod_and_chown(fs, mode, uid, gid);
722 if (r < 0)
723 return r;
724
725 /* Compatibility, Always keep values for "tasks" in sync with
726 * "cgroup.procs" */
727 r = cg_get_path(controller, path, "tasks", &procs);
728 if (r < 0)
729 return r;
730
731 return chmod_and_chown(procs, mode, uid, gid);
732 }
733
734 int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
735 _cleanup_fclose_ FILE *f = NULL;
736 char line[LINE_MAX];
737 const char *fs;
738 size_t cs;
739
740 assert(path);
741 assert(pid >= 0);
742
743 if (controller) {
744 if (!cg_controller_is_valid(controller, true))
745 return -EINVAL;
746
747 controller = normalize_controller(controller);
748 } else
749 controller = SYSTEMD_CGROUP_CONTROLLER;
750
751 fs = procfs_file_alloca(pid, "cgroup");
752
753 f = fopen(fs, "re");
754 if (!f)
755 return errno == ENOENT ? -ESRCH : -errno;
756
757 cs = strlen(controller);
758
759 FOREACH_LINE(line, f, return -errno) {
760 char *l, *p, *e;
761 size_t k;
762 const char *word, *state;
763 bool found = false;
764
765 truncate_nl(line);
766
767 l = strchr(line, ':');
768 if (!l)
769 continue;
770
771 l++;
772 e = strchr(l, ':');
773 if (!e)
774 continue;
775
776 *e = 0;
777
778 FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
779
780 if (k == cs && memcmp(word, controller, cs) == 0) {
781 found = true;
782 break;
783 }
784
785 if (k == 5 + cs &&
786 memcmp(word, "name=", 5) == 0 &&
787 memcmp(word+5, controller, cs) == 0) {
788 found = true;
789 break;
790 }
791 }
792
793 if (!found)
794 continue;
795
796 p = strdup(e + 1);
797 if (!p)
798 return -ENOMEM;
799
800 *path = p;
801 return 0;
802 }
803
804 return -ENOENT;
805 }
806
807 int cg_install_release_agent(const char *controller, const char *agent) {
808 _cleanup_free_ char *fs = NULL, *contents = NULL;
809 char *sc;
810 int r;
811
812 assert(agent);
813
814 r = cg_get_path(controller, NULL, "release_agent", &fs);
815 if (r < 0)
816 return r;
817
818 r = read_one_line_file(fs, &contents);
819 if (r < 0)
820 return r;
821
822 sc = strstrip(contents);
823 if (sc[0] == 0) {
824 r = write_string_file_no_create(fs, agent);
825 if (r < 0)
826 return r;
827 } else if (!streq(sc, agent))
828 return -EEXIST;
829
830 free(fs);
831 fs = NULL;
832 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
833 if (r < 0)
834 return r;
835
836 free(contents);
837 contents = NULL;
838 r = read_one_line_file(fs, &contents);
839 if (r < 0)
840 return r;
841
842 sc = strstrip(contents);
843 if (streq(sc, "0")) {
844 r = write_string_file_no_create(fs, "1");
845 if (r < 0)
846 return r;
847
848 return 1;
849 }
850
851 if (!streq(sc, "1"))
852 return -EIO;
853
854 return 0;
855 }
856
857 int cg_uninstall_release_agent(const char *controller) {
858 _cleanup_free_ char *fs = NULL;
859 int r;
860
861 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
862 if (r < 0)
863 return r;
864
865 r = write_string_file_no_create(fs, "0");
866 if (r < 0)
867 return r;
868
869 free(fs);
870 fs = NULL;
871
872 r = cg_get_path(controller, NULL, "release_agent", &fs);
873 if (r < 0)
874 return r;
875
876 r = write_string_file_no_create(fs, "");
877 if (r < 0)
878 return r;
879
880 return 0;
881 }
882
883 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
884 _cleanup_fclose_ FILE *f = NULL;
885 pid_t pid = 0, self_pid;
886 bool found = false;
887 int r;
888
889 assert(path);
890
891 r = cg_enumerate_processes(controller, path, &f);
892 if (r < 0)
893 return r == -ENOENT ? 1 : r;
894
895 self_pid = getpid();
896
897 while ((r = cg_read_pid(f, &pid)) > 0) {
898
899 if (ignore_self && pid == self_pid)
900 continue;
901
902 found = true;
903 break;
904 }
905
906 if (r < 0)
907 return r;
908
909 return !found;
910 }
911
912 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
913 _cleanup_closedir_ DIR *d = NULL;
914 char *fn;
915 int r;
916
917 assert(path);
918
919 r = cg_is_empty(controller, path, ignore_self);
920 if (r <= 0)
921 return r;
922
923 r = cg_enumerate_subgroups(controller, path, &d);
924 if (r < 0)
925 return r == -ENOENT ? 1 : r;
926
927 while ((r = cg_read_subgroup(d, &fn)) > 0) {
928 _cleanup_free_ char *p = NULL;
929
930 p = strjoin(path, "/", fn, NULL);
931 free(fn);
932 if (!p)
933 return -ENOMEM;
934
935 r = cg_is_empty_recursive(controller, p, ignore_self);
936 if (r <= 0)
937 return r;
938 }
939
940 if (r < 0)
941 return r;
942
943 return 1;
944 }
945
946 int cg_split_spec(const char *spec, char **controller, char **path) {
947 const char *e;
948 char *t = NULL, *u = NULL;
949 _cleanup_free_ char *v = NULL;
950
951 assert(spec);
952
953 if (*spec == '/') {
954 if (!path_is_safe(spec))
955 return -EINVAL;
956
957 if (path) {
958 t = strdup(spec);
959 if (!t)
960 return -ENOMEM;
961
962 *path = path_kill_slashes(t);
963 }
964
965 if (controller)
966 *controller = NULL;
967
968 return 0;
969 }
970
971 e = strchr(spec, ':');
972 if (!e) {
973 if (!cg_controller_is_valid(spec, true))
974 return -EINVAL;
975
976 if (controller) {
977 t = strdup(normalize_controller(spec));
978 if (!t)
979 return -ENOMEM;
980
981 *controller = t;
982 }
983
984 if (path)
985 *path = NULL;
986
987 return 0;
988 }
989
990 v = strndup(spec, e-spec);
991 if (!v)
992 return -ENOMEM;
993 t = strdup(normalize_controller(v));
994 if (!t)
995 return -ENOMEM;
996 if (!cg_controller_is_valid(t, true)) {
997 free(t);
998 return -EINVAL;
999 }
1000
1001 if (streq(e+1, "")) {
1002 u = strdup("/");
1003 if (!u) {
1004 free(t);
1005 return -ENOMEM;
1006 }
1007 } else {
1008 u = strdup(e+1);
1009 if (!u) {
1010 free(t);
1011 return -ENOMEM;
1012 }
1013
1014 if (!path_is_safe(u) ||
1015 !path_is_absolute(u)) {
1016 free(t);
1017 free(u);
1018 return -EINVAL;
1019 }
1020
1021 path_kill_slashes(u);
1022 }
1023
1024 if (controller)
1025 *controller = t;
1026 else
1027 free(t);
1028
1029 if (path)
1030 *path = u;
1031 else
1032 free(u);
1033
1034 return 0;
1035 }
1036
1037 int cg_mangle_path(const char *path, char **result) {
1038 _cleanup_free_ char *c = NULL, *p = NULL;
1039 char *t;
1040 int r;
1041
1042 assert(path);
1043 assert(result);
1044
1045 /* First, check if it already is a filesystem path */
1046 if (path_startswith(path, "/sys/fs/cgroup")) {
1047
1048 t = strdup(path);
1049 if (!t)
1050 return -ENOMEM;
1051
1052 *result = path_kill_slashes(t);
1053 return 0;
1054 }
1055
1056 /* Otherwise, treat it as cg spec */
1057 r = cg_split_spec(path, &c, &p);
1058 if (r < 0)
1059 return r;
1060
1061 return cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1062 }
1063
1064 int cg_get_root_path(char **path) {
1065 char *p, *e;
1066 int r;
1067
1068 assert(path);
1069
1070 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
1071 if (r < 0)
1072 return r;
1073
1074 e = endswith(p, "/" SPECIAL_SYSTEM_SLICE);
1075 if (e)
1076 *e = 0;
1077
1078 *path = p;
1079 return 0;
1080 }
1081
1082 int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
1083 _cleanup_free_ char *rt = NULL;
1084 char *p;
1085 int r;
1086
1087 assert(cgroup);
1088 assert(shifted);
1089
1090 if (!root) {
1091 /* If the root was specified let's use that, otherwise
1092 * let's determine it from PID 1 */
1093
1094 r = cg_get_root_path(&rt);
1095 if (r < 0)
1096 return r;
1097
1098 root = rt;
1099 }
1100
1101 p = path_startswith(cgroup, root);
1102 if (p)
1103 *shifted = p - 1;
1104 else
1105 *shifted = cgroup;
1106
1107 return 0;
1108 }
1109
1110 int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
1111 _cleanup_free_ char *raw = NULL;
1112 const char *c;
1113 int r;
1114
1115 assert(pid >= 0);
1116 assert(cgroup);
1117
1118 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &raw);
1119 if (r < 0)
1120 return r;
1121
1122 r = cg_shift_path(raw, root, &c);
1123 if (r < 0)
1124 return r;
1125
1126 if (c == raw) {
1127 *cgroup = raw;
1128 raw = NULL;
1129 } else {
1130 char *n;
1131
1132 n = strdup(c);
1133 if (!n)
1134 return -ENOMEM;
1135
1136 *cgroup = n;
1137 }
1138
1139 return 0;
1140 }
1141
1142 int cg_path_decode_unit(const char *cgroup, char **unit){
1143 char *e, *c, *s;
1144
1145 assert(cgroup);
1146 assert(unit);
1147
1148 e = strchrnul(cgroup, '/');
1149 c = strndupa(cgroup, e - cgroup);
1150 c = cg_unescape(c);
1151
1152 if (!unit_name_is_valid(c, TEMPLATE_INVALID))
1153 return -EINVAL;
1154
1155 s = strdup(c);
1156 if (!s)
1157 return -ENOMEM;
1158
1159 *unit = s;
1160 return 0;
1161 }
1162
1163 static const char *skip_slices(const char *p) {
1164 /* Skips over all slice assignments */
1165
1166 for (;;) {
1167 size_t n;
1168
1169 p += strspn(p, "/");
1170
1171 n = strcspn(p, "/");
1172 if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0)
1173 return p;
1174
1175 p += n;
1176 }
1177 }
1178
1179 int cg_path_get_unit(const char *path, char **unit) {
1180 const char *e;
1181
1182 assert(path);
1183 assert(unit);
1184
1185 e = skip_slices(path);
1186
1187 return cg_path_decode_unit(e, unit);
1188 }
1189
1190 int cg_pid_get_unit(pid_t pid, char **unit) {
1191 _cleanup_free_ char *cgroup = NULL;
1192 int r;
1193
1194 assert(unit);
1195
1196 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1197 if (r < 0)
1198 return r;
1199
1200 return cg_path_get_unit(cgroup, unit);
1201 }
1202
1203 /**
1204 * Skip session-*.scope, but require it to be there.
1205 */
1206 static const char *skip_session(const char *p) {
1207 size_t n;
1208
1209 assert(p);
1210
1211 p += strspn(p, "/");
1212
1213 n = strcspn(p, "/");
1214 if (n < strlen("session-x.scope") || memcmp(p, "session-", 8) != 0 || memcmp(p + n - 6, ".scope", 6) != 0)
1215 return NULL;
1216
1217 p += n;
1218 p += strspn(p, "/");
1219
1220 return p;
1221 }
1222
1223 /**
1224 * Skip user@*.service, but require it to be there.
1225 */
1226 static const char *skip_user_manager(const char *p) {
1227 size_t n;
1228
1229 assert(p);
1230
1231 p += strspn(p, "/");
1232
1233 n = strcspn(p, "/");
1234 if (n < strlen("user@x.service") || memcmp(p, "user@", 5) != 0 || memcmp(p + n - 8, ".service", 8) != 0)
1235 return NULL;
1236
1237 p += n;
1238 p += strspn(p, "/");
1239
1240 return p;
1241 }
1242
1243 int cg_path_get_user_unit(const char *path, char **unit) {
1244 const char *e, *t;
1245
1246 assert(path);
1247 assert(unit);
1248
1249 /* We always have to parse the path from the beginning as unit
1250 * cgroups might have arbitrary child cgroups and we shouldn't get
1251 * confused by those */
1252
1253 /* Skip slices, if there are any */
1254 e = skip_slices(path);
1255
1256 /* Skip the session scope or user manager... */
1257 t = skip_session(e);
1258 if (!t)
1259 t = skip_user_manager(e);
1260 if (!t)
1261 return -ENOENT;
1262
1263 /* ... and skip more slices if there are any */
1264 e = skip_slices(t);
1265
1266 return cg_path_decode_unit(e, unit);
1267 }
1268
1269 int cg_pid_get_user_unit(pid_t pid, char **unit) {
1270 _cleanup_free_ char *cgroup = NULL;
1271 int r;
1272
1273 assert(unit);
1274
1275 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1276 if (r < 0)
1277 return r;
1278
1279 return cg_path_get_user_unit(cgroup, unit);
1280 }
1281
1282 int cg_path_get_machine_name(const char *path, char **machine) {
1283 _cleanup_free_ char *u = NULL, *sl = NULL;
1284 int r;
1285
1286 r = cg_path_get_unit(path, &u);
1287 if (r < 0)
1288 return r;
1289
1290 sl = strjoin("/run/systemd/machines/unit:", u, NULL);
1291 if (!sl)
1292 return -ENOMEM;
1293
1294 return readlink_malloc(sl, machine);
1295 }
1296
1297 int cg_pid_get_machine_name(pid_t pid, char **machine) {
1298 _cleanup_free_ char *cgroup = NULL;
1299 int r;
1300
1301 assert(machine);
1302
1303 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1304 if (r < 0)
1305 return r;
1306
1307 return cg_path_get_machine_name(cgroup, machine);
1308 }
1309
1310 int cg_path_get_session(const char *path, char **session) {
1311 const char *e, *n, *x, *y;
1312 char *s;
1313
1314 assert(path);
1315
1316 /* Skip slices, if there are any */
1317 e = skip_slices(path);
1318
1319 n = strchrnul(e, '/');
1320 if (e == n)
1321 return -ENOENT;
1322
1323 s = strndupa(e, n - e);
1324 s = cg_unescape(s);
1325
1326 x = startswith(s, "session-");
1327 if (!x)
1328 return -ENOENT;
1329 y = endswith(x, ".scope");
1330 if (!y || x == y)
1331 return -ENOENT;
1332
1333 if (session) {
1334 char *r;
1335
1336 r = strndup(x, y - x);
1337 if (!r)
1338 return -ENOMEM;
1339
1340 *session = r;
1341 }
1342
1343 return 0;
1344 }
1345
1346 int cg_pid_get_session(pid_t pid, char **session) {
1347 _cleanup_free_ char *cgroup = NULL;
1348 int r;
1349
1350 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1351 if (r < 0)
1352 return r;
1353
1354 return cg_path_get_session(cgroup, session);
1355 }
1356
1357 int cg_path_get_owner_uid(const char *path, uid_t *uid) {
1358 _cleanup_free_ char *slice = NULL;
1359 const char *start, *end;
1360 char *s;
1361 uid_t u;
1362 int r;
1363
1364 assert(path);
1365
1366 r = cg_path_get_slice(path, &slice);
1367 if (r < 0)
1368 return r;
1369
1370 start = startswith(slice, "user-");
1371 if (!start)
1372 return -ENOENT;
1373 end = endswith(slice, ".slice");
1374 if (!end)
1375 return -ENOENT;
1376
1377 s = strndupa(start, end - start);
1378 if (!s)
1379 return -ENOENT;
1380
1381 if (parse_uid(s, &u) < 0)
1382 return -EIO;
1383
1384 if (uid)
1385 *uid = u;
1386
1387 return 0;
1388 }
1389
1390 int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
1391 _cleanup_free_ char *cgroup = NULL;
1392 int r;
1393
1394 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1395 if (r < 0)
1396 return r;
1397
1398 return cg_path_get_owner_uid(cgroup, uid);
1399 }
1400
1401 int cg_path_get_slice(const char *p, char **slice) {
1402 const char *e = NULL;
1403 size_t m = 0;
1404
1405 assert(p);
1406 assert(slice);
1407
1408 for (;;) {
1409 size_t n;
1410
1411 p += strspn(p, "/");
1412
1413 n = strcspn(p, "/");
1414 if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0) {
1415 char *s;
1416
1417 if (!e)
1418 return -ENOENT;
1419
1420 s = strndup(e, m);
1421 if (!s)
1422 return -ENOMEM;
1423
1424 *slice = s;
1425 return 0;
1426 }
1427
1428 e = p;
1429 m = n;
1430
1431 p += n;
1432 }
1433 }
1434
1435 int cg_pid_get_slice(pid_t pid, char **slice) {
1436 _cleanup_free_ char *cgroup = NULL;
1437 int r;
1438
1439 assert(slice);
1440
1441 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1442 if (r < 0)
1443 return r;
1444
1445 return cg_path_get_slice(cgroup, slice);
1446 }
1447
1448 char *cg_escape(const char *p) {
1449 bool need_prefix = false;
1450
1451 /* This implements very minimal escaping for names to be used
1452 * as file names in the cgroup tree: any name which might
1453 * conflict with a kernel name or is prefixed with '_' is
1454 * prefixed with a '_'. That way, when reading cgroup names it
1455 * is sufficient to remove a single prefixing underscore if
1456 * there is one. */
1457
1458 /* The return value of this function (unlike cg_unescape())
1459 * needs free()! */
1460
1461 if (p[0] == 0 ||
1462 p[0] == '_' ||
1463 p[0] == '.' ||
1464 streq(p, "notify_on_release") ||
1465 streq(p, "release_agent") ||
1466 streq(p, "tasks"))
1467 need_prefix = true;
1468 else {
1469 const char *dot;
1470
1471 dot = strrchr(p, '.');
1472 if (dot) {
1473
1474 if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0)
1475 need_prefix = true;
1476 else {
1477 char *n;
1478
1479 n = strndupa(p, dot - p);
1480
1481 if (check_hierarchy(n) >= 0)
1482 need_prefix = true;
1483 }
1484 }
1485 }
1486
1487 if (need_prefix)
1488 return strappend("_", p);
1489 else
1490 return strdup(p);
1491 }
1492
1493 char *cg_unescape(const char *p) {
1494 assert(p);
1495
1496 /* The return value of this function (unlike cg_escape())
1497 * doesn't need free()! */
1498
1499 if (p[0] == '_')
1500 return (char*) p+1;
1501
1502 return (char*) p;
1503 }
1504
1505 #define CONTROLLER_VALID \
1506 DIGITS LETTERS \
1507 "_"
1508
1509 bool cg_controller_is_valid(const char *p, bool allow_named) {
1510 const char *t, *s;
1511
1512 if (!p)
1513 return false;
1514
1515 if (allow_named) {
1516 s = startswith(p, "name=");
1517 if (s)
1518 p = s;
1519 }
1520
1521 if (*p == 0 || *p == '_')
1522 return false;
1523
1524 for (t = p; *t; t++)
1525 if (!strchr(CONTROLLER_VALID, *t))
1526 return false;
1527
1528 if (t - p > FILENAME_MAX)
1529 return false;
1530
1531 return true;
1532 }
1533
1534 int cg_slice_to_path(const char *unit, char **ret) {
1535 _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
1536 const char *dash;
1537
1538 assert(unit);
1539 assert(ret);
1540
1541 if (!unit_name_is_valid(unit, TEMPLATE_INVALID))
1542 return -EINVAL;
1543
1544 if (!endswith(unit, ".slice"))
1545 return -EINVAL;
1546
1547 p = unit_name_to_prefix(unit);
1548 if (!p)
1549 return -ENOMEM;
1550
1551 dash = strchr(p, '-');
1552 while (dash) {
1553 _cleanup_free_ char *escaped = NULL;
1554 char n[dash - p + sizeof(".slice")];
1555
1556 strcpy(stpncpy(n, p, dash - p), ".slice");
1557
1558 if (!unit_name_is_valid(n, TEMPLATE_INVALID))
1559 return -EINVAL;
1560
1561 escaped = cg_escape(n);
1562 if (!escaped)
1563 return -ENOMEM;
1564
1565 if (!strextend(&s, escaped, "/", NULL))
1566 return -ENOMEM;
1567
1568 dash = strchr(dash+1, '-');
1569 }
1570
1571 e = cg_escape(unit);
1572 if (!e)
1573 return -ENOMEM;
1574
1575 if (!strextend(&s, e, NULL))
1576 return -ENOMEM;
1577
1578 *ret = s;
1579 s = NULL;
1580
1581 return 0;
1582 }
1583
1584 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
1585 _cleanup_free_ char *p = NULL;
1586 int r;
1587
1588 r = cg_get_path(controller, path, attribute, &p);
1589 if (r < 0)
1590 return r;
1591
1592 return write_string_file_no_create(p, value);
1593 }
1594
1595 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) {
1596 _cleanup_free_ char *p = NULL;
1597 int r;
1598
1599 r = cg_get_path(controller, path, attribute, &p);
1600 if (r < 0)
1601 return r;
1602
1603 return read_one_line_file(p, ret);
1604 }
1605
1606 static const char mask_names[] =
1607 "cpu\0"
1608 "cpuacct\0"
1609 "blkio\0"
1610 "memory\0"
1611 "devices\0";
1612
1613 int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
1614 CGroupControllerMask bit = 1;
1615 const char *n;
1616 int r;
1617
1618 /* This one will create a cgroup in our private tree, but also
1619 * duplicate it in the trees specified in mask, and remove it
1620 * in all others */
1621
1622 /* First create the cgroup in our own hierarchy. */
1623 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
1624 if (r < 0)
1625 return r;
1626
1627 /* Then, do the same in the other hierarchies */
1628 NULSTR_FOREACH(n, mask_names) {
1629 if (mask & bit)
1630 cg_create(n, path);
1631 else if (supported & bit)
1632 cg_trim(n, path, true);
1633
1634 bit <<= 1;
1635 }
1636
1637 return 0;
1638 }
1639
1640 int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
1641 CGroupControllerMask bit = 1;
1642 const char *n;
1643 int r;
1644
1645 r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
1646 if (r < 0)
1647 return r;
1648
1649 NULSTR_FOREACH(n, mask_names) {
1650
1651 if (supported & bit) {
1652 const char *p = NULL;
1653
1654 if (path_callback)
1655 p = path_callback(bit, userdata);
1656
1657 if (!p)
1658 p = path;
1659
1660 cg_attach_fallback(n, path, pid);
1661 }
1662
1663 bit <<= 1;
1664 }
1665
1666 return 0;
1667 }
1668
1669 int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
1670 Iterator i;
1671 void *pidp;
1672 int r = 0;
1673
1674 SET_FOREACH(pidp, pids, i) {
1675 pid_t pid = PTR_TO_LONG(pidp);
1676 int q;
1677
1678 q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
1679 if (q < 0)
1680 r = q;
1681 }
1682
1683 return r;
1684 }
1685
1686 int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
1687 CGroupControllerMask bit = 1;
1688 const char *n;
1689 int r;
1690
1691 if (!path_equal(from, to)) {
1692 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
1693 if (r < 0)
1694 return r;
1695 }
1696
1697 NULSTR_FOREACH(n, mask_names) {
1698 if (supported & bit) {
1699 const char *p = NULL;
1700
1701 if (to_callback)
1702 p = to_callback(bit, userdata);
1703
1704 if (!p)
1705 p = to;
1706
1707 cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, n, p, false, false);
1708 }
1709
1710 bit <<= 1;
1711 }
1712
1713 return 0;
1714 }
1715
1716 int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
1717 CGroupControllerMask bit = 1;
1718 const char *n;
1719 int r;
1720
1721 r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
1722 if (r < 0)
1723 return r;
1724
1725 NULSTR_FOREACH(n, mask_names) {
1726 if (supported & bit)
1727 cg_trim(n, path, delete_root);
1728
1729 bit <<= 1;
1730 }
1731
1732 return 0;
1733 }
1734
1735 CGroupControllerMask cg_mask_supported(void) {
1736 CGroupControllerMask bit = 1, mask = 0;
1737 const char *n;
1738
1739 NULSTR_FOREACH(n, mask_names) {
1740 if (check_hierarchy(n) >= 0)
1741 mask |= bit;
1742
1743 bit <<= 1;
1744 }
1745
1746 return mask;
1747 }
1748
1749 int cg_kernel_controllers(Set *controllers) {
1750 _cleanup_fclose_ FILE *f = NULL;
1751 char buf[LINE_MAX];
1752 int r;
1753
1754 assert(controllers);
1755
1756 f = fopen("/proc/cgroups", "re");
1757 if (!f) {
1758 if (errno == ENOENT)
1759 return 0;
1760 return -errno;
1761 }
1762
1763 /* Ignore the header line */
1764 (void) fgets(buf, sizeof(buf), f);
1765
1766 for (;;) {
1767 char *controller;
1768 int enabled = 0;
1769
1770 errno = 0;
1771 if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
1772
1773 if (feof(f))
1774 break;
1775
1776 if (ferror(f) && errno)
1777 return -errno;
1778
1779 return -EBADMSG;
1780 }
1781
1782 if (!enabled) {
1783 free(controller);
1784 continue;
1785 }
1786
1787 if (!filename_is_valid(controller)) {
1788 free(controller);
1789 return -EBADMSG;
1790 }
1791
1792 r = set_consume(controllers, controller);
1793 if (r < 0)
1794 return r;
1795 }
1796
1797 return 0;
1798 }