chiark / gitweb /
Add --enable-debug=elogind configure option and fix cgroup path
[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 2013 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 <fcntl.h>
23 #include <fnmatch.h>
24
25 #include "process-util.h"
26 #include "path-util.h"
27 // #include "special.h"
28 #include "cgroup-util.h"
29 #include "cgroup.h"
30
31 #define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
32
33 void cgroup_context_init(CGroupContext *c) {
34         assert(c);
35
36         /* Initialize everything to the kernel defaults, assuming the
37          * structure is preinitialized to 0 */
38
39         c->cpu_shares = (unsigned long) -1;
40         c->startup_cpu_shares = (unsigned long) -1;
41         c->memory_limit = (uint64_t) -1;
42         c->blockio_weight = (unsigned long) -1;
43         c->startup_blockio_weight = (unsigned long) -1;
44
45         c->cpu_quota_per_sec_usec = USEC_INFINITY;
46 }
47
48 void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
49         assert(c);
50         assert(a);
51
52         LIST_REMOVE(device_allow, c->device_allow, a);
53         free(a->path);
54         free(a);
55 }
56
57 void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) {
58         assert(c);
59         assert(w);
60
61         LIST_REMOVE(device_weights, c->blockio_device_weights, w);
62         free(w->path);
63         free(w);
64 }
65
66 void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b) {
67         assert(c);
68         assert(b);
69
70         LIST_REMOVE(device_bandwidths, c->blockio_device_bandwidths, b);
71         free(b->path);
72         free(b);
73 }
74
75 void cgroup_context_done(CGroupContext *c) {
76         assert(c);
77
78         while (c->blockio_device_weights)
79                 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
80
81         while (c->blockio_device_bandwidths)
82                 cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths);
83
84         while (c->device_allow)
85                 cgroup_context_free_device_allow(c, c->device_allow);
86 }
87
88 /// UNNEEDED by elogind
89 #if 0
90 void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
91         CGroupBlockIODeviceBandwidth *b;
92         CGroupBlockIODeviceWeight *w;
93         CGroupDeviceAllow *a;
94         char u[FORMAT_TIMESPAN_MAX];
95
96         assert(c);
97         assert(f);
98
99         prefix = strempty(prefix);
100
101         fprintf(f,
102                 "%sCPUAccounting=%s\n"
103                 "%sBlockIOAccounting=%s\n"
104                 "%sMemoryAccounting=%s\n"
105                 "%sCPUShares=%lu\n"
106                 "%sStartupCPUShares=%lu\n"
107                 "%sCPUQuotaPerSecSec=%s\n"
108                 "%sBlockIOWeight=%lu\n"
109                 "%sStartupBlockIOWeight=%lu\n"
110                 "%sMemoryLimit=%" PRIu64 "\n"
111                 "%sDevicePolicy=%s\n"
112                 "%sDelegate=%s\n",
113                 prefix, yes_no(c->cpu_accounting),
114                 prefix, yes_no(c->blockio_accounting),
115                 prefix, yes_no(c->memory_accounting),
116                 prefix, c->cpu_shares,
117                 prefix, c->startup_cpu_shares,
118                 prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
119                 prefix, c->blockio_weight,
120                 prefix, c->startup_blockio_weight,
121                 prefix, c->memory_limit,
122                 prefix, cgroup_device_policy_to_string(c->device_policy),
123                 prefix, yes_no(c->delegate));
124
125         LIST_FOREACH(device_allow, a, c->device_allow)
126                 fprintf(f,
127                         "%sDeviceAllow=%s %s%s%s\n",
128                         prefix,
129                         a->path,
130                         a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
131
132         LIST_FOREACH(device_weights, w, c->blockio_device_weights)
133                 fprintf(f,
134                         "%sBlockIODeviceWeight=%s %lu",
135                         prefix,
136                         w->path,
137                         w->weight);
138
139         LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
140                 char buf[FORMAT_BYTES_MAX];
141
142                 fprintf(f,
143                         "%s%s=%s %s\n",
144                         prefix,
145                         b->read ? "BlockIOReadBandwidth" : "BlockIOWriteBandwidth",
146                         b->path,
147                         format_bytes(buf, sizeof(buf), b->bandwidth));
148         }
149 }
150
151 static int lookup_blkio_device(const char *p, dev_t *dev) {
152         struct stat st;
153         int r;
154
155         assert(p);
156         assert(dev);
157
158         r = stat(p, &st);
159         if (r < 0)
160                 return log_warning_errno(errno, "Couldn't stat device %s: %m", p);
161
162         if (S_ISBLK(st.st_mode))
163                 *dev = st.st_rdev;
164         else if (major(st.st_dev) != 0) {
165                 /* If this is not a device node then find the block
166                  * device this file is stored on */
167                 *dev = st.st_dev;
168
169                 /* If this is a partition, try to get the originating
170                  * block device */
171                 block_get_whole_disk(*dev, dev);
172         } else {
173                 log_warning("%s is not a block device and file system block device cannot be determined or is not local.", p);
174                 return -ENODEV;
175         }
176
177         return 0;
178 }
179
180 static int whitelist_device(const char *path, const char *node, const char *acc) {
181         char buf[2+DECIMAL_STR_MAX(dev_t)*2+2+4];
182         struct stat st;
183         int r;
184
185         assert(path);
186         assert(acc);
187
188         if (stat(node, &st) < 0) {
189                 log_warning("Couldn't stat device %s", node);
190                 return -errno;
191         }
192
193         if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
194                 log_warning("%s is not a device.", node);
195                 return -ENODEV;
196         }
197
198         sprintf(buf,
199                 "%c %u:%u %s",
200                 S_ISCHR(st.st_mode) ? 'c' : 'b',
201                 major(st.st_rdev), minor(st.st_rdev),
202                 acc);
203
204         r = cg_set_attribute("devices", path, "devices.allow", buf);
205         if (r < 0)
206                 log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
207                                "Failed to set devices.allow on %s: %m", path);
208
209         return r;
210 }
211
212 static int whitelist_major(const char *path, const char *name, char type, const char *acc) {
213         _cleanup_fclose_ FILE *f = NULL;
214         char line[LINE_MAX];
215         bool good = false;
216         int r;
217
218         assert(path);
219         assert(acc);
220         assert(type == 'b' || type == 'c');
221
222         f = fopen("/proc/devices", "re");
223         if (!f)
224                 return log_warning_errno(errno, "Cannot open /proc/devices to resolve %s (%c): %m", name, type);
225
226         FOREACH_LINE(line, f, goto fail) {
227                 char buf[2+DECIMAL_STR_MAX(unsigned)+3+4], *p, *w;
228                 unsigned maj;
229
230                 truncate_nl(line);
231
232                 if (type == 'c' && streq(line, "Character devices:")) {
233                         good = true;
234                         continue;
235                 }
236
237                 if (type == 'b' && streq(line, "Block devices:")) {
238                         good = true;
239                         continue;
240                 }
241
242                 if (isempty(line)) {
243                         good = false;
244                         continue;
245                 }
246
247                 if (!good)
248                         continue;
249
250                 p = strstrip(line);
251
252                 w = strpbrk(p, WHITESPACE);
253                 if (!w)
254                         continue;
255                 *w = 0;
256
257                 r = safe_atou(p, &maj);
258                 if (r < 0)
259                         continue;
260                 if (maj <= 0)
261                         continue;
262
263                 w++;
264                 w += strspn(w, WHITESPACE);
265
266                 if (fnmatch(name, w, 0) != 0)
267                         continue;
268
269                 sprintf(buf,
270                         "%c %u:* %s",
271                         type,
272                         maj,
273                         acc);
274
275                 r = cg_set_attribute("devices", path, "devices.allow", buf);
276                 if (r < 0)
277                         log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
278                                        "Failed to set devices.allow on %s: %m", path);
279         }
280
281         return 0;
282
283 fail:
284         log_warning_errno(errno, "Failed to read /proc/devices: %m");
285         return -errno;
286 }
287
288 void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) {
289         bool is_root;
290         int r;
291
292         assert(c);
293         assert(path);
294
295         if (mask == 0)
296                 return;
297
298         /* Some cgroup attributes are not supported on the root cgroup,
299          * hence silently ignore */
300         is_root = isempty(path) || path_equal(path, "/");
301         if (is_root)
302                 /* Make sure we don't try to display messages with an empty path. */
303                 path = "/";
304
305         /* We generally ignore errors caused by read-only mounted
306          * cgroup trees (assuming we are running in a container then),
307          * and missing cgroups, i.e. EROFS and ENOENT. */
308
309         if ((mask & CGROUP_MASK_CPU) && !is_root) {
310                 char buf[MAX(DECIMAL_STR_MAX(unsigned long), DECIMAL_STR_MAX(usec_t)) + 1];
311
312                 sprintf(buf, "%lu\n",
313                         IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != (unsigned long) -1 ? c->startup_cpu_shares :
314                         c->cpu_shares != (unsigned long) -1 ? c->cpu_shares : 1024);
315                 r = cg_set_attribute("cpu", path, "cpu.shares", buf);
316                 if (r < 0)
317                         log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
318                                        "Failed to set cpu.shares on %s: %m", path);
319
320                 sprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
321                 r = cg_set_attribute("cpu", path, "cpu.cfs_period_us", buf);
322                 if (r < 0)
323                         log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
324                                        "Failed to set cpu.cfs_period_us on %s: %m", path);
325
326                 if (c->cpu_quota_per_sec_usec != USEC_INFINITY) {
327                         sprintf(buf, USEC_FMT "\n", c->cpu_quota_per_sec_usec * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC);
328                         r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", buf);
329                 } else
330                         r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", "-1");
331                 if (r < 0)
332                         log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
333                                        "Failed to set cpu.cfs_quota_us on %s: %m", path);
334         }
335
336         if (mask & CGROUP_MASK_BLKIO) {
337                 char buf[MAX3(DECIMAL_STR_MAX(unsigned long)+1,
338                               DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(unsigned long)*1,
339                               DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
340                 CGroupBlockIODeviceWeight *w;
341                 CGroupBlockIODeviceBandwidth *b;
342
343                 if (!is_root) {
344                         sprintf(buf, "%lu\n", IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != (unsigned long) -1 ? c->startup_blockio_weight :
345                                 c->blockio_weight != (unsigned long) -1 ? c->blockio_weight : 1000);
346                         r = cg_set_attribute("blkio", path, "blkio.weight", buf);
347                         if (r < 0)
348                                 log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
349                                                "Failed to set blkio.weight on %s: %m", path);
350
351                         /* FIXME: no way to reset this list */
352                         LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
353                                 dev_t dev;
354
355                                 r = lookup_blkio_device(w->path, &dev);
356                                 if (r < 0)
357                                         continue;
358
359                                 sprintf(buf, "%u:%u %lu", major(dev), minor(dev), w->weight);
360                                 r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
361                                 if (r < 0)
362                                         log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
363                                                        "Failed to set blkio.weight_device on %s: %m", path);
364                         }
365                 }
366
367                 /* FIXME: no way to reset this list */
368                 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
369                         const char *a;
370                         dev_t dev;
371
372                         r = lookup_blkio_device(b->path, &dev);
373                         if (r < 0)
374                                 continue;
375
376                         a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device";
377
378                         sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
379                         r = cg_set_attribute("blkio", path, a, buf);
380                         if (r < 0)
381                                 log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
382                                                "Failed to set %s on %s: %m", a, path);
383                 }
384         }
385
386         if ((mask & CGROUP_MASK_MEMORY) && !is_root) {
387                 if (c->memory_limit != (uint64_t) -1) {
388                         char buf[DECIMAL_STR_MAX(uint64_t) + 1];
389
390                         sprintf(buf, "%" PRIu64 "\n", c->memory_limit);
391
392                         if (cg_unified() <= 0)
393                                 r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
394                         else
395                                 r = cg_set_attribute("memory", path, "memory.max", buf);
396
397                 } else {
398                         if (cg_unified() <= 0)
399                                 r = cg_set_attribute("memory", path, "memory.limit_in_bytes", "-1");
400                         else
401                                 r = cg_set_attribute("memory", path, "memory.max", "max");
402                 }
403
404                 if (r < 0)
405                         log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
406                                        "Failed to set memory.limit_in_bytes/memory.max on %s: %m", path);
407         }
408
409         if ((mask & CGROUP_MASK_DEVICE) && !is_root) {
410                 CGroupDeviceAllow *a;
411
412                 /* Changing the devices list of a populated cgroup
413                  * might result in EINVAL, hence ignore EINVAL
414                  * here. */
415
416                 if (c->device_allow || c->device_policy != CGROUP_AUTO)
417                         r = cg_set_attribute("devices", path, "devices.deny", "a");
418                 else
419                         r = cg_set_attribute("devices", path, "devices.allow", "a");
420                 if (r < 0)
421                         log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
422                                        "Failed to reset devices.list on %s: %m", path);
423
424                 if (c->device_policy == CGROUP_CLOSED ||
425                     (c->device_policy == CGROUP_AUTO && c->device_allow)) {
426                         static const char auto_devices[] =
427                                 "/dev/null\0" "rwm\0"
428                                 "/dev/zero\0" "rwm\0"
429                                 "/dev/full\0" "rwm\0"
430                                 "/dev/random\0" "rwm\0"
431                                 "/dev/urandom\0" "rwm\0"
432                                 "/dev/tty\0" "rwm\0"
433                                 "/dev/pts/ptmx\0" "rw\0"; /* /dev/pts/ptmx may not be duplicated, but accessed */
434
435                         const char *x, *y;
436
437                         NULSTR_FOREACH_PAIR(x, y, auto_devices)
438                                 whitelist_device(path, x, y);
439
440                         whitelist_major(path, "pts", 'c', "rw");
441                         whitelist_major(path, "kdbus", 'c', "rw");
442                         whitelist_major(path, "kdbus/*", 'c', "rw");
443                 }
444
445                 LIST_FOREACH(device_allow, a, c->device_allow) {
446                         char acc[4];
447                         unsigned k = 0;
448
449                         if (a->r)
450                                 acc[k++] = 'r';
451                         if (a->w)
452                                 acc[k++] = 'w';
453                         if (a->m)
454                                 acc[k++] = 'm';
455
456                         if (k == 0)
457                                 continue;
458
459                         acc[k++] = 0;
460
461                         if (startswith(a->path, "/dev/"))
462                                 whitelist_device(path, a->path, acc);
463                         else if (startswith(a->path, "block-"))
464                                 whitelist_major(path, a->path + 6, 'b', acc);
465                         else if (startswith(a->path, "char-"))
466                                 whitelist_major(path, a->path + 5, 'c', acc);
467                         else
468                                 log_debug("Ignoring device %s while writing cgroup attribute.", a->path);
469                 }
470         }
471 }
472 #endif // 0
473
474 CGroupMask cgroup_context_get_mask(CGroupContext *c) {
475         CGroupMask mask = 0;
476
477         /* Figure out which controllers we need */
478
479         if (c->cpu_accounting ||
480             c->cpu_shares != (unsigned long) -1 ||
481             c->startup_cpu_shares != (unsigned long) -1 ||
482             c->cpu_quota_per_sec_usec != USEC_INFINITY)
483                 mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU;
484
485         if (c->blockio_accounting ||
486             c->blockio_weight != (unsigned long) -1 ||
487             c->startup_blockio_weight != (unsigned long) -1 ||
488             c->blockio_device_weights ||
489             c->blockio_device_bandwidths)
490                 mask |= CGROUP_MASK_BLKIO;
491
492         if (c->memory_accounting ||
493             c->memory_limit != (uint64_t) -1)
494                 mask |= CGROUP_MASK_MEMORY;
495
496         if (c->device_allow ||
497             c->device_policy != CGROUP_AUTO)
498                 mask |= CGROUP_MASK_DEVICE;
499
500         return mask;
501 }
502
503 /// UNNEEDED by elogind
504 #if 0
505 CGroupMask unit_get_own_mask(Unit *u) {
506         CGroupContext *c;
507
508         /* Returns the mask of controllers the unit needs for itself */
509
510         c = unit_get_cgroup_context(u);
511         if (!c)
512                 return 0;
513
514         /* If delegation is turned on, then turn on all cgroups,
515          * unless we are on the legacy hierarchy and the process we
516          * fork into it is known to drop privileges, and hence
517          * shouldn't get access to the controllers.
518          *
519          * Note that on the unified hierarchy it is safe to delegate
520          * controllers to unprivileged services. */
521
522         if (c->delegate) {
523                 ExecContext *e;
524
525                 e = unit_get_exec_context(u);
526                 if (!e ||
527                     exec_context_maintains_privileges(e) ||
528                     cg_unified() > 0)
529                         return _CGROUP_MASK_ALL;
530         }
531
532         return cgroup_context_get_mask(c);
533 }
534
535 CGroupMask unit_get_members_mask(Unit *u) {
536         assert(u);
537
538         /* Returns the mask of controllers all of the unit's children
539          * require, merged */
540
541         if (u->cgroup_members_mask_valid)
542                 return u->cgroup_members_mask;
543
544         u->cgroup_members_mask = 0;
545
546         if (u->type == UNIT_SLICE) {
547                 Unit *member;
548                 Iterator i;
549
550                 SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) {
551
552                         if (member == u)
553                                 continue;
554
555                         if (UNIT_DEREF(member->slice) != u)
556                                 continue;
557
558                         u->cgroup_members_mask |=
559                                 unit_get_own_mask(member) |
560                                 unit_get_members_mask(member);
561                 }
562         }
563
564         u->cgroup_members_mask_valid = true;
565         return u->cgroup_members_mask;
566 }
567
568 CGroupMask unit_get_siblings_mask(Unit *u) {
569         assert(u);
570
571         /* Returns the mask of controllers all of the unit's siblings
572          * require, i.e. the members mask of the unit's parent slice
573          * if there is one. */
574
575         if (UNIT_ISSET(u->slice))
576                 return unit_get_members_mask(UNIT_DEREF(u->slice));
577
578         return unit_get_own_mask(u) | unit_get_members_mask(u);
579 }
580
581 CGroupMask unit_get_subtree_mask(Unit *u) {
582
583         /* Returns the mask of this subtree, meaning of the group
584          * itself and its children. */
585
586         return unit_get_own_mask(u) | unit_get_members_mask(u);
587 }
588
589 CGroupMask unit_get_target_mask(Unit *u) {
590         CGroupMask mask;
591
592         /* This returns the cgroup mask of all controllers to enable
593          * for a specific cgroup, i.e. everything it needs itself,
594          * plus all that its children need, plus all that its siblings
595          * need. This is primarily useful on the legacy cgroup
596          * hierarchy, where we need to duplicate each cgroup in each
597          * hierarchy that shall be enabled for it. */
598
599         mask = unit_get_own_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u);
600         mask &= u->manager->cgroup_supported;
601
602         return mask;
603 }
604
605 CGroupMask unit_get_enable_mask(Unit *u) {
606         CGroupMask mask;
607
608         /* This returns the cgroup mask of all controllers to enable
609          * for the children of a specific cgroup. This is primarily
610          * useful for the unified cgroup hierarchy, where each cgroup
611          * controls which controllers are enabled for its children. */
612
613         mask = unit_get_members_mask(u);
614         mask &= u->manager->cgroup_supported;
615
616         return mask;
617 }
618
619 /* Recurse from a unit up through its containing slices, propagating
620  * mask bits upward. A unit is also member of itself. */
621 void unit_update_cgroup_members_masks(Unit *u) {
622         CGroupMask m;
623         bool more;
624
625         assert(u);
626
627         /* Calculate subtree mask */
628         m = unit_get_subtree_mask(u);
629
630         /* See if anything changed from the previous invocation. If
631          * not, we're done. */
632         if (u->cgroup_subtree_mask_valid && m == u->cgroup_subtree_mask)
633                 return;
634
635         more =
636                 u->cgroup_subtree_mask_valid &&
637                 ((m & ~u->cgroup_subtree_mask) != 0) &&
638                 ((~m & u->cgroup_subtree_mask) == 0);
639
640         u->cgroup_subtree_mask = m;
641         u->cgroup_subtree_mask_valid = true;
642
643         if (UNIT_ISSET(u->slice)) {
644                 Unit *s = UNIT_DEREF(u->slice);
645
646                 if (more)
647                         /* There's more set now than before. We
648                          * propagate the new mask to the parent's mask
649                          * (not caring if it actually was valid or
650                          * not). */
651
652                         s->cgroup_members_mask |= m;
653
654                 else
655                         /* There's less set now than before (or we
656                          * don't know), we need to recalculate
657                          * everything, so let's invalidate the
658                          * parent's members mask */
659
660                         s->cgroup_members_mask_valid = false;
661
662                 /* And now make sure that this change also hits our
663                  * grandparents */
664                 unit_update_cgroup_members_masks(s);
665         }
666 }
667
668 static const char *migrate_callback(CGroupMask mask, void *userdata) {
669         Unit *u = userdata;
670
671         assert(mask != 0);
672         assert(u);
673
674         while (u) {
675                 if (u->cgroup_path &&
676                     u->cgroup_realized &&
677                     (u->cgroup_realized_mask & mask) == mask)
678                         return u->cgroup_path;
679
680                 u = UNIT_DEREF(u->slice);
681         }
682
683         return NULL;
684 }
685
686 char *unit_default_cgroup_path(Unit *u) {
687         _cleanup_free_ char *escaped = NULL, *slice = NULL;
688         int r;
689
690         assert(u);
691
692         if (unit_has_name(u, SPECIAL_ROOT_SLICE))
693                 return strdup(u->manager->cgroup_root);
694
695         if (UNIT_ISSET(u->slice) && !unit_has_name(UNIT_DEREF(u->slice), SPECIAL_ROOT_SLICE)) {
696                 r = cg_slice_to_path(UNIT_DEREF(u->slice)->id, &slice);
697                 if (r < 0)
698                         return NULL;
699         }
700
701         escaped = cg_escape(u->id);
702         if (!escaped)
703                 return NULL;
704
705         if (slice)
706                 return strjoin(u->manager->cgroup_root, "/", slice, "/", escaped, NULL);
707         else
708                 return strjoin(u->manager->cgroup_root, "/", escaped, NULL);
709 }
710
711 int unit_set_cgroup_path(Unit *u, const char *path) {
712         _cleanup_free_ char *p = NULL;
713         int r;
714
715         assert(u);
716
717         if (path) {
718                 p = strdup(path);
719                 if (!p)
720                         return -ENOMEM;
721         } else
722                 p = NULL;
723
724         if (streq_ptr(u->cgroup_path, p))
725                 return 0;
726
727         if (p) {
728                 r = hashmap_put(u->manager->cgroup_unit, p, u);
729                 if (r < 0)
730                         return r;
731         }
732
733         unit_release_cgroup(u);
734
735         u->cgroup_path = p;
736         p = NULL;
737
738         return 1;
739 }
740
741 int unit_watch_cgroup(Unit *u) {
742         _cleanup_free_ char *populated = NULL;
743         int r;
744
745         assert(u);
746
747         if (!u->cgroup_path)
748                 return 0;
749
750         if (u->cgroup_inotify_wd >= 0)
751                 return 0;
752
753         /* Only applies to the unified hierarchy */
754         r = cg_unified();
755         if (r < 0)
756                 return log_unit_error_errno(u, r, "Failed detect wether the unified hierarchy is used: %m");
757         if (r == 0)
758                 return 0;
759
760         /* Don't watch the root slice, it's pointless. */
761         if (unit_has_name(u, SPECIAL_ROOT_SLICE))
762                 return 0;
763
764         r = hashmap_ensure_allocated(&u->manager->cgroup_inotify_wd_unit, &trivial_hash_ops);
765         if (r < 0)
766                 return log_oom();
767
768         r = cg_get_path(ELOGIND_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.populated", &populated);
769         if (r < 0)
770                 return log_oom();
771
772         u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, populated, IN_MODIFY);
773         if (u->cgroup_inotify_wd < 0) {
774
775                 if (errno == ENOENT) /* If the directory is already
776                                       * gone we don't need to track
777                                       * it, so this is not an error */
778                         return 0;
779
780                 return log_unit_error_errno(u, errno, "Failed to add inotify watch descriptor for control group %s: %m", u->cgroup_path);
781         }
782
783         r = hashmap_put(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd), u);
784         if (r < 0)
785                 return log_unit_error_errno(u, r, "Failed to add inotify watch descriptor to hash map: %m");
786
787         return 0;
788 }
789
790 static int unit_create_cgroup(
791                 Unit *u,
792                 CGroupMask target_mask,
793                 CGroupMask enable_mask) {
794
795         CGroupContext *c;
796         int r;
797
798         assert(u);
799
800         c = unit_get_cgroup_context(u);
801         if (!c)
802                 return 0;
803
804         if (!u->cgroup_path) {
805                 _cleanup_free_ char *path = NULL;
806
807                 path = unit_default_cgroup_path(u);
808                 if (!path)
809                         return log_oom();
810
811                 r = unit_set_cgroup_path(u, path);
812                 if (r == -EEXIST)
813                         return log_unit_error_errno(u, r, "Control group %s exists already.", path);
814                 if (r < 0)
815                         return log_unit_error_errno(u, r, "Failed to set unit's control group path to %s: %m", path);
816         }
817
818         /* First, create our own group */
819         r = cg_create_everywhere(u->manager->cgroup_supported, target_mask, u->cgroup_path);
820         if (r < 0)
821                 return log_unit_error_errno(u, r, "Failed to create cgroup %s: %m", u->cgroup_path);
822
823         /* Start watching it */
824         (void) unit_watch_cgroup(u);
825
826         /* Enable all controllers we need */
827         r = cg_enable_everywhere(u->manager->cgroup_supported, enable_mask, u->cgroup_path);
828         if (r < 0)
829                 log_unit_warning_errno(u, r, "Failed to enable controllers on cgroup %s, ignoring: %m", u->cgroup_path);
830
831         /* Keep track that this is now realized */
832         u->cgroup_realized = true;
833         u->cgroup_realized_mask = target_mask;
834
835         if (u->type != UNIT_SLICE && !c->delegate) {
836
837                 /* Then, possibly move things over, but not if
838                  * subgroups may contain processes, which is the case
839                  * for slice and delegation units. */
840                 r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u);
841                 if (r < 0)
842                         log_unit_warning_errno(u, r, "Failed to migrate cgroup from to %s, ignoring: %m", u->cgroup_path);
843         }
844
845         return 0;
846 }
847
848 int unit_attach_pids_to_cgroup(Unit *u) {
849         int r;
850         assert(u);
851
852         r = unit_realize_cgroup(u);
853         if (r < 0)
854                 return r;
855
856         r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->pids, migrate_callback, u);
857         if (r < 0)
858                 return r;
859
860         return 0;
861 }
862
863 static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask) {
864         assert(u);
865
866         return u->cgroup_realized && u->cgroup_realized_mask == target_mask;
867 }
868
869 /* Check if necessary controllers and attributes for a unit are in place.
870  *
871  * If so, do nothing.
872  * If not, create paths, move processes over, and set attributes.
873  *
874  * Returns 0 on success and < 0 on failure. */
875 static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
876         CGroupMask target_mask, enable_mask;
877         int r;
878
879         assert(u);
880
881         if (u->in_cgroup_queue) {
882                 LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
883                 u->in_cgroup_queue = false;
884         }
885
886         target_mask = unit_get_target_mask(u);
887         if (unit_has_mask_realized(u, target_mask))
888                 return 0;
889
890         /* First, realize parents */
891         if (UNIT_ISSET(u->slice)) {
892                 r = unit_realize_cgroup_now(UNIT_DEREF(u->slice), state);
893                 if (r < 0)
894                         return r;
895         }
896
897         /* And then do the real work */
898         enable_mask = unit_get_enable_mask(u);
899         r = unit_create_cgroup(u, target_mask, enable_mask);
900         if (r < 0)
901                 return r;
902
903         /* Finally, apply the necessary attributes. */
904         cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, state);
905
906         return 0;
907 }
908
909 static void unit_add_to_cgroup_queue(Unit *u) {
910
911         if (u->in_cgroup_queue)
912                 return;
913
914         LIST_PREPEND(cgroup_queue, u->manager->cgroup_queue, u);
915         u->in_cgroup_queue = true;
916 }
917
918 unsigned manager_dispatch_cgroup_queue(Manager *m) {
919         ManagerState state;
920         unsigned n = 0;
921         Unit *i;
922         int r;
923
924         state = manager_state(m);
925
926         while ((i = m->cgroup_queue)) {
927                 assert(i->in_cgroup_queue);
928
929                 r = unit_realize_cgroup_now(i, state);
930                 if (r < 0)
931                         log_warning_errno(r, "Failed to realize cgroups for queued unit %s, ignoring: %m", i->id);
932
933                 n++;
934         }
935
936         return n;
937 }
938
939 static void unit_queue_siblings(Unit *u) {
940         Unit *slice;
941
942         /* This adds the siblings of the specified unit and the
943          * siblings of all parent units to the cgroup queue. (But
944          * neither the specified unit itself nor the parents.) */
945
946         while ((slice = UNIT_DEREF(u->slice))) {
947                 Iterator i;
948                 Unit *m;
949
950                 SET_FOREACH(m, slice->dependencies[UNIT_BEFORE], i) {
951                         if (m == u)
952                                 continue;
953
954                         /* Skip units that have a dependency on the slice
955                          * but aren't actually in it. */
956                         if (UNIT_DEREF(m->slice) != slice)
957                                 continue;
958
959                         /* No point in doing cgroup application for units
960                          * without active processes. */
961                         if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m)))
962                                 continue;
963
964                         /* If the unit doesn't need any new controllers
965                          * and has current ones realized, it doesn't need
966                          * any changes. */
967                         if (unit_has_mask_realized(m, unit_get_target_mask(m)))
968                                 continue;
969
970                         unit_add_to_cgroup_queue(m);
971                 }
972
973                 u = slice;
974         }
975 }
976
977 int unit_realize_cgroup(Unit *u) {
978         assert(u);
979
980         if (!UNIT_HAS_CGROUP_CONTEXT(u))
981                 return 0;
982
983         /* So, here's the deal: when realizing the cgroups for this
984          * unit, we need to first create all parents, but there's more
985          * actually: for the weight-based controllers we also need to
986          * make sure that all our siblings (i.e. units that are in the
987          * same slice as we are) have cgroups, too. Otherwise, things
988          * would become very uneven as each of their processes would
989          * get as much resources as all our group together. This call
990          * will synchronously create the parent cgroups, but will
991          * defer work on the siblings to the next event loop
992          * iteration. */
993
994         /* Add all sibling slices to the cgroup queue. */
995         unit_queue_siblings(u);
996
997         /* And realize this one now (and apply the values) */
998         return unit_realize_cgroup_now(u, manager_state(u->manager));
999 }
1000
1001 void unit_release_cgroup(Unit *u) {
1002         assert(u);
1003
1004         /* Forgets all cgroup details for this cgroup */
1005
1006         if (u->cgroup_path) {
1007                 (void) hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
1008                 u->cgroup_path = mfree(u->cgroup_path);
1009         }
1010
1011         if (u->cgroup_inotify_wd >= 0) {
1012                 if (inotify_rm_watch(u->manager->cgroup_inotify_fd, u->cgroup_inotify_wd) < 0)
1013                         log_unit_debug_errno(u, errno, "Failed to remove cgroup inotify watch %i for %s, ignoring", u->cgroup_inotify_wd, u->id);
1014
1015                 (void) hashmap_remove(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd));
1016                 u->cgroup_inotify_wd = -1;
1017         }
1018 }
1019
1020 void unit_prune_cgroup(Unit *u) {
1021         int r;
1022         bool is_root_slice;
1023
1024         assert(u);
1025
1026         /* Removes the cgroup, if empty and possible, and stops watching it. */
1027
1028         if (!u->cgroup_path)
1029                 return;
1030
1031         is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
1032
1033         r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice);
1034         if (r < 0) {
1035                 log_debug_errno(r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path);
1036                 return;
1037         }
1038
1039         if (is_root_slice)
1040                 return;
1041
1042         unit_release_cgroup(u);
1043
1044         u->cgroup_realized = false;
1045         u->cgroup_realized_mask = 0;
1046 }
1047
1048 int unit_search_main_pid(Unit *u, pid_t *ret) {
1049         _cleanup_fclose_ FILE *f = NULL;
1050         pid_t pid = 0, npid, mypid;
1051         int r;
1052
1053         assert(u);
1054         assert(ret);
1055
1056         if (!u->cgroup_path)
1057                 return -ENXIO;
1058
1059         r = cg_enumerate_processes(ELOGIND_CGROUP_CONTROLLER, u->cgroup_path, &f);
1060         if (r < 0)
1061                 return r;
1062
1063         mypid = getpid();
1064         while (cg_read_pid(f, &npid) > 0)  {
1065                 pid_t ppid;
1066
1067                 if (npid == pid)
1068                         continue;
1069
1070                 /* Ignore processes that aren't our kids */
1071                 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
1072                         continue;
1073
1074                 if (pid != 0)
1075                         /* Dang, there's more than one daemonized PID
1076                         in this group, so we don't know what process
1077                         is the main process. */
1078
1079                         return -ENODATA;
1080
1081                 pid = npid;
1082         }
1083
1084         *ret = pid;
1085         return 0;
1086 }
1087
1088 static int unit_watch_pids_in_path(Unit *u, const char *path) {
1089         _cleanup_closedir_ DIR *d = NULL;
1090         _cleanup_fclose_ FILE *f = NULL;
1091         int ret = 0, r;
1092
1093         assert(u);
1094         assert(path);
1095
1096         r = cg_enumerate_processes(ELOGIND_CGROUP_CONTROLLER, path, &f);
1097         if (r < 0)
1098                 ret = r;
1099         else {
1100                 pid_t pid;
1101
1102                 while ((r = cg_read_pid(f, &pid)) > 0) {
1103                         r = unit_watch_pid(u, pid);
1104                         if (r < 0 && ret >= 0)
1105                                 ret = r;
1106                 }
1107
1108                 if (r < 0 && ret >= 0)
1109                         ret = r;
1110         }
1111
1112         r = cg_enumerate_subgroups(ELOGIND_CGROUP_CONTROLLER, path, &d);
1113         if (r < 0) {
1114                 if (ret >= 0)
1115                         ret = r;
1116         } else {
1117                 char *fn;
1118
1119                 while ((r = cg_read_subgroup(d, &fn)) > 0) {
1120                         _cleanup_free_ char *p = NULL;
1121
1122                         p = strjoin(path, "/", fn, NULL);
1123                         free(fn);
1124
1125                         if (!p)
1126                                 return -ENOMEM;
1127
1128                         r = unit_watch_pids_in_path(u, p);
1129                         if (r < 0 && ret >= 0)
1130                                 ret = r;
1131                 }
1132
1133                 if (r < 0 && ret >= 0)
1134                         ret = r;
1135         }
1136
1137         return ret;
1138 }
1139
1140 int unit_watch_all_pids(Unit *u) {
1141         assert(u);
1142
1143         /* Adds all PIDs from our cgroup to the set of PIDs we
1144          * watch. This is a fallback logic for cases where we do not
1145          * get reliable cgroup empty notifications: we try to use
1146          * SIGCHLD as replacement. */
1147
1148         if (!u->cgroup_path)
1149                 return -ENOENT;
1150
1151         if (cg_unified() > 0) /* On unified we can use proper notifications */
1152                 return 0;
1153
1154         return unit_watch_pids_in_path(u, u->cgroup_path);
1155 }
1156
1157 int unit_notify_cgroup_empty(Unit *u) {
1158         int r;
1159
1160         assert(u);
1161
1162         if (!u->cgroup_path)
1163                 return 0;
1164
1165         r = cg_is_empty_recursive(ELOGIND_CGROUP_CONTROLLER, u->cgroup_path);
1166         if (r <= 0)
1167                 return r;
1168
1169         unit_add_to_gc_queue(u);
1170
1171         if (UNIT_VTABLE(u)->notify_cgroup_empty)
1172                 UNIT_VTABLE(u)->notify_cgroup_empty(u);
1173
1174         return 0;
1175 }
1176
1177 static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
1178         Manager *m = userdata;
1179
1180         assert(s);
1181         assert(fd >= 0);
1182         assert(m);
1183
1184         for (;;) {
1185                 union inotify_event_buffer buffer;
1186                 struct inotify_event *e;
1187                 ssize_t l;
1188
1189                 l = read(fd, &buffer, sizeof(buffer));
1190                 if (l < 0) {
1191                         if (errno == EINTR || errno == EAGAIN)
1192                                 return 0;
1193
1194                         return log_error_errno(errno, "Failed to read control group inotify events: %m");
1195                 }
1196
1197                 FOREACH_INOTIFY_EVENT(e, buffer, l) {
1198                         Unit *u;
1199
1200                         if (e->wd < 0)
1201                                 /* Queue overflow has no watch descriptor */
1202                                 continue;
1203
1204                         if (e->mask & IN_IGNORED)
1205                                 /* The watch was just removed */
1206                                 continue;
1207
1208                         u = hashmap_get(m->cgroup_inotify_wd_unit, INT_TO_PTR(e->wd));
1209                         if (!u) /* Not that inotify might deliver
1210                                  * events for a watch even after it
1211                                  * was removed, because it was queued
1212                                  * before the removal. Let's ignore
1213                                  * this here safely. */
1214                                 continue;
1215
1216                         (void) unit_notify_cgroup_empty(u);
1217                 }
1218         }
1219 }
1220 #endif // 0
1221
1222 int manager_setup_cgroup(Manager *m) {
1223         _cleanup_free_ char *path = NULL;
1224         CGroupController c;
1225         int r, unified;
1226         char *e;
1227
1228         assert(m);
1229
1230         /* 1. Determine hierarchy */
1231         m->cgroup_root = mfree(m->cgroup_root);
1232         r = cg_pid_get_path(ELOGIND_CGROUP_CONTROLLER, 0, &m->cgroup_root);
1233         if (r < 0)
1234                 return log_error_errno(r, "Cannot determine cgroup we are running in: %m");
1235 /// elogind does not support systemd scopes and slices
1236 #if 0
1237         /* Chop off the init scope, if we are already located in it */
1238         e = endswith(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
1239
1240         /* LEGACY: Also chop off the system slice if we are in
1241          * it. This is to support live upgrades from older systemd
1242          * versions where PID 1 was moved there. Also see
1243          * cg_get_root_path(). */
1244         if (!e) {
1245                 e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
1246                 if (!e)
1247                         e = endswith(m->cgroup_root, "/system"); /* even more legacy */
1248         }
1249         if (e)
1250                 *e = 0;
1251 #endif // 0
1252
1253         /* And make sure to store away the root value without trailing
1254          * slash, even for the root dir, so that we can easily prepend
1255          * it everywhere. */
1256         while ((e = endswith(m->cgroup_root, "/")))
1257                 *e = 0;
1258         log_debug_elogind("Cgroup Controller \"%s\" -> root \"%s\"",
1259                           ELOGIND_CGROUP_CONTROLLER, m->cgroup_root);
1260
1261         /* 2. Show data */
1262         r = cg_get_path(ELOGIND_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path);
1263         if (r < 0)
1264                 return log_error_errno(r, "Cannot find cgroup mount point: %m");
1265
1266         unified = cg_unified();
1267         if (unified < 0)
1268                 return log_error_errno(r, "Couldn't determine if we are running in the unified hierarchy: %m");
1269         if (unified > 0)
1270                 log_debug("Unified cgroup hierarchy is located at %s.", path);
1271         else
1272                 log_debug("Using cgroup controller " ELOGIND_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
1273
1274         if (!m->test_run) {
1275                 const char *scope_path;
1276
1277                 /* 3. Install agent */
1278                 if (unified) {
1279
1280                         /* In the unified hierarchy we can can get
1281                          * cgroup empty notifications via inotify. */
1282 /// elogind does not support the unified hierarchy, yet.
1283 #if 0
1284                         m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
1285                         safe_close(m->cgroup_inotify_fd);
1286
1287                         m->cgroup_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1288                         if (m->cgroup_inotify_fd < 0)
1289                                 return log_error_errno(errno, "Failed to create control group inotify object: %m");
1290
1291                         r = sd_event_add_io(m->event, &m->cgroup_inotify_event_source, m->cgroup_inotify_fd, EPOLLIN, on_cgroup_inotify_event, m);
1292                         if (r < 0)
1293                                 return log_error_errno(r, "Failed to watch control group inotify object: %m");
1294
1295                         r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_IDLE - 5);
1296                         if (r < 0)
1297                                 return log_error_errno(r, "Failed to set priority of inotify event source: %m");
1298
1299                         (void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
1300
1301 #else
1302                         return log_error_errno(EOPNOTSUPP, "Unified cgroup hierarchy not supported: %m");
1303 #endif // elogind
1304                 } else if (m->running_as == MANAGER_SYSTEM) {
1305                         /* On the legacy hierarchy we only get
1306                          * notifications via cgroup agents. (Which
1307                          * isn't really reliable, since it does not
1308                          * generate events when control groups with
1309                          * children run empty. */
1310
1311                         r = cg_install_release_agent(ELOGIND_CGROUP_CONTROLLER, ELOGIND_CGROUP_AGENT_PATH);
1312                         if (r < 0)
1313                                 log_warning_errno(r, "Failed to install release agent, ignoring: %m");
1314                         else if (r > 0)
1315                                 log_debug("Installed release agent.");
1316                         else if (r == 0)
1317                                 log_debug("Release agent already installed.");
1318                 }
1319
1320 /// elogind is not meant to run in systemd init scope
1321 #if 0
1322                 /* 4. Make sure we are in the special "init.scope" unit in the root slice. */
1323                 scope_path = strjoina(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
1324                 r = cg_create_and_attach(ELOGIND_CGROUP_CONTROLLER, scope_path, 0);
1325 #else
1326                 if (streq(m->cgroup_root, "/elogind"))
1327                         // root already is our cgroup
1328                         scope_path = strjoina(m->cgroup_root);
1329                 else
1330                         // we have to create our own group
1331                         scope_path = strjoina(m->cgroup_root, "/elogind");
1332                 r = cg_create_and_attach(ELOGIND_CGROUP_CONTROLLER, scope_path, 0);
1333 #endif // 0
1334                 if (r < 0)
1335                         return log_error_errno(r, "Failed to create %s control group: %m", scope_path);
1336                 log_debug_elogind("Created control group \"%s\"", scope_path);
1337
1338                 /* also, move all other userspace processes remaining
1339                  * in the root cgroup into that scope. */
1340                 if (!streq(m->cgroup_root, scope_path)) {
1341                         r = cg_migrate(ELOGIND_CGROUP_CONTROLLER, m->cgroup_root, ELOGIND_CGROUP_CONTROLLER, scope_path, false);
1342                         if (r < 0)
1343                                 log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %m");
1344                 }
1345
1346                 /* 5. And pin it, so that it cannot be unmounted */
1347                 safe_close(m->pin_cgroupfs_fd);
1348                 m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
1349                 if (m->pin_cgroupfs_fd < 0)
1350                         return log_error_errno(errno, "Failed to open pin file: %m");
1351
1352                 /* 6.  Always enable hierarchical support if it exists... */
1353                 if (!unified)
1354                         (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
1355         }
1356
1357         /* 7. Figure out which controllers are supported */
1358         r = cg_mask_supported(&m->cgroup_supported);
1359         if (r < 0)
1360                 return log_error_errno(r, "Failed to determine supported controllers: %m");
1361
1362         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
1363                 log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & c));
1364
1365         return 0;
1366 }
1367
1368 void manager_shutdown_cgroup(Manager *m, bool delete) {
1369         assert(m);
1370
1371         /* We can't really delete the group, since we are in it. But
1372          * let's trim it. */
1373         if (delete && m->cgroup_root)
1374                 (void) cg_trim(ELOGIND_CGROUP_CONTROLLER, m->cgroup_root, false);
1375
1376 /// elogind does not support the unified hierarchy, yet.
1377 #if 0
1378         m->cgroup_inotify_wd_unit = hashmap_free(m->cgroup_inotify_wd_unit);
1379
1380         m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
1381         m->cgroup_inotify_fd = safe_close(m->cgroup_inotify_fd);
1382 #endif // 0
1383
1384         m->pin_cgroupfs_fd = safe_close(m->pin_cgroupfs_fd);
1385
1386         m->cgroup_root = mfree(m->cgroup_root);
1387 }
1388
1389 /// UNNEEDED by elogind
1390 #if 0
1391 Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
1392         char *p;
1393         Unit *u;
1394
1395         assert(m);
1396         assert(cgroup);
1397
1398         u = hashmap_get(m->cgroup_unit, cgroup);
1399         if (u)
1400                 return u;
1401
1402         p = strdupa(cgroup);
1403         for (;;) {
1404                 char *e;
1405
1406                 e = strrchr(p, '/');
1407                 if (!e || e == p)
1408                         return hashmap_get(m->cgroup_unit, SPECIAL_ROOT_SLICE);
1409
1410                 *e = 0;
1411
1412                 u = hashmap_get(m->cgroup_unit, p);
1413                 if (u)
1414                         return u;
1415         }
1416 }
1417
1418 Unit *manager_get_unit_by_pid_cgroup(Manager *m, pid_t pid) {
1419         _cleanup_free_ char *cgroup = NULL;
1420         int r;
1421
1422         assert(m);
1423
1424         if (pid <= 0)
1425                 return NULL;
1426
1427         r = cg_pid_get_path(ELOGIND_CGROUP_CONTROLLER, pid, &cgroup);
1428         if (r < 0)
1429                 return NULL;
1430
1431         return manager_get_unit_by_cgroup(m, cgroup);
1432 }
1433
1434 Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
1435         Unit *u;
1436
1437         assert(m);
1438
1439         if (pid <= 0)
1440                 return NULL;
1441
1442         if (pid == 1)
1443                 return hashmap_get(m->units, SPECIAL_INIT_SCOPE);
1444
1445         u = hashmap_get(m->watch_pids1, PID_TO_PTR(pid));
1446         if (u)
1447                 return u;
1448
1449         u = hashmap_get(m->watch_pids2, PID_TO_PTR(pid));
1450         if (u)
1451                 return u;
1452
1453         return manager_get_unit_by_pid_cgroup(m, pid);
1454 }
1455
1456 int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
1457         Unit *u;
1458
1459         assert(m);
1460         assert(cgroup);
1461
1462         u = manager_get_unit_by_cgroup(m, cgroup);
1463         if (!u)
1464                 return 0;
1465
1466         return unit_notify_cgroup_empty(u);
1467 }
1468
1469 int unit_get_memory_current(Unit *u, uint64_t *ret) {
1470         _cleanup_free_ char *v = NULL;
1471         int r;
1472
1473         assert(u);
1474         assert(ret);
1475
1476         if (!u->cgroup_path)
1477                 return -ENODATA;
1478
1479         if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0)
1480                 return -ENODATA;
1481
1482         if (cg_unified() <= 0)
1483                 r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
1484         else
1485                 r = cg_get_attribute("memory", u->cgroup_path, "memory.current", &v);
1486         if (r == -ENOENT)
1487                 return -ENODATA;
1488         if (r < 0)
1489                 return r;
1490
1491         return safe_atou64(v, ret);
1492 }
1493
1494 static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) {
1495         _cleanup_free_ char *v = NULL;
1496         uint64_t ns;
1497         int r;
1498
1499         assert(u);
1500         assert(ret);
1501
1502         if (!u->cgroup_path)
1503                 return -ENODATA;
1504
1505         if ((u->cgroup_realized_mask & CGROUP_MASK_CPUACCT) == 0)
1506                 return -ENODATA;
1507
1508         r = cg_get_attribute("cpuacct", u->cgroup_path, "cpuacct.usage", &v);
1509         if (r == -ENOENT)
1510                 return -ENODATA;
1511         if (r < 0)
1512                 return r;
1513
1514         r = safe_atou64(v, &ns);
1515         if (r < 0)
1516                 return r;
1517
1518         *ret = ns;
1519         return 0;
1520 }
1521
1522 int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
1523         nsec_t ns;
1524         int r;
1525
1526         r = unit_get_cpu_usage_raw(u, &ns);
1527         if (r < 0)
1528                 return r;
1529
1530         if (ns > u->cpuacct_usage_base)
1531                 ns -= u->cpuacct_usage_base;
1532         else
1533                 ns = 0;
1534
1535         *ret = ns;
1536         return 0;
1537 }
1538
1539 int unit_reset_cpu_usage(Unit *u) {
1540         nsec_t ns;
1541         int r;
1542
1543         assert(u);
1544
1545         r = unit_get_cpu_usage_raw(u, &ns);
1546         if (r < 0) {
1547                 u->cpuacct_usage_base = 0;
1548                 return r;
1549         }
1550
1551         u->cpuacct_usage_base = ns;
1552         return 0;
1553 }
1554
1555 bool unit_cgroup_delegate(Unit *u) {
1556         CGroupContext *c;
1557
1558         assert(u);
1559
1560         c = unit_get_cgroup_context(u);
1561         if (!c)
1562                 return false;
1563
1564         return c->delegate;
1565 }
1566 #endif // 0
1567
1568 static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
1569         [CGROUP_AUTO] = "auto",
1570         [CGROUP_CLOSED] = "closed",
1571         [CGROUP_STRICT] = "strict",
1572 };
1573
1574 DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy);