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