chiark / gitweb /
2f3fcb5981dac8a713bf5714992a285e608530bf
[elogind.git] / src / cgroup-util.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <unistd.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <dirent.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30
31 #include "cgroup-util.h"
32 #include "log.h"
33 #include "set.h"
34 #include "macro.h"
35 #include "util.h"
36
37 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
38         char *fs;
39         int r;
40         FILE *f;
41
42         assert(controller);
43         assert(path);
44         assert(_f);
45
46         if ((r = cg_get_path(controller, path, "cgroup.procs", &fs)) < 0)
47                 return r;
48
49         f = fopen(fs, "re");
50         free(fs);
51
52         if (!f)
53                 return -errno;
54
55         *_f = f;
56         return 0;
57 }
58
59 int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
60         char *fs;
61         int r;
62         FILE *f;
63
64         assert(controller);
65         assert(path);
66         assert(_f);
67
68         if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
69                 return r;
70
71         f = fopen(fs, "re");
72         free(fs);
73
74         if (!f)
75                 return -errno;
76
77         *_f = f;
78         return 0;
79 }
80
81 int cg_read_pid(FILE *f, pid_t *_pid) {
82         unsigned long ul;
83
84         /* Note that the cgroup.procs might contain duplicates! See
85          * cgroups.txt for details. */
86
87         errno = 0;
88         if (fscanf(f, "%lu", &ul) != 1) {
89
90                 if (feof(f))
91                         return 0;
92
93                 return errno ? -errno : -EIO;
94         }
95
96         if (ul <= 0)
97                 return -EIO;
98
99         *_pid = (pid_t) ul;
100         return 1;
101 }
102
103 int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
104         char *fs;
105         int r;
106         DIR *d;
107
108         assert(controller);
109         assert(path);
110         assert(_d);
111
112         /* This is not recursive! */
113
114         if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
115                 return r;
116
117         d = opendir(fs);
118         free(fs);
119
120         if (!d)
121                 return -errno;
122
123         *_d = d;
124         return 0;
125 }
126
127 int cg_read_subgroup(DIR *d, char **fn) {
128         struct dirent *de;
129
130         assert(d);
131
132         errno = 0;
133         while ((de = readdir(d))) {
134                 char *b;
135
136                 if (de->d_type != DT_DIR)
137                         continue;
138
139                 if (streq(de->d_name, ".") ||
140                     streq(de->d_name, ".."))
141                         continue;
142
143                 if (!(b = strdup(de->d_name)))
144                         return -ENOMEM;
145
146                 *fn = b;
147                 return 1;
148         }
149
150         if (errno)
151                 return -errno;
152
153         return 0;
154 }
155
156 int cg_rmdir(const char *controller, const char *path) {
157         char *p;
158         int r;
159
160         if ((r = cg_get_path(controller, path, NULL, &p)) < 0)
161                 return r;
162
163         r = rmdir(p);
164         free(p);
165
166         return r < 0 ? -errno : 0;
167 }
168
169 int cg_kill(const char *controller, const char *path, int sig, bool ignore_self) {
170         bool done = false;
171         Set *s;
172         int r, ret = 0;
173         pid_t my_pid;
174         FILE *f = NULL;
175
176         assert(controller);
177         assert(path);
178         assert(sig >= 0);
179
180         /* This goes through the tasks list and kills them all. This
181          * is repeated until no further processes are added to the
182          * tasks list, to properly handle forking processes */
183
184         if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
185                 return -ENOMEM;
186
187         my_pid = getpid();
188
189         do {
190                 pid_t pid;
191                 done = true;
192
193                 if ((r = cg_enumerate_processes(controller, path, &f)) < 0) {
194                         if (ret >= 0 && r != -ENOENT)
195                                 ret = r;
196
197                         goto finish;
198                 }
199
200                 while ((r = cg_read_pid(f, &pid)) > 0) {
201
202                         if (pid == my_pid && ignore_self)
203                                 continue;
204
205                         if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
206                                 continue;
207
208                         /* If we haven't killed this process yet, kill
209                          * it */
210                         if (kill(pid, sig) < 0) {
211                                 if (ret >= 0 && errno != ESRCH)
212                                         ret = -errno;
213                         } else if (ret == 0)
214                                 ret = 1;
215
216                         done = false;
217
218                         if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) {
219                                 if (ret >= 0)
220                                         ret = r;
221
222                                 goto finish;
223                         }
224                 }
225
226                 if (r < 0) {
227                         if (ret >= 0)
228                                 ret = r;
229
230                         goto finish;
231                 }
232
233                 fclose(f);
234                 f = NULL;
235
236                 /* To avoid racing against processes which fork
237                  * quicker than we can kill them we repeat this until
238                  * no new pids need to be killed. */
239
240         } while (!done);
241
242 finish:
243         set_free(s);
244
245         if (f)
246                 fclose(f);
247
248         return ret;
249 }
250
251 int cg_kill_recursive(const char *controller, const char *path, int sig, bool ignore_self, bool rem) {
252         int r, ret = 0;
253         DIR *d = NULL;
254         char *fn;
255
256         assert(path);
257         assert(controller);
258         assert(sig >= 0);
259
260         ret = cg_kill(controller, path, sig, ignore_self);
261
262         if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0) {
263                 if (ret >= 0 && r != -ENOENT)
264                         ret = r;
265
266                 goto finish;
267         }
268
269         while ((r = cg_read_subgroup(d, &fn)) > 0) {
270                 char *p = NULL;
271
272                 r = asprintf(&p, "%s/%s", path, fn);
273                 free(fn);
274
275                 if (r < 0) {
276                         if (ret >= 0)
277                                 ret = -ENOMEM;
278
279                         goto finish;
280                 }
281
282                 r = cg_kill_recursive(controller, p, sig, ignore_self, rem);
283                 free(p);
284
285                 if (r != 0 && ret >= 0)
286                         ret = r;
287         }
288
289         if (r < 0 && ret >= 0)
290                 ret = r;
291
292         if (rem)
293                 if ((r = cg_rmdir(controller, path)) < 0) {
294                         if (ret >= 0 && r != -ENOENT)
295                                 ret = r;
296                 }
297
298 finish:
299         if (d)
300                 closedir(d);
301
302         return ret;
303 }
304
305 int cg_kill_recursive_and_wait(const char *controller, const char *path, bool rem) {
306         unsigned i;
307
308         assert(path);
309         assert(controller);
310
311         /* This safely kills all processes; first it sends a SIGTERM,
312          * then checks 8 times after 50ms whether the group is
313          * now empty, and finally kills everything that is left with
314          * SIGKILL */
315
316         for (i = 0; i < 10; i++) {
317                 int sig, r;
318
319                 if (i <= 0)
320                         sig = SIGTERM;
321                 else if (i >= 9)
322                         sig = SIGKILL;
323                 else
324                         sig = 0;
325
326                 if ((r = cg_kill_recursive(controller, path, sig, true, rem)) <= 0)
327                         return r;
328
329                 usleep(50 * USEC_PER_MSEC);
330         }
331
332         return 0;
333 }
334
335 int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self) {
336         bool done = false;
337         Set *s;
338         int r, ret = 0;
339         pid_t my_pid;
340         FILE *f = NULL;
341
342         assert(controller);
343         assert(from);
344         assert(to);
345
346         if (!(s = set_new(trivial_hash_func, trivial_compare_func)))
347                 return -ENOMEM;
348
349         my_pid = getpid();
350
351         do {
352                 pid_t pid;
353                 done = true;
354
355                 if ((r = cg_enumerate_tasks(controller, from, &f)) < 0) {
356                         if (ret >= 0 && r != -ENOENT)
357                                 ret = r;
358
359                         goto finish;
360                 }
361
362                 while ((r = cg_read_pid(f, &pid)) > 0) {
363
364                         /* This might do weird stuff if we aren't a
365                          * single-threaded program. However, we
366                          * luckily know we are not */
367                         if (pid == my_pid && ignore_self)
368                                 continue;
369
370                         if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
371                                 continue;
372
373                         if ((r = cg_attach(controller, to, pid)) < 0) {
374                                 if (ret >= 0 && r != -ESRCH)
375                                         ret = r;
376                         } else if (ret == 0)
377                                 ret = 1;
378
379                         done = false;
380
381                         if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) {
382                                 if (ret >= 0)
383                                         ret = r;
384
385                                 goto finish;
386                         }
387                 }
388
389                 if (r < 0) {
390                         if (ret >= 0)
391                                 ret = r;
392
393                         goto finish;
394                 }
395
396                 fclose(f);
397                 f = NULL;
398
399         } while (!done);
400
401 finish:
402         set_free(s);
403
404         if (f)
405                 fclose(f);
406
407         return ret;
408 }
409
410 int cg_migrate_recursive(const char *controller, const char *from, const char *to, bool ignore_self, bool rem) {
411         int r, ret = 0;
412         DIR *d = NULL;
413         char *fn;
414
415         assert(controller);
416         assert(from);
417         assert(to);
418
419         ret = cg_migrate(controller, from, to, ignore_self);
420
421         if ((r = cg_enumerate_subgroups(controller, from, &d)) < 0) {
422                 if (ret >= 0 && r != -ENOENT)
423                         ret = r;
424                 goto finish;
425         }
426
427         while ((r = cg_read_subgroup(d, &fn)) > 0) {
428                 char *p = NULL;
429
430                 r = asprintf(&p, "%s/%s", from, fn);
431                 free(fn);
432
433                 if (r < 0) {
434                         if (ret >= 0)
435                                 ret = -ENOMEM;
436
437                         goto finish;
438                 }
439
440                 r = cg_migrate_recursive(controller, p, to, ignore_self, rem);
441                 free(p);
442
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                 if ((r = cg_rmdir(controller, from)) < 0) {
452                         if (ret >= 0 && r != -ENOENT)
453                                 ret = r;
454                 }
455
456 finish:
457         if (d)
458                 closedir(d);
459
460         return ret;
461 }
462
463 int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) {
464         const char *p;
465         char *mp;
466         int r;
467
468         assert(controller);
469         assert(fs);
470
471         /* This is a very minimal lookup from controller names to
472          * paths. Since we have mounted most hierarchies ourselves
473          * should be kinda safe, but eventually we might want to
474          * extend this to have a fallback to actually check
475          * /proc/mounts. Might need caching then. */
476
477         if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
478                 p = "systemd";
479         else if (startswith(controller, "name="))
480                 p = controller + 5;
481         else
482                 p = controller;
483
484         if (asprintf(&mp, "/cgroup/%s", p) < 0)
485                 return -ENOMEM;
486
487         if ((r = path_is_mount_point(mp)) <= 0) {
488                 free(mp);
489                 return r < 0 ? r : -ENOENT;
490         }
491
492         if (path && suffix)
493                 r = asprintf(fs, "%s/%s/%s", mp, path, suffix);
494         else if (path)
495                 r = asprintf(fs, "%s/%s", mp, path);
496         else if (suffix)
497                 r = asprintf(fs, "%s/%s", mp, suffix);
498         else {
499                 path_kill_slashes(mp);
500                 *fs = mp;
501                 return 0;
502         }
503
504         free(mp);
505         path_kill_slashes(*fs);
506         return r < 0 ? -ENOMEM : 0;
507 }
508
509 int cg_trim(const char *controller, const char *path, bool delete_root) {
510         char *fs;
511         int r;
512
513         assert(controller);
514         assert(path);
515
516         if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
517                 return r;
518
519         r = rm_rf(fs, true, delete_root);
520         free(fs);
521
522         return r == -ENOENT ? 0 : r;
523 }
524
525 int cg_delete(const char *controller, const char *path) {
526         char *parent;
527         int r;
528
529         assert(controller);
530         assert(path);
531
532         if ((r = parent_of_path(path, &parent)) < 0)
533                 return r;
534
535         r = cg_migrate_recursive(controller, path, parent, false, true);
536         free(parent);
537
538         return r == -ENOENT ? 0 : r;
539 }
540
541 int cg_create(const char *controller, const char *path) {
542         char *fs;
543         int r;
544
545         assert(controller);
546         assert(path);
547
548         if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
549                 return r;
550
551         r = mkdir_parents(fs, 0755);
552
553         if (r >= 0) {
554                 if (mkdir(fs, 0755) >= 0)
555                         r = 1;
556                 else if (errno == EEXIST)
557                         r = 0;
558                 else
559                         r = -errno;
560         }
561
562         free(fs);
563
564         return r;
565 }
566
567 int cg_attach(const char *controller, const char *path, pid_t pid) {
568         char *fs;
569         int r;
570         char c[32];
571
572         assert(controller);
573         assert(path);
574         assert(pid >= 0);
575
576         if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
577                 return r;
578
579         if (pid == 0)
580                 pid = getpid();
581
582         snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid);
583         char_array_0(c);
584
585         r = write_one_line_file(fs, c);
586         free(fs);
587
588         return r;
589 }
590
591 int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
592         int r, q;
593
594         assert(controller);
595         assert(path);
596         assert(pid >= 0);
597
598         if ((r = cg_create(controller, path)) < 0)
599                 return r;
600
601         if ((q = cg_attach(controller, path, pid)) < 0)
602                 return q;
603
604         /* This does not remove the cgroup on failure */
605
606         return r;
607 }
608
609 int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
610         char *fs;
611         int r;
612
613         assert(controller);
614         assert(path);
615
616         if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
617                 return r;
618
619         r = chmod_and_chown(fs, mode, uid, gid);
620         free(fs);
621
622         return r;
623 }
624
625 int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) {
626         char *fs;
627         int r;
628
629         assert(controller);
630         assert(path);
631
632         if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
633                 return r;
634
635         r = chmod_and_chown(fs, mode, uid, gid);
636         free(fs);
637
638         return r;
639 }
640
641 int cg_get_by_pid(const char *controller, pid_t pid, char **path) {
642         int r;
643         char *p = NULL;
644         FILE *f;
645         char *fs;
646         size_t cs;
647
648         assert(controller);
649         assert(path);
650         assert(pid >= 0);
651
652         if (pid == 0)
653                 pid = getpid();
654
655         if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0)
656                 return -ENOMEM;
657
658         f = fopen(fs, "re");
659         free(fs);
660
661         if (!f)
662                 return errno == ENOENT ? -ESRCH : -errno;
663
664         cs = strlen(controller);
665
666         while (!feof(f)) {
667                 char line[LINE_MAX];
668                 char *l;
669
670                 errno = 0;
671                 if (!(fgets(line, sizeof(line), f))) {
672                         if (feof(f))
673                                 break;
674
675                         r = errno ? -errno : -EIO;
676                         goto finish;
677                 }
678
679                 truncate_nl(line);
680
681                 if (!(l = strchr(line, ':')))
682                         continue;
683
684                 l++;
685                 if (strncmp(l, controller, cs) != 0)
686                         continue;
687
688                 if (l[cs] != ':')
689                         continue;
690
691                 if (!(p = strdup(l + cs + 1))) {
692                         r = -ENOMEM;
693                         goto finish;
694                 }
695
696                 *path = p;
697                 r = 0;
698                 goto finish;
699         }
700
701         r = -ENOENT;
702
703 finish:
704         fclose(f);
705
706         return r;
707 }
708
709 int cg_install_release_agent(const char *controller, const char *agent) {
710         char *fs = NULL, *contents = NULL, *line = NULL, *sc;
711         int r;
712
713         assert(controller);
714         assert(agent);
715
716         if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0)
717                 return r;
718
719         if ((r = read_one_line_file(fs, &contents)) < 0)
720                 goto finish;
721
722         sc = strstrip(contents);
723         if (sc[0] == 0) {
724
725                 if (asprintf(&line, "%s\n", agent) < 0) {
726                         r = -ENOMEM;
727                         goto finish;
728                 }
729
730                 if ((r = write_one_line_file(fs, line)) < 0)
731                         goto finish;
732
733         } else if (!streq(sc, agent)) {
734                 r = -EEXIST;
735                 goto finish;
736         }
737
738         free(fs);
739         fs = NULL;
740         if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0) {
741                 r = -ENOMEM;
742                 goto finish;
743         }
744
745         free(contents);
746         contents = NULL;
747         if ((r = read_one_line_file(fs, &contents)) < 0)
748                 goto finish;
749
750         sc = strstrip(contents);
751
752         if (streq(sc, "0")) {
753                 if ((r = write_one_line_file(fs, "1\n")) < 0)
754                         goto finish;
755
756                 r = 1;
757         } else if (!streq(sc, "1")) {
758                 r = -EIO;
759                 goto finish;
760         } else
761                 r = 0;
762
763 finish:
764         free(fs);
765         free(contents);
766         free(line);
767
768         return r;
769 }
770
771 int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
772         pid_t pid;
773         int r;
774         FILE *f;
775         bool found = false;
776
777         assert(controller);
778         assert(path);
779
780         if ((r = cg_enumerate_tasks(controller, path, &f)) < 0)
781                 return r == -ENOENT ? 1 : r;
782
783         while ((r = cg_read_pid(f, &pid)) > 0) {
784
785                 if (ignore_self && pid == getpid())
786                         continue;
787
788                 found = true;
789                 break;
790         }
791
792         fclose(f);
793
794         if (r < 0)
795                 return r;
796
797         return !found;
798 }
799
800 int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
801         int r;
802         DIR *d = NULL;
803         char *fn;
804
805         assert(controller);
806         assert(path);
807
808         if ((r = cg_is_empty(controller, path, ignore_self)) <= 0)
809                 return r;
810
811         if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0)
812                 return r == -ENOENT ? 1 : r;
813
814         while ((r = cg_read_subgroup(d, &fn)) > 0) {
815                 char *p = NULL;
816
817                 r = asprintf(&p, "%s/%s", path, fn);
818                 free(fn);
819
820                 if (r < 0) {
821                         r = -ENOMEM;
822                         goto finish;
823                 }
824
825                 r = cg_is_empty_recursive(controller, p, ignore_self);
826                 free(p);
827
828                 if (r <= 0)
829                         goto finish;
830         }
831
832         if (r >= 0)
833                 r = 1;
834
835 finish:
836
837         if (d)
838                 closedir(d);
839
840         return r;
841 }
842
843 int cg_split_spec(const char *spec, char **controller, char **path) {
844         const char *e;
845         char *t = NULL, *u = NULL;
846
847         assert(spec);
848         assert(controller || path);
849
850         if (*spec == '/') {
851
852                 if (path) {
853                         if (!(t = strdup(spec)))
854                                 return -ENOMEM;
855
856                         *path = t;
857                 }
858
859                 if (controller)
860                         *controller = NULL;
861
862                 return 0;
863         }
864
865         if (!(e = strchr(spec, ':'))) {
866
867                 if (strchr(spec, '/') || spec[0] == 0)
868                         return -EINVAL;
869
870                 if (controller) {
871                         if (!(t = strdup(spec)))
872                                 return -ENOMEM;
873
874                         *controller = t;
875                 }
876
877                 if (path)
878                         *path = NULL;
879
880                 return 0;
881         }
882
883         if (e[1] != '/' ||
884             e == spec ||
885             memchr(spec, '/', e-spec))
886                 return -EINVAL;
887
888         if (controller)
889                 if (!(t = strndup(spec, e-spec)))
890                         return -ENOMEM;
891
892         if (path)
893                 if (!(u = strdup(e+1))) {
894                         free(t);
895                         return -ENOMEM;
896                 }
897
898         if (controller)
899                 *controller = t;
900
901         if (path)
902                 *path = u;
903
904         return 0;
905 }
906
907 int cg_join_spec(const char *controller, const char *path, char **spec) {
908         assert(controller);
909         assert(path);
910
911         if (!path_is_absolute(path) ||
912             controller[0] == 0 ||
913             strchr(controller, ':') ||
914             strchr(controller, '/'))
915                 return -EINVAL;
916
917         if (asprintf(spec, "%s:%s", controller, path) < 0)
918                 return -ENOMEM;
919
920         return 0;
921 }
922
923 int cg_fix_path(const char *path, char **result) {
924         char *t, *c, *p;
925         int r;
926
927         assert(path);
928         assert(result);
929
930         /* First check if it already is a filesystem path */
931         if (path_is_absolute(path) &&
932             path_startswith(path, "/cgroup") &&
933             access(path, F_OK) >= 0) {
934
935                 if (!(t = strdup(path)))
936                         return -ENOMEM;
937
938                 *result = t;
939                 return 0;
940         }
941
942         /* Otherwise treat it as cg spec */
943         if ((r = cg_split_spec(path, &c, &p)) < 0)
944                 return r;
945
946         r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result);
947         free(c);
948         free(p);
949
950         return r;
951 }