~kampka/ubuntu/quantal/lxc/upstart-instance

« back to all changes in this revision

Viewing changes to .pc/0201-fix-mkdir-race/src/lxc/cgroup.c

  • Committer: Package Import Robot
  • Author(s): Stéphane Graber, Serge Hallyn, Stéphane Graber
  • Date: 2012-08-25 12:44:17 UTC
  • Revision ID: package-import@ubuntu.com-20120825124417-yn1xu1x10fi7o972
Tags: 0.8.0~rc1-4ubuntu29
[ Serge Hallyn ]
* fix lxcapi_start to not return true when it container failed to start.
* 0201-fix-mkdir-race: don't raise error if mkdir fails with EEXIST.
* 0202-make-api-start-reliable: have daemonized start through the api
  wait until the container is RUNNING before returning true.  If a 5
  second timeout is hit before the container is RUNNING, return false.

[ Stéphane Graber ]
* python-lxc: in get_ips() if timeout is 1 don't wait one second before
  returning.
* python-lxc: Add import time warning that the API isn't yet stable and
  so may change at any point in the future.

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 <dirent.h>
 
32
#include <fcntl.h>
 
33
#include <sys/types.h>
 
34
#include <sys/stat.h>
 
35
#include <sys/param.h>
 
36
#include <sys/inotify.h>
 
37
#include <netinet/in.h>
 
38
#include <net/if.h>
 
39
 
 
40
#include "error.h"
 
41
#include "config.h"
 
42
 
 
43
#include <lxc/log.h>
 
44
#include <lxc/cgroup.h>
 
45
#include <lxc/start.h>
 
46
 
 
47
lxc_log_define(lxc_cgroup, lxc);
 
48
 
 
49
#define MTAB "/proc/mounts"
 
50
 
 
51
enum {
 
52
        CGROUP_NS_CGROUP = 1,
 
53
        CGROUP_CLONE_CHILDREN,
 
54
};
 
55
 
 
56
static char *hasmntopt_multiple(struct mntent *mntent, const char *options)
 
57
{
 
58
        const char *ptr = options;
 
59
        const char *ptr2 = strchr(options, ',');
 
60
        char *result;
 
61
 
 
62
        while (ptr2 != NULL) {
 
63
                char *option = strndup(ptr, ptr2 - ptr);
 
64
                if (!option) {
 
65
                        SYSERROR("Temporary memory allocation error");
 
66
                        return NULL;
 
67
                }
 
68
 
 
69
                result = hasmntopt(mntent, option);
 
70
                free(option);
 
71
 
 
72
                if (!result) {
 
73
                        return NULL;
 
74
                }
 
75
 
 
76
                ptr = ptr2 + 1;
 
77
                ptr2 = strchr(ptr, ',');
 
78
        }
 
79
 
 
80
        /* for multiple mount options, the return value is basically NULL
 
81
         * or non-NULL, so this should suffice for our purposes */
 
82
        return hasmntopt(mntent, ptr);
 
83
}
 
84
 
 
85
/*
 
86
 * get_init_cgroup: get the cgroup init is in.
 
87
 *  dsg: preallocated buffer to put the output in
 
88
 *  subsystem: the exact cgroup subsystem to look up
 
89
 *  mntent: a mntent (from getmntent) whose mntopts contains the
 
90
 *          subsystem to look up.
 
91
 *
 
92
 * subsystem and mntent can both be NULL, in which case we return
 
93
 * the first entry in /proc/1/cgroup.
 
94
 *
 
95
 * Returns a pointer to the answer, which may be "".
 
96
 */
 
97
static char *get_init_cgroup(const char *subsystem, struct mntent *mntent,
 
98
                             char *dsg)
 
99
{
 
100
        FILE *f;
 
101
        char *c, *c2;
 
102
        char line[MAXPATHLEN];
 
103
 
 
104
        *dsg = '\0';
 
105
        f = fopen("/proc/1/cgroup", "r");
 
106
        if (!f)
 
107
                return dsg;
 
108
 
 
109
        while (fgets(line, MAXPATHLEN, f)) {
 
110
                c = index(line, ':');
 
111
                if (!c)
 
112
                        continue;
 
113
                c++;
 
114
                c2 = index(c, ':');
 
115
                if (!c2)
 
116
                        continue;
 
117
                *c2 = '\0';
 
118
                c2++;
 
119
                if (!subsystem && !mntent)
 
120
                        goto good;
 
121
                if (subsystem && strcmp(c, subsystem) != 0)
 
122
                        continue;
 
123
                if (mntent && !hasmntopt(mntent, c))
 
124
                        continue;
 
125
good:
 
126
                DEBUG("get_init_cgroup: found init cgroup for subsys %s at %s\n",
 
127
                        subsystem, c2);
 
128
                strncpy(dsg, c2, MAXPATHLEN);
 
129
                c = &dsg[strlen(dsg)-1];
 
130
                if (*c == '\n')
 
131
                        *c = '\0';
 
132
                goto found;
 
133
        }
 
134
 
 
135
found:
 
136
        fclose(f);
 
137
        return dsg;
 
138
}
 
139
 
 
140
static int get_cgroup_mount(const char *subsystem, char *mnt)
 
141
{
 
142
        struct mntent *mntent;
 
143
        char initcgroup[MAXPATHLEN];
 
144
        FILE *file = NULL;
 
145
 
 
146
        file = setmntent(MTAB, "r");
 
147
        if (!file) {
 
148
                SYSERROR("failed to open %s", MTAB);
 
149
                return -1;
 
150
        }
 
151
 
 
152
        while ((mntent = getmntent(file))) {
 
153
 
 
154
                if (strcmp(mntent->mnt_type, "cgroup"))
 
155
                        continue;
 
156
                if (!subsystem || hasmntopt_multiple(mntent, subsystem)) {
 
157
                        int ret;
 
158
                        ret = snprintf(mnt, MAXPATHLEN, "%s%s/lxc",
 
159
                                       mntent->mnt_dir,
 
160
                                       get_init_cgroup(subsystem, NULL,
 
161
                                                       initcgroup));
 
162
                        if (ret < 0 || ret >= MAXPATHLEN)
 
163
                                goto fail;
 
164
                        fclose(file);
 
165
                        DEBUG("using cgroup mounted at '%s'", mnt);
 
166
                        return 0;
 
167
                }
 
168
        };
 
169
 
 
170
fail:
 
171
        DEBUG("Failed to find cgroup for %s\n",
 
172
              subsystem ? subsystem : "(NULL)");
 
173
 
 
174
        fclose(file);
 
175
 
 
176
        return -1;
 
177
}
 
178
 
 
179
int lxc_ns_is_mounted(void)
 
180
{
 
181
        static char        buf[MAXPATHLEN];
 
182
 
 
183
        return (get_cgroup_mount("ns", buf) == 0);
 
184
}
 
185
 
 
186
static int get_cgroup_flags(struct mntent *mntent)
 
187
{
 
188
        int flags = 0;
 
189
 
 
190
 
 
191
        if (hasmntopt(mntent, "ns"))
 
192
                flags |= CGROUP_NS_CGROUP;
 
193
 
 
194
        if (hasmntopt(mntent, "clone_children"))
 
195
                flags |= CGROUP_CLONE_CHILDREN;
 
196
 
 
197
        DEBUG("cgroup %s has flags 0x%x", mntent->mnt_dir, flags);
 
198
        return flags;
 
199
}
 
200
 
 
201
static int cgroup_rename_nsgroup(const char *mnt, const char *name, pid_t pid)
 
202
{
 
203
        char oldname[MAXPATHLEN];
 
204
        int ret;
 
205
 
 
206
        ret = snprintf(oldname, MAXPATHLEN, "%s/%d", mnt, pid);
 
207
        if (ret < 0 || ret >= MAXPATHLEN) {
 
208
                ERROR("Name too long");
 
209
                return -1;
 
210
        }
 
211
 
 
212
        if (rename(oldname, name)) {
 
213
                SYSERROR("failed to rename cgroup %s->%s", oldname, name);
 
214
                return -1;
 
215
        }
 
216
 
 
217
        DEBUG("'%s' renamed to '%s'", oldname, name);
 
218
 
 
219
        return 0;
 
220
}
 
221
 
 
222
static int cgroup_enable_clone_children(const char *path)
 
223
{
 
224
        FILE *f;
 
225
        int ret = 0;
 
226
 
 
227
        f = fopen(path, "w");
 
228
        if (!f) {
 
229
                SYSERROR("failed to open '%s'", path);
 
230
                return -1;
 
231
        }
 
232
 
 
233
        if (fprintf(f, "1") < 1) {
 
234
                ERROR("failed to write flag to '%s'", path);
 
235
                ret = -1;
 
236
        }
 
237
 
 
238
        fclose(f);
 
239
 
 
240
        return ret;
 
241
}
 
242
 
 
243
int lxc_cgroup_attach(const char *path, pid_t pid)
 
244
{
 
245
        FILE *f;
 
246
        char tasks[MAXPATHLEN];
 
247
        int ret = 0;
 
248
        int rc;
 
249
 
 
250
        rc = snprintf(tasks, MAXPATHLEN, "%s/tasks", path);
 
251
        if (rc < 0 || rc >= MAXPATHLEN) {
 
252
                ERROR("pathname too long");
 
253
                return -1;
 
254
        }
 
255
 
 
256
        f = fopen(tasks, "w");
 
257
        if (!f) {
 
258
                SYSERROR("failed to open '%s'", tasks);
 
259
                return -1;
 
260
        }
 
261
 
 
262
        if (fprintf(f, "%d", pid) <= 0) {
 
263
                SYSERROR("failed to write pid '%d' to '%s'", pid, tasks);
 
264
                ret = -1;
 
265
        }
 
266
 
 
267
        fclose(f);
 
268
 
 
269
        return ret;
 
270
}
 
271
 
 
272
/*
 
273
 * rename cgname, which is under cgparent, to a new name starting
 
274
 * with 'cgparent/dead'.  That way cgname can be reused.  Return
 
275
 * 0 on success, -1 on failure.
 
276
 */
 
277
int try_to_move_cgname(char *cgparent, char *cgname)
 
278
{
 
279
        char *newdir;
 
280
 
 
281
        /* tempnam problems don't matter here - cgroupfs will prevent
 
282
         * duplicates if we race, and we'll just fail at that (unlikely)
 
283
         * point
 
284
         */
 
285
 
 
286
        newdir = tempnam(cgparent, "dead");
 
287
        if (!newdir)
 
288
                return -1;
 
289
        if (rename(cgname, newdir))
 
290
                return -1;
 
291
        WARN("non-empty cgroup %s renamed to %s, please manually inspect it\n",
 
292
                cgname, newdir);
 
293
 
 
294
        return 0;
 
295
}
 
296
 
 
297
/*
 
298
 * create a cgroup for the container in a particular subsystem.
 
299
 */
 
300
static int lxc_one_cgroup_create(const char *name,
 
301
                                 struct mntent *mntent, pid_t pid)
 
