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