]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/conf.c
confile:add lxc.init.cwd
[mirror_lxc.git] / src / lxc / conf.c
index 93d4c15880ebb0c3563687702c1e0817b35a3523..8234279f995687a35ed83cebb546f788fa353879 100644 (file)
 #include <../include/openpty.h>
 #endif
 
-#ifdef HAVE_LINUX_MEMFD_H
-#include <linux/memfd.h>
-#endif
-
 #include "af_unix.h"
 #include "caps.h"       /* for lxc_caps_last_cap() */
 #include "cgroup.h"
@@ -84,6 +80,7 @@
 #include "namespace.h"
 #include "network.h"
 #include "parse.h"
+#include "ringbuf.h"
 #include "storage.h"
 #include "storage/aufs.h"
 #include "storage/overlay.h"
 
 #if IS_BIONIC
 #include <../include/lxcmntent.h>
-#ifndef HAVE_PRLIMIT
-#include <../include/prlimit.h>
-#endif
 #else
 #include <mntent.h>
 #endif
 
-lxc_log_define(lxc_conf, lxc);
-
-#if HAVE_LIBCAP
-#ifndef CAP_SETFCAP
-#define CAP_SETFCAP 31
-#endif
-
-#ifndef CAP_MAC_OVERRIDE
-#define CAP_MAC_OVERRIDE 32
-#endif
-
-#ifndef CAP_MAC_ADMIN
-#define CAP_MAC_ADMIN 33
-#endif
-#endif
-
-#ifndef PR_CAPBSET_DROP
-#define PR_CAPBSET_DROP 24
-#endif
-
-#ifndef LO_FLAGS_AUTOCLEAR
-#define LO_FLAGS_AUTOCLEAR 4
-#endif
-
-#ifndef CAP_SETUID
-#define CAP_SETUID 7
-#endif
-
-#ifndef CAP_SETGID
-#define CAP_SETGID 6
+#if !defined(HAVE_PRLIMIT) && defined(HAVE_PRLIMIT64)
+#include <../include/prlimit.h>
 #endif
 
-/* needed for cgroup automount checks, regardless of whether we
- * have included linux/capability.h or not */
-#ifndef CAP_SYS_ADMIN
-#define CAP_SYS_ADMIN 21
-#endif
+lxc_log_define(lxc_conf, lxc);
 
 /* Define pivot_root() if missing from the C library */
 #ifndef HAVE_PIVOT_ROOT
@@ -160,19 +122,6 @@ static int pivot_root(const char * new_root, const char * put_old)
 extern int pivot_root(const char * new_root, const char * put_old);
 #endif
 
-/* Define sethostname() if missing from the C library */
-#ifndef HAVE_SETHOSTNAME
-static int sethostname(const char * name, size_t len)
-{
-#ifdef __NR_sethostname
-       return syscall(__NR_sethostname, name, len);
-#else
-       errno = ENOSYS;
-       return -1;
-#endif
-}
-#endif
-
 #ifndef MS_PRIVATE
 #define MS_PRIVATE (1<<18)
 #endif
@@ -181,64 +130,10 @@ static int sethostname(const char * name, size_t len)
 #define MS_LAZYTIME (1<<25)
 #endif
 
