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