]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/cgroup.c
detect APT_PROXY from host apt.conf
[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
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <sys/param.h>
35#include <sys/inotify.h>
36#include <netinet/in.h>
37#include <net/if.h>
38
e2bcd7db 39#include "error.h"
881450bb 40#include "config.h"
ae5c8b8e 41#include "commands.h"
36eb9bde 42
36eb9bde 43#include <lxc/log.h>
00b3c2e2
CLG
44#include <lxc/cgroup.h>
45#include <lxc/start.h>
36eb9bde 46
edaf8b1b
SG
47#if IS_BIONIC
48#include <../include/lxcmntent.h>
49#else
50#include <mntent.h>
51#endif
52
36eb9bde 53lxc_log_define(lxc_cgroup, lxc);
576f946d 54
5193cc3d 55#define MTAB "/proc/mounts"
576f946d 56
1d39a065
DW
57/* Check if a mount is a cgroup hierarchy for any subsystem.
58 * Return the first subsystem found (or NULL if none).
59 */
60static char *mount_has_subsystem(const struct mntent *mntent)
61{
62 FILE *f;
5270bf4b 63 char *c, *ret = NULL;
1d39a065
DW
64 char line[MAXPATHLEN];
65
66 /* read the list of subsystems from the kernel */
67 f = fopen("/proc/cgroups", "r");
68 if (!f)
69 return 0;
70
71 /* skip the first line, which contains column headings */
00b6be44
SH
72 if (!fgets(line, MAXPATHLEN, f)) {
73 fclose(f);
1d39a065 74 return 0;
00b6be44 75 }
1d39a065
DW
76
77 while (fgets(line, MAXPATHLEN, f)) {
78 c = strchr(line, '\t');
79 if (!c)
80 continue;
81 *c = '\0';
82
83 ret = hasmntopt(mntent, line);
84 if (ret)
85 break;
86 }
87
88 fclose(f);
89 return ret;
90}
91
d08ba6ec 92/*
23622a2a 93 * Determine mountpoint for a cgroup subsystem.
ae5c8b8e
SH
94 * @subsystem: cgroup subsystem (i.e. freezer). If this is NULL, the first
95 * cgroup mountpoint with any subsystems is used.
96 * @mnt: a passed-in buffer of at least size MAXPATHLEN into which the path
97 * is copied.
98 *
99 * Returns 0 on success, -1 on error.
100 */
bcbd102c 101static int get_cgroup_mount(const char *subsystem, char *mnt)
576f946d 102{
bcbd102c
SH
103 struct mntent *mntent;
104 FILE *file = NULL;
ae5c8b8e 105 int ret, err = -1;
576f946d 106
bcbd102c
SH
107 file = setmntent(MTAB, "r");
108 if (!file) {
109 SYSERROR("failed to open %s", MTAB);
5193cc3d 110 return -1;
bcbd102c 111 }
0d9f8e18 112
bcbd102c 113 while ((mntent = getmntent(file))) {
bcbd102c
SH
114 if (strcmp(mntent->mnt_type, "cgroup"))
115 continue;
1d39a065
DW
116
117 if (subsystem) {
118 if (!hasmntopt(mntent, subsystem))
119 continue;
ae5c8b8e 120 } else {
1d39a065
DW
121 if (!mount_has_subsystem(mntent))
122 continue;
123 }
ad08bbb7 124
23622a2a 125 ret = snprintf(mnt, MAXPATHLEN, "%s", mntent->mnt_dir);
ad08bbb7
DW
126 if (ret < 0 || ret >= MAXPATHLEN)
127 goto fail;
128
129 DEBUG("using cgroup mounted at '%s'", mnt);
130 err = 0;
131 goto out;
bcbd102c 132 };
576f946d 133
d08ba6ec
SH
134fail:
135 DEBUG("Failed to find cgroup for %s\n",
136 subsystem ? subsystem : "(NULL)");
ad08bbb7
DW
137out:
138 endmntent(file);
139 return err;
5193cc3d
DL
140}
141
ae5c8b8e
SH
142/*
143 * cgroup_path_get: Calculate the full path for a particular subsystem, plus
144 * a passed-in (to be appended) relative cgpath for a container.
145 * @path: a char** into which a pointer to the answer is copied
146 * @subsystem: subsystem of interest (i.e. freezer).
147 * @cgpath: a container's (relative) cgroup path, i.e. "/lxc/c1".
148 *
149 * Returns 0 on success, -1 on error.
150 *
151 * The answer is written in a static char[MAXPATHLEN] in this function and
152 * should not be freed.
153 */
154extern int cgroup_path_get(char **path, const char *subsystem, const char *cgpath)
0b9c21ab
SH
155{
156 static char buf[MAXPATHLEN];
ae5c8b8e
SH
157 static char retbuf[MAXPATHLEN];
158 int rc;
0b9c21ab 159
ae5c8b8e
SH
160 /* lxc_cgroup_set passes a state object for the subsystem,
161 * so trim it to just the subsystem part */
162 if (subsystem) {
163 rc = snprintf(retbuf, MAXPATHLEN, "%s", subsystem);
164 if (rc < 0 || rc >= MAXPATHLEN) {
165 ERROR("subsystem name too long");
166 return -1;
167 }
168 char *s = index(retbuf, '.');
169 if (s)
170 *s = '\0';
171 DEBUG("%s: called for subsys %s name %s\n", __func__, retbuf, cgpath);
172 }
173 if (get_cgroup_mount(subsystem ? retbuf : NULL, buf)) {
174 ERROR("cgroup is not mounted");
175 return -1;
176 }
177
178 rc = snprintf(retbuf, MAXPATHLEN, "%s/%s", buf, cgpath);
179 if (rc < 0 || rc >= MAXPATHLEN) {
180 ERROR("name too long");
181 return -1;
182 }
183
184 DEBUG("%s: returning %s for subsystem %s", __func__, retbuf, subsystem);
185
186 *path = retbuf;
187 return 0;
0b9c21ab
SH
188}
189
ae5c8b8e
SH
190/*
191 * Calculate a container's cgroup path for a particular subsystem. This
192 * is the cgroup path relative to the root of the cgroup filesystem.
193 * @path: A char ** into which we copy the char* containing the answer
194 * @subsystem: the cgroup subsystem of interest (i.e. freezer)
195 * @name: container name
196 * @lxcpath: the lxcpath in which the container is running.
197 *
198 * Returns 0 on success, -1 on error.
199 *
200 * Note that the char* copied into *path is a static char[MAXPATHLEN] in
201 * commands.c:receive_answer(). It should not be freed.
202 */
203extern int lxc_get_cgpath(const char **path, const char *subsystem, const char *name, const char *lxcpath)
6203de18 204{
ae5c8b8e
SH
205 struct lxc_command command = {
206 .request = { .type = LXC_COMMAND_CGROUP },
207 };
208
209 int ret, stopped = 0;
fc3c7f7f 210
ae5c8b8e
SH
211 ret = lxc_command(name, &command, &stopped, lxcpath);
212 if (ret < 0) {
213 if (!stopped)
214 ERROR("failed to send command");
fc3c7f7f 215 return -1;
ae5c8b8e 216 }
6203de18 217
ae5c8b8e
SH
218 if (!ret) {
219 WARN("'%s' has stopped before sending its state", name);
fc3c7f7f 220 return -1;
ae5c8b8e 221 }
6203de18 222
ae5c8b8e
SH
223 if (command.answer.ret < 0 || command.answer.pathlen < 0) {
224 ERROR("failed to get state for '%s': %s",
225 name, strerror(-command.answer.ret));
ef342abb 226 return -1;
0dd4566e
DL
227 }
228
ae5c8b8e 229 *path = command.answer.path;
758437c5 230
ef342abb 231 return 0;
6203de18
DL
232}
233
ae5c8b8e
SH
234/*
235 * lxc_cgroup_path_get: determine full pathname for a cgroup
236 * file for a specific container.
237 * @path: char ** used to return the answer. The char * will point
238 * into the static char* retuf from cgroup_path_get() (so no need
239 * to free it).
240 * @subsystem: cgroup subsystem (i.e. "freezer") for which to
241 * return an answer. If NULL, then the first cgroup entry in
242 * mtab will be used.
243 *
244 * This is the exported function, which determines cgpath from the
245 * monitor running in lxcpath.
246 *
247 * Returns 0 on success, < 0 on error.
248 */
249int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name, const char *lxcpath)
fd4f5a56 250{
ae5c8b8e 251 const char *cgpath;
fd4f5a56 252
ae5c8b8e 253 if (lxc_get_cgpath(&cgpath, subsystem, name, lxcpath) < 0)
fd4f5a56 254 return -1;
fd4f5a56 255
ae5c8b8e
SH
256 return cgroup_path_get(path, subsystem, cgpath);
257}
258
259/*
260 * small helper which simply write a value into a (cgroup) file
261 */
262static int do_cgroup_set(const char *path, const char *value)
263{
264 int fd, ret;
265
266 if ((fd = open(path, O_WRONLY)) < 0) {
267 SYSERROR("open %s : %s", path, strerror(errno));
268 return -1;
fd4f5a56
DL
269 }
270
ae5c8b8e
SH
271 if ((ret = write(fd, value, strlen(value))) < 0) {
272 close(fd);
273 SYSERROR("write %s : %s", path, strerror(errno));
274 return ret;
275 }
fd4f5a56 276
ae5c8b8e
SH
277 if ((ret = close(fd)) < 0) {
278 SYSERROR("close %s : %s", path, strerror(errno));
279 return ret;
280 }
281 return 0;
fd4f5a56
DL
282}
283
ae5c8b8e
SH
284/*
285 * small helper to write a value into a file in a particular directory.
286 * @cgpath: the directory in which to find the file
287 * @filename: the file (under cgpath) to which to write
288 * @value: what to write
289 *
290 * Returns 0 on success, < 0 on error.
291 */
292int lxc_cgroup_set_bypath(const char *cgpath, const char *filename, const char *value)
fd4f5a56 293{
ae5c8b8e
SH
294 int ret;
295 char *dirpath;
296 char path[MAXPATHLEN];
c8f7c563 297
ae5c8b8e
SH
298 ret = cgroup_path_get(&dirpath, filename, cgpath);
299 if (ret)
300 return -1;
c8f7c563 301
ae5c8b8e
SH
302 ret = snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename);
303 if (ret < 0 || ret >= MAXPATHLEN) {
304 ERROR("pathname too long");
305 return -1;
306 }
c8f7c563 307
ae5c8b8e 308 return do_cgroup_set(path, value);
c8f7c563
CS
309}
310
ae5c8b8e
SH
311/*
312 * set a cgroup value for a container
313 *
314 * @name: name of the container
315 * @filename: the cgroup file (i.e. freezer.state) whose value to change
316 * @value: the value to write to the file
317 * @lxcpath: the lxcpath under which the container is running.
318 *
319 * Returns 0 on success, < 0 on error.
320 */
321
322int lxc_cgroup_set(const char *name, const char *filename, const char *value,
323 const char *lxcpath)
c8f7c563 324{
ae5c8b8e
SH
325 int ret;
326 char *dirpath;
327 char path[MAXPATHLEN];
328
329 ret = lxc_cgroup_path_get(&dirpath, filename, name, lxcpath);
330 if (ret)
331 return -1;
332
333 ret = snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename);
334 if (ret < 0 || ret >= MAXPATHLEN) {
335 ERROR("pathname too long");
336 return -1;
337 }
338
339 return do_cgroup_set(path, value);
c8f7c563
CS
340}
341
ae5c8b8e
SH
342/*
343 * Get value of a cgroup setting for a container.
344 *
345 * @name: name of the container
346 * @filename: the cgroup file to read (i.e. 'freezer.state')
347 * @value: a preallocated char* into which to copy the answer
348 * @len: the length of pre-allocated @value
349 * @lxcpath: the lxcpath in which the container is running (i.e.
350 * /var/lib/lxc)
351 *
352 * Returns < 0 on error, or the number of bytes read.
353 *
354 * If you pass in NULL value or 0 len, then you are asking for the size of the
355 * file.
356 *
357 * Note that we can't get the file size quickly through stat or lseek.
358 * Therefore if you pass in len > 0 but less than the file size, your only
359 * indication will be that the return value will be equal to the passed-in ret.
360 * We will not return the actual full file size.
361 */
362int lxc_cgroup_get(const char *name, const char *filename, char *value,
363 size_t len, const char *lxcpath)
c8f7c563 364{
ae5c8b8e
SH
365 int fd, ret = -1;
366 char *dirpath;
367 char path[MAXPATHLEN];
9ba8130c 368 int rc;
460a1cf0 369
ae5c8b8e
SH
370 ret = lxc_cgroup_path_get(&dirpath, filename, name, lxcpath);
371 if (ret)
372 return -1;
fd4f5a56 373
ae5c8b8e 374 rc = snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename);
9ba8130c
SH
375 if (rc < 0 || rc >= MAXPATHLEN) {
376 ERROR("pathname too long");
377 return -1;
378 }
fd4f5a56 379
ae5c8b8e 380 fd = open(path, O_RDONLY);
c8f7c563 381 if (fd < 0) {
ae5c8b8e 382 ERROR("open %s : %s", path, strerror(errno));
fd4f5a56
DL
383 return -1;
384 }
385
ae5c8b8e
SH
386 if (!len || !value) {
387 char buf[100];
388 int count = 0;
389 while ((ret = read(fd, buf, 100)) > 0)
390 count += ret;
391 if (ret >= 0)
392 ret = count;
393 } else {
394 memset(value, 0, len);
395 ret = read(fd, value, len);
fd4f5a56
DL
396 }
397
ae5c8b8e
SH
398 if (ret < 0)
399 ERROR("read %s : %s", path, strerror(errno));
400
401 close(fd);
402 return ret;
c8f7c563
CS
403}
404
ae5c8b8e 405int lxc_cgroup_nrtasks(const char *cgpath)
c8f7c563 406{
ae5c8b8e
SH
407 char *dpath;
408 char path[MAXPATHLEN];
409 int pid, ret, count = 0;
410 FILE *file;
411 int rc;
c8f7c563 412
ae5c8b8e
SH
413 ret = cgroup_path_get(&dpath, NULL, cgpath);
414 if (ret)
415 return -1;
c8f7c563 416
ae5c8b8e
SH
417 rc = snprintf(path, MAXPATHLEN, "%s/tasks", dpath);
418 if (rc < 0 || rc >= MAXPATHLEN) {
419 ERROR("pathname too long");
420 return -1;
421 }
c8f7c563 422
ae5c8b8e
SH
423 file = fopen(path, "r");
424 if (!file) {
425 SYSERROR("fopen '%s' failed", path);
426 return -1;
c8f7c563
CS
427 }
428
ae5c8b8e
SH
429 while (fscanf(file, "%d", &pid) != EOF)
430 count++;
fd4f5a56 431
ae5c8b8e
SH
432 fclose(file);
433
434 return count;
fd4f5a56
DL
435}
436
fc7de561
SH
437/*
438 * If first creating the /sys/fs/cgroup/$subsys/lxc container, then
439 * try to set clone_children to 1. Some kernels don't support
440 * clone_children, and cgroup maintainer wants to deprecate it. So
441 * XXX TODO we should instead after each cgroup mkdir (here and in
442 * hooks/mountcgroup) check if cpuset is in the subsystems, and if so
443 * manually copy over mems and cpus.
444 */
23622a2a 445static void set_clone_children(const char *mntdir)
fc7de561
SH
446{
447 char path[MAXPATHLEN];
448 FILE *fout;
449 int ret;
450
23622a2a 451 ret = snprintf(path, MAXPATHLEN, "%s/cgroup.clone_children", mntdir);
fc7de561
SH
452 INFO("writing to %s\n", path);
453 if (ret < 0 || ret > MAXPATHLEN)
454 return;
455 fout = fopen(path, "w");
456 if (!fout)
457 return;
458 fprintf(fout, "1\n");
459 fclose(fout);
460}
461
ae5c8b8e
SH
462/*
463 * Make sure the 'cgroup group' exists, so that we don't have to worry about
464 * that later.
465 *
466 * @lxcgroup: the cgroup group, i.e. 'lxc' by default.
467 *
468 * See detailed comments at lxc_cgroup_path_create for more information.
469 *
470 * Returns 0 on success, -1 on error.
471 */
472static int create_lxcgroups(const char *lxcgroup)
460a1cf0 473{
460a1cf0 474 FILE *file = NULL;
ae5c8b8e
SH
475 struct mntent *mntent;
476 int ret, retv = -1;
23622a2a 477 char path[MAXPATHLEN];
460a1cf0
DW
478
479 file = setmntent(MTAB, "r");
480 if (!file) {
481 SYSERROR("failed to open %s", MTAB);
482 return -1;
483 }
484
485 while ((mntent = getmntent(file))) {
460a1cf0
DW
486
487 if (strcmp(mntent->mnt_type, "cgroup"))
488 continue;
1d39a065
DW
489 if (!mount_has_subsystem(mntent))
490 continue;
460a1cf0 491
ae5c8b8e
SH
492 /*
493 * TODO - handle case where lxcgroup has subdirs? (i.e. build/l1)
23622a2a
SH
494 * We probably only want to support that for /users/joe
495 */
496 ret = snprintf(path, MAXPATHLEN, "%s/%s",
497 mntent->mnt_dir, lxcgroup ? lxcgroup : "lxc");
ae5c8b8e
SH
498 if (ret < 0 || ret >= MAXPATHLEN)
499 goto fail;
500 if (access(path, F_OK)) {
23622a2a 501 set_clone_children(mntent->mnt_dir);
ae5c8b8e
SH
502 ret = mkdir(path, 0755);
503 if (ret == -1 && errno != EEXIST) {
504 SYSERROR("failed to create '%s' directory", path);
505 goto fail;
506 }
c8f7c563 507 }
c8f7c563 508
c8f7c563
CS
509 }
510
ae5c8b8e
SH
511 retv = 0;
512fail:
513 endmntent(file);
514 return retv;
c8f7c563
CS
515}
516
d08ba6ec 517/*
ae5c8b8e
SH
518 * For a new container, find a cgroup path which is unique in all cgroup mounts.
519 * I.e. if r1 is already running, then /lxc/r1-1 may be used.
520 *
521 * @lxcgroup: the cgroup 'group' the contaienr should run in. By default, this
522 * is just 'lxc'. Admins may wish to group some containers into other groups,
523 * i.e. 'build', to take advantage of cgroup hierarchy to simplify group
524 * administration. Also, unprivileged users who are placed into a cgroup by
525 * libcgroup_pam will be using that cgroup rather than the system-wide 'lxc'
526 * group.
527 * @name: the name of the container
528 *
529 * The chosen cgpath is returned as a strdup'd string. The caller will have to
530 * free that eventually, however the lxc monitor will keep that string so as to
531 * return it in response to a LXC_COMMAND_CGROUP query.
532 *
23622a2a
SH
533 * Note the path is relative to cgroup mounts. I.e. if the freezer subsystem
534 * is at /sys/fs/cgroup/freezer, and this fn returns '/lxc/r1', then the
535 * freezer cgroup's full path will be /sys/fs/cgroup/freezer/lxc/r1/.
ae5c8b8e
SH
536 *
537 * XXX This should probably be locked globally
538 *
539 * Races won't be determintal, you'll just end up with leftover unused cgroups
d08ba6ec 540 */
ae5c8b8e 541char *lxc_cgroup_path_create(const char *lxcgroup, const char *name)
d08ba6ec 542{
ae5c8b8e 543 int i = 0, ret;
23622a2a 544 char *retpath, path[MAXPATHLEN];
ae5c8b8e
SH
545 char tail[12];
546 FILE *file = NULL;
547 struct mntent *mntent;
d08ba6ec 548
ae5c8b8e
SH
549 if (create_lxcgroups(lxcgroup) < 0)
550 return NULL;
d08ba6ec 551
ae5c8b8e
SH
552again:
553 file = setmntent(MTAB, "r");
554 if (!file) {
555 SYSERROR("failed to open %s", MTAB);
556 return NULL;
d08ba6ec 557 }
1ac470c0 558
ae5c8b8e
SH
559 if (i)
560 snprintf(tail, 12, "-%d", i);
561 else
562 *tail = '\0';
257e5824 563
ae5c8b8e 564 while ((mntent = getmntent(file))) {
fd4f5a56 565
ae5c8b8e
SH
566 if (strcmp(mntent->mnt_type, "cgroup"))
567 continue;
568 if (!mount_has_subsystem(mntent))
569 continue;
e4659536 570
23622a2a
SH
571 /* find unused mnt_dir + lxcgroup + name + -$i */
572 ret = snprintf(path, MAXPATHLEN, "%s/%s/%s%s", mntent->mnt_dir,
ae5c8b8e
SH
573 lxcgroup ? lxcgroup : "lxc", name, tail);
574 if (ret < 0 || ret >= MAXPATHLEN)
575 goto fail;
5193cc3d 576
ae5c8b8e 577 if (access(path, F_OK) == 0) goto next;
fd4f5a56 578
ae5c8b8e
SH
579 if (mkdir(path, 0755)) {
580 ERROR("Error creating cgroups");
581 goto fail;
e7f40d8a 582 }
d08ba6ec 583
d08ba6ec
SH
584 }
585
ae5c8b8e 586 endmntent(file);
fd4f5a56 587
ae5c8b8e
SH
588 // print out the cgpath part
589 ret = snprintf(path, MAXPATHLEN, "%s/%s%s",
590 lxcgroup ? lxcgroup : "lxc", name, tail);
591 if (ret < 0 || ret >= MAXPATHLEN) // can't happen
592 goto fail;
bcbd102c 593
ae5c8b8e
SH
594 retpath = strdup(path);
595
596 return retpath;
597
598next:
599 endmntent(file);
600 i++;
601 goto again;
602
603fail:
604 endmntent(file);
605 return NULL;
36b86299
DL
606}
607
ae5c8b8e 608int lxc_cgroup_enter(const char *cgpath, pid_t pid)
36b86299 609{
23622a2a 610 char path[MAXPATHLEN];
ae5c8b8e 611 FILE *file = NULL, *fout;
bcbd102c 612 struct mntent *mntent;
ae5c8b8e 613 int ret, retv = -1;
ef342abb 614
bcbd102c
SH
615 file = setmntent(MTAB, "r");
616 if (!file) {
617 SYSERROR("failed to open %s", MTAB);
ef342abb
DL
618 return -1;
619 }
620
bcbd102c 621 while ((mntent = getmntent(file))) {
ad08bbb7
DW
622 if (strcmp(mntent->mnt_type, "cgroup"))
623 continue;
1d39a065
DW
624 if (!mount_has_subsystem(mntent))
625 continue;
23622a2a
SH
626 ret = snprintf(path, MAXPATHLEN, "%s/%s/tasks",
627 mntent->mnt_dir, cgpath);
ae5c8b8e
SH
628 if (ret < 0 || ret >= MAXPATHLEN) {
629 ERROR("entering cgroup");
ad08bbb7 630 goto out;
ae5c8b8e
SH
631 }
632 fout = fopen(path, "w");
633 if (!fout) {
634 ERROR("entering cgroup");
460a1cf0 635 goto out;
ae5c8b8e
SH
636 }
637 fprintf(fout, "%d\n", (int)pid);
638 fclose(fout);
639 }
640 retv = 0;
f0e64b8b 641
bcbd102c
SH
642out:
643 endmntent(file);
ae5c8b8e 644 return retv;
bcbd102c
SH
645}
646
341a9bd8
SH
647int recursive_rmdir(char *dirname)
648{
649 struct dirent dirent, *direntp;
341a9bd8
SH
650 DIR *dir;
651 int ret;
652 char pathname[MAXPATHLEN];
653
654 dir = opendir(dirname);
655 if (!dir) {
656 WARN("failed to open directory: %m");
657 return -1;
658 }
659
341a9bd8
SH
660 while (!readdir_r(dir, &dirent, &direntp)) {
661 struct stat mystat;
9ba8130c 662 int rc;
341a9bd8
SH
663
664 if (!direntp)
665 break;
666
667 if (!strcmp(direntp->d_name, ".") ||
668 !strcmp(direntp->d_name, ".."))
669 continue;
670
9ba8130c
SH
671 rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name);
672 if (rc < 0 || rc >= MAXPATHLEN) {
673 ERROR("pathname too long");
674 continue;
675 }
341a9bd8
SH
676 ret = stat(pathname, &mystat);
677 if (ret)
678 continue;
679 if (S_ISDIR(mystat.st_mode))
680 recursive_rmdir(pathname);
681 }
682
683 ret = rmdir(dirname);
684
685 if (closedir(dir))
686 ERROR("failed to close directory");
687 return ret;
688
689
690}
bcbd102c 691
ae5c8b8e 692static int lxc_one_cgroup_destroy(struct mntent *mntent, const char *cgpath)
bcbd102c 693{
23622a2a 694 char cgname[MAXPATHLEN];
d08ba6ec 695 char *cgmnt = mntent->mnt_dir;
9ba8130c 696 int rc;
bcbd102c 697
23622a2a 698 rc = snprintf(cgname, MAXPATHLEN, "%s/%s", cgmnt, cgpath);
9ba8130c
SH
699 if (rc < 0 || rc >= MAXPATHLEN) {
700 ERROR("name too long");
701 return -1;
702 }
d08ba6ec 703 DEBUG("destroying %s\n", cgname);
341a9bd8 704 if (recursive_rmdir(cgname)) {
ef342abb
DL
705 SYSERROR("failed to remove cgroup '%s'", cgname);
706 return -1;
707 }
708
709 DEBUG("'%s' unlinked", cgname);
710
711 return 0;
36b86299
DL
712}
713
bcbd102c
SH
714/*
715 * for each mounted cgroup, destroy the cgroup for the container
716 */
ae5c8b8e 717int lxc_cgroup_destroy(const char *cgpath)
a6ddef61 718{
bcbd102c
SH
719 struct mntent *mntent;
720 FILE *file = NULL;
ae5c8b8e 721 int err, retv = 0;
bcbd102c
SH
722
723 file = setmntent(MTAB, "r");
724 if (!file) {
725 SYSERROR("failed to open %s", MTAB);
726 return -1;
727 }
0411a752 728
bcbd102c 729 while ((mntent = getmntent(file))) {
ad08bbb7
DW
730 if (strcmp(mntent->mnt_type, "cgroup"))
731 continue;
1d39a065
DW
732 if (!mount_has_subsystem(mntent))
733 continue;
a6ddef61 734
ae5c8b8e
SH
735 err = lxc_one_cgroup_destroy(mntent, cgpath);
736 if (err) // keep trying to clean up the others
737 retv = -1;
ad08bbb7 738 }
bcbd102c 739
ad08bbb7 740 endmntent(file);
ae5c8b8e 741 return retv;
a6ddef61
MN
742}
743
ae5c8b8e 744int lxc_cgroup_attach(pid_t pid, const char *name, const char *lxcpath)
576f946d 745{
ae5c8b8e 746 const char *dirpath;
576f946d 747
ae5c8b8e
SH
748 if (lxc_get_cgpath(&dirpath, NULL, name, lxcpath) < 0) {
749 ERROR("Error getting cgroup for container %s: %s", lxcpath, name);
576f946d 750 return -1;
8b92dc3a 751 }
ae5c8b8e 752 INFO("joining pid %d to cgroup %s", pid, dirpath);
576f946d 753
ae5c8b8e 754 return lxc_cgroup_enter(dirpath, pid);
e0f888d9 755}