Ohai,

On Sat, May 13, 2017 at 09:44:42AM +0100, Evgeni Golov wrote:
> I wonder if you would be OK with accepting the latest LXC stable release
> into Stretch at this point in time.
> Admittedly, the diff between the version in testing and 2.0.8 is quite
> big (64 files changed, 1652 insertions(+), 996 deletions(-)), but it
> allows us to drop both cherry-picked patches we carry today and gives an
> IMHO better base for later updates during the Stretch life cycle.

Niels asked on IRC if the diff can be filtered a bit.

It can, but it still does not look magically awesome then:
 54 files changed, 1548 insertions(+), 955 deletions(-)

Generated with:
 git diff debian/1%2.0.7-2.. |filterdiff -x a/debian/patches/\* -x a/configure 
-x a/src/tests/\* -x a/README -x a/doc/\* -x \*/Makefile.in

Bear in mind that the above still contains the upstream versions of
the two dropped patches:
 lxc-2.0-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch
  src/lxc/lxc_user_nic.c | 119 ++++++++++++++++++++++++++++++++++++-------------
 0010-lxc-debian-root-password.patch
  templates/lxc-debian.in | 3 ---
And I have no way to filter that out.

New debdiff attached.

Also, as it was asked, lxc and lxcfs are not coupled, we can update them 
independently.
diff --git a/config/init/common/lxc-containers.in 
b/config/init/common/lxc-containers.in
index ebce36e..35b9084 100644
--- a/config/init/common/lxc-containers.in
+++ b/config/init/common/lxc-containers.in
@@ -51,7 +51,9 @@ fi
 # to start
 wait_for_bridge()
 {
-    local BRNAME try flags
+    [ "x$USE_LXC_BRIDGE" = "xtrue" ] || { return 0; }
+
+    local BRNAME try flags br
     [ -f "$sysconfdir"/lxc/default.conf ] || { return 0; }
 
     BRNAME=`grep '^[   ]*lxc.network.link' "$sysconfdir"/lxc/default.conf | 
sed 's/^.*=[       ]*//'`
@@ -60,11 +62,12 @@ wait_for_bridge()
     fi
 
     for try in `seq 1 30`; do
-        if [ -r /sys/class/net/$BRNAME/flags ]; then
-            read flags < /sys/class/net/$BRNAME/flags
-            [ $((flags & 0x1)) -eq 1 ] && { return 0; }
-        fi
-        sleep 1
+        for br in ${BRNAME}; do
+             [ -r /sys/class/net/${br}/flags ] || { sleep 1; continue 2; }
+             read flags < /sys/class/net/${br}/flags
+             [ $((flags & 0x1)) -eq 1 ] || { sleep 1; continue 2; }
+        done
+        return 0
     done
 }
 
diff --git a/config/init/common/lxc-net.in b/config/init/common/lxc-net.in
index 4797f20..f770950 100644
--- a/config/init/common/lxc-net.in
+++ b/config/init/common/lxc-net.in
@@ -66,6 +66,7 @@ start() {
         if [ "$FAILED" = "1" ]; then
             echo "Failed to setup lxc-net." >&2
             stop force
+            exit 1
         fi
     }
 
diff --git a/config/templates/userns.conf.in b/config/templates/userns.conf.in
index 5dc19c7..78383eb 100644
--- a/config/templates/userns.conf.in
+++ b/config/templates/userns.conf.in
@@ -6,7 +6,6 @@ lxc.cgroup.devices.allow =
 lxc.devttydir =
 
 # Extra bind-mounts for userns
-lxc.mount.entry = /dev/console dev/console none bind,create=file 0 0
 lxc.mount.entry = /dev/full dev/full none bind,create=file 0 0
 lxc.mount.entry = /dev/null dev/null none bind,create=file 0 0
 lxc.mount.entry = /dev/random dev/random none bind,create=file 0 0
diff --git a/configure.ac b/configure.ac
index 42ece7a..bd2d82f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
 m4_define([lxc_devel], 0)
 m4_define([lxc_version_major], 2)
 m4_define([lxc_version_minor], 0)
-m4_define([lxc_version_micro], 7)
+m4_define([lxc_version_micro], 8)
 m4_define([lxc_version_beta], [])
 
 m4_define([lxc_abi_major], 1)
@@ -113,13 +113,13 @@ case "$with_init_script" in
                        fedora|altlinux|opensuse*)
                                init_script=systemd
                                ;;
-                       redhat|centos|oracle|oracleserver|sparclinux|plamo)
+                       redhat|oracle|oracleserver|sparclinux|plamo)
                                init_script=sysvinit
                                ;;
-                       debian|raspbian)
-                               init_script=upstart,systemd
+                       centos)
+                               init_script=sysvinit,systemd
                                ;;
-                       ubuntu)
+                       debian|raspbian|ubuntu)
                                init_script=upstart,systemd
                                ;;
                        *)
@@ -366,8 +366,11 @@ fi
 AM_CONDITIONAL([ENABLE_CAP], [test "x$enable_capabilities" = "xyes"])
 
 AM_COND_IF([ENABLE_CAP],
-       [AC_CHECK_LIB(cap,cap_set_proc,[true],[AC_MSG_ERROR([You are missing 
libcap support.])])
-       AC_SUBST([CAP_LIBS], [-lcap])])
+       [AC_CHECK_HEADER([sys/capability.h],[],[AC_MSG_ERROR([You must install 
the libcap development package in order to compile lxc])])
+       AC_CHECK_LIB(cap,cap_set_proc,[],[AC_MSG_ERROR([You must install the 
libcap development package in order to compile lxc])])
+        # Test whether we support getting file capabilities via cap_get_file().
+        AC_CHECK_LIB(cap,cap_get_file, 
AC_DEFINE(LIBCAP_SUPPORTS_FILE_CAPABILITIES,1,[Have cap_get_file]),[],[])
+        AC_SUBST([CAP_LIBS], [-lcap])])
 
 # HAVE_SCMP_FILTER_CTX=1 will tell us we have libseccomp api >= 1.0.0
 OLD_CFLAGS="$CFLAGS"
@@ -630,7 +633,7 @@ AM_CONDITIONAL([IS_BIONIC], [test "x$is_bionic" = "xyes"])
 AC_CHECK_DECLS([PR_CAPBSET_DROP], [], [], [#include <sys/prctl.h>])
 
 # Check for some headers
-AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/capability.h sys/memfd.h 
sys/personality.h utmpx.h sys/timerfd.h])
+AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/memfd.h sys/personality.h 
utmpx.h sys/timerfd.h])
 
 # lookup major()/minor()/makedev()
 AC_HEADER_MAJOR
diff --git a/hooks/clonehostname b/hooks/clonehostname
index ed2765c..8eec7a6 100755
--- a/hooks/clonehostname
+++ b/hooks/clonehostname
@@ -19,9 +19,9 @@
 
 # Note that /etc/hostname is updated by lxc itself
 for file in \
-    $LXC_ROOTFS_PATH/etc/sysconfig/network \
-    $LXC_ROOTFS_PATH/etc/sysconfig/network-scripts/ifcfg-* \
-    $LXC_ROOTFS_PATH/etc/hosts ;
+    $LXC_ROOTFS_MOUNT/etc/sysconfig/network \
+    $LXC_ROOTFS_MOUNT/etc/sysconfig/network-scripts/ifcfg-* \
+    $LXC_ROOTFS_MOUNT/etc/hosts ;
 do
     if [ -f $file ]; then
         sed -i "s|$LXC_SRC_NAME|$LXC_NAME|" $file
diff --git a/lxc.spec b/lxc.spec
index 4d4ef07..993c46c 100644
--- a/lxc.spec
+++ b/lxc.spec
@@ -60,7 +60,7 @@ BuildRequires: systemd
 %endif
 
 Name: lxc
-Version: 2.0.7
+Version: 2.0.8
 Release: %{?beta_rel:0.1.%{beta_rel}}%{?!beta_rel:%{norm_rel}}%{?dist}
 URL: http://linuxcontainers.org
 Source: 
http://linuxcontainers.org/downloads/%{name}-%{version}%{?beta_dot}.tar.gz
diff --git a/src/config.h.in b/src/config.h.in
index a83788a..1228131 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -56,6 +56,9 @@
 /* Define to 1 if you have the `apparmor' library (-lapparmor). */
 #undef HAVE_LIBAPPARMOR
 
+/* Define to 1 if you have the `cap' library (-lcap). */
+#undef HAVE_LIBCAP
+
 /* Define to 1 if you have the `gnutls' library (-lgnutls). */
 #undef HAVE_LIBGNUTLS
 
@@ -128,9 +131,6 @@
 /* Define to 1 if you have the <string.h> header file. */
 #undef HAVE_STRING_H
 
-/* Define to 1 if you have the <sys/capability.h> header file. */
-#undef HAVE_SYS_CAPABILITY_H
-
 /* Define to 1 if you have the <sys/memfd.h> header file. */
 #undef HAVE_SYS_MEMFD_H
 
@@ -167,6 +167,9 @@
 /* bionic libc */
 #undef IS_BIONIC
 
+/* Have cap_get_file */
+#undef LIBCAP_SUPPORTS_FILE_CAPABILITIES
+
 /* Define to the sub-directory where libtool stores uninstalled libraries. */
 #undef LT_OBJDIR
 
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 6bcb6da..d7c05d6 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -290,7 +290,7 @@ init_lxc_static_SOURCES += ../include/getline.c
 endif
 endif
 
-init_lxc_static_LDFLAGS = -static
+init_lxc_static_LDFLAGS = -all-static
 init_lxc_static_LDADD = @CAP_LIBS@
 init_lxc_static_CFLAGS = $(AM_CFLAGS) -DNO_LXC_CONF
 endif
diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c
index 46d8e50..ac83994 100644
--- a/src/lxc/af_unix.c
+++ b/src/lxc/af_unix.c
@@ -55,8 +55,9 @@ int lxc_abstract_unix_open(const char *path, int type, int 
flags)
 
        addr.sun_family = AF_UNIX;
 
-       len = strlen(&path[1]) + 1;
-       if (len >= sizeof(addr.sun_path) - 1) {
+       len = strlen(&path[1]);
+       /* do not enforce \0-termination */
+       if (len >= sizeof(addr.sun_path)) {
                close(fd);
                errno = ENAMETOOLONG;
                return -1;
@@ -64,7 +65,7 @@ int lxc_abstract_unix_open(const char *path, int type, int 
flags)
        /* addr.sun_path[0] has already been set to 0 by memset() */
        strncpy(&addr.sun_path[1], &path[1], strlen(&path[1]));
 
-       if (bind(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, 
sun_path) + len)) {
+       if (bind(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, 
sun_path) + len + 1)) {
                int tmp = errno;
                close(fd);
                errno = tmp;
@@ -109,8 +110,9 @@ int lxc_abstract_unix_connect(const char *path)
 
        addr.sun_family = AF_UNIX;
 
-       len = strlen(&path[1]) + 1;
-       if (len >= sizeof(addr.sun_path) - 1) {
+       len = strlen(&path[1]);
+       /* do not enforce \0-termination */
+       if (len >= sizeof(addr.sun_path)) {
                close(fd);
                errno = ENAMETOOLONG;
                return -1;
@@ -118,7 +120,7 @@ int lxc_abstract_unix_connect(const char *path)
        /* addr.sun_path[0] has already been set to 0 by memset() */
        strncpy(&addr.sun_path[1], &path[1], strlen(&path[1]));
 
-       if (connect(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, 
sun_path) + len)) {
+       if (connect(fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, 
sun_path) + len + 1)) {
                int tmp = errno;
                /* special case to connect to older containers */
                if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0)
@@ -136,8 +138,8 @@ int lxc_abstract_unix_send_fd(int fd, int sendfd, void 
*data, size_t size)
        struct msghdr msg = { 0 };
        struct iovec iov;
        struct cmsghdr *cmsg;
-       char cmsgbuf[CMSG_SPACE(sizeof(int))];
-       char buf[1];
+       char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0};
+       char buf[1] = {0};
        int *val;
 
        msg.msg_control = cmsgbuf;
@@ -166,9 +168,9 @@ int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void 
*data, size_t size)
        struct msghdr msg = { 0 };
        struct iovec iov;
        struct cmsghdr *cmsg;
-       char cmsgbuf[CMSG_SPACE(sizeof(int))];
-       char buf[1];
        int ret, *val;
+       char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0};
+       char buf[1] = {0};
 
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
@@ -210,8 +212,8 @@ int lxc_abstract_unix_send_credential(int fd, void *data, 
size_t size)
                .uid = getuid(),
                .gid = getgid(),
        };
-       char cmsgbuf[CMSG_SPACE(sizeof(cred))];
-       char buf[1];
+       char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0};
+       char buf[1] = {0};
 
        msg.msg_control = cmsgbuf;
        msg.msg_controllen = sizeof(cmsgbuf);
@@ -239,9 +241,9 @@ int lxc_abstract_unix_rcv_credential(int fd, void *data, 
size_t size)
        struct iovec iov;
        struct cmsghdr *cmsg;
        struct ucred cred;
-       char cmsgbuf[CMSG_SPACE(sizeof(cred))];
-       char buf[1];
        int ret;
+       char cmsgbuf[CMSG_SPACE(sizeof(cred))] = {0};
+       char buf[1] = {0};
 
        msg.msg_name = NULL;
        msg.msg_namelen = 0;
diff --git a/src/lxc/af_unix.h b/src/lxc/af_unix.h
index 3f5d01f..d25a211 100644
--- a/src/lxc/af_unix.h
+++ b/src/lxc/af_unix.h
@@ -24,8 +24,10 @@
 #ifndef __LXC_AF_UNIX_H
 #define __LXC_AF_UNIX_H
 
+/* does not enforce \0-termination */
 extern int lxc_abstract_unix_open(const char *path, int type, int flags);
 extern int lxc_abstract_unix_close(int fd);
+/* does not enforce \0-termination */
 extern int lxc_abstract_unix_connect(const char *path);
 extern int lxc_abstract_unix_send_fd(int fd, int sendfd, void *data, size_t 
size);
 extern int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t 
size);
diff --git a/src/lxc/bdev/lxcloop.c b/src/lxc/bdev/lxcloop.c
index b322002..a4633e4 100644
--- a/src/lxc/bdev/lxcloop.c
+++ b/src/lxc/bdev/lxcloop.c
@@ -35,19 +35,9 @@
 #include "lxcloop.h"
 #include "utils.h"
 
-#ifndef LO_FLAGS_AUTOCLEAR
-#define LO_FLAGS_AUTOCLEAR 4
-#endif
-
-#ifndef LOOP_CTL_GET_FREE
-#define LOOP_CTL_GET_FREE 0x4C82
-#endif
-
 lxc_log_define(lxcloop, lxc);
 
 static int do_loop_create(const char *path, uint64_t size, const char *fstype);
-static int find_free_loopdev_no_control(int *retfd, char *namep);
-static int find_free_loopdev(int *retfd, char *namep);
 
 /*
  * No idea what the original blockdev will be called, but the copy will be
@@ -174,47 +164,26 @@ int loop_detect(const char *path)
 
 int loop_mount(struct bdev *bdev)
 {
-       int lfd, ffd = -1, ret = -1;
-       struct loop_info64 lo;
-       char loname[100];
+       int ret, loopfd;
+       char loname[MAXPATHLEN];
 
        if (strcmp(bdev->type, "loop"))
                return -22;
        if (!bdev->src || !bdev->dest)
                return -22;
-       if (find_free_loopdev(&lfd, loname) < 0)
-               return -22;
-
-       ffd = open(bdev->src + 5, O_RDWR);
-       if (ffd < 0) {
-               SYSERROR("Error opening backing file %s", bdev->src);
-               goto out;
-       }
 
-       if (ioctl(lfd, LOOP_SET_FD, ffd) < 0) {
-               SYSERROR("Error attaching backing file to loop dev");
-               goto out;
-       }
-       memset(&lo, 0, sizeof(lo));
-       lo.lo_flags = LO_FLAGS_AUTOCLEAR;
-       if (ioctl(lfd, LOOP_SET_STATUS64, &lo) < 0) {
-               SYSERROR("Error setting autoclear on loop dev");
-               goto out;
-       }
+       loopfd = lxc_prepare_loop_dev(bdev->src + 5, loname, 
LO_FLAGS_AUTOCLEAR);
+       if (loopfd < 0)
+               return -1;
+       DEBUG("prepared loop device \"%s\"", loname);
 
        ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
        if (ret < 0)
-               ERROR("Error mounting %s", bdev->src);
+               ERROR("failed to mount rootfs \"%s\" onto \"%s\" via loop 
device \"%s\"", bdev->src, bdev->dest, loname);
        else
-               bdev->lofd = lfd;
+               bdev->lofd = loopfd;
+       DEBUG("mounted rootfs \"%s\" onto \"%s\" via loop device \"%s\"", 
bdev->src, bdev->dest, loname);
 
-out:
-       if (ffd > -1)
-               close(ffd);
-       if (ret < 0) {
-               close(lfd);
-               bdev->lofd = -1;
-       }
        return ret;
 }
 
@@ -266,63 +235,3 @@ static int do_loop_create(const char *path, uint64_t size, 
const char *fstype)
 
        return 0;
 }
-
-static int find_free_loopdev_no_control(int *retfd, char *namep)
-{
-       struct dirent *direntp;
-       struct loop_info64 lo;
-       DIR *dir;
-       int fd = -1;
-
-       dir = opendir("/dev");
-       if (!dir) {
-               SYSERROR("Error opening /dev");
-               return -1;
-       }
-       while ((direntp = readdir(dir))) {
-
-               if (!direntp)
-                       break;
-               if (strncmp(direntp->d_name, "loop", 4) != 0)
-                       continue;
-               fd = openat(dirfd(dir), direntp->d_name, O_RDWR);
-               if (fd < 0)
-                       continue;
-               if (ioctl(fd, LOOP_GET_STATUS64, &lo) == 0 || errno != ENXIO) {
-                       close(fd);
-                       fd = -1;
-                       continue;
-               }
-               // We can use this fd
-               snprintf(namep, 100, "/dev/%s", direntp->d_name);
-               break;
-       }
-       closedir(dir);
-       if (fd == -1) {
-               ERROR("No loop device found");
-               return -1;
-       }
-
-       *retfd = fd;
-       return 0;
-}
-
-static int find_free_loopdev(int *retfd, char *namep)
-{
-       int rc, fd = -1;
-       int ctl = open("/dev/loop-control", O_RDWR);
-       if (ctl < 0)
-               return find_free_loopdev_no_control(retfd, namep);
-       rc = ioctl(ctl, LOOP_CTL_GET_FREE);
-       if (rc >= 0) {
-               snprintf(namep, 100, "/dev/loop%d", rc);
-               fd = open(namep, O_RDWR);
-       }
-       close(ctl);
-       if (fd == -1) {
-               ERROR("No loop device found");
-               return -1;
-       }
-       *retfd = fd;
-       return 0;
-}
diff --git a/src/lxc/bdev/lxclvm.c b/src/lxc/bdev/lxclvm.c
index 75de17f..bcd8be8 100644
--- a/src/lxc/bdev/lxclvm.c
+++ b/src/lxc/bdev/lxclvm.c
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/sysmacros.h>
 #include <sys/wait.h>
 
 #include "bdev.h"
@@ -41,9 +42,6 @@
 #ifdef MAJOR_IN_MKDEV
 #    include <sys/mkdev.h>
 #endif
-#ifdef MAJOR_IN_SYSMACROS
-#    include <sys/sysmacros.h>
-#endif
 
 lxc_log_define(lxclvm, lxc);
 
diff --git a/src/lxc/caps.c b/src/lxc/caps.c
index 73b5516..195707f 100644
--- a/src/lxc/caps.c
+++ b/src/lxc/caps.c
@@ -36,7 +36,7 @@
 
 lxc_log_define(lxc_caps, lxc);
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 
 #ifndef PR_CAPBSET_READ
 #define PR_CAPBSET_READ 23
@@ -209,27 +209,61 @@ int lxc_caps_last_cap(void)
        return last_cap;
 }
 
-bool lxc_cap_is_set(cap_value_t cap, cap_flag_t flag)
+static bool lxc_cap_is_set(cap_t caps, cap_value_t cap, cap_flag_t flag)
 {
        int ret;
-       cap_t caps;
        cap_flag_value_t flagval;
 
-       caps = cap_get_proc();
+       ret = cap_get_flag(caps, cap, flag, &flagval);
+       if (ret < 0) {
+               ERROR("Failed to perform cap_get_flag(): %s.", strerror(errno));
+               return false;
+       }
+
+       return flagval == CAP_SET;
+}
+
+bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
+{
+       #if LIBCAP_SUPPORTS_FILE_CAPABILITIES
+       bool cap_is_set;
+       cap_t caps;
+
+       caps = cap_get_file(path);
        if (!caps) {
-               ERROR("Failed to perform cap_get_proc(): %s.", strerror(errno));
+               /* This is undocumented in the manpage but the source code show
+                * that cap_get_file() may return NULL when successful for the
+                * case where it didn't detect any file capabilities. In this
+                * case errno will be set to ENODATA.
+                */
+               if (errno != ENODATA)
+                       ERROR("Failed to perform cap_get_file(): %s.\n", 
strerror(errno));
                return false;
        }
 
-       ret = cap_get_flag(caps, cap, flag, &flagval);
-       if (ret < 0) {
-               ERROR("Failed to perform cap_get_flag(): %s.", strerror(errno));
-               cap_free(caps);
+       cap_is_set = lxc_cap_is_set(caps, cap, flag);
+       cap_free(caps);
+       return cap_is_set;
+       #else
+       errno = ENODATA;
+       return false;
+       #endif
+}
+
+bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
+{
+       bool cap_is_set;
+       cap_t caps;
+
+       caps = cap_get_proc();
+       if (!caps) {
+               ERROR("Failed to perform cap_get_proc(): %s.\n", 
strerror(errno));
                return false;
        }
 
+       cap_is_set = lxc_cap_is_set(caps, cap, flag);
        cap_free(caps);
-       return flagval == CAP_SET;
+       return cap_is_set;
 }
 
 #endif
diff --git a/src/lxc/caps.h b/src/lxc/caps.h
index 390dbdd..2a8c282 100644
--- a/src/lxc/caps.h
+++ b/src/lxc/caps.h
@@ -27,7 +27,7 @@
 #ifndef __LXC_CAPS_H
 #define __LXC_CAPS_H
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 #include <sys/capability.h>
 
 extern int lxc_caps_down(void);
