2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2008
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
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.
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.
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
34 #include <sys/types.h>
35 #include <sys/utsname.h>
36 #include <sys/param.h>
38 #include <sys/socket.h>
39 #include <sys/mount.h>
42 #include <arpa/inet.h>
44 #include <netinet/in.h>
55 #include <lxc/lxc.h> /* for lxc_cgroup_set() */
57 lxc_log_define(lxc_conf
, lxc
);
60 #define MAXINDEXLEN 20
62 #define MAXLINELEN 128
68 extern int pivot_root(const char * new_root
, const char * put_old
);
70 typedef int (*instanciate_cb
)(struct lxc_netdev
*);
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
*);
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
,
92 static struct mount_opt mount_opt
[] = {
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
},
116 static int configure_find_fstype_cb(void* buffer
, void *data
)
127 /* we don't try 'nodev' entries */
128 if (strstr(buffer
, "nodev"))
132 fstype
+= lxc_char_left_gc(fstype
, strlen(fstype
));
133 fstype
[lxc_char_right_gc(fstype
, strlen(fstype
))] = '\0';
135 if (mount(cbarg
->rootfs
, cbarg
->testdir
, fstype
, cbarg
->mntopt
, NULL
))
139 umount(cbarg
->testdir
);
140 strcpy(cbarg
->fstype
, fstype
);
145 /* find the filesystem type with brute force */
146 static int configure_find_fstype(const char *rootfs
, char *fstype
, int mntopt
)
149 char buffer
[MAXPATHLEN
];
162 /* first we check with /etc/filesystems, in case the modules
163 * are auto-loaded and fall back to the supported kernel fs
170 cbarg
.testdir
= tempnam("/tmp", "lxc-");
171 if (!cbarg
.testdir
) {
172 SYSERROR("failed to build a temp name");
176 if (mkdir(cbarg
.testdir
, 0755)) {
177 SYSERROR("failed to create temporary directory");
181 for (i
= 0; i
< sizeof(fsfile
)/sizeof(fsfile
[0]); i
++) {
183 found
= lxc_file_for_each_line(fsfile
[i
],
184 configure_find_fstype_cb
,
185 buffer
, sizeof(buffer
), &cbarg
);
188 SYSERROR("failed to read '%s'", fsfile
[i
]);
197 ERROR("failed to determine fs type for '%s'", rootfs
);
202 rmdir(cbarg
.testdir
);
206 static int configure_rootfs_dir_cb(const char *rootfs
, const char *absrootfs
,
209 return fprintf(f
, "%s %s none rbind 0 0\n", absrootfs
, rootfs
);
212 static int configure_rootfs_blk_cb(const char *rootfs
, const char *absrootfs
,
215 char fstype
[MAXPATHLEN
];
217 if (configure_find_fstype(absrootfs
, fstype
, 0)) {
218 ERROR("failed to configure mount for block device '%s'",
223 return fprintf(f
, "%s %s %s defaults 0 0\n", absrootfs
, rootfs
, fstype
);
226 static int configure_rootfs(const char *name
, const char *rootfs
)
228 char path
[MAXPATHLEN
];
229 char absrootfs
[MAXPATHLEN
];
230 char fstab
[MAXPATHLEN
];
235 typedef int (*rootfs_cb
)(const char *, const char *, FILE *);
241 { __S_IFDIR
, configure_rootfs_dir_cb
},
242 { __S_IFBLK
, configure_rootfs_blk_cb
},
245 if (!realpath(rootfs
, absrootfs
)) {
246 SYSERROR("failed to get real path for '%s'", rootfs
);
250 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s/rootfs", name
);
252 if (mkdir(path
, 0755)) {
253 SYSERROR("failed to create the '%s' directory", path
);
257 if (access(absrootfs
, F_OK
)) {
258 SYSERROR("'%s' is not accessible", absrootfs
);
262 if (stat(absrootfs
, &s
)) {
263 SYSERROR("failed to stat '%s'", absrootfs
);
267 for (i
= 0; i
< sizeof(rtfs_type
)/sizeof(rtfs_type
[0]); i
++) {
269 if (!__S_ISTYPE(s
.st_mode
, rtfs_type
[i
].type
))
272 snprintf(fstab
, MAXPATHLEN
, LXCPATH
"/%s/fstab", name
);
274 f
= fopen(fstab
, "a+");
276 SYSERROR("failed to open fstab file");
280 ret
= rtfs_type
[i
].cb(path
, absrootfs
, f
);
285 ERROR("failed to add rootfs mount in fstab");
289 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s/rootfs/rootfs", name
);
291 return symlink(absrootfs
, path
);
294 ERROR("unsupported rootfs type for '%s'", absrootfs
);
298 static int setup_utsname(struct utsname
*utsname
)
303 if (sethostname(utsname
->nodename
, strlen(utsname
->nodename
))) {
304 SYSERROR("failed to set the hostname to '%s'", utsname
->nodename
);
308 INFO("'%s' hostname has been setup", utsname
->nodename
);
313 static int setup_tty(const char *rootfs
, const struct lxc_tty_info
*tty_info
)
315 char path
[MAXPATHLEN
];
318 for (i
= 0; i
< tty_info
->nbtty
; i
++) {
320 struct lxc_pty_info
*pty_info
= &tty_info
->pty_info
[i
];
322 snprintf(path
, sizeof(path
), "%s/dev/tty%d",
323 rootfs
? rootfs
: "", i
+ 1);
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 :( */
329 if (mount(pty_info
->name
, path
, "none", MS_BIND
, 0)) {
330 WARN("failed to mount '%s'->'%s'",
331 pty_info
->name
, path
);
336 INFO("%d tty(s) has been setup", tty_info
->nbtty
);
341 static int setup_rootfs_pivot_root_cb(void *buffer
, void *data
)
343 struct lxc_list
*mountlist
, *listentry
, *iterator
;
344 char *pivotdir
, *mountpoint
, *mountentry
;
349 cbparm
= (void **)data
;
351 mountlist
= cbparm
[0];
352 pivotdir
= cbparm
[1];
354 /* parse entry, first field is mountname, ignore */
355 mountpoint
= strtok(mountentry
, " ");
359 /* second field is mountpoint */
360 mountpoint
= strtok(NULL
, " ");
364 /* only consider mountpoints below old root fs */
365 if (strncmp(mountpoint
, pivotdir
, strlen(pivotdir
)))
368 /* filter duplicate mountpoints */
370 lxc_list_for_each(iterator
, mountlist
) {
371 if (!strcmp(iterator
->elem
, mountpoint
)) {
379 /* add entry to list */
380 listentry
= malloc(sizeof(*listentry
));
382 SYSERROR("malloc for mountpoint listentry failed");
386 listentry
->elem
= strdup(mountpoint
);
387 if (!listentry
->elem
) {
388 SYSERROR("strdup failed");
391 lxc_list_add_tail(mountlist
, listentry
);
397 static int setup_rootfs_pivot_root(const char *rootfs
, const char *pivotdir
)
399 char path
[MAXPATHLEN
], buffer
[MAXPATHLEN
];
401 struct lxc_list mountlist
, *iterator
;
402 int ok
, still_mounted
, last_still_mounted
;
403 int pivotdir_is_temp
= 0;
405 /* change into new root fs */
407 SYSERROR("can't chroot to new rootfs '%s'", rootfs
);
411 /* create temporary mountpoint if none specified */
414 snprintf(path
, sizeof(path
), "./lxc-oldrootfs-XXXXXX" );
415 if (!mkdtemp(path
)) {
416 SYSERROR("can't make temporary mountpoint");
420 pivotdir
= strdup(&path
[1]); /* get rid of leading dot */
422 SYSERROR("strdup failed");
426 pivotdir_is_temp
= 1;
429 snprintf(path
, sizeof(path
), ".%s", pivotdir
);
432 DEBUG("temporary mountpoint for old rootfs is '%s'", path
);
434 /* pivot_root into our new root fs */
436 if (pivot_root(".", path
)) {
437 SYSERROR("pivot_root syscall failed");
442 SYSERROR("can't chroot to / after pivot_root");
446 DEBUG("pivot_root syscall to '%s' successful", pivotdir
);
448 /* read and parse /proc/mounts in old root fs */
449 lxc_list_init(&mountlist
);
451 snprintf(path
, sizeof(path
), "%s/", pivotdir
);
452 cbparm
[0] = &mountlist
;
453 cbparm
[1] = strdup(path
);
456 SYSERROR("strdup failed");
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
);
465 SYSERROR("failed to read or parse mount list '%s'", path
);
469 /* umount filesystems until none left or list no longer shrinks */
472 last_still_mounted
= still_mounted
;
475 lxc_list_for_each(iterator
, &mountlist
) {
477 if (!umount(iterator
->elem
)) {
478 DEBUG("umounted '%s'", (char *)iterator
->elem
);
479 lxc_list_del(iterator
);
483 if (errno
!= EBUSY
) {
484 SYSERROR("failed to umount '%s'", (char *)iterator
->elem
);
490 } while (still_mounted
> 0 && still_mounted
!= last_still_mounted
);
493 ERROR("could not umount %d mounts", still_mounted
);
497 /* umount old root fs */
498 if (umount(pivotdir
)) {
499 SYSERROR("could not unmount old rootfs");
502 DEBUG("umounted '%s'", pivotdir
);
504 /* remove temporary mount point */
505 if (pivotdir_is_temp
) {
506 if (rmdir(pivotdir
)) {
507 SYSERROR("can't remove temporary mountpoint");
513 INFO("pivoted to '%s'", rootfs
);
517 static int setup_rootfs(const char *rootfs
, const char *pivotdir
)
525 tmpname
= tempnam("/tmp", "lxc-rootfs");
527 SYSERROR("failed to generate temporary name");
531 if (mkdir(tmpname
, 0700)) {
532 SYSERROR("failed to create temporary directory '%s'", tmpname
);
536 if (mount(rootfs
, tmpname
, "none", MS_BIND
|MS_REC
, NULL
)) {
537 SYSERROR("failed to mount '%s'->'%s'", rootfs
, tmpname
);
541 if (setup_rootfs_pivot_root(tmpname
, pivotdir
)) {
542 ERROR("failed to pivot_root to '%s'", rootfs
);
552 static int setup_pts(int pts
)
557 if (!access("/dev/pts/ptmx", F_OK
) && umount("/dev/pts")) {
558 SYSERROR("failed to umount 'dev/pts'");
562 if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL
, "newinstance")) {
563 SYSERROR("failed to mount a new instance of '/dev/pts'");
567 if (chmod("/dev/pts/ptmx", 0666)) {
568 SYSERROR("failed to set permission for '/dev/pts/ptmx'");
572 if (access("/dev/ptmx", F_OK
)) {
573 if (!symlink("/dev/pts/ptmx", "/dev/ptmx"))
575 SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'");
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'");
585 INFO("created new pts instance");
591 static int setup_console(const char *rootfs
, const char *tty
)
593 char console
[MAXPATHLEN
];
595 snprintf(console
, sizeof(console
), "%s/dev/console",
596 rootfs
? rootfs
: "");
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
602 if (rootfs
&& !tty
[0]) {
604 if (!access(console
, F_OK
)) {
606 if (mount("/dev/null", console
, "none", MS_BIND
, 0)) {
607 SYSERROR("failed to mount '/dev/null'->'%s'",
617 if (access(console
, R_OK
|W_OK
))
620 if (mount(tty
, console
, "none", MS_BIND
, 0)) {
621 ERROR("failed to mount the console");
625 INFO("console '%s' mounted to '%s'", tty
, console
);
630 static int setup_cgroup(const char *name
, struct lxc_list
*cgroups
)
632 struct lxc_list
*iterator
;
633 struct lxc_cgroup
*cg
;
636 if (lxc_list_empty(cgroups
))
639 lxc_list_for_each(iterator
, cgroups
) {
643 if (lxc_cgroup_set(name
, cg
->subsystem
, cg
->value
))
646 DEBUG("cgroup '%s' set to '%s'", cg
->subsystem
, cg
->value
);
650 INFO("cgroup has been setup");
655 static void parse_mntopt(char *opt
, unsigned long *flags
, char **data
)
657 struct mount_opt
*mo
;
659 /* If opt is found in mount_opt, set or clear flags.
660 * Otherwise append it to data. */
662 for (mo
= &mount_opt
[0]; mo
->name
!= NULL
; mo
++) {
663 if (!strncmp(opt
, mo
->name
, strlen(mo
->name
))) {
677 static int parse_mntopts(struct mntent
*mntent
, unsigned long *mntflags
,
681 char *p
, *saveptr
= NULL
;
683 if (!mntent
->mnt_opts
)
686 s
= strdup(mntent
->mnt_opts
);
688 SYSERROR("failed to allocate memory");
692 data
= malloc(strlen(s
) + 1);
694 SYSERROR("failed to allocate memory");
700 for (p
= strtok_r(s
, ",", &saveptr
); p
!= NULL
;
701 p
= strtok_r(NULL
, ",", &saveptr
))
702 parse_mntopt(p
, mntflags
, &data
);
713 static int mount_file_entries(FILE *file
)
715 struct mntent
*mntent
;
717 unsigned long mntflags
;
720 while ((mntent
= getmntent(file
))) {
724 if (parse_mntopts(mntent
, &mntflags
, &mntdata
) < 0) {
725 ERROR("failed to parse mount option '%s'",
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
);
737 DEBUG("mounted %s on %s, type %s", mntent
->mnt_fsname
,
738 mntent
->mnt_dir
, mntent
->mnt_type
);
745 INFO("mount points have been setup");
750 static int setup_mount(const char *fstab
)
758 file
= setmntent(fstab
, "r");
760 SYSERROR("failed to use '%s'", fstab
);
764 ret
= mount_file_entries(file
);
770 static int setup_mount_entries(struct lxc_list
*mount
)
773 struct lxc_list
*iterator
;
779 ERROR("tmpfile error: %m");
783 lxc_list_for_each(iterator
, mount
) {
784 mount_entry
= iterator
->elem
;
785 fprintf(file
, "%s\n", mount_entry
);
790 ret
= mount_file_entries(file
);
796 static int setup_hw_addr(char *hwaddr
, const char *ifname
)
798 struct sockaddr sockaddr
;
802 if (lxc_convert_mac(hwaddr
, &sockaddr
)) {
803 ERROR("conversion has failed");
807 memcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
808 memcpy((char *) &ifr
.ifr_hwaddr
, (char *) &sockaddr
, sizeof(sockaddr
));
810 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
812 ERROR("socket failure : %s", strerror(errno
));
816 ret
= ioctl(fd
, SIOCSIFHWADDR
, &ifr
);
819 ERROR("ioctl failure : %s", strerror(errno
));
821 DEBUG("mac address '%s' on '%s' has been setup", hwaddr
, ifname
);
826 static int setup_ipv4_addr(struct lxc_list
*ip
, int ifindex
)
828 struct lxc_list
*iterator
;
829 struct lxc_inetdev
*inetdev
;
831 lxc_list_for_each(iterator
, ip
) {
833 inetdev
= iterator
->elem
;
835 if (lxc_ip_addr_add(AF_INET
, ifindex
,
836 &inetdev
->addr
, inetdev
->prefix
)) {
844 static int setup_ipv6_addr(struct lxc_list
*ip
, int ifindex
)
846 struct lxc_list
*iterator
;
847 struct lxc_inet6dev
*inet6dev
;
849 lxc_list_for_each(iterator
, ip
) {
851 inet6dev
= iterator
->elem
;
853 if (lxc_ip_addr_add(AF_INET6
, ifindex
,
854 & inet6dev
->addr
, inet6dev
->prefix
))
861 static int setup_netdev(struct lxc_netdev
*netdev
)
863 char ifname
[IFNAMSIZ
];
864 char *current_ifname
= ifname
;
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");
877 /* retrieve the name of the interface */
878 if (!if_indextoname(netdev
->ifindex
, current_ifname
)) {
879 ERROR("no interface corresponding to index '%d'",
884 /* default: let the system to choose one interface name */
886 netdev
->name
= "eth%d";
888 /* rename the interface name */
889 if (lxc_device_rename(ifname
, netdev
->name
)) {
890 ERROR("failed to rename %s->%s", ifname
, current_ifname
);
894 /* Re-read the name of the interface because its name has changed
895 * and would be automatically allocated by the system
897 if (!if_indextoname(netdev
->ifindex
, current_ifname
)) {
898 ERROR("no interface corresponding to index '%d'",
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'",
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'",
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'",
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
);
933 /* the network is up, make the loopback up too */
934 if (lxc_device_up("lo")) {
935 ERROR("failed to set the loopback up");
940 DEBUG("'%s' has been setup", current_ifname
);
945 static int setup_network(struct lxc_list
*network
)
947 struct lxc_list
*iterator
;
948 struct lxc_netdev
*netdev
;
950 lxc_list_for_each(iterator
, network
) {
952 netdev
= iterator
->elem
;
954 if (setup_netdev(netdev
)) {
955 ERROR("failed to setup netdev");
960 if (!lxc_list_empty(network
))
961 INFO("network has been setup");
966 int conf_has(const char *name
, const char *info
)
969 char path
[MAXPATHLEN
];
972 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s/%s", name
, info
);
974 if (!stat(path
, &st
) || !lstat(path
, &st
)) {
979 if (errno
== ENOENT
) {
984 SYSERROR("failed to stat %s info", info
);
989 struct lxc_conf
*lxc_conf_init(void)
991 struct lxc_conf
*new;
993 new = malloc(sizeof(*new));
995 ERROR("lxc_conf_init : %m");
998 memset(new, 0, sizeof(*new));
1001 new->pivotdir
= NULL
;
1003 new->utsname
= NULL
;
1006 new->console
[0] = '\0';
1007 lxc_list_init(&new->cgroup
);
1008 lxc_list_init(&new->network
);
1009 lxc_list_init(&new->mount_list
);
1014 static int instanciate_veth(struct lxc_netdev
*netdev
)
1016 char veth1buf
[IFNAMSIZ
], *veth1
;
1017 char veth2
[IFNAMSIZ
];
1019 if (netdev
->priv
.veth_attr
.pair
)
1020 veth1
= netdev
->priv
.veth_attr
.pair
;
1022 snprintf(veth1buf
, sizeof(veth1buf
), "vethXXXXXX");
1027 snprintf(veth2
, sizeof(veth2
), "vethXXXXXX");
1030 if (!strlen(veth1
) || !strlen(veth2
)) {
1031 ERROR("failed to allocate a temporary name");
1035 if (lxc_veth_create(veth1
, veth2
)) {
1036 ERROR("failed to create %s-%s", veth1
, veth2
);
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
);
1049 if (netdev
->link
&& lxc_bridge_attach(netdev
->link
, veth1
)) {
1050 ERROR("failed to attach '%s' to the bridge '%s'",
1051 veth1
, netdev
->link
);
1055 netdev
->ifindex
= if_nametoindex(veth2
);
1056 if (!netdev
->ifindex
) {
1057 ERROR("failed to retrieve the index for %s", veth2
);
1061 if (netdev
->flags
& IFF_UP
) {
1062 if (lxc_device_up(veth1
)) {
1063 ERROR("failed to set %s up", veth1
);
1068 DEBUG("instanciated veth '%s/%s', index is '%d'",
1069 veth1
, veth2
, netdev
->ifindex
);
1074 lxc_device_delete(veth1
);
1078 static int instanciate_macvlan(struct lxc_netdev
*netdev
)
1080 char peer
[IFNAMSIZ
];
1082 if (!netdev
->link
) {
1083 ERROR("no link specified for macvlan netdev");
1087 snprintf(peer
, sizeof(peer
), "mcXXXXXX");
1091 if (!strlen(peer
)) {
1092 ERROR("failed to make a temporary name");
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
);
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
);
1110 DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'",
1111 peer
, netdev
->ifindex
, netdev
->priv
.macvlan_attr
.mode
);
1116 /* XXX: merge with instanciate_macvlan */
1117 static int instanciate_vlan(struct lxc_netdev
*netdev
)
1119 char peer
[IFNAMSIZ
];
1121 if (!netdev
->link
) {
1122 ERROR("no link specified for vlan netdev");
1126 snprintf(peer
, sizeof(peer
), "vlan%d", netdev
->priv
.vlan_attr
.vid
);
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
);
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
);
1141 DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000",
1147 static int instanciate_phys(struct lxc_netdev
*netdev
)
1149 netdev
->ifindex
= if_nametoindex(netdev
->link
);
1150 if (!netdev
->ifindex
) {
1151 ERROR("failed to retrieve the index for %s", netdev
->link
);
1158 static int instanciate_empty(struct lxc_netdev
*netdev
)
1160 netdev
->ifindex
= 0;
1164 int lxc_create_network(struct lxc_list
*network
)
1166 struct lxc_list
*iterator
;
1167 struct lxc_netdev
*netdev
;
1169 lxc_list_for_each(iterator
, network
) {
1171 netdev
= iterator
->elem
;
1173 if (netdev
->type
< 0 || netdev
->type
> MAXCONFTYPE
) {
1174 ERROR("invalid network configuration type '%d'",
1179 if (netdev_conf
[netdev
->type
](netdev
)) {
1180 ERROR("failed to create netdev");
1188 int lxc_assign_network(struct lxc_list
*network
, pid_t pid
)
1190 struct lxc_list
*iterator
;
1191 struct lxc_netdev
*netdev
;
1193 lxc_list_for_each(iterator
, network
) {
1195 netdev
= iterator
->elem
;
1197 if (lxc_device_move(netdev
->ifindex
, pid
)) {
1198 ERROR("failed to move '%s' to the container",
1203 DEBUG("move '%s' to '%d'", netdev
->link
, pid
);
1209 int lxc_create_tty(const char *name
, struct lxc_conf
*conf
)
1211 struct lxc_tty_info
*tty_info
= &conf
->tty_info
;
1214 /* no tty in the configuration */
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");
1225 for (i
= 0; i
< conf
->tty
; i
++) {
1227 struct lxc_pty_info
*pty_info
= &tty_info
->pty_info
[i
];
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
);
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
);
1244 tty_info
->nbtty
= conf
->tty
;
1246 INFO("tty's configured");
1251 void lxc_delete_tty(struct lxc_tty_info
*tty_info
)
1255 for (i
= 0; i
< tty_info
->nbtty
; i
++) {
1256 struct lxc_pty_info
*pty_info
= &tty_info
->pty_info
[i
];
1258 close(pty_info
->master
);
1259 close(pty_info
->slave
);
1262 free(tty_info
->pty_info
);
1263 tty_info
->nbtty
= 0;
1266 int lxc_setup(const char *name
, struct lxc_conf
*lxc_conf
)
1268 if (setup_utsname(lxc_conf
->utsname
)) {
1269 ERROR("failed to setup the utsname for '%s'", name
);
1273 if (setup_network(&lxc_conf
->network
)) {
1274 ERROR("failed to setup the network for '%s'", name
);
1278 if (setup_cgroup(name
, &lxc_conf
->cgroup
)) {
1279 ERROR("failed to setup the cgroups for '%s'", name
);
1283 if (setup_mount(lxc_conf
->fstab
)) {
1284 ERROR("failed to setup the mounts for '%s'", name
);
1288 if (setup_mount_entries(&lxc_conf
->mount_list
)) {
1289 ERROR("failed to setup the mount entries for '%s'", name
);
1293 if (setup_console(lxc_conf
->rootfs
, lxc_conf
->console
)) {
1294 ERROR("failed to setup the console for '%s'", name
);
1298 if (setup_tty(lxc_conf
->rootfs
, &lxc_conf
->tty_info
)) {
1299 ERROR("failed to setup the ttys for '%s'", name
);
1303 if (setup_rootfs(lxc_conf
->rootfs
, lxc_conf
->pivotdir
)) {
1304 ERROR("failed to set rootfs for '%s'", name
);
1308 if (setup_pts(lxc_conf
->pts
)) {
1309 ERROR("failed to setup the new pts instance");
1313 NOTICE("'%s' is setup.", name
);