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