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