302
{
 
303
        char cginit[MAXPATHLEN], cgname[MAXPATHLEN], cgparent[MAXPATHLEN];
 
304
        char clonechild[MAXPATHLEN];
 
305
        char initcgroup[MAXPATHLEN];
 
306
        int flags, ret;
 
307
 
 
308
        /* cgparent is the parent dir, /sys/fs/cgroup/<cgroup>/<init-cgroup>/lxc */
 
309
        /* (remember get_init_cgroup() returns a path starting with '/') */
 
310
        /* cgname is the full name,    /sys/fs/cgroup/</cgroup>/<init-cgroup>/lxc/name */
 
311
        ret = snprintf(cginit, MAXPATHLEN, "%s%s", mntent->mnt_dir,
 
312
                get_init_cgroup(NULL, mntent, initcgroup));
 
313
        if (ret < 0 || ret >= MAXPATHLEN) {
 
314
                SYSERROR("Failed creating pathname for init's cgroup (%d)\n", ret);
 
315
                return -1;
 
316
        }
 
317
 
 
318
        ret = snprintf(cgparent, MAXPATHLEN, "%s/lxc", cginit);
 
319
        if (ret < 0 || ret >= MAXPATHLEN) {
 
320
                SYSERROR("Failed creating pathname for cgroup parent (%d)\n", ret);
 
321
                return -1;
 
322
        }
 
323
        ret = snprintf(cgname, MAXPATHLEN, "%s/%s", cgparent, name);
 
324
        if (ret < 0 || ret >= MAXPATHLEN) {
 
325
                SYSERROR("Failed creating pathname for cgroup (%d)\n", ret);
 
326
                return -1;
 
327
        }
 
328
 
 
329
        flags = get_cgroup_flags(mntent);
 
330
 
 
331
        /* Do we have the deprecated ns_cgroup subsystem? */
 
332
        if (flags & CGROUP_NS_CGROUP) {
 
333
                WARN("using deprecated ns_cgroup");
 
334
                return cgroup_rename_nsgroup(cgparent, cgname, pid);
 
335
        }
 
336
 
 
337
        ret = snprintf(clonechild, MAXPATHLEN, "%s/cgroup.clone_children",
 
338
                       cginit);
 
339
        if (ret < 0 || ret >= MAXPATHLEN) {
 
340
                SYSERROR("Failed creating pathname for clone_children (%d)\n", ret);
 
341
                return -1;
 
342
        }
 
343
 
 
344
        /* we check if the kernel has clone_children, at this point if there
 
345
         * no clone_children neither ns_cgroup, that means the cgroup is mounted
 
346
         * without the ns_cgroup and it has not the compatibility flag
 
347
         */
 
348
        if (access(clonechild, F_OK)) {
 
349
                ERROR("no ns_cgroup option specified");
 
350
                return -1;
 
351
        }
 
352
 
 
353
        /* enable the clone_children flag of the cgroup */
 
354
        if (cgroup_enable_clone_children(clonechild)) {
 
355
                SYSERROR("failed to enable 'clone_children flag");
 
356
                return -1;
 
357
        }
 
358
 
 
359
        /* if /sys/fs/cgroup/<cgroup>/<init-cgroup>/lxc does not exist, create it */
 
360
        if (access(cgparent, F_OK) && mkdir(cgparent, 0755)) {
 
361
                SYSERROR("failed to create '%s' directory", cgparent);
 
362
                return -1;
 
363
        }
 
364
 
 
365
        /*
 
366
         * There is a previous cgroup.  Try to delete it.  If that fails
 
367
         * (i.e. it is not empty) try to move it out of the way.
 
368
         */
 
369
        if (!access(cgname, F_OK) && rmdir(cgname)) {
 
370
                if (try_to_move_cgname(cgparent, cgname)) {
 
371
                        SYSERROR("failed to remove previous cgroup '%s'", cgname);
 
372
                        return -1;
 
373
                }
 
374
        }
 
375
 
 
376
        /* Let's create the cgroup */
 
377
        if (mkdir(cgname, 0755)) {
 
378
                SYSERROR("failed to create '%s' directory", cgname);
 
379
                return -1;
 
380
        }
 
381
 
 
382
        /* Let's add the pid to the 'tasks' file */
 
383
        if (lxc_cgroup_attach(cgname, pid)) {
 
384
                SYSERROR("failed to attach pid '%d' to '%s'", pid, cgname);
 
385
                rmdir(cgname);
 
386
                return -1;
 
387
        }
 
388
 
 
389
        INFO("created cgroup '%s'", cgname);
 
390
 
 
391
        return 0;
 
392
}
 
393
 
 
394
/*
 
395
 * for each mounted cgroup, create a cgroup for the container
 
396
 */
 
397
int lxc_cgroup_create(const char *name, pid_t pid)
 
398
{
 
399
        struct mntent *mntent;
 
400
        FILE *file = NULL;
 
401
        int err = -1;
 
402
        int found = 0;
 
403
 
 
404
        file = setmntent(MTAB, "r");
 
405
        if (!file) {
 
406
                SYSERROR("failed to open %s", MTAB);
 
407
                return -1;
 
408
        }
 
409
 
 
410
        while ((mntent = getmntent(file))) {
 
411
 
 
412
                DEBUG("checking '%s' (%s)", mntent->mnt_dir, mntent->mnt_type);
 
413
 
 
414
                if (!strcmp(mntent->mnt_type, "cgroup")) {
 
415
 
 
416
                        INFO("[%d] found cgroup mounted at '%s',opts='%s'",
 
417
                             ++found, mntent->mnt_dir, mntent->mnt_opts);
 
418
 
 
419
                        err = lxc_one_cgroup_create(name, mntent, pid);
 
420
                        if (err)
 
421
                                goto out;
 
422
                }
 
423
        };
 
424
 
 
425
        if (!found)
 
426
                ERROR("No cgroup mounted on the system");
 
427
 
 
428
out:
 
429
        endmntent(file);
 
430
        return err;
 
431
}
 
432
 
 
433
int recursive_rmdir(char *dirname)
 
