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