~xnox/ubuntu/saucy/lxc/dep8

« back to all changes in this revision

Viewing changes to src/lxc/attach.c

  • Committer: Stéphane Graber
  • Date: 2013-02-18 15:20:18 UTC
  • mto: This revision was merged to the branch mainline in revision 190.
  • Revision ID: stgraber@ubuntu.com-20130218152018-ls2gi9hkqs2kuhj8
Tags: upstream-0.9.0~alpha3
Import upstream version 0.9.0~alpha3

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
#include <fcntl.h>
31
31
#include <sys/param.h>
32
32
#include <sys/prctl.h>
 
33
#include <sys/mount.h>
 
34
#include <sys/syscall.h>
 
35
#include <linux/unistd.h>
33
36
 
34
37
#if !HAVE_DECL_PR_CAPBSET_DROP
35
38
#define PR_CAPBSET_DROP 24
42
45
#include "cgroup.h"
43
46
#include "config.h"
44
47
 
45
 
#include "setns.h"
46
 
 
47
48
lxc_log_define(lxc_attach, lxc);
48
49
 
49
 
int setns(int fd, int nstype)
50
 
{
51
 
#ifndef __NR_setns
52
 
        errno = ENOSYS;
53
 
        return -1;
54
 
#else
55
 
        return syscall(__NR_setns, fd, nstype);
56
 
#endif
57
 
}
 
50
/* Define setns() if missing from the C library */
 
51
#ifndef HAVE_SETNS
 
52
static int setns(int fd, int nstype)
 
53
{
 
54
#ifdef __NR_setns
 
55
return syscall(__NR_setns, fd, nstype);
 
56
#else
 
57
errno = ENOSYS;
 
58
return -1;
 
59
#endif
 
60
}
 
61
#endif
 
62
 
 
63
/* Define unshare() if missing from the C library */
 
64
#ifndef HAVE_UNSHARE
 
65
static int unshare(int flags)
 
66
{
 
67
#ifdef __NR_unshare
 
68
return syscall(__NR_unshare, flags);
 
69
#else
 
70
errno = ENOSYS;
 
71
return -1;
 
72
#endif
 
73
}
 
74
#endif
 
75
 
 
76
/* Define getline() if missing from the C library */
 
77
#ifndef HAVE_GETLINE
 
78
#ifdef HAVE_FGETLN
 
79
#include <../include/getline.h>
 
80
#endif
 
81
#endif
58
82
 
59
83
struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
60
84
{
61
85
        struct lxc_proc_context_info *info = calloc(1, sizeof(*info));
62
86
        FILE *proc_file;
63
87
        char proc_fn[MAXPATHLEN];
64
 
        char *line = NULL, *ptr, *ptr2;
 
88
        char *line = NULL;
65
89
        size_t line_bufsz = 0;
66
 
        int ret, found, l;
67
 
        int i;
 
90
        int ret, found;
68
91
 
69
92
        if (!info) {
70
93
                SYSERROR("Could not allocate memory.");
115
138
                goto out_error;
116
139
        }
117
140
 
118
 
        /* read cgroups */
119
 
        snprintf(proc_fn, MAXPATHLEN, "/proc/%d/cgroup", pid);
120
 
 
121
 
        proc_file = fopen(proc_fn, "r");
122
 
        if (!proc_file) {
123
 
                SYSERROR("Could not open %s", proc_fn);
124
 
                goto out_error;
125
 
        }
126
 
 
127
 
        /* we don't really know how many cgroup subsystems there are
128
 
         * mounted, so we go through the whole file twice */
129
 
        i = 0;
130
 
        while (getline(&line, &line_bufsz, proc_file) != -1) {
131
 
                /* we assume that all lines containing at least two colons
132
 
                 * are valid */
133
 
                ptr = strchr(line, ':');
134
 
                if (ptr && strchr(ptr + 1, ':'))
135
 
                        i++;
136
 
        }
137
 
 
138
 
        rewind(proc_file);
139
 
 
140
 
        info->cgroups = calloc(i, sizeof(*(info->cgroups)));
141
 
        info->cgroups_count = i;
142
 
 
143
 
        i = 0;
144
 
        while (getline(&line, &line_bufsz, proc_file) != -1 && i < info->cgroups_count) {
145
 
                /* format of the lines is:
146
 
                 * id:subsystems:path, where subsystems are separated by
147
 
                 * commas and each subsystem may also be of the form
148
 
                 * name=xxx if it describes a private named hierarchy
149
 
                 * we will ignore the id in the following */
150
 
                ptr = strchr(line, ':');
151
 
                ptr2 = ptr ? strchr(ptr + 1, ':') : NULL;
152
 
 
153
 
                /* ignore invalid lines */
154
 
                if (!ptr || !ptr2) continue;
155
 
 
156
 
                l = strlen(ptr2) - 1;
157
 
                if (ptr2[l] == '\n')
158
 
                        ptr2[l] = '\0';
159
 
 
160
 
                info->cgroups[i].subsystems = strndup(ptr + 1, ptr2 - (ptr + 1));
161
 
                info->cgroups[i].cgroup = strdup(ptr2 + 1);
162
 
 
163
 
                i++;
164
 
        }
165
 
 
166
 
        free(line);
167
 
        fclose(proc_file);
168
 
 
169
141
        return info;
170
142
 
171
143
out_error:
172
 
        lxc_proc_free_context_info(info);
 
144
        free(info);
173
145
        free(line);
174
146
        return NULL;
175
147
}
176
148
 
177
 
void lxc_proc_free_context_info(struct lxc_proc_context_info *info)
178
 
{
179
 
        if (!info)
180
 
                return;
181
 
 
182
 
        if (info->cgroups) {
183
 
                int i;
184
 
                for (i = 0; i < info->cgroups_count; i++) {
185
 
                        free(info->cgroups[i].subsystems);
186
 
                        free(info->cgroups[i].cgroup);
187
 
                }
188
 
        }
189
 
        free(info->cgroups);
190
 
        free(info);
191
 
}
192
 
 
193
 
int lxc_attach_proc_to_cgroups(pid_t pid, struct lxc_proc_context_info *ctx)
194
 
{
195
 
        int i, ret;
196
 
 
197
 
        if (!ctx) {
198
 
                ERROR("No valid context supplied when asked to attach "
199
 
                      "process to cgroups.");
200
 
                return -1;
201
 
        }
202
 
 
203
 
        for (i = 0; i < ctx->cgroups_count; i++) {
204
 
                char *path;
205
 
 
206
 
                /* the kernel should return paths that start with '/' */
207
 
                if (ctx->cgroups[i].cgroup[0] != '/') {
208
 
                        ERROR("For cgroup subsystem(s) %s the path '%s' does "
209
 
                              "not start with a '/'",
210
 
                              ctx->cgroups[i].subsystems,
211
 
                              ctx->cgroups[i].cgroup);
212
 
                        return -1;
213
 
                }
214
 
 
215
 
                /* lxc_cgroup_path_get can process multiple subsystems */
216
 
                ret = lxc_cgroup_path_get(&path, ctx->cgroups[i].subsystems,
217
 
                                          &ctx->cgroups[i].cgroup[1]);
218
 
                if (ret)
219
 
                        return -1;
220
 
 
221
 
                ret = lxc_cgroup_attach(path, pid);
222
 
                if (ret)
223
 
                        return -1;
224
 
        }
225
 
 
226
 
        return 0;
227
 
}
228
 
 
229
 
int lxc_attach_to_ns(pid_t pid)
 
149
int lxc_attach_to_ns(pid_t pid, int which)
230
150
{
231
151
        char path[MAXPATHLEN];
232
 
        char *ns[] = { "pid", "mnt", "net", "ipc", "uts" };
233
 
        const int size = sizeof(ns) / sizeof(char *);
 
152
        /* according to <http://article.gmane.org/gmane.linux.kernel.containers.lxc.devel/1429>,
 
153
         * the file for user namepsaces in /proc/$pid/ns will be called
 
154
         * 'user' once the kernel supports it
 
155
         */
 
156
        static char *ns[] = { "mnt", "pid", "uts", "ipc", "user", "net" };
 
157
        static int flags[] = {
 
158
                CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWIPC,
 
159
                CLONE_NEWUSER, CLONE_NEWNET
 
160
        };
 
161
        static const int size = sizeof(ns) / sizeof(char *);
234
162
        int fd[size];
235
 
        int i;
 
163
        int i, j, saved_errno;
 
164
 
236
165
 
237
166
        snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
238
167
        if (access(path, X_OK)) {
241
170
        }
242
171
 
243
172
        for (i = 0; i < size; i++) {
 
173
                /* ignore if we are not supposed to attach to that
 
174
                 * namespace
 
175
                 */
 
176
                if (which != -1 && !(which & flags[i])) {
 
177
                        fd[i] = -1;
 
178
                        continue;
 
179
                }
 
180
 
244
181
                snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]);
245
182
                fd[i] = open(path, O_RDONLY);
246
183
                if (fd[i] < 0) {
 
184
                        saved_errno = errno;
 
185
 
 
186
                        /* close all already opened file descriptors before
 
187
                         * we return an error, so we don't leak them
 
188
                         */
 
189
                        for (j = 0; j < i; j++)
 
190
                                close(fd[j]);
 
191
 
 
192
                        errno = saved_errno;
247
193
                        SYSERROR("failed to open '%s'", path);
248
194
                        return -1;
249
195
                }
250
196
        }
251
197
 
252
198
        for (i = 0; i < size; i++) {
253
 
                if (setns(fd[i], 0)) {
 
199
                if (fd[i] >= 0 && setns(fd[i], 0) != 0) {
 
200
                        saved_errno = errno;
 
201
 
 
202
                        for (j = i; j < size; j++)
 
203
                                close(fd[j]);
 
204
 
 
205
                        errno = saved_errno;
254
206
                        SYSERROR("failed to set namespace '%s'", ns[i]);
255
207
                        return -1;
256
208
                }
261
213
        return 0;
262
214
}
263
215
 
 
216
int lxc_attach_remount_sys_proc()
 
217
{
 
218
        int ret;
 
219
 
 
220
        ret = unshare(CLONE_NEWNS);
 
221
        if (ret < 0) {
 
222
                SYSERROR("failed to unshare mount namespace");
 
223
                return -1;
 
224
        }
 
225
 
 
226
        /* assume /proc is always mounted, so remount it */
 
227
        ret = umount2("/proc", MNT_DETACH);
 
228
        if (ret < 0) {
 
229
                SYSERROR("failed to unmount /proc");
 
230
                return -1;
 
231
        }
 
232
 
 
233
        ret = mount("none", "/proc", "proc", 0, NULL);
 
234
        if (ret < 0) {
 
235
                SYSERROR("failed to remount /proc");
 
236
                return -1;
 
237
        }
 
238
 
 
239
        /* try to umount /sys - if it's not a mount point,
 
240
         * we'll get EINVAL, then we ignore it because it
 
241
         * may not have been mounted in the first place
 
242
         */
 
243
        ret = umount2("/sys", MNT_DETACH);
 
244
        if (ret < 0 && errno != EINVAL) {
 
245
                SYSERROR("failed to unmount /sys");
 
246
                return -1;
 
247
        } else if (ret == 0) {
 
248
                /* remount it */
 
249
                ret = mount("none", "/sys", "sysfs", 0, NULL);
 
250
                if (ret < 0) {
 
251
                        SYSERROR("failed to remount /sys");
 
252
                        return -1;
 
253
                }
 
254
        }
 
255
 
 
256
        return 0;
 
257
}
 
258
 
264
259
int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
265
260
{
266
261
        int last_cap = lxc_caps_last_cap();