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