]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/cgroup.c
split up lxc_cgroup_load_meta2
[mirror_lxc.git] / src / lxc / cgroup.c
CommitLineData
576f946d 1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
576f946d 8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
576f946d 22 */
23#define _GNU_SOURCE
24#include <stdio.h>
25#undef _GNU_SOURCE
26#include <stdlib.h>
27#include <errno.h>
576f946d 28#include <unistd.h>
29#include <string.h>
341a9bd8 30#include <dirent.h>
576f946d 31#include <fcntl.h>
b98f7d6e 32#include <ctype.h>
576f946d 33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/param.h>
36#include <sys/inotify.h>
aae1f3c4 37#include <sys/mount.h>
576f946d 38#include <netinet/in.h>
39#include <net/if.h>
40
e2bcd7db 41#include "error.h"
881450bb 42#include "config.h"
ae5c8b8e 43#include "commands.h"
b98f7d6e
SH
44#include "list.h"
45#include "conf.h"
33ad9f1a 46#include "utils.h"
740d1928 47#include "bdev.h"
025ed0f3 48#include "lxclock.h"
36eb9bde 49
36eb9bde 50#include <lxc/log.h>
00b3c2e2
CLG
51#include <lxc/cgroup.h>
52#include <lxc/start.h>
36eb9bde 53
edaf8b1b
SG
54#if IS_BIONIC
55#include <../include/lxcmntent.h>
56#else
57#include <mntent.h>
58#endif
59
120ce443
SG
60#ifndef HAVE_GETLINE
61#ifdef HAVE_FGETLN
62#include <../include/getline.h>
63#endif
64#endif
65
36eb9bde 66lxc_log_define(lxc_cgroup, lxc);
576f946d 67
33ad9f1a
CS
68static struct cgroup_process_info *lxc_cgroup_process_info_getx(const char *proc_pid_cgroup_str, struct cgroup_meta_data *meta);
69static char **subsystems_from_mount_options(const char *mount_options, char **kernel_list);
70static void lxc_cgroup_mount_point_free(struct cgroup_mount_point *mp);
71static void lxc_cgroup_hierarchy_free(struct cgroup_hierarchy *h);
72static bool is_valid_cgroup(const char *name);
73static int create_or_remove_cgroup(bool remove, struct cgroup_mount_point *mp, const char *path);
74static int create_cgroup(struct cgroup_mount_point *mp, const char *path);
75static int remove_cgroup(struct cgroup_mount_point *mp, const char *path);
76static char *cgroup_to_absolute_path(struct cgroup_mount_point *mp, const char *path, const char *suffix);
77static struct cgroup_process_info *find_info_for_subsystem(struct cgroup_process_info *info, const char *subsystem);
78static int do_cgroup_get(const char *cgroup_path, const char *sub_filename, char *value, size_t len);
79static int do_cgroup_set(const char *cgroup_path, const char *sub_filename, const char *value);
80static bool cgroup_devices_has_allow_or_deny(struct lxc_handler *h, char *v, bool for_allow);
81static int do_setup_cgroup(struct lxc_handler *h, struct lxc_list *cgroup_settings, bool do_devices);
82static int cgroup_recursive_task_count(const char *cgroup_path);
83static int count_lines(const char *fn);
84static int handle_clone_children(struct cgroup_mount_point *mp, char *cgroup_path);
85
86struct cgroup_meta_data *lxc_cgroup_load_meta()
87{
88 const char *cgroup_use = NULL;
89 char **cgroup_use_list = NULL;
90 struct cgroup_meta_data *md = NULL;
91 int saved_errno;
92
93 errno = 0;
94 cgroup_use = lxc_global_config_value("cgroup.use");
95 if (!cgroup_use && errno != 0)
96 return NULL;
97 if (cgroup_use) {
98 cgroup_use_list = lxc_string_split_and_trim(cgroup_use, ',');
99 if (!cgroup_use_list)
100 return NULL;
101 }
576f946d 102
33ad9f1a
CS
103 md = lxc_cgroup_load_meta2((const char **)cgroup_use_list);
104 saved_errno = errno;
105 lxc_free_array((void **)cgroup_use_list, free);
106 errno = saved_errno;
107 return md;
108}
fd37327f 109
b653309a
SH
110/* Step 1: determine all kernel subsystems */
111static bool find_cgroup_subsystems(char ***kernel_subsystems)
1d39a065 112{
b653309a
SH
113 FILE *proc_cgroups;
114 bool bret = false;
33ad9f1a
CS
115 char *line = NULL;
116 size_t sz = 0;
b653309a
SH
117 size_t kernel_subsystems_count = 0;
118 size_t kernel_subsystems_capacity = 0;
119 int r;
1d39a065 120
025ed0f3 121 process_lock();
33ad9f1a 122 proc_cgroups = fopen_cloexec("/proc/cgroups", "r");
025ed0f3 123 process_unlock();
33ad9f1a 124 if (!proc_cgroups)
b653309a 125 return false;
1d39a065 126
33ad9f1a
CS
127 while (getline(&line, &sz, proc_cgroups) != -1) {
128 char *tab1;
129 char *tab2;
130 int hierarchy_number;
1d39a065 131
33ad9f1a
CS
132 if (line[0] == '#')
133 continue;
134 if (!line[0])
135 continue;
1d39a065 136
33ad9f1a
CS
137 tab1 = strchr(line, '\t');
138 if (!tab1)
8900b9eb 139 continue;
33ad9f1a
CS
140 *tab1++ = '\0';
141 tab2 = strchr(tab1, '\t');
142 if (!tab2)
143 continue;
144 *tab2 = '\0';
fd37327f 145
33ad9f1a
CS
146 tab2 = NULL;
147 hierarchy_number = strtoul(tab1, &tab2, 10);
148 if (!tab2 || *tab2)
149 continue;
150 (void)hierarchy_number;
151
b653309a 152 r = lxc_grow_array((void ***)kernel_subsystems, &kernel_subsystems_capacity, kernel_subsystems_count + 1, 12);
33ad9f1a 153 if (r < 0)
b653309a
SH
154 goto out;
155 (*kernel_subsystems)[kernel_subsystems_count] = strdup(line);
156 if (!(*kernel_subsystems)[kernel_subsystems_count])
157 goto out;
33ad9f1a 158 kernel_subsystems_count++;
bcbd102c 159 }
b653309a 160 bret = true;
0d9f8e18 161
b653309a 162out:
025ed0f3 163 process_lock();
33ad9f1a 164 fclose(proc_cgroups);
025ed0f3 165 process_unlock();
b653309a
SH
166 return bret;
167}
168
169/* Step 2: determine all hierarchies (by reading /proc/self/cgroup),
170 * since mount points don't specify hierarchy number and
171 * /proc/cgroups does not contain named hierarchies
172 */
173static bool find_cgroup_hierarchies(struct cgroup_meta_data *meta_data,
174 bool all_kernel_subsystems, bool all_named_subsystems,
175 const char **subsystem_whitelist)
176{
177 FILE *proc_self_cgroup;
178 char *line = NULL;
179 size_t sz = 0;
180 int r;
181 bool bret = false;
182 size_t hierarchy_capacity = 0;
ef6e34ee 183
025ed0f3 184 process_lock();
33ad9f1a
CS
185 proc_self_cgroup = fopen_cloexec("/proc/self/cgroup", "r");
186 /* if for some reason (because of setns() and pid namespace for example),
187 * /proc/self is not valid, we try /proc/1/cgroup... */
188 if (!proc_self_cgroup)
189 proc_self_cgroup = fopen_cloexec("/proc/1/cgroup", "r");
025ed0f3 190 process_unlock();
33ad9f1a 191 if (!proc_self_cgroup)
b653309a 192 return false;
33ad9f1a
CS
193
194 while (getline(&line, &sz, proc_self_cgroup) != -1) {
195 /* file format: hierarchy:subsystems:group,
196 * we only extract hierarchy and subsystems
197 * here */
198 char *colon1;
199 char *colon2;
200 int hierarchy_number;
201 struct cgroup_hierarchy *h = NULL;
202 char **p;
203
204 if (!line[0])
205 continue;
ad08bbb7 206
33ad9f1a
CS
207 colon1 = strchr(line, ':');
208 if (!colon1)
8900b9eb 209 continue;
33ad9f1a
CS
210 *colon1++ = '\0';
211 colon2 = strchr(colon1, ':');
212 if (!colon2)
213 continue;
214 *colon2 = '\0';
ad08bbb7 215
33ad9f1a
CS
216 colon2 = NULL;
217 hierarchy_number = strtoul(line, &colon2, 10);
218 if (!colon2 || *colon2)
219 continue;
576f946d 220
33ad9f1a
CS
221 if (hierarchy_number > meta_data->maximum_hierarchy) {
222 /* lxc_grow_array will never shrink, so even if we find a lower
223 * hierarchy number here, the array will never be smaller
224 */
225 r = lxc_grow_array((void ***)&meta_data->hierarchies, &hierarchy_capacity, hierarchy_number + 1, 12);
226 if (r < 0)
b653309a 227 goto out;
5193cc3d 228
33ad9f1a
CS
229 meta_data->maximum_hierarchy = hierarchy_number;
230 }
fd37327f 231
33ad9f1a
CS
232 /* this shouldn't happen, we had this already */
233 if (meta_data->hierarchies[hierarchy_number])
b653309a 234 goto out;
33ad9f1a
CS
235
236 h = calloc(1, sizeof(struct cgroup_hierarchy));
237 if (!h)
b653309a 238 goto out;
33ad9f1a
CS
239
240 meta_data->hierarchies[hierarchy_number] = h;
241
242 h->index = hierarchy_number;
243 h->subsystems = lxc_string_split_and_trim(colon1, ',');
244 if (!h->subsystems)
b653309a 245 goto out;
33ad9f1a
CS
246 /* see if this hierarchy should be considered */
247 if (!all_kernel_subsystems || !all_named_subsystems) {
248 for (p = h->subsystems; *p; p++) {
249 if (!strncmp(*p, "name=", 5)) {
250 if (all_named_subsystems || (subsystem_whitelist && lxc_string_in_array(*p, subsystem_whitelist))) {
251 h->used = true;
252 break;
253 }
254 } else {
255 if (all_kernel_subsystems || (subsystem_whitelist && lxc_string_in_array(*p, subsystem_whitelist))) {
256 h->used = true;
257 break;
258 }
259 }
260 }
261 } else {
262 /* we want all hierarchy anyway */
263 h->used = true;
ae5c8b8e 264 }
ae5c8b8e 265 }
b653309a 266 bret = true;
0b9c21ab 267
b653309a 268out:
025ed0f3 269 process_lock();
33ad9f1a 270 fclose(proc_self_cgroup);
025ed0f3 271 process_unlock();
b653309a
SH
272 return bret;
273}
274
275/* Step 3: determine all mount points of each hierarchy */
276static bool find_hierarchy_mountpts( struct cgroup_meta_data *meta_data, char **kernel_subsystems)
277{
278 bool bret = false;
279 FILE *proc_self_mountinfo;
280 char *line = NULL;
281 size_t sz = 0;
282 char **tokens = NULL;
283 size_t mount_point_count = 0;
284 size_t mount_point_capacity = 0;
285 size_t token_capacity = 0;
286 int r;
287
025ed0f3 288 process_lock();
33ad9f1a
CS
289 proc_self_mountinfo = fopen_cloexec("/proc/self/mountinfo", "r");
290 /* if for some reason (because of setns() and pid namespace for example),
291 * /proc/self is not valid, we try /proc/1/cgroup... */
292 if (!proc_self_mountinfo)
293 proc_self_mountinfo = fopen_cloexec("/proc/1/mountinfo", "r");
025ed0f3 294 process_unlock();
33ad9f1a 295 if (!proc_self_mountinfo)
b653309a 296 return false;
33ad9f1a
CS
297
298 while (getline(&line, &sz, proc_self_mountinfo) != -1) {
299 char *token, *saveptr = NULL;
300 size_t i, j, k;
301 struct cgroup_mount_point *mount_point;
302 struct cgroup_hierarchy *h;
303 char **subsystems;
304
305 if (line[0] && line[strlen(line) - 1] == '\n')
306 line[strlen(line) - 1] = '\0';
307
308 for (i = 0; (token = strtok_r(line, " ", &saveptr)); line = NULL) {
309 r = lxc_grow_array((void ***)&tokens, &token_capacity, i + 1, 64);
310 if (r < 0)
b653309a 311 goto out;
33ad9f1a
CS
312 tokens[i++] = token;
313 }
b98f7d6e 314
33ad9f1a
CS
315 /* layout of /proc/self/mountinfo:
316 * 0: id
317 * 1: parent id
318 * 2: device major:minor
319 * 3: mount prefix
8900b9eb 320 * 4: mount point
33ad9f1a
CS
321 * 5: per-mount options
322 * [optional X]: additional data
323 * X+7: "-"
324 * X+8: type
325 * X+9: source
326 * X+10: per-superblock options
327 */
328 for (j = 6; j < i && tokens[j]; j++)
329 if (!strcmp(tokens[j], "-"))
330 break;
fd4f5a56 331
33ad9f1a
CS
332 /* could not find separator */
333 if (j >= i || !tokens[j])
334 continue;
335 /* there should be exactly three fields after
336 * the separator
337 */
338 if (i != j + 4)
339 continue;
fd4f5a56 340
33ad9f1a
CS
341 /* not a cgroup filesystem */
342 if (strcmp(tokens[j + 1], "cgroup") != 0)
343 continue;
b98f7d6e 344
33ad9f1a
CS
345 subsystems = subsystems_from_mount_options(tokens[j + 3], kernel_subsystems);
346 if (!subsystems)
b653309a 347 goto out;
33ad9f1a
CS
348
349 h = NULL;
350 for (k = 1; k <= meta_data->maximum_hierarchy; k++) {
351 if (meta_data->hierarchies[k] &&
352 meta_data->hierarchies[k]->subsystems[0] &&
353 lxc_string_in_array(meta_data->hierarchies[k]->subsystems[0], (const char **)subsystems)) {
354 /* TODO: we could also check if the lists really match completely,
355 * just to have an additional sanity check */
356 h = meta_data->hierarchies[k];
b98f7d6e 357 break;
33ad9f1a 358 }
b98f7d6e 359 }
33ad9f1a
CS
360 lxc_free_array((void **)subsystems, free);
361
362 r = lxc_grow_array((void ***)&meta_data->mount_points, &mount_point_capacity, mount_point_count + 1, 12);
363 if (r < 0)
b653309a 364 goto out;
33ad9f1a
CS
365
366 /* create mount point object */
367 mount_point = calloc(1, sizeof(*mount_point));
368 if (!mount_point)
b653309a 369 goto out;
33ad9f1a
CS
370
371 meta_data->mount_points[mount_point_count++] = mount_point;
372
373 mount_point->hierarchy = h;
374 mount_point->mount_point = strdup(tokens[4]);
375 mount_point->mount_prefix = strdup(tokens[3]);
376 if (!mount_point->mount_point || !mount_point->mount_prefix)
b653309a 377 goto out;
33ad9f1a
CS
378 mount_point->read_only = !lxc_string_in_list("rw", tokens[5], ',');
379
380 if (!strcmp(mount_point->mount_prefix, "/")) {
381 if (mount_point->read_only) {
382 if (!h->ro_absolute_mount_point)
383 h->ro_absolute_mount_point = mount_point;
384 } else {
385 if (!h->rw_absolute_mount_point)
386 h->rw_absolute_mount_point = mount_point;
387 }
b98f7d6e 388 }
ae5c8b8e 389
33ad9f1a
CS
390 k = lxc_array_len((void **)h->all_mount_points);
391 r = lxc_grow_array((void ***)&h->all_mount_points, &h->all_mount_point_capacity, k + 1, 4);
392 if (r < 0)
b653309a 393 goto out;
33ad9f1a 394 h->all_mount_points[k] = mount_point;
fd4f5a56 395 }
b653309a
SH
396 bret = true;
397
398out:
399 process_lock();
400 fclose(proc_self_mountinfo);
401 process_unlock();
402 free(tokens);
403 return bret;
404}
405
406struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist)
407{
408 bool all_kernel_subsystems = true;
409 bool all_named_subsystems = false;
410 struct cgroup_meta_data *meta_data = NULL;
411 char **kernel_subsystems = NULL;
412 int saved_errno = 0;
413
414 /* if the subsystem whitelist is not specified, include all
415 * hierarchies that contain kernel subsystems by default but
416 * no hierarchies that only contain named subsystems
417 *
418 * if it is specified, the specifier @all will select all
419 * hierarchies, @kernel will select all hierarchies with
420 * kernel subsystems and @named will select all named
421 * hierarchies
422 */
423 all_kernel_subsystems = subsystem_whitelist ?
424 (lxc_string_in_array("@kernel", subsystem_whitelist) || lxc_string_in_array("@all", subsystem_whitelist)) :
425 true;
426 all_named_subsystems = subsystem_whitelist ?
427 (lxc_string_in_array("@named", subsystem_whitelist) || lxc_string_in_array("@all", subsystem_whitelist)) :
428 false;
429
430 meta_data = calloc(1, sizeof(struct cgroup_meta_data));
431 if (!meta_data)
432 return NULL;
433 meta_data->ref = 1;
434
435 if (!find_cgroup_subsystems(&kernel_subsystems))
436 goto out_error;
437
438 if (!find_cgroup_hierarchies(meta_data, all_kernel_subsystems,
439 all_named_subsystems, subsystem_whitelist))
440 goto out_error;
441
442 if (!find_hierarchy_mountpts(meta_data, kernel_subsystems))
443 goto out_error;
fd4f5a56 444
33ad9f1a
CS
445 /* oops, we couldn't find anything */
446 if (!meta_data->hierarchies || !meta_data->mount_points) {
447 errno = EINVAL;
448 goto out_error;
ae5c8b8e 449 }
fd4f5a56 450
33ad9f1a
CS
451 return meta_data;
452
453out_error:
454 saved_errno = errno;
33ad9f1a
CS
455 lxc_free_array((void **)kernel_subsystems, free);
456 lxc_cgroup_put_meta(meta_data);
457 errno = saved_errno;
458 return NULL;
fd4f5a56
DL
459}
460
33ad9f1a 461struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data)
e14f67a7 462{
33ad9f1a
CS
463 meta_data->ref++;
464 return meta_data;
465}
e14f67a7 466
33ad9f1a
CS
467struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data)
468{
469 size_t i;
470 if (!meta_data)
471 return NULL;
472 if (--meta_data->ref > 0)
473 return meta_data;
474 lxc_free_array((void **)meta_data->mount_points, (lxc_free_fn)lxc_cgroup_mount_point_free);
475 if (meta_data->hierarchies) {
476 for (i = 0; i <= meta_data->maximum_hierarchy; i++)
477 lxc_cgroup_hierarchy_free(meta_data->hierarchies[i]);
e14f67a7 478 }
33ad9f1a
CS
479 free(meta_data->hierarchies);
480 return NULL;
e14f67a7
U
481}
482
33ad9f1a 483struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta_data, const char *subsystem)
e14f67a7 484{
33ad9f1a
CS
485 size_t i;
486 for (i = 0; i <= meta_data->maximum_hierarchy; i++) {
487 struct cgroup_hierarchy *h = meta_data->hierarchies[i];
488 if (h && lxc_string_in_array(subsystem, (const char **)h->subsystems))
489 return h;
e14f67a7 490 }
e14f67a7
U
491 return NULL;
492}
493
33ad9f1a 494struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *hierarchy, const char *group, bool should_be_writable)
b98f7d6e 495{
33ad9f1a
CS
496 struct cgroup_mount_point **mps;
497 struct cgroup_mount_point *current_result = NULL;
498 ssize_t quality = -1;
b98f7d6e 499
33ad9f1a
CS
500 /* trivial case */
501 if (hierarchy->rw_absolute_mount_point)
502 return hierarchy->rw_absolute_mount_point;
503 if (!should_be_writable && hierarchy->ro_absolute_mount_point)
504 return hierarchy->ro_absolute_mount_point;
b98f7d6e 505
33ad9f1a
CS
506 for (mps = hierarchy->all_mount_points; mps && *mps; mps++) {
507 struct cgroup_mount_point *mp = *mps;
508 size_t prefix_len = mp->mount_prefix ? strlen(mp->mount_prefix) : 0;
b98f7d6e 509
33ad9f1a
CS
510 if (prefix_len == 1 && mp->mount_prefix[0] == '/')
511 prefix_len = 0;
b98f7d6e 512
33ad9f1a
CS
513 if (should_be_writable && mp->read_only)
514 continue;
515
516 if (!prefix_len ||
517 (strncmp(group, mp->mount_prefix, prefix_len) == 0 &&
518 (group[prefix_len] == '\0' || group[prefix_len] == '/'))) {
519 /* search for the best quality match, i.e. the match with the
520 * shortest prefix where this group is still contained
521 */
522 if (quality == -1 || prefix_len < quality) {
523 current_result = mp;
524 quality = prefix_len;
525 }
b98f7d6e
SH
526 }
527 }
528
33ad9f1a
CS
529 if (!current_result)
530 errno = ENOENT;
531 return current_result;
b98f7d6e
SH
532}
533
33ad9f1a 534char *lxc_cgroup_find_abs_path(const char *subsystem, const char *group, bool should_be_writable, const char *suffix)
b98f7d6e 535{
33ad9f1a
CS
536 struct cgroup_meta_data *meta_data;
537 struct cgroup_hierarchy *h;
538 struct cgroup_mount_point *mp;
539 char *result;
540 int saved_errno;
541
542 meta_data = lxc_cgroup_load_meta();
543 if (!meta_data)
544 return NULL;
b98f7d6e 545
33ad9f1a
CS
546 h = lxc_cgroup_find_hierarchy(meta_data, subsystem);
547 if (!h)
548 goto out_error;
b98f7d6e 549
33ad9f1a
CS
550 mp = lxc_cgroup_find_mount_point(h, group, should_be_writable);
551 if (!mp)
552 goto out_error;
b98f7d6e 553
33ad9f1a
CS
554 result = cgroup_to_absolute_path(mp, group, suffix);
555 if (!result)
556 goto out_error;
b98f7d6e 557
33ad9f1a
CS
558 lxc_cgroup_put_meta(meta_data);
559 return result;
b98f7d6e 560
33ad9f1a
CS
561out_error:
562 saved_errno = errno;
563 lxc_cgroup_put_meta(meta_data);
564 errno = saved_errno;
565 return NULL;
b98f7d6e
SH
566}
567
33ad9f1a 568struct cgroup_process_info *lxc_cgroup_process_info_get(pid_t pid, struct cgroup_meta_data *meta)
fd4f5a56 569{
33ad9f1a
CS
570 char pid_buf[32];
571 snprintf(pid_buf, 32, "/proc/%lu/cgroup", (unsigned long)pid);
572 return lxc_cgroup_process_info_getx(pid_buf, meta);
c8f7c563
CS
573}
574
33ad9f1a 575struct cgroup_process_info *lxc_cgroup_process_info_get_init(struct cgroup_meta_data *meta)
c8f7c563 576{
33ad9f1a
CS
577 return lxc_cgroup_process_info_get(1, meta);
578}
b98f7d6e 579
33ad9f1a
CS
580struct cgroup_process_info *lxc_cgroup_process_info_get_self(struct cgroup_meta_data *meta)
581{
582 struct cgroup_process_info *i;
583 i = lxc_cgroup_process_info_getx("/proc/self/cgroup", meta);
584 if (!i)
585 i = lxc_cgroup_process_info_get(getpid(), meta);
586 return i;
587}
ae5c8b8e 588
692ba18f
SH
589/*
590 * If a controller has ns cgroup mounted, then in that cgroup the handler->pid
591 * is already in a new cgroup named after the pid. 'mnt' is passed in as
592 * the full current cgroup. Say that is /sys/fs/cgroup/lxc/2975 and the container
593 * name is c1. . We want to rename the cgroup directory to /sys/fs/cgroup/lxc/c1,
594 * and return the string /sys/fs/cgroup/lxc/c1.
595 */
cea0552e 596static char *cgroup_rename_nsgroup(const char *mountpath, const char *oldname, pid_t pid, const char *name)
692ba18f
SH
597{
598 char *dir, *fulloldpath;
599 char *newname, *fullnewpath;
cea0552e 600 int len, newlen, ret;
692ba18f
SH
601
602 /*
603 * if cgroup is mounted at /cgroup and task is in cgroup /ab/, pid 2375 and
604 * name is c1,
605 * dir: /ab
606 * fulloldpath = /cgroup/ab/2375
607 * fullnewpath = /cgroup/ab/c1
608 * newname = /ab/c1
609 */
610 dir = alloca(strlen(oldname) + 1);
611 strcpy(dir, oldname);
612
cea0552e
SH
613 len = strlen(oldname) + strlen(mountpath) + 22;
614 fulloldpath = alloca(len);
615 ret = snprintf(fulloldpath, len, "%s/%s/%ld", mountpath, oldname, (unsigned long)pid);
616 if (ret < 0 || ret >= len)
617 return NULL;
692ba18f
SH
618
619 len = strlen(dir) + strlen(name) + 2;
620 newname = malloc(len);
621 if (!newname) {
622 SYSERROR("Out of memory");
623 return NULL;
624 }
cea0552e
SH
625 ret = snprintf(newname, len, "%s/%s", dir, name);
626 if (ret < 0 || ret >= len) {
627 free(newname);
628 return NULL;
629 }
692ba18f 630
cea0552e
SH
631 newlen = strlen(mountpath) + len + 2;
632 fullnewpath = alloca(newlen);
633 ret = snprintf(fullnewpath, newlen, "%s/%s", mountpath, newname);
634 if (ret < 0 || ret >= newlen) {
635 free(newname);
636 return NULL;
637 }
692ba18f
SH
638
639 if (access(fullnewpath, F_OK) == 0) {
640 if (rmdir(fullnewpath) != 0) {
641 SYSERROR("container cgroup %s already exists.", fullnewpath);
642 free(newname);
643 return NULL;
644 }
645 }
646 if (rename(fulloldpath, fullnewpath)) {
647 SYSERROR("failed to rename cgroup %s->%s", fulloldpath, fullnewpath);
648 free(newname);
649 return NULL;
650 }
651
652 DEBUG("'%s' renamed to '%s'", oldname, newname);
653
654 return newname;
655}
656
33ad9f1a 657/* create a new cgroup */
47d8fb3b 658extern struct cgroup_process_info *lxc_cgroup_create(const char *name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern)
33ad9f1a 659{
001b026e 660 char **cgroup_path_components = NULL;
33ad9f1a
CS
661 char **p = NULL;
662 char *path_so_far = NULL;
663 char **new_cgroup_paths = NULL;
664 char **new_cgroup_paths_sub = NULL;
665 struct cgroup_mount_point *mp;
666 struct cgroup_hierarchy *h;
667 struct cgroup_process_info *base_info = NULL;
668 struct cgroup_process_info *info_ptr;
669 int saved_errno;
670 int r;
671 unsigned suffix = 0;
672 bool had_sub_pattern = false;
673 size_t i;
ae5c8b8e 674
33ad9f1a
CS
675 if (!is_valid_cgroup(name)) {
676 ERROR("Invalid cgroup name: '%s'", name);
677 errno = EINVAL;
678 return NULL;
ae5c8b8e
SH
679 }
680
33ad9f1a
CS
681 if (!strstr(path_pattern, "%n")) {
682 ERROR("Invalid cgroup path pattern: '%s'; contains no %%n for specifying container name", path_pattern);
683 errno = EINVAL;
684 return NULL;
685 }
fd37327f 686
33ad9f1a
CS
687 /* we will modify the result of this operation directly,
688 * so we don't have to copy the data structure
689 */
690 base_info = (path_pattern[0] == '/') ?
691 lxc_cgroup_process_info_get_init(meta_data) :
692 lxc_cgroup_process_info_get_self(meta_data);
693 if (!base_info)
694 return NULL;
c8f7c563 695
33ad9f1a
CS
696 new_cgroup_paths = calloc(meta_data->maximum_hierarchy + 1, sizeof(char *));
697 if (!new_cgroup_paths)
698 goto out_initial_error;
699
700 new_cgroup_paths_sub = calloc(meta_data->maximum_hierarchy + 1, sizeof(char *));
701 if (!new_cgroup_paths_sub)
702 goto out_initial_error;
703
704 /* find mount points we can use */
705 for (info_ptr = base_info; info_ptr; info_ptr = info_ptr->next) {
706 h = info_ptr->hierarchy;
707 mp = lxc_cgroup_find_mount_point(h, info_ptr->cgroup_path, true);
708 if (!mp) {
709 ERROR("Could not find writable mount point for cgroup hierarchy %d while trying to create cgroup.", h->index);
710 goto out_initial_error;
711 }
712 info_ptr->designated_mount_point = mp;
460a1cf0 713
692ba18f
SH
714 if (lxc_string_in_array("ns", (const char **)h->subsystems))
715 continue;
33ad9f1a
CS
716 if (handle_clone_children(mp, info_ptr->cgroup_path) < 0) {
717 ERROR("Could not set clone_children to 1 for cpuset hierarchy in parent cgroup.");
718 goto out_initial_error;
719 }
720 }
b98f7d6e 721
33ad9f1a
CS
722 /* normalize the path */
723 cgroup_path_components = lxc_normalize_path(path_pattern);
724 if (!cgroup_path_components)
725 goto out_initial_error;
726
727 /* go through the path components to see if we can create them */
728 for (p = cgroup_path_components; *p || (sub_pattern && !had_sub_pattern); p++) {
729 /* we only want to create the same component with -1, -2, etc.
730 * if the component contains the container name itself, otherwise
731 * it's not an error if it already exists
732 */
733 char *p_eff = *p ? *p : (char *)sub_pattern;
734 bool contains_name = strstr(p_eff, "%n");
735 char *current_component = NULL;
736 char *current_subpath = NULL;
737 char *current_entire_path = NULL;
738 char *parts[3];
739 size_t j = 0;
740 i = 0;
741
742 /* if we are processing the subpattern, we want to make sure
743 * loop is ended the next time around
744 */
745 if (!*p) {
746 had_sub_pattern = true;
747 p--;
748 }
b98f7d6e 749
33ad9f1a
CS
750 goto find_name_on_this_level;
751
752 cleanup_name_on_this_level:
753 /* This is reached if we found a name clash.
754 * In that case, remove the cgroup from all previous hierarchies
755 */
756 for (j = 0, info_ptr = base_info; j < i && info_ptr; info_ptr = info_ptr->next, j++) {
757 r = remove_cgroup(info_ptr->designated_mount_point, info_ptr->created_paths[info_ptr->created_paths_count - 1]);
758 if (r < 0)
759 WARN("could not clean up cgroup we created when trying to create container");
760 free(info_ptr->created_paths[info_ptr->created_paths_count - 1]);
761 info_ptr->created_paths[--info_ptr->created_paths_count] = NULL;
762 }
763 if (current_component != current_subpath)
764 free(current_subpath);
765 if (current_component != p_eff)
766 free(current_component);
767 current_component = current_subpath = NULL;
768 /* try again with another suffix */
769 ++suffix;
770
771 find_name_on_this_level:
772 /* determine name of the path component we should create */
773 if (contains_name && suffix > 0) {
774 char *buf = calloc(strlen(name) + 32, 1);
775 if (!buf)
776 goto out_initial_error;
777 snprintf(buf, strlen(name) + 32, "%s-%u", name, suffix);
778 current_component = lxc_string_replace("%n", buf, p_eff);
779 free(buf);
780 } else {
781 current_component = contains_name ? lxc_string_replace("%n", name, p_eff) : p_eff;
782 }
783 parts[0] = path_so_far;
784 parts[1] = current_component;
785 parts[2] = NULL;
786 current_subpath = path_so_far ? lxc_string_join("/", (const char **)parts, false) : current_component;
787
788 /* Now go through each hierarchy and try to create the
789 * corresponding cgroup
790 */
791 for (i = 0, info_ptr = base_info; info_ptr; info_ptr = info_ptr->next, i++) {
792 char *parts2[3];
692ba18f
SH
793
794 if (lxc_string_in_array("ns", (const char **)info_ptr->hierarchy->subsystems))
795 continue;
33ad9f1a
CS
796 current_entire_path = NULL;
797
798 parts2[0] = !strcmp(info_ptr->cgroup_path, "/") ? "" : info_ptr->cgroup_path;
799 parts2[1] = current_subpath;
800 parts2[2] = NULL;
801 current_entire_path = lxc_string_join("/", (const char **)parts2, false);
802
803 if (!*p) {
804 /* we are processing the subpath, so only update that one */
805 free(new_cgroup_paths_sub[i]);
806 new_cgroup_paths_sub[i] = strdup(current_entire_path);
807 if (!new_cgroup_paths_sub[i])
808 goto cleanup_from_error;
809 } else {
810 /* remember which path was used on this controller */
811 free(new_cgroup_paths[i]);
812 new_cgroup_paths[i] = strdup(current_entire_path);
813 if (!new_cgroup_paths[i])
814 goto cleanup_from_error;
815 }
fd4f5a56 816
33ad9f1a
CS
817 r = create_cgroup(info_ptr->designated_mount_point, current_entire_path);
818 if (r < 0 && errno == EEXIST && contains_name) {
819 /* name clash => try new name with new suffix */
820 free(current_entire_path);
821 current_entire_path = NULL;
822 goto cleanup_name_on_this_level;
823 } else if (r < 0 && errno != EEXIST) {
824 SYSERROR("Could not create cgroup %s", current_entire_path);
825 goto cleanup_from_error;
826 } else if (r == 0) {
827 /* successfully created */
828 r = lxc_grow_array((void ***)&info_ptr->created_paths, &info_ptr->created_paths_capacity, info_ptr->created_paths_count + 1, 8);
829 if (r < 0)
830 goto cleanup_from_error;
831 info_ptr->created_paths[info_ptr->created_paths_count++] = current_entire_path;
832 } else {
833 /* if we didn't create the cgroup, then we have to make sure that
834 * further cgroups will be created properly
835 */
836 if (handle_clone_children(mp, info_ptr->cgroup_path) < 0) {
837 ERROR("Could not set clone_children to 1 for cpuset hierarchy in pre-existing cgroup.");
838 goto cleanup_from_error;
839 }
840
841 /* already existed but path component of pattern didn't contain '%n',
842 * so this is not an error; but then we don't need current_entire_path
843 * anymore...
844 */
845 free(current_entire_path);
846 current_entire_path = NULL;
847 }
848 }
fd4f5a56 849
33ad9f1a
CS
850 /* save path so far */
851 free(path_so_far);
852 path_so_far = strdup(current_subpath);
853 if (!path_so_far)
854 goto cleanup_from_error;
855
856 /* cleanup */
857 if (current_component != current_subpath)
858 free(current_subpath);
859 if (current_component != p_eff)
860 free(current_component);
861 current_component = current_subpath = NULL;
862 continue;
863
864 cleanup_from_error:
865 /* called if an error occured in the loop, so we
866 * do some additional cleanup here
867 */
868 saved_errno = errno;
869 if (current_component != current_subpath)
870 free(current_subpath);
871 if (current_component != p_eff)
872 free(current_component);
873 free(current_entire_path);
874 errno = saved_errno;
875 goto out_initial_error;
fd4f5a56
DL
876 }
877
33ad9f1a
CS
878 /* we're done, now update the paths */
879 for (i = 0, info_ptr = base_info; info_ptr; info_ptr = info_ptr->next, i++) {
47d8fb3b
CS
880 /* ignore legacy 'ns' subsystem here, lxc_cgroup_create_legacy
881 * will take care of it
882 * Since we do a continue in above loop, new_cgroup_paths[i] is
883 * unset anyway, as is new_cgroup_paths_sub[i]
692ba18f 884 */
47d8fb3b
CS
885 if (lxc_string_in_array("ns", (const char **)info_ptr->hierarchy->subsystems))
886 continue;
887 free(info_ptr->cgroup_path);
888 info_ptr->cgroup_path = new_cgroup_paths[i];
889 info_ptr->cgroup_path_sub = new_cgroup_paths_sub[i];
fd4f5a56 890 }
33ad9f1a
CS
891 /* don't use lxc_free_array since we used the array members
892 * to store them in our result...
893 */
894 free(new_cgroup_paths);
895 free(new_cgroup_paths_sub);
896 free(path_so_far);
897 lxc_free_array((void **)cgroup_path_components, free);
898 return base_info;
899
900out_initial_error:
901 saved_errno = errno;
902 free(path_so_far);
903 lxc_cgroup_process_info_free_and_remove(base_info);
904 lxc_free_array((void **)new_cgroup_paths, free);
905 lxc_free_array((void **)new_cgroup_paths_sub, free);
906 lxc_free_array((void **)cgroup_path_components, free);
907 errno = saved_errno;
908 return NULL;
c8f7c563
CS
909}
910
47d8fb3b
CS
911int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *name, pid_t pid)
912{
913 struct cgroup_process_info *info_ptr;
914 int r;
915
916 for (info_ptr = base_info; info_ptr; info_ptr = info_ptr->next) {
917 if (!lxc_string_in_array("ns", (const char **)info_ptr->hierarchy->subsystems))
918 continue;
919 /*
920 * For any path which has ns cgroup mounted, handler->pid is already
921 * moved into a container called '%d % (handler->pid)'. Rename it to
922 * the cgroup name and record that.
923 */
924 char *tmp = cgroup_rename_nsgroup((const char *)info_ptr->designated_mount_point->mount_point,
925 info_ptr->cgroup_path, pid, name);
926 if (!tmp)
927 return -1;
928 free(info_ptr->cgroup_path);
929 info_ptr->cgroup_path = tmp;
930 r = lxc_grow_array((void ***)&info_ptr->created_paths, &info_ptr->created_paths_capacity, info_ptr->created_paths_count + 1, 8);
931 if (r < 0)
932 return -1;
933 tmp = strdup(tmp);
934 if (!tmp)
935 return -1;
936 info_ptr->created_paths[info_ptr->created_paths_count++] = tmp;
937 }
938 return 0;
939}
940
33ad9f1a
CS
941/* get the cgroup membership of a given container */
942struct cgroup_process_info *lxc_cgroup_get_container_info(const char *name, const char *lxcpath, struct cgroup_meta_data *meta_data)
c8f7c563 943{
33ad9f1a
CS
944 struct cgroup_process_info *result = NULL;
945 int saved_errno = 0;
946 size_t i;
947 struct cgroup_process_info **cptr = &result;
948 struct cgroup_process_info *entry = NULL;
949 char *path = NULL;
950
951 for (i = 0; i <= meta_data->maximum_hierarchy; i++) {
952 struct cgroup_hierarchy *h = meta_data->hierarchies[i];
953 if (!h || !h->used)
954 continue;
c8f7c563 955
33ad9f1a
CS
956 /* use the command interface to look for the cgroup */
957 path = lxc_cmd_get_cgroup_path(name, lxcpath, h->subsystems[0]);
958 if (!path)
959 goto out_error;
960
961 entry = calloc(1, sizeof(struct cgroup_process_info));
962 if (!entry)
963 goto out_error;
964 entry->meta_ref = lxc_cgroup_get_meta(meta_data);
965 entry->hierarchy = h;
966 entry->cgroup_path = path;
967 path = NULL;
968
969 /* it is not an error if we don't find anything here,
970 * it is up to the caller to decide what to do in that
971 * case */
972 entry->designated_mount_point = lxc_cgroup_find_mount_point(h, entry->cgroup_path, true);
973
974 *cptr = entry;
975 cptr = &entry->next;
976 entry = NULL;
c8f7c563
CS
977 }
978
33ad9f1a
CS
979 return result;
980out_error:
981 saved_errno = errno;
982 free(path);
983 lxc_cgroup_process_info_free(result);
984 lxc_cgroup_process_info_free(entry);
985 errno = saved_errno;
986 return NULL;
fd4f5a56
DL
987}
988
33ad9f1a
CS
989/* move a processs to the cgroups specified by the membership */
990int lxc_cgroup_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub)
4f17323e 991{
33ad9f1a
CS
992 char pid_buf[32];
993 char *cgroup_tasks_fn;
994 int r;
995 struct cgroup_process_info *info_ptr;
996
997 snprintf(pid_buf, 32, "%lu", (unsigned long)pid);
998 for (info_ptr = info; info_ptr; info_ptr = info_ptr->next) {
999 char *cgroup_path = (enter_sub && info_ptr->cgroup_path_sub) ?
1000 info_ptr->cgroup_path_sub :
1001 info_ptr->cgroup_path;
1002
1003 if (!info_ptr->designated_mount_point) {
1004 info_ptr->designated_mount_point = lxc_cgroup_find_mount_point(info_ptr->hierarchy, cgroup_path, true);
1005 if (!info_ptr->designated_mount_point) {
1006 SYSERROR("Could not add pid %lu to cgroup %s: internal error (couldn't find any writable mountpoint to cgroup filesystem)", (unsigned long)pid, cgroup_path);
1007 return -1;
1008 }
1009 }
4f17323e 1010
33ad9f1a
CS
1011 cgroup_tasks_fn = cgroup_to_absolute_path(info_ptr->designated_mount_point, cgroup_path, "/tasks");
1012 if (!cgroup_tasks_fn) {
1013 SYSERROR("Could not add pid %lu to cgroup %s: internal error", (unsigned long)pid, cgroup_path);
1014 return -1;
1015 }
4f17323e 1016
33ad9f1a
CS
1017 r = lxc_write_to_file(cgroup_tasks_fn, pid_buf, strlen(pid_buf), false);
1018 if (r < 0) {
1019 SYSERROR("Could not add pid %lu to cgroup %s: internal error", (unsigned long)pid, cgroup_path);
1020 return -1;
1021 }
4f17323e
CS
1022 }
1023
33ad9f1a 1024 return 0;
4f17323e
CS
1025}
1026
33ad9f1a
CS
1027/* free process membership information */
1028void lxc_cgroup_process_info_free(struct cgroup_process_info *info)
fc7de561 1029{
33ad9f1a
CS
1030 struct cgroup_process_info *next;
1031 if (!info)
b98f7d6e 1032 return;
33ad9f1a
CS
1033 next = info->next;
1034 lxc_cgroup_put_meta(info->meta_ref);
1035 free(info->cgroup_path);
1036 free(info->cgroup_path_sub);
1037 lxc_free_array((void **)info->created_paths, free);
1038 free(info);
1039 lxc_cgroup_process_info_free(next);
fc7de561
SH
1040}
1041
33ad9f1a
CS
1042/* free process membership information and remove cgroups that were created */
1043void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info)
b98f7d6e 1044{
33ad9f1a
CS
1045 struct cgroup_process_info *next;
1046 char **pp;
1047 if (!info)
1048 return;
1049 next = info->next;
1050 for (pp = info->created_paths; pp && *pp; pp++);
1051 for ((void)(pp && --pp); info->created_paths && pp >= info->created_paths; --pp) {
1052 struct cgroup_mount_point *mp = info->designated_mount_point;
1053 if (!mp)
1054 mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
1055 if (mp)
1056 /* ignore return value here, perhaps we created the
1057 * '/lxc' cgroup in this container but another container
1058 * is still running (for example)
1059 */
1060 (void)remove_cgroup(mp, *pp);
1061 free(*pp);
b98f7d6e 1062 }
33ad9f1a
CS
1063 free(info->created_paths);
1064 lxc_cgroup_put_meta(info->meta_ref);
1065 free(info->cgroup_path);
1066 free(info->cgroup_path_sub);
1067 free(info);
9431aa65 1068 lxc_cgroup_process_info_free_and_remove(next);
33ad9f1a 1069}
b98f7d6e 1070
33ad9f1a
CS
1071char *lxc_cgroup_get_hierarchy_path_handler(const char *subsystem, struct lxc_handler *handler)
1072{
1073 struct cgroup_process_info *info = find_info_for_subsystem(handler->cgroup, subsystem);
1074 if (!info)
1075 return NULL;
1076 return info->cgroup_path;
b98f7d6e
SH
1077}
1078
33ad9f1a 1079char *lxc_cgroup_get_hierarchy_path(const char *subsystem, const char *name, const char *lxcpath)
b98f7d6e 1080{
33ad9f1a 1081 return lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
b98f7d6e
SH
1082}
1083
33ad9f1a 1084char *lxc_cgroup_get_hierarchy_abs_path_handler(const char *subsystem, struct lxc_handler *handler)
b98f7d6e 1085{
33ad9f1a
CS
1086 struct cgroup_mount_point *mp = NULL;
1087 struct cgroup_process_info *info = find_info_for_subsystem(handler->cgroup, subsystem);
1088 if (!info)
1089 return NULL;
1090 if (info->designated_mount_point) {
8900b9eb 1091 mp = info->designated_mount_point;
33ad9f1a
CS
1092 } else {
1093 mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
1094 if (!mp)
1095 return NULL;
b98f7d6e 1096 }
33ad9f1a 1097 return cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
b98f7d6e 1098}
55c76589 1099
33ad9f1a 1100char *lxc_cgroup_get_hierarchy_abs_path(const char *subsystem, const char *name, const char *lxcpath)
9a93d992 1101{
33ad9f1a
CS
1102 struct cgroup_meta_data *meta;
1103 struct cgroup_process_info *base_info, *info;
1104 struct cgroup_mount_point *mp;
1105 char *result = NULL;
1106 int saved_errno;
1107
1108 meta = lxc_cgroup_load_meta();
1109 if (!meta)
9a93d992 1110 return NULL;
33ad9f1a
CS
1111 base_info = lxc_cgroup_get_container_info(name, lxcpath, meta);
1112 if (!base_info)
1113 return NULL;
1114 info = find_info_for_subsystem(base_info, subsystem);
1115 if (!info)
1116 return NULL;
1117 if (info->designated_mount_point) {
8900b9eb 1118 mp = info->designated_mount_point;
33ad9f1a
CS
1119 } else {
1120 mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
1121 if (!mp)
1122 return NULL;
1123 }
1124 result = cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
1125 saved_errno = errno;
1126 lxc_cgroup_process_info_free(base_info);
1127 lxc_cgroup_put_meta(meta);
1128 errno = saved_errno;
1129 return result;
1130}
9a93d992 1131
33ad9f1a
CS
1132int lxc_cgroup_set_handler(const char *filename, const char *value, struct lxc_handler *handler)
1133{
1134 char *subsystem = NULL, *p, *path;
1135 int ret = -1;
9a93d992 1136
33ad9f1a
CS
1137 subsystem = alloca(strlen(filename) + 1);
1138 strcpy(subsystem, filename);
1139 if ((p = index(subsystem, '.')) != NULL)
1140 *p = '\0';
9a93d992 1141
33ad9f1a
CS
1142 path = lxc_cgroup_get_hierarchy_abs_path_handler(subsystem, handler);
1143 if (path) {
1144 ret = do_cgroup_set(path, filename, value);
1145 free(path);
9a93d992 1146 }
33ad9f1a
CS
1147 return ret;
1148}
9a93d992 1149
33ad9f1a
CS
1150int lxc_cgroup_get_handler(const char *filename, char *value, size_t len, struct lxc_handler *handler)
1151{
1152 char *subsystem = NULL, *p, *path;
1153 int ret = -1;
1154
1155 subsystem = alloca(strlen(filename) + 1);
1156 strcpy(subsystem, filename);
1157 if ((p = index(subsystem, '.')) != NULL)
1158 *p = '\0';
1159
1160 path = lxc_cgroup_get_hierarchy_abs_path_handler(subsystem, handler);
1161 if (path) {
1162 ret = do_cgroup_get(path, filename, value, len);
1163 free(path);
1164 }
9a93d992
SH
1165 return ret;
1166}
1167
33ad9f1a 1168int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath)
9a93d992 1169{
33ad9f1a
CS
1170 char *subsystem = NULL, *p, *path;
1171 int ret = -1;
9a93d992 1172
33ad9f1a
CS
1173 subsystem = alloca(strlen(filename) + 1);
1174 strcpy(subsystem, filename);
1175 if ((p = index(subsystem, '.')) != NULL)
1176 *p = '\0';
9a93d992 1177
33ad9f1a
CS
1178 path = lxc_cgroup_get_hierarchy_abs_path(subsystem, name, lxcpath);
1179 if (path) {
1180 ret = do_cgroup_set(path, filename, value);
1181 free(path);
1182 }
b98f7d6e 1183 return ret;
9a93d992
SH
1184}
1185
33ad9f1a 1186int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
9a93d992 1187{
33ad9f1a
CS
1188 char *subsystem = NULL, *p, *path;
1189 int ret = -1;
1190
1191 subsystem = alloca(strlen(filename) + 1);
1192 strcpy(subsystem, filename);
1193 if ((p = index(subsystem, '.')) != NULL)
1194 *p = '\0';
1195
1196 path = lxc_cgroup_get_hierarchy_abs_path(subsystem, name, lxcpath);
1197 if (path) {
1198 ret = do_cgroup_get(path, filename, value, len);
1199 free(path);
9a93d992 1200 }
33ad9f1a 1201 return ret;
9a93d992
SH
1202}
1203
33ad9f1a
CS
1204/*
1205 * lxc_cgroup_path_get: Get the absolute pathname for a cgroup
1206 * file for a running container.
1207 *
1208 * @filename : the file of interest (e.g. "freezer.state") or
1209 * the subsystem name (e.g. "freezer") in which case
1210 * the directory where the cgroup may be modified
1211 * will be returned
1212 * @name : name of container to connect to
1213 * @lxcpath : the lxcpath in which the container is running
8900b9eb 1214 *
33ad9f1a
CS
1215 * This is the exported function, which determines cgpath from the
1216 * lxc-start of the @name container running in @lxcpath.
1217 *
1218 * Returns path on success, NULL on error. The caller must free()
1219 * the returned path.
1220 */
1221char *lxc_cgroup_path_get(const char *filename, const char *name,
1222 const char *lxcpath)
9a93d992 1223{
33ad9f1a 1224 char *subsystem = NULL, *longer_file = NULL, *p, *group, *path;
9a93d992 1225
33ad9f1a
CS
1226 subsystem = alloca(strlen(filename) + 1);
1227 strcpy(subsystem, filename);
1228 if ((p = index(subsystem, '.')) != NULL) {
1229 *p = '\0';
1230 longer_file = alloca(strlen(filename) + 2);
1231 longer_file[0] = '/';
1232 strcpy(longer_file + 1, filename);
b98f7d6e
SH
1233 }
1234
33ad9f1a
CS
1235 group = lxc_cgroup_get_hierarchy_path(subsystem, name, lxcpath);
1236 if (!group)
1237 return NULL;
b98f7d6e 1238
33ad9f1a
CS
1239 path = lxc_cgroup_find_abs_path(subsystem, group, true, *p ? longer_file : NULL);
1240 free(group);
1241 return path;
9a93d992
SH
1242}
1243
33ad9f1a
CS
1244int lxc_setup_cgroup_without_devices(struct lxc_handler *h, struct lxc_list *cgroup_settings)
1245{
1246 return do_setup_cgroup(h, cgroup_settings, false);
1247}
b98f7d6e 1248
33ad9f1a 1249int lxc_setup_cgroup_devices(struct lxc_handler *h, struct lxc_list *cgroup_settings)
460a1cf0 1250{
33ad9f1a
CS
1251 return do_setup_cgroup(h, cgroup_settings, true);
1252}
fd37327f 1253
aae1f3c4
CS
1254int lxc_setup_mount_cgroup(const char *root, struct cgroup_process_info *base_info)
1255{
1256 size_t bufsz = strlen(root) + sizeof("/sys/fs/cgroup");
1257 char *path = NULL;
1258 char **parts = NULL;
1259 char *dirname = NULL;
1260 char *abs_path = NULL;
1261 char *abs_path2 = NULL;
1262 struct cgroup_process_info *info;
1263 int r, saved_errno = 0;
1264
1265 path = calloc(1, bufsz);
1266 if (!path)
1267 return -1;
1268 snprintf(path, bufsz, "%s/sys/fs/cgroup", root);
1269 r = mount("cgroup_root", path, "tmpfs", MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME, "size=10240k,mode=755");
1270 if (r < 0) {
1271 SYSERROR("could not mount tmpfs to /sys/fs/cgroup in the container");
1272 return -1;
1273 }
1274
1275 /* now mount all the hierarchies we care about */
1276 for (info = base_info; info; info = info->next) {
1277 size_t subsystem_count, i;
1278 struct cgroup_mount_point *mp = info->designated_mount_point;
1279 if (!mp)
1280 mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
1281 if (!mp) {
1282 SYSERROR("could not find original mount point for cgroup hierarchy while trying to mount cgroup filesystem");
1283 goto out_error;
1284 }
1285
1286 subsystem_count = lxc_array_len((void **)info->hierarchy->subsystems);
1287 parts = calloc(subsystem_count + 1, sizeof(char *));
1288 if (!parts)
1289 goto out_error;
1290
1291 for (i = 0; i < subsystem_count; i++) {
1292 if (!strncmp(info->hierarchy->subsystems[i], "name=", 5))
1293 parts[i] = info->hierarchy->subsystems[i] + 5;
1294 else
1295 parts[i] = info->hierarchy->subsystems[i];
1296 }
1297 dirname = lxc_string_join(",", (const char **)parts, false);
1298 if (!dirname)
1299 goto out_error;
1300
1301 /* create subsystem directory */
1302 abs_path = lxc_append_paths(path, dirname);
1303 if (!abs_path)
1304 goto out_error;
1305 r = mkdir_p(abs_path, 0755);
1306 if (r < 0 && errno != EEXIST) {
1307 SYSERROR("could not create cgroup subsystem directory /sys/fs/cgroup/%s", dirname);
1308 goto out_error;
1309 }
1310
1311 /* create path for container's cgroup */
1312 abs_path2 = lxc_append_paths(abs_path, info->cgroup_path);
1313 if (!abs_path2)
1314 goto out_error;
1315 r = mkdir_p(abs_path2, 0755);
1316 if (r < 0 && errno != EEXIST) {
1317 SYSERROR("could not create cgroup directory /sys/fs/cgroup/%s%s", dirname, info->cgroup_path);
1318 goto out_error;
1319 }
1320
1321 free(abs_path);
1322 abs_path = NULL;
1323
1324 /* bind-mount container's cgroup to that directory */
1325 abs_path = cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
1326 if (!abs_path)
1327 goto out_error;
1328 r = mount(abs_path, abs_path2, "none", MS_BIND, 0);
1329 if (r < 0) {
1330 SYSERROR("error bind-mounting %s to %s", abs_path, abs_path2);
1331 goto out_error;
1332 }
1333
1334 free(abs_path);
1335 free(abs_path2);
1336 abs_path = NULL;
1337 abs_path2 = NULL;
1338
1339 /* add symlinks for every single subsystem */
1340 if (subsystem_count > 1) {
1341 for (i = 0; i < subsystem_count; i++) {
1342 abs_path = lxc_append_paths(path, parts[i]);
1343 if (!abs_path)
1344 goto out_error;
1345 r = symlink(dirname, abs_path);
1346 if (r < 0)
1347 WARN("could not create symlink %s -> %s in /sys/fs/cgroup of container", parts[i], dirname);
1348 free(abs_path);
1349 abs_path = NULL;
1350 }
1351 }
1352 free(dirname);
1353 free(parts);
1354 dirname = NULL;
1355 parts = NULL;
1356 }
1357
1358 /* try to remount the tmpfs readonly, since the container shouldn't
1359 * change anything (this will also make sure that trying to create
1360 * new cgroups outside the allowed area fails with an error instead
1361 * of simply causing this to create directories in the tmpfs itself)
1362 */
1363 mount(NULL, path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
1364
1365 free(path);
1366
1367 return 0;
1368
1369out_error:
1370 saved_errno = errno;
1371 free(path);
1372 free(dirname);
1373 free(parts);
1374 free(abs_path);
1375 free(abs_path2);
1376 errno = saved_errno;
1377 return -1;
1378}
1379
33ad9f1a
CS
1380int lxc_cgroup_nrtasks_handler(struct lxc_handler *handler)
1381{
1382 struct cgroup_process_info *info = handler->cgroup;
1383 struct cgroup_mount_point *mp = NULL;
1384 char *abs_path = NULL;
1385 int ret;
460a1cf0 1386
33ad9f1a
CS
1387 if (!info) {
1388 errno = ENOENT;
1389 return -1;
b98f7d6e 1390 }
c8f7c563 1391
33ad9f1a 1392 if (info->designated_mount_point) {
8900b9eb 1393 mp = info->designated_mount_point;
33ad9f1a
CS
1394 } else {
1395 mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, false);
1396 if (!mp)
1397 return -1;
c8f7c563
CS
1398 }
1399
33ad9f1a
CS
1400 abs_path = cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
1401 if (!abs_path)
1402 return -1;
1403
1404 ret = cgroup_recursive_task_count(abs_path);
1405 free(abs_path);
1406 return ret;
c8f7c563
CS
1407}
1408
33ad9f1a 1409struct cgroup_process_info *lxc_cgroup_process_info_getx(const char *proc_pid_cgroup_str, struct cgroup_meta_data *meta)
d08ba6ec 1410{
33ad9f1a
CS
1411 struct cgroup_process_info *result = NULL;
1412 FILE *proc_pid_cgroup = NULL;
1413 char *line = NULL;
1414 size_t sz = 0;
1415 int saved_errno = 0;
1416 struct cgroup_process_info **cptr = &result;
1417 struct cgroup_process_info *entry = NULL;
1418
025ed0f3 1419 process_lock();
33ad9f1a 1420 proc_pid_cgroup = fopen_cloexec(proc_pid_cgroup_str, "r");
025ed0f3 1421 process_unlock();
33ad9f1a 1422 if (!proc_pid_cgroup)
b98f7d6e 1423 return NULL;
1ac470c0 1424
33ad9f1a
CS
1425 while (getline(&line, &sz, proc_pid_cgroup) != -1) {
1426 /* file format: hierarchy:subsystems:group */
1427 char *colon1;
1428 char *colon2;
1429 char *endptr;
1430 int hierarchy_number;
1431 struct cgroup_hierarchy *h = NULL;
fd4f5a56 1432
33ad9f1a 1433 if (!line[0])
ae5c8b8e 1434 continue;
b98f7d6e 1435
33ad9f1a
CS
1436 if (line[strlen(line) - 1] == '\n')
1437 line[strlen(line) - 1] = '\0';
1438
1439 colon1 = strchr(line, ':');
1440 if (!colon1)
8900b9eb 1441 continue;
33ad9f1a
CS
1442 *colon1++ = '\0';
1443 colon2 = strchr(colon1, ':');
1444 if (!colon2)
ae5c8b8e 1445 continue;
33ad9f1a 1446 *colon2++ = '\0';
e4659536 1447
33ad9f1a
CS
1448 endptr = NULL;
1449 hierarchy_number = strtoul(line, &endptr, 10);
1450 if (!endptr || *endptr)
9a93d992 1451 continue;
9a93d992 1452
33ad9f1a
CS
1453 if (hierarchy_number > meta->maximum_hierarchy) {
1454 /* we encountered a hierarchy we didn't have before,
1455 * so probably somebody remounted some stuff in the
1456 * mean time...
1457 */
1458 errno = EAGAIN;
1459 goto out_error;
b98f7d6e 1460 }
33ad9f1a
CS
1461
1462 h = meta->hierarchies[hierarchy_number];
1463 if (!h) {
1464 /* we encountered a hierarchy that was thought to be
1465 * dead before, so probably somebody remounted some
1466 * stuff in the mean time...
1467 */
1468 errno = EAGAIN;
1469 goto out_error;
b98f7d6e 1470 }
33ad9f1a
CS
1471
1472 /* we are told that we should ignore this hierarchy */
1473 if (!h->used)
b98f7d6e 1474 continue;
5193cc3d 1475
33ad9f1a
CS
1476 entry = calloc(1, sizeof(struct cgroup_process_info));
1477 if (!entry)
1478 goto out_error;
fd4f5a56 1479
33ad9f1a
CS
1480 entry->meta_ref = lxc_cgroup_get_meta(meta);
1481 entry->hierarchy = h;
1482 entry->cgroup_path = strdup(colon2);
1483 if (!entry->cgroup_path)
1484 goto out_error;
d08ba6ec 1485
33ad9f1a
CS
1486 *cptr = entry;
1487 cptr = &entry->next;
1488 entry = NULL;
b98f7d6e 1489 }
b98f7d6e 1490
025ed0f3 1491 process_lock();
33ad9f1a 1492 fclose(proc_pid_cgroup);
025ed0f3 1493 process_unlock();
33ad9f1a
CS
1494 free(line);
1495 return result;
1496
1497out_error:
1498 saved_errno = errno;
025ed0f3 1499 process_lock();
33ad9f1a
CS
1500 if (proc_pid_cgroup)
1501 fclose(proc_pid_cgroup);
025ed0f3 1502 process_unlock();
33ad9f1a
CS
1503 lxc_cgroup_process_info_free(result);
1504 lxc_cgroup_process_info_free(entry);
1505 free(line);
1506 errno = saved_errno;
ae5c8b8e 1507 return NULL;
36b86299
DL
1508}
1509
33ad9f1a 1510char **subsystems_from_mount_options(const char *mount_options, char **kernel_list)
36b86299 1511{
33ad9f1a
CS
1512 char *token, *str, *saveptr = NULL;
1513 char **result = NULL;
1514 size_t result_capacity = 0;
8900b9eb 1515 size_t result_count = 0;
33ad9f1a
CS
1516 int saved_errno;
1517 int r;
ef342abb 1518
33ad9f1a
CS
1519 str = alloca(strlen(mount_options)+1);
1520 strcpy(str, mount_options);
1521 for (; (token = strtok_r(str, ",", &saveptr)); str = NULL) {
1522 /* we have a subsystem if it's either in the list of
1523 * subsystems provided by the kernel OR if it starts
1524 * with name= for named hierarchies
1525 */
1526 if (!strncmp(token, "name=", 5) || lxc_string_in_array(token, (const char **)kernel_list)) {
1527 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 12);
1528 if (r < 0)
1529 goto out_free;
1530 result[result_count + 1] = NULL;
1531 result[result_count] = strdup(token);
1532 if (!result[result_count])
1533 goto out_free;
1534 result_count++;
1535 }
ae5c8b8e 1536 }
f0e64b8b 1537
33ad9f1a
CS
1538 return result;
1539
1540out_free:
1541 saved_errno = errno;
1542 lxc_free_array((void**)result, free);
1543 errno = saved_errno;
1544 return NULL;
b98f7d6e
SH
1545}
1546
33ad9f1a 1547void lxc_cgroup_mount_point_free(struct cgroup_mount_point *mp)
b98f7d6e 1548{
33ad9f1a
CS
1549 if (!mp)
1550 return;
1551 free(mp->mount_point);
1552 free(mp->mount_prefix);
1553 free(mp);
bcbd102c
SH
1554}
1555
33ad9f1a 1556void lxc_cgroup_hierarchy_free(struct cgroup_hierarchy *h)
341a9bd8 1557{
33ad9f1a
CS
1558 if (!h)
1559 return;
1560 lxc_free_array((void **)h->subsystems, free);
1561 free(h);
1562}
341a9bd8 1563
33ad9f1a
CS
1564bool is_valid_cgroup(const char *name)
1565{
1566 const char *p;
1567 for (p = name; *p; p++) {
1568 if (*p < 32 || *p == 127 || *p == '/')
1569 return false;
341a9bd8 1570 }
33ad9f1a
CS
1571 return strcmp(name, ".") != 0 && strcmp(name, "..") != 0;
1572}
341a9bd8 1573
33ad9f1a
CS
1574int create_or_remove_cgroup(bool do_remove, struct cgroup_mount_point *mp, const char *path)
1575{
1576 int r, saved_errno = 0;
1577 char *buf = cgroup_to_absolute_path(mp, path, NULL);
1578 if (!buf)
1579 return -1;
341a9bd8 1580
33ad9f1a
CS
1581 /* create or remove directory */
1582 r = do_remove ?
1583 rmdir(buf) :
1584 mkdir(buf, 0777);
1585 saved_errno = errno;
1586 free(buf);
1587 errno = saved_errno;
1588 return r;
341a9bd8 1589}
bcbd102c 1590
33ad9f1a 1591int create_cgroup(struct cgroup_mount_point *mp, const char *path)
a6ddef61 1592{
33ad9f1a 1593 return create_or_remove_cgroup(false, mp, path);
a6ddef61
MN
1594}
1595
33ad9f1a 1596int remove_cgroup(struct cgroup_mount_point *mp, const char *path)
576f946d 1597{
33ad9f1a
CS
1598 return create_or_remove_cgroup(true, mp, path);
1599}
576f946d 1600
33ad9f1a
CS
1601char *cgroup_to_absolute_path(struct cgroup_mount_point *mp, const char *path, const char *suffix)
1602{
1603 /* first we have to make sure we subtract the mount point's prefix */
1604 char *prefix = mp->mount_prefix;
1605 char *buf;
1606 ssize_t len, rv;
1607
1608 /* we want to make sure only absolute paths to cgroups are passed to us */
1609 if (path[0] != '/') {
1610 errno = EINVAL;
1611 return NULL;
1612 }
b98f7d6e 1613
33ad9f1a
CS
1614 if (prefix && !strcmp(prefix, "/"))
1615 prefix = NULL;
b98f7d6e 1616
33ad9f1a
CS
1617 /* prefix doesn't match */
1618 if (prefix && strncmp(prefix, path, strlen(prefix)) != 0) {
1619 errno = EINVAL;
1620 return NULL;
1621 }
1622 /* if prefix is /foo and path is /foobar */
1623 if (prefix && path[strlen(prefix)] != '/' && path[strlen(prefix)] != '\0') {
1624 errno = EINVAL;
1625 return NULL;
1626 }
b98f7d6e 1627
33ad9f1a
CS
1628 /* remove prefix from path */
1629 path += prefix ? strlen(prefix) : 0;
b98f7d6e 1630
33ad9f1a
CS
1631 len = strlen(mp->mount_point) + strlen(path) + (suffix ? strlen(suffix) : 0);
1632 buf = calloc(len + 1, 1);
1633 rv = snprintf(buf, len + 1, "%s%s%s", mp->mount_point, path, suffix ? suffix : "");
8900b9eb 1634 if (rv > len) {
33ad9f1a
CS
1635 free(buf);
1636 errno = ENOMEM;
8900b9eb 1637 return NULL;
8b92dc3a 1638 }
576f946d 1639
33ad9f1a 1640 return buf;
e0f888d9 1641}
283678ed 1642
33ad9f1a 1643struct cgroup_process_info *find_info_for_subsystem(struct cgroup_process_info *info, const char *subsystem)
283678ed 1644{
33ad9f1a
CS
1645 struct cgroup_process_info *info_ptr;
1646 for (info_ptr = info; info_ptr; info_ptr = info_ptr->next) {
1647 struct cgroup_hierarchy *h = info_ptr->hierarchy;
1648 if (lxc_string_in_array(subsystem, (const char **)h->subsystems))
1649 return info_ptr;
b98f7d6e 1650 }
33ad9f1a
CS
1651 errno = ENOENT;
1652 return NULL;
1653}
283678ed 1654
33ad9f1a
CS
1655int do_cgroup_get(const char *cgroup_path, const char *sub_filename, char *value, size_t len)
1656{
1657 const char *parts[3] = {
1658 cgroup_path,
1659 sub_filename,
1660 NULL
1661 };
1662 char *filename;
1663 int ret, saved_errno;
1664
1665 filename = lxc_string_join("/", parts, false);
1666 if (!filename)
1667 return -1;
1668
1669 ret = lxc_read_from_file(filename, value, len);
1670 saved_errno = errno;
1671 free(filename);
1672 errno = saved_errno;
1673 return ret;
283678ed 1674}
b113383b 1675
33ad9f1a 1676int do_cgroup_set(const char *cgroup_path, const char *sub_filename, const char *value)
b113383b 1677{
33ad9f1a
CS
1678 const char *parts[3] = {
1679 cgroup_path,
1680 sub_filename,
1681 NULL
1682 };
1683 char *filename;
1684 int ret, saved_errno;
b113383b 1685
33ad9f1a
CS
1686 filename = lxc_string_join("/", parts, false);
1687 if (!filename)
1688 return -1;
b113383b 1689
33ad9f1a
CS
1690 ret = lxc_write_to_file(filename, value, strlen(value), false);
1691 saved_errno = errno;
1692 free(filename);
1693 errno = saved_errno;
1694 return ret;
b98f7d6e
SH
1695}
1696
33ad9f1a 1697int do_setup_cgroup(struct lxc_handler *h, struct lxc_list *cgroup_settings, bool do_devices)
b98f7d6e
SH
1698{
1699 struct lxc_list *iterator;
1700 struct lxc_cgroup *cg;
1701 int ret = -1;
1702
33ad9f1a 1703 if (lxc_list_empty(cgroup_settings))
b98f7d6e
SH
1704 return 0;
1705
33ad9f1a 1706 lxc_list_for_each(iterator, cgroup_settings) {
b98f7d6e
SH
1707 cg = iterator->elem;
1708
33ad9f1a 1709 if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
b98f7d6e 1710 if (strcmp(cg->subsystem, "devices.deny") == 0 &&
33ad9f1a 1711 cgroup_devices_has_allow_or_deny(h, cg->value, false))
b98f7d6e
SH
1712 continue;
1713 if (strcmp(cg->subsystem, "devices.allow") == 0 &&
33ad9f1a 1714 cgroup_devices_has_allow_or_deny(h, cg->value, true))
b98f7d6e 1715 continue;
33ad9f1a 1716 if (lxc_cgroup_set_handler(cg->subsystem, cg->value, h)) {
b98f7d6e
SH
1717 ERROR("Error setting %s to %s for %s\n",
1718 cg->subsystem, cg->value, h->name);
1719 goto out;
1720 }
b113383b 1721 }
b98f7d6e
SH
1722
1723 DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
b113383b
SH
1724 }
1725
b98f7d6e
SH
1726 ret = 0;
1727 INFO("cgroup has been setup");
1728out:
b113383b
SH
1729 return ret;
1730}
b98f7d6e 1731
33ad9f1a
CS
1732bool cgroup_devices_has_allow_or_deny(struct lxc_handler *h, char *v, bool for_allow)
1733{
1734 char *path;
1735 FILE *devices_list;
8900b9eb 1736 char *line = NULL;
33ad9f1a
CS
1737 size_t sz = 0;
1738 bool ret = !for_allow;
1739 const char *parts[3] = {
1740 NULL,
1741 "devices.list",
1742 NULL
1743 };
1744
1745 // XXX FIXME if users could use something other than 'lxc.devices.deny = a'.
1746 // not sure they ever do, but they *could*
1747 // right now, I'm assuming they do NOT
1748 if (!for_allow && strcmp(v, "a") != 0 && strcmp(v, "a *:* rwm") != 0)
1749 return false;
1750
1751 parts[0] = (const char *)lxc_cgroup_get_hierarchy_abs_path_handler("devices", h);
1752 if (!parts[0])
1753 return false;
1754 path = lxc_string_join("/", parts, false);
1755 if (!path) {
1756 free((void *)parts[0]);
1757 return false;
1758 }
1759
025ed0f3 1760 process_lock();
33ad9f1a 1761 devices_list = fopen_cloexec(path, "r");
025ed0f3 1762 process_unlock();
33ad9f1a
CS
1763 if (!devices_list) {
1764 free(path);
1765 return false;
1766 }
1767
1768 while (getline(&line, &sz, devices_list) != -1) {
1769 size_t len = strlen(line);
1770 if (len > 0 && line[len-1] == '\n')
1771 line[len-1] = '\0';
1772 if (strcmp(line, "a *:* rwm") == 0) {
1773 ret = for_allow;
1774 goto out;
1775 } else if (for_allow && strcmp(line, v) == 0) {
1776 ret = true;
8900b9eb 1777 goto out;
33ad9f1a
CS
1778 }
1779 }
1780
1781out:
025ed0f3 1782 process_lock();
33ad9f1a 1783 fclose(devices_list);
025ed0f3 1784 process_unlock();
33ad9f1a
CS
1785 free(line);
1786 free(path);
1787 return ret;
1788}
1789
1790int cgroup_recursive_task_count(const char *cgroup_path)
b98f7d6e 1791{
33ad9f1a
CS
1792 DIR *d;
1793 struct dirent *dent_buf;
1794 struct dirent *dent;
8900b9eb 1795 ssize_t name_max;
33ad9f1a
CS
1796 int n = 0, r;
1797
1798 /* see man readdir_r(3) */
1799 name_max = pathconf(cgroup_path, _PC_NAME_MAX);
1800 if (name_max <= 0)
1801 name_max = 255;
1802 dent_buf = malloc(offsetof(struct dirent, d_name) + name_max + 1);
1803 if (!dent_buf)
1804 return -1;
1805
025ed0f3 1806 process_lock();
33ad9f1a 1807 d = opendir(cgroup_path);
025ed0f3 1808 process_unlock();
33ad9f1a
CS
1809 if (!d)
1810 return 0;
1811
1812 while (readdir_r(d, dent_buf, &dent) == 0 && dent) {
1813 const char *parts[3] = {
1814 cgroup_path,
1815 dent->d_name,
1816 NULL
1817 };
1818 char *sub_path;
1819 struct stat st;
1820
1821 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1822 continue;
1823 sub_path = lxc_string_join("/", parts, false);
1824 if (!sub_path) {
025ed0f3 1825 process_lock();
33ad9f1a 1826 closedir(d);
025ed0f3 1827 process_unlock();
33ad9f1a
CS
1828 free(dent_buf);
1829 return -1;
1830 }
1831 r = stat(sub_path, &st);
1832 if (r < 0) {
025ed0f3 1833 process_lock();
33ad9f1a 1834 closedir(d);
025ed0f3 1835 process_unlock();
33ad9f1a
CS
1836 free(dent_buf);
1837 free(sub_path);
1838 return -1;
1839 }
1840 if (S_ISDIR(st.st_mode)) {
1841 r = cgroup_recursive_task_count(sub_path);
1842 if (r >= 0)
1843 n += r;
1844 } else if (!strcmp(dent->d_name, "tasks")) {
1845 r = count_lines(sub_path);
1846 if (r >= 0)
1847 n += r;
1848 }
1849 free(sub_path);
1850 }
025ed0f3 1851 process_lock();
33ad9f1a 1852 closedir(d);
025ed0f3 1853 process_unlock();
33ad9f1a
CS
1854 free(dent_buf);
1855
1856 return n;
1857}
1858
8900b9eb 1859int count_lines(const char *fn)
33ad9f1a
CS
1860{
1861 FILE *f;
1862 char *line = NULL;
1863 size_t sz = 0;
1864 int n = 0;
1865
025ed0f3 1866 process_lock();
33ad9f1a 1867 f = fopen_cloexec(fn, "r");
025ed0f3 1868 process_unlock();
33ad9f1a
CS
1869 if (!f)
1870 return -1;
1871
1872 while (getline(&line, &sz, f) != -1) {
1873 n++;
1874 }
1875 free(line);
025ed0f3 1876 process_lock();
33ad9f1a 1877 fclose(f);
025ed0f3 1878 process_unlock();
33ad9f1a 1879 return n;
b98f7d6e
SH
1880}
1881
33ad9f1a 1882int handle_clone_children(struct cgroup_mount_point *mp, char *cgroup_path)
b98f7d6e 1883{
33ad9f1a
CS
1884 int r, saved_errno = 0;
1885 /* if this is a cpuset hierarchy, we have to set cgroup.clone_children in
1886 * the base cgroup, otherwise containers will start with an empty cpuset.mems
1887 * and cpuset.cpus and then
1888 */
1889 if (lxc_string_in_array("cpuset", (const char **)mp->hierarchy->subsystems)) {
1890 char *cc_path = cgroup_to_absolute_path(mp, cgroup_path, "/cgroup.clone_children");
1891 if (!cc_path)
1892 return -1;
1893 r = lxc_write_to_file(cc_path, "1", 1, false);
1894 saved_errno = errno;
1895 free(cc_path);
1896 errno = saved_errno;
1897 return r < 0 ? -1 : 0;
1898 }
1899 return 0;
b98f7d6e 1900}