]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/cgroups/cgfsng.c
cgfsng: cg_legacy_must_prefix_named()
[mirror_lxc.git] / src / lxc / cgroups / cgfsng.c
CommitLineData
ccb4cabe
SH
1/*
2 * lxc: linux Container library
3 *
4 * Copyright © 2016 Canonical Ltd.
5 *
6 * Authors:
7 * Serge Hallyn <serge.hallyn@ubuntu.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24/*
25 * cgfs-ng.c: this is a new, simplified implementation of a filesystem
26 * cgroup backend. The original cgfs.c was designed to be as flexible
27 * as possible. It would try to find cgroup filesystems no matter where
28 * or how you had them mounted, and deduce the most usable mount for
0e7ff52c 29 * each controller.
ccb4cabe
SH
30 *
31 * This new implementation assumes that cgroup filesystems are mounted
32 * under /sys/fs/cgroup/clist where clist is either the controller, or
33 * a comman-separated list of controllers.
34 */
a54694f8 35
ccb4cabe 36#include "config.h"
a54694f8
CB
37
38#include <ctype.h>
39#include <dirent.h>
40#include <errno.h>
41#include <grp.h>
42#include <stdint.h>
ccb4cabe
SH
43#include <stdio.h>
44#include <stdlib.h>
a54694f8 45#include <string.h>
ccb4cabe 46#include <unistd.h>
c8bf519d 47#include <linux/kdev_t.h>
438c4581
CB
48#include <linux/types.h>
49#include <sys/types.h>
c8bf519d 50
b635e92d 51#include "caps.h"
ccb4cabe 52#include "cgroup.h"
6328fd9c 53#include "cgroup_utils.h"
ccb4cabe 54#include "commands.h"
43654d34 55#include "conf.h"
a54694f8 56#include "log.h"
43654d34 57#include "storage/storage.h"
a54694f8 58#include "utils.h"
ccb4cabe
SH
59
60lxc_log_define(lxc_cgfsng, lxc);
61
62static struct cgroup_ops cgfsng_ops;
63
9e288301 64/* A descriptor for a mounted hierarchy
16a2cde9
CB
65 *
66 * @controllers
67 * - legacy hierarchy
9e288301 68 * Either NULL, or a null-terminated list of all the co-mounted controllers.
16a2cde9 69 * - unified hierarchy
9e288301 70 * Either NULL, or a null-terminated list of all enabled controllers.
16a2cde9
CB
71 *
72 * @mountpoint
9e288301 73 * - The mountpoint we will use.
16a2cde9 74 * - legacy hierarchy
9e288301
CB
75 * It will be either /sys/fs/cgroup/controller or
76 * /sys/fs/cgroup/controllerlist.
16a2cde9 77 * - unified hierarchy
9e288301
CB
78 * It will either be /sys/fs/cgroup or /sys/fs/cgroup/<mountpoint-name>
79 * depending on whether this is a hybrid cgroup layout (mix of legacy and
80 * unified hierarchies) or a pure unified cgroup layout.
16a2cde9
CB
81 *
82 * @base_cgroup
9e288301
CB
83 * - The cgroup under which the container cgroup path
84 * is created. This will be either the caller's cgroup (if not root), or
85 * init's cgroup (if root).
16a2cde9
CB
86 *
87 * @fullcgpath
9e288301 88 * - The full path to the containers cgroup.
16a2cde9
CB
89 *
90 * @version
91 * - legacy hierarchy
9e288301
CB
92 * If the hierarchy is a legacy hierarchy this will be set to
93 * CGROUP_SUPER_MAGIC.
16a2cde9 94 * - unified hierarchy
9e288301
CB
95 * If the hierarchy is a legacy hierarchy this will be set to
96 * CGROUP2_SUPER_MAGIC.
ccb4cabe
SH
97 */
98struct hierarchy {
99 char **controllers;
100 char *mountpoint;
101 char *base_cgroup;
102 char *fullcgpath;
d6337a5f 103 int version;
ccb4cabe
SH
104};
105
16a2cde9
CB
106/* The cgroup data which is attached to the lxc_handler.
107 *
108 * @cgroup_pattern
109 * - A copy of lxc.cgroup.pattern.
110 *
111 * @container_cgroup
112 * - If not null, the cgroup which was created for the container. For each
113 * hierarchy, it is created under the @hierarchy->base_cgroup directory.
114 * Relative to the base_cgroup it is the same for all hierarchies.
115 *
116 * @name
117 * - The name of the container.
118 *
119 * @cgroup_meta
120 * - A copy of the container's cgroup information. This overrides
121 * @cgroup_pattern.
122 *
09f3bb13
CB
123 * @cgroup_layout
124 * - What cgroup layout the container is running with.
16a2cde9
CB
125 * - CGROUP_LAYOUT_UNKNOWN
126 * The cgroup layout could not be determined. This should be treated as an
127 * error condition.
128 * - CGROUP_LAYOUT_LEGACY
129 * The container is running with all controllers mounted into legacy cgroup
130 * hierarchies.
131 * - CGROUP_LAYOUT_HYBRID
132 * The container is running with at least one controller mounted into a
133 * legacy cgroup hierarchy and a mountpoint for the unified hierarchy. The
134 * unified hierarchy can be empty (no controllers enabled) or non-empty
135 * (controllers enabled).
136 * - CGROUP_LAYOUT_UNIFIED
137 * The container is running on a pure unified cgroup hierarchy. The unified
138 * hierarchy can be empty (no controllers enabled) or non-empty (controllers
139 * enabled).
ccb4cabe
SH
140 */
141struct cgfsng_handler_data {
ccb4cabe 142 char *cgroup_pattern;
1a0e70ac
CB
143 char *container_cgroup; /* cgroup we created for the container */
144 char *name; /* container name */
43654d34
CB
145 /* per-container cgroup information */
146 struct lxc_cgroup cgroup_meta;
d6337a5f 147 cgroup_layout_t cgroup_layout;
ccb4cabe
SH
148};
149
09f3bb13
CB
150/* @hierarchies
151 * - A NULL-terminated array of struct hierarchy, one per legacy hierarchy. No
152 * duplicates. First sufficient, writeable mounted hierarchy wins.
457ca9aa
SH
153 */
154struct hierarchy **hierarchies;
09f3bb13
CB
155/* Pointer to the unified hierarchy in the null terminated list @hierarchies.
156 * This is merely a convenience for hybrid cgroup layouts to easily retrieve the
157 * unified hierarchy without iterating throught @hierarchies.
158 */
d6337a5f 159struct hierarchy *unified;
457ca9aa 160/*
09f3bb13
CB
161 * @cgroup_layout
162 * - What cgroup layout the container is running with.
163 * - CGROUP_LAYOUT_UNKNOWN
164 * The cgroup layout could not be determined. This should be treated as an
165 * error condition.
166 * - CGROUP_LAYOUT_LEGACY
167 * The container is running with all controllers mounted into legacy cgroup
168 * hierarchies.
169 * - CGROUP_LAYOUT_HYBRID
170 * The container is running with at least one controller mounted into a
171 * legacy cgroup hierarchy and a mountpoint for the unified hierarchy. The
172 * unified hierarchy can be empty (no controllers enabled) or non-empty
173 * (controllers enabled).
174 * - CGROUP_LAYOUT_UNIFIED
175 * The container is running on a pure unified cgroup hierarchy. The unified
176 * hierarchy can be empty (no controllers enabled) or non-empty (controllers
177 * enabled).
457ca9aa 178 */
09f3bb13
CB
179cgroup_layout_t cgroup_layout;
180/* What controllers is the container supposed to use. */
457ca9aa
SH
181char *cgroup_use;
182
09f3bb13
CB
183/* @lxc_cgfsng_debug
184 * - Whether to print debug info to stdout for the cgfsng driver.
e4aeecf5
CB
185 */
186static bool lxc_cgfsng_debug;
187
09f3bb13
CB
188#define CGFSNG_DEBUG(format, ...) \
189 do { \
190 if (lxc_cgfsng_debug) \
191 printf("cgfsng: " format, ##__VA_ARGS__); \
192 } while (0)
65d78313 193
ccb4cabe
SH
194static void free_string_list(char **clist)
195{
2d5fe5ba 196 int i;
ccb4cabe 197
2d5fe5ba
CB
198 if (!clist)
199 return;
200
201 for (i = 0; clist[i]; i++)
202 free(clist[i]);
203
204 free(clist);
ccb4cabe
SH
205}
206
7745483d 207/* Allocate a pointer, do not fail. */
ccb4cabe
SH
208static void *must_alloc(size_t sz)
209{
210 return must_realloc(NULL, sz);
211}
212
7745483d
CB
213/* Return a copy of @entry prepending "name=", i.e. turn "systemd" into
214 * "name=systemd". Do not fail.
ccb4cabe 215 */
7745483d 216static char *cg_legacy_must_prefix_named(char *entry)
ccb4cabe 217{
7745483d
CB
218 size_t len;
219 char *prefixed;
220
221 len = strlen(entry);
222 prefixed = must_alloc(len + 6);
ccb4cabe 223
7745483d
CB
224 memcpy(prefixed, "name=", sizeof("name="));
225 memcpy(prefixed + sizeof("name="), entry, len);
226 prefixed[len + 5] = '\0';
227 return prefixed;
ccb4cabe
SH
228}
229
230/*
231 * Given a pointer to a null-terminated array of pointers, realloc to
232 * add one entry, and point the new entry to NULL. Do not fail. Return
233 * the index to the second-to-last entry - that is, the one which is
234 * now available for use (keeping the list null-terminated).
235 */
236static int append_null_to_list(void ***list)
237{
238 int newentry = 0;
239
240 if (*list)
241 for (; (*list)[newentry]; newentry++);
242
243 *list = must_realloc(*list, (newentry + 2) * sizeof(void **));
244 (*list)[newentry + 1] = NULL;
245 return newentry;
246}
247
248/*
249 * Given a null-terminated array of strings, check whether @entry
250 * is one of the strings
251 */
252static bool string_in_list(char **list, const char *entry)
253{
254 int i;
255
256 if (!list)
257 return false;
d6337a5f 258
ccb4cabe
SH
259 for (i = 0; list[i]; i++)
260 if (strcmp(list[i], entry) == 0)
261 return true;
262
263 return false;
264}
265
266/*
267 * append an entry to the clist. Do not fail.
268 * *clist must be NULL the first time we are called.
269 *
270 * We also handle named subsystems here. Any controller which is not a
271 * kernel subsystem, we prefix 'name='. Any which is both a kernel and
272 * named subsystem, we refuse to use because we're not sure which we
273 * have here. (TODO - we could work around this in some cases by just
274 * remounting to be unambiguous, or by comparing mountpoint contents
275 * with current cgroup)
276 *
277 * The last entry will always be NULL.
278 */
279static void must_append_controller(char **klist, char **nlist, char ***clist, char *entry)
280{
281 int newentry;
282 char *copy;
283
284 if (string_in_list(klist, entry) && string_in_list(nlist, entry)) {
c2712f64 285 ERROR("Refusing to use ambiguous controller \"%s\"", entry);
ccb4cabe
SH
286 ERROR("It is both a named and kernel subsystem");
287 return;
288 }
289
290 newentry = append_null_to_list((void ***)clist);
291
292 if (strncmp(entry, "name=", 5) == 0)
293 copy = must_copy_string(entry);
294 else if (string_in_list(klist, entry))
295 copy = must_copy_string(entry);
296 else
7745483d 297 copy = cg_legacy_must_prefix_named(entry);
ccb4cabe
SH
298
299 (*clist)[newentry] = copy;
300}
301
ccb4cabe
SH
302static void free_handler_data(struct cgfsng_handler_data *d)
303{
ccb4cabe
SH
304 free(d->cgroup_pattern);
305 free(d->container_cgroup);
306 free(d->name);
43654d34
CB
307 if (d->cgroup_meta.dir)
308 free(d->cgroup_meta.dir);
309 if (d->cgroup_meta.controllers)
310 free(d->cgroup_meta.controllers);
ccb4cabe
SH
311 free(d);
312}
313
314/*
315 * Given a handler's cgroup data, return the struct hierarchy for the
316 * controller @c, or NULL if there is none.
317 */
457ca9aa 318struct hierarchy *get_hierarchy(const char *c)
ccb4cabe
SH
319{
320 int i;
321
457ca9aa 322 if (!hierarchies)
ccb4cabe 323 return NULL;
d6337a5f 324
457ca9aa 325 for (i = 0; hierarchies[i]; i++) {
d6337a5f
CB
326 if (!c) {
327 /* This is the empty unified hierarchy. */
328 if (hierarchies[i]->controllers &&
329 !hierarchies[i]->controllers[0])
330 return hierarchies[i];
331
332 return NULL;
333 }
334
457ca9aa
SH
335 if (string_in_list(hierarchies[i]->controllers, c))
336 return hierarchies[i];
ccb4cabe 337 }
d6337a5f 338
ccb4cabe
SH
339 return NULL;
340}
341
a54694f8
CB
342#define BATCH_SIZE 50
343static void batch_realloc(char **mem, size_t oldlen, size_t newlen)
344{
345 int newbatches = (newlen / BATCH_SIZE) + 1;
346 int oldbatches = (oldlen / BATCH_SIZE) + 1;
347
348 if (!*mem || newbatches > oldbatches) {
349 *mem = must_realloc(*mem, newbatches * BATCH_SIZE);
350 }
351}
352
353static void append_line(char **dest, size_t oldlen, char *new, size_t newlen)
354{
355 size_t full = oldlen + newlen;
356
357 batch_realloc(dest, oldlen, full + 1);
358
359 memcpy(*dest + oldlen, new, newlen + 1);
360}
361
362/* Slurp in a whole file */
d6337a5f 363static char *read_file(const char *fnam)
a54694f8
CB
364{
365 FILE *f;
366 char *line = NULL, *buf = NULL;
367 size_t len = 0, fulllen = 0;
368 int linelen;
369
370 f = fopen(fnam, "r");
371 if (!f)
372 return NULL;
373 while ((linelen = getline(&line, &len, f)) != -1) {
374 append_line(&buf, fulllen, line, linelen);
375 fulllen += linelen;
376 }
377 fclose(f);
378 free(line);
379 return buf;
380}
381
382/* Taken over modified from the kernel sources. */
383#define NBITS 32 /* bits in uint32_t */
384#define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
385#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, NBITS)
386
387static void set_bit(unsigned bit, uint32_t *bitarr)
388{
389 bitarr[bit / NBITS] |= (1 << (bit % NBITS));
390}
391
392static void clear_bit(unsigned bit, uint32_t *bitarr)
393{
394 bitarr[bit / NBITS] &= ~(1 << (bit % NBITS));
395}
396
397static bool is_set(unsigned bit, uint32_t *bitarr)
398{
399 return (bitarr[bit / NBITS] & (1 << (bit % NBITS))) != 0;
400}
401
402/* Create cpumask from cpulist aka turn:
403 *
404 * 0,2-3
405 *
406 * into bit array
407 *
408 * 1 0 1 1
409 */
410static uint32_t *lxc_cpumask(char *buf, size_t nbits)
411{
412 char *token;
413 char *saveptr = NULL;
414 size_t arrlen = BITS_TO_LONGS(nbits);
415 uint32_t *bitarr = calloc(arrlen, sizeof(uint32_t));
416 if (!bitarr)
417 return NULL;
418
419 for (; (token = strtok_r(buf, ",", &saveptr)); buf = NULL) {
420 errno = 0;
421 unsigned start = strtoul(token, NULL, 0);
422 unsigned end = start;
423
424 char *range = strchr(token, '-');
425 if (range)
426 end = strtoul(range + 1, NULL, 0);
427 if (!(start <= end)) {
428 free(bitarr);
429 return NULL;
430 }
431
432 if (end >= nbits) {
433 free(bitarr);
434 return NULL;
435 }
436
437 while (start <= end)
438 set_bit(start++, bitarr);
439 }
440
441 return bitarr;
442}
443
a54694f8
CB
444/* Turn cpumask into simple, comma-separated cpulist. */
445static char *lxc_cpumask_to_cpulist(uint32_t *bitarr, size_t nbits)
446{
447 size_t i;
448 int ret;
eab15c1e 449 char numstr[LXC_NUMSTRLEN64] = {0};
a54694f8
CB
450 char **cpulist = NULL;
451
452 for (i = 0; i <= nbits; i++) {
453 if (is_set(i, bitarr)) {
eab15c1e
CB
454 ret = snprintf(numstr, LXC_NUMSTRLEN64, "%zu", i);
455 if (ret < 0 || (size_t)ret >= LXC_NUMSTRLEN64) {
a54694f8
CB
456 lxc_free_array((void **)cpulist, free);
457 return NULL;
458 }
459 if (lxc_append_string(&cpulist, numstr) < 0) {
460 lxc_free_array((void **)cpulist, free);
461 return NULL;
462 }
463 }
464 }
465 return lxc_string_join(",", (const char **)cpulist, false);
466}
467
468static ssize_t get_max_cpus(char *cpulist)
469{
470 char *c1, *c2;
471 char *maxcpus = cpulist;
472 size_t cpus = 0;
473
474 c1 = strrchr(maxcpus, ',');
475 if (c1)
476 c1++;
477
478 c2 = strrchr(maxcpus, '-');
479 if (c2)
480 c2++;
481
482 if (!c1 && !c2)
483 c1 = maxcpus;
484 else if (c1 > c2)
485 c2 = c1;
486 else if (c1 < c2)
487 c1 = c2;
1a0e70ac 488 else if (!c1 && c2) /* The reverse case is obvs. not needed. */
a54694f8
CB
489 c1 = c2;
490
491 /* If the above logic is correct, c1 should always hold a valid string
492 * here.
493 */
494
495 errno = 0;
496 cpus = strtoul(c1, NULL, 0);
497 if (errno != 0)
498 return -1;
499
500 return cpus;
501}
502
6f9584d8 503#define __ISOL_CPUS "/sys/devices/system/cpu/isolated"
a3926f6a 504static bool cg_legacy_filter_and_set_cpus(char *path, bool am_initialized)
a54694f8
CB
505{
506 char *lastslash, *fpath, oldv;
507 int ret;
508 ssize_t i;
509
510 ssize_t maxposs = 0, maxisol = 0;
511 char *cpulist = NULL, *posscpus = NULL, *isolcpus = NULL;
512 uint32_t *possmask = NULL, *isolmask = NULL;
6f9584d8 513 bool bret = false, flipped_bit = false;
a54694f8
CB
514
515 lastslash = strrchr(path, '/');
1a0e70ac 516 if (!lastslash) { /* bug... this shouldn't be possible */
6f9584d8 517 ERROR("Invalid path: %s.", path);
a54694f8
CB
518 return bret;
519 }
520 oldv = *lastslash;
521 *lastslash = '\0';
522 fpath = must_make_path(path, "cpuset.cpus", NULL);
523 posscpus = read_file(fpath);
6f9584d8
CB
524 if (!posscpus) {
525 SYSERROR("Could not read file: %s.\n", fpath);
526 goto on_error;
527 }
a54694f8
CB
528
529 /* Get maximum number of cpus found in possible cpuset. */
530 maxposs = get_max_cpus(posscpus);
531 if (maxposs < 0)
6f9584d8 532 goto on_error;
a54694f8 533
6f9584d8
CB
534 if (!file_exists(__ISOL_CPUS)) {
535 /* This system doesn't expose isolated cpus. */
536 DEBUG("Path: "__ISOL_CPUS" to read isolated cpus from does not exist.\n");
65d29cbc
CB
537 cpulist = posscpus;
538 /* No isolated cpus but we weren't already initialized by
539 * someone. We should simply copy the parents cpuset.cpus
540 * values.
541 */
542 if (!am_initialized) {
543 DEBUG("Copying cpuset of parent cgroup.");
544 goto copy_parent;
545 }
546 /* No isolated cpus but we were already initialized by someone.
547 * Nothing more to do for us.
548 */
6f9584d8
CB
549 goto on_success;
550 }
551
552 isolcpus = read_file(__ISOL_CPUS);
553 if (!isolcpus) {
554 SYSERROR("Could not read file "__ISOL_CPUS);
555 goto on_error;
556 }
a54694f8 557 if (!isdigit(isolcpus[0])) {
6f9584d8 558 DEBUG("No isolated cpus detected.");
a54694f8
CB
559 cpulist = posscpus;
560 /* No isolated cpus but we weren't already initialized by
561 * someone. We should simply copy the parents cpuset.cpus
562 * values.
563 */
6f9584d8
CB
564 if (!am_initialized) {
565 DEBUG("Copying cpuset of parent cgroup.");
a54694f8 566 goto copy_parent;
6f9584d8 567 }
a54694f8
CB
568 /* No isolated cpus but we were already initialized by someone.
569 * Nothing more to do for us.
570 */
6f9584d8 571 goto on_success;
a54694f8
CB
572 }
573
574 /* Get maximum number of cpus found in isolated cpuset. */
575 maxisol = get_max_cpus(isolcpus);
576 if (maxisol < 0)
6f9584d8 577 goto on_error;
a54694f8
CB
578
579 if (maxposs < maxisol)
580 maxposs = maxisol;
581 maxposs++;
582
583 possmask = lxc_cpumask(posscpus, maxposs);
6f9584d8
CB
584 if (!possmask) {
585 ERROR("Could not create cpumask for all possible cpus.\n");
586 goto on_error;
587 }
a54694f8
CB
588
589 isolmask = lxc_cpumask(isolcpus, maxposs);
6f9584d8
CB
590 if (!isolmask) {
591 ERROR("Could not create cpumask for all isolated cpus.\n");
592 goto on_error;
593 }
a54694f8
CB
594
595 for (i = 0; i <= maxposs; i++) {
596 if (is_set(i, isolmask) && is_set(i, possmask)) {
6f9584d8 597 flipped_bit = true;
a54694f8
CB
598 clear_bit(i, possmask);
599 }
600 }
601
6f9584d8
CB
602 if (!flipped_bit) {
603 DEBUG("No isolated cpus present in cpuset.");
604 goto on_success;
605 }
606 DEBUG("Removed isolated cpus from cpuset.");
607
a54694f8 608 cpulist = lxc_cpumask_to_cpulist(possmask, maxposs);
6f9584d8
CB
609 if (!cpulist) {
610 ERROR("Could not create cpu list.\n");
611 goto on_error;
612 }
a54694f8
CB
613
614copy_parent:
615 *lastslash = oldv;
dcbc861e 616 free(fpath);
a54694f8
CB
617 fpath = must_make_path(path, "cpuset.cpus", NULL);
618 ret = lxc_write_to_file(fpath, cpulist, strlen(cpulist), false);
6f9584d8
CB
619 if (ret < 0) {
620 SYSERROR("Could not write cpu list to: %s.\n", fpath);
621 goto on_error;
622 }
623
624on_success:
625 bret = true;
a54694f8 626
6f9584d8 627on_error:
a54694f8
CB
628 free(fpath);
629
630 free(isolcpus);
631 free(isolmask);
632
633 if (posscpus != cpulist)
634 free(posscpus);
635 free(possmask);
636
637 free(cpulist);
638 return bret;
639}
640
e3a3fecf
SH
641/* Copy contents of parent(@path)/@file to @path/@file */
642static bool copy_parent_file(char *path, char *file)
643{
644 char *lastslash, *value = NULL, *fpath, oldv;
645 int len = 0;
646 int ret;
647
648 lastslash = strrchr(path, '/');
1a0e70ac 649 if (!lastslash) { /* bug... this shouldn't be possible */
e3a3fecf
SH
650 ERROR("cgfsng:copy_parent_file: bad path %s", path);
651 return false;
652 }
653 oldv = *lastslash;
654 *lastslash = '\0';
655 fpath = must_make_path(path, file, NULL);
656 len = lxc_read_from_file(fpath, NULL, 0);
657 if (len <= 0)
658 goto bad;
659 value = must_alloc(len + 1);
660 if (lxc_read_from_file(fpath, value, len) != len)
661 goto bad;
662 free(fpath);
663 *lastslash = oldv;
664 fpath = must_make_path(path, file, NULL);
665 ret = lxc_write_to_file(fpath, value, len, false);
666 if (ret < 0)
667 SYSERROR("Unable to write %s to %s", value, fpath);
668 free(fpath);
669 free(value);
670 return ret >= 0;
671
672bad:
673 SYSERROR("Error reading '%s'", fpath);
674 free(fpath);
675 free(value);
676 return false;
677}
678
679/*
680 * Initialize the cpuset hierarchy in first directory of @gname and
681 * set cgroup.clone_children so that children inherit settings.
682 * Since the h->base_path is populated by init or ourselves, we know
683 * it is already initialized.
684 */
a3926f6a 685static bool cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
e3a3fecf
SH
686{
687 char *cgpath, *clonechildrenpath, v, *slash;
688
689 if (!string_in_list(h->controllers, "cpuset"))
690 return true;
691
692 if (*cgname == '/')
693 cgname++;
694 slash = strchr(cgname, '/');
695 if (slash)
696 *slash = '\0';
697
698 cgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
699 if (slash)
700 *slash = '/';
701 if (mkdir(cgpath, 0755) < 0 && errno != EEXIST) {
702 SYSERROR("Failed to create '%s'", cgpath);
703 free(cgpath);
704 return false;
705 }
6f9584d8 706
e3a3fecf 707 clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL);
6328fd9c
CB
708 /* unified hierarchy doesn't have clone_children */
709 if (!file_exists(clonechildrenpath)) {
e3a3fecf
SH
710 free(clonechildrenpath);
711 free(cgpath);
712 return true;
713 }
714 if (lxc_read_from_file(clonechildrenpath, &v, 1) < 0) {
715 SYSERROR("Failed to read '%s'", clonechildrenpath);
716 free(clonechildrenpath);
717 free(cgpath);
718 return false;
719 }
720
a54694f8 721 /* Make sure any isolated cpus are removed from cpuset.cpus. */
a3926f6a 722 if (!cg_legacy_filter_and_set_cpus(cgpath, v == '1')) {
6f9584d8
CB
723 SYSERROR("Failed to remove isolated cpus.");
724 free(clonechildrenpath);
725 free(cgpath);
a54694f8 726 return false;
6f9584d8 727 }
a54694f8 728
e3a3fecf 729 if (v == '1') { /* already set for us by someone else */
6f9584d8 730 DEBUG("\"cgroup.clone_children\" was already set to \"1\".");
e3a3fecf
SH
731 free(clonechildrenpath);
732 free(cgpath);
733 return true;
734 }
735
736 /* copy parent's settings */
a54694f8 737 if (!copy_parent_file(cgpath, "cpuset.mems")) {
6f9584d8 738 SYSERROR("Failed to copy \"cpuset.mems\" settings.");
e3a3fecf
SH
739 free(cgpath);
740 free(clonechildrenpath);
741 return false;
742 }
743 free(cgpath);
744
745 if (lxc_write_to_file(clonechildrenpath, "1", 1, false) < 0) {
746 /* Set clone_children so children inherit our settings */
747 SYSERROR("Failed to write 1 to %s", clonechildrenpath);
748 free(clonechildrenpath);
749 return false;
750 }
751 free(clonechildrenpath);
752 return true;
753}
754
ccb4cabe
SH
755/*
756 * Given two null-terminated lists of strings, return true if any string
757 * is in both.
758 */
759static bool controller_lists_intersect(char **l1, char **l2)
760{
761 int i;
762
763 if (!l1 || !l2)
764 return false;
765
766 for (i = 0; l1[i]; i++) {
767 if (string_in_list(l2, l1[i]))
768 return true;
769 }
770 return false;
771}
772
773/*
774 * For a null-terminated list of controllers @clist, return true if any of
775 * those controllers is already listed the null-terminated list of
776 * hierarchies @hlist. Realistically, if one is present, all must be present.
777 */
778static bool controller_list_is_dup(struct hierarchy **hlist, char **clist)
779{
780 int i;
781
782 if (!hlist)
783 return false;
784 for (i = 0; hlist[i]; i++)
785 if (controller_lists_intersect(hlist[i]->controllers, clist))
786 return true;
787 return false;
788
789}
790
791/*
792 * Return true if the controller @entry is found in the null-terminated
793 * list of hierarchies @hlist
794 */
795static bool controller_found(struct hierarchy **hlist, char *entry)
796{
797 int i;
d6337a5f 798
ccb4cabe
SH
799 if (!hlist)
800 return false;
801
802 for (i = 0; hlist[i]; i++)
803 if (string_in_list(hlist[i]->controllers, entry))
804 return true;
d6337a5f 805
ccb4cabe
SH
806 return false;
807}
808
809/*
c30b61c3
SH
810 * Return true if all of the controllers which we require have been found.
811 * The required list is freezer and anything in * lxc.cgroup.use.
ccb4cabe 812 */
457ca9aa 813static bool all_controllers_found(void)
ccb4cabe
SH
814{
815 char *p, *saveptr = NULL;
457ca9aa 816 struct hierarchy ** hlist = hierarchies;
ccb4cabe 817
ccb4cabe 818 if (!controller_found(hlist, "freezer")) {
65d78313 819 CGFSNG_DEBUG("No freezer controller mountpoint found\n");
ccb4cabe
SH
820 return false;
821 }
822
457ca9aa 823 if (!cgroup_use)
ccb4cabe 824 return true;
c2712f64 825
457ca9aa 826 for (p = strtok_r(cgroup_use, ",", &saveptr); p;
ccb4cabe
SH
827 p = strtok_r(NULL, ",", &saveptr)) {
828 if (!controller_found(hlist, p)) {
65d78313 829 CGFSNG_DEBUG("No %s controller mountpoint found\n", p);
ccb4cabe
SH
830 return false;
831 }
832 }
c2712f64 833
ccb4cabe
SH
834 return true;
835}
836
ccb4cabe
SH
837/*
838 * Get the controllers from a mountinfo line
839 * There are other ways we could get this info. For lxcfs, field 3
840 * is /cgroup/controller-list. For cgroupfs, we could parse the mount
841 * options. But we simply assume that the mountpoint must be
842 * /sys/fs/cgroup/controller-list
843 */
a3926f6a
CB
844static char **cg_hybrid_get_controllers(char **klist, char **nlist, char *line,
845 int type)
ccb4cabe 846{
6328fd9c 847 /* the fourth field is /sys/fs/cgroup/comma-delimited-controller-list */
ccb4cabe 848 int i;
411ac6d8 849 char *dup, *p2, *tok;
d6337a5f 850 char *p = line, *saveptr = NULL, *sep = ",";
411ac6d8 851 char **aret = NULL;
6328fd9c 852
ccb4cabe 853 for (i = 0; i < 4; i++) {
235f1815 854 p = strchr(p, ' ');
ccb4cabe
SH
855 if (!p)
856 return NULL;
857 p++;
858 }
a55f31bd 859
ccb4cabe
SH
860 /* note - if we change how mountinfo works, then our caller
861 * will need to verify /sys/fs/cgroup/ in this field */
c2712f64 862 if (strncmp(p, "/sys/fs/cgroup/", 15)) {
65d78313 863 CGFSNG_DEBUG("Found hierarchy not under /sys/fs/cgroup: \"%s\"\n", p);
ccb4cabe 864 return NULL;
5059aae9 865 }
d6337a5f 866
ccb4cabe 867 p += 15;
235f1815 868 p2 = strchr(p, ' ');
ccb4cabe 869 if (!p2) {
65d78313 870 CGFSNG_DEBUG("Corrupt mountinfo\n");
ccb4cabe
SH
871 return NULL;
872 }
873 *p2 = '\0';
6328fd9c 874
d6337a5f
CB
875 if (type == CGROUP_SUPER_MAGIC) {
876 /* strdup() here for v1 hierarchies. Otherwise strtok_r() will
877 * destroy mountpoints such as "/sys/fs/cgroup/cpu,cpuacct".
878 */
879 dup = strdup(p);
880 if (!dup)
881 return NULL;
882
883 for (tok = strtok_r(dup, sep, &saveptr); tok;
884 tok = strtok_r(NULL, sep, &saveptr))
885 must_append_controller(klist, nlist, &aret, tok);
886
887 free(dup);
411ac6d8 888 }
d6337a5f
CB
889 *p2 = ' ';
890 return aret;
891}
411ac6d8 892
d6337a5f
CB
893static char **cg_unified_make_empty_controller(void)
894{
895 int newentry;
896 char **aret = NULL;
897
898 newentry = append_null_to_list((void ***)&aret);
899 aret[newentry] = NULL;
900 return aret;
901}
902
903static char **cg_unified_get_controllers(const char *file)
904{
905 char *buf, *tok;
906 char *saveptr = NULL, *sep = " \t\n";
907 char **aret = NULL;
908
909 buf = read_file(file);
910 if (!buf)
411ac6d8 911 return NULL;
6328fd9c 912
d6337a5f
CB
913 for (tok = strtok_r(buf, sep, &saveptr); tok;
914 tok = strtok_r(NULL, sep, &saveptr)) {
915 int newentry;
916 char *copy;
917
918 newentry = append_null_to_list((void ***)&aret);
919 copy = must_copy_string(tok);
920 aret[newentry] = copy;
ccb4cabe
SH
921 }
922
d6337a5f 923 free(buf);
ccb4cabe
SH
924 return aret;
925}
926
d6337a5f
CB
927static struct hierarchy *add_hierarchy(char **clist, char *mountpoint,
928 char *base_cgroup, int type)
ccb4cabe
SH
929{
930 struct hierarchy *new;
931 int newentry;
932
933 new = must_alloc(sizeof(*new));
934 new->controllers = clist;
935 new->mountpoint = mountpoint;
936 new->base_cgroup = base_cgroup;
937 new->fullcgpath = NULL;
d6337a5f 938 new->version = type;
6328fd9c 939
457ca9aa
SH
940 newentry = append_null_to_list((void ***)&hierarchies);
941 hierarchies[newentry] = new;
d6337a5f 942 return new;
ccb4cabe
SH
943}
944
945/*
946 * Get a copy of the mountpoint from @line, which is a line from
947 * /proc/self/mountinfo
948 */
a3926f6a 949static char *cg_hybrid_get_mountpoint(char *line)
ccb4cabe
SH
950{
951 int i;
d6337a5f 952 char *p2;
ccb4cabe 953 size_t len;
d6337a5f
CB
954 char *p = line;
955 char *sret = NULL;
ccb4cabe
SH
956
957 for (i = 0; i < 4; i++) {
235f1815 958 p = strchr(p, ' ');
ccb4cabe
SH
959 if (!p)
960 return NULL;
961 p++;
962 }
d6337a5f
CB
963
964 if (strncmp(p, "/sys/fs/cgroup/", 15))
965 return NULL;
966
967 p2 = strchr(p + 15, ' ');
968 if (!p2)
969 return NULL;
970 *p2 = '\0';
971
ccb4cabe
SH
972 len = strlen(p);
973 sret = must_alloc(len + 1);
974 memcpy(sret, p, len);
975 sret[len] = '\0';
976 return sret;
977}
978
979/*
980 * Given a multi-line string, return a null-terminated copy of the
981 * current line.
982 */
983static char *copy_to_eol(char *p)
984{
235f1815 985 char *p2 = strchr(p, '\n'), *sret;
ccb4cabe
SH
986 size_t len;
987
988 if (!p2)
989 return NULL;
990
991 len = p2 - p;
992 sret = must_alloc(len + 1);
993 memcpy(sret, p, len);
994 sret[len] = '\0';
995 return sret;
996}
997
998/*
999 * cgline: pointer to character after the first ':' in a line in a
1000 * \n-terminated /proc/self/cgroup file. Check whether * controller c is
1001 * present.
1002 */
1003static bool controller_in_clist(char *cgline, char *c)
1004{
1005 char *tok, *saveptr = NULL, *eol, *tmp;
1006 size_t len;
1007
235f1815 1008 eol = strchr(cgline, ':');
ccb4cabe
SH
1009 if (!eol)
1010 return false;
1011
1012 len = eol - cgline;
1013 tmp = alloca(len + 1);
1014 memcpy(tmp, cgline, len);
1015 tmp[len] = '\0';
1016
1017 for (tok = strtok_r(tmp, ",", &saveptr); tok;
d6337a5f 1018 tok = strtok_r(NULL, ",", &saveptr)) {
ccb4cabe
SH
1019 if (strcmp(tok, c) == 0)
1020 return true;
1021 }
d6337a5f 1022
ccb4cabe
SH
1023 return false;
1024}
1025
1026/*
1027 * @basecginfo is a copy of /proc/$$/cgroup. Return the current
1028 * cgroup for @controller
1029 */
a3926f6a 1030static char *cg_hybrid_get_current_cgroup(char *basecginfo, char *controller, int type)
ccb4cabe
SH
1031{
1032 char *p = basecginfo;
6328fd9c 1033
d6337a5f
CB
1034 for (;;) {
1035 bool is_cgv2_base_cgroup = false;
1036
6328fd9c 1037 /* cgroup v2 entry in "/proc/<pid>/cgroup": "0::/some/path" */
d6337a5f
CB
1038 if ((type == CGROUP2_SUPER_MAGIC) && (*p == '0'))
1039 is_cgv2_base_cgroup = true;
ccb4cabe 1040
235f1815 1041 p = strchr(p, ':');
ccb4cabe
SH
1042 if (!p)
1043 return NULL;
1044 p++;
d6337a5f
CB
1045
1046 if (is_cgv2_base_cgroup || (controller && controller_in_clist(p, controller))) {
235f1815 1047 p = strchr(p, ':');
ccb4cabe
SH
1048 if (!p)
1049 return NULL;
1050 p++;
1051 return copy_to_eol(p);
1052 }
1053
235f1815 1054 p = strchr(p, '\n');
ccb4cabe
SH
1055 if (!p)
1056 return NULL;
1057 p++;
1058 }
1059}
1060
ccb4cabe
SH
1061static void must_append_string(char ***list, char *entry)
1062{
1063 int newentry = append_null_to_list((void ***)list);
1064 char *copy;
1065
1066 copy = must_copy_string(entry);
1067 (*list)[newentry] = copy;
1068}
1069
d6337a5f 1070static int get_existing_subsystems(char ***klist, char ***nlist)
ccb4cabe
SH
1071{
1072 FILE *f;
1073 char *line = NULL;
1074 size_t len = 0;
1075
d6337a5f
CB
1076 f = fopen("/proc/self/cgroup", "r");
1077 if (!f)
1078 return -1;
1079
ccb4cabe
SH
1080 while (getline(&line, &len, f) != -1) {
1081 char *p, *p2, *tok, *saveptr = NULL;
235f1815 1082 p = strchr(line, ':');
ccb4cabe
SH
1083 if (!p)
1084 continue;
1085 p++;
235f1815 1086 p2 = strchr(p, ':');
ccb4cabe
SH
1087 if (!p2)
1088 continue;
1089 *p2 = '\0';
ff8d6ee9 1090
6328fd9c
CB
1091 /* If the kernel has cgroup v2 support, then /proc/self/cgroup
1092 * contains an entry of the form:
ff8d6ee9
CB
1093 *
1094 * 0::/some/path
1095 *
6328fd9c 1096 * In this case we use "cgroup2" as controller name.
ff8d6ee9 1097 */
6328fd9c
CB
1098 if ((p2 - p) == 0) {
1099 must_append_string(klist, "cgroup2");
ff8d6ee9 1100 continue;
6328fd9c 1101 }
ff8d6ee9 1102
ccb4cabe 1103 for (tok = strtok_r(p, ",", &saveptr); tok;
d6337a5f 1104 tok = strtok_r(NULL, ",", &saveptr)) {
ccb4cabe
SH
1105 if (strncmp(tok, "name=", 5) == 0)
1106 must_append_string(nlist, tok);
1107 else
1108 must_append_string(klist, tok);
1109 }
1110 }
1111
1112 free(line);
1113 fclose(f);
d6337a5f 1114 return 0;
ccb4cabe
SH
1115}
1116
1117static void trim(char *s)
1118{
1119 size_t len = strlen(s);
2c28d76b 1120 while ((len > 1) && (s[len - 1] == '\n'))
ccb4cabe
SH
1121 s[--len] = '\0';
1122}
1123
e4aeecf5
CB
1124static void lxc_cgfsng_print_handler_data(const struct cgfsng_handler_data *d)
1125{
1126 printf("Cgroup information:\n");
1127 printf(" container name: %s\n", d->name ? d->name : "(null)");
1128 printf(" lxc.cgroup.use: %s\n", cgroup_use ? cgroup_use : "(null)");
43654d34
CB
1129 printf(" lxc.cgroup.pattern: %s\n",
1130 d->cgroup_pattern ? d->cgroup_pattern : "(null)");
1131 printf(" lxc.cgroup.dir: %s\n",
1132 d->cgroup_meta.dir ? d->cgroup_meta.dir : "(null)");
1133 printf(" cgroup: %s\n",
1134 d->container_cgroup ? d->container_cgroup : "(null)");
e4aeecf5
CB
1135}
1136
1137static void lxc_cgfsng_print_hierarchies()
ccb4cabe 1138{
a7b0cc4c 1139 struct hierarchy **it;
ccb4cabe 1140 int i;
41c33dbe 1141
457ca9aa 1142 if (!hierarchies) {
c2712f64 1143 printf(" No hierarchies found\n");
ccb4cabe
SH
1144 return;
1145 }
e4aeecf5 1146 printf(" Hierarchies:\n");
a7b0cc4c
CB
1147 for (i = 0, it = hierarchies; it && *it; it++, i++) {
1148 char **cit;
ccb4cabe 1149 int j;
c2712f64
CB
1150 printf(" %d: base_cgroup: %s\n", i, (*it)->base_cgroup ? (*it)->base_cgroup : "(null)");
1151 printf(" mountpoint: %s\n", (*it)->mountpoint ? (*it)->mountpoint : "(null)");
e4aeecf5 1152 printf(" controllers:\n");
a7b0cc4c 1153 for (j = 0, cit = (*it)->controllers; cit && *cit; cit++, j++)
e4aeecf5 1154 printf(" %d: %s\n", j, *cit);
ccb4cabe
SH
1155 }
1156}
41c33dbe 1157
a3926f6a
CB
1158static void lxc_cgfsng_print_basecg_debuginfo(char *basecginfo, char **klist,
1159 char **nlist)
41c33dbe
SH
1160{
1161 int k;
a7b0cc4c 1162 char **it;
41c33dbe 1163
a7b0cc4c
CB
1164 printf("basecginfo is:\n");
1165 printf("%s\n", basecginfo);
41c33dbe 1166
a7b0cc4c
CB
1167 for (k = 0, it = klist; it && *it; it++, k++)
1168 printf("kernel subsystem %d: %s\n", k, *it);
1169 for (k = 0, it = nlist; it && *it; it++, k++)
1170 printf("named subsystem %d: %s\n", k, *it);
41c33dbe 1171}
ccb4cabe 1172
e4aeecf5
CB
1173static void lxc_cgfsng_print_debuginfo(const struct cgfsng_handler_data *d)
1174{
1175 lxc_cgfsng_print_handler_data(d);
1176 lxc_cgfsng_print_hierarchies();
1177}
1178
ccb4cabe
SH
1179/*
1180 * At startup, parse_hierarchies finds all the info we need about
1181 * cgroup mountpoints and current cgroups, and stores it in @d.
1182 */
a3926f6a 1183static bool cg_hybrid_init(void)
ccb4cabe 1184{
d6337a5f
CB
1185 int ret;
1186 char *basecginfo;
1187 bool will_escape;
ccb4cabe 1188 FILE *f;
ccb4cabe 1189 size_t len = 0;
d6337a5f
CB
1190 char *line = NULL;
1191 char **klist = NULL, **nlist = NULL;
ccb4cabe 1192
d30ec4cb
SH
1193 /*
1194 * Root spawned containers escape the current cgroup, so use init's
1195 * cgroups as our base in that case.
1196 */
d6337a5f
CB
1197 will_escape = (geteuid() == 0);
1198 if (will_escape)
ccb4cabe 1199 basecginfo = read_file("/proc/1/cgroup");
d6337a5f
CB
1200 else
1201 basecginfo = read_file("/proc/self/cgroup");
ccb4cabe
SH
1202 if (!basecginfo)
1203 return false;
1204
d6337a5f
CB
1205 ret = get_existing_subsystems(&klist, &nlist);
1206 if (ret < 0) {
1207 CGFSNG_DEBUG("Failed to retrieve available cgroup v1 controllers\n");
1208 free(basecginfo);
ccb4cabe
SH
1209 return false;
1210 }
1211
d6337a5f
CB
1212 f = fopen("/proc/self/mountinfo", "r");
1213 if (!f) {
1214 CGFSNG_DEBUG("Failed to open \"/proc/self/mountinfo\"\n");
bd01b7d5 1215 free(basecginfo);
d6337a5f
CB
1216 return false;
1217 }
41c33dbe 1218
e4aeecf5
CB
1219 if (lxc_cgfsng_debug)
1220 lxc_cgfsng_print_basecg_debuginfo(basecginfo, klist, nlist);
ccb4cabe 1221
ccb4cabe 1222 while (getline(&line, &len, f) != -1) {
49ff3958 1223 int type;
d6337a5f
CB
1224 bool writeable;
1225 struct hierarchy *new;
1226 char *mountpoint = NULL, *base_cgroup = NULL;
1227 char **controller_list = NULL;
ccb4cabe 1228
49ff3958 1229 type = get_cgroup_version(line);
d6337a5f 1230 if (type == 0)
ccb4cabe
SH
1231 continue;
1232
d6337a5f 1233 if (type == CGROUP2_SUPER_MAGIC && unified)
ccb4cabe
SH
1234 continue;
1235
d6337a5f
CB
1236 if (cgroup_layout == CGROUP_LAYOUT_UNKNOWN) {
1237 if (type == CGROUP2_SUPER_MAGIC)
1238 cgroup_layout = CGROUP_LAYOUT_UNIFIED;
1239 else if (type == CGROUP_SUPER_MAGIC)
1240 cgroup_layout = CGROUP_LAYOUT_LEGACY;
1241 } else if (cgroup_layout == CGROUP_LAYOUT_UNIFIED) {
1242 if (type == CGROUP_SUPER_MAGIC)
1243 cgroup_layout = CGROUP_LAYOUT_HYBRID;
1244 } else if (cgroup_layout == CGROUP_LAYOUT_LEGACY) {
1245 if (type == CGROUP2_SUPER_MAGIC)
1246 cgroup_layout = CGROUP_LAYOUT_HYBRID;
ccb4cabe
SH
1247 }
1248
a3926f6a 1249 controller_list = cg_hybrid_get_controllers(klist, nlist, line, type);
d6337a5f
CB
1250 if (!controller_list && type == CGROUP_SUPER_MAGIC)
1251 continue;
1252
1253 if (type == CGROUP_SUPER_MAGIC)
1254 if (controller_list_is_dup(hierarchies, controller_list))
1255 goto next;
1256
a3926f6a 1257 mountpoint = cg_hybrid_get_mountpoint(line);
ccb4cabe 1258 if (!mountpoint) {
65d78313 1259 CGFSNG_DEBUG("Failed parsing mountpoint from \"%s\"\n", line);
d6337a5f 1260 goto next;
ccb4cabe
SH
1261 }
1262
d6337a5f 1263 if (type == CGROUP_SUPER_MAGIC)
a3926f6a 1264 base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, controller_list[0], CGROUP_SUPER_MAGIC);
d6337a5f 1265 else
a3926f6a 1266 base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, NULL, CGROUP2_SUPER_MAGIC);
ccb4cabe 1267 if (!base_cgroup) {
d6337a5f
CB
1268 CGFSNG_DEBUG("Failed to find current cgroup\n");
1269 goto next;
ccb4cabe 1270 }
6328fd9c 1271
ccb4cabe
SH
1272 trim(base_cgroup);
1273 prune_init_scope(base_cgroup);
d6337a5f 1274 if (type == CGROUP2_SUPER_MAGIC)
6328fd9c
CB
1275 writeable = test_writeable_v2(mountpoint, base_cgroup);
1276 else
1277 writeable = test_writeable_v1(mountpoint, base_cgroup);
d6337a5f
CB
1278 if (!writeable)
1279 goto next;
1280
1281 if (type == CGROUP2_SUPER_MAGIC) {
1282 char *cgv2_ctrl_path;
1283
1284 cgv2_ctrl_path = must_make_path(mountpoint, base_cgroup,
1285 "cgroup.controllers",
1286 NULL);
1287
1288 controller_list = cg_unified_get_controllers(cgv2_ctrl_path);
1289 free(cgv2_ctrl_path);
1290 if (!controller_list)
1291 controller_list = cg_unified_make_empty_controller();
ccb4cabe 1292 }
d6337a5f
CB
1293 new = add_hierarchy(controller_list, mountpoint, base_cgroup, type);
1294 if (type == CGROUP2_SUPER_MAGIC && !unified)
1295 unified = new;
1296
1297 continue;
1298
1299 next:
1300 free_string_list(controller_list);
1301 free(mountpoint);
1302 free(base_cgroup);
ccb4cabe
SH
1303 }
1304
1305 free_string_list(klist);
1306 free_string_list(nlist);
1307
1308 free(basecginfo);
1309
1310 fclose(f);
1311 free(line);
1312
e4aeecf5
CB
1313 if (lxc_cgfsng_debug) {
1314 printf("writeable subsystems:\n");
1315 lxc_cgfsng_print_hierarchies();
1316 }
1317
ccb4cabe
SH
1318 /* verify that all controllers in cgroup.use and all crucial
1319 * controllers are accounted for
1320 */
c2712f64 1321 if (!all_controllers_found())
ccb4cabe
SH
1322 return false;
1323
1324 return true;
1325}
1326
d6337a5f
CB
1327static int cg_is_pure_unified(void) {
1328
1329 int ret;
1330 struct statfs fs;
1331
1332 ret = statfs("/sys/fs/cgroup", &fs);
1333 if (ret < 0)
1334 return -ENOMEDIUM;
1335
1336 if (is_fs_type(&fs, CGROUP2_SUPER_MAGIC))
1337 return CGROUP2_SUPER_MAGIC;
1338
1339 return 0;
1340}
1341
1342/* Get current cgroup from /proc/self/cgroup for the cgroupfs v2 hierarchy. */
a3926f6a 1343static char *cg_unified_get_current_cgroup(void)
457ca9aa 1344{
d6337a5f
CB
1345 char *basecginfo;
1346 char *base_cgroup;
1347 bool will_escape;
1348 char *copy = NULL;
1349
1350 will_escape = (geteuid() == 0);
1351 if (will_escape)
1352 basecginfo = read_file("/proc/1/cgroup");
1353 else
1354 basecginfo = read_file("/proc/self/cgroup");
1355 if (!basecginfo)
1356 return NULL;
1357
1358 base_cgroup = strstr(basecginfo, "0::/");
1359 if (!base_cgroup)
1360 goto cleanup_on_err;
1361
1362 base_cgroup = base_cgroup + 3;
1363 copy = copy_to_eol(base_cgroup);
1364 if (!copy)
1365 goto cleanup_on_err;
1366
1367cleanup_on_err:
1368 free(basecginfo);
1369 if (copy)
1370 trim(copy);
1371
1372 return copy;
1373}
1374
a3926f6a 1375static int cg_unified_init(void)
d6337a5f
CB
1376{
1377 int ret;
1378 char *mountpoint, *subtree_path;
1379 char **delegatable;
1380 char *base_cgroup = NULL;
1381
1382 ret = cg_is_pure_unified();
1383 if (ret == -ENOMEDIUM)
1384 return -ENOMEDIUM;
1385
1386 if (ret != CGROUP2_SUPER_MAGIC)
1387 return 0;
1388
a3926f6a 1389 base_cgroup = cg_unified_get_current_cgroup();
d6337a5f
CB
1390 if (!base_cgroup)
1391 return -EINVAL;
1392 prune_init_scope(base_cgroup);
1393
1394 /* We assume that we have already been given controllers to delegate
1395 * further down the hierarchy. If not it is up to the user to delegate
1396 * them to us.
1397 */
1398 mountpoint = must_copy_string("/sys/fs/cgroup");
1399 subtree_path = must_make_path(mountpoint, base_cgroup,
1400 "cgroup.subtree_control", NULL);
1401 delegatable = cg_unified_get_controllers(subtree_path);
1402 free(subtree_path);
1403 if (!delegatable)
1404 delegatable = cg_unified_make_empty_controller();
1405 if (!delegatable[0])
1406 CGFSNG_DEBUG("No controllers are enabled for delegation\n");
1407
1408 /* TODO: If the user requested specific controllers via lxc.cgroup.use
1409 * we should verify here. The reason I'm not doing it right is that I'm
1410 * not convinced that lxc.cgroup.use will be the future since it is a
1411 * global property. I much rather have an option that lets you request
1412 * controllers per container.
1413 */
1414
1415 add_hierarchy(delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC);
1416 unified = hierarchies[0];
1417
1418 cgroup_layout = CGROUP_LAYOUT_UNIFIED;
1419 return CGROUP2_SUPER_MAGIC;
1420}
1421
1422static bool cg_init(void)
1423{
1424 int ret;
457ca9aa 1425 const char *tmp;
d6337a5f 1426
457ca9aa
SH
1427 errno = 0;
1428 tmp = lxc_global_config_value("lxc.cgroup.use");
1a0e70ac 1429 if (!cgroup_use && errno != 0) { /* lxc.cgroup.use can be NULL */
65d78313 1430 CGFSNG_DEBUG("Failed to retrieve list of cgroups to use\n");
457ca9aa
SH
1431 return false;
1432 }
1433 cgroup_use = must_copy_string(tmp);
1434
a3926f6a 1435 ret = cg_unified_init();
d6337a5f
CB
1436 if (ret < 0)
1437 return false;
1438
1439 if (ret == CGROUP2_SUPER_MAGIC)
1440 return true;
1441
a3926f6a 1442 return cg_hybrid_init();
457ca9aa
SH
1443}
1444
43654d34 1445static void *cgfsng_init(struct lxc_handler *handler)
ccb4cabe 1446{
457ca9aa 1447 const char *cgroup_pattern;
43654d34 1448 struct cgfsng_handler_data *d;
ccb4cabe
SH
1449
1450 d = must_alloc(sizeof(*d));
1451 memset(d, 0, sizeof(*d));
1452
43654d34
CB
1453 /* copy container name */
1454 d->name = must_copy_string(handler->name);
1455
1456 /* copy per-container cgroup information */
ae5e6c08
CB
1457 d->cgroup_meta.dir = NULL;
1458 d->cgroup_meta.controllers = NULL;
9b5396f9
CB
1459 if (handler->conf) {
1460 d->cgroup_meta.dir = must_copy_string(handler->conf->cgroup_meta.dir);
1461 d->cgroup_meta.controllers = must_copy_string(handler->conf->cgroup_meta.controllers);
1462 }
ccb4cabe 1463
43654d34 1464 /* copy system-wide cgroup information */
ccb4cabe 1465 cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
43654d34
CB
1466 if (!cgroup_pattern) {
1467 /* lxc.cgroup.pattern is only NULL on error. */
ccb4cabe
SH
1468 ERROR("Error getting cgroup pattern");
1469 goto out_free;
1470 }
1471 d->cgroup_pattern = must_copy_string(cgroup_pattern);
1472
d6337a5f
CB
1473 d->cgroup_layout = cgroup_layout;
1474 if (d->cgroup_layout == CGROUP_LAYOUT_LEGACY)
1475 TRACE("Running with legacy cgroup layout");
1476 else if (d->cgroup_layout == CGROUP_LAYOUT_HYBRID)
1477 TRACE("Running with hybrid cgroup layout");
1478 else if (d->cgroup_layout == CGROUP_LAYOUT_UNIFIED)
1479 TRACE("Running with unified cgroup layout");
1480 else
1481 WARN("Running with unknown cgroup layout");
1482
e4aeecf5
CB
1483 if (lxc_cgfsng_debug)
1484 lxc_cgfsng_print_debuginfo(d);
ccb4cabe
SH
1485
1486 return d;
1487
1488out_free:
1489 free_handler_data(d);
1490 return NULL;
1491}
1492
bd8ef4e4 1493static int recursive_destroy(char *dirname)
ccb4cabe 1494{
a17f8b3f 1495 int ret;
74f96976 1496 struct dirent *direntp;
ccb4cabe
SH
1497 DIR *dir;
1498 int r = 0;
1499
1500 dir = opendir(dirname);
1501 if (!dir)
1502 return -1;
1503
74f96976 1504 while ((direntp = readdir(dir))) {
ccb4cabe 1505 char *pathname;
a17f8b3f 1506 struct stat mystat;
ccb4cabe 1507
ccb4cabe
SH
1508 if (!strcmp(direntp->d_name, ".") ||
1509 !strcmp(direntp->d_name, ".."))
1510 continue;
1511
1512 pathname = must_make_path(dirname, direntp->d_name, NULL);
1513
a17f8b3f
CB
1514 ret = lstat(pathname, &mystat);
1515 if (ret < 0) {
ccb4cabe 1516 if (!r)
a17f8b3f 1517 WARN("Failed to stat %s", pathname);
ccb4cabe
SH
1518 r = -1;
1519 goto next;
1520 }
1521
1522 if (!S_ISDIR(mystat.st_mode))
1523 goto next;
a17f8b3f 1524
bd8ef4e4 1525 ret = recursive_destroy(pathname);
a17f8b3f 1526 if (ret < 0)
ccb4cabe 1527 r = -1;
bd8ef4e4 1528 next:
ccb4cabe
SH
1529 free(pathname);
1530 }
1531
a17f8b3f
CB
1532 ret = rmdir(dirname);
1533 if (ret < 0) {
ccb4cabe 1534 if (!r)
bd8ef4e4
CB
1535 WARN("%s - Failed to delete \"%s\"", strerror(errno),
1536 dirname);
ccb4cabe
SH
1537 r = -1;
1538 }
1539
a17f8b3f
CB
1540 ret = closedir(dir);
1541 if (ret < 0) {
ccb4cabe 1542 if (!r)
bd8ef4e4
CB
1543 WARN("%s - Failed to delete \"%s\"", strerror(errno),
1544 dirname);
ccb4cabe
SH
1545 r = -1;
1546 }
a17f8b3f 1547
ccb4cabe
SH
1548 return r;
1549}
1550
bd8ef4e4
CB
1551static int cgroup_rmdir(char *container_cgroup)
1552{
1553 int i;
1554
1555 if (!container_cgroup || !hierarchies)
1556 return 0;
1557
1558 for (i = 0; hierarchies[i]; i++) {
1559 int ret;
1560 struct hierarchy *h = hierarchies[i];
1561
1562 if (!h->fullcgpath)
1563 continue;
1564
1565 ret = recursive_destroy(h->fullcgpath);
1566 if (ret < 0)
1567 WARN("Failed to destroy \"%s\"", h->fullcgpath);
1568
1569 free(h->fullcgpath);
1570 h->fullcgpath = NULL;
1571 }
1572
1573 return 0;
1574}
1575
4160c3a0
CB
1576struct generic_userns_exec_data {
1577 struct cgfsng_handler_data *d;
1578 struct lxc_conf *conf;
1579 uid_t origuid; /* target uid in parent namespace */
1580 char *path;
1581};
1582
bd8ef4e4 1583static int cgroup_rmdir_wrapper(void *data)
ccb4cabe 1584{
6efacf80 1585 int ret;
4160c3a0
CB
1586 struct generic_userns_exec_data *arg = data;
1587 uid_t nsuid = (arg->conf->root_nsuid_map != NULL) ? 0 : arg->conf->init_uid;
1588 gid_t nsgid = (arg->conf->root_nsgid_map != NULL) ? 0 : arg->conf->init_gid;
ccb4cabe 1589
6efacf80
CB
1590 ret = setresgid(nsgid, nsgid, nsgid);
1591 if (ret < 0) {
1592 SYSERROR("Failed to setresgid(%d, %d, %d)", (int)nsgid,
1593 (int)nsgid, (int)nsgid);
1594 return -1;
1595 }
1596
1597 ret = setresuid(nsuid, nsuid, nsuid);
1598 if (ret < 0) {
1599 SYSERROR("Failed to setresuid(%d, %d, %d)", (int)nsuid,
1600 (int)nsuid, (int)nsuid);
1601 return -1;
1602 }
1603
1604 ret = setgroups(0, NULL);
1605 if (ret < 0 && errno != EPERM) {
1606 SYSERROR("Failed to setgroups(0, NULL)");
1607 return -1;
1608 }
ccb4cabe 1609
bd8ef4e4 1610 return cgroup_rmdir(arg->d->container_cgroup);
ccb4cabe
SH
1611}
1612
bd8ef4e4 1613static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
ccb4cabe 1614{
bd8ef4e4
CB
1615 int ret;
1616 struct cgfsng_handler_data *d = hdata;
4160c3a0
CB
1617 struct generic_userns_exec_data wrap;
1618
bd8ef4e4
CB
1619 if (!d)
1620 return;
1621
4160c3a0 1622 wrap.origuid = 0;
bd8ef4e4 1623 wrap.d = hdata;
4160c3a0
CB
1624 wrap.conf = conf;
1625
ccb4cabe 1626 if (conf && !lxc_list_empty(&conf->id_map))
bd8ef4e4
CB
1627 ret = userns_exec_1(conf, cgroup_rmdir_wrapper, &wrap,
1628 "cgroup_rmdir_wrapper");
ccb4cabe 1629 else
bd8ef4e4
CB
1630 ret = cgroup_rmdir(d->container_cgroup);
1631 if (ret < 0) {
1632 WARN("Failed to destroy cgroups");
ccb4cabe 1633 return;
ccb4cabe
SH
1634 }
1635
1636 free_handler_data(d);
1637}
1638
1639struct cgroup_ops *cgfsng_ops_init(void)
1640{
e4aeecf5
CB
1641 if (getenv("LXC_DEBUG_CGFSNG"))
1642 lxc_cgfsng_debug = true;
1643
d6337a5f 1644 if (!cg_init())
457ca9aa 1645 return NULL;
e4aeecf5 1646
ccb4cabe
SH
1647 return &cgfsng_ops;
1648}
1649
a3926f6a 1650static bool cg_unified_create_cgroup(struct hierarchy *h, char *cgname)
0c3deb94
CB
1651{
1652 char **it;
1653 size_t i, parts_len;
1654 size_t full_len = 0;
1655 char *add_controllers = NULL, *cgroup = NULL;
1656 char **parts = NULL;
1657 bool bret = false;
1658
1659 if (h->version != CGROUP2_SUPER_MAGIC)
1660 return true;
1661
1662 if (!h->controllers)
1663 return true;
1664
1665 /* For now we simply enable all controllers that we have detected by
1666 * creating a string like "+memory +pids +cpu +io".
1667 * TODO: In the near future we might want to support "-<controller>"
1668 * etc. but whether supporting semantics like this make sense will need
1669 * some thinking.
1670 */
1671 for (it = h->controllers; it && *it; it++) {
1672 full_len += strlen(*it) + 2;
1673 add_controllers = must_realloc(add_controllers, full_len + 1);
1674 if (h->controllers[0] == *it)
1675 add_controllers[0] = '\0';
1676 strcat(add_controllers, "+");
1677 strcat(add_controllers, *it);
1678 if ((it + 1) && *(it + 1))
1679 strcat(add_controllers, " ");
1680 }
1681
1682 parts = lxc_string_split(cgname, '/');
1683 if (!parts)
1684 goto on_error;
1685 parts_len = lxc_array_len((void **)parts);
1686 if (parts_len > 0)
1687 parts_len--;
1688
1689 cgroup = must_make_path(h->mountpoint, h->base_cgroup, NULL);
1690 for (i = 0; i < parts_len; i++) {
1691 int ret;
1692 char *target;
1693
1694 cgroup = must_append_path(cgroup, parts[i], NULL);
1695 target = must_make_path(cgroup, "cgroup.subtree_control", NULL);
1696 ret = lxc_write_to_file(target, add_controllers, full_len, false);
1697 free(target);
1698 if (ret < 0) {
1699 SYSERROR("Could not enable \"%s\" controllers in the "
1700 "unified cgroup \"%s\"", add_controllers, cgroup);
1701 goto on_error;
1702 }
1703 }
1704
1705 bret = true;
1706
1707on_error:
1708 lxc_free_array((void **)parts, free);
1709 free(add_controllers);
1710 free(cgroup);
1711 return bret;
1712}
1713
ccb4cabe
SH
1714static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
1715{
0c3deb94
CB
1716 int ret;
1717
e3a3fecf 1718 h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
1a0e70ac 1719 if (dir_exists(h->fullcgpath)) { /* it must not already exist */
0c3deb94 1720 ERROR("cgroup \"%s\" already existed", h->fullcgpath);
d8da679e 1721 return false;
6f9584d8 1722 }
0c3deb94 1723
a3926f6a 1724 if (!cg_legacy_handle_cpuset_hierarchy(h, cgname)) {
0c3deb94
CB
1725 ERROR("Failed to handle cgroupfs v1 cpuset controller");
1726 return false;
1727 }
1728
1729 ret = mkdir_p(h->fullcgpath, 0755);
1730 if (ret < 0) {
1731 ERROR("Failed to create cgroup \"%s\"", h->fullcgpath);
e3a3fecf 1732 return false;
6f9584d8 1733 }
0c3deb94 1734
a3926f6a 1735 return cg_unified_create_cgroup(h, cgname);
ccb4cabe
SH
1736}
1737
1738static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
1739{
1740 if (rmdir(h->fullcgpath) < 0)
1741 SYSERROR("Failed to clean up cgroup %s from failed creation attempt", h->fullcgpath);
1742 free(h->fullcgpath);
1743 h->fullcgpath = NULL;
1744}
1745
1746/*
d30ec4cb 1747 * Try to create the same cgroup in all hierarchies.
ccb4cabe
SH
1748 * Start with cgroup_pattern; next cgroup_pattern-1, -2, ..., -999
1749 */
1750static inline bool cgfsng_create(void *hdata)
1751{
bb30b52a 1752 int i;
ccb4cabe 1753 size_t len;
0c3deb94 1754 char *container_cgroup, *offset, *tmp;
7d531e9b
CB
1755 int idx = 0;
1756 struct cgfsng_handler_data *d = hdata;
ccb4cabe
SH
1757
1758 if (!d)
1759 return false;
43654d34 1760
ccb4cabe
SH
1761 if (d->container_cgroup) {
1762 WARN("cgfsng_create called a second time");
1763 return false;
1764 }
1765
43654d34 1766 if (d->cgroup_meta.dir)
7d531e9b 1767 tmp = lxc_string_join("/", (const char *[]){d->cgroup_meta.dir, d->name, NULL}, false);
43654d34
CB
1768 else
1769 tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
ccb4cabe
SH
1770 if (!tmp) {
1771 ERROR("Failed expanding cgroup name pattern");
1772 return false;
1773 }
1a0e70ac 1774 len = strlen(tmp) + 5; /* leave room for -NNN\0 */
0c3deb94
CB
1775 container_cgroup = must_alloc(len);
1776 strcpy(container_cgroup, tmp);
ccb4cabe 1777 free(tmp);
0c3deb94 1778 offset = container_cgroup + len - 5;
ccb4cabe
SH
1779
1780again:
95adfe93
SH
1781 if (idx == 1000) {
1782 ERROR("Too many conflicting cgroup names");
ccb4cabe 1783 goto out_free;
95adfe93 1784 }
66b66624 1785 if (idx) {
bb30b52a
CB
1786 int ret;
1787
66b66624
CB
1788 ret = snprintf(offset, 5, "-%d", idx);
1789 if (ret < 0 || (size_t)ret >= 5) {
1790 FILE *f = fopen("/dev/null", "w");
97ebced3 1791 if (f) {
66b66624
CB
1792 fprintf(f, "Workaround for GCC7 bug: "
1793 "https://gcc.gnu.org/bugzilla/"
1794 "show_bug.cgi?id=78969");
1795 fclose(f);
1796 }
1797 }
1798 }
457ca9aa 1799 for (i = 0; hierarchies[i]; i++) {
0c3deb94 1800 if (!create_path_for_hierarchy(hierarchies[i], container_cgroup)) {
ccb4cabe 1801 int j;
1a0e70ac 1802 ERROR("Failed to create \"%s\"", hierarchies[i]->fullcgpath);
457ca9aa
SH
1803 free(hierarchies[i]->fullcgpath);
1804 hierarchies[i]->fullcgpath = NULL;
ccb4cabe 1805 for (j = 0; j < i; j++)
0c3deb94 1806 remove_path_for_hierarchy(hierarchies[j], container_cgroup);
ccb4cabe
SH
1807 idx++;
1808 goto again;
1809 }
1810 }
1811 /* Done */
0c3deb94 1812 d->container_cgroup = container_cgroup;
ccb4cabe
SH
1813 return true;
1814
1815out_free:
0c3deb94 1816 free(container_cgroup);
ccb4cabe
SH
1817 return false;
1818}
1819
ccb4cabe
SH
1820static bool cgfsng_enter(void *hdata, pid_t pid)
1821{
ccb4cabe
SH
1822 char pidstr[25];
1823 int i, len;
1824
1825 len = snprintf(pidstr, 25, "%d", pid);
1826 if (len < 0 || len > 25)
1827 return false;
1828
457ca9aa
SH
1829 for (i = 0; hierarchies[i]; i++) {
1830 char *fullpath = must_make_path(hierarchies[i]->fullcgpath,
ccb4cabe
SH
1831 "cgroup.procs", NULL);
1832 if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
d3b00a8f 1833 SYSERROR("Failed to enter %s", fullpath);
ccb4cabe
SH
1834 free(fullpath);
1835 return false;
1836 }
1837 free(fullpath);
1838 }
1839
1840 return true;
1841}
1842
6efacf80
CB
1843static int chowmod(char *path, uid_t chown_uid, gid_t chown_gid,
1844 mode_t chmod_mode)
1845{
1846 int ret;
1847
1848 ret = chown(path, chown_uid, chown_gid);
1849 if (ret < 0) {
1850 WARN("%s - Failed to chown(%s, %d, %d)", strerror(errno), path,
1851 (int)chown_uid, (int)chown_gid);
1852 return -1;
1853 }
1854
1855 ret = chmod(path, chmod_mode);
1856 if (ret < 0) {
1857 WARN("%s - Failed to chmod(%s, %d)", strerror(errno), path,
1858 (int)chmod_mode);
1859 return -1;
1860 }
1861
1862 return 0;
1863}
1864
1865/* chgrp the container cgroups to container group. We leave
c0888dfe
SH
1866 * the container owner as cgroup owner. So we must make the
1867 * directories 775 so that the container can create sub-cgroups.
43647298
SH
1868 *
1869 * Also chown the tasks and cgroup.procs files. Those may not
1870 * exist depending on kernel version.
c0888dfe 1871 */
ccb4cabe
SH
1872static int chown_cgroup_wrapper(void *data)
1873{
6efacf80 1874 int i, ret;
4160c3a0
CB
1875 uid_t destuid;
1876 struct generic_userns_exec_data *arg = data;
1877 uid_t nsuid = (arg->conf->root_nsuid_map != NULL) ? 0 : arg->conf->init_uid;
1878 gid_t nsgid = (arg->conf->root_nsgid_map != NULL) ? 0 : arg->conf->init_gid;
ccb4cabe 1879
6efacf80
CB
1880 ret = setresgid(nsgid, nsgid, nsgid);
1881 if (ret < 0) {
1882 SYSERROR("Failed to setresgid(%d, %d, %d)",
1883 (int)nsgid, (int)nsgid, (int)nsgid);
1884 return -1;
1885 }
1886
1887 ret = setresuid(nsuid, nsuid, nsuid);
1888 if (ret < 0) {
1889 SYSERROR("Failed to setresuid(%d, %d, %d)",
1890 (int)nsuid, (int)nsuid, (int)nsuid);
1891 return -1;
1892 }
1893
1894 ret = setgroups(0, NULL);
1895 if (ret < 0 && errno != EPERM) {
1896 SYSERROR("Failed to setgroups(0, NULL)");
1897 return -1;
1898 }
ccb4cabe
SH
1899
1900 destuid = get_ns_uid(arg->origuid);
1901
457ca9aa 1902 for (i = 0; hierarchies[i]; i++) {
6efacf80
CB
1903 char *fullpath;
1904 char *path = hierarchies[i]->fullcgpath;
43647298 1905
63e42fee 1906 ret = chowmod(path, destuid, nsgid, 0775);
6efacf80 1907 if (ret < 0)
ccb4cabe 1908 return -1;
c0888dfe 1909
6efacf80
CB
1910 /* Failures to chown() these are inconvenient but not
1911 * detrimental We leave these owned by the container launcher,
1912 * so that container root can write to the files to attach. We
1913 * chmod() them 664 so that container systemd can write to the
1914 * files (which systemd in wily insists on doing).
ab8f5424 1915 */
6efacf80
CB
1916
1917 if (hierarchies[i]->version == CGROUP_SUPER_MAGIC) {
1918 fullpath = must_make_path(path, "tasks", NULL);
1919 (void)chowmod(fullpath, destuid, nsgid, 0664);
1920 free(fullpath);
1921 }
43647298
SH
1922
1923 fullpath = must_make_path(path, "cgroup.procs", NULL);
6efacf80 1924 (void)chowmod(fullpath, destuid, 0, 0664);
ccb4cabe 1925 free(fullpath);
0e17357c 1926
d6337a5f 1927 if (hierarchies[i]->version != CGROUP2_SUPER_MAGIC)
0e17357c
CB
1928 continue;
1929
1930 fullpath = must_make_path(path, "cgroup.subtree_control", NULL);
6efacf80 1931 (void)chowmod(fullpath, destuid, nsgid, 0664);
0e17357c
CB
1932 free(fullpath);
1933
1934 fullpath = must_make_path(path, "cgroup.threads", NULL);
6efacf80 1935 (void)chowmod(fullpath, destuid, nsgid, 0664);
0e17357c 1936 free(fullpath);
ccb4cabe
SH
1937 }
1938
1939 return 0;
1940}
1941
058c1cb6 1942static bool cgfsng_chown(void *hdata, struct lxc_conf *conf)
ccb4cabe
SH
1943{
1944 struct cgfsng_handler_data *d = hdata;
4160c3a0 1945 struct generic_userns_exec_data wrap;
ccb4cabe
SH
1946
1947 if (!d)
1948 return false;
1949
1950 if (lxc_list_empty(&conf->id_map))
1951 return true;
1952
ccb4cabe 1953 wrap.origuid = geteuid();
4160c3a0
CB
1954 wrap.path = NULL;
1955 wrap.d = d;
1956 wrap.conf = conf;
ccb4cabe 1957
c9b7c33e
CB
1958 if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap,
1959 "chown_cgroup_wrapper") < 0) {
ccb4cabe
SH
1960 ERROR("Error requesting cgroup chown in new namespace");
1961 return false;
1962 }
1963
1964 return true;
1965}
1966
8aa1044f
SH
1967/*
1968 * We've safe-mounted a tmpfs as parent, so we don't need to protect against
1969 * symlinks any more - just use mount
1970 */
1971
1972/* mount cgroup-full if requested */
1973static int mount_cgroup_full(int type, struct hierarchy *h, char *dest,
a3926f6a 1974 char *container_cgroup)
8aa1044f
SH
1975{
1976 if (type < LXC_AUTO_CGROUP_FULL_RO || type > LXC_AUTO_CGROUP_FULL_MIXED)
1977 return 0;
1978 if (mount(h->mountpoint, dest, "cgroup", MS_BIND, NULL) < 0) {
1979 SYSERROR("Error bind-mounting %s cgroup onto %s", h->mountpoint,
1980 dest);
1981 return -1;
1982 }
1983 if (type != LXC_AUTO_CGROUP_FULL_RW) {
5b6f9369
SH
1984 unsigned long flags = MS_BIND | MS_NOSUID | MS_NOEXEC | MS_NODEV |
1985 MS_REMOUNT | MS_RDONLY;
1986 if (mount(NULL, dest, "cgroup", flags, NULL) < 0) {
8aa1044f
SH
1987 SYSERROR("Error remounting %s readonly", dest);
1988 return -1;
1989 }
1990 }
1991
1992 INFO("Bind mounted %s onto %s", h->mountpoint, dest);
1993 if (type != LXC_AUTO_CGROUP_FULL_MIXED)
1994 return 0;
1995
1996 /* mount just the container path rw */
1997 char *source = must_make_path(h->mountpoint, h->base_cgroup, container_cgroup, NULL);
5b6f9369 1998 char *rwpath = must_make_path(dest, h->base_cgroup, container_cgroup, NULL);
8aa1044f 1999 if (mount(source, rwpath, "cgroup", MS_BIND, NULL) < 0)
13277ec4 2000 WARN("Failed to mount %s read-write: %s", rwpath,
2001 strerror(errno));
8aa1044f
SH
2002 INFO("Made %s read-write", rwpath);
2003 free(rwpath);
2004 free(source);
2005 return 0;
2006}
2007
2008/* cgroup-full:* is done, no need to create subdirs */
2009static bool cg_mount_needs_subdirs(int type)
2010{
2011 if (type >= LXC_AUTO_CGROUP_FULL_RO)
2012 return false;
a3926f6a 2013
8aa1044f
SH
2014 return true;
2015}
2016
886cac86
CB
2017/* After $rootfs/sys/fs/container/controller/the/cg/path has been created,
2018 * remount controller ro if needed and bindmount the cgroupfs onto
2019 * controll/the/cg/path.
8aa1044f 2020 */
a3926f6a
CB
2021static int do_secondstage_mounts_if_needed(int type, struct hierarchy *h,
2022 char *controllerpath, char *cgpath,
2023 const char *container_cgroup)
8aa1044f 2024{
5285689c 2025 int ret, remount_flags;
886cac86
CB
2026 char *sourcepath;
2027 int flags = MS_BIND;
2028
8aa1044f 2029 if (type == LXC_AUTO_CGROUP_RO || type == LXC_AUTO_CGROUP_MIXED) {
886cac86
CB
2030 ret = mount(controllerpath, controllerpath, "cgroup", MS_BIND, NULL);
2031 if (ret < 0) {
2032 SYSERROR("Failed to bind mount \"%s\" onto \"%s\"",
2033 controllerpath, controllerpath);
8aa1044f
SH
2034 return -1;
2035 }
886cac86 2036
5285689c
CB
2037 remount_flags = add_required_remount_flags(controllerpath,
2038 controllerpath,
2039 flags | MS_REMOUNT);
886cac86
CB
2040 ret = mount(controllerpath, controllerpath, "cgroup",
2041 MS_REMOUNT | MS_BIND | MS_RDONLY, NULL);
2042 if (ret < 0) {
2043 SYSERROR("Failed to remount \"%s\" ro", controllerpath);
8aa1044f
SH
2044 return -1;
2045 }
886cac86 2046
8aa1044f
SH
2047 INFO("Remounted %s read-only", controllerpath);
2048 }
886cac86
CB
2049
2050 sourcepath = must_make_path(h->mountpoint, h->base_cgroup,
2051 container_cgroup, NULL);
8aa1044f
SH
2052 if (type == LXC_AUTO_CGROUP_RO)
2053 flags |= MS_RDONLY;
886cac86
CB
2054
2055 ret = mount(sourcepath, cgpath, "cgroup", flags, NULL);
2056 if (ret < 0) {
2057 SYSERROR("Failed to mount \"%s\" onto \"%s\"", h->controllers[0], cgpath);
8aa1044f 2058 free(sourcepath);
8aa1044f
SH
2059 return -1;
2060 }
886cac86 2061 INFO("Mounted \"%s\" onto \"%s\"", h->controllers[0], cgpath);
f8c40ffa
L
2062
2063 if (flags & MS_RDONLY) {
5285689c
CB
2064 remount_flags = add_required_remount_flags(sourcepath, cgpath,
2065 flags | MS_REMOUNT);
2066 ret = mount(sourcepath, cgpath, "cgroup", remount_flags, NULL);
886cac86
CB
2067 if (ret < 0) {
2068 SYSERROR("Failed to remount \"%s\" ro", cgpath);
f8c40ffa 2069 free(sourcepath);
f8c40ffa
L
2070 return -1;
2071 }
5285689c 2072 INFO("Remounted %s read-only", cgpath);
f8c40ffa
L
2073 }
2074
8aa1044f 2075 free(sourcepath);
886cac86 2076 INFO("Completed second stage cgroup automounts for \"%s\"", cgpath);
8aa1044f
SH
2077 return 0;
2078}
2079
5285689c
CB
2080static int cg_mount_in_cgroup_namespace(int type, struct hierarchy *h,
2081 const char *controllerpath)
b635e92d
CB
2082{
2083 int ret;
2084 char *controllers = NULL;
a760603e
CB
2085 char *fstype = "cgroup2";
2086 unsigned long flags = 0;
b635e92d 2087
a760603e
CB
2088 flags |= MS_NOSUID;
2089 flags |= MS_NOEXEC;
2090 flags |= MS_NODEV;
2091 flags |= MS_RELATIME;
2092
2093 if (type == LXC_AUTO_CGROUP_RO || type == LXC_AUTO_CGROUP_FULL_RO)
2094 flags |= MS_RDONLY;
2095
d6337a5f 2096 if (h->version != CGROUP2_SUPER_MAGIC) {
a760603e
CB
2097 controllers = lxc_string_join(",", (const char **)h->controllers, false);
2098 if (!controllers)
2099 return -ENOMEM;
2100 fstype = "cgroup";
b635e92d
CB
2101 }
2102
a760603e 2103 ret = mount("cgroup", controllerpath, fstype, flags, controllers);
b635e92d
CB
2104 free(controllers);
2105 if (ret < 0) {
a760603e 2106 SYSERROR("Failed to mount %s with cgroup filesystem type %s", controllerpath, fstype);
b635e92d
CB
2107 return -1;
2108 }
2109
a760603e 2110 DEBUG("Mounted %s with cgroup filesystem type %s", controllerpath, fstype);
b635e92d
CB
2111 return 0;
2112}
2113
ccb4cabe
SH
2114static bool cgfsng_mount(void *hdata, const char *root, int type)
2115{
3f69fb12 2116 int i, ret;
8aa1044f
SH
2117 char *tmpfspath = NULL;
2118 bool retval = false;
b635e92d
CB
2119 struct lxc_handler *handler = hdata;
2120 struct cgfsng_handler_data *d = handler->cgroup_data;
3f69fb12 2121 bool has_cgns = false, wants_force_mount = false;
8aa1044f
SH
2122
2123 if ((type & LXC_AUTO_CGROUP_MASK) == 0)
2124 return true;
2125
3f69fb12
SY
2126 if (type & LXC_AUTO_CGROUP_FORCE) {
2127 type &= ~LXC_AUTO_CGROUP_FORCE;
2128 wants_force_mount = true;
2129 }
b635e92d 2130
3f69fb12
SY
2131 if (!wants_force_mount){
2132 if (!lxc_list_empty(&handler->conf->keepcaps))
2133 wants_force_mount = !in_caplist(CAP_SYS_ADMIN, &handler->conf->keepcaps);
2134 else
2135 wants_force_mount = in_caplist(CAP_SYS_ADMIN, &handler->conf->caps);
2136 }
8aa1044f 2137
3f69fb12
SY
2138 has_cgns = cgns_supported();
2139 if (has_cgns && !wants_force_mount)
2140 return true;
8aa1044f
SH
2141
2142 if (type == LXC_AUTO_CGROUP_NOSPEC)
2143 type = LXC_AUTO_CGROUP_MIXED;
2144 else if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
2145 type = LXC_AUTO_CGROUP_FULL_MIXED;
2146
2147 /* Mount tmpfs */
3f69fb12
SY
2148 tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
2149 ret = safe_mount("cgroup_root", tmpfspath, "tmpfs",
2150 MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME,
2151 "size=10240k,mode=755", root);
2152 if (ret < 0)
2153 goto on_error;
8aa1044f 2154
457ca9aa 2155 for (i = 0; hierarchies[i]; i++) {
8aa1044f 2156 char *controllerpath, *path2;
457ca9aa 2157 struct hierarchy *h = hierarchies[i];
8aa1044f 2158 char *controller = strrchr(h->mountpoint, '/');
8aa1044f
SH
2159
2160 if (!controller)
2161 continue;
2162 controller++;
2163 controllerpath = must_make_path(tmpfspath, controller, NULL);
2164 if (dir_exists(controllerpath)) {
2165 free(controllerpath);
2166 continue;
2167 }
3f69fb12
SY
2168 ret = mkdir(controllerpath, 0755);
2169 if (ret < 0) {
8aa1044f
SH
2170 SYSERROR("Error creating cgroup path: %s", controllerpath);
2171 free(controllerpath);
3f69fb12 2172 goto on_error;
8aa1044f 2173 }
b635e92d 2174
3f69fb12 2175 if (has_cgns && wants_force_mount) {
b635e92d
CB
2176 /* If cgroup namespaces are supported but the container
2177 * will not have CAP_SYS_ADMIN after it has started we
2178 * need to mount the cgroups manually.
2179 */
3f69fb12 2180 ret = cg_mount_in_cgroup_namespace(type, h, controllerpath);
b635e92d 2181 free(controllerpath);
3f69fb12
SY
2182 if (ret < 0)
2183 goto on_error;
2184
b635e92d
CB
2185 continue;
2186 }
2187
3f69fb12
SY
2188 ret = mount_cgroup_full(type, h, controllerpath, d->container_cgroup);
2189 if (ret < 0) {
8aa1044f 2190 free(controllerpath);
3f69fb12 2191 goto on_error;
8aa1044f 2192 }
3f69fb12 2193
8aa1044f
SH
2194 if (!cg_mount_needs_subdirs(type)) {
2195 free(controllerpath);
2196 continue;
2197 }
3f69fb12
SY
2198
2199 path2 = must_make_path(controllerpath, h->base_cgroup,
2200 d->container_cgroup, NULL);
2201 ret = mkdir_p(path2, 0755);
2202 if (ret < 0) {
8aa1044f 2203 free(controllerpath);
8e0c6620 2204 free(path2);
3f69fb12 2205 goto on_error;
8aa1044f 2206 }
2f62fb00 2207
3f69fb12
SY
2208 ret = do_secondstage_mounts_if_needed(
2209 type, h, controllerpath, path2, d->container_cgroup);
8aa1044f
SH
2210 free(controllerpath);
2211 free(path2);
3f69fb12
SY
2212 if (ret < 0)
2213 goto on_error;
8aa1044f
SH
2214 }
2215 retval = true;
2216
3f69fb12 2217on_error:
8aa1044f
SH
2218 free(tmpfspath);
2219 return retval;
ccb4cabe
SH
2220}
2221
2222static int recursive_count_nrtasks(char *dirname)
2223{
74f96976 2224 struct dirent *direntp;
ccb4cabe
SH
2225 DIR *dir;
2226 int count = 0, ret;
2227 char *path;
2228
2229 dir = opendir(dirname);
2230 if (!dir)
2231 return 0;
2232
74f96976 2233 while ((direntp = readdir(dir))) {
ccb4cabe
SH
2234 struct stat mystat;
2235
2236 if (!direntp)
2237 break;
2238
2239 if (!strcmp(direntp->d_name, ".") ||
2240 !strcmp(direntp->d_name, ".."))
2241 continue;
2242
2243 path = must_make_path(dirname, direntp->d_name, NULL);
2244
2245 if (lstat(path, &mystat))
2246 goto next;
2247
2248 if (!S_ISDIR(mystat.st_mode))
2249 goto next;
2250
2251 count += recursive_count_nrtasks(path);
2252next:
2253 free(path);
2254 }
2255
2256 path = must_make_path(dirname, "cgroup.procs", NULL);
2257 ret = lxc_count_file_lines(path);
2258 if (ret != -1)
2259 count += ret;
2260 free(path);
2261
2262 (void) closedir(dir);
2263
2264 return count;
2265}
2266
2267static int cgfsng_nrtasks(void *hdata) {
2268 struct cgfsng_handler_data *d = hdata;
2269 char *path;
2270 int count;
2271
457ca9aa 2272 if (!d || !d->container_cgroup || !hierarchies)
ccb4cabe 2273 return -1;
a3926f6a 2274
457ca9aa 2275 path = must_make_path(hierarchies[0]->fullcgpath, NULL);
ccb4cabe
SH
2276 count = recursive_count_nrtasks(path);
2277 free(path);
2278 return count;
2279}
2280
2281/* Only root needs to escape to the cgroup of its init */
7103fe6f 2282static bool cgfsng_escape()
ccb4cabe 2283{
ccb4cabe
SH
2284 int i;
2285
2286 if (geteuid())
2287 return true;
2288
457ca9aa
SH
2289 for (i = 0; hierarchies[i]; i++) {
2290 char *fullpath = must_make_path(hierarchies[i]->mountpoint,
2291 hierarchies[i]->base_cgroup,
ccb4cabe
SH
2292 "cgroup.procs", NULL);
2293 if (lxc_write_to_file(fullpath, "0", 2, false) != 0) {
d3b00a8f 2294 SYSERROR("Failed to escape to %s", fullpath);
ccb4cabe 2295 free(fullpath);
6df334d1 2296 return false;
ccb4cabe
SH
2297 }
2298 free(fullpath);
2299 }
2300
6df334d1 2301 return true;
ccb4cabe
SH
2302}
2303
36662416
TA
2304static int cgfsng_num_hierarchies(void)
2305{
2306 int i;
2307
2308 for (i = 0; hierarchies[i]; i++)
2309 ;
2310
2311 return i;
2312}
2313
2314static bool cgfsng_get_hierarchies(int n, char ***out)
2315{
2316 int i;
2317
2318 /* sanity check n */
6b38e644 2319 for (i = 0; i < n; i++)
36662416
TA
2320 if (!hierarchies[i])
2321 return false;
36662416
TA
2322
2323 *out = hierarchies[i]->controllers;
2324
2325 return true;
2326}
2327
ccb4cabe
SH
2328#define THAWED "THAWED"
2329#define THAWED_LEN (strlen(THAWED))
2330
d6337a5f
CB
2331/* TODO: If the unified cgroup hierarchy grows a freezer controller this needs
2332 * to be adapted.
2333 */
ccb4cabe
SH
2334static bool cgfsng_unfreeze(void *hdata)
2335{
d6337a5f 2336 int ret;
ccb4cabe 2337 char *fullpath;
d6337a5f 2338 struct hierarchy *h;
ccb4cabe 2339
d6337a5f 2340 h = get_hierarchy("freezer");
457ca9aa 2341 if (!h)
ccb4cabe 2342 return false;
d6337a5f 2343
ccb4cabe 2344 fullpath = must_make_path(h->fullcgpath, "freezer.state", NULL);
d6337a5f 2345 ret = lxc_write_to_file(fullpath, THAWED, THAWED_LEN, false);
ccb4cabe 2346 free(fullpath);
d6337a5f
CB
2347 if (ret < 0)
2348 return false;
2349
ccb4cabe
SH
2350 return true;
2351}
2352
2353static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem)
2354{
d6337a5f
CB
2355 struct hierarchy *h;
2356
2357 h = get_hierarchy(subsystem);
ccb4cabe
SH
2358 if (!h)
2359 return NULL;
2360
371f834d
SH
2361 return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
2362}
2363
2364/*
2365 * Given a cgroup path returned from lxc_cmd_get_cgroup_path, build a
2366 * full path, which must be freed by the caller.
2367 */
2368static char *build_full_cgpath_from_monitorpath(struct hierarchy *h,
2369 const char *inpath,
2370 const char *filename)
2371{
371f834d 2372 return must_make_path(h->mountpoint, inpath, filename, NULL);
ccb4cabe
SH
2373}
2374
c2aed66d
CB
2375/* Technically, we're always at a delegation boundary here. (This is especially
2376 * true when cgroup namespaces are available.) The reasoning is that in order
2377 * for us to have been able to start a container in the first place the root
2378 * cgroup must have been a leaf node. Now, either the container's init system
2379 * has populated the cgroup and kept it as a leaf node or it has created
2380 * subtrees. In the former case we will simply attach to the leaf node we
2381 * created when we started the container in the latter case we create our own
2382 * cgroup for the attaching process.
2383 */
a3926f6a
CB
2384static int __cg_unified_attach(const struct hierarchy *h, const char *name,
2385 const char *lxcpath, const char *pidstr,
2386 size_t pidstr_len, const char *controller)
c2aed66d
CB
2387{
2388 int ret;
2389 size_t len;
2390 int fret = -1, idx = 0;
2391 char *base_path = NULL, *container_cgroup = NULL, *full_path = NULL;
2392
2393 container_cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
2394 /* not running */
2395 if (!container_cgroup)
2396 return 0;
2397
2398 base_path = must_make_path(h->mountpoint, container_cgroup, NULL);
2399 full_path = must_make_path(base_path, "cgroup.procs", NULL);
2400 /* cgroup is populated */
2401 ret = lxc_write_to_file(full_path, pidstr, pidstr_len, false);
2402 if (ret < 0 && errno != EBUSY)
2403 goto on_error;
2404
2405 if (ret == 0)
2406 goto on_success;
2407
2408 free(full_path);
2409
2410 len = strlen(base_path) + sizeof("/lxc-1000") - 1 +
2411 sizeof("/cgroup-procs") - 1;
2412 full_path = must_alloc(len + 1);
2413 do {
2414 if (idx)
2415 ret = snprintf(full_path, len + 1, "%s/lxc-%d",
2416 base_path, idx);
2417 else
2418 ret = snprintf(full_path, len + 1, "%s/lxc", base_path);
2419 if (ret < 0 || (size_t)ret >= len + 1)
2420 goto on_error;
2421
2422 ret = mkdir_p(full_path, 0755);
2423 if (ret < 0 && errno != EEXIST)
2424 goto on_error;
2425
2426 strcat(full_path, "/cgroup.procs");
2427 ret = lxc_write_to_file(full_path, pidstr, len, false);
2428 if (ret == 0)
2429 goto on_success;
2430
2431 /* this is a non-leaf node */
2432 if (errno != EBUSY)
2433 goto on_error;
2434
2435 } while (++idx > 0 && idx < 1000);
2436
2437on_success:
2438 if (idx < 1000)
2439 fret = 0;
2440
2441on_error:
2442 free(base_path);
2443 free(container_cgroup);
2444 free(full_path);
2445
2446 return fret;
2447}
2448
ccb4cabe
SH
2449static bool cgfsng_attach(const char *name, const char *lxcpath, pid_t pid)
2450{
c2aed66d 2451 int i, len, ret;
ccb4cabe 2452 char pidstr[25];
ccb4cabe
SH
2453
2454 len = snprintf(pidstr, 25, "%d", pid);
2455 if (len < 0 || len > 25)
2456 return false;
2457
457ca9aa 2458 for (i = 0; hierarchies[i]; i++) {
c2aed66d
CB
2459 char *path;
2460 char *fullpath = NULL;
457ca9aa 2461 struct hierarchy *h = hierarchies[i];
ccb4cabe 2462
c2aed66d 2463 if (h->version == CGROUP2_SUPER_MAGIC) {
a3926f6a
CB
2464 ret = __cg_unified_attach(h, name, lxcpath, pidstr, len,
2465 h->controllers[0]);
c2aed66d
CB
2466 if (ret < 0)
2467 return false;
2468
2469 continue;
2470 }
2471
ccb4cabe 2472 path = lxc_cmd_get_cgroup_path(name, lxcpath, h->controllers[0]);
c2aed66d
CB
2473 /* not running */
2474 if (!path)
ccb4cabe
SH
2475 continue;
2476
371f834d 2477 fullpath = build_full_cgpath_from_monitorpath(h, path, "cgroup.procs");
c2aed66d
CB
2478 ret = lxc_write_to_file(fullpath, pidstr, len, false);
2479 if (ret < 0) {
ccb4cabe
SH
2480 SYSERROR("Failed to attach %d to %s", (int)pid, fullpath);
2481 free(fullpath);
ccb4cabe
SH
2482 return false;
2483 }
ccb4cabe
SH
2484 free(fullpath);
2485 }
2486
ccb4cabe
SH
2487 return true;
2488}
2489
2490/*
2491 * Called externally (i.e. from 'lxc-cgroup') to query cgroup limits.
2492 * Here we don't have a cgroup_data set up, so we ask the running
2493 * container through the commands API for the cgroup path
2494 */
0069cc61
CB
2495static int cgfsng_get(const char *filename, char *value, size_t len,
2496 const char *name, const char *lxcpath)
ccb4cabe 2497{
ccb4cabe 2498 int ret = -1;
0069cc61
CB
2499 size_t controller_len;
2500 char *controller, *p, *path;
2501 struct hierarchy *h;
ccb4cabe 2502
0069cc61
CB
2503 controller_len = strlen(filename);
2504 controller = alloca(controller_len + 1);
2505 strcpy(controller, filename);
2506 p = strchr(controller, '.');
2507 if (p)
ccb4cabe
SH
2508 *p = '\0';
2509
0069cc61
CB
2510 path = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
2511 /* not running */
2512 if (!path)
ccb4cabe
SH
2513 return -1;
2514
0069cc61 2515 h = get_hierarchy(controller);
ccb4cabe 2516 if (h) {
0069cc61
CB
2517 char *fullpath;
2518
2519 fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
ccb4cabe
SH
2520 ret = lxc_read_from_file(fullpath, value, len);
2521 free(fullpath);
2522 }
ccb4cabe
SH
2523 free(path);
2524
2525 return ret;
2526}
2527
2528/*
2529 * Called externally (i.e. from 'lxc-cgroup') to set new cgroup limits.
2530 * Here we don't have a cgroup_data set up, so we ask the running
2531 * container through the commands API for the cgroup path
2532 */
87777968
CB
2533static int cgfsng_set(const char *filename, const char *value, const char *name,
2534 const char *lxcpath)
ccb4cabe 2535{
ccb4cabe 2536 int ret = -1;
87777968
CB
2537 size_t controller_len;
2538 char *controller, *p, *path;
2539 struct hierarchy *h;
ccb4cabe 2540
87777968
CB
2541 controller_len = strlen(filename);
2542 controller = alloca(controller_len + 1);
2543 strcpy(controller, filename);
2544 p = strchr(controller, '.');
2545 if (p)
ccb4cabe
SH
2546 *p = '\0';
2547
87777968
CB
2548 path = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
2549 /* not running */
2550 if (!path)
ccb4cabe
SH
2551 return -1;
2552
87777968 2553 h = get_hierarchy(controller);
ccb4cabe 2554 if (h) {
87777968
CB
2555 char *fullpath;
2556
2557 fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
ccb4cabe
SH
2558 ret = lxc_write_to_file(fullpath, value, strlen(value), false);
2559 free(fullpath);
2560 }
ccb4cabe
SH
2561 free(path);
2562
2563 return ret;
2564}
2565
72add155
SH
2566/*
2567 * take devices cgroup line
2568 * /dev/foo rwx
2569 * and convert it to a valid
2570 * type major:minor mode
2571 * line. Return <0 on error. Dest is a preallocated buffer
2572 * long enough to hold the output.
2573 */
2574static int convert_devpath(const char *invalue, char *dest)
2575{
2a06d041
CB
2576 int n_parts;
2577 char *p, *path, type;
72add155
SH
2578 struct stat sb;
2579 unsigned long minor, major;
2a06d041
CB
2580 int ret = -EINVAL;
2581 char *mode = NULL;
72add155
SH
2582
2583 path = must_copy_string(invalue);
2584
2585 /*
2586 * read path followed by mode; ignore any trailing text.
2587 * A ' # comment' would be legal. Technically other text
2588 * is not legal, we could check for that if we cared to
2589 */
2590 for (n_parts = 1, p = path; *p && n_parts < 3; p++) {
2c2d6c49
SH
2591 if (*p != ' ')
2592 continue;
2593 *p = '\0';
2594 if (n_parts != 1)
2595 break;
2596 p++;
2597 n_parts++;
2598 while (*p == ' ')
2599 p++;
2600 mode = p;
2601 if (*p == '\0')
2602 goto out;
72add155 2603 }
2c2d6c49
SH
2604
2605 if (n_parts == 1)
72add155 2606 goto out;
72add155
SH
2607
2608 ret = stat(path, &sb);
2609 if (ret < 0)
2610 goto out;
2611
72add155
SH
2612 mode_t m = sb.st_mode & S_IFMT;
2613 switch (m) {
2614 case S_IFBLK:
2615 type = 'b';
2616 break;
2617 case S_IFCHR:
2618 type = 'c';
2619 break;
2c2d6c49 2620 default:
72add155
SH
2621 ERROR("Unsupported device type %i for %s", m, path);
2622 ret = -EINVAL;
2623 goto out;
2624 }
2c2d6c49
SH
2625
2626 major = MAJOR(sb.st_rdev);
2627 minor = MINOR(sb.st_rdev);
2628 ret = snprintf(dest, 50, "%c %lu:%lu %s", type, major, minor, mode);
72add155 2629 if (ret < 0 || ret >= 50) {
2a06d041
CB
2630 ERROR("Error on configuration value \"%c %lu:%lu %s\" (max 50 "
2631 "chars)", type, major, minor, mode);
72add155
SH
2632 ret = -ENAMETOOLONG;
2633 goto out;
2634 }
2635 ret = 0;
2636
2637out:
2638 free(path);
2639 return ret;
2640}
2641
ccb4cabe
SH
2642/*
2643 * Called from setup_limits - here we have the container's cgroup_data because
2644 * we created the cgroups
2645 */
a3926f6a
CB
2646static int cg_legacy_set_data(const char *filename, const char *value,
2647 struct cgfsng_handler_data *d)
ccb4cabe 2648{
b3646d7e 2649 char *fullpath, *p;
ab1a6cac 2650 size_t len;
1a0e70ac
CB
2651 /* "b|c <2^64-1>:<2^64-1> r|w|m" = 47 chars max */
2652 char converted_value[50];
b3646d7e
CB
2653 struct hierarchy *h;
2654 int ret = 0;
2655 char *controller = NULL;
ccb4cabe 2656
ab1a6cac
CB
2657 len = strlen(filename);
2658 controller = alloca(len + 1);
b3646d7e 2659 strcpy(controller, filename);
ab1a6cac
CB
2660 p = strchr(controller, '.');
2661 if (p)
ccb4cabe
SH
2662 *p = '\0';
2663
c8bf519d 2664 if (strcmp("devices.allow", filename) == 0 && value[0] == '/') {
72add155
SH
2665 ret = convert_devpath(value, converted_value);
2666 if (ret < 0)
c8bf519d 2667 return ret;
72add155 2668 value = converted_value;
c8bf519d 2669 }
2670
b3646d7e
CB
2671 h = get_hierarchy(controller);
2672 if (!h) {
2673 ERROR("Failed to setup limits for the \"%s\" controller. "
2674 "The controller seems to be unused by \"cgfsng\" cgroup "
2675 "driver or not enabled on the cgroup hierarchy",
2676 controller);
d1953b26 2677 errno = ENOENT;
ab1a6cac 2678 return -ENOENT;
ccb4cabe 2679 }
b3646d7e
CB
2680
2681 fullpath = must_make_path(h->fullcgpath, filename, NULL);
2682 ret = lxc_write_to_file(fullpath, value, strlen(value), false);
2683 free(fullpath);
ccb4cabe
SH
2684 return ret;
2685}
2686
a3926f6a
CB
2687static bool __cg_legacy_setup_limits(void *hdata,
2688 struct lxc_list *cgroup_settings,
2689 bool do_devices)
ccb4cabe
SH
2690{
2691 struct cgfsng_handler_data *d = hdata;
2692 struct lxc_list *iterator, *sorted_cgroup_settings, *next;
2693 struct lxc_cgroup *cg;
ccb4cabe
SH
2694 bool ret = false;
2695
2696 if (lxc_list_empty(cgroup_settings))
2697 return true;
2698
2699 sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
6b38e644 2700 if (!sorted_cgroup_settings)
ccb4cabe 2701 return false;
ccb4cabe 2702
ccb4cabe
SH
2703 lxc_list_for_each(iterator, sorted_cgroup_settings) {
2704 cg = iterator->elem;
2705
2706 if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
a3926f6a 2707 if (cg_legacy_set_data(cg->subsystem, cg->value, d)) {
ccb4cabe
SH
2708 if (do_devices && (errno == EACCES || errno == EPERM)) {
2709 WARN("Error setting %s to %s for %s",
2710 cg->subsystem, cg->value, d->name);
2711 continue;
2712 }
2713 SYSERROR("Error setting %s to %s for %s",
2714 cg->subsystem, cg->value, d->name);
2715 goto out;
2716 }
6a628f4a 2717 DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
ccb4cabe 2718 }
ccb4cabe
SH
2719 }
2720
2721 ret = true;
6b38e644 2722 INFO("Limits for the legacy cgroup hierarchies have been setup");
ccb4cabe 2723out:
ccb4cabe
SH
2724 lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
2725 lxc_list_del(iterator);
2726 free(iterator);
2727 }
2728 free(sorted_cgroup_settings);
2729 return ret;
2730}
2731
a3926f6a
CB
2732static bool __cg_unified_setup_limits(void *hdata,
2733 struct lxc_list *cgroup_settings)
6b38e644
CB
2734{
2735 struct lxc_list *iterator;
2736 struct hierarchy *h = unified;
2737
2738 if (lxc_list_empty(cgroup_settings))
2739 return true;
2740
2741 if (!h)
2742 return false;
2743
2744 lxc_list_for_each(iterator, cgroup_settings) {
2745 int ret;
2746 char *fullpath;
2747 struct lxc_cgroup *cg = iterator->elem;
2748
2749 fullpath = must_make_path(h->fullcgpath, cg->subsystem, NULL);
2750 ret = lxc_write_to_file(fullpath, cg->value, strlen(cg->value), false);
2751 free(fullpath);
2752 if (ret < 0) {
2753 SYSERROR("Failed to set \"%s\" to \"%s\"", cg->subsystem, cg->value);
2754 return false;
2755 }
2756 TRACE("Set \"%s\" to \"%s\"", cg->subsystem, cg->value);
2757 }
2758
2759 INFO("Limits for the unified cgroup hierarchy have been setup");
2760 return true;
2761}
2762
2763static bool cgfsng_setup_limits(void *hdata, struct lxc_conf *conf,
2764 bool do_devices)
2765{
2766 bool bret;
2767
a3926f6a 2768 bret = __cg_legacy_setup_limits(hdata, &conf->cgroup, do_devices);
6b38e644
CB
2769 if (!bret)
2770 return false;
2771
a3926f6a 2772 return __cg_unified_setup_limits(hdata, &conf->cgroup2);
6b38e644
CB
2773}
2774
ccb4cabe
SH
2775static struct cgroup_ops cgfsng_ops = {
2776 .init = cgfsng_init,
2777 .destroy = cgfsng_destroy,
2778 .create = cgfsng_create,
2779 .enter = cgfsng_enter,
ccb4cabe 2780 .escape = cgfsng_escape,
36662416
TA
2781 .num_hierarchies = cgfsng_num_hierarchies,
2782 .get_hierarchies = cgfsng_get_hierarchies,
ccb4cabe
SH
2783 .get_cgroup = cgfsng_get_cgroup,
2784 .get = cgfsng_get,
2785 .set = cgfsng_set,
2786 .unfreeze = cgfsng_unfreeze,
2787 .setup_limits = cgfsng_setup_limits,
2788 .name = "cgroupfs-ng",
2789 .attach = cgfsng_attach,
058c1cb6 2790 .chown = cgfsng_chown,
ccb4cabe
SH
2791 .mount_cgroup = cgfsng_mount,
2792 .nrtasks = cgfsng_nrtasks,
2793 .driver = CGFSNG,
2794
2795 /* unsupported */
2796 .create_legacy = NULL,
2797};