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