42
45
#include "cgroup.h"
43
46
#include "config.h"
47
48
lxc_log_define(lxc_attach, lxc);
49
int setns(int fd, int nstype)
55
return syscall(__NR_setns, fd, nstype);
50
/* Define setns() if missing from the C library */
52
static int setns(int fd, int nstype)
55
return syscall(__NR_setns, fd, nstype);
63
/* Define unshare() if missing from the C library */
65
static int unshare(int flags)
68
return syscall(__NR_unshare, flags);
76
/* Define getline() if missing from the C library */
79
#include <../include/getline.h>
59
83
struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
61
85
struct lxc_proc_context_info *info = calloc(1, sizeof(*info));
63
87
char proc_fn[MAXPATHLEN];
64
char *line = NULL, *ptr, *ptr2;
65
89
size_t line_bufsz = 0;
70
93
SYSERROR("Could not allocate memory.");
119
snprintf(proc_fn, MAXPATHLEN, "/proc/%d/cgroup", pid);
121
proc_file = fopen(proc_fn, "r");
123
SYSERROR("Could not open %s", proc_fn);
127
/* we don't really know how many cgroup subsystems there are
128
* mounted, so we go through the whole file twice */
130
while (getline(&line, &line_bufsz, proc_file) != -1) {
131
/* we assume that all lines containing at least two colons
133
ptr = strchr(line, ':');
134
if (ptr && strchr(ptr + 1, ':'))
140
info->cgroups = calloc(i, sizeof(*(info->cgroups)));
141
info->cgroups_count = i;
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;
153
/* ignore invalid lines */
154
if (!ptr || !ptr2) continue;
156
l = strlen(ptr2) - 1;
160
info->cgroups[i].subsystems = strndup(ptr + 1, ptr2 - (ptr + 1));
161
info->cgroups[i].cgroup = strdup(ptr2 + 1);
172
lxc_proc_free_context_info(info);
177
void lxc_proc_free_context_info(struct lxc_proc_context_info *info)
184
for (i = 0; i < info->cgroups_count; i++) {
185
free(info->cgroups[i].subsystems);
186
free(info->cgroups[i].cgroup);
193
int lxc_attach_proc_to_cgroups(pid_t pid, struct lxc_proc_context_info *ctx)
198
ERROR("No valid context supplied when asked to attach "
199
"process to cgroups.");
203
for (i = 0; i < ctx->cgroups_count; i++) {
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);
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]);
221
ret = lxc_cgroup_attach(path, pid);
229
int lxc_attach_to_ns(pid_t pid)
149
int lxc_attach_to_ns(pid_t pid, int which)
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
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
161
static const int size = sizeof(ns) / sizeof(char *);
163
int i, j, saved_errno;
237
166
snprintf(path, MAXPATHLEN, "/proc/%d/ns", pid);
238
167
if (access(path, X_OK)) {
243
172
for (i = 0; i < size; i++) {
173
/* ignore if we are not supposed to attach to that
176
if (which != -1 && !(which & flags[i])) {
244
181
snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns[i]);
245
182
fd[i] = open(path, O_RDONLY);
186
/* close all already opened file descriptors before
187
* we return an error, so we don't leak them
189
for (j = 0; j < i; j++)
247
193
SYSERROR("failed to open '%s'", path);
252
198
for (i = 0; i < size; i++) {
253
if (setns(fd[i], 0)) {
199
if (fd[i] >= 0 && setns(fd[i], 0) != 0) {
202
for (j = i; j < size; j++)
254
206
SYSERROR("failed to set namespace '%s'", ns[i]);
216
int lxc_attach_remount_sys_proc()
220
ret = unshare(CLONE_NEWNS);
222
SYSERROR("failed to unshare mount namespace");
226
/* assume /proc is always mounted, so remount it */
227
ret = umount2("/proc", MNT_DETACH);
229
SYSERROR("failed to unmount /proc");
233
ret = mount("none", "/proc", "proc", 0, NULL);
235
SYSERROR("failed to remount /proc");
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
243
ret = umount2("/sys", MNT_DETACH);
244
if (ret < 0 && errno != EINVAL) {
245
SYSERROR("failed to unmount /sys");
247
} else if (ret == 0) {
249
ret = mount("none", "/sys", "sysfs", 0, NULL);
251
SYSERROR("failed to remount /sys");
264
259
int lxc_attach_drop_privs(struct lxc_proc_context_info *ctx)
266
261
int last_cap = lxc_caps_last_cap();