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