~serge-hallyn/ubuntu/quantal/lxc/lxc-fixapi

« back to all changes in this revision

Viewing changes to .pc/0016-nested-cgroups.patch/src/lxc/cgroup.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2012-04-26 15:18:35 UTC
  • mfrom: (3.1.41 sid)
  • Revision ID: package-import@ubuntu.com-20120426151835-3vz6kb4m90gb26js
Tags: 0.8.0~rc1-4ubuntu1
* Merge from unstable.  Remaining changes:
  - control:
    - update maintainer
    - Build-Depends: add dh-apparmor and libapparmor-dev
    - lxc Depends: add bridge-utils, dnsmasq-base, iptables, rsync
    - lxc Recommends: add cgroup-lite | cgroup-bin, openssl
    - lxc Suggests: add btrfs-tools, lvm2, qemu-user-static
    - lxc Conflicts: remove (cgroup-bin)
  - Add lxc-start-ephemeral and lxc-wait to debian/local
  - apparmor:
    - add lxc.apparmor, lxc-containers.apparmor,
      lxc-default.apparmor, and new lxc.apparmor.in
  - add debian/lxc.conf (default container creation config file)
  - debian/lxc.install.in:
    * add lxc-start-ephemeral
    * add debian/lxc.conf
    * skip lxc-debconf*
    * skip lxc-ls (Use upstream's)
  - debian/lxc*.install.in: use '*', not @DEB_HOST_MULTIARCH@
  - Use our own completely different lxc.postinst and lxc.postrm
  - remove lxc.templates
  - debian/rules:
    * add DEB_DH_INSTALLINIT_ARGS = --upstart-only
    * don't do debconf stuff
    * add debian/*.apparmor.in to files processed under
      override_dh_auto_clean
    * don't comment out ubuntu or busybox templates
    * do apparmor stuff and install our own lxc-wait under override_dh_install
    * install our upstart scripts in override_dh_installinit
  - add lxc.default, lxc.lxc-net.upstart, lxc.upstart under
    debian/

* patches kept:
  - 0013-lxc-create-use-default-config.patch (needed manual rebase)
  - 0030-ubuntu-template-fail.patch
  - 0031-ubuntu-template-resolvconf.patch
  - 0044-lxc-destroy-rm-autos
  - debian/patches/0045-fix-other-templates
  - debian/patches/0046-lxc-clone-change-hwaddr
  - debian/patches/0047-bindhome-check-shell
  - debian/patches/0049-ubuntu-template-sudo-and-cleanup
  - debian/patches/0050-clone-lvm-sizes
  - debian/patches/0052-ubuntu-bind-user-conflict
  - debian/patches/0053-lxc-start-pin-rootfs
  - debian/patches/0054-ubuntu-debug
  - debian/patches/0055-ubuntu-handle-badgrp
  - debian/patches/0056-dont-watch-utmp
  - debian/patches/0057-update-manpages
  - debian/patches/0058-fixup-ubuntu-cloud
  - debian/patches/0059-reenable-daily-cloudimg
  - debian/patches/0060-lxc-shutdown
  - debian/patches/0061-lxc-start-apparmor
  - debian/patches/0062-templates-relative-paths
  - debian/patches/0063-check-apparmor-enabled
  - debian/patches/0064-apparmor-mount-proc
  - debian/patches/0065-fix-bindhome-relpath
  - debian/patches/0066-confile-typo
  - debian/patches/0067-templates-lxc-profile
  - debian/patches/0068-fix-lxc-config-layout 
  - debian/patches/0069-ubuntu-cloud-fix
  - debian/patches/0070-templates-rmdir-dev-shm
  - debian/patches/0071-ubuntu-cloud-fix-image-extraction
  - debian/patches/0072-lxc-shutdown-help
  - debian/patches/0073-lxc-destroy-waits-before-destroy
  - mark all patches which have been forwarded as such, refresh all
* 0074-lxc-execute-find-init: lxc-init had moved.  Introduce a function in
  lxc-execute to go find it.  Otherwise lxc-execute for any older releases
  will fail.
* 0075-lxc-ls-bash: lxc-ls needs bash, not sh
* add debian/lxc.apparmor.in so DEB_HOST_MULTIARCH can be expanded
* 0076-fix-sprintfs:  - check return values for all sprintfs and snprintfs
  which could overflow (LP: #988918)
* 0077-execute-without-rootfs: let lxc-execute succeed with no rootfs
  (LP: #981955)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * lxc: linux Container library
3
 
 *
4
 
 * (C) Copyright IBM Corp. 2007, 2008
5
 
 *
6
 
 * Authors:
7
 
 * Daniel Lezcano <dlezcano at fr.ibm.com>
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 <mntent.h>
29
 
#include <unistd.h>
30
 
#include <string.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
 
 
42
 
#include <lxc/log.h>
43
 
#include <lxc/cgroup.h>
44
 
#include <lxc/start.h>
45
 
 
46
 
lxc_log_define(lxc_cgroup, lxc);
47
 
 
48
 
#define MTAB "/proc/mounts"
49
 
 
50
 
enum {
51
 
        CGROUP_NS_CGROUP = 1,
52
 
        CGROUP_CLONE_CHILDREN,
53
 
};
54
 
 
55
 
static int get_cgroup_mount(const char *subsystem, char *mnt)
56
 
{
57
 
        struct mntent *mntent;
58
 
        FILE *file = NULL;
59
 
 
60
 
        file = setmntent(MTAB, "r");
61
 
        if (!file) {
62
 
                SYSERROR("failed to open %s", MTAB);
63
 
                return -1;
64
 
        }
65
 
 
66
 
        while ((mntent = getmntent(file))) {
67
 
 
68
 
                if (strcmp(mntent->mnt_type, "cgroup"))
69
 
                        continue;
70
 
                if (!subsystem || hasmntopt(mntent, subsystem)) {
71
 
                        strcpy(mnt, mntent->mnt_dir);
72
 
                        fclose(file);
73
 
                        DEBUG("using cgroup mounted at '%s'", mnt);
74
 
                        return 0;
75
 
                }
76
 
        };
77
 
 
78
 
        DEBUG("Failed to find cgroup for %s\n", subsystem ? subsystem : "(NULL)");
79
 
 
80
 
        fclose(file);
81
 
 
82
 
        return -1;
83
 
}
84
 
 
85
 
int lxc_ns_is_mounted(void)
86
 
{
87
 
        static char        buf[MAXPATHLEN];
88
 
 
89
 
        return (get_cgroup_mount("ns", buf) == 0);
90
 
}
91
 
 
92
 
static int get_cgroup_flags(struct mntent *mntent)
93
 
{
94
 
        int flags = 0;
95
 
 
96
 
 
97
 
        if (hasmntopt(mntent, "ns"))
98
 
                flags |= CGROUP_NS_CGROUP;
99
 
 
100
 
        if (hasmntopt(mntent, "clone_children"))
101
 
                flags |= CGROUP_CLONE_CHILDREN;
102
 
 
103
 
        DEBUG("cgroup %s has flags 0x%x", mntent->mnt_dir, flags);
104
 
        return flags;
105
 
}
106
 
 
107
 
static int cgroup_rename_nsgroup(const char *mnt, const char *name, pid_t pid)
108
 
{
109
 
        char oldname[MAXPATHLEN];
110
 
 
111
 
        snprintf(oldname, MAXPATHLEN, "%s/%d", mnt, pid);
112
 
 
113
 
        if (rename(oldname, name)) {
114
 
                SYSERROR("failed to rename cgroup %s->%s", oldname, name);
115
 
                return -1;
116
 
        }
117
 
 
118
 
        DEBUG("'%s' renamed to '%s'", oldname, name);
119
 
 
120
 
        return 0;
121
 
}
122
 
 
123
 
static int cgroup_enable_clone_children(const char *path)
124
 
{
125
 
        FILE *f;
126
 
        int ret = 0;
127
 
 
128
 
        f = fopen(path, "w");
129
 
        if (!f) {
130
 
                SYSERROR("failed to open '%s'", path);
131
 
                return -1;
132
 
        }
133
 
 
134
 
        if (fprintf(f, "1") < 1) {
135
 
                ERROR("failed to write flag to '%s'", path);
136
 
                ret = -1;
137
 
        }
138
 
 
139
 
        fclose(f);
140
 
 
141
 
        return ret;
142
 
}
143
 
 
144
 
static int cgroup_attach(const char *path, pid_t pid)
145
 
{
146
 
        FILE *f;
147
 
        char tasks[MAXPATHLEN];
148
 
        int ret = 0;
149
 
 
150
 
        snprintf(tasks, MAXPATHLEN, "%s/tasks", path);
151
 
 
152
 
        f = fopen(tasks, "w");
153
 
        if (!f) {
154
 
                SYSERROR("failed to open '%s'", tasks);
155
 
                return -1;
156
 
        }
157
 
 
158
 
        if (fprintf(f, "%d", pid) <= 0) {
159
 
                SYSERROR("failed to write pid '%d' to '%s'", pid, tasks);
160
 
                ret = -1;
161
 
        }
162
 
 
163
 
        fclose(f);
164
 
 
165
 
        return ret;
166
 
}
167
 
 
168
 
/*
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.
172
 
 */
173
 
static int lxc_one_cgroup_create(const char *name,
174
 
                                 struct mntent *mntent, pid_t pid)
175
 
{
176
 
        char cgname[MAXPATHLEN];
177
 
        char clonechild[MAXPATHLEN];
178
 
        int flags;
179
 
 
180
 
        snprintf(cgname, MAXPATHLEN, "%s/%s", mntent->mnt_dir, name);
181
 
 
182
 
        /*
183
 
         * There is a previous cgroup, assume it is empty,
184
 
         * otherwise that fails
185
 
         */
186
 
        if (!access(cgname, F_OK) && rmdir(cgname)) {
187
 
                SYSERROR("failed to remove previous cgroup '%s'", cgname);
188
 
                return -1;
189
 
        }
190
 
 
191
 
        flags = get_cgroup_flags(mntent);
192
 
 
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);
197
 
        }
