chiark / gitweb /
util: split-out path-util.[ch]
[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 = join(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 = join(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                         log_error("Out of memory");
334                         r = -ENOMEM;
335                         goto finish;
336                 }
337         }
338
339         /* 2. Show data */
340         r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path);
341         if (r < 0) {
342                 log_error("Cannot find cgroup mount point: %s", strerror(-r));
343                 goto finish;
344         }
345
346         log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
347
348         /* 3. Install agent */
349         r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
350         if (r < 0)
351                 log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
352         else if (r > 0)
353                 log_debug("Installed release agent.");
354         else
355                 log_debug("Release agent already installed.");
356
357         /* 4. Realize the group */
358         r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0);
359         if (r < 0) {
360                 log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
361                 goto finish;
362         }
363
364         /* 5. And pin it, so that it cannot be unmounted */
365         if (m->pin_cgroupfs_fd >= 0)
366                 close_nointr_nofail(m->pin_cgroupfs_fd);
367
368         m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
369         if (r < 0) {
370                 log_error("Failed to open pin file: %m");
371                 r = -errno;
372                 goto finish;
373         }
374
375         log_debug("Created root group.");
376
377         cg_shorten_controllers(m->default_controllers);
378
379 finish:
380         free(current);
381         free(path);
382
383         return r;
384 }
385
386 void manager_shutdown_cgroup(Manager *m, bool delete) {
387         assert(m);
388
389         if (delete && m->cgroup_hierarchy)
390                 cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
391
392         if (m->pin_cgroupfs_fd >= 0) {
393                 close_nointr_nofail(m->pin_cgroupfs_fd);
394                 m->pin_cgroupfs_fd = -1;
395         }
396
397         free(m->cgroup_hierarchy);
398         m->cgroup_hierarchy = NULL;
399 }
400
401 int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
402         CGroupBonding *b;
403         char *p;
404
405         assert(m);
406         assert(cgroup);
407         assert(bonding);
408
409         b = hashmap_get(m->cgroup_bondings, cgroup);
410         if (b) {
411                 *bonding = b;
412                 return 1;
413         }
414
415         p = strdup(cgroup);
416         if (!p)
417                 return -ENOMEM;
418
419         for (;;) {
420                 char *e;
421
422                 e = strrchr(p, '/');
423                 if (!e || e == p) {
424                         free(p);
425                         *bonding = NULL;
426                         return 0;
427                 }
428
429                 *e = 0;
430
431                 b = hashmap_get(m->cgroup_bondings, p);
432                 if (b) {
433                         free(p);
434                         *bonding = b;
435                         return 1;
436                 }
437         }
438 }
439
440 int cgroup_notify_empty(Manager *m, const char *group) {
441         CGroupBonding *l, *b;
442         int r;
443
444         assert(m);
445         assert(group);
446
447         r = cgroup_bonding_get(m, group, &l);
448         if (r <= 0)
449                 return r;
450
451         LIST_FOREACH(by_path, b, l) {
452                 int t;
453
454                 if (!b->unit)
455                         continue;
456
457                 t = cgroup_bonding_is_empty_list(b);
458                 if (t < 0) {
459
460                         /* If we don't know, we don't know */
461                         if (t != -EAGAIN)
462                                 log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
463
464                         continue;
465                 }
466
467                 if (t > 0) {
468                         /* If it is empty, let's delete it */
469                         cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
470
471                         if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
472                                 UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
473                 }
474         }
475
476         return 0;
477 }
478
479 Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
480         CGroupBonding *l, *b;
481         char *group = NULL;
482
483         assert(m);
484
485         if (pid <= 1)
486                 return NULL;
487
488         if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
489                 return NULL;
490
491         l = hashmap_get(m->cgroup_bondings, group);
492
493         if (!l) {
494                 char *slash;
495
496                 while ((slash = strrchr(group, '/'))) {
497                         if (slash == group)
498                                 break;
499
500                         *slash = 0;
501
502                         if ((l = hashmap_get(m->cgroup_bondings, group)))
503                                 break;
504                 }
505         }
506
507         free(group);
508
509         LIST_FOREACH(by_path, b, l) {
510
511                 if (!b->unit)
512                         continue;
513
514                 if (b->ours)
515                         return b->unit;
516         }
517
518         return NULL;
519 }
520
521 CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
522         CGroupBonding *b;
523
524         assert(controller);
525
526         LIST_FOREACH(by_unit, b, first)
527                 if (streq(b->controller, controller))
528                         return b;
529
530         return NULL;
531 }
532
533 char *cgroup_bonding_to_string(CGroupBonding *b) {
534         char *r;
535
536         assert(b);
537
538         if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
539                 return NULL;
540
541         return r;
542 }
543
544 pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
545         FILE *f;
546         pid_t pid = 0, npid, mypid;
547
548         assert(b);
549
550         if (!b->ours)
551                 return 0;
552
553         if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
554                 return 0;
555
556         mypid = getpid();
557
558         while (cg_read_pid(f, &npid) > 0)  {
559                 pid_t ppid;
560
561                 if (npid == pid)
562                         continue;
563
564                 /* Ignore processes that aren't our kids */
565                 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
566                         continue;
567
568                 if (pid != 0) {
569                         /* Dang, there's more than one daemonized PID
570                         in this group, so we don't know what process
571                         is the main process. */
572                         pid = 0;
573                         break;
574                 }
575
576                 pid = npid;
577         }
578
579         fclose(f);
580
581         return pid;
582 }
583
584 pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
585         CGroupBonding *b;
586         pid_t pid;
587
588         /* Try to find a main pid from this cgroup, but checking if
589          * there's only one PID in the cgroup and returning it. Later
590          * on we might want to add additional, smarter heuristics
591          * here. */
592
593         LIST_FOREACH(by_unit, b, first)
594                 if ((pid = cgroup_bonding_search_main_pid(b)) != 0)
595                         return pid;
596
597         return 0;
598
599 }