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