198
 
 
199
 
        snprintf(clonechild, MAXPATHLEN, "%s/cgroup.clone_children",
200
 
                 mntent->mnt_dir);
201
 
 
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
205
 
         */
206
 
        if (access(clonechild, F_OK)) {
207
 
                ERROR("no ns_cgroup option specified");
208
 
                return -1;
209
 
        }
210
 
 
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");
214
 
                return -1;
215
 
        }
216
 
 
217
 
        /* Let's create the cgroup */
218
 
        if (mkdir(cgname, 0700)) {
219
 
                SYSERROR("failed to create '%s' directory", cgname);
220
 
                return -1;
221
 
        }
222
 
 
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);
226
 
                rmdir(cgname);
227
 
                return -1;
228
 
        }
229
 
 
230
 
        INFO("created cgroup '%s'", cgname);
231
 
 
232
 
        return 0;
233
 
}
234
 
 
235
 
/*
236
 
 * for each mounted cgroup, create a cgroup for the container
237
 
 */
238
 
int lxc_cgroup_create(const char *name, pid_t pid)
239
 
{
240
 
        struct mntent *mntent;
241
 
        FILE *file = NULL;
242
 
        int err = -1;
243
 
 
244
 
        file = setmntent(MTAB, "r");
245
 
        if (!file) {
246
 
                SYSERROR("failed to open %s", MTAB);
247
 
                return -1;
248
 
        }
249
 
 
250
 
        while ((mntent = getmntent(file))) {
251
 
 
252
 
                DEBUG("checking '%s' (%s)", mntent->mnt_dir, mntent->mnt_type);
253
 
 
254
 
                if (!strcmp(mntent->mnt_type, "cgroup")) {
255
 
 
256
 
                        INFO("found cgroup mounted at '%s'", mntent->mnt_dir);
257
 
                        err = lxc_one_cgroup_create(name, mntent, pid);
258
 
                        if (err)
259
 
                                goto out;
260
 
                }
261
 
        };
262
 
 
263
 
out:
264
 
        endmntent(file);
265
 
        return err;
266
 
}
267
 
 
268
 
 
269
 