@@ -36,7 +36,8 @@ extern int lxc_caps_init(void);
 
 extern int lxc_caps_last_cap(void);
 
-extern bool lxc_cap_is_set(cap_value_t cap, cap_flag_t flag);
+extern bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag);
+extern bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t 
flag);
 #else
 static inline int lxc_caps_down(void) {
        return 0;
@@ -54,8 +55,12 @@ static inline int lxc_caps_last_cap(void) {
 
 typedef int cap_value_t;
 typedef int cap_flag_t;
-static inline bool lxc_cap_is_set(cap_value_t cap, cap_flag_t flag) {
-       return true;
+static inline bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag) {
+       return false;
+}
+
+static inline bool lxc_file_cap_is_set(const char *path, cap_value_t cap, 
cap_flag_t flag) {
+       return false;
 }
 #endif
 
diff --git a/src/lxc/cgroups/cgfs.c b/src/lxc/cgroups/cgfs.c
index 8499200..3bfa523 100644
--- a/src/lxc/cgroups/cgfs.c
+++ b/src/lxc/cgroups/cgfs.c
@@ -1880,7 +1880,7 @@ static int create_or_remove_cgroup(bool do_remove,
                } else
                        r = rmdir(buf);
        } else
-               r = mkdir(buf, 0777);
+               r = mkdir_p(buf, 0777);
        saved_errno = errno;
        free(buf);
        errno = saved_errno;
diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 2b772e2..ebd548b 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -101,6 +101,12 @@ struct hierarchy **hierarchies;
  */
 char *cgroup_use;
 
+/*
+ * @lxc_cgfsng_debug - whether to print debug info to stdout for the cgfsng
+ * driver
+ */
+static bool lxc_cgfsng_debug;
+
 static void free_string_list(char **clist)
 {
        if (clist) {
@@ -986,45 +992,44 @@ static void get_existing_subsystems(char ***klist, char 
***nlist)
 static void trim(char *s)
 {
        size_t len = strlen(s);
-       while (s[len-1] == '\n')
+       while ((len > 1) && (s[len - 1] == '\n'))
                s[--len] = '\0';
 }
 
-static void print_init_debuginfo(struct cgfsng_handler_data *d)
+static void lxc_cgfsng_print_handler_data(const struct cgfsng_handler_data *d)
+{
+       printf("Cgroup information:\n");
+       printf("  container name: %s\n", d->name ? d->name : "(null)");
+       printf("  lxc.cgroup.use: %s\n", cgroup_use ? cgroup_use : "(null)");
+       printf("  lxc.cgroup.pattern: %s\n", d->cgroup_pattern ? 
d->cgroup_pattern : "(null)");
+       printf("  cgroup: %s\n", d->container_cgroup ? d->container_cgroup : 
"(null)");
+}
+
+static void lxc_cgfsng_print_hierarchies()
 {
        struct hierarchy **it;
        int i;
 
-       if (!getenv("LXC_DEBUG_CGFSNG"))
-               return;
-
-       DEBUG("Cgroup information:");
-       DEBUG("  container name: %s", d->name ? d->name : "(null)");
-       DEBUG("  lxc.cgroup.use: %s", cgroup_use ? cgroup_use : "(null)");
-       DEBUG("  lxc.cgroup.pattern: %s", d->cgroup_pattern ? d->cgroup_pattern 
: "(null)");
-       DEBUG("  cgroup: %s", d->container_cgroup ? d->container_cgroup : 
"(null)");
        if (!hierarchies) {
-               DEBUG("  No hierarchies found.");
+               printf("  No hierarchies found.");
                return;
        }
-       DEBUG("  Hierarchies:");
+       printf("  Hierarchies:\n");
        for (i = 0, it = hierarchies; it && *it; it++, i++) {
                char **cit;
                int j;
-               DEBUG("  %d: base_cgroup %s", i, (*it)->base_cgroup ? 
(*it)->base_cgroup : "(null)");
-               DEBUG("      mountpoint %s", (*it)->mountpoint ? 
(*it)->mountpoint : "(null)");
-               DEBUG("      controllers:");
+               printf("  %d: base_cgroup %s\n", i, (*it)->base_cgroup ? 
(*it)->base_cgroup : "(null)");
+               printf("      mountpoint %s\n", (*it)->mountpoint ? 
(*it)->mountpoint : "(null)");
+               printf("      controllers:\n");
                for (j = 0, cit = (*it)->controllers; cit && *cit; cit++, j++)
-                       DEBUG("      %d: %s", j, *cit);
+                       printf("      %d: %s\n", j, *cit);
        }
 }
 
-static void print_basecg_debuginfo(char *basecginfo, char **klist, char 
**nlist)
+static void lxc_cgfsng_print_basecg_debuginfo(char *basecginfo, char **klist, 
char **nlist)
 {
        int k;
        char **it;
-       if (!getenv("LXC_DEBUG_CGFSNG"))
-               return;
 
        printf("basecginfo is:\n");
        printf("%s\n", basecginfo);
@@ -1035,6 +1040,12 @@ static void print_basecg_debuginfo(char *basecginfo, 
char **klist, char **nlist)
                printf("named subsystem %d: %s\n", k, *it);
 }
 
+static void lxc_cgfsng_print_debuginfo(const struct cgfsng_handler_data *d)
+{
+       lxc_cgfsng_print_handler_data(d);
+       lxc_cgfsng_print_hierarchies();
+}
+
 /*
  * At startup, parse_hierarchies finds all the info we need about
  * cgroup mountpoints and current cgroups, and stores it in @d.
@@ -1064,7 +1075,8 @@ static bool parse_hierarchies(void)
 
        get_existing_subsystems(&klist, &nlist);
 
-       print_basecg_debuginfo(basecginfo, klist, nlist);
+       if (lxc_cgfsng_debug)
+               lxc_cgfsng_print_basecg_debuginfo(basecginfo, klist, nlist);
 
        /* we support simple cgroup mounts and lxcfs mounts */
        while (getline(&line, &len, f) != -1) {
@@ -1116,6 +1128,11 @@ static bool parse_hierarchies(void)
        fclose(f);
        free(line);
 
+       if (lxc_cgfsng_debug) {
+               printf("writeable subsystems:\n");
+               lxc_cgfsng_print_hierarchies();
+       }
+
        /* verify that all controllers in cgroup.use and all crucial
         * controllers are accounted for
         */
@@ -1156,7 +1173,8 @@ static void *cgfsng_init(const char *name)
        }
        d->cgroup_pattern = must_copy_string(cgroup_pattern);
 
-       print_init_debuginfo(d);
+       if (lxc_cgfsng_debug)
+               lxc_cgfsng_print_debuginfo(d);
 
        return d;
 
@@ -1294,8 +1312,12 @@ static void cgfsng_destroy(void *hdata, struct lxc_conf 
*conf)
 
 struct cgroup_ops *cgfsng_ops_init(void)
 {
+       if (getenv("LXC_DEBUG_CGFSNG"))
+               lxc_cgfsng_debug = true;
+
        if (!collect_hierarchy_info())
                return NULL;
+
        return &cgfsng_ops;
 }
 
diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index b17879b..27c8c08 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -74,14 +74,19 @@
 
 lxc_log_define(lxc_commands, lxc);
 
-static int fill_sock_name(char *path, int len, const char *name,
+static int fill_sock_name(char *path, int len, const char *lxcname,
                          const char *lxcpath, const char *hashed_sock_name)
 {
+       const char *name;
        char *tmppath;
        size_t tmplen;
        uint64_t hash;
        int ret;
 
+       name = lxcname;
+       if (!name)
+               name = "";
+
        if (hashed_sock_name != NULL) {
                ret = snprintf(path, len, "lxc/%s/command", hashed_sock_name);
                if (ret < 0 || ret >= len) {
@@ -193,8 +198,11 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr 
*cmd)
                rsp->data = rspdata;
        }
 
-       if (rsp->datalen == 0)
+       if (rsp->datalen == 0) {
+               DEBUG("command %s response data length is 0",
+                     lxc_cmd_str(cmd->req.cmd));
                return ret;
+       }
        if (rsp->datalen > LXC_CMD_DATA_MAX) {
                ERROR("Command %s response data %d too long.",
                      lxc_cmd_str(cmd->req.cmd), rsp->datalen);
@@ -274,7 +282,7 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr 
*cmd, int *stopped,
        int sock, ret = -1;
        char path[sizeof(((struct sockaddr_un *)0)->sun_path)] = { 0 };
        char *offset = &path[1];
-       int len;
+       size_t len;
        int stay_connected = cmd->req.cmd == LXC_CMD_CONSOLE;
 
        *stopped = 0;
@@ -982,7 +990,7 @@ int lxc_cmd_init(const char *name, struct lxc_handler 
*handler,
         * Although null termination isn't required by the API, we do it anyway
         * because we print the sockname out sometimes.
         */
-       len = sizeof(path)-2;
+       len = sizeof(path) - 2;
        if (fill_sock_name(offset, len, name, lxcpath, NULL))
                return -1;
 
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index a93124b..923a4d9 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -47,6 +47,7 @@
 #include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <sys/sysmacros.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
 #include <sys/utsname.h>
@@ -56,9 +57,6 @@
 #ifdef MAJOR_IN_MKDEV
 #    include <sys/mkdev.h>
 #endif
-#ifdef MAJOR_IN_SYSMACROS
-#    include <sys/sysmacros.h>
-#endif
 
 #ifdef HAVE_STATVFS
 #include <sys/statvfs.h>
@@ -91,7 +89,7 @@
 #include "utils.h"
 #include "lsm/lsm.h"
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 #include <sys/capability.h>
 #endif
 
@@ -107,7 +105,7 @@
 
 lxc_log_define(lxc_conf, lxc);
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 #ifndef CAP_SETFCAP
 #define CAP_SETFCAP 31
 #endif
@@ -172,6 +170,10 @@ static int sethostname(const char * name, size_t len)
 #define MS_PRIVATE (1<<18)
 #endif
 
+#ifndef MS_LAZYTIME
+#define MS_LAZYTIME (1<<25)
+#endif
+
 /* memfd_create() */
 #ifndef MFD_CLOEXEC
 #define MFD_CLOEXEC 0x0001U
@@ -288,35 +290,36 @@ static  instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE 
+ 1] = {
 };
 
 static struct mount_opt mount_opt[] = {
+       { "async",         1, MS_SYNCHRONOUS },
+       { "atime",         1, MS_NOATIME     },
+       { "bind",          0, MS_BIND        },
        { "defaults",      0, 0              },
-       { "ro",            0, MS_RDONLY      },
-       { "rw",            1, MS_RDONLY      },
-       { "suid",          1, MS_NOSUID      },
-       { "nosuid",        0, MS_NOSUID      },
        { "dev",           1, MS_NODEV       },
-       { "nodev",         0, MS_NODEV       },
-       { "exec",          1, MS_NOEXEC      },
-       { "noexec",        0, MS_NOEXEC      },
-       { "sync",          0, MS_SYNCHRONOUS },
-       { "async",         1, MS_SYNCHRONOUS },
+       { "diratime",      1, MS_NODIRATIME  },
        { "dirsync",       0, MS_DIRSYNC     },
-       { "remount",       0, MS_REMOUNT     },
+       { "exec",          1, MS_NOEXEC      },
+       { "lazytime",      0, MS_LAZYTIME    },
        { "mand",          0, MS_MANDLOCK    },
-       { "nomand",        1, MS_MANDLOCK    },
-       { "atime",         1, MS_NOATIME     },
        { "noatime",       0, MS_NOATIME     },
-       { "diratime",      1, MS_NODIRATIME  },
+       { "nodev",         0, MS_NODEV       },
        { "nodiratime",    0, MS_NODIRATIME  },
-       { "bind",          0, MS_BIND        },
+       { "noexec",        0, MS_NOEXEC      },
+       { "nomand",        1, MS_MANDLOCK    },
+       { "norelatime",    1, MS_RELATIME    },
+       { "nostrictatime", 1, MS_STRICTATIME },
+       { "nosuid",        0, MS_NOSUID      },
        { "rbind",         0, MS_BIND|MS_REC },
        { "relatime",      0, MS_RELATIME    },
-       { "norelatime",    1, MS_RELATIME    },
+       { "remount",       0, MS_REMOUNT     },
+       { "ro",            0, MS_RDONLY      },
+       { "rw",            1, MS_RDONLY      },
        { "strictatime",   0, MS_STRICTATIME },
-       { "nostrictatime", 1, MS_STRICTATIME },
+       { "suid",          1, MS_NOSUID      },
+       { "sync",          0, MS_SYNCHRONOUS },
        { NULL,            0, 0              },
 };
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 static struct caps_opt caps_opt[] = {
        { "chown",             CAP_CHOWN             },
        { "dac_override",      CAP_DAC_OVERRIDE      },
@@ -516,7 +519,7 @@ static int run_script(const char *name, const char 
*section, const char *script,
 }
 
 static int mount_rootfs_dir(const char *rootfs, const char *target,
-                                       const char *options)
+                           const char *options)
 {
        unsigned long mntflags;
        char *mntdata;
@@ -533,99 +536,21 @@ static int mount_rootfs_dir(const char *rootfs, const 
char *target,
        return ret;
 }
 
-static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
-{
-       int rfd;
-       int ret = -1;
-
-       rfd = open(rootfs, O_RDWR);
-       if (rfd < 0) {
-               SYSERROR("failed to open '%s'", rootfs);
-               return -1;
-       }
-
-       memset(loinfo, 0, sizeof(*loinfo));
-
-       loinfo->lo_flags = LO_FLAGS_AUTOCLEAR;
-
-       if (ioctl(fd, LOOP_SET_FD, rfd)) {
-               SYSERROR("failed to LOOP_SET_FD");
-               goto out;
-       }
-
-       if (ioctl(fd, LOOP_SET_STATUS64, loinfo)) {
-               SYSERROR("failed to LOOP_SET_STATUS64");
-               goto out;
-       }
-
-       ret = 0;
-out:
-       close(rfd);
-
-       return ret;
-}
-
-static int mount_rootfs_file(const char *rootfs, const char *target,
-                                            const char *options)
+static int lxc_mount_rootfs_file(const char *rootfs, const char *target,
+                            const char *options)
 {
-       struct dirent *direntp;
-       struct loop_info64 loinfo;
-       int ret = -1, fd = -1, rc;
-       DIR *dir;
+       int ret, loopfd;
        char path[MAXPATHLEN];
 
-       dir = opendir("/dev");
-       if (!dir) {
-               SYSERROR("failed to open '/dev'");
+       loopfd = lxc_prepare_loop_dev(rootfs, path, LO_FLAGS_AUTOCLEAR);
+       if (loopfd < 0)
                return -1;
-       }
+       DEBUG("prepared loop device \"%s\"", path);
 
-       while ((direntp = readdir(dir))) {
+       ret = mount_unknown_fs(path, target, options);
+       close(loopfd);
 
-               if (!direntp)
-                       break;
-
-               if (!strcmp(direntp->d_name, "."))
-                       continue;
-
-               if (!strcmp(direntp->d_name, ".."))
-                       continue;
-
-               if (strncmp(direntp->d_name, "loop", 4))
-                       continue;
-
-               rc = snprintf(path, MAXPATHLEN, "/dev/%s", direntp->d_name);
-               if (rc < 0 || rc >= MAXPATHLEN)
-                       continue;
-
-               fd = open(path, O_RDWR);
-               if (fd < 0)
-                       continue;
-
-               if (ioctl(fd, LOOP_GET_STATUS64, &loinfo) == 0) {
-                       close(fd);
-                       continue;
-               }
-
-               if (errno != ENXIO) {
-                       WARN("unexpected error for ioctl on '%s': %m",
-                            direntp->d_name);
-                       close(fd);
-                       continue;
-               }
-
-               DEBUG("found '%s' free lodev", path);
-
-               ret = setup_lodev(rootfs, fd, &loinfo);
-               if (!ret)
-                       ret = mount_unknown_fs(path, target, options);
-               close(fd);
-
-               break;
-       }
-
-       if (closedir(dir))
-               WARN("failed to close directory");
+       DEBUG("mounted rootfs \"%s\" on loop device \"%s\" via loop device 
\"%s\"", rootfs, target, path);
 
        return ret;
 }
@@ -858,33 +783,32 @@ static int mount_rootfs(const char *rootfs, const char 
*target, const char *opti
        } rtfs_type[] = {
                { S_IFDIR, mount_rootfs_dir },
                { S_IFBLK, mount_rootfs_block },
-               { S_IFREG, mount_rootfs_file },
+               { S_IFREG, lxc_mount_rootfs_file },
        };
 
        if (!realpath(rootfs, absrootfs)) {
-               SYSERROR("failed to get real path for '%s'", rootfs);
+               SYSERROR("Failed to get real path for \"%s\".", rootfs);
                return -1;
        }
 
        if (access(absrootfs, F_OK)) {
-               SYSERROR("'%s' is not accessible", absrootfs);
+               SYSERROR("The rootfs \"%s\" is not accessible.", absrootfs);
                return -1;
        }
 
        if (stat(absrootfs, &s)) {
-               SYSERROR("failed to stat '%s'", absrootfs);
+               SYSERROR("Failed to stat the rootfs \"%s\".", absrootfs);
                return -1;
        }
 
        for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) {
-
                if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
                        continue;
 
                return rtfs_type[i].cb(absrootfs, target, options);
        }
 
-       ERROR("unsupported rootfs type for '%s'", absrootfs);
+       ERROR("Unsupported rootfs type for rootfs \"%s\".", absrootfs);
        return -1;
 }
 
@@ -1186,45 +1110,47 @@ static const struct lxc_devs lxc_devs[] = {
        { "urandom",    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 9     },
        { "random",     S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 8     },
        { "tty",        S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 5, 0     },
-       { "console",    S_IFCHR | S_IRUSR | S_IWUSR,           5, 1     },
 };
 
-static int fill_autodev(const struct lxc_rootfs *rootfs, bool mount_console)
+static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
 {
        int ret;
        char path[MAXPATHLEN];
        int i;
        mode_t cmask;
 
-       INFO("Creating initial consoles under container /dev");
-
        ret = snprintf(path, MAXPATHLEN, "%s/dev", rootfs->path ? rootfs->mount 
: "");
        if (ret < 0 || ret >= MAXPATHLEN) {
                ERROR("Error calculating container /dev location");
                return -1;
        }
 
-       if (!dir_exists(path)) // ignore, just don't try to fill in
+       /* ignore, just don't try to fill in */
+       if (!dir_exists(path))
                return 0;
 
-       INFO("Populating container /dev");
+       INFO("populating container /dev");
        cmask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
        for (i = 0; i < sizeof(lxc_devs) / sizeof(lxc_devs[0]); i++) {
                const struct lxc_devs *d = &lxc_devs[i];
 
-               if (!strcmp(d->name, "console") && !mount_console)
-                       continue;
-
                ret = snprintf(path, MAXPATHLEN, "%s/dev/%s", rootfs->path ? 
rootfs->mount : "", d->name);
                if (ret < 0 || ret >= MAXPATHLEN)
                        return -1;
+
                ret = mknod(path, d->mode, makedev(d->maj, d->min));
-               if (ret && errno != EEXIST) {
+               if (ret < 0) {
                        char hostpath[MAXPATHLEN];
                        FILE *pathfile;
 
-                       // Unprivileged containers cannot create devices, so
-                       // bind mount the device from the host
+                       if (errno == EEXIST) {
+                               DEBUG("\"%s\" device already existed", path);
+                               continue;
+                       }
+
+                       /* Unprivileged containers cannot create devices, so
+                        * bind mount the device from the host.
+                        */
                        ret = snprintf(hostpath, MAXPATHLEN, "/dev/%s", 
d->name);
                        if (ret < 0 || ret >= MAXPATHLEN)
                                return -1;
@@ -1234,54 +1160,62 @@ static int fill_autodev(const struct lxc_rootfs 
*rootfs, bool mount_console)
                                return -1;
                        }
                        fclose(pathfile);
-                       if (safe_mount(hostpath, path, 0, MS_BIND, NULL,
-                                               rootfs->path ? rootfs->mount : 
NULL) != 0) {
-                               SYSERROR("Failed bind mounting device %s from 
host into container",
-                                       d->name);
+                       if (safe_mount(hostpath, path, 0, MS_BIND, NULL, 
rootfs->path ? rootfs->mount : NULL) != 0) {
+                               SYSERROR("Failed bind mounting device %s from 
host into container", d->name);
                                return -1;
                        }
+                       DEBUG("bind mounted \"%s\" onto \"%s\"", hostpath, 
path);
+               } else {
+                       DEBUG("created device node \"%s\"", path);
                }
        }
        umask(cmask);
 
-       INFO("Populated container /dev");
+       INFO("populated container /dev");
        return 0;
 }
 
 static int setup_rootfs(struct lxc_conf *conf)
 {
-       const struct lxc_rootfs *rootfs = &conf->rootfs;
+       struct bdev *bdev;
+       const struct lxc_rootfs *rootfs;
 
+       rootfs = &conf->rootfs;
        if (!rootfs->path) {
-               if (mount("", "/", NULL, MS_SLAVE|MS_REC, 0)) {
-                       SYSERROR("Failed to make / rslave");
+               if (mount("", "/", NULL, MS_SLAVE | MS_REC, 0)) {
+                       SYSERROR("Failed to make / rslave.");
                        return -1;
                }
                return 0;
        }
 
        if (access(rootfs->mount, F_OK)) {
-               SYSERROR("failed to access to '%s', check it is present",
+               SYSERROR("Failed to access to \"%s\". Check it is present.",
                         rootfs->mount);
                return -1;
        }
 
-       // First try mounting rootfs using a bdev
-       struct bdev *bdev = bdev_init(conf, rootfs->path, rootfs->mount, 
rootfs->options);
-       if (bdev && bdev->ops->mount(bdev) == 0) {
+       /* First try mounting rootfs using a bdev. */
+       bdev = bdev_init(conf, rootfs->path, rootfs->mount, rootfs->options);
+       if (bdev && !bdev->ops->mount(bdev)) {
                bdev_put(bdev);
-               DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
+               DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\".",
+                     rootfs->path, rootfs->mount,
+                     rootfs->options ? rootfs->options : "(null)");
                return 0;
        }
        if (bdev)
                bdev_put(bdev);
        if (mount_rootfs(rootfs->path, rootfs->mount, rootfs->options)) {
-               ERROR("failed to mount rootfs");
+               ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options 
\"%s\".",
+                     rootfs->path, rootfs->mount,
+                     rootfs->options ? rootfs->options : "(null)");
                return -1;
        }
 
-       DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
-
+       DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\".",
+             rootfs->path, rootfs->mount,
+             rootfs->options ? rootfs->options : "(null)");
        return 0;
 }
 
@@ -1294,23 +1228,23 @@ int prepare_ramfs_root(char *root)
        char *p2;
 
        if (realpath(root, nroot) == NULL)
-               return -1;
+               return -errno;
 
        if (chdir("/") == -1)
-               return -1;
+               return -errno;
 
        /*
         * We could use here MS_MOVE, but in userns this mount is
         * locked and can't be moved.
         */
-       if (mount(root, "/", NULL, MS_REC | MS_BIND, NULL)) {
+       if (mount(root, "/", NULL, MS_REC | MS_BIND, NULL) < 0) {
                SYSERROR("Failed to move %s into /", root);
-               return -1;
+               return -errno;
        }
 
-       if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) {
+       if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) < 0) {
                SYSERROR("Failed to make . rprivate");
-               return -1;
+               return -errno;
        }
 
        /*
@@ -1376,64 +1310,112 @@ int prepare_ramfs_root(char *root)
 
 static int setup_pivot_root(const struct lxc_rootfs *rootfs)
 {
-       if (!rootfs->path)
+       if (!rootfs->path) {
+               DEBUG("container does not have a rootfs, so not doing pivot 
root");
                return 0;
+       }
 
        if (detect_ramfs_rootfs()) {
-               if (prepare_ramfs_root(rootfs->mount))
+               DEBUG("detected that container is on ramfs");
+               if (prepare_ramfs_root(rootfs->mount)) {
+                       ERROR("failed to prepare minimal ramfs root");
                        return -1;
-       } else if (setup_rootfs_pivot_root(rootfs->mount)) {
-               ERROR("failed to setup pivot root");
+               }
+
+               DEBUG("prepared ramfs root for container");
+               return 0;
+       }
+
+       if (setup_rootfs_pivot_root(rootfs->mount) < 0) {
+               ERROR("failed to pivot root");
                return -1;
        }
 
+       DEBUG("finished pivot root");
        return 0;
 }
 
-static int setup_pts(int pts)
+static int lxc_setup_devpts(int num_pts)
 {
-       char target[PATH_MAX];
+       int ret;
+       const char *devpts_mntopts = 
"newinstance,ptmxmode=0666,mode=0620,gid=5";
 
-       if (!pts)
+       if (!num_pts) {
+               DEBUG("no new devpts instance will be mounted since no pts "
+                     "devices are requested");
                return 0;
-
-       if (!access("/dev/pts/ptmx", F_OK) && umount("/dev/pts")) {
-               SYSERROR("failed to umount 'dev/pts'");
-               return -1;
        }
 
-       if (mkdir("/dev/pts", 0755)) {
-               if ( errno != EEXIST ) {
-                   SYSERROR("failed to create '/dev/pts'");
-                   return -1;
+       /* Unmount old devpts instance. */
+       ret = access("/dev/pts/ptmx", F_OK);
+       if (!ret) {
+               ret = umount("/dev/pts");
+               if (ret < 0) {
+                       SYSERROR("failed to unmount old devpts instance");
+                       return -1;
                }
+               DEBUG("unmounted old /dev/pts instance");
        }
 
-       if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,
-                 "newinstance,ptmxmode=0666,mode=0620,gid=5")) {
-               SYSERROR("failed to mount a new instance of '/dev/pts'");
+       /* Create mountpoint for devpts instance. */
+       ret = mkdir("/dev/pts", 0755);
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("failed to create the \"/dev/pts\" directory");
                return -1;
        }
 
-       if (access("/dev/ptmx", F_OK)) {
-               if (!symlink("/dev/pts/ptmx", "/dev/ptmx"))
-                       goto out;
-               SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'");
+       /* Mount new devpts instance. */
+       ret = mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, devpts_mntopts);
+       if (ret < 0) {
+               SYSERROR("failed to mount new devpts instance");
                return -1;
        }
 
-       if (realpath("/dev/ptmx", target) && !strcmp(target, "/dev/pts/ptmx"))
-               goto out;
+       /* Remove any pre-existing /dev/ptmx file. */
+       ret = access("/dev/ptmx", F_OK);
+       if (!ret) {
+               ret = remove("/dev/ptmx");
+               if (ret < 0) {
+                       SYSERROR("failed to remove existing \"/dev/ptmx\"");
+                       return -1;
+               }
+               DEBUG("removed existing \"/dev/ptmx\"");
+       }
 
-       /* fallback here, /dev/pts/ptmx exists just mount bind */
-       if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) {
-               SYSERROR("mount failed '/dev/pts/ptmx'->'/dev/ptmx'");
+       /* Create dummy /dev/ptmx file as bind mountpoint for /dev/pts/ptmx. */
+       ret = open("/dev/ptmx", O_CREAT, 0666);
+       if (ret < 0) {
+               SYSERROR("failed to create dummy \"/dev/ptmx\" file as bind 
mount target");
                return -1;
        }
+       close(ret);
+       DEBUG("created dummy \"/dev/ptmx\" file as bind mount target");
 
-       INFO("created new pts instance");
+       /* Fallback option: create symlink /dev/ptmx -> /dev/pts/ptmx  */
+       ret = mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_BIND, NULL);
+       if (!ret) {
+               DEBUG("bind mounted \"/dev/pts/ptmx\" to \"/dev/ptmx\"");
+               return 0;
+       } else {
+               /* Fallthrough and try to create a symlink. */
+               ERROR("failed to bind mount \"/dev/pts/ptmx\" to 
\"/dev/ptmx\"");
+       }
+
+       /* Remove the dummy /dev/ptmx file we created above. */
+       ret = remove("/dev/ptmx");
+       if (ret < 0) {
+               SYSERROR("failed to remove existing \"/dev/ptmx\"");
+               return -1;
+       }
+
+       /* Fallback option: Create symlink /dev/ptmx -> /dev/pts/ptmx. */
+       ret = symlink("/dev/pts/ptmx", "/dev/ptmx");
+       if (ret < 0) {
+               SYSERROR("failed to create symlink \"/dev/ptmx\" -> 
\"/dev/pts/ptmx\"");
+               return -1;
+       }
+       DEBUG("created symlink \"/dev/ptmx\" -> \"/dev/pts/ptmx\"");
 
-out:
        return 0;
 }
 
@@ -1454,127 +1436,204 @@ static int setup_personality(int persona)
        return 0;
 }
 
-static int setup_dev_console(const struct lxc_rootfs *rootfs,
-                        const struct lxc_console *console)
+static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs,
+                                const struct lxc_console *console)
 {
        char path[MAXPATHLEN];
        int ret, fd;
 
+       if (console->path && !strcmp(console->path, "none"))
+               return 0;
+
        ret = snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
-       if (ret >= sizeof(path)) {
-               ERROR("console path too long");
+       if (ret < 0 || (size_t)ret >= sizeof(path))
                return -1;
+
+       /* When we are asked to setup a console we remove any previous
+        * /dev/console bind-mounts.
+        */
+       if (file_exists(path)) {
+               ret = lxc_unstack_mountpoint(path, false);
+               if (ret < 0) {
+                       ERROR("failed to unmount \"%s\": %s", path, 
strerror(errno));
+                       return -ret;
+               } else {
+                       DEBUG("cleared all (%d) mounts from \"%s\"", ret, path);
+               }
+               ret = unlink(path);
+               if (ret < 0) {
+                       SYSERROR("error unlinking %s", path);
+                       return -errno;
+               }
        }
 
+       /* For unprivileged containers autodev or automounts will already have
+        * taken care of creating /dev/console.
+        */
        fd = open(path, O_CREAT | O_EXCL, S_IXUSR | S_IXGRP | S_IXOTH);
        if (fd < 0) {
                if (errno != EEXIST) {
                        SYSERROR("failed to create console");
-                       return -1;
+                       return -errno;
                }
        } else {
                close(fd);
        }
 
-       if (console->master < 0) {
-               INFO("no console");
-               return 0;
-       }
-
        if (chmod(console->name, S_IXUSR | S_IXGRP | S_IXOTH)) {
-               SYSERROR("failed to set mode '0%o' to '%s'",
-                        S_IXUSR | S_IXGRP | S_IXOTH, console->name);
-               return -1;
+               SYSERROR("failed to set mode '0%o' to '%s'", S_IXUSR | S_IXGRP 
| S_IXOTH, console->name);
+               return -errno;
        }
 
-       if (safe_mount(console->name, path, "none", MS_BIND, 0, rootfs->mount)) 
{
+       if (safe_mount(console->name, path, "none", MS_BIND, 0, rootfs->mount) 
< 0) {
                ERROR("failed to mount '%s' on '%s'", console->name, path);
                return -1;
        }
 
-       INFO("console has been setup");
+       DEBUG("mounted pts device \"%s\" onto \"%s\"", console->name, path);
        return 0;
 }
 
-static int setup_ttydir_console(const struct lxc_rootfs *rootfs,
-                        const struct lxc_console *console,
-                        char *ttydir)
+static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs,
+                                   const struct lxc_console *console,
+                                   char *ttydir)
 {
-       char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
        int ret;
+       char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
 
        /* create rootfs/dev/<ttydir> directory */
-       ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->mount,
-                      ttydir);
-       if (ret >= sizeof(path))
+       ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->mount, ttydir);
+       if (ret < 0 || (size_t)ret >= sizeof(path))
                return -1;
+
        ret = mkdir(path, 0755);
        if (ret && errno != EEXIST) {
                SYSERROR("failed with errno %d to create %s", errno, path);
-               return -1;
-       }
-       INFO("created %s", path);
-
-       ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/console",
-                      rootfs->mount, ttydir);
-       if (ret >= sizeof(lxcpath)) {
-               ERROR("console path too long");
-               return -1;
+               return -errno;
        }
