chiark / gitweb /
cgroup: if a controller is not available don't try to create cgroups in its hierarchy
[elogind.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
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 static const char *normalize_controller(const char *controller) {
506
507         if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
508                 return "systemd";
509         else if (startswith(controller, "name="))
510                 return controller + 5;
511         else
512                 return controller;
513 }
514
515 static int join_path(const char *controller, const char *path, const char *suffix, char **fs) {
516         char *t;
517
518         if (path && suffix)
519                 t = join("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL);
520         else if (path)
521                 t = join("/sys/fs/cgroup/", controller, "/", path, NULL);
522         else if (suffix)
523                 t = join("/sys/fs/cgroup/", controller, "/", suffix, NULL);
524         else
525                 t = join("/sys/fs/cgroup/", controller, NULL);
526
527         if (!t)
528                 return -ENOMEM;
529
530         path_kill_slashes(t);
531
532         *fs = t;
533         return 0;
534 }
535
536 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
537         const char *p;
538         static __thread bool good = false;
539
540         assert(controller);
541         assert(fs);
542
543         if (isempty(controller))
544                 return -EINVAL;
545
546         if (_unlikely_(!good)) {
547                 int r;
548
549                 r = path_is_mount_point("/sys/fs/cgroup", false);
550                 if (r <= 0)
551                         return r < 0 ? r : -ENOENT;
552
553                 /* Cache this to save a few stat()s */
554                 good = true;
555         }
556
557         p = normalize_controller(controller);
558
559         return join_path(p, path, suffix, fs);
560 }
561
562 int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
563         const char *p;
564         char *cc;
565
566         assert(controller);
567         assert(fs);
568
569         if (isempty(controller))
570                 return -EINVAL;
571
572         p = normalize_controller(controller);
573
574         /* Check if this controller actually really exists */
575         cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(p));
576         strcpy(stpcpy(cc, "/sys/fs/cgroup/"), p);
577         if (access(cc, F_OK) < 0)
578                 return -errno;
579
580         return join_path(p, path, suffix, fs);
581 }
582
583 static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
584         char *p;
585         bool is_sticky;
586
587         if (typeflag != FTW_DP)
588                 return 0;
589
590         if (ftwbuf->level < 1)
591                 return 0;
592
593         p = strappend(path, "/tasks");
594         if (!p) {
595                 errno = ENOMEM;
596                 return 1;
597         }
598
599         is_sticky = file_is_priv_sticky(p) > 0;
600         free(p);
601
602         if (is_sticky)
603                 return 0;
604
605         rmdir(path);
606         return 0;
607 }
608
609 int cg_trim(const char *controller, const char *path, bool delete_root) {
610         char *fs;
611         int r = 0;
612
613         assert(controller);
614         assert(path);
615
616         r = cg_get_path(controller, path, NULL, &fs);
617         if (r < 0)
618                 return r;
619
620         errno = 0;
621         if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
622                 r = errno ? -errno : -EIO;
623
624         if (delete_root) {
625                 bool is_sticky;
626                 char *p;
627
628                 p = strappend(fs, "/tasks");
629                 if (!p) {
630                         free(fs);
631                         return -ENOMEM;
632                 }
633
634                 is_sticky = file_is_priv_sticky(p) > 0;
635                 free(p);
636
637                 if (!is_sticky)
638                         if (rmdir(fs) < 0 && errno != ENOENT) {
639                                 if (r == 0)
640                                         r = -errno;
641                         }
642         }
643
644         free(fs);
645
646         return r;
647 }
648
649 int cg_delete(const char *controller, const char *path) {
650         char *parent;
651         int r;
652
653         assert(controller);
654         assert(path);
655
656         if ((r = parent_of_path(path, &parent)) < 0)
657                 return r;
658
659         r = cg_migrate_recursive(controller, path, parent, false, true);
660         free(parent);
661
662         return r == -ENOENT ? 0 : r;
663 }
664
665 int cg_attach(const char *controller, const char *path, pid_t pid) {
666         char *fs;
667         int r;
668         char c[32];
669
670         assert(controller);
671         assert(path);
672         assert(pid >= 0);
673
674         r = cg_get_path_and_check(controller, path, "tasks", &fs);
675         if (r < 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_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
691         char *fs;
692         int r;
693
694         assert(controller);
695         assert(path);
696
697         if (mode != (mode_t) -1)
698                 mode &= 0777;
699
700         r = cg_get_path(controller, path, NULL, &fs);
701         if (r < 0)
702                 return r;
703
704         r = chmod_and_chown(fs, mode, uid, gid);
705         free(fs);
706
707         return r;
708 }
709
710 int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid, int sticky) {
711         char *fs;
712         int r;
713
714         assert(controller);
715         assert(path);
716
717         if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1 && sticky < 0)
718                 return 0;
719
720         if (mode != (mode_t) -1)
721                 mode &= 0666;
722
723         r = cg_get_path(controller, path, "tasks", &fs);
724         if (r < 0)
725                 return r;
726
727         if (sticky >= 0 && mode != (mode_t) -1)
728                 /* Both mode and sticky param are passed */
729                 mode |= (sticky ? S_ISVTX : 0);
730         else if ((sticky >= 0 && mode == (mode_t) -1) ||
731                  (mode != (mode_t) -1 && sticky < 0)) {
732                 struct stat st;
733
734                 /* Only one param is passed, hence read the current
735                  * mode from the file itself */
736
737                 r = lstat(fs, &st);
738                 if (r < 0) {
739                         free(fs);
740                         return -errno;
741                 }
742
743                 if (mode == (mode_t) -1)
744                         /* No mode set, we just shall set the sticky bit */
745                         mode = (st.st_mode & ~S_ISVTX) | (sticky ? S_ISVTX : 0);
746                 else
747                         /* Only mode set, leave sticky bit untouched */
748                         mode = (st.st_mode & ~0777) | mode;
749         }
750
751         r = chmod_and_chown(fs, mode, uid, gid);
752         free(fs);
753
754         return r;
755 }
756
757 int cg_get_by_pid(const char *controller, pid_t pid, char **path) {
758         int r;
759         char *p = NULL;
760         FILE *f;
761         char *fs;
762         size_t cs;
763
764         assert(controller);
765         assert(path);
766         assert(pid >= 0);
767
768         if (pid == 0)
769                 pid = getpid();
770
771         if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0)
772                 return -ENOMEM;
773
774         f = fopen(fs, "re");
775         free(fs);
776
777         if (!f)
778                 return errno == ENOENT ? -ESRCH : -errno;
779
780         cs = strlen(controller);
781
782         while (!feof(f)) {
783                 char line[LINE_MAX];
784                 char *l;
785
786                 errno = 0;
787                 if (!(fgets(line, sizeof(line), f))) {
788                         if (feof(f))
789                                 break;
790
791                         r = errno ? -errno : -EIO;
792                         goto finish;
793                 }
794
795                 truncate_nl(line);
796
797                 if (!(l = strchr(line, ':')))
798                         continue;
799
800                 l++;
801                 if (strncmp(l, controller, cs) != 0)
802                         continue;
803
804                 if (l[cs] != ':')
805                         continue;
806
807                 if (!(p = strdup(l + cs + 1))) {
808                         r = -ENOMEM;
809                         goto finish;
810                 }
811
812                 *path = p;
813                 r = 0;
814                 goto finish;
815         }
816
817         r = -ENOENT;
818
819 finish:
820         fclose(f);
821
822         return r;
823 }
824
825 int cg_install_release_agent(const char *controller, const char *agent) {
826         char *fs = NULL, *contents = NULL, *line = NULL, *sc;
827         int r;
828
829         assert(controller);
830         assert(agent);
831
832         if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0)
833                 return r;
834
835         if ((r = read_one_line_file(fs, &contents)) < 0)
836                 goto finish;
837
838         sc = strstrip(contents);
839         if (sc[0] == 0) {
840
841                 if (asprintf(&line, "%s\n", agent) < 0) {
842                         r = -ENOMEM;
843                         goto finish;
844                 }
845
846                 if ((r = write_one_line_file(fs, line)) < 0)
847                         goto finish;
848
849         } else if (!streq(sc, agent)) {
850                 r = -EEXIST;
851                 goto finish;
852         }
853
854         free(fs);
855         fs = NULL;
856         if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0)
857                 goto finish;
858
859         free(contents);
860         contents = NULL;
861         if ((r = read_one_line_file(fs, &contents)) < 0)
862                 goto finish;
863
864         sc = strstrip(contents);
865
866         if (streq(sc, "0")) {
867                 if ((r = write_one_line_file(fs, "1\n")) < 0)
868                         goto finish;
869
870                 r = 1;
871         } else if (!streq(sc, "1")) {
872                 r = -EIO;
873                 goto finish;
874         } else
875                 r = 0;
876
877 finish:
878         free(fs);
879         free(contents);
880         free(line);
881
882         return r;
883 }
884
885 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
886         pid_t pid = 0;
887         int r;
888         FILE *f = NULL;
889         bool found = false;
890
891         assert(controller);
892         assert(path);
893
894         if ((r = cg_enumerate_tasks(controller, path, &f)) < 0)
895                 return r == -ENOENT ? 1 : r;
896
897         while ((r = cg_read_pid(f, &pid)) > 0) {
898
899                 if (ignore_self && pid == getpid())
900                         continue;
901
902                 found = true;
903                 break;
904         }
905
906         fclose(f);
907
908         if (r < 0)
909                 return r;
910
911         return !found;
912 }
913
914 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
915         int r;
916         DIR *d = NULL;
917         char *fn;
918
919         assert(controller);
920         assert(path);
921
922         if ((r = cg_is_empty(controller, path, ignore_self)) <= 0)
923                 return r;
924
925         if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0)
926                 return r == -ENOENT ? 1 : r;
927
928         while ((r = cg_read_subgroup(d, &fn)) > 0) {
929                 char *p = NULL;
930
931                 r = asprintf(&p, "%s/%s", path, fn);
932                 free(fn);
933
934                 if (r < 0) {
935                         r = -ENOMEM;
936                         goto finish;
937                 }
938
939                 r = cg_is_empty_recursive(controller, p, ignore_self);
940                 free(p);
941
942                 if (r <= 0)
943                         goto finish;
944         }
945
946         if (r >= 0)
947                 r = 1;
948
949 finish:
950
951         if (d)
952                 closedir(d);
953
954         return r;
955 }
956
957 int cg_split_spec(const char *spec, char **controller, char **path) {
958         const char *e;
959         char *t = NULL, *u = NULL;
960
961         assert(spec);
962         assert(controller || path);
963
964         if (*spec == '/') {
965
966                 if (path) {
967                         if (!(t = strdup(spec)))
968                                 return -ENOMEM;
969
970                         *path = t;
971                 }
972
973                 if (controller)
974                         *controller = NULL;
975
976                 return 0;
977         }
978
979         if (!(e = strchr(spec, ':'))) {
980
981                 if (strchr(spec, '/') || spec[0] == 0)
982                         return -EINVAL;
983
984                 if (controller) {
985                         if (!(t = strdup(spec)))
986                                 return -ENOMEM;
987
988                         *controller = t;
989                 }
990
991                 if (path)
992                         *path = NULL;
993
994                 return 0;
995         }
996
997         if (e[1] != '/' ||
998             e == spec ||
999             memchr(spec, '/', e-spec))
1000                 return -EINVAL;
1001
1002         if (controller)
1003                 if (!(t = strndup(spec, e-spec)))
1004                         return -ENOMEM;
1005
1006         if (path)
1007                 if (!(u = strdup(e+1))) {
1008                         free(t);
1009                         return -ENOMEM;
1010                 }
1011
1012         if (controller)
1013                 *controller = t;
1014
1015         if (path)
1016                 *path = u;
1017
1018         return 0;
1019 }
1020
1021 int cg_join_spec(const char *controller, const char *path, char **spec) {
1022         assert(controller);
1023         assert(path);
1024
1025         if (!path_is_absolute(path) ||
1026             controller[0] == 0 ||
1027             strchr(controller, ':') ||
1028             strchr(controller, '/'))
1029                 return -EINVAL;
1030
1031         if (asprintf(spec, "%s:%s", controller, path) < 0)
1032                 return -ENOMEM;
1033
1034         return 0;
1035 }
1036
1037 int cg_fix_path(const char *path, char **result) {
1038         char *t, *c, *p;
1039         int r;
1040
1041         assert(path);
1042         assert(result);
1043
1044         /* First check if it already is a filesystem path */
1045         if (path_is_absolute(path) &&
1046             path_startswith(path, "/sys/fs/cgroup") &&
1047             access(path, F_OK) >= 0) {
1048
1049                 if (!(t = strdup(path)))
1050                         return -ENOMEM;
1051
1052                 *result = t;
1053                 return 0;
1054         }
1055
1056         /* Otherwise treat it as cg spec */
1057         if ((r = cg_split_spec(path, &c, &p)) < 0)
1058                 return r;
1059
1060         r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1061         free(c);
1062         free(p);
1063
1064         return r;
1065 }
1066
1067 int cg_get_user_path(char **path) {
1068         char *root, *p;
1069
1070         assert(path);
1071
1072         /* Figure out the place to put user cgroups below. We use the
1073          * same as PID 1 has but with the "/system" suffix replaced by
1074          * "/user" */
1075
1076         if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0)
1077                 p = strdup("/user");
1078         else {
1079                 if (endswith(root, "/system"))
1080                         root[strlen(root) - 7] = 0;
1081                 else if (streq(root, "/"))
1082                         root[0] = 0;
1083
1084                 p = strappend(root, "/user");
1085                 free(root);
1086         }
1087
1088         if (!p)
1089                 return -ENOMEM;
1090
1091         *path = p;
1092         return 0;
1093 }