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