434
{
 
435
        struct dirent dirent, *direntp;
 
436
        DIR *dir;
 
437
        int ret;
 
438
        char pathname[MAXPATHLEN];
 
439
 
 
440
        dir = opendir(dirname);
 
441
        if (!dir) {
 
442
                WARN("failed to open directory: %m");
 
443
                return -1;
 
444
        }
 
445
 
 
446
        while (!readdir_r(dir, &dirent, &direntp)) {
 
447
                struct stat mystat;
 
448
                int rc;
 
449
 
 
450
                if (!direntp)
 
451
                        break;
 
452
 
 
453
                if (!strcmp(direntp->d_name, ".") ||
 
454
                    !strcmp(direntp->d_name, ".."))
 
455
                        continue;
 
456
 
 
457
                rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name);
 
458
                if (rc < 0 || rc >= MAXPATHLEN) {
 
459
                        ERROR("pathname too long");
 
460
                        continue;
 
461
                }
 
462
                ret = stat(pathname, &mystat);
 
463
                if (ret)
 
464
                        continue;
 
465
                if (S_ISDIR(mystat.st_mode))
 
466
                        recursive_rmdir(pathname);
 
467
        }
 
468
 
 
469
        ret = rmdir(dirname);
 
470
 
 
471
        if (closedir(dir))
 
472
                ERROR("failed to close directory");
 
473
        return ret;
 
474
 
 
475
 
 
476
}
 
477
 
 
478
int lxc_one_cgroup_destroy(struct mntent *mntent, const char *name)
 
479
{
 
480
        char cgname[MAXPATHLEN], initcgroup[MAXPATHLEN];
 
481
        char *cgmnt = mntent->mnt_dir;
 
482
        int rc;
 
483
 
 
484
        rc = snprintf(cgname, MAXPATHLEN, "%s%s/lxc/%s", cgmnt,
 
485
                get_init_cgroup(NULL, mntent, initcgroup), name);
 
486
        if (rc < 0 || rc >= MAXPATHLEN) {
 
487
                ERROR("name too long");
 
488
                return -1;
 
489
        }
 
490
        DEBUG("destroying %s\n", cgname);
 
491
        if (recursive_rmdir(cgname)) {
 
492
                SYSERROR("failed to remove cgroup '%s'", cgname);
 
493
                return -1;
 
494
        }
 
495
 
 
496
        DEBUG("'%s' unlinked", cgname);
 
497
 
 
498
        return 0;
 
499
}
 
500
 
 
501
/*
 
502
 * for each mounted cgroup, destroy the cgroup for the container
 
503
 */
 
504
int lxc_cgroup_destroy(const char *name)
 
505
{
 
506
        struct mntent *mntent;
 
507
        FILE *file = NULL;
 
508
        int ret, err = -1;
 
509
 
 
510
        file = setmntent(MTAB, "r");
 
511
        if (!file) {
 
512
                SYSERROR("failed to open %s", MTAB);
 
513
                return -1;
 
514
        }
 
515
 
 
516
        while ((mntent = getmntent(file))) {
 
517
                if (!strcmp(mntent->mnt_type, "cgroup")) {
 
518
                        ret = lxc_one_cgroup_destroy(mntent, name);
 
519
                        if (ret) {
 
520
                                fclose(file);
 
521
                                return ret;
 
522
                        }
 
523
                        err = 0;
 
524
                }
 
525
        }
 
526
 
 
527
        fclose(file);
 
528
 
 
529
        return err;
 
530
}
 
531
/*
 
532
 * lxc_cgroup_path_get: put into *path the pathname for
 
533
 * %subsystem and cgroup %name.  If %subsystem is NULL, then
 
534
 * the first mounted cgroup will be used (for nr_tasks)
 
535
 */
 
536
int lxc_cgroup_path_get(char **path, const char *subsystem, const char *name)
 