-/* memfd_create() */
-#ifndef MFD_CLOEXEC
-#define MFD_CLOEXEC 0x0001U
-#endif
-
-#ifndef MFD_ALLOW_SEALING
-#define MFD_ALLOW_SEALING 0x0002U
-#endif
-
-#ifndef HAVE_MEMFD_CREATE
-static int memfd_create(const char *name, unsigned int flags) {
-       #ifndef __NR_memfd_create
-               #if defined __i386__
-                       #define __NR_memfd_create 356
-               #elif defined __x86_64__
-                       #define __NR_memfd_create 319
-               #elif defined __arm__
-                       #define __NR_memfd_create 385
-               #elif defined __aarch64__
-                       #define __NR_memfd_create 279
-               #elif defined __s390__
-                       #define __NR_memfd_create 350
-               #elif defined __powerpc__
-                       #define __NR_memfd_create 360
-               #elif defined __sparc__
-                       #define __NR_memfd_create 348
-               #elif defined __blackfin__
-                       #define __NR_memfd_create 390
-               #elif defined __ia64__
-                       #define __NR_memfd_create 1340
-               #elif defined _MIPS_SIM
-                       #if _MIPS_SIM == _MIPS_SIM_ABI32
-                               #define __NR_memfd_create 4354
-                       #endif
-                       #if _MIPS_SIM == _MIPS_SIM_NABI32
-                               #define __NR_memfd_create 6318
-                       #endif
-                       #if _MIPS_SIM == _MIPS_SIM_ABI64
-                               #define __NR_memfd_create 5314
-                       #endif
-               #endif
-       #endif
-       #ifdef __NR_memfd_create
-       return syscall(__NR_memfd_create, name, flags);
-       #else
-       errno = ENOSYS;
-       return -1;
-       #endif
-}
-#else
-extern int memfd_create(const char *name, unsigned int flags);
-#endif
-
 char *lxchook_names[NUM_LXC_HOOKS] = {"pre-start", "pre-mount", "mount",
                                      "autodev",   "start",     "stop",
-                                     "post-stop", "clone",     "destroy"};
-
-typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
+                                     "post-stop", "clone",     "destroy",
+                                     "start-host"};
 
 struct mount_opt {
        char *name;
@@ -267,41 +162,6 @@ __thread struct lxc_conf *current_config;
 struct lxc_conf *current_config;
 #endif
 
-/* Declare this here, since we don't want to reshuffle the whole file. */
-static int in_caplist(int cap, struct lxc_list *caps);
-
-static int instantiate_veth(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_macvlan(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_vlan(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_phys(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_empty(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_none(struct lxc_handler *, struct lxc_netdev *);
-
-static  instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
-       [LXC_NET_VETH]    = instantiate_veth,
-       [LXC_NET_MACVLAN] = instantiate_macvlan,
-       [LXC_NET_VLAN]    = instantiate_vlan,
-       [LXC_NET_PHYS]    = instantiate_phys,
-       [LXC_NET_EMPTY]   = instantiate_empty,
-       [LXC_NET_NONE]    = instantiate_none,
-};
-
-static int shutdown_veth(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_macvlan(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_vlan(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_phys(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_empty(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_none(struct lxc_handler *, struct lxc_netdev *);
-
-static  instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
-       [LXC_NET_VETH]    = shutdown_veth,
-       [LXC_NET_MACVLAN] = shutdown_macvlan,
-       [LXC_NET_VLAN]    = shutdown_vlan,
-       [LXC_NET_PHYS]    = shutdown_phys,
-       [LXC_NET_EMPTY]   = shutdown_empty,
-       [LXC_NET_NONE]    = shutdown_none,
-};
-
 static struct mount_opt mount_opt[] = {
        { "async",         1, MS_SYNCHRONOUS },
        { "atime",         1, MS_NOATIME     },
@@ -530,8 +390,7 @@ static int run_script_argv(const char *name, const char *section,
        return run_buffer(buffer);
 }
 
-static int run_script(const char *name, const char *section, const char *script,
-                     ...)
+int run_script(const char *name, const char *section, const char *script, ...)
 {
        int ret;
        char *buffer, *p;
@@ -817,7 +676,7 @@ static const struct dev_symlinks dev_symlinks[] = {
        {"/proc/self/fd/2",     "stderr"},
 };
 
-static int setup_dev_symlinks(const struct lxc_rootfs *rootfs)
+static int lxc_setup_dev_symlinks(const struct lxc_rootfs *rootfs)
 {
        char path[MAXPATHLEN];
        int ret,i;
@@ -852,9 +711,7 @@ static int setup_dev_symlinks(const struct lxc_rootfs *rootfs)
        return 0;
 }
 
-/*
- * Build a space-separate list of ptys to pass to systemd.
- */
+/* Build a space-separate list of ptys to pass to systemd. */
 static bool append_ptyname(char **pp, char *name)
 {
        char *p;
@@ -875,7 +732,7 @@ static bool append_ptyname(char **pp, char *name)
        return true;
 }
 
-static int lxc_setup_tty(struct lxc_conf *conf)
+static int lxc_setup_ttys(struct lxc_conf *conf)
 {
        int i, ret;
        const struct lxc_tty_info *tty_info = &conf->tty_info;
@@ -889,23 +746,19 @@ static int lxc_setup_tty(struct lxc_conf *conf)
                struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
 
                ret = snprintf(path, sizeof(path), "/dev/tty%d", i + 1);
-               if (ret < 0 || (size_t)ret >= sizeof(path)) {
-                       ERROR("pathname too long for ttys");
+               if (ret < 0 || (size_t)ret >= sizeof(path))
                        return -1;
-               }
 
                if (ttydir) {
                        /* create dev/lxc/tty%d" */
                        ret = snprintf(lxcpath, sizeof(lxcpath),
                                       "/dev/%s/tty%d", ttydir, i + 1);
-                       if (ret < 0 || (size_t)ret >= sizeof(lxcpath)) {
-                               ERROR("pathname too long for ttys");
+                       if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
                                return -1;
-                       }
 
                        ret = creat(lxcpath, 0660);
                        if (ret < 0 && errno != EEXIST) {
-                               SYSERROR("failed to create \"%s\"", lxcpath);
+                               SYSERROR("Failed to create \"%s\"", lxcpath);
                                return -1;
                        }
                        if (ret >= 0)
@@ -913,13 +766,13 @@ static int lxc_setup_tty(struct lxc_conf *conf)
 
                        ret = unlink(path);
                        if (ret < 0 && errno != ENOENT) {
-                               SYSERROR("failed to unlink \"%s\"", path);
+                               SYSERROR("Failed to unlink \"%s\"", path);
                                return -1;
                        }
 
                        ret = mount(pty_info->name, lxcpath, "none", MS_BIND, 0);
                        if (ret < 0) {
-                               WARN("failed to bind mount \"%s\" onto \"%s\"",
+                               WARN("Failed to bind mount \"%s\" onto \"%s\"",
                                     pty_info->name, path);
                                continue;
                        }
@@ -928,14 +781,12 @@ static int lxc_setup_tty(struct lxc_conf *conf)
 
                        ret = snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d",
                                       ttydir, i + 1);
-                       if (ret < 0 || (size_t)ret >= sizeof(lxcpath)) {
-                               ERROR("tty pathname too long");
+                       if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
                                return -1;
-                       }
 
                        ret = symlink(lxcpath, path);
                        if (ret < 0) {
-                               SYSERROR("failed to create symlink \"%s\" -> \"%s\"",
+                               SYSERROR("Failed to create symlink \"%s\" -> \"%s\"",
                                         path, lxcpath);
                                return -1;
                        }
@@ -947,7 +798,7 @@ static int lxc_setup_tty(struct lxc_conf *conf)
                        if (ret < 0) {
                                ret = creat(path, 0660);
                                if (ret < 0) {
-                                       SYSERROR("failed to create \"%s\"", path);
+                                       SYSERROR("Failed to create \"%s\"", path);
                                        /* this isn't fatal, continue */
                                } else {
                                        close(ret);
@@ -956,11 +807,11 @@ static int lxc_setup_tty(struct lxc_conf *conf)
 
                        ret = mount(pty_info->name, path, "none", MS_BIND, 0);
                        if (ret < 0) {
-                               SYSERROR("failed to mount '%s'->'%s'", pty_info->name, path);
+                               SYSERROR("Failed to mount '%s'->'%s'", pty_info->name, path);
                                continue;
                        }
 
-                       DEBUG("bind mounted \"%s\" onto \"%s\"", pty_info->name,
+                       DEBUG("Bind mounted \"%s\" onto \"%s\"", pty_info->name,
                              path);
                }
 
@@ -970,10 +821,154 @@ static int lxc_setup_tty(struct lxc_conf *conf)
                }
        }
 
-       INFO("finished setting up %d /dev/tty<N> device(s)", tty_info->nbtty);
+       INFO("Finished setting up %d /dev/tty<N> device(s)", tty_info->nbtty);
+       return 0;
+}
+
+int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
+{
+       struct lxc_tty_info *tty_info = &conf->tty_info;
+       int i, ret;
+
+       /* no tty in the configuration */
+       if (!conf->tty)
+               return 0;
+
+       tty_info->pty_info = malloc(sizeof(*tty_info->pty_info) * conf->tty);
+       if (!tty_info->pty_info) {
+               SYSERROR("failed to allocate struct *pty_info");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < conf->tty; i++) {
+               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+               process_lock();
+               ret = openpty(&pty_info->master, &pty_info->slave,
+                             pty_info->name, NULL, NULL);
+               process_unlock();
+               if (ret) {
+                       SYSERROR("failed to create pty device number %d", i);
+                       tty_info->nbtty = i;
+                       lxc_delete_tty(tty_info);
+                       return -ENOTTY;
+               }
+
+               DEBUG("allocated pty \"%s\" with master fd %d and slave fd %d",
+                     pty_info->name, pty_info->master, pty_info->slave);
+
+               /* Prevent leaking the file descriptors to the container */
+               ret = fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
+               if (ret < 0)
+                       WARN("failed to set FD_CLOEXEC flag on master fd %d of "
+                            "pty device \"%s\": %s",
+                            pty_info->master, pty_info->name, strerror(errno));
+
+               ret = fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
+               if (ret < 0)
+                       WARN("failed to set FD_CLOEXEC flag on slave fd %d of "
+                            "pty device \"%s\": %s",
+                            pty_info->slave, pty_info->name, strerror(errno));
+
+               pty_info->busy = 0;
+       }
+
+       tty_info->nbtty = conf->tty;
+
+       INFO("finished allocating %d pts devices", conf->tty);
        return 0;
 }
 
+void lxc_delete_tty(struct lxc_tty_info *tty_info)
+{
+       int i;
+
+       for (i = 0; i < tty_info->nbtty; i++) {
+               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+               close(pty_info->master);
+               close(pty_info->slave);
+       }
+
+       free(tty_info->pty_info);
+       tty_info->pty_info = NULL;
+       tty_info->nbtty = 0;
+}
+
+static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
+{
+       int i;
+       struct lxc_conf *conf = handler->conf;
+       struct lxc_tty_info *tty_info = &conf->tty_info;
+       int sock = handler->data_sock[0];
+       int ret = -1;
+
+       if (!conf->tty)
+               return 0;
+
+       for (i = 0; i < conf->tty; i++) {
+               int ttyfds[2];
+               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+               ttyfds[0] = pty_info->master;
+               ttyfds[1] = pty_info->slave;
+
+               ret = lxc_abstract_unix_send_fds(sock, ttyfds, 2, NULL, 0);
+               if (ret < 0)
+                       break;
+
+               TRACE("Send pty \"%s\" with master fd %d and slave fd %d to "
+                     "parent", pty_info->name, pty_info->master, pty_info->slave);
+       }
+
+       if (ret < 0)
+               ERROR("Failed to send %d ttys to parent: %s", conf->tty,
+                     strerror(errno));
+       else
+               TRACE("Sent %d ttys to parent", conf->tty);
+
+       return ret;
+}
+
+static int lxc_create_ttys(struct lxc_handler *handler)
+{
+       int ret = -1;
+       struct lxc_conf *conf = handler->conf;
+
+       ret = lxc_allocate_ttys(handler->name, conf);
+       if (ret < 0) {
+               ERROR("Failed to allocate ttys");
+               goto on_error;
+       }
+
+       ret = lxc_send_ttys_to_parent(handler);
+       if (ret < 0) {
+               ERROR("Failed to send ttys to parent");
+               goto on_error;
+       }
+
+       if (!conf->is_execute) {
+               ret = lxc_setup_ttys(conf);
+               if (ret < 0) {
+                       ERROR("Failed to setup ttys");
+                       goto on_error;
+               }
+       }
+
+       if (conf->pty_names) {
+               ret = setenv("container_ttys", conf->pty_names, 1);
+               if (ret < 0)
+                       SYSERROR("Failed to set \"container_ttys=%s\"", conf->pty_names);
+       }
+
+       ret = 0;
+
+on_error:
+       lxc_delete_tty(&conf->tty_info);
+
+       return ret;
+}
+
 static int setup_rootfs_pivot_root(const char *rootfs)
 {
        int oldroot = -1, newroot = -1;
@@ -2325,1098 +2320,115 @@ static int dropcaps_except(struct lxc_list *caps)
        return 0;
 }
 
-static int setup_hw_addr(char *hwaddr, const char *ifname)
-{
-       struct sockaddr sockaddr;
-       struct ifreq ifr;
-       int ret, fd, saved_errno;
-
-       ret = lxc_convert_mac(hwaddr, &sockaddr);
-       if (ret) {
-               ERROR("mac address '%s' conversion failed : %s",
-                     hwaddr, strerror(-ret));
-               return -1;
-       }
-
-       memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-       ifr.ifr_name[IFNAMSIZ-1] = '\0';
-       memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
+static int parse_resource(const char *res) {
+       size_t i;
+       int resid = -1;
 
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-       if (fd < 0) {
-               ERROR("socket failure : %s", strerror(errno));
-               return -1;
+       for (i = 0; i < sizeof(limit_opt)/sizeof(limit_opt[0]); ++i) {
+               if (strcmp(res, limit_opt[i].name) == 0)
+                       return limit_opt[i].value;
        }
 
-       ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
-       saved_errno = errno;
-       close(fd);
-       if (ret)
-               ERROR("ioctl failure : %s", strerror(saved_errno));
-
-       DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifr.ifr_name);
-
-       return ret;
+       /* try to see if it's numeric, so the user may specify
+        * resources that the running kernel knows about but
+        * we don't */
+       if (lxc_safe_int(res, &resid) == 0)
+               return resid;
+       return -1;
 }
 
-static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
-{
-       struct lxc_list *iterator;
-       struct lxc_inetdev *inetdev;
-       int err;
-
-       lxc_list_for_each(iterator, ip) {
+int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
+       struct lxc_list *it;
+       struct lxc_limit *lim;
+       int resid;
 
-               inetdev = iterator->elem;
+       lxc_list_for_each(it, limits) {
+               lim = it->elem;
 
-               err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
-                                       &inetdev->bcast, inetdev->prefix);
-               if (err) {
-                       ERROR("failed to setup_ipv4_addr ifindex %d : %s",
-                             ifindex, strerror(-err));
+               resid = parse_resource(lim->resource);
+               if (resid < 0) {
+                       ERROR("unknown resource %s", lim->resource);
                        return -1;
                }
-       }
-
-       return 0;
-}
-
-static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
-{
-       struct lxc_list *iterator;
-       struct lxc_inet6dev *inet6dev;
-       int err;
-
-       lxc_list_for_each(iterator, ip) {
-
-               inet6dev = iterator->elem;
 
-               err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
-                                       &inet6dev->mcast, &inet6dev->acast,
-                                       inet6dev->prefix);
-               if (err) {
-                       ERROR("failed to setup_ipv6_addr ifindex %d : %s",
-                             ifindex, strerror(-err));
+#if HAVE_PRLIMIT || HAVE_PRLIMIT64
+               if (prlimit(pid, resid, &lim->limit, NULL) != 0) {
+                       ERROR("failed to set limit %s: %s", lim->resource, strerror(errno));
                        return -1;
                }
+#else
+               ERROR("Cannot set limit %s as prlimit is missing", lim->resource);
+               return -1;
+#endif
        }
-
        return 0;
 }
 
-static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
-{
-       char ifname[IFNAMSIZ];
-       int err;
-       const char *net_type_name;
-       char *current_ifname = ifname;
-
-       /* empty network namespace */
-       if (!netdev->ifindex) {
-               if (netdev->flags & IFF_UP) {
-                       err = lxc_netdev_up("lo");
-                       if (err) {
-                               ERROR("failed to set the loopback up : %s",
-                                     strerror(-err));
-                               return -1;
-                       }
-               }
-
-               if (netdev->type == LXC_NET_EMPTY)
-                       return 0;
-
-               if (netdev->type == LXC_NET_NONE)
-                       return 0;
-
-               if (netdev->type != LXC_NET_VETH) {
-                       net_type_name = lxc_net_type_to_str(netdev->type);
-                       ERROR("%s networks are not supported for containers "
-                             "not setup up by privileged users",
-                             net_type_name);
-                       return -1;
-               }
-
-               netdev->ifindex = if_nametoindex(netdev->name);
-       }
+static char *default_rootfs_mount = LXCROOTFSMOUNT;
 
-       /* get the new ifindex in case of physical netdev */
-       if (netdev->type == LXC_NET_PHYS) {
-               if (!(netdev->ifindex = if_nametoindex(netdev->link))) {
-                       ERROR("failed to get ifindex for %s",
-                               netdev->link);
-                       return -1;
-               }
-       }
+struct lxc_conf *lxc_conf_init(void)
+{
+       struct lxc_conf *new;
+       int i;
 
-       /* retrieve the name of the interface */
-       if (!if_indextoname(netdev->ifindex, current_ifname)) {
-               ERROR("no interface corresponding to index '%d'",
-                     netdev->ifindex);
-               return -1;
+       new = malloc(sizeof(*new));
+       if (!new) {
+               ERROR("lxc_conf_init : %s", strerror(errno));
+               return NULL;
        }
+       memset(new, 0, sizeof(*new));
 
-       /* default: let the system to choose one interface name */
-       if (!netdev->name)
-               netdev->name = netdev->type == LXC_NET_PHYS ?
-                       netdev->link : "eth%d";
-
-       /* rename the interface name */
-       if (strcmp(ifname, netdev->name) != 0) {
-               err = lxc_netdev_rename_by_name(ifname, netdev->name);
-               if (err) {
-                       ERROR("failed to rename %s->%s : %s", ifname, netdev->name,
-                             strerror(-err));
-                       return -1;
-               }
-       }
-
-       /* Re-read the name of the interface because its name has changed
-        * and would be automatically allocated by the system
-        */
-       if (!if_indextoname(netdev->ifindex, current_ifname)) {
-               ERROR("no interface corresponding to index '%d'",
-                     netdev->ifindex);
-               return -1;
-       }
-
-       /* set a mac address */
-       if (netdev->hwaddr) {
-               if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
-                       ERROR("failed to setup hw address for '%s'",
-                             current_ifname);
-                       return -1;
-               }
-       }
-
-       /* setup ipv4 addresses on the interface */
-       if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
-               ERROR("failed to setup ip addresses for '%s'",
-                             ifname);
-               return -1;
-       }
-
-       /* setup ipv6 addresses on the interface */
-       if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
-               ERROR("failed to setup ipv6 addresses for '%s'",
-                             ifname);
-               return -1;
-       }
-
-       /* set the network device up */
-       if (netdev->flags & IFF_UP) {
-               int err;
-
-               err = lxc_netdev_up(current_ifname);
-               if (err) {
-                       ERROR("failed to set '%s' up : %s", current_ifname,
-                             strerror(-err));
-                       return -1;
-               }
-
-               /* the network is up, make the loopback up too */
-               err = lxc_netdev_up("lo");
-               if (err) {
-                       ERROR("failed to set the loopback up : %s",
-                             strerror(-err));
-                       return -1;
-               }
-       }
-
-       /* We can only set up the default routes after bringing
-        * up the interface, sine bringing up the interface adds
-        * the link-local routes and we can't add a default
-        * route if the gateway is not reachable. */
-
-       /* setup ipv4 gateway on the interface */
-       if (netdev->ipv4_gateway) {
-               if (!(netdev->flags & IFF_UP)) {
-                       ERROR("Cannot add ipv4 gateway for %s when not bringing up the interface", ifname);
-                       return -1;
-               }
-
-               if (lxc_list_empty(&netdev->ipv4)) {
-                       ERROR("Cannot add ipv4 gateway for %s when not assigning an address", ifname);
-                       return -1;
-               }
-
-               err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
-               if (err) {
-                       err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway);
-                       if (err) {
-                               ERROR("failed to add ipv4 dest for '%s': %s",
-                                             ifname, strerror(-err));
-                       }
-
-                       err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
-                       if (err) {
-                               ERROR("failed to setup ipv4 gateway for '%s': %s",
-                                             ifname, strerror(-err));
-                               if (netdev->ipv4_gateway_auto) {
-                                       char buf[INET_ADDRSTRLEN];
-                                       inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
-                                       ERROR("tried to set autodetected ipv4 gateway '%s'", buf);
-                               }
-                               return -1;
-                       }
-               }
-       }
-
-       /* setup ipv6 gateway on the interface */
-       if (netdev->ipv6_gateway) {
-               if (!(netdev->flags & IFF_UP)) {
-                       ERROR("Cannot add ipv6 gateway for %s when not bringing up the interface", ifname);
-                       return -1;
-               }
-
-               if (lxc_list_empty(&netdev->ipv6) && !IN6_IS_ADDR_LINKLOCAL(netdev->ipv6_gateway)) {
-                       ERROR("Cannot add ipv6 gateway for %s when not assigning an address", ifname);
-                       return -1;
-               }
-
-               err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
-               if (err) {
-                       err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway);
-                       if (err) {
-                               ERROR("failed to add ipv6 dest for '%s': %s",
-                                     ifname, strerror(-err));
-                       }
-
-                       err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
-                       if (err) {
-                               ERROR("failed to setup ipv6 gateway for '%s': %s",
-                                             ifname, strerror(-err));
-                               if (netdev->ipv6_gateway_auto) {
-                                       char buf[INET6_ADDRSTRLEN];
-                                       inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
-                                       ERROR("tried to set autodetected ipv6 gateway '%s'", buf);
-                               }
-                               return -1;
-                       }
-               }
-       }
-
-       DEBUG("'%s' has been setup", current_ifname);
-
-       return 0;
-}
-
-static int lxc_setup_networks_in_child_namespaces(const struct lxc_conf *conf,
-                                                 struct lxc_list *network)
-{
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-
-       lxc_log_configured_netdevs(conf);
-
-       lxc_list_for_each(iterator, network) {
-               netdev = iterator->elem;
-
-               /* REMOVE in LXC 3.0 */
-               if (netdev->idx < 0) {
-                       ERROR("WARNING: using \"lxc.network.*\" keys to define "
-                             "networks is DEPRECATED, please switch to using "
-                             "\"lxc.net.[i].* keys\"");
-               }
-
-               if (lxc_setup_netdev_in_child_namespaces(netdev)) {
-                       ERROR("failed to setup netdev");
-                       return -1;
-               }
-       }
-
-       if (!lxc_list_empty(network))
-               INFO("network has been setup");
-
-       return 0;
-}
-
-static int parse_resource(const char *res) {
-       size_t i;
-       int resid = -1;
-
-       for (i = 0; i < sizeof(limit_opt)/sizeof(limit_opt[0]); ++i) {
-               if (strcmp(res, limit_opt[i].name) == 0)
-                       return limit_opt[i].value;
-       }
-
-       /* try to see if it's numeric, so the user may specify
-        * resources that the running kernel knows about but
-        * we don't */
-       if (lxc_safe_int(res, &resid) == 0)
-               return resid;
-       return -1;
-}
-
-int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
-       struct lxc_list *it;
-       struct lxc_limit *lim;
-       int resid;
-
-       lxc_list_for_each(it, limits) {
-               lim = it->elem;
-
-               resid = parse_resource(lim->resource);
-               if (resid < 0) {
-                       ERROR("unknown resource %s", lim->resource);
-                       return -1;
-               }
-
-               if (prlimit(pid, resid, &lim->limit, NULL) != 0) {
-                       ERROR("failed to set limit %s: %s", lim->resource, strerror(errno));
-                       return -1;
-               }
-       }
-       return 0;
-}
-
-/* try to move physical nics to the init netns */
-void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
-{
-       int i, oldfd;
-       char ifname[IFNAMSIZ];
-
-       if (netnsfd < 0 || conf->num_savednics == 0)
-               return;
-
-       INFO("Running to reset %d nic names.", conf->num_savednics);
-
-       oldfd = lxc_preserve_ns(getpid(), "net");
-       if (oldfd < 0) {
-               SYSERROR("Failed to open monitor netns fd.");
-               return;
-       }
-
-       if (setns(netnsfd, 0) != 0) {
-               SYSERROR("Failed to enter container netns to reset nics");
-               close(oldfd);
-               return;
-       }
-       for (i=0; i<conf->num_savednics; i++) {
-               struct saved_nic *s = &conf->saved_nics[i];
-               /* retrieve the name of the interface */
-               if (!if_indextoname(s->ifindex, ifname)) {
-                       WARN("no interface corresponding to index '%d'", s->ifindex);
-                       continue;
-               }
-               if (lxc_netdev_move_by_name(ifname, 1, s->orig_name))
-                       WARN("Error moving nic name:%s back to host netns", ifname);
-               free(s->orig_name);
-       }
-       conf->num_savednics = 0;
-
-       if (setns(oldfd, 0) != 0)
-               SYSERROR("Failed to re-enter monitor's netns");
-       close(oldfd);
-}
-
-static char *default_rootfs_mount = LXCROOTFSMOUNT;
-
-struct lxc_conf *lxc_conf_init(void)
-{
-       struct lxc_conf *new;
-       int i;
-
-       new = malloc(sizeof(*new));
-       if (!new) {
-               ERROR("lxc_conf_init : %s", strerror(errno));
-               return NULL;
-       }
-       memset(new, 0, sizeof(*new));
-
-       new->loglevel = LXC_LOG_LEVEL_NOTSET;
-       new->personality = -1;
-       new->autodev = 1;
-       new->console.log_path = NULL;
-       new->console.log_fd = -1;
-       new->console.path = NULL;
-       new->console.peer = -1;
-       new->console.peerpty.busy = -1;
-       new->console.peerpty.master = -1;
-       new->console.peerpty.slave = -1;
-       new->console.master = -1;
-       new->console.slave = -1;
-       new->console.name[0] = '\0';
-       new->maincmd_fd = -1;
-       new->nbd_idx = -1;
-       new->rootfs.mount = strdup(default_rootfs_mount);
-       if (!new->rootfs.mount) {
-               ERROR("lxc_conf_init : %s", strerror(errno));
-               free(new);
-               return NULL;
-       }
-       new->logfd = -1;
-       lxc_list_init(&new->cgroup);
-       lxc_list_init(&new->network);
-       lxc_list_init(&new->mount_list);
-       lxc_list_init(&new->caps);
-       lxc_list_init(&new->keepcaps);
-       lxc_list_init(&new->id_map);
-       lxc_list_init(&new->includes);
-       lxc_list_init(&new->aliens);
-       lxc_list_init(&new->environment);
-       lxc_list_init(&new->limits);
-       for (i=0; i<NUM_LXC_HOOKS; i++)
-               lxc_list_init(&new->hooks[i]);
-       lxc_list_init(&new->groups);
-       new->lsm_aa_profile = NULL;
-       new->lsm_se_context = NULL;
-       new->tmp_umount_proc = 0;
-
-       for (i = 0; i < LXC_NS_MAX; i++)
-               new->inherit_ns_fd[i] = -1;
-
-       /* if running in a new user namespace, init and COMMAND
-        * default to running as UID/GID 0 when using lxc-execute */
-       new->init_uid = 0;
-       new->init_gid = 0;
-       memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
-
-       return new;
-}
-
-static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       char *veth1, *veth2;
-       char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
-       int bridge_index, err;
-       unsigned int mtu = 0;
-
-       if (netdev->priv.veth_attr.pair) {
-               veth1 = netdev->priv.veth_attr.pair;
-               if (handler->conf->reboot)
-                       lxc_netdev_delete_by_name(veth1);
-       } else {
-               err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
-               if (err >= sizeof(veth1buf)) { /* can't *really* happen, but... */
-                       ERROR("veth1 name too long");
-                       return -1;
-               }
-               veth1 = lxc_mkifname(veth1buf);
-               if (!veth1) {
-                       ERROR("failed to allocate a temporary name");
-                       return -1;
-               }
-               /* store away for deconf */
-               memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
-       }
-
-       snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
-       veth2 = lxc_mkifname(veth2buf);
-       if (!veth2) {
-               ERROR("failed to allocate a temporary name");
-               goto out_delete;
-       }
-
-       err = lxc_veth_create(veth1, veth2);
-       if (err) {
-               ERROR("failed to create veth pair \"%s\" and \"%s\": %s", veth1,
-                     veth2, strerror(-err));
-               goto out_delete;
-       }
-
-       /* changing the high byte of the mac address to 0xfe, the bridge interface
-        * will always keep the host's mac address and not take the mac address
-        * of a container */
-       err = setup_private_host_hw_addr(veth1);
-       if (err) {
-               ERROR("failed to change mac address of host interface \"%s\": %s",
-                     veth1, strerror(-err));
-               goto out_delete;
-       }
-
-       netdev->ifindex = if_nametoindex(veth2);
-       if (!netdev->ifindex) {
-               ERROR("failed to retrieve the index for \"%s\"", veth2);
-               goto out_delete;
-       }
-
-       if (netdev->mtu) {
-               if (lxc_safe_uint(netdev->mtu, &mtu) < 0)
-                       WARN("failed to parse mtu from");
-               else
-                       INFO("retrieved mtu %d", mtu);
-       } else if (netdev->link) {
-               bridge_index = if_nametoindex(netdev->link);
-               if (bridge_index) {
-                       mtu = netdev_get_mtu(bridge_index);
-                       INFO("retrieved mtu %d from %s", mtu, netdev->link);
-               } else {
-                       mtu = netdev_get_mtu(netdev->ifindex);
-                       INFO("retrieved mtu %d from %s", mtu, veth2);
-               }
-       }
-
-       if (mtu) {
-               err = lxc_netdev_set_mtu(veth1, mtu);
-               if (!err)
-                       err = lxc_netdev_set_mtu(veth2, mtu);
-               if (err) {
-                       ERROR("failed to set mtu \"%d\" for veth pair \"%s\" "
-                             "and \"%s\": %s",
-                             mtu, veth1, veth2, strerror(-err));
-                       goto out_delete;
-               }
-       }
-
-       if (netdev->link) {
-               err = lxc_bridge_attach(handler->lxcpath, handler->name, netdev->link, veth1);
-               if (err) {
-                       ERROR("failed to attach \"%s\" to bridge \"%s\": %s",
-                             veth1, netdev->link, strerror(-err));
-                       goto out_delete;
-               }
-               INFO("attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
-       }
-
-       err = lxc_netdev_up(veth1);
-       if (err) {
-               ERROR("failed to set \"%s\" up: %s", veth1, strerror(-err));
-               goto out_delete;
-       }
-
-       if (netdev->upscript) {
-               err = run_script(handler->name, "net", netdev->upscript, "up",
-                                "veth", veth1, (char*) NULL);
-               if (err)
-                       goto out_delete;
-       }
-
-       DEBUG("instantiated veth \"%s/%s\", index is \"%d\"", veth1, veth2,
-             netdev->ifindex);
-
-       return 0;
-
-out_delete:
-       if (netdev->ifindex != 0)
-               lxc_netdev_delete_by_name(veth1);
-       if (!netdev->priv.veth_attr.pair)
-               free(veth1);
-       free(veth2);
-       return -1;
-}
-
-static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       char *veth1;
-       int err;
-
-       if (netdev->priv.veth_attr.pair)
-               veth1 = netdev->priv.veth_attr.pair;
-       else
-               veth1 = netdev->priv.veth_attr.veth1;
-
-       if (netdev->downscript) {
-               err = run_script(handler->name, "net", netdev->downscript,
-                                "down", "veth", veth1, (char*) NULL);
-               if (err)
-                       return -1;
-       }
-       return 0;
-}
-
-static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       char peerbuf[IFNAMSIZ], *peer;
-       int err;
-
-       if (!netdev->link) {
-               ERROR("no link specified for macvlan netdev");
-               return -1;
-       }
-
-       err = snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
-       if (err >= sizeof(peerbuf))
-               return -1;
-
-       peer = lxc_mkifname(peerbuf);
-       if (!peer) {
-               ERROR("failed to make a temporary name");
-               return -1;
-       }
-
-       err = lxc_macvlan_create(netdev->link, peer,
-                                netdev->priv.macvlan_attr.mode);
-       if (err) {
-               ERROR("failed to create macvlan interface '%s' on '%s' : %s",
-                     peer, netdev->link, strerror(-err));
-               goto out;
-       }
-
-       netdev->ifindex = if_nametoindex(peer);
-       if (!netdev->ifindex) {
-               ERROR("failed to retrieve the index for %s", peer);
-               goto out;
-       }
-
-       if (netdev->upscript) {
-               err = run_script(handler->name, "net", netdev->upscript, "up",
-                                "macvlan", netdev->link, (char*) NULL);
-               if (err)
-                       goto out;
-       }
-
-       DEBUG("instantiated macvlan '%s', index is '%d' and mode '%d'",
-             peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
-
-       return 0;
-out:
-       lxc_netdev_delete_by_name(peer);
-       free(peer);
-       return -1;
-}
-
-static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       int err;
-
-       if (netdev->downscript) {
-               err = run_script(handler->name, "net", netdev->downscript,
-                                "down", "macvlan", netdev->link,
-                                (char*) NULL);
-               if (err)
-                       return -1;
-       }
-       return 0;
-}
-
-/* XXX: merge with instantiate_macvlan */
-static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       char peer[IFNAMSIZ];
-       int err;
-       static uint16_t vlan_cntr = 0;
-       unsigned int mtu = 0;
-
-       if (!netdev->link) {
-               ERROR("no link specified for vlan netdev");
-               return -1;
-       }
-
-       err = snprintf(peer, sizeof(peer), "vlan%d-%d", netdev->priv.vlan_attr.vid, vlan_cntr++);
-       if (err >= sizeof(peer)) {
-               ERROR("peer name too long");
-               return -1;
-       }
-
-       err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
-       if (err) {
-               ERROR("failed to create vlan interface '%s' on '%s' : %s",
-                     peer, netdev->link, strerror(-err));
-               return -1;
-       }
-
-       netdev->ifindex = if_nametoindex(peer);
-       if (!netdev->ifindex) {
-               ERROR("failed to retrieve the ifindex for %s", peer);
-               lxc_netdev_delete_by_name(peer);
-               return -1;
-       }
-
-       DEBUG("instantiated vlan '%s', ifindex is '%d'", " vlan1000",
-             netdev->ifindex);
-       if (netdev->mtu) {
-               if (lxc_safe_uint(netdev->mtu, &mtu) < 0) {
-                       ERROR("Failed to retrieve mtu from: '%d'/'%s'.",
-                             netdev->ifindex, netdev->name);
-                       return -1;
-               }
-               err = lxc_netdev_set_mtu(peer, mtu);
-               if (err) {
-                       ERROR("failed to set mtu '%s' for %s : %s",
-                             netdev->mtu, peer, strerror(-err));
-                       lxc_netdev_delete_by_name(peer);
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       return 0;
-}
-
-static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       if (!netdev->link) {
-               ERROR("no link specified for the physical interface");
-               return -1;
-       }
-
-       netdev->ifindex = if_nametoindex(netdev->link);
-       if (!netdev->ifindex) {
-               ERROR("failed to retrieve the index for %s", netdev->link);
-               return -1;
-       }
-
-       if (netdev->upscript) {
-               int err;
-               err = run_script(handler->name, "net", netdev->upscript,
-                                "up", "phys", netdev->link, (char*) NULL);
-               if (err)
-                       return -1;
-       }
-
-       return 0;
-}
-
-static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       int err;
-
-       if (netdev->downscript) {
-               err = run_script(handler->name, "net", netdev->downscript,
-                                "down", "phys", netdev->link, (char*) NULL);
-               if (err)
-                       return -1;
-       }
-       return 0;
-}
-
-static int instantiate_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       netdev->ifindex = 0;
-       return 0;
-}
-
-static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       netdev->ifindex = 0;
-       if (netdev->upscript) {
-               int err;
-               err = run_script(handler->name, "net", netdev->upscript,
-                                "up", "empty", (char*) NULL);
-               if (err)
-                       return -1;
-       }
-       return 0;
-}
-
-static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       int err;
-
-       if (netdev->downscript) {
-               err = run_script(handler->name, "net", netdev->downscript,
-                                "down", "empty", (char*) NULL);
-               if (err)
-                       return -1;
-       }
-       return 0;
-}
-
-static int shutdown_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
-       return 0;
-}
-
-int lxc_requests_empty_network(struct lxc_handler *handler)
-{
-       struct lxc_list *network = &handler->conf->network;
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-       bool found_none = false, found_nic = false;
-
-       if (lxc_list_empty(network))
-               return 0;
-
-       lxc_list_for_each(iterator, network) {
-
-               netdev = iterator->elem;
-
-               if (netdev->type == LXC_NET_NONE)
-                       found_none = true;
-               else
-                       found_nic = true;
-       }
-       if (found_none && !found_nic)
-               return 1;
-       return 0;
-}
-
-int lxc_setup_networks_in_parent_namespaces(struct lxc_handler *handler)
-{
-       bool am_root;
-       struct lxc_netdev *netdev;
-       struct lxc_list *iterator;
-       struct lxc_list *network = &handler->conf->network;
-
-       /* We need to be root. */
-       am_root = (getuid() == 0);
-       if (!am_root)
-               return 0;
-
-       lxc_list_for_each(iterator, network) {
-               netdev = iterator->elem;
-
-               if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) {
-                       ERROR("invalid network configuration type '%d'",
-                             netdev->type);
-                       return -1;
-               }
-
-               if (netdev->type != LXC_NET_MACVLAN &&
-                   netdev->priv.macvlan_attr.mode) {
-                       ERROR("Invalid macvlan.mode for a non-macvlan netdev");
-                       return -1;
-               }
-
-               if (netdev->type != LXC_NET_VETH &&
-                   netdev->priv.veth_attr.pair) {
-                       ERROR("Invalid veth pair for a non-veth netdev");
-                       return -1;
-               }
-
-               if (netdev->type != LXC_NET_VLAN &&
-                   netdev->priv.vlan_attr.vid > 0) {
-                       ERROR("Invalid vlan.id for a non-macvlan netdev");
-                       return -1;
-               }
-
-               if (netdev_conf[netdev->type](handler, netdev)) {
-                       ERROR("failed to create netdev");
-                       return -1;
-               }
-
-       }
-
-       return 0;
-}
-
-bool lxc_delete_network(struct lxc_handler *handler)
-{
-       int ret;
-       struct lxc_list *network = &handler->conf->network;
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-       bool deleted_all = true;
-
-       lxc_list_for_each(iterator, network) {
-               netdev = iterator->elem;
-
-               if (netdev->ifindex != 0 && netdev->type == LXC_NET_PHYS) {
-                       if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link))
-                               WARN("Failed to rename interface with index %d "
-                                    "to its initial name \"%s\".",
-                                    netdev->ifindex, netdev->link);
-                       continue;
-               }
-
-               if (netdev_deconf[netdev->type](handler, netdev)) {
-                       WARN("Failed to destroy netdev");
-               }
-
-               /* Recent kernel remove the virtual interfaces when the network
-                * namespace is destroyed but in case we did not moved the
-                * interface to the network namespace, we have to destroy it
-                */
-               if (netdev->ifindex != 0) {
-                       ret = lxc_netdev_delete_by_index(netdev->ifindex);
-                       if (-ret == ENODEV) {
-                               INFO("Interface \"%s\" with index %d already "
-                                    "deleted or existing in different network "
-                                    "namespace.",
-                                    netdev->name ? netdev->name : "(null)",
-                                    netdev->ifindex);
-                       } else if (ret < 0) {
-                               deleted_all = false;
-                               WARN("Failed to remove interface \"%s\" with "
-                                    "index %d: %s.",
-                                    netdev->name ? netdev->name : "(null)",
-                                    netdev->ifindex, strerror(-ret));
-                       } else {
-                               INFO("Removed interface \"%s\" with index %d.",
-                                    netdev->name ? netdev->name : "(null)",
-                                    netdev->ifindex);
-                       }
-               }
-
-               /* Explicitly delete host veth device to prevent lingering
-                * devices. We had issues in LXD around this.
-                */
-               if (netdev->ifindex != 0 && netdev->type == LXC_NET_VETH && !am_unpriv()) {
-                       char *hostveth;
-                       if (netdev->priv.veth_attr.pair) {
-                               hostveth = netdev->priv.veth_attr.pair;
-                               ret = lxc_netdev_delete_by_name(hostveth);
-                               if (ret < 0) {
-                                       WARN("Failed to remove interface \"%s\" from host: %s.", hostveth, strerror(-ret));
-                               } else {
-                                       INFO("Removed interface \"%s\" from host.", hostveth);
-                               }
-                       } else if (strlen(netdev->priv.veth_attr.veth1) > 0) {
-                               hostveth = netdev->priv.veth_attr.veth1;
-                               ret = lxc_netdev_delete_by_name(hostveth);
-                               if (ret < 0) {
-                                       WARN("Failed to remove \"%s\" from host: %s.", hostveth, strerror(-ret));
-                               } else {
-                                       INFO("Removed interface \"%s\" from host.", hostveth);
-                                       memset((void *)&netdev->priv.veth_attr.veth1, 0, sizeof(netdev->priv.veth_attr.veth1));
-                               }
-                       }
-               }
-       }
-
-       return deleted_all;
-}
-
-#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
-
-/* lxc-user-nic returns "interface_name:interface_name\n" */
-#define MAX_BUFFER_SIZE IFNAMSIZ * 2 + 2
-static int unpriv_assign_nic(const char *lxcpath, char *lxcname,
-                            struct lxc_netdev *netdev, pid_t pid)
-{
-       pid_t child;
-       int bytes, pipefd[2];
-       char *token, *saveptr = NULL;
-       char buffer[MAX_BUFFER_SIZE];
-       char netdev_link[IFNAMSIZ + 1];
-
-       if (netdev->type != LXC_NET_VETH) {
-               ERROR("nic type %d not support for unprivileged use",
-                     netdev->type);
-               return -1;
-       }
-
-       if (pipe(pipefd) < 0) {
-               SYSERROR("pipe failed");
-               return -1;
-       }
-
-       child = fork();
-       if (child < 0) {
-               SYSERROR("fork");
-               close(pipefd[0]);
-               close(pipefd[1]);
-               return -1;
-       }
-
-       if (child == 0) { /* child */
-               /* Call lxc-user-nic pid type bridge. */
-               int ret;
-               char pidstr[LXC_NUMSTRLEN64];
-
-               close(pipefd[0]); /* Close the read-end of the pipe. */
-
-               /* Redirect stdout to write-end of the pipe. */
-               ret = dup2(pipefd[1], STDOUT_FILENO);
-               close(pipefd[1]); /* Close the write-end of the pipe. */
-               if (ret < 0) {
-                       SYSERROR("Failed to dup2() to redirect stdout to pipe file descriptor.");
-                       exit(EXIT_FAILURE);
-               }
-
-               if (netdev->link)
-                       strncpy(netdev_link, netdev->link, IFNAMSIZ);
-               else
-                       strncpy(netdev_link, "none", IFNAMSIZ);
-
-               ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
-               if (ret < 0 || ret >= LXC_NUMSTRLEN64)
-                       exit(EXIT_FAILURE);
-               pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
-
-               INFO("Execing lxc-user-nic %s %s %s veth %s %s", lxcpath,
-                    lxcname, pidstr, netdev_link, netdev->name);
-               execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, lxcpath, lxcname,
-                      pidstr, "veth", netdev_link, netdev->name, NULL);
-
-               SYSERROR("Failed to exec lxc-user-nic.");
-               exit(EXIT_FAILURE);
-       }
-
-       /* close the write-end of the pipe */
-       close(pipefd[1]);
-
-       bytes = read(pipefd[0], &buffer, MAX_BUFFER_SIZE);
-       if (bytes < 0)
-               SYSERROR("Failed to read from pipe file descriptor.");
-       buffer[bytes - 1] = '\0';
-
-       if (wait_for_pid(child) != 0) {
-               close(pipefd[0]);
-               return -1;
-       }
-
-       /* close the read-end of the pipe */
-       close(pipefd[0]);
-
-       /* fill netdev->name field */
-       token = strtok_r(buffer, ":", &saveptr);
-       if (!token)
-               return -1;
-
-       netdev->name = malloc(IFNAMSIZ + 1);
-       if (!netdev->name) {
-               SYSERROR("Failed to allocate memory.");
-               return -1;
-       }
-       memset(netdev->name, 0, IFNAMSIZ + 1);
-       strncpy(netdev->name, token, IFNAMSIZ);
-
-       /* fill netdev->veth_attr.pair field */
-       token = strtok_r(NULL, ":", &saveptr);
-       if (!token)
-               return -1;
-
-       netdev->priv.veth_attr.pair = strdup(token);
-       if (!netdev->priv.veth_attr.pair) {
-               ERROR("Failed to allocate memory.");
-               return -1;
+       new->loglevel = LXC_LOG_LEVEL_NOTSET;
+       new->personality = -1;
+       new->autodev = 1;
+       new->console.buffer_log_file = NULL;
+       new->console.buffer_log_file_fd = -1;
+       new->console.buffer_size = 0;
+       new->console.log_path = NULL;
+       new->console.log_fd = -1;
+       new->console.path = NULL;
+       new->console.peer = -1;
+       new->console.peerpty.busy = -1;
+       new->console.peerpty.master = -1;
+       new->console.peerpty.slave = -1;
+       new->console.master = -1;
+       new->console.slave = -1;
+       new->console.name[0] = '\0';
+       memset(&new->console.ringbuf, 0, sizeof(struct lxc_ringbuf));
+       new->maincmd_fd = -1;
+       new->nbd_idx = -1;
+       new->rootfs.mount = strdup(default_rootfs_mount);
+       if (!new->rootfs.mount) {
+               ERROR("lxc_conf_init : %s", strerror(errno));
+               free(new);
+               return NULL;
        }
+       new->logfd = -1;
+       lxc_list_init(&new->cgroup);
+       lxc_list_init(&new->network);
+       lxc_list_init(&new->mount_list);
+       lxc_list_init(&new->caps);
+       lxc_list_init(&new->keepcaps);
+       lxc_list_init(&new->id_map);
+       lxc_list_init(&new->includes);
+       lxc_list_init(&new->aliens);
+       lxc_list_init(&new->environment);
+       lxc_list_init(&new->limits);
+       for (i = 0; i < NUM_LXC_HOOKS; i++)
+               lxc_list_init(&new->hooks[i]);
+       lxc_list_init(&new->groups);
+       new->lsm_aa_profile = NULL;
+       new->lsm_se_context = NULL;
+       new->tmp_umount_proc = 0;
 
-       return 0;
-}
-
-int lxc_assign_network(const char *lxcpath, char *lxcname,
-                      struct lxc_list *network, pid_t pid)
-{
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-       char ifname[IFNAMSIZ];
-       int am_root = (getuid() == 0);
-       int err;
-
-       lxc_list_for_each(iterator, network) {
-
-               netdev = iterator->elem;
-
-               if (netdev->type == LXC_NET_VETH && !am_root) {
-                       if (netdev->mtu)
-                               INFO("mtu ignored due to insufficient privilege");
-                       if (unpriv_assign_nic(lxcpath, lxcname, netdev, pid))
-                               return -1;
-                       /* lxc-user-nic has moved the nic to the new ns.
-                        * unpriv_assign_nic() fills in netdev->name.
-                        * netdev->ifindex will be filed in at
-                        * lxc_setup_netdev_in_child_namespaces.
-                        */
-                       continue;
-               }
-
-               /* empty network namespace, nothing to move */
-               if (!netdev->ifindex)
-                       continue;
-
-               /* retrieve the name of the interface */
-               if (!if_indextoname(netdev->ifindex, ifname)) {
-                       ERROR("no interface corresponding to index '%d'", netdev->ifindex);
-                       return -1;
-               }
-
-               err = lxc_netdev_move_by_name(ifname, pid, NULL);
-               if (err) {
-                       ERROR("failed to move '%s' to the container : %s",
-                             netdev->link, strerror(-err));
-                       return -1;
-               }
-
-               DEBUG("move '%s'/'%s' to '%d': .", ifname, netdev->name, pid);
-       }
+       /* if running in a new user namespace, init and COMMAND
+        * default to running as UID/GID 0 when using lxc-execute */
+       new->init_uid = 0;
+       new->init_gid = 0;
+       memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
+       memset(&new->inherit_ns, 0, sizeof(char *) * LXC_NS_MAX);
 
-       return 0;
+       return new;
 }
 
 static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
@@ -3589,9 +2601,6 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
                        pos += sprintf(mapbuf, "new%cidmap %d", u_or_g, pid);
 
                lxc_list_for_each(iterator, idmap) {
-                       /* The kernel only takes <= 4k for writes to
-                        * /proc/<nr>/[ug]id_map
-                        */
                        map = iterator->elem;
                        if (map->idtype != type)
                                continue;
@@ -3603,8 +2612,13 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
                                        use_shadow ? " " : "", map->nsid,
                                        map->hostid, map->range,
                                        use_shadow ? "" : "\n");
-                       if (fill <= 0 || fill >= left)
-                               SYSERROR("Too many {g,u}id mappings defined.");
+                       if (fill <= 0 || fill >= left) {
+                               /* The kernel only takes <= 4k for writes to
+                                * /proc/<pid>/{g,u}id_map
+                                */
+                               SYSERROR("Too many %cid mappings defined", u_or_g);
+                               return -1;
+                       }
 
                        pos += fill;
                }
