]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
7 | * Daniel Lezcano <daniel.lezcano at free.fr> | |
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> | |
28 | #include <unistd.h> | |
29 | #include <string.h> | |
30 | #include <dirent.h> | |
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 | ||
39 | #include "error.h" | |
40 | #include "config.h" | |
41 | #include "commands.h" | |
42 | ||
43 | #include <lxc/log.h> | |
44 | #include <lxc/cgroup.h> | |
45 | #include <lxc/start.h> | |
46 | ||
47 | #if IS_BIONIC | |
48 | #include <../include/lxcmntent.h> | |
49 | #else | |
50 | #include <mntent.h> | |
51 | #endif | |
52 | ||
53 | lxc_log_define(lxc_cgroup, lxc); | |
54 | ||
55 | #define MTAB "/proc/mounts" | |
56 | ||
57 | /* Check if a mount is a cgroup hierarchy for any subsystem. | |
58 | * Return the first subsystem found (or NULL if none). | |
59 | */ | |
60 | static char *mount_has_subsystem(const struct mntent *mntent) | |
61 | { | |
62 | FILE *f; | |
63 | char *c, *ret = NULL; | |
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 */ | |
72 | if (!fgets(line, MAXPATHLEN, f)) { | |
73 | fclose(f); | |
74 | return 0; | |
75 | } | |
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 | ||
92 | /* | |
93 | * Determine mountpoint for a cgroup subsystem. | |
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 | */ | |
101 | static int get_cgroup_mount(const char *subsystem, char *mnt) | |
102 | { | |
103 | struct mntent *mntent; | |
104 | FILE *file = NULL; | |
105 | int ret, err = -1; | |
106 | ||
107 | file = setmntent(MTAB, "r"); | |
108 | if (!file) { | |
109 | SYSERROR("failed to open %s", MTAB); | |
110 | return -1; | |
111 | } | |
112 | ||
113 | while ((mntent = getmntent(file))) { | |
114 | if (strcmp(mntent->mnt_type, "cgroup")) | |
115 | continue; | |
116 | ||
117 | if (subsystem) { | |
118 | if (!hasmntopt(mntent, subsystem)) | |
119 | continue; | |
120 | } else { | |
121 | if (!mount_has_subsystem(mntent)) | |
122 | continue; | |
123 | } | |
124 | ||
125 | ret = snprintf(mnt, MAXPATHLEN, "%s", mntent->mnt_dir); | |
126 | if (ret < 0 || ret >= MAXPATHLEN) | |
127 | goto fail; | |
128 | ||
129 | DEBUG("using cgroup mounted at '%s'", mnt); | |
130 | err = 0; | |
131 | goto out; | |
132 | }; | |
133 | ||
134 | fail: | |
135 | DEBUG("Failed to find cgroup for %s\n", | |
136 | subsystem ? subsystem : "(NULL)"); | |
137 | out: | |
138 | endmntent(file); | |
139 | return err; | |
140 | } | |
141 | ||
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 | */ | |
154 | extern int cgroup_path_get(char **path, const char *subsystem, const char *cgpath) | |
155 | { | |
156 | static char buf[MAXPATHLEN]; | |
157 | static char retbuf[MAXPATHLEN]; | |
158 | int rc; | |
159 | ||
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; | |
188 | } | |
189 | ||
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 | */ | |
203 | extern int lxc_get_cgpath(const char **path, const char *subsystem, const char *name, const char *lxcpath) | |
204 | { | |
205 | struct lxc_command command = { | |
206 | .request = { .type = LXC_COMMAND_CGROUP }, | |
207 | }; | |
208 | ||
209 | int ret, stopped = 0; | |
210 | ||
211 | ret = lxc_command(name, &command, &stopped, lxcpath); | |
212 | if (ret < 0) { | |
213 | if (!stopped) | |
214 | ERROR("failed to send command"); | |
215 | return -1; | |
216 | } | |
217 | ||
218 | if (!ret) { | |
219 | WARN("'%s' has stopped before sending its state", name); | |
220 | return -1; | |
221 | } | |
222 | ||
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)); | |
226 | return -1; | |
227 | } | |
228 | ||
229 | *path = command.answer.path; | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
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 | */ | |
249 | int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name, const char *lxcpath) | |
250 | { | |
251 | const char *cgpath; | |
252 | ||
253 | if (lxc_get_cgpath(&cgpath, subsystem, name, lxcpath) < 0) | |
254 | return -1; | |
255 | ||
256 | return cgroup_path_get(path, subsystem, cgpath); | |
257 | } | |
258 | ||
259 | /* | |
260 | * small helper which simply write a value into a (cgroup) file | |
261 | */ | |
262 | static 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; | |
269 | } | |
270 | ||
271 | if ((ret = write(fd, value, strlen(value))) < 0) { | |
272 | close(fd); | |
273 | SYSERROR("write %s : %s", path, strerror(errno)); | |
274 | return ret; | |
275 | } | |
276 | ||
277 | if ((ret = close(fd)) < 0) { | |
278 | SYSERROR("close %s : %s", path, strerror(errno)); | |
279 | return ret; | |
280 | } | |
281 | return 0; | |
282 | } | |
283 | ||
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 | */ | |
292 | int lxc_cgroup_set_bypath(const char *cgpath, const char *filename, const char *value) | |
293 | { | |
294 | int ret; | |
295 | char *dirpath; | |
296 | char path[MAXPATHLEN]; | |
297 | ||
298 | ret = cgroup_path_get(&dirpath, filename, cgpath); | |
299 | if (ret) | |
300 | return -1; | |
301 | ||
302 | ret = snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename); | |
303 | if (ret < 0 || ret >= MAXPATHLEN) { | |
304 | ERROR("pathname too long"); | |
305 | return -1; | |
306 | } | |
307 | ||
308 | return do_cgroup_set(path, value); | |
309 | } | |
310 | ||
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 | ||
322 | int lxc_cgroup_set(const char *name, const char *filename, const char *value, | |
323 | const char *lxcpath) | |
324 | { | |
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); | |
340 | } | |
341 | ||
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 | */ | |
362 | int lxc_cgroup_get(const char *name, const char *filename, char *value, | |
363 | size_t len, const char *lxcpath) | |
364 | { | |
365 | int fd, ret = -1; | |
366 | char *dirpath; | |
367 | char path[MAXPATHLEN]; | |
368 | int rc; | |
369 | ||
370 | ret = lxc_cgroup_path_get(&dirpath, filename, name, lxcpath); | |
371 | if (ret) | |
372 | return -1; | |
373 | ||
374 | rc = snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename); | |
375 | if (rc < 0 || rc >= MAXPATHLEN) { | |
376 | ERROR("pathname too long"); | |
377 | return -1; | |
378 | } | |
379 | ||
380 | fd = open(path, O_RDONLY); | |
381 | if (fd < 0) { | |
382 | ERROR("open %s : %s", path, strerror(errno)); | |
383 | return -1; | |
384 | } | |
385 | ||
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); | |
396 | } | |
397 | ||
398 | if (ret < 0) | |
399 | ERROR("read %s : %s", path, strerror(errno)); | |
400 | ||
401 | close(fd); | |
402 | return ret; | |
403 | } | |
404 | ||
405 | int lxc_cgroup_nrtasks(const char *cgpath) | |
406 | { | |
407 | char *dpath; | |
408 | char path[MAXPATHLEN]; | |
409 | int pid, ret, count = 0; | |
410 | FILE *file; | |
411 | int rc; | |
412 | ||
413 | ret = cgroup_path_get(&dpath, NULL, cgpath); | |
414 | if (ret) | |
415 | return -1; | |
416 | ||
417 | rc = snprintf(path, MAXPATHLEN, "%s/tasks", dpath); | |
418 | if (rc < 0 || rc >= MAXPATHLEN) { | |
419 | ERROR("pathname too long"); | |
420 | return -1; | |
421 | } | |
422 | ||
423 | file = fopen(path, "r"); | |
424 | if (!file) { | |
425 | SYSERROR("fopen '%s' failed", path); | |
426 | return -1; | |
427 | } | |
428 | ||
429 | while (fscanf(file, "%d", &pid) != EOF) | |
430 | count++; | |
431 | ||
432 | fclose(file); | |
433 | ||
434 | return count; | |
435 | } | |
436 | ||
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 | */ | |
445 | static void set_clone_children(const char *mntdir) | |
446 | { | |
447 | char path[MAXPATHLEN]; | |
448 | FILE *fout; | |
449 | int ret; | |
450 | ||
451 | ret = snprintf(path, MAXPATHLEN, "%s/cgroup.clone_children", mntdir); | |
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 | ||
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 | */ | |
472 | static int create_lxcgroups(const char *lxcgroup) | |
473 | { | |
474 | FILE *file = NULL; | |
475 | struct mntent *mntent; | |
476 | int ret, retv = -1; | |
477 | char path[MAXPATHLEN]; | |
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))) { | |
486 | ||
487 | if (strcmp(mntent->mnt_type, "cgroup")) | |
488 | continue; | |
489 | if (!mount_has_subsystem(mntent)) | |
490 | continue; | |
491 | ||
492 | /* | |
493 | * TODO - handle case where lxcgroup has subdirs? (i.e. build/l1) | |
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"); | |
498 | if (ret < 0 || ret >= MAXPATHLEN) | |
499 | goto fail; | |
500 | if (access(path, F_OK)) { | |
501 | set_clone_children(mntent->mnt_dir); | |
502 | ret = mkdir(path, 0755); | |
503 | if (ret == -1 && errno != EEXIST) { | |
504 | SYSERROR("failed to create '%s' directory", path); | |
505 | goto fail; | |
506 | } | |
507 | } | |
508 | ||
509 | } | |
510 | ||
511 | retv = 0; | |
512 | fail: | |
513 | endmntent(file); | |
514 | return retv; | |
515 | } | |
516 | ||
517 | /* | |
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 | * | |
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/. | |
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 | |
540 | */ | |
541 | char *lxc_cgroup_path_create(const char *lxcgroup, const char *name) | |
542 | { | |
543 | int i = 0, ret; | |
544 | char *retpath, path[MAXPATHLEN]; | |
545 | char tail[12]; | |
546 | FILE *file = NULL; | |
547 | struct mntent *mntent; | |
548 | ||
549 | if (create_lxcgroups(lxcgroup) < 0) | |
550 | return NULL; | |
551 | ||
552 | again: | |
553 | file = setmntent(MTAB, "r"); | |
554 | if (!file) { | |
555 | SYSERROR("failed to open %s", MTAB); | |
556 | return NULL; | |
557 | } | |
558 | ||
559 | if (i) | |
560 | snprintf(tail, 12, "-%d", i); | |
561 | else | |
562 | *tail = '\0'; | |
563 | ||
564 | while ((mntent = getmntent(file))) { | |
565 | ||
566 | if (strcmp(mntent->mnt_type, "cgroup")) | |
567 | continue; | |
568 | if (!mount_has_subsystem(mntent)) | |
569 | continue; | |
570 | ||
571 | /* find unused mnt_dir + lxcgroup + name + -$i */ | |
572 | ret = snprintf(path, MAXPATHLEN, "%s/%s/%s%s", mntent->mnt_dir, | |
573 | lxcgroup ? lxcgroup : "lxc", name, tail); | |
574 | if (ret < 0 || ret >= MAXPATHLEN) | |
575 | goto fail; | |
576 | ||
577 | if (access(path, F_OK) == 0) goto next; | |
578 | ||
579 | if (mkdir(path, 0755)) { | |
580 | ERROR("Error creating cgroups"); | |
581 | goto fail; | |
582 | } | |
583 | ||
584 | } | |
585 | ||
586 | endmntent(file); | |
587 | ||
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; | |
593 | ||
594 | retpath = strdup(path); | |
595 | ||
596 | return retpath; | |
597 | ||
598 | next: | |
599 | endmntent(file); | |
600 | i++; | |
601 | goto again; | |
602 | ||
603 | fail: | |
604 | endmntent(file); | |
605 | return NULL; | |
606 | } | |
607 | ||
608 | int lxc_cgroup_enter(const char *cgpath, pid_t pid) | |
609 | { | |
610 | char path[MAXPATHLEN]; | |
611 | FILE *file = NULL, *fout; | |
612 | struct mntent *mntent; | |
613 | int ret, retv = -1; | |
614 | ||
615 | file = setmntent(MTAB, "r"); | |
616 | if (!file) { | |
617 | SYSERROR("failed to open %s", MTAB); | |
618 | return -1; | |
619 | } | |
620 | ||
621 | while ((mntent = getmntent(file))) { | |
622 | if (strcmp(mntent->mnt_type, "cgroup")) | |
623 | continue; | |
624 | if (!mount_has_subsystem(mntent)) | |
625 | continue; | |
626 | ret = snprintf(path, MAXPATHLEN, "%s/%s/tasks", | |
627 | mntent->mnt_dir, cgpath); | |
628 | if (ret < 0 || ret >= MAXPATHLEN) { | |
629 | ERROR("entering cgroup"); | |
630 | goto out; | |
631 | } | |
632 | fout = fopen(path, "w"); | |
633 | if (!fout) { | |
634 | ERROR("entering cgroup"); | |
635 | goto out; | |
636 | } | |
637 | fprintf(fout, "%d\n", (int)pid); | |
638 | fclose(fout); | |
639 | } | |
640 | retv = 0; | |
641 | ||
642 | out: | |
643 | endmntent(file); | |
644 | return retv; | |
645 | } | |
646 | ||
647 | int recursive_rmdir(char *dirname) | |
648 | { | |
649 | struct dirent dirent, *direntp; | |
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 | ||
660 | while (!readdir_r(dir, &dirent, &direntp)) { | |
661 | struct stat mystat; | |
662 | int rc; | |
663 | ||
664 | if (!direntp) | |
665 | break; | |
666 | ||
667 | if (!strcmp(direntp->d_name, ".") || | |
668 | !strcmp(direntp->d_name, "..")) | |
669 | continue; | |
670 | ||
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 | } | |
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 | } | |
691 | ||
692 | static int lxc_one_cgroup_destroy(struct mntent *mntent, const char *cgpath) | |
693 | { | |
694 | char cgname[MAXPATHLEN]; | |
695 | char *cgmnt = mntent->mnt_dir; | |
696 | int rc; | |
697 | ||
698 | rc = snprintf(cgname, MAXPATHLEN, "%s/%s", cgmnt, cgpath); | |
699 | if (rc < 0 || rc >= MAXPATHLEN) { | |
700 | ERROR("name too long"); | |
701 | return -1; | |
702 | } | |
703 | DEBUG("destroying %s\n", cgname); | |
704 | if (recursive_rmdir(cgname)) { | |
705 | SYSERROR("failed to remove cgroup '%s'", cgname); | |
706 | return -1; | |
707 | } | |
708 | ||
709 | DEBUG("'%s' unlinked", cgname); | |
710 | ||
711 | return 0; | |
712 | } | |
713 | ||
714 | /* | |
715 | * for each mounted cgroup, destroy the cgroup for the container | |
716 | */ | |
717 | int lxc_cgroup_destroy(const char *cgpath) | |
718 | { | |
719 | struct mntent *mntent; | |
720 | FILE *file = NULL; | |
721 | int err, retv = 0; | |
722 | ||
723 | file = setmntent(MTAB, "r"); | |
724 | if (!file) { | |
725 | SYSERROR("failed to open %s", MTAB); | |
726 | return -1; | |
727 | } | |
728 | ||
729 | while ((mntent = getmntent(file))) { | |
730 | if (strcmp(mntent->mnt_type, "cgroup")) | |
731 | continue; | |
732 | if (!mount_has_subsystem(mntent)) | |
733 | continue; | |
734 | ||
735 | err = lxc_one_cgroup_destroy(mntent, cgpath); | |
736 | if (err) // keep trying to clean up the others | |
737 | retv = -1; | |
738 | } | |
739 | ||
740 | endmntent(file); | |
741 | return retv; | |
742 | } | |
743 | ||
744 | int lxc_cgroup_attach(pid_t pid, const char *name, const char *lxcpath) | |
745 | { | |
746 | const char *dirpath; | |
747 | ||
748 | if (lxc_get_cgpath(&dirpath, NULL, name, lxcpath) < 0) { | |
749 | ERROR("Error getting cgroup for container %s: %s", lxcpath, name); | |
750 | return -1; | |
751 | } | |
752 | INFO("joining pid %d to cgroup %s", pid, dirpath); | |
753 | ||
754 | return lxc_cgroup_enter(dirpath, pid); | |
755 | } |