537
{
 
538
        static char        buf[MAXPATHLEN];
 
539
        static char        retbuf[MAXPATHLEN];
 
540
        int rc;
 
541
 
 
542
        /* what lxc_cgroup_set calls subsystem is actually the filename, i.e.
 
543
           'devices.allow'.  So for our purposee we trim it */
 
544
        if (subsystem) {
 
545
                rc = snprintf(retbuf, MAXPATHLEN, "%s", subsystem);
 
546
                if (rc < 0 || rc >= MAXPATHLEN) {
 
547
                        ERROR("subsystem name too long");
 
548
                        return -1;
 
549
                }
 
550
                char *s = index(retbuf, '.');
 
551
                if (s)
 
552
                        *s = '\0';
 
553
                DEBUG("%s: called for subsys %s name %s\n", __func__, retbuf, name);
 
554
        }
 
555
        if (get_cgroup_mount(subsystem ? retbuf : NULL, buf)) {
 
556
                ERROR("cgroup is not mounted");
 
557
                return -1;
 
558
        }
 
559
 
 
560
        rc = snprintf(retbuf, MAXPATHLEN, "%s/%s", buf, name);
 
561
        if (rc < 0 || rc >= MAXPATHLEN) {
 
562
                ERROR("name too long");
 
563
                return -1;
 
564
        }
 
565
 
 
566
        DEBUG("%s: returning %s for subsystem %s", __func__, retbuf, subsystem);
 
567
 
 
568
        *path = retbuf;
 
569
        return 0;
 
570
}
 
571
 
 
572
int lxc_cgroup_set(const char *name, const char *filename, const char *value)
 
573
{
 
574
        int fd, ret;
 
575
        char *dirpath;
 
576
        char path[MAXPATHLEN];
 
577
        int rc;
 
578
 
 
579
        ret = lxc_cgroup_path_get(&dirpath, filename, name);
 
580
        if (ret)
 
581
                return -1;
 
582
 
 
583
        rc = snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename);
 
584
        if (rc < 0 || rc >= MAXPATHLEN) {
 
585
                ERROR("pathname too long");
 
586
                return -1;
 
587
        }
 
588
 
 
589
        fd = open(path, O_WRONLY);
 
590
        if (fd < 0) {
 
591
                ERROR("open %s : %s", path, strerror(errno));
 
592
                return -1;
 
593
        }
 
594
 
 
595
        ret = write(fd, value, strlen(value));
 
596
        if (ret < 0) {
 
597
                ERROR("write %s : %s", path, strerror(errno));
 
598
                goto out;
 
599
        }
 
600
 
 
601
        ret = 0;
 
602
out:
 
603
        close(fd);
 
604
        return ret;
 
605
}
 
606
 
 
607
int lxc_cgroup_get(const char *name, const char *filename,
 
608
                   char *value, size_t len)
 
609
{
 
610
        int fd, ret = -1;
 
611
        char *dirpath;
 
612
        char path[MAXPATHLEN];
 
613
        int rc;
 
614
 
 
615
        ret = lxc_cgroup_path_get(&dirpath, filename, name);
 
616
        if (ret)
 
617
                return -1;
 
618
 
 
619
        rc = snprintf(path, MAXPATHLEN, "%s/%s", dirpath, filename);
 
620
        if (rc < 0 || rc >= MAXPATHLEN) {
 
621
                ERROR("pathname too long");
 
622
                return -1;
 
623
        }
 
624
 
 
625
        fd = open(path, O_RDONLY);
 
626
        if (fd < 0) {
 
627
                ERROR("open %s : %s", path, strerror(errno));
 
628
                return -1;
 
629
        }
 
630
 
 
631
        ret = read(fd, value, len);
 
632
        if (ret < 0)
 
633
                ERROR("read %s : %s", path, strerror(errno));
 
634
 
 
635
        close(fd);
 
636
        return ret;
 
637
}
 
638
 
 
639
int lxc_cgroup_nrtasks(const char *name)
 
640
{
 
641
        char *dpath;
 
642
        char path[MAXPATHLEN];
 
643
        int pid, ret, count = 0;
 
644
        FILE *file;
 
645
        int rc;
 
646
 
 
647
        ret = lxc_cgroup_path_get(&dpath, NULL, name);
 
648
        if (ret)
 
649
                return -1;
 
650
 
 
651
        rc = snprintf(path, MAXPATHLEN, "%s/tasks", dpath);
 
652
        if (rc < 0 || rc >= MAXPATHLEN) {
 
653
                ERROR("pathname too long");
 
654
                return -1;
 
655
        }
 
656
 
 
657
        file = fopen(path, "r");
 
658
        if (!file) {
 
659
                SYSERROR("fopen '%s' failed", path);
 
660
                return -1;
 
661
        }
 
662
 
 
663
        while (fscanf(file, "%d", &pid) != EOF)
 
664
                count++;
 
665
 
 
666
        fclose(file);
 
667
 
 
668
        return count;
 
669
}