@@ -3619,14 +2633,18 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
                                          lxc_map_ids_exec_wrapper,
                                          (void *)mapbuf);
                        if (ret < 0) {
-                               ERROR("new%cidmap failed to write mapping: %s",
-                                     u_or_g, cmd_output);
+                               ERROR("new%cidmap failed to write mapping \"%s\": %s",
+                                     u_or_g, cmd_output, mapbuf);
                                return -1;
                        }
+                       TRACE("new%cidmap wrote mapping \"%s\"", u_or_g, mapbuf);
                } else {
                        ret = write_id_mapping(type, pid, mapbuf, pos - mapbuf);
-                       if (ret < 0)
+                       if (ret < 0) {
+                               ERROR("Failed to write mapping: %s", mapbuf);
                                return -1;
+                       }
+                       TRACE("Wrote mapping \"%s\"", mapbuf);
                }
 
                memset(mapbuf, 0, sizeof(mapbuf));
@@ -3646,168 +2664,49 @@ bool get_mapped_rootid(struct lxc_conf *conf, enum idtype idtype,
        struct lxc_list *it;
        struct id_map *map;
 
-       lxc_list_for_each(it, &conf->id_map) {
-               map = it->elem;
-               if (map->idtype != idtype)
-                       continue;
-               if (map->nsid != 0)
-                       continue;
-               *val = map->hostid;
-               return true;
-       }
-       return false;
-}
-
-int mapped_hostid(unsigned id, struct lxc_conf *conf, enum idtype idtype)
-{
-       struct lxc_list *it;
-       struct id_map *map;
-       lxc_list_for_each(it, &conf->id_map) {
-               map = it->elem;
-               if (map->idtype != idtype)
-                       continue;
-               if (id >= map->hostid && id < map->hostid + map->range)
-                       return (id - map->hostid) + map->nsid;
-       }
-       return -1;
-}
-
-int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype)
-{
-       struct lxc_list *it;
-       struct id_map *map;
-       unsigned int freeid = 0;
-again:
-       lxc_list_for_each(it, &conf->id_map) {
-               map = it->elem;
-               if (map->idtype != idtype)
-                       continue;
-               if (freeid >= map->nsid && freeid < map->nsid + map->range) {
-                       freeid = map->nsid + map->range;
-                       goto again;
-               }
-       }
-       return freeid;
-}
-
-int lxc_find_gateway_addresses(struct lxc_handler *handler)
-{
-       struct lxc_list *network = &handler->conf->network;
-       struct lxc_list *iterator;
-       struct lxc_netdev *netdev;
-       int link_index;
-
-       lxc_list_for_each(iterator, network) {
-               netdev = iterator->elem;
-
-               if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto)
-                       continue;
-
-               if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN) {
-                       ERROR("gateway = auto only supported for "
-                             "veth and macvlan");
-                       return -1;
-               }
-
-               if (!netdev->link) {
-                       ERROR("gateway = auto needs a link interface");
-                       return -1;
-               }
-
-               link_index = if_nametoindex(netdev->link);
-               if (!link_index)
-                       return -EINVAL;
-
-               if (netdev->ipv4_gateway_auto) {
-                       if (lxc_ipv4_addr_get(link_index, &netdev->ipv4_gateway)) {
-                               ERROR("failed to automatically find ipv4 gateway "
-                                     "address from link interface '%s'", netdev->link);
-                               return -1;
-                       }
-               }
-
-               if (netdev->ipv6_gateway_auto) {
-                       if (lxc_ipv6_addr_get(link_index, &netdev->ipv6_gateway)) {
-                               ERROR("failed to automatically find ipv6 gateway "
-                                     "address from link interface '%s'", netdev->link);
-                               return -1;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-int lxc_create_tty(const char *name, struct lxc_conf *conf)
-{
-       struct lxc_tty_info *tty_info = &conf->tty_info;
-       int i, ret;
-
-       /* no tty in the configuration */
-       if (!conf->tty)
-               return 0;
-
-       tty_info->pty_info = malloc(sizeof(*tty_info->pty_info) * conf->tty);
-       if (!tty_info->pty_info) {
-               SYSERROR("failed to allocate struct *pty_info");
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < conf->tty; i++) {
-               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
-
-               process_lock();
-               ret = openpty(&pty_info->master, &pty_info->slave,
-                             pty_info->name, NULL, NULL);
-               process_unlock();
-               if (ret) {
-                       SYSERROR("failed to create pty device number %d", i);
-                       tty_info->nbtty = i;
-                       lxc_delete_tty(tty_info);
-                       return -ENOTTY;
-               }
-
-               DEBUG("allocated pty \"%s\" with master fd %d and slave fd %d",
-                     pty_info->name, pty_info->master, pty_info->slave);
-
-               /* Prevent leaking the file descriptors to the container */
-               ret = fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
-               if (ret < 0)
-                       WARN("failed to set FD_CLOEXEC flag on master fd %d of "
-                            "pty device \"%s\": %s",
-                            pty_info->master, pty_info->name, strerror(errno));
-
-               ret = fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
-               if (ret < 0)
-                       WARN("failed to set FD_CLOEXEC flag on slave fd %d of "
-                            "pty device \"%s\": %s",
-                            pty_info->slave, pty_info->name, strerror(errno));
-
-               pty_info->busy = 0;
+       lxc_list_for_each(it, &conf->id_map) {
+               map = it->elem;
+               if (map->idtype != idtype)
+                       continue;
+               if (map->nsid != 0)
+                       continue;
+               *val = map->hostid;
+               return true;
        }
-
-       tty_info->nbtty = conf->tty;
-
-       INFO("finished allocating %d pts devices", conf->tty);
-       return 0;
+       return false;
 }
 
-void lxc_delete_tty(struct lxc_tty_info *tty_info)
+int mapped_hostid(unsigned id, struct lxc_conf *conf, enum idtype idtype)
 {
-       int i;
-
-       for (i = 0; i < tty_info->nbtty; i++) {
-               struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
-
-               close(pty_info->master);
-               close(pty_info->slave);
+       struct lxc_list *it;
+       struct id_map *map;
+       lxc_list_for_each(it, &conf->id_map) {
+               map = it->elem;
+               if (map->idtype != idtype)
+                       continue;
+               if (id >= map->hostid && id < map->hostid + map->range)
+                       return (id - map->hostid) + map->nsid;
        }
-
-       free(tty_info->pty_info);
-       tty_info->pty_info = NULL;
-       tty_info->nbtty = 0;
+       return -1;
 }
 
+int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype)
+{
+       struct lxc_list *it;
+       struct id_map *map;
+       unsigned int freeid = 0;
+again:
+       lxc_list_for_each(it, &conf->id_map) {
+               map = it->elem;
+               if (map->idtype != idtype)
+                       continue;
+               if (freeid >= map->nsid && freeid < map->nsid + map->range) {
+                       freeid = map->nsid + map->range;
+                       goto again;
+               }
+       }
+       return freeid;
+}
 
 int chown_mapped_root_exec_wrapper(void *args)
 {
@@ -4137,50 +3036,9 @@ static bool verify_start_hooks(struct lxc_conf *conf)
        return true;
 }
 
-static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
-{
-       int i;
-       int *ttyfds;
-       struct lxc_pty_info *pty_info;
-       struct lxc_conf *conf = handler->conf;
-       const struct lxc_tty_info *tty_info = &conf->tty_info;
-       int sock = handler->ttysock[0];
-       int ret = -1;
-       size_t num_ttyfds = (2 * conf->tty);
-
-       ttyfds = malloc(num_ttyfds * sizeof(int));
-       if (!ttyfds)
-               return -1;
-
-       for (i = 0; i < num_ttyfds; i++) {
-               pty_info = &tty_info->pty_info[i / 2];
-               ttyfds[i++] = pty_info->slave;
-               ttyfds[i] = pty_info->master;
-               TRACE("send pty \"%s\" with master fd %d and slave fd %d to "
-                     "parent",
-                     pty_info->name, pty_info->master, pty_info->slave);
-       }
-
-       ret = lxc_abstract_unix_send_fds(sock, ttyfds, num_ttyfds, NULL, 0);
-       if (ret < 0)
-               ERROR("failed to send %d ttys to parent: %s", conf->tty,
-                     strerror(errno));
-       else
-               TRACE("sent %d ttys to parent", conf->tty);
-
-       close(handler->ttysock[0]);
-       close(handler->ttysock[1]);
-
-       for (i = 0; i < num_ttyfds; i++)
-               close(ttyfds[i]);
-
-       free(ttyfds);
-
-       return ret;
-}
-
 int lxc_setup(struct lxc_handler *handler)
 {
+       int ret;
        const char *name = handler->name;
        struct lxc_conf *lxc_conf = handler->conf;
        const char *lxcpath = handler->lxcpath;
@@ -4190,19 +3048,23 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
        }
 
-       if (lxc_conf->inherit_ns_fd[LXC_NS_UTS] == -1) {
+       if (handler->nsfd[LXC_NS_UTS] == -1) {
                if (setup_utsname(lxc_conf->utsname)) {
                        ERROR("failed to setup the utsname for '%s'", name);
                        return -1;
                }
        }
 
-       if (lxc_setup_networks_in_child_namespaces(lxc_conf,
-                                                  &lxc_conf->network)) {
+       if (lxc_setup_network_in_child_namespaces(lxc_conf, &lxc_conf->network)) {
                ERROR("failed to setup the network for '%s'", name);
                return -1;
        }
 
+       if (lxc_network_send_name_and_ifindex_to_parent(handler) < 0) {
+               ERROR("Failed to network device names and ifindices to parent");
+               return -1;
+       }
+
        if (lxc_conf->autodev > 0) {
                if (mount_autodev(name, &lxc_conf->rootfs, lxcpath)) {
                        ERROR("failed to mount /dev in the container");
@@ -4261,13 +3123,16 @@ int lxc_setup(struct lxc_handler *handler)
                }
        }
 
-       if (!lxc_conf->is_execute && lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
-               ERROR("failed to setup the console for '%s'", name);
+       ret = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console,
+                               lxc_conf->ttydir);
+       if (ret < 0) {
+               ERROR("Failed to setup console");
                return -1;
        }
 
-       if (!lxc_conf->is_execute && setup_dev_symlinks(&lxc_conf->rootfs)) {
-               ERROR("failed to setup /dev symlinks for '%s'", name);
+       ret = lxc_setup_dev_symlinks(&lxc_conf->rootfs);
+       if (ret < 0) {
+               ERROR("Failed to setup /dev symlinks");
                return -1;
        }
 
@@ -4287,24 +3152,9 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
        }
 
-       if (lxc_create_tty(name, lxc_conf)) {
-               ERROR("failed to create the ttys");
-               return -1;
-       }
-
-       if (lxc_send_ttys_to_parent(handler) < 0) {
-               ERROR("failure sending console info to parent");
-               return -1;
-       }
-
-       if (!lxc_conf->is_execute && lxc_setup_tty(lxc_conf)) {
-               ERROR("failed to setup the ttys for '%s'", name);
+       ret = lxc_create_ttys(handler);
+       if (ret < 0)
                return -1;
-       }
-
-       if (lxc_conf->pty_names && setenv("container_ttys", lxc_conf->pty_names, 1))
-               SYSERROR("failed to set environment variable for container ptys");
-
 
        if (setup_personality(lxc_conf->personality)) {
                ERROR("failed to setup personality");
@@ -4338,6 +3188,8 @@ int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
 
        if (strcmp(hook, "pre-start") == 0)
                which = LXCHOOK_PRESTART;
+       else if (strcmp(hook, "start-host") == 0)
+               which = LXCHOOK_START_HOST;
        else if (strcmp(hook, "pre-mount") == 0)
                which = LXCHOOK_PREMOUNT;
        else if (strcmp(hook, "mount") == 0)
@@ -4484,7 +3336,6 @@ int lxc_clear_environment(struct lxc_conf *c)
        return 0;
 }
 
-
 int lxc_clear_mount_entries(struct lxc_conf *c)
 {
        struct lxc_list *it,*next;
@@ -4535,17 +3386,6 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key)
        return 0;
 }
 
-static void lxc_clear_saved_nics(struct lxc_conf *conf)
-{
-       int i;
-
-       if (!conf->saved_nics)
-               return;
-       for (i=0; i < conf->num_savednics; i++)
-               free(conf->saved_nics[i].orig_name);
-       free(conf->saved_nics);
-}
-
 static inline void lxc_clear_aliens(struct lxc_conf *conf)
 {
        struct lxc_list *it,*next;
@@ -4574,8 +3414,11 @@ void lxc_conf_free(struct lxc_conf *conf)
                return;
        if (current_config == conf)
                current_config = NULL;
+       free(conf->console.buffer_log_file);
        free(conf->console.log_path);
        free(conf->console.path);
+       if (conf->console.buffer_size > 0 && conf->console.ringbuf.addr)
+               lxc_ringbuf_release(&conf->console.ringbuf);
        free(conf->rootfs.mount);
        free(conf->rootfs.bdev_type);
        free(conf->rootfs.options);
@@ -4587,7 +3430,9 @@ void lxc_conf_free(struct lxc_conf *conf)
        free(conf->ttydir);
        free(conf->fstab);
        free(conf->rcfile);
+       free(conf->execute_cmd);
        free(conf->init_cmd);
+       free(conf->init_cwd);
        free(conf->unexpanded_config);
        free(conf->pty_names);
        free(conf->syslog);
@@ -4600,7 +3445,6 @@ void lxc_conf_free(struct lxc_conf *conf)
        lxc_clear_cgroups(conf, "lxc.cgroup");
        lxc_clear_hooks(conf, "lxc.hook");
        lxc_clear_mount_entries(conf);
-       lxc_clear_saved_nics(conf);
        lxc_clear_idmaps(conf);
        lxc_clear_groups(conf);
        lxc_clear_includes(conf);
@@ -4725,7 +3569,7 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
        struct lxc_list *it;
        struct id_map *map;
        char c = '1';
-       int ret = -1;
+       int ret = -1, status = -1;
        struct lxc_list *idmap = NULL, *tmplist = NULL;
        struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
                      *host_uid_map = NULL, *host_gid_map = NULL;
@@ -4751,6 +3595,9 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
        close(p[0]);
        p[0] = -1;
 
+       euid = geteuid();
+       egid = getegid();
+
        /* Find container root. */
        lxc_list_for_each(it, &conf->id_map) {
                map = it->elem;
@@ -4766,6 +3613,12 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
                        container_root_uid->hostid = map->hostid;
                        container_root_uid->nsid = 0;
                        container_root_uid->range = map->range;
+
+                       /* Check if container root mapping contains a mapping
+                        * for user's uid.
+                        */
+                       if (euid >= map->hostid && euid < map->hostid + map->range)
+                               host_uid_map = container_root_uid;
                } else if (map->idtype == ID_TYPE_GID && container_root_gid == NULL) {
                        container_root_gid = malloc(sizeof(*container_root_gid));
                        if (!container_root_gid)
@@ -4774,6 +3627,12 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
                        container_root_gid->hostid = map->hostid;
                        container_root_gid->nsid = 0;
                        container_root_gid->range = map->range;
+
+                       /* Check if container root mapping contains a mapping
+                        * for user's gid.
+                        */
+                       if (egid >= map->hostid && egid < map->hostid + map->range)
+                               host_gid_map = container_root_gid;
                }
 
                /* Found container root. */
@@ -4787,16 +3646,11 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
                goto on_error;
        }
 
-       host_uid_map = container_root_uid;
-       host_gid_map = container_root_gid;
-
        /* Check whether the {g,u}id of the user has a mapping. */
-       euid = geteuid();
-       egid = getegid();
-       if (euid != container_root_uid->hostid)
+       if (!host_uid_map)
                host_uid_map = idmap_add(conf, euid, ID_TYPE_UID);
 
-       if (egid != container_root_gid->hostid)
+       if (!host_gid_map)
                host_gid_map = idmap_add(conf, egid, ID_TYPE_GID);
 
        if (!host_uid_map) {
@@ -4875,8 +3729,7 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
        ret = lxc_map_ids(idmap, pid);
        if (ret < 0) {
                ERROR("error setting up {g,u}id mappings for child process "
-                     "\"%d\"",
-                     pid);
+                     "\"%d\"", pid);
                goto on_error;
        }
 
@@ -4886,10 +3739,11 @@ int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
                goto on_error;
        }
 
+on_error:
        /* Wait for child to finish. */
-       ret = wait_for_pid(pid);
+       if (pid > 0)
+               status = wait_for_pid(pid);
 
-on_error:
        if (idmap)
                lxc_free_idmap(idmap);
        if (container_root_uid)
@@ -4905,6 +3759,188 @@ on_error:
                close(p[0]);
        close(p[1]);
 
+       if (status < 0)
+               ret = -1;
+
+       return ret;
+}
+
+int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
+                    const char *fn_name)
+{
+       pid_t pid;
+       uid_t euid, egid;
+       struct userns_fn_data d;
+       int p[2];
+       struct id_map *map;
+       struct lxc_list *cur;
+       char c = '1';
+       int ret = -1;
+       struct lxc_list *idmap = NULL, *tmplist = NULL;
+       struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
+                     *host_uid_map = NULL, *host_gid_map = NULL;
+
+       ret = pipe(p);
+       if (ret < 0) {
+               SYSERROR("opening pipe");
+               return -1;
+       }
+       d.fn = fn;
+       d.fn_name = fn_name;
+       d.arg = data;
+       d.p[0] = p[0];
+       d.p[1] = p[1];
+
+       /* Clone child in new user namespace. */
+       pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER);
+       if (pid < 0) {
+               ERROR("failed to clone child process in new user namespace");
+               goto on_error;
+       }
+
+       close(p[0]);
+       p[0] = -1;
+
+       euid = geteuid();
+       egid = getegid();
+
+       /* Allocate new {g,u}id map list. */
+       idmap = malloc(sizeof(*idmap));
+       if (!idmap)
+               goto on_error;
+       lxc_list_init(idmap);
+
+       /* Find container root. */
+       lxc_list_for_each(cur, &conf->id_map) {
+               struct id_map *tmpmap;
+
+               tmplist = malloc(sizeof(*tmplist));
+               if (!tmplist)
+                       goto on_error;
+
+               tmpmap = malloc(sizeof(*tmpmap));
+               if (!tmpmap) {
+                       free(tmplist);
+                       goto on_error;
+               }
+
+               memset(tmpmap, 0, sizeof(*tmpmap));
+               memcpy(tmpmap, cur->elem, sizeof(*tmpmap));
+               tmplist->elem = tmpmap;
+
+               lxc_list_add_tail(idmap, tmplist);
+
+               map = cur->elem;
+
+               if (map->idtype == ID_TYPE_UID)
+                       if (euid >= map->hostid && euid < map->hostid + map->range)
+                               host_uid_map = map;
+
+               if (map->idtype == ID_TYPE_GID)
+                       if (egid >= map->hostid && egid < map->hostid + map->range)
+                               host_gid_map = map;
+
+               if (map->nsid != 0)
+                       continue;
+
+               if (map->idtype == ID_TYPE_UID)
+                       if (container_root_uid == NULL)
+                               container_root_uid = map;
+
+               if (map->idtype == ID_TYPE_GID)
+                       if (container_root_gid == NULL)
+                               container_root_gid = map;
+       }
+
+       if (!container_root_uid || !container_root_gid) {
+               ERROR("No mapping for container root found");
+               goto on_error;
+       }
+
+       /* Check whether the {g,u}id of the user has a mapping. */
+       if (!host_uid_map)
+               host_uid_map = idmap_add(conf, euid, ID_TYPE_UID);
+       else
+               host_uid_map = container_root_uid;
+
+       if (!host_gid_map)
+               host_gid_map = idmap_add(conf, egid, ID_TYPE_GID);
+       else
+               host_gid_map = container_root_gid;
+
+       if (!host_uid_map) {
+               DEBUG("Failed to find mapping for uid %d", euid);
+               goto on_error;
+       }
+
+       if (!host_gid_map) {
+               DEBUG("Failed to find mapping for gid %d", egid);
+               goto on_error;
+       }
+
+       if (host_uid_map && (host_uid_map != container_root_uid)) {
+               /* Add container root to the map. */
+               tmplist = malloc(sizeof(*tmplist));
+               if (!tmplist)
+                       goto on_error;
+               lxc_list_add_elem(tmplist, host_uid_map);
+               lxc_list_add_tail(idmap, tmplist);
+       }
+       /* idmap will now keep track of that memory. */
+       host_uid_map = NULL;
+
+       if (host_gid_map && (host_gid_map != container_root_gid)) {
+               tmplist = malloc(sizeof(*tmplist));
+               if (!tmplist)
+                       goto on_error;
+               lxc_list_add_elem(tmplist, host_gid_map);
+               lxc_list_add_tail(idmap, tmplist);
+       }
+       /* idmap will now keep track of that memory. */
+       host_gid_map = NULL;
+
+       if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE ||
+           conf->loglevel == LXC_LOG_LEVEL_TRACE) {
+               lxc_list_for_each(cur, idmap) {
+                       map = cur->elem;
+                       TRACE("establishing %cid mapping for \"%d\" in new "
+                             "user namespace: nsuid %lu - hostid %lu - range "
+                             "%lu",
+                             (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid,
+                             map->nsid, map->hostid, map->range);
+               }
+       }
+
+       /* Set up {g,u}id mapping for user namespace of child process. */
+       ret = lxc_map_ids(idmap, pid);
+       if (ret < 0) {
+               ERROR("error setting up {g,u}id mappings for child process "
+                     "\"%d\"", pid);
+               goto on_error;
+       }
+
+       /* Tell child to proceed. */
+       if (write(p[1], &c, 1) != 1) {
+               SYSERROR("failed telling child process \"%d\" to proceed", pid);
+               goto on_error;
+       }
+
+on_error:
+       /* Wait for child to finish. */
+       if (pid > 0)
+               ret = wait_for_pid(pid);
+
+       if (idmap)
+               lxc_free_idmap(idmap);
+       if (host_uid_map && (host_uid_map != container_root_uid))
+               free(host_uid_map);
+       if (host_gid_map && (host_gid_map != container_root_gid))
+               free(host_gid_map);
+
+       if (p[0] != -1)
+               close(p[0]);
+       close(p[1]);
+
        return ret;
 }
 
@@ -5031,8 +4067,8 @@ void suggest_default_idmap(void)
        ERROR("To pass uid mappings to lxc-create, you could create");
        ERROR("~/.config/lxc/default.conf:");
        ERROR("lxc.include = %s", LXC_DEFAULT_CONFIG);
-       ERROR("lxc.id_map = u 0 %u %u", uid, urange);
-       ERROR("lxc.id_map = g 0 %u %u", gid, grange);
+       ERROR("lxc.idmap = u 0 %u %u", uid, urange);
+       ERROR("lxc.idmap = g 0 %u %u", gid, grange);
 
        free(gname);
        free(uname);