]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/conf.c
stop config reading if cgroup setting failed
[mirror_lxc.git] / src / lxc / conf.c
CommitLineData
0ad19a3f 1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23#define _GNU_SOURCE
24#include <stdio.h>
25#undef _GNU_SOURCE
26#include <stdlib.h>
27#include <errno.h>
28#include <string.h>
29#include <dirent.h>
30#include <mntent.h>
31#include <unistd.h>
b0a33c1e 32#include <pty.h>
0ad19a3f 33
34#include <sys/types.h>
35#include <sys/utsname.h>
36#include <sys/param.h>
37#include <sys/stat.h>
38#include <sys/socket.h>
39#include <sys/mount.h>
40#include <sys/mman.h>
41
42#include <arpa/inet.h>
43#include <fcntl.h>
44#include <netinet/in.h>
45#include <net/if.h>
6f4a3756 46#include <libgen.h>
0ad19a3f 47
e5bda9ee 48#include "network.h"
49#include "error.h"
b2718c72 50#include "parse.h"
881450bb 51#include "config.h"
e5bda9ee 52
b113348e 53#include <lxc/lxc.h>
36eb9bde
CLG
54#include <lxc/log.h>
55
56lxc_log_define(lxc_conf, lxc);
e5bda9ee 57
0ad19a3f 58#define MAXHWLEN 18
59#define MAXINDEXLEN 20
442cbbe6 60#define MAXMTULEN 16
0ad19a3f 61#define MAXLINELEN 128
62
fdc03323
DL
63#ifndef MS_REC
64#define MS_REC 16384
65#endif
66
82d5ae15 67typedef int (*instanciate_cb)(struct lxc_netdev *);
0ad19a3f 68
998ac676
RT
69struct mount_opt {
70 char *name;
71 int clear;
72 int flag;
73};
74
82d5ae15
DL
75static int instanciate_veth(struct lxc_netdev *);
76static int instanciate_macvlan(struct lxc_netdev *);
77static int instanciate_phys(struct lxc_netdev *);
78static int instanciate_empty(struct lxc_netdev *);
79
80static instanciate_cb netdev_conf[MAXCONFTYPE + 1] = {
81 [VETH] = instanciate_veth,
82 [MACVLAN] = instanciate_macvlan,
83 [PHYS] = instanciate_phys,
84 [EMPTY] = instanciate_empty,
0ad19a3f 85};
86
998ac676
RT
87static struct mount_opt mount_opt[] = {
88 { "defaults", 0, 0 },
89 { "ro", 0, MS_RDONLY },
90 { "rw", 1, MS_RDONLY },
91 { "suid", 1, MS_NOSUID },
92 { "nosuid", 0, MS_NOSUID },
93 { "dev", 1, MS_NODEV },
94 { "nodev", 0, MS_NODEV },
95 { "exec", 1, MS_NOEXEC },
96 { "noexec", 0, MS_NOEXEC },
97 { "sync", 0, MS_SYNCHRONOUS },
98 { "async", 1, MS_SYNCHRONOUS },
99 { "remount", 0, MS_REMOUNT },
100 { "mand", 0, MS_MANDLOCK },
101 { "nomand", 1, MS_MANDLOCK },
102 { "atime", 1, MS_NOATIME },
103 { "noatime", 0, MS_NOATIME },
104 { "diratime", 1, MS_NODIRATIME },
105 { "nodiratime", 0, MS_NODIRATIME },
106 { "bind", 0, MS_BIND },
107 { "rbind", 0, MS_BIND|MS_REC },
108 { NULL, 0, 0 },
109};
110
78ae2fcc 111static int configure_find_fstype_cb(void* buffer, void *data)
112{
113 struct cbarg {
114 const char *rootfs;
115 const char *testdir;
116 char *fstype;
117 int mntopt;
118 } *cbarg = data;
119
120 char *fstype;
121
122 /* we don't try 'nodev' entries */
123 if (strstr(buffer, "nodev"))
124 return 0;
125
126 fstype = buffer;
b2718c72 127 fstype += lxc_char_left_gc(fstype, strlen(fstype));
128 fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
78ae2fcc 129
130 if (mount(cbarg->rootfs, cbarg->testdir, fstype, cbarg->mntopt, NULL))
131 return 0;
132
133 /* found ! */
134 umount(cbarg->testdir);
135 strcpy(cbarg->fstype, fstype);
136
137 return 1;
138}
139
140/* find the filesystem type with brute force */
141static int configure_find_fstype(const char *rootfs, char *fstype, int mntopt)
142{
143 int i, found;
144 char buffer[MAXPATHLEN];
145
146 struct cbarg {
147 const char *rootfs;
148 const char *testdir;
149 char *fstype;
150 int mntopt;
151 } cbarg = {
152 .rootfs = rootfs,
153 .fstype = fstype,
154 .mntopt = mntopt,
155 };
156
157 /* first we check with /etc/filesystems, in case the modules
158 * are auto-loaded and fall back to the supported kernel fs
159 */
160 char *fsfile[] = {
161 "/etc/filesystems",
162 "/proc/filesystems",
163 };
164
165 cbarg.testdir = tempnam("/tmp", "lxc-");
166 if (!cbarg.testdir) {
36eb9bde 167 SYSERROR("failed to build a temp name");
78ae2fcc 168 return -1;
169 }
170
171 if (mkdir(cbarg.testdir, 0755)) {
36eb9bde 172 SYSERROR("failed to create temporary directory");
78ae2fcc 173 return -1;
174 }
175
176 for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) {
177
b2718c72 178 found = lxc_file_for_each_line(fsfile[i],
179 configure_find_fstype_cb,
180 buffer, sizeof(buffer), &cbarg);
78ae2fcc 181
182 if (found < 0) {
36eb9bde 183 SYSERROR("failed to read '%s'", fsfile[i]);
78ae2fcc 184 goto out;
185 }
186
187 if (found)
188 break;
189 }
190
191 if (!found) {
36eb9bde 192 ERROR("failed to determine fs type for '%s'", rootfs);
78ae2fcc 193 goto out;
194 }
195
196out:
197 rmdir(cbarg.testdir);
198 return found - 1;
199}
200
201static int configure_rootfs_dir_cb(const char *rootfs, const char *absrootfs,
202 FILE *f)
203{
fdc03323 204 return fprintf(f, "%s %s none rbind 0 0\n", absrootfs, rootfs);
78ae2fcc 205}
206
207static int configure_rootfs_blk_cb(const char *rootfs, const char *absrootfs,
208 FILE *f)
209{
210 char fstype[MAXPATHLEN];
211
212 if (configure_find_fstype(absrootfs, fstype, 0)) {
36eb9bde 213 ERROR("failed to configure mount for block device '%s'",
78ae2fcc 214 absrootfs);
215 return -1;
216 }
217
218 return fprintf(f, "%s %s %s defaults 0 0\n", absrootfs, rootfs, fstype);
219}
220
eae6543d 221static int configure_rootfs(const char *name, const char *rootfs)
0ad19a3f 222{
223 char path[MAXPATHLEN];
b09ef133 224 char absrootfs[MAXPATHLEN];
9b0f0477 225 char fstab[MAXPATHLEN];
78ae2fcc 226 struct stat s;
9b0f0477 227 FILE *f;
78ae2fcc 228 int i, ret;
229
230 typedef int (*rootfs_cb)(const char *, const char *, FILE *);
231
232 struct rootfs_type {
233 int type;
234 rootfs_cb cb;
235 } rtfs_type[] = {
236 { __S_IFDIR, configure_rootfs_dir_cb },
237 { __S_IFBLK, configure_rootfs_blk_cb },
238 };
0ad19a3f 239
4c8ab83b 240 if (!realpath(rootfs, absrootfs)) {
36eb9bde 241 SYSERROR("failed to get real path for '%s'", rootfs);
4c8ab83b 242 return -1;
243 }
b09ef133 244
4c8ab83b 245 snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name);
b09ef133 246
78ae2fcc 247 if (mkdir(path, 0755)) {
36eb9bde 248 SYSERROR("failed to create the '%s' directory", path);
78ae2fcc 249 return -1;
250 }
251
b09ef133 252 if (access(absrootfs, F_OK)) {
36eb9bde 253 SYSERROR("'%s' is not accessible", absrootfs);
b09ef133 254 return -1;
255 }
256
78ae2fcc 257 if (stat(absrootfs, &s)) {
36eb9bde 258 SYSERROR("failed to stat '%s'", absrootfs);
9b0f0477 259 return -1;
260 }
261
78ae2fcc 262 for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) {
9b0f0477 263
78ae2fcc 264 if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
265 continue;
9b0f0477 266
78ae2fcc 267 snprintf(fstab, MAXPATHLEN, LXCPATH "/%s/fstab", name);
4c8ab83b 268
78ae2fcc 269 f = fopen(fstab, "a+");
270 if (!f) {
36eb9bde 271 SYSERROR("failed to open fstab file");
78ae2fcc 272 return -1;
273 }
9b0f0477 274
78ae2fcc 275 ret = rtfs_type[i].cb(path, absrootfs, f);
9b0f0477 276
78ae2fcc 277 fclose(f);
278
279 if (ret < 0) {
36eb9bde 280 ERROR("failed to add rootfs mount in fstab");
78ae2fcc 281 return -1;
282 }
283
284 snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs/rootfs", name);
285
286 return symlink(absrootfs, path);
287 }
9b0f0477 288
36eb9bde 289 ERROR("unsupported rootfs type for '%s'", absrootfs);
78ae2fcc 290 return -1;
0ad19a3f 291}
292
4e5440c6 293static int setup_utsname(struct utsname *utsname)
0ad19a3f 294{
4e5440c6
DL
295 if (!utsname)
296 return 0;
0ad19a3f 297
4e5440c6
DL
298 if (sethostname(utsname->nodename, strlen(utsname->nodename))) {
299 SYSERROR("failed to set the hostname to '%s'", utsname->nodename);
0ad19a3f 300 return -1;
301 }
302
4e5440c6 303 INFO("'%s' hostname has been setup", utsname->nodename);
cd54d859 304
0ad19a3f 305 return 0;
306}
307
52e35957 308static int setup_tty(const char *rootfs, const struct lxc_tty_info *tty_info)
b0a33c1e 309{
310 char path[MAXPATHLEN];
311 int i;
312
313 for (i = 0; i < tty_info->nbtty; i++) {
314
315 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
316
52e35957
DL
317 snprintf(path, sizeof(path), "%s/dev/tty%d",
318 rootfs ? rootfs : "", i + 1);
b0a33c1e 319
13954cce 320 /* At this point I can not use the "access" function
b0a33c1e 321 * to check the file is present or not because it fails
322 * with EACCES errno and I don't know why :( */
13954cce 323
b0a33c1e 324 if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
36eb9bde 325 WARN("failed to mount '%s'->'%s'",
52e35957 326 pty_info->name, path);
b0a33c1e 327 continue;
328 }
329 }
330
cd54d859
DL
331 INFO("%d tty(s) has been setup", tty_info->nbtty);
332
b0a33c1e 333 return 0;
334}
335
c69bd12f 336static int setup_rootfs(const char *rootfs)
0ad19a3f 337{
c69bd12f
DL
338 char *tmpname;
339 int ret = -1;
0ad19a3f 340
c69bd12f
DL
341 if (!rootfs)
342 return 0;
0ad19a3f 343
c69bd12f
DL
344 tmpname = tempnam("/tmp", "lxc-rootfs");
345 if (!tmpname) {
346 SYSERROR("failed to generate temporary name");
c3f0a28c 347 return -1;
348 }
0ad19a3f 349
c69bd12f
DL
350 if (mkdir(tmpname, 0700)) {
351 SYSERROR("failed to create temporary directory '%s'", tmpname);
352 return -1;
353 }
354
355 if (mount(rootfs, tmpname, "none", MS_BIND|MS_REC, NULL)) {
356 SYSERROR("failed to mount '%s'->'%s'", rootfs, tmpname);
357 goto out;
358 }
359
360 if (chroot(tmpname)) {
361 SYSERROR("failed to set chroot %s", tmpname);
362 goto out;
363 }
364
c3f0a28c 365 if (chdir(getenv("HOME")) && chdir("/")) {
36eb9bde 366 SYSERROR("failed to change to home directory");
c69bd12f 367 goto out;
0ad19a3f 368 }
369
c69bd12f 370 INFO("chrooted to '%s'", rootfs);
cd54d859 371
c69bd12f
DL
372 ret = 0;
373out:
374 rmdir(tmpname);
375 return ret;
0ad19a3f 376}
377
d852c78c 378static int setup_pts(int pts)
3c26f34e 379{
d852c78c
DL
380 if (!pts)
381 return 0;
3c26f34e 382
383 if (!access("/dev/pts/ptmx", F_OK) && umount("/dev/pts")) {
36eb9bde 384 SYSERROR("failed to umount 'dev/pts'");
3c26f34e 385 return -1;
386 }
387
d852c78c 388 if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, "newinstance")) {
36eb9bde 389 SYSERROR("failed to mount a new instance of '/dev/pts'");
3c26f34e 390 return -1;
391 }
392
393 if (chmod("/dev/pts/ptmx", 0666)) {
36eb9bde 394 SYSERROR("failed to set permission for '/dev/pts/ptmx'");
3c26f34e 395 return -1;
396 }
397
398 if (access("/dev/ptmx", F_OK)) {
399 if (!symlink("/dev/pts/ptmx", "/dev/ptmx"))
400 goto out;
36eb9bde 401 SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'");
3c26f34e 402 return -1;
403 }
404
405 /* fallback here, /dev/pts/ptmx exists just mount bind */
406 if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) {
36eb9bde 407 SYSERROR("mount failed '/dev/pts/ptmx'->'/dev/ptmx'");
3c26f34e 408 return -1;
409 }
cd54d859
DL
410
411 INFO("created new pts instance");
d852c78c 412
3c26f34e 413out:
414 return 0;
415}
416
52e35957 417static int setup_console(const char *rootfs, const char *tty)
6e590161 418{
ed502555 419 char console[MAXPATHLEN];
420
52e35957
DL
421 snprintf(console, sizeof(console), "%s/dev/console",
422 rootfs ? rootfs : "");
423
424 /* we have the rootfs with /dev/console but no tty
425 * to be used as console, let's remap /dev/console
426 * to /dev/null to avoid to log to the system console
427 */
428 if (rootfs && !tty[0]) {
429
430 if (!access(console, F_OK)) {
431
432 if (mount("/dev/null", console, "none", MS_BIND, 0)) {
433 SYSERROR("failed to mount '/dev/null'->'%s'",
434 console);
435 return -1;
436 }
437 }
438 }
439
440 if (!tty[0])
441 return 0;
ed502555 442
443 if (access(console, R_OK|W_OK))
6e590161 444 return 0;
13954cce 445
ed502555 446 if (mount(tty, console, "none", MS_BIND, 0)) {
36eb9bde 447 ERROR("failed to mount the console");
6e590161 448 return -1;
449 }
450
cd54d859
DL
451 INFO("console '%s' mounted to '%s'", tty, console);
452
6e590161 453 return 0;
454}
455
102a5303 456static int setup_cgroup(const char *name, struct lxc_list *cgroups)
576f946d 457{
102a5303
DL
458 struct lxc_list *iterator;
459 struct lxc_cgroup *cg;
88329c69 460 int ret = -1;
6f4a3756 461
102a5303
DL
462 if (lxc_list_empty(cgroups))
463 return 0;
6f4a3756 464
102a5303 465 lxc_list_for_each(iterator, cgroups) {
13954cce 466
102a5303 467 cg = iterator->elem;
6f4a3756 468
102a5303 469 if (lxc_cgroup_set(name, cg->subsystem, cg->value))
88329c69 470 goto out;
6f4a3756 471
102a5303 472 DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
6f4a3756 473 }
13954cce 474
88329c69 475 ret = 0;
cd54d859 476 INFO("cgroup has been setup");
88329c69
MN
477out:
478 return ret;
576f946d 479}
480
998ac676
RT
481static void parse_mntopt(char *opt, unsigned long *flags, char **data)
482{
483 struct mount_opt *mo;
484
485 /* If opt is found in mount_opt, set or clear flags.
486 * Otherwise append it to data. */
487
488 for (mo = &mount_opt[0]; mo->name != NULL; mo++) {
489 if (!strncmp(opt, mo->name, strlen(mo->name))) {
490 if (mo->clear)
491 *flags &= ~mo->flag;
492 else
493 *flags |= mo->flag;
494 return;
495 }
496 }
497
498 if (strlen(*data))
499 strcat(*data, ",");
500 strcat(*data, opt);
501}
502
503static int parse_mntopts(struct mntent *mntent, unsigned long *mntflags,
504 char **mntdata)
505{
506 char *s, *data;
507 char *p, *saveptr = NULL;
508
509 if (!mntent->mnt_opts)
510 return 0;
511
512 s = strdup(mntent->mnt_opts);
513 if (!s) {
36eb9bde 514 SYSERROR("failed to allocate memory");
998ac676
RT
515 return -1;
516 }
517
518 data = malloc(strlen(s) + 1);
519 if (!data) {
36eb9bde 520 SYSERROR("failed to allocate memory");
998ac676
RT
521 free(s);
522 return -1;
523 }
524 *data = 0;
525
526 for (p = strtok_r(s, ",", &saveptr); p != NULL;
527 p = strtok_r(NULL, ",", &saveptr))
528 parse_mntopt(p, mntflags, &data);
529
530 if (*data)
531 *mntdata = data;
532 else
533 free(data);
534 free(s);
535
536 return 0;
537}
538
1bc60a65 539static int setup_mount(const char *fstab)
0ad19a3f 540{
0ad19a3f 541 struct mntent *mntent;
542 FILE *file;
543 int ret = -1;
998ac676
RT
544 unsigned long mntflags;
545 char *mntdata;
0ad19a3f 546
1bc60a65
DL
547 if (!fstab)
548 return 0;
0ad19a3f 549
1bc60a65 550 file = setmntent(fstab, "r");
0ad19a3f 551 if (!file) {
1bc60a65
DL
552 SYSERROR("failed to use '%s'", fstab);
553 return -1;
0ad19a3f 554 }
555
998ac676 556 while ((mntent = getmntent(file))) {
1bc60a65 557
998ac676
RT
558 mntflags = 0;
559 mntdata = NULL;
560 if (parse_mntopts(mntent, &mntflags, &mntdata) < 0) {
36eb9bde 561 ERROR("failed to parse mount option '%s'",
998ac676
RT
562 mntent->mnt_opts);
563 goto out;
564 }
0ad19a3f 565
566 if (mount(mntent->mnt_fsname, mntent->mnt_dir,
998ac676 567 mntent->mnt_type, mntflags, mntdata)) {
36eb9bde 568 SYSERROR("failed to mount '%s' on '%s'",
0ad19a3f 569 mntent->mnt_fsname, mntent->mnt_dir);
570 goto out;
571 }
998ac676 572
cd54d859
DL
573 DEBUG("mounted %s on %s, type %s", mntent->mnt_fsname,
574 mntent->mnt_dir, mntent->mnt_type);
575
998ac676 576 free(mntdata);
0ad19a3f 577 }
cd54d859 578
0ad19a3f 579 ret = 0;
cd54d859
DL
580
581 INFO("mount points have been setup");
0ad19a3f 582out:
583 endmntent(file);
584 return ret;
585}
586
0ad19a3f 587static int setup_hw_addr(char *hwaddr, const char *ifname)
588{
589 struct sockaddr sockaddr;
590 struct ifreq ifr;
591 int ret, fd;
592
593 if (lxc_convert_mac(hwaddr, &sockaddr)) {
3ab87b66 594 ERROR("conversion has failed");
0ad19a3f 595 return -1;
596 }
597
598 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
599 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
600
601 fd = socket(AF_INET, SOCK_DGRAM, 0);
602 if (fd < 0) {
3ab87b66 603 ERROR("socket failure : %s", strerror(errno));
0ad19a3f 604 return -1;
605 }
606
607 ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
608 close(fd);
609 if (ret)
3ab87b66 610 ERROR("ioctl failure : %s", strerror(errno));
0ad19a3f 611
cd54d859
DL
612 DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifname);
613
0ad19a3f 614 return ret;
615}
616
82d5ae15 617static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
0ad19a3f 618{
82d5ae15
DL
619 struct lxc_list *iterator;
620 struct lxc_inetdev *inetdev;
0ad19a3f 621
82d5ae15
DL
622 lxc_list_for_each(iterator, ip) {
623
624 inetdev = iterator->elem;
625
4bf1968d
DL
626 if (lxc_ip_addr_add(AF_INET, ifindex,
627 &inetdev->addr, inetdev->prefix)) {
82d5ae15
DL
628 return -1;
629 }
630 }
631
632 return 0;
0ad19a3f 633}
634
82d5ae15 635static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
0ad19a3f 636{
82d5ae15 637 struct lxc_list *iterator;
7fa9074f 638 struct lxc_inet6dev *inet6dev;
0ad19a3f 639
82d5ae15
DL
640 lxc_list_for_each(iterator, ip) {
641
642 inet6dev = iterator->elem;
643
4bf1968d
DL
644 if (lxc_ip_addr_add(AF_INET6, ifindex,
645 & inet6dev->addr, inet6dev->prefix))
82d5ae15 646 return -1;
82d5ae15
DL
647 }
648
649 return 0;
0ad19a3f 650}
651
82d5ae15 652static int setup_netdev(struct lxc_netdev *netdev)
0ad19a3f 653{
0ad19a3f 654 char ifname[IFNAMSIZ];
0ad19a3f 655 char *current_ifname = ifname;
0ad19a3f 656
82d5ae15
DL
657 /* empty network namespace */
658 if (!netdev->ifindex) {
659 if (netdev->flags | IFF_UP) {
660 if (lxc_device_up("lo")) {
661 ERROR("failed to set the loopback up");
662 return -1;
663 }
664 return 0;
665 }
0ad19a3f 666 }
13954cce 667
82d5ae15
DL
668 /* retrieve the name of the interface */
669 if (!if_indextoname(netdev->ifindex, current_ifname)) {
36eb9bde 670 ERROR("no interface corresponding to index '%d'",
82d5ae15 671 netdev->ifindex);
0ad19a3f 672 return -1;
673 }
13954cce 674
018ef520 675 /* default: let the system to choose one interface name */
82d5ae15
DL
676 if (!netdev->newname)
677 netdev->newname = "eth%d";
018ef520 678
82d5ae15
DL
679 /* rename the interface name */
680 if (lxc_device_rename(ifname, netdev->newname)) {
018ef520
DL
681 ERROR("failed to rename %s->%s", ifname, current_ifname);
682 return -1;
683 }
684
685 /* Re-read the name of the interface because its name has changed
686 * and would be automatically allocated by the system
687 */
82d5ae15 688 if (!if_indextoname(netdev->ifindex, current_ifname)) {
018ef520 689 ERROR("no interface corresponding to index '%d'",
82d5ae15 690 netdev->ifindex);
018ef520 691 return -1;
0ad19a3f 692 }
693
82d5ae15
DL
694 /* set a mac address */
695 if (netdev->hwaddr) {
696 if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
36eb9bde 697 ERROR("failed to setup hw address for '%s'",
82d5ae15 698 current_ifname);
0ad19a3f 699 return -1;
700 }
701 }
702
82d5ae15
DL
703 /* setup ipv4 addresses on the interface */
704 if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
36eb9bde 705 ERROR("failed to setup ip addresses for '%s'",
0ad19a3f 706 ifname);
707 return -1;
708 }
709
82d5ae15
DL
710 /* setup ipv6 addresses on the interface */
711 if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
36eb9bde 712 ERROR("failed to setup ipv6 addresses for '%s'",
0ad19a3f 713 ifname);
714 return -1;
715 }
716
82d5ae15
DL
717 /* set the network device up */
718 if (netdev->flags | IFF_UP) {
497353b6 719 if (lxc_device_up(current_ifname)) {
36eb9bde 720 ERROR("failed to set '%s' up", current_ifname);
0ad19a3f 721 return -1;
722 }
723
724 /* the network is up, make the loopback up too */
497353b6 725 if (lxc_device_up("lo")) {
36eb9bde 726 ERROR("failed to set the loopback up");
0ad19a3f 727 return -1;
728 }
729 }
730
cd54d859
DL
731 DEBUG("'%s' has been setup", current_ifname);
732
0ad19a3f 733 return 0;
734}
735
5f4535a3 736static int setup_network(struct lxc_list *network)
0ad19a3f 737{
82d5ae15 738 struct lxc_list *iterator;
82d5ae15 739 struct lxc_netdev *netdev;
0ad19a3f 740
5f4535a3 741 lxc_list_for_each(iterator, network) {
cd54d859 742
5f4535a3 743 netdev = iterator->elem;
82d5ae15
DL
744
745 if (setup_netdev(netdev)) {
746 ERROR("failed to setup netdev");
747 return -1;
748 }
749 }
cd54d859 750
5f4535a3
DL
751 if (!lxc_list_empty(network))
752 INFO("network has been setup");
cd54d859
DL
753
754 return 0;
0ad19a3f 755}
756
757int conf_has(const char *name, const char *info)
758{
b09ef133 759 int ret = 0;
0ad19a3f 760 char path[MAXPATHLEN];
761 struct stat st;
762
763 snprintf(path, MAXPATHLEN, LXCPATH "/%s/%s", name, info);
764
b09ef133 765 if (!stat(path, &st) || !lstat(path, &st)) {
0ad19a3f 766 ret = 1;
767 goto out;
768 }
769
770 if (errno == ENOENT) {
771 ret = 0;
772 goto out;
773 }
774
36eb9bde 775 SYSERROR("failed to stat %s info", info);
0ad19a3f 776out:
777 return ret;
778}
779
089cd8b8
DL
780int lxc_conf_init(struct lxc_conf *conf)
781{
782 conf->rootfs = NULL;
783 conf->fstab = NULL;
784 conf->utsname = NULL;
785 conf->tty = 0;
786 conf->pts = 0;
571e6ec8 787 conf->console[0] = '\0';
089cd8b8 788 lxc_list_init(&conf->cgroup);
5f4535a3 789 lxc_list_init(&conf->network);
089cd8b8
DL
790 return 0;
791}
792
82d5ae15 793static int instanciate_veth(struct lxc_netdev *netdev)
0ad19a3f 794{
82d5ae15
DL
795 char veth1[IFNAMSIZ];
796 char veth2[IFNAMSIZ];
797 int ret = -1;
13954cce 798
82d5ae15
DL
799 snprintf(veth1, sizeof(veth1), "vethXXXXXX");
800 snprintf(veth2, sizeof(veth2), "vethXXXXXX");
801
802 mktemp(veth1);
803 mktemp(veth2);
804
805 if (!strlen(veth1) || !strlen(veth2)) {
806 ERROR("failed to allocate a temporary name");
807 return -1;
0ad19a3f 808 }
809
eb14c10a 810 if (lxc_veth_create(veth1, veth2)) {
82d5ae15
DL
811 ERROR("failed to create %s-%s/%s",
812 veth1, veth2, netdev->ifname);
0ad19a3f 813 goto out;
814 }
13954cce 815
82d5ae15
DL
816 if (netdev->mtu) {
817 if (lxc_device_set_mtu(veth1, atoi(netdev->mtu))) {
818 ERROR("failed to set mtu '%s' for '%s'",
819 netdev->mtu, veth1);
eb14c10a 820 goto out_delete;
75d09f83
DL
821 }
822
82d5ae15
DL
823 if (lxc_device_set_mtu(veth2, atoi(netdev->mtu))) {
824 ERROR("failed to set mtu '%s' for '%s'",
825 netdev->mtu, veth2);
eb14c10a 826 goto out_delete;
75d09f83
DL
827 }
828 }
829
82d5ae15 830 if (lxc_bridge_attach(netdev->ifname, veth1)) {
36eb9bde 831 ERROR("failed to attach '%s' to the bridge '%s'",
82d5ae15 832 veth1, netdev->ifname);
eb14c10a
DL
833 goto out_delete;
834 }
835
82d5ae15
DL
836 netdev->ifindex = if_nametoindex(veth2);
837 if (!netdev->ifindex) {
36eb9bde 838 ERROR("failed to retrieve the index for %s", veth2);
eb14c10a
DL
839 goto out_delete;
840 }
841
82d5ae15 842 if (netdev->flags & IFF_UP) {
497353b6 843 if (lxc_device_up(veth1)) {
36eb9bde 844 ERROR("failed to set %s up", veth1);
eb14c10a 845 goto out_delete;
0ad19a3f 846 }
847 }
848
82d5ae15
DL
849 DEBUG("instanciated veth '%s/%s', index is '%d'",
850 veth1, veth2, netdev->ifindex);
851
0ad19a3f 852 ret = 0;
853out:
0ad19a3f 854 return ret;
eb14c10a
DL
855
856out_delete:
857 lxc_device_delete(veth1);
858 goto out;
13954cce 859}
82d5ae15 860static int instanciate_macvlan(struct lxc_netdev *netdev)
0ad19a3f 861{
82d5ae15
DL
862 char peer[IFNAMSIZ];
863 int ret = -1;
13954cce 864
82d5ae15 865 snprintf(peer, sizeof(peer), "mcXXXXXX");
22ebac19 866
82d5ae15
DL
867 mktemp(peer);
868
869 if (!strlen(peer)) {
870 ERROR("failed to make a temporary name");
871 return -1;
0ad19a3f 872 }
873
82d5ae15 874 if (lxc_macvlan_create(netdev->ifname, peer)) {
36eb9bde 875 ERROR("failed to create macvlan interface '%s' on '%s'",
82d5ae15 876 peer, netdev->ifname);
0ad19a3f 877 goto out;
878 }
879
82d5ae15
DL
880 netdev->ifindex = if_nametoindex(peer);
881 if (!netdev->ifindex) {
36eb9bde 882 ERROR("failed to retrieve the index for %s", peer);
82d5ae15 883 goto out_delete;
22ebac19 884 }
885
82d5ae15 886 DEBUG("instanciated macvlan '%s', index is '%d'", peer, netdev->ifindex);
0ad19a3f 887
888 ret = 0;
889out:
0ad19a3f 890 return ret;
22ebac19 891
82d5ae15
DL
892out_delete:
893 lxc_device_delete(peer);
894 goto out;
0ad19a3f 895}
896
82d5ae15 897static int instanciate_phys(struct lxc_netdev *netdev)
0ad19a3f 898{
82d5ae15
DL
899 netdev->ifindex = if_nametoindex(netdev->ifname);
900 if (!netdev->ifindex) {
901 ERROR("failed to retrieve the index for %s", netdev->ifname);
0ad19a3f 902 return -1;
903 }
904
82d5ae15 905 return 0;
0ad19a3f 906}
907
82d5ae15 908static int instanciate_empty(struct lxc_netdev *netdev)
0ad19a3f 909{
82d5ae15
DL
910 netdev->ifindex = 0;
911 return 0;
0ad19a3f 912}
913
5f4535a3 914int lxc_create_network(struct lxc_list *network)
0ad19a3f 915{
82d5ae15 916 struct lxc_list *iterator;
82d5ae15 917 struct lxc_netdev *netdev;
0ad19a3f 918
5f4535a3 919 lxc_list_for_each(iterator, network) {
0ad19a3f 920
5f4535a3 921 netdev = iterator->elem;
13954cce 922
5f4535a3 923 if (netdev->type < 0 || netdev->type > MAXCONFTYPE) {
82d5ae15 924 ERROR("invalid network configuration type '%d'",
5f4535a3 925 netdev->type);
82d5ae15
DL
926 return -1;
927 }
0ad19a3f 928
5f4535a3 929 if (netdev_conf[netdev->type](netdev)) {
82d5ae15
DL
930 ERROR("failed to create netdev");
931 return -1;
932 }
0ad19a3f 933 }
934
935 return 0;
936}
937
5f4535a3 938int lxc_assign_network(struct lxc_list *network, pid_t pid)
0ad19a3f 939{
82d5ae15 940 struct lxc_list *iterator;
82d5ae15 941 struct lxc_netdev *netdev;
0ad19a3f 942
5f4535a3 943 lxc_list_for_each(iterator, network) {
82d5ae15 944
5f4535a3 945 netdev = iterator->elem;
82d5ae15
DL
946
947 if (lxc_device_move(netdev->ifindex, pid)) {
948 ERROR("failed to move '%s' to the container",
949 netdev->ifname);
950 return -1;
951 }
952
953 DEBUG("move '%s' to '%d'", netdev->ifname, pid);
0ad19a3f 954 }
955
956 return 0;
957}
958
5e4a62bf 959int lxc_create_tty(const char *name, struct lxc_conf *conf)
b0a33c1e 960{
5e4a62bf 961 struct lxc_tty_info *tty_info = &conf->tty_info;
b0a33c1e 962 int i, ret = -1;
963
5e4a62bf
DL
964 /* no tty in the configuration */
965 if (!conf->tty)
b0a33c1e 966 return 0;
967
5e4a62bf 968 tty_info->nbtty = conf->tty;
13954cce 969 tty_info->pty_info =
b0a33c1e 970 malloc(sizeof(*tty_info->pty_info)*tty_info->nbtty);
13954cce 971
b0a33c1e 972 if (!tty_info->pty_info) {
36eb9bde 973 SYSERROR("failed to allocate pty_info");
b0a33c1e 974 goto out;
975 }
976
977 for (i = 0; i < tty_info->nbtty; i++) {
13954cce 978
b0a33c1e 979 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
980
13954cce 981 if (openpty(&pty_info->master, &pty_info->slave,
b0a33c1e 982 pty_info->name, NULL, NULL)) {
36eb9bde 983 SYSERROR("failed to create pty #%d", i);
b0a33c1e 984 goto out_free;
985 }
986
b035ad62
MS
987 /* Prevent leaking the file descriptors to the container */
988 fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
989 fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
990
b0a33c1e 991 pty_info->busy = 0;
992 }
993
994 ret = 0;
1ac470c0
DL
995
996 INFO("tty's configured");
997
b0a33c1e 998out:
999 return ret;
1000
1001out_free:
1002 free(tty_info->pty_info);
1003 goto out;
1004}
1005
1006void lxc_delete_tty(struct lxc_tty_info *tty_info)
1007{
1008 int i;
1009
1010 for (i = 0; i < tty_info->nbtty; i++) {
1011 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
1012
1013 close(pty_info->master);
1014 close(pty_info->slave);
1015 }
1016
1017 free(tty_info->pty_info);
1018 tty_info->nbtty = 0;
1019}
1020
571e6ec8 1021int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
0ad19a3f 1022{
571e6ec8 1023 if (setup_utsname(lxc_conf->utsname)) {
36eb9bde 1024 ERROR("failed to setup the utsname for '%s'", name);
95b5ffaf 1025 return -1;
0ad19a3f 1026 }
1027
5f4535a3 1028 if (setup_network(&lxc_conf->network)) {
36eb9bde 1029 ERROR("failed to setup the network for '%s'", name);
95b5ffaf 1030 return -1;
0ad19a3f 1031 }
1032
571e6ec8 1033 if (setup_cgroup(name, &lxc_conf->cgroup)) {
36eb9bde 1034 ERROR("failed to setup the cgroups for '%s'", name);
95b5ffaf 1035 return -1;
0ad19a3f 1036 }
1037
571e6ec8 1038 if (setup_mount(lxc_conf->fstab)) {
36eb9bde 1039 ERROR("failed to setup the mounts for '%s'", name);
95b5ffaf 1040 return -1;
576f946d 1041 }
1042
571e6ec8 1043 if (setup_console(lxc_conf->rootfs, lxc_conf->console)) {
36eb9bde 1044 ERROR("failed to setup the console for '%s'", name);
95b5ffaf 1045 return -1;
6e590161 1046 }
1047
571e6ec8 1048 if (setup_tty(lxc_conf->rootfs, &lxc_conf->tty_info)) {
36eb9bde 1049 ERROR("failed to setup the ttys for '%s'", name);
95b5ffaf 1050 return -1;
b0a33c1e 1051 }
1052
571e6ec8 1053 if (setup_rootfs(lxc_conf->rootfs)) {
36eb9bde 1054 ERROR("failed to set rootfs for '%s'", name);
95b5ffaf 1055 return -1;
ed502555 1056 }
1057
571e6ec8 1058 if (setup_pts(lxc_conf->pts)) {
36eb9bde 1059 ERROR("failed to setup the new pts instance");
95b5ffaf 1060 return -1;
3c26f34e 1061 }
1062
cd54d859
DL
1063 NOTICE("'%s' is setup.", name);
1064
0ad19a3f 1065 return 0;
1066}