2
* lxc: linux Container library
4
* (C) Copyright IBM Corp. 2007, 2008
7
* Daniel Lezcano <dlezcano at fr.ibm.com>
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.
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.
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
32
#include <sys/types.h>
34
#include <sys/param.h>
35
#include <sys/inotify.h>
36
#include <netinet/in.h>
43
#include <lxc/cgroup.h>
44
#include <lxc/start.h>
46
lxc_log_define(lxc_cgroup, lxc);
48
#define MTAB "/proc/mounts"
52
CGROUP_CLONE_CHILDREN,
55
static int get_cgroup_mount(const char *subsystem, char *mnt)
57
struct mntent *mntent;
60
file = setmntent(MTAB, "r");
62
SYSERROR("failed to open %s", MTAB);
66
while ((mntent = getmntent(file))) {
68
if (strcmp(mntent->mnt_type, "cgroup"))
70
if (!subsystem || hasmntopt(mntent, subsystem)) {
71
strcpy(mnt, mntent->mnt_dir);
73
DEBUG("using cgroup mounted at '%s'", mnt);
78
DEBUG("Failed to find cgroup for %s\n", subsystem ? subsystem : "(NULL)");
85
int lxc_ns_is_mounted(void)
87
static char buf[MAXPATHLEN];
89
return (get_cgroup_mount("ns", buf) == 0);
92
static int get_cgroup_flags(struct mntent *mntent)
97
if (hasmntopt(mntent, "ns"))
98
flags |= CGROUP_NS_CGROUP;
100
if (hasmntopt(mntent, "clone_children"))
101
flags |= CGROUP_CLONE_CHILDREN;
103
DEBUG("cgroup %s has flags 0x%x", mntent->mnt_dir, flags);
107
static int cgroup_rename_nsgroup(const char *mnt, const char *name, pid_t pid)
109
char oldname[MAXPATHLEN];
111
snprintf(oldname, MAXPATHLEN, "%s/%d", mnt, pid);
113
if (rename(oldname, name)) {
114
SYSERROR("failed to rename cgroup %s->%s", oldname, name);
118
DEBUG("'%s' renamed to '%s'", oldname, name);
123
static int cgroup_enable_clone_children(const char *path)
128
f = fopen(path, "w");
130
SYSERROR("failed to open '%s'", path);
134
if (fprintf(f, "1") < 1) {
135
ERROR("failed to write flag to '%s'", path);
144
static int cgroup_attach(const char *path, pid_t pid)
147
char tasks[MAXPATHLEN];
150
snprintf(tasks, MAXPATHLEN, "%s/tasks", path);
152
f = fopen(tasks, "w");
154
SYSERROR("failed to open '%s'", tasks);
158
if (fprintf(f, "%d", pid) <= 0) {
159
SYSERROR("failed to write pid '%d' to '%s'", pid, tasks);
169
* create a cgroup for the container in a particular subsystem.
170
* XXX TODO we will of course want to use cgroup_path{subsystem}/lxc/name,
171
* not just cgroup_path{subsystem}/name.
173
static int lxc_one_cgroup_create(const char *name,
174
struct mntent *mntent, pid_t pid)
176
char cgname[MAXPATHLEN];
177
char clonechild[MAXPATHLEN];
180
snprintf(cgname, MAXPATHLEN, "%s/%s", mntent->mnt_dir, name);
183
* There is a previous cgroup, assume it is empty,
184
* otherwise that fails
186
if (!access(cgname, F_OK) && rmdir(cgname)) {
187
SYSERROR("failed to remove previous cgroup '%s'", cgname);
191
flags = get_cgroup_flags(mntent);
193
/* We have the deprecated ns_cgroup subsystem */
194
if (flags & CGROUP_NS_CGROUP) {
195
WARN("using deprecated ns_cgroup");
196
return cgroup_rename_nsgroup(mntent->mnt_dir, cgname, pid);
199
snprintf(clonechild, MAXPATHLEN, "%s/cgroup.clone_children",
202
/* we check if the kernel has clone_children, at this point if there
203
* no clone_children neither ns_cgroup, that means the cgroup is mounted
204
* without the ns_cgroup and it has not the compatibility flag
206
if (access(clonechild, F_OK)) {
207
ERROR("no ns_cgroup option specified");
211
/* we enable the clone_children flag of the cgroup */
212
if (cgroup_enable_clone_children(clonechild)) {
213
SYSERROR("failed to enable 'clone_children flag");
217
/* Let's create the cgroup */
218
if (mkdir(cgname, 0700)) {
219
SYSERROR("failed to create '%s' directory", cgname);
223
/* Let's add the pid to the 'tasks' file */
224
if (cgroup_attach(cgname, pid)) {
225
SYSERROR("failed to attach pid '%d' to '%s'", pid, cgname);
230
INFO("created cgroup '%s'", cgname);
236
* for each mounted cgroup, create a cgroup for the container
238
int lxc_cgroup_create(const char *name, pid_t pid)
240
struct mntent *mntent;
244
file = setmntent(MTAB, "r");
246
SYSERROR("failed to open %s", MTAB);
250
while ((mntent = getmntent(file))) {
252
DEBUG("checking '%s' (%s)", mntent->mnt_dir, mntent->mnt_type);
254
if (!strcmp(mntent->mnt_type, "cgroup")) {
256
INFO("found cgroup mounted at '%s'", mntent->mnt_dir);
257
err = lxc_one_cgroup_create(name, mntent, pid);
269
int lxc_one_cgroup_destroy(const char *cgmnt, const char *name)
271
char cgname[MAXPATHLEN];
273
snprintf(cgname, MAXPATHLEN, "%s/%s", cgmnt, name);
275
SYSERROR("failed to remove cgroup '%s'", cgname);
279
DEBUG("'%s' unlinked", cgname);
285
* for each mounted cgroup, destroy the cgroup for the container
287
int lxc_cgroup_destroy(const char *name)
289
struct mntent *mntent;
293
file = setmntent(MTAB, "r");
295
SYSERROR("failed to open %s", MTAB);
299
while ((mntent = getmntent(file))) {
300
if (!strcmp(mntent->mnt_type, "cgroup")) {
301
DEBUG("destroying %s %s\n", mntent->mnt_dir, name);
302
ret = lxc_one_cgroup_destroy(mntent->mnt_dir, name);
316
* lxc_cgroup_path_get: put into *path the pathname for
317
* %subsystem and cgroup %name. If %subsystem is NULL, then
318
* the first mounted cgroup will be used (for nr_tasks)
320
int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name)
322
static char buf[MAXPATHLEN];
323
static char retbuf[MAXPATHLEN];
325
/* what lxc_cgroup_set calls subsystem is actually the filename, i.e.
326
'devices.allow'. So for our purposee we trim it */
328
snprintf(retbuf, MAXPATHLEN, "%s", subsystem);
329
char *s = index(retbuf, '.');
332
DEBUG("%s: called for subsys %s name %s\n", __func__, retbuf, name);
334
if (get_cgroup_mount(subsystem ? retbuf : NULL, buf)) {
335
ERROR("cgroup is not mounted");
339
snprintf(retbuf, MAXPATHLEN, "%s/%s", buf, name);
341
DEBUG("%s: returning %s for subsystem %s", __func__, retbuf, subsystem);
347
int lxc_cgroup_set(const char *name, const char *filename, const char *value)
351
char path[MAXPATHLEN];
353
ret = lxc_cgroup_path_get(&dirpath, filename, name);
357
snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename);
359
fd = open(path, O_WRONLY);
361
ERROR("open %s : %s", path, strerror(errno));
365
ret = write(fd, value, strlen(value));
367
ERROR("write %s : %s", path, strerror(errno));
377
int lxc_cgroup_get(const char *name, const char *filename,
378
char *value, size_t len)
382
char path[MAXPATHLEN];
384
ret = lxc_cgroup_path_get(&dirpath, filename, name);
388
snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename);
390
fd = open(path, O_RDONLY);
392
ERROR("open %s : %s", path, strerror(errno));
396
ret = read(fd, value, len);
398
ERROR("read %s : %s", path, strerror(errno));
404
int lxc_cgroup_nrtasks(const char *name)
407
char path[MAXPATHLEN];
408
int pid, ret, count = 0;
411
ret = lxc_cgroup_path_get(&dpath, NULL, name);
415
snprintf(path, MAXPATHLEN, "%s/tasks", dpath);
417
file = fopen(path, "r");
419
SYSERROR("fopen '%s' failed", path);
423
while (fscanf(file, "%d", &pid) != EOF)