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