int lxc_one_cgroup_destroy(const char *cgmnt, const char *name)
270
 
{
271
 
        char cgname[MAXPATHLEN];
272
 
 
273
 
        snprintf(cgname, MAXPATHLEN, "%s/%s", cgmnt, name);
274
 
        if (rmdir(cgname)) {
275
 
                SYSERROR("failed to remove cgroup '%s'", cgname);
276
 
                return -1;
277
 
        }
278
 
 
279
 
        DEBUG("'%s' unlinked", cgname);
280
 
 
281
 
        return 0;
282
 
}
283
 
 
284
 
/*
285
 
 * for each mounted cgroup, destroy the cgroup for the container
286
 
 */
287
 
int lxc_cgroup_destroy(const char *name)
288
 
{
289
 
        struct mntent *mntent;
290
 
        FILE *file = NULL;
291
 
        int ret, err = -1;
292
 
 
293
 
        file = setmntent(MTAB, "r");
294
 
        if (!file) {
295
 
                SYSERROR("failed to open %s", MTAB);
296
 
                return -1;
297
 
        }
298
 
 
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);
303
 
                        if (ret) {
304
 
                                fclose(file);
305
 
                                return ret;
306
 
                        }
307
 
                        err = 0;
308
 
                }
309
 
        }
310
 
 
311
 
        fclose(file);
