]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/conf.c
lxc-0.7.4
[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
911324ef 877static int parse_mntopts(const char *mntopts, unsigned long *mntflags,
998ac676
RT
878 char **mntdata)
879{
880 char *s, *data;
881 char *p, *saveptr = NULL;
882
911324ef 883 *mntdata = NULL;
91656ce5 884 *mntflags = 0L;
911324ef
DL
885
886 if (!mntopts)
998ac676
RT
887 return 0;
888
911324ef 889 s = strdup(mntopts);
998ac676 890 if (!s) {
36eb9bde 891 SYSERROR("failed to allocate memory");
998ac676
RT
892 return -1;
893 }
894
895 data = malloc(strlen(s) + 1);
896 if (!data) {
36eb9bde 897 SYSERROR("failed to allocate memory");
998ac676
RT
898 free(s);
899 return -1;
900 }
901 *data = 0;
902
903 for (p = strtok_r(s, ",", &saveptr); p != NULL;
904 p = strtok_r(NULL, ",", &saveptr))
905 parse_mntopt(p, mntflags, &data);
906
907 if (*data)
908 *mntdata = data;
909 else
910 free(data);
911 free(s);
912
913 return 0;
914}
915
911324ef
DL
916static int mount_entry(const char *fsname, const char *target,
917 const char *fstype, unsigned long mountflags,
918 const char *data)
919{
920 if (mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data)) {
921 SYSERROR("failed to mount '%s' on '%s'", fsname, target);
922 return -1;
923 }
924
925 if ((mountflags & MS_REMOUNT) || (mountflags & MS_BIND)) {
926
927 DEBUG("remounting %s on %s to respect bind or remount options",
928 fsname, target);
929
930 if (mount(fsname, target, fstype,
931 mountflags | MS_REMOUNT, data)) {
932 SYSERROR("failed to mount '%s' on '%s'",
933 fsname, target);
934 return -1;
935 }
936 }
937
938 DEBUG("mounted '%s' on '%s', type '%s'", fsname, target, fstype);
939
940 return 0;
941}
942
943static inline int mount_entry_on_systemfs(struct mntent *mntent)
0ad19a3f 944{
998ac676
RT
945 unsigned long mntflags;
946 char *mntdata;
911324ef
DL
947 int ret;
948
949 if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
950 ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
951 return -1;
952 }
953
954 ret = mount_entry(mntent->mnt_fsname, mntent->mnt_dir,
955 mntent->mnt_type, mntflags, mntdata);
956
957 free(mntdata);
958
959 return ret;
960}
961
962static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
013bd428 963 const struct lxc_rootfs *rootfs)
911324ef 964{
013bd428 965 char *aux;
59760f5d 966 char path[MAXPATHLEN];
911324ef
DL
967 unsigned long mntflags;
968 char *mntdata;
013bd428 969 int ret = 0;
0ad19a3f 970
911324ef
DL
971 if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
972 ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
973 return -1;
974 }
1bc60a65 975
013bd428
DL
976 aux = strstr(mntent->mnt_dir, rootfs->path);
977 if (!aux) {
978 WARN("ignoring mount point '%s'", mntent->mnt_dir);
979 goto out;
980 }
981
982 snprintf(path, MAXPATHLEN, "%s%s", rootfs->mount,
983 aux + strlen(rootfs->path));
d330fe7b 984
013bd428 985 ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
911324ef 986 mntflags, mntdata);
0ad19a3f 987
013bd428 988out:
911324ef
DL
989 free(mntdata);
990 return ret;
991}
d330fe7b 992
911324ef
DL
993static int mount_entry_on_relative_rootfs(struct mntent *mntent,
994 const char *rootfs)
995{
996 char path[MAXPATHLEN];
997 unsigned long mntflags;
998 char *mntdata;
999 int ret;
d330fe7b 1000
911324ef
DL
1001 if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
1002 ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
1003 return -1;
1004 }
d330fe7b 1005
911324ef
DL
1006 /* relative to root mount point */
1007 snprintf(path, sizeof(path), "%s/%s", rootfs, mntent->mnt_dir);
1008
1009 ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
1010 mntflags, mntdata);
1011
1012 free(mntdata);
998ac676 1013
911324ef
DL
1014 return ret;
1015}
1016
1017static int mount_file_entries(const struct lxc_rootfs *rootfs, FILE *file)
1018{
1019 struct mntent *mntent;
1020 int ret = -1;
e76b8764 1021
911324ef 1022 while ((mntent = getmntent(file))) {
e76b8764 1023
911324ef
DL
1024 if (!rootfs->path) {
1025 if (mount_entry_on_systemfs(mntent))
e76b8764 1026 goto out;
911324ef 1027 continue;
e76b8764
CDC
1028 }
1029
911324ef
DL
1030 /* We have a separate root, mounts are relative to it */
1031 if (mntent->mnt_dir[0] != '/') {
1032 if (mount_entry_on_relative_rootfs(mntent,
1033 rootfs->mount))
1034 goto out;
1035 continue;
1036 }
cd54d859 1037
013bd428 1038 if (mount_entry_on_absolute_rootfs(mntent, rootfs))
911324ef 1039 goto out;
0ad19a3f 1040 }
cd54d859 1041
0ad19a3f 1042 ret = 0;
cd54d859
DL
1043
1044 INFO("mount points have been setup");
0ad19a3f 1045out:
e7938e9e
MN
1046 return ret;
1047}
1048
59760f5d 1049static int setup_mount(const struct lxc_rootfs *rootfs, const char *fstab)
e7938e9e
MN
1050{
1051 FILE *file;
1052 int ret;
1053
1054 if (!fstab)
1055 return 0;
1056
1057 file = setmntent(fstab, "r");
1058 if (!file) {
1059 SYSERROR("failed to use '%s'", fstab);
1060 return -1;
1061 }
1062
59760f5d 1063 ret = mount_file_entries(rootfs, file);
e7938e9e 1064
0ad19a3f 1065 endmntent(file);
1066 return ret;
1067}
1068
59760f5d 1069static int setup_mount_entries(const struct lxc_rootfs *rootfs, struct lxc_list *mount)
e7938e9e
MN
1070{
1071 FILE *file;
1072 struct lxc_list *iterator;
1073 char *mount_entry;
1074 int ret;
1075
1076 file = tmpfile();
1077 if (!file) {
1078 ERROR("tmpfile error: %m");
1079 return -1;
1080 }
1081
1082 lxc_list_for_each(iterator, mount) {
1083 mount_entry = iterator->elem;
1d6b1976 1084 fprintf(file, "%s\n", mount_entry);
e7938e9e
MN
1085 }
1086
1087 rewind(file);
1088
59760f5d 1089 ret = mount_file_entries(rootfs, file);
e7938e9e
MN
1090
1091 fclose(file);
1092 return ret;
1093}
1094
81810dd1
DL
1095static int setup_caps(struct lxc_list *caps)
1096{
1097 struct lxc_list *iterator;
1098 char *drop_entry;
1099 int i, capid;
1100
1101 lxc_list_for_each(iterator, caps) {
1102
1103 drop_entry = iterator->elem;
1104
1105 capid = -1;
1106
1107 for (i = 0; i < sizeof(caps_opt)/sizeof(caps_opt[0]); i++) {
1108
1109 if (strcmp(drop_entry, caps_opt[i].name))
1110 continue;
1111
1112 capid = caps_opt[i].value;
1113 break;
1114 }
1115
1116 if (capid < 0) {
1e11be34
DL
1117 ERROR("unknown capability %s", drop_entry);
1118 return -1;
81810dd1
DL
1119 }
1120
1121 DEBUG("drop capability '%s' (%d)", drop_entry, capid);
1122
1123 if (prctl(PR_CAPBSET_DROP, capid, 0, 0, 0)) {
1124 SYSERROR("failed to remove %s capability", drop_entry);
1125 return -1;
1126 }
1127
1128 }
1129
1130 DEBUG("capabilities has been setup");
1131
1132 return 0;
1133}
1134
0ad19a3f 1135static int setup_hw_addr(char *hwaddr, const char *ifname)
1136{
1137 struct sockaddr sockaddr;
1138 struct ifreq ifr;
1139 int ret, fd;
1140
3cfc0f3a
MN
1141 ret = lxc_convert_mac(hwaddr, &sockaddr);
1142 if (ret) {
1143 ERROR("mac address '%s' conversion failed : %s",
1144 hwaddr, strerror(-ret));
0ad19a3f 1145 return -1;
1146 }
1147
1148 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
1149 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
1150
1151 fd = socket(AF_INET, SOCK_DGRAM, 0);
1152 if (fd < 0) {
3ab87b66 1153 ERROR("socket failure : %s", strerror(errno));
0ad19a3f 1154 return -1;
1155 }
1156
1157 ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
1158 close(fd);
1159 if (ret)
3ab87b66 1160 ERROR("ioctl failure : %s", strerror(errno));
0ad19a3f 1161
cd54d859
DL
1162 DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifname);
1163
0ad19a3f 1164 return ret;
1165}
1166
82d5ae15 1167static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
0ad19a3f 1168{
82d5ae15
DL
1169 struct lxc_list *iterator;
1170 struct lxc_inetdev *inetdev;
3cfc0f3a 1171 int err;
0ad19a3f 1172
82d5ae15
DL
1173 lxc_list_for_each(iterator, ip) {
1174
1175 inetdev = iterator->elem;
1176
0093bb8c
DL
1177 err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
1178 &inetdev->bcast, inetdev->prefix);
3cfc0f3a
MN
1179 if (err) {
1180 ERROR("failed to setup_ipv4_addr ifindex %d : %s",
1181 ifindex, strerror(-err));
82d5ae15
DL
1182 return -1;
1183 }
1184 }
1185
1186 return 0;
0ad19a3f 1187}
1188
82d5ae15 1189static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
0ad19a3f 1190{
82d5ae15 1191 struct lxc_list *iterator;
7fa9074f 1192 struct lxc_inet6dev *inet6dev;
3cfc0f3a 1193 int err;
0ad19a3f 1194
82d5ae15
DL
1195 lxc_list_for_each(iterator, ip) {
1196
1197 inet6dev = iterator->elem;
1198
b3df193c 1199 err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
0093bb8c
DL
1200 &inet6dev->mcast, &inet6dev->acast,
1201 inet6dev->prefix);
3cfc0f3a
MN
1202 if (err) {
1203 ERROR("failed to setup_ipv6_addr ifindex %d : %s",
1204 ifindex, strerror(-err));
82d5ae15 1205 return -1;
3cfc0f3a 1206 }
82d5ae15
DL
1207 }
1208
1209 return 0;
0ad19a3f 1210}
1211
82d5ae15 1212static int setup_netdev(struct lxc_netdev *netdev)
0ad19a3f 1213{
0ad19a3f 1214 char ifname[IFNAMSIZ];
0ad19a3f 1215 char *current_ifname = ifname;
3cfc0f3a 1216 int err;
0ad19a3f 1217
82d5ae15
DL
1218 /* empty network namespace */
1219 if (!netdev->ifindex) {
b0efbac4 1220 if (netdev->flags & IFF_UP) {
3cfc0f3a
MN
1221 err = lxc_device_up("lo");
1222 if (err) {
1223 ERROR("failed to set the loopback up : %s",
1224 strerror(-err));
82d5ae15
DL
1225 return -1;
1226 }
82d5ae15 1227 }
7b57e8b6 1228 return 0;
0ad19a3f 1229 }
13954cce 1230
82d5ae15
DL
1231 /* retrieve the name of the interface */
1232 if (!if_indextoname(netdev->ifindex, current_ifname)) {
36eb9bde 1233 ERROR("no interface corresponding to index '%d'",
82d5ae15 1234 netdev->ifindex);
0ad19a3f 1235 return -1;
1236 }
13954cce 1237
018ef520 1238 /* default: let the system to choose one interface name */
9d083402 1239 if (!netdev->name)
fb6d9b2f
DL
1240 netdev->name = netdev->type == LXC_NET_PHYS ?
1241 netdev->link : "eth%d";
018ef520 1242
82d5ae15 1243 /* rename the interface name */
3cfc0f3a
MN
1244 err = lxc_device_rename(ifname, netdev->name);
1245 if (err) {
1246 ERROR("failed to rename %s->%s : %s", ifname, netdev->name,
1247 strerror(-err));
018ef520
DL
1248 return -1;
1249 }
1250
1251 /* Re-read the name of the interface because its name has changed
1252 * and would be automatically allocated by the system
1253 */
82d5ae15 1254 if (!if_indextoname(netdev->ifindex, current_ifname)) {
018ef520 1255 ERROR("no interface corresponding to index '%d'",
82d5ae15 1256 netdev->ifindex);
018ef520 1257 return -1;
0ad19a3f 1258 }
1259
82d5ae15
DL
1260 /* set a mac address */
1261 if (netdev->hwaddr) {
1262 if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
36eb9bde 1263 ERROR("failed to setup hw address for '%s'",
82d5ae15 1264 current_ifname);
0ad19a3f 1265 return -1;
1266 }
1267 }
1268
82d5ae15
DL
1269 /* setup ipv4 addresses on the interface */
1270 if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
36eb9bde 1271 ERROR("failed to setup ip addresses for '%s'",
0ad19a3f 1272 ifname);
1273 return -1;
1274 }
1275
82d5ae15
DL
1276 /* setup ipv6 addresses on the interface */
1277 if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
36eb9bde 1278 ERROR("failed to setup ipv6 addresses for '%s'",
0ad19a3f 1279 ifname);
1280 return -1;
1281 }
1282
82d5ae15 1283 /* set the network device up */
b0efbac4 1284 if (netdev->flags & IFF_UP) {
3cfc0f3a
MN
1285 int err;
1286
1287 err = lxc_device_up(current_ifname);
1288 if (err) {
1289 ERROR("failed to set '%s' up : %s", current_ifname,
1290 strerror(-err));
0ad19a3f 1291 return -1;
1292 }
1293
1294 /* the network is up, make the loopback up too */
3cfc0f3a
MN
1295 err = lxc_device_up("lo");
1296 if (err) {
1297 ERROR("failed to set the loopback up : %s",
1298 strerror(-err));
0ad19a3f 1299 return -1;
1300 }
1301 }
1302
cd54d859
DL
1303 DEBUG("'%s' has been setup", current_ifname);
1304
0ad19a3f 1305 return 0;
1306}
1307
5f4535a3 1308static int setup_network(struct lxc_list *network)
0ad19a3f 1309{
82d5ae15 1310 struct lxc_list *iterator;
82d5ae15 1311 struct lxc_netdev *netdev;
0ad19a3f 1312
5f4535a3 1313 lxc_list_for_each(iterator, network) {
cd54d859 1314
5f4535a3 1315 netdev = iterator->elem;
82d5ae15
DL
1316
1317 if (setup_netdev(netdev)) {
1318 ERROR("failed to setup netdev");
1319 return -1;
1320 }
1321 }
cd54d859 1322
5f4535a3
DL
1323 if (!lxc_list_empty(network))
1324 INFO("network has been setup");
cd54d859
DL
1325
1326 return 0;
0ad19a3f 1327}
1328
7b379ab3 1329struct lxc_conf *lxc_conf_init(void)
089cd8b8 1330{
7b379ab3
MN
1331 struct lxc_conf *new;
1332
1333 new = malloc(sizeof(*new));
1334 if (!new) {
1335 ERROR("lxc_conf_init : %m");
1336 return NULL;
1337 }
1338 memset(new, 0, sizeof(*new));
1339
cccc74b5 1340 new->personality = -1;
28a4b0e5 1341 new->console.path = NULL;
63376d7d
DL
1342 new->console.peer = -1;
1343 new->console.master = -1;
1344 new->console.slave = -1;
1345 new->console.name[0] = '\0';
12297168 1346 new->rootfs.mount = LXCROOTFSMOUNT;
7b379ab3
MN
1347 lxc_list_init(&new->cgroup);
1348 lxc_list_init(&new->network);
1349 lxc_list_init(&new->mount_list);
81810dd1 1350 lxc_list_init(&new->caps);
7b379ab3
MN
1351
1352 return new;
089cd8b8
DL
1353}
1354
e3b4c4c4 1355static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 1356{
8634bc19 1357 char veth1buf[IFNAMSIZ], *veth1;
0e391e57 1358 char veth2buf[IFNAMSIZ], *veth2;
3cfc0f3a 1359 int err;
13954cce 1360
e892973e
DL
1361 if (netdev->priv.veth_attr.pair)
1362 veth1 = netdev->priv.veth_attr.pair;
8634bc19
MT
1363 else {
1364 snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
0e391e57 1365 veth1 = mktemp(veth1buf);
8634bc19 1366 }
82d5ae15 1367
0e391e57
DL
1368 snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
1369 veth2 = mktemp(veth2buf);
82d5ae15
DL
1370
1371 if (!strlen(veth1) || !strlen(veth2)) {
1372 ERROR("failed to allocate a temporary name");
1373 return -1;
0ad19a3f 1374 }
1375
3cfc0f3a
MN
1376 err = lxc_veth_create(veth1, veth2);
1377 if (err) {
1378 ERROR("failed to create %s-%s : %s", veth1, veth2,
1379 strerror(-err));
6ab9ab6d 1380 return -1;
0ad19a3f 1381 }
13954cce 1382
82d5ae15 1383 if (netdev->mtu) {
3cfc0f3a
MN
1384 err = lxc_device_set_mtu(veth1, atoi(netdev->mtu));
1385 if (!err)
1386 err = lxc_device_set_mtu(veth2, atoi(netdev->mtu));
1387 if (err) {
1388 ERROR("failed to set mtu '%s' for %s-%s : %s",
1389 netdev->mtu, veth1, veth2, strerror(-err));
eb14c10a 1390 goto out_delete;
75d09f83
DL
1391 }
1392 }
1393
3cfc0f3a
MN
1394 if (netdev->link) {
1395 err = lxc_bridge_attach(netdev->link, veth1);
1396 if (err) {
1397 ERROR("failed to attach '%s' to the bridge '%s' : %s",
1398 veth1, netdev->link, strerror(-err));
1399 goto out_delete;
1400 }
eb14c10a
DL
1401 }
1402
82d5ae15
DL
1403 netdev->ifindex = if_nametoindex(veth2);
1404 if (!netdev->ifindex) {
36eb9bde 1405 ERROR("failed to retrieve the index for %s", veth2);
eb14c10a
DL
1406 goto out_delete;
1407 }
1408
6e35af2e
DL
1409 err = lxc_device_up(veth1);
1410 if (err) {
1411 ERROR("failed to set %s up : %s", veth1, strerror(-err));
1412 goto out_delete;
0ad19a3f 1413 }
1414
e3b4c4c4 1415 if (netdev->upscript) {
751d9dcd
DL
1416 err = run_script(handler->name, "net", netdev->upscript, "up",
1417 "veth", veth1, (char*) NULL);
1418 if (err)
e3b4c4c4 1419 goto out_delete;
e3b4c4c4
ST
1420 }
1421
82d5ae15
DL
1422 DEBUG("instanciated veth '%s/%s', index is '%d'",
1423 veth1, veth2, netdev->ifindex);
1424
6ab9ab6d 1425 return 0;
eb14c10a
DL
1426
1427out_delete:
1428 lxc_device_delete(veth1);
6ab9ab6d 1429 return -1;
13954cce 1430}
d957ae2d 1431
e3b4c4c4 1432static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 1433{
0e391e57 1434 char peerbuf[IFNAMSIZ], *peer;
3cfc0f3a 1435 int err;
d957ae2d
MT
1436
1437 if (!netdev->link) {
1438 ERROR("no link specified for macvlan netdev");
1439 return -1;
1440 }
13954cce 1441
0e391e57 1442 snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
82d5ae15 1443
0e391e57 1444 peer = mktemp(peerbuf);
82d5ae15
DL
1445 if (!strlen(peer)) {
1446 ERROR("failed to make a temporary name");
1447 return -1;
0ad19a3f 1448 }
1449
3cfc0f3a
MN
1450 err = lxc_macvlan_create(netdev->link, peer,
1451 netdev->priv.macvlan_attr.mode);
1452 if (err) {
1453 ERROR("failed to create macvlan interface '%s' on '%s' : %s",
1454 peer, netdev->link, strerror(-err));
d957ae2d 1455 return -1;
0ad19a3f 1456 }
1457
82d5ae15
DL
1458 netdev->ifindex = if_nametoindex(peer);
1459 if (!netdev->ifindex) {
36eb9bde 1460 ERROR("failed to retrieve the index for %s", peer);
d957ae2d
MT
1461 lxc_device_delete(peer);
1462 return -1;
22ebac19 1463 }
1464
e3b4c4c4 1465 if (netdev->upscript) {
751d9dcd
DL
1466 err = run_script(handler->name, "net", netdev->upscript, "up",
1467 "macvlan", netdev->link, (char*) NULL);
1468 if (err)
e3b4c4c4 1469 return -1;
e3b4c4c4
ST
1470 }
1471
e892973e
DL
1472 DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'",
1473 peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
0ad19a3f 1474
d957ae2d 1475 return 0;
0ad19a3f 1476}
1477
26c39028 1478/* XXX: merge with instanciate_macvlan */
e3b4c4c4 1479static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
26c39028
JHS
1480{
1481 char peer[IFNAMSIZ];
3cfc0f3a 1482 int err;
26c39028
JHS
1483
1484 if (!netdev->link) {
1485 ERROR("no link specified for vlan netdev");
1486 return -1;
1487 }
1488
e892973e 1489 snprintf(peer, sizeof(peer), "vlan%d", netdev->priv.vlan_attr.vid);
26c39028 1490
3cfc0f3a
MN
1491 err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
1492 if (err) {
1493 ERROR("failed to create vlan interface '%s' on '%s' : %s",
1494 peer, netdev->link, strerror(-err));
26c39028
JHS
1495 return -1;
1496 }
1497
1498 netdev->ifindex = if_nametoindex(peer);
1499 if (!netdev->ifindex) {
1500 ERROR("failed to retrieve the ifindex for %s", peer);
1501 lxc_device_delete(peer);
1502 return -1;
1503 }
1504
e892973e
DL
1505 DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000",
1506 netdev->ifindex);
1507
26c39028
JHS
1508 return 0;
1509}
1510
e3b4c4c4 1511static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 1512{
6168e99f
DL
1513 if (!netdev->link) {
1514 ERROR("no link specified for the physical interface");
1515 return -1;
1516 }
1517
9d083402 1518 netdev->ifindex = if_nametoindex(netdev->link);
82d5ae15 1519 if (!netdev->ifindex) {
9d083402 1520 ERROR("failed to retrieve the index for %s", netdev->link);
0ad19a3f 1521 return -1;
1522 }
1523
e3b4c4c4
ST
1524 if (netdev->upscript) {
1525 int err;
751d9dcd
DL
1526 err = run_script(handler->name, "net", netdev->upscript,
1527 "up", "phys", netdev->link, (char*) NULL);
1528 if (err)
e3b4c4c4 1529 return -1;
e3b4c4c4
ST
1530 }
1531
82d5ae15 1532 return 0;
0ad19a3f 1533}
1534
e3b4c4c4 1535static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 1536{
82d5ae15 1537 netdev->ifindex = 0;
e3b4c4c4
ST
1538 if (netdev->upscript) {
1539 int err;
751d9dcd
DL
1540 err = run_script(handler->name, "net", netdev->upscript,
1541 "up", "empty", (char*) NULL);
1542 if (err)
e3b4c4c4 1543 return -1;
e3b4c4c4 1544 }
82d5ae15 1545 return 0;
0ad19a3f 1546}
1547
e3b4c4c4 1548int lxc_create_network(struct lxc_handler *handler)
0ad19a3f 1549{
e3b4c4c4 1550 struct lxc_list *network = &handler->conf->network;
82d5ae15 1551 struct lxc_list *iterator;
82d5ae15 1552 struct lxc_netdev *netdev;
0ad19a3f 1553
5f4535a3 1554 lxc_list_for_each(iterator, network) {
0ad19a3f 1555
5f4535a3 1556 netdev = iterator->elem;
13954cce 1557
24654103 1558 if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) {
82d5ae15 1559 ERROR("invalid network configuration type '%d'",
5f4535a3 1560 netdev->type);
82d5ae15
DL
1561 return -1;
1562 }
0ad19a3f 1563
e3b4c4c4 1564 if (netdev_conf[netdev->type](handler, netdev)) {
82d5ae15
DL
1565 ERROR("failed to create netdev");
1566 return -1;
1567 }
e3b4c4c4 1568
0ad19a3f 1569 }
1570
1571 return 0;
1572}
1573
7fef7a06
DL
1574void lxc_delete_network(struct lxc_list *network)
1575{
1576 struct lxc_list *iterator;
1577 struct lxc_netdev *netdev;
1578
1579 lxc_list_for_each(iterator, network) {
1580 netdev = iterator->elem;
96bcd56a 1581 if (netdev->ifindex > 0 && netdev->type != LXC_NET_PHYS)
7fef7a06
DL
1582 lxc_device_delete_index(netdev->ifindex);
1583 }
1584}
1585
5f4535a3 1586int lxc_assign_network(struct lxc_list *network, pid_t pid)
0ad19a3f 1587{
82d5ae15 1588 struct lxc_list *iterator;
82d5ae15 1589 struct lxc_netdev *netdev;
3cfc0f3a 1590 int err;
0ad19a3f 1591
5f4535a3 1592 lxc_list_for_each(iterator, network) {
82d5ae15 1593
5f4535a3 1594 netdev = iterator->elem;
82d5ae15 1595
236087a6
DL
1596 /* empty network namespace, nothing to move */
1597 if (!netdev->ifindex)
1598 continue;
1599
3cfc0f3a
MN
1600 err = lxc_device_move(netdev->ifindex, pid);
1601 if (err) {
1602 ERROR("failed to move '%s' to the container : %s",
1603 netdev->link, strerror(-err));
82d5ae15
DL
1604 return -1;
1605 }
1606
9d083402 1607 DEBUG("move '%s' to '%d'", netdev->link, pid);
0ad19a3f 1608 }
1609
1610 return 0;
1611}
1612
5e4a62bf 1613int lxc_create_tty(const char *name, struct lxc_conf *conf)
b0a33c1e 1614{
5e4a62bf 1615 struct lxc_tty_info *tty_info = &conf->tty_info;
985d15b1 1616 int i;
b0a33c1e 1617
5e4a62bf
DL
1618 /* no tty in the configuration */
1619 if (!conf->tty)
b0a33c1e 1620 return 0;
1621
13954cce 1622 tty_info->pty_info =
e4e7d59d 1623 malloc(sizeof(*tty_info->pty_info)*conf->tty);
b0a33c1e 1624 if (!tty_info->pty_info) {
36eb9bde 1625 SYSERROR("failed to allocate pty_info");
985d15b1 1626 return -1;
b0a33c1e 1627 }
1628
985d15b1 1629 for (i = 0; i < conf->tty; i++) {
13954cce 1630
b0a33c1e 1631 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
1632
13954cce 1633 if (openpty(&pty_info->master, &pty_info->slave,
b0a33c1e 1634 pty_info->name, NULL, NULL)) {
36eb9bde 1635 SYSERROR("failed to create pty #%d", i);
985d15b1
MT
1636 tty_info->nbtty = i;
1637 lxc_delete_tty(tty_info);
1638 return -1;
b0a33c1e 1639 }
1640
5332bb84
DL
1641 DEBUG("allocated pty '%s' (%d/%d)",
1642 pty_info->name, pty_info->master, pty_info->slave);
1643
b035ad62
MS
1644 /* Prevent leaking the file descriptors to the container */
1645 fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
1646 fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
1647
b0a33c1e 1648 pty_info->busy = 0;
1649 }
1650
985d15b1 1651 tty_info->nbtty = conf->tty;
1ac470c0
DL
1652
1653 INFO("tty's configured");
1654
985d15b1 1655 return 0;
b0a33c1e 1656}
1657
1658void lxc_delete_tty(struct lxc_tty_info *tty_info)
1659{
1660 int i;
1661
1662 for (i = 0; i < tty_info->nbtty; i++) {
1663 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
1664
1665 close(pty_info->master);
1666 close(pty_info->slave);
1667 }
1668
1669 free(tty_info->pty_info);
1670 tty_info->nbtty = 0;
1671}
1672
571e6ec8 1673int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
0ad19a3f 1674{
571e6ec8 1675 if (setup_utsname(lxc_conf->utsname)) {
36eb9bde 1676 ERROR("failed to setup the utsname for '%s'", name);
95b5ffaf 1677 return -1;
0ad19a3f 1678 }
1679
5f4535a3 1680 if (setup_network(&lxc_conf->network)) {
36eb9bde 1681 ERROR("failed to setup the network for '%s'", name);
95b5ffaf 1682 return -1;
0ad19a3f 1683 }
1684
ac778708
DL
1685 if (setup_rootfs(&lxc_conf->rootfs)) {
1686 ERROR("failed to setup rootfs for '%s'", name);
95b5ffaf 1687 return -1;
0ad19a3f 1688 }
1689
59760f5d 1690 if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab)) {
36eb9bde 1691 ERROR("failed to setup the mounts for '%s'", name);
95b5ffaf 1692 return -1;
576f946d 1693 }
1694
59760f5d 1695 if (setup_mount_entries(&lxc_conf->rootfs, &lxc_conf->mount_list)) {
e7938e9e
MN
1696 ERROR("failed to setup the mount entries for '%s'", name);
1697 return -1;
1698 }
1699
ac778708
DL
1700 if (setup_cgroup(name, &lxc_conf->cgroup)) {
1701 ERROR("failed to setup the cgroups for '%s'", name);
1702 return -1;
1703 }
1704
33fcb7a0 1705 if (setup_console(&lxc_conf->rootfs, &lxc_conf->console)) {
36eb9bde 1706 ERROR("failed to setup the console for '%s'", name);
95b5ffaf 1707 return -1;
6e590161 1708 }
1709
33fcb7a0 1710 if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info)) {
36eb9bde 1711 ERROR("failed to setup the ttys for '%s'", name);
95b5ffaf 1712 return -1;
b0a33c1e 1713 }
1714
ac778708 1715 if (setup_pivot_root(&lxc_conf->rootfs)) {
36eb9bde 1716 ERROR("failed to set rootfs for '%s'", name);
95b5ffaf 1717 return -1;
ed502555 1718 }
1719
571e6ec8 1720 if (setup_pts(lxc_conf->pts)) {
36eb9bde 1721 ERROR("failed to setup the new pts instance");
95b5ffaf 1722 return -1;
3c26f34e 1723 }
1724
cccc74b5
DL
1725 if (setup_personality(lxc_conf->personality)) {
1726 ERROR("failed to setup personality");
1727 return -1;
1728 }
1729
81810dd1
DL
1730 if (setup_caps(&lxc_conf->caps)) {
1731 ERROR("failed to drop capabilities");
1732 return -1;
1733 }
1734
cd54d859
DL
1735 NOTICE("'%s' is setup.", name);
1736
0ad19a3f 1737 return 0;
1738}