]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/cgroup-util.c
util: unify how we see srand()
[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 "log.h"
34 #include "set.h"
35 #include "macro.h"
36 #include "util.h"
37 #include "path-util.h"
38 #include "strv.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)
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 < 0 ? r : -ENOENT;
494
495 /* Cache this to save a few stat()s */
496 good = true;
497 }
498
499 p = controller ? normalize_controller(controller) : NULL;
500
501 return join_path(p, path, suffix, fs);
502 }
503
504 static int check_hierarchy(const char *p) {
505 char *cc;
506
507 assert(p);
508
509 /* Check if this controller actually really exists */
510 cc = alloca(strlen("/sys/fs/cgroup/") + strlen(p) + 1);
511 strcpy(stpcpy(cc, "/sys/fs/cgroup/"), p);
512 if (access(cc, F_OK) < 0)
513 return -errno;
514
515 return 0;
516 }
517
518 int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
519 const char *p;
520 int r;
521
522 assert(fs);
523
524 if (!cg_controller_is_valid(controller, true))
525 return -EINVAL;
526
527 /* Normalize the controller syntax */
528 p = normalize_controller(controller);
529
530 /* Check if this controller actually really exists */
531 r = check_hierarchy(p);
532 if (r < 0)
533 return r;
534
535 return join_path(p, path, suffix, fs);
536 }
537
538 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
539 assert(path);
540 assert(sb);
541 assert(ftwbuf);
542
543 if (typeflag != FTW_DP)
544 return 0;
545
546 if (ftwbuf->level < 1)
547 return 0;
548
549 rmdir(path);
550 return 0;
551 }
552
553 int cg_trim(const char *controller, const char *path, bool delete_root) {
554 _cleanup_free_ char *fs = NULL;
555 int r = 0;
556
557 assert(path);
558
559 r = cg_get_path(controller, path, NULL, &fs);
560 if (r < 0)
561 return r;
562
563 errno = 0;
564 if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0)
565 r = errno ? -errno : -EIO;
566
567 if (delete_root) {
568 if (rmdir(fs) < 0 && errno != ENOENT)
569 return -errno;
570 }
571
572 return r;
573 }
574
575 int cg_delete(const char *controller, const char *path) {
576 _cleanup_free_ char *parent = NULL;
577 int r;
578
579 assert(path);
580
581 r = path_get_parent(path, &parent);
582 if (r < 0)
583 return r;
584
585 r = cg_migrate_recursive(controller, path, controller, parent, false, true);
586 return r == -ENOENT ? 0 : r;
587 }
588
589 int cg_create(const char *controller, const char *path) {
590 _cleanup_free_ char *fs = NULL;
591 int r;
592
593 r = cg_get_path_and_check(controller, path, NULL, &fs);
594 if (r < 0)
595 return r;
596
597 r = mkdir_parents(fs, 0755);
598 if (r < 0)
599 return r;
600
601 if (mkdir(fs, 0755) < 0) {
602
603 if (errno == EEXIST)
604 return 0;
605
606 return -errno;
607 }
608
609 return 1;
610 }
611
612 int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
613 int r, q;
614
615 assert(pid >= 0);
616
617 r = cg_create(controller, path);
618 if (r < 0)
619 return r;
620
621 q = cg_attach(controller, path, pid);
622 if (q < 0)
623 return q;
624
625 /* This does not remove the cgroup on failure */
626 return r;
627 }
628
629 int cg_attach(const char *controller, const char *path, pid_t pid) {
630 _cleanup_free_ char *fs = NULL;
631 char c[DECIMAL_STR_MAX(pid_t) + 2];
632 int r;
633
634 assert(path);
635 assert(pid >= 0);
636
637 r = cg_get_path_and_check(controller, path, "cgroup.procs", &fs);
638 if (r < 0)
639 return r;
640
641 if (pid == 0)
642 pid = getpid();
643
644 snprintf(c, sizeof(c), PID_FMT"\n", pid);
645
646 return write_string_file_no_create(fs, c);
647 }
648
649 int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
650 int r;
651
652 assert(controller);
653 assert(path);
654 assert(pid >= 0);
655
656 r = cg_attach(controller, path, pid);
657 if (r < 0) {
658 char prefix[strlen(path) + 1];
659
660 /* This didn't work? Then let's try all prefixes of
661 * the destination */
662
663 PATH_FOREACH_PREFIX(prefix, path) {
664 r = cg_attach(controller, prefix, pid);
665 if (r >= 0)
666 break;
667 }
668 }
669
670 return 0;
671 }
672
673 int cg_set_group_access(
674 const char *controller,
675 const char *path,
676 mode_t mode,
677 uid_t uid,
678 gid_t gid) {
679
680 _cleanup_free_ char *fs = NULL;
681 int r;
682
683 assert(path);
684
685 if (mode != (mode_t) -1)
686 mode &= 0777;
687
688 r = cg_get_path(controller, path, NULL, &fs);
689 if (r < 0)
690 return r;
691
692 return chmod_and_chown(fs, mode, uid, gid);
693 }
694
695 int cg_set_task_access(
696 const char *controller,
697 const char *path,
698 mode_t mode,
699 uid_t uid,
700 gid_t gid) {
701
702 _cleanup_free_ char *fs = NULL, *procs = NULL;
703 int r;
704
705 assert(path);
706
707 if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1)
708 return 0;
709
710 if (mode != (mode_t) -1)
711 mode &= 0666;
712
713 r = cg_get_path(controller, path, "cgroup.procs", &fs);
714 if (r < 0)
715 return r;
716
717 r = chmod_and_chown(fs, mode, uid, gid);
718 if (r < 0)
719 return r;
720
721 /* Compatibility, Always keep values for "tasks" in sync with
722 * "cgroup.procs" */
723 r = cg_get_path(controller, path, "tasks", &procs);
724 if (r < 0)
725 return r;
726
727 return chmod_and_chown(procs, mode, uid, gid);
728 }
729
730 int cg_pid_get_path(const char *controller, pid_t pid, char **path) {
731 _cleanup_fclose_ FILE *f = NULL;
732 char line[LINE_MAX];
733 const char *fs;
734 size_t cs;
735
736 assert(path);
737 assert(pid >= 0);
738
739 if (controller) {
740 if (!cg_controller_is_valid(controller, true))
741 return -EINVAL;
742
743 controller = normalize_controller(controller);
744 } else
745 controller = SYSTEMD_CGROUP_CONTROLLER;
746
747 fs = procfs_file_alloca(pid, "cgroup");
748
749 f = fopen(fs, "re");
750 if (!f)
751 return errno == ENOENT ? -ESRCH : -errno;
752
753 cs = strlen(controller);
754
755 FOREACH_LINE(line, f, return -errno) {
756 char *l, *p, *e;
757 size_t k;
758 const char *word, *state;
759 bool found = false;
760
761 truncate_nl(line);
762
763 l = strchr(line, ':');
764 if (!l)
765 continue;
766
767 l++;
768 e = strchr(l, ':');
769 if (!e)
770 continue;
771
772 *e = 0;
773
774 FOREACH_WORD_SEPARATOR(word, k, l, ",", state) {
775
776 if (k == cs && memcmp(word, controller, cs) == 0) {
777 found = true;
778 break;
779 }
780
781 if (k == 5 + cs &&
782 memcmp(word, "name=", 5) == 0 &&
783 memcmp(word+5, controller, cs) == 0) {
784 found = true;
785 break;
786 }
787 }
788
789 if (!found)
790 continue;
791
792 p = strdup(e + 1);
793 if (!p)
794 return -ENOMEM;
795
796 *path = p;
797 return 0;
798 }
799
800 return -ENOENT;
801 }
802
803 int cg_install_release_agent(const char *controller, const char *agent) {
804 _cleanup_free_ char *fs = NULL, *contents = NULL;
805 char *sc;
806 int r;
807
808 assert(agent);
809
810 r = cg_get_path(controller, NULL, "release_agent", &fs);
811 if (r < 0)
812 return r;
813
814 r = read_one_line_file(fs, &contents);
815 if (r < 0)
816 return r;
817
818 sc = strstrip(contents);
819 if (sc[0] == 0) {
820 r = write_string_file_no_create(fs, agent);
821 if (r < 0)
822 return r;
823 } else if (!streq(sc, agent))
824 return -EEXIST;
825
826 free(fs);
827 fs = NULL;
828 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
829 if (r < 0)
830 return r;
831
832 free(contents);
833 contents = NULL;
834 r = read_one_line_file(fs, &contents);
835 if (r < 0)
836 return r;
837
838 sc = strstrip(contents);
839 if (streq(sc, "0")) {
840 r = write_string_file_no_create(fs, "1");
841 if (r < 0)
842 return r;
843
844 return 1;
845 }
846
847 if (!streq(sc, "1"))
848 return -EIO;
849
850 return 0;
851 }
852
853 int cg_uninstall_release_agent(const char *controller) {
854 _cleanup_free_ char *fs = NULL;
855 int r;
856
857 r = cg_get_path(controller, NULL, "notify_on_release", &fs);
858 if (r < 0)
859 return r;
860
861 r = write_string_file_no_create(fs, "0");
862 if (r < 0)
863 return r;
864
865 free(fs);
866 fs = NULL;
867
868 r = cg_get_path(controller, NULL, "release_agent", &fs);
869 if (r < 0)
870 return r;
871
872 r = write_string_file_no_create(fs, "");
873 if (r < 0)
874 return r;
875
876 return 0;
877 }
878
879 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
880 _cleanup_fclose_ FILE *f = NULL;
881 pid_t pid = 0, self_pid;
882 bool found = false;
883 int r;
884
885 assert(path);
886
887 r = cg_enumerate_processes(controller, path, &f);
888 if (r < 0)
889 return r == -ENOENT ? 1 : r;
890
891 self_pid = getpid();
892
893 while ((r = cg_read_pid(f, &pid)) > 0) {
894
895 if (ignore_self && pid == self_pid)
896 continue;
897
898 found = true;
899 break;
900 }
901
902 if (r < 0)
903 return r;
904
905 return !found;
906 }
907
908 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
909 _cleanup_closedir_ DIR *d = NULL;
910 char *fn;
911 int r;
912
913 assert(path);
914
915 r = cg_is_empty(controller, path, ignore_self);
916 if (r <= 0)
917 return r;
918
919 r = cg_enumerate_subgroups(controller, path, &d);
920 if (r < 0)
921 return r == -ENOENT ? 1 : r;
922
923 while ((r = cg_read_subgroup(d, &fn)) > 0) {
924 _cleanup_free_ char *p = NULL;
925
926 p = strjoin(path, "/", fn, NULL);
927 free(fn);
928 if (!p)
929 return -ENOMEM;
930
931 r = cg_is_empty_recursive(controller, p, ignore_self);
932 if (r <= 0)
933 return r;
934 }
935
936 if (r < 0)
937 return r;
938
939 return 1;
940 }
941
942 int cg_split_spec(const char *spec, char **controller, char **path) {
943 const char *e;
944 char *t = NULL, *u = NULL;
945 _cleanup_free_ char *v = NULL;
946
947 assert(spec);
948
949 if (*spec == '/') {
950 if (!path_is_safe(spec))
951 return -EINVAL;
952
953 if (path) {
954 t = strdup(spec);
955 if (!t)
956 return -ENOMEM;
957
958 *path = path_kill_slashes(t);
959 }
960
961 if (controller)
962 *controller = NULL;
963
964 return 0;
965 }
966
967 e = strchr(spec, ':');
968 if (!e) {
969 if (!cg_controller_is_valid(spec, true))
970 return -EINVAL;
971
972 if (controller) {
973 t = strdup(normalize_controller(spec));
974 if (!t)
975 return -ENOMEM;
976
977 *controller = t;
978 }
979
980 if (path)
981 *path = NULL;
982
983 return 0;
984 }
985
986 v = strndup(spec, e-spec);
987 if (!v)
988 return -ENOMEM;
989 t = strdup(normalize_controller(v));
990 if (!t)
991 return -ENOMEM;
992 if (!cg_controller_is_valid(t, true)) {
993 free(t);
994 return -EINVAL;
995 }
996
997 if (streq(e+1, "")) {
998 u = strdup("/");
999 if (!u) {
1000 free(t);
1001 return -ENOMEM;
1002 }
1003 } else {
1004 u = strdup(e+1);
1005 if (!u) {
1006 free(t);
1007 return -ENOMEM;
1008 }
1009
1010 if (!path_is_safe(u) ||
1011 !path_is_absolute(u)) {
1012 free(t);
1013 free(u);
1014 return -EINVAL;
1015 }
1016
1017 path_kill_slashes(u);
1018 }
1019
1020 if (controller)
1021 *controller = t;
1022 else
1023 free(t);
1024
1025 if (path)
1026 *path = u;
1027 else
1028 free(u);
1029
1030 return 0;
1031 }
1032
1033 int cg_mangle_path(const char *path, char **result) {
1034 _cleanup_free_ char *c = NULL, *p = NULL;
1035 char *t;
1036 int r;
1037
1038 assert(path);
1039 assert(result);
1040
1041 /* First, check if it already is a filesystem path */
1042 if (path_startswith(path, "/sys/fs/cgroup")) {
1043
1044 t = strdup(path);
1045 if (!t)
1046 return -ENOMEM;
1047
1048 *result = path_kill_slashes(t);
1049 return 0;
1050 }
1051
1052 /* Otherwise, treat it as cg spec */
1053 r = cg_split_spec(path, &c, &p);
1054 if (r < 0)
1055 return r;
1056
1057 return cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1058 }
1059
1060 int cg_get_root_path(char **path) {
1061 char *p, *e;
1062 int r;
1063
1064 assert(path);
1065
1066 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 1, &p);
1067 if (r < 0)
1068 return r;
1069
1070 e = endswith(p, "/" SPECIAL_SYSTEM_SLICE);
1071 if (e)
1072 *e = 0;
1073
1074 *path = p;
1075 return 0;
1076 }
1077
1078 int cg_shift_path(const char *cgroup, const char *root, const char **shifted) {
1079 _cleanup_free_ char *rt = NULL;
1080 char *p;
1081 int r;
1082
1083 assert(cgroup);
1084 assert(shifted);
1085
1086 if (!root) {
1087 /* If the root was specified let's use that, otherwise
1088 * let's determine it from PID 1 */
1089
1090 r = cg_get_root_path(&rt);
1091 if (r < 0)
1092 return r;
1093
1094 root = rt;
1095 }
1096
1097 p = path_startswith(cgroup, root);
1098 if (p)
1099 *shifted = p - 1;
1100 else
1101 *shifted = cgroup;
1102
1103 return 0;
1104 }
1105
1106 int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
1107 _cleanup_free_ char *raw = NULL;
1108 const char *c;
1109 int r;
1110
1111 assert(pid >= 0);
1112 assert(cgroup);
1113
1114 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &raw);
1115 if (r < 0)
1116 return r;
1117
1118 r = cg_shift_path(raw, root, &c);
1119 if (r < 0)
1120 return r;
1121
1122 if (c == raw) {
1123 *cgroup = raw;
1124 raw = NULL;
1125 } else {
1126 char *n;
1127
1128 n = strdup(c);
1129 if (!n)
1130 return -ENOMEM;
1131
1132 *cgroup = n;
1133 }
1134
1135 return 0;
1136 }
1137
1138 int cg_path_decode_unit(const char *cgroup, char **unit){
1139 char *e, *c, *s;
1140
1141 assert(cgroup);
1142 assert(unit);
1143
1144 e = strchrnul(cgroup, '/');
1145 c = strndupa(cgroup, e - cgroup);
1146 c = cg_unescape(c);
1147
1148 if (!unit_name_is_valid(c, TEMPLATE_INVALID))
1149 return -EINVAL;
1150
1151 s = strdup(c);
1152 if (!s)
1153 return -ENOMEM;
1154
1155 *unit = s;
1156 return 0;
1157 }
1158
1159 static const char *skip_slices(const char *p) {
1160 /* Skips over all slice assignments */
1161
1162 for (;;) {
1163 size_t n;
1164
1165 p += strspn(p, "/");
1166
1167 n = strcspn(p, "/");
1168 if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0)
1169 return p;
1170
1171 p += n;
1172 }
1173 }
1174
1175 int cg_path_get_unit(const char *path, char **unit) {
1176 const char *e;
1177
1178 assert(path);
1179 assert(unit);
1180
1181 e = skip_slices(path);
1182
1183 return cg_path_decode_unit(e, unit);
1184 }
1185
1186 int cg_pid_get_unit(pid_t pid, char **unit) {
1187 _cleanup_free_ char *cgroup = NULL;
1188 int r;
1189
1190 assert(unit);
1191
1192 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1193 if (r < 0)
1194 return r;
1195
1196 return cg_path_get_unit(cgroup, unit);
1197 }
1198
1199 /**
1200 * Skip session-*.scope, but require it to be there.
1201 */
1202 static const char *skip_session(const char *p) {
1203 size_t n;
1204
1205 assert(p);
1206
1207 p += strspn(p, "/");
1208
1209 n = strcspn(p, "/");
1210 if (n < strlen("session-x.scope") || memcmp(p, "session-", 8) != 0 || memcmp(p + n - 6, ".scope", 6) != 0)
1211 return NULL;
1212
1213 p += n;
1214 p += strspn(p, "/");
1215
1216 return p;
1217 }
1218
1219 /**
1220 * Skip user@*.service, but require it to be there.
1221 */
1222 static const char *skip_user_manager(const char *p) {
1223 size_t n;
1224
1225 assert(p);
1226
1227 p += strspn(p, "/");
1228
1229 n = strcspn(p, "/");
1230 if (n < strlen("user@x.service") || memcmp(p, "user@", 5) != 0 || memcmp(p + n - 8, ".service", 8) != 0)
1231 return NULL;
1232
1233 p += n;
1234 p += strspn(p, "/");
1235
1236 return p;
1237 }
1238
1239 int cg_path_get_user_unit(const char *path, char **unit) {
1240 const char *e, *t;
1241
1242 assert(path);
1243 assert(unit);
1244
1245 /* We always have to parse the path from the beginning as unit
1246 * cgroups might have arbitrary child cgroups and we shouldn't get
1247 * confused by those */
1248
1249 /* Skip slices, if there are any */
1250 e = skip_slices(path);
1251
1252 /* Skip the session scope... */
1253 t = skip_session(e);
1254 if (t)
1255 /* ... and skip more slices if there's one */
1256 e = skip_slices(t);
1257 else {
1258 /* ... or require a user manager unit to be there */
1259 e = skip_user_manager(e);
1260 if (!e)
1261 return -ENOENT;
1262 }
1263
1264 return cg_path_decode_unit(e, unit);
1265 }
1266
1267 int cg_pid_get_user_unit(pid_t pid, char **unit) {
1268 _cleanup_free_ char *cgroup = NULL;
1269 int r;
1270
1271 assert(unit);
1272
1273 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1274 if (r < 0)
1275 return r;
1276
1277 return cg_path_get_user_unit(cgroup, unit);
1278 }
1279
1280 int cg_path_get_machine_name(const char *path, char **machine) {
1281 _cleanup_free_ char *u = NULL, *sl = NULL;
1282 int r;
1283
1284 r = cg_path_get_unit(path, &u);
1285 if (r < 0)
1286 return r;
1287
1288 sl = strjoin("/run/systemd/machines/unit:", u, NULL);
1289 if (!sl)
1290 return -ENOMEM;
1291
1292 return readlink_malloc(sl, machine);
1293 }
1294
1295 int cg_pid_get_machine_name(pid_t pid, char **machine) {
1296 _cleanup_free_ char *cgroup = NULL;
1297 int r;
1298
1299 assert(machine);
1300
1301 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1302 if (r < 0)
1303 return r;
1304
1305 return cg_path_get_machine_name(cgroup, machine);
1306 }
1307
1308 int cg_path_get_session(const char *path, char **session) {
1309 const char *e, *n, *x, *y;
1310 char *s;
1311
1312 assert(path);
1313
1314 /* Skip slices, if there are any */
1315 e = skip_slices(path);
1316
1317 n = strchrnul(e, '/');
1318 if (e == n)
1319 return -ENOENT;
1320
1321 s = strndupa(e, n - e);
1322 s = cg_unescape(s);
1323
1324 x = startswith(s, "session-");
1325 if (!x)
1326 return -ENOENT;
1327 y = endswith(x, ".scope");
1328 if (!y || x == y)
1329 return -ENOENT;
1330
1331 if (session) {
1332 char *r;
1333
1334 r = strndup(x, y - x);
1335 if (!r)
1336 return -ENOMEM;
1337
1338 *session = r;
1339 }
1340
1341 return 0;
1342 }
1343
1344 int cg_pid_get_session(pid_t pid, char **session) {
1345 _cleanup_free_ char *cgroup = NULL;
1346 int r;
1347
1348 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1349 if (r < 0)
1350 return r;
1351
1352 return cg_path_get_session(cgroup, session);
1353 }
1354
1355 int cg_path_get_owner_uid(const char *path, uid_t *uid) {
1356 _cleanup_free_ char *slice = NULL;
1357 const char *start, *end;
1358 char *s;
1359 uid_t u;
1360 int r;
1361
1362 assert(path);
1363
1364 r = cg_path_get_slice(path, &slice);
1365 if (r < 0)
1366 return r;
1367
1368 start = startswith(slice, "user-");
1369 if (!start)
1370 return -ENOENT;
1371 end = endswith(slice, ".slice");
1372 if (!end)
1373 return -ENOENT;
1374
1375 s = strndupa(start, end - start);
1376 if (!s)
1377 return -ENOENT;
1378
1379 if (parse_uid(s, &u) < 0)
1380 return -EIO;
1381
1382 if (uid)
1383 *uid = u;
1384
1385 return 0;
1386 }
1387
1388 int cg_pid_get_owner_uid(pid_t pid, uid_t *uid) {
1389 _cleanup_free_ char *cgroup = NULL;
1390 int r;
1391
1392 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1393 if (r < 0)
1394 return r;
1395
1396 return cg_path_get_owner_uid(cgroup, uid);
1397 }
1398
1399 int cg_path_get_slice(const char *p, char **slice) {
1400 const char *e = NULL;
1401 size_t m = 0;
1402
1403 assert(p);
1404 assert(slice);
1405
1406 for (;;) {
1407 size_t n;
1408
1409 p += strspn(p, "/");
1410
1411 n = strcspn(p, "/");
1412 if (n <= 6 || memcmp(p + n - 6, ".slice", 6) != 0) {
1413 char *s;
1414
1415 if (!e)
1416 return -ENOENT;
1417
1418 s = strndup(e, m);
1419 if (!s)
1420 return -ENOMEM;
1421
1422 *slice = s;
1423 return 0;
1424 }
1425
1426 e = p;
1427 m = n;
1428
1429 p += n;
1430 }
1431 }
1432
1433 int cg_pid_get_slice(pid_t pid, char **slice) {
1434 _cleanup_free_ char *cgroup = NULL;
1435 int r;
1436
1437 assert(slice);
1438
1439 r = cg_pid_get_path_shifted(pid, NULL, &cgroup);
1440 if (r < 0)
1441 return r;
1442
1443 return cg_path_get_slice(cgroup, slice);
1444 }
1445
1446 char *cg_escape(const char *p) {
1447 bool need_prefix = false;
1448
1449 /* This implements very minimal escaping for names to be used
1450 * as file names in the cgroup tree: any name which might
1451 * conflict with a kernel name or is prefixed with '_' is
1452 * prefixed with a '_'. That way, when reading cgroup names it
1453 * is sufficient to remove a single prefixing underscore if
1454 * there is one. */
1455
1456 /* The return value of this function (unlike cg_unescape())
1457 * needs free()! */
1458
1459 if (p[0] == 0 ||
1460 p[0] == '_' ||
1461 p[0] == '.' ||
1462 streq(p, "notify_on_release") ||
1463 streq(p, "release_agent") ||
1464 streq(p, "tasks"))
1465 need_prefix = true;
1466 else {
1467 const char *dot;
1468
1469 dot = strrchr(p, '.');
1470 if (dot) {
1471
1472 if (dot - p == 6 && memcmp(p, "cgroup", 6) == 0)
1473 need_prefix = true;
1474 else {
1475 char *n;
1476
1477 n = strndupa(p, dot - p);
1478
1479 if (check_hierarchy(n) >= 0)
1480 need_prefix = true;
1481 }
1482 }
1483 }
1484
1485 if (need_prefix)
1486 return strappend("_", p);
1487 else
1488 return strdup(p);
1489 }
1490
1491 char *cg_unescape(const char *p) {
1492 assert(p);
1493
1494 /* The return value of this function (unlike cg_escape())
1495 * doesn't need free()! */
1496
1497 if (p[0] == '_')
1498 return (char*) p+1;
1499
1500 return (char*) p;
1501 }
1502
1503 #define CONTROLLER_VALID \
1504 DIGITS LETTERS \
1505 "_"
1506
1507 bool cg_controller_is_valid(const char *p, bool allow_named) {
1508 const char *t, *s;
1509
1510 if (!p)
1511 return false;
1512
1513 if (allow_named) {
1514 s = startswith(p, "name=");
1515 if (s)
1516 p = s;
1517 }
1518
1519 if (*p == 0 || *p == '_')
1520 return false;
1521
1522 for (t = p; *t; t++)
1523 if (!strchr(CONTROLLER_VALID, *t))
1524 return false;
1525
1526 if (t - p > FILENAME_MAX)
1527 return false;
1528
1529 return true;
1530 }
1531
1532 int cg_slice_to_path(const char *unit, char **ret) {
1533 _cleanup_free_ char *p = NULL, *s = NULL, *e = NULL;
1534 const char *dash;
1535
1536 assert(unit);
1537 assert(ret);
1538
1539 if (!unit_name_is_valid(unit, TEMPLATE_INVALID))
1540 return -EINVAL;
1541
1542 if (!endswith(unit, ".slice"))
1543 return -EINVAL;
1544
1545 p = unit_name_to_prefix(unit);
1546 if (!p)
1547 return -ENOMEM;
1548
1549 dash = strchr(p, '-');
1550 while (dash) {
1551 _cleanup_free_ char *escaped = NULL;
1552 char n[dash - p + sizeof(".slice")];
1553
1554 strcpy(stpncpy(n, p, dash - p), ".slice");
1555
1556 if (!unit_name_is_valid(n, TEMPLATE_INVALID))
1557 return -EINVAL;
1558
1559 escaped = cg_escape(n);
1560 if (!escaped)
1561 return -ENOMEM;
1562
1563 if (!strextend(&s, escaped, "/", NULL))
1564 return -ENOMEM;
1565
1566 dash = strchr(dash+1, '-');
1567 }
1568
1569 e = cg_escape(unit);
1570 if (!e)
1571 return -ENOMEM;
1572
1573 if (!strextend(&s, e, NULL))
1574 return -ENOMEM;
1575
1576 *ret = s;
1577 s = NULL;
1578
1579 return 0;
1580 }
1581
1582 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value) {
1583 _cleanup_free_ char *p = NULL;
1584 int r;
1585
1586 r = cg_get_path(controller, path, attribute, &p);
1587 if (r < 0)
1588 return r;
1589
1590 return write_string_file_no_create(p, value);
1591 }
1592
1593 static const char mask_names[] =
1594 "cpu\0"
1595 "cpuacct\0"
1596 "blkio\0"
1597 "memory\0"
1598 "devices\0";
1599
1600 int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path) {
1601 CGroupControllerMask bit = 1;
1602 const char *n;
1603 int r;
1604
1605 /* This one will create a cgroup in our private tree, but also
1606 * duplicate it in the trees specified in mask, and remove it
1607 * in all others */
1608
1609 /* First create the cgroup in our own hierarchy. */
1610 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
1611 if (r < 0)
1612 return r;
1613
1614 /* Then, do the same in the other hierarchies */
1615 NULSTR_FOREACH(n, mask_names) {
1616 if (mask & bit)
1617 cg_create(n, path);
1618 else if (supported & bit)
1619 cg_trim(n, path, true);
1620
1621 bit <<= 1;
1622 }
1623
1624 return 0;
1625 }
1626
1627 int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid) {
1628 CGroupControllerMask bit = 1;
1629 const char *n;
1630 int r;
1631
1632 r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
1633 if (r < 0)
1634 return r;
1635
1636 NULSTR_FOREACH(n, mask_names) {
1637 if (supported & bit)
1638 cg_attach_fallback(n, path, pid);
1639
1640 bit <<= 1;
1641 }
1642
1643 return 0;
1644 }
1645
1646 int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids) {
1647 Iterator i;
1648 void *pidp;
1649 int r = 0;
1650
1651 SET_FOREACH(pidp, pids, i) {
1652 pid_t pid = PTR_TO_LONG(pidp);
1653 int q;
1654
1655 q = cg_attach_everywhere(supported, path, pid);
1656 if (q < 0)
1657 r = q;
1658 }
1659
1660 return r;
1661 }
1662
1663 int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
1664 CGroupControllerMask bit = 1;
1665 const char *n;
1666 int r;
1667
1668 if (!path_equal(from, to)) {
1669 r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
1670 if (r < 0)
1671 return r;
1672 }
1673
1674 NULSTR_FOREACH(n, mask_names) {
1675 if (supported & bit) {
1676 const char *p = NULL;
1677
1678 if (to_callback)
1679 p = to_callback(bit, userdata);
1680
1681 if (!p)
1682 p = to;
1683
1684 cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, n, p, false, false);
1685 }
1686
1687 bit <<= 1;
1688 }
1689
1690 return 0;
1691 }
1692
1693 int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root) {
1694 CGroupControllerMask bit = 1;
1695 const char *n;
1696 int r;
1697
1698 r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
1699 if (r < 0)
1700 return r;
1701
1702 NULSTR_FOREACH(n, mask_names) {
1703 if (supported & bit)
1704 cg_trim(n, path, delete_root);
1705
1706 bit <<= 1;
1707 }
1708
1709 return 0;
1710 }
1711
1712 CGroupControllerMask cg_mask_supported(void) {
1713 CGroupControllerMask bit = 1, mask = 0;
1714 const char *n;
1715
1716 NULSTR_FOREACH(n, mask_names) {
1717 if (check_hierarchy(n) >= 0)
1718 mask |= bit;
1719
1720 bit <<= 1;
1721 }
1722
1723 return mask;
1724 }