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