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