chiark / gitweb /
journalctl: display source timestamp, not journald timestamp, if known
[elogind.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_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_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_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 ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
716                 return r;
717
718         r = chmod_and_chown(fs, mode, uid, gid);
719         free(fs);
720
721         return r;
722 }
723
724 int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
725         char *fs;
726         int r;
727
728         assert(controller);
729         assert(path);
730
731         if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
732                 return r;
733
734         r = chmod_and_chown(fs, mode, uid, gid);
735         free(fs);
736
737         return r;
738 }
739
740 int cg_get_by_pid(const char *controller, pid_t pid, char **path) {
741         int r;
742         char *p = NULL;
743         FILE *f;
744         char *fs;
745         size_t cs;
746
747         assert(controller);
748         assert(path);
749         assert(pid >= 0);
750
751         if (pid == 0)
752                 pid = getpid();
753
754         if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0)
755                 return -ENOMEM;
756
757         f = fopen(fs, "re");
758         free(fs);
759
760         if (!f)
761                 return errno == ENOENT ? -ESRCH : -errno;
762
763         cs = strlen(controller);
764
765         while (!feof(f)) {
766                 char line[LINE_MAX];
767                 char *l;
768
769                 errno = 0;
770                 if (!(fgets(line, sizeof(line), f))) {
771                         if (feof(f))
772                                 break;
773
774                         r = errno ? -errno : -EIO;
775                         goto finish;
776                 }
777
778                 truncate_nl(line);
779
780                 if (!(l = strchr(line, ':')))
781                         continue;
782
783                 l++;
784                 if (strncmp(l, controller, cs) != 0)
785                         continue;
786
787                 if (l[cs] != ':')
788                         continue;
789
790                 if (!(p = strdup(l + cs + 1))) {
791                         r = -ENOMEM;
792                         goto finish;
793                 }
794
795                 *path = p;
796                 r = 0;
797                 goto finish;
798         }
799
800         r = -ENOENT;
801
802 finish:
803         fclose(f);
804
805         return r;
806 }
807
808 int cg_install_release_agent(const char *controller, const char *agent) {
809         char *fs = NULL, *contents = NULL, *line = NULL, *sc;
810         int r;
811
812         assert(controller);
813         assert(agent);
814
815         if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0)
816                 return r;
817
818         if ((r = read_one_line_file(fs, &contents)) < 0)
819                 goto finish;
820
821         sc = strstrip(contents);
822         if (sc[0] == 0) {
823
824                 if (asprintf(&line, "%s\n", agent) < 0) {
825                         r = -ENOMEM;
826                         goto finish;
827                 }
828
829                 if ((r = write_one_line_file(fs, line)) < 0)
830                         goto finish;
831
832         } else if (!streq(sc, agent)) {
833                 r = -EEXIST;
834                 goto finish;
835         }
836
837         free(fs);
838         fs = NULL;
839         if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0)
840                 goto finish;
841
842         free(contents);
843         contents = NULL;
844         if ((r = read_one_line_file(fs, &contents)) < 0)
845                 goto finish;
846
847         sc = strstrip(contents);
848
849         if (streq(sc, "0")) {
850                 if ((r = write_one_line_file(fs, "1\n")) < 0)
851                         goto finish;
852
853                 r = 1;
854         } else if (!streq(sc, "1")) {
855                 r = -EIO;
856                 goto finish;
857         } else
858                 r = 0;
859
860 finish:
861         free(fs);
862         free(contents);
863         free(line);
864
865         return r;
866 }
867
868 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
869         pid_t pid = 0;
870         int r;
871         FILE *f = NULL;
872         bool found = false;
873
874         assert(controller);
875         assert(path);
876
877         if ((r = cg_enumerate_tasks(controller, path, &f)) < 0)
878                 return r == -ENOENT ? 1 : r;
879
880         while ((r = cg_read_pid(f, &pid)) > 0) {
881
882                 if (ignore_self && pid == getpid())
883                         continue;
884
885                 found = true;
886                 break;
887         }
888
889         fclose(f);
890
891         if (r < 0)
892                 return r;
893
894         return !found;
895 }
896
897 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
898         int r;
899         DIR *d = NULL;
900         char *fn;
901
902         assert(controller);
903         assert(path);
904
905         if ((r = cg_is_empty(controller, path, ignore_self)) <= 0)
906                 return r;
907
908         if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0)
909                 return r == -ENOENT ? 1 : r;
910
911         while ((r = cg_read_subgroup(d, &fn)) > 0) {
912                 char *p = NULL;
913
914                 r = asprintf(&p, "%s/%s", path, fn);
915                 free(fn);
916
917                 if (r < 0) {
918                         r = -ENOMEM;
919                         goto finish;
920                 }
921
922                 r = cg_is_empty_recursive(controller, p, ignore_self);
923                 free(p);
924
925                 if (r <= 0)
926                         goto finish;
927         }
928
929         if (r >= 0)
930                 r = 1;
931
932 finish:
933
934         if (d)
935                 closedir(d);
936
937         return r;
938 }
939
940 int cg_split_spec(const char *spec, char **controller, char **path) {
941         const char *e;
942         char *t = NULL, *u = NULL;
943
944         assert(spec);
945         assert(controller || path);
946
947         if (*spec == '/') {
948
949                 if (path) {
950                         if (!(t = strdup(spec)))
951                                 return -ENOMEM;
952
953                         *path = t;
954                 }
955
956                 if (controller)
957                         *controller = NULL;
958
959                 return 0;
960         }
961
962         if (!(e = strchr(spec, ':'))) {
963
964                 if (strchr(spec, '/') || spec[0] == 0)
965                         return -EINVAL;
966
967                 if (controller) {
968                         if (!(t = strdup(spec)))
969                                 return -ENOMEM;
970
971                         *controller = t;
972                 }
973
974                 if (path)
975                         *path = NULL;
976
977                 return 0;
978         }
979
980         if (e[1] != '/' ||
981             e == spec ||
982             memchr(spec, '/', e-spec))
983                 return -EINVAL;
984
985         if (controller)
986                 if (!(t = strndup(spec, e-spec)))
987                         return -ENOMEM;
988
989         if (path)
990                 if (!(u = strdup(e+1))) {
991                         free(t);
992                         return -ENOMEM;
993                 }
994
995         if (controller)
996                 *controller = t;
997
998         if (path)
999                 *path = u;
1000
1001         return 0;
1002 }
1003
1004 int cg_join_spec(const char *controller, const char *path, char **spec) {
1005         assert(controller);
1006         assert(path);
1007
1008         if (!path_is_absolute(path) ||
1009             controller[0] == 0 ||
1010             strchr(controller, ':') ||
1011             strchr(controller, '/'))
1012                 return -EINVAL;
1013
1014         if (asprintf(spec, "%s:%s", controller, path) < 0)
1015                 return -ENOMEM;
1016
1017         return 0;
1018 }
1019
1020 int cg_fix_path(const char *path, char **result) {
1021         char *t, *c, *p;
1022         int r;
1023
1024         assert(path);
1025         assert(result);
1026
1027         /* First check if it already is a filesystem path */
1028         if (path_is_absolute(path) &&
1029             path_startswith(path, "/sys/fs/cgroup") &&
1030             access(path, F_OK) >= 0) {
1031
1032                 if (!(t = strdup(path)))
1033                         return -ENOMEM;
1034
1035                 *result = t;
1036                 return 0;
1037         }
1038
1039         /* Otherwise treat it as cg spec */
1040         if ((r = cg_split_spec(path, &c, &p)) < 0)
1041                 return r;
1042
1043         r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
1044         free(c);
1045         free(p);
1046
1047         return r;
1048 }
1049
1050 int cg_get_user_path(char **path) {
1051         char *root, *p;
1052
1053         assert(path);
1054
1055         /* Figure out the place to put user cgroups below. We use the
1056          * same as PID 1 has but with the "/system" suffix replaced by
1057          * "/user" */
1058
1059         if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0)
1060                 p = strdup("/user");
1061         else {
1062                 if (endswith(root, "/system"))
1063                         root[strlen(root) - 7] = 0;
1064                 else if (streq(root, "/"))
1065                         root[0] = 0;
1066
1067                 p = strappend(root, "/user");
1068                 free(root);
1069         }
1070
1071         if (!p)
1072                 return -ENOMEM;
1073
1074         *path = p;
1075         return 0;
1076 }