]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cgroup-util.c
exec: introduce ControlGroupPersistant= to make cgroups persistant
[thirdparty/systemd.git] / src / 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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU 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
38 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
39 char *fs;
40 int r;
41 FILE *f;
42
43 assert(controller);
44 assert(path);
45 assert(_f);
46
47 if ((r = cg_get_path(controller, path, "cgroup.procs", &fs)) < 0)
48 return r;
49
50 f = fopen(fs, "re");
51 free(fs);
52
53 if (!f)
54 return -errno;
55
56 *_f = f;
57 return 0;
58 }
59
60 int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
61 char *fs;
62 int r;
63 FILE *f;
64
65 assert(controller);
66 assert(path);
67 assert(_f);
68
69 if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
70 return r;
71
72 f = fopen(fs, "re");
73 free(fs);
74
75 if (!f)
76 return -errno;
77
78 *_f = f;
79 return 0;
80 }
81
82 int cg_read_pid(FILE *f, pid_t *_pid) {
83 unsigned long ul;
84
85 /* Note that the cgroup.procs might contain duplicates! See
86 * cgroups.txt for details. */
87
88 errno = 0;
89 if (fscanf(f, "%lu", &ul) != 1) {
90
91 if (feof(f))
92 return 0;
93
94 return errno ? -errno : -EIO;
95 }
96
97 if (ul <= 0)
98 return -EIO;
99
100 *_pid = (pid_t) ul;
101 return 1;
102 }
103
104 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
105 char *fs;
106 int r;
107 DIR *d;
108
109 assert(controller);
110 assert(path);
111 assert(_d);
112
113 /* This is not recursive! */
114
115 if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
116 return r;
117
118 d = opendir(fs);
119 free(fs);
120
121 if (!d)
122 return -errno;
123
124 *_d = d;
125 return 0;
126 }
127
128 int cg_read_subgroup(DIR *d, char **fn) {
129 struct dirent *de;
130
131 assert(d);
132
133 errno = 0;
134 while ((de = readdir(d))) {
135 char *b;
136
137 if (de->d_type != DT_DIR)
138 continue;
139
140 if (streq(de->d_name, ".") ||
141 streq(de->d_name, ".."))
142 continue;
143
144 if (!(b = strdup(de->d_name)))
145 return -ENOMEM;
146
147 *fn = b;
148 return 1;
149 }
150
151 if (errno)
152 return -errno;
153
154 return 0;
155 }
156
157 int cg_rmdir(const char *controller, const char *path, bool honour_sticky) {
158 char *p;
159 int r;
160
161 r = cg_get_path(controller, path, NULL, &p);
162 if (r < 0)
163 return r;
164
165 if (honour_sticky) {
166 char *tasks;
167
168 /* If the sticky bit is set don't remove the directory */
169
170 tasks = strappend(p, "/tasks");
171 if (!tasks) {
172 free(p);
173 return -ENOMEM;
174 }
175
176 r = file_is_priv_sticky(tasks);
177 free(tasks);
178
179 if (r > 0) {
180 free(p);
181 return 0;
182 }
183 }
184
185 r = rmdir(p);
186 free(p);
187
188 return (r < 0 && errno != ENOENT) ? -errno : 0;
189 }
190
191 int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
192 bool done = false;
193 int r, ret = 0;
194 pid_t my_pid;
195 FILE *f = NULL;
196 Set *allocated_set = NULL;
197
198 assert(controller);
199 assert(path);
200 assert(sig >= 0);
201
202 /* This goes through the tasks list and kills them all. This
203 * is repeated until no further processes are added to the
204 * tasks list, to properly handle forking processes */
205
206 if (!s)
207 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
208 return -ENOMEM;
209
210 my_pid = getpid();
211
212 do {
213 pid_t pid = 0;
214 done = true;
215
216 if ((r = cg_enumerate_processes(controller, path, &f)) < 0) {
217 if (ret >= 0 && r != -ENOENT)
218 ret = r;
219
220 goto finish;
221 }
222
223 while ((r = cg_read_pid(f, &pid)) > 0) {
224
225 if (pid == my_pid && ignore_self)
226 continue;
227
228 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
229 continue;
230
231 /* If we haven't killed this process yet, kill
232 * it */
233 if (kill(pid, sig) < 0) {
234 if (ret >= 0 && errno != ESRCH)
235 ret = -errno;
236 } else if (ret == 0) {
237
238 if (sigcont)
239 kill(pid, SIGCONT);
240
241 ret = 1;
242 }
243
244 done = false;
245
246 if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) {
247 if (ret >= 0)
248 ret = r;
249
250 goto finish;
251 }
252 }
253
254 if (r < 0) {
255 if (ret >= 0)
256 ret = r;
257
258 goto finish;
259 }
260
261 fclose(f);
262 f = NULL;
263
264 /* To avoid racing against processes which fork
265 * quicker than we can kill them we repeat this until
266 * no new pids need to be killed. */
267
268 } while (!done);
269
270 finish:
271 if (allocated_set)
272 set_free(allocated_set);
273
274 if (f)
275 fclose(f);
276
277 return ret;
278 }
279
280 int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
281 int r, ret = 0;
282 DIR *d = NULL;
283 char *fn;
284 Set *allocated_set = NULL;
285
286 assert(path);
287 assert(controller);
288 assert(sig >= 0);
289
290 if (!s)
291 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
292 return -ENOMEM;
293
294 ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
295
296 if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0) {
297 if (ret >= 0 && r != -ENOENT)
298 ret = r;
299
300 goto finish;
301 }
302
303 while ((r = cg_read_subgroup(d, &fn)) > 0) {
304 char *p = NULL;
305
306 r = asprintf(&p, "%s/%s", path, fn);
307 free(fn);
308
309 if (r < 0) {
310 if (ret >= 0)
311 ret = -ENOMEM;
312
313 goto finish;
314 }
315
316 r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
317 free(p);
318
319 if (r != 0 && ret >= 0)
320 ret = r;
321 }
322
323 if (r < 0 && ret >= 0)
324 ret = r;
325
326 if (rem)
327 if ((r = cg_rmdir(controller, path, true)) < 0) {
328 if (ret >= 0 &&
329 r != -ENOENT &&
330 r != -EBUSY)
331 ret = r;
332 }
333
334 finish:
335 if (d)
336 closedir(d);
337
338 if (allocated_set)
339 set_free(allocated_set);
340
341 return ret;
342 }
343
344 int cg_kill_recursive_and_wait(const char *controller, const char *path, bool rem) {
345 unsigned i;
346
347 assert(path);
348 assert(controller);
349
350 /* This safely kills all processes; first it sends a SIGTERM,
351 * then checks 8 times after 200ms whether the group is now
352 * empty, then kills everything that is left with SIGKILL and
353 * finally checks 5 times after 200ms each whether the group
354 * is finally empty. */
355
356 for (i = 0; i < 15; i++) {
357 int sig, r;
358
359 if (i <= 0)
360 sig = SIGTERM;
361 else if (i == 9)
362 sig = SIGKILL;
363 else
364 sig = 0;
365
366 if ((r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL)) <= 0)
367 return r;
368
369 usleep(200 * USEC_PER_MSEC);
370 }
371
372 return 0;
373 }
374
375 int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self) {
376 bool done = false;
377 Set *s;
378 int r, ret = 0;
379 pid_t my_pid;
380 FILE *f = NULL;
381
382 assert(controller);
383 assert(from);
384 assert(to);
385
386 if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
387 return -ENOMEM;
388
389 my_pid = getpid();
390
391 do {
392 pid_t pid = 0;
393 done = true;
394
395 if ((r = cg_enumerate_tasks(controller, from, &f)) < 0) {
396 if (ret >= 0 && r != -ENOENT)
397 ret = r;
398
399 goto finish;
400 }
401
402 while ((r = cg_read_pid(f, &pid)) > 0) {
403
404 /* This might do weird stuff if we aren't a
405 * single-threaded program. However, we
406 * luckily know we are not */
407 if (pid == my_pid && ignore_self)
408 continue;
409
410 if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
411 continue;
412
413 if ((r = cg_attach(controller, to, pid)) < 0) {
414 if (ret >= 0 && r != -ESRCH)
415 ret = r;
416 } else if (ret == 0)
417 ret = 1;
418
419 done = false;
420
421 if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) {
422 if (ret >= 0)
423 ret = r;
424
425 goto finish;
426 }
427 }
428
429 if (r < 0) {
430 if (ret >= 0)
431 ret = r;
432
433 goto finish;
434 }
435
436 fclose(f);
437 f = NULL;
438
439 } while (!done);
440
441 finish:
442 set_free(s);
443
444 if (f)
445 fclose(f);
446
447 return ret;
448 }
449
450 int cg_migrate_recursive(const char *controller, const char *from, const char *to, bool ignore_self, bool rem) {
451 int r, ret = 0;
452 DIR *d = NULL;
453 char *fn;
454
455 assert(controller);
456 assert(from);
457 assert(to);
458
459 ret = cg_migrate(controller, from, to, ignore_self);
460
461 if ((r = cg_enumerate_subgroups(controller, from, &d)) < 0) {
462 if (ret >= 0 && r != -ENOENT)
463 ret = r;
464 goto finish;
465 }
466
467 while ((r = cg_read_subgroup(d, &fn)) > 0) {
468 char *p = NULL;
469
470 r = asprintf(&p, "%s/%s", from, fn);
471 free(fn);
472
473 if (r < 0) {
474 if (ret >= 0)
475 ret = -ENOMEM;
476
477 goto finish;
478 }
479
480 r = cg_migrate_recursive(controller, p, to, ignore_self, rem);
481 free(p);
482
483 if (r != 0 && ret >= 0)
484 ret = r;
485 }
486
487 if (r < 0 && ret >= 0)
488 ret = r;
489
490 if (rem)
491 if ((r = cg_rmdir(controller, from, true)) < 0) {
492 if (ret >= 0 &&
493 r != -ENOENT &&
494 r != -EBUSY)
495 ret = r;
496 }
497
498 finish:
499 if (d)
500 closedir(d);
501
502 return ret;
503 }
504
505 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
506 const char *p;
507 char *t;
508 static __thread bool good = false;
509
510 assert(controller);
511 assert(fs);
512
513 if (_unlikely_(!good)) {
514 int r;
515
516 r = path_is_mount_point("/sys/fs/cgroup", false);
517 if (r <= 0)
518 return r < 0 ? r : -ENOENT;
519
520 /* Cache this to save a few stat()s */
521 good = true;
522 }
523
524 if (isempty(controller))
525 return -EINVAL;
526
527 /* This is a very minimal lookup from controller names to
528 * paths. Since we have mounted most hierarchies ourselves
529 * should be kinda safe, but eventually we might want to
530 * extend this to have a fallback to actually check
531 * /proc/mounts. Might need caching then. */
532
533 if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
534 p = "systemd";
535 else if (startswith(controller, "name="))
536 p = controller + 5;
537 else
538 p = controller;
539
540 if (path && suffix)
541 t = join("/sys/fs/cgroup/", p, "/", path, "/", suffix, NULL);
542 else if (path)
543 t = join("/sys/fs/cgroup/", p, "/", path, NULL);
544 else if (suffix)
545 t = join("/sys/fs/cgroup/", p, "/", suffix, NULL);
546 else
547 t = join("/sys/fs/cgroup/", p, NULL);
548
549 if (!t)
550 return -ENOMEM;
551
552 path_kill_slashes(t);
553
554 *fs = t;
555 return 0;
556 }
557
558 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
559 char *p;
560 bool is_sticky;
561
562 if (typeflag != FTW_DP)
563 return 0;
564
565 if (ftwbuf->level < 1)
566 return 0;
567
568 p = strappend(path, "/tasks");
569 if (!p) {
570 errno = ENOMEM;
571 return 1;
572 }
573
574 is_sticky = file_is_priv_sticky(p) > 0;
575 free(p);
576
577 if (is_sticky)
578 return 0;
579
580 rmdir(path);
581 return 0;
582 }
583
584 int cg_trim(const char *controller, const char *path, bool delete_root) {
585 char *fs;
586 int r = 0;
587
588 assert(controller);
589 assert(path);
590
591 r = cg_get_path(controller, path, NULL, &fs);
592 if (r < 0)
593 return r;
594
595 errno = 0;
596 if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
597 r = errno ? -errno : -EIO;
598
599 if (delete_root) {
600 bool is_sticky;
601 char *p;
602
603 p = strappend(fs, "/tasks");
604 if (!p) {
605 free(fs);
606 return -ENOMEM;
607 }
608
609 is_sticky = file_is_priv_sticky(p) > 0;
610 free(p);
611
612 if (!is_sticky)
613 if (rmdir(fs) < 0 && errno != ENOENT) {
614 if (r == 0)
615 r = -errno;
616 }
617 }
618
619 free(fs);
620
621 return r;
622 }
623
624 int cg_delete(const char *controller, const char *path) {
625 char *parent;
626 int r;
627
628 assert(controller);
629 assert(path);
630
631 if ((r = parent_of_path(path, &parent)) < 0)
632 return r;
633
634 r = cg_migrate_recursive(controller, path, parent, false, true);
635 free(parent);
636
637 return r == -ENOENT ? 0 : r;
638 }
639
640 int cg_create(const char *controller, const char *path) {
641 char *fs;
642 int r;
643
644 assert(controller);
645 assert(path);
646
647 if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
648 return r;
649
650 r = mkdir_parents(fs, 0755);
651
652 if (r >= 0) {
653 if (mkdir(fs, 0755) >= 0)
654 r = 1;
655 else if (errno == EEXIST)
656 r = 0;
657 else
658 r = -errno;
659 }
660
661 free(fs);
662
663 return r;
664 }
665
666 int cg_attach(const char *controller, const char *path, pid_t pid) {
667 char *fs;
668 int r;
669 char c[32];
670
671 assert(controller);
672 assert(path);
673 assert(pid >= 0);
674
675 if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
676 return r;
677
678 if (pid == 0)
679 pid = getpid();
680
681 snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid);
682 char_array_0(c);
683
684 r = write_one_line_file(fs, c);
685 free(fs);
686
687 return r;
688 }
689
690 int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
691 int r, q;
692
693 assert(controller);
694 assert(path);
695 assert(pid >= 0);
696
697 if ((r = cg_create(controller, path)) < 0)
698 return r;
699
700 if ((q = cg_attach(controller, path, pid)) < 0)
701 return q;
702
703 /* This does not remove the cgroup on failure */
704
705 return r;
706 }
707
708 int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
709 char *fs;
710 int r;
711
712 assert(controller);
713 assert(path);
714
715 if (mode != (mode_t) -1)
716 mode &= 0777;
717
718 r = cg_get_path(controller, path, NULL, &fs);
719 if (r < 0)
720 return r;
721
722 r = chmod_and_chown(fs, mode, uid, gid);
723 free(fs);
724
725 return r;
726 }
727
728 int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid, int sticky) {
729 char *fs;
730 int r;
731
732 assert(controller);
733 assert(path);
734
735 if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1 && sticky < 0)
736 return 0;
737
738 if (mode != (mode_t) -1)
739 mode &= 0666;
740
741 r = cg_get_path(controller, path, "tasks", &fs);
742 if (r < 0)
743 return r;
744
745 if (sticky >= 0 && mode != (mode_t) -1)
746 /* Both mode and sticky param are passed */
747 mode |= (sticky ? S_ISVTX : 0);
748 else if ((sticky >= 0 && mode == (mode_t) -1) ||
749 (mode != (mode_t) -1 && sticky < 0)) {
750 struct stat st;
751
752 /* Only one param is passed, hence read the current
753 * mode from the file itself */
754
755 r = lstat(fs, &st);
756 if (r < 0) {
757 free(fs);
758 return -errno;
759 }
760
761 if (mode == (mode_t) -1)
762 /* No mode set, we just shall set the sticky bit */
763 mode = (st.st_mode & ~S_ISVTX) | (sticky ? S_ISVTX : 0);
764 else
765 /* Only mode set, leave sticky bit untouched */
766 mode = (st.st_mode & ~0777) | mode;
767 }
768
769 r = chmod_and_chown(fs, mode, uid, gid);
770 free(fs);
771
772 return r;
773 }
774
775 int cg_get_by_pid(const char *controller, pid_t pid, char **path) {
776 int r;
777 char *p = NULL;
778 FILE *f;
779 char *fs;
780 size_t cs;
781
782 assert(controller);
783 assert(path);
784 assert(pid >= 0);
785
786 if (pid == 0)
787 pid = getpid();
788
789 if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0)
790 return -ENOMEM;
791
792 f = fopen(fs, "re");
793 free(fs);
794
795 if (!f)
796 return errno == ENOENT ? -ESRCH : -errno;
797
798 cs = strlen(controller);
799
800 while (!feof(f)) {
801 char line[LINE_MAX];
802 char *l;
803
804 errno = 0;
805 if (!(fgets(line, sizeof(line), f))) {
806 if (feof(f))
807 break;
808
809 r = errno ? -errno : -EIO;
810 goto finish;
811 }
812
813 truncate_nl(line);
814
815 if (!(l = strchr(line, ':')))
816 continue;
817
818 l++;
819 if (strncmp(l, controller, cs) != 0)
820 continue;
821
822 if (l[cs] != ':')
823 continue;
824
825 if (!(p = strdup(l + cs + 1))) {
826 r = -ENOMEM;
827 goto finish;
828 }
829
830 *path = p;
831 r = 0;
832 goto finish;
833 }
834
835 r = -ENOENT;
836
837 finish:
838 fclose(f);
839
840 return r;
841 }
842
843 int cg_install_release_agent(const char *controller, const char *agent) {
844 char *fs = NULL, *contents = NULL, *line = NULL, *sc;
845 int r;
846
847 assert(controller);
848 assert(agent);
849
850 if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0)
851 return r;
852
853 if ((r = read_one_line_file(fs, &contents)) < 0)
854 goto finish;
855
856 sc = strstrip(contents);
857 if (sc[0] == 0) {
858
859 if (asprintf(&line, "%s\n", agent) < 0) {
860 r = -ENOMEM;
861 goto finish;
862 }
863
864 if ((r = write_one_line_file(fs, line)) < 0)
865 goto finish;
866
867 } else if (!streq(sc, agent)) {
868 r = -EEXIST;
869 goto finish;
870 }
871
872 free(fs);
873 fs = NULL;
874 if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0)
875 goto finish;
876
877 free(contents);
878 contents = NULL;
879 if ((r = read_one_line_file(fs, &contents)) < 0)
880 goto finish;
881
882 sc = strstrip(contents);
883
884 if (streq(sc, "0")) {
885 if ((r = write_one_line_file(fs, "1\n")) < 0)
886 goto finish;
887
888 r = 1;
889 } else if (!streq(sc, "1")) {
890 r = -EIO;
891 goto finish;
892 } else
893 r = 0;
894
895 finish:
896 free(fs);
897 free(contents);
898 free(line);
899
900 return r;
901 }
902
903 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
904 pid_t pid = 0;
905 int r;
906 FILE *f = NULL;
907 bool found = false;
908
909 assert(controller);
910 assert(path);
911
912 if ((r = cg_enumerate_tasks(controller, path, &f)) < 0)
913 return r == -ENOENT ? 1 : r;
914
915 while ((r = cg_read_pid(f, &pid)) > 0) {
916
917 if (ignore_self && pid == getpid())
918 continue;
919
920 found = true;
921 break;
922 }
923
924 fclose(f);
925
926 if (r < 0)
927 return r;
928
929 return !found;
930 }
931
932 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
933 int r;
934 DIR *d = NULL;
935 char *fn;
936
937 assert(controller);
938 assert(path);
939
940 if ((r = cg_is_empty(controller, path, ignore_self)) <= 0)
941 return r;
942
943 if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0)
944 return r == -ENOENT ? 1 : r;
945
946 while ((r = cg_read_subgroup(d, &fn)) > 0) {
947 char *p = NULL;
948
949 r = asprintf(&p, "%s/%s", path, fn);
950 free(fn);
951
952 if (r < 0) {
953 r = -ENOMEM;
954 goto finish;
955 }
956
957 r = cg_is_empty_recursive(controller, p, ignore_self);
958 free(p);
959
960 if (r <= 0)
961 goto finish;
962 }
963
964 if (r >= 0)
965 r = 1;
966
967 finish:
968
969 if (d)
970 closedir(d);
971
972 return r;
973 }
974
975 int cg_split_spec(const char *spec, char **controller, char **path) {
976 const char *e;
977 char *t = NULL, *u = NULL;
978
979 assert(spec);
980 assert(controller || path);
981
982 if (*spec == '/') {
983
984 if (path) {
985 if (!(t = strdup(spec)))
986 return -ENOMEM;
987
988 *path = t;
989 }
990
991 if (controller)
992 *controller = NULL;
993
994 return 0;
995 }
996
997 if (!(e = strchr(spec, ':'))) {
998
999 if (strchr(spec, '/') || spec[0] == 0)
1000 return -EINVAL;
1001
1002 if (controller) {
1003 if (!(t = strdup(spec)))
1004 return -ENOMEM;
1005
1006 *controller = t;
1007 }
1008
1009 if (path)
1010 *path = NULL;
1011
1012 return 0;
1013 }
1014
1015 if (e[1] != '/' ||
1016 e == spec ||
1017 memchr(spec, '/', e-spec))
1018 return -EINVAL;
1019
1020 if (controller)
1021 if (!(t = strndup(spec, e-spec)))
1022 return -ENOMEM;
1023
1024 if (path)
1025 if (!(u = strdup(e+1))) {
1026 free(t);
1027 return -ENOMEM;
1028 }
1029
1030 if (controller)
1031 *controller = t;
1032
1033 if (path)
1034 *path = u;
1035
1036 return 0;
1037 }
1038
1039 int cg_join_spec(const char *controller, const char *path, char **spec) {
1040 assert(controller);
1041 assert(path);
1042
1043 if (!path_is_absolute(path) ||
1044 controller[0] == 0 ||
1045 strchr(controller, ':') ||
1046 strchr(controller, '/'))
1047 return -EINVAL;
1048
1049 if (asprintf(spec, "%s:%s", controller, path) < 0)
1050 return -ENOMEM;
1051
1052 return 0;
1053 }
1054
1055 int cg_fix_path(const char *path, char **result) {
1056 char *t, *c, *p;
1057 int r;
1058
1059 assert(path);
1060 assert(result);
1061
1062 /* First check if it already is a filesystem path */
1063 if (path_is_absolute(path) &&
1064 path_startswith(path, "/sys/fs/cgroup") &&
1065 access(path, F_OK) >= 0) {
1066
1067 if (!(t = strdup(path)))
1068 return -ENOMEM;
1069
1070 *result = t;
1071 return 0;
1072 }
1073
1074 /* Otherwise treat it as cg spec */
1075 if ((r = cg_split_spec(path, &c, &p)) < 0)
1076 return r;
1077
1078 r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1079 free(c);
1080 free(p);
1081
1082 return r;
1083 }
1084
1085 int cg_get_user_path(char **path) {
1086 char *root, *p;
1087
1088 assert(path);
1089
1090 /* Figure out the place to put user cgroups below. We use the
1091 * same as PID 1 has but with the "/system" suffix replaced by
1092 * "/user" */
1093
1094 if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0)
1095 p = strdup("/user");
1096 else {
1097 if (endswith(root, "/system"))
1098 root[strlen(root) - 7] = 0;
1099 else if (streq(root, "/"))
1100 root[0] = 0;
1101
1102 p = strappend(root, "/user");
1103 free(root);
1104 }
1105
1106 if (!p)
1107 return -ENOMEM;
1108
1109 *path = p;
1110 return 0;
1111 }