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