chiark / gitweb /
1733521cd9aa01600aef820129a765e9f4d8fe1a
[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 // UNNEEDED by elogind
34 #if 0
35 void cgroup_context_init(CGroupContext *c) {
36         assert(c);
37
38         /* Initialize everything to the kernel defaults, assuming the
39          * structure is preinitialized to 0 */
40
41         c->cpu_shares = (unsigned long) -1;
42         c->startup_cpu_shares = (unsigned long) -1;
43         c->memory_limit = (uint64_t) -1;
44         c->blockio_weight = (unsigned long) -1;
45         c->startup_blockio_weight = (unsigned long) -1;
46
47         c->cpu_quota_per_sec_usec = USEC_INFINITY;
48 }
49
50 void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
51         assert(c);
52         assert(a);
53
54         LIST_REMOVE(device_allow, c->device_allow, a);
55         free(a->path);
56         free(a);
57 }
58
59 void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) {
60         assert(c);
61         assert(w);
62
63         LIST_REMOVE(device_weights, c->blockio_device_weights, w);
64         free(w->path);
65         free(w);
66 }
67
68 void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b) {
69         assert(c);
70         assert(b);
71
72         LIST_REMOVE(device_bandwidths, c->blockio_device_bandwidths, b);
73         free(b->path);
74         free(b);
75 }
76
77 void cgroup_context_done(CGroupContext *c) {
78         assert(c);
79
80         while (c->blockio_device_weights)
81                 cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
82
83         while (c->blockio_device_bandwidths)
84                 cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths);
85
86         while (c->device_allow)
87                 cgroup_context_free_device_allow(c, c->device_allow);
88 }
89
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
473 CGroupMask cgroup_context_get_mask(CGroupContext *c) {
474         CGroupMask mask = 0;
475
476         /* Figure out which controllers we need */
477
478         if (c->cpu_accounting ||
479             c->cpu_shares != (unsigned long) -1 ||
480             c->startup_cpu_shares != (unsigned long) -1 ||
481             c->cpu_quota_per_sec_usec != USEC_INFINITY)
482                 mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU;
483
484         if (c->blockio_accounting ||
485             c->blockio_weight != (unsigned long) -1 ||
486             c->startup_blockio_weight != (unsigned long) -1 ||
487             c->blockio_device_weights ||
488             c->blockio_device_bandwidths)
489                 mask |= CGROUP_MASK_BLKIO;
490
491         if (c->memory_accounting ||
492             c->memory_limit != (uint64_t) -1)
493                 mask |= CGROUP_MASK_MEMORY;
494
495         if (c->device_allow ||
496             c->device_policy != CGROUP_AUTO)
497                 mask |= CGROUP_MASK_DEVICE;
498
499         return mask;
500 }
501
502 CGroupMask unit_get_own_mask(Unit *u) {
503         CGroupContext *c;
504
505         /* Returns the mask of controllers the unit needs for itself */
506
507         c = unit_get_cgroup_context(u);
508         if (!c)
509                 return 0;
510
511         /* If delegation is turned on, then turn on all cgroups,
512          * unless we are on the legacy hierarchy and the process we
513          * fork into it is known to drop privileges, and hence
514          * shouldn't get access to the controllers.
515          *
516          * Note that on the unified hierarchy it is safe to delegate
517          * controllers to unprivileged services. */
518
519         if (c->delegate) {
520                 ExecContext *e;
521
522                 e = unit_get_exec_context(u);
523                 if (!e ||
524                     exec_context_maintains_privileges(e) ||
525                     cg_unified() > 0)
526                         return _CGROUP_MASK_ALL;
527         }
528
529         return cgroup_context_get_mask(c);
530 }
531
532 CGroupMask unit_get_members_mask(Unit *u) {
533         assert(u);
534
535         /* Returns the mask of controllers all of the unit's children
536          * require, merged */
537
538         if (u->cgroup_members_mask_valid)
539                 return u->cgroup_members_mask;
540
541         u->cgroup_members_mask = 0;
542
543         if (u->type == UNIT_SLICE) {
544                 Unit *member;
545                 Iterator i;
546
547                 SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) {
548
549                         if (member == u)
550                                 continue;
551
552                         if (UNIT_DEREF(member->slice) != u)
553                                 continue;
554
555                         u->cgroup_members_mask |=
556                                 unit_get_own_mask(member) |
557                                 unit_get_members_mask(member);
558                 }
559         }
560
561         u->cgroup_members_mask_valid = true;
562         return u->cgroup_members_mask;
563 }
564
565 CGroupMask unit_get_siblings_mask(Unit *u) {
566         assert(u);
567
568         /* Returns the mask of controllers all of the unit's siblings
569          * require, i.e. the members mask of the unit's parent slice
570          * if there is one. */
571
572         if (UNIT_ISSET(u->slice))
573                 return unit_get_members_mask(UNIT_DEREF(u->slice));
574
575         return unit_get_own_mask(u) | unit_get_members_mask(u);
576 }
577
578 CGroupMask unit_get_subtree_mask(Unit *u) {
579
580         /* Returns the mask of this subtree, meaning of the group
581          * itself and its children. */
582
583         return unit_get_own_mask(u) | unit_get_members_mask(u);
584 }
585
586 CGroupMask unit_get_target_mask(Unit *u) {
587         CGroupMask mask;
588
589         /* This returns the cgroup mask of all controllers to enable
590          * for a specific cgroup, i.e. everything it needs itself,
591          * plus all that its children need, plus all that its siblings
592          * need. This is primarily useful on the legacy cgroup
593          * hierarchy, where we need to duplicate each cgroup in each
594          * hierarchy that shall be enabled for it. */
595
596         mask = unit_get_own_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u);
597         mask &= u->manager->cgroup_supported;
598
599         return mask;
600 }
601
602 CGroupMask unit_get_enable_mask(Unit *u) {
603         CGroupMask mask;
604
605         /* This returns the cgroup mask of all controllers to enable
606          * for the children of a specific cgroup. This is primarily
607          * useful for the unified cgroup hierarchy, where each cgroup
608          * controls which controllers are enabled for its children. */
609
610         mask = unit_get_members_mask(u);
611         mask &= u->manager->cgroup_supported;
612
613         return mask;
614 }
615
616 /* Recurse from a unit up through its containing slices, propagating
617  * mask bits upward. A unit is also member of itself. */
618 void unit_update_cgroup_members_masks(Unit *u) {
619         CGroupMask m;
620         bool more;
621
622         assert(u);
623
624         /* Calculate subtree mask */
625         m = unit_get_subtree_mask(u);
626
627         /* See if anything changed from the previous invocation. If
628          * not, we're done. */
629         if (u->cgroup_subtree_mask_valid && m == u->cgroup_subtree_mask)
630                 return;
631
632         more =
633                 u->cgroup_subtree_mask_valid &&
634                 ((m & ~u->cgroup_subtree_mask) != 0) &&
635                 ((~m & u->cgroup_subtree_mask) == 0);
636
637         u->cgroup_subtree_mask = m;
638         u->cgroup_subtree_mask_valid = true;
639
640         if (UNIT_ISSET(u->slice)) {
641                 Unit *s = UNIT_DEREF(u->slice);
642
643                 if (more)
644                         /* There's more set now than before. We
645                          * propagate the new mask to the parent's mask
646                          * (not caring if it actually was valid or
647                          * not). */
648
649                         s->cgroup_members_mask |= m;
650
651                 else
652                         /* There's less set now than before (or we
653                          * don't know), we need to recalculate
654                          * everything, so let's invalidate the
655                          * parent's members mask */
656
657                         s->cgroup_members_mask_valid = false;
658
659                 /* And now make sure that this change also hits our
660                  * grandparents */
661                 unit_update_cgroup_members_masks(s);
662         }
663 }
664
665 static const char *migrate_callback(CGroupMask mask, void *userdata) {
666         Unit *u = userdata;
667
668         assert(mask != 0);
669         assert(u);
670
671         while (u) {
672                 if (u->cgroup_path &&
673                     u->cgroup_realized &&
674                     (u->cgroup_realized_mask & mask) == mask)
675                         return u->cgroup_path;
676
677                 u = UNIT_DEREF(u->slice);
678         }
679
680         return NULL;
681 }
682
683 char *unit_default_cgroup_path(Unit *u) {
684         _cleanup_free_ char *escaped = NULL, *slice = NULL;
685         int r;
686
687         assert(u);
688
689         if (unit_has_name(u, SPECIAL_ROOT_SLICE))
690                 return strdup(u->manager->cgroup_root);
691
692         if (UNIT_ISSET(u->slice) && !unit_has_name(UNIT_DEREF(u->slice), SPECIAL_ROOT_SLICE)) {
693                 r = cg_slice_to_path(UNIT_DEREF(u->slice)->id, &slice);
694                 if (r < 0)
695                         return NULL;
696         }
697
698         escaped = cg_escape(u->id);
699         if (!escaped)
700                 return NULL;
701
702         if (slice)
703                 return strjoin(u->manager->cgroup_root, "/", slice, "/", escaped, NULL);
704         else
705                 return strjoin(u->manager->cgroup_root, "/", escaped, NULL);
706 }
707
708 int unit_set_cgroup_path(Unit *u, const char *path) {
709         _cleanup_free_ char *p = NULL;
710         int r;
711
712         assert(u);
713
714         if (path) {
715                 p = strdup(path);
716                 if (!p)
717                         return -ENOMEM;
718         } else
719                 p = NULL;
720
721         if (streq_ptr(u->cgroup_path, p))
722                 return 0;
723
724         if (p) {
725                 r = hashmap_put(u->manager->cgroup_unit, p, u);
726                 if (r < 0)
727                         return r;
728         }
729
730         unit_release_cgroup(u);
731
732         u->cgroup_path = p;
733         p = NULL;
734
735         return 1;
736 }
737
738 int unit_watch_cgroup(Unit *u) {
739         _cleanup_free_ char *populated = NULL;
740         int r;
741
742         assert(u);
743
744         if (!u->cgroup_path)
745                 return 0;
746
747         if (u->cgroup_inotify_wd >= 0)
748                 return 0;
749
750         /* Only applies to the unified hierarchy */
751         r = cg_unified();
752         if (r < 0)
753                 return log_unit_error_errno(u, r, "Failed detect wether the unified hierarchy is used: %m");
754         if (r == 0)
755                 return 0;
756
757         /* Don't watch the root slice, it's pointless. */
758         if (unit_has_name(u, SPECIAL_ROOT_SLICE))
759                 return 0;
760
761         r = hashmap_ensure_allocated(&u->manager->cgroup_inotify_wd_unit, &trivial_hash_ops);
762         if (r < 0)
763                 return log_oom();
764
765         r = cg_get_path(ELOGIND_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.populated", &populated);
766         if (r < 0)
767                 return log_oom();
768
769         u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, populated, IN_MODIFY);
770         if (u->cgroup_inotify_wd < 0) {
771
772                 if (errno == ENOENT) /* If the directory is already
773                                       * gone we don't need to track
774                                       * it, so this is not an error */
775                         return 0;
776
777                 return log_unit_error_errno(u, errno, "Failed to add inotify watch descriptor for control group %s: %m", u->cgroup_path);
778         }
779
780         r = hashmap_put(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd), u);
781         if (r < 0)
782                 return log_unit_error_errno(u, r, "Failed to add inotify watch descriptor to hash map: %m");
783
784         return 0;
785 }
786
787 static int unit_create_cgroup(
788                 Unit *u,
789                 CGroupMask target_mask,
790                 CGroupMask enable_mask) {
791
792         CGroupContext *c;
793         int r;
794
795         assert(u);
796
797         c = unit_get_cgroup_context(u);
798         if (!c)
799                 return 0;
800
801         if (!u->cgroup_path) {
802                 _cleanup_free_ char *path = NULL;
803
804                 path = unit_default_cgroup_path(u);
805                 if (!path)
806                         return log_oom();
807
808                 r = unit_set_cgroup_path(u, path);
809                 if (r == -EEXIST)
810                         return log_unit_error_errno(u, r, "Control group %s exists already.", path);
811                 if (r < 0)
812                         return log_unit_error_errno(u, r, "Failed to set unit's control group path to %s: %m", path);
813         }
814
815         /* First, create our own group */
816         r = cg_create_everywhere(u->manager->cgroup_supported, target_mask, u->cgroup_path);
817         if (r < 0)
818                 return log_unit_error_errno(u, r, "Failed to create cgroup %s: %m", u->cgroup_path);
819
820         /* Start watching it */
821         (void) unit_watch_cgroup(u);
822
823         /* Enable all controllers we need */
824         r = cg_enable_everywhere(u->manager->cgroup_supported, enable_mask, u->cgroup_path);
825         if (r < 0)
826                 log_unit_warning_errno(u, r, "Failed to enable controllers on cgroup %s, ignoring: %m", u->cgroup_path);
827
828         /* Keep track that this is now realized */
829         u->cgroup_realized = true;
830         u->cgroup_realized_mask = target_mask;
831
832         if (u->type != UNIT_SLICE && !c->delegate) {
833
834                 /* Then, possibly move things over, but not if
835                  * subgroups may contain processes, which is the case
836                  * for slice and delegation units. */
837                 r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u);
838                 if (r < 0)
839                         log_unit_warning_errno(u, r, "Failed to migrate cgroup from to %s, ignoring: %m", u->cgroup_path);
840         }
841
842         return 0;
843 }
844
845 int unit_attach_pids_to_cgroup(Unit *u) {
846         int r;
847         assert(u);
848
849         r = unit_realize_cgroup(u);
850         if (r < 0)
851                 return r;
852
853         r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->pids, migrate_callback, u);
854         if (r < 0)
855                 return r;
856
857         return 0;
858 }
859
860 static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask) {
861         assert(u);
862
863         return u->cgroup_realized && u->cgroup_realized_mask == target_mask;
864 }
865
866 /* Check if necessary controllers and attributes for a unit are in place.
867  *
868  * If so, do nothing.
869  * If not, create paths, move processes over, and set attributes.
870  *
871  * Returns 0 on success and < 0 on failure. */
872 static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
873         CGroupMask target_mask, enable_mask;
874         int r;
875
876         assert(u);
877
878         if (u->in_cgroup_queue) {
879                 LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
880                 u->in_cgroup_queue = false;
881         }
882
883         target_mask = unit_get_target_mask(u);
884         if (unit_has_mask_realized(u, target_mask))
885                 return 0;
886
887         /* First, realize parents */
888         if (UNIT_ISSET(u->slice)) {
889                 r = unit_realize_cgroup_now(UNIT_DEREF(u->slice), state);
890                 if (r < 0)
891                         return r;
892         }
893
894         /* And then do the real work */
895         enable_mask = unit_get_enable_mask(u);
896         r = unit_create_cgroup(u, target_mask, enable_mask);
897         if (r < 0)
898                 return r;
899
900         /* Finally, apply the necessary attributes. */
901         cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, state);
902
903         return 0;
904 }
905
906 static void unit_add_to_cgroup_queue(Unit *u) {
907
908         if (u->in_cgroup_queue)
909                 return;
910
911         LIST_PREPEND(cgroup_queue, u->manager->cgroup_queue, u);
912         u->in_cgroup_queue = true;
913 }
914
915 unsigned manager_dispatch_cgroup_queue(Manager *m) {
916         ManagerState state;
917         unsigned n = 0;
918         Unit *i;
919         int r;
920
921         state = manager_state(m);
922
923         while ((i = m->cgroup_queue)) {
924                 assert(i->in_cgroup_queue);
925
926                 r = unit_realize_cgroup_now(i, state);
927                 if (r < 0)
928                         log_warning_errno(r, "Failed to realize cgroups for queued unit %s, ignoring: %m", i->id);
929
930                 n++;
931         }
932
933         return n;
934 }
935
936 static void unit_queue_siblings(Unit *u) {
937         Unit *slice;
938
939         /* This adds the siblings of the specified unit and the
940          * siblings of all parent units to the cgroup queue. (But
941          * neither the specified unit itself nor the parents.) */
942
943         while ((slice = UNIT_DEREF(u->slice))) {
944                 Iterator i;
945                 Unit *m;
946
947                 SET_FOREACH(m, slice->dependencies[UNIT_BEFORE], i) {
948                         if (m == u)
949                                 continue;
950
951                         /* Skip units that have a dependency on the slice
952                          * but aren't actually in it. */
953                         if (UNIT_DEREF(m->slice) != slice)
954                                 continue;
955
956                         /* No point in doing cgroup application for units
957                          * without active processes. */
958                         if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m)))
959                                 continue;
960
961                         /* If the unit doesn't need any new controllers
962                          * and has current ones realized, it doesn't need
963                          * any changes. */
964                         if (unit_has_mask_realized(m, unit_get_target_mask(m)))
965                                 continue;
966
967                         unit_add_to_cgroup_queue(m);
968                 }
969
970                 u = slice;
971         }
972 }
973
974 int unit_realize_cgroup(Unit *u) {
975         assert(u);
976
977         if (!UNIT_HAS_CGROUP_CONTEXT(u))
978                 return 0;
979
980         /* So, here's the deal: when realizing the cgroups for this
981          * unit, we need to first create all parents, but there's more
982          * actually: for the weight-based controllers we also need to
983          * make sure that all our siblings (i.e. units that are in the
984          * same slice as we are) have cgroups, too. Otherwise, things
985          * would become very uneven as each of their processes would
986          * get as much resources as all our group together. This call
987          * will synchronously create the parent cgroups, but will
988          * defer work on the siblings to the next event loop
989          * iteration. */
990
991         /* Add all sibling slices to the cgroup queue. */
992         unit_queue_siblings(u);
993
994         /* And realize this one now (and apply the values) */
995         return unit_realize_cgroup_now(u, manager_state(u->manager));
996 }
997
998 void unit_release_cgroup(Unit *u) {
999         assert(u);
1000
1001         /* Forgets all cgroup details for this cgroup */
1002
1003         if (u->cgroup_path) {
1004                 (void) hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
1005                 u->cgroup_path = mfree(u->cgroup_path);
1006         }
1007
1008         if (u->cgroup_inotify_wd >= 0) {
1009                 if (inotify_rm_watch(u->manager->cgroup_inotify_fd, u->cgroup_inotify_wd) < 0)
1010                         log_unit_debug_errno(u, errno, "Failed to remove cgroup inotify watch %i for %s, ignoring", u->cgroup_inotify_wd, u->id);
1011
1012                 (void) hashmap_remove(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd));
1013                 u->cgroup_inotify_wd = -1;
1014         }
1015 }
1016
1017 void unit_prune_cgroup(Unit *u) {
1018         int r;
1019         bool is_root_slice;
1020
1021         assert(u);
1022
1023         /* Removes the cgroup, if empty and possible, and stops watching it. */
1024
1025         if (!u->cgroup_path)
1026                 return;
1027
1028         is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
1029
1030         r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice);
1031         if (r < 0) {
1032                 log_debug_errno(r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path);
1033                 return;
1034         }
1035
1036         if (is_root_slice)
1037                 return;
1038
1039         unit_release_cgroup(u);
1040
1041         u->cgroup_realized = false;
1042         u->cgroup_realized_mask = 0;
1043 }
1044
1045 int unit_search_main_pid(Unit *u, pid_t *ret) {
1046         _cleanup_fclose_ FILE *f = NULL;
1047         pid_t pid = 0, npid, mypid;
1048         int r;
1049
1050         assert(u);
1051         assert(ret);
1052
1053         if (!u->cgroup_path)
1054                 return -ENXIO;
1055
1056         r = cg_enumerate_processes(ELOGIND_CGROUP_CONTROLLER, u->cgroup_path, &f);
1057         if (r < 0)
1058                 return r;
1059
1060         mypid = getpid();
1061         while (cg_read_pid(f, &npid) > 0)  {
1062                 pid_t ppid;
1063
1064                 if (npid == pid)
1065                         continue;
1066
1067                 /* Ignore processes that aren't our kids */
1068                 if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
1069                         continue;
1070
1071                 if (pid != 0)
1072                         /* Dang, there's more than one daemonized PID
1073                         in this group, so we don't know what process
1074                         is the main process. */
1075
1076                         return -ENODATA;
1077
1078                 pid = npid;
1079         }
1080
1081         *ret = pid;
1082         return 0;
1083 }
1084
1085 static int unit_watch_pids_in_path(Unit *u, const char *path) {
1086         _cleanup_closedir_ DIR *d = NULL;
1087         _cleanup_fclose_ FILE *f = NULL;
1088         int ret = 0, r;
1089
1090         assert(u);
1091         assert(path);
1092
1093         r = cg_enumerate_processes(ELOGIND_CGROUP_CONTROLLER, path, &f);
1094         if (r < 0)
1095                 ret = r;
1096         else {
1097                 pid_t pid;
1098
1099                 while ((r = cg_read_pid(f, &pid)) > 0) {
1100                         r = unit_watch_pid(u, pid);
1101                         if (r < 0 && ret >= 0)
1102                                 ret = r;
1103                 }
1104
1105                 if (r < 0 && ret >= 0)
1106                         ret = r;
1107         }
1108
1109         r = cg_enumerate_subgroups(ELOGIND_CGROUP_CONTROLLER, path, &d);
1110         if (r < 0) {
1111                 if (ret >= 0)
1112                         ret = r;
1113         } else {
1114                 char *fn;
1115
1116                 while ((r = cg_read_subgroup(d, &fn)) > 0) {
1117                         _cleanup_free_ char *p = NULL;
1118
1119                         p = strjoin(path, "/", fn, NULL);
1120                         free(fn);
1121
1122                         if (!p)
1123                                 return -ENOMEM;
1124
1125                         r = unit_watch_pids_in_path(u, p);
1126                         if (r < 0 && ret >= 0)
1127                                 ret = r;
1128                 }
1129
1130                 if (r < 0 && ret >= 0)
1131                         ret = r;
1132         }
1133
1134         return ret;
1135 }
1136
1137 int unit_watch_all_pids(Unit *u) {
1138         assert(u);
1139
1140         /* Adds all PIDs from our cgroup to the set of PIDs we
1141          * watch. This is a fallback logic for cases where we do not
1142          * get reliable cgroup empty notifications: we try to use
1143          * SIGCHLD as replacement. */
1144
1145         if (!u->cgroup_path)
1146                 return -ENOENT;
1147
1148         if (cg_unified() > 0) /* On unified we can use proper notifications */
1149                 return 0;
1150
1151         return unit_watch_pids_in_path(u, u->cgroup_path);
1152 }
1153
1154 int unit_notify_cgroup_empty(Unit *u) {
1155         int r;
1156
1157         assert(u);
1158
1159         if (!u->cgroup_path)
1160                 return 0;
1161
1162         r = cg_is_empty_recursive(ELOGIND_CGROUP_CONTROLLER, u->cgroup_path);
1163         if (r <= 0)
1164                 return r;
1165
1166         unit_add_to_gc_queue(u);
1167
1168         if (UNIT_VTABLE(u)->notify_cgroup_empty)
1169                 UNIT_VTABLE(u)->notify_cgroup_empty(u);
1170
1171         return 0;
1172 }
1173
1174 static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
1175         Manager *m = userdata;
1176
1177         assert(s);
1178         assert(fd >= 0);
1179         assert(m);
1180
1181         for (;;) {
1182                 union inotify_event_buffer buffer;
1183                 struct inotify_event *e;
1184                 ssize_t l;
1185
1186                 l = read(fd, &buffer, sizeof(buffer));
1187                 if (l < 0) {
1188                         if (errno == EINTR || errno == EAGAIN)
1189                                 return 0;
1190
1191                         return log_error_errno(errno, "Failed to read control group inotify events: %m");
1192                 }
1193
1194                 FOREACH_INOTIFY_EVENT(e, buffer, l) {
1195                         Unit *u;
1196
1197                         if (e->wd < 0)
1198                                 /* Queue overflow has no watch descriptor */
1199                                 continue;
1200
1201                         if (e->mask & IN_IGNORED)
1202                                 /* The watch was just removed */
1203                                 continue;
1204
1205                         u = hashmap_get(m->cgroup_inotify_wd_unit, INT_TO_PTR(e->wd));
1206                         if (!u) /* Not that inotify might deliver
1207                                  * events for a watch even after it
1208                                  * was removed, because it was queued
1209                                  * before the removal. Let's ignore
1210                                  * this here safely. */
1211                                 continue;
1212
1213                         (void) unit_notify_cgroup_empty(u);
1214                 }
1215         }
1216 }
1217 #endif // 0
1218
1219 int manager_setup_cgroup(Manager *m) {
1220         _cleanup_free_ char *path = NULL;
1221         CGroupController c;
1222         int r, unified;
1223         char *e;
1224
1225         assert(m);
1226
1227         /* 1. Determine hierarchy */
1228         m->cgroup_root = mfree(m->cgroup_root);
1229         r = cg_pid_get_path(ELOGIND_CGROUP_CONTROLLER, 0, &m->cgroup_root);
1230         if (r < 0)
1231                 return log_error_errno(r, "Cannot determine cgroup we are running in: %m");
1232 /// elogind does not support systemd scopes and slices
1233 #if 0
1234         /* Chop off the init scope, if we are already located in it */
1235         e = endswith(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
1236
1237         /* LEGACY: Also chop off the system slice if we are in
1238          * it. This is to support live upgrades from older systemd
1239          * versions where PID 1 was moved there. Also see
1240          * cg_get_root_path(). */
1241         if (!e) {
1242                 e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
1243                 if (!e)
1244                         e = endswith(m->cgroup_root, "/system"); /* even more legacy */
1245         }
1246         if (e)
1247                 *e = 0;
1248 #endif // 0
1249
1250         /* And make sure to store away the root value without trailing
1251          * slash, even for the root dir, so that we can easily prepend
1252          * it everywhere. */
1253         while ((e = endswith(m->cgroup_root, "/")))
1254                 *e = 0;
1255         log_debug_elogind("Cgroup Controller \"%s\" -> root \"%s\"",
1256                           ELOGIND_CGROUP_CONTROLLER, m->cgroup_root);
1257
1258         /* 2. Show data */
1259         r = cg_get_path(ELOGIND_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path);
1260         if (r < 0)
1261                 return log_error_errno(r, "Cannot find cgroup mount point: %m");
1262
1263         unified = cg_unified();
1264         if (unified < 0)
1265                 return log_error_errno(r, "Couldn't determine if we are running in the unified hierarchy: %m");
1266         if (unified > 0)
1267                 log_debug("Unified cgroup hierarchy is located at %s.", path);
1268         else
1269                 log_debug("Using cgroup controller " ELOGIND_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
1270
1271         if (!m->test_run) {
1272                 const char *scope_path;
1273
1274                 /* 3. Install agent */
1275                 if (unified) {
1276
1277                         /* In the unified hierarchy we can can get
1278                          * cgroup empty notifications via inotify. */
1279 /// elogind does not support the unified hierarchy, yet.
1280 #if 0
1281                         m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
1282                         safe_close(m->cgroup_inotify_fd);
1283
1284                         m->cgroup_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1285                         if (m->cgroup_inotify_fd < 0)
1286                                 return log_error_errno(errno, "Failed to create control group inotify object: %m");
1287
1288                         r = sd_event_add_io(m->event, &m->cgroup_inotify_event_source, m->cgroup_inotify_fd, EPOLLIN, on_cgroup_inotify_event, m);
1289                         if (r < 0)
1290                                 return log_error_errno(r, "Failed to watch control group inotify object: %m");
1291
1292                         r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_IDLE - 5);
1293                         if (r < 0)
1294                                 return log_error_errno(r, "Failed to set priority of inotify event source: %m");
1295
1296                         (void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
1297
1298 #else
1299                         return log_error_errno(EOPNOTSUPP, "Unified cgroup hierarchy not supported: %m");
1300 #endif // elogind
1301                 } else if (m->running_as == MANAGER_SYSTEM) {
1302                         /* On the legacy hierarchy we only get
1303                          * notifications via cgroup agents. (Which
1304                          * isn't really reliable, since it does not
1305                          * generate events when control groups with
1306                          * children run empty. */
1307
1308                         r = cg_install_release_agent(ELOGIND_CGROUP_CONTROLLER, ELOGIND_CGROUP_AGENT_PATH);
1309                         if (r < 0)
1310                                 log_warning_errno(r, "Failed to install release agent, ignoring: %m");
1311                         else if (r > 0)
1312                                 log_debug("Installed release agent.");
1313                         else if (r == 0)
1314                                 log_debug("Release agent already installed.");
1315                 }
1316
1317 /// elogind is not meant to run in systemd init scope
1318 #if 0
1319                 /* 4. Make sure we are in the special "init.scope" unit in the root slice. */
1320                 scope_path = strjoina(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
1321                 r = cg_create_and_attach(ELOGIND_CGROUP_CONTROLLER, scope_path, 0);
1322 #else
1323                 if (streq(m->cgroup_root, "/elogind"))
1324                         // root already is our cgroup
1325                         scope_path = strjoina(m->cgroup_root);
1326                 else
1327                         // we have to create our own group
1328                         scope_path = strjoina(m->cgroup_root, "/elogind");
1329                 r = cg_create_and_attach(ELOGIND_CGROUP_CONTROLLER, scope_path, 0);
1330 #endif // 0
1331                 if (r < 0)
1332                         return log_error_errno(r, "Failed to create %s control group: %m", scope_path);
1333                 log_debug_elogind("Created control group \"%s\"", scope_path);
1334
1335                 /* also, move all other userspace processes remaining
1336                  * in the root cgroup into that scope. */
1337                 if (!streq(m->cgroup_root, scope_path)) {
1338                         r = cg_migrate(ELOGIND_CGROUP_CONTROLLER, m->cgroup_root, ELOGIND_CGROUP_CONTROLLER, scope_path, false);
1339                         if (r < 0)
1340                                 log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %m");
1341                 }
1342
1343                 /* 5. And pin it, so that it cannot be unmounted */
1344                 safe_close(m->pin_cgroupfs_fd);
1345                 m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
1346                 if (m->pin_cgroupfs_fd < 0)
1347                         return log_error_errno(errno, "Failed to open pin file: %m");
1348
1349                 /* 6.  Always enable hierarchical support if it exists... */
1350                 if (!unified)
1351                         (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
1352         }
1353
1354         /* 7. Figure out which controllers are supported */
1355         r = cg_mask_supported(&m->cgroup_supported);
1356         if (r < 0)
1357                 return log_error_errno(r, "Failed to determine supported controllers: %m");
1358
1359         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
1360                 log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & c));
1361
1362         return 0;
1363 }
1364
1365 void manager_shutdown_cgroup(Manager *m, bool delete) {
1366         assert(m);
1367
1368         /* We can't really delete the group, since we are in it. But
1369          * let's trim it. */
1370         if (delete && m->cgroup_root)
1371                 (void) cg_trim(ELOGIND_CGROUP_CONTROLLER, m->cgroup_root, false);
1372
1373 /// elogind does not support the unified hierarchy, yet.
1374 #if 0
1375         m->cgroup_inotify_wd_unit = hashmap_free(m->cgroup_inotify_wd_unit);
1376
1377         m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
1378         m->cgroup_inotify_fd = safe_close(m->cgroup_inotify_fd);
1379 #endif // 0
1380
1381         m->pin_cgroupfs_fd = safe_close(m->pin_cgroupfs_fd);
1382
1383         m->cgroup_root = mfree(m->cgroup_root);
1384 }
1385
1386 /// UNNEEDED by elogind
1387 #if 0
1388 Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
1389         char *p;
1390         Unit *u;
1391
1392         assert(m);
1393         assert(cgroup);
1394
1395         u = hashmap_get(m->cgroup_unit, cgroup);
1396         if (u)
1397                 return u;
1398
1399         p = strdupa(cgroup);
1400         for (;;) {
1401                 char *e;
1402
1403                 e = strrchr(p, '/');
1404                 if (!e || e == p)
1405                         return hashmap_get(m->cgroup_unit, SPECIAL_ROOT_SLICE);
1406
1407                 *e = 0;
1408
1409                 u = hashmap_get(m->cgroup_unit, p);
1410                 if (u)
1411                         return u;
1412         }
1413 }
1414
1415 Unit *manager_get_unit_by_pid_cgroup(Manager *m, pid_t pid) {
1416         _cleanup_free_ char *cgroup = NULL;
1417         int r;
1418
1419         assert(m);
1420
1421         if (pid <= 0)
1422                 return NULL;
1423
1424         r = cg_pid_get_path(ELOGIND_CGROUP_CONTROLLER, pid, &cgroup);
1425         if (r < 0)
1426                 return NULL;
1427
1428         return manager_get_unit_by_cgroup(m, cgroup);
1429 }
1430
1431 Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
1432         Unit *u;
1433
1434         assert(m);
1435
1436         if (pid <= 0)
1437                 return NULL;
1438
1439         if (pid == 1)
1440                 return hashmap_get(m->units, SPECIAL_INIT_SCOPE);
1441
1442         u = hashmap_get(m->watch_pids1, PID_TO_PTR(pid));
1443         if (u)
1444                 return u;
1445
1446         u = hashmap_get(m->watch_pids2, PID_TO_PTR(pid));
1447         if (u)
1448                 return u;
1449
1450         return manager_get_unit_by_pid_cgroup(m, pid);
1451 }
1452
1453 int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
1454         Unit *u;
1455
1456         assert(m);
1457         assert(cgroup);
1458
1459         u = manager_get_unit_by_cgroup(m, cgroup);
1460         if (!u)
1461                 return 0;
1462
1463         return unit_notify_cgroup_empty(u);
1464 }
1465
1466 int unit_get_memory_current(Unit *u, uint64_t *ret) {
1467         _cleanup_free_ char *v = NULL;
1468         int r;
1469
1470         assert(u);
1471         assert(ret);
1472
1473         if (!u->cgroup_path)
1474                 return -ENODATA;
1475
1476         if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0)
1477                 return -ENODATA;
1478
1479         if (cg_unified() <= 0)
1480                 r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
1481         else
1482                 r = cg_get_attribute("memory", u->cgroup_path, "memory.current", &v);
1483         if (r == -ENOENT)
1484                 return -ENODATA;
1485         if (r < 0)
1486                 return r;
1487
1488         return safe_atou64(v, ret);
1489 }
1490
1491 static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) {
1492         _cleanup_free_ char *v = NULL;
1493         uint64_t ns;
1494         int r;
1495
1496         assert(u);
1497         assert(ret);
1498
1499         if (!u->cgroup_path)
1500                 return -ENODATA;
1501
1502         if ((u->cgroup_realized_mask & CGROUP_MASK_CPUACCT) == 0)
1503                 return -ENODATA;
1504
1505         r = cg_get_attribute("cpuacct", u->cgroup_path, "cpuacct.usage", &v);
1506         if (r == -ENOENT)
1507                 return -ENODATA;
1508         if (r < 0)
1509                 return r;
1510
1511         r = safe_atou64(v, &ns);
1512         if (r < 0)
1513                 return r;
1514
1515         *ret = ns;
1516         return 0;
1517 }
1518
1519 int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
1520         nsec_t ns;
1521         int r;
1522
1523         r = unit_get_cpu_usage_raw(u, &ns);
1524         if (r < 0)
1525                 return r;
1526
1527         if (ns > u->cpuacct_usage_base)
1528                 ns -= u->cpuacct_usage_base;
1529         else
1530                 ns = 0;
1531
1532         *ret = ns;
1533         return 0;
1534 }
1535
1536 int unit_reset_cpu_usage(Unit *u) {
1537         nsec_t ns;
1538         int r;
1539
1540         assert(u);
1541
1542         r = unit_get_cpu_usage_raw(u, &ns);
1543         if (r < 0) {
1544                 u->cpuacct_usage_base = 0;
1545                 return r;
1546         }
1547
1548         u->cpuacct_usage_base = ns;
1549         return 0;
1550 }
1551
1552 bool unit_cgroup_delegate(Unit *u) {
1553         CGroupContext *c;
1554
1555         assert(u);
1556
1557         c = unit_get_cgroup_context(u);
1558         if (!c)
1559                 return false;
1560
1561         return c->delegate;
1562 }
1563
1564 static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
1565         [CGROUP_AUTO] = "auto",
1566         [CGROUP_CLOSED] = "closed",
1567         [CGROUP_STRICT] = "strict",
1568 };
1569
1570 DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy);
1571 #endif // 0