chiark / gitweb /
doc: disable "make check" for gtk-doc
[elogind.git] / src / core / cgroup.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 <assert.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <signal.h>
27 #include <sys/mount.h>
28 #include <fcntl.h>
29
30 #include "cgroup.h"
31 #include "cgroup-util.h"
32 #include "log.h"
33 #include "strv.h"
34 #include "path-util.h"
35
36 int cgroup_bonding_realize(CGroupBonding *b) {
37         int r;
38
39         assert(b);
40         assert(b->path);
41         assert(b->controller);
42
43         r = cg_create(b->controller, b->path);
44         if (r < 0) {
45                 log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
46                 return r;
47         }
48
49         b->realized = true;
50
51         return 0;
52 }
53
54 int cgroup_bonding_realize_list(CGroupBonding *first) {
55         CGroupBonding *b;
56         int r;
57
58         LIST_FOREACH(by_unit, b, first)
59                 if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
60                         return r;
61
62         return 0;
63 }
64
65 void cgroup_bonding_free(CGroupBonding *b, bool trim) {
66         assert(b);
67
68         if (b->unit) {
69                 CGroupBonding *f;
70
71                 LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
72
73                 if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
74                         assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
75                         LIST_REMOVE(CGroupBonding, by_path, f, b);
76
77                         if (f)
78                                 hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
79                         else
80                                 hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
81                 }
82         }
83
84         if (b->realized && b->ours && trim)
85                 cg_trim(b->controller, b->path, false);
86
87         free(b->controller);
88         free(b->path);
89         free(b);
90 }
91
92 void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
93         CGroupBonding *b, *n;
94
95         LIST_FOREACH_SAFE(by_unit, b, n, first)
96                 cgroup_bonding_free(b, remove_or_trim);
97 }
98
99 void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
100         assert(b);
101
102         if (b->realized && b->ours)
103                 cg_trim(b->controller, b->path, delete_root);
104 }
105
106 void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) {
107         CGroupBonding *b;
108
109         LIST_FOREACH(by_unit, b, first)
110                 cgroup_bonding_trim(b, delete_root);
111 }
112
113 int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *cgroup_suffix) {
114         char *p = NULL;
115         const char *path;
116         int r;
117
118         assert(b);
119         assert(pid >= 0);
120
121         if (cgroup_suffix) {
122                 p = strjoin(b->path, "/", cgroup_suffix, NULL);
123                 if (!p)
124                         return -ENOMEM;
125
126                 path = p;
127         } else
128                 path = b->path;
129
130         r = cg_create_and_attach(b->controller, path, pid);
131         free(p);
132
133         if (r < 0)
134                 return r;
135
136         b->realized = true;
137         return 0;
138 }
139
140 int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid, const char *cgroup_suffix) {
141         CGroupBonding *b;
142         int r;
143
144         LIST_FOREACH(by_unit, b, first) {
145                 r = cgroup_bonding_install(b, pid, cgroup_suffix);
146                 if (r < 0 && b->essential)
147                         return r;
148         }
149
150         return 0;
151 }
152
153 int cgroup_bonding_migrate(CGroupBonding *b, CGroupBonding *list) {
154         CGroupBonding *q;
155         int ret = 0;
156
157         LIST_FOREACH(by_unit, q, list) {
158                 int r;
159
160                 if (q == b)
161                         continue;
162
163                 if (!q->ours)
164                         continue;
165
166                 r = cg_migrate_recursive(q->controller, q->path, b->controller, b->path, true, false);
167                 if (r < 0 && ret == 0)
168                         ret = r;
169         }
170
171         return ret;
172 }
173
174 int cgroup_bonding_migrate_to(CGroupBonding *b, const char *target, bool rem) {
175         assert(b);
176         assert(target);
177
178         return cg_migrate_recursive(b->controller, b->path, b->controller, target, true, rem);
179 }
180
181 int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
182         assert(b);
183
184         if (!b->realized)
185                 return -EINVAL;
186
187         return cg_set_group_access(b->controller, b->path, mode, uid, gid);
188 }
189
190 int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
191         CGroupBonding *b;
192         int r;
193
194         LIST_FOREACH(by_unit, b, first) {
195                 r = cgroup_bonding_set_group_access(b, mode, uid, gid);
196                 if (r < 0)
197                         return r;
198         }
199
200         return 0;
201 }
202
203 int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
204         assert(b);
205
206         if (!b->realized)
207                 return -EINVAL;
208
209         return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
210 }
211
212 int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
213         CGroupBonding *b;
214         int r;
215
216         LIST_FOREACH(by_unit, b, first) {
217                 r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
218                 if (r < 0)
219                         return r;
220         }
221
222         return 0;
223 }
224
225 int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
226         char *p = NULL;
227         const char *path;
228         int r;
229
230         assert(b);
231         assert(sig >= 0);
232
233         /* Don't kill cgroups that aren't ours */
234         if (!b->ours)
235                 return 0;
236
237         if (cgroup_suffix) {
238                 p = strjoin(b->path, "/", cgroup_suffix, NULL);
239                 if (!p)
240                         return -ENOMEM;
241
242                 path = p;
243         } else
244                 path = b->path;
245
246         r = cg_kill_recursive(b->controller, path, sig, sigcont, true, rem, s);
247         free(p);
248
249         return r;
250 }
251
252 int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
253         CGroupBonding *b;
254         Set *allocated_set = NULL;
255         int ret = -EAGAIN, r;
256
257         if (!first)
258                 return 0;
259
260         if (!s)
261                 if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
262                         return -ENOMEM;
263
264         LIST_FOREACH(by_unit, b, first) {
265                 r = cgroup_bonding_kill(b, sig, sigcont, rem, s, cgroup_suffix);
266                 if (r < 0) {
267                         if (r == -EAGAIN || r == -ESRCH)
268                                 continue;
269
270                         ret = r;
271                         goto finish;
272                 }
273
274                 if (ret < 0 || r > 0)
275                         ret = r;
276         }
277
278 finish:
279         if (allocated_set)
280                 set_free(allocated_set);
281
282         return ret;
283 }
284
285 /* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
286  * cannot know */
287 int cgroup_bonding_is_empty(CGroupBonding *b) {
288         int r;
289
290         assert(b);
291
292         if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
293                 return r;
294
295         /* If it is empty it is empty */
296         if (r > 0)
297                 return 1;
298
299         /* It's not only us using this cgroup, so we just don't know */
300         return b->ours ? 0 : -EAGAIN;
301 }
302
303 int cgroup_bonding_is_empty_list(CGroupBonding *first) {
304         CGroupBonding *b;
305
306         LIST_FOREACH(by_unit, b, first) {
307                 int r;
308
309                 if ((r = cgroup_bonding_is_empty(b)) < 0) {
310                         /* If this returned -EAGAIN, then we don't know if the
311                          * group is empty, so let's see if another group can
312                          * tell us */
313
314                         if (r != -EAGAIN)
315                                 return r;
316                 } else
317                         return r;
318         }
319
320         return -EAGAIN;
321 }
322
323 int manager_setup_cgroup(Manager *m) {
324         char *current = NULL, *path = NULL;
325         int r;
326         char suffix[32];
327
328         assert(m);
329
330         /* 0. Be nice to Ingo Molnar #628004 */
331         if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
332                 log_warning("No control group support available, not creating root group.");
333                 return 0;
334         }
335
336         /* 1. Determine hierarchy */
337         r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &current);
338         if (r < 0) {
339                 log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
340                 goto finish;
341         }
342
343         if (m->running_as == SYSTEMD_SYSTEM)
344                 strcpy(suffix, "/system");
345         else {
346                 snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
347                 char_array_0(suffix);
348         }
349
350         free(m->cgroup_hierarchy);
351         if (endswith(current, suffix)) {
352                 /* We probably got reexecuted and can continue to use our root cgroup */
353                 m->cgroup_hierarchy = current;
354                 current = NULL;
355
356         } else {
357                 /* We need a new root cgroup */
358                 m->cgroup_hierarchy = NULL;
359                 if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
360                         r = log_oom();
361                         goto finish;
362                 }
363         }
364
365         /* 2. Show data */
366         r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path);
367         if (r < 0) {
368                 log_error("Cannot find cgroup mount point: %s", strerror(-r));
369                 goto finish;
370         }
371
372         log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
373
374         /* 3. Install agent */
375         r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
376         if (r < 0)
377                 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
378         else if (r > 0)
379                 log_debug("Installed release agent.");
380         else
381                 log_debug("Release agent already installed.");
382
383         /* 4. Realize the group */
384         r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0);
385         if (r < 0) {
386                 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
387                 goto finish;
388         }
389
390         /* 5. And pin it, so that it cannot be unmounted */
391         if (m->pin_cgroupfs_fd >= 0)
392                 close_nointr_nofail(m->pin_cgroupfs_fd);
393
394         m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
395         if (r < 0) {
396                 log_error("Failed to open pin file: %m");
397                 r = -errno;
398                 goto finish;
399         }
400
401         log_debug("Created root group.");
402
403         cg_shorten_controllers(m->default_controllers);
404
405 finish:
406         free(current);
407         free(path);
408
409         return r;
410 }
411
412 void manager_shutdown_cgroup(Manager *m, bool delete) {
413         assert(m);
414
415         if (delete && m->cgroup_hierarchy)
416                 cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
417
418         if (m->pin_cgroupfs_fd >= 0) {
419                 close_nointr_nofail(m->pin_cgroupfs_fd);
420                 m->pin_cgroupfs_fd = -1;
421         }
422
423         free(m->cgroup_hierarchy);
424         m->cgroup_hierarchy = NULL;
425 }
426
427 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
428         CGroupBonding *b;
429         char *p;
430
431         assert(m);
432         assert(cgroup);
433         assert(bonding);
434
435         b = hashmap_get(m->cgroup_bondings, cgroup);
436         if (b) {
437                 *bonding = b;
438                 return 1;
439         }
440
441         p = strdup(cgroup);
442         if (!p)
443                 return -ENOMEM;
444
445         for (;;) {
446                 char *e;
447
448                 e = strrchr(p, '/');
449                 if (!e || e == p) {
450                         free(p);
451                         *bonding = NULL;
452                         return 0;
453                 }
454
455                 *e = 0;
456
457                 b = hashmap_get(m->cgroup_bondings, p);
458                 if (b) {
459                         free(p);
460                         *bonding = b;
461                         return 1;
462                 }
463         }
464 }
465
466 int cgroup_notify_empty(Manager *m, const char *group) {
467         CGroupBonding *l, *b;
468         int r;
469
470         assert(m);
471         assert(group);
472
473         r = cgroup_bonding_get(m, group, &l);
474         if (r <= 0)
475                 return r;
476
477         LIST_FOREACH(by_path, b, l) {
478                 int t;
479
480                 if (!b->unit)
481                         continue;
482
483                 t = cgroup_bonding_is_empty_list(b);
484                 if (t < 0) {
485
486                         /* If we don't know, we don't know */
487                         if (t != -EAGAIN)
488                                 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
489
490                         continue;
491                 }
492
493                 if (t > 0) {
494                         /* If it is empty, let's delete it */
495                         cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
496
497                         if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
498                                 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
499                 }
500         }
501
502         return 0;
503 }
504
505 Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
506         CGroupBonding *l, *b;
507         char *group = NULL;
508
509         assert(m);
510
511         if (pid <= 1)
512                 return NULL;
513
514         if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
515                 return NULL;
516
517         l = hashmap_get(m->cgroup_bondings, group);
518
519         if (!l) {
520                 char *slash;
521
522                 while ((slash = strrchr(group, '/'))) {
523                         if (slash == group)
524                                 break;
525
526                         *slash = 0;
527
528                         if ((l = hashmap_get(m->cgroup_bondings, group)))
529                                 break;
530                 }
531         }
532
533         free(group);
534
535         LIST_FOREACH(by_path, b, l) {
536
537                 if (!b->unit)
538                         continue;
539
540                 if (b->ours)
541                         return b->unit;
542         }
543
544         return NULL;
545 }
546
547 CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
548         CGroupBonding *b;
549
550         if (!controller)
551                 controller = SYSTEMD_CGROUP_CONTROLLER;
552
553         LIST_FOREACH(by_unit, b, first)
554                 if (streq(b->controller, controller))
555                         return b;
556
557         return NULL;
558 }
559
560 char *cgroup_bonding_to_string(CGroupBonding *b) {
561         char *r;
562
563         assert(b);
564
565         if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
566                 return NULL;
567
568         return r;
569 }
570
571 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
572         FILE *f;
573         pid_t pid = 0, npid, mypid;
574
575         assert(b);
576
577         if (!b->ours)
578                 return 0;
579
580         if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
581                 return 0;
582
583         mypid = getpid();
584
585         while (cg_read_pid(f, &npid) > 0)  {
586                 pid_t ppid;
587
588                 if (npid == pid)
589                         continue;
590
591                 /* Ignore processes that aren't our kids */
592                 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
593                         continue;
594
595                 if (pid != 0) {
596                         /* Dang, there's more than one daemonized PID
597                         in this group, so we don't know what process
598                         is the main process. */
599                         pid = 0;
600                         break;
601                 }
602
603                 pid = npid;
604         }
605
606         fclose(f);
607
608         return pid;
609 }
610
611 pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
612         CGroupBonding *b;
613         pid_t pid;
614
615         /* Try to find a main pid from this cgroup, but checking if
616          * there's only one PID in the cgroup and returning it. Later
617          * on we might want to add additional, smarter heuristics
618          * here. */
619
620         LIST_FOREACH(by_unit, b, first)
621                 if ((pid = cgroup_bonding_search_main_pid(b)) != 0)
622                         return pid;
623
624         return 0;
625
626 }