312
 
 
313
 
        return err;
314
 
}
315
 
/*
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)
319
 
 */
320
 
int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name)
321
 
{
322
 
        static char        buf[MAXPATHLEN];
323
 
        static char        retbuf[MAXPATHLEN];
324
 
 
325
 
        /* what lxc_cgroup_set calls subsystem is actually the filename, i.e.
326
 
           'devices.allow'.  So for our purposee we trim it */
327
 
        if (subsystem) {
328
 
                snprintf(retbuf, MAXPATHLEN, "%s", subsystem);
329
 
                char *s = index(retbuf, '.');
330
 
                if (s)
331
 
                        *s = '\0';
332
 
                DEBUG("%s: called for subsys %s name %s\n", __func__, retbuf, name);
333
 
        }
334
 
        if (get_cgroup_mount(subsystem ? retbuf : NULL, buf)) {
335
 
                ERROR("cgroup is not mounted");
336
 
                return -1;
337
 
        }
338
 
 
339
 
        snprintf(retbuf, MAXPATHLEN, "%s/%s", buf, name);
340
 
 
341
 
        DEBUG("%s: returning %s for subsystem %s", __func__, retbuf, subsystem);
342
 
 
343
 
        *path = retbuf;
344
 
        return 0;
345
 
}
346
 
 
347
 
int lxc_cgroup_set(const char *name, const char *filename, const char *value)
348
 
{
349
 
        int fd, ret;
350
 
        char *dirpath;
351
 
        char path[MAXPATHLEN];
352
 
 
353
 
        ret = lxc_cgroup_path_get(&dirpath, filename, name);
354
 
        if (ret)
355
 
                return -1;
356
 
 
357
 
        snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename);
358
 
 
359
 
        fd = open(path, O_WRONLY);
360
 
        if (fd < 0) {
361
 
                ERROR("open %s : %s", path, strerror(errno));
362
 
                return -1;
363
 
        }
364
 
 
365
 
        ret = write(fd, value, strlen(value));
366
 
        if (ret < 0) {
367
 
                ERROR("write %s : %s", path, strerror(errno));
368
 
                goto out;
369
 
        }
370
 
 
371
 
        ret = 0;
372
 
out:
373
 
        close(fd);
374
 
        return ret;
375
 
}
376
 
 
377
 
int lxc_cgroup_get(const char *name, const char *filename,
378
 
                   char *value, size_t len)
379
 
{
380
 
        int fd, ret = -1;
381
 
        char *dirpath;
382
 
        char path[MAXPATHLEN];
383
 
 
384
 
        ret = lxc_cgroup_path_get(&dirpath, filename, name);
385
 
        if (ret)
386
 
                return -1;
387
 
 
388
 
        snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename);
389
 
 
390
 
        fd = open(path, O_RDONLY);
391
 
        if (fd < 0) {
392
 
                ERROR("open %s : %s", path, strerror(errno));
393
 
                return -1;
394
 
        }
395
 
 
396
 
        ret = read(fd, value, len);
397
 
        if (ret < 0)
398
 
                ERROR("read %s : %s", path, strerror(errno));
399
 
 
400
 
        close(fd);
401
 
        return ret;
402
 
}
403
 
 
404
 
int lxc_cgroup_nrtasks(const char *name)
405
 
{
406
 
        char *dpath;
407
 
        char path[MAXPATHLEN];
408
 
        int pid, ret, count = 0;
409
 
        FILE *file;
410
 
 
411
 
        ret = lxc_cgroup_path_get(&dpath, NULL, name);
412
 
        if (ret)
413
 
                return -1;
414
 
 
415
 
        snprintf(path, MAXPATHLEN, "%s/tasks", dpath);
416
 
 
417
 
        file = fopen(path, "r");
418
 
        if (!file) {
419
 
                SYSERROR("fopen '%s' failed", path);
420
 
                return -1;
421
 
        }
422
 
 
423
 
        while (fscanf(file, "%d", &pid) != EOF)
424
 
                count++;
425
 
 
426
 
        fclose(file);
427
 
 
428
 
        return count;
429
 
}