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