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