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