+       DEBUG("created directory for console and tty devices at \%s\"", path);
 
-       snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
-       ret = unlink(path);
-       if (ret && errno != ENOENT) {
-               SYSERROR("error unlinking %s", path);
+       ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/console", 
rootfs->mount, ttydir);
+       if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
                return -1;
-       }
 
        ret = creat(lxcpath, 0660);
-       if (ret==-1 && errno != EEXIST) {
+       if (ret == -1 && errno != EEXIST) {
                SYSERROR("error %d creating %s", errno, lxcpath);
-               return -1;
+               return -errno;
        }
        if (ret >= 0)
                close(ret);
 
-       if (console->master < 0) {
-               INFO("no console");
-               return 0;
-       }
-
-       if (safe_mount(console->name, lxcpath, "none", MS_BIND, 0, 
rootfs->mount)) {
-               ERROR("failed to mount '%s' on '%s'", console->name, lxcpath);
+       ret = snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
+       if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
                return -1;
+
+       /* When we are asked to setup a console we remove any previous
+        * /dev/console bind-mounts.
+        */
+       if (console->path && !strcmp(console->path, "none")) {
+               struct stat st;
+               ret = stat(path, &st);
+               if (ret < 0) {
+                       if (errno == ENOENT)
+                               return 0;
+                       SYSERROR("failed stat() \"%s\"", path);
+                       return -errno;
+               }
+
+               /* /dev/console must be character device with major number 5 and
+                * minor number 1. If not, give benefit of the doubt and assume
+                * the user has mounted something else right there on purpose.
+                */
+               if (((st.st_mode & S_IFMT) != S_IFCHR) || major(st.st_rdev) != 
5 || minor(st.st_rdev) != 1)
+                       return 0;
+
+               /* In case the user requested a bind-mount for /dev/console and
+                * requests a ttydir we move the mount to the
+                * /dev/<ttydir/console.
+                * Note, we only move the uppermost mount and clear all other
+                * mounts underneath for safety.
+                * If it is a character device created via mknod() we simply
+                * rename it.
+                */
+               ret = safe_mount(path, lxcpath, "none", MS_MOVE, NULL, 
rootfs->mount);
+               if (ret < 0) {
+                       if (errno != EINVAL) {
+                               ERROR("failed to MS_MOVE \"%s\" to \"%s\": %s", 
path, lxcpath, strerror(errno));
+                               return -errno;
+                       }
+                       /* path was not a mountpoint */
+                       ret = rename(path, lxcpath);
+                       if (ret < 0) {
+                               ERROR("failed to rename \"%s\" to \"%s\": %s", 
path, lxcpath, strerror(errno));
+                               return -errno;
+                       }
+                       DEBUG("renamed \"%s\" to \"%s\"", path, lxcpath);
+               } else {
+                       DEBUG("moved mount \"%s\" to \"%s\"", path, lxcpath);
+               }
+
+               /* Clear all remaining bind-mounts. */
+               ret = lxc_unstack_mountpoint(path, false);
+               if (ret < 0) {
+                       ERROR("failed to unmount \"%s\": %s", path, 
strerror(errno));
+                       return -ret;
+               } else {
+                       DEBUG("cleared all (%d) mounts from \"%s\"", ret, path);
+               }
+       } else {
+               if (file_exists(path)) {
+                       ret = lxc_unstack_mountpoint(path, false);
+                       if (ret < 0) {
+                               ERROR("failed to unmount \"%s\": %s", path, 
strerror(errno));
+                               return -ret;
+                       } else {
+                               DEBUG("cleared all (%d) mounts from \"%s\"", 
ret, path);
+                       }
+               }
+
+               if (safe_mount(console->name, lxcpath, "none", MS_BIND, 0, 
rootfs->mount) < 0) {
+                       ERROR("failed to mount '%s' on '%s'", console->name, 
lxcpath);
+                       return -1;
+               }
+               DEBUG("mounted \"%s\" onto \"%s\"", console->name, lxcpath);
        }
 
-       /* create symlink from rootfs/dev/console to 'lxc/console' */
+       /* create symlink from rootfs /dev/console to '<ttydir>/console' */
        ret = snprintf(lxcpath, sizeof(lxcpath), "%s/console", ttydir);
-       if (ret >= sizeof(lxcpath)) {
-               ERROR("lxc/console path too long");
+       if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
                return -1;
+
+       ret = unlink(path);
+       if (ret && errno != ENOENT) {
+               SYSERROR("error unlinking %s", path);
+               return -errno;
        }
+
        ret = symlink(lxcpath, path);
-       if (ret) {
-               SYSERROR("failed to create symlink for console");
+       if (ret < 0) {
+               SYSERROR("failed to create symlink for console from \"%s\" to 
\"%s\"", lxcpath, path);
                return -1;
        }
 
-       INFO("console has been setup on %s", lxcpath);
-
+       DEBUG("console has been setup under \"%s\" and symlinked to \"%s\"", 
lxcpath, path);
        return 0;
 }
 
-static int setup_console(const struct lxc_rootfs *rootfs,
-                        const struct lxc_console *console,
-                        char *ttydir)
+static int lxc_setup_console(const struct lxc_rootfs *rootfs,
+                            const struct lxc_console *console, char *ttydir)
 {
-       /* We don't have a rootfs, /dev/console will be shared */
-       if (!rootfs->path)
+       /* We don't have a rootfs, /dev/console will be shared. */
+       if (!rootfs->path) {
+               DEBUG("/dev/console will be shared with the host");
                return 0;
+       }
+
        if (!ttydir)
-               return setup_dev_console(rootfs, console);
+               return lxc_setup_dev_console(rootfs, console);
 
-       return setup_ttydir_console(rootfs, console, ttydir);
+       return lxc_setup_ttydir_console(rootfs, console, ttydir);
 }
 
 static int setup_kmsg(const struct lxc_rootfs *rootfs,
@@ -3019,7 +3078,7 @@ bool lxc_delete_network(struct lxc_handler *handler)
                /* Explicitly delete host veth device to prevent lingering
                 * devices. We had issues in LXD around this.
                 */
-               if (netdev->type == LXC_NET_VETH) {
+               if (netdev->type == LXC_NET_VETH && !am_unpriv()) {
                        char *hostveth;
                        if (netdev->priv.veth_attr.pair) {
                                hostveth = netdev->priv.veth_attr.pair;
@@ -3028,8 +3087,6 @@ bool lxc_delete_network(struct lxc_handler *handler)
                                        WARN("Failed to remove interface \"%s\" 
from host: %s.", hostveth, strerror(-ret));
                                } else {
                                        INFO("Removed interface \"%s\" from 
host.", hostveth);
-                                       free(netdev->priv.veth_attr.pair);
-                                       netdev->priv.veth_attr.pair = NULL;
                                }
                        } else if (strlen(netdev->priv.veth_attr.veth1) > 0) {
                                hostveth = netdev->priv.veth_attr.veth1;
@@ -3058,20 +3115,21 @@ static int unpriv_assign_nic(const char *lxcpath, char 
*lxcname,
        int bytes, pipefd[2];
        char *token, *saveptr = NULL;
        char buffer[MAX_BUFFER_SIZE];
-       char netdev_link[IFNAMSIZ+1];
+       char netdev_link[IFNAMSIZ + 1];
 
        if (netdev->type != LXC_NET_VETH) {
                ERROR("nic type %d not support for unprivileged use",
-                       netdev->type);
+                     netdev->type);
                return -1;
        }
 
-       if(pipe(pipefd) < 0) {
+       if (pipe(pipefd) < 0) {
                SYSERROR("pipe failed");
                return -1;
        }
 
-       if ((child = fork()) < 0) {
+       child = fork();
+       if (child < 0) {
                SYSERROR("fork");
                close(pipefd[0]);
                close(pipefd[1]);
@@ -3079,35 +3137,45 @@ static int unpriv_assign_nic(const char *lxcpath, char 
*lxcname,
        }
 
        if (child == 0) { // child
-               /* close the read-end of the pipe */
-               close(pipefd[0]);
-               /* redirect the stdout to write-end of the pipe */
-               dup2(pipefd[1], STDOUT_FILENO);
-               /* close the write-end of the pipe */
-               close(pipefd[1]);
+               /* Call lxc-user-nic pid type bridge. */
+               int ret;
+               char pidstr[LXC_NUMSTRLEN64];
 
-               // Call lxc-user-nic pid type bridge
-               char pidstr[20];
-               if (netdev->link) {
+               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 {
+               else
                        strncpy(netdev_link, "none", IFNAMSIZ);
-               }
-               snprintf(pidstr, 19, "%lu", (unsigned long) pid);
-               pidstr[19] = '\0';
+
+               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("execvp lxc-user-nic");
-               exit(1);
+                      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("read failed");
-       }
+       if (bytes < 0)
+               SYSERROR("Failed to read from pipe file descriptor.");
        buffer[bytes - 1] = '\0';
 
        if (wait_for_pid(child) != 0) {
@@ -3122,21 +3190,23 @@ static int unpriv_assign_nic(const char *lxcpath, char 
*lxcname,
        token = strtok_r(buffer, ":", &saveptr);
        if (!token)
                return -1;
-       netdev->name = malloc(IFNAMSIZ+1);
+
+       netdev->name = malloc(IFNAMSIZ + 1);
        if (!netdev->name) {
-               ERROR("Out of memory");
+               SYSERROR("Failed to allocate memory.");
                return -1;
        }
-       memset(netdev->name, 0, IFNAMSIZ+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("Out of memory");
+               ERROR("Failed to allocate memory.");
                return -1;
        }
 
@@ -3214,75 +3284,145 @@ static int write_id_mapping(enum idtype idtype, pid_t 
pid, const char *buf,
        return ret < 0 ? ret : closeret;
 }
 
+/* Check whether a binary exist and has either CAP_SETUID, CAP_SETGID or both. 
*/
+static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t 
cap)
+{
+       char *path;
+       int ret;
+       struct stat st;
+       int fret = 0;
+
+       path = on_path(binary, NULL);
+       if (!path)
+               return -ENOENT;
+
+       ret = stat(path, &st);
+       if (ret < 0) {
+               fret = -errno;
+               goto cleanup;
+       }
+
+       /* Check if the binary is setuid. */
+       if (st.st_mode & S_ISUID) {
+               DEBUG("The binary \"%s\" does have the setuid bit set.", path);
+               fret = 1;
+               goto cleanup;
+       }
+
+       #if HAVE_LIBCAP && LIBCAP_SUPPORTS_FILE_CAPABILITIES
+       /* Check if it has the CAP_SETUID capability. */
+       if ((cap & CAP_SETUID) &&
+           lxc_file_cap_is_set(path, CAP_SETUID, CAP_EFFECTIVE) &&
+           lxc_file_cap_is_set(path, CAP_SETUID, CAP_PERMITTED)) {
+               DEBUG("The binary \"%s\" has CAP_SETUID in its CAP_EFFECTIVE "
+                     "and CAP_PERMITTED sets.", path);
+               fret = 1;
+               goto cleanup;
+       }
+
+       /* Check if it has the CAP_SETGID capability. */
+       if ((cap & CAP_SETGID) &&
+           lxc_file_cap_is_set(path, CAP_SETGID, CAP_EFFECTIVE) &&
+           lxc_file_cap_is_set(path, CAP_SETGID, CAP_PERMITTED)) {
+               DEBUG("The binary \"%s\" has CAP_SETGID in its CAP_EFFECTIVE "
+                     "and CAP_PERMITTED sets.", path);
+               fret = 1;
+               goto cleanup;
+       }
+       #else
+       /* If we cannot check for file capabilities we need to give the benefit
+        * of the doubt. Otherwise we might fail even though all the necessary
+        * file capabilities are set.
+        */
+       DEBUG("Cannot check for file capabilites as full capability support is "
+             "missing. Manual intervention needed.");
+       fret = 1;
+       #endif
+
+cleanup:
+       free(path);
+       return fret;
+}
+
 int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
 {
-       struct lxc_list *iterator;
        struct id_map *map;
-       int ret = 0, use_shadow = 0;
+       struct lxc_list *iterator;
        enum idtype type;
-       char *buf = NULL, *pos, *cmdpath = NULL;
+       char *pos;
+       int euid;
+       int ret = 0, use_shadow = 0;
+       int uidmap = 0, gidmap = 0;
+       char *buf = NULL;
 
-       /*
-        * If newuidmap exists, that is, if shadow is handing out subuid
-        * ranges, then insist that root also reserve ranges in subuid.  This
+       euid = geteuid();
+
+       /* If new{g,u}idmap exists, that is, if shadow is handing out subuid
+        * ranges, then insist that root also reserve ranges in subuid. This
         * will protected it by preventing another user from being handed the
         * range by shadow.
         */
-       cmdpath = on_path("newuidmap", NULL);
-       if (cmdpath) {
-               use_shadow = 1;
-               free(cmdpath);
-       }
-
-       if (!use_shadow && geteuid()) {
-               ERROR("Missing newuidmap/newgidmap");
+       uidmap = idmaptool_on_path_and_privileged("newuidmap", CAP_SETUID);
+       gidmap = idmaptool_on_path_and_privileged("newgidmap", CAP_SETGID);
+       if (uidmap > 0 && gidmap > 0) {
+               DEBUG("Functional newuidmap and newgidmap binary found.");
+               use_shadow = true;
+       } else if (uidmap == -ENOENT && gidmap == -ENOENT && !euid) {
+               DEBUG("No newuidmap and newgidmap binary found. Trying to "
+                     "write directly with euid 0.");
+               use_shadow = false;
+       } else {
+               DEBUG("Either one or both of the newuidmap and newgidmap "
+                     "binaries do not exist or are missing necessary "
+                     "privilege.");
                return -1;
        }
 
-       for(type = ID_TYPE_UID; type <= ID_TYPE_GID; type++) {
+       for (type = ID_TYPE_UID; type <= ID_TYPE_GID; type++) {
                int left, fill;
-               int had_entry = 0;
+               bool had_entry = false;
                if (!buf) {
-                       buf = pos = malloc(4096);
+                       buf = pos = malloc(LXC_IDMAPLEN);
                        if (!buf)
                                return -ENOMEM;
                }
                pos = buf;
                if (use_shadow)
-                       pos += sprintf(buf, "new%cidmap %d",
-                               type == ID_TYPE_UID ? 'u' : 'g',
-                               pid);
+                       pos += sprintf(buf, "new%cidmap %d", type == 
ID_TYPE_UID ? 'u' : 'g', pid);
 
                lxc_list_for_each(iterator, idmap) {
-                       /* The kernel only takes <= 4k for writes to 
/proc/<nr>/[ug]id_map */
+                       /* The kernel only takes <= 4k for writes to
+                        * /proc/<nr>/[ug]id_map
+                        */
                        map = iterator->elem;
                        if (map->idtype != type)
                                continue;
 
-                       had_entry = 1;
-                       left = 4096 - (pos - buf);
+                       had_entry = true;
+
+                       left = LXC_IDMAPLEN - (pos - buf);
                        fill = snprintf(pos, left, "%s%lu %lu %lu%s",
-                                       use_shadow ? " " : "",
-                                       map->nsid, map->hostid, map->range,
+                                       use_shadow ? " " : "", map->nsid,
+                                       map->hostid, map->range,
                                        use_shadow ? "" : "\n");
                        if (fill <= 0 || fill >= left)
-                               SYSERROR("snprintf failed, too many mappings");
+                               SYSERROR("Too many {g,u}id mappings defined.");
+
                        pos += fill;
                }
                if (!had_entry)
                        continue;
 
                if (!use_shadow) {
-                       ret = write_id_mapping(type, pid, buf, pos-buf);
+                       ret = write_id_mapping(type, pid, buf, pos - buf);
                } else {
-                       left = 4096 - (pos - buf);
+                       left = LXC_IDMAPLEN - (pos - buf);
                        fill = snprintf(pos, left, "\n");
                        if (fill <= 0 || fill >= left)
-                               SYSERROR("snprintf failed, too many mappings");
+                               SYSERROR("Too many {g,u}id mappings defined.");
                        pos += fill;
                        ret = system(buf);
                }
-
                if (ret)
                        break;
        }
@@ -3617,20 +3757,21 @@ int ttys_shift_ids(struct lxc_conf *c)
        return 0;
 }
 
-/* NOTE: not to be called from inside the container namespace! */
-int tmp_proc_mount(struct lxc_conf *lxc_conf)
+/* NOTE: Must not be called from inside the container namespace! */
+int lxc_create_tmp_proc_mount(struct lxc_conf *conf)
 {
        int mounted;
 
-       mounted = mount_proc_if_needed(lxc_conf->rootfs.path ? 
lxc_conf->rootfs.mount : "");
+       mounted = lxc_mount_proc_if_needed(conf->rootfs.path ? 
conf->rootfs.mount : "");
        if (mounted == -1) {
-               SYSERROR("failed to mount /proc in the container.");
+               SYSERROR("failed to mount /proc in the container");
                /* continue only if there is no rootfs */
-               if (lxc_conf->rootfs.path)
+               if (conf->rootfs.path)
                        return -1;
        } else if (mounted == 1) {
-               lxc_conf->tmp_umount_proc = 1;
+               conf->tmp_umount_proc = 1;
        }
+
        return 0;
 }
 
@@ -3892,19 +4033,17 @@ int lxc_setup(struct lxc_handler *handler)
        }
 
        if (lxc_conf->autodev > 0) {
-               bool mount_console = lxc_conf->console.path && 
!strcmp(lxc_conf->console.path, "none");
-
                if (run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL)) {
                        ERROR("failed to run autodev hooks for container 
'%s'.", name);
                        return -1;
                }
-               if (fill_autodev(&lxc_conf->rootfs, mount_console)) {
+               if (lxc_fill_autodev(&lxc_conf->rootfs)) {
                        ERROR("failed to populate /dev in the container");
                        return -1;
                }
        }
 
-       if (!lxc_conf->is_execute && setup_console(&lxc_conf->rootfs, 
&lxc_conf->console, lxc_conf->ttydir)) {
+       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);
                return -1;
        }
@@ -3920,7 +4059,7 @@ int lxc_setup(struct lxc_handler *handler)
        }
 
        /* mount /proc if it's not already there */
-       if (tmp_proc_mount(lxc_conf) < 0) {
+       if (lxc_create_tmp_proc_mount(lxc_conf) < 0) {
                ERROR("failed to LSM mount proc for '%s'", name);
                return -1;
        }
@@ -3930,7 +4069,7 @@ int lxc_setup(struct lxc_handler *handler)
                return -1;
        }
 
-       if (setup_pts(lxc_conf->pts)) {
+       if (lxc_setup_devpts(lxc_conf->pts)) {
                ERROR("failed to setup the new pts instance");
                return -1;
        }
@@ -4151,10 +4290,14 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char 
*key)
 {
        struct lxc_list *it,*next;
        bool all = false;
-       const char *k = key + 11;
+       const char *k = NULL;
 
        if (strcmp(key, "lxc.cgroup") == 0)
                all = true;
+       else if (strncmp(key, "lxc.cgroup.", sizeof("lxc.cgroup.")-1) == 0)
+               k = key + sizeof("lxc.cgroup.")-1;
+       else
+               return -1;
 
        lxc_list_for_each_safe(it, &c->cgroup, next) {
                struct lxc_cgroup *cg = it->elem;
@@ -4216,11 +4359,15 @@ int lxc_clear_hooks(struct lxc_conf *c, const char *key)
 {
        struct lxc_list *it,*next;
        bool all = false, done = false;
-       const char *k = key + 9;
+       const char *k = NULL;
        int i;
 
        if (strcmp(key, "lxc.hook") == 0)
                all = true;
+       else if (strncmp(key, "lxc.hook.", sizeof("lxc.hook.")-1) == 0)
+               k = key + sizeof("lxc.hook.")-1;
+       else
+               return -1;
 
        for (i=0; i<NUM_LXC_HOOKS; i++) {
                if (all || strcmp(k, lxchook_names[i]) == 0) {
@@ -4548,7 +4695,7 @@ void suggest_default_idmap(void)
        }
        fclose(f);
 
-       f = fopen(subuidfile, "r");
+       f = fopen(subgidfile, "r");
        if (!f) {
                ERROR("Your system is not configured with subgids");
                free(gname);
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 2abde72..9b22c6d 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -790,6 +790,9 @@ static int config_network_ipv4(const char *key, const char 
*value,
        struct lxc_list *list;
        char *cursor, *slash, *addr = NULL, *bcast = NULL, *prefix = NULL;
 
+       if (!value || !strlen(value))
+               return lxc_clear_config_item(lxc_conf, key);
+
        netdev = network_netdev(key, value, &lxc_conf->network);
        if (!netdev)
                return -1;
@@ -917,6 +920,9 @@ static int config_network_ipv6(const char *key, const char 
*value,
        char *slash,*valdup;
        char *netmask;
 
+       if (!value || !strlen(value))
+               return lxc_clear_config_item(lxc_conf, key);
+
        netdev = network_netdev(key, value, &lxc_conf->network);
        if (!netdev)
                return -1;
@@ -2873,21 +2879,21 @@ next:
        } \
 }
 
-static void new_hwaddr(char *hwaddr)
+static bool new_hwaddr(char *hwaddr)
 {
-       FILE *f;
-       f = fopen("/dev/urandom", "r");
-       if (f) {
-               unsigned int seed;
-               int ret = fread(&seed, sizeof(seed), 1, f);
-               if (ret != 1)
-                       seed = time(NULL);
-               fclose(f);
-               srand(seed);
-       } else
-               srand(time(NULL));
-       snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x",
-                       rand() % 255, rand() % 255, rand() % 255);
+       int ret;
+
+       /* COMMENT(brauner): Initialize random number generator. */
+       (void)randseed(true);
+
+       ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
+                      rand() % 255, rand() % 255);
+       if (ret < 0 || ret >= 18) {
+               SYSERROR("Failed to call snprintf().");
+               return false;
+       }
+
+       return true;
 }
 
 /*
@@ -2909,27 +2915,33 @@ bool network_new_hwaddrs(struct lxc_conf *conf)
 
        if (!conf->unexpanded_config)
                return true;
+
        while (*lstart) {
                char newhwaddr[18], oldhwaddr[17];
+
                lend = strchr(lstart, '\n');
                if (!lend)
                        lend = lstart + strlen(lstart);
                else
                        lend++;
+
                if (strncmp(lstart, key, strlen(key)) != 0) {
                        lstart = lend;
                        continue;
                }
+
                p = strchr(lstart+strlen(key), '=');
                if (!p) {
                        lstart = lend;
                        continue;
                }
+
                p++;
                while (isblank(*p))
                        p++;
                if (!*p)
                        return true;
+
                p2 = p;
                while (*p2 && !isblank(*p2) && *p2 != '\n')
                        p2++;
@@ -2938,8 +2950,12 @@ bool network_new_hwaddrs(struct lxc_conf *conf)
                        lstart = lend;
                        continue;
                }
+
                memcpy(oldhwaddr, p, 17);
-               new_hwaddr(newhwaddr);
+
+               if (!new_hwaddr(newhwaddr))
+                       return false;
+
                memcpy(p, newhwaddr, 17);
                lxc_list_for_each(it, &conf->network) {
                        struct lxc_netdev *n = it->elem;
@@ -2949,6 +2965,7 @@ bool network_new_hwaddrs(struct lxc_conf *conf)
 
                lstart = lend;
        }
+
        return true;
 }
 
diff --git a/src/lxc/console.c b/src/lxc/console.c
index 908ead0..3baaed4 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
@@ -257,6 +257,14 @@ int lxc_setup_tios(int fd, struct termios *oldtios)
                return -1;
        }
 
+       /* ensure we don't end up in an endless loop:
+        * The kernel might fire SIGTTOU while an
+        * ioctl() in tcsetattr() is executed. When the ioctl()
+        * is resumed and retries, the signal handler interrupts it again.
+        */
+       signal (SIGTTIN, SIG_IGN);
+       signal (SIGTTOU, SIG_IGN);
+
        newtios = *oldtios;
 
        /* We use the same settings that ssh does. */
@@ -265,7 +273,7 @@ int lxc_setup_tios(int fd, struct termios *oldtios)
 #ifdef IUCLC
        newtios.c_iflag &= ~IUCLC;
 #endif
-       newtios.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+       newtios.c_lflag &= ~(TOSTOP | ISIG | ICANON | ECHO | ECHOE | ECHOK | 
ECHONL);
 #ifdef IEXTEN
        newtios.c_lflag &= ~IEXTEN;
 #endif
@@ -407,16 +415,17 @@ void lxc_console_free(struct lxc_conf *conf, int fd)
        }
 }
 
-static void lxc_console_peer_default(struct lxc_console *console)
+static int lxc_console_peer_default(struct lxc_console *console)
 {
        struct lxc_tty_state *ts;
        const char *path = console->path;
+       int fd;
+       int ret = 0;
 
-       /* if no console was given, try current controlling terminal, there
-        * won't be one if we were started as a daemon (-d)
+       /* If no console was given, try current controlling terminal, there
+        * won't be one if we were started as a daemon (-d).
         */
        if (!path && !access("/dev/tty", F_OK)) {
-               int fd;
                fd = open("/dev/tty", O_RDWR);
                if (fd >= 0) {
                        close(fd);
@@ -424,25 +433,29 @@ static void lxc_console_peer_default(struct lxc_console 
*console)
                }
        }
 
-       if (!path)
-               goto out;
-
-       DEBUG("opening %s for console peer", path);
-       console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT |
-                                       O_APPEND, 0600));
-       if (console->peer < 0)
+       if (!path) {
+               errno = ENOTTY;
+               DEBUG("process does not have a controlling terminal");
                goto out;
+       }
 
-       DEBUG("using '%s' as console", path);
+       console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT | 
O_APPEND, 0600));
+       if (console->peer < 0) {
+               ERROR("failed to open \"%s\"", path);
+               return -ENOTTY;
+       }
+       DEBUG("using \"%s\" as peer tty device", path);
 
-       if (!isatty(console->peer))
-               goto err1;
+       if (!isatty(console->peer)) {
+               ERROR("file descriptor for file \"%s\" does not refer to a tty 
device", path);
+               goto on_error1;
+       }
 
        ts = lxc_console_sigwinch_init(console->peer, console->master);
        console->tty_state = ts;
        if (!ts) {
-               WARN("Unable to install SIGWINCH");
-               goto err1;
+               WARN("unable to install SIGWINCH handler");
+               goto on_error1;
        }
 
        lxc_console_winsz(console->peer, console->master);
@@ -450,23 +463,27 @@ static void lxc_console_peer_default(struct lxc_console 
*console)
        console->tios = malloc(sizeof(*console->tios));
        if (!console->tios) {
                SYSERROR("failed to allocate memory");
-               goto err1;
+               ret = -ENOMEM;
+               goto on_error1;
        }
 
        if (lxc_setup_tios(console->peer, console->tios) < 0)
-               goto err2;
-
-       return;
+               goto on_error2;
+       else
+               goto out;
 
-err2:
+on_error2:
        free(console->tios);
        console->tios = NULL;
-err1:
+       ret = -ENOTTY;
+
+on_error1:
        close(console->peer);
        console->peer = -1;
+       ret = -ENOTTY;
+
 out:
-       DEBUG("no console peer");
-       return;
+       return ret;
 }
 
 void lxc_console_delete(struct lxc_console *console)
@@ -495,21 +512,24 @@ int lxc_console_create(struct lxc_conf *conf)
        int ret;
 
        if (conf->is_execute) {
-               INFO("no console for lxc-execute.");
+               INFO("not allocating a console device for lxc-execute.");
                return 0;
        }
 
-       if (!conf->rootfs.path)
+       if (!conf->rootfs.path) {
+               INFO("container does not have a rootfs, console device will be 
shared with the host");
                return 0;
+       }
 
-       if (console->path && !strcmp(console->path, "none"))
+       if (console->path && !strcmp(console->path, "none")) {
+               INFO("no console requested");
                return 0;
+       }
 
        process_lock();
-       ret = openpty(&console->master, &console->slave,
-                   console->name, NULL, NULL);
+       ret = openpty(&console->master, &console->slave, console->name, NULL, 
NULL);
        process_unlock();
-       if (ret) {
+       if (ret < 0) {
                SYSERROR("failed to allocate a pty");
                return -1;
        }
@@ -524,17 +544,19 @@ int lxc_console_create(struct lxc_conf *conf)
                goto err;
        }
 
-       lxc_console_peer_default(console);
+       ret = lxc_console_peer_default(console);
+       if (ret < 0) {
+               ERROR("failed to allocate peer tty device");
+               goto err;
+       }
 
        if (console->log_path) {
-               console->log_fd = lxc_unpriv(open(console->log_path,
-                                                 O_CLOEXEC | O_RDWR |
-                                                 O_CREAT | O_APPEND, 0600));
+               console->log_fd = lxc_unpriv(open(console->log_path, O_CLOEXEC 
| O_RDWR | O_CREAT | O_APPEND, 0600));
                if (console->log_fd < 0) {
-                       SYSERROR("failed to open '%s'", console->log_path);
+                       SYSERROR("failed to open console log file \"%s\"", 
console->log_path);
                        goto err;
                }
-               DEBUG("using '%s' as console log", console->log_path);
+               DEBUG("using \"%s\" as console log file", console->log_path);
        }
 
        return 0;
diff --git a/src/lxc/criu.c b/src/lxc/criu.c
index 8a0702f..d757bef 100644
--- a/src/lxc/criu.c
+++ b/src/lxc/criu.c
@@ -334,8 +334,18 @@ static void exec_criu(struct criu_opts *opts)
                goto err;
 
        while (getmntent_r(mnts, &mntent, buf, sizeof(buf))) {
-               char *fmt, *key, *val;
+               char *fmt, *key, *val, *mntdata;
                char arg[2 * PATH_MAX + 2];
+               unsigned long flags;
+
+               if (parse_mntopts(mntent.mnt_opts, &flags, &mntdata) < 0)
+                       goto err;
+
+               free(mntdata);
+
+               /* only add --ext-mount-map for actual bind mounts */
+               if (!(flags & MS_BIND))
+                       continue;
 
                if (strcmp(opts->action, "dump") == 0) {
                        fmt = "/%s:%s";
diff --git a/src/lxc/log.c b/src/lxc/log.c
index 678bec7..c9b54dc 100644
--- a/src/lxc/log.c
+++ b/src/lxc/log.c
@@ -106,7 +106,7 @@ int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const 
struct timespec *time
        yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
 
        /* Given year-of-era, and era, one can now compute the year. */
-       year = (yoe) + era * 400;
+       year = yoe + era * 400;
 
        /* Also the day-of-year, again with the year beginning on Mar. 1, can be
         * computed from the day-of-era and year-of-era.
@@ -126,6 +126,11 @@ int lxc_unix_epoch_to_utc(char *buf, size_t bufsize, const 
struct timespec *time
         */
        month = mp + (mp < 10 ? 3 : -9);
 
+       /* The algorithm assumes that a year begins on 1 March, so add 1 before
+        * that. */
+       if (month < 3)
+               year++;
+
        /* Transform days in the epoch to seconds. */
        d_in_s = epoch_to_days * 86400;
 
diff --git a/src/lxc/lxc_user_nic.c b/src/lxc/lxc_user_nic.c
index 409a53a..c93b4cc 100644
--- a/src/lxc/lxc_user_nic.c
+++ b/src/lxc/lxc_user_nic.c
@@ -18,37 +18,44 @@
  */
 
 #define _GNU_SOURCE             /* See feature_test_macros(7) */
+#include <alloca.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sched.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdbool.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/file.h>
-#include <alloca.h>
 #include <string.h>
-#include <sched.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <linux/netlink.h>
+#include <unistd.h>
 #include <arpa/inet.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 #include <linux/sockios.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "config.h"
-#include "utils.h"
 #include "network.h"
+#include "utils.h"
+
+#define usernic_debug_stream(stream, format, ...)                              
\
+       do {                                                                   \
+               fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__,     \
+                       __func__, __VA_ARGS__);                                \
+       } while (false)
+
+#define usernic_error(format, ...) usernic_debug_stream(stderr, format, 
__VA_ARGS__)
 
 static void usage(char *me, bool fail)
 {
@@ -66,9 +73,8 @@ static int open_and_lock(char *path)
 
        fd = open(path, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR);
        if (fd < 0) {
-               fprintf(stderr, "Failed to open %s: %s\n",
-                       path, strerror(errno));
-               return(fd);
+               usernic_error("Failed to open %s: %s.\n", path, 
strerror(errno));
+               return -1;
        }
 
        lk.l_type = F_WRLCK;
@@ -76,8 +82,7 @@ static int open_and_lock(char *path)
        lk.l_start = 0;
        lk.l_len = 0;
        if (fcntl(fd, F_SETLKW, &lk) < 0) {
-               fprintf(stderr, "Failed to lock %s: %s\n",
-                       path, strerror(errno));
+               usernic_error("Failed to lock %s: %s.\n", path, 
strerror(errno));
                close(fd);
                return -1;
        }
@@ -88,10 +93,11 @@ static int open_and_lock(char *path)
 
 static char *get_username(void)
 {
-       struct passwd *pwd = getpwuid(getuid());
+       struct passwd *pwd;
 
-       if (pwd == NULL) {
-               perror("getpwuid");
+       pwd = getpwuid(getuid());
+       if (!pwd) {
+               usernic_error("Failed to call get username: %s.\n", 
strerror(errno));
                return NULL;
        }
 
@@ -101,10 +107,13 @@ static char *get_username(void)
 static void free_groupnames(char **groupnames)
 {
        int i;
+
        if (!groupnames)
                return;
+
        for (i = 0; groupnames[i]; i++)
                free(groupnames[i]);
+
        free(groupnames);
 }
 
@@ -117,53 +126,56 @@ static char **get_groupnames(void)
        struct group *gr;
 
        ngroups = getgroups(0, NULL);
-
-       if (ngroups == -1) {
-               fprintf(stderr, "Failed to get number of groups user belongs 
to: %s\n", strerror(errno));
+       if (ngroups < 0) {
+               usernic_error(
+                   "Failed to get number of groups the user belongs to: %s.\n",
+                   strerror(errno));
                return NULL;
        }
        if (ngroups == 0)
                return NULL;
 
-       group_ids = (gid_t *)malloc(sizeof(gid_t)*ngroups);
-
-       if (group_ids == NULL) {
-               fprintf(stderr, "Out of memory while getting groups the user 
belongs to\n");
+       group_ids = malloc(sizeof(gid_t) * ngroups);
+       if (!group_ids) {
+               usernic_error("Failed to allocate memory while getting groups "
+                             "the user belongs to: %s.\n",
+                             strerror(errno));
                return NULL;
        }
 
        ret = getgroups(ngroups, group_ids);
-
        if (ret < 0) {
                free(group_ids);
-               fprintf(stderr, "Failed to get process groups: %s\n", 
strerror(errno));
+               usernic_error("Failed to get process groups: %s.\n",
+                             strerror(errno));
                return NULL;
        }
 
-       groupnames = (char **)malloc(sizeof(char *)*(ngroups+1));
-
-       if (groupnames == NULL) {
+       groupnames = malloc(sizeof(char *) * (ngroups + 1));
+       if (!groupnames) {
                free(group_ids);
-               fprintf(stderr, "Out of memory while getting group names\n");
+               usernic_error("Failed to allocate memory while getting group "
+                             "names: %s.\n",
+                             strerror(errno));
                return NULL;
        }
 
-       memset(groupnames, 0, sizeof(char *)*(ngroups+1));
+       memset(groupnames, 0, sizeof(char *) * (ngroups + 1));
 
-       for (i=0; i<ngroups; i++ ) {
+       for (i = 0; i < ngroups; i++) {
                gr = getgrgid(group_ids[i]);
-
-               if (gr == NULL) {
-                       fprintf(stderr, "Failed to get group name\n");
+               if (!gr) {
+                       usernic_error("Failed to get group name: %s.\n",
+                                     strerror(errno));
                        free(group_ids);
                        free_groupnames(groupnames);
                        return NULL;
                }
 
                groupnames[i] = strdup(gr->gr_name);
-
-               if (groupnames[i] == NULL) {
-                       fprintf(stderr, "Failed to copy group name: %s", 
gr->gr_name);
+               if (!groupnames[i]) {
+                       usernic_error("Failed to copy group name \"%s\".",
+                                     gr->gr_name);
                        free(group_ids);
                        free_groupnames(groupnames);
                        return NULL;
@@ -177,8 +189,8 @@ static char **get_groupnames(void)
 
 static bool name_is_in_groupnames(char *name, char **groupnames)
 {
-       while (groupnames != NULL) {
-               if (strcmp(name, *groupnames) == 0)
+       while (groupnames) {
+               if (!strcmp(name, *groupnames))
                        return true;
                groupnames++;
        }
@@ -195,23 +207,20 @@ static struct alloted_s *append_alloted(struct alloted_s 
**head, char *name, int
 {
        struct alloted_s *cur, *al;
 
-       if (head == NULL || name == NULL) {
+       if (!head || !name) {
                // sanity check. parameters should not be null
-               fprintf(stderr, "NULL parameters to append_alloted not 
allowed\n");
+               usernic_error("%s\n", "Unexpected NULL argument.");
                return NULL;
        }
 
-       al = (struct alloted_s *)malloc(sizeof(struct alloted_s));
-
-       if (al == NULL) {
-               // unable to allocate memory to new struct
-               fprintf(stderr, "Out of memory in append_alloted\n");
+       al = malloc(sizeof(struct alloted_s));
+       if (!al) {
+               usernic_error("Failed to allocate memory: %s.\n", 
strerror(errno));
                return NULL;
        }
 
        al->name = strdup(name);
-
-       if (al->name == NULL) {
+       if (!al->name) {
                free(al);
                return NULL;
        }
@@ -219,16 +228,16 @@ static struct alloted_s *append_alloted(struct alloted_s 
**head, char *name, int
        al->allowed = n;
        al->next = NULL;
 
-       if (*head == NULL) {
+       if (!*head) {
                *head = al;
                return al;
        }
 
        cur = *head;
-       while (cur->next != NULL)
+       while (cur->next)
                cur = cur->next;
-
        cur->next = al;
+
        return al;
 }
 
@@ -236,13 +245,11 @@ static void free_alloted(struct alloted_s **head)
 {
        struct alloted_s *cur;
 
-       if (head == NULL) {
+       if (!head)
                return;
-       }
 
        cur = *head;
-
-       while (cur != NULL) {
+       while (cur) {
                cur = cur->next;
                free((*head)->name);
                free(*head);
@@ -261,49 +268,55 @@ static void free_alloted(struct alloted_s **head)
  */
 static int get_alloted(char *me, char *intype, char *link, struct alloted_s 
**alloted)
 {
-       FILE *fin = fopen(LXC_USERNIC_CONF, "r");
-       char *line = NULL;
+       int n, ret;
        char name[100], type[100], br[100];
-       size_t len = 0;
-       int n, ret, count = 0;
        char **groups;
+       FILE *fin;
+
+       int count = 0;
+       size_t len = 0;
+       char *line = NULL;
 
+       fin = fopen(LXC_USERNIC_CONF, "r");
        if (!fin) {
-               fprintf(stderr, "Failed to open %s: %s\n", LXC_USERNIC_CONF,
-                       strerror(errno));
+               usernic_error("Failed to open \"%s\": %s.\n", LXC_USERNIC_CONF, 
strerror(errno));
                return -1;
        }
 
        groups = get_groupnames();
        while ((getline(&line, &len, fin)) != -1) {
                ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", name, 
type, br, &n);
-
                if (ret != 4)
                        continue;
 
                if (strlen(name) == 0)
                        continue;
 
-               if (strcmp(name, me) != 0)
-               {
+               if (strcmp(name, me)) {
                        if (name[0] != '@')
                                continue;
-                       if (!name_is_in_groupnames(name+1, groups))
+
+                       if (!name_is_in_groupnames(name + 1, groups))
                                continue;
                }
-               if (strcmp(type, intype) != 0)
+
+               if (strcmp(type, intype))
                        continue;
-               if (strcmp(link, br) != 0)
+
+               if (strcmp(link, br))
                        continue;
 
-               /* found the user or group with the appropriate settings, 
therefore finish the search.
-                * what to do if there are more than one applicable lines? not 
specified in the docs.
-                * since getline is implemented with realloc, we don't need to 
free line until exiting func.
+               /* Found the user or group with the appropriate settings,
+                * therefore finish the search. What to do if there are more
+                * than one applicable lines? not specified in the docs. Since
+                * getline is implemented with realloc, we don't need to free
+                * line until exiting func.
                 *
-                * if append_alloted returns NULL, e.g. due to a malloc error, 
we set count to 0 and break the loop,
-                * allowing cleanup and then exiting from main()
+                * If append_alloted returns NULL, e.g. due to a malloc error,
+                * we set count to 0 and break the loop, allowing cleanup and
+                * then exiting from main().
                 */
-               if (append_alloted(alloted, name, n) == NULL) {
+               if (!append_alloted(alloted, name, n)) {
                        count = 0;
                        break;
                }
@@ -314,20 +327,20 @@ static int get_alloted(char *me, char *intype, char 
*link, struct alloted_s **al
        fclose(fin);
        free(line);
 
-       // now return the total number of nics that this user can create
+       /* Now return the total number of nics that this user can create. */
        return count;
 }
 
 static char *get_eol(char *s, char *e)
 {
-       while (s<e && *s && *s != '\n')
+       while ((s < e) && *s && (*s != '\n'))
                s++;
        return s;
 }
 
 static char *get_eow(char *s, char *e)
 {
-       while (s<e && *s && !isblank(*s) && *s != '\n')
+       while ((s < e) && *s && !isblank(*s) && (*s != '\n'))
                s++;
        return s;
 }
@@ -336,24 +349,34 @@ static char *find_line(char *p, char *e, char *u, char 
*t, char *l)
 {
        char *p1, *p2, *ret;
 
-       while (p<e  && (p1 = get_eol(p, e)) < e) {
+       while ((p < e) && (p1 = get_eol(p, e)) < e) {
                ret = p;
                if (*p == '#')
                        goto next;
-               while (p<e && isblank(*p)) p++;
+
+               while ((p < e) && isblank(*p))
+                       p++;
+
                p2 = get_eow(p, e);
-               if (!p2 || p2-p != strlen(u) || strncmp(p, u, strlen(u)) != 0)
+               if (!p2 || ((size_t)(p2 - p)) != strlen(u) || strncmp(p, u, 
strlen(u)))
                        goto next;
-               p = p2+1;
-               while (p<e && isblank(*p)) p++;
+
+               p = p2 + 1;
+               while ((p < e) && isblank(*p))
+                       p++;
+
                p2 = get_eow(p, e);
-               if (!p2 || p2-p != strlen(t) || strncmp(p, t, strlen(t)) != 0)
+               if (!p2 || ((size_t)(p2 - p)) != strlen(t) || strncmp(p, t, 
strlen(t)))
                        goto next;
-               p = p2+1;
-               while (p<e && isblank(*p)) p++;
+
+               p = p2 + 1;
+               while ((p < e) && isblank(*p))
+                       p++;
+
                p2 = get_eow(p, e);
-               if (!p2 || p2-p != strlen(l) || strncmp(p, l, strlen(l)) != 0)
+               if (!p2 || ((size_t)(p2 - p)) != strlen(l) || strncmp(p, l, 
strlen(l)))
                        goto next;
+
                return ret;
 next:
                p = p1 + 1;
@@ -368,14 +391,17 @@ static bool nic_exists(char *nic)
        int ret;
        struct stat sb;
 
-       if (strcmp(nic, "none") == 0)
+       if (!strcmp(nic, "none"))
                return true;
+
        ret = snprintf(path, MAXPATHLEN, "/sys/class/net/%s", nic);
-       if (ret < 0 || ret >= MAXPATHLEN) // should never happen!
+       if (ret < 0 || ret >= MAXPATHLEN)
                return false;
+
        ret = stat(path, &sb);
-       if (ret != 0)
+       if (ret < 0)
                return false;
+
        return true;
 }
 
@@ -385,68 +411,81 @@ static int instantiate_veth(char *n1, char **n2)
 
        err = snprintf(*n2, IFNAMSIZ, "%sp", n1);
        if (err < 0 || err >= IFNAMSIZ) {
-               fprintf(stderr, "nic name too long\n");
+               usernic_error("%s\n", "Could not create nic name.");
                return -1;
        }
 
        err = lxc_veth_create(n1, *n2);
        if (err) {
-               fprintf(stderr, "failed to create %s-%s : %s\n", n1, *n2,
-                     strerror(-err));
+               usernic_error("Failed to create %s-%s : %s.\n", n1, *n2, 
strerror(-err));
                return -1;
        }
 
-       /* 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 */
+       /* 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(n1);
-       if (err) {
-               fprintf(stderr, "failed to change mac address of host interface 
'%s' : %s\n",
-                       n1, strerror(-err));
-       }
+       if (err)
+               usernic_error("Failed to change mac address of host interface "
+                             "%s : %s.\n",
+                             n1, strerror(-err));
 
        return netdev_set_flag(n1, IFF_UP);
 }
 
 static int get_mtu(char *name)
 {
-       int idx = if_nametoindex(name);
+       int idx;
+
+       idx = if_nametoindex(name);
        return netdev_get_mtu(idx);
 }
 
 static bool create_nic(char *nic, char *br, int pid, char **cnic)
 {
        char *veth1buf, *veth2buf;
+       int mtu, ret;
+
        veth1buf = alloca(IFNAMSIZ);
        veth2buf = alloca(IFNAMSIZ);
-       int ret, mtu;
+       if (!veth1buf || !veth2buf) {
+               usernic_error("Failed allocate memory: %s.\n", strerror(errno));
+               return false;
+       }
 
        ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
        if (ret < 0 || ret >= IFNAMSIZ) {
-               fprintf(stderr, "host nic name too long\n");
+               usernic_error("%s", "Could not create nic name.\n");
                return false;
        }
 
        /* create the nics */
        if (instantiate_veth(veth1buf, &veth2buf) < 0) {
-               fprintf(stderr, "Error creating veth tunnel\n");
+               usernic_error("%s", "Error creating veth tunnel.\n");
                return false;
        }
 
-       if (strcmp(br, "none") != 0) {
+       if (strcmp(br, "none")) {
                /* copy the bridge's mtu to both ends */
                mtu = get_mtu(br);
-               if (mtu != -1) {
-                       if (lxc_netdev_set_mtu(veth1buf, mtu) < 0 ||
-                                       lxc_netdev_set_mtu(veth2buf, mtu) < 0) {
-                               fprintf(stderr, "Failed setting mtu\n");
+               if (mtu > 0) {
+                       ret = lxc_netdev_set_mtu(veth1buf, mtu);
+                       if (ret < 0) {
+                               usernic_error("Failed to set mtu to %d on 
%s.\n", mtu, veth1buf);
+                               goto out_del;
+                       }
+
+                       ret = lxc_netdev_set_mtu(veth2buf, mtu);
+                       if (ret < 0) {
+                               usernic_error("Failed to set mtu to %d on 
%s.\n", mtu, veth2buf);
                                goto out_del;
                        }
                }
 
                /* attach veth1 to bridge */
-               if (lxc_bridge_attach(lxcpath, lxcname, br, veth1buf) < 0) {
-                       fprintf(stderr, "Error attaching %s to %s\n", veth1buf, 
br);
+               ret = lxc_bridge_attach(lxcpath, lxcname, br, veth1buf);
+               if (ret < 0) {
+                       usernic_error("Error attaching %s to %s.\n", veth1buf, 
br);
                        goto out_del;
                }
        }
@@ -454,10 +493,16 @@ static bool create_nic(char *nic, char *br, int pid, char 
**cnic)
        /* pass veth2 to target netns */
        ret = lxc_netdev_move_by_name(veth2buf, pid, NULL);
        if (ret < 0) {
-               fprintf(stderr, "Error moving %s to netns %d\n", veth2buf, pid);
+               usernic_error("Error moving %s to network namespace of %d.\n", 
veth2buf, pid);
                goto out_del;
        }
+
        *cnic = strdup(veth2buf);
+       if (!*cnic) {
+               usernic_error("Failed to copy string \"%s\".\n", veth2buf);
+               return false;
+       }
+
        return true;
 
 out_del:
@@ -467,29 +512,34 @@ out_del:
 
 /*
  * Get a new nic.
- * *dest will container the name (vethXXXXXX) which is attached
+ * *dest will contain the name (vethXXXXXX) which is attached
  * on the host to the lxc bridge
  */
 static bool get_new_nicname(char **dest, char *br, int pid, char **cnic)
 {
+       int ret;
        char template[IFNAMSIZ];
-       snprintf(template, sizeof(template), "vethXXXXXX");
-       *dest = lxc_mkifname(template);
 
-       if (!create_nic(*dest, br, pid, cnic)) {
+       ret = snprintf(template, sizeof(template), "vethXXXXXX");
+       if (ret < 0 || (size_t)ret >= sizeof(template))
                return false;
-       }
+
+       *dest = lxc_mkifname(template);
+       if (!create_nic(*dest, br, pid, cnic))
+               return false;
+
        return true;
 }
 
 static bool get_nic_from_line(char *p, char **nic)
 {
-       char user[100], type[100], br[100];
        int ret;
+       char user[100], type[100], br[100];
 
        ret = sscanf(p, "%99[^ \t\n] %99[^ \t\n] %99[^ \t\n] %99[^ \t\n]", 
user, type, br, *nic);
        if (ret != 4)
                return false;
+
        return true;
 }
 
@@ -501,35 +551,42 @@ struct entry_line {
 
 static bool cull_entries(int fd, char *me, char *t, char *br)
 {
-       struct stat sb;
-       char *buf, *p, *e, *nic;
+       int i, n = 0;
        off_t len;
+       char *buf, *p, *e, *nic;
+       struct stat sb;
        struct entry_line *entry_lines = NULL;
-       int i, n = 0;
 
        nic = alloca(100);
+       if (!nic)
+               return false;
 
        if (fstat(fd, &sb) < 0) {
-               fprintf(stderr, "Failed to fstat: %s\n", strerror(errno));
+               usernic_error("Failed to fstat: %s.\n", strerror(errno));
                return false;
        }
+
        len = sb.st_size;
        if (len == 0)
                return true;
+
        buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if (buf == MAP_FAILED) {
-               fprintf(stderr, "Failed to create mapping: %s\n", 
strerror(errno));
+               usernic_error("Failed to establish shared memory mapping: 
%s.\n", strerror(errno));
                return false;
        }
 
        p = buf;
        e = buf + len;
-       while ((p = find_line(p, e, me, t, br)) != NULL) {
-               struct entry_line *newe = realloc(entry_lines, 
sizeof(*entry_lines)*(n+1));
+       while ((p = find_line(p, e, me, t, br))) {
+               struct entry_line *newe;
+
+               newe = realloc(entry_lines, sizeof(*entry_lines) * (n + 1));
                if (!newe) {
                        free(entry_lines);
                        return false;
                }
+
                entry_lines = newe;
                entry_lines[n].start = p;
                entry_lines[n].len = get_eol(p, e) - entry_lines[n].start;
@@ -537,35 +594,43 @@ static bool cull_entries(int fd, char *me, char *t, char 
*br)
                n++;
                if (!get_nic_from_line(p, &nic))
                        continue;
+
                if (nic && !nic_exists(nic))
-                       entry_lines[n-1].keep = false;
-               p += entry_lines[n-1].len + 1;
+                       entry_lines[n - 1].keep = false;
+
+               p += entry_lines[n - 1].len + 1;
                if (p >= e)
                        break;
-       }
+       }
+
        p = buf;
-       for (i=0; i<n; i++) {
+       for (i = 0; i < n; i++) {
                if (!entry_lines[i].keep)
                        continue;
+
                memcpy(p, entry_lines[i].start, entry_lines[i].len);
                p += entry_lines[i].len;
                *p = '\n';
                p++;
        }
        free(entry_lines);
+
        munmap(buf, sb.st_size);
-       if (ftruncate(fd, p-buf))
-               fprintf(stderr, "Failed to set new file size\n");
+       if (ftruncate(fd, p - buf))
+               usernic_error("Failed to set new file size: %s.\n", 
strerror(errno));
+
        return true;
 }
 
 static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
 {
-       char *e = &buf[len];
+       char *e;
        int count = 0;
-       while ((buf = find_line(buf, e, me, t, br)) != NULL) {
+
+       e = &buf[len];
+       while ((buf = find_line(buf, e, me, t, br))) {
                count++;
-               buf = get_eol(buf, e)+1;
+               buf = get_eol(buf, e) + 1;
                if (buf >= e)
                        break;
        }
@@ -577,16 +642,19 @@ static int count_entries(char *buf, off_t len, char *me, 
char *t, char *br)
  * The dbfile has lines of the format:
  * user type bridge nicname
  */
-static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid, char 
*intype, char *br, int allowed, char **nicname, char **cnic)
+static bool get_nic_if_avail(int fd, struct alloted_s *names, int pid,
+                            char *intype, char *br, int allowed,
+                            char **nicname, char **cnic)
 {
+       int ret;
        off_t len, slen;
+       char *newline, *owner;
        struct stat sb;
-       char *buf = NULL, *newline;
-       int ret, count = 0;
-       char *owner;
        struct alloted_s *n;
+       int count = 0;
+       char *buf = NULL;
 
-       for (n=names; n!=NULL; n=n->next)
+       for (n = names; n != NULL; n = n->next)
                cull_entries(fd, n->name, intype, br);
 
        if (allowed == 0)
@@ -595,19 +663,20 @@ static bool get_nic_if_avail(int fd, struct alloted_s 
*names, int pid, char *int
        owner = names->name;
 
        if (fstat(fd, &sb) < 0) {
-               fprintf(stderr, "Failed to fstat: %s\n", strerror(errno));
+               usernic_error("Failed to fstat: %s.\n", strerror(errno));
                return false;
        }
+
        len = sb.st_size;
-       if (len != 0) {
+       if (len > 0) {
                buf = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
                if (buf == MAP_FAILED) {
-                       fprintf(stderr, "Failed to create mapping\n");
+                       usernic_error("Failed to establish shared memory 
mapping: %s.\n", strerror(errno));
                        return false;
                }
 
                owner = NULL;
-               for (n=names; n!=NULL; n=n->next) {
+               for (n = names; n != NULL; n = n->next) {
                        count = count_entries(buf, len, n->name, intype, br);
 
                        if (count >= n->allowed)
@@ -623,115 +692,177 @@ static bool get_nic_if_avail(int fd, struct alloted_s 
*names, int pid, char *int
 
        if (!get_new_nicname(nicname, br, pid, cnic))
                return false;
+
        /* owner  ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
        slen = strlen(owner) + strlen(intype) + strlen(br) + strlen(*nicname) + 
5;
        newline = alloca(slen);
+       if (!newline) {
+               usernic_error("Failed allocate memory: %s.\n", strerror(errno));
+               return false;
+       }
+
        ret = snprintf(newline, slen, "%s %s %s %s\n", owner, intype, br, 
*nicname);
        if (ret < 0 || ret >= slen) {
                if (lxc_netdev_delete_by_name(*nicname) != 0)
-                       fprintf(stderr, "Error unlinking %s!\n", *nicname);
+                       usernic_error("Error unlinking %s.\n", *nicname);
                return false;
        }
        if (len)
                munmap(buf, len);
+
        if (ftruncate(fd, len + slen))
-               fprintf(stderr, "Failed to set new file size\n");
+               usernic_error("Failed to set new file size: %s.\n", 
strerror(errno));
+
        buf = mmap(NULL, len + slen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        if (buf == MAP_FAILED) {
-               fprintf(stderr, "Failed to create mapping after extending: 
%s\n", strerror(errno));
+               usernic_error("Failed to establish shared memory mapping: 
%s.\n", strerror(errno));
                if (lxc_netdev_delete_by_name(*nicname) != 0)
-                       fprintf(stderr, "Error unlinking %s!\n", *nicname);
+                       usernic_error("Error unlinking %s.\n", *nicname);
                return false;
        }
-       strcpy(buf+len, newline);
-       munmap(buf, len+slen);
+
+       strcpy(buf + len, newline);
+       munmap(buf, len + slen);
+
        return true;
 }
 
 static bool create_db_dir(char *fnam)
 {
-       char *p = alloca(strlen(fnam)+1);
+       char *p;
 
+       p = alloca(strlen(fnam) + 1);
        strcpy(p, fnam);
        fnam = p;
        p = p + 1;
+
 again:
-       while (*p && *p != '/') p++;
+       while (*p && *p != '/')
+               p++;
        if (!*p)
                return true;
+
        *p = '\0';
        if (mkdir(fnam, 0755) && errno != EEXIST) {
-               fprintf(stderr, "failed to create %s\n", fnam);
+               usernic_error("Failed to create %s: %s.\n", fnam, 
strerror(errno));
                *p = '/';
                return false;
        }
        *(p++) = '/';
+
        goto again;
 }
 
 #define VETH_DEF_NAME "eth%d"
-
 static int rename_in_ns(int pid, char *oldname, char **newnamep)
 {
-       int fd = -1, ofd = -1, ret, ifindex = -1;
+       uid_t ruid, suid, euid;
+       int fret = -1;
+       int fd = -1, ifindex = -1, ofd = -1, ret;
        bool grab_newname = false;
 
        ofd = lxc_preserve_ns(getpid(), "net");
        if (ofd < 0) {
-               fprintf(stderr, "Failed opening network namespace path for 
'%d'.", getpid());
-               return -1;
+               usernic_error("Failed opening network namespace path for 
'%d'.", getpid());
+               return fret;
        }
 
        fd = lxc_preserve_ns(pid, "net");
        if (fd < 0) {
-               fprintf(stderr, "Failed opening network namespace path for 
'%d'.", pid);
-               return -1;
+               usernic_error("Failed opening network namespace path for 
'%d'.", pid);
+               goto do_partial_cleanup;
+       }
+
+       ret = getresuid(&ruid, &euid, &suid);
+       if (ret < 0) {
+               usernic_error("Failed to retrieve real, effective, and saved "
+                             "user IDs: %s\n",
+                             strerror(errno));
+               goto do_partial_cleanup;
+       }
+
+       ret = setns(fd, CLONE_NEWNET);
+       close(fd);
+       fd = -1;
+       if (ret < 0) {
+               usernic_error("Failed to setns() to the network namespace of "
+                             "the container with PID %d: %s.\n",
+                             pid, strerror(errno));
+               goto do_partial_cleanup;
        }
 
-       if (setns(fd, 0) < 0) {
-               fprintf(stderr, "setns to container network namespace\n");
-               goto out_err;
+       ret = setresuid(ruid, ruid, 0);
+       if (ret < 0) {
+               usernic_error("Failed to drop privilege by setting effective "
+                             "user id and real user id to %d, and saved user "
+                             "ID to 0: %s.\n",
+                             ruid, strerror(errno));
+               // COMMENT(brauner): It's ok to jump to do_full_cleanup here
+               // since setresuid() will succeed when trying to set real,
+               // effective, and saved to values they currently have.
+               goto do_full_cleanup;
        }
-       close(fd); fd = -1;
+
        if (!*newnamep) {
                grab_newname = true;
                *newnamep = VETH_DEF_NAME;
-               if (!(ifindex = if_nametoindex(oldname))) {
-                       fprintf(stderr, "failed to get netdev index\n");
-                       goto out_err;
+
+               ifindex = if_nametoindex(oldname);
+               if (!ifindex) {
+                       usernic_error("Failed to get netdev index: %s.\n", 
strerror(errno));
+                       goto do_full_cleanup;
                }
        }
-       if ((ret = lxc_netdev_rename_by_name(oldname, *newnamep)) < 0) {
-               fprintf(stderr, "Error %d renaming netdev %s to %s in 
container\n", ret, oldname, *newnamep);
-               goto out_err;
+
+       ret = lxc_netdev_rename_by_name(oldname, *newnamep);
+       if (ret < 0) {
+               usernic_error("Error %d renaming netdev %s to %s in 
container.\n", ret, oldname, *newnamep);
+               goto do_full_cleanup;
        }
+
        if (grab_newname) {
-               char ifname[IFNAMSIZ], *namep = ifname;
+               char ifname[IFNAMSIZ];
+               char *namep = ifname;
+
                if (!if_indextoname(ifindex, namep)) {
-                       fprintf(stderr, "Failed to get new netdev name\n");
-                       goto out_err;
+                       usernic_error("Failed to get new netdev name: %s.\n", 
strerror(errno));
+                       goto do_full_cleanup;
                }
+
                *newnamep = strdup(namep);
                if (!*newnamep)
-                       goto out_err;
+                       goto do_full_cleanup;
        }
-       if (setns(ofd, 0) < 0) {
-               fprintf(stderr, "Error returning to original netns\n");
-               close(ofd);
-               return -1;
+
+       fret = 0;
+
+do_full_cleanup:
+       ret = setresuid(ruid, euid, suid);
+       if (ret < 0) {
+               usernic_error("Failed to restore privilege by setting effective 
"
+                             "user id to %d, real user id to %d, and saved 
user "
+                             "ID to %d: %s.\n",
+                             ruid, euid, suid, strerror(errno));
+               fret = -1;
+               // COMMENT(brauner): setns() should fail if setresuid() doesn't
+               // succeed but there's no harm in falling through; keeps the
+               // code cleaner.
        }
-       close(ofd);
 
-       return 0;
+       ret = setns(ofd, CLONE_NEWNET);
+       if (ret < 0) {
+               usernic_error("Failed to setns() to original network namespace "
+                             "of PID %d: %s.\n",
+                             ofd, strerror(errno));
+               fret = -1;
+       }
 
-out_err:
-       if (ofd >= 0)
-               close(ofd);
-       if (setns(ofd, 0) < 0)
-               fprintf(stderr, "Error returning to original network 
namespace\n");
+do_partial_cleanup:
        if (fd >= 0)
                close(fd);
-       return -1;
+       close(ofd);
+
+       return fret;
 }
 
 /*
@@ -747,61 +878,78 @@ static bool may_access_netns(int pid)
        bool may_access = false;
 
        ret = getresuid(&ruid, &euid, &suid);
-       if (ret) {
-               fprintf(stderr, "Failed to get my uids: %s\n", strerror(errno));
+       if (ret < 0) {
+               usernic_error("Failed to retrieve real, effective, and saved "
+                             "user IDs: %s\n",
+                             strerror(errno));
                return false;
        }
+
        ret = setresuid(ruid, ruid, euid);
-       if (ret) {
-               fprintf(stderr, "Failed to set temp uids to (%d,%d,%d): %s\n",
-                               (int)ruid, (int)ruid, (int)euid, 
strerror(errno));
+       if (ret < 0) {
+               usernic_error("Failed to drop privilege by setting effective "
+                             "user id and real user id to %d, and saved user "
+                             "ID to %d: %s.\n",
+                             ruid, euid, strerror(errno));
                return false;
        }
+
        ret = snprintf(s, 200, "/proc/%d/ns/net", pid);
-       if (ret < 0 || ret >= 200)  // can't happen
+       if (ret < 0 || ret >= 200)
                return false;
+
        ret = access(s, R_OK);
-       if (ret) {
-               fprintf(stderr, "Uid %d may not access %s: %s\n",
-                               (int)ruid, s, strerror(errno));
+       may_access = true;
+       if (ret < 0)  {
+               may_access = false;
+               usernic_error("Uid %d may not access %s: %s\n", (int)ruid, s, 
strerror(errno));
        }
-       may_access = ret == 0;
+
        ret = setresuid(ruid, euid, suid);
-       if (ret) {
-               fprintf(stderr, "Failed to restore uids to (%d,%d,%d): %s\n",
-                               (int)ruid, (int)euid, (int)suid, 
strerror(errno));
+       if (ret < 0) {
+               usernic_error("Failed to restore user id to %d, real user id "
+                             "to %d, and saved user ID to %d: %s.\n",
+                             ruid, euid, suid, strerror(errno));
                may_access = false;
        }
+
        return may_access;
 }
 
 int main(int argc, char *argv[])
 {
        int n, fd;
-       bool gotone = false;
        char *me;
-       char *nicname = alloca(40);
-       char *cnic = NULL; // created nic name in container is returned here.
-       char *vethname = NULL;
+       char *nicname;
        int pid;
+       char *cnic = NULL; /* Created nic name in container is returned here. */
+       char *vethname = NULL;
+       bool gotone = false;
        struct alloted_s *alloted = NULL;
 
+       nicname = alloca(40);
+       if (!nicname) {
+               usernic_error("Failed allocate memory: %s.\n", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
        /* set a sane env, because we are setuid-root */
        if (clearenv() < 0) {
-               fprintf(stderr, "Failed to clear environment");
-               exit(1);
+               usernic_error("%s", "Failed to clear environment.\n");
+               exit(EXIT_FAILURE);
        }
        if (setenv("PATH", 
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1) < 0) {
-               fprintf(stderr, "Failed to set PATH, exiting\n");
-               exit(1);
+               usernic_error("%s", "Failed to set PATH, exiting.\n");
+               exit(EXIT_FAILURE);
        }
        if ((me = get_username()) == NULL) {
-               fprintf(stderr, "Failed to get username\n");
-               exit(1);
+               usernic_error("%s", "Failed to get username.\n");
+               exit(EXIT_FAILURE);
        }
 
        if (argc < 6)
                usage(argv[0], true);
+
        if (argc >= 7)
                vethname = argv[6];
 
@@ -809,26 +957,25 @@ int main(int argc, char *argv[])
        lxcname = argv[2];
 
        errno = 0;
-       pid = (int) strtol(argv[3], NULL, 10);
+       pid = strtol(argv[3], NULL, 10);
        if (errno) {
-               fprintf(stderr, "Could not read pid: %s\n", argv[1]);
-               exit(1);
+               usernic_error("Could not read pid: %s.\n", argv[1]);
+               exit(EXIT_FAILURE);
        }
 
        if (!create_db_dir(LXC_USERNIC_DB)) {
-               fprintf(stderr, "Failed to create directory for db file\n");
-               exit(1);
+               usernic_error("%s", "Failed to create directory for db 
file.\n");
+               exit(EXIT_FAILURE);
        }
 
        if ((fd = open_and_lock(LXC_USERNIC_DB)) < 0) {
-               fprintf(stderr, "Failed to lock %s\n", LXC_USERNIC_DB);
-               exit(1);
+               usernic_error("Failed to lock %s.\n", LXC_USERNIC_DB);
+               exit(EXIT_FAILURE);
        }
 
        if (!may_access_netns(pid)) {
-               fprintf(stderr, "User %s may not modify netns for pid %d\n",
-                       me, pid);
-               exit(1);
+               usernic_error("User %s may not modify netns for pid %d.\n", me, 
pid);
+               exit(EXIT_FAILURE);
        }
 
        n = get_alloted(me, argv[4], argv[5], &alloted);
@@ -838,17 +985,21 @@ int main(int argc, char *argv[])
        close(fd);
        free_alloted(&alloted);
        if (!gotone) {
-               fprintf(stderr, "Quota reached\n");
-               exit(1);
+               usernic_error("%s", "Quota reached.\n");
+               exit(EXIT_FAILURE);
        }
 
-       // Now rename the link
+       /* Now rename the link. */
        if (rename_in_ns(pid, cnic, &vethname) < 0) {
-               fprintf(stderr, "Failed to rename the link\n");
-               exit(1);
+               usernic_error("%s", "Failed to rename the link.\n");
+               if (lxc_netdev_delete_by_name(cnic) < 0)
+                       usernic_error("Failed to delete link \"%s\" the link. 
Manual cleanup needed.\n", cnic);
+               exit(EXIT_FAILURE);
        }
 
-       // write the name of the interface pair to the stdout - like 
eth0:veth9MT2L4
+       /* Write the name of the interface pair to the stdout - like
+        * eth0:veth9MT2L4.
+        */
        fprintf(stdout, "%s:%s\n", vethname, nicname);
-       exit(0);
+       exit(EXIT_SUCCESS);
 }
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 0dbbf2c..dc1d955 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -31,6 +31,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <arpa/inet.h>
+#include <sys/sysmacros.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
 #include <sys/syscall.h>
@@ -64,9 +65,6 @@
 #ifdef MAJOR_IN_MKDEV
 #    include <sys/mkdev.h>
 #endif
-#ifdef MAJOR_IN_SYSMACROS
-#    include <sys/sysmacros.h>
-#endif
 
 #if HAVE_IFADDRS_H
 #include <ifaddrs.h>
@@ -4372,7 +4370,10 @@ int list_active_containers(const char *lxcpath, char 
***nret,
                *p2 = '\0';
 
                if (is_hashed) {
-                       if (strncmp(lxcpath, lxc_cmd_get_lxcpath(p), 
lxcpath_len) != 0)
+                       char *recvpath = lxc_cmd_get_lxcpath(p);
+                       if (!recvpath)
+                               continue;
+                       if (strncmp(lxcpath, recvpath, lxcpath_len) != 0)
                                continue;
                        p = lxc_cmd_get_name(p);
                }
diff --git a/src/lxc/monitor.c b/src/lxc/monitor.c
index d9b3e21..1758402 100644
--- a/src/lxc/monitor.c
+++ b/src/lxc/monitor.c
@@ -153,36 +153,52 @@ int lxc_monitor_close(int fd)
        return close(fd);
 }
 
+/* Enforces \0-termination for the abstract unix socket. This is not required
+ * but allows us to print it out.
+ *
+ * Older version of liblxc only allowed for 105 bytes to be used for the
+ * abstract unix domain socket name because the code for our abstract unix
+ * socket handling performed invalid checks. Since we \0-terminate we could now
+ * have a maximum of 106 chars. But to not break backwards compatibility we 
keep
+ * the limit at 105.
+ */
 int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr) {
        size_t len;
        int ret;
-       char *sockname;
        char *path;
        uint64_t hash;
 
        /* addr.sun_path is only 108 bytes, so we hash the full name and
         * then append as much of the name as we can fit.
         */
-       sockname = &addr->sun_path[1];
        memset(addr, 0, sizeof(*addr));
        addr->sun_family = AF_UNIX;
 
+       /* strlen("lxc/") + strlen("/monitor-sock") + 1 = 18 */
        len = strlen(lxcpath) + 18;
        path = alloca(len);
        ret = snprintf(path, len, "lxc/%s/monitor-sock", lxcpath);
        if (ret < 0 || (size_t)ret >= len) {
-               ERROR("Failed to create path for monitor.");
+               ERROR("failed to create name for monitor socket");
                return -1;
        }
 
+       /* Note: snprintf() will \0-terminate addr->sun_path on the 106th byte
+        * and so the abstract socket name has 105 "meaningful" characters. This
+        * is absolutely intentional. For further info read the comment for this
+        * function above!
+        */
        len = sizeof(addr->sun_path) - 1;
        hash = fnv_64a_buf(path, ret, FNV1A_64_INIT);
-       ret = snprintf(sockname, len, "lxc/%016" PRIx64 "/%s", hash, lxcpath);
-       if (ret < 0)
+       ret = snprintf(addr->sun_path, len, "@lxc/%016" PRIx64 "/%s", hash, 
lxcpath);
+       if (ret < 0) {
+               ERROR("failed to create hashed name for monitor socket");
                return -1;
+       }
 
-       sockname[sizeof(addr->sun_path)-3] = '\0';
-       INFO("Using monitor socket name \"%s\".", sockname);
+       /* replace @ with \0 */
+       addr->sun_path[0] = '\0';
+       INFO("using monitor socket name \"%s\" (length of socket name %zu must 
be <= %zu)", &addr->sun_path[1], strlen(&addr->sun_path[1]), 
sizeof(addr->sun_path) - 3);
 
        return 0;
 }
@@ -193,7 +209,8 @@ int lxc_monitor_open(const char *lxcpath)
        int fd;
        size_t retry;
        size_t len;
-       int ret = 0, backoff_ms[] = {10, 50, 100};
+       int ret = -1;
+       int backoff_ms[] = {10, 50, 100};
 
        if (lxc_monitor_sock_name(lxcpath, &addr) < 0)
                return -1;
@@ -201,28 +218,32 @@ int lxc_monitor_open(const char *lxcpath)
        fd = socket(PF_UNIX, SOCK_STREAM, 0);
        if (fd < 0) {
                ERROR("Failed to create socket: %s.", strerror(errno));
-               return -1;
+               return -errno;
        }
 
-       len = strlen(&addr.sun_path[1]) + 1;
+       len = strlen(&addr.sun_path[1]);
+       DEBUG("opening monitor socket %s with len %zu", &addr.sun_path[1], len);
        if (len >= sizeof(addr.sun_path) - 1) {
-               ret = -1;
                errno = ENAMETOOLONG;
+               ret = -errno;
+               ERROR("name of monitor socket too long (%zu bytes): %s", len, 
strerror(errno));
                goto on_error;
        }
 
        for (retry = 0; retry < sizeof(backoff_ms) / sizeof(backoff_ms[0]); 
retry++) {
-               ret = connect(fd, (struct sockaddr *)&addr, offsetof(struct 
sockaddr_un, sun_path) + len);
-               if (ret == 0 || errno != ECONNREFUSED)
+               fd = lxc_abstract_unix_connect(addr.sun_path);
+               if (fd < 0 || errno != ECONNREFUSED)
                        break;
-               ERROR("Failed to connect to monitor socket. Retrying in %d 
ms.", backoff_ms[retry]);
+               ERROR("Failed to connect to monitor socket. Retrying in %d ms: 
%s", backoff_ms[retry], strerror(errno));
                usleep(backoff_ms[retry] * 1000);
        }
 
-       if (ret < 0) {
+       if (fd < 0) {
+               ret = -errno;
                ERROR("Failed to connect to monitor socket: %s.", 
strerror(errno));
                goto on_error;
        }
+       ret = 0;
 
        return fd;
 
@@ -340,7 +361,7 @@ int lxc_monitord_spawn(const char *lxcpath)
 
                close(pipefd[0]);
 
-               DEBUG("Sucessfully synced with child process.");
+               DEBUG("Successfully synced with child process.");
                exit(EXIT_SUCCESS);
        }
 
@@ -366,7 +387,7 @@ int lxc_monitord_spawn(const char *lxcpath)
        DEBUG("Using pipe file descriptor %d for monitord.", pipefd[1]);
 
        execvp(args[0], args);
-       ERROR("Failed to exec lxc-monitord.");
+       SYSERROR("failed to exec lxc-monitord");
 
        exit(EXIT_FAILURE);
 }
diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c
index 83b1cb4..3b4d7ed 100644
--- a/src/lxc/seccomp.c
+++ b/src/lxc/seccomp.c
@@ -119,6 +119,7 @@ enum lxc_hostarch_t {
        lxc_seccomp_arch_all = 0,
        lxc_seccomp_arch_native,
        lxc_seccomp_arch_i386,
+       lxc_seccomp_arch_x32,
        lxc_seccomp_arch_amd64,
        lxc_seccomp_arch_arm,
        lxc_seccomp_arch_arm64,
@@ -152,6 +153,7 @@ int get_hostarch(void)
        }
        if (strcmp(uts.machine, "i686") == 0)
                return lxc_seccomp_arch_i386;
+       // no x32 kernels
        else if (strcmp(uts.machine, "x86_64") == 0)
                return lxc_seccomp_arch_amd64;
        else if (strncmp(uts.machine, "armv7", 5) == 0)
@@ -181,6 +183,7 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, 
uint32_t default_policy_
 
        switch(n_arch) {
        case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
+       case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break;
        case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
        case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
 #ifdef SCMP_ARCH_AARCH64
@@ -218,6 +221,11 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, 
uint32_t default_policy_
                seccomp_release(ctx);
                return NULL;
        }
+#ifdef SCMP_FLTATR_ATL_TSKIP
+       if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
+               WARN("Failed to turn on seccomp nop-skip, continuing");
+       }
+#endif
        ret = seccomp_arch_add(ctx, arch);
        if (ret != 0) {
                ERROR("Seccomp error %d (%s) adding arch: %d", ret,
@@ -336,7 +344,10 @@ static int parse_config_v2(FILE *f, char *line, struct 
lxc_conf *conf)
                compat_arch[0] = SCMP_ARCH_X86;
                compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386,
                                default_policy_action);
-               if (!compat_ctx[0])
+               compat_arch[1] = SCMP_ARCH_X32;
+               compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_x32,
+                               default_policy_action);
+               if (!compat_ctx[0] || !compat_ctx[1])
                        goto bad;
 #ifdef SCMP_ARCH_PPC
        } else if (native_arch == lxc_seccomp_arch_ppc64) {
@@ -390,6 +401,11 @@ static int parse_config_v2(FILE *f, char *line, struct 
lxc_conf *conf)
                        ERROR("Failed to turn off n-new-privs.");
                        return -1;
                }
+#ifdef SCMP_FLTATR_ATL_TSKIP
+               if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 
1)) {
+                       WARN("Failed to turn on seccomp nop-skip, continuing");
+               }
+#endif
        }
 
        while (fgets(line, 1024, f)) {
@@ -410,6 +426,13 @@ static int parse_config_v2(FILE *f, char *line, struct 
lxc_conf *conf)
                                        continue;
                                }
                                cur_rule_arch = lxc_seccomp_arch_i386;
+                       } else if (strcmp(line, "[x32]") == 0 ||
+                                  strcmp(line, "[X32]") == 0) {
+                               if (native_arch != lxc_seccomp_arch_amd64) {
+                                       cur_rule_arch = 
lxc_seccomp_arch_unknown;
+                                       continue;
+                               }
+                               cur_rule_arch = lxc_seccomp_arch_x32;
                        } else if (strcmp(line, "[X86_64]") == 0 ||
                                   strcmp(line, "[x86_64]") == 0) {
                                if (native_arch != lxc_seccomp_arch_amd64) {
@@ -704,7 +727,7 @@ int lxc_read_seccomp_config(struct lxc_conf *conf)
                return -1;
        }
 
-/* turn of no-new-privs.  We don't want it in lxc, and it breaks
+/* turn off no-new-privs.  We don't want it in lxc, and it breaks
  * with apparmor */
 #if HAVE_SCMP_FILTER_CTX
        check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, 
SCMP_FLTATR_CTL_NNP, 0);
@@ -715,6 +738,11 @@ int lxc_read_seccomp_config(struct lxc_conf *conf)
                ERROR("Failed to turn off n-new-privs.");
                return -1;
        }
+#ifdef SCMP_FLTATR_ATL_TSKIP
+       if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
+               WARN("Failed to turn on seccomp nop-skip, continuing");
+       }
+#endif
 
        f = fopen(conf->seccomp, "r");
        if (!f) {
diff --git a/src/lxc/start.c b/src/lxc/start.c
index c2c14a7..bca7f8e 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -46,7 +46,7 @@
 #include <sys/un.h>
 #include <sys/wait.h>
 
-#if HAVE_SYS_CAPABILITY_H
+#if HAVE_LIBCAP
 #include <sys/capability.h>
 #endif
 
@@ -319,7 +319,7 @@ static int signal_handler(int fd, uint32_t events, void 
*data,
         * by a process different from the container init.
         */
        if (siginfo.ssi_pid != *pid) {
-               WARN("Invalid pid for SIGCHLD. Received pid %d, expected pid 
%d.", siginfo.ssi_pid, *pid);
+               NOTICE("Received SIGCHLD from pid %d instead of container init 
%d.", siginfo.ssi_pid, *pid);
                return init_died ? 1 : 0;
        }
 
@@ -361,7 +361,7 @@ int lxc_poll(const char *name, struct lxc_handler *handler)
        }
 
        if (handler->conf->need_utmp_watch) {
-               #if HAVE_SYS_CAPABILITY_H
+               #if HAVE_LIBCAP
                if (lxc_utmp_mainloop_add(&descr, handler)) {
                        ERROR("Failed to add utmp handler to LXC mainloop.");
                        goto out_mainloop_open;
@@ -773,7 +773,7 @@ static int do_start(void *data)
                goto out_warn_father;
        }
 
-       #if HAVE_SYS_CAPABILITY_H
+       #if HAVE_LIBCAP
        if (handler->conf->need_utmp_watch) {
                if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
                        SYSERROR("Failed to remove the CAP_SYS_BOOT 
capability.");
@@ -873,7 +873,11 @@ static int do_start(void *data)
                 * further above. Only drop groups if we can, so ensure that we
                 * have necessary privilege.
                 */
-               have_cap_setgid = lxc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE);
+               #if HAVE_LIBCAP
+               have_cap_setgid = lxc_proc_cap_is_set(CAP_SETGID, 
CAP_EFFECTIVE);
+               #else
+               have_cap_setgid = false;
+               #endif
                if (lxc_list_empty(&handler->conf->id_map) && have_cap_setgid) {
                        if (lxc_setgroups(0, NULL) < 0)
                                goto out_warn_father;
@@ -1042,6 +1046,13 @@ void resolve_clone_flags(struct lxc_handler *handler)
                INFO("Inheriting a UTS namespace.");
 }
 
+/* lxc_spawn() performs crucial setup tasks and clone()s the new process which
+ * exec()s the requested container binary.
+ * Note that lxc_spawn() runs in the parent namespaces. Any operations 
performed
+ * right here should be double checked if they'd pose a security risk. (For
+ * example, any {u}mount() operations performed here will be reflected on the
+ * host!)
+ */
 static int lxc_spawn(struct lxc_handler *handler)
 {
        int failed_before_rename = 0;
@@ -1255,9 +1266,6 @@ static int lxc_spawn(struct lxc_handler *handler)
        if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_CGROUP))
                return -1;
 
-       if (detect_shared_rootfs())
-               umount2(handler->conf->rootfs.mount, MNT_DETACH);
-
        if (handler->ops->post_start(handler, handler->data))
                goto out_abort;
 
@@ -1308,7 +1316,7 @@ int __lxc_start(const char *name, struct lxc_conf *conf,
        handler->netnsfd = -1;
 
        if (must_drop_cap_sys_boot(handler->conf)) {
-               #if HAVE_SYS_CAPABILITY_H
+               #if HAVE_LIBCAP
                DEBUG("Dropping CAP_SYS_BOOT capability.");
                #else
                DEBUG("Not dropping CAP_SYS_BOOT capability as capabilities 
aren't supported.");
diff --git a/src/lxc/tools/lxc-checkconfig.in b/src/lxc/tools/lxc-checkconfig.in
index 61627e0..4182191 100644
--- a/src/lxc/tools/lxc-checkconfig.in
+++ b/src/lxc/tools/lxc-checkconfig.in
@@ -88,6 +88,24 @@ echo -n "Utsname namespace: " && is_enabled CONFIG_UTS_NS
 echo -n "Ipc namespace: " && is_enabled CONFIG_IPC_NS yes
 echo -n "Pid namespace: " && is_enabled CONFIG_PID_NS yes
 echo -n "User namespace: " && is_enabled CONFIG_USER_NS
+if is_set CONFIG_USER_NS; then
+       if type newuidmap > /dev/null 2>&1; then
+               f=`type -P newuidmap`
+               if [ ! -u "${f}" ]; then
+                       echo "Warning: newuidmap is not setuid-root"
+               fi
+       else
+               echo "newuidmap is not installed"
+       fi
+       if type newgidmap > /dev/null 2>&1; then
+               f=`type -P newgidmap`
+               if [ ! -u "${f}" ]; then
+                       echo "Warning: newgidmap is not setuid-root"
+               fi
+       else
+               echo "newgidmap is not installed"
+       fi
+fi
 echo -n "Network namespace: " && is_enabled CONFIG_NET_NS
 if ([ $KVER_MAJOR -lt 4 ]) || ([ $KVER_MAJOR -eq 4 ] && [ $KVER_MINOR -lt 7 
]); then
        echo -n "Multiple /dev/pts instances: " && is_enabled 
DEVPTS_MULTIPLE_INSTANCES
diff --git a/src/lxc/tools/lxc-start-ephemeral.in 
b/src/lxc/tools/lxc-start-ephemeral.in
index 7e0c8ea..90d5f6f 100644
--- a/src/lxc/tools/lxc-start-ephemeral.in
+++ b/src/lxc/tools/lxc-start-ephemeral.in
@@ -28,6 +28,7 @@
 import argparse
 import gettext
 import lxc
+import locale
 import os
 import sys
 import subprocess
@@ -363,9 +364,14 @@ if os.path.exists("/proc/self/ns/pid"):
             if args.user:
                 username = args.user
 
-            line = subprocess.check_output(
-                ["getent", "passwd", username],
-                universal_newlines=True).rstrip("\n")
+            # This should really just use universal_newlines=True, but we do
+            # the decoding by hand instead for compatibility with Python
+            # 3.2; that used locale.getpreferredencoding() internally rather
+            # than locale.getpreferredencoding(False), and the former breaks
+            # here because we can't reload codecs at this point unless the
+            # container has the same version of Python installed.
+            line = subprocess.check_output(["getent", "passwd", username])
+            line = line.decode(locale.getpreferredencoding(False)).rstrip("\n")
             _, _, pw_uid, pw_gid, _, pw_dir, _ = line.split(":", 6)
             pw_uid = int(pw_uid)
             pw_gid = int(pw_gid)
diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
index ca66201..c5e319f 100644
--- a/src/lxc/tools/lxc_attach.c
+++ b/src/lxc/tools/lxc_attach.c
@@ -142,7 +142,7 @@ static int my_parser(struct lxc_arguments* args, int c, 
char* arg)
                 *
                 * then we memmove()
                 *
-                *      dest: del + 1 == ONT|PID
+                *      dest: del + 1 == OUNT|PID
                 *      src:  del + 3 == NT|PID
                 */
                while ((del = strstr(arg, "MOUNT")))
diff --git a/src/lxc/tools/lxc_execute.c b/src/lxc/tools/lxc_execute.c
index fae2dca..f26105a 100644
--- a/src/lxc/tools/lxc_execute.c
+++ b/src/lxc/tools/lxc_execute.c
@@ -166,5 +166,5 @@ int main(int argc, char *argv[])
 
        if (ret < 0)
                exit(EXIT_FAILURE);
-       exit(EXIT_SUCCESS);
+       exit(ret);
 }
diff --git a/src/lxc/tools/lxc_info.c b/src/lxc/tools/lxc_info.c
index 2888537..c977f29 100644
--- a/src/lxc/tools/lxc_info.c
+++ b/src/lxc/tools/lxc_info.c
@@ -204,7 +204,7 @@ static void print_net_stats(struct lxc_container *c)
 static void print_stats(struct lxc_container *c)
 {
        int i, ret;
-       char buf[256];
+       char buf[4096];
 
        ret = c->get_cgroup_item(c, "cpuacct.usage", buf, sizeof(buf));
        if (ret > 0 && ret < sizeof(buf)) {
diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c
index 363d3d2..63053b1 100644
--- a/src/lxc/tools/lxc_ls.c
+++ b/src/lxc/tools/lxc_ls.c
@@ -356,7 +356,7 @@ static int ls_get(struct ls **m, size_t *size, const struct 
lxc_arguments *args,
        }
 
        /* Do not do more work than is necessary right from the start. */
-       if (args->ls_active || (args->ls_active && args->ls_frozen))
+       if (args->ls_active || args->ls_frozen)
                num = list_active_containers(path, &containers, NULL);
        else
                num = list_all_containers(path, &containers, NULL);
diff --git a/src/lxc/tools/lxc_top.c b/src/lxc/tools/lxc_top.c
index d8e7247..797ff3c 100644
--- a/src/lxc/tools/lxc_top.c
+++ b/src/lxc/tools/lxc_top.c
@@ -513,5 +513,5 @@ int main(int argc, char *argv[])
 err1:
        lxc_mainloop_close(&descr);
 out:
-       exit(EXIT_FAILURE);
+       exit(ret);
 }
diff --git a/src/lxc/tools/lxc_unshare.c b/src/lxc/tools/lxc_unshare.c
index 82c8244..a0f943f 100644
--- a/src/lxc/tools/lxc_unshare.c
+++ b/src/lxc/tools/lxc_unshare.c
@@ -225,7 +225,7 @@ int main(int argc, char *argv[])
         *
         * then we memmove()
         *
-        *      dest: del + 1 == ONT|PID
+        *      dest: del + 1 == OUNT|PID
         *      src:  del + 3 == NT|PID
         */
        while ((del = strstr(namespaces, "MOUNT")))
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 0227c32..778d4da 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1014,7 +1014,7 @@ int randseed(bool srand_it)
        /*
           srand pre-seed function based on /dev/urandom
           */
-       unsigned int seed=time(NULL)+getpid();
+       unsigned int seed = time(NULL) + getpid();
 
        FILE *f;
        f = fopen("/dev/urandom", "r");
@@ -1199,7 +1199,7 @@ bool detect_ramfs_rootfs(void)
        return false;
 }
 
-char *on_path(char *cmd, const char *rootfs) {
+char *on_path(const char *cmd, const char *rootfs) {
        char *path = NULL;
        char *entry = NULL;
        char *saveptr = NULL;
@@ -1405,11 +1405,8 @@ char *get_template_path(const char *t)
 }
 
 /*
- * Sets the process title to the specified title. Note:
- *   1. this function requires root to succeed
- *   2. it clears /proc/self/environ
- *   3. it may not succed (e.g. if title is longer than /proc/self/environ +
- *      the original title)
+ * Sets the process title to the specified title. Note that this may fail if
+ * the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
  */
 int setproctitle(char *title)
 {
@@ -1463,34 +1460,24 @@ int setproctitle(char *title)
        if (!tmp)
                return -1;
 
-       i = sscanf(tmp, "%lu %lu %lu %lu %lu %lu %lu",
+       i = sscanf(tmp, "%lu %lu %lu %*u %*u %lu %lu",
                &start_data,
                &end_data,
                &start_brk,
-               &arg_start,
-               &arg_end,
                &env_start,
                &env_end);
-       if (i != 7)
+       if (i != 5)
                return -1;
 
        /* Include the null byte here, because in the calculations below we
         * want to have room for it. */
        len = strlen(title) + 1;
 
-       /* If we don't have enough room by just overwriting the old proctitle,
-        * let's allocate a new one.
-        */
-       if (len > arg_end - arg_start) {
-               void *m;
-               m = realloc(proctitle, len);
-               if (!m)
-                       return -1;
-               proctitle = m;
-
-               arg_start = (unsigned long) proctitle;
-       }
+       proctitle = realloc(proctitle, len);
+       if (!proctitle)
+               return -1;
 
+       arg_start = (unsigned long) proctitle;
        arg_end = arg_start + len;
 
        brk_val = syscall(__NR_brk, 0);
@@ -1767,7 +1754,7 @@ int safe_mount(const char *src, const char *dest, const 
char *fstype,
  *
  * NOTE: not to be called from inside the container namespace!
  */
-int mount_proc_if_needed(const char *rootfs)
+int lxc_mount_proc_if_needed(const char *rootfs)
 {
        char path[MAXPATHLEN];
        char link[20];
@@ -1779,37 +1766,48 @@ int mount_proc_if_needed(const char *rootfs)
                SYSERROR("proc path name too long");
                return -1;
        }
+
        memset(link, 0, 20);
        linklen = readlink(path, link, 20);
        mypid = (int)getpid();
-       INFO("I am %d, /proc/self points to '%s'", mypid, link);
+       INFO("I am %d, /proc/self points to \"%s\"", mypid, link);
+
        ret = snprintf(path, MAXPATHLEN, "%s/proc", rootfs);
        if (ret < 0 || ret >= MAXPATHLEN) {
                SYSERROR("proc path name too long");
                return -1;
        }
-       if (linklen < 0) /* /proc not mounted */
+
+       /* /proc not mounted */
+       if (linklen < 0) {
+               if (mkdir(path, 0755) && errno != EEXIST)
+                       return -1;
                goto domount;
+       }
+
        if (lxc_safe_int(link, &link_to_pid) < 0)
                return -1;
+
+       /* wrong /procs mounted */
        if (link_to_pid != mypid) {
-               /* wrong /procs mounted */
-               umount2(path, MNT_DETACH); /* ignore failure */
+               /* ignore failure */
+               umount2(path, MNT_DETACH);
                goto domount;
        }
+
        /* the right proc is already mounted */
        return 0;
 
 domount:
-       if (!strcmp(rootfs,"")) /* rootfs is NULL */
+       /* rootfs is NULL */
+       if (!strcmp(rootfs,""))
                ret = mount("proc", path, "proc", 0, NULL);
        else
                ret = safe_mount("proc", path, "proc", 0, NULL, rootfs);
-
        if (ret < 0)
                return -1;
 
-       INFO("Mounted /proc in container for security transition");
+       INFO("mounted /proc in container for security transition");
        return 1;
 }
 
@@ -2083,3 +2081,157 @@ int lxc_setgroups(int size, gid_t list[])
 
        return 0;
 }
+
+static int lxc_get_unused_loop_dev_legacy(char *loop_name)
+{
+       struct dirent *dp;
+       struct loop_info64 lo64;
+       DIR *dir;
+       int dfd = -1, fd = -1, ret = -1;
+
+       dir = opendir("/dev");
+       if (!dir)
+               return -1;
+
+       while ((dp = readdir(dir))) {
+               if (!dp)
+                       break;
+
+               if (strncmp(dp->d_name, "loop", 4) != 0)
+                       continue;
+
+               dfd = dirfd(dir);
+               if (dfd < 0)
+                       continue;
+
+               fd = openat(dfd, dp->d_name, O_RDWR);
+               if (fd < 0)
+                       continue;
+
+               ret = ioctl(fd, LOOP_GET_STATUS64, &lo64);
+               if (ret < 0) {
+                       if (ioctl(fd, LOOP_GET_STATUS64, &lo64) == 0 ||
+                           errno != ENXIO) {
+                               close(fd);
+                               fd = -1;
+                               continue;
+                       }
+               }
+
+               ret = snprintf(loop_name, LO_NAME_SIZE, "/dev/%s", dp->d_name);
+               if (ret < 0 || ret >= LO_NAME_SIZE) {
+                       close(fd);
+                       fd = -1;
+                       continue;
+               }
+
+               break;
+       }
+
+       closedir(dir);
+
+       if (fd < 0)
+               return -1;
+
+       return fd;
+}
+
+static int lxc_get_unused_loop_dev(char *name_loop)
+{
+       int loop_nr, ret;
+       int fd_ctl = -1, fd_tmp = -1;
+
+       fd_ctl = open("/dev/loop-control", O_RDWR | O_CLOEXEC);
+       if (fd_ctl < 0)
+               return -ENODEV;
+
+       loop_nr = ioctl(fd_ctl, LOOP_CTL_GET_FREE);
+       if (loop_nr < 0)
+               goto on_error;
+
+       ret = snprintf(name_loop, LO_NAME_SIZE, "/dev/loop%d", loop_nr);
+       if (ret < 0 || ret >= LO_NAME_SIZE)
+               goto on_error;
+
+       fd_tmp = open(name_loop, O_RDWR | O_CLOEXEC);
+       if (fd_tmp < 0)
+               goto on_error;
+
+on_error:
+       close(fd_ctl);
+       return fd_tmp;
+}
+
+int lxc_prepare_loop_dev(const char *source, char *loop_dev, int flags)
+{
+       int ret;
+       struct loop_info64 lo64;
+       int fd_img = -1, fret = -1, fd_loop = -1;
+
+       fd_loop = lxc_get_unused_loop_dev(loop_dev);
+       if (fd_loop < 0) {
+               if (fd_loop == -ENODEV)
+                       fd_loop = lxc_get_unused_loop_dev_legacy(loop_dev);
+               else
+                       goto on_error;
+       }
+
+       fd_img = open(source, O_RDWR | O_CLOEXEC);
+       if (fd_img < 0)
+               goto on_error;
+
+       ret = ioctl(fd_loop, LOOP_SET_FD, fd_img);
+       if (ret < 0)
+               goto on_error;
+
+       memset(&lo64, 0, sizeof(lo64));
+       lo64.lo_flags = flags;
+
+       ret = ioctl(fd_loop, LOOP_SET_STATUS64, &lo64);
+       if (ret < 0)
+               goto on_error;
+
+       fret = 0;
+
+on_error:
+       if (fd_img >= 0)
+               close(fd_img);
+
+       if (fret < 0 && fd_loop >= 0) {
+               close(fd_loop);
+               fd_loop = -1;
+       }
+
+       return fd_loop;
+}
+
+int lxc_unstack_mountpoint(const char *path, bool lazy)
+{
+       int ret;
+       int umounts = 0;
+
+pop_stack:
+       ret = umount2(path, lazy ? MNT_DETACH : 0);
+       if (ret < 0) {
+               /* We consider anything else than EINVAL deadly to prevent going
+                * into an infinite loop. (The other alternative is constantly
+                * parsing /proc/self/mountinfo which is yucky and probably
+                * racy.)
+                */
+               if (errno != EINVAL)
+                       return -errno;
+       } else {
+               /* Just stop counting when this happens. That'd just be so
+                * stupid that we won't even bother trying to report back the
+                * correct value anymore.
+                */
+               if (umounts != INT_MAX)
+                       umounts++;
+               /* We succeeded in umounting. Make sure that there's no other
+                * mountpoint stacked underneath.
+                */
+               goto pop_stack;
+       }
+
+       return umounts;
+}
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index 2b56905..320aa6b 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -23,15 +23,19 @@
 #ifndef __LXC_UTILS_H
 #define __LXC_UTILS_H
 
+/* Properly support loop devices on 32bit systems. */
+#define _FILE_OFFSET_BITS 64
+
 #include "config.h"
 
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdbool.h>
+#include <unistd.h>
+#include <linux/loop.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
-#include <unistd.h>
 
 #include "initutils.h"
 
@@ -39,6 +43,7 @@
 /* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 
*/
 #define LXC_NUMSTRLEN64 21
 #define LXC_LINELEN 4096
+#define LXC_IDMAPLEN 4096
 
 /* returns 1 on success, 0 if there were any failures */
 extern int lxc_rmdir_onedev(char *path, const char *exclude);
@@ -163,6 +168,15 @@ static inline int signalfd(int fd, const sigset_t *mask, 
int flags)
 }
 #endif
 
+/* loop devices */
+#ifndef LO_FLAGS_AUTOCLEAR
+#define LO_FLAGS_AUTOCLEAR 4
+#endif
+
+#ifndef LOOP_CTL_GET_FREE
+#define LOOP_CTL_GET_FREE 0x4C82
+#endif
+
 /* Struct to carry child pid from lxc_popen() to lxc_pclose().
  * Not an opaque struct to allow direct access to the underlying FILE *
  * (i.e., struct lxc_popen_FILE *file; fgets(buf, sizeof(buf), file->f))
@@ -301,7 +315,7 @@ uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval);
 
 int detect_shared_rootfs(void);
 bool detect_ramfs_rootfs(void);
-char *on_path(char *cmd, const char *rootfs);
+char *on_path(const char *cmd, const char *rootfs);
 bool file_exists(const char *f);
 bool cgns_supported(void);
 char *choose_init(const char *rootfs);
@@ -312,7 +326,7 @@ char *get_template_path(const char *t);
 int setproctitle(char *title);
 int safe_mount(const char *src, const char *dest, const char *fstype,
                unsigned long flags, const void *data, const char *rootfs);
-int mount_proc_if_needed(const char *rootfs);
+int lxc_mount_proc_if_needed(const char *rootfs);
 int open_devnull(void);
 int set_stdfds(int fd);
 int null_stdfds(void);
@@ -331,4 +345,14 @@ int lxc_safe_long(const char *numstr, long int *converted);
 int lxc_switch_uid_gid(uid_t uid, gid_t gid);
 int lxc_setgroups(int size, gid_t list[]);
 
+/* Find an unused loop device and associate it with source. */
+int lxc_prepare_loop_dev(const char *source, char *loop_dev, int flags);
+
+/* Clear all mounts on a given node.
+ * >= 0 successfully cleared. The number returned is the number of umounts
+ *      performed.
+ * < 0  error umounting. Return -errno.
+ */
+int lxc_unstack_mountpoint(const char *path, bool lazy);
+
 #endif /* __LXC_UTILS_H */
diff --git a/src/lxc/version.h b/src/lxc/version.h
index 7ebf428..d65ed7e 100644
--- a/src/lxc/version.h
+++ b/src/lxc/version.h
@@ -26,8 +26,8 @@
 #define LXC_DEVEL 0
 #define LXC_VERSION_MAJOR 2
 #define LXC_VERSION_MINOR 0
-#define LXC_VERSION_MICRO 7
+#define LXC_VERSION_MICRO 8
 #define LXC_VERSION_ABI "1.2.0"
-#define LXC_VERSION "2.0.7"
+#define LXC_VERSION "2.0.8"
 
 #endif
diff --git a/src/python-lxc/lxc.c b/src/python-lxc/lxc.c
index 4f637d0..5f15072 100644
--- a/src/python-lxc/lxc.c
+++ b/src/python-lxc/lxc.c
@@ -353,7 +353,14 @@ LXC_get_global_config_item(PyObject *self, PyObject *args, 
PyObject *kwds)
 static PyObject *
 LXC_get_version(PyObject *self, PyObject *args)
 {
-    return PyUnicode_FromString(lxc_get_version());
+    const char *rv = NULL;
+
+    rv = lxc_get_version();
+    if (!rv) {
+        return PyUnicode_FromString("");
+    }
+
+    return PyUnicode_FromString(rv);
 }
 
 static PyObject *
@@ -407,6 +414,10 @@ LXC_list_containers(PyObject *self, PyObject *args, 
PyObject *kwds)
     /* Generate the tuple */
     list = PyTuple_New(list_count);
     for (i = 0; i < list_count; i++) {
+        if (!names[i]) {
+            continue;
+        }
+
         PyTuple_SET_ITEM(list, i, PyUnicode_FromString(names[i]));
         free(names[i]);
     }
@@ -451,7 +462,7 @@ Container_init(Container *self, PyObject *args, PyObject 
*kwds)
         Py_XDECREF(fs_config_path);
 
         PyErr_Format(PyExc_RuntimeError, "%s:%s:%d: error during init for 
container '%s'.",
-                       __FUNCTION__, __FILE__, __LINE__, name);
+            __FUNCTION__, __FILE__, __LINE__, name);
         return -1;
     }
 
@@ -473,8 +484,14 @@ Container_new(PyTypeObject *type, PyObject *args, PyObject 
*kwds)
 static PyObject *
 Container_config_file_name(Container *self, void *closure)
 {
-    return PyUnicode_FromString(
-                self->container->config_file_name(self->container));
+    char *rv = NULL;
+
+    rv = self->container->config_file_name(self->container);
+    if (!rv) {
+        return PyUnicode_FromString("");
+    }
+
+    return PyUnicode_FromString(rv);
 }
 
 static PyObject *
@@ -506,6 +523,10 @@ Container_init_pid(Container *self, void *closure)
 static PyObject *
 Container_name(Container *self, void *closure)
 {
+    if (!self->container->name) {
+        return PyUnicode_FromString("");
+    }
+
     return PyUnicode_FromString(self->container->name);
 }
 
@@ -522,7 +543,15 @@ Container_running(Container *self, void *closure)
 static PyObject *
 Container_state(Container *self, void *closure)
 {
-    return PyUnicode_FromString(self->container->state(self->container));
+    const char *rv = NULL;
+
+    rv = self->container->state(self->container);
+
+    if (!rv) {
+        return PyUnicode_FromString("");
+    }
+
+    return PyUnicode_FromString(rv);
 }
 
 /* Container Functions */
@@ -946,8 +975,15 @@ Container_get_config_item(Container *self, PyObject *args, 
PyObject *kwds)
 static PyObject *
 Container_get_config_path(Container *self, PyObject *args, PyObject *kwds)
 {
-    return PyUnicode_FromString(
-                self->container->get_config_path(self->container));
+    const char *rv = NULL;
+
+    rv = self->container->get_config_path(self->container);
+
+    if (!rv) {
+        return PyUnicode_FromString("");
+    }
+
+    return PyUnicode_FromString(rv);
 }
 
 static PyObject *
@@ -1011,6 +1047,11 @@ Container_get_interfaces(Container *self)
     /* Add the entries to the tuple and free the memory */
     i = 0;
     while (interfaces[i]) {
+        if (!interfaces[i]) {
+            i++;
+            continue;
+        }
+
         PyObject *unicode = PyUnicode_FromString(interfaces[i]);
         if (!unicode) {
             Py_DECREF(ret);
@@ -1066,6 +1107,11 @@ Container_get_ips(Container *self, PyObject *args, 
PyObject *kwds)
     /* Add the entries to the tuple and free the memory */
     i = 0;
     while (ips[i]) {
+        if (!ips[i]) {
+            i++;
+            continue;
+        }
+
         PyObject *unicode = PyUnicode_FromString(ips[i]);
         if (!unicode) {
             Py_DECREF(ret);
diff --git a/templates/lxc-alpine.in b/templates/lxc-alpine.in
index 06616b3..e66c469 100644
--- a/templates/lxc-alpine.in
+++ b/templates/lxc-alpine.in
@@ -46,7 +46,7 @@ 
ebf31683b56410ecc4c00acd9f6e2839e237a3b62b5ae7ef686705c7ba0396a9  alpine-devel@l
 12f899e55a7691225603d6fb3324940fc51cd7f133e7ead788663c2b7eecb00c  
alpine-de...@lists.alpinelinux.org-5261cecb.rsa.pub"
 
 readonly APK_KEYS_URI='http://alpinelinux.org/keys'
-readonly MIRRORS_LIST_URL='http://rsync.alpinelinux.org/alpine/MIRRORS.txt'
+readonly DEFAULT_MIRROR_URL='http://dl-cdn.alpinelinux.org/alpine'
 
 : ${APK_KEYS_DIR:=/etc/apk/keys}
 if ! ls "$APK_KEYS_DIR"/alpine* >/dev/null 2>&1; then
@@ -76,7 +76,7 @@ usage() {
                                          to the host arch.
                   -d, --debug            Run this script in a debug mode (set 
-x and wget w/o -q).
                   -F, --flush-cache      Remove cached files before build.
-                  -m URL --mirror=URL    The Alpine mirror to use; defaults to 
random mirror.
+                  -m URL --mirror=URL    The Alpine mirror to use; defaults to 
$DEFAULT_MIRROR_URL.
                   -r VER, --release=VER  The Alpine release branch to install; 
default is the
                                          latest stable.
 
@@ -130,11 +130,6 @@ parse_arch() {
        esac
 }
 
-random_mirror_url() {
-       local url=$(fetch "$MIRRORS_LIST_URL" | shuf -n 1)
-       [ -n "$url" ] && echo "$url"
-}
-
 run_exclusively() {
        local lock_name="$1"
        local timeout=$2
@@ -266,8 +261,8 @@ install() {
 }
 
 install_packages() {
-       local arch="$1"; shift
-       local packages="$@"
+       local arch="$1"
+       local packages="$2"
 
        $APK --arch="$arch" --root=. --keys-dir="$APK_KEYS_DIR" \
                --update-cache --initdb add $packages
@@ -475,7 +470,7 @@ extra_packages="$@"
 # Set global variables.
 readonly DEBUG="$debug"
 readonly FLUSH_CACHE="$flush_cache"
-readonly MIRROR_URL="${mirror_url:-$(random_mirror_url)}"
+readonly MIRROR_URL="${mirror_url:-$DEFAULT_MIRROR_URL}"
 
 # Validate options.
 [ -n "$name" ] || die 1 'Missing required option --name'
diff --git a/templates/lxc-altlinux.in b/templates/lxc-altlinux.in
index 69c18d4..7accf24 100644
--- a/templates/lxc-altlinux.in
+++ b/templates/lxc-altlinux.in
@@ -43,7 +43,6 @@ cache_base=@LOCALSTATEDIR@/cache/lxc/altlinux/$arch
 default_path=@LXCPATH@
 default_profile=default
 profile_dir=/etc/lxc/profiles
-root_password=rooter
 lxc_network_type=veth
 lxc_network_link=virbr0
 
@@ -156,8 +155,10 @@ EOF
     mkdir -m 755 ${dev_path}/net
     mknod -m 666 ${dev_path}/net/tun c 10 200
 
-    echo "setting root passwd to $root_password"
-    echo "root:$root_password" | chroot $rootfs_path chpasswd
+    if [ -n "${root_password}" ]; then
+        echo "setting root passwd to $root_password"
+        echo "root:$root_password" | chroot $rootfs_path chpasswd
+    fi
 
     return 0
 }
diff --git a/templates/lxc-archlinux.in b/templates/lxc-archlinux.in
index c52459d..200b84e 100644
--- a/templates/lxc-archlinux.in
+++ b/templates/lxc-archlinux.in
@@ -42,7 +42,6 @@ export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
 arch=$(uname -m)
 default_path="@LXCPATH@"
 default_locale="en-US.UTF-8"
-default_timezone="UTC"
 pacman_config="/etc/pacman.conf"
 common_config="@LXCTEMPLATECONFIG@/common.conf"
 shared_config="@LXCTEMPLATECONFIG@/archlinux.common.conf"
@@ -87,9 +86,6 @@ configure_arch() {
 
     # hostname and nameservers
     echo "${name}" > "${rootfs_path}/etc/hostname"
-    while read r; do
-       [ "${r#nameserver}" = "$r" ] || echo "$r"
-    done < /etc/resolv.conf > "${rootfs_path}/etc/resolv.conf"
 
     # network configuration
     cat > "${rootfs_path}/etc/systemd/network/eth0.network" << EOF
@@ -104,7 +100,6 @@ EOF
     arch-chroot "${rootfs_path}" /bin/bash -s << EOF
 mkdir /run/lock
 locale-gen
-ln -s /usr/share/zoneinfo/${default_timezone} /etc/localtime
 # set default boot target
 ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
 # override getty@.service for container ttys
diff --git a/templates/lxc-busybox.in b/templates/lxc-busybox.in
index 336fa12..0d8db33 100644
--- a/templates/lxc-busybox.in
+++ b/templates/lxc-busybox.in
@@ -330,35 +330,6 @@ configure_busybox()
     chmod +s $rootfs/bin/passwd
     touch $rootfs/etc/shadow
 
-    # setting passwd for root
-    CHPASSWD_FILE=$rootfs/root/chpasswd.sh
-
-    cat <<EOF >$CHPASSWD_FILE
-echo "setting root password to \"root\""
-
-mount -n --bind /lib $rootfs/lib
-if [ \$? -ne 0 ]; then
-    echo "Failed bind-mounting /lib at $rootfs/lib"
-    exit 1
-fi
-
-chroot $rootfs chpasswd <<EOFF 2>/dev/null
-root:root
-EOFF
-
-
-if [ \$? -ne 0 ]; then
-    echo "Failed to change root password"
-    exit 1
-fi
-
-umount $rootfs/lib
-
-EOF
-
-    lxc-unshare -s MOUNT -- /bin/sh < $CHPASSWD_FILE
-    rm $CHPASSWD_FILE
-
     return 0
 }
 
diff --git a/templates/lxc-debian.in b/templates/lxc-debian.in
index f752ccd..4477aff 100644
--- a/templates/lxc-debian.in
+++ b/templates/lxc-debian.in
@@ -158,9 +158,6 @@ EOF
         echo "Timezone in container is not configured. Adjust it manually."
     fi
 
-    echo "root:root" | chroot "$rootfs" chpasswd
-    echo "Root password is 'root', please change !"
-
     return 0
 }
 
@@ -291,9 +288,6 @@ openssh-server
     if [ ! -f $releasekeyring ]; then
         releasekeyring="$cache/archive-key.gpg"
         case $release in
-            "squeeze")
-                gpgkeyname="archive-key-6.0"
-                ;;
             "wheezy")
                 gpgkeyname="archive-key-7.0"
                 ;;
diff --git a/templates/lxc-download.in b/templates/lxc-download.in
index e0ffdb2..f09475d 100644
--- a/templates/lxc-download.in
+++ b/templates/lxc-download.in
@@ -34,7 +34,6 @@ DOWNLOAD_FLUSH_CACHE="false"
 DOWNLOAD_FORCE_CACHE="false"
 DOWNLOAD_INTERACTIVE="false"
 DOWNLOAD_KEYID="0xE7FB0CAEC8173D669066514CBAEFF88C22F6E216"
-DOWNLOAD_KEYSERVER="hkp://pool.sks-keyservers.net"
 DOWNLOAD_LIST_IMAGES="false"
 DOWNLOAD_MODE="system"
 DOWNLOAD_READY_GPG="false"
@@ -54,9 +53,13 @@ LXC_NAME=
 LXC_PATH=
 LXC_ROOTFS=
 
-# Deal with GPG over http proxy
-if [ -n "${http_proxy:-}" ]; then
-    DOWNLOAD_KEYSERVER="hkp://p80.pool.sks-keyservers.net:80"
+if [ -z "${DOWNLOAD_KEYSERVER:-}" ]; then
+       DOWNLOAD_KEYSERVER="hkp://pool.sks-keyservers.net"
+
+       # Deal with GPG over http proxy
+       if [ -n "${http_proxy:-}" ]; then
+           DOWNLOAD_KEYSERVER="hkp://p80.pool.sks-keyservers.net:80"
+       fi
 fi
 
 # Make sure the usual locations are in PATH
@@ -201,7 +204,7 @@ Optional arguments:
 [ --variant <variant> ]: Variant of the image (default: "default")
 [ --server <server> ]: Image server (default: "images.linuxcontainers.org")
 [ --keyid <keyid> ]: GPG keyid (default: 0x...)
-[ --keyserver <keyserver> ]: GPG keyserver to use
+[ --keyserver <keyserver> ]: GPG keyserver to use. Environment variable: 
DOWNLOAD_KEYSERVER
 [ --no-validate ]: Disable GPG validation (not recommended)
 [ --flush-cache ]: Flush the local copy (if present)
 [ --force-cache ]: Force the use of the local copy even if expired
@@ -212,6 +215,11 @@ LXC internal arguments (do not pass manually!):
 [ --rootfs <rootfs> ]: The path to the container's rootfs
 [ --mapped-uid <map> ]: A uid map (user namespaces)
 [ --mapped-gid <map> ]: A gid map (user namespaces)
+
+Environment Variables:
+DOWNLOAD_KEYSERVER : The URL of the key server to use, instead of the default.
+                     Can be further overridden by using optional argument 
--keyserver
+
 EOF
     return 0
 }
diff --git a/templates/lxc-gentoo.in b/templates/lxc-gentoo.in
index 2ad16e8..47f24d0 100644
--- a/templates/lxc-gentoo.in
+++ b/templates/lxc-gentoo.in
@@ -654,8 +654,6 @@ container_auth()
         printf "  => done. if you didn't specify , default is 'toor'\n"
         if [[ -n "${forced_password}" ]]; then
             store_user_message "${user} has the password you give for him"
-        else
-            store_user_message "${user} has the default password 'toor', 
please change it ASAP"
         fi
     fi
 
@@ -779,7 +777,6 @@ set_default_arch
 
 mirror="http://distfiles.gentoo.org";
 user="root"
-password="toor"
 tty=1
 settings="common"
 options=$(getopt -o hp:n:a:FcPv:t:S:u:w:s:m: -l 
help,rootfs:,path:,name:,arch:,flush-cache,cache-only,private-portage,variant:,portage-dir:,tarball:,auth-key:,user:,autologin,password:,settings:,mirror:,tty:
 -- "$@")
diff --git a/templates/lxc-openmandriva.in b/templates/lxc-openmandriva.in
index 12f9985..daba812 100644
--- a/templates/lxc-openmandriva.in
+++ b/templates/lxc-openmandriva.in
@@ -46,7 +46,6 @@ hostarch=$(uname -m)
 cache_base="${LXC_CACHE_PATH:-@LOCALSTATEDIR@/cache/lxc/openmandriva/$arch}"
 default_path=@LXCPATH@
 default_profile=default
-root_password=root
 lxc_network_type=veth
 lxc_network_link=br0
 
diff --git a/templates/lxc-opensuse.in b/templates/lxc-opensuse.in
index 66176c3..5e8686b 100644
--- a/templates/lxc-opensuse.in
+++ b/templates/lxc-opensuse.in
@@ -112,7 +112,6 @@ EOF
     touch $rootfs/etc/sysconfig/kernel
 
     echo "Please change root-password !"
-    echo "root:root" | chpasswd -R $rootfs
 
     return 0
 }
@@ -459,7 +458,7 @@ fi
 if [ -z "$DISTRO" ]; then
     echo ""
     echo "No release selected, using openSUSE Leap 42.2"
-    DISTRO=42.2
+    DISTRO="leap/42.2"
 else
     echo ""
     case "$DISTRO" in
diff --git a/templates/lxc-oracle.in b/templates/lxc-oracle.in
index 20c212b..19fe912 100644
--- a/templates/lxc-oracle.in
+++ b/templates/lxc-oracle.in
@@ -462,12 +462,10 @@ EOF
         fi
     fi
 
-    # add oracle user, set root password
+    # add oracle user
     chroot $container_rootfs useradd -m -s /bin/bash oracle
-    echo "oracle:oracle" | chroot $container_rootfs chpasswd
-    echo "root:root" | chroot $container_rootfs chpasswd
-    printf "Added container user:\033[1moracle\033[0m 
password:\033[1moracle\033[0m\n"
-    printf "Added container user:\033[1mroot\033[0m 
password:\033[1mroot\033[0m\n"
+    printf "Added container user:\033[1moracle\033[0m\n"
+    printf "Added container user:\033[1mroot\033[0m\n"
 }
 
 # create the container's lxc config file
diff --git a/templates/lxc-plamo.in b/templates/lxc-plamo.in
index 009fa4f..c96e23e 100644
--- a/templates/lxc-plamo.in
+++ b/templates/lxc-plamo.in
@@ -186,9 +186,6 @@ configure_plamo() {
   # glibc configure
   mv $rootfs/etc/ld.so.conf{.new,}
   chroot $rootfs ldconfig
-  # root password
-  echo "Setting root password to 'root'..."
-  echo "root:root" | chroot $rootfs chpasswd
   echo "Please change root password!"
   ed - $rootfs/etc/rc.d/rc.S <<- "EOF"
        /^mount -w -n -t proc/;/^mkdir \/dev\/shm/-1d
diff --git a/templates/lxc-slackware.in b/templates/lxc-slackware.in
index 5005918..216c7a7 100644
--- a/templates/lxc-slackware.in
+++ b/templates/lxc-slackware.in
@@ -471,10 +471,6 @@ sed -i 's/.*genpowerfail.*//' $rootfs/etc/inittab
 # add a message to rc.local that confirms successful container startup
 echo "echo ; echo \"* container $name started. *\" ; echo" >> 
$rootfs/etc/rc.d/rc.local
 
-# set a default combination for the luggage
-echo "root:root" | chroot $rootfs chpasswd
-echo "Root default password is 'root', please change it!"
-
 # borrow the time configuration from the local machine
 cp -a /etc/localtime $rootfs/etc/localtime
 
diff --git a/templates/lxc-sparclinux.in b/templates/lxc-sparclinux.in
index 70616ba..124c50b 100644
--- a/templates/lxc-sparclinux.in
+++ b/templates/lxc-sparclinux.in
@@ -296,12 +296,10 @@ EOF
         echo "Timezone in container is not configured. Adjust it manually."
     fi
 
-    # add oracle user, set root password
+    # add oracle user
     chroot $container_rootfs useradd -m -s /bin/bash oracle
-    echo "oracle:oracle" | chroot $container_rootfs chpasswd
-    echo "root:root" | chroot $container_rootfs chpasswd
-    printf "Added container user:\033[1moracle\033[0m 
password:\033[1moracle\033[0m\n"
-    printf "Added container user:\033[1mroot\033[0m 
password:\033[1mroot\033[0m\n"
+    printf "Added container user:\033[1moracle\033[0m\n"
+    printf "Added container user:\033[1mroot\033[0m\n"
 }
 
 # create the container's lxc config file
diff --git a/templates/lxc-sshd.in b/templates/lxc-sshd.in
index 9b07ea6..7db13cc 100644
--- a/templates/lxc-sshd.in
+++ b/templates/lxc-sshd.in
@@ -38,7 +38,6 @@ install_sshd()
     rootfs=$1
 
     tree="\
-$rootfs/var/run/sshd \
 $rootfs/var/empty/sshd \
 $rootfs/var/lib/empty/sshd \
 $rootfs/etc/init.d \
@@ -46,7 +45,7 @@ $rootfs/etc/rc.d \
 $rootfs/etc/ssh \
 $rootfs/etc/sysconfig/network-scripts \
 $rootfs/dev/shm \
-$rootfs/run/shm \
+$rootfs/run/sshd \
 $rootfs/proc \
 $rootfs/sys \
 $rootfs/bin \
@@ -63,6 +62,11 @@ $rootfs/lib64"
         return 1
     fi
 
+    ln -s /run $rootfs/var/run
+    if [ $? -ne 0 ]; then
+        return 1
+    fi
+
     return 0
 }
 
@@ -90,17 +94,13 @@ Protocol 2
 HostKey /etc/ssh/ssh_host_rsa_key
 HostKey /etc/ssh/ssh_host_dsa_key
 UsePrivilegeSeparation yes
-KeyRegenerationInterval 3600
-ServerKeyBits 768
 SyslogFacility AUTH
 LogLevel INFO
 LoginGraceTime 120
 PermitRootLogin yes
 StrictModes yes
-RSAAuthentication yes
 PubkeyAuthentication yes
 IgnoreRhosts yes
-RhostsRSAAuthentication no
 HostbasedAuthentication no
 PermitEmptyPasswords yes
 ChallengeResponseAuthentication no
@@ -141,7 +141,7 @@ lxc.mount.entry = /lib lib none ro,bind 0 0
 lxc.mount.entry = /bin bin none ro,bind 0 0
 lxc.mount.entry = /usr usr none ro,bind 0 0
 lxc.mount.entry = /sbin sbin none ro,bind 0 0
-lxc.mount.entry = tmpfs var/run/sshd tmpfs mode=0644 0 0
+lxc.mount.entry = tmpfs run/sshd tmpfs mode=0644 0 0
 lxc.mount.entry = @LXCTEMPLATEDIR@/lxc-sshd $init_path none ro,bind 0 0
 lxc.mount.entry = /etc/init.d etc/init.d none ro,bind 0 0
 
diff --git a/templates/lxc-ubuntu.in b/templates/lxc-ubuntu.in
index 8320993..ae3a22a 100644
--- a/templates/lxc-ubuntu.in
+++ b/templates/lxc-ubuntu.in
@@ -674,7 +674,7 @@ $1 -h|--help [-a|--arch] [-b|--bindhome <user>] [-d|--debug]
    [-F | --flush-cache] [-r|--release <release>] [-v|--variant] [ -S | 
--auth-key <keyfile>]
    [--rootfs <rootfs>] [--packages <packages>] [-u|--user <user>] [--password 
<password>]
    [--mirror <url>] [--security-mirror <url>]
-release: the ubuntu release (e.g. precise): defaults to host release on 
ubuntu, otherwise uses latest LTS
+release: the ubuntu release (e.g. xenial): defaults to host release on ubuntu, 
otherwise uses latest LTS
 variant: debootstrap variant to use (see debootstrap(8))
 bindhome: bind <user>'s home into the container
           The ubuntu user will not be created, and <user> will have
@@ -694,7 +694,7 @@ if [ $? -ne 0 ]; then
 fi
 eval set -- "$options"
 
-release=precise # Default to the last Ubuntu LTS release for non-Ubuntu systems
+release=xenial # Default to the last Ubuntu LTS release for non-Ubuntu systems
 if [ -f /etc/lsb-release ]; then
     . /etc/lsb-release
     if [ "$DISTRIB_ID" = "Ubuntu" ]; then

Reply via email to