]> 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 a7ae90a1daed7218e9e1751186027e495020c231..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,62 +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"};
+                                     "post-stop", "clone",     "destroy",
+                                     "start-host"};
 
 struct mount_opt {
        char *name;
@@ -265,9 +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 struct mount_opt mount_opt[] = {
        { "async",         1, MS_SYNCHRONOUS },
        { "atime",         1, MS_NOATIME     },
@@ -782,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;
@@ -817,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;
@@ -840,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;
@@ -854,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)
@@ -878,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;
                        }
@@ -893,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;
                        }
@@ -912,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);
@@ -921,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);
                }
 
@@ -935,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;
@@ -2321,10 +2351,15 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
                        return -1;
                }
 
+#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;
 }
@@ -2346,6 +2381,9 @@ struct lxc_conf *lxc_conf_init(void)
        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;
@@ -2356,6 +2394,7 @@ struct lxc_conf *lxc_conf_init(void)
        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);
@@ -2375,21 +2414,19 @@ struct lxc_conf *lxc_conf_init(void)
        lxc_list_init(&new->aliens);
        lxc_list_init(&new->environment);
        lxc_list_init(&new->limits);
-       for (i=0; i<NUM_LXC_HOOKS; i++)
+       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));
+       memset(&new->inherit_ns, 0, sizeof(char *) * LXC_NS_MAX);
 
        return new;
 }
@@ -2564,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;
@@ -2578,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;
                }
@@ -2594,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));
@@ -2665,77 +2708,6 @@ again:
        return freeid;
 }
 
-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;
-       }
-
-       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;
-}
-
-
 int chown_mapped_root_exec_wrapper(void *args)
 {
        execvp("lxc-usernsexec", args);
@@ -3064,45 +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;
-       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);
-
-       lxc_delete_tty(tty_info);
-
-       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;
@@ -3112,7 +3048,7 @@ 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;
@@ -3187,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;
        }
 
@@ -3213,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");
@@ -3264,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)
@@ -3488,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);
@@ -3501,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);
@@ -3638,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;
@@ -3664,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;
@@ -3679,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)
@@ -3687,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. */
@@ -3700,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) {
@@ -3788,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;
        }
 
@@ -3799,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)
@@ -3818,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;
 }
 
@@ -3944,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);