]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/conf.c
set version to 0.7.3
[mirror_lxc.git] / src / lxc / conf.c
CommitLineData
0ad19a3f 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>
e3b4c4c4 27#include <stdarg.h>
0ad19a3f 28#include <errno.h>
29#include <string.h>
30#include <dirent.h>
31#include <mntent.h>
32#include <unistd.h>
e3b4c4c4 33#include <sys/wait.h>
b0a33c1e 34#include <pty.h>
0ad19a3f 35
b3ecde1e
DL
36#include <linux/loop.h>
37
0ad19a3f 38#include <sys/types.h>
39#include <sys/utsname.h>
40#include <sys/param.h>
41#include <sys/stat.h>
42#include <sys/socket.h>
43#include <sys/mount.h>
44#include <sys/mman.h>
81810dd1
DL
45#include <sys/prctl.h>
46#include <sys/capability.h>
cccc74b5 47#include <sys/personality.h>
0ad19a3f 48
49#include <arpa/inet.h>
50#include <fcntl.h>
51#include <netinet/in.h>
52#include <net/if.h>
6f4a3756 53#include <libgen.h>
0ad19a3f 54
e5bda9ee 55#include "network.h"
56#include "error.h"
b2718c72 57#include "parse.h"
881450bb 58#include "config.h"
1b09f2c0
DL
59#include "utils.h"
60#include "conf.h"
61#include "log.h"
62#include "lxc.h" /* for lxc_cgroup_set() */
36eb9bde
CLG
63
64lxc_log_define(lxc_conf, lxc);
e5bda9ee 65
0ad19a3f 66#define MAXHWLEN 18
67#define MAXINDEXLEN 20
442cbbe6 68#define MAXMTULEN 16
0ad19a3f 69#define MAXLINELEN 128
70
fdc03323
DL
71#ifndef MS_REC
72#define MS_REC 16384
73#endif
74
c08556c6
DL
75#ifndef MNT_DETACH
76#define MNT_DETACH 2
77#endif
78
b09094da
MN
79#ifndef CAP_SETFCAP
80#define CAP_SETFCAP 31
81#endif
82
83#ifndef CAP_MAC_OVERRIDE
84#define CAP_MAC_OVERRIDE 32
85#endif
86
87#ifndef CAP_MAC_ADMIN
88#define CAP_MAC_ADMIN 33
89#endif
90
91#ifndef PR_CAPBSET_DROP
92#define PR_CAPBSET_DROP 24
93#endif
94
bf601689
MH
95extern int pivot_root(const char * new_root, const char * put_old);
96
e3b4c4c4 97typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
0ad19a3f 98
998ac676
RT
99struct mount_opt {
100 char *name;
101 int clear;
102 int flag;
103};
104
81810dd1
DL
105struct caps_opt {
106 char *name;
107 int value;
108};
109
e3b4c4c4
ST
110static int instanciate_veth(struct lxc_handler *, struct lxc_netdev *);
111static int instanciate_macvlan(struct lxc_handler *, struct lxc_netdev *);
112static int instanciate_vlan(struct lxc_handler *, struct lxc_netdev *);
113static int instanciate_phys(struct lxc_handler *, struct lxc_netdev *);
114static int instanciate_empty(struct lxc_handler *, struct lxc_netdev *);
82d5ae15 115
24654103
DL
116static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
117 [LXC_NET_VETH] = instanciate_veth,
118 [LXC_NET_MACVLAN] = instanciate_macvlan,
119 [LXC_NET_VLAN] = instanciate_vlan,
120 [LXC_NET_PHYS] = instanciate_phys,
121 [LXC_NET_EMPTY] = instanciate_empty,
0ad19a3f 122};
123
998ac676
RT
124static struct mount_opt mount_opt[] = {
125 { "defaults", 0, 0 },
126 { "ro", 0, MS_RDONLY },
127 { "rw", 1, MS_RDONLY },
128 { "suid", 1, MS_NOSUID },
129 { "nosuid", 0, MS_NOSUID },
130 { "dev", 1, MS_NODEV },
131 { "nodev", 0, MS_NODEV },
132 { "exec", 1, MS_NOEXEC },
133 { "noexec", 0, MS_NOEXEC },
134 { "sync", 0, MS_SYNCHRONOUS },
135 { "async", 1, MS_SYNCHRONOUS },
136 { "remount", 0, MS_REMOUNT },
137 { "mand", 0, MS_MANDLOCK },
138 { "nomand", 1, MS_MANDLOCK },
139 { "atime", 1, MS_NOATIME },
140 { "noatime", 0, MS_NOATIME },
141 { "diratime", 1, MS_NODIRATIME },
142 { "nodiratime", 0, MS_NODIRATIME },
143 { "bind", 0, MS_BIND },
144 { "rbind", 0, MS_BIND|MS_REC },
145 { NULL, 0, 0 },
146};
147
81810dd1 148static struct caps_opt caps_opt[] = {
a6afdde9 149 { "chown", CAP_CHOWN },
1e11be34
DL
150 { "dac_override", CAP_DAC_OVERRIDE },
151 { "dac_read_search", CAP_DAC_READ_SEARCH },
152 { "fowner", CAP_FOWNER },
153 { "fsetid", CAP_FSETID },
81810dd1
DL
154 { "kill", CAP_KILL },
155 { "setgid", CAP_SETGID },
156 { "setuid", CAP_SETUID },
157 { "setpcap", CAP_SETPCAP },
158 { "linux_immutable", CAP_LINUX_IMMUTABLE },
159 { "net_bind_service", CAP_NET_BIND_SERVICE },
160 { "net_broadcast", CAP_NET_BROADCAST },
161 { "net_admin", CAP_NET_ADMIN },
162 { "net_raw", CAP_NET_RAW },
163 { "ipc_lock", CAP_IPC_LOCK },
164 { "ipc_owner", CAP_IPC_OWNER },
165 { "sys_module", CAP_SYS_MODULE },
166 { "sys_rawio", CAP_SYS_RAWIO },
167 { "sys_chroot", CAP_SYS_CHROOT },
168 { "sys_ptrace", CAP_SYS_PTRACE },
169 { "sys_pacct", CAP_SYS_PACCT },
170 { "sys_admin", CAP_SYS_ADMIN },
171 { "sys_boot", CAP_SYS_BOOT },
172 { "sys_nice", CAP_SYS_NICE },
173 { "sys_resource", CAP_SYS_RESOURCE },
174 { "sys_time", CAP_SYS_TIME },
175 { "sys_tty_config", CAP_SYS_TTY_CONFIG },
176 { "mknod", CAP_MKNOD },
177 { "lease", CAP_LEASE },
9527e566 178#ifdef CAP_AUDIT_WRITE
81810dd1 179 { "audit_write", CAP_AUDIT_WRITE },
9527e566
FW
180#endif
181#ifdef CAP_AUDIT_CONTROL
81810dd1 182 { "audit_control", CAP_AUDIT_CONTROL },
9527e566 183#endif
81810dd1
DL
184 { "setfcap", CAP_SETFCAP },
185 { "mac_override", CAP_MAC_OVERRIDE },
186 { "mac_admin", CAP_MAC_ADMIN },
81810dd1
DL
187};
188
751d9dcd
DL
189static int run_script(const char *name, const char *section,
190 const char *script, ...)
e3b4c4c4 191{
abbfd20b
DL
192 int ret;
193 FILE *f;
194 char *buffer, *p, *output;
195 size_t size = 0;
196 va_list ap;
751d9dcd
DL
197
198 INFO("Executing script '%s' for container '%s', config section '%s'",
199 script, name, section);
e3b4c4c4 200
abbfd20b
DL
201 va_start(ap, script);
202 while ((p = va_arg(ap, char *)))
203 size += strlen(p);
204 va_end(ap);
205
206 size += strlen(script);
207 size += strlen(name);
208 size += strlen(section);
209
210 buffer = alloca(size + 1);
211 if (!buffer) {
212 ERROR("failed to allocate memory");
751d9dcd
DL
213 return -1;
214 }
215
abbfd20b 216 ret = sprintf(buffer, "%s %s %s", script, name, section);
751d9dcd 217
abbfd20b
DL
218 va_start(ap, script);
219 while ((p = va_arg(ap, char *)))
220 ret += sprintf(buffer + ret, " %s", p);
221 va_end(ap);
751d9dcd 222
abbfd20b
DL
223 f = popen(buffer, "r");
224 if (!f) {
225 SYSERROR("popen failed");
226 return -1;
227 }
e3b4c4c4 228
abbfd20b
DL
229 output = malloc(LXC_LOG_BUFFER_SIZE);
230 if (!output) {
231 ERROR("failed to allocate memory for script output");
232 return -1;
e3b4c4c4 233 }
751d9dcd 234
abbfd20b
DL
235 while(fgets(output, LXC_LOG_BUFFER_SIZE, f))
236 DEBUG("script output: %s", output);
237
238 free(output);
239
240 if (pclose(f)) {
241 ERROR("Script exited on error");
751d9dcd
DL
242 return -1;
243 }
244
245 return 0;
e3b4c4c4
ST
246}
247
a6afdde9 248static int find_fstype_cb(char* buffer, void *data)
78ae2fcc 249{
250 struct cbarg {
251 const char *rootfs;
a6afdde9 252 const char *target;
78ae2fcc 253 int mntopt;
254 } *cbarg = data;
255
256 char *fstype;
257
258 /* we don't try 'nodev' entries */
259 if (strstr(buffer, "nodev"))
260 return 0;
261
262 fstype = buffer;
b2718c72 263 fstype += lxc_char_left_gc(fstype, strlen(fstype));
264 fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
78ae2fcc 265
a6afdde9
DL
266 DEBUG("trying to mount '%s'->'%s' with fstype '%s'",
267 cbarg->rootfs, cbarg->target, fstype);
268
269 if (mount(cbarg->rootfs, cbarg->target, fstype, cbarg->mntopt, NULL)) {
270 DEBUG("mount failed with error: %s", strerror(errno));
78ae2fcc 271 return 0;
a6afdde9 272 }
78ae2fcc 273
a6afdde9
DL
274 INFO("mounted '%s' on '%s', with fstype '%s'",
275 cbarg->rootfs, cbarg->target, fstype);
78ae2fcc 276
277 return 1;
278}
279
2656d231 280static int mount_unknow_fs(const char *rootfs, const char *target, int mntopt)
78ae2fcc 281{
a6afdde9 282 int i;
78ae2fcc 283
284 struct cbarg {
285 const char *rootfs;
a6afdde9 286 const char *target;
78ae2fcc 287 int mntopt;
288 } cbarg = {
289 .rootfs = rootfs,
a6afdde9 290 .target = target,
78ae2fcc 291 .mntopt = mntopt,
292 };
293
a6afdde9
DL
294 /*
295 * find the filesystem type with brute force:
296 * first we check with /etc/filesystems, in case the modules
78ae2fcc 297 * are auto-loaded and fall back to the supported kernel fs
298 */
299 char *fsfile[] = {
300 "/etc/filesystems",
301 "/proc/filesystems",
302 };
303
a6afdde9
DL
304 for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) {
305
306 int ret;
307
308 if (access(fsfile[i], F_OK))
309 continue;
310
311 ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
312 if (ret < 0) {
313 ERROR("failed to parse '%s'", fsfile[i]);
314 return -1;
315 }
316
317 if (ret)
318 return 0;
78ae2fcc 319 }
320
a6afdde9
DL
321 ERROR("failed to determine fs type for '%s'", rootfs);
322 return -1;
323}
324
2656d231 325static int mount_rootfs_dir(const char *rootfs, const char *target)
a6afdde9
DL
326{
327 return mount(rootfs, target, "none", MS_BIND | MS_REC, NULL);
328}
329
330static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
331{
332 int rfd;
333 int ret = -1;
334
335 rfd = open(rootfs, O_RDWR);
336 if (rfd < 0) {
337 SYSERROR("failed to open '%s'", rootfs);
78ae2fcc 338 return -1;
339 }
340
a6afdde9 341 memset(loinfo, 0, sizeof(*loinfo));
78ae2fcc 342
a6afdde9 343 loinfo->lo_flags = LO_FLAGS_AUTOCLEAR;
78ae2fcc 344
a6afdde9
DL
345 if (ioctl(fd, LOOP_SET_FD, rfd)) {
346 SYSERROR("failed to LOOP_SET_FD");
347 goto out;
78ae2fcc 348 }
349
a6afdde9
DL
350 if (ioctl(fd, LOOP_SET_STATUS64, loinfo)) {
351 SYSERROR("failed to LOOP_SET_STATUS64");
78ae2fcc 352 goto out;
353 }
354
a6afdde9 355 ret = 0;
78ae2fcc 356out:
a6afdde9 357 close(rfd);
78ae2fcc 358
a6afdde9 359 return ret;
78ae2fcc 360}
361
2656d231 362static int mount_rootfs_file(const char *rootfs, const char *target)
78ae2fcc 363{
a6afdde9
DL
364 struct dirent dirent, *direntp;
365 struct loop_info64 loinfo;
366 int ret = -1, fd = -1;
367 DIR *dir;
368 char path[MAXPATHLEN];
78ae2fcc 369
a6afdde9
DL
370 dir = opendir("/dev");
371 if (!dir) {
372 SYSERROR("failed to open '/dev'");
78ae2fcc 373 return -1;
374 }
375
a6afdde9
DL
376 while (!readdir_r(dir, &dirent, &direntp)) {
377
378 if (!direntp)
379 break;
380
381 if (!strcmp(direntp->d_name, "."))
382 continue;
383
384 if (!strcmp(direntp->d_name, ".."))
385 continue;
386
387 if (strncmp(direntp->d_name, "loop", 4))
388 continue;
389
390 sprintf(path, "/dev/%s", direntp->d_name);
391 fd = open(path, O_RDWR);
392 if (fd < 0)
393 continue;
394
395 if (ioctl(fd, LOOP_GET_STATUS64, &loinfo) == 0) {
396 close(fd);
397 continue;
398 }
399
400 if (errno != ENXIO) {
401 WARN("unexpected error for ioctl on '%s': %m",
402 direntp->d_name);
403 continue;
404 }
405
406 DEBUG("found '%s' free lodev", path);
407
408 ret = setup_lodev(rootfs, fd, &loinfo);
409 if (!ret)
2656d231 410 ret = mount_unknow_fs(path, target, 0);
a6afdde9
DL
411 close(fd);
412
413 break;
414 }
415
416 if (closedir(dir))
417 WARN("failed to close directory");
418
419 return ret;
78ae2fcc 420}
421
2656d231 422static int mount_rootfs_block(const char *rootfs, const char *target)
a6afdde9 423{
2656d231 424 return mount_unknow_fs(rootfs, target, 0);
a6afdde9
DL
425}
426
2656d231 427static int mount_rootfs(const char *rootfs, const char *target)
0ad19a3f 428{
b09ef133 429 char absrootfs[MAXPATHLEN];
78ae2fcc 430 struct stat s;
a6afdde9 431 int i;
78ae2fcc 432
a6afdde9 433 typedef int (*rootfs_cb)(const char *, const char *);
78ae2fcc 434
435 struct rootfs_type {
436 int type;
437 rootfs_cb cb;
438 } rtfs_type[] = {
2656d231
DL
439 { S_IFDIR, mount_rootfs_dir },
440 { S_IFBLK, mount_rootfs_block },
441 { S_IFREG, mount_rootfs_file },
78ae2fcc 442 };
0ad19a3f 443
4c8ab83b 444 if (!realpath(rootfs, absrootfs)) {
36eb9bde 445 SYSERROR("failed to get real path for '%s'", rootfs);
4c8ab83b 446 return -1;
447 }
b09ef133 448
b09ef133 449 if (access(absrootfs, F_OK)) {
36eb9bde 450 SYSERROR("'%s' is not accessible", absrootfs);
b09ef133 451 return -1;
452 }
453
78ae2fcc 454 if (stat(absrootfs, &s)) {
36eb9bde 455 SYSERROR("failed to stat '%s'", absrootfs);
9b0f0477 456 return -1;
457 }
458
78ae2fcc 459 for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) {
9b0f0477 460
78ae2fcc 461 if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
462 continue;
9b0f0477 463
a6afdde9 464 return rtfs_type[i].cb(absrootfs, target);
78ae2fcc 465 }
9b0f0477 466
36eb9bde 467 ERROR("unsupported rootfs type for '%s'", absrootfs);
78ae2fcc 468 return -1;
0ad19a3f 469}
470
4e5440c6 471static int setup_utsname(struct utsname *utsname)
0ad19a3f 472{
4e5440c6
DL
473 if (!utsname)
474 return 0;
0ad19a3f 475
4e5440c6
DL
476 if (sethostname(utsname->nodename, strlen(utsname->nodename))) {
477 SYSERROR("failed to set the hostname to '%s'", utsname->nodename);
0ad19a3f 478 return -1;
479 }
480
4e5440c6 481 INFO("'%s' hostname has been setup", utsname->nodename);
cd54d859 482
0ad19a3f 483 return 0;
484}
485
33fcb7a0
DL
486static int setup_tty(const struct lxc_rootfs *rootfs,
487 const struct lxc_tty_info *tty_info)
b0a33c1e 488{
489 char path[MAXPATHLEN];
490 int i;
491
bc9bd0e3
DL
492 if (!rootfs->path)
493 return 0;
494
b0a33c1e 495 for (i = 0; i < tty_info->nbtty; i++) {
496
497 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
498
52e35957 499 snprintf(path, sizeof(path), "%s/dev/tty%d",
12297168 500 rootfs->mount, i + 1);
b0a33c1e 501
13954cce 502 /* At this point I can not use the "access" function
b0a33c1e 503 * to check the file is present or not because it fails
504 * with EACCES errno and I don't know why :( */
13954cce 505
b0a33c1e 506 if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
36eb9bde 507 WARN("failed to mount '%s'->'%s'",
52e35957 508 pty_info->name, path);
b0a33c1e 509 continue;
510 }
511 }
512
cd54d859
DL
513 INFO("%d tty(s) has been setup", tty_info->nbtty);
514
b0a33c1e 515 return 0;
516}
517
7a7ff0c6 518static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
bf601689
MH
519{
520 struct lxc_list *mountlist, *listentry, *iterator;
521 char *pivotdir, *mountpoint, *mountentry;
522 int found;
523 void **cbparm;
524
525 mountentry = buffer;
526 cbparm = (void **)data;
527
528 mountlist = cbparm[0];
529 pivotdir = cbparm[1];
530
531 /* parse entry, first field is mountname, ignore */
532 mountpoint = strtok(mountentry, " ");
533 if (!mountpoint)
534 return -1;
535
536 /* second field is mountpoint */
537 mountpoint = strtok(NULL, " ");
538 if (!mountpoint)
539 return -1;
540
541 /* only consider mountpoints below old root fs */
542 if (strncmp(mountpoint, pivotdir, strlen(pivotdir)))
543 return 0;
544
545 /* filter duplicate mountpoints */
546 found = 0;
547 lxc_list_for_each(iterator, mountlist) {
548 if (!strcmp(iterator->elem, mountpoint)) {
549 found = 1;
550 break;
551 }
552 }
553 if (found)
554 return 0;
555
556 /* add entry to list */
557 listentry = malloc(sizeof(*listentry));
558 if (!listentry) {
559 SYSERROR("malloc for mountpoint listentry failed");
560 return -1;
561 }
562
563 listentry->elem = strdup(mountpoint);
564 if (!listentry->elem) {
565 SYSERROR("strdup failed");
566 return -1;
567 }
568 lxc_list_add_tail(mountlist, listentry);
569
570 return 0;
571}
572
cc6f6dd7 573static int umount_oldrootfs(const char *oldrootfs)
bf601689 574{
2382ecff 575 char path[MAXPATHLEN];
bf601689
MH
576 void *cbparm[2];
577 struct lxc_list mountlist, *iterator;
578 int ok, still_mounted, last_still_mounted;
bf601689
MH
579
580 /* read and parse /proc/mounts in old root fs */
581 lxc_list_init(&mountlist);
582
cc6f6dd7
DL
583 /* oldrootfs is on the top tree directory now */
584 snprintf(path, sizeof(path), "/%s", oldrootfs);
bf601689 585 cbparm[0] = &mountlist;
bf601689 586
cc6f6dd7 587 cbparm[1] = strdup(path);
bf601689
MH
588 if (!cbparm[1]) {
589 SYSERROR("strdup failed");
590 return -1;
591 }
592
cc6f6dd7
DL
593 snprintf(path, sizeof(path), "%s/proc/mounts", oldrootfs);
594
595 ok = lxc_file_for_each_line(path,
596 setup_rootfs_pivot_root_cb, &cbparm);
bf601689
MH
597 if (ok < 0) {
598 SYSERROR("failed to read or parse mount list '%s'", path);
599 return -1;
600 }
601
602 /* umount filesystems until none left or list no longer shrinks */
603 still_mounted = 0;
604 do {
605 last_still_mounted = still_mounted;
606 still_mounted = 0;
607
608 lxc_list_for_each(iterator, &mountlist) {
609
c08556c6 610 /* umount normally */
bf601689
MH
611 if (!umount(iterator->elem)) {
612 DEBUG("umounted '%s'", (char *)iterator->elem);
613 lxc_list_del(iterator);
614 continue;
615 }
616
bf601689
MH
617 still_mounted++;
618 }
7df119ee 619
bf601689
MH
620 } while (still_mounted > 0 && still_mounted != last_still_mounted);
621
7df119ee 622
c08556c6
DL
623 lxc_list_for_each(iterator, &mountlist) {
624
625 /* let's try a lazy umount */
626 if (!umount2(iterator->elem, MNT_DETACH)) {
627 INFO("lazy unmount of '%s'", (char *)iterator->elem);
628 continue;
629 }
630
631 /* be more brutal (nfs) */
632 if (!umount2(iterator->elem, MNT_FORCE)) {
633 INFO("forced unmount of '%s'", (char *)iterator->elem);
634 continue;
635 }
636
7df119ee 637 WARN("failed to unmount '%s'", (char *)iterator->elem);
c08556c6 638 }
bf601689 639
cc6f6dd7
DL
640 return 0;
641}
642
643static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
644{
645 char path[MAXPATHLEN];
646 int remove_pivotdir = 0;
647
648 /* change into new root fs */
649 if (chdir(rootfs)) {
650 SYSERROR("can't chdir to new rootfs '%s'", rootfs);
651 return -1;
652 }
653
654 if (!pivotdir)
3103609d 655 pivotdir = "mnt";
cc6f6dd7 656
4f9293b1 657 /* compute the full path to pivotdir under rootfs */
cc6f6dd7
DL
658 snprintf(path, sizeof(path), "%s/%s", rootfs, pivotdir);
659
660 if (access(path, F_OK)) {
661
662 if (mkdir_p(path, 0755)) {
663 SYSERROR("failed to create pivotdir '%s'", path);
664 return -1;
665 }
666
667 remove_pivotdir = 1;
668 DEBUG("created '%s' directory", path);
669 }
670
671 DEBUG("mountpoint for old rootfs is '%s'", path);
672
673 /* pivot_root into our new root fs */
674 if (pivot_root(".", path)) {
675 SYSERROR("pivot_root syscall failed");
bf601689
MH
676 return -1;
677 }
cc6f6dd7
DL
678
679 if (chdir("/")) {
680 SYSERROR("can't chdir to / after pivot_root");
681 return -1;
682 }
683
684 DEBUG("pivot_root syscall to '%s' successful", rootfs);
685
686 /* we switch from absolute path to relative path */
687 if (umount_oldrootfs(pivotdir))
688 return -1;
bf601689 689
c08556c6
DL
690 /* remove temporary mount point, we don't consider the removing
691 * as fatal */
a91d897a
FW
692 if (remove_pivotdir && rmdir(pivotdir))
693 WARN("can't remove mountpoint '%s': %m", pivotdir);
bf601689 694
bf601689
MH
695 return 0;
696}
697
33fcb7a0 698static int setup_rootfs(const struct lxc_rootfs *rootfs)
0ad19a3f 699{
33fcb7a0 700 if (!rootfs->path)
c69bd12f 701 return 0;
0ad19a3f 702
12297168 703 if (access(rootfs->mount, F_OK)) {
b1789442 704 SYSERROR("failed to access to '%s', check it is present",
12297168 705 rootfs->mount);
b1789442
DL
706 return -1;
707 }
708
2656d231 709 if (mount_rootfs(rootfs->path, rootfs->mount)) {
a6afdde9 710 ERROR("failed to mount rootfs");
c3f0a28c 711 return -1;
712 }
0ad19a3f 713
12297168 714 DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
c69bd12f 715
ac778708
DL
716 return 0;
717}
718
719int setup_pivot_root(const struct lxc_rootfs *rootfs)
720{
ac778708
DL
721 if (!rootfs->path)
722 return 0;
723
12297168 724 if (setup_rootfs_pivot_root(rootfs->mount, rootfs->pivot)) {
cc6f6dd7 725 ERROR("failed to setup pivot root");
25368b52 726 return -1;
c69bd12f
DL
727 }
728
25368b52 729 return 0;
0ad19a3f 730}
731
d852c78c 732static int setup_pts(int pts)
3c26f34e 733{
d852c78c
DL
734 if (!pts)
735 return 0;
3c26f34e 736
737 if (!access("/dev/pts/ptmx", F_OK) && umount("/dev/pts")) {
36eb9bde 738 SYSERROR("failed to umount 'dev/pts'");
3c26f34e 739 return -1;
740 }
741
a6afdde9
DL
742 if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,
743 "newinstance,ptmxmode=0666")) {
36eb9bde 744 SYSERROR("failed to mount a new instance of '/dev/pts'");
3c26f34e 745 return -1;
746 }
747
3c26f34e 748 if (access("/dev/ptmx", F_OK)) {
749 if (!symlink("/dev/pts/ptmx", "/dev/ptmx"))
750 goto out;
36eb9bde 751 SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'");
3c26f34e 752 return -1;
753 }
754
755 /* fallback here, /dev/pts/ptmx exists just mount bind */
756 if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) {
36eb9bde 757 SYSERROR("mount failed '/dev/pts/ptmx'->'/dev/ptmx'");
3c26f34e 758 return -1;
759 }
cd54d859
DL
760
761 INFO("created new pts instance");
d852c78c 762
3c26f34e 763out:
764 return 0;
765}
766
cccc74b5
DL
767static int setup_personality(int persona)
768{
769 if (persona == -1)
770 return 0;
771
772 if (personality(persona) < 0) {
773 SYSERROR("failed to set personality to '0x%x'", persona);
774 return -1;
775 }
776
777 INFO("set personality to '0x%x'", persona);
778
779 return 0;
780}
781
33fcb7a0
DL
782static int setup_console(const struct lxc_rootfs *rootfs,
783 const struct lxc_console *console)
6e590161 784{
63376d7d
DL
785 char path[MAXPATHLEN];
786 struct stat s;
52e35957 787
63376d7d 788 /* We don't have a rootfs, /dev/console will be shared */
33fcb7a0 789 if (!rootfs->path)
63376d7d 790 return 0;
52e35957 791
12297168 792 snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
52e35957 793
63376d7d 794 if (access(path, F_OK)) {
466978b0 795 WARN("rootfs specified but no console found at '%s'", path);
63376d7d 796 return 0;
52e35957
DL
797 }
798
f78a1f32 799 if (console->peer == -1) {
63376d7d 800 INFO("no console output required");
f78a1f32
DL
801 return 0;
802 }
ed502555 803
63376d7d
DL
804 if (stat(path, &s)) {
805 SYSERROR("failed to stat '%s'", path);
806 return -1;
807 }
808
809 if (chmod(console->name, s.st_mode)) {
810 SYSERROR("failed to set mode '0%o' to '%s'",
811 s.st_mode, console->name);
812 return -1;
813 }
13954cce 814
63376d7d
DL
815 if (mount(console->name, path, "none", MS_BIND, 0)) {
816 ERROR("failed to mount '%s' on '%s'", console->name, path);
6e590161 817 return -1;
818 }
819
63376d7d 820 INFO("console has been setup");
cd54d859 821
6e590161 822 return 0;
823}
824
102a5303 825static int setup_cgroup(const char *name, struct lxc_list *cgroups)
576f946d 826{
102a5303
DL
827 struct lxc_list *iterator;
828 struct lxc_cgroup *cg;
88329c69 829 int ret = -1;
6f4a3756 830
102a5303
DL
831 if (lxc_list_empty(cgroups))
832 return 0;
6f4a3756 833
102a5303 834 lxc_list_for_each(iterator, cgroups) {
13954cce 835
102a5303 836 cg = iterator->elem;
6f4a3756 837
102a5303 838 if (lxc_cgroup_set(name, cg->subsystem, cg->value))
88329c69 839 goto out;
6f4a3756 840
102a5303 841 DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
6f4a3756 842 }
13954cce 843
88329c69 844 ret = 0;
cd54d859 845 INFO("cgroup has been setup");
88329c69
MN
846out:
847 return ret;
576f946d 848}
849
998ac676
RT
850static void parse_mntopt(char *opt, unsigned long *flags, char **data)
851{
852 struct mount_opt *mo;
853
854 /* If opt is found in mount_opt, set or clear flags.
855 * Otherwise append it to data. */
856
857 for (mo = &mount_opt[0]; mo->name != NULL; mo++) {
858 if (!strncmp(opt, mo->name, strlen(mo->name))) {
859 if (mo->clear)
860 *flags &= ~mo->flag;
861 else
862 *flags |= mo->flag;
863 return;
864 }
865 }
866
867 if (strlen(*data))
868 strcat(*data, ",");
869 strcat(*data, opt);
870}
871
872static int parse_mntopts(struct mntent *mntent, unsigned long *mntflags,
873 char **mntdata)
874{
875 char *s, *data;
876 char *p, *saveptr = NULL;
877
878 if (!mntent->mnt_opts)
879 return 0;
880
881 s = strdup(mntent->mnt_opts);
882 if (!s) {
36eb9bde 883 SYSERROR("failed to allocate memory");
998ac676
RT
884 return -1;
885 }
886
887 data = malloc(strlen(s) + 1);
888 if (!data) {
36eb9bde 889 SYSERROR("failed to allocate memory");
998ac676
RT
890 free(s);
891 return -1;
892 }
893 *data = 0;
894
895 for (p = strtok_r(s, ",", &saveptr); p != NULL;
896 p = strtok_r(NULL, ",", &saveptr))
897 parse_mntopt(p, mntflags, &data);
898
899 if (*data)
900 *mntdata = data;
901 else
902 free(data);
903 free(s);
904
905 return 0;
906}
907
e7938e9e 908static int mount_file_entries(FILE *file)
0ad19a3f 909{
0ad19a3f 910 struct mntent *mntent;
0ad19a3f 911 int ret = -1;
998ac676
RT
912 unsigned long mntflags;
913 char *mntdata;
0ad19a3f 914
998ac676 915 while ((mntent = getmntent(file))) {
1bc60a65 916
998ac676
RT
917 mntflags = 0;
918 mntdata = NULL;
919 if (parse_mntopts(mntent, &mntflags, &mntdata) < 0) {
36eb9bde 920 ERROR("failed to parse mount option '%s'",
998ac676
RT
921 mntent->mnt_opts);
922 goto out;
923 }
0ad19a3f 924
925 if (mount(mntent->mnt_fsname, mntent->mnt_dir,
e76b8764 926 mntent->mnt_type, mntflags & ~MS_REMOUNT, mntdata)) {
36eb9bde 927 SYSERROR("failed to mount '%s' on '%s'",
0ad19a3f 928 mntent->mnt_fsname, mntent->mnt_dir);
929 goto out;
930 }
998ac676 931
e76b8764
CDC
932 if ((mntflags & MS_REMOUNT) == MS_REMOUNT ||
933 ((mntflags & MS_BIND) == MS_BIND)) {
934
935 DEBUG ("remounting %s on %s to respect bind " \
936 "or remount options",
937 mntent->mnt_fsname, mntent->mnt_dir);
938
939 if (mount(mntent->mnt_fsname, mntent->mnt_dir,
940 mntent->mnt_type,
941 mntflags | MS_REMOUNT, mntdata)) {
942 SYSERROR("failed to mount '%s' on '%s'",
943 mntent->mnt_fsname, mntent->mnt_dir);
944 goto out;
945 }
946 }
947
cd54d859
DL
948 DEBUG("mounted %s on %s, type %s", mntent->mnt_fsname,
949 mntent->mnt_dir, mntent->mnt_type);
950
998ac676 951 free(mntdata);
0ad19a3f 952 }
cd54d859 953
0ad19a3f 954 ret = 0;
cd54d859
DL
955
956 INFO("mount points have been setup");
0ad19a3f 957out:
e7938e9e
MN
958 return ret;
959}
960
961static int setup_mount(const char *fstab)
962{
963 FILE *file;
964 int ret;
965
966 if (!fstab)
967 return 0;
968
969 file = setmntent(fstab, "r");
970 if (!file) {
971 SYSERROR("failed to use '%s'", fstab);
972 return -1;
973 }
974
975 ret = mount_file_entries(file);
976
0ad19a3f 977 endmntent(file);
978 return ret;
979}
980
e7938e9e
MN
981static int setup_mount_entries(struct lxc_list *mount)
982{
983 FILE *file;
984 struct lxc_list *iterator;
985 char *mount_entry;
986 int ret;
987
988 file = tmpfile();
989 if (!file) {
990 ERROR("tmpfile error: %m");
991 return -1;
992 }
993
994 lxc_list_for_each(iterator, mount) {
995 mount_entry = iterator->elem;
1d6b1976 996 fprintf(file, "%s\n", mount_entry);
e7938e9e
MN
997 }
998
999 rewind(file);
1000
1001 ret = mount_file_entries(file);
1002
1003 fclose(file);
1004 return ret;
1005}
1006
81810dd1
DL
1007static int setup_caps(struct lxc_list *caps)
1008{
1009 struct lxc_list *iterator;
1010 char *drop_entry;
1011 int i, capid;
1012
1013 lxc_list_for_each(iterator, caps) {
1014
1015 drop_entry = iterator->elem;
1016
1017 capid = -1;
1018
1019 for (i = 0; i < sizeof(caps_opt)/sizeof(caps_opt[0]); i++) {
1020
1021 if (strcmp(drop_entry, caps_opt[i].name))
1022 continue;
1023
1024 capid = caps_opt[i].value;
1025 break;
1026 }
1027
1028 if (capid < 0) {
1e11be34
DL
1029 ERROR("unknown capability %s", drop_entry);
1030 return -1;
81810dd1
DL
1031 }
1032
1033 DEBUG("drop capability '%s' (%d)", drop_entry, capid);
1034
1035 if (prctl(PR_CAPBSET_DROP, capid, 0, 0, 0)) {
1036 SYSERROR("failed to remove %s capability", drop_entry);
1037 return -1;
1038 }
1039
1040 }
1041
1042 DEBUG("capabilities has been setup");
1043
1044 return 0;
1045}
1046
0ad19a3f 1047static int setup_hw_addr(char *hwaddr, const char *ifname)
1048{
1049 struct sockaddr sockaddr;
1050 struct ifreq ifr;
1051 int ret, fd;
1052
3cfc0f3a
MN
1053 ret = lxc_convert_mac(hwaddr, &sockaddr);
1054 if (ret) {
1055 ERROR("mac address '%s' conversion failed : %s",
1056 hwaddr, strerror(-ret));
0ad19a3f 1057 return -1;
1058 }
1059
1060 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
1061 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
1062
1063 fd = socket(AF_INET, SOCK_DGRAM, 0);
1064 if (fd < 0) {
3ab87b66 1065 ERROR("socket failure : %s", strerror(errno));
0ad19a3f 1066 return -1;
1067 }
1068
1069 ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
1070 close(fd);
1071 if (ret)
3ab87b66 1072 ERROR("ioctl failure : %s", strerror(errno));
0ad19a3f 1073
cd54d859
DL
1074 DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifname);
1075
0ad19a3f 1076 return ret;
1077}
1078
82d5ae15 1079static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
0ad19a3f 1080{
82d5ae15
DL
1081 struct lxc_list *iterator;
1082 struct lxc_inetdev *inetdev;
3cfc0f3a 1083 int err;
0ad19a3f 1084
82d5ae15
DL
1085 lxc_list_for_each(iterator, ip) {
1086
1087 inetdev = iterator->elem;
1088
0093bb8c
DL
1089 err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
1090 &inetdev->bcast, inetdev->prefix);
3cfc0f3a
MN
1091 if (err) {
1092 ERROR("failed to setup_ipv4_addr ifindex %d : %s",
1093 ifindex, strerror(-err));
82d5ae15
DL
1094 return -1;
1095 }
1096 }
1097
1098 return 0;
0ad19a3f 1099}
1100
82d5ae15 1101static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
0ad19a3f 1102{
82d5ae15 1103 struct lxc_list *iterator;
7fa9074f 1104 struct lxc_inet6dev *inet6dev;
3cfc0f3a 1105 int err;
0ad19a3f 1106
82d5ae15
DL
1107 lxc_list_for_each(iterator, ip) {
1108
1109 inet6dev = iterator->elem;
1110
b3df193c 1111 err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
0093bb8c
DL
1112 &inet6dev->mcast, &inet6dev->acast,
1113 inet6dev->prefix);
3cfc0f3a
MN
1114 if (err) {
1115 ERROR("failed to setup_ipv6_addr ifindex %d : %s",
1116 ifindex, strerror(-err));
82d5ae15 1117 return -1;
3cfc0f3a 1118 }
82d5ae15
DL
1119 }
1120
1121 return 0;
0ad19a3f 1122}
1123
82d5ae15 1124static int setup_netdev(struct lxc_netdev *netdev)
0ad19a3f 1125{
0ad19a3f 1126 char ifname[IFNAMSIZ];
0ad19a3f 1127 char *current_ifname = ifname;
3cfc0f3a 1128 int err;
0ad19a3f 1129
82d5ae15
DL
1130 /* empty network namespace */
1131 if (!netdev->ifindex) {
1132 if (netdev->flags | IFF_UP) {
3cfc0f3a
MN
1133 err = lxc_device_up("lo");
1134 if (err) {
1135 ERROR("failed to set the loopback up : %s",
1136 strerror(-err));
82d5ae15
DL
1137 return -1;
1138 }
1139 return 0;
1140 }
0ad19a3f 1141 }
13954cce 1142
82d5ae15
DL
1143 /* retrieve the name of the interface */
1144 if (!if_indextoname(netdev->ifindex, current_ifname)) {
36eb9bde 1145 ERROR("no interface corresponding to index '%d'",
82d5ae15 1146 netdev->ifindex);
0ad19a3f 1147 return -1;
1148 }
13954cce 1149
018ef520 1150 /* default: let the system to choose one interface name */
9d083402 1151 if (!netdev->name)
fb6d9b2f
DL
1152 netdev->name = netdev->type == LXC_NET_PHYS ?
1153 netdev->link : "eth%d";
018ef520 1154
82d5ae15 1155 /* rename the interface name */
3cfc0f3a
MN
1156 err = lxc_device_rename(ifname, netdev->name);
1157 if (err) {
1158 ERROR("failed to rename %s->%s : %s", ifname, netdev->name,
1159 strerror(-err));
018ef520
DL
1160 return -1;
1161 }
1162
1163 /* Re-read the name of the interface because its name has changed
1164 * and would be automatically allocated by the system
1165 */
82d5ae15 1166 if (!if_indextoname(netdev->ifindex, current_ifname)) {
018ef520 1167 ERROR("no interface corresponding to index '%d'",
82d5ae15 1168 netdev->ifindex);
018ef520 1169 return -1;
0ad19a3f 1170 }
1171
82d5ae15
DL
1172 /* set a mac address */
1173 if (netdev->hwaddr) {
1174 if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
36eb9bde 1175 ERROR("failed to setup hw address for '%s'",
82d5ae15 1176 current_ifname);
0ad19a3f 1177 return -1;
1178 }
1179 }
1180
82d5ae15
DL
1181 /* setup ipv4 addresses on the interface */
1182 if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
36eb9bde 1183 ERROR("failed to setup ip addresses for '%s'",
0ad19a3f 1184 ifname);
1185 return -1;
1186 }
1187
82d5ae15
DL
1188 /* setup ipv6 addresses on the interface */
1189 if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
36eb9bde 1190 ERROR("failed to setup ipv6 addresses for '%s'",
0ad19a3f 1191 ifname);
1192 return -1;
1193 }
1194
82d5ae15
DL
1195 /* set the network device up */
1196 if (netdev->flags | IFF_UP) {
3cfc0f3a
MN
1197 int err;
1198
1199 err = lxc_device_up(current_ifname);
1200 if (err) {
1201 ERROR("failed to set '%s' up : %s", current_ifname,
1202 strerror(-err));
0ad19a3f 1203 return -1;
1204 }
1205
1206 /* the network is up, make the loopback up too */
3cfc0f3a
MN
1207 err = lxc_device_up("lo");
1208 if (err) {
1209 ERROR("failed to set the loopback up : %s",
1210 strerror(-err));
0ad19a3f 1211 return -1;
1212 }
1213 }
1214
cd54d859
DL
1215 DEBUG("'%s' has been setup", current_ifname);
1216
0ad19a3f 1217 return 0;
1218}
1219
5f4535a3 1220static int setup_network(struct lxc_list *network)
0ad19a3f 1221{
82d5ae15 1222 struct lxc_list *iterator;
82d5ae15 1223 struct lxc_netdev *netdev;
0ad19a3f 1224
5f4535a3 1225 lxc_list_for_each(iterator, network) {
cd54d859 1226
5f4535a3 1227 netdev = iterator->elem;
82d5ae15
DL
1228
1229 if (setup_netdev(netdev)) {
1230 ERROR("failed to setup netdev");
1231 return -1;
1232 }
1233 }
cd54d859 1234
5f4535a3
DL
1235 if (!lxc_list_empty(network))
1236 INFO("network has been setup");
cd54d859
DL
1237
1238 return 0;
0ad19a3f 1239}
1240
7b379ab3 1241struct lxc_conf *lxc_conf_init(void)
089cd8b8 1242{
7b379ab3
MN
1243 struct lxc_conf *new;
1244
1245 new = malloc(sizeof(*new));
1246 if (!new) {
1247 ERROR("lxc_conf_init : %m");
1248 return NULL;
1249 }
1250 memset(new, 0, sizeof(*new));
1251
cccc74b5 1252 new->personality = -1;
28a4b0e5 1253 new->console.path = NULL;
63376d7d
DL
1254 new->console.peer = -1;
1255 new->console.master = -1;
1256 new->console.slave = -1;
1257 new->console.name[0] = '\0';
12297168 1258 new->rootfs.mount = LXCROOTFSMOUNT;
7b379ab3
MN
1259 lxc_list_init(&new->cgroup);
1260 lxc_list_init(&new->network);
1261 lxc_list_init(&new->mount_list);
81810dd1 1262 lxc_list_init(&new->caps);
7b379ab3
MN
1263
1264 return new;
089cd8b8
DL
1265}
1266
e3b4c4c4 1267static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 1268{
8634bc19 1269 char veth1buf[IFNAMSIZ], *veth1;
0e391e57 1270 char veth2buf[IFNAMSIZ], *veth2;
3cfc0f3a 1271 int err;
13954cce 1272
e892973e
DL
1273 if (netdev->priv.veth_attr.pair)
1274 veth1 = netdev->priv.veth_attr.pair;
8634bc19
MT
1275 else {
1276 snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
0e391e57 1277 veth1 = mktemp(veth1buf);
8634bc19 1278 }
82d5ae15 1279
0e391e57
DL
1280 snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
1281 veth2 = mktemp(veth2buf);
82d5ae15
DL
1282
1283 if (!strlen(veth1) || !strlen(veth2)) {
1284 ERROR("failed to allocate a temporary name");
1285 return -1;
0ad19a3f 1286 }
1287
3cfc0f3a
MN
1288 err = lxc_veth_create(veth1, veth2);
1289 if (err) {
1290 ERROR("failed to create %s-%s : %s", veth1, veth2,
1291 strerror(-err));
6ab9ab6d 1292 return -1;
0ad19a3f 1293 }
13954cce 1294
82d5ae15 1295 if (netdev->mtu) {
3cfc0f3a
MN
1296 err = lxc_device_set_mtu(veth1, atoi(netdev->mtu));
1297 if (!err)
1298 err = lxc_device_set_mtu(veth2, atoi(netdev->mtu));
1299 if (err) {
1300 ERROR("failed to set mtu '%s' for %s-%s : %s",
1301 netdev->mtu, veth1, veth2, strerror(-err));
eb14c10a 1302 goto out_delete;
75d09f83
DL
1303 }
1304 }
1305
3cfc0f3a
MN
1306 if (netdev->link) {
1307 err = lxc_bridge_attach(netdev->link, veth1);
1308 if (err) {
1309 ERROR("failed to attach '%s' to the bridge '%s' : %s",
1310 veth1, netdev->link, strerror(-err));
1311 goto out_delete;
1312 }
eb14c10a
DL
1313 }
1314
82d5ae15
DL
1315 netdev->ifindex = if_nametoindex(veth2);
1316 if (!netdev->ifindex) {
36eb9bde 1317 ERROR("failed to retrieve the index for %s", veth2);
eb14c10a
DL
1318 goto out_delete;
1319 }
1320
82d5ae15 1321 if (netdev->flags & IFF_UP) {
3cfc0f3a
MN
1322 err = lxc_device_up(veth1);
1323 if (err) {
1324 ERROR("failed to set %s up : %s", veth1,
1325 strerror(-err));
eb14c10a 1326 goto out_delete;
0ad19a3f 1327 }
1328 }
1329
e3b4c4c4 1330 if (netdev->upscript) {
751d9dcd
DL
1331 err = run_script(handler->name, "net", netdev->upscript, "up",
1332 "veth", veth1, (char*) NULL);
1333 if (err)
e3b4c4c4 1334 goto out_delete;
e3b4c4c4
ST
1335 }
1336
82d5ae15
DL
1337 DEBUG("instanciated veth '%s/%s', index is '%d'",
1338 veth1, veth2, netdev->ifindex);
1339
6ab9ab6d 1340 return 0;
eb14c10a
DL
1341
1342out_delete:
1343 lxc_device_delete(veth1);
6ab9ab6d 1344 return -1;
13954cce 1345}
d957ae2d 1346
e3b4c4c4 1347static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 1348{
0e391e57 1349 char peerbuf[IFNAMSIZ], *peer;
3cfc0f3a 1350 int err;
d957ae2d
MT
1351
1352 if (!netdev->link) {
1353 ERROR("no link specified for macvlan netdev");
1354 return -1;
1355 }
13954cce 1356
0e391e57 1357 snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
82d5ae15 1358
0e391e57 1359 peer = mktemp(peerbuf);
82d5ae15
DL
1360 if (!strlen(peer)) {
1361 ERROR("failed to make a temporary name");
1362 return -1;
0ad19a3f 1363 }
1364
3cfc0f3a
MN
1365 err = lxc_macvlan_create(netdev->link, peer,
1366 netdev->priv.macvlan_attr.mode);
1367 if (err) {
1368 ERROR("failed to create macvlan interface '%s' on '%s' : %s",
1369 peer, netdev->link, strerror(-err));
d957ae2d 1370 return -1;
0ad19a3f 1371 }
1372
82d5ae15
DL
1373 netdev->ifindex = if_nametoindex(peer);
1374 if (!netdev->ifindex) {
36eb9bde 1375 ERROR("failed to retrieve the index for %s", peer);
d957ae2d
MT
1376 lxc_device_delete(peer);
1377 return -1;
22ebac19 1378 }
1379
e3b4c4c4 1380 if (netdev->upscript) {
751d9dcd
DL
1381 err = run_script(handler->name, "net", netdev->upscript, "up",
1382 "macvlan", netdev->link, (char*) NULL);
1383 if (err)
e3b4c4c4 1384 return -1;
e3b4c4c4
ST
1385 }
1386
e892973e
DL
1387 DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'",
1388 peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
0ad19a3f 1389
d957ae2d 1390 return 0;
0ad19a3f 1391}
1392
26c39028 1393/* XXX: merge with instanciate_macvlan */
e3b4c4c4 1394static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
26c39028
JHS
1395{
1396 char peer[IFNAMSIZ];
3cfc0f3a 1397 int err;
26c39028
JHS
1398
1399 if (!netdev->link) {
1400 ERROR("no link specified for vlan netdev");
1401 return -1;
1402 }
1403
e892973e 1404 snprintf(peer, sizeof(peer), "vlan%d", netdev->priv.vlan_attr.vid);
26c39028 1405
3cfc0f3a
MN
1406 err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
1407 if (err) {
1408 ERROR("failed to create vlan interface '%s' on '%s' : %s",
1409 peer, netdev->link, strerror(-err));
26c39028
JHS
1410 return -1;
1411 }
1412
1413 netdev->ifindex = if_nametoindex(peer);
1414 if (!netdev->ifindex) {
1415 ERROR("failed to retrieve the ifindex for %s", peer);
1416 lxc_device_delete(peer);
1417 return -1;
1418 }
1419
e892973e
DL
1420 DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000",
1421 netdev->ifindex);
1422
26c39028
JHS
1423 return 0;
1424}
1425
e3b4c4c4 1426static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 1427{
6168e99f
DL
1428 if (!netdev->link) {
1429 ERROR("no link specified for the physical interface");
1430 return -1;
1431 }
1432
9d083402 1433 netdev->ifindex = if_nametoindex(netdev->link);
82d5ae15 1434 if (!netdev->ifindex) {
9d083402 1435 ERROR("failed to retrieve the index for %s", netdev->link);
0ad19a3f 1436 return -1;
1437 }
1438
e3b4c4c4
ST
1439 if (netdev->upscript) {
1440 int err;
751d9dcd
DL
1441 err = run_script(handler->name, "net", netdev->upscript,
1442 "up", "phys", netdev->link, (char*) NULL);
1443 if (err)
e3b4c4c4 1444 return -1;
e3b4c4c4
ST
1445 }
1446
82d5ae15 1447 return 0;
0ad19a3f 1448}
1449
e3b4c4c4 1450static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 1451{
82d5ae15 1452 netdev->ifindex = 0;
e3b4c4c4
ST
1453 if (netdev->upscript) {
1454 int err;
751d9dcd
DL
1455 err = run_script(handler->name, "net", netdev->upscript,
1456 "up", "empty", (char*) NULL);
1457 if (err)
e3b4c4c4 1458 return -1;
e3b4c4c4 1459 }
82d5ae15 1460 return 0;
0ad19a3f 1461}
1462
e3b4c4c4 1463int lxc_create_network(struct lxc_handler *handler)
0ad19a3f 1464{
e3b4c4c4 1465 struct lxc_list *network = &handler->conf->network;
82d5ae15 1466 struct lxc_list *iterator;
82d5ae15 1467 struct lxc_netdev *netdev;
0ad19a3f 1468
5f4535a3 1469 lxc_list_for_each(iterator, network) {
0ad19a3f 1470
5f4535a3 1471 netdev = iterator->elem;
13954cce 1472
24654103 1473 if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) {
82d5ae15 1474 ERROR("invalid network configuration type '%d'",
5f4535a3 1475 netdev->type);
82d5ae15
DL
1476 return -1;
1477 }
0ad19a3f 1478
e3b4c4c4 1479 if (netdev_conf[netdev->type](handler, netdev)) {
82d5ae15
DL
1480 ERROR("failed to create netdev");
1481 return -1;
1482 }
e3b4c4c4 1483
0ad19a3f 1484 }
1485
1486 return 0;
1487}
1488
7fef7a06
DL
1489void lxc_delete_network(struct lxc_list *network)
1490{
1491 struct lxc_list *iterator;
1492 struct lxc_netdev *netdev;
1493
1494 lxc_list_for_each(iterator, network) {
1495 netdev = iterator->elem;
96bcd56a 1496 if (netdev->ifindex > 0 && netdev->type != LXC_NET_PHYS)
7fef7a06
DL
1497 lxc_device_delete_index(netdev->ifindex);
1498 }
1499}
1500
5f4535a3 1501int lxc_assign_network(struct lxc_list *network, pid_t pid)
0ad19a3f 1502{
82d5ae15 1503 struct lxc_list *iterator;
82d5ae15 1504 struct lxc_netdev *netdev;
3cfc0f3a 1505 int err;
0ad19a3f 1506
5f4535a3 1507 lxc_list_for_each(iterator, network) {
82d5ae15 1508
5f4535a3 1509 netdev = iterator->elem;
82d5ae15 1510
236087a6
DL
1511 /* empty network namespace, nothing to move */
1512 if (!netdev->ifindex)
1513 continue;
1514
3cfc0f3a
MN
1515 err = lxc_device_move(netdev->ifindex, pid);
1516 if (err) {
1517 ERROR("failed to move '%s' to the container : %s",
1518 netdev->link, strerror(-err));
82d5ae15
DL
1519 return -1;
1520 }
1521
9d083402 1522 DEBUG("move '%s' to '%d'", netdev->link, pid);
0ad19a3f 1523 }
1524
1525 return 0;
1526}
1527
5e4a62bf 1528int lxc_create_tty(const char *name, struct lxc_conf *conf)
b0a33c1e 1529{
5e4a62bf 1530 struct lxc_tty_info *tty_info = &conf->tty_info;
985d15b1 1531 int i;
b0a33c1e 1532
5e4a62bf
DL
1533 /* no tty in the configuration */
1534 if (!conf->tty)
b0a33c1e 1535 return 0;
1536
13954cce 1537 tty_info->pty_info =
e4e7d59d 1538 malloc(sizeof(*tty_info->pty_info)*conf->tty);
b0a33c1e 1539 if (!tty_info->pty_info) {
36eb9bde 1540 SYSERROR("failed to allocate pty_info");
985d15b1 1541 return -1;
b0a33c1e 1542 }
1543
985d15b1 1544 for (i = 0; i < conf->tty; i++) {
13954cce 1545
b0a33c1e 1546 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
1547
13954cce 1548 if (openpty(&pty_info->master, &pty_info->slave,
b0a33c1e 1549 pty_info->name, NULL, NULL)) {
36eb9bde 1550 SYSERROR("failed to create pty #%d", i);
985d15b1
MT
1551 tty_info->nbtty = i;
1552 lxc_delete_tty(tty_info);
1553 return -1;
b0a33c1e 1554 }
1555
5332bb84
DL
1556 DEBUG("allocated pty '%s' (%d/%d)",
1557 pty_info->name, pty_info->master, pty_info->slave);
1558
b035ad62
MS
1559 /* Prevent leaking the file descriptors to the container */
1560 fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
1561 fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
1562
b0a33c1e 1563 pty_info->busy = 0;
1564 }
1565
985d15b1 1566 tty_info->nbtty = conf->tty;
1ac470c0
DL
1567
1568 INFO("tty's configured");
1569
985d15b1 1570 return 0;
b0a33c1e 1571}
1572
1573void lxc_delete_tty(struct lxc_tty_info *tty_info)
1574{
1575 int i;
1576
1577 for (i = 0; i < tty_info->nbtty; i++) {
1578 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
1579
1580 close(pty_info->master);
1581 close(pty_info->slave);
1582 }
1583
1584 free(tty_info->pty_info);
1585 tty_info->nbtty = 0;
1586}
1587
571e6ec8 1588int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
0ad19a3f 1589{
571e6ec8 1590 if (setup_utsname(lxc_conf->utsname)) {
36eb9bde 1591 ERROR("failed to setup the utsname for '%s'", name);
95b5ffaf 1592 return -1;
0ad19a3f 1593 }
1594
5f4535a3 1595 if (setup_network(&lxc_conf->network)) {
36eb9bde 1596 ERROR("failed to setup the network for '%s'", name);
95b5ffaf 1597 return -1;
0ad19a3f 1598 }
1599
ac778708
DL
1600 if (setup_rootfs(&lxc_conf->rootfs)) {
1601 ERROR("failed to setup rootfs for '%s'", name);
95b5ffaf 1602 return -1;
0ad19a3f 1603 }
1604
571e6ec8 1605 if (setup_mount(lxc_conf->fstab)) {
36eb9bde 1606 ERROR("failed to setup the mounts for '%s'", name);
95b5ffaf 1607 return -1;
576f946d 1608 }
1609
e7938e9e
MN
1610 if (setup_mount_entries(&lxc_conf->mount_list)) {
1611 ERROR("failed to setup the mount entries for '%s'", name);
1612 return -1;
1613 }
1614
ac778708
DL
1615 if (setup_cgroup(name, &lxc_conf->cgroup)) {
1616 ERROR("failed to setup the cgroups for '%s'", name);
1617 return -1;
1618 }
1619
33fcb7a0 1620 if (setup_console(&lxc_conf->rootfs, &lxc_conf->console)) {
36eb9bde 1621 ERROR("failed to setup the console for '%s'", name);
95b5ffaf 1622 return -1;
6e590161 1623 }
1624
33fcb7a0 1625 if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info)) {
36eb9bde 1626 ERROR("failed to setup the ttys for '%s'", name);
95b5ffaf 1627 return -1;
b0a33c1e 1628 }
1629
ac778708 1630 if (setup_pivot_root(&lxc_conf->rootfs)) {
36eb9bde 1631 ERROR("failed to set rootfs for '%s'", name);
95b5ffaf 1632 return -1;
ed502555 1633 }
1634
571e6ec8 1635 if (setup_pts(lxc_conf->pts)) {
36eb9bde 1636 ERROR("failed to setup the new pts instance");
95b5ffaf 1637 return -1;
3c26f34e 1638 }
1639
cccc74b5
DL
1640 if (setup_personality(lxc_conf->personality)) {
1641 ERROR("failed to setup personality");
1642 return -1;
1643 }
1644
81810dd1
DL
1645 if (setup_caps(&lxc_conf->caps)) {
1646 ERROR("failed to drop capabilities");
1647 return -1;
1648 }
1649
cd54d859
DL
1650 NOTICE("'%s' is setup.", name);
1651
0ad19a3f 1652 return 0;
1653}