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