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 lxc_log_define(lxc_conf
, lxc
);
58 #define MAXINDEXLEN 20
60 #define MAXLINELEN 128
66 typedef int (*instanciate_cb
)(struct lxc_netdev
*);
74 static int instanciate_veth(struct lxc_netdev
*);
75 static int instanciate_macvlan(struct lxc_netdev
*);
76 static int instanciate_phys(struct lxc_netdev
*);
77 static int instanciate_empty(struct lxc_netdev
*);
79 static instanciate_cb netdev_conf
[MAXCONFTYPE
+ 1] = {
80 [VETH
] = instanciate_veth
,
81 [MACVLAN
] = instanciate_macvlan
,
82 [PHYS
] = instanciate_phys
,
83 [EMPTY
] = instanciate_empty
,
86 static struct mount_opt mount_opt
[] = {
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
},
110 static int delete_info(const char *path
, const char *file
)
112 char info
[MAXPATHLEN
];
115 snprintf(info
, MAXPATHLEN
, "%s/%s", path
, file
);
121 static int configure_find_fstype_cb(void* buffer
, void *data
)
132 /* we don't try 'nodev' entries */
133 if (strstr(buffer
, "nodev"))
137 fstype
+= lxc_char_left_gc(fstype
, strlen(fstype
));
138 fstype
[lxc_char_right_gc(fstype
, strlen(fstype
))] = '\0';
140 if (mount(cbarg
->rootfs
, cbarg
->testdir
, fstype
, cbarg
->mntopt
, NULL
))
144 umount(cbarg
->testdir
);
145 strcpy(cbarg
->fstype
, fstype
);
150 /* find the filesystem type with brute force */
151 static int configure_find_fstype(const char *rootfs
, char *fstype
, int mntopt
)
154 char buffer
[MAXPATHLEN
];
167 /* first we check with /etc/filesystems, in case the modules
168 * are auto-loaded and fall back to the supported kernel fs
175 cbarg
.testdir
= tempnam("/tmp", "lxc-");
176 if (!cbarg
.testdir
) {
177 SYSERROR("failed to build a temp name");
181 if (mkdir(cbarg
.testdir
, 0755)) {
182 SYSERROR("failed to create temporary directory");
186 for (i
= 0; i
< sizeof(fsfile
)/sizeof(fsfile
[0]); i
++) {
188 found
= lxc_file_for_each_line(fsfile
[i
],
189 configure_find_fstype_cb
,
190 buffer
, sizeof(buffer
), &cbarg
);
193 SYSERROR("failed to read '%s'", fsfile
[i
]);
202 ERROR("failed to determine fs type for '%s'", rootfs
);
207 rmdir(cbarg
.testdir
);
211 static int configure_rootfs_dir_cb(const char *rootfs
, const char *absrootfs
,
214 return fprintf(f
, "%s %s none rbind 0 0\n", absrootfs
, rootfs
);
217 static int configure_rootfs_blk_cb(const char *rootfs
, const char *absrootfs
,
220 char fstype
[MAXPATHLEN
];
222 if (configure_find_fstype(absrootfs
, fstype
, 0)) {
223 ERROR("failed to configure mount for block device '%s'",
228 return fprintf(f
, "%s %s %s defaults 0 0\n", absrootfs
, rootfs
, fstype
);
231 static int configure_rootfs(const char *name
, const char *rootfs
)
233 char path
[MAXPATHLEN
];
234 char absrootfs
[MAXPATHLEN
];
235 char fstab
[MAXPATHLEN
];
240 typedef int (*rootfs_cb
)(const char *, const char *, FILE *);
246 { __S_IFDIR
, configure_rootfs_dir_cb
},
247 { __S_IFBLK
, configure_rootfs_blk_cb
},
250 if (!realpath(rootfs
, absrootfs
)) {
251 SYSERROR("failed to get real path for '%s'", rootfs
);
255 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s/rootfs", name
);
257 if (mkdir(path
, 0755)) {
258 SYSERROR("failed to create the '%s' directory", path
);
262 if (access(absrootfs
, F_OK
)) {
263 SYSERROR("'%s' is not accessible", absrootfs
);
267 if (stat(absrootfs
, &s
)) {
268 SYSERROR("failed to stat '%s'", absrootfs
);
272 for (i
= 0; i
< sizeof(rtfs_type
)/sizeof(rtfs_type
[0]); i
++) {
274 if (!__S_ISTYPE(s
.st_mode
, rtfs_type
[i
].type
))
277 snprintf(fstab
, MAXPATHLEN
, LXCPATH
"/%s/fstab", name
);
279 f
= fopen(fstab
, "a+");
281 SYSERROR("failed to open fstab file");
285 ret
= rtfs_type
[i
].cb(path
, absrootfs
, f
);
290 ERROR("failed to add rootfs mount in fstab");
294 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s/rootfs/rootfs", name
);
296 return symlink(absrootfs
, path
);
299 ERROR("unsupported rootfs type for '%s'", absrootfs
);
303 static int unconfigure_ip_addresses(const char *directory
)
305 char path
[MAXPATHLEN
];
307 snprintf(path
, MAXPATHLEN
, "%s/ipv4", directory
);
308 delete_info(path
, "addresses");
311 snprintf(path
, MAXPATHLEN
, "%s/ipv6", directory
);
312 delete_info(path
, "addresses");
318 static int unconfigure_network_cb(const char *name
, const char *directory
,
319 const char *file
, void *data
)
321 char path
[MAXPATHLEN
];
323 snprintf(path
, MAXPATHLEN
, "%s/%s", directory
, file
);
324 delete_info(path
, "ifindex");
325 delete_info(path
, "name");
326 delete_info(path
, "addr");
327 delete_info(path
, "link");
328 delete_info(path
, "hwaddr");
329 delete_info(path
, "mtu");
330 delete_info(path
, "up");
331 unconfigure_ip_addresses(path
);
337 static int unconfigure_network(const char *name
)
339 char directory
[MAXPATHLEN
];
341 snprintf(directory
, MAXPATHLEN
, LXCPATH
"/%s/network", name
);
342 lxc_dir_for_each(name
, directory
, unconfigure_network_cb
, NULL
);
348 static int unconfigure_cgroup_cb(const char *name
, const char *directory
,
349 const char *file
, void *data
)
351 return delete_info(directory
, file
);
354 static int unconfigure_cgroup(const char *name
)
356 char filename
[MAXPATHLEN
];
359 snprintf(filename
, MAXPATHLEN
, LXCPATH
"/%s/cgroup", name
);
361 if (stat(filename
, &s
)) {
362 SYSERROR("failed to stat '%s'", filename
);
366 if (S_ISDIR(s
.st_mode
)) {
367 /* old cgroup configuration */
368 lxc_dir_for_each(name
, filename
, unconfigure_cgroup_cb
, NULL
);
377 static int unconfigure_rootfs(const char *name
)
379 char path
[MAXPATHLEN
];
381 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s/rootfs", name
);
383 #warning deprecated code to be removed in the next version
385 /* ugly but for backward compatibily, */
386 delete_info(path
, "rootfs");
393 static int unconfigure_pts(const char *name
)
395 char path
[MAXPATHLEN
];
397 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s", name
);
398 delete_info(path
, "pts");
403 static int unconfigure_tty(const char *name
)
405 char path
[MAXPATHLEN
];
407 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s", name
);
408 delete_info(path
, "tty");
413 static int unconfigure_mount(const char *name
)
415 char path
[MAXPATHLEN
];
417 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s", name
);
418 delete_info(path
, "fstab");
423 static int unconfigure_utsname(const char *name
)
425 char path
[MAXPATHLEN
];
427 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s", name
);
428 delete_info(path
, "utsname");
433 static int setup_utsname(struct utsname
*utsname
)
438 if (sethostname(utsname
->nodename
, strlen(utsname
->nodename
))) {
439 SYSERROR("failed to set the hostname to '%s'", utsname
->nodename
);
443 INFO("'%s' hostname has been setup", utsname
->nodename
);
448 static int setup_tty(const char *rootfs
, const struct lxc_tty_info
*tty_info
)
450 char path
[MAXPATHLEN
];
453 for (i
= 0; i
< tty_info
->nbtty
; i
++) {
455 struct lxc_pty_info
*pty_info
= &tty_info
->pty_info
[i
];
457 snprintf(path
, sizeof(path
), "%s/dev/tty%d",
458 rootfs
? rootfs
: "", i
+ 1);
460 /* At this point I can not use the "access" function
461 * to check the file is present or not because it fails
462 * with EACCES errno and I don't know why :( */
464 if (mount(pty_info
->name
, path
, "none", MS_BIND
, 0)) {
465 WARN("failed to mount '%s'->'%s'",
466 pty_info
->name
, path
);
471 INFO("%d tty(s) has been setup", tty_info
->nbtty
);
476 static int setup_rootfs(const char *rootfs
)
484 tmpname
= tempnam("/tmp", "lxc-rootfs");
486 SYSERROR("failed to generate temporary name");
490 if (mkdir(tmpname
, 0700)) {
491 SYSERROR("failed to create temporary directory '%s'", tmpname
);
495 if (mount(rootfs
, tmpname
, "none", MS_BIND
|MS_REC
, NULL
)) {
496 SYSERROR("failed to mount '%s'->'%s'", rootfs
, tmpname
);
500 if (chroot(tmpname
)) {
501 SYSERROR("failed to set chroot %s", tmpname
);
505 if (chdir(getenv("HOME")) && chdir("/")) {
506 SYSERROR("failed to change to home directory");
510 INFO("chrooted to '%s'", rootfs
);
518 static int setup_pts(int pts
)
523 if (!access("/dev/pts/ptmx", F_OK
) && umount("/dev/pts")) {
524 SYSERROR("failed to umount 'dev/pts'");
528 if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL
, "newinstance")) {
529 SYSERROR("failed to mount a new instance of '/dev/pts'");
533 if (chmod("/dev/pts/ptmx", 0666)) {
534 SYSERROR("failed to set permission for '/dev/pts/ptmx'");
538 if (access("/dev/ptmx", F_OK
)) {
539 if (!symlink("/dev/pts/ptmx", "/dev/ptmx"))
541 SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'");
545 /* fallback here, /dev/pts/ptmx exists just mount bind */
546 if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND
, 0)) {
547 SYSERROR("mount failed '/dev/pts/ptmx'->'/dev/ptmx'");
551 INFO("created new pts instance");
557 static int setup_console(const char *rootfs
, const char *tty
)
559 char console
[MAXPATHLEN
];
561 snprintf(console
, sizeof(console
), "%s/dev/console",
562 rootfs
? rootfs
: "");
564 /* we have the rootfs with /dev/console but no tty
565 * to be used as console, let's remap /dev/console
566 * to /dev/null to avoid to log to the system console
568 if (rootfs
&& !tty
[0]) {
570 if (!access(console
, F_OK
)) {
572 if (mount("/dev/null", console
, "none", MS_BIND
, 0)) {
573 SYSERROR("failed to mount '/dev/null'->'%s'",
583 if (access(console
, R_OK
|W_OK
))
586 if (mount(tty
, console
, "none", MS_BIND
, 0)) {
587 ERROR("failed to mount the console");
591 INFO("console '%s' mounted to '%s'", tty
, console
);
596 static int setup_cgroup(const char *name
, struct lxc_list
*cgroups
)
598 struct lxc_list
*iterator
;
599 struct lxc_cgroup
*cg
;
601 if (lxc_list_empty(cgroups
))
604 lxc_list_for_each(iterator
, cgroups
) {
608 if (lxc_cgroup_set(name
, cg
->subsystem
, cg
->value
))
611 DEBUG("cgroup '%s' set to '%s'", cg
->subsystem
, cg
->value
);
614 INFO("cgroup has been setup");
619 static void parse_mntopt(char *opt
, unsigned long *flags
, char **data
)
621 struct mount_opt
*mo
;
623 /* If opt is found in mount_opt, set or clear flags.
624 * Otherwise append it to data. */
626 for (mo
= &mount_opt
[0]; mo
->name
!= NULL
; mo
++) {
627 if (!strncmp(opt
, mo
->name
, strlen(mo
->name
))) {
641 static int parse_mntopts(struct mntent
*mntent
, unsigned long *mntflags
,
645 char *p
, *saveptr
= NULL
;
647 if (!mntent
->mnt_opts
)
650 s
= strdup(mntent
->mnt_opts
);
652 SYSERROR("failed to allocate memory");
656 data
= malloc(strlen(s
) + 1);
658 SYSERROR("failed to allocate memory");
664 for (p
= strtok_r(s
, ",", &saveptr
); p
!= NULL
;
665 p
= strtok_r(NULL
, ",", &saveptr
))
666 parse_mntopt(p
, mntflags
, &data
);
677 static int setup_mount(const char *fstab
)
679 struct mntent
*mntent
;
682 unsigned long mntflags
;
688 file
= setmntent(fstab
, "r");
690 SYSERROR("failed to use '%s'", fstab
);
694 while ((mntent
= getmntent(file
))) {
698 if (parse_mntopts(mntent
, &mntflags
, &mntdata
) < 0) {
699 ERROR("failed to parse mount option '%s'",
704 if (mount(mntent
->mnt_fsname
, mntent
->mnt_dir
,
705 mntent
->mnt_type
, mntflags
, mntdata
)) {
706 SYSERROR("failed to mount '%s' on '%s'",
707 mntent
->mnt_fsname
, mntent
->mnt_dir
);
711 DEBUG("mounted %s on %s, type %s", mntent
->mnt_fsname
,
712 mntent
->mnt_dir
, mntent
->mnt_type
);
719 INFO("mount points have been setup");
725 static int setup_hw_addr(char *hwaddr
, const char *ifname
)
727 struct sockaddr sockaddr
;
731 if (lxc_convert_mac(hwaddr
, &sockaddr
)) {
732 ERROR("conversion has failed");
736 memcpy(ifr
.ifr_name
, ifname
, IFNAMSIZ
);
737 memcpy((char *) &ifr
.ifr_hwaddr
, (char *) &sockaddr
, sizeof(sockaddr
));
739 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
741 ERROR("socket failure : %s", strerror(errno
));
745 ret
= ioctl(fd
, SIOCSIFHWADDR
, &ifr
);
748 ERROR("ioctl failure : %s", strerror(errno
));
750 DEBUG("mac address '%s' on '%s' has been setup", hwaddr
, ifname
);
755 static int setup_ipv4_addr(struct lxc_list
*ip
, int ifindex
)
757 struct lxc_list
*iterator
;
758 struct lxc_inetdev
*inetdev
;
760 lxc_list_for_each(iterator
, ip
) {
762 inetdev
= iterator
->elem
;
764 if (lxc_ip_addr_add(AF_INET
, ifindex
,
765 &inetdev
->addr
, inetdev
->prefix
)) {
773 static int setup_ipv6_addr(struct lxc_list
*ip
, int ifindex
)
775 struct lxc_list
*iterator
;
776 struct lxc_inetdev
*inet6dev
;
778 lxc_list_for_each(iterator
, ip
) {
780 inet6dev
= iterator
->elem
;
782 if (lxc_ip_addr_add(AF_INET6
, ifindex
,
783 & inet6dev
->addr
, inet6dev
->prefix
))
790 static int setup_netdev(struct lxc_netdev
*netdev
)
792 char ifname
[IFNAMSIZ
];
793 char *current_ifname
= ifname
;
795 /* empty network namespace */
796 if (!netdev
->ifindex
) {
797 if (netdev
->flags
| IFF_UP
) {
798 if (lxc_device_up("lo")) {
799 ERROR("failed to set the loopback up");
806 /* retrieve the name of the interface */
807 if (!if_indextoname(netdev
->ifindex
, current_ifname
)) {
808 ERROR("no interface corresponding to index '%d'",
813 /* default: let the system to choose one interface name */
814 if (!netdev
->newname
)
815 netdev
->newname
= "eth%d";
817 /* rename the interface name */
818 if (lxc_device_rename(ifname
, netdev
->newname
)) {
819 ERROR("failed to rename %s->%s", ifname
, current_ifname
);
823 /* Re-read the name of the interface because its name has changed
824 * and would be automatically allocated by the system
826 if (!if_indextoname(netdev
->ifindex
, current_ifname
)) {
827 ERROR("no interface corresponding to index '%d'",
832 /* set a mac address */
833 if (netdev
->hwaddr
) {
834 if (setup_hw_addr(netdev
->hwaddr
, current_ifname
)) {
835 ERROR("failed to setup hw address for '%s'",
841 /* setup ipv4 addresses on the interface */
842 if (setup_ipv4_addr(&netdev
->ipv4
, netdev
->ifindex
)) {
843 ERROR("failed to setup ip addresses for '%s'",
848 /* setup ipv6 addresses on the interface */
849 if (setup_ipv6_addr(&netdev
->ipv6
, netdev
->ifindex
)) {
850 ERROR("failed to setup ipv6 addresses for '%s'",
855 /* set the network device up */
856 if (netdev
->flags
| IFF_UP
) {
857 if (lxc_device_up(current_ifname
)) {
858 ERROR("failed to set '%s' up", current_ifname
);
862 /* the network is up, make the loopback up too */
863 if (lxc_device_up("lo")) {
864 ERROR("failed to set the loopback up");
869 DEBUG("'%s' has been setup", current_ifname
);
874 static int setup_network(struct lxc_list
*network
)
876 struct lxc_list
*iterator
;
877 struct lxc_netdev
*netdev
;
879 lxc_list_for_each(iterator
, network
) {
881 netdev
= iterator
->elem
;
883 if (setup_netdev(netdev
)) {
884 ERROR("failed to setup netdev");
889 if (!lxc_list_empty(network
))
890 INFO("network has been setup");
895 int conf_has(const char *name
, const char *info
)
898 char path
[MAXPATHLEN
];
901 snprintf(path
, MAXPATHLEN
, LXCPATH
"/%s/%s", name
, info
);
903 if (!stat(path
, &st
) || !lstat(path
, &st
)) {
908 if (errno
== ENOENT
) {
913 SYSERROR("failed to stat %s info", info
);
918 int lxc_conf_init(struct lxc_conf
*conf
)
922 conf
->utsname
= NULL
;
925 conf
->console
[0] = '\0';
926 lxc_list_init(&conf
->cgroup
);
927 lxc_list_init(&conf
->network
);
931 int lxc_unconfigure(const char *name
)
933 if (conf_has_utsname(name
) && unconfigure_utsname(name
))
934 ERROR("failed to cleanup utsname");
936 if (conf_has_network(name
) && unconfigure_network(name
))
937 ERROR("failed to cleanup the network");
939 if (conf_has_cgroup(name
) && unconfigure_cgroup(name
))
940 ERROR("failed to cleanup cgroup");
942 if (conf_has_tty(name
) && unconfigure_tty(name
))
943 ERROR("failed to cleanup tty");
945 if (conf_has_rootfs(name
) && unconfigure_rootfs(name
))
946 ERROR("failed to cleanup rootfs");
948 if (conf_has_fstab(name
) && unconfigure_mount(name
))
949 ERROR("failed to cleanup mount");
951 if (conf_has_pts(name
) && unconfigure_pts(name
))
952 ERROR("failed to cleanup pts");
957 static int instanciate_veth(struct lxc_netdev
*netdev
)
959 char veth1
[IFNAMSIZ
];
960 char veth2
[IFNAMSIZ
];
963 snprintf(veth1
, sizeof(veth1
), "vethXXXXXX");
964 snprintf(veth2
, sizeof(veth2
), "vethXXXXXX");
969 if (!strlen(veth1
) || !strlen(veth2
)) {
970 ERROR("failed to allocate a temporary name");
974 if (lxc_veth_create(veth1
, veth2
)) {
975 ERROR("failed to create %s-%s/%s",
976 veth1
, veth2
, netdev
->ifname
);
981 if (lxc_device_set_mtu(veth1
, atoi(netdev
->mtu
))) {
982 ERROR("failed to set mtu '%s' for '%s'",
987 if (lxc_device_set_mtu(veth2
, atoi(netdev
->mtu
))) {
988 ERROR("failed to set mtu '%s' for '%s'",
994 if (lxc_bridge_attach(netdev
->ifname
, veth1
)) {
995 ERROR("failed to attach '%s' to the bridge '%s'",
996 veth1
, netdev
->ifname
);
1000 netdev
->ifindex
= if_nametoindex(veth2
);
1001 if (!netdev
->ifindex
) {
1002 ERROR("failed to retrieve the index for %s", veth2
);
1006 if (netdev
->flags
& IFF_UP
) {
1007 if (lxc_device_up(veth1
)) {
1008 ERROR("failed to set %s up", veth1
);
1013 DEBUG("instanciated veth '%s/%s', index is '%d'",
1014 veth1
, veth2
, netdev
->ifindex
);
1021 lxc_device_delete(veth1
);
1024 static int instanciate_macvlan(struct lxc_netdev
*netdev
)
1026 char peer
[IFNAMSIZ
];
1029 snprintf(peer
, sizeof(peer
), "mcXXXXXX");
1033 if (!strlen(peer
)) {
1034 ERROR("failed to make a temporary name");
1038 if (lxc_macvlan_create(netdev
->ifname
, peer
)) {
1039 ERROR("failed to create macvlan interface '%s' on '%s'",
1040 peer
, netdev
->ifname
);
1044 netdev
->ifindex
= if_nametoindex(peer
);
1045 if (!netdev
->ifindex
) {
1046 ERROR("failed to retrieve the index for %s", peer
);
1050 DEBUG("instanciated macvlan '%s', index is '%d'", peer
, netdev
->ifindex
);
1057 lxc_device_delete(peer
);
1061 static int instanciate_phys(struct lxc_netdev
*netdev
)
1063 netdev
->ifindex
= if_nametoindex(netdev
->ifname
);
1064 if (!netdev
->ifindex
) {
1065 ERROR("failed to retrieve the index for %s", netdev
->ifname
);
1072 static int instanciate_empty(struct lxc_netdev
*netdev
)
1074 netdev
->ifindex
= 0;
1078 int lxc_create_network(struct lxc_list
*network
)
1080 struct lxc_list
*iterator
;
1081 struct lxc_netdev
*netdev
;
1083 lxc_list_for_each(iterator
, network
) {
1085 netdev
= iterator
->elem
;
1087 if (netdev
->type
< 0 || netdev
->type
> MAXCONFTYPE
) {
1088 ERROR("invalid network configuration type '%d'",
1093 if (netdev_conf
[netdev
->type
](netdev
)) {
1094 ERROR("failed to create netdev");
1102 int lxc_assign_network(struct lxc_list
*network
, pid_t pid
)
1104 struct lxc_list
*iterator
;
1105 struct lxc_netdev
*netdev
;
1107 lxc_list_for_each(iterator
, network
) {
1109 netdev
= iterator
->elem
;
1111 if (lxc_device_move(netdev
->ifindex
, pid
)) {
1112 ERROR("failed to move '%s' to the container",
1117 DEBUG("move '%s' to '%d'", netdev
->ifname
, pid
);
1123 int lxc_create_tty(const char *name
, struct lxc_conf
*conf
)
1125 struct lxc_tty_info
*tty_info
= &conf
->tty_info
;
1128 /* no tty in the configuration */
1132 tty_info
->nbtty
= conf
->tty
;
1133 tty_info
->pty_info
=
1134 malloc(sizeof(*tty_info
->pty_info
)*tty_info
->nbtty
);
1136 if (!tty_info
->pty_info
) {
1137 SYSERROR("failed to allocate pty_info");
1141 for (i
= 0; i
< tty_info
->nbtty
; i
++) {
1143 struct lxc_pty_info
*pty_info
= &tty_info
->pty_info
[i
];
1145 if (openpty(&pty_info
->master
, &pty_info
->slave
,
1146 pty_info
->name
, NULL
, NULL
)) {
1147 SYSERROR("failed to create pty #%d", i
);
1151 /* Prevent leaking the file descriptors to the container */
1152 fcntl(pty_info
->master
, F_SETFD
, FD_CLOEXEC
);
1153 fcntl(pty_info
->slave
, F_SETFD
, FD_CLOEXEC
);
1160 INFO("tty's configured");
1166 free(tty_info
->pty_info
);
1170 void lxc_delete_tty(struct lxc_tty_info
*tty_info
)
1174 for (i
= 0; i
< tty_info
->nbtty
; i
++) {
1175 struct lxc_pty_info
*pty_info
= &tty_info
->pty_info
[i
];
1177 close(pty_info
->master
);
1178 close(pty_info
->slave
);
1181 free(tty_info
->pty_info
);
1182 tty_info
->nbtty
= 0;
1185 int lxc_setup(const char *name
, struct lxc_conf
*lxc_conf
)
1187 if (setup_utsname(lxc_conf
->utsname
)) {
1188 ERROR("failed to setup the utsname for '%s'", name
);
1192 if (setup_network(&lxc_conf
->network
)) {
1193 ERROR("failed to setup the network for '%s'", name
);
1197 if (setup_cgroup(name
, &lxc_conf
->cgroup
)) {
1198 ERROR("failed to setup the cgroups for '%s'", name
);
1202 if (setup_mount(lxc_conf
->fstab
)) {
1203 ERROR("failed to setup the mounts for '%s'", name
);
1207 if (setup_console(lxc_conf
->rootfs
, lxc_conf
->console
)) {
1208 ERROR("failed to setup the console for '%s'", name
);
1212 if (setup_tty(lxc_conf
->rootfs
, &lxc_conf
->tty_info
)) {
1213 ERROR("failed to setup the ttys for '%s'", name
);
1217 if (setup_rootfs(lxc_conf
->rootfs
)) {
1218 ERROR("failed to set rootfs for '%s'", name
);
1222 if (setup_pts(lxc_conf
->pts
)) {
1223 ERROR("failed to setup the new pts instance");
1227 NOTICE("'%s' is setup.", name
);