[lxc-devel] [lxc/master] 2016 07 31/append to search path

brauner on Github lxc-bot at linuxcontainers.org
Sun Jul 31 10:50:54 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 412 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160731/7e3575bc/attachment.bin>
-------------- next part --------------
From d8e4899290758cdafb2c33d65b5d319a5fe1ca9b Mon Sep 17 00:00:00 2001
From: Christian Brauner <cbrauner at suse.de>
Date: Sun, 31 Jul 2016 12:04:28 +0200
Subject: [PATCH 1/3] bdev: add subdirectories to search path

This allows us to avoid using relative includes which is cleaner in the long
run when we create subdirectories for other components of liblxc.

Signed-off-by: Christian Brauner <cbrauner at suse.de>
---
 src/lxc/Makefile.am    | 8 +++++---
 src/lxc/cgfs.c         | 2 +-
 src/lxc/cgfsng.c       | 2 +-
 src/lxc/cgmanager.c    | 2 +-
 src/lxc/conf.c         | 6 +++---
 src/lxc/confile.c      | 2 +-
 src/lxc/criu.c         | 2 +-
 src/lxc/lxc_copy.c     | 2 +-
 src/lxc/lxc_create.c   | 2 +-
 src/lxc/lxc_snapshot.c | 2 +-
 src/lxc/lxccontainer.c | 6 +++---
 src/lxc/start.c        | 2 +-
 12 files changed, 20 insertions(+), 18 deletions(-)

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index f361c3f..5078b5c 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -138,8 +138,7 @@ liblxc_so_SOURCES += ../include/getline.c ../include/getline.h
 endif
 endif
 
-AM_CFLAGS=-I$(top_srcdir)/src \
-	-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
+AM_CFLAGS=-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
 	-DLXCPATH=\"$(LXCPATH)\" \
 	-DLXC_GLOBAL_CONF=\"$(LXC_GLOBAL_CONF)\" \
 	-DLXCINITDIR=\"$(LXCINITDIR)\" \
@@ -152,7 +151,10 @@ AM_CFLAGS=-I$(top_srcdir)/src \
 	-DLXC_USERNIC_CONF=\"$(LXC_USERNIC_CONF)\" \
 	-DDEFAULT_CGROUP_PATTERN=\"$(DEFAULT_CGROUP_PATTERN)\" \
 	-DRUNTIME_PATH=\"$(RUNTIME_PATH)\" \
-	-DSBINDIR=\"$(SBINDIR)\"
+	-DSBINDIR=\"$(SBINDIR)\" \
+	-I $(top_srcdir)/src \
+	-I $(top_srcdir)/src/lxc \
+	-I $(top_srcdir)/src/lxc/bdev
 
 if ENABLE_APPARMOR
 AM_CFLAGS += -DHAVE_APPARMOR
diff --git a/src/lxc/cgfs.c b/src/lxc/cgfs.c
index c493d58..6b2ac7e 100644
--- a/src/lxc/cgfs.c
+++ b/src/lxc/cgfs.c
@@ -39,12 +39,12 @@
 #include <netinet/in.h>
 #include <net/if.h>
 
+#include "bdev.h"
 #include "error.h"
 #include "commands.h"
 #include "list.h"
 #include "conf.h"
 #include "utils.h"
-#include "bdev/bdev.h"
 #include "log.h"
 #include "cgroup.h"
 #include "start.h"
diff --git a/src/lxc/cgfsng.c b/src/lxc/cgfsng.c
index 16a9457..27c2721 100644
--- a/src/lxc/cgfsng.c
+++ b/src/lxc/cgfsng.c
@@ -43,11 +43,11 @@
 #include <dirent.h>
 #include <grp.h>
 
+#include "bdev.h"
 #include "log.h"
 #include "cgroup.h"
 #include "utils.h"
 #include "commands.h"
-#include "bdev/bdev.h"
 
 lxc_log_define(lxc_cgfsng, lxc);
 
diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c
index c387b00..4da891d 100644
--- a/src/lxc/cgmanager.c
+++ b/src/lxc/cgmanager.c
@@ -41,12 +41,12 @@
 #include <net/if.h>
 #include <poll.h>
 
+#include "bdev.h"
 #include "error.h"
 #include "commands.h"
 #include "list.h"
 #include "conf.h"
 #include "utils.h"
-#include "bdev/bdev.h"
 #include "log.h"
 #include "cgroup.h"
 #include "start.h"
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 1e330ac..9fea993 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -66,6 +66,7 @@
 #include <net/if.h>
 #include <libgen.h>
 
+#include "bdev.h"
 #include "network.h"
 #include "error.h"
 #include "af_unix.h"
@@ -74,9 +75,8 @@
 #include "conf.h"
 #include "log.h"
 #include "caps.h"       /* for lxc_caps_last_cap() */
-#include "bdev/bdev.h"
-#include "bdev/lxcaufs.h"
-#include "bdev/lxcoverlay.h"
+#include "lxcaufs.h"
+#include "lxcoverlay.h"
 #include "cgroup.h"
 #include "lxclock.h"
 #include "namespace.h"
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 645cac0..db89caa 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -40,10 +40,10 @@
 #include <dirent.h>
 #include <syslog.h>
 
+#include "bdev.h"
 #include "parse.h"
 #include "config.h"
 #include "confile.h"
-#include "bdev/bdev.h"
 #include "utils.h"
 #include "log.h"
 #include "conf.h"
diff --git a/src/lxc/criu.c b/src/lxc/criu.c
index bf9a87a..65998ed 100644
--- a/src/lxc/criu.c
+++ b/src/lxc/criu.c
@@ -35,7 +35,7 @@
 
 #include "config.h"
 
-#include "bdev/bdev.h"
+#include "bdev.h"
 #include "cgroup.h"
 #include "conf.h"
 #include "commands.h"
diff --git a/src/lxc/lxc_copy.c b/src/lxc/lxc_copy.c
index 69de7d5..9f653e3 100644
--- a/src/lxc/lxc_copy.c
+++ b/src/lxc/lxc_copy.c
@@ -37,6 +37,7 @@
 #include <lxc/lxccontainer.h>
 
 #include "attach.h"
+#include "bdev.h"
 #include "log.h"
 #include "confile.h"
 #include "arguments.h"
@@ -44,7 +45,6 @@
 #include "conf.h"
 #include "state.h"
 #include "utils.h"
-#include "bdev/bdev.h"
 
 #ifndef HAVE_GETSUBOPT
 #include <../include/getsubopt.h>
diff --git a/src/lxc/lxc_create.c b/src/lxc/lxc_create.c
index 5fd5a29..4b0e9d7 100644
--- a/src/lxc/lxc_create.c
+++ b/src/lxc/lxc_create.c
@@ -27,10 +27,10 @@
 #include <sys/types.h>
 
 #include "arguments.h"
+#include "bdev.h"
 #include "log.h"
 #include "lxc.h"
 #include "utils.h"
-#include "bdev/bdev.h"
 
 lxc_log_define(lxc_create_ui, lxc);
 
diff --git a/src/lxc/lxc_snapshot.c b/src/lxc/lxc_snapshot.c
index 147101e..8f44891 100644
--- a/src/lxc/lxc_snapshot.c
+++ b/src/lxc/lxc_snapshot.c
@@ -27,9 +27,9 @@
 
 #include <lxc/lxccontainer.h>
 
+#include "bdev.h"
 #include "lxc.h"
 #include "log.h"
-#include "bdev/bdev.h"
 #include "arguments.h"
 #include "utils.h"
 
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 8ea0005..24ded6f 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -39,9 +39,9 @@
 #include <sys/wait.h>
 
 #include "attach.h"
-#include "bdev/bdev.h"
-#include "bdev/lxcoverlay.h"
-#include "bdev/lxcbtrfs.h"
+#include "bdev.h"
+#include "lxcoverlay.h"
+#include "lxcbtrfs.h"
 #include "cgroup.h"
 #include "conf.h"
 #include "config.h"
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 1ba0f9b..1ce9903 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -55,6 +55,7 @@
 #endif
 
 #include "af_unix.h"
+#include "bdev.h"
 #include "caps.h"
 #include "cgroup.h"
 #include "commands.h"
@@ -71,7 +72,6 @@
 #include "start.h"
 #include "sync.h"
 #include "utils.h"
-#include "bdev/bdev.h"
 #include "lsm/lsm.h"
 
 lxc_log_define(lxc_start, lxc);

From 8d3b0a65b2f71e2c8c4261b18890ac7457e5e5fb Mon Sep 17 00:00:00 2001
From: Christian Brauner <cbrauner at suse.de>
Date: Sun, 31 Jul 2016 12:21:58 +0200
Subject: [PATCH 2/3] cgroups: move cgroup files to common subfolder

Signed-off-by: Christian Brauner <cbrauner at suse.de>
---
 src/lxc/Makefile.am         |   13 +-
 src/lxc/cgfs.c              | 2655 -------------------------------------------
 src/lxc/cgfsng.c            | 1691 ---------------------------
 src/lxc/cgmanager.c         | 1672 ---------------------------
 src/lxc/cgroup.c            |  245 ----
 src/lxc/cgroup.h            |   89 --
 src/lxc/cgroups/cgfs.c      | 2655 +++++++++++++++++++++++++++++++++++++++++++
 src/lxc/cgroups/cgfsng.c    | 1691 +++++++++++++++++++++++++++
 src/lxc/cgroups/cgmanager.c | 1672 +++++++++++++++++++++++++++
 src/lxc/cgroups/cgroup.c    |  245 ++++
 src/lxc/cgroups/cgroup.h    |   89 ++
 11 files changed, 6359 insertions(+), 6358 deletions(-)
 delete mode 100644 src/lxc/cgfs.c
 delete mode 100644 src/lxc/cgfsng.c
 delete mode 100644 src/lxc/cgmanager.c
 delete mode 100644 src/lxc/cgroup.c
 delete mode 100644 src/lxc/cgroup.h
 create mode 100644 src/lxc/cgroups/cgfs.c
 create mode 100644 src/lxc/cgroups/cgfsng.c
 create mode 100644 src/lxc/cgroups/cgmanager.c
 create mode 100644 src/lxc/cgroups/cgroup.c
 create mode 100644 src/lxc/cgroups/cgroup.h

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 5078b5c..9a87c15 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -17,8 +17,8 @@ noinst_HEADERS = \
 	bdev/lxcrbd.h \
 	bdev/lxcrsync.h \
 	bdev/lxczfs.h \
+	cgroups/cgroup.h \
 	caps.h \
-	cgroup.h \
 	conf.h \
 	console.h \
 	error.h \
@@ -80,6 +80,9 @@ liblxc_so_SOURCES = \
 	bdev/lxcrbd.c bdev/lxcrbd.h \
 	bdev/lxcrsync.c bdev/lxcrsync.h \
 	bdev/lxczfs.c bdev/lxczfs.h \
+	cgroups/cgfs.c \
+	cgroups/cgfsng.c \
+	cgroups/cgroup.c cgroups/cgroup.h \
 	commands.c commands.h \
 	start.c start.h \
 	execute.c \
@@ -88,9 +91,6 @@ liblxc_so_SOURCES = \
 	freezer.c \
 	error.h error.c \
 	parse.c parse.h \
-	cgfs.c \
-	cgfsng.c \
-	cgroup.c cgroup.h \
 	lxc.h \
 	initutils.c initutils.h \
 	utils.c utils.h \
@@ -122,7 +122,7 @@ liblxc_so_SOURCES = \
 	$(LSM_SOURCES)
 
 if ENABLE_CGMANAGER
-liblxc_so_SOURCES += cgmanager.c
+liblxc_so_SOURCES += cgroups/cgmanager.c
 endif
 
 if IS_BIONIC
@@ -154,7 +154,8 @@ AM_CFLAGS=-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
 	-DSBINDIR=\"$(SBINDIR)\" \
 	-I $(top_srcdir)/src \
 	-I $(top_srcdir)/src/lxc \
-	-I $(top_srcdir)/src/lxc/bdev
+	-I $(top_srcdir)/src/lxc/bdev \
+	-I $(top_srcdir)/src/lxc/cgroups
 
 if ENABLE_APPARMOR
 AM_CFLAGS += -DHAVE_APPARMOR
diff --git a/src/lxc/cgfs.c b/src/lxc/cgfs.c
deleted file mode 100644
index 6b2ac7e..0000000
--- a/src/lxc/cgfs.c
+++ /dev/null
@@ -1,2655 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <grp.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <sys/inotify.h>
-#include <sys/mount.h>
-#include <netinet/in.h>
-#include <net/if.h>
-
-#include "bdev.h"
-#include "error.h"
-#include "commands.h"
-#include "list.h"
-#include "conf.h"
-#include "utils.h"
-#include "log.h"
-#include "cgroup.h"
-#include "start.h"
-#include "state.h"
-
-#if IS_BIONIC
-#include <../include/lxcmntent.h>
-#else
-#include <mntent.h>
-#endif
-
-struct cgroup_hierarchy;
-struct cgroup_meta_data;
-struct cgroup_mount_point;
-
-/*
- * cgroup_meta_data: the metadata about the cgroup infrastructure on this
- *                   host
- */
-struct cgroup_meta_data {
-	ptrdiff_t ref; /* simple refcount */
-	struct cgroup_hierarchy **hierarchies;
-	struct cgroup_mount_point **mount_points;
-	int maximum_hierarchy;
-};
-
-/*
- * cgroup_hierarchy: describes a single cgroup hierarchy
- *                   (may have multiple mount points)
- */
-struct cgroup_hierarchy {
-	int index;
-	bool used; /* false if the hierarchy should be ignored by lxc */
-	char **subsystems;
-	struct cgroup_mount_point *rw_absolute_mount_point;
-	struct cgroup_mount_point *ro_absolute_mount_point;
-	struct cgroup_mount_point **all_mount_points;
-	size_t all_mount_point_capacity;
-};
-
-/*
- * cgroup_mount_point: a mount point to where a hierarchy
- *                     is mounted to
- */
-struct cgroup_mount_point {
-	struct cgroup_hierarchy *hierarchy;
-	char *mount_point;
-	char *mount_prefix;
-	bool read_only;
-	bool need_cpuset_init;
-};
-
-/*
- * cgroup_process_info: describes the membership of a
- *                      process to the different cgroup
- *                      hierarchies
- *
- * Note this is the per-process info tracked by the cgfs_ops.
- * This is not used with cgmanager.
- */
-struct cgroup_process_info {
-	struct cgroup_process_info *next;
-	struct cgroup_meta_data *meta_ref;
-	struct cgroup_hierarchy *hierarchy;
-	char *cgroup_path;
-	char *cgroup_path_sub;
-	char **created_paths;
-	size_t created_paths_capacity;
-	size_t created_paths_count;
-	struct cgroup_mount_point *designated_mount_point;
-};
-
-struct cgfs_data {
-	char *name;
-	const char *cgroup_pattern;
-	struct cgroup_meta_data *meta;
-	struct cgroup_process_info *info;
-};
-
-lxc_log_define(lxc_cgfs, lxc);
-
-static struct cgroup_process_info *lxc_cgroup_process_info_getx(const char *proc_pid_cgroup_str, struct cgroup_meta_data *meta);
-static char **subsystems_from_mount_options(const char *mount_options, char **kernel_list);
-static void lxc_cgroup_mount_point_free(struct cgroup_mount_point *mp);
-static void lxc_cgroup_hierarchy_free(struct cgroup_hierarchy *h);
-static bool is_valid_cgroup(const char *name);
-static int create_cgroup(struct cgroup_mount_point *mp, const char *path);
-static int remove_cgroup(struct cgroup_mount_point *mp, const char *path, bool recurse,
-				struct lxc_conf *conf);
-static char *cgroup_to_absolute_path(struct cgroup_mount_point *mp, const char *path, const char *suffix);
-static struct cgroup_process_info *find_info_for_subsystem(struct cgroup_process_info *info, const char *subsystem);
-static int do_cgroup_get(const char *cgroup_path, const char *sub_filename, char *value, size_t len);
-static int do_cgroup_set(const char *cgroup_path, const char *sub_filename, const char *value);
-static bool cgroup_devices_has_allow_or_deny(struct cgfs_data *d, char *v, bool for_allow);
-static int do_setup_cgroup_limits(struct cgfs_data *d, struct lxc_list *cgroup_settings, bool do_devices);
-static int cgroup_recursive_task_count(const char *cgroup_path);
-static int handle_cgroup_settings(struct cgroup_mount_point *mp, char *cgroup_path);
-static bool init_cpuset_if_needed(struct cgroup_mount_point *mp, const char *path);
-
-static struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist);
-static struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data);
-static struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data);
-
-/* free process membership information */
-static void lxc_cgroup_process_info_free(struct cgroup_process_info *info);
-static void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info,
-				struct lxc_conf *conf);
-
-static struct cgroup_ops cgfs_ops;
-
-static int cgroup_rmdir(char *dirname)
-{
-	struct dirent dirent, *direntp;
-	int saved_errno = 0;
-	DIR *dir;
-	int ret, failed=0;
-	char pathname[MAXPATHLEN];
-
-	dir = opendir(dirname);
-	if (!dir) {
-		ERROR("%s: failed to open %s", __func__, dirname);
-		return -1;
-	}
-
-	while (!readdir_r(dir, &dirent, &direntp)) {
-		struct stat mystat;
-		int rc;
-
-		if (!direntp)
-			break;
-
-		if (!strcmp(direntp->d_name, ".") ||
-		    !strcmp(direntp->d_name, ".."))
-			continue;
-
-		rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name);
-		if (rc < 0 || rc >= MAXPATHLEN) {
-			ERROR("pathname too long");
-			failed=1;
-			if (!saved_errno)
-				saved_errno = -ENOMEM;
-			continue;
-		}
-		ret = lstat(pathname, &mystat);
-		if (ret) {
-			SYSERROR("%s: failed to stat %s", __func__, pathname);
-			failed=1;
-			if (!saved_errno)
-				saved_errno = errno;
-			continue;
-		}
-		if (S_ISDIR(mystat.st_mode)) {
-			if (cgroup_rmdir(pathname) < 0) {
-				if (!saved_errno)
-					saved_errno = errno;
-				failed=1;
-			}
-		}
-	}
-
-	if (rmdir(dirname) < 0) {
-		SYSERROR("%s: failed to delete %s", __func__, dirname);
-		if (!saved_errno)
-			saved_errno = errno;
-		failed=1;
-	}
-
-	ret = closedir(dir);
-	if (ret) {
-		SYSERROR("%s: failed to close directory %s", __func__, dirname);
-		if (!saved_errno)
-			saved_errno = errno;
-		failed=1;
-	}
-
-	errno = saved_errno;
-	return failed ? -1 : 0;
-}
-
-static int rmdir_wrapper(void *data)
-{
-	char *path = data;
-
-	if (setresgid(0,0,0) < 0)
-		SYSERROR("Failed to setgid to 0");
-	if (setresuid(0,0,0) < 0)
-		SYSERROR("Failed to setuid to 0");
-	if (setgroups(0, NULL) < 0)
-		SYSERROR("Failed to clear groups");
-
-	return cgroup_rmdir(path);
-}
-
-static struct cgroup_meta_data *lxc_cgroup_load_meta()
-{
-	const char *cgroup_use = NULL;
-	char **cgroup_use_list = NULL;
-	struct cgroup_meta_data *md = NULL;
-	int saved_errno;
-
-	errno = 0;
-	cgroup_use = lxc_global_config_value("lxc.cgroup.use");
-	if (!cgroup_use && errno != 0)
-		return NULL;
-	if (cgroup_use) {
-		cgroup_use_list = lxc_string_split_and_trim(cgroup_use, ',');
-		if (!cgroup_use_list)
-			return NULL;
-	}
-
-	md = lxc_cgroup_load_meta2((const char **)cgroup_use_list);
-	saved_errno = errno;
-	lxc_free_array((void **)cgroup_use_list, free);
-	errno = saved_errno;
-	return md;
-}
-
-/* Step 1: determine all kernel subsystems */
-static bool find_cgroup_subsystems(char ***kernel_subsystems)
-{
-	FILE *proc_cgroups;
-	bool bret = false;
-	char *line = NULL;
-	size_t sz = 0;
-	size_t kernel_subsystems_count = 0;
-	size_t kernel_subsystems_capacity = 0;
-	int r;
-
-	proc_cgroups = fopen_cloexec("/proc/cgroups", "r");
-	if (!proc_cgroups)
-		return false;
-
-	while (getline(&line, &sz, proc_cgroups) != -1) {
-		char *tab1;
-		char *tab2;
-		int hierarchy_number;
-
-		if (line[0] == '#')
-			continue;
-		if (!line[0])
-			continue;
-
-		tab1 = strchr(line, '\t');
-		if (!tab1)
-			continue;
-		*tab1++ = '\0';
-		tab2 = strchr(tab1, '\t');
-		if (!tab2)
-			continue;
-		*tab2 = '\0';
-
-		tab2 = NULL;
-		hierarchy_number = strtoul(tab1, &tab2, 10);
-		if (!tab2 || *tab2)
-			continue;
-		(void)hierarchy_number;
-
-		r = lxc_grow_array((void ***)kernel_subsystems, &kernel_subsystems_capacity, kernel_subsystems_count + 1, 12);
-		if (r < 0)
-			goto out;
-		(*kernel_subsystems)[kernel_subsystems_count] = strdup(line);
-		if (!(*kernel_subsystems)[kernel_subsystems_count])
-			goto out;
-		kernel_subsystems_count++;
-	}
-	bret = true;
-
-out:
-	fclose(proc_cgroups);
-	free(line);
-	return bret;
-}
-
-/* Step 2: determine all hierarchies (by reading /proc/self/cgroup),
- *         since mount points don't specify hierarchy number and
- *         /proc/cgroups does not contain named hierarchies
- */
-static bool find_cgroup_hierarchies(struct cgroup_meta_data *meta_data,
-	bool all_kernel_subsystems, bool all_named_subsystems,
-	const char **subsystem_whitelist)
-{
-	FILE *proc_self_cgroup;
-	char *line = NULL;
-	size_t sz = 0;
-	int r;
-	bool bret = false;
-	size_t hierarchy_capacity = 0;
-
-	proc_self_cgroup = fopen_cloexec("/proc/self/cgroup", "r");
-	/* if for some reason (because of setns() and pid namespace for example),
-	 * /proc/self is not valid, we try /proc/1/cgroup... */
-	if (!proc_self_cgroup)
-		proc_self_cgroup = fopen_cloexec("/proc/1/cgroup", "r");
-	if (!proc_self_cgroup)
-		return false;
-
-	while (getline(&line, &sz, proc_self_cgroup) != -1) {
-		/* file format: hierarchy:subsystems:group,
-		 * we only extract hierarchy and subsystems
-		 * here */
-		char *colon1;
-		char *colon2;
-		int hierarchy_number;
-		struct cgroup_hierarchy *h = NULL;
-		char **p;
-
-		if (!line[0])
-			continue;
-
-		colon1 = strchr(line, ':');
-		if (!colon1)
-			continue;
-		*colon1++ = '\0';
-		colon2 = strchr(colon1, ':');
-		if (!colon2)
-			continue;
-		*colon2 = '\0';
-
-		colon2 = NULL;
-		hierarchy_number = strtoul(line, &colon2, 10);
-		if (!colon2 || *colon2)
-			continue;
-
-		if (hierarchy_number > meta_data->maximum_hierarchy) {
-			/* lxc_grow_array will never shrink, so even if we find a lower
-			* hierarchy number here, the array will never be smaller
-			*/
-			r = lxc_grow_array((void ***)&meta_data->hierarchies, &hierarchy_capacity, hierarchy_number + 1, 12);
-			if (r < 0)
-				goto out;
-
-			meta_data->maximum_hierarchy = hierarchy_number;
-		}
-
-		/* this shouldn't happen, we had this already */
-		if (meta_data->hierarchies[hierarchy_number])
-			goto out;
-
-		h = calloc(1, sizeof(struct cgroup_hierarchy));
-		if (!h)
-			goto out;
-
-		meta_data->hierarchies[hierarchy_number] = h;
-
-		h->index = hierarchy_number;
-		h->subsystems = lxc_string_split_and_trim(colon1, ',');
-		if (!h->subsystems)
-			goto out;
-		/* see if this hierarchy should be considered */
-		if (!all_kernel_subsystems || !all_named_subsystems) {
-			for (p = h->subsystems; *p; p++) {
-				if (!strncmp(*p, "name=", 5)) {
-					if (all_named_subsystems || (subsystem_whitelist && lxc_string_in_array(*p, subsystem_whitelist))) {
-						h->used = true;
-						break;
-					}
-				} else {
-					if (all_kernel_subsystems || (subsystem_whitelist && lxc_string_in_array(*p, subsystem_whitelist))) {
-						h->used = true;
-						break;
-					}
-				}
-			}
-		} else {
-			/* we want all hierarchy anyway */
-			h->used = true;
-		}
-	}
-	bret = true;
-
-out:
-	fclose(proc_self_cgroup);
-	free(line);
-	return bret;
-}
-
-/* Step 3: determine all mount points of each hierarchy */
-static bool find_hierarchy_mountpts( struct cgroup_meta_data *meta_data, char **kernel_subsystems)
-{
-	bool bret = false;
-	FILE *proc_self_mountinfo;
-	char *line = NULL;
-	size_t sz = 0;
-	char **tokens = NULL;
-	size_t mount_point_count = 0;
-	size_t mount_point_capacity = 0;
-	size_t token_capacity = 0;
-	int r;
-	bool is_cgns = cgns_supported();
-
-	proc_self_mountinfo = fopen_cloexec("/proc/self/mountinfo", "r");
-	/* if for some reason (because of setns() and pid namespace for example),
-	 * /proc/self is not valid, we try /proc/1/cgroup... */
-	if (!proc_self_mountinfo)
-		proc_self_mountinfo = fopen_cloexec("/proc/1/mountinfo", "r");
-	if (!proc_self_mountinfo)
-		return false;
-
-	while (getline(&line, &sz, proc_self_mountinfo) != -1) {
-		char *token, *line_tok, *saveptr = NULL;
-		size_t i, j, k;
-		struct cgroup_mount_point *mount_point;
-		struct cgroup_hierarchy *h;
-		char **subsystems;
-		bool is_lxcfs = false;
-
-		if (line[0] && line[strlen(line) - 1] == '\n')
-			line[strlen(line) - 1] = '\0';
-
-		for (i = 0, line_tok = line; (token = strtok_r(line_tok, " ", &saveptr)); line_tok = NULL) {
-			r = lxc_grow_array((void ***)&tokens, &token_capacity, i + 1, 64);
-			if (r < 0)
-				goto out;
-			tokens[i++] = token;
-		}
-
-		/* layout of /proc/self/mountinfo:
-		 *      0: id
-		 *      1: parent id
-		 *      2: device major:minor
-		 *      3: mount prefix
-		 *      4: mount point
-		 *      5: per-mount options
-		 *    [optional X]: additional data
-		 *    X+7: "-"
-		 *    X+8: type
-		 *    X+9: source
-		 *    X+10: per-superblock options
-		 */
-		for (j = 6; j < i && tokens[j]; j++)
-			if (!strcmp(tokens[j], "-"))
-				break;
-
-		/* could not find separator */
-		if (j >= i || !tokens[j])
-			continue;
-		/* there should be exactly three fields after
-		 * the separator
-		 */
-		if (i != j + 4)
-			continue;
-
-		/* not a cgroup filesystem */
-		if (strcmp(tokens[j + 1], "cgroup") != 0) {
-			if (strcmp(tokens[j + 1], "fuse.lxcfs") != 0)
-				continue;
-			if (strncmp(tokens[4], "/sys/fs/cgroup/", 15) != 0)
-				continue;
-			is_lxcfs = true;
-			char *curtok = tokens[4] + 15;
-			subsystems = subsystems_from_mount_options(curtok,
-							 kernel_subsystems);
-		} else
-			subsystems = subsystems_from_mount_options(tokens[j + 3],
-							 kernel_subsystems);
-		if (!subsystems)
-			goto out;
-
-		h = NULL;
-		for (k = 1; k <= meta_data->maximum_hierarchy; k++) {
-			if (meta_data->hierarchies[k] &&
-			    meta_data->hierarchies[k]->subsystems[0] &&
-			    lxc_string_in_array(meta_data->hierarchies[k]->subsystems[0], (const char **)subsystems)) {
-				/* TODO: we could also check if the lists really match completely,
-				 *       just to have an additional sanity check */
-				h = meta_data->hierarchies[k];
-				break;
-			}
-		}
-		lxc_free_array((void **)subsystems, free);
-
-		r = lxc_grow_array((void ***)&meta_data->mount_points, &mount_point_capacity, mount_point_count + 1, 12);
-		if (r < 0)
-			goto out;
-
-		/* create mount point object */
-		mount_point = calloc(1, sizeof(*mount_point));
-		if (!mount_point)
-			goto out;
-
-		meta_data->mount_points[mount_point_count++] = mount_point;
-
-		mount_point->hierarchy = h;
-		if (is_lxcfs || is_cgns)
-			mount_point->mount_prefix = strdup("/");
-		else
-			mount_point->mount_prefix = strdup(tokens[3]);
-		mount_point->mount_point = strdup(tokens[4]);
-		if (!mount_point->mount_point || !mount_point->mount_prefix)
-			goto out;
-		mount_point->read_only = !lxc_string_in_list("rw", tokens[5], ',');
-
-		if (!strcmp(mount_point->mount_prefix, "/")) {
-			if (mount_point->read_only) {
-				if (!h->ro_absolute_mount_point)
-					h->ro_absolute_mount_point = mount_point;
-			} else {
-				if (!h->rw_absolute_mount_point)
-					h->rw_absolute_mount_point = mount_point;
-			}
-		}
-
-		k = lxc_array_len((void **)h->all_mount_points);
-		r = lxc_grow_array((void ***)&h->all_mount_points, &h->all_mount_point_capacity, k + 1, 4);
-		if (r < 0)
-			goto out;
-		h->all_mount_points[k] = mount_point;
-	}
-	bret = true;
-
-out:
-	fclose(proc_self_mountinfo);
-	free(tokens);
-	free(line);
-	return bret;
-}
-
-static struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist)
-{
-	bool all_kernel_subsystems = true;
-	bool all_named_subsystems = false;
-	struct cgroup_meta_data *meta_data = NULL;
-	char **kernel_subsystems = NULL;
-	int saved_errno = 0;
-
-	/* if the subsystem whitelist is not specified, include all
-	 * hierarchies that contain kernel subsystems by default but
-	 * no hierarchies that only contain named subsystems
-	 *
-	 * if it is specified, the specifier @all will select all
-	 * hierarchies, @kernel will select all hierarchies with
-	 * kernel subsystems and @named will select all named
-	 * hierarchies
-	 */
-	all_kernel_subsystems = subsystem_whitelist ?
-		(lxc_string_in_array("@kernel", subsystem_whitelist) || lxc_string_in_array("@all", subsystem_whitelist)) :
-		true;
-	all_named_subsystems = subsystem_whitelist ?
-		(lxc_string_in_array("@named", subsystem_whitelist) || lxc_string_in_array("@all", subsystem_whitelist)) :
-		true;
-
-	meta_data = calloc(1, sizeof(struct cgroup_meta_data));
-	if (!meta_data)
-		return NULL;
-	meta_data->ref = 1;
-
-	if (!find_cgroup_subsystems(&kernel_subsystems))
-		goto out_error;
-
-	if (!find_cgroup_hierarchies(meta_data, all_kernel_subsystems,
-				all_named_subsystems, subsystem_whitelist))
-		goto out_error;
-
-	if (!find_hierarchy_mountpts(meta_data, kernel_subsystems))
-		goto out_error;
-
-	/* oops, we couldn't find anything */
-	if (!meta_data->hierarchies || !meta_data->mount_points) {
-		errno = EINVAL;
-		goto out_error;
-	}
-
-	lxc_free_array((void **)kernel_subsystems, free);
-	return meta_data;
-
-out_error:
-	saved_errno = errno;
-	lxc_free_array((void **)kernel_subsystems, free);
-	lxc_cgroup_put_meta(meta_data);
-	errno = saved_errno;
-	return NULL;
-}
-
-static struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data)
-{
-	meta_data->ref++;
-	return meta_data;
-}
-
-static struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data)
-{
-	size_t i;
-	if (!meta_data)
-		return NULL;
-	if (--meta_data->ref > 0)
-		return meta_data;
-	lxc_free_array((void **)meta_data->mount_points, (lxc_free_fn)lxc_cgroup_mount_point_free);
-	if (meta_data->hierarchies) {
-		for (i = 0; i <= meta_data->maximum_hierarchy; i++)
-			lxc_cgroup_hierarchy_free(meta_data->hierarchies[i]);
-	}
-	free(meta_data->hierarchies);
-	free(meta_data);
-	return NULL;
-}
-
-static struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta_data, const char *subsystem)
-{
-	size_t i;
-	for (i = 0; i <= meta_data->maximum_hierarchy; i++) {
-		struct cgroup_hierarchy *h = meta_data->hierarchies[i];
-		if (h && lxc_string_in_array(subsystem, (const char **)h->subsystems))
-			return h;
-	}
-	return NULL;
-}
-
-static bool mountpoint_is_accessible(struct cgroup_mount_point *mp)
-{
-	return mp && access(mp->mount_point, F_OK) == 0;
-}
-
-static struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *hierarchy, const char *group, bool should_be_writable)
-{
-	struct cgroup_mount_point **mps;
-	struct cgroup_mount_point *current_result = NULL;
-	ssize_t quality = -1;
-
-	/* trivial case */
-	if (mountpoint_is_accessible(hierarchy->rw_absolute_mount_point))
-		return hierarchy->rw_absolute_mount_point;
-	if (!should_be_writable && mountpoint_is_accessible(hierarchy->ro_absolute_mount_point))
-		return hierarchy->ro_absolute_mount_point;
-
-	for (mps = hierarchy->all_mount_points; mps && *mps; mps++) {
-		struct cgroup_mount_point *mp = *mps;
-		size_t prefix_len = mp->mount_prefix ? strlen(mp->mount_prefix) : 0;
-
-		if (prefix_len == 1 && mp->mount_prefix[0] == '/')
-			prefix_len = 0;
-
-		if (!mountpoint_is_accessible(mp))
-			continue;
-
-		if (should_be_writable && mp->read_only)
-			continue;
-
-		if (!prefix_len ||
-		    (strncmp(group, mp->mount_prefix, prefix_len) == 0 &&
-		     (group[prefix_len] == '\0' || group[prefix_len] == '/'))) {
-			/* search for the best quality match, i.e. the match with the
-			 * shortest prefix where this group is still contained
-			 */
-			if (quality == -1 || prefix_len < quality) {
-				current_result = mp;
-				quality = prefix_len;
-			}
-		}
-	}
-
-	if (!current_result)
-		errno = ENOENT;
-	return current_result;
-}
-
-static char *lxc_cgroup_find_abs_path(const char *subsystem, const char *group, bool should_be_writable, const char *suffix)
-{
-	struct cgroup_meta_data *meta_data;
-	struct cgroup_hierarchy *h;
-	struct cgroup_mount_point *mp;
-	char *result;
-	int saved_errno;
-
-	meta_data = lxc_cgroup_load_meta();
-	if (!meta_data)
-		return NULL;
-
-	h = lxc_cgroup_find_hierarchy(meta_data, subsystem);
-	if (!h)
-		goto out_error;
-
-	mp = lxc_cgroup_find_mount_point(h, group, should_be_writable);
-	if (!mp)
-		goto out_error;
-
-	result = cgroup_to_absolute_path(mp, group, suffix);
-	if (!result)
-		goto out_error;
-
-	lxc_cgroup_put_meta(meta_data);
-	return result;
-
-out_error:
-	saved_errno = errno;
-	lxc_cgroup_put_meta(meta_data);
-	errno = saved_errno;
-	return NULL;
-}
-
-static struct cgroup_process_info *lxc_cgroup_process_info_get(pid_t pid, struct cgroup_meta_data *meta)
-{
-	char pid_buf[32];
-	snprintf(pid_buf, 32, "/proc/%lu/cgroup", (unsigned long)pid);
-	return lxc_cgroup_process_info_getx(pid_buf, meta);
-}
-
-static struct cgroup_process_info *lxc_cgroup_process_info_get_init(struct cgroup_meta_data *meta)
-{
-	return lxc_cgroup_process_info_get(1, meta);
-}
-
-static struct cgroup_process_info *lxc_cgroup_process_info_get_self(struct cgroup_meta_data *meta)
-{
-	struct cgroup_process_info *i;
-	i = lxc_cgroup_process_info_getx("/proc/self/cgroup", meta);
-	if (!i)
-		i = lxc_cgroup_process_info_get(getpid(), meta);
-	return i;
-}
-
-/*
- * If a controller has ns cgroup mounted, then in that cgroup the handler->pid
- * is already in a new cgroup named after the pid.  'mnt' is passed in as
- * the full current cgroup.  Say that is /sys/fs/cgroup/lxc/2975 and the container
- * name is c1. .  We want to rename the cgroup directory to /sys/fs/cgroup/lxc/c1,
- * and return the string /sys/fs/cgroup/lxc/c1.
- */
-static char *cgroup_rename_nsgroup(const char *mountpath, const char *oldname, pid_t pid, const char *name)
-{
-	char *dir, *fulloldpath;
-	char *newname, *fullnewpath;
-	int len, newlen, ret;
-
-	/*
-	 * if cgroup is mounted at /cgroup and task is in cgroup /ab/, pid 2375 and
-	 * name is c1,
-	 * dir: /ab
-	 * fulloldpath = /cgroup/ab/2375
-	 * fullnewpath = /cgroup/ab/c1
-	 * newname = /ab/c1
-	 */
-	dir = alloca(strlen(oldname) + 1);
-	strcpy(dir, oldname);
-
-	len = strlen(oldname) + strlen(mountpath) + 22;
-	fulloldpath = alloca(len);
-	ret = snprintf(fulloldpath, len, "%s/%s/%ld", mountpath, oldname, (unsigned long)pid);
-	if (ret < 0 || ret >= len)
-		return NULL;
-
-	len = strlen(dir) + strlen(name) + 2;
-	newname = malloc(len);
-	if (!newname) {
-		SYSERROR("Out of memory");
-		return NULL;
-	}
-	ret = snprintf(newname, len, "%s/%s", dir, name);
-	if (ret < 0 || ret >= len) {
-		free(newname);
-		return NULL;
-	}
-
-	newlen = strlen(mountpath) + len + 2;
-	fullnewpath = alloca(newlen);
-	ret = snprintf(fullnewpath, newlen, "%s/%s", mountpath, newname);
-	if (ret < 0 || ret >= newlen) {
-		free(newname);
-		return NULL;
-	}
-
-	if (access(fullnewpath, F_OK) == 0) {
-		if (rmdir(fullnewpath) != 0) {
-			SYSERROR("container cgroup %s already exists.", fullnewpath);
-			free(newname);
-			return NULL;
-		}
-	}
-	if (rename(fulloldpath, fullnewpath)) {
-		SYSERROR("failed to rename cgroup %s->%s", fulloldpath, fullnewpath);
-		free(newname);
-		return NULL;
-	}
-
-	DEBUG("'%s' renamed to '%s'", oldname, newname);
-
-	return newname;
-}
-
-static bool is_crucial_hierarchy(struct cgroup_hierarchy *h)
-{
-	char **p;
-
-	for (p = h->subsystems; *p; p++) {
-		if (is_crucial_cgroup_subsystem(*p))
-			return true;
-	}
-	return false;
-}
-
-/* create a new cgroup */
-static struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern)
-{
-	char **cgroup_path_components = NULL;
-	char **p = NULL;
-	char *path_so_far = NULL;
-	char **new_cgroup_paths = NULL;
-	char **new_cgroup_paths_sub = NULL;
-	struct cgroup_mount_point *mp;
-	struct cgroup_hierarchy *h;
-	struct cgroup_process_info *base_info = NULL;
-	struct cgroup_process_info *info_ptr;
-	int saved_errno;
-	int r;
-	unsigned suffix = 0;
-	bool had_sub_pattern = false;
-	size_t i;
-
-	if (!is_valid_cgroup(name)) {
-		ERROR("Invalid cgroup name: '%s'", name);
-		errno = EINVAL;
-		return NULL;
-	}
-
-	if (!strstr(path_pattern, "%n")) {
-		ERROR("Invalid cgroup path pattern: '%s'; contains no %%n for specifying container name", path_pattern);
-		errno = EINVAL;
-		return NULL;
-	}
-
-	/* we will modify the result of this operation directly,
-	 * so we don't have to copy the data structure
-	 */
-	base_info = (path_pattern[0] == '/') ?
-		lxc_cgroup_process_info_get_init(meta_data) :
-		lxc_cgroup_process_info_get_self(meta_data);
-	if (!base_info)
-		return NULL;
-
-	new_cgroup_paths = calloc(meta_data->maximum_hierarchy + 1, sizeof(char *));
-	if (!new_cgroup_paths)
-		goto out_initial_error;
-
-	new_cgroup_paths_sub = calloc(meta_data->maximum_hierarchy + 1, sizeof(char *));
-	if (!new_cgroup_paths_sub)
-		goto out_initial_error;
-
-	/* find mount points we can use */
-	for (info_ptr = base_info; info_ptr; info_ptr = info_ptr->next) {
-		h = info_ptr->hierarchy;
-		mp = lxc_cgroup_find_mount_point(h, info_ptr->cgroup_path, true);
-		if (!mp) {
-			ERROR("Could not find writable mount point for cgroup hierarchy %d while trying to create cgroup.", h->index);
-			goto out_initial_error;
-		}
-		info_ptr->designated_mount_point = mp;
-
-		if (lxc_string_in_array("ns", (const char **)h->subsystems))
-			continue;
-		if (handle_cgroup_settings(mp, info_ptr->cgroup_path) < 0) {
-			ERROR("Could not set clone_children to 1 for cpuset hierarchy in parent cgroup.");
-			goto out_initial_error;
-		}
-	}
-
-	/* normalize the path */
-	cgroup_path_components = lxc_normalize_path(path_pattern);
-	if (!cgroup_path_components)
-		goto out_initial_error;
-
-	/* go through the path components to see if we can create them */
-	for (p = cgroup_path_components; *p || (sub_pattern && !had_sub_pattern); p++) {
-		/* we only want to create the same component with -1, -2, etc.
-		 * if the component contains the container name itself, otherwise
-		 * it's not an error if it already exists
-		 */
-		char *p_eff = *p ? *p : (char *)sub_pattern;
-		bool contains_name = strstr(p_eff, "%n");
-		char *current_component = NULL;
-		char *current_subpath = NULL;
-		char *current_entire_path = NULL;
-		char *parts[3];
-		size_t j = 0;
-		i = 0;
-
-		/* if we are processing the subpattern, we want to make sure
-		 * loop is ended the next time around
-		 */
-		if (!*p) {
-			had_sub_pattern = true;
-			p--;
-		}
-
-		goto find_name_on_this_level;
-
-	cleanup_name_on_this_level:
-		/* This is reached if we found a name clash.
-		 * In that case, remove the cgroup from all previous hierarchies
-		 */
-		for (j = 0, info_ptr = base_info; j < i && info_ptr; info_ptr = info_ptr->next, j++) {
-			if (info_ptr->created_paths_count < 1)
-				continue;
-			r = remove_cgroup(info_ptr->designated_mount_point, info_ptr->created_paths[info_ptr->created_paths_count - 1], false, NULL);
-			if (r < 0)
-				WARN("could not clean up cgroup we created when trying to create container");
-			free(info_ptr->created_paths[info_ptr->created_paths_count - 1]);
-			info_ptr->created_paths[--info_ptr->created_paths_count] = NULL;
-		}
-		if (current_component != current_subpath)
-			free(current_subpath);
-		if (current_component != p_eff)
-			free(current_component);
-		current_component = current_subpath = NULL;
-		/* try again with another suffix */
-		++suffix;
-
-	find_name_on_this_level:
-		/* determine name of the path component we should create */
-		if (contains_name && suffix > 0) {
-			char *buf = calloc(strlen(name) + 32, 1);
-			if (!buf)
-				goto out_initial_error;
-			snprintf(buf, strlen(name) + 32, "%s-%u", name, suffix);
-			current_component = lxc_string_replace("%n", buf, p_eff);
-			free(buf);
-		} else {
-			current_component = contains_name ? lxc_string_replace("%n", name, p_eff) : p_eff;
-		}
-		parts[0] = path_so_far;
-		parts[1] = current_component;
-		parts[2] = NULL;
-		current_subpath = path_so_far ? lxc_string_join("/", (const char **)parts, false) : current_component;
-
-		/* Now go through each hierarchy and try to create the
-		 * corresponding cgroup
-		 */
-		for (i = 0, info_ptr = base_info; info_ptr; info_ptr = info_ptr->next, i++) {
-			char *parts2[3];
-
-			if (lxc_string_in_array("ns", (const char **)info_ptr->hierarchy->subsystems))
-				continue;
-			current_entire_path = NULL;
-
-			parts2[0] = !strcmp(info_ptr->cgroup_path, "/") ? "" : info_ptr->cgroup_path;
-			parts2[1] = current_subpath;
-			parts2[2] = NULL;
-			current_entire_path = lxc_string_join("/", (const char **)parts2, false);
-
-			if (!*p) {
-				/* we are processing the subpath, so only update that one */
-				free(new_cgroup_paths_sub[i]);
-				new_cgroup_paths_sub[i] = strdup(current_entire_path);
-				if (!new_cgroup_paths_sub[i])
-					goto cleanup_from_error;
-			} else {
-				/* remember which path was used on this controller */
-				free(new_cgroup_paths[i]);
-				new_cgroup_paths[i] = strdup(current_entire_path);
-				if (!new_cgroup_paths[i])
-					goto cleanup_from_error;
-			}
-
-			r = create_cgroup(info_ptr->designated_mount_point, current_entire_path);
-			if (r < 0 && errno == EEXIST && contains_name) {
-				/* name clash => try new name with new suffix */
-				free(current_entire_path);
-				current_entire_path = NULL;
-				goto cleanup_name_on_this_level;
-			} else if (r < 0 && errno != EEXIST) {
-				if (is_crucial_hierarchy(info_ptr->hierarchy)) {
-					SYSERROR("Could not create cgroup '%s' in '%s'.", current_entire_path, info_ptr->designated_mount_point->mount_point);
-					goto cleanup_from_error;
-				}
-				goto skip;
-			} else if (r == 0) {
-				/* successfully created */
-				r = lxc_grow_array((void ***)&info_ptr->created_paths, &info_ptr->created_paths_capacity, info_ptr->created_paths_count + 1, 8);
-				if (r < 0)
-					goto cleanup_from_error;
-				if (!init_cpuset_if_needed(info_ptr->designated_mount_point, current_entire_path)) {
-					ERROR("Failed to initialize cpuset for '%s' in '%s'.", current_entire_path, info_ptr->designated_mount_point->mount_point);
-					goto cleanup_from_error;
-				}
-				info_ptr->created_paths[info_ptr->created_paths_count++] = current_entire_path;
-			} else {
-				/* if we didn't create the cgroup, then we have to make sure that
-				 * further cgroups will be created properly
-				 */
-				if (handle_cgroup_settings(info_ptr->designated_mount_point, info_ptr->cgroup_path) < 0) {
-					ERROR("Could not set clone_children to 1 for cpuset hierarchy in pre-existing cgroup.");
-					goto cleanup_from_error;
-				}
-				if (!init_cpuset_if_needed(info_ptr->designated_mount_point, info_ptr->cgroup_path)) {
-					ERROR("Failed to initialize cpuset in pre-existing '%s'.", info_ptr->cgroup_path);
-					goto cleanup_from_error;
-				}
-
-skip:
-				/* already existed but path component of pattern didn't contain '%n',
-				 * so this is not an error; but then we don't need current_entire_path
-				 * anymore...
-				 */
-				free(current_entire_path);
-				current_entire_path = NULL;
-			}
-		}
-
-		/* save path so far */
-		free(path_so_far);
-		path_so_far = strdup(current_subpath);
-		if (!path_so_far)
-			goto cleanup_from_error;
-
-		/* cleanup */
-		if (current_component != current_subpath)
-			free(current_subpath);
-		if (current_component != p_eff)
-			free(current_component);
-		current_component = current_subpath = NULL;
-		continue;
-
-	cleanup_from_error:
-		/* called if an error occurred in the loop, so we
-		 * do some additional cleanup here
-		 */
-		saved_errno = errno;
-		if (current_component != current_subpath)
-			free(current_subpath);
-		if (current_component != p_eff)
-			free(current_component);
-		free(current_entire_path);
-		errno = saved_errno;
-		goto out_initial_error;
-	}
-
-	/* we're done, now update the paths */
-	for (i = 0, info_ptr = base_info; info_ptr; info_ptr = info_ptr->next, i++) {
-		/* ignore legacy 'ns' subsystem here, lxc_cgroup_create_legacy
-		 * will take care of it
-		 * Since we do a continue in above loop, new_cgroup_paths[i] is
-		 * unset anyway, as is new_cgroup_paths_sub[i]
-		 */
-		if (lxc_string_in_array("ns", (const char **)info_ptr->hierarchy->subsystems))
-			continue;
-		free(info_ptr->cgroup_path);
-		info_ptr->cgroup_path = new_cgroup_paths[i];
-		info_ptr->cgroup_path_sub = new_cgroup_paths_sub[i];
-	}
-	/* don't use lxc_free_array since we used the array members
-	 * to store them in our result...
-	 */
-	free(new_cgroup_paths);
-	free(new_cgroup_paths_sub);
-	free(path_so_far);
-	lxc_free_array((void **)cgroup_path_components, free);
-	return base_info;
-
-out_initial_error:
-	saved_errno = errno;
-	free(path_so_far);
-	lxc_cgroup_process_info_free_and_remove(base_info, NULL);
-	lxc_free_array((void **)new_cgroup_paths, free);
-	lxc_free_array((void **)new_cgroup_paths_sub, free);
-	lxc_free_array((void **)cgroup_path_components, free);
-	errno = saved_errno;
-	return NULL;
-}
-
-static int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *name, pid_t pid)
-{
-	struct cgroup_process_info *info_ptr;
-	int r;
-
-	for (info_ptr = base_info; info_ptr; info_ptr = info_ptr->next) {
-		if (!lxc_string_in_array("ns", (const char **)info_ptr->hierarchy->subsystems))
-			continue;
-		/*
-		 * For any path which has ns cgroup mounted, handler->pid is already
-		 * moved into a container called '%d % (handler->pid)'.  Rename it to
-		 * the cgroup name and record that.
-		 */
-		char *tmp = cgroup_rename_nsgroup((const char *)info_ptr->designated_mount_point->mount_point,
-				info_ptr->cgroup_path, pid, name);
-		if (!tmp)
-			return -1;
-		free(info_ptr->cgroup_path);
-		info_ptr->cgroup_path = tmp;
-		r = lxc_grow_array((void ***)&info_ptr->created_paths, &info_ptr->created_paths_capacity, info_ptr->created_paths_count + 1, 8);
-		if (r < 0)
-			return -1;
-		tmp = strdup(tmp);
-		if (!tmp)
-			return -1;
-		info_ptr->created_paths[info_ptr->created_paths_count++] = tmp;
-	}
-	return 0;
-}
-
-/* get the cgroup membership of a given container */
-static struct cgroup_process_info *lxc_cgroup_get_container_info(const char *name, const char *lxcpath, struct cgroup_meta_data *meta_data)
-{
-	struct cgroup_process_info *result = NULL;
-	int saved_errno = 0;
-	size_t i;
-	struct cgroup_process_info **cptr = &result;
-	struct cgroup_process_info *entry = NULL;
-	char *path = NULL;
-
-	for (i = 0; i <= meta_data->maximum_hierarchy; i++) {
-		struct cgroup_hierarchy *h = meta_data->hierarchies[i];
-		if (!h || !h->used)
-			continue;
-
-		/* use the command interface to look for the cgroup */
-		path = lxc_cmd_get_cgroup_path(name, lxcpath, h->subsystems[0]);
-		if (!path) {
-			h->used = false;
-			continue;
-		}
-
-		entry = calloc(1, sizeof(struct cgroup_process_info));
-		if (!entry)
-			goto out_error;
-		entry->meta_ref = lxc_cgroup_get_meta(meta_data);
-		entry->hierarchy = h;
-		entry->cgroup_path = path;
-		path = NULL;
-
-		/* it is not an error if we don't find anything here,
-		 * it is up to the caller to decide what to do in that
-		 * case */
-		entry->designated_mount_point = lxc_cgroup_find_mount_point(h, entry->cgroup_path, true);
-
-		*cptr = entry;
-		cptr = &entry->next;
-		entry = NULL;
-	}
-
-	return result;
-out_error:
-	saved_errno = errno;
-	free(path);
-	lxc_cgroup_process_info_free(result);
-	lxc_cgroup_process_info_free(entry);
-	errno = saved_errno;
-	return NULL;
-}
-
-/* move a processs to the cgroups specified by the membership */
-static int lxc_cgroupfs_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub)
-{
-	char pid_buf[32];
-	char *cgroup_tasks_fn;
-	int r;
-	struct cgroup_process_info *info_ptr;
-
-	snprintf(pid_buf, 32, "%lu", (unsigned long)pid);
-	for (info_ptr = info; info_ptr; info_ptr = info_ptr->next) {
-		char *cgroup_path = (enter_sub && info_ptr->cgroup_path_sub) ?
-			info_ptr->cgroup_path_sub :
-			info_ptr->cgroup_path;
-
-		if (!info_ptr->designated_mount_point) {
-			info_ptr->designated_mount_point = lxc_cgroup_find_mount_point(info_ptr->hierarchy, cgroup_path, true);
-			if (!info_ptr->designated_mount_point) {
-				SYSERROR("Could not add pid %lu to cgroup %s: internal error (couldn't find any writable mountpoint to cgroup filesystem)", (unsigned long)pid, cgroup_path);
-				return -1;
-			}
-		}
-
-		cgroup_tasks_fn = cgroup_to_absolute_path(info_ptr->designated_mount_point, cgroup_path, "/tasks");
-		if (!cgroup_tasks_fn) {
-			SYSERROR("Could not add pid %lu to cgroup %s: internal error", (unsigned long)pid, cgroup_path);
-			return -1;
-		}
-
-		r = lxc_write_to_file(cgroup_tasks_fn, pid_buf, strlen(pid_buf), false);
-		free(cgroup_tasks_fn);
-		if (r < 0 && is_crucial_hierarchy(info_ptr->hierarchy)) {
-			SYSERROR("Could not add pid %lu to cgroup %s: internal error", (unsigned long)pid, cgroup_path);
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-/* free process membership information */
-void lxc_cgroup_process_info_free(struct cgroup_process_info *info)
-{
-	struct cgroup_process_info *next;
-	if (!info)
-		return;
-	next = info->next;
-	lxc_cgroup_put_meta(info->meta_ref);
-	free(info->cgroup_path);
-	free(info->cgroup_path_sub);
-	lxc_free_array((void **)info->created_paths, free);
-	free(info);
-	lxc_cgroup_process_info_free(next);
-}
-
-/* free process membership information and remove cgroups that were created */
-void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info, struct lxc_conf *conf)
-{
-	struct cgroup_process_info *next;
-	char **pp;
-	if (!info)
-		return;
-	next = info->next;
-	{
-		struct cgroup_mount_point *mp = info->designated_mount_point;
-		if (!mp)
-			mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
-		if (mp)
-			/* ignore return value here, perhaps we created the
-			 * '/lxc' cgroup in this container but another container
-			 * is still running (for example)
-			 */
-			(void)remove_cgroup(mp, info->cgroup_path, true, conf);
-	}
-	for (pp = info->created_paths; pp && *pp; pp++);
-	for ((void)(pp && --pp); info->created_paths && pp >= info->created_paths; --pp) {
-		free(*pp);
-	}
-	free(info->created_paths);
-	lxc_cgroup_put_meta(info->meta_ref);
-	free(info->cgroup_path);
-	free(info->cgroup_path_sub);
-	free(info);
-	lxc_cgroup_process_info_free_and_remove(next, conf);
-}
-
-static char *lxc_cgroup_get_hierarchy_path_data(const char *subsystem, struct cgfs_data *d)
-{
-	struct cgroup_process_info *info = d->info;
-	info = find_info_for_subsystem(info, subsystem);
-	if (!info)
-		return NULL;
-	prune_init_scope(info->cgroup_path);
-	return info->cgroup_path;
-}
-
-static char *lxc_cgroup_get_hierarchy_abs_path_data(const char *subsystem, struct cgfs_data *d)
-{
-	struct cgroup_process_info *info = d->info;
-	struct cgroup_mount_point *mp = NULL;
-
-	info = find_info_for_subsystem(info, subsystem);
-	if (!info)
-		return NULL;
-	if (info->designated_mount_point) {
-		mp = info->designated_mount_point;
-	} else {
-		mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
-		if (!mp)
-			return NULL;
-	}
-	return cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
-}
-
-static char *lxc_cgroup_get_hierarchy_abs_path(const char *subsystem, const char *name, const char *lxcpath)
-{
-	struct cgroup_meta_data *meta;
-	struct cgroup_process_info *base_info, *info;
-	struct cgroup_mount_point *mp;
-	char *result = NULL;
-
-	meta = lxc_cgroup_load_meta();
-	if (!meta)
-		return NULL;
-	base_info = lxc_cgroup_get_container_info(name, lxcpath, meta);
-	if (!base_info)
-		goto out1;
-	info = find_info_for_subsystem(base_info, subsystem);
-	if (!info)
-		goto out2;
-	if (info->designated_mount_point) {
-		mp = info->designated_mount_point;
-	} else {
-		mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
-		if (!mp)
-			goto out3;
-	}
-	result = cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
-out3:
-out2:
-	lxc_cgroup_process_info_free(base_info);
-out1:
-	lxc_cgroup_put_meta(meta);
-	return result;
-}
-
-static int lxc_cgroup_set_data(const char *filename, const char *value, struct cgfs_data *d)
-{
-	char *subsystem = NULL, *p, *path;
-	int ret = -1;
-
-	subsystem = alloca(strlen(filename) + 1);
-	strcpy(subsystem, filename);
-	if ((p = strchr(subsystem, '.')) != NULL)
-		*p = '\0';
-
-	errno = ENOENT;
-	path = lxc_cgroup_get_hierarchy_abs_path_data(subsystem, d);
-	if (path) {
-		ret = do_cgroup_set(path, filename, value);
-		int saved_errno = errno;
-		free(path);
-		errno = saved_errno;
-	}
-	return ret;
-}
-
-static int lxc_cgroupfs_set(const char *filename, const char *value, const char *name, const char *lxcpath)
-{
-	char *subsystem = NULL, *p, *path;
-	int ret = -1;
-
-	subsystem = alloca(strlen(filename) + 1);
-	strcpy(subsystem, filename);
-	if ((p = strchr(subsystem, '.')) != NULL)
-		*p = '\0';
-
-	path = lxc_cgroup_get_hierarchy_abs_path(subsystem, name, lxcpath);
-	if (path) {
-		ret = do_cgroup_set(path, filename, value);
-		free(path);
-	}
-	return ret;
-}
-
-static int lxc_cgroupfs_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
-{
-	char *subsystem = NULL, *p, *path;
-	int ret = -1;
-
-	subsystem = alloca(strlen(filename) + 1);
-	strcpy(subsystem, filename);
-	if ((p = strchr(subsystem, '.')) != NULL)
-		*p = '\0';
-
-	path = lxc_cgroup_get_hierarchy_abs_path(subsystem, name, lxcpath);
-	if (path) {
-		ret = do_cgroup_get(path, filename, value, len);
-		free(path);
-	}
-	return ret;
-}
-
-static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
-{
-	size_t bufsz = strlen(root) + sizeof("/sys/fs/cgroup");
-	char *path = NULL;
-	char **parts = NULL;
-	char *dirname = NULL;
-	char *abs_path = NULL;
-	char *abs_path2 = NULL;
-	struct cgfs_data *cgfs_d;
-	struct cgroup_process_info *info, *base_info;
-	int r, saved_errno = 0;
-
-	if (cgns_supported())
-		return true;
-
-	cgfs_d = hdata;
-	if (!cgfs_d)
-		return false;
-	base_info = cgfs_d->info;
-
-	/* If we get passed the _NOSPEC types, we default to _MIXED, since we don't
-	 * have access to the lxc_conf object at this point. It really should be up
-	 * to the caller to fix this, but this doesn't really hurt.
-	 */
-	if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
-		type = LXC_AUTO_CGROUP_FULL_MIXED;
-	else if (type == LXC_AUTO_CGROUP_NOSPEC)
-		type = LXC_AUTO_CGROUP_MIXED;
-
-	if (type < LXC_AUTO_CGROUP_RO || type > LXC_AUTO_CGROUP_FULL_MIXED) {
-		ERROR("could not mount cgroups into container: invalid type specified internally");
-		errno = EINVAL;
-		return false;
-	}
-
-	path = calloc(1, bufsz);
-	if (!path)
-		return false;
-	snprintf(path, bufsz, "%s/sys/fs/cgroup", root);
-	r = safe_mount("cgroup_root", path, "tmpfs",
-			MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME,
-			"size=10240k,mode=755",
-			root);
-	if (r < 0) {
-		SYSERROR("could not mount tmpfs to /sys/fs/cgroup in the container");
-		return false;
-	}
-
-	/* now mount all the hierarchies we care about */
-	for (info = base_info; info; info = info->next) {
-		size_t subsystem_count, i;
-		struct cgroup_mount_point *mp = info->designated_mount_point;
-		if (!mountpoint_is_accessible(mp))
-			mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
-
-		if (!mp) {
-			SYSERROR("could not find original mount point for cgroup hierarchy while trying to mount cgroup filesystem");
-			goto out_error;
-		}
-
-		subsystem_count = lxc_array_len((void **)info->hierarchy->subsystems);
-		parts = calloc(subsystem_count + 1, sizeof(char *));
-		if (!parts)
-			goto out_error;
-
-		for (i = 0; i < subsystem_count; i++) {
-			if (!strncmp(info->hierarchy->subsystems[i], "name=", 5))
-				parts[i] = info->hierarchy->subsystems[i] + 5;
-			else
-				parts[i] = info->hierarchy->subsystems[i];
-		}
-		dirname = lxc_string_join(",", (const char **)parts, false);
-		if (!dirname)
-			goto out_error;
-
-		/* create subsystem directory */
-		abs_path = lxc_append_paths(path, dirname);
-		if (!abs_path)
-			goto out_error;
-		r = mkdir_p(abs_path, 0755);
-		if (r < 0 && errno != EEXIST) {
-			SYSERROR("could not create cgroup subsystem directory /sys/fs/cgroup/%s", dirname);
-			goto out_error;
-		}
-
-		abs_path2 = lxc_append_paths(abs_path, info->cgroup_path);
-		if (!abs_path2)
-			goto out_error;
-
-		if (type == LXC_AUTO_CGROUP_FULL_RO || type == LXC_AUTO_CGROUP_FULL_RW || type == LXC_AUTO_CGROUP_FULL_MIXED) {
-			/* bind-mount the cgroup entire filesystem there */
-			if (strcmp(mp->mount_prefix, "/") != 0) {
-				/* FIXME: maybe we should just try to remount the entire hierarchy
-				 *        with a regular mount command? may that works? */
-				ERROR("could not automatically mount cgroup-full to /sys/fs/cgroup/%s: host has no mount point for this cgroup filesystem that has access to the root cgroup", dirname);
-				goto out_error;
-			}
-			r = mount(mp->mount_point, abs_path, "none", MS_BIND, 0);
-			if (r < 0) {
-				SYSERROR("error bind-mounting %s to %s", mp->mount_point, abs_path);
-				goto out_error;
-			}
-			/* main cgroup path should be read-only */
-			if (type == LXC_AUTO_CGROUP_FULL_RO || type == LXC_AUTO_CGROUP_FULL_MIXED) {
-				r = mount(NULL, abs_path, NULL, MS_REMOUNT|MS_BIND|MS_RDONLY, NULL);
-				if (r < 0) {
-					SYSERROR("error re-mounting %s readonly", abs_path);
-					goto out_error;
-				}
-			}
-			/* own cgroup should be read-write */
-			if (type == LXC_AUTO_CGROUP_FULL_MIXED) {
-				r = mount(abs_path2, abs_path2, NULL, MS_BIND, NULL);
-				if (r < 0) {
-					SYSERROR("error bind-mounting %s onto itself", abs_path2);
-					goto out_error;
-				}
-				r = mount(NULL, abs_path2, NULL, MS_REMOUNT|MS_BIND, NULL);
-				if (r < 0) {
-					SYSERROR("error re-mounting %s readwrite", abs_path2);
-					goto out_error;
-				}
-			}
-		} else {
-			/* create path for container's cgroup */
-			r = mkdir_p(abs_path2, 0755);
-			if (r < 0 && errno != EEXIST) {
-				SYSERROR("could not create cgroup directory /sys/fs/cgroup/%s%s", dirname, info->cgroup_path);
-				goto out_error;
-			}
-
-			/* for read-only and mixed cases, we have to bind-mount the tmpfs directory
-			 * that points to the hierarchy itself (i.e. /sys/fs/cgroup/cpu etc.) onto
-			 * itself and then bind-mount it read-only, since we keep the tmpfs itself
-			 * read-write (see comment below)
-			 */
-			if (type == LXC_AUTO_CGROUP_MIXED || type == LXC_AUTO_CGROUP_RO) {
-				r = mount(abs_path, abs_path, NULL, MS_BIND, NULL);
-				if (r < 0) {
-					SYSERROR("error bind-mounting %s onto itself", abs_path);
-					goto out_error;
-				}
-				r = mount(NULL, abs_path, NULL, MS_REMOUNT|MS_BIND|MS_RDONLY, NULL);
-				if (r < 0) {
-					SYSERROR("error re-mounting %s readonly", abs_path);
-					goto out_error;
-				}
-			}
-
-			free(abs_path);
-			abs_path = NULL;
-
-			/* bind-mount container's cgroup to that directory */
-			abs_path = cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
-			if (!abs_path)
-				goto out_error;
-			r = mount(abs_path, abs_path2, "none", MS_BIND, 0);
-			if (r < 0 && is_crucial_hierarchy(info->hierarchy)) {
-				SYSERROR("error bind-mounting %s to %s", abs_path, abs_path2);
-				goto out_error;
-			}
-			if (type == LXC_AUTO_CGROUP_RO) {
-				r = mount(NULL, abs_path2, NULL, MS_REMOUNT|MS_BIND|MS_RDONLY, NULL);
-				if (r < 0) {
-					SYSERROR("error re-mounting %s readonly", abs_path2);
-					goto out_error;
-				}
-			}
-		}
-
-		free(abs_path);
-		free(abs_path2);
-		abs_path = NULL;
-		abs_path2 = NULL;
-
-		/* add symlinks for every single subsystem */
-		if (subsystem_count > 1) {
-			for (i = 0; i < subsystem_count; i++) {
-				abs_path = lxc_append_paths(path, parts[i]);
-				if (!abs_path)
-					goto out_error;
-				r = symlink(dirname, abs_path);
-				if (r < 0)
-					WARN("could not create symlink %s -> %s in /sys/fs/cgroup of container", parts[i], dirname);
-				free(abs_path);
-				abs_path = NULL;
-			}
-		}
-		free(dirname);
-		free(parts);
-		dirname = NULL;
-		parts = NULL;
-	}
-
-	/* We used to remount the entire tmpfs readonly if any :ro or
-	 * :mixed mode was specified. However, Ubuntu's mountall has the
-	 * unfortunate behavior to block bootup if /sys/fs/cgroup is
-	 * mounted read-only and cannot be remounted read-write.
-	 * (mountall reads /lib/init/fstab and tries to (re-)mount all of
-	 * these if they are not already mounted with the right options;
-	 * it contains an entry for /sys/fs/cgroup. In case it can't do
-	 * that, it prompts for the user to either manually fix it or
-	 * boot anyway. But without user input, booting of the container
-	 * hangs.)
-	 *
-	 * Instead of remounting the entire tmpfs readonly, we only
-	 * remount the paths readonly that are part of the cgroup
-	 * hierarchy.
-	 */
-
-	free(path);
-
-	return true;
-
-out_error:
-	saved_errno = errno;
-	free(path);
-	free(dirname);
-	free(parts);
-	free(abs_path);
-	free(abs_path2);
-	errno = saved_errno;
-	return false;
-}
-
-static int cgfs_nrtasks(void *hdata)
-{
-	struct cgfs_data *d = hdata;
-	struct cgroup_process_info *info;
-	struct cgroup_mount_point *mp = NULL;
-	char *abs_path = NULL;
-	int ret;
-
-	if (!d) {
-		errno = ENOENT;
-		return -1;
-	}
-
-	info = d->info;
-	if (!info) {
-		errno = ENOENT;
-		return -1;
-	}
-
-	if (info->designated_mount_point) {
-		mp = info->designated_mount_point;
-	} else {
-		mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, false);
-		if (!mp)
-			return -1;
-	}
-
-	abs_path = cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
-	if (!abs_path)
-		return -1;
-
-	ret = cgroup_recursive_task_count(abs_path);
-	free(abs_path);
-	return ret;
-}
-
-static struct cgroup_process_info *
-lxc_cgroup_process_info_getx(const char *proc_pid_cgroup_str,
-			     struct cgroup_meta_data *meta)
-{
-	struct cgroup_process_info *result = NULL;
-	FILE *proc_pid_cgroup = NULL;
-	char *line = NULL;
-	size_t sz = 0;
-	int saved_errno = 0;
-	struct cgroup_process_info **cptr = &result;
-	struct cgroup_process_info *entry = NULL;
-
-	proc_pid_cgroup = fopen_cloexec(proc_pid_cgroup_str, "r");
-	if (!proc_pid_cgroup)
-		return NULL;
-
-	while (getline(&line, &sz, proc_pid_cgroup) != -1) {
-		/* file format: hierarchy:subsystems:group */
-		char *colon1;
-		char *colon2;
-		char *endptr;
-		int hierarchy_number;
-		struct cgroup_hierarchy *h = NULL;
-
-		if (!line[0])
-			continue;
-
-		if (line[strlen(line) - 1] == '\n')
-			line[strlen(line) - 1] = '\0';
-
-		colon1 = strchr(line, ':');
-		if (!colon1)
-			continue;
-		*colon1++ = '\0';
-		colon2 = strchr(colon1, ':');
-		if (!colon2)
-			continue;
-		*colon2++ = '\0';
-
-		endptr = NULL;
-		hierarchy_number = strtoul(line, &endptr, 10);
-		if (!endptr || *endptr)
-			continue;
-
-		if (hierarchy_number > meta->maximum_hierarchy) {
-			/* we encountered a hierarchy we didn't have before,
-			 * so probably somebody remounted some stuff in the
-			 * mean time...
-			 */
-			errno = EAGAIN;
-			goto out_error;
-		}
-
-		h = meta->hierarchies[hierarchy_number];
-		if (!h) {
-			/* we encountered a hierarchy that was thought to be
-			 * dead before, so probably somebody remounted some
-			 * stuff in the mean time...
-			 */
-			errno = EAGAIN;
-			goto out_error;
-		}
-
-		/* we are told that we should ignore this hierarchy */
-		if (!h->used)
-			continue;
-
-		entry = calloc(1, sizeof(struct cgroup_process_info));
-		if (!entry)
-			goto out_error;
-
-		entry->meta_ref = lxc_cgroup_get_meta(meta);
-		entry->hierarchy = h;
-		entry->cgroup_path = strdup(colon2);
-		if (!entry->cgroup_path)
-			goto out_error;
-		prune_init_scope(entry->cgroup_path);
-
-		*cptr = entry;
-		cptr = &entry->next;
-		entry = NULL;
-	}
-
-	fclose(proc_pid_cgroup);
-	free(line);
-	return result;
-
-out_error:
-	saved_errno = errno;
-	if (proc_pid_cgroup)
-		fclose(proc_pid_cgroup);
-	lxc_cgroup_process_info_free(result);
-	lxc_cgroup_process_info_free(entry);
-	free(line);
-	errno = saved_errno;
-	return NULL;
-}
-
-static char **subsystems_from_mount_options(const char *mount_options,
-					    char **kernel_list)
-{
-	char *token, *str, *saveptr = NULL;
-	char **result = NULL;
-	size_t result_capacity = 0;
-	size_t result_count = 0;
-	int saved_errno;
-	int r;
-
-	str = alloca(strlen(mount_options)+1);
-	strcpy(str, mount_options);
-	for (; (token = strtok_r(str, ",", &saveptr)); str = NULL) {
-		/* we have a subsystem if it's either in the list of
-		 * subsystems provided by the kernel OR if it starts
-		 * with name= for named hierarchies
-		 */
-		r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 12);
-		if (r < 0)
-			goto out_free;
-		result[result_count + 1] = NULL;
-		if (strncmp(token, "name=", 5) && !lxc_string_in_array(token, (const char **)kernel_list)) {
-			// this is eg 'systemd' but the mount will be 'name=systemd'
-			result[result_count] = malloc(strlen(token) + 6);
-			if (result[result_count])
-				sprintf(result[result_count], "name=%s", token);
-		} else
-			result[result_count] = strdup(token);
-		if (!result[result_count])
-			goto out_free;
-		result_count++;
-	}
-
-	return result;
-
-out_free:
-	saved_errno = errno;
-	lxc_free_array((void**)result, free);
-	errno = saved_errno;
-	return NULL;
-}
-
-static void lxc_cgroup_mount_point_free(struct cgroup_mount_point *mp)
-{
-	if (!mp)
-		return;
-	free(mp->mount_point);
-	free(mp->mount_prefix);
-	free(mp);
-}
-
-static void lxc_cgroup_hierarchy_free(struct cgroup_hierarchy *h)
-{
-	if (!h)
-		return;
-	lxc_free_array((void **)h->subsystems, free);
-	free(h->all_mount_points);
-	free(h);
-}
-
-static bool is_valid_cgroup(const char *name)
-{
-	const char *p;
-	for (p = name; *p; p++) {
-		/* Use the ASCII printable characters range(32 - 127)
-		 * is reasonable, we kick out 32(SPACE) because it'll
-		 * break legacy lxc-ls
-		 */
-		if (*p <= 32 || *p >= 127 || *p == '/')
-			return false;
-	}
-	return strcmp(name, ".") != 0 && strcmp(name, "..") != 0;
-}
-
-static int create_or_remove_cgroup(bool do_remove,
-		struct cgroup_mount_point *mp, const char *path, int recurse,
-		struct lxc_conf *conf)
-{
-	int r, saved_errno = 0;
-	char *buf = cgroup_to_absolute_path(mp, path, NULL);
-	if (!buf)
-		return -1;
-
-	/* create or remove directory */
-	if (do_remove) {
-		if (!dir_exists(buf))
-			return 0;
-		if (recurse) {
-			if (conf && !lxc_list_empty(&conf->id_map))
-				r = userns_exec_1(conf, rmdir_wrapper, buf);
-			else
-				r = cgroup_rmdir(buf);
-		} else
-			r = rmdir(buf);
-	} else
-		r = mkdir(buf, 0777);
-	saved_errno = errno;
-	free(buf);
-	errno = saved_errno;
-	return r;
-}
-
-static int create_cgroup(struct cgroup_mount_point *mp, const char *path)
-{
-	return create_or_remove_cgroup(false, mp, path, false, NULL);
-}
-
-static int remove_cgroup(struct cgroup_mount_point *mp,
-			 const char *path, bool recurse, struct lxc_conf *conf)
-{
-	return create_or_remove_cgroup(true, mp, path, recurse, conf);
-}
-
-static char *cgroup_to_absolute_path(struct cgroup_mount_point *mp,
-				     const char *path, const char *suffix)
-{
-	/* first we have to make sure we subtract the mount point's prefix */
-	char *prefix = mp->mount_prefix;
-	char *buf;
-	ssize_t len, rv;
-
-	/* we want to make sure only absolute paths to cgroups are passed to us */
-	if (path[0] != '/') {
-		errno = EINVAL;
-		return NULL;
-	}
-
-	if (prefix && !strcmp(prefix, "/"))
-		prefix = NULL;
-
-	/* prefix doesn't match */
-	if (prefix && strncmp(prefix, path, strlen(prefix)) != 0) {
-		errno = EINVAL;
-		return NULL;
-	}
-	/* if prefix is /foo and path is /foobar */
-	if (prefix && path[strlen(prefix)] != '/' && path[strlen(prefix)] != '\0') {
-		errno = EINVAL;
-		return NULL;
-	}
-
-	/* remove prefix from path */
-	path += prefix ? strlen(prefix) : 0;
-
-	len = strlen(mp->mount_point) + strlen(path) + (suffix ? strlen(suffix) : 0);
-	buf = calloc(len + 1, 1);
-	if (!buf)
-		return NULL;
-	rv = snprintf(buf, len + 1, "%s%s%s", mp->mount_point, path, suffix ? suffix : "");
-	if (rv > len) {
-		free(buf);
-		errno = ENOMEM;
-		return NULL;
-	}
-
-	return buf;
-}
-
-static struct cgroup_process_info *
-find_info_for_subsystem(struct cgroup_process_info *info, const char *subsystem)
-{
-	struct cgroup_process_info *info_ptr;
-	for (info_ptr = info; info_ptr; info_ptr = info_ptr->next) {
-		struct cgroup_hierarchy *h = info_ptr->hierarchy;
-		if (lxc_string_in_array(subsystem, (const char **)h->subsystems))
-			return info_ptr;
-	}
-	errno = ENOENT;
-	return NULL;
-}
-
-static int do_cgroup_get(const char *cgroup_path, const char *sub_filename,
-			 char *value, size_t len)
-{
-	const char *parts[3] = {
-		cgroup_path,
-		sub_filename,
-		NULL
-	};
-	char *filename;
-	int ret, saved_errno;
-
-	filename = lxc_string_join("/", parts, false);
-	if (!filename)
-		return -1;
-
-	ret = lxc_read_from_file(filename, value, len);
-	saved_errno = errno;
-	free(filename);
-	errno = saved_errno;
-	return ret;
-}
-
-static int do_cgroup_set(const char *cgroup_path, const char *sub_filename,
-			 const char *value)
-{
-	const char *parts[3] = {
-		cgroup_path,
-		sub_filename,
-		NULL
-	};
-	char *filename;
-	int ret, saved_errno;
-
-	filename = lxc_string_join("/", parts, false);
-	if (!filename)
-		return -1;
-
-	ret = lxc_write_to_file(filename, value, strlen(value), false);
-	saved_errno = errno;
-	free(filename);
-	errno = saved_errno;
-	return ret;
-}
-
-static int do_setup_cgroup_limits(struct cgfs_data *d,
-			   struct lxc_list *cgroup_settings, bool do_devices)
-{
-	struct lxc_list *iterator, *sorted_cgroup_settings, *next;
-	struct lxc_cgroup *cg;
-	int ret = -1;
-
-	if (lxc_list_empty(cgroup_settings))
-		return 0;
-
-	sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
-	if (!sorted_cgroup_settings) {
-		return -1;
-	}
-
-	lxc_list_for_each(iterator, sorted_cgroup_settings) {
-		cg = iterator->elem;
-
-		if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
-			if (strcmp(cg->subsystem, "devices.deny") == 0 &&
-					cgroup_devices_has_allow_or_deny(d, cg->value, false))
-				continue;
-			if (strcmp(cg->subsystem, "devices.allow") == 0 &&
-					cgroup_devices_has_allow_or_deny(d, cg->value, true))
-				continue;
-			if (lxc_cgroup_set_data(cg->subsystem, cg->value, d)) {
-				if (do_devices && (errno == EACCES || errno == EPERM)) {
-					WARN("Error setting %s to %s for %s",
-					      cg->subsystem, cg->value, d->name);
-					continue;
-				}
-				SYSERROR("Error setting %s to %s for %s",
-				      cg->subsystem, cg->value, d->name);
-				goto out;
-			}
-		}
-
-		DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
-	}
-
-	ret = 0;
-	INFO("cgroup has been setup");
-out:
-	lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
-		lxc_list_del(iterator);
-		free(iterator);
-	}
-	free(sorted_cgroup_settings);
-	return ret;
-}
-
-static bool cgroup_devices_has_allow_or_deny(struct cgfs_data *d,
-					     char *v, bool for_allow)
-{
-	char *path;
-	FILE *devices_list;
-	char *line = NULL;
-	size_t sz = 0;
-	bool ret = !for_allow;
-	const char *parts[3] = {
-		NULL,
-		"devices.list",
-		NULL
-	};
-
-	// XXX FIXME if users could use something other than 'lxc.devices.deny = a'.
-	// not sure they ever do, but they *could*
-	// right now, I'm assuming they do NOT
-	if (!for_allow && strcmp(v, "a") != 0 && strcmp(v, "a *:* rwm") != 0)
-		return false;
-
-	parts[0] = (const char *)lxc_cgroup_get_hierarchy_abs_path_data("devices", d);
-	if (!parts[0])
-		return false;
-	path = lxc_string_join("/", parts, false);
-	if (!path) {
-		free((void *)parts[0]);
-		return false;
-	}
-
-	devices_list = fopen_cloexec(path, "r");
-	if (!devices_list) {
-		free(path);
-		return false;
-	}
-
-	while (getline(&line, &sz, devices_list) != -1) {
-		size_t len = strlen(line);
-		if (len > 0 && line[len-1] == '\n')
-			line[len-1] = '\0';
-		if (strcmp(line, "a *:* rwm") == 0) {
-			ret = for_allow;
-			goto out;
-		} else if (for_allow && strcmp(line, v) == 0) {
-			ret = true;
-			goto out;
-		}
-	}
-
-out:
-	fclose(devices_list);
-	free(line);
-	free(path);
-	return ret;
-}
-
-static int cgroup_recursive_task_count(const char *cgroup_path)
-{
-	DIR *d;
-	struct dirent *dent_buf;
-	struct dirent *dent;
-	ssize_t name_max;
-	int n = 0, r;
-
-	/* see man readdir_r(3) */
-	name_max = pathconf(cgroup_path, _PC_NAME_MAX);
-	if (name_max <= 0)
-		name_max = 255;
-	dent_buf = malloc(offsetof(struct dirent, d_name) + name_max + 1);
-	if (!dent_buf)
-		return -1;
-
-	d = opendir(cgroup_path);
-	if (!d) {
-		free(dent_buf);
-		return 0;
-	}
-
-	while (readdir_r(d, dent_buf, &dent) == 0 && dent) {
-		const char *parts[3] = {
-			cgroup_path,
-			dent->d_name,
-			NULL
-		};
-		char *sub_path;
-		struct stat st;
-
-		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
-			continue;
-		sub_path = lxc_string_join("/", parts, false);
-		if (!sub_path) {
-			closedir(d);
-			free(dent_buf);
-			return -1;
-		}
-		r = stat(sub_path, &st);
-		if (r < 0) {
-			closedir(d);
-			free(dent_buf);
-			free(sub_path);
-			return -1;
-		}
-		if (S_ISDIR(st.st_mode)) {
-			r = cgroup_recursive_task_count(sub_path);
-			if (r >= 0)
-				n += r;
-		} else if (!strcmp(dent->d_name, "tasks")) {
-			r = lxc_count_file_lines(sub_path);
-			if (r >= 0)
-				n += r;
-		}
-		free(sub_path);
-	}
-	closedir(d);
-	free(dent_buf);
-
-	return n;
-}
-
-static int handle_cgroup_settings(struct cgroup_mount_point *mp,
-				  char *cgroup_path)
-{
-	int r, saved_errno = 0;
-	char buf[2];
-
-	mp->need_cpuset_init = false;
-
-	/* If this is the memory cgroup, we want to enforce hierarchy.
-	 * But don't fail if for some reason we can't.
-	 */
-	if (lxc_string_in_array("memory", (const char **)mp->hierarchy->subsystems)) {
-		char *cc_path = cgroup_to_absolute_path(mp, cgroup_path, "/memory.use_hierarchy");
-		if (cc_path) {
-			r = lxc_read_from_file(cc_path, buf, 1);
-			if (r < 1 || buf[0] != '1') {
-				r = lxc_write_to_file(cc_path, "1", 1, false);
-				if (r < 0)
-					SYSERROR("failed to set memory.use_hierarchy to 1; continuing");
-			}
-			free(cc_path);
-		}
-	}
-
-	/* if this is a cpuset hierarchy, we have to set cgroup.clone_children in
-	 * the base cgroup, otherwise containers will start with an empty cpuset.mems
-	 * and cpuset.cpus and then
-	 */
-	if (lxc_string_in_array("cpuset", (const char **)mp->hierarchy->subsystems)) {
-		char *cc_path = cgroup_to_absolute_path(mp, cgroup_path, "/cgroup.clone_children");
-		struct stat sb;
-
-		if (!cc_path)
-			return -1;
-		/* cgroup.clone_children is not available when running under
-		 * older kernel versions; in this case, we'll initialize
-		 * cpuset.cpus and cpuset.mems later, after the new cgroup
-		 * was created
-		 */
-		if (stat(cc_path, &sb) != 0 && errno == ENOENT) {
-			mp->need_cpuset_init = true;
-			free(cc_path);
-			return 0;
-		}
-		r = lxc_read_from_file(cc_path, buf, 1);
-		if (r == 1 && buf[0] == '1') {
-			free(cc_path);
-			return 0;
-		}
-		r = lxc_write_to_file(cc_path, "1", 1, false);
-		saved_errno = errno;
-		free(cc_path);
-		errno = saved_errno;
-		return r < 0 ? -1 : 0;
-	}
-	return 0;
-}
-
-static int cgroup_read_from_file(const char *fn, char buf[], size_t bufsize)
-{
-	int ret = lxc_read_from_file(fn, buf, bufsize);
-	if (ret < 0) {
-		SYSERROR("failed to read %s", fn);
-		return ret;
-	}
-	if (ret == bufsize) {
-		if (bufsize > 0) {
-			/* obviously this wasn't empty */
-			buf[bufsize-1] = '\0';
-			return ret;
-		}
-		/* Callers don't do this, but regression/sanity check */
-		ERROR("%s: was not expecting 0 bufsize", __func__);
-		return -1;
-	}
-	buf[ret] = '\0';
-	return ret;
-}
-
-static bool do_init_cpuset_file(struct cgroup_mount_point *mp,
-				const char *path, const char *name)
-{
-	char value[1024];
-	char *childfile, *parentfile = NULL, *tmp;
-	int ret;
-	bool ok = false;
-
-	childfile = cgroup_to_absolute_path(mp, path, name);
-	if (!childfile)
-		return false;
-
-	/* don't overwrite a non-empty value in the file */
-	ret = cgroup_read_from_file(childfile, value, sizeof(value));
-	if (ret < 0)
-		goto out;
-	if (value[0] != '\0' && value[0] != '\n') {
-		ok = true;
-		goto out;
-	}
-
-	/* path to the same name in the parent cgroup */
-	parentfile = strdup(path);
-	if (!parentfile)
-		goto out;
-
-	tmp = strrchr(parentfile, '/');
-	if (!tmp)
-		goto out;
-	if (tmp == parentfile)
-		tmp++; /* keep the '/' at the start */
-	*tmp = '\0';
-	tmp = parentfile;
-	parentfile = cgroup_to_absolute_path(mp, tmp, name);
-	free(tmp);
-	if (!parentfile)
-		goto out;
-
-	/* copy from parent to child cgroup */
-	ret = cgroup_read_from_file(parentfile, value, sizeof(value));
-	if (ret < 0)
-		goto out;
-	if (ret == sizeof(value)) {
-		/* If anyone actually sees this error, we can address it */
-		ERROR("parent cpuset value too long");
-		goto out;
-	}
-	ok = (lxc_write_to_file(childfile, value, strlen(value), false) >= 0);
-	if (!ok)
-		SYSERROR("failed writing %s", childfile);
-
-out:
-	free(parentfile);
-	free(childfile);
-	return ok;
-}
-
-static bool init_cpuset_if_needed(struct cgroup_mount_point *mp,
-				  const char *path)
-{
-	/* the files we have to handle here are only in cpuset hierarchies */
-	if (!lxc_string_in_array("cpuset",
-				 (const char **)mp->hierarchy->subsystems))
-		return true;
-
-	if (!mp->need_cpuset_init)
-		return true;
-
-	return (do_init_cpuset_file(mp, path, "/cpuset.cpus") &&
-		do_init_cpuset_file(mp, path, "/cpuset.mems") );
-}
-
-struct cgroup_ops *cgfs_ops_init(void)
-{
-	return &cgfs_ops;
-}
-
-static void *cgfs_init(const char *name)
-{
-	struct cgfs_data *d;
-
-	d = malloc(sizeof(*d));
-	if (!d)
-		return NULL;
-
-	memset(d, 0, sizeof(*d));
-	d->name = strdup(name);
-	if (!d->name)
-		goto err1;
-
-	d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
-
-	d->meta = lxc_cgroup_load_meta();
-	if (!d->meta) {
-		ERROR("cgroupfs failed to detect cgroup metadata");
-		goto err2;
-	}
-	return d;
-
-err2:
-	free(d->name);
-err1:
-	free(d);
-	return NULL;
-}
-
-static void cgfs_destroy(void *hdata, struct lxc_conf *conf)
-{
-	struct cgfs_data *d = hdata;
-
-	if (!d)
-		return;
-	free(d->name);
-	lxc_cgroup_process_info_free_and_remove(d->info, conf);
-	lxc_cgroup_put_meta(d->meta);
-	free(d);
-}
-
-static inline bool cgfs_create(void *hdata)
-{
-	struct cgfs_data *d = hdata;
-	struct cgroup_process_info *i;
-	struct cgroup_meta_data *md;
-
-	if (!d)
-		return false;
-	md = d->meta;
-	i = lxc_cgroupfs_create(d->name, d->cgroup_pattern, md, NULL);
-	if (!i)
-		return false;
-	d->info = i;
-	return true;
-}
-
-static inline bool cgfs_enter(void *hdata, pid_t pid)
-{
-	struct cgfs_data *d = hdata;
-	struct cgroup_process_info *i;
-	int ret;
-
-	if (!d)
-		return false;
-	i = d->info;
-	ret = lxc_cgroupfs_enter(i, pid, false);
-
-	return ret == 0;
-}
-
-static inline bool cgfs_create_legacy(void *hdata, pid_t pid)
-{
-	struct cgfs_data *d = hdata;
-	struct cgroup_process_info *i;
-
-	if (!d)
-		return false;
-	i = d->info;
-	if (lxc_cgroup_create_legacy(i, d->name, pid) < 0) {
-		ERROR("failed to create legacy ns cgroups for '%s'", d->name);
-		return false;
-	}
-	return true;
-}
-
-static const char *cgfs_get_cgroup(void *hdata, const char *subsystem)
-{
-	struct cgfs_data *d = hdata;
-
-	if (!d)
-		return NULL;
-	return lxc_cgroup_get_hierarchy_path_data(subsystem, d);
-}
-
-static const char *cgfs_canonical_path(void *hdata)
-{
-	struct cgfs_data *d = hdata;
-	struct cgroup_process_info *info_ptr;
-	char *path = NULL;
-
-	if (!d)
-		return NULL;
-
-	for (info_ptr = d->info; info_ptr; info_ptr = info_ptr->next) {
-		if (!path)
-			path = info_ptr->cgroup_path;
-		else if (strcmp(path, info_ptr->cgroup_path) != 0) {
-			ERROR("not all paths match %s, %s has path %s", path,
-				info_ptr->hierarchy->subsystems[0], info_ptr->cgroup_path);
-			return NULL;
-		}
-	}
-
-	return path;
-}
-
-static bool cgfs_escape(void *hdata)
-{
-	struct cgroup_meta_data *md;
-	int i;
-	bool ret = false;
-
-	md = lxc_cgroup_load_meta();
-	if (!md)
-		return false;
-
-	for (i = 1; i <= md->maximum_hierarchy; i++) {
-		struct cgroup_hierarchy *h = md->hierarchies[i];
-		struct cgroup_mount_point *mp;
-		char *tasks;
-		FILE *f;
-		int written;
-
-		if (!h) {
-			WARN("not escaping hierarchy %d", i);
-			continue;
-		}
-
-		mp = lxc_cgroup_find_mount_point(h, "/", true);
-		if (!mp)
-			goto out;
-
-		tasks = cgroup_to_absolute_path(mp, "/", "tasks");
-		if (!tasks)
-			goto out;
-
-		f = fopen(tasks, "a");
-		free(tasks);
-		if (!f)
-			goto out;
-
-		written = fprintf(f, "%d\n", getpid());
-		fclose(f);
-		if (written < 0) {
-			SYSERROR("writing tasks failed\n");
-			goto out;
-		}
-	}
-
-	ret = true;
-out:
-	lxc_cgroup_put_meta(md);
-	return ret;
-}
-
-static bool cgfs_unfreeze(void *hdata)
-{
-	struct cgfs_data *d = hdata;
-	char *cgabspath, *cgrelpath;
-	int ret;
-
-	if (!d)
-		return false;
-
-	cgrelpath = lxc_cgroup_get_hierarchy_path_data("freezer", d);
-	cgabspath = lxc_cgroup_find_abs_path("freezer", cgrelpath, true, NULL);
-	if (!cgabspath)
-		return false;
-
-	ret = do_cgroup_set(cgabspath, "freezer.state", "THAWED");
-	free(cgabspath);
-	return ret == 0;
-}
-
-static bool cgroupfs_setup_limits(void *hdata, struct lxc_list *cgroup_conf,
-				  bool with_devices)
-{
-	struct cgfs_data *d = hdata;
-
-	if (!d)
-		return false;
-	return do_setup_cgroup_limits(d, cgroup_conf, with_devices) == 0;
-}
-
-static bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
-{
-	struct cgroup_meta_data *meta_data;
-	struct cgroup_process_info *container_info;
-	int ret;
-
-	meta_data = lxc_cgroup_load_meta();
-	if (!meta_data) {
-		ERROR("could not move attached process %d to cgroup of container", pid);
-		return false;
-	}
-
-	container_info = lxc_cgroup_get_container_info(name, lxcpath, meta_data);
-	lxc_cgroup_put_meta(meta_data);
-	if (!container_info) {
-		ERROR("could not move attached process %d to cgroup of container", pid);
-		return false;
-	}
-
-	ret = lxc_cgroupfs_enter(container_info, pid, false);
-	lxc_cgroup_process_info_free(container_info);
-	if (ret < 0) {
-		ERROR("could not move attached process %d to cgroup of container", pid);
-		return false;
-	}
-	return true;
-}
-
-struct chown_data {
-	const char *cgroup_path;
-	uid_t origuid;
-};
-
-/*
- * TODO - someone should refactor this to unshare once passing all the paths
- * to be chowned in one go
- */
-static int chown_cgroup_wrapper(void *data)
-{
-	struct chown_data *arg = data;
-	uid_t destuid;
-	char *fpath;
-
-	if (setresgid(0,0,0) < 0)
-		SYSERROR("Failed to setgid to 0");
-	if (setresuid(0,0,0) < 0)
-		SYSERROR("Failed to setuid to 0");
-	if (setgroups(0, NULL) < 0)
-		SYSERROR("Failed to clear groups");
-	destuid = get_ns_uid(arg->origuid);
-
-	if (chown(arg->cgroup_path, destuid, 0) < 0)
-		SYSERROR("Failed chowning %s to %d", arg->cgroup_path, (int)destuid);
-
-	fpath = lxc_append_paths(arg->cgroup_path, "tasks");
-	if (!fpath)
-		return -1;
-	if (chown(fpath, destuid, 0) < 0)
-		SYSERROR("Error chowning %s\n", fpath);
-	free(fpath);
-
-	fpath = lxc_append_paths(arg->cgroup_path, "cgroup.procs");
-	if (!fpath)
-		return -1;
-	if (chown(fpath, destuid, 0) < 0)
-		SYSERROR("Error chowning %s", fpath);
-	free(fpath);
-
-	return 0;
-}
-
-static bool do_cgfs_chown(char *cgroup_path, struct lxc_conf *conf)
-{
-	struct chown_data data;
-	char *fpath;
-
-	if (!dir_exists(cgroup_path))
-		return true;
-
-	if (lxc_list_empty(&conf->id_map))
-		/* If there's no mapping then we don't need to chown */
-		return true;
-
-	data.cgroup_path = cgroup_path;
-	data.origuid = geteuid();
-
-	/* Unpriv users can't chown it themselves, so chown from
-	 * a child namespace mapping both our own and the target uid
-	 */
-	if (userns_exec_1(conf, chown_cgroup_wrapper, &data) < 0) {
-		ERROR("Error requesting cgroup chown in new namespace");
-		return false;
-	}
-
-	/*
-	 * Now chmod 775 the directory else the container cannot create cgroups.
-	 * This can't be done in the child namespace because it only group-owns
-	 * the cgroup
-	 */
-	if (chmod(cgroup_path, 0775) < 0) {
-		SYSERROR("Error chmoding %s\n", cgroup_path);
-		return false;
-	}
-	fpath = lxc_append_paths(cgroup_path, "tasks");
-	if (!fpath)
-		return false;
-	if (chmod(fpath, 0664) < 0)
-		SYSERROR("Error chmoding %s\n", fpath);
-	free(fpath);
-	fpath = lxc_append_paths(cgroup_path, "cgroup.procs");
-	if (!fpath)
-		return false;
-	if (chmod(fpath, 0664) < 0)
-		SYSERROR("Error chmoding %s\n", fpath);
-	free(fpath);
-
-	return true;
-}
-
-static bool cgfs_chown(void *hdata, struct lxc_conf *conf)
-{
-	struct cgfs_data *d = hdata;
-	struct cgroup_process_info *info_ptr;
-	char *cgpath;
-	bool r = true;
-
-	if (!d)
-		return false;
-
-	for (info_ptr = d->info; info_ptr; info_ptr = info_ptr->next) {
-		if (!info_ptr->designated_mount_point) {
-			info_ptr->designated_mount_point = lxc_cgroup_find_mount_point(info_ptr->hierarchy, info_ptr->cgroup_path, true);
-			if (!info_ptr->designated_mount_point) {
-				SYSERROR("Could not chown cgroup %s: internal error (couldn't find any writable mountpoint to cgroup filesystem)", info_ptr->cgroup_path);
-				return false;
-			}
-		}
-
-		cgpath = cgroup_to_absolute_path(info_ptr->designated_mount_point, info_ptr->cgroup_path, NULL);
-		if (!cgpath) {
-			SYSERROR("Could not chown cgroup %s: internal error", info_ptr->cgroup_path);
-			continue;
-		}
-		r = do_cgfs_chown(cgpath, conf);
-		if (!r && is_crucial_hierarchy(info_ptr->hierarchy)) {
-			ERROR("Failed chowning %s\n", cgpath);
-			free(cgpath);
-			return false;
-		}
-		free(cgpath);
-	}
-
-	return true;
-}
-
-static struct cgroup_ops cgfs_ops = {
-	.init = cgfs_init,
-	.destroy = cgfs_destroy,
-	.create = cgfs_create,
-	.enter = cgfs_enter,
-	.create_legacy = cgfs_create_legacy,
-	.get_cgroup = cgfs_get_cgroup,
-	.canonical_path = cgfs_canonical_path,
-	.escape = cgfs_escape,
-	.get = lxc_cgroupfs_get,
-	.set = lxc_cgroupfs_set,
-	.unfreeze = cgfs_unfreeze,
-	.setup_limits = cgroupfs_setup_limits,
-	.name = "cgroupfs",
-	.attach = lxc_cgroupfs_attach,
-	.chown = cgfs_chown,
-	.mount_cgroup = cgroupfs_mount_cgroup,
-	.nrtasks = cgfs_nrtasks,
-	.driver = CGFS,
-};
diff --git a/src/lxc/cgfsng.c b/src/lxc/cgfsng.c
deleted file mode 100644
index 27c2721..0000000
--- a/src/lxc/cgfsng.c
+++ /dev/null
@@ -1,1691 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * Copyright © 2016 Canonical Ltd.
- *
- * Authors:
- * Serge Hallyn <serge.hallyn at ubuntu.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- * cgfs-ng.c: this is a new, simplified implementation of a filesystem
- * cgroup backend.  The original cgfs.c was designed to be as flexible
- * as possible.  It would try to find cgroup filesystems no matter where
- * or how you had them mounted, and deduce the most usable mount for
- * each controller.  It also was not designed for unprivileged use, as
- * that was reserved for cgmanager.
- *
- * This new implementation assumes that cgroup filesystems are mounted
- * under /sys/fs/cgroup/clist where clist is either the controller, or
- * a comman-separated list of controllers.
- */
-#include "config.h"
-#include <stdio.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <grp.h>
-
-#include "bdev.h"
-#include "log.h"
-#include "cgroup.h"
-#include "utils.h"
-#include "commands.h"
-
-lxc_log_define(lxc_cgfsng, lxc);
-
-static struct cgroup_ops cgfsng_ops;
-
-/*
- * A descriptor for a mounted hierarchy
- * @controllers: either NULL, or a null-terminated list of all
- *   the co-mounted controllers
- * @mountpoint: the mountpoint we will use.  It will be either
- *   /sys/fs/cgroup/controller or /sys/fs/cgroup/controllerlist
- * @base_cgroup: the cgroup under which the container cgroup path
-     is created.  This will be either the caller's cgroup (if not
-     root), or init's cgroup (if root).
- */
-struct hierarchy {
-	char **controllers;
-	char *mountpoint;
-	char *base_cgroup;
-	char *fullcgpath;
-};
-
-/*
- * The cgroup data which is attached to the lxc_handler.
- * @cgroup_pattern - a copy of the lxc.cgroup.pattern
- * @container_cgroup - if not null, the cgroup which was created for
- *   the container.  For each hierarchy, it is created under the
- *   @hierarchy->base_cgroup directory.  Relative to the base_cgroup
- *   it is the same for all hierarchies.
- * @name - the container name
- */
-struct cgfsng_handler_data {
-	char *cgroup_pattern;
-	char *container_cgroup; // cgroup we created for the container
-	char *name; // container name
-};
-
-/*
- * @hierarchies - a NULL-terminated array of struct hierarchy, one per
- *   hierarchy.  No duplicates.  First sufficient, writeable mounted
- *   hierarchy wins
- */
-struct hierarchy **hierarchies;
-
-/*
- * @cgroup_use - a copy of the lxc.cgroup.use
- */
-char *cgroup_use;
-
-static void free_string_list(char **clist)
-{
-	if (clist) {
-		int i;
-
-		for (i = 0; clist[i]; i++)
-			free(clist[i]);
-		free(clist);
-	}
-}
-
-/* Re-alllocate a pointer, do not fail */
-static void *must_realloc(void *orig, size_t sz)
-{
-	void *ret;
-
-	do {
-		ret = realloc(orig, sz);
-	} while (!ret);
-	return ret;
-}
-
-/* Allocate a pointer, do not fail */
-static void *must_alloc(size_t sz)
-{
-	return must_realloc(NULL, sz);
-}
-
-/* return copy of string @entry;  do not fail. */
-static char *must_copy_string(const char *entry)
-{
-	char *ret;
-
-	if (!entry)
-		return NULL;
-	do {
-		ret = strdup(entry);
-	} while (!ret);
-	return ret;
-}
-
-/*
- * This is a special case - return a copy of @entry
- * prepending 'name='.  I.e. turn systemd into name=systemd.
- * Do not fail.
- */
-static char *must_prefix_named(char *entry)
-{
-	char *ret;
-	size_t len = strlen(entry);
-
-	ret = must_alloc(len + 6);
-	snprintf(ret, len + 6, "name=%s", entry);
-	return ret;
-}
-
-/*
- * Given a pointer to a null-terminated array of pointers, realloc to
- * add one entry, and point the new entry to NULL.  Do not fail.  Return
- * the index to the second-to-last entry - that is, the one which is
- * now available for use (keeping the list null-terminated).
- */
-static int append_null_to_list(void ***list)
-{
-	int newentry = 0;
-
-	if (*list)
-		for (; (*list)[newentry]; newentry++);
-
-	*list = must_realloc(*list, (newentry + 2) * sizeof(void **));
-	(*list)[newentry + 1] = NULL;
-	return newentry;
-}
-
-/*
- * Given a null-terminated array of strings, check whether @entry
- * is one of the strings
- */
-static bool string_in_list(char **list, const char *entry)
-{
-	int i;
-
-	if (!list)
-		return false;
-	for (i = 0; list[i]; i++)
-		if (strcmp(list[i], entry) == 0)
-			return true;
-
-	return false;
-}
-
-/*
- * append an entry to the clist.  Do not fail.
- * *clist must be NULL the first time we are called.
- *
- * We also handle named subsystems here.  Any controller which is not a
- * kernel subsystem, we prefix 'name='.  Any which is both a kernel and
- * named subsystem, we refuse to use because we're not sure which we
- * have here.  (TODO - we could work around this in some cases by just
- * remounting to be unambiguous, or by comparing mountpoint contents
- * with current cgroup)
- *
- * The last entry will always be NULL.
- */
-static void must_append_controller(char **klist, char **nlist, char ***clist, char *entry)
-{
-	int newentry;
-	char *copy;
-
-	if (string_in_list(klist, entry) && string_in_list(nlist, entry)) {
-		ERROR("Refusing to use ambiguous controller '%s'", entry);
-		ERROR("It is both a named and kernel subsystem");
-		return;
-	}
-
-	newentry = append_null_to_list((void ***)clist);
-
-	if (strncmp(entry, "name=", 5) == 0)
-		copy = must_copy_string(entry);
-	else if (string_in_list(klist, entry))
-		copy = must_copy_string(entry);
-	else
-		copy = must_prefix_named(entry);
-
-	(*clist)[newentry] = copy;
-}
-
-static void free_handler_data(struct cgfsng_handler_data *d)
-{
-	free(d->cgroup_pattern);
-	free(d->container_cgroup);
-	free(d->name);
-	free(d);
-}
-
-/*
- * Given a handler's cgroup data, return the struct hierarchy for the
- * controller @c, or NULL if there is none.
- */
-struct hierarchy *get_hierarchy(const char *c)
-{
-	int i;
-
-	if (!hierarchies)
-		return NULL;
-	for (i = 0; hierarchies[i]; i++) {
-		if (string_in_list(hierarchies[i]->controllers, c))
-			return hierarchies[i];
-	}
-	return NULL;
-}
-
-static char *must_make_path(const char *first, ...) __attribute__((sentinel));
-
-/* Copy contents of parent(@path)/@file to @path/@file */
-static bool copy_parent_file(char *path, char *file)
-{
-	char *lastslash, *value = NULL, *fpath, oldv;
-	int len = 0;
-	int ret;
-
-	lastslash = strrchr(path, '/');
-	if (!lastslash) { // bug...  this shouldn't be possible
-		ERROR("cgfsng:copy_parent_file: bad path %s", path);
-		return false;
-	}
-	oldv = *lastslash;
-	*lastslash = '\0';
-	fpath = must_make_path(path, file, NULL);
-	len = lxc_read_from_file(fpath, NULL, 0);
-	if (len <= 0)
-		goto bad;
-	value = must_alloc(len + 1);
-	if (lxc_read_from_file(fpath, value, len) != len)
-		goto bad;
-	free(fpath);
-	*lastslash = oldv;
-	fpath = must_make_path(path, file, NULL);
-	ret = lxc_write_to_file(fpath, value, len, false);
-	if (ret < 0)
-		SYSERROR("Unable to write %s to %s", value, fpath);
-	free(fpath);
-	free(value);
-	return ret >= 0;
-
-bad:
-	SYSERROR("Error reading '%s'", fpath);
-	free(fpath);
-	free(value);
-	return false;
-}
-
-/*
- * Initialize the cpuset hierarchy in first directory of @gname and
- * set cgroup.clone_children so that children inherit settings.
- * Since the h->base_path is populated by init or ourselves, we know
- * it is already initialized.
- */
-bool handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
-{
-	char *cgpath, *clonechildrenpath, v, *slash;
-
-	if (!string_in_list(h->controllers, "cpuset"))
-		return true;
-
-	if (*cgname == '/')
-		cgname++;
-	slash = strchr(cgname, '/');
-	if (slash)
-		*slash = '\0';
-
-	cgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
-	if (slash)
-		*slash = '/';
-	if (mkdir(cgpath, 0755) < 0 && errno != EEXIST) {
-		SYSERROR("Failed to create '%s'", cgpath);
-		free(cgpath);
-		return false;
-	}
-	clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL);
-	if (!file_exists(clonechildrenpath)) { /* unified hierarchy doesn't have clone_children */
-		free(clonechildrenpath);
-		free(cgpath);
-		return true;
-	}
-	if (lxc_read_from_file(clonechildrenpath, &v, 1) < 0) {
-		SYSERROR("Failed to read '%s'", clonechildrenpath);
-		free(clonechildrenpath);
-		free(cgpath);
-		return false;
-	}
-
-	if (v == '1') {  /* already set for us by someone else */
-		free(clonechildrenpath);
-		free(cgpath);
-		return true;
-	}
-
-	/* copy parent's settings */
-	if (!copy_parent_file(cgpath, "cpuset.cpus") ||
-			!copy_parent_file(cgpath, "cpuset.mems")) {
-		free(cgpath);
-		free(clonechildrenpath);
-		return false;
-	}
-	free(cgpath);
-
-	if (lxc_write_to_file(clonechildrenpath, "1", 1, false) < 0) {
-		/* Set clone_children so children inherit our settings */
-		SYSERROR("Failed to write 1 to %s", clonechildrenpath);
-		free(clonechildrenpath);
-		return false;
-	}
-	free(clonechildrenpath);
-	return true;
-}
-
-/*
- * Given two null-terminated lists of strings, return true if any string
- * is in both.
- */
-static bool controller_lists_intersect(char **l1, char **l2)
-{
-	int i;
-
-	if (!l1 || !l2)
-		return false;
-
-	for (i = 0; l1[i]; i++) {
-		if (string_in_list(l2, l1[i]))
-			return true;
-	}
-	return false;
-}
-
-/*
- * For a null-terminated list of controllers @clist, return true if any of
- * those controllers is already listed the null-terminated list of
- * hierarchies @hlist.  Realistically, if one is present, all must be present.
- */
-static bool controller_list_is_dup(struct hierarchy **hlist, char **clist)
-{
-	int i;
-
-	if (!hlist)
-		return false;
-	for (i = 0; hlist[i]; i++)
-		if (controller_lists_intersect(hlist[i]->controllers, clist))
-			return true;
-	return false;
-
-}
-
-/*
- * Return true if the controller @entry is found in the null-terminated
- * list of hierarchies @hlist
- */
-static bool controller_found(struct hierarchy **hlist, char *entry)
-{
-	int i;
-	if (!hlist)
-		return false;
-
-	for (i = 0; hlist[i]; i++)
-		if (string_in_list(hlist[i]->controllers, entry))
-			return true;
-	return false;
-}
-
-/*
- * Return true if all of the controllers which we require have been found.
- * The required list is  freezer and anything in * lxc.cgroup.use.
- */
-static bool all_controllers_found(void)
-{
-	char *p, *saveptr = NULL;
-	struct hierarchy ** hlist = hierarchies;
-
-	if (!controller_found(hlist, "freezer")) {
-		ERROR("no freezer controller mountpoint found");
-		return false;
-	}
-
-	if (!cgroup_use)
-		return true;
-	for (p = strtok_r(cgroup_use, ",", &saveptr); p;
-			p = strtok_r(NULL, ",", &saveptr)) {
-		if (!controller_found(hlist, p)) {
-			ERROR("no %s controller mountpoint found", p);
-			return false;
-		}
-	}
-	return true;
-}
-
-/* Return true if the fs type is fuse.lxcfs */
-static bool is_lxcfs(const char *line)
-{
-	char *p = strstr(line, " - ");
-	if (!p)
-		return false;
-	return strncmp(p, " - fuse.lxcfs ", 14) == 0;
-}
-
-/*
- * Get the controllers from a mountinfo line
- * There are other ways we could get this info.  For lxcfs, field 3
- * is /cgroup/controller-list.  For cgroupfs, we could parse the mount
- * options.  But we simply assume that the mountpoint must be
- * /sys/fs/cgroup/controller-list
- */
-static char **get_controllers(char **klist, char **nlist, char *line)
-{
-	// the fourth field is /sys/fs/cgroup/comma-delimited-controller-list
-	int i;
-	char *p = line, *p2, *tok, *saveptr = NULL;
-	char **aret = NULL;
-
-	for (i = 0; i < 4; i++) {
-		p = strchr(p, ' ');
-		if (!p)
-			return NULL;
-		p++;
-	}
-	if (!p)
-		return NULL;
-	/* note - if we change how mountinfo works, then our caller
-	 * will need to verify /sys/fs/cgroup/ in this field */
-	if (strncmp(p, "/sys/fs/cgroup/", 15) != 0)
-		return NULL;
-	p += 15;
-	p2 = strchr(p, ' ');
-	if (!p2) {
-		ERROR("corrupt mountinfo");
-		return NULL;
-	}
-	*p2 = '\0';
-	for (tok = strtok_r(p, ",", &saveptr); tok;
-			tok = strtok_r(NULL, ",", &saveptr)) {
-		must_append_controller(klist, nlist, &aret, tok);
-	}
-
-	return aret;
-}
-
-/* return true if the fstype is cgroup */
-static bool is_cgroupfs(char *line)
-{
-	char *p = strstr(line, " - ");
-	if (!p)
-		return false;
-	return strncmp(p, " - cgroup ", 10) == 0;
-}
-
-/* Add a controller to our list of hierarchies */
-static void add_controller(char **clist, char *mountpoint, char *base_cgroup)
-{
-	struct hierarchy *new;
-	int newentry;
-
-	new = must_alloc(sizeof(*new));
-	new->controllers = clist;
-	new->mountpoint = mountpoint;
-	new->base_cgroup = base_cgroup;
-	new->fullcgpath = NULL;
-
-	newentry = append_null_to_list((void ***)&hierarchies);
-	hierarchies[newentry] = new;
-}
-
-/*
- * Get a copy of the mountpoint from @line, which is a line from
- * /proc/self/mountinfo
- */
-static char *get_mountpoint(char *line)
-{
-	int i;
-	char *p = line, *sret;
-	size_t len;
-
-	for (i = 0; i < 4; i++) {
-		p = strchr(p, ' ');
-		if (!p)
-			return NULL;
-		p++;
-	}
-	/* we've already stuck a \0 after the mountpoint */
-	len = strlen(p);
-	sret = must_alloc(len + 1);
-	memcpy(sret, p, len);
-	sret[len] = '\0';
-	return sret;
-}
-
-/*
- * Given a multi-line string, return a null-terminated copy of the
- * current line.
- */
-static char *copy_to_eol(char *p)
-{
-	char *p2 = strchr(p, '\n'), *sret;
-	size_t len;
-
-	if (!p2)
-		return NULL;
-
-	len = p2 - p;
-	sret = must_alloc(len + 1);
-	memcpy(sret, p, len);
-	sret[len] = '\0';
-	return sret;
-}
-
-/*
- * cgline: pointer to character after the first ':' in a line in a
- * \n-terminated /proc/self/cgroup file. Check whether * controller c is
- * present.
- */
-static bool controller_in_clist(char *cgline, char *c)
-{
-	char *tok, *saveptr = NULL, *eol, *tmp;
-	size_t len;
-
-	eol = strchr(cgline, ':');
-	if (!eol)
-		return false;
-
-	len = eol - cgline;
-	tmp = alloca(len + 1);
-	memcpy(tmp, cgline, len);
-	tmp[len] = '\0';
-
-	for (tok = strtok_r(tmp, ",", &saveptr); tok;
-			tok = strtok_r(NULL, ",", &saveptr)) {
-		if (strcmp(tok, c) == 0)
-			return true;
-	}
-	return false;
-}
-
-/*
- * @basecginfo is a copy of /proc/$$/cgroup.  Return the current
- * cgroup for @controller
- */
-static char *get_current_cgroup(char *basecginfo, char *controller)
-{
-	char *p = basecginfo;
-
-	while (1) {
-		p = strchr(p, ':');
-		if (!p)
-			return NULL;
-		p++;
-		if (controller_in_clist(p, controller)) {
-			p = strchr(p, ':');
-			if (!p)
-				return NULL;
-			p++;
-			return copy_to_eol(p);
-		}
-
-		p = strchr(p, '\n');
-		if (!p)
-			return NULL;
-		p++;
-	}
-}
-
-#define BATCH_SIZE 50
-static void batch_realloc(char **mem, size_t oldlen, size_t newlen)
-{
-	int newbatches = (newlen / BATCH_SIZE) + 1;
-	int oldbatches = (oldlen / BATCH_SIZE) + 1;
-
-	if (!*mem || newbatches > oldbatches) {
-		*mem = must_realloc(*mem, newbatches * BATCH_SIZE);
-	}
-}
-
-static void append_line(char **dest, size_t oldlen, char *new, size_t newlen)
-{
-	size_t full = oldlen + newlen;
-
-	batch_realloc(dest, oldlen, full + 1);
-
-	memcpy(*dest + oldlen, new, newlen + 1);
-}
-
-/* Slurp in a whole file */
-static char *read_file(char *fnam)
-{
-	FILE *f;
-	char *line = NULL, *buf = NULL;
-	size_t len = 0, fulllen = 0;
-	int linelen;
-
-	f = fopen(fnam, "r");
-	if (!f)
-		return NULL;
-	while ((linelen = getline(&line, &len, f)) != -1) {
-		append_line(&buf, fulllen, line, linelen);
-		fulllen += linelen;
-	}
-	fclose(f);
-	free(line);
-	return buf;
-}
-
-/*
- * Given a hierarchy @mountpoint and base @path, verify that we can create
- * directories underneath it.
- */
-static bool test_writeable(char *mountpoint, char *path)
-{
-	char *fullpath = must_make_path(mountpoint, path, NULL);
-	int ret;
-
-	ret = access(fullpath, W_OK);
-	free(fullpath);
-	return ret == 0;
-}
-
-static void must_append_string(char ***list, char *entry)
-{
-	int newentry = append_null_to_list((void ***)list);
-	char *copy;
-
-	copy = must_copy_string(entry);
-	(*list)[newentry] = copy;
-}
-
-static void get_existing_subsystems(char ***klist, char ***nlist)
-{
-	FILE *f;
-	char *line = NULL;
-	size_t len = 0;
-
-	if ((f = fopen("/proc/self/cgroup", "r")) == NULL)
-		return;
-	while (getline(&line, &len, f) != -1) {
-		char *p, *p2, *tok, *saveptr = NULL;
-		p = strchr(line, ':');
-		if (!p)
-			continue;
-		p++;
-		p2 = strchr(p, ':');
-		if (!p2)
-			continue;
-		*p2 = '\0';
-		for (tok = strtok_r(p, ",", &saveptr); tok;
-				tok = strtok_r(NULL, ",", &saveptr)) {
-			if (strncmp(tok, "name=", 5) == 0)
-				must_append_string(nlist, tok);
-			else
-				must_append_string(klist, tok);
-		}
-	}
-
-	free(line);
-	fclose(f);
-}
-
-static void trim(char *s)
-{
-	size_t len = strlen(s);
-	while (s[len-1] == '\n')
-		s[--len] = '\0';
-}
-
-static void print_init_debuginfo(struct cgfsng_handler_data *d)
-{
-	int i;
-
-	if (!getenv("LXC_DEBUG_CGFSNG"))
-		return;
-
-	printf("Cgroup information:\n");
-	printf("  container name: %s\n", d->name);
-	printf("  lxc.cgroup.use: %s\n", cgroup_use ? cgroup_use : "(none)");
-	printf("  lxc.cgroup.pattern: %s\n", d->cgroup_pattern);
-	printf("  cgroup: %s\n", d->container_cgroup ? d->container_cgroup : "(none)");
-	if (!hierarchies) {
-		printf("  No hierarchies found.\n");
-		return;
-	}
-	printf("  Hierarchies:\n");
-	for (i = 0; hierarchies[i]; i++) {
-		struct hierarchy *h = hierarchies[i];
-		int j;
-		printf("  %d: base_cgroup %s\n", i, h->base_cgroup);
-		printf("      mountpoint %s\n", h->mountpoint);
-		printf("      controllers:\n");
-		for (j = 0; h->controllers[j]; j++)
-			printf("     %d: %s\n", j, h->controllers[j]);
-	}
-}
-
-static void print_basecg_debuginfo(char *basecginfo, char **klist, char **nlist)
-{
-	int k;
-	if (!getenv("LXC_DEBUG_CGFSNG"))
-		return;
-
-	printf("basecginfo is %s\n", basecginfo);
-
-	for (k = 0; klist[k]; k++)
-		printf("kernel subsystem %d: %s\n", k, klist[k]);
-	for (k = 0; nlist[k]; k++)
-		printf("named subsystem %d: %s\n", k, nlist[k]);
-}
-
-/*
- * At startup, parse_hierarchies finds all the info we need about
- * cgroup mountpoints and current cgroups, and stores it in @d.
- */
-static bool parse_hierarchies(void)
-{
-	FILE *f;
-	char * line = NULL, *basecginfo;
-	char **klist = NULL, **nlist = NULL;
-	size_t len = 0;
-
-	/*
-	 * Root spawned containers escape the current cgroup, so use init's
-	 * cgroups as our base in that case.
-	 */
-	if (geteuid())
-		basecginfo = read_file("/proc/self/cgroup");
-	else
-		basecginfo = read_file("/proc/1/cgroup");
-	if (!basecginfo)
-		return false;
-
-	if ((f = fopen("/proc/self/mountinfo", "r")) == NULL) {
-		SYSERROR("Failed opening /proc/self/mountinfo");
-		return false;
-	}
-
-	get_existing_subsystems(&klist, &nlist);
-
-	print_basecg_debuginfo(basecginfo, klist, nlist);
-
-	/* we support simple cgroup mounts and lxcfs mounts */
-	while (getline(&line, &len, f) != -1) {
-		char **controller_list = NULL;
-		char *mountpoint, *base_cgroup;
-
-		if (!is_lxcfs(line) && !is_cgroupfs(line))
-			continue;
-
-		controller_list = get_controllers(klist, nlist, line);
-		if (!controller_list)
-			continue;
-
-		if (controller_list_is_dup(hierarchies, controller_list)) {
-			free(controller_list);
-			continue;
-		}
-
-		mountpoint = get_mountpoint(line);
-		if (!mountpoint) {
-			ERROR("Error reading mountinfo: bad line '%s'", line);
-			free_string_list(controller_list);
-			continue;
-		}
-
-		base_cgroup = get_current_cgroup(basecginfo, controller_list[0]);
-		if (!base_cgroup) {
-			ERROR("Failed to find current cgroup for controller '%s'", controller_list[0]);
-			free_string_list(controller_list);
-			free(mountpoint);
-			continue;
-		}
-		trim(base_cgroup);
-		prune_init_scope(base_cgroup);
-		if (!test_writeable(mountpoint, base_cgroup)) {
-			free_string_list(controller_list);
-			free(mountpoint);
-			free(base_cgroup);
-			continue;
-		}
-		add_controller(controller_list, mountpoint, base_cgroup);
-	}
-
-	free_string_list(klist);
-	free_string_list(nlist);
-
-	free(basecginfo);
-
-	fclose(f);
-	free(line);
-
-	/* verify that all controllers in cgroup.use and all crucial
-	 * controllers are accounted for
-	 */
-	if (!all_controllers_found())
-		return false;
-
-	return true;
-}
-
-static bool collect_hierarchy_info(void)
-{
-	const char *tmp;
-	errno = 0;
-	tmp = lxc_global_config_value("lxc.cgroup.use");
-	if (!cgroup_use && errno != 0) { // lxc.cgroup.use can be NULL
-		SYSERROR("cgfsng: error reading list of cgroups to use");
-		return false;
-	}
-	cgroup_use = must_copy_string(tmp);
-
-	return parse_hierarchies();
-}
-
-static void *cgfsng_init(const char *name)
-{
-	struct cgfsng_handler_data *d;
-	const char *cgroup_pattern;
-
-	d = must_alloc(sizeof(*d));
-	memset(d, 0, sizeof(*d));
-
-	d->name = must_copy_string(name);
-
-	cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
-	if (!cgroup_pattern) { // lxc.cgroup.pattern is only NULL on error
-		ERROR("Error getting cgroup pattern");
-		goto out_free;
-	}
-	d->cgroup_pattern = must_copy_string(cgroup_pattern);
-
-	print_init_debuginfo(d);
-
-	return d;
-
-out_free:
-	free_handler_data(d);
-	return NULL;
-}
-
-/*
- * Concatenate all passed-in strings into one path.  Do not fail.  If any piece is
- * not prefixed with '/', add a '/'.
- */
-static char *must_make_path(const char *first, ...)
-{
-	va_list args;
-	char *cur, *dest;
-	size_t full_len = strlen(first);
-
-	dest = must_copy_string(first);
-
-	va_start(args, first);
-	while ((cur = va_arg(args, char *)) != NULL) {
-		full_len += strlen(cur);
-		if (cur[0] != '/')
-			full_len++;
-		dest = must_realloc(dest, full_len + 1);
-		if (cur[0] != '/')
-			strcat(dest, "/");
-		strcat(dest, cur);
-	}
-	va_end(args);
-
-	return dest;
-}
-
-static int cgroup_rmdir(char *dirname)
-{
-	struct dirent dirent, *direntp;
-	DIR *dir;
-	int r = 0;
-
-	dir = opendir(dirname);
-	if (!dir)
-		return -1;
-
-	while (!readdir_r(dir, &dirent, &direntp)) {
-		struct stat mystat;
-		char *pathname;
-
-		if (!direntp)
-			break;
-
-		if (!strcmp(direntp->d_name, ".") ||
-		    !strcmp(direntp->d_name, ".."))
-			continue;
-
-		pathname = must_make_path(dirname, direntp->d_name, NULL);
-
-		if (lstat(pathname, &mystat)) {
-			if (!r)
-				WARN("failed to stat %s", pathname);
-			r = -1;
-			goto next;
-		}
-
-		if (!S_ISDIR(mystat.st_mode))
-			goto next;
-		if (cgroup_rmdir(pathname) < 0)
-			r = -1;
-next:
-		free(pathname);
-	}
-
-	if (rmdir(dirname) < 0) {
-		if (!r)
-			WARN("%s: failed to delete %s: %m", __func__, dirname);
-		r = -1;
-	}
-
-	if (closedir(dir) < 0) {
-		if (!r)
-			WARN("%s: failed to delete %s: %m", __func__, dirname);
-		r = -1;
-	}
-	return r;
-}
-
-static int rmdir_wrapper(void *data)
-{
-	char *path = data;
-
-	if (setresgid(0,0,0) < 0)
-		SYSERROR("Failed to setgid to 0");
-	if (setresuid(0,0,0) < 0)
-		SYSERROR("Failed to setuid to 0");
-	if (setgroups(0, NULL) < 0)
-		SYSERROR("Failed to clear groups");
-
-	return cgroup_rmdir(path);
-}
-
-void recursive_destroy(char *path, struct lxc_conf *conf)
-{
-	int r;
-	if (conf && !lxc_list_empty(&conf->id_map))
-		r = userns_exec_1(conf, rmdir_wrapper, path);
-	else
-		r = cgroup_rmdir(path);
-
-	if (r < 0)
-		ERROR("Error destroying %s", path);
-}
-
-static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
-{
-	struct cgfsng_handler_data *d = hdata;
-
-	if (!d)
-		return;
-
-	if (d->container_cgroup && hierarchies) {
-		int i;
-		for (i = 0; hierarchies[i]; i++) {
-			struct hierarchy *h = hierarchies[i];
-			if (h->fullcgpath) {
-				recursive_destroy(h->fullcgpath, conf);
-				free(h->fullcgpath);
-				h->fullcgpath = NULL;
-			}
-		}
-	}
-
-	free_handler_data(d);
-}
-
-struct cgroup_ops *cgfsng_ops_init(void)
-{
-	if (!collect_hierarchy_info())
-		return NULL;
-	return &cgfsng_ops;
-}
-
-static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
-{
-	h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
-	if (dir_exists(h->fullcgpath)) // it must not already exist
-		return false;
-	if (!handle_cpuset_hierarchy(h, cgname))
-		return false;
-	return mkdir_p(h->fullcgpath, 0755) == 0;
-}
-
-static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
-{
-	if (rmdir(h->fullcgpath) < 0)
-		SYSERROR("Failed to clean up cgroup %s from failed creation attempt", h->fullcgpath);
-	free(h->fullcgpath);
-	h->fullcgpath = NULL;
-}
-
-/*
- * Try to create the same cgroup in all hierarchies.
- * Start with cgroup_pattern; next cgroup_pattern-1, -2, ..., -999
- */
-static inline bool cgfsng_create(void *hdata)
-{
-	struct cgfsng_handler_data *d = hdata;
-	char *tmp, *cgname, *offset;
-	int i, idx = 0;
-	size_t len;
-
-	if (!d)
-		return false;
-	if (d->container_cgroup) {
-		WARN("cgfsng_create called a second time");
-		return false;
-	}
-
-	tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
-	if (!tmp) {
-		ERROR("Failed expanding cgroup name pattern");
-		return false;
-	}
-	len = strlen(tmp) + 5; // leave room for -NNN\0
-	cgname = must_alloc(len);
-	strcpy(cgname, tmp);
-	free(tmp);
-	offset = cgname + len - 5;
-
-again:
-	if (idx == 1000) {
-		ERROR("Too many conflicting cgroup names");
-		goto out_free;
-	}
-	if (idx)
-		snprintf(offset, 5, "-%d", idx);
-	for (i = 0; hierarchies[i]; i++) {
-		if (!create_path_for_hierarchy(hierarchies[i], cgname)) {
-			int j;
-			SYSERROR("Failed to create %s: %s", hierarchies[i]->fullcgpath, strerror(errno));
-			free(hierarchies[i]->fullcgpath);
-			hierarchies[i]->fullcgpath = NULL;
-			for (j = 0; j < i; j++)
-				remove_path_for_hierarchy(hierarchies[j], cgname);
-			idx++;
-			goto again;
-		}
-	}
-	/* Done */
-	d->container_cgroup = cgname;
-	return true;
-
-out_free:
-	free(cgname);
-	return false;
-}
-
-static const char *cgfsng_canonical_path(void *hdata)
-{
-	struct cgfsng_handler_data *d = hdata;
-
-	return d->container_cgroup;
-}
-
-static bool cgfsng_enter(void *hdata, pid_t pid)
-{
-	char pidstr[25];
-	int i, len;
-
-	len = snprintf(pidstr, 25, "%d", pid);
-	if (len < 0 || len > 25)
-		return false;
-
-	for (i = 0; hierarchies[i]; i++) {
-		char *fullpath = must_make_path(hierarchies[i]->fullcgpath,
-						"cgroup.procs", NULL);
-		if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
-			SYSERROR("Failed to enter %s", fullpath);
-			free(fullpath);
-			return false;
-		}
-		free(fullpath);
-	}
-
-	return true;
-}
-
-struct chown_data {
-	struct cgfsng_handler_data *d;
-	uid_t origuid; // target uid in parent namespace
-};
-
-/*
- * chgrp the container cgroups to container group.  We leave
- * the container owner as cgroup owner.  So we must make the
- * directories 775 so that the container can create sub-cgroups.
- *
- * Also chown the tasks and cgroup.procs files.  Those may not
- * exist depending on kernel version.
- */
-static int chown_cgroup_wrapper(void *data)
-{
-	struct chown_data *arg = data;
-	uid_t destuid;
-	int i;
-
-	if (setresgid(0,0,0) < 0)
-		SYSERROR("Failed to setgid to 0");
-	if (setresuid(0,0,0) < 0)
-		SYSERROR("Failed to setuid to 0");
-	if (setgroups(0, NULL) < 0)
-		SYSERROR("Failed to clear groups");
-
-	destuid = get_ns_uid(arg->origuid);
-
-	for (i = 0; hierarchies[i]; i++) {
-		char *fullpath, *path = hierarchies[i]->fullcgpath;
-
-		if (chown(path, destuid, 0) < 0) {
-			SYSERROR("Error chowning %s to %d", path, (int) destuid);
-			return -1;
-		}
-
-		if (chmod(path, 0775) < 0) {
-			SYSERROR("Error chmoding %s", path);
-			return -1;
-		}
-
-		/*
-		 * Failures to chown these are inconvenient but not detrimental
-		 * We leave these owned by the container launcher, so that container
-		 * root can write to the files to attach.  We chmod them 664 so that
-		 * container systemd can write to the files (which systemd in wily
-		 * insists on doing)
-		 */
-		fullpath = must_make_path(path, "tasks", NULL);
-		if (chown(fullpath, destuid, 0) < 0 && errno != ENOENT)
-			WARN("Failed chowning %s to %d: %m", fullpath, (int) destuid);
-		if (chmod(fullpath, 0664) < 0)
-			WARN("Error chmoding %s: %m", path);
-		free(fullpath);
-
-		fullpath = must_make_path(path, "cgroup.procs", NULL);
-		if (chown(fullpath, destuid, 0) < 0 && errno != ENOENT)
-			WARN("Failed chowning %s to %d: %m", fullpath, (int) destuid);
-		if (chmod(fullpath, 0664) < 0)
-			WARN("Error chmoding %s: %m", path);
-		free(fullpath);
-	}
-
-	return 0;
-}
-
-static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
-{
-	struct cgfsng_handler_data *d = hdata;
-	struct chown_data wrap;
-
-	if (!d)
-		return false;
-
-	if (lxc_list_empty(&conf->id_map))
-		return true;
-
-	wrap.d = d;
-	wrap.origuid = geteuid();
-
-	if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap) < 0) {
-		ERROR("Error requesting cgroup chown in new namespace");
-		return false;
-	}
-
-	return true;
-}
-
-/*
- * We've safe-mounted a tmpfs as parent, so we don't need to protect against
- * symlinks any more - just use mount
- */
-
-/* mount cgroup-full if requested */
-static int mount_cgroup_full(int type, struct hierarchy *h, char *dest,
-				   char *container_cgroup)
-{
-	if (type < LXC_AUTO_CGROUP_FULL_RO || type > LXC_AUTO_CGROUP_FULL_MIXED)
-		return 0;
-	if (mount(h->mountpoint, dest, "cgroup", MS_BIND, NULL) < 0) {
-		SYSERROR("Error bind-mounting %s cgroup onto %s", h->mountpoint,
-			 dest);
-		return -1;
-	}
-	if (type != LXC_AUTO_CGROUP_FULL_RW) {
-		unsigned long flags = MS_BIND | MS_NOSUID | MS_NOEXEC | MS_NODEV |
-				      MS_REMOUNT | MS_RDONLY;
-		if (mount(NULL, dest, "cgroup", flags, NULL) < 0) {
-			SYSERROR("Error remounting %s readonly", dest);
-			return -1;
-		}
-	}
-
-	INFO("Bind mounted %s onto %s", h->mountpoint, dest);
-	if (type != LXC_AUTO_CGROUP_FULL_MIXED)
-		return 0;
-
-	/* mount just the container path rw */
-	char *source = must_make_path(h->mountpoint, h->base_cgroup, container_cgroup, NULL);
-	char *rwpath = must_make_path(dest, h->base_cgroup, container_cgroup, NULL);
-	if (mount(source, rwpath, "cgroup", MS_BIND, NULL) < 0)
-		WARN("Failed to mount %s read-write: %m", rwpath);
-	INFO("Made %s read-write", rwpath);
-	free(rwpath);
-	free(source);
-	return 0;
-}
-
-/* cgroup-full:* is done, no need to create subdirs */
-static bool cg_mount_needs_subdirs(int type)
-{
-	if (type >= LXC_AUTO_CGROUP_FULL_RO)
-		return false;
-	return true;
-}
-
-/*
- * After $rootfs/sys/fs/container/controller/the/cg/path has been
- * created, remount controller ro if needed and bindmount the
- * cgroupfs onto controll/the/cg/path
- */
-static int
-do_secondstage_mounts_if_needed(int type, struct hierarchy *h,
-				char *controllerpath, char *cgpath,
-				const char *container_cgroup)
-{
-	if (type == LXC_AUTO_CGROUP_RO || type == LXC_AUTO_CGROUP_MIXED) {
-		if (mount(controllerpath, controllerpath, "cgroup", MS_BIND, NULL) < 0) {
-			SYSERROR("Error bind-mounting %s", controllerpath);
-			return -1;
-		}
-		if (mount(controllerpath, controllerpath, "cgroup",
-			   MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) < 0) {
-			SYSERROR("Error remounting %s read-only", controllerpath);
-			return -1;
-		}
-		INFO("Remounted %s read-only", controllerpath);
-	}
-	char *sourcepath = must_make_path(h->mountpoint, h->base_cgroup, container_cgroup, NULL);
-	int flags = MS_BIND;
-	if (type == LXC_AUTO_CGROUP_RO)
-		flags |= MS_RDONLY;
-	INFO("Mounting %s onto %s", sourcepath, cgpath);
-	if (mount(sourcepath, cgpath, "cgroup", flags, NULL) < 0) {
-		free(sourcepath);
-		SYSERROR("Error mounting cgroup %s onto %s", h->controllers[0],
-				cgpath);
-		return -1;
-	}
-	free(sourcepath);
-	INFO("Completed second stage cgroup automounts for %s", cgpath);
-	return 0;
-}
-
-static bool cgfsng_mount(void *hdata, const char *root, int type)
-{
-	struct cgfsng_handler_data *d = hdata;
-	char *tmpfspath = NULL;
-	bool retval = false;
-	int i;
-
-	if ((type & LXC_AUTO_CGROUP_MASK) == 0)
-		return true;
-
-	if (cgns_supported())
-		return true;
-
-	tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
-
-	if (type == LXC_AUTO_CGROUP_NOSPEC)
-		type = LXC_AUTO_CGROUP_MIXED;
-	else if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
-		type = LXC_AUTO_CGROUP_FULL_MIXED;
-
-	/* Mount tmpfs */
-	if (safe_mount("cgroup_root", tmpfspath, "tmpfs",
-			MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME,
-			"size=10240k,mode=755",
-			root) < 0)
-		goto  bad;
-
-	for (i = 0; hierarchies[i]; i++) {
-		char *controllerpath, *path2;
-		struct hierarchy *h = hierarchies[i];
-		char *controller = strrchr(h->mountpoint, '/');
-		int r;
-
-		if (!controller)
-			continue;
-		controller++;
-		controllerpath = must_make_path(tmpfspath, controller, NULL);
-		if (dir_exists(controllerpath)) {
-			free(controllerpath);
-			continue;
-		}
-		if (mkdir(controllerpath, 0755) < 0) {
-			SYSERROR("Error creating cgroup path: %s", controllerpath);
-			free(controllerpath);
-			goto bad;
-		}
-		if (mount_cgroup_full(type, h, controllerpath, d->container_cgroup) < 0) {
-			free(controllerpath);
-			goto bad;
-		}
-		if (!cg_mount_needs_subdirs(type)) {
-			free(controllerpath);
-			continue;
-		}
-		path2 = must_make_path(controllerpath, h->base_cgroup, d->container_cgroup, NULL);
-		if (mkdir_p(path2, 0755) < 0) {
-			free(controllerpath);
-			goto bad;
-		}
-
-		r = do_secondstage_mounts_if_needed(type, h, controllerpath, path2,
-						    d->container_cgroup);
-		free(controllerpath);
-		free(path2);
-		if (r < 0)
-			goto bad;
-	}
-	retval = true;
-
-bad:
-	free(tmpfspath);
-	return retval;
-}
-
-static int recursive_count_nrtasks(char *dirname)
-{
-	struct dirent dirent, *direntp;
-	DIR *dir;
-	int count = 0, ret;
-	char *path;
-
-	dir = opendir(dirname);
-	if (!dir)
-		return 0;
-
-	while (!readdir_r(dir, &dirent, &direntp)) {
-		struct stat mystat;
-
-		if (!direntp)
-			break;
-
-		if (!strcmp(direntp->d_name, ".") ||
-		    !strcmp(direntp->d_name, ".."))
-			continue;
-
-		path = must_make_path(dirname, direntp->d_name, NULL);
-
-		if (lstat(path, &mystat))
-			goto next;
-
-		if (!S_ISDIR(mystat.st_mode))
-			goto next;
-
-		count += recursive_count_nrtasks(path);
-next:
-		free(path);
-	}
-
-	path = must_make_path(dirname, "cgroup.procs", NULL);
-	ret = lxc_count_file_lines(path);
-	if (ret != -1)
-		count += ret;
-	free(path);
-
-	(void) closedir(dir);
-
-	return count;
-}
-
-static int cgfsng_nrtasks(void *hdata) {
-	struct cgfsng_handler_data *d = hdata;
-	char *path;
-	int count;
-
-	if (!d || !d->container_cgroup || !hierarchies)
-		return -1;
-	path = must_make_path(hierarchies[0]->fullcgpath, NULL);
-	count = recursive_count_nrtasks(path);
-	free(path);
-	return count;
-}
-
-/* Only root needs to escape to the cgroup of its init */
-static bool cgfsng_escape()
-{
-	struct cgfsng_handler_data *d;
-	int i;
-	bool ret = false;
-
-	if (geteuid())
-		return true;
-
-	d = cgfsng_init("criu-temp-cgfsng");
-	if (!d) {
-		ERROR("cgfsng_init failed");
-		return false;
-	}
-
-	for (i = 0; hierarchies[i]; i++) {
-		char *fullpath = must_make_path(hierarchies[i]->mountpoint,
-						hierarchies[i]->base_cgroup,
-						"cgroup.procs", NULL);
-		if (lxc_write_to_file(fullpath, "0", 2, false) != 0) {
-			SYSERROR("Failed to escape to %s", fullpath);
-			free(fullpath);
-			goto out;
-		}
-		free(fullpath);
-	}
-
-	ret = true;
-out:
-	free_handler_data(d);
-	return ret;
-}
-
-#define THAWED "THAWED"
-#define THAWED_LEN (strlen(THAWED))
-
-static bool cgfsng_unfreeze(void *hdata)
-{
-	char *fullpath;
-	struct hierarchy *h = get_hierarchy("freezer");
-
-	if (!h)
-		return false;
-	fullpath = must_make_path(h->fullcgpath, "freezer.state", NULL);
-	if (lxc_write_to_file(fullpath, THAWED, THAWED_LEN, false) != 0) {
-		free(fullpath);
-		return false;
-	}
-	free(fullpath);
-	return true;
-}
-
-static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem)
-{
-	struct hierarchy *h = get_hierarchy(subsystem);
-	if (!h)
-		return NULL;
-
-	return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
-}
-
-/*
- * Given a cgroup path returned from lxc_cmd_get_cgroup_path, build a
- * full path, which must be freed by the caller.
- */
-static char *build_full_cgpath_from_monitorpath(struct hierarchy *h,
-						const char *inpath,
-						const char *filename)
-{
-	/*
-	 * XXX Remove this case after 2.0 release.  It's for dealing with
-	 * containers spawned under the old buggy cgfsng which wasn't around
-	 * for long.
-	 */
-	if (strncmp(inpath, "/sys/fs/cgroup/", 15) == 0)
-		return must_make_path(inpath, filename, NULL);
-	return must_make_path(h->mountpoint, inpath, filename, NULL);
-}
-
-static bool cgfsng_attach(const char *name, const char *lxcpath, pid_t pid)
-{
-	char pidstr[25];
-	int i, len;
-
-	len = snprintf(pidstr, 25, "%d", pid);
-	if (len < 0 || len > 25)
-		return false;
-
-	for (i = 0; hierarchies[i]; i++) {
-		char *path, *fullpath;
-		struct hierarchy *h = hierarchies[i];
-
-		path = lxc_cmd_get_cgroup_path(name, lxcpath, h->controllers[0]);
-		if (!path) // not running
-			continue;
-
-		fullpath = build_full_cgpath_from_monitorpath(h, path, "cgroup.procs");
-		free(path);
-		if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
-			SYSERROR("Failed to attach %d to %s", (int)pid, fullpath);
-			free(fullpath);
-			return false;
-		}
-		free(fullpath);
-	}
-
-	return true;
-}
-
-/*
- * Called externally (i.e. from 'lxc-cgroup') to query cgroup limits.
- * Here we don't have a cgroup_data set up, so we ask the running
- * container through the commands API for the cgroup path
- */
-static int cgfsng_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
-{
-	char *subsystem, *p, *path;
-	struct hierarchy *h;
-	int ret = -1;
-
-	subsystem = alloca(strlen(filename) + 1);
-	strcpy(subsystem, filename);
-	if ((p = strchr(subsystem, '.')) != NULL)
-		*p = '\0';
-
-	path = lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
-	if (!path) // not running
-		return -1;
-
-	h = get_hierarchy(subsystem);
-	if (h) {
-		char *fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
-		ret = lxc_read_from_file(fullpath, value, len);
-		free(fullpath);
-	}
-
-	free(path);
-
-	return ret;
-}
-
-/*
- * Called externally (i.e. from 'lxc-cgroup') to set new cgroup limits.
- * Here we don't have a cgroup_data set up, so we ask the running
- * container through the commands API for the cgroup path
- */
-static int cgfsng_set(const char *filename, const char *value, const char *name, const char *lxcpath)
-{
-	char *subsystem, *p, *path;
-	struct hierarchy *h;
-	int ret = -1;
-
-	subsystem = alloca(strlen(filename) + 1);
-	strcpy(subsystem, filename);
-	if ((p = strchr(subsystem, '.')) != NULL)
-		*p = '\0';
-
-	path = lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
-	if (!path) // not running
-		return -1;
-
-	h = get_hierarchy(subsystem);
-	if (h) {
-		char *fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
-		ret = lxc_write_to_file(fullpath, value, strlen(value), false);
-		free(fullpath);
-	}
-
-	free(path);
-
-	return ret;
-}
-
-/*
- * Called from setup_limits - here we have the container's cgroup_data because
- * we created the cgroups
- */
-static int lxc_cgroup_set_data(const char *filename, const char *value, struct cgfsng_handler_data *d)
-{
-	char *subsystem = NULL, *p;
-	int ret = -1;
-	struct hierarchy *h;
-
-	subsystem = alloca(strlen(filename) + 1);
-	strcpy(subsystem, filename);
-	if ((p = strchr(subsystem, '.')) != NULL)
-		*p = '\0';
-
-	h = get_hierarchy(subsystem);
-	if (h) {
-		char *fullpath = must_make_path(h->fullcgpath, filename, NULL);
-		ret = lxc_write_to_file(fullpath, value, strlen(value), false);
-		free(fullpath);
-	}
-	return ret;
-}
-
-static bool cgfsng_setup_limits(void *hdata, struct lxc_list *cgroup_settings,
-				  bool do_devices)
-{
-	struct cgfsng_handler_data *d = hdata;
-	struct lxc_list *iterator, *sorted_cgroup_settings, *next;
-	struct lxc_cgroup *cg;
-	bool ret = false;
-
-	if (lxc_list_empty(cgroup_settings))
-		return true;
-
-	sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
-	if (!sorted_cgroup_settings) {
-		return false;
-	}
-
-	lxc_list_for_each(iterator, sorted_cgroup_settings) {
-		cg = iterator->elem;
-
-		if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
-			if (lxc_cgroup_set_data(cg->subsystem, cg->value, d)) {
-				if (do_devices && (errno == EACCES || errno == EPERM)) {
-					WARN("Error setting %s to %s for %s",
-					      cg->subsystem, cg->value, d->name);
-					continue;
-				}
-				SYSERROR("Error setting %s to %s for %s",
-				      cg->subsystem, cg->value, d->name);
-				goto out;
-			}
-		}
-
-		DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
-	}
-
-	ret = true;
-	INFO("cgroup has been setup");
-out:
-	lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
-		lxc_list_del(iterator);
-		free(iterator);
-	}
-	free(sorted_cgroup_settings);
-	return ret;
-}
-
-static struct cgroup_ops cgfsng_ops = {
-	.init = cgfsng_init,
-	.destroy = cgfsng_destroy,
-	.create = cgfsng_create,
-	.enter = cgfsng_enter,
-	.canonical_path = cgfsng_canonical_path,
-	.escape = cgfsng_escape,
-	.get_cgroup = cgfsng_get_cgroup,
-	.get = cgfsng_get,
-	.set = cgfsng_set,
-	.unfreeze = cgfsng_unfreeze,
-	.setup_limits = cgfsng_setup_limits,
-	.name = "cgroupfs-ng",
-	.attach = cgfsng_attach,
-	.chown = cgfsns_chown,
-	.mount_cgroup = cgfsng_mount,
-	.nrtasks = cgfsng_nrtasks,
-	.driver = CGFSNG,
-
-	/* unsupported */
-	.create_legacy = NULL,
-};
diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c
deleted file mode 100644
index 4da891d..0000000
--- a/src/lxc/cgmanager.c
+++ /dev/null
@@ -1,1672 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <pthread.h>
-#include <grp.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <sys/inotify.h>
-#include <sys/mount.h>
-#include <netinet/in.h>
-#include <net/if.h>
-#include <poll.h>
-
-#include "bdev.h"
-#include "error.h"
-#include "commands.h"
-#include "list.h"
-#include "conf.h"
-#include "utils.h"
-#include "log.h"
-#include "cgroup.h"
-#include "start.h"
-#include "state.h"
-
-#define CGM_SUPPORTS_GET_ABS 3
-#define CGM_SUPPORTS_NAMED 4
-#define CGM_SUPPORTS_MULT_CONTROLLERS 10
-
-#ifdef HAVE_CGMANAGER
-lxc_log_define(lxc_cgmanager, lxc);
-
-#include <nih-dbus/dbus_connection.h>
-#include <cgmanager/cgmanager-client.h>
-#include <nih/alloc.h>
-#include <nih/error.h>
-#include <nih/string.h>
-
-struct cgm_data {
-	char *name;
-	char *cgroup_path;
-	const char *cgroup_pattern;
-};
-
-static pthread_mutex_t cgm_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void lock_mutex(pthread_mutex_t *l)
-{
-	int ret;
-
-	if ((ret = pthread_mutex_lock(l)) != 0) {
-		fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
-		exit(1);
-	}
-}
-
-static void unlock_mutex(pthread_mutex_t *l)
-{
-	int ret;
-
-	if ((ret = pthread_mutex_unlock(l)) != 0) {
-		fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret));
-		exit(1);
-	}
-}
-
-void cgm_lock(void)
-{
-	lock_mutex(&cgm_mutex);
-}
-
-void cgm_unlock(void)
-{
-	unlock_mutex(&cgm_mutex);
-}
-
-#ifdef HAVE_PTHREAD_ATFORK
-__attribute__((constructor))
-static void process_lock_setup_atfork(void)
-{
-	pthread_atfork(cgm_lock, cgm_unlock, cgm_unlock);
-}
-#endif
-
-static NihDBusProxy *cgroup_manager = NULL;
-static int32_t api_version;
-
-static struct cgroup_ops cgmanager_ops;
-static int nr_subsystems;
-static char **subsystems, **subsystems_inone;
-static bool dbus_threads_initialized = false;
-static void cull_user_controllers(void);
-
-static void cgm_dbus_disconnect(void)
-{
-	if (cgroup_manager) {
-		dbus_connection_flush(cgroup_manager->connection);
-		dbus_connection_close(cgroup_manager->connection);
-		nih_free(cgroup_manager);
-	}
-	cgroup_manager = NULL;
-	cgm_unlock();
-}
-
-#define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
-static bool cgm_dbus_connect(void)
-{
-	DBusError dbus_error;
-	static DBusConnection *connection;
-
-	cgm_lock();
-	if (!dbus_threads_initialized) {
-		// tell dbus to do struct locking for thread safety
-		dbus_threads_init_default();
-		dbus_threads_initialized = true;
-	}
-
-	dbus_error_init(&dbus_error);
-
-	connection = dbus_connection_open_private(CGMANAGER_DBUS_SOCK, &dbus_error);
-	if (!connection) {
-		DEBUG("Failed opening dbus connection: %s: %s",
-				dbus_error.name, dbus_error.message);
-		dbus_error_free(&dbus_error);
-		cgm_unlock();
-		return false;
-	}
-	dbus_connection_set_exit_on_disconnect(connection, FALSE);
-	dbus_error_free(&dbus_error);
-	cgroup_manager = nih_dbus_proxy_new(NULL, connection,
-				NULL /* p2p */,
-				"/org/linuxcontainers/cgmanager", NULL, NULL);
-	dbus_connection_unref(connection);
-	if (!cgroup_manager) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("Error opening cgmanager proxy: %s", nerr->message);
-		nih_free(nerr);
-		cgm_dbus_disconnect();
-		return false;
-	}
-
-	// get the api version
-	if (cgmanager_get_api_version_sync(NULL, cgroup_manager, &api_version) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("Error cgroup manager api version: %s", nerr->message);
-		nih_free(nerr);
-		cgm_dbus_disconnect();
-		return false;
-	}
-	if (api_version < CGM_SUPPORTS_NAMED)
-		cull_user_controllers();
-	return true;
-}
-
-static bool cgm_all_controllers_same;
-
-/*
- * Check whether we can use "all" when talking to cgmanager.
- * We check two things:
- * 1. whether cgmanager is new enough to support this.
- * 2. whether the task we are interested in is in the same
- *    cgroup for all controllers.
- * In cgm_init (before an lxc-start) we care about our own
- * cgroup.  In cgm_attach, we care about the target task's
- * cgroup.
- */
-static void check_supports_multiple_controllers(pid_t pid)
-{
-	FILE *f;
-	char *line = NULL, *prevpath = NULL;
-	size_t sz = 0;
-	char path[100];
-
-	cgm_all_controllers_same = false;
-
-	if (pid == -1)
-		sprintf(path, "/proc/self/cgroup");
-	else
-		sprintf(path, "/proc/%d/cgroup", pid);
-	f = fopen(path, "r");
-	if (!f)
-		return;
-
-	cgm_all_controllers_same = true;
-
-	while (getline(&line, &sz, f) != -1) {
-		/* file format: hierarchy:subsystems:group */
-		char *colon;
-		if (!line[0])
-			continue;
-
-		colon = strchr(line, ':');
-		if (!colon)
-			continue;
-		colon = strchr(colon+1, ':');
-		if (!colon)
-			continue;
-		colon++;
-		if (!prevpath) {
-			prevpath = alloca(strlen(colon)+1);
-			strcpy(prevpath, colon);
-			continue;
-		}
-		if (strcmp(prevpath, colon) != 0) {
-			cgm_all_controllers_same = false;
-			break;
-		}
-	}
-
-	fclose(f);
-	free(line);
-}
-
-static int send_creds(int sock, int rpid, int ruid, int rgid)
-{
-	struct msghdr msg = { 0 };
-	struct iovec iov;
-	struct cmsghdr *cmsg;
-	struct ucred cred = {
-		.pid = rpid,
-		.uid = ruid,
-		.gid = rgid,
-	};
-	char cmsgbuf[CMSG_SPACE(sizeof(cred))];
-	char buf[1];
-	buf[0] = 'p';
-
-	msg.msg_control = cmsgbuf;
-	msg.msg_controllen = sizeof(cmsgbuf);
-
-	cmsg = CMSG_FIRSTHDR(&msg);
-	cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
-	cmsg->cmsg_level = SOL_SOCKET;
-	cmsg->cmsg_type = SCM_CREDENTIALS;
-	memcpy(CMSG_DATA(cmsg), &cred, sizeof(cred));
-
-	msg.msg_name = NULL;
-	msg.msg_namelen = 0;
-
-	iov.iov_base = buf;
-	iov.iov_len = sizeof(buf);
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
-
-	if (sendmsg(sock, &msg, 0) < 0)
-		return -1;
-	return 0;
-}
-
-static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path, int32_t *existed)
-{
-	bool ret = true;
-	if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
-				       cgroup_path, existed) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("call to cgmanager_create_sync failed: %s", nerr->message);
-		nih_free(nerr);
-		ERROR("Failed to create %s:%s", controller, cgroup_path);
-		ret = false;
-	}
-
-	return ret;
-}
-
-/*
- * Escape to the root cgroup if we are root, so that the container will
- * be in "/lxc/c1" rather than "/user/..../c1"
- * called internally with connection already open
- */
-static bool cgm_escape(void *hdata)
-{
-	bool ret = true, cgm_needs_disconnect = false;
-	pid_t me = getpid();
-	char **slist = subsystems;
-	int i;
-
-	if (!cgroup_manager) {
-		if (!cgm_dbus_connect()) {
-			ERROR("Error connecting to cgroup manager");
-			return false;
-		}
-		cgm_needs_disconnect = true;
-	}
-
-
-	if (cgm_all_controllers_same)
-		slist = subsystems_inone;
-
-	for (i = 0; slist[i]; i++) {
-		if (cgmanager_move_pid_abs_sync(NULL, cgroup_manager,
-					slist[i], "/", me) != 0) {
-			NihError *nerr;
-			nerr = nih_error_get();
-			ERROR("call to cgmanager_move_pid_abs_sync(%s) failed: %s",
-					slist[i], nerr->message);
-			nih_free(nerr);
-			ret = false;
-			break;
-		}
-	}
-
-	if (cgm_needs_disconnect)
-		cgm_dbus_disconnect();
-
-	return ret;
-}
-
-struct chown_data {
-	const char *cgroup_path;
-	uid_t origuid;
-};
-
-static int do_chown_cgroup(const char *controller, const char *cgroup_path,
-		uid_t newuid)
-{
-	int sv[2] = {-1, -1}, optval = 1, ret = -1;
-	char buf[1];
-	struct pollfd fds;
-
-	if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
-		SYSERROR("Error creating socketpair");
-		goto out;
-	}
-	if (setsockopt(sv[1], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
-		SYSERROR("setsockopt failed");
-		goto out;
-	}
-	if (setsockopt(sv[0], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
-		SYSERROR("setsockopt failed");
-		goto out;
-	}
-	if ( cgmanager_chown_scm_sync(NULL, cgroup_manager, controller,
-				       cgroup_path, sv[1]) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("call to cgmanager_chown_scm_sync failed: %s", nerr->message);
-		nih_free(nerr);
-		goto out;
-	}
-	/* now send credentials */
-
-	fds.fd = sv[0];
-	fds.events = POLLIN;
-	fds.revents = 0;
-	if (poll(&fds, 1, -1) <= 0) {
-		ERROR("Error getting go-ahead from server: %s", strerror(errno));
-		goto out;
-	}
-	if (read(sv[0], &buf, 1) != 1) {
-		ERROR("Error getting reply from server over socketpair");
-		goto out;
-	}
-	if (send_creds(sv[0], getpid(), getuid(), getgid())) {
-		SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__);
-		goto out;
-	}
-	fds.fd = sv[0];
-	fds.events = POLLIN;
-	fds.revents = 0;
-	if (poll(&fds, 1, -1) <= 0) {
-		ERROR("Error getting go-ahead from server: %s", strerror(errno));
-		goto out;
-	}
-	if (read(sv[0], &buf, 1) != 1) {
-		ERROR("Error getting reply from server over socketpair");
-		goto out;
-	}
-	if (send_creds(sv[0], getpid(), newuid, 0)) {
-		SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__);
-		goto out;
-	}
-	fds.fd = sv[0];
-	fds.events = POLLIN;
-	fds.revents = 0;
-	if (poll(&fds, 1, -1) <= 0) {
-		ERROR("Error getting go-ahead from server: %s", strerror(errno));
-		goto out;
-	}
-	ret = read(sv[0], buf, 1);
-out:
-	close(sv[0]);
-	close(sv[1]);
-	if (ret == 1 && *buf == '1')
-		return 0;
-	return -1;
-}
-
-static int chown_cgroup_wrapper(void *data)
-{
-	struct chown_data *arg = data;
-	char **slist = subsystems;
-	int i, ret = -1;
-	uid_t destuid;
-
-	if (setresgid(0,0,0) < 0)
-		SYSERROR("Failed to setgid to 0");
-	if (setresuid(0,0,0) < 0)
-		SYSERROR("Failed to setuid to 0");
-	if (setgroups(0, NULL) < 0)
-		SYSERROR("Failed to clear groups");
-	cgm_dbus_disconnect();
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		return -1;
-	}
-	destuid = get_ns_uid(arg->origuid);
-
-	if (cgm_all_controllers_same)
-		slist = subsystems_inone;
-
-	for (i = 0; slist[i]; i++) {
-		if (do_chown_cgroup(slist[i], arg->cgroup_path, destuid) < 0) {
-			ERROR("Failed to chown %s:%s to container root",
-				slist[i], arg->cgroup_path);
-			goto fail;
-		}
-	}
-	ret = 0;
-fail:
-	cgm_dbus_disconnect();
-	return ret;
-}
-
-/* Internal helper.  Must be called with the cgmanager dbus socket open */
-static bool lxc_cgmanager_chmod(const char *controller,
-		const char *cgroup_path, const char *file, int mode)
-{
-	if (cgmanager_chmod_sync(NULL, cgroup_manager, controller,
-			cgroup_path, file, mode) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("call to cgmanager_chmod_sync failed: %s", nerr->message);
-		nih_free(nerr);
-		return false;
-	}
-	return true;
-}
-
-/* Internal helper.  Must be called with the cgmanager dbus socket open */
-static bool chown_cgroup(const char *cgroup_path, struct lxc_conf *conf)
-{
-	struct chown_data data;
-	char **slist = subsystems;
-	int i;
-
-	if (lxc_list_empty(&conf->id_map))
-		/* If there's no mapping then we don't need to chown */
-		return true;
-
-	data.cgroup_path = cgroup_path;
-	data.origuid = geteuid();
-
-	/* Unpriv users can't chown it themselves, so chown from
-	 * a child namespace mapping both our own and the target uid
-	 */
-	if (userns_exec_1(conf, chown_cgroup_wrapper, &data) < 0) {
-		ERROR("Error requesting cgroup chown in new namespace");
-		return false;
-	}
-
-	/*
-	 * Now chmod 775 the directory else the container cannot create cgroups.
-	 * This can't be done in the child namespace because it only group-owns
-	 * the cgroup
-	 */
-	if (cgm_all_controllers_same)
-		slist = subsystems_inone;
-
-	for (i = 0; slist[i]; i++) {
-		if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "", 0775))
-			return false;
-		if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "tasks", 0664))
-			return false;
-		if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "cgroup.procs", 0664))
-			return false;
-	}
-
-	return true;
-}
-
-#define CG_REMOVE_RECURSIVE 1
-/* Internal helper.  Must be called with the cgmanager dbus socket open */
-static void cgm_remove_cgroup(const char *controller, const char *path)
-{
-	int existed;
-	if ( cgmanager_remove_sync(NULL, cgroup_manager, controller,
-				   path, CG_REMOVE_RECURSIVE, &existed) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("call to cgmanager_remove_sync failed: %s", nerr->message);
-		nih_free(nerr);
-		ERROR("Error removing %s:%s", controller, path);
-	}
-	if (existed == -1)
-		INFO("cgroup removal attempt: %s:%s did not exist", controller, path);
-}
-
-static void *cgm_init(const char *name)
-{
-	struct cgm_data *d;
-
-	d = malloc(sizeof(*d));
-	if (!d)
-		return NULL;
-
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		goto err1;
-	}
-
-	memset(d, 0, sizeof(*d));
-	d->name = strdup(name);
-	if (!d->name) {
-		cgm_dbus_disconnect();
-		goto err1;
-	}
-
-	d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
-
-	// cgm_create immediately gets called so keep the connection open
-	return d;
-
-err1:
-	free(d);
-	return NULL;
-}
-
-/* Called after a failed container startup */
-static void cgm_destroy(void *hdata, struct lxc_conf *conf)
-{
-	struct cgm_data *d = hdata;
-	char **slist = subsystems;
-	int i;
-
-	if (!d || !d->cgroup_path)
-		return;
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		return;
-	}
-
-	if (cgm_all_controllers_same)
-		slist = subsystems_inone;
-	for (i = 0; slist[i]; i++)
-		cgm_remove_cgroup(slist[i], d->cgroup_path);
-
-	free(d->name);
-	free(d->cgroup_path);
-	free(d);
-	cgm_dbus_disconnect();
-}
-
-/*
- * remove all the cgroups created
- * called internally with dbus connection open
- */
-static inline void cleanup_cgroups(char *path)
-{
-	int i;
-	char **slist = subsystems;
-
-	if (cgm_all_controllers_same)
-		slist = subsystems_inone;
-	for (i = 0; slist[i]; i++)
-		cgm_remove_cgroup(slist[i], path);
-}
-
-static inline bool cgm_create(void *hdata)
-{
-	struct cgm_data *d = hdata;
-	char **slist = subsystems;
-	int i, index=0, baselen, ret;
-	int32_t existed;
-	char result[MAXPATHLEN], *tmp, *cgroup_path;
-
-	if (!d)
-		return false;
-// XXX we should send a hint to the cgmanager that when these
-// cgroups become empty they should be deleted.  Requires a cgmanager
-// extension
-
-	memset(result, 0, MAXPATHLEN);
-	tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
-	if (!tmp)
-		goto bad;
-	if (strlen(tmp) >= MAXPATHLEN) {
-		free(tmp);
-		goto bad;
-	}
-	strcpy(result, tmp);
-	baselen = strlen(result);
-	free(tmp);
-	tmp = result;
-	while (*tmp == '/')
-		tmp++;
-again:
-	if (index == 100) { // turn this into a warn later
-		ERROR("cgroup error?  100 cgroups with this name already running");
-		goto bad;
-	}
-	if (index) {
-		ret = snprintf(result+baselen, MAXPATHLEN-baselen, "-%d", index);
-		if (ret < 0 || ret >= MAXPATHLEN-baselen)
-			goto bad;
-	}
-	existed = 0;
-
-	if (cgm_all_controllers_same)
-		slist = subsystems_inone;
-
-	for (i = 0; slist[i]; i++) {
-		if (!lxc_cgmanager_create(slist[i], tmp, &existed)) {
-			ERROR("Error creating cgroup %s:%s", slist[i], result);
-			cleanup_cgroups(tmp);
-			goto bad;
-		}
-		if (existed == 1)
-			goto next;
-	}
-	// success
-	cgroup_path = strdup(tmp);
-	if (!cgroup_path) {
-		cleanup_cgroups(tmp);
-		goto bad;
-	}
-	d->cgroup_path = cgroup_path;
-	cgm_dbus_disconnect();
-	return true;
-
-next:
-	index++;
-	goto again;
-bad:
-	cgm_dbus_disconnect();
-	return false;
-}
-
-/*
- * Use the cgmanager to move a task into a cgroup for a particular
- * hierarchy.
- * All the subsystems in this hierarchy are co-mounted, so we only
- * need to transition the task into one of the cgroups
- *
- * Internal helper, must be called with cgmanager dbus socket open
- */
-static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
-		const char *cgroup_path, bool abs)
-{
-	int ret;
-
-	if (abs)
-		ret = cgmanager_move_pid_abs_sync(NULL, cgroup_manager,
-			controller, cgroup_path, pid);
-	else
-		ret = cgmanager_move_pid_sync(NULL, cgroup_manager,
-			controller, cgroup_path, pid);
-	if (ret != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		WARN("call to cgmanager_move_pid_%ssync failed: %s",
-			abs ? "abs_" : "", nerr->message);
-		nih_free(nerr);
-		return false;
-	}
-	return true;
-}
-
-static inline bool cgm_enter(void *hdata, pid_t pid)
-{
-	struct cgm_data *d = hdata;
-	char **slist = subsystems;
-	bool ret = false;
-	int i;
-
-	if (!d || !d->cgroup_path)
-		return false;
-
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		return false;
-	}
-
-	if (cgm_all_controllers_same)
-		slist = subsystems_inone;
-
-	for (i = 0; slist[i]; i++) {
-		if (!lxc_cgmanager_enter(pid, slist[i], d->cgroup_path, false))
-			goto out;
-	}
-	ret = true;
-out:
-	cgm_dbus_disconnect();
-	return ret;
-}
-
-static const char *cgm_get_cgroup(void *hdata, const char *subsystem)
-{
-	struct cgm_data *d = hdata;
-
-	if (!d || !d->cgroup_path)
-		return NULL;
-	return d->cgroup_path;
-}
-
-static const char *cgm_canonical_path(void *hdata)
-{
-	struct cgm_data *d = hdata;
-
-	if (!d || !d->cgroup_path)
-		return NULL;
-	return d->cgroup_path;
-}
-
-#if HAVE_CGMANAGER_GET_PID_CGROUP_ABS_SYNC
-static inline bool abs_cgroup_supported(void) {
-	return api_version >= CGM_SUPPORTS_GET_ABS;
-}
-#else
-static inline bool abs_cgroup_supported(void) {
-	return false;
-}
-#define cgmanager_get_pid_cgroup_abs_sync(...) -1
-#endif
-
-static char *try_get_abs_cgroup(const char *name, const char *lxcpath,
-		const char *controller)
-{
-	char *cgroup = NULL;
-
-	if (abs_cgroup_supported()) {
-		/* get the container init pid and ask for its abs cgroup */
-		pid_t pid = lxc_cmd_get_init_pid(name, lxcpath);
-		if (pid < 0)
-			return NULL;
-		if (cgmanager_get_pid_cgroup_abs_sync(NULL, cgroup_manager,
-				controller, pid, &cgroup) != 0) {
-			cgroup = NULL;
-			NihError *nerr;
-			nerr = nih_error_get();
-			nih_free(nerr);
-		} else
-			prune_init_scope(cgroup);
-		return cgroup;
-	}
-
-	/* use the command interface to look for the cgroup */
-	return lxc_cmd_get_cgroup_path(name, lxcpath, controller);
-}
-
-/*
- * nrtasks is called by the utmp helper by the container monitor.
- * cgmanager socket was closed after cgroup setup was complete, so we need
- * to reopen here.
- *
- * Return -1 on error.
- */
-static int cgm_get_nrtasks(void *hdata)
-{
-	struct cgm_data *d = hdata;
-	int32_t *pids;
-	size_t pids_len;
-
-	if (!d || !d->cgroup_path)
-		return -1;
-
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		return -1;
-	}
-	if (cgmanager_get_tasks_sync(NULL, cgroup_manager, subsystems[0],
-				     d->cgroup_path, &pids, &pids_len) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("call to cgmanager_get_tasks_sync failed: %s", nerr->message);
-		nih_free(nerr);
-		pids_len = -1;
-		goto out;
-	}
-	nih_free(pids);
-out:
-	cgm_dbus_disconnect();
-	return pids_len;
-}
-
-#if HAVE_CGMANAGER_LIST_CONTROLLERS
-static bool lxc_list_controllers(char ***list)
-{
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		return false;
-	}
-	if (cgmanager_list_controllers_sync(NULL, cgroup_manager, list) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("call to cgmanager_list_controllers_sync failed: %s", nerr->message);
-		nih_free(nerr);
-		cgm_dbus_disconnect();
-		return false;
-	}
-
-	cgm_dbus_disconnect();
-	return true;
-}
-#else
-static bool lxc_list_controllers(char ***list)
-{
-	return false;
-}
-#endif
-
-static inline void free_abs_cgroup(char *cgroup)
-{
-	if (!cgroup)
-		return;
-	if (abs_cgroup_supported())
-		nih_free(cgroup);
-	else
-		free(cgroup);
-}
-
-static void do_cgm_get(const char *name, const char *lxcpath, const char *filename, int outp, bool sendvalue)
-{
-	char *controller, *key, *cgroup = NULL, *cglast;
-	int len = -1;
-	int ret;
-	nih_local char *result = NULL;
-
-	controller = alloca(strlen(filename)+1);
-	strcpy(controller, filename);
-	key = strchr(controller, '.');
-	if (!key) {
-		ret = write(outp, &len, sizeof(len));
-		if (ret != sizeof(len))
-			WARN("Failed to warn cgm_get of error; parent may hang");
-		exit(1);
-	}
-	*key = '\0';
-
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		ret = write(outp, &len, sizeof(len));
-		if (ret != sizeof(len))
-			WARN("Failed to warn cgm_get of error; parent may hang");
-		exit(1);
-	}
-	cgroup = try_get_abs_cgroup(name, lxcpath, controller);
-	if (!cgroup) {
-		cgm_dbus_disconnect();
-		ret = write(outp, &len, sizeof(len));
-		if (ret != sizeof(len))
-			WARN("Failed to warn cgm_get of error; parent may hang");
-		exit(1);
-	}
-	cglast = strrchr(cgroup, '/');
-	if (!cglast) {
-		cgm_dbus_disconnect();
-		free_abs_cgroup(cgroup);
-		ret = write(outp, &len, sizeof(len));
-		if (ret != sizeof(len))
-			WARN("Failed to warn cgm_get of error; parent may hang");
-		exit(1);
-	}
-	*cglast = '\0';
-	if (!lxc_cgmanager_enter(getpid(), controller, cgroup, abs_cgroup_supported())) {
-		WARN("Failed to enter container cgroup %s:%s", controller, cgroup);
-		ret = write(outp, &len, sizeof(len));
-		if (ret != sizeof(len))
-			WARN("Failed to warn cgm_get of error; parent may hang");
-		cgm_dbus_disconnect();
-		free_abs_cgroup(cgroup);
-		exit(1);
-	}
-	if (cgmanager_get_value_sync(NULL, cgroup_manager, controller, cglast+1, filename, &result) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		nih_free(nerr);
-		free_abs_cgroup(cgroup);
-		cgm_dbus_disconnect();
-		ret = write(outp, &len, sizeof(len));
-		if (ret != sizeof(len))
-			WARN("Failed to warn cgm_get of error; parent may hang");
-		exit(1);
-	}
-	free_abs_cgroup(cgroup);
-	cgm_dbus_disconnect();
-	len = strlen(result);
-	ret = write(outp, &len, sizeof(len));
-	if (ret != sizeof(len)) {
-		WARN("Failed to send length to parent");
-		exit(1);
-	}
-	if (!len || !sendvalue) {
-		exit(0);
-	}
-	ret = write(outp, result, len);
-	if (ret < 0)
-		exit(1);
-	exit(0);
-}
-
-/* cgm_get is called to get container cgroup settings, not during startup */
-static int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
-{
-	pid_t pid;
-	int p[2], ret, newlen, readlen;
-
-	if (pipe(p) < 0)
-		return -1;
-	if ((pid = fork()) < 0) {
-		close(p[0]);
-		close(p[1]);
-		return -1;
-	}
-	if (!pid) // do_cgm_get exits
-		do_cgm_get(name, lxcpath, filename, p[1], len && value);
-	close(p[1]);
-	ret = read(p[0], &newlen, sizeof(newlen));
-	if (ret != sizeof(newlen)) {
-		close(p[0]);
-		ret = -1;
-		goto out;
-	}
-	if (!len || !value) {
-		close(p[0]);
-		ret = newlen;
-		goto out;
-	}
-	memset(value, 0, len);
-	if (newlen < 0) { // child is reporting an error
-		close(p[0]);
-		ret = -1;
-		goto out;
-	}
-	if (newlen == 0) { // empty read
-		close(p[0]);
-		ret = 0;
-		goto out;
-	}
-	readlen = newlen > len ? len : newlen;
-	ret = read(p[0], value, readlen);
-	close(p[0]);
-	if (ret != readlen) {
-		ret = -1;
-		goto out;
-	}
-	if (newlen >= len) {
-		value[len-1] = '\0';
-		newlen = len-1;
-	} else if (newlen+1 < len) {
-		// cgmanager doesn't add eol to last entry
-		value[newlen++] = '\n';
-		value[newlen] = '\0';
-	}
-	ret = newlen;
-out:
-	if (wait_for_pid(pid))
-		WARN("do_cgm_get exited with error");
-	return ret;
-}
-
-static void do_cgm_set(const char *name, const char *lxcpath, const char *filename, const char *value, int outp)
-{
-	char *controller, *key, *cgroup = NULL;
-	int retval = 0;  // value we are sending to the parent over outp
-	int ret;
-	char *cglast;
-
-	controller = alloca(strlen(filename)+1);
-	strcpy(controller, filename);
-	key = strchr(controller, '.');
-	if (!key) {
-		ret = write(outp, &retval, sizeof(retval));
-		if (ret != sizeof(retval))
-			WARN("Failed to warn cgm_set of error; parent may hang");
-		exit(1);
-	}
-	*key = '\0';
-
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		ret = write(outp, &retval, sizeof(retval));
-		if (ret != sizeof(retval))
-			WARN("Failed to warn cgm_set of error; parent may hang");
-		exit(1);
-	}
-	cgroup = try_get_abs_cgroup(name, lxcpath, controller);
-	if (!cgroup) {
-		cgm_dbus_disconnect();
-		ret = write(outp, &retval, sizeof(retval));
-		if (ret != sizeof(retval))
-			WARN("Failed to warn cgm_set of error; parent may hang");
-		exit(1);
-	}
-	cglast = strrchr(cgroup, '/');
-	if (!cglast) {
-		cgm_dbus_disconnect();
-		free_abs_cgroup(cgroup);
-		ret = write(outp, &retval, sizeof(retval));
-		if (ret != sizeof(retval))
-			WARN("Failed to warn cgm_set of error; parent may hang");
-		exit(1);
-	}
-	*cglast = '\0';
-	if (!lxc_cgmanager_enter(getpid(), controller, cgroup, abs_cgroup_supported())) {
-		ERROR("Failed to enter container cgroup %s:%s", controller, cgroup);
-		ret = write(outp, &retval, sizeof(retval));
-		if (ret != sizeof(retval))
-			WARN("Failed to warn cgm_set of error; parent may hang");
-		cgm_dbus_disconnect();
-		free_abs_cgroup(cgroup);
-		exit(1);
-	}
-	if (cgmanager_set_value_sync(NULL, cgroup_manager, controller, cglast+1, filename, value) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("Error setting cgroup value %s for %s:%s", filename, controller, cgroup);
-		ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
-		nih_free(nerr);
-		free_abs_cgroup(cgroup);
-		cgm_dbus_disconnect();
-		ret = write(outp, &retval, sizeof(retval));
-		if (ret != sizeof(retval))
-			WARN("Failed to warn cgm_set of error; parent may hang");
-		exit(1);
-	}
-	free_abs_cgroup(cgroup);
-	cgm_dbus_disconnect();
-	/* tell parent that we are done */
-	retval = 1;
-	ret = write(outp, &retval, sizeof(retval));
-	if (ret != sizeof(retval)) {
-		exit(1);
-	}
-	exit(0);
-}
-
-/* cgm_set is called to change cgroup settings, not during startup */
-static int cgm_set(const char *filename, const char *value, const char *name, const char *lxcpath)
-{
-	pid_t pid;
-	int p[2], ret, v;
-
-	if (pipe(p) < 0)
-		return -1;
-	if ((pid = fork()) < 0) {
-		close(p[1]);
-		close(p[0]);
-		return -1;
-	}
-	if (!pid) // do_cgm_set exits
-		do_cgm_set(name, lxcpath, filename, value, p[1]);
-	close(p[1]);
-	ret = read(p[0], &v, sizeof(v));
-	close(p[0]);
-	if (wait_for_pid(pid))
-		WARN("do_cgm_set exited with error");
-	if (ret != sizeof(v) || !v)
-		return -1;
-	return 0;
-}
-
-static void free_subsystems(void)
-{
-	int i;
-
-	for (i = 0; i < nr_subsystems; i++)
-		free(subsystems[i]);
-	free(subsystems);
-	subsystems = NULL;
-	nr_subsystems = 0;
-}
-
-static void cull_user_controllers(void)
-{
-	int i, j;
-
-	for (i = 0;  i < nr_subsystems; i++) {
-		if (strncmp(subsystems[i], "name=", 5) != 0)
-			continue;
-		for (j = i;  j < nr_subsystems-1; j++)
-			subsystems[j] = subsystems[j+1];
-		nr_subsystems--;
-	}
-}
-
-/*
- * return true if inword is in the comma-delimited list cgroup_use
- */
-static bool in_comma_list(const char *inword, const char *cgroup_use)
-{
-	char *e;
-	size_t inlen = strlen(inword), len;
-
-	do {
-		e = strchr(cgroup_use, ',');
-		len = e ? e - cgroup_use : strlen(cgroup_use);
-		if (len == inlen && strncmp(inword, cgroup_use, len) == 0)
-			return true;
-		cgroup_use = e + 1;
-	} while (e);
-
-	return false;
-}
-
-/*
- * inlist is a comma-delimited list of cgroups;  so is checklist.  Return
- * true if any member of inlist is in checklist.
- */
-static bool any_in_comma_list(const char *inlist, const char *checklist)
-{
-	char *tmp = alloca(strlen(inlist) + 1), *tok, *saveptr = NULL;
-
-	strcpy(tmp, inlist);
-	for (tok = strtok_r(tmp, ",", &saveptr); tok; tok = strtok_r(NULL, ",", &saveptr)) {
-		if (in_comma_list(tok, checklist))
-			return true;
-	}
-
-	return false;
-}
-
-static bool in_subsystem_list(const char *c)
-{
-	int i;
-
-	for (i = 0; i < nr_subsystems; i++) {
-		if (strcmp(c, subsystems[i]) == 0)
-			return true;
-	}
-
-	return false;
-}
-
-/*
- * If /etc/lxc/lxc.conf specifies lxc.cgroup.use = "freezer,memory",
- * then clear out any other subsystems, and make sure that freezer
- * and memory are both enabled
- */
-static bool verify_and_prune(const char *cgroup_use)
-{
-	const char *p;
-	char *e;
-	int i, j;
-
-	for (p = cgroup_use; p && *p; p = e + 1) {
-		e = strchr(p, ',');
-		if (e)
-			*e = '\0';
-
-		if (!in_subsystem_list(p)) {
-			ERROR("Controller %s required by lxc.cgroup.use but not available\n", p);
-			return false;
-		}
-
-		if (e)
-			*e = ',';
-		if (!e)
-			break;
-	}
-
-	for (i = 0; i < nr_subsystems;) {
-		if (in_comma_list(subsystems[i], cgroup_use)) {
-			i++;
-			continue;
-		}
-		free(subsystems[i]);
-		for (j = i;  j < nr_subsystems-1; j++)
-			subsystems[j] = subsystems[j+1];
-		subsystems[nr_subsystems-1] = NULL;
-		nr_subsystems--;
-	}
-
-	return true;
-}
-
-static void drop_subsystem(int which)
-{
-	int i;
-
-	if (which < 0 || which >= nr_subsystems) {
-		ERROR("code error: dropping invalid subsystem index\n");
-		exit(1);
-	}
-
-	free(subsystems[which]);
-	/* note - we have nr_subsystems+1 entries, last one a NULL */
-	for (i = which; i < nr_subsystems; i++)
-		subsystems[i] = subsystems[i+1];
-	nr_subsystems -= 1;
-}
-
-/*
- * Check whether we can create the cgroups we would want
- */
-static bool subsys_is_writeable(const char *controller, const char *probe)
-{
-	int32_t existed;
-	bool ret = true;
-
-	if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
-				       probe, &existed) != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("call to cgmanager_create_sync failed: %s", nerr->message);
-		nih_free(nerr);
-		ERROR("Failed to create %s:%s", controller, probe);
-		ret = false;
-	}
-
-	return ret;
-}
-
-static char *get_last_controller_in_list(char *list)
-{
-	char *p;
-
-	while ((p = strchr(list, ',')) != NULL)
-		list = p + 1;
-
-	return list;
-}
-
-/*
- * Make sure that all the controllers are writeable.
- * If any are not, then
- *   - if they are listed in lxc.cgroup.use, refuse to start
- *   - else if they are crucial subsystems, refuse to start
- *   - else warn and do not use them
- */
-static bool verify_final_subsystems(const char *cgroup_use)
-{
-	int i;
-	bool dropped_any = false;
-	bool bret = false;
-	const char *cgroup_pattern;
-	char tmpnam[50], *probe;
-
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		return false;
-	}
-
-	cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
-	i = snprintf(tmpnam, 50, "lxcprobe-%d", getpid());
-	if (i < 0 || i >= 50) {
-		ERROR("Attack - format string modified?");
-		return false;
-	}
-	probe = lxc_string_replace("%n", tmpnam, cgroup_pattern);
-	if (!probe)
-		goto out;
-
-	i = 0;
-	while (i < nr_subsystems) {
-		char *p = get_last_controller_in_list(subsystems[i]);
-
-		if (!subsys_is_writeable(p, probe)) {
-			if (is_crucial_cgroup_subsystem(p)) {
-				ERROR("Cannot write to crucial subsystem %s\n",
-					subsystems[i]);
-				goto out;
-			}
-			if (cgroup_use && any_in_comma_list(subsystems[i], cgroup_use)) {
-				ERROR("Cannot write to subsystem %s which is requested in lxc.cgroup.use\n",
-					subsystems[i]);
-				goto out;
-			}
-			WARN("Cannot write to subsystem %s, continuing with out it\n",
-				subsystems[i]);
-			dropped_any = true;
-			drop_subsystem(i);
-		} else {
-			cgm_remove_cgroup(subsystems[i], probe);
-			i++;
-		}
-	}
-
-	if (dropped_any)
-		cgm_all_controllers_same = false;
-	bret = true;
-
-out:
-	free(probe);
-	cgm_dbus_disconnect();
-	return bret;
-}
-
-static bool collect_subsystems(void)
-{
-	char *line = NULL;
-	nih_local char **cgm_subsys_list = NULL;
-	size_t sz = 0;
-	FILE *f = NULL;
-
-	if (subsystems) // already initialized
-		return true;
-
-	subsystems_inone = malloc(2 * sizeof(char *));
-	if (!subsystems_inone)
-		return false;
-	subsystems_inone[0] = "all";
-	subsystems_inone[1] = NULL;
-
-	if (lxc_list_controllers(&cgm_subsys_list)) {
-		while (cgm_subsys_list[nr_subsystems]) {
-			char **tmp = NIH_MUST( realloc(subsystems,
-						(nr_subsystems+2)*sizeof(char *)) );
-			tmp[nr_subsystems] = NIH_MUST(
-					strdup(cgm_subsys_list[nr_subsystems++]) );
-			subsystems = tmp;
-		}
-		if (nr_subsystems)
-			subsystems[nr_subsystems] = NULL;
-		goto collected;
-	}
-
-	INFO("cgmanager_list_controllers failed, falling back to /proc/self/cgroups");
-	f = fopen_cloexec("/proc/self/cgroup", "r");
-	if (!f) {
-		f = fopen_cloexec("/proc/1/cgroup", "r");
-		if (!f)
-			return false;
-	}
-	while (getline(&line, &sz, f) != -1) {
-		/* file format: hierarchy:subsystems:group,
-		 * with multiple subsystems being ,-separated */
-		char *slist, *end, *p, *saveptr = NULL, **tmp;
-
-		if (!line[0])
-			continue;
-
-		slist = strchr(line, ':');
-		if (!slist)
-			continue;
-		slist++;
-		end = strchr(slist, ':');
-		if (!end)
-			continue;
-		*end = '\0';
-
-		for (p = strtok_r(slist, ",", &saveptr);
-				p;
-				p = strtok_r(NULL, ",", &saveptr)) {
-			tmp = realloc(subsystems, (nr_subsystems+2)*sizeof(char *));
-			if (!tmp)
-				goto out_free;
-
-			subsystems = tmp;
-			tmp[nr_subsystems] = strdup(p);
-			tmp[nr_subsystems+1] = NULL;
-			if (!tmp[nr_subsystems])
-				goto out_free;
-			nr_subsystems++;
-		}
-	}
-	fclose(f);
-	f = NULL;
-
-	free(line);
-	line = NULL;
-
-collected:
-	if (!nr_subsystems) {
-		ERROR("No cgroup subsystems found");
-		return false;
-	}
-
-	/* make sure that cgroup.use can be and is honored */
-	const char *cgroup_use = lxc_global_config_value("lxc.cgroup.use");
-	if (!cgroup_use && errno != 0)
-		goto final_verify;
-	if (cgroup_use) {
-		if (!verify_and_prune(cgroup_use)) {
-			free_subsystems();
-			return false;
-		}
-		subsystems_inone[0] = NIH_MUST( strdup(cgroup_use) );
-		cgm_all_controllers_same = false;
-	}
-
-final_verify:
-	return verify_final_subsystems(cgroup_use);
-
-out_free:
-	free(line);
-	if (f)
-		fclose(f);
-	free_subsystems();
-	return false;
-}
-
-/*
- * called during cgroup.c:cgroup_ops_init(), at startup.  No threads.
- * We check whether we can talk to cgmanager, escape to root cgroup if
- * we are root, then close the connection.
- */
-struct cgroup_ops *cgm_ops_init(void)
-{
-	check_supports_multiple_controllers(-1);
-	if (!collect_subsystems())
-		return NULL;
-
-	if (api_version < CGM_SUPPORTS_MULT_CONTROLLERS)
-		cgm_all_controllers_same = false;
-
-	// if root, try to escape to root cgroup
-	if (geteuid() == 0 && !cgm_escape(NULL)) {
-		free_subsystems();
-		return NULL;
-	}
-
-	return &cgmanager_ops;
-}
-
-/* unfreeze is called by the command api after killing a container.  */
-static bool cgm_unfreeze(void *hdata)
-{
-	struct cgm_data *d = hdata;
-	bool ret = true;
-
-	if (!d || !d->cgroup_path)
-		return false;
-
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		return false;
-	}
-	if (cgmanager_set_value_sync(NULL, cgroup_manager, "freezer", d->cgroup_path,
-			"freezer.state", "THAWED") != 0) {
-		NihError *nerr;
-		nerr = nih_error_get();
-		ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
-		nih_free(nerr);
-		ERROR("Error unfreezing %s", d->cgroup_path);
-		ret = false;
-	}
-	cgm_dbus_disconnect();
-	return ret;
-}
-
-static bool cgm_setup_limits(void *hdata, struct lxc_list *cgroup_settings, bool do_devices)
-{
-	struct cgm_data *d = hdata;
-	struct lxc_list *iterator, *sorted_cgroup_settings, *next;
-	struct lxc_cgroup *cg;
-	bool ret = false;
-
-	if (lxc_list_empty(cgroup_settings))
-		return true;
-
-	if (!d || !d->cgroup_path)
-		return false;
-
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		return false;
-	}
-
-	sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
-	if (!sorted_cgroup_settings) {
-		return false;
-	}
-
-	lxc_list_for_each(iterator, sorted_cgroup_settings) {
-		char controller[100], *p;
-		cg = iterator->elem;
-		if (do_devices != !strncmp("devices", cg->subsystem, 7))
-			continue;
-		if (strlen(cg->subsystem) > 100) // i smell a rat
-			goto out;
-		strcpy(controller, cg->subsystem);
-		p = strchr(controller, '.');
-		if (p)
-			*p = '\0';
-		if (cgmanager_set_value_sync(NULL, cgroup_manager, controller,
-					 d->cgroup_path, cg->subsystem, cg->value) != 0) {
-			NihError *nerr;
-			nerr = nih_error_get();
-			if (do_devices) {
-				WARN("call to cgmanager_set_value_sync failed: %s", nerr->message);
-				nih_free(nerr);
-				WARN("Error setting cgroup %s:%s limit type %s", controller,
-					d->cgroup_path, cg->subsystem);
-				continue;
-			}
-
-			ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
-			nih_free(nerr);
-			ERROR("Error setting cgroup %s:%s limit type %s", controller,
-				d->cgroup_path, cg->subsystem);
-			goto out;
-		}
-
-		DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
-	}
-
-	ret = true;
-	INFO("cgroup limits have been setup");
-out:
-	lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
-		lxc_list_del(iterator);
-		free(iterator);
-	}
-	free(sorted_cgroup_settings);
-	cgm_dbus_disconnect();
-	return ret;
-}
-
-static bool cgm_chown(void *hdata, struct lxc_conf *conf)
-{
-	struct cgm_data *d = hdata;
-
-	if (!d || !d->cgroup_path)
-		return false;
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		return false;
-	}
-	if (!chown_cgroup(d->cgroup_path, conf))
-		WARN("Failed to chown %s to container root", d->cgroup_path);
-	cgm_dbus_disconnect();
-	return true;
-}
-
-/*
- * TODO: this should be re-written to use the get_config_item("lxc.id_map")
- * cmd api instead of getting the idmap from c->lxc_conf.  The reason is
- * that the id_maps may be different if the container was started with a
- * -f or -s argument.
- * The reason I'm punting on that is because we'll need to parse the
- * idmap results.
- */
-static bool cgm_attach(const char *name, const char *lxcpath, pid_t pid)
-{
-	bool pass = true;
-	char *cgroup = NULL;
-	char **slist = subsystems;
-	int i;
-
-	if (!cgm_dbus_connect()) {
-		ERROR("Error connecting to cgroup manager");
-		return false;
-	}
-
-	for (i = 0; slist[i]; i++) {
-		cgroup = try_get_abs_cgroup(name, lxcpath, slist[i]);
-		if (!cgroup) {
-			ERROR("Failed to get cgroup for controller %s", slist[i]);
-			cgm_dbus_disconnect();
-			return false;
-		}
-
-		if (!lxc_cgmanager_enter(pid, slist[i], cgroup, abs_cgroup_supported())) {
-			pass = false;
-			break;
-		}
-
-	}
-	cgm_dbus_disconnect();
-	if (!pass)
-		ERROR("Failed to enter group %s", cgroup);
-
-	free_abs_cgroup(cgroup);
-	return pass;
-}
-
-static bool cgm_bind_dir(const char *root, const char *dirname)
-{
-	nih_local char *cgpath = NULL;
-
-	/* /sys should have been mounted by now */
-	cgpath = NIH_MUST( nih_strdup(NULL, root) );
-	NIH_MUST( nih_strcat(&cgpath, NULL, "/sys/fs/cgroup") );
-
-	if (!dir_exists(cgpath)) {
-		ERROR("%s does not exist", cgpath);
-		return false;
-	}
-
-	/* mount a tmpfs there so we can create subdirs */
-	if (safe_mount("cgroup", cgpath, "tmpfs", 0, "size=10000,mode=755", root)) {
-		SYSERROR("Failed to mount tmpfs at %s", cgpath);
-		return false;
-	}
-	NIH_MUST( nih_strcat(&cgpath, NULL, "/cgmanager") );
-
-	if (mkdir(cgpath, 0755) < 0) {
-		SYSERROR("Failed to create %s", cgpath);
-		return false;
-	}
-
-	if (safe_mount(dirname, cgpath, "none", MS_BIND, 0, root)) {
-		SYSERROR("Failed to bind mount %s to %s", dirname, cgpath);
-		return false;
-	}
-
-	return true;
-}
-
-/*
- * cgm_mount_cgroup:
- * If /sys/fs/cgroup/cgmanager.lower/ exists, bind mount that to
- * /sys/fs/cgroup/cgmanager/ in the container.
- * Otherwise, if /sys/fs/cgroup/cgmanager exists, bind mount that.
- * Else do nothing
- */
-#define CGMANAGER_LOWER_SOCK "/sys/fs/cgroup/cgmanager.lower"
-#define CGMANAGER_UPPER_SOCK "/sys/fs/cgroup/cgmanager"
-static bool cgm_mount_cgroup(void *hdata, const char *root, int type)
-{
-	if (dir_exists(CGMANAGER_LOWER_SOCK))
-		return cgm_bind_dir(root, CGMANAGER_LOWER_SOCK);
-	if (dir_exists(CGMANAGER_UPPER_SOCK))
-		return cgm_bind_dir(root, CGMANAGER_UPPER_SOCK);
-	// Host doesn't have cgmanager running?  Then how did we get here?
-	return false;
-}
-
-static struct cgroup_ops cgmanager_ops = {
-	.init = cgm_init,
-	.destroy = cgm_destroy,
-	.create = cgm_create,
-	.enter = cgm_enter,
-	.create_legacy = NULL,
-	.get_cgroup = cgm_get_cgroup,
-	.canonical_path = cgm_canonical_path,
-	.escape = cgm_escape,
-	.get = cgm_get,
-	.set = cgm_set,
-	.unfreeze = cgm_unfreeze,
-	.setup_limits = cgm_setup_limits,
-	.name = "cgmanager",
-	.chown = cgm_chown,
-	.attach = cgm_attach,
-	.mount_cgroup = cgm_mount_cgroup,
-	.nrtasks = cgm_get_nrtasks,
-	.disconnect = NULL,
-	.driver = CGMANAGER,
-};
-#endif
diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
deleted file mode 100644
index 91ef359..0000000
--- a/src/lxc/cgroup.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <unistd.h>
-#include <sys/types.h>
-
-#include "cgroup.h"
-#include "conf.h"
-#include "log.h"
-#include "start.h"
-
-lxc_log_define(lxc_cgroup, lxc);
-
-static struct cgroup_ops *ops = NULL;
-
-extern struct cgroup_ops *cgfs_ops_init(void);
-extern struct cgroup_ops *cgfsng_ops_init(void);
-extern struct cgroup_ops *cgm_ops_init(void);
-
-__attribute__((constructor))
-void cgroup_ops_init(void)
-{
-	if (ops) {
-		INFO("cgroup driver %s", ops->name);
-		return;
-	}
-
-	DEBUG("cgroup_init");
-	#if HAVE_CGMANAGER
-	ops = cgm_ops_init();
-	#endif
-	if (!ops)
-		ops = cgfsng_ops_init();
-	if (!ops)
-		ops = cgfs_ops_init();
-	if (ops)
-		INFO("Initialized cgroup driver %s", ops->name);
-}
-
-bool cgroup_init(struct lxc_handler *handler)
-{
-	if (handler->cgroup_data) {
-		ERROR("cgroup_init called on already inited handler");
-		return true;
-	}
-
-	if (ops) {
-		INFO("cgroup driver %s initing for %s", ops->name, handler->name);
-		handler->cgroup_data = ops->init(handler->name);
-	}
-	return handler->cgroup_data != NULL;
-}
-
-void cgroup_destroy(struct lxc_handler *handler)
-{
-	if (ops) {
-		ops->destroy(handler->cgroup_data, handler->conf);
-		handler->cgroup_data = NULL;
-	}
-}
-
-/* Create the container cgroups for all requested controllers */
-bool cgroup_create(struct lxc_handler *handler)
-{
-	if (ops)
-		return ops->create(handler->cgroup_data);
-	return false;
-}
-
-/*
- * Enter the container init into its new cgroups for all
- * requested controllers
- */
-bool cgroup_enter(struct lxc_handler *handler)
-{
-	if (ops)
-		return ops->enter(handler->cgroup_data, handler->pid);
-	return false;
-}
-
-bool cgroup_create_legacy(struct lxc_handler *handler)
-{
-	if (ops && ops->create_legacy)
-		return ops->create_legacy(handler->cgroup_data, handler->pid);
-	return true;
-}
-
-const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem)
-{
-	if (ops)
-		return ops->get_cgroup(handler->cgroup_data, subsystem);
-	return NULL;
-}
-
-bool cgroup_escape(struct lxc_handler *handler)
-{
-	if (ops)
-		return ops->escape(handler->cgroup_data);
-	return false;
-}
-
-const char *cgroup_canonical_path(struct lxc_handler *handler)
-{
-	if (geteuid()) {
-		WARN("cgroup_canonical_path only makes sense for privileged containers.\n");
-		return NULL;
-	}
-
-	if (ops)
-		return ops->canonical_path(handler->cgroup_data);
-
-	return NULL;
-}
-
-bool cgroup_unfreeze(struct lxc_handler *handler)
-{
-	if (ops)
-		return ops->unfreeze(handler->cgroup_data);
-	return false;
-}
-
-bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
-{
-	if (ops)
-		return ops->setup_limits(handler->cgroup_data,
-					 &handler->conf->cgroup, with_devices);
-	return false;
-}
-
-bool cgroup_chown(struct lxc_handler *handler)
-{
-	if (ops && ops->chown)
-		return ops->chown(handler->cgroup_data, handler->conf);
-	return true;
-}
-
-bool cgroup_mount(const char *root, struct lxc_handler *handler, int type)
-{
-	if (ops) {
-		return ops->mount_cgroup(handler->cgroup_data, root, type);
-	}
-	return false;
-}
-
-int cgroup_nrtasks(struct lxc_handler *handler)
-{
-	if (ops) {
-		if (ops->nrtasks)
-			return ops->nrtasks(handler->cgroup_data);
-		else
-			WARN("CGROUP driver %s doesn't implement nrtasks", ops->name);
-	}
-	return -1;
-}
-
-bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid)
-{
-	if (ops)
-		return ops->attach(name, lxcpath, pid);
-	return false;
-}
-
-int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath)
-{
-	if (ops)
-		return ops->set(filename, value, name, lxcpath);
-	return -1;
-}
-
-int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
-{
-	if (ops)
-		return ops->get(filename, value, len, name, lxcpath);
-	return -1;
-}
-
-void cgroup_disconnect(void)
-{
-	if (ops && ops->disconnect)
-		ops->disconnect();
-}
-
-cgroup_driver_t cgroup_driver(void)
-{
-	return ops->driver;
-}
-
-#define INIT_SCOPE "/init.scope"
-void prune_init_scope(char *cg)
-{
-	char *point;
-
-	if (!cg)
-		return;
-
-	point = cg + strlen(cg) - strlen(INIT_SCOPE);
-	if (point < cg)
-		return;
-	if (strcmp(point, INIT_SCOPE) == 0) {
-		if (point == cg)
-			*(point+1) = '\0';
-		else
-			*point = '\0';
-	}
-}
-
-/*
- * Return true if this is a subsystem which we cannot do
- * without.
- *
- * systemd is questionable here.  The way callers currently
- * use this, if systemd is not mounted then it will be ignored.
- * But if systemd is mounted, then it must be setup so that lxc
- * can create cgroups in it, else containers will fail.
- */
-bool is_crucial_cgroup_subsystem(const char *s)
-{
-	if (strcmp(s, "systemd") == 0)
-		return true;
-	if (strcmp(s, "name=systemd") == 0)
-		return true;
-	if (strcmp(s, "freezer") == 0)
-		return true;
-	return false;
-}
diff --git a/src/lxc/cgroup.h b/src/lxc/cgroup.h
deleted file mode 100644
index e56a115..0000000
--- a/src/lxc/cgroup.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef __LXC_CGROUP_H
-#define __LXC_CGROUP_H
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-struct lxc_handler;
-struct lxc_conf;
-struct lxc_list;
-
-typedef enum {
-	CGFS,
-	CGMANAGER,
-	CGFSNG,
-} cgroup_driver_t;
-
-struct cgroup_ops {
-	const char *name;
-
-	void *(*init)(const char *name);
-	void (*destroy)(void *hdata, struct lxc_conf *conf);
-	bool (*create)(void *hdata);
-	bool (*enter)(void *hdata, pid_t pid);
-	bool (*create_legacy)(void *hdata, pid_t pid);
-	const char *(*get_cgroup)(void *hdata, const char *subsystem);
-	const char *(*canonical_path)(void *hdata);
-	bool (*escape)();
-	int (*set)(const char *filename, const char *value, const char *name, const char *lxcpath);
-	int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
-	bool (*unfreeze)(void *hdata);
-	bool (*setup_limits)(void *hdata, struct lxc_list *cgroup_conf, bool with_devices);
-	bool (*chown)(void *hdata, struct lxc_conf *conf);
-	bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
-	bool (*mount_cgroup)(void *hdata, const char *root, int type);
-	int (*nrtasks)(void *hdata);
-	void (*disconnect)(void);
-	cgroup_driver_t driver;
-};
-
-extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
-extern bool cgroup_mount(const char *root, struct lxc_handler *handler, int type);
-extern void cgroup_destroy(struct lxc_handler *handler);
-extern bool cgroup_init(struct lxc_handler *handler);
-extern bool cgroup_create(struct lxc_handler *handler);
-extern bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices);
-extern bool cgroup_chown(struct lxc_handler *handler);
-extern bool cgroup_enter(struct lxc_handler *handler);
-extern void cgroup_cleanup(struct lxc_handler *handler);
-extern bool cgroup_create_legacy(struct lxc_handler *handler);
-extern int cgroup_nrtasks(struct lxc_handler *handler);
-extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
-extern bool cgroup_escape();
-
-/*
- * Currently, this call  only makes sense for privileged containers.
- */
-extern const char *cgroup_canonical_path(struct lxc_handler *handler);
-extern bool cgroup_unfreeze(struct lxc_handler *handler);
-extern void cgroup_disconnect(void);
-extern cgroup_driver_t cgroup_driver(void);
-
-extern void prune_init_scope(char *cg);
-extern bool is_crucial_cgroup_subsystem(const char *s);
-
-#endif
diff --git a/src/lxc/cgroups/cgfs.c b/src/lxc/cgroups/cgfs.c
new file mode 100644
index 0000000..6b2ac7e
--- /dev/null
+++ b/src/lxc/cgroups/cgfs.c
@@ -0,0 +1,2655 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include "bdev.h"
+#include "error.h"
+#include "commands.h"
+#include "list.h"
+#include "conf.h"
+#include "utils.h"
+#include "log.h"
+#include "cgroup.h"
+#include "start.h"
+#include "state.h"
+
+#if IS_BIONIC
+#include <../include/lxcmntent.h>
+#else
+#include <mntent.h>
+#endif
+
+struct cgroup_hierarchy;
+struct cgroup_meta_data;
+struct cgroup_mount_point;
+
+/*
+ * cgroup_meta_data: the metadata about the cgroup infrastructure on this
+ *                   host
+ */
+struct cgroup_meta_data {
+	ptrdiff_t ref; /* simple refcount */
+	struct cgroup_hierarchy **hierarchies;
+	struct cgroup_mount_point **mount_points;
+	int maximum_hierarchy;
+};
+
+/*
+ * cgroup_hierarchy: describes a single cgroup hierarchy
+ *                   (may have multiple mount points)
+ */
+struct cgroup_hierarchy {
+	int index;
+	bool used; /* false if the hierarchy should be ignored by lxc */
+	char **subsystems;
+	struct cgroup_mount_point *rw_absolute_mount_point;
+	struct cgroup_mount_point *ro_absolute_mount_point;
+	struct cgroup_mount_point **all_mount_points;
+	size_t all_mount_point_capacity;
+};
+
+/*
+ * cgroup_mount_point: a mount point to where a hierarchy
+ *                     is mounted to
+ */
+struct cgroup_mount_point {
+	struct cgroup_hierarchy *hierarchy;
+	char *mount_point;
+	char *mount_prefix;
+	bool read_only;
+	bool need_cpuset_init;
+};
+
+/*
+ * cgroup_process_info: describes the membership of a
+ *                      process to the different cgroup
+ *                      hierarchies
+ *
+ * Note this is the per-process info tracked by the cgfs_ops.
+ * This is not used with cgmanager.
+ */
+struct cgroup_process_info {
+	struct cgroup_process_info *next;
+	struct cgroup_meta_data *meta_ref;
+	struct cgroup_hierarchy *hierarchy;
+	char *cgroup_path;
+	char *cgroup_path_sub;
+	char **created_paths;
+	size_t created_paths_capacity;
+	size_t created_paths_count;
+	struct cgroup_mount_point *designated_mount_point;
+};
+
+struct cgfs_data {
+	char *name;
+	const char *cgroup_pattern;
+	struct cgroup_meta_data *meta;
+	struct cgroup_process_info *info;
+};
+
+lxc_log_define(lxc_cgfs, lxc);
+
+static struct cgroup_process_info *lxc_cgroup_process_info_getx(const char *proc_pid_cgroup_str, struct cgroup_meta_data *meta);
+static char **subsystems_from_mount_options(const char *mount_options, char **kernel_list);
+static void lxc_cgroup_mount_point_free(struct cgroup_mount_point *mp);
+static void lxc_cgroup_hierarchy_free(struct cgroup_hierarchy *h);
+static bool is_valid_cgroup(const char *name);
+static int create_cgroup(struct cgroup_mount_point *mp, const char *path);
+static int remove_cgroup(struct cgroup_mount_point *mp, const char *path, bool recurse,
+				struct lxc_conf *conf);
+static char *cgroup_to_absolute_path(struct cgroup_mount_point *mp, const char *path, const char *suffix);
+static struct cgroup_process_info *find_info_for_subsystem(struct cgroup_process_info *info, const char *subsystem);
+static int do_cgroup_get(const char *cgroup_path, const char *sub_filename, char *value, size_t len);
+static int do_cgroup_set(const char *cgroup_path, const char *sub_filename, const char *value);
+static bool cgroup_devices_has_allow_or_deny(struct cgfs_data *d, char *v, bool for_allow);
+static int do_setup_cgroup_limits(struct cgfs_data *d, struct lxc_list *cgroup_settings, bool do_devices);
+static int cgroup_recursive_task_count(const char *cgroup_path);
+static int handle_cgroup_settings(struct cgroup_mount_point *mp, char *cgroup_path);
+static bool init_cpuset_if_needed(struct cgroup_mount_point *mp, const char *path);
+
+static struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist);
+static struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data);
+static struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data);
+
+/* free process membership information */
+static void lxc_cgroup_process_info_free(struct cgroup_process_info *info);
+static void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info,
+				struct lxc_conf *conf);
+
+static struct cgroup_ops cgfs_ops;
+
+static int cgroup_rmdir(char *dirname)
+{
+	struct dirent dirent, *direntp;
+	int saved_errno = 0;
+	DIR *dir;
+	int ret, failed=0;
+	char pathname[MAXPATHLEN];
+
+	dir = opendir(dirname);
+	if (!dir) {
+		ERROR("%s: failed to open %s", __func__, dirname);
+		return -1;
+	}
+
+	while (!readdir_r(dir, &dirent, &direntp)) {
+		struct stat mystat;
+		int rc;
+
+		if (!direntp)
+			break;
+
+		if (!strcmp(direntp->d_name, ".") ||
+		    !strcmp(direntp->d_name, ".."))
+			continue;
+
+		rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name);
+		if (rc < 0 || rc >= MAXPATHLEN) {
+			ERROR("pathname too long");
+			failed=1;
+			if (!saved_errno)
+				saved_errno = -ENOMEM;
+			continue;
+		}
+		ret = lstat(pathname, &mystat);
+		if (ret) {
+			SYSERROR("%s: failed to stat %s", __func__, pathname);
+			failed=1;
+			if (!saved_errno)
+				saved_errno = errno;
+			continue;
+		}
+		if (S_ISDIR(mystat.st_mode)) {
+			if (cgroup_rmdir(pathname) < 0) {
+				if (!saved_errno)
+					saved_errno = errno;
+				failed=1;
+			}
+		}
+	}
+
+	if (rmdir(dirname) < 0) {
+		SYSERROR("%s: failed to delete %s", __func__, dirname);
+		if (!saved_errno)
+			saved_errno = errno;
+		failed=1;
+	}
+
+	ret = closedir(dir);
+	if (ret) {
+		SYSERROR("%s: failed to close directory %s", __func__, dirname);
+		if (!saved_errno)
+			saved_errno = errno;
+		failed=1;
+	}
+
+	errno = saved_errno;
+	return failed ? -1 : 0;
+}
+
+static int rmdir_wrapper(void *data)
+{
+	char *path = data;
+
+	if (setresgid(0,0,0) < 0)
+		SYSERROR("Failed to setgid to 0");
+	if (setresuid(0,0,0) < 0)
+		SYSERROR("Failed to setuid to 0");
+	if (setgroups(0, NULL) < 0)
+		SYSERROR("Failed to clear groups");
+
+	return cgroup_rmdir(path);
+}
+
+static struct cgroup_meta_data *lxc_cgroup_load_meta()
+{
+	const char *cgroup_use = NULL;
+	char **cgroup_use_list = NULL;
+	struct cgroup_meta_data *md = NULL;
+	int saved_errno;
+
+	errno = 0;
+	cgroup_use = lxc_global_config_value("lxc.cgroup.use");
+	if (!cgroup_use && errno != 0)
+		return NULL;
+	if (cgroup_use) {
+		cgroup_use_list = lxc_string_split_and_trim(cgroup_use, ',');
+		if (!cgroup_use_list)
+			return NULL;
+	}
+
+	md = lxc_cgroup_load_meta2((const char **)cgroup_use_list);
+	saved_errno = errno;
+	lxc_free_array((void **)cgroup_use_list, free);
+	errno = saved_errno;
+	return md;
+}
+
+/* Step 1: determine all kernel subsystems */
+static bool find_cgroup_subsystems(char ***kernel_subsystems)
+{
+	FILE *proc_cgroups;
+	bool bret = false;
+	char *line = NULL;
+	size_t sz = 0;
+	size_t kernel_subsystems_count = 0;
+	size_t kernel_subsystems_capacity = 0;
+	int r;
+
+	proc_cgroups = fopen_cloexec("/proc/cgroups", "r");
+	if (!proc_cgroups)
+		return false;
+
+	while (getline(&line, &sz, proc_cgroups) != -1) {
+		char *tab1;
+		char *tab2;
+		int hierarchy_number;
+
+		if (line[0] == '#')
+			continue;
+		if (!line[0])
+			continue;
+
+		tab1 = strchr(line, '\t');
+		if (!tab1)
+			continue;
+		*tab1++ = '\0';
+		tab2 = strchr(tab1, '\t');
+		if (!tab2)
+			continue;
+		*tab2 = '\0';
+
+		tab2 = NULL;
+		hierarchy_number = strtoul(tab1, &tab2, 10);
+		if (!tab2 || *tab2)
+			continue;
+		(void)hierarchy_number;
+
+		r = lxc_grow_array((void ***)kernel_subsystems, &kernel_subsystems_capacity, kernel_subsystems_count + 1, 12);
+		if (r < 0)
+			goto out;
+		(*kernel_subsystems)[kernel_subsystems_count] = strdup(line);
+		if (!(*kernel_subsystems)[kernel_subsystems_count])
+			goto out;
+		kernel_subsystems_count++;
+	}
+	bret = true;
+
+out:
+	fclose(proc_cgroups);
+	free(line);
+	return bret;
+}
+
+/* Step 2: determine all hierarchies (by reading /proc/self/cgroup),
+ *         since mount points don't specify hierarchy number and
+ *         /proc/cgroups does not contain named hierarchies
+ */
+static bool find_cgroup_hierarchies(struct cgroup_meta_data *meta_data,
+	bool all_kernel_subsystems, bool all_named_subsystems,
+	const char **subsystem_whitelist)
+{
+	FILE *proc_self_cgroup;
+	char *line = NULL;
+	size_t sz = 0;
+	int r;
+	bool bret = false;
+	size_t hierarchy_capacity = 0;
+
+	proc_self_cgroup = fopen_cloexec("/proc/self/cgroup", "r");
+	/* if for some reason (because of setns() and pid namespace for example),
+	 * /proc/self is not valid, we try /proc/1/cgroup... */
+	if (!proc_self_cgroup)
+		proc_self_cgroup = fopen_cloexec("/proc/1/cgroup", "r");
+	if (!proc_self_cgroup)
+		return false;
+
+	while (getline(&line, &sz, proc_self_cgroup) != -1) {
+		/* file format: hierarchy:subsystems:group,
+		 * we only extract hierarchy and subsystems
+		 * here */
+		char *colon1;
+		char *colon2;
+		int hierarchy_number;
+		struct cgroup_hierarchy *h = NULL;
+		char **p;
+
+		if (!line[0])
+			continue;
+
+		colon1 = strchr(line, ':');
+		if (!colon1)
+			continue;
+		*colon1++ = '\0';
+		colon2 = strchr(colon1, ':');
+		if (!colon2)
+			continue;
+		*colon2 = '\0';
+
+		colon2 = NULL;
+		hierarchy_number = strtoul(line, &colon2, 10);
+		if (!colon2 || *colon2)
+			continue;
+
+		if (hierarchy_number > meta_data->maximum_hierarchy) {
+			/* lxc_grow_array will never shrink, so even if we find a lower
+			* hierarchy number here, the array will never be smaller
+			*/
+			r = lxc_grow_array((void ***)&meta_data->hierarchies, &hierarchy_capacity, hierarchy_number + 1, 12);
+			if (r < 0)
+				goto out;
+
+			meta_data->maximum_hierarchy = hierarchy_number;
+		}
+
+		/* this shouldn't happen, we had this already */
+		if (meta_data->hierarchies[hierarchy_number])
+			goto out;
+
+		h = calloc(1, sizeof(struct cgroup_hierarchy));
+		if (!h)
+			goto out;
+
+		meta_data->hierarchies[hierarchy_number] = h;
+
+		h->index = hierarchy_number;
+		h->subsystems = lxc_string_split_and_trim(colon1, ',');
+		if (!h->subsystems)
+			goto out;
+		/* see if this hierarchy should be considered */
+		if (!all_kernel_subsystems || !all_named_subsystems) {
+			for (p = h->subsystems; *p; p++) {
+				if (!strncmp(*p, "name=", 5)) {
+					if (all_named_subsystems || (subsystem_whitelist && lxc_string_in_array(*p, subsystem_whitelist))) {
+						h->used = true;
+						break;
+					}
+				} else {
+					if (all_kernel_subsystems || (subsystem_whitelist && lxc_string_in_array(*p, subsystem_whitelist))) {
+						h->used = true;
+						break;
+					}
+				}
+			}
+		} else {
+			/* we want all hierarchy anyway */
+			h->used = true;
+		}
+	}
+	bret = true;
+
+out:
+	fclose(proc_self_cgroup);
+	free(line);
+	return bret;
+}
+
+/* Step 3: determine all mount points of each hierarchy */
+static bool find_hierarchy_mountpts( struct cgroup_meta_data *meta_data, char **kernel_subsystems)
+{
+	bool bret = false;
+	FILE *proc_self_mountinfo;
+	char *line = NULL;
+	size_t sz = 0;
+	char **tokens = NULL;
+	size_t mount_point_count = 0;
+	size_t mount_point_capacity = 0;
+	size_t token_capacity = 0;
+	int r;
+	bool is_cgns = cgns_supported();
+
+	proc_self_mountinfo = fopen_cloexec("/proc/self/mountinfo", "r");
+	/* if for some reason (because of setns() and pid namespace for example),
+	 * /proc/self is not valid, we try /proc/1/cgroup... */
+	if (!proc_self_mountinfo)
+		proc_self_mountinfo = fopen_cloexec("/proc/1/mountinfo", "r");
+	if (!proc_self_mountinfo)
+		return false;
+
+	while (getline(&line, &sz, proc_self_mountinfo) != -1) {
+		char *token, *line_tok, *saveptr = NULL;
+		size_t i, j, k;
+		struct cgroup_mount_point *mount_point;
+		struct cgroup_hierarchy *h;
+		char **subsystems;
+		bool is_lxcfs = false;
+
+		if (line[0] && line[strlen(line) - 1] == '\n')
+			line[strlen(line) - 1] = '\0';
+
+		for (i = 0, line_tok = line; (token = strtok_r(line_tok, " ", &saveptr)); line_tok = NULL) {
+			r = lxc_grow_array((void ***)&tokens, &token_capacity, i + 1, 64);
+			if (r < 0)
+				goto out;
+			tokens[i++] = token;
+		}
+
+		/* layout of /proc/self/mountinfo:
+		 *      0: id
+		 *      1: parent id
+		 *      2: device major:minor
+		 *      3: mount prefix
+		 *      4: mount point
+		 *      5: per-mount options
+		 *    [optional X]: additional data
+		 *    X+7: "-"
+		 *    X+8: type
+		 *    X+9: source
+		 *    X+10: per-superblock options
+		 */
+		for (j = 6; j < i && tokens[j]; j++)
+			if (!strcmp(tokens[j], "-"))
+				break;
+
+		/* could not find separator */
+		if (j >= i || !tokens[j])
+			continue;
+		/* there should be exactly three fields after
+		 * the separator
+		 */
+		if (i != j + 4)
+			continue;
+
+		/* not a cgroup filesystem */
+		if (strcmp(tokens[j + 1], "cgroup") != 0) {
+			if (strcmp(tokens[j + 1], "fuse.lxcfs") != 0)
+				continue;
+			if (strncmp(tokens[4], "/sys/fs/cgroup/", 15) != 0)
+				continue;
+			is_lxcfs = true;
+			char *curtok = tokens[4] + 15;
+			subsystems = subsystems_from_mount_options(curtok,
+							 kernel_subsystems);
+		} else
+			subsystems = subsystems_from_mount_options(tokens[j + 3],
+							 kernel_subsystems);
+		if (!subsystems)
+			goto out;
+
+		h = NULL;
+		for (k = 1; k <= meta_data->maximum_hierarchy; k++) {
+			if (meta_data->hierarchies[k] &&
+			    meta_data->hierarchies[k]->subsystems[0] &&
+			    lxc_string_in_array(meta_data->hierarchies[k]->subsystems[0], (const char **)subsystems)) {
+				/* TODO: we could also check if the lists really match completely,
+				 *       just to have an additional sanity check */
+				h = meta_data->hierarchies[k];
+				break;
+			}
+		}
+		lxc_free_array((void **)subsystems, free);
+
+		r = lxc_grow_array((void ***)&meta_data->mount_points, &mount_point_capacity, mount_point_count + 1, 12);
+		if (r < 0)
+			goto out;
+
+		/* create mount point object */
+		mount_point = calloc(1, sizeof(*mount_point));
+		if (!mount_point)
+			goto out;
+
+		meta_data->mount_points[mount_point_count++] = mount_point;
+
+		mount_point->hierarchy = h;
+		if (is_lxcfs || is_cgns)
+			mount_point->mount_prefix = strdup("/");
+		else
+			mount_point->mount_prefix = strdup(tokens[3]);
+		mount_point->mount_point = strdup(tokens[4]);
+		if (!mount_point->mount_point || !mount_point->mount_prefix)
+			goto out;
+		mount_point->read_only = !lxc_string_in_list("rw", tokens[5], ',');
+
+		if (!strcmp(mount_point->mount_prefix, "/")) {
+			if (mount_point->read_only) {
+				if (!h->ro_absolute_mount_point)
+					h->ro_absolute_mount_point = mount_point;
+			} else {
+				if (!h->rw_absolute_mount_point)
+					h->rw_absolute_mount_point = mount_point;
+			}
+		}
+
+		k = lxc_array_len((void **)h->all_mount_points);
+		r = lxc_grow_array((void ***)&h->all_mount_points, &h->all_mount_point_capacity, k + 1, 4);
+		if (r < 0)
+			goto out;
+		h->all_mount_points[k] = mount_point;
+	}
+	bret = true;
+
+out:
+	fclose(proc_self_mountinfo);
+	free(tokens);
+	free(line);
+	return bret;
+}
+
+static struct cgroup_meta_data *lxc_cgroup_load_meta2(const char **subsystem_whitelist)
+{
+	bool all_kernel_subsystems = true;
+	bool all_named_subsystems = false;
+	struct cgroup_meta_data *meta_data = NULL;
+	char **kernel_subsystems = NULL;
+	int saved_errno = 0;
+
+	/* if the subsystem whitelist is not specified, include all
+	 * hierarchies that contain kernel subsystems by default but
+	 * no hierarchies that only contain named subsystems
+	 *
+	 * if it is specified, the specifier @all will select all
+	 * hierarchies, @kernel will select all hierarchies with
+	 * kernel subsystems and @named will select all named
+	 * hierarchies
+	 */
+	all_kernel_subsystems = subsystem_whitelist ?
+		(lxc_string_in_array("@kernel", subsystem_whitelist) || lxc_string_in_array("@all", subsystem_whitelist)) :
+		true;
+	all_named_subsystems = subsystem_whitelist ?
+		(lxc_string_in_array("@named", subsystem_whitelist) || lxc_string_in_array("@all", subsystem_whitelist)) :
+		true;
+
+	meta_data = calloc(1, sizeof(struct cgroup_meta_data));
+	if (!meta_data)
+		return NULL;
+	meta_data->ref = 1;
+
+	if (!find_cgroup_subsystems(&kernel_subsystems))
+		goto out_error;
+
+	if (!find_cgroup_hierarchies(meta_data, all_kernel_subsystems,
+				all_named_subsystems, subsystem_whitelist))
+		goto out_error;
+
+	if (!find_hierarchy_mountpts(meta_data, kernel_subsystems))
+		goto out_error;
+
+	/* oops, we couldn't find anything */
+	if (!meta_data->hierarchies || !meta_data->mount_points) {
+		errno = EINVAL;
+		goto out_error;
+	}
+
+	lxc_free_array((void **)kernel_subsystems, free);
+	return meta_data;
+
+out_error:
+	saved_errno = errno;
+	lxc_free_array((void **)kernel_subsystems, free);
+	lxc_cgroup_put_meta(meta_data);
+	errno = saved_errno;
+	return NULL;
+}
+
+static struct cgroup_meta_data *lxc_cgroup_get_meta(struct cgroup_meta_data *meta_data)
+{
+	meta_data->ref++;
+	return meta_data;
+}
+
+static struct cgroup_meta_data *lxc_cgroup_put_meta(struct cgroup_meta_data *meta_data)
+{
+	size_t i;
+	if (!meta_data)
+		return NULL;
+	if (--meta_data->ref > 0)
+		return meta_data;
+	lxc_free_array((void **)meta_data->mount_points, (lxc_free_fn)lxc_cgroup_mount_point_free);
+	if (meta_data->hierarchies) {
+		for (i = 0; i <= meta_data->maximum_hierarchy; i++)
+			lxc_cgroup_hierarchy_free(meta_data->hierarchies[i]);
+	}
+	free(meta_data->hierarchies);
+	free(meta_data);
+	return NULL;
+}
+
+static struct cgroup_hierarchy *lxc_cgroup_find_hierarchy(struct cgroup_meta_data *meta_data, const char *subsystem)
+{
+	size_t i;
+	for (i = 0; i <= meta_data->maximum_hierarchy; i++) {
+		struct cgroup_hierarchy *h = meta_data->hierarchies[i];
+		if (h && lxc_string_in_array(subsystem, (const char **)h->subsystems))
+			return h;
+	}
+	return NULL;
+}
+
+static bool mountpoint_is_accessible(struct cgroup_mount_point *mp)
+{
+	return mp && access(mp->mount_point, F_OK) == 0;
+}
+
+static struct cgroup_mount_point *lxc_cgroup_find_mount_point(struct cgroup_hierarchy *hierarchy, const char *group, bool should_be_writable)
+{
+	struct cgroup_mount_point **mps;
+	struct cgroup_mount_point *current_result = NULL;
+	ssize_t quality = -1;
+
+	/* trivial case */
+	if (mountpoint_is_accessible(hierarchy->rw_absolute_mount_point))
+		return hierarchy->rw_absolute_mount_point;
+	if (!should_be_writable && mountpoint_is_accessible(hierarchy->ro_absolute_mount_point))
+		return hierarchy->ro_absolute_mount_point;
+
+	for (mps = hierarchy->all_mount_points; mps && *mps; mps++) {
+		struct cgroup_mount_point *mp = *mps;
+		size_t prefix_len = mp->mount_prefix ? strlen(mp->mount_prefix) : 0;
+
+		if (prefix_len == 1 && mp->mount_prefix[0] == '/')
+			prefix_len = 0;
+
+		if (!mountpoint_is_accessible(mp))
+			continue;
+
+		if (should_be_writable && mp->read_only)
+			continue;
+
+		if (!prefix_len ||
+		    (strncmp(group, mp->mount_prefix, prefix_len) == 0 &&
+		     (group[prefix_len] == '\0' || group[prefix_len] == '/'))) {
+			/* search for the best quality match, i.e. the match with the
+			 * shortest prefix where this group is still contained
+			 */
+			if (quality == -1 || prefix_len < quality) {
+				current_result = mp;
+				quality = prefix_len;
+			}
+		}
+	}
+
+	if (!current_result)
+		errno = ENOENT;
+	return current_result;
+}
+
+static char *lxc_cgroup_find_abs_path(const char *subsystem, const char *group, bool should_be_writable, const char *suffix)
+{
+	struct cgroup_meta_data *meta_data;
+	struct cgroup_hierarchy *h;
+	struct cgroup_mount_point *mp;
+	char *result;
+	int saved_errno;
+
+	meta_data = lxc_cgroup_load_meta();
+	if (!meta_data)
+		return NULL;
+
+	h = lxc_cgroup_find_hierarchy(meta_data, subsystem);
+	if (!h)
+		goto out_error;
+
+	mp = lxc_cgroup_find_mount_point(h, group, should_be_writable);
+	if (!mp)
+		goto out_error;
+
+	result = cgroup_to_absolute_path(mp, group, suffix);
+	if (!result)
+		goto out_error;
+
+	lxc_cgroup_put_meta(meta_data);
+	return result;
+
+out_error:
+	saved_errno = errno;
+	lxc_cgroup_put_meta(meta_data);
+	errno = saved_errno;
+	return NULL;
+}
+
+static struct cgroup_process_info *lxc_cgroup_process_info_get(pid_t pid, struct cgroup_meta_data *meta)
+{
+	char pid_buf[32];
+	snprintf(pid_buf, 32, "/proc/%lu/cgroup", (unsigned long)pid);
+	return lxc_cgroup_process_info_getx(pid_buf, meta);
+}
+
+static struct cgroup_process_info *lxc_cgroup_process_info_get_init(struct cgroup_meta_data *meta)
+{
+	return lxc_cgroup_process_info_get(1, meta);
+}
+
+static struct cgroup_process_info *lxc_cgroup_process_info_get_self(struct cgroup_meta_data *meta)
+{
+	struct cgroup_process_info *i;
+	i = lxc_cgroup_process_info_getx("/proc/self/cgroup", meta);
+	if (!i)
+		i = lxc_cgroup_process_info_get(getpid(), meta);
+	return i;
+}
+
+/*
+ * If a controller has ns cgroup mounted, then in that cgroup the handler->pid
+ * is already in a new cgroup named after the pid.  'mnt' is passed in as
+ * the full current cgroup.  Say that is /sys/fs/cgroup/lxc/2975 and the container
+ * name is c1. .  We want to rename the cgroup directory to /sys/fs/cgroup/lxc/c1,
+ * and return the string /sys/fs/cgroup/lxc/c1.
+ */
+static char *cgroup_rename_nsgroup(const char *mountpath, const char *oldname, pid_t pid, const char *name)
+{
+	char *dir, *fulloldpath;
+	char *newname, *fullnewpath;
+	int len, newlen, ret;
+
+	/*
+	 * if cgroup is mounted at /cgroup and task is in cgroup /ab/, pid 2375 and
+	 * name is c1,
+	 * dir: /ab
+	 * fulloldpath = /cgroup/ab/2375
+	 * fullnewpath = /cgroup/ab/c1
+	 * newname = /ab/c1
+	 */
+	dir = alloca(strlen(oldname) + 1);
+	strcpy(dir, oldname);
+
+	len = strlen(oldname) + strlen(mountpath) + 22;
+	fulloldpath = alloca(len);
+	ret = snprintf(fulloldpath, len, "%s/%s/%ld", mountpath, oldname, (unsigned long)pid);
+	if (ret < 0 || ret >= len)
+		return NULL;
+
+	len = strlen(dir) + strlen(name) + 2;
+	newname = malloc(len);
+	if (!newname) {
+		SYSERROR("Out of memory");
+		return NULL;
+	}
+	ret = snprintf(newname, len, "%s/%s", dir, name);
+	if (ret < 0 || ret >= len) {
+		free(newname);
+		return NULL;
+	}
+
+	newlen = strlen(mountpath) + len + 2;
+	fullnewpath = alloca(newlen);
+	ret = snprintf(fullnewpath, newlen, "%s/%s", mountpath, newname);
+	if (ret < 0 || ret >= newlen) {
+		free(newname);
+		return NULL;
+	}
+
+	if (access(fullnewpath, F_OK) == 0) {
+		if (rmdir(fullnewpath) != 0) {
+			SYSERROR("container cgroup %s already exists.", fullnewpath);
+			free(newname);
+			return NULL;
+		}
+	}
+	if (rename(fulloldpath, fullnewpath)) {
+		SYSERROR("failed to rename cgroup %s->%s", fulloldpath, fullnewpath);
+		free(newname);
+		return NULL;
+	}
+
+	DEBUG("'%s' renamed to '%s'", oldname, newname);
+
+	return newname;
+}
+
+static bool is_crucial_hierarchy(struct cgroup_hierarchy *h)
+{
+	char **p;
+
+	for (p = h->subsystems; *p; p++) {
+		if (is_crucial_cgroup_subsystem(*p))
+			return true;
+	}
+	return false;
+}
+
+/* create a new cgroup */
+static struct cgroup_process_info *lxc_cgroupfs_create(const char *name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char *sub_pattern)
+{
+	char **cgroup_path_components = NULL;
+	char **p = NULL;
+	char *path_so_far = NULL;
+	char **new_cgroup_paths = NULL;
+	char **new_cgroup_paths_sub = NULL;
+	struct cgroup_mount_point *mp;
+	struct cgroup_hierarchy *h;
+	struct cgroup_process_info *base_info = NULL;
+	struct cgroup_process_info *info_ptr;
+	int saved_errno;
+	int r;
+	unsigned suffix = 0;
+	bool had_sub_pattern = false;
+	size_t i;
+
+	if (!is_valid_cgroup(name)) {
+		ERROR("Invalid cgroup name: '%s'", name);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (!strstr(path_pattern, "%n")) {
+		ERROR("Invalid cgroup path pattern: '%s'; contains no %%n for specifying container name", path_pattern);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/* we will modify the result of this operation directly,
+	 * so we don't have to copy the data structure
+	 */
+	base_info = (path_pattern[0] == '/') ?
+		lxc_cgroup_process_info_get_init(meta_data) :
+		lxc_cgroup_process_info_get_self(meta_data);
+	if (!base_info)
+		return NULL;
+
+	new_cgroup_paths = calloc(meta_data->maximum_hierarchy + 1, sizeof(char *));
+	if (!new_cgroup_paths)
+		goto out_initial_error;
+
+	new_cgroup_paths_sub = calloc(meta_data->maximum_hierarchy + 1, sizeof(char *));
+	if (!new_cgroup_paths_sub)
+		goto out_initial_error;
+
+	/* find mount points we can use */
+	for (info_ptr = base_info; info_ptr; info_ptr = info_ptr->next) {
+		h = info_ptr->hierarchy;
+		mp = lxc_cgroup_find_mount_point(h, info_ptr->cgroup_path, true);
+		if (!mp) {
+			ERROR("Could not find writable mount point for cgroup hierarchy %d while trying to create cgroup.", h->index);
+			goto out_initial_error;
+		}
+		info_ptr->designated_mount_point = mp;
+
+		if (lxc_string_in_array("ns", (const char **)h->subsystems))
+			continue;
+		if (handle_cgroup_settings(mp, info_ptr->cgroup_path) < 0) {
+			ERROR("Could not set clone_children to 1 for cpuset hierarchy in parent cgroup.");
+			goto out_initial_error;
+		}
+	}
+
+	/* normalize the path */
+	cgroup_path_components = lxc_normalize_path(path_pattern);
+	if (!cgroup_path_components)
+		goto out_initial_error;
+
+	/* go through the path components to see if we can create them */
+	for (p = cgroup_path_components; *p || (sub_pattern && !had_sub_pattern); p++) {
+		/* we only want to create the same component with -1, -2, etc.
+		 * if the component contains the container name itself, otherwise
+		 * it's not an error if it already exists
+		 */
+		char *p_eff = *p ? *p : (char *)sub_pattern;
+		bool contains_name = strstr(p_eff, "%n");
+		char *current_component = NULL;
+		char *current_subpath = NULL;
+		char *current_entire_path = NULL;
+		char *parts[3];
+		size_t j = 0;
+		i = 0;
+
+		/* if we are processing the subpattern, we want to make sure
+		 * loop is ended the next time around
+		 */
+		if (!*p) {
+			had_sub_pattern = true;
+			p--;
+		}
+
+		goto find_name_on_this_level;
+
+	cleanup_name_on_this_level:
+		/* This is reached if we found a name clash.
+		 * In that case, remove the cgroup from all previous hierarchies
+		 */
+		for (j = 0, info_ptr = base_info; j < i && info_ptr; info_ptr = info_ptr->next, j++) {
+			if (info_ptr->created_paths_count < 1)
+				continue;
+			r = remove_cgroup(info_ptr->designated_mount_point, info_ptr->created_paths[info_ptr->created_paths_count - 1], false, NULL);
+			if (r < 0)
+				WARN("could not clean up cgroup we created when trying to create container");
+			free(info_ptr->created_paths[info_ptr->created_paths_count - 1]);
+			info_ptr->created_paths[--info_ptr->created_paths_count] = NULL;
+		}
+		if (current_component != current_subpath)
+			free(current_subpath);
+		if (current_component != p_eff)
+			free(current_component);
+		current_component = current_subpath = NULL;
+		/* try again with another suffix */
+		++suffix;
+
+	find_name_on_this_level:
+		/* determine name of the path component we should create */
+		if (contains_name && suffix > 0) {
+			char *buf = calloc(strlen(name) + 32, 1);
+			if (!buf)
+				goto out_initial_error;
+			snprintf(buf, strlen(name) + 32, "%s-%u", name, suffix);
+			current_component = lxc_string_replace("%n", buf, p_eff);
+			free(buf);
+		} else {
+			current_component = contains_name ? lxc_string_replace("%n", name, p_eff) : p_eff;
+		}
+		parts[0] = path_so_far;
+		parts[1] = current_component;
+		parts[2] = NULL;
+		current_subpath = path_so_far ? lxc_string_join("/", (const char **)parts, false) : current_component;
+
+		/* Now go through each hierarchy and try to create the
+		 * corresponding cgroup
+		 */
+		for (i = 0, info_ptr = base_info; info_ptr; info_ptr = info_ptr->next, i++) {
+			char *parts2[3];
+
+			if (lxc_string_in_array("ns", (const char **)info_ptr->hierarchy->subsystems))
+				continue;
+			current_entire_path = NULL;
+
+			parts2[0] = !strcmp(info_ptr->cgroup_path, "/") ? "" : info_ptr->cgroup_path;
+			parts2[1] = current_subpath;
+			parts2[2] = NULL;
+			current_entire_path = lxc_string_join("/", (const char **)parts2, false);
+
+			if (!*p) {
+				/* we are processing the subpath, so only update that one */
+				free(new_cgroup_paths_sub[i]);
+				new_cgroup_paths_sub[i] = strdup(current_entire_path);
+				if (!new_cgroup_paths_sub[i])
+					goto cleanup_from_error;
+			} else {
+				/* remember which path was used on this controller */
+				free(new_cgroup_paths[i]);
+				new_cgroup_paths[i] = strdup(current_entire_path);
+				if (!new_cgroup_paths[i])
+					goto cleanup_from_error;
+			}
+
+			r = create_cgroup(info_ptr->designated_mount_point, current_entire_path);
+			if (r < 0 && errno == EEXIST && contains_name) {
+				/* name clash => try new name with new suffix */
+				free(current_entire_path);
+				current_entire_path = NULL;
+				goto cleanup_name_on_this_level;
+			} else if (r < 0 && errno != EEXIST) {
+				if (is_crucial_hierarchy(info_ptr->hierarchy)) {
+					SYSERROR("Could not create cgroup '%s' in '%s'.", current_entire_path, info_ptr->designated_mount_point->mount_point);
+					goto cleanup_from_error;
+				}
+				goto skip;
+			} else if (r == 0) {
+				/* successfully created */
+				r = lxc_grow_array((void ***)&info_ptr->created_paths, &info_ptr->created_paths_capacity, info_ptr->created_paths_count + 1, 8);
+				if (r < 0)
+					goto cleanup_from_error;
+				if (!init_cpuset_if_needed(info_ptr->designated_mount_point, current_entire_path)) {
+					ERROR("Failed to initialize cpuset for '%s' in '%s'.", current_entire_path, info_ptr->designated_mount_point->mount_point);
+					goto cleanup_from_error;
+				}
+				info_ptr->created_paths[info_ptr->created_paths_count++] = current_entire_path;
+			} else {
+				/* if we didn't create the cgroup, then we have to make sure that
+				 * further cgroups will be created properly
+				 */
+				if (handle_cgroup_settings(info_ptr->designated_mount_point, info_ptr->cgroup_path) < 0) {
+					ERROR("Could not set clone_children to 1 for cpuset hierarchy in pre-existing cgroup.");
+					goto cleanup_from_error;
+				}
+				if (!init_cpuset_if_needed(info_ptr->designated_mount_point, info_ptr->cgroup_path)) {
+					ERROR("Failed to initialize cpuset in pre-existing '%s'.", info_ptr->cgroup_path);
+					goto cleanup_from_error;
+				}
+
+skip:
+				/* already existed but path component of pattern didn't contain '%n',
+				 * so this is not an error; but then we don't need current_entire_path
+				 * anymore...
+				 */
+				free(current_entire_path);
+				current_entire_path = NULL;
+			}
+		}
+
+		/* save path so far */
+		free(path_so_far);
+		path_so_far = strdup(current_subpath);
+		if (!path_so_far)
+			goto cleanup_from_error;
+
+		/* cleanup */
+		if (current_component != current_subpath)
+			free(current_subpath);
+		if (current_component != p_eff)
+			free(current_component);
+		current_component = current_subpath = NULL;
+		continue;
+
+	cleanup_from_error:
+		/* called if an error occurred in the loop, so we
+		 * do some additional cleanup here
+		 */
+		saved_errno = errno;
+		if (current_component != current_subpath)
+			free(current_subpath);
+		if (current_component != p_eff)
+			free(current_component);
+		free(current_entire_path);
+		errno = saved_errno;
+		goto out_initial_error;
+	}
+
+	/* we're done, now update the paths */
+	for (i = 0, info_ptr = base_info; info_ptr; info_ptr = info_ptr->next, i++) {
+		/* ignore legacy 'ns' subsystem here, lxc_cgroup_create_legacy
+		 * will take care of it
+		 * Since we do a continue in above loop, new_cgroup_paths[i] is
+		 * unset anyway, as is new_cgroup_paths_sub[i]
+		 */
+		if (lxc_string_in_array("ns", (const char **)info_ptr->hierarchy->subsystems))
+			continue;
+		free(info_ptr->cgroup_path);
+		info_ptr->cgroup_path = new_cgroup_paths[i];
+		info_ptr->cgroup_path_sub = new_cgroup_paths_sub[i];
+	}
+	/* don't use lxc_free_array since we used the array members
+	 * to store them in our result...
+	 */
+	free(new_cgroup_paths);
+	free(new_cgroup_paths_sub);
+	free(path_so_far);
+	lxc_free_array((void **)cgroup_path_components, free);
+	return base_info;
+
+out_initial_error:
+	saved_errno = errno;
+	free(path_so_far);
+	lxc_cgroup_process_info_free_and_remove(base_info, NULL);
+	lxc_free_array((void **)new_cgroup_paths, free);
+	lxc_free_array((void **)new_cgroup_paths_sub, free);
+	lxc_free_array((void **)cgroup_path_components, free);
+	errno = saved_errno;
+	return NULL;
+}
+
+static int lxc_cgroup_create_legacy(struct cgroup_process_info *base_info, const char *name, pid_t pid)
+{
+	struct cgroup_process_info *info_ptr;
+	int r;
+
+	for (info_ptr = base_info; info_ptr; info_ptr = info_ptr->next) {
+		if (!lxc_string_in_array("ns", (const char **)info_ptr->hierarchy->subsystems))
+			continue;
+		/*
+		 * For any path which has ns cgroup mounted, handler->pid is already
+		 * moved into a container called '%d % (handler->pid)'.  Rename it to
+		 * the cgroup name and record that.
+		 */
+		char *tmp = cgroup_rename_nsgroup((const char *)info_ptr->designated_mount_point->mount_point,
+				info_ptr->cgroup_path, pid, name);
+		if (!tmp)
+			return -1;
+		free(info_ptr->cgroup_path);
+		info_ptr->cgroup_path = tmp;
+		r = lxc_grow_array((void ***)&info_ptr->created_paths, &info_ptr->created_paths_capacity, info_ptr->created_paths_count + 1, 8);
+		if (r < 0)
+			return -1;
+		tmp = strdup(tmp);
+		if (!tmp)
+			return -1;
+		info_ptr->created_paths[info_ptr->created_paths_count++] = tmp;
+	}
+	return 0;
+}
+
+/* get the cgroup membership of a given container */
+static struct cgroup_process_info *lxc_cgroup_get_container_info(const char *name, const char *lxcpath, struct cgroup_meta_data *meta_data)
+{
+	struct cgroup_process_info *result = NULL;
+	int saved_errno = 0;
+	size_t i;
+	struct cgroup_process_info **cptr = &result;
+	struct cgroup_process_info *entry = NULL;
+	char *path = NULL;
+
+	for (i = 0; i <= meta_data->maximum_hierarchy; i++) {
+		struct cgroup_hierarchy *h = meta_data->hierarchies[i];
+		if (!h || !h->used)
+			continue;
+
+		/* use the command interface to look for the cgroup */
+		path = lxc_cmd_get_cgroup_path(name, lxcpath, h->subsystems[0]);
+		if (!path) {
+			h->used = false;
+			continue;
+		}
+
+		entry = calloc(1, sizeof(struct cgroup_process_info));
+		if (!entry)
+			goto out_error;
+		entry->meta_ref = lxc_cgroup_get_meta(meta_data);
+		entry->hierarchy = h;
+		entry->cgroup_path = path;
+		path = NULL;
+
+		/* it is not an error if we don't find anything here,
+		 * it is up to the caller to decide what to do in that
+		 * case */
+		entry->designated_mount_point = lxc_cgroup_find_mount_point(h, entry->cgroup_path, true);
+
+		*cptr = entry;
+		cptr = &entry->next;
+		entry = NULL;
+	}
+
+	return result;
+out_error:
+	saved_errno = errno;
+	free(path);
+	lxc_cgroup_process_info_free(result);
+	lxc_cgroup_process_info_free(entry);
+	errno = saved_errno;
+	return NULL;
+}
+
+/* move a processs to the cgroups specified by the membership */
+static int lxc_cgroupfs_enter(struct cgroup_process_info *info, pid_t pid, bool enter_sub)
+{
+	char pid_buf[32];
+	char *cgroup_tasks_fn;
+	int r;
+	struct cgroup_process_info *info_ptr;
+
+	snprintf(pid_buf, 32, "%lu", (unsigned long)pid);
+	for (info_ptr = info; info_ptr; info_ptr = info_ptr->next) {
+		char *cgroup_path = (enter_sub && info_ptr->cgroup_path_sub) ?
+			info_ptr->cgroup_path_sub :
+			info_ptr->cgroup_path;
+
+		if (!info_ptr->designated_mount_point) {
+			info_ptr->designated_mount_point = lxc_cgroup_find_mount_point(info_ptr->hierarchy, cgroup_path, true);
+			if (!info_ptr->designated_mount_point) {
+				SYSERROR("Could not add pid %lu to cgroup %s: internal error (couldn't find any writable mountpoint to cgroup filesystem)", (unsigned long)pid, cgroup_path);
+				return -1;
+			}
+		}
+
+		cgroup_tasks_fn = cgroup_to_absolute_path(info_ptr->designated_mount_point, cgroup_path, "/tasks");
+		if (!cgroup_tasks_fn) {
+			SYSERROR("Could not add pid %lu to cgroup %s: internal error", (unsigned long)pid, cgroup_path);
+			return -1;
+		}
+
+		r = lxc_write_to_file(cgroup_tasks_fn, pid_buf, strlen(pid_buf), false);
+		free(cgroup_tasks_fn);
+		if (r < 0 && is_crucial_hierarchy(info_ptr->hierarchy)) {
+			SYSERROR("Could not add pid %lu to cgroup %s: internal error", (unsigned long)pid, cgroup_path);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* free process membership information */
+void lxc_cgroup_process_info_free(struct cgroup_process_info *info)
+{
+	struct cgroup_process_info *next;
+	if (!info)
+		return;
+	next = info->next;
+	lxc_cgroup_put_meta(info->meta_ref);
+	free(info->cgroup_path);
+	free(info->cgroup_path_sub);
+	lxc_free_array((void **)info->created_paths, free);
+	free(info);
+	lxc_cgroup_process_info_free(next);
+}
+
+/* free process membership information and remove cgroups that were created */
+void lxc_cgroup_process_info_free_and_remove(struct cgroup_process_info *info, struct lxc_conf *conf)
+{
+	struct cgroup_process_info *next;
+	char **pp;
+	if (!info)
+		return;
+	next = info->next;
+	{
+		struct cgroup_mount_point *mp = info->designated_mount_point;
+		if (!mp)
+			mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
+		if (mp)
+			/* ignore return value here, perhaps we created the
+			 * '/lxc' cgroup in this container but another container
+			 * is still running (for example)
+			 */
+			(void)remove_cgroup(mp, info->cgroup_path, true, conf);
+	}
+	for (pp = info->created_paths; pp && *pp; pp++);
+	for ((void)(pp && --pp); info->created_paths && pp >= info->created_paths; --pp) {
+		free(*pp);
+	}
+	free(info->created_paths);
+	lxc_cgroup_put_meta(info->meta_ref);
+	free(info->cgroup_path);
+	free(info->cgroup_path_sub);
+	free(info);
+	lxc_cgroup_process_info_free_and_remove(next, conf);
+}
+
+static char *lxc_cgroup_get_hierarchy_path_data(const char *subsystem, struct cgfs_data *d)
+{
+	struct cgroup_process_info *info = d->info;
+	info = find_info_for_subsystem(info, subsystem);
+	if (!info)
+		return NULL;
+	prune_init_scope(info->cgroup_path);
+	return info->cgroup_path;
+}
+
+static char *lxc_cgroup_get_hierarchy_abs_path_data(const char *subsystem, struct cgfs_data *d)
+{
+	struct cgroup_process_info *info = d->info;
+	struct cgroup_mount_point *mp = NULL;
+
+	info = find_info_for_subsystem(info, subsystem);
+	if (!info)
+		return NULL;
+	if (info->designated_mount_point) {
+		mp = info->designated_mount_point;
+	} else {
+		mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
+		if (!mp)
+			return NULL;
+	}
+	return cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
+}
+
+static char *lxc_cgroup_get_hierarchy_abs_path(const char *subsystem, const char *name, const char *lxcpath)
+{
+	struct cgroup_meta_data *meta;
+	struct cgroup_process_info *base_info, *info;
+	struct cgroup_mount_point *mp;
+	char *result = NULL;
+
+	meta = lxc_cgroup_load_meta();
+	if (!meta)
+		return NULL;
+	base_info = lxc_cgroup_get_container_info(name, lxcpath, meta);
+	if (!base_info)
+		goto out1;
+	info = find_info_for_subsystem(base_info, subsystem);
+	if (!info)
+		goto out2;
+	if (info->designated_mount_point) {
+		mp = info->designated_mount_point;
+	} else {
+		mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
+		if (!mp)
+			goto out3;
+	}
+	result = cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
+out3:
+out2:
+	lxc_cgroup_process_info_free(base_info);
+out1:
+	lxc_cgroup_put_meta(meta);
+	return result;
+}
+
+static int lxc_cgroup_set_data(const char *filename, const char *value, struct cgfs_data *d)
+{
+	char *subsystem = NULL, *p, *path;
+	int ret = -1;
+
+	subsystem = alloca(strlen(filename) + 1);
+	strcpy(subsystem, filename);
+	if ((p = strchr(subsystem, '.')) != NULL)
+		*p = '\0';
+
+	errno = ENOENT;
+	path = lxc_cgroup_get_hierarchy_abs_path_data(subsystem, d);
+	if (path) {
+		ret = do_cgroup_set(path, filename, value);
+		int saved_errno = errno;
+		free(path);
+		errno = saved_errno;
+	}
+	return ret;
+}
+
+static int lxc_cgroupfs_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+{
+	char *subsystem = NULL, *p, *path;
+	int ret = -1;
+
+	subsystem = alloca(strlen(filename) + 1);
+	strcpy(subsystem, filename);
+	if ((p = strchr(subsystem, '.')) != NULL)
+		*p = '\0';
+
+	path = lxc_cgroup_get_hierarchy_abs_path(subsystem, name, lxcpath);
+	if (path) {
+		ret = do_cgroup_set(path, filename, value);
+		free(path);
+	}
+	return ret;
+}
+
+static int lxc_cgroupfs_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+{
+	char *subsystem = NULL, *p, *path;
+	int ret = -1;
+
+	subsystem = alloca(strlen(filename) + 1);
+	strcpy(subsystem, filename);
+	if ((p = strchr(subsystem, '.')) != NULL)
+		*p = '\0';
+
+	path = lxc_cgroup_get_hierarchy_abs_path(subsystem, name, lxcpath);
+	if (path) {
+		ret = do_cgroup_get(path, filename, value, len);
+		free(path);
+	}
+	return ret;
+}
+
+static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
+{
+	size_t bufsz = strlen(root) + sizeof("/sys/fs/cgroup");
+	char *path = NULL;
+	char **parts = NULL;
+	char *dirname = NULL;
+	char *abs_path = NULL;
+	char *abs_path2 = NULL;
+	struct cgfs_data *cgfs_d;
+	struct cgroup_process_info *info, *base_info;
+	int r, saved_errno = 0;
+
+	if (cgns_supported())
+		return true;
+
+	cgfs_d = hdata;
+	if (!cgfs_d)
+		return false;
+	base_info = cgfs_d->info;
+
+	/* If we get passed the _NOSPEC types, we default to _MIXED, since we don't
+	 * have access to the lxc_conf object at this point. It really should be up
+	 * to the caller to fix this, but this doesn't really hurt.
+	 */
+	if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
+		type = LXC_AUTO_CGROUP_FULL_MIXED;
+	else if (type == LXC_AUTO_CGROUP_NOSPEC)
+		type = LXC_AUTO_CGROUP_MIXED;
+
+	if (type < LXC_AUTO_CGROUP_RO || type > LXC_AUTO_CGROUP_FULL_MIXED) {
+		ERROR("could not mount cgroups into container: invalid type specified internally");
+		errno = EINVAL;
+		return false;
+	}
+
+	path = calloc(1, bufsz);
+	if (!path)
+		return false;
+	snprintf(path, bufsz, "%s/sys/fs/cgroup", root);
+	r = safe_mount("cgroup_root", path, "tmpfs",
+			MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME,
+			"size=10240k,mode=755",
+			root);
+	if (r < 0) {
+		SYSERROR("could not mount tmpfs to /sys/fs/cgroup in the container");
+		return false;
+	}
+
+	/* now mount all the hierarchies we care about */
+	for (info = base_info; info; info = info->next) {
+		size_t subsystem_count, i;
+		struct cgroup_mount_point *mp = info->designated_mount_point;
+		if (!mountpoint_is_accessible(mp))
+			mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true);
+
+		if (!mp) {
+			SYSERROR("could not find original mount point for cgroup hierarchy while trying to mount cgroup filesystem");
+			goto out_error;
+		}
+
+		subsystem_count = lxc_array_len((void **)info->hierarchy->subsystems);
+		parts = calloc(subsystem_count + 1, sizeof(char *));
+		if (!parts)
+			goto out_error;
+
+		for (i = 0; i < subsystem_count; i++) {
+			if (!strncmp(info->hierarchy->subsystems[i], "name=", 5))
+				parts[i] = info->hierarchy->subsystems[i] + 5;
+			else
+				parts[i] = info->hierarchy->subsystems[i];
+		}
+		dirname = lxc_string_join(",", (const char **)parts, false);
+		if (!dirname)
+			goto out_error;
+
+		/* create subsystem directory */
+		abs_path = lxc_append_paths(path, dirname);
+		if (!abs_path)
+			goto out_error;
+		r = mkdir_p(abs_path, 0755);
+		if (r < 0 && errno != EEXIST) {
+			SYSERROR("could not create cgroup subsystem directory /sys/fs/cgroup/%s", dirname);
+			goto out_error;
+		}
+
+		abs_path2 = lxc_append_paths(abs_path, info->cgroup_path);
+		if (!abs_path2)
+			goto out_error;
+
+		if (type == LXC_AUTO_CGROUP_FULL_RO || type == LXC_AUTO_CGROUP_FULL_RW || type == LXC_AUTO_CGROUP_FULL_MIXED) {
+			/* bind-mount the cgroup entire filesystem there */
+			if (strcmp(mp->mount_prefix, "/") != 0) {
+				/* FIXME: maybe we should just try to remount the entire hierarchy
+				 *        with a regular mount command? may that works? */
+				ERROR("could not automatically mount cgroup-full to /sys/fs/cgroup/%s: host has no mount point for this cgroup filesystem that has access to the root cgroup", dirname);
+				goto out_error;
+			}
+			r = mount(mp->mount_point, abs_path, "none", MS_BIND, 0);
+			if (r < 0) {
+				SYSERROR("error bind-mounting %s to %s", mp->mount_point, abs_path);
+				goto out_error;
+			}
+			/* main cgroup path should be read-only */
+			if (type == LXC_AUTO_CGROUP_FULL_RO || type == LXC_AUTO_CGROUP_FULL_MIXED) {
+				r = mount(NULL, abs_path, NULL, MS_REMOUNT|MS_BIND|MS_RDONLY, NULL);
+				if (r < 0) {
+					SYSERROR("error re-mounting %s readonly", abs_path);
+					goto out_error;
+				}
+			}
+			/* own cgroup should be read-write */
+			if (type == LXC_AUTO_CGROUP_FULL_MIXED) {
+				r = mount(abs_path2, abs_path2, NULL, MS_BIND, NULL);
+				if (r < 0) {
+					SYSERROR("error bind-mounting %s onto itself", abs_path2);
+					goto out_error;
+				}
+				r = mount(NULL, abs_path2, NULL, MS_REMOUNT|MS_BIND, NULL);
+				if (r < 0) {
+					SYSERROR("error re-mounting %s readwrite", abs_path2);
+					goto out_error;
+				}
+			}
+		} else {
+			/* create path for container's cgroup */
+			r = mkdir_p(abs_path2, 0755);
+			if (r < 0 && errno != EEXIST) {
+				SYSERROR("could not create cgroup directory /sys/fs/cgroup/%s%s", dirname, info->cgroup_path);
+				goto out_error;
+			}
+
+			/* for read-only and mixed cases, we have to bind-mount the tmpfs directory
+			 * that points to the hierarchy itself (i.e. /sys/fs/cgroup/cpu etc.) onto
+			 * itself and then bind-mount it read-only, since we keep the tmpfs itself
+			 * read-write (see comment below)
+			 */
+			if (type == LXC_AUTO_CGROUP_MIXED || type == LXC_AUTO_CGROUP_RO) {
+				r = mount(abs_path, abs_path, NULL, MS_BIND, NULL);
+				if (r < 0) {
+					SYSERROR("error bind-mounting %s onto itself", abs_path);
+					goto out_error;
+				}
+				r = mount(NULL, abs_path, NULL, MS_REMOUNT|MS_BIND|MS_RDONLY, NULL);
+				if (r < 0) {
+					SYSERROR("error re-mounting %s readonly", abs_path);
+					goto out_error;
+				}
+			}
+
+			free(abs_path);
+			abs_path = NULL;
+
+			/* bind-mount container's cgroup to that directory */
+			abs_path = cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
+			if (!abs_path)
+				goto out_error;
+			r = mount(abs_path, abs_path2, "none", MS_BIND, 0);
+			if (r < 0 && is_crucial_hierarchy(info->hierarchy)) {
+				SYSERROR("error bind-mounting %s to %s", abs_path, abs_path2);
+				goto out_error;
+			}
+			if (type == LXC_AUTO_CGROUP_RO) {
+				r = mount(NULL, abs_path2, NULL, MS_REMOUNT|MS_BIND|MS_RDONLY, NULL);
+				if (r < 0) {
+					SYSERROR("error re-mounting %s readonly", abs_path2);
+					goto out_error;
+				}
+			}
+		}
+
+		free(abs_path);
+		free(abs_path2);
+		abs_path = NULL;
+		abs_path2 = NULL;
+
+		/* add symlinks for every single subsystem */
+		if (subsystem_count > 1) {
+			for (i = 0; i < subsystem_count; i++) {
+				abs_path = lxc_append_paths(path, parts[i]);
+				if (!abs_path)
+					goto out_error;
+				r = symlink(dirname, abs_path);
+				if (r < 0)
+					WARN("could not create symlink %s -> %s in /sys/fs/cgroup of container", parts[i], dirname);
+				free(abs_path);
+				abs_path = NULL;
+			}
+		}
+		free(dirname);
+		free(parts);
+		dirname = NULL;
+		parts = NULL;
+	}
+
+	/* We used to remount the entire tmpfs readonly if any :ro or
+	 * :mixed mode was specified. However, Ubuntu's mountall has the
+	 * unfortunate behavior to block bootup if /sys/fs/cgroup is
+	 * mounted read-only and cannot be remounted read-write.
+	 * (mountall reads /lib/init/fstab and tries to (re-)mount all of
+	 * these if they are not already mounted with the right options;
+	 * it contains an entry for /sys/fs/cgroup. In case it can't do
+	 * that, it prompts for the user to either manually fix it or
+	 * boot anyway. But without user input, booting of the container
+	 * hangs.)
+	 *
+	 * Instead of remounting the entire tmpfs readonly, we only
+	 * remount the paths readonly that are part of the cgroup
+	 * hierarchy.
+	 */
+
+	free(path);
+
+	return true;
+
+out_error:
+	saved_errno = errno;
+	free(path);
+	free(dirname);
+	free(parts);
+	free(abs_path);
+	free(abs_path2);
+	errno = saved_errno;
+	return false;
+}
+
+static int cgfs_nrtasks(void *hdata)
+{
+	struct cgfs_data *d = hdata;
+	struct cgroup_process_info *info;
+	struct cgroup_mount_point *mp = NULL;
+	char *abs_path = NULL;
+	int ret;
+
+	if (!d) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	info = d->info;
+	if (!info) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	if (info->designated_mount_point) {
+		mp = info->designated_mount_point;
+	} else {
+		mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, false);
+		if (!mp)
+			return -1;
+	}
+
+	abs_path = cgroup_to_absolute_path(mp, info->cgroup_path, NULL);
+	if (!abs_path)
+		return -1;
+
+	ret = cgroup_recursive_task_count(abs_path);
+	free(abs_path);
+	return ret;
+}
+
+static struct cgroup_process_info *
+lxc_cgroup_process_info_getx(const char *proc_pid_cgroup_str,
+			     struct cgroup_meta_data *meta)
+{
+	struct cgroup_process_info *result = NULL;
+	FILE *proc_pid_cgroup = NULL;
+	char *line = NULL;
+	size_t sz = 0;
+	int saved_errno = 0;
+	struct cgroup_process_info **cptr = &result;
+	struct cgroup_process_info *entry = NULL;
+
+	proc_pid_cgroup = fopen_cloexec(proc_pid_cgroup_str, "r");
+	if (!proc_pid_cgroup)
+		return NULL;
+
+	while (getline(&line, &sz, proc_pid_cgroup) != -1) {
+		/* file format: hierarchy:subsystems:group */
+		char *colon1;
+		char *colon2;
+		char *endptr;
+		int hierarchy_number;
+		struct cgroup_hierarchy *h = NULL;
+
+		if (!line[0])
+			continue;
+
+		if (line[strlen(line) - 1] == '\n')
+			line[strlen(line) - 1] = '\0';
+
+		colon1 = strchr(line, ':');
+		if (!colon1)
+			continue;
+		*colon1++ = '\0';
+		colon2 = strchr(colon1, ':');
+		if (!colon2)
+			continue;
+		*colon2++ = '\0';
+
+		endptr = NULL;
+		hierarchy_number = strtoul(line, &endptr, 10);
+		if (!endptr || *endptr)
+			continue;
+
+		if (hierarchy_number > meta->maximum_hierarchy) {
+			/* we encountered a hierarchy we didn't have before,
+			 * so probably somebody remounted some stuff in the
+			 * mean time...
+			 */
+			errno = EAGAIN;
+			goto out_error;
+		}
+
+		h = meta->hierarchies[hierarchy_number];
+		if (!h) {
+			/* we encountered a hierarchy that was thought to be
+			 * dead before, so probably somebody remounted some
+			 * stuff in the mean time...
+			 */
+			errno = EAGAIN;
+			goto out_error;
+		}
+
+		/* we are told that we should ignore this hierarchy */
+		if (!h->used)
+			continue;
+
+		entry = calloc(1, sizeof(struct cgroup_process_info));
+		if (!entry)
+			goto out_error;
+
+		entry->meta_ref = lxc_cgroup_get_meta(meta);
+		entry->hierarchy = h;
+		entry->cgroup_path = strdup(colon2);
+		if (!entry->cgroup_path)
+			goto out_error;
+		prune_init_scope(entry->cgroup_path);
+
+		*cptr = entry;
+		cptr = &entry->next;
+		entry = NULL;
+	}
+
+	fclose(proc_pid_cgroup);
+	free(line);
+	return result;
+
+out_error:
+	saved_errno = errno;
+	if (proc_pid_cgroup)
+		fclose(proc_pid_cgroup);
+	lxc_cgroup_process_info_free(result);
+	lxc_cgroup_process_info_free(entry);
+	free(line);
+	errno = saved_errno;
+	return NULL;
+}
+
+static char **subsystems_from_mount_options(const char *mount_options,
+					    char **kernel_list)
+{
+	char *token, *str, *saveptr = NULL;
+	char **result = NULL;
+	size_t result_capacity = 0;
+	size_t result_count = 0;
+	int saved_errno;
+	int r;
+
+	str = alloca(strlen(mount_options)+1);
+	strcpy(str, mount_options);
+	for (; (token = strtok_r(str, ",", &saveptr)); str = NULL) {
+		/* we have a subsystem if it's either in the list of
+		 * subsystems provided by the kernel OR if it starts
+		 * with name= for named hierarchies
+		 */
+		r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 12);
+		if (r < 0)
+			goto out_free;
+		result[result_count + 1] = NULL;
+		if (strncmp(token, "name=", 5) && !lxc_string_in_array(token, (const char **)kernel_list)) {
+			// this is eg 'systemd' but the mount will be 'name=systemd'
+			result[result_count] = malloc(strlen(token) + 6);
+			if (result[result_count])
+				sprintf(result[result_count], "name=%s", token);
+		} else
+			result[result_count] = strdup(token);
+		if (!result[result_count])
+			goto out_free;
+		result_count++;
+	}
+
+	return result;
+
+out_free:
+	saved_errno = errno;
+	lxc_free_array((void**)result, free);
+	errno = saved_errno;
+	return NULL;
+}
+
+static void lxc_cgroup_mount_point_free(struct cgroup_mount_point *mp)
+{
+	if (!mp)
+		return;
+	free(mp->mount_point);
+	free(mp->mount_prefix);
+	free(mp);
+}
+
+static void lxc_cgroup_hierarchy_free(struct cgroup_hierarchy *h)
+{
+	if (!h)
+		return;
+	lxc_free_array((void **)h->subsystems, free);
+	free(h->all_mount_points);
+	free(h);
+}
+
+static bool is_valid_cgroup(const char *name)
+{
+	const char *p;
+	for (p = name; *p; p++) {
+		/* Use the ASCII printable characters range(32 - 127)
+		 * is reasonable, we kick out 32(SPACE) because it'll
+		 * break legacy lxc-ls
+		 */
+		if (*p <= 32 || *p >= 127 || *p == '/')
+			return false;
+	}
+	return strcmp(name, ".") != 0 && strcmp(name, "..") != 0;
+}
+
+static int create_or_remove_cgroup(bool do_remove,
+		struct cgroup_mount_point *mp, const char *path, int recurse,
+		struct lxc_conf *conf)
+{
+	int r, saved_errno = 0;
+	char *buf = cgroup_to_absolute_path(mp, path, NULL);
+	if (!buf)
+		return -1;
+
+	/* create or remove directory */
+	if (do_remove) {
+		if (!dir_exists(buf))
+			return 0;
+		if (recurse) {
+			if (conf && !lxc_list_empty(&conf->id_map))
+				r = userns_exec_1(conf, rmdir_wrapper, buf);
+			else
+				r = cgroup_rmdir(buf);
+		} else
+			r = rmdir(buf);
+	} else
+		r = mkdir(buf, 0777);
+	saved_errno = errno;
+	free(buf);
+	errno = saved_errno;
+	return r;
+}
+
+static int create_cgroup(struct cgroup_mount_point *mp, const char *path)
+{
+	return create_or_remove_cgroup(false, mp, path, false, NULL);
+}
+
+static int remove_cgroup(struct cgroup_mount_point *mp,
+			 const char *path, bool recurse, struct lxc_conf *conf)
+{
+	return create_or_remove_cgroup(true, mp, path, recurse, conf);
+}
+
+static char *cgroup_to_absolute_path(struct cgroup_mount_point *mp,
+				     const char *path, const char *suffix)
+{
+	/* first we have to make sure we subtract the mount point's prefix */
+	char *prefix = mp->mount_prefix;
+	char *buf;
+	ssize_t len, rv;
+
+	/* we want to make sure only absolute paths to cgroups are passed to us */
+	if (path[0] != '/') {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (prefix && !strcmp(prefix, "/"))
+		prefix = NULL;
+
+	/* prefix doesn't match */
+	if (prefix && strncmp(prefix, path, strlen(prefix)) != 0) {
+		errno = EINVAL;
+		return NULL;
+	}
+	/* if prefix is /foo and path is /foobar */
+	if (prefix && path[strlen(prefix)] != '/' && path[strlen(prefix)] != '\0') {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/* remove prefix from path */
+	path += prefix ? strlen(prefix) : 0;
+
+	len = strlen(mp->mount_point) + strlen(path) + (suffix ? strlen(suffix) : 0);
+	buf = calloc(len + 1, 1);
+	if (!buf)
+		return NULL;
+	rv = snprintf(buf, len + 1, "%s%s%s", mp->mount_point, path, suffix ? suffix : "");
+	if (rv > len) {
+		free(buf);
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	return buf;
+}
+
+static struct cgroup_process_info *
+find_info_for_subsystem(struct cgroup_process_info *info, const char *subsystem)
+{
+	struct cgroup_process_info *info_ptr;
+	for (info_ptr = info; info_ptr; info_ptr = info_ptr->next) {
+		struct cgroup_hierarchy *h = info_ptr->hierarchy;
+		if (lxc_string_in_array(subsystem, (const char **)h->subsystems))
+			return info_ptr;
+	}
+	errno = ENOENT;
+	return NULL;
+}
+
+static int do_cgroup_get(const char *cgroup_path, const char *sub_filename,
+			 char *value, size_t len)
+{
+	const char *parts[3] = {
+		cgroup_path,
+		sub_filename,
+		NULL
+	};
+	char *filename;
+	int ret, saved_errno;
+
+	filename = lxc_string_join("/", parts, false);
+	if (!filename)
+		return -1;
+
+	ret = lxc_read_from_file(filename, value, len);
+	saved_errno = errno;
+	free(filename);
+	errno = saved_errno;
+	return ret;
+}
+
+static int do_cgroup_set(const char *cgroup_path, const char *sub_filename,
+			 const char *value)
+{
+	const char *parts[3] = {
+		cgroup_path,
+		sub_filename,
+		NULL
+	};
+	char *filename;
+	int ret, saved_errno;
+
+	filename = lxc_string_join("/", parts, false);
+	if (!filename)
+		return -1;
+
+	ret = lxc_write_to_file(filename, value, strlen(value), false);
+	saved_errno = errno;
+	free(filename);
+	errno = saved_errno;
+	return ret;
+}
+
+static int do_setup_cgroup_limits(struct cgfs_data *d,
+			   struct lxc_list *cgroup_settings, bool do_devices)
+{
+	struct lxc_list *iterator, *sorted_cgroup_settings, *next;
+	struct lxc_cgroup *cg;
+	int ret = -1;
+
+	if (lxc_list_empty(cgroup_settings))
+		return 0;
+
+	sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
+	if (!sorted_cgroup_settings) {
+		return -1;
+	}
+
+	lxc_list_for_each(iterator, sorted_cgroup_settings) {
+		cg = iterator->elem;
+
+		if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
+			if (strcmp(cg->subsystem, "devices.deny") == 0 &&
+					cgroup_devices_has_allow_or_deny(d, cg->value, false))
+				continue;
+			if (strcmp(cg->subsystem, "devices.allow") == 0 &&
+					cgroup_devices_has_allow_or_deny(d, cg->value, true))
+				continue;
+			if (lxc_cgroup_set_data(cg->subsystem, cg->value, d)) {
+				if (do_devices && (errno == EACCES || errno == EPERM)) {
+					WARN("Error setting %s to %s for %s",
+					      cg->subsystem, cg->value, d->name);
+					continue;
+				}
+				SYSERROR("Error setting %s to %s for %s",
+				      cg->subsystem, cg->value, d->name);
+				goto out;
+			}
+		}
+
+		DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
+	}
+
+	ret = 0;
+	INFO("cgroup has been setup");
+out:
+	lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
+		lxc_list_del(iterator);
+		free(iterator);
+	}
+	free(sorted_cgroup_settings);
+	return ret;
+}
+
+static bool cgroup_devices_has_allow_or_deny(struct cgfs_data *d,
+					     char *v, bool for_allow)
+{
+	char *path;
+	FILE *devices_list;
+	char *line = NULL;
+	size_t sz = 0;
+	bool ret = !for_allow;
+	const char *parts[3] = {
+		NULL,
+		"devices.list",
+		NULL
+	};
+
+	// XXX FIXME if users could use something other than 'lxc.devices.deny = a'.
+	// not sure they ever do, but they *could*
+	// right now, I'm assuming they do NOT
+	if (!for_allow && strcmp(v, "a") != 0 && strcmp(v, "a *:* rwm") != 0)
+		return false;
+
+	parts[0] = (const char *)lxc_cgroup_get_hierarchy_abs_path_data("devices", d);
+	if (!parts[0])
+		return false;
+	path = lxc_string_join("/", parts, false);
+	if (!path) {
+		free((void *)parts[0]);
+		return false;
+	}
+
+	devices_list = fopen_cloexec(path, "r");
+	if (!devices_list) {
+		free(path);
+		return false;
+	}
+
+	while (getline(&line, &sz, devices_list) != -1) {
+		size_t len = strlen(line);
+		if (len > 0 && line[len-1] == '\n')
+			line[len-1] = '\0';
+		if (strcmp(line, "a *:* rwm") == 0) {
+			ret = for_allow;
+			goto out;
+		} else if (for_allow && strcmp(line, v) == 0) {
+			ret = true;
+			goto out;
+		}
+	}
+
+out:
+	fclose(devices_list);
+	free(line);
+	free(path);
+	return ret;
+}
+
+static int cgroup_recursive_task_count(const char *cgroup_path)
+{
+	DIR *d;
+	struct dirent *dent_buf;
+	struct dirent *dent;
+	ssize_t name_max;
+	int n = 0, r;
+
+	/* see man readdir_r(3) */
+	name_max = pathconf(cgroup_path, _PC_NAME_MAX);
+	if (name_max <= 0)
+		name_max = 255;
+	dent_buf = malloc(offsetof(struct dirent, d_name) + name_max + 1);
+	if (!dent_buf)
+		return -1;
+
+	d = opendir(cgroup_path);
+	if (!d) {
+		free(dent_buf);
+		return 0;
+	}
+
+	while (readdir_r(d, dent_buf, &dent) == 0 && dent) {
+		const char *parts[3] = {
+			cgroup_path,
+			dent->d_name,
+			NULL
+		};
+		char *sub_path;
+		struct stat st;
+
+		if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+			continue;
+		sub_path = lxc_string_join("/", parts, false);
+		if (!sub_path) {
+			closedir(d);
+			free(dent_buf);
+			return -1;
+		}
+		r = stat(sub_path, &st);
+		if (r < 0) {
+			closedir(d);
+			free(dent_buf);
+			free(sub_path);
+			return -1;
+		}
+		if (S_ISDIR(st.st_mode)) {
+			r = cgroup_recursive_task_count(sub_path);
+			if (r >= 0)
+				n += r;
+		} else if (!strcmp(dent->d_name, "tasks")) {
+			r = lxc_count_file_lines(sub_path);
+			if (r >= 0)
+				n += r;
+		}
+		free(sub_path);
+	}
+	closedir(d);
+	free(dent_buf);
+
+	return n;
+}
+
+static int handle_cgroup_settings(struct cgroup_mount_point *mp,
+				  char *cgroup_path)
+{
+	int r, saved_errno = 0;
+	char buf[2];
+
+	mp->need_cpuset_init = false;
+
+	/* If this is the memory cgroup, we want to enforce hierarchy.
+	 * But don't fail if for some reason we can't.
+	 */
+	if (lxc_string_in_array("memory", (const char **)mp->hierarchy->subsystems)) {
+		char *cc_path = cgroup_to_absolute_path(mp, cgroup_path, "/memory.use_hierarchy");
+		if (cc_path) {
+			r = lxc_read_from_file(cc_path, buf, 1);
+			if (r < 1 || buf[0] != '1') {
+				r = lxc_write_to_file(cc_path, "1", 1, false);
+				if (r < 0)
+					SYSERROR("failed to set memory.use_hierarchy to 1; continuing");
+			}
+			free(cc_path);
+		}
+	}
+
+	/* if this is a cpuset hierarchy, we have to set cgroup.clone_children in
+	 * the base cgroup, otherwise containers will start with an empty cpuset.mems
+	 * and cpuset.cpus and then
+	 */
+	if (lxc_string_in_array("cpuset", (const char **)mp->hierarchy->subsystems)) {
+		char *cc_path = cgroup_to_absolute_path(mp, cgroup_path, "/cgroup.clone_children");
+		struct stat sb;
+
+		if (!cc_path)
+			return -1;
+		/* cgroup.clone_children is not available when running under
+		 * older kernel versions; in this case, we'll initialize
+		 * cpuset.cpus and cpuset.mems later, after the new cgroup
+		 * was created
+		 */
+		if (stat(cc_path, &sb) != 0 && errno == ENOENT) {
+			mp->need_cpuset_init = true;
+			free(cc_path);
+			return 0;
+		}
+		r = lxc_read_from_file(cc_path, buf, 1);
+		if (r == 1 && buf[0] == '1') {
+			free(cc_path);
+			return 0;
+		}
+		r = lxc_write_to_file(cc_path, "1", 1, false);
+		saved_errno = errno;
+		free(cc_path);
+		errno = saved_errno;
+		return r < 0 ? -1 : 0;
+	}
+	return 0;
+}
+
+static int cgroup_read_from_file(const char *fn, char buf[], size_t bufsize)
+{
+	int ret = lxc_read_from_file(fn, buf, bufsize);
+	if (ret < 0) {
+		SYSERROR("failed to read %s", fn);
+		return ret;
+	}
+	if (ret == bufsize) {
+		if (bufsize > 0) {
+			/* obviously this wasn't empty */
+			buf[bufsize-1] = '\0';
+			return ret;
+		}
+		/* Callers don't do this, but regression/sanity check */
+		ERROR("%s: was not expecting 0 bufsize", __func__);
+		return -1;
+	}
+	buf[ret] = '\0';
+	return ret;
+}
+
+static bool do_init_cpuset_file(struct cgroup_mount_point *mp,
+				const char *path, const char *name)
+{
+	char value[1024];
+	char *childfile, *parentfile = NULL, *tmp;
+	int ret;
+	bool ok = false;
+
+	childfile = cgroup_to_absolute_path(mp, path, name);
+	if (!childfile)
+		return false;
+
+	/* don't overwrite a non-empty value in the file */
+	ret = cgroup_read_from_file(childfile, value, sizeof(value));
+	if (ret < 0)
+		goto out;
+	if (value[0] != '\0' && value[0] != '\n') {
+		ok = true;
+		goto out;
+	}
+
+	/* path to the same name in the parent cgroup */
+	parentfile = strdup(path);
+	if (!parentfile)
+		goto out;
+
+	tmp = strrchr(parentfile, '/');
+	if (!tmp)
+		goto out;
+	if (tmp == parentfile)
+		tmp++; /* keep the '/' at the start */
+	*tmp = '\0';
+	tmp = parentfile;
+	parentfile = cgroup_to_absolute_path(mp, tmp, name);
+	free(tmp);
+	if (!parentfile)
+		goto out;
+
+	/* copy from parent to child cgroup */
+	ret = cgroup_read_from_file(parentfile, value, sizeof(value));
+	if (ret < 0)
+		goto out;
+	if (ret == sizeof(value)) {
+		/* If anyone actually sees this error, we can address it */
+		ERROR("parent cpuset value too long");
+		goto out;
+	}
+	ok = (lxc_write_to_file(childfile, value, strlen(value), false) >= 0);
+	if (!ok)
+		SYSERROR("failed writing %s", childfile);
+
+out:
+	free(parentfile);
+	free(childfile);
+	return ok;
+}
+
+static bool init_cpuset_if_needed(struct cgroup_mount_point *mp,
+				  const char *path)
+{
+	/* the files we have to handle here are only in cpuset hierarchies */
+	if (!lxc_string_in_array("cpuset",
+				 (const char **)mp->hierarchy->subsystems))
+		return true;
+
+	if (!mp->need_cpuset_init)
+		return true;
+
+	return (do_init_cpuset_file(mp, path, "/cpuset.cpus") &&
+		do_init_cpuset_file(mp, path, "/cpuset.mems") );
+}
+
+struct cgroup_ops *cgfs_ops_init(void)
+{
+	return &cgfs_ops;
+}
+
+static void *cgfs_init(const char *name)
+{
+	struct cgfs_data *d;
+
+	d = malloc(sizeof(*d));
+	if (!d)
+		return NULL;
+
+	memset(d, 0, sizeof(*d));
+	d->name = strdup(name);
+	if (!d->name)
+		goto err1;
+
+	d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
+
+	d->meta = lxc_cgroup_load_meta();
+	if (!d->meta) {
+		ERROR("cgroupfs failed to detect cgroup metadata");
+		goto err2;
+	}
+	return d;
+
+err2:
+	free(d->name);
+err1:
+	free(d);
+	return NULL;
+}
+
+static void cgfs_destroy(void *hdata, struct lxc_conf *conf)
+{
+	struct cgfs_data *d = hdata;
+
+	if (!d)
+		return;
+	free(d->name);
+	lxc_cgroup_process_info_free_and_remove(d->info, conf);
+	lxc_cgroup_put_meta(d->meta);
+	free(d);
+}
+
+static inline bool cgfs_create(void *hdata)
+{
+	struct cgfs_data *d = hdata;
+	struct cgroup_process_info *i;
+	struct cgroup_meta_data *md;
+
+	if (!d)
+		return false;
+	md = d->meta;
+	i = lxc_cgroupfs_create(d->name, d->cgroup_pattern, md, NULL);
+	if (!i)
+		return false;
+	d->info = i;
+	return true;
+}
+
+static inline bool cgfs_enter(void *hdata, pid_t pid)
+{
+	struct cgfs_data *d = hdata;
+	struct cgroup_process_info *i;
+	int ret;
+
+	if (!d)
+		return false;
+	i = d->info;
+	ret = lxc_cgroupfs_enter(i, pid, false);
+
+	return ret == 0;
+}
+
+static inline bool cgfs_create_legacy(void *hdata, pid_t pid)
+{
+	struct cgfs_data *d = hdata;
+	struct cgroup_process_info *i;
+
+	if (!d)
+		return false;
+	i = d->info;
+	if (lxc_cgroup_create_legacy(i, d->name, pid) < 0) {
+		ERROR("failed to create legacy ns cgroups for '%s'", d->name);
+		return false;
+	}
+	return true;
+}
+
+static const char *cgfs_get_cgroup(void *hdata, const char *subsystem)
+{
+	struct cgfs_data *d = hdata;
+
+	if (!d)
+		return NULL;
+	return lxc_cgroup_get_hierarchy_path_data(subsystem, d);
+}
+
+static const char *cgfs_canonical_path(void *hdata)
+{
+	struct cgfs_data *d = hdata;
+	struct cgroup_process_info *info_ptr;
+	char *path = NULL;
+
+	if (!d)
+		return NULL;
+
+	for (info_ptr = d->info; info_ptr; info_ptr = info_ptr->next) {
+		if (!path)
+			path = info_ptr->cgroup_path;
+		else if (strcmp(path, info_ptr->cgroup_path) != 0) {
+			ERROR("not all paths match %s, %s has path %s", path,
+				info_ptr->hierarchy->subsystems[0], info_ptr->cgroup_path);
+			return NULL;
+		}
+	}
+
+	return path;
+}
+
+static bool cgfs_escape(void *hdata)
+{
+	struct cgroup_meta_data *md;
+	int i;
+	bool ret = false;
+
+	md = lxc_cgroup_load_meta();
+	if (!md)
+		return false;
+
+	for (i = 1; i <= md->maximum_hierarchy; i++) {
+		struct cgroup_hierarchy *h = md->hierarchies[i];
+		struct cgroup_mount_point *mp;
+		char *tasks;
+		FILE *f;
+		int written;
+
+		if (!h) {
+			WARN("not escaping hierarchy %d", i);
+			continue;
+		}
+
+		mp = lxc_cgroup_find_mount_point(h, "/", true);
+		if (!mp)
+			goto out;
+
+		tasks = cgroup_to_absolute_path(mp, "/", "tasks");
+		if (!tasks)
+			goto out;
+
+		f = fopen(tasks, "a");
+		free(tasks);
+		if (!f)
+			goto out;
+
+		written = fprintf(f, "%d\n", getpid());
+		fclose(f);
+		if (written < 0) {
+			SYSERROR("writing tasks failed\n");
+			goto out;
+		}
+	}
+
+	ret = true;
+out:
+	lxc_cgroup_put_meta(md);
+	return ret;
+}
+
+static bool cgfs_unfreeze(void *hdata)
+{
+	struct cgfs_data *d = hdata;
+	char *cgabspath, *cgrelpath;
+	int ret;
+
+	if (!d)
+		return false;
+
+	cgrelpath = lxc_cgroup_get_hierarchy_path_data("freezer", d);
+	cgabspath = lxc_cgroup_find_abs_path("freezer", cgrelpath, true, NULL);
+	if (!cgabspath)
+		return false;
+
+	ret = do_cgroup_set(cgabspath, "freezer.state", "THAWED");
+	free(cgabspath);
+	return ret == 0;
+}
+
+static bool cgroupfs_setup_limits(void *hdata, struct lxc_list *cgroup_conf,
+				  bool with_devices)
+{
+	struct cgfs_data *d = hdata;
+
+	if (!d)
+		return false;
+	return do_setup_cgroup_limits(d, cgroup_conf, with_devices) == 0;
+}
+
+static bool lxc_cgroupfs_attach(const char *name, const char *lxcpath, pid_t pid)
+{
+	struct cgroup_meta_data *meta_data;
+	struct cgroup_process_info *container_info;
+	int ret;
+
+	meta_data = lxc_cgroup_load_meta();
+	if (!meta_data) {
+		ERROR("could not move attached process %d to cgroup of container", pid);
+		return false;
+	}
+
+	container_info = lxc_cgroup_get_container_info(name, lxcpath, meta_data);
+	lxc_cgroup_put_meta(meta_data);
+	if (!container_info) {
+		ERROR("could not move attached process %d to cgroup of container", pid);
+		return false;
+	}
+
+	ret = lxc_cgroupfs_enter(container_info, pid, false);
+	lxc_cgroup_process_info_free(container_info);
+	if (ret < 0) {
+		ERROR("could not move attached process %d to cgroup of container", pid);
+		return false;
+	}
+	return true;
+}
+
+struct chown_data {
+	const char *cgroup_path;
+	uid_t origuid;
+};
+
+/*
+ * TODO - someone should refactor this to unshare once passing all the paths
+ * to be chowned in one go
+ */
+static int chown_cgroup_wrapper(void *data)
+{
+	struct chown_data *arg = data;
+	uid_t destuid;
+	char *fpath;
+
+	if (setresgid(0,0,0) < 0)
+		SYSERROR("Failed to setgid to 0");
+	if (setresuid(0,0,0) < 0)
+		SYSERROR("Failed to setuid to 0");
+	if (setgroups(0, NULL) < 0)
+		SYSERROR("Failed to clear groups");
+	destuid = get_ns_uid(arg->origuid);
+
+	if (chown(arg->cgroup_path, destuid, 0) < 0)
+		SYSERROR("Failed chowning %s to %d", arg->cgroup_path, (int)destuid);
+
+	fpath = lxc_append_paths(arg->cgroup_path, "tasks");
+	if (!fpath)
+		return -1;
+	if (chown(fpath, destuid, 0) < 0)
+		SYSERROR("Error chowning %s\n", fpath);
+	free(fpath);
+
+	fpath = lxc_append_paths(arg->cgroup_path, "cgroup.procs");
+	if (!fpath)
+		return -1;
+	if (chown(fpath, destuid, 0) < 0)
+		SYSERROR("Error chowning %s", fpath);
+	free(fpath);
+
+	return 0;
+}
+
+static bool do_cgfs_chown(char *cgroup_path, struct lxc_conf *conf)
+{
+	struct chown_data data;
+	char *fpath;
+
+	if (!dir_exists(cgroup_path))
+		return true;
+
+	if (lxc_list_empty(&conf->id_map))
+		/* If there's no mapping then we don't need to chown */
+		return true;
+
+	data.cgroup_path = cgroup_path;
+	data.origuid = geteuid();
+
+	/* Unpriv users can't chown it themselves, so chown from
+	 * a child namespace mapping both our own and the target uid
+	 */
+	if (userns_exec_1(conf, chown_cgroup_wrapper, &data) < 0) {
+		ERROR("Error requesting cgroup chown in new namespace");
+		return false;
+	}
+
+	/*
+	 * Now chmod 775 the directory else the container cannot create cgroups.
+	 * This can't be done in the child namespace because it only group-owns
+	 * the cgroup
+	 */
+	if (chmod(cgroup_path, 0775) < 0) {
+		SYSERROR("Error chmoding %s\n", cgroup_path);
+		return false;
+	}
+	fpath = lxc_append_paths(cgroup_path, "tasks");
+	if (!fpath)
+		return false;
+	if (chmod(fpath, 0664) < 0)
+		SYSERROR("Error chmoding %s\n", fpath);
+	free(fpath);
+	fpath = lxc_append_paths(cgroup_path, "cgroup.procs");
+	if (!fpath)
+		return false;
+	if (chmod(fpath, 0664) < 0)
+		SYSERROR("Error chmoding %s\n", fpath);
+	free(fpath);
+
+	return true;
+}
+
+static bool cgfs_chown(void *hdata, struct lxc_conf *conf)
+{
+	struct cgfs_data *d = hdata;
+	struct cgroup_process_info *info_ptr;
+	char *cgpath;
+	bool r = true;
+
+	if (!d)
+		return false;
+
+	for (info_ptr = d->info; info_ptr; info_ptr = info_ptr->next) {
+		if (!info_ptr->designated_mount_point) {
+			info_ptr->designated_mount_point = lxc_cgroup_find_mount_point(info_ptr->hierarchy, info_ptr->cgroup_path, true);
+			if (!info_ptr->designated_mount_point) {
+				SYSERROR("Could not chown cgroup %s: internal error (couldn't find any writable mountpoint to cgroup filesystem)", info_ptr->cgroup_path);
+				return false;
+			}
+		}
+
+		cgpath = cgroup_to_absolute_path(info_ptr->designated_mount_point, info_ptr->cgroup_path, NULL);
+		if (!cgpath) {
+			SYSERROR("Could not chown cgroup %s: internal error", info_ptr->cgroup_path);
+			continue;
+		}
+		r = do_cgfs_chown(cgpath, conf);
+		if (!r && is_crucial_hierarchy(info_ptr->hierarchy)) {
+			ERROR("Failed chowning %s\n", cgpath);
+			free(cgpath);
+			return false;
+		}
+		free(cgpath);
+	}
+
+	return true;
+}
+
+static struct cgroup_ops cgfs_ops = {
+	.init = cgfs_init,
+	.destroy = cgfs_destroy,
+	.create = cgfs_create,
+	.enter = cgfs_enter,
+	.create_legacy = cgfs_create_legacy,
+	.get_cgroup = cgfs_get_cgroup,
+	.canonical_path = cgfs_canonical_path,
+	.escape = cgfs_escape,
+	.get = lxc_cgroupfs_get,
+	.set = lxc_cgroupfs_set,
+	.unfreeze = cgfs_unfreeze,
+	.setup_limits = cgroupfs_setup_limits,
+	.name = "cgroupfs",
+	.attach = lxc_cgroupfs_attach,
+	.chown = cgfs_chown,
+	.mount_cgroup = cgroupfs_mount_cgroup,
+	.nrtasks = cgfs_nrtasks,
+	.driver = CGFS,
+};
diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
new file mode 100644
index 0000000..27c2721
--- /dev/null
+++ b/src/lxc/cgroups/cgfsng.c
@@ -0,0 +1,1691 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2016 Canonical Ltd.
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn at ubuntu.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * cgfs-ng.c: this is a new, simplified implementation of a filesystem
+ * cgroup backend.  The original cgfs.c was designed to be as flexible
+ * as possible.  It would try to find cgroup filesystems no matter where
+ * or how you had them mounted, and deduce the most usable mount for
+ * each controller.  It also was not designed for unprivileged use, as
+ * that was reserved for cgmanager.
+ *
+ * This new implementation assumes that cgroup filesystems are mounted
+ * under /sys/fs/cgroup/clist where clist is either the controller, or
+ * a comman-separated list of controllers.
+ */
+#include "config.h"
+#include <stdio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <grp.h>
+
+#include "bdev.h"
+#include "log.h"
+#include "cgroup.h"
+#include "utils.h"
+#include "commands.h"
+
+lxc_log_define(lxc_cgfsng, lxc);
+
+static struct cgroup_ops cgfsng_ops;
+
+/*
+ * A descriptor for a mounted hierarchy
+ * @controllers: either NULL, or a null-terminated list of all
+ *   the co-mounted controllers
+ * @mountpoint: the mountpoint we will use.  It will be either
+ *   /sys/fs/cgroup/controller or /sys/fs/cgroup/controllerlist
+ * @base_cgroup: the cgroup under which the container cgroup path
+     is created.  This will be either the caller's cgroup (if not
+     root), or init's cgroup (if root).
+ */
+struct hierarchy {
+	char **controllers;
+	char *mountpoint;
+	char *base_cgroup;
+	char *fullcgpath;
+};
+
+/*
+ * The cgroup data which is attached to the lxc_handler.
+ * @cgroup_pattern - a copy of the lxc.cgroup.pattern
+ * @container_cgroup - if not null, the cgroup which was created for
+ *   the container.  For each hierarchy, it is created under the
+ *   @hierarchy->base_cgroup directory.  Relative to the base_cgroup
+ *   it is the same for all hierarchies.
+ * @name - the container name
+ */
+struct cgfsng_handler_data {
+	char *cgroup_pattern;
+	char *container_cgroup; // cgroup we created for the container
+	char *name; // container name
+};
+
+/*
+ * @hierarchies - a NULL-terminated array of struct hierarchy, one per
+ *   hierarchy.  No duplicates.  First sufficient, writeable mounted
+ *   hierarchy wins
+ */
+struct hierarchy **hierarchies;
+
+/*
+ * @cgroup_use - a copy of the lxc.cgroup.use
+ */
+char *cgroup_use;
+
+static void free_string_list(char **clist)
+{
+	if (clist) {
+		int i;
+
+		for (i = 0; clist[i]; i++)
+			free(clist[i]);
+		free(clist);
+	}
+}
+
+/* Re-alllocate a pointer, do not fail */
+static void *must_realloc(void *orig, size_t sz)
+{
+	void *ret;
+
+	do {
+		ret = realloc(orig, sz);
+	} while (!ret);
+	return ret;
+}
+
+/* Allocate a pointer, do not fail */
+static void *must_alloc(size_t sz)
+{
+	return must_realloc(NULL, sz);
+}
+
+/* return copy of string @entry;  do not fail. */
+static char *must_copy_string(const char *entry)
+{
+	char *ret;
+
+	if (!entry)
+		return NULL;
+	do {
+		ret = strdup(entry);
+	} while (!ret);
+	return ret;
+}
+
+/*
+ * This is a special case - return a copy of @entry
+ * prepending 'name='.  I.e. turn systemd into name=systemd.
+ * Do not fail.
+ */
+static char *must_prefix_named(char *entry)
+{
+	char *ret;
+	size_t len = strlen(entry);
+
+	ret = must_alloc(len + 6);
+	snprintf(ret, len + 6, "name=%s", entry);
+	return ret;
+}
+
+/*
+ * Given a pointer to a null-terminated array of pointers, realloc to
+ * add one entry, and point the new entry to NULL.  Do not fail.  Return
+ * the index to the second-to-last entry - that is, the one which is
+ * now available for use (keeping the list null-terminated).
+ */
+static int append_null_to_list(void ***list)
+{
+	int newentry = 0;
+
+	if (*list)
+		for (; (*list)[newentry]; newentry++);
+
+	*list = must_realloc(*list, (newentry + 2) * sizeof(void **));
+	(*list)[newentry + 1] = NULL;
+	return newentry;
+}
+
+/*
+ * Given a null-terminated array of strings, check whether @entry
+ * is one of the strings
+ */
+static bool string_in_list(char **list, const char *entry)
+{
+	int i;
+
+	if (!list)
+		return false;
+	for (i = 0; list[i]; i++)
+		if (strcmp(list[i], entry) == 0)
+			return true;
+
+	return false;
+}
+
+/*
+ * append an entry to the clist.  Do not fail.
+ * *clist must be NULL the first time we are called.
+ *
+ * We also handle named subsystems here.  Any controller which is not a
+ * kernel subsystem, we prefix 'name='.  Any which is both a kernel and
+ * named subsystem, we refuse to use because we're not sure which we
+ * have here.  (TODO - we could work around this in some cases by just
+ * remounting to be unambiguous, or by comparing mountpoint contents
+ * with current cgroup)
+ *
+ * The last entry will always be NULL.
+ */
+static void must_append_controller(char **klist, char **nlist, char ***clist, char *entry)
+{
+	int newentry;
+	char *copy;
+
+	if (string_in_list(klist, entry) && string_in_list(nlist, entry)) {
+		ERROR("Refusing to use ambiguous controller '%s'", entry);
+		ERROR("It is both a named and kernel subsystem");
+		return;
+	}
+
+	newentry = append_null_to_list((void ***)clist);
+
+	if (strncmp(entry, "name=", 5) == 0)
+		copy = must_copy_string(entry);
+	else if (string_in_list(klist, entry))
+		copy = must_copy_string(entry);
+	else
+		copy = must_prefix_named(entry);
+
+	(*clist)[newentry] = copy;
+}
+
+static void free_handler_data(struct cgfsng_handler_data *d)
+{
+	free(d->cgroup_pattern);
+	free(d->container_cgroup);
+	free(d->name);
+	free(d);
+}
+
+/*
+ * Given a handler's cgroup data, return the struct hierarchy for the
+ * controller @c, or NULL if there is none.
+ */
+struct hierarchy *get_hierarchy(const char *c)
+{
+	int i;
+
+	if (!hierarchies)
+		return NULL;
+	for (i = 0; hierarchies[i]; i++) {
+		if (string_in_list(hierarchies[i]->controllers, c))
+			return hierarchies[i];
+	}
+	return NULL;
+}
+
+static char *must_make_path(const char *first, ...) __attribute__((sentinel));
+
+/* Copy contents of parent(@path)/@file to @path/@file */
+static bool copy_parent_file(char *path, char *file)
+{
+	char *lastslash, *value = NULL, *fpath, oldv;
+	int len = 0;
+	int ret;
+
+	lastslash = strrchr(path, '/');
+	if (!lastslash) { // bug...  this shouldn't be possible
+		ERROR("cgfsng:copy_parent_file: bad path %s", path);
+		return false;
+	}
+	oldv = *lastslash;
+	*lastslash = '\0';
+	fpath = must_make_path(path, file, NULL);
+	len = lxc_read_from_file(fpath, NULL, 0);
+	if (len <= 0)
+		goto bad;
+	value = must_alloc(len + 1);
+	if (lxc_read_from_file(fpath, value, len) != len)
+		goto bad;
+	free(fpath);
+	*lastslash = oldv;
+	fpath = must_make_path(path, file, NULL);
+	ret = lxc_write_to_file(fpath, value, len, false);
+	if (ret < 0)
+		SYSERROR("Unable to write %s to %s", value, fpath);
+	free(fpath);
+	free(value);
+	return ret >= 0;
+
+bad:
+	SYSERROR("Error reading '%s'", fpath);
+	free(fpath);
+	free(value);
+	return false;
+}
+
+/*
+ * Initialize the cpuset hierarchy in first directory of @gname and
+ * set cgroup.clone_children so that children inherit settings.
+ * Since the h->base_path is populated by init or ourselves, we know
+ * it is already initialized.
+ */
+bool handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
+{
+	char *cgpath, *clonechildrenpath, v, *slash;
+
+	if (!string_in_list(h->controllers, "cpuset"))
+		return true;
+
+	if (*cgname == '/')
+		cgname++;
+	slash = strchr(cgname, '/');
+	if (slash)
+		*slash = '\0';
+
+	cgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
+	if (slash)
+		*slash = '/';
+	if (mkdir(cgpath, 0755) < 0 && errno != EEXIST) {
+		SYSERROR("Failed to create '%s'", cgpath);
+		free(cgpath);
+		return false;
+	}
+	clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL);
+	if (!file_exists(clonechildrenpath)) { /* unified hierarchy doesn't have clone_children */
+		free(clonechildrenpath);
+		free(cgpath);
+		return true;
+	}
+	if (lxc_read_from_file(clonechildrenpath, &v, 1) < 0) {
+		SYSERROR("Failed to read '%s'", clonechildrenpath);
+		free(clonechildrenpath);
+		free(cgpath);
+		return false;
+	}
+
+	if (v == '1') {  /* already set for us by someone else */
+		free(clonechildrenpath);
+		free(cgpath);
+		return true;
+	}
+
+	/* copy parent's settings */
+	if (!copy_parent_file(cgpath, "cpuset.cpus") ||
+			!copy_parent_file(cgpath, "cpuset.mems")) {
+		free(cgpath);
+		free(clonechildrenpath);
+		return false;
+	}
+	free(cgpath);
+
+	if (lxc_write_to_file(clonechildrenpath, "1", 1, false) < 0) {
+		/* Set clone_children so children inherit our settings */
+		SYSERROR("Failed to write 1 to %s", clonechildrenpath);
+		free(clonechildrenpath);
+		return false;
+	}
+	free(clonechildrenpath);
+	return true;
+}
+
+/*
+ * Given two null-terminated lists of strings, return true if any string
+ * is in both.
+ */
+static bool controller_lists_intersect(char **l1, char **l2)
+{
+	int i;
+
+	if (!l1 || !l2)
+		return false;
+
+	for (i = 0; l1[i]; i++) {
+		if (string_in_list(l2, l1[i]))
+			return true;
+	}
+	return false;
+}
+
+/*
+ * For a null-terminated list of controllers @clist, return true if any of
+ * those controllers is already listed the null-terminated list of
+ * hierarchies @hlist.  Realistically, if one is present, all must be present.
+ */
+static bool controller_list_is_dup(struct hierarchy **hlist, char **clist)
+{
+	int i;
+
+	if (!hlist)
+		return false;
+	for (i = 0; hlist[i]; i++)
+		if (controller_lists_intersect(hlist[i]->controllers, clist))
+			return true;
+	return false;
+
+}
+
+/*
+ * Return true if the controller @entry is found in the null-terminated
+ * list of hierarchies @hlist
+ */
+static bool controller_found(struct hierarchy **hlist, char *entry)
+{
+	int i;
+	if (!hlist)
+		return false;
+
+	for (i = 0; hlist[i]; i++)
+		if (string_in_list(hlist[i]->controllers, entry))
+			return true;
+	return false;
+}
+
+/*
+ * Return true if all of the controllers which we require have been found.
+ * The required list is  freezer and anything in * lxc.cgroup.use.
+ */
+static bool all_controllers_found(void)
+{
+	char *p, *saveptr = NULL;
+	struct hierarchy ** hlist = hierarchies;
+
+	if (!controller_found(hlist, "freezer")) {
+		ERROR("no freezer controller mountpoint found");
+		return false;
+	}
+
+	if (!cgroup_use)
+		return true;
+	for (p = strtok_r(cgroup_use, ",", &saveptr); p;
+			p = strtok_r(NULL, ",", &saveptr)) {
+		if (!controller_found(hlist, p)) {
+			ERROR("no %s controller mountpoint found", p);
+			return false;
+		}
+	}
+	return true;
+}
+
+/* Return true if the fs type is fuse.lxcfs */
+static bool is_lxcfs(const char *line)
+{
+	char *p = strstr(line, " - ");
+	if (!p)
+		return false;
+	return strncmp(p, " - fuse.lxcfs ", 14) == 0;
+}
+
+/*
+ * Get the controllers from a mountinfo line
+ * There are other ways we could get this info.  For lxcfs, field 3
+ * is /cgroup/controller-list.  For cgroupfs, we could parse the mount
+ * options.  But we simply assume that the mountpoint must be
+ * /sys/fs/cgroup/controller-list
+ */
+static char **get_controllers(char **klist, char **nlist, char *line)
+{
+	// the fourth field is /sys/fs/cgroup/comma-delimited-controller-list
+	int i;
+	char *p = line, *p2, *tok, *saveptr = NULL;
+	char **aret = NULL;
+
+	for (i = 0; i < 4; i++) {
+		p = strchr(p, ' ');
+		if (!p)
+			return NULL;
+		p++;
+	}
+	if (!p)
+		return NULL;
+	/* note - if we change how mountinfo works, then our caller
+	 * will need to verify /sys/fs/cgroup/ in this field */
+	if (strncmp(p, "/sys/fs/cgroup/", 15) != 0)
+		return NULL;
+	p += 15;
+	p2 = strchr(p, ' ');
+	if (!p2) {
+		ERROR("corrupt mountinfo");
+		return NULL;
+	}
+	*p2 = '\0';
+	for (tok = strtok_r(p, ",", &saveptr); tok;
+			tok = strtok_r(NULL, ",", &saveptr)) {
+		must_append_controller(klist, nlist, &aret, tok);
+	}
+
+	return aret;
+}
+
+/* return true if the fstype is cgroup */
+static bool is_cgroupfs(char *line)
+{
+	char *p = strstr(line, " - ");
+	if (!p)
+		return false;
+	return strncmp(p, " - cgroup ", 10) == 0;
+}
+
+/* Add a controller to our list of hierarchies */
+static void add_controller(char **clist, char *mountpoint, char *base_cgroup)
+{
+	struct hierarchy *new;
+	int newentry;
+
+	new = must_alloc(sizeof(*new));
+	new->controllers = clist;
+	new->mountpoint = mountpoint;
+	new->base_cgroup = base_cgroup;
+	new->fullcgpath = NULL;
+
+	newentry = append_null_to_list((void ***)&hierarchies);
+	hierarchies[newentry] = new;
+}
+
+/*
+ * Get a copy of the mountpoint from @line, which is a line from
+ * /proc/self/mountinfo
+ */
+static char *get_mountpoint(char *line)
+{
+	int i;
+	char *p = line, *sret;
+	size_t len;
+
+	for (i = 0; i < 4; i++) {
+		p = strchr(p, ' ');
+		if (!p)
+			return NULL;
+		p++;
+	}
+	/* we've already stuck a \0 after the mountpoint */
+	len = strlen(p);
+	sret = must_alloc(len + 1);
+	memcpy(sret, p, len);
+	sret[len] = '\0';
+	return sret;
+}
+
+/*
+ * Given a multi-line string, return a null-terminated copy of the
+ * current line.
+ */
+static char *copy_to_eol(char *p)
+{
+	char *p2 = strchr(p, '\n'), *sret;
+	size_t len;
+
+	if (!p2)
+		return NULL;
+
+	len = p2 - p;
+	sret = must_alloc(len + 1);
+	memcpy(sret, p, len);
+	sret[len] = '\0';
+	return sret;
+}
+
+/*
+ * cgline: pointer to character after the first ':' in a line in a
+ * \n-terminated /proc/self/cgroup file. Check whether * controller c is
+ * present.
+ */
+static bool controller_in_clist(char *cgline, char *c)
+{
+	char *tok, *saveptr = NULL, *eol, *tmp;
+	size_t len;
+
+	eol = strchr(cgline, ':');
+	if (!eol)
+		return false;
+
+	len = eol - cgline;
+	tmp = alloca(len + 1);
+	memcpy(tmp, cgline, len);
+	tmp[len] = '\0';
+
+	for (tok = strtok_r(tmp, ",", &saveptr); tok;
+			tok = strtok_r(NULL, ",", &saveptr)) {
+		if (strcmp(tok, c) == 0)
+			return true;
+	}
+	return false;
+}
+
+/*
+ * @basecginfo is a copy of /proc/$$/cgroup.  Return the current
+ * cgroup for @controller
+ */
+static char *get_current_cgroup(char *basecginfo, char *controller)
+{
+	char *p = basecginfo;
+
+	while (1) {
+		p = strchr(p, ':');
+		if (!p)
+			return NULL;
+		p++;
+		if (controller_in_clist(p, controller)) {
+			p = strchr(p, ':');
+			if (!p)
+				return NULL;
+			p++;
+			return copy_to_eol(p);
+		}
+
+		p = strchr(p, '\n');
+		if (!p)
+			return NULL;
+		p++;
+	}
+}
+
+#define BATCH_SIZE 50
+static void batch_realloc(char **mem, size_t oldlen, size_t newlen)
+{
+	int newbatches = (newlen / BATCH_SIZE) + 1;
+	int oldbatches = (oldlen / BATCH_SIZE) + 1;
+
+	if (!*mem || newbatches > oldbatches) {
+		*mem = must_realloc(*mem, newbatches * BATCH_SIZE);
+	}
+}
+
+static void append_line(char **dest, size_t oldlen, char *new, size_t newlen)
+{
+	size_t full = oldlen + newlen;
+
+	batch_realloc(dest, oldlen, full + 1);
+
+	memcpy(*dest + oldlen, new, newlen + 1);
+}
+
+/* Slurp in a whole file */
+static char *read_file(char *fnam)
+{
+	FILE *f;
+	char *line = NULL, *buf = NULL;
+	size_t len = 0, fulllen = 0;
+	int linelen;
+
+	f = fopen(fnam, "r");
+	if (!f)
+		return NULL;
+	while ((linelen = getline(&line, &len, f)) != -1) {
+		append_line(&buf, fulllen, line, linelen);
+		fulllen += linelen;
+	}
+	fclose(f);
+	free(line);
+	return buf;
+}
+
+/*
+ * Given a hierarchy @mountpoint and base @path, verify that we can create
+ * directories underneath it.
+ */
+static bool test_writeable(char *mountpoint, char *path)
+{
+	char *fullpath = must_make_path(mountpoint, path, NULL);
+	int ret;
+
+	ret = access(fullpath, W_OK);
+	free(fullpath);
+	return ret == 0;
+}
+
+static void must_append_string(char ***list, char *entry)
+{
+	int newentry = append_null_to_list((void ***)list);
+	char *copy;
+
+	copy = must_copy_string(entry);
+	(*list)[newentry] = copy;
+}
+
+static void get_existing_subsystems(char ***klist, char ***nlist)
+{
+	FILE *f;
+	char *line = NULL;
+	size_t len = 0;
+
+	if ((f = fopen("/proc/self/cgroup", "r")) == NULL)
+		return;
+	while (getline(&line, &len, f) != -1) {
+		char *p, *p2, *tok, *saveptr = NULL;
+		p = strchr(line, ':');
+		if (!p)
+			continue;
+		p++;
+		p2 = strchr(p, ':');
+		if (!p2)
+			continue;
+		*p2 = '\0';
+		for (tok = strtok_r(p, ",", &saveptr); tok;
+				tok = strtok_r(NULL, ",", &saveptr)) {
+			if (strncmp(tok, "name=", 5) == 0)
+				must_append_string(nlist, tok);
+			else
+				must_append_string(klist, tok);
+		}
+	}
+
+	free(line);
+	fclose(f);
+}
+
+static void trim(char *s)
+{
+	size_t len = strlen(s);
+	while (s[len-1] == '\n')
+		s[--len] = '\0';
+}
+
+static void print_init_debuginfo(struct cgfsng_handler_data *d)
+{
+	int i;
+
+	if (!getenv("LXC_DEBUG_CGFSNG"))
+		return;
+
+	printf("Cgroup information:\n");
+	printf("  container name: %s\n", d->name);
+	printf("  lxc.cgroup.use: %s\n", cgroup_use ? cgroup_use : "(none)");
+	printf("  lxc.cgroup.pattern: %s\n", d->cgroup_pattern);
+	printf("  cgroup: %s\n", d->container_cgroup ? d->container_cgroup : "(none)");
+	if (!hierarchies) {
+		printf("  No hierarchies found.\n");
+		return;
+	}
+	printf("  Hierarchies:\n");
+	for (i = 0; hierarchies[i]; i++) {
+		struct hierarchy *h = hierarchies[i];
+		int j;
+		printf("  %d: base_cgroup %s\n", i, h->base_cgroup);
+		printf("      mountpoint %s\n", h->mountpoint);
+		printf("      controllers:\n");
+		for (j = 0; h->controllers[j]; j++)
+			printf("     %d: %s\n", j, h->controllers[j]);
+	}
+}
+
+static void print_basecg_debuginfo(char *basecginfo, char **klist, char **nlist)
+{
+	int k;
+	if (!getenv("LXC_DEBUG_CGFSNG"))
+		return;
+
+	printf("basecginfo is %s\n", basecginfo);
+
+	for (k = 0; klist[k]; k++)
+		printf("kernel subsystem %d: %s\n", k, klist[k]);
+	for (k = 0; nlist[k]; k++)
+		printf("named subsystem %d: %s\n", k, nlist[k]);
+}
+
+/*
+ * At startup, parse_hierarchies finds all the info we need about
+ * cgroup mountpoints and current cgroups, and stores it in @d.
+ */
+static bool parse_hierarchies(void)
+{
+	FILE *f;
+	char * line = NULL, *basecginfo;
+	char **klist = NULL, **nlist = NULL;
+	size_t len = 0;
+
+	/*
+	 * Root spawned containers escape the current cgroup, so use init's
+	 * cgroups as our base in that case.
+	 */
+	if (geteuid())
+		basecginfo = read_file("/proc/self/cgroup");
+	else
+		basecginfo = read_file("/proc/1/cgroup");
+	if (!basecginfo)
+		return false;
+
+	if ((f = fopen("/proc/self/mountinfo", "r")) == NULL) {
+		SYSERROR("Failed opening /proc/self/mountinfo");
+		return false;
+	}
+
+	get_existing_subsystems(&klist, &nlist);
+
+	print_basecg_debuginfo(basecginfo, klist, nlist);
+
+	/* we support simple cgroup mounts and lxcfs mounts */
+	while (getline(&line, &len, f) != -1) {
+		char **controller_list = NULL;
+		char *mountpoint, *base_cgroup;
+
+		if (!is_lxcfs(line) && !is_cgroupfs(line))
+			continue;
+
+		controller_list = get_controllers(klist, nlist, line);
+		if (!controller_list)
+			continue;
+
+		if (controller_list_is_dup(hierarchies, controller_list)) {
+			free(controller_list);
+			continue;
+		}
+
+		mountpoint = get_mountpoint(line);
+		if (!mountpoint) {
+			ERROR("Error reading mountinfo: bad line '%s'", line);
+			free_string_list(controller_list);
+			continue;
+		}
+
+		base_cgroup = get_current_cgroup(basecginfo, controller_list[0]);
+		if (!base_cgroup) {
+			ERROR("Failed to find current cgroup for controller '%s'", controller_list[0]);
+			free_string_list(controller_list);
+			free(mountpoint);
+			continue;
+		}
+		trim(base_cgroup);
+		prune_init_scope(base_cgroup);
+		if (!test_writeable(mountpoint, base_cgroup)) {
+			free_string_list(controller_list);
+			free(mountpoint);
+			free(base_cgroup);
+			continue;
+		}
+		add_controller(controller_list, mountpoint, base_cgroup);
+	}
+
+	free_string_list(klist);
+	free_string_list(nlist);
+
+	free(basecginfo);
+
+	fclose(f);
+	free(line);
+
+	/* verify that all controllers in cgroup.use and all crucial
+	 * controllers are accounted for
+	 */
+	if (!all_controllers_found())
+		return false;
+
+	return true;
+}
+
+static bool collect_hierarchy_info(void)
+{
+	const char *tmp;
+	errno = 0;
+	tmp = lxc_global_config_value("lxc.cgroup.use");
+	if (!cgroup_use && errno != 0) { // lxc.cgroup.use can be NULL
+		SYSERROR("cgfsng: error reading list of cgroups to use");
+		return false;
+	}
+	cgroup_use = must_copy_string(tmp);
+
+	return parse_hierarchies();
+}
+
+static void *cgfsng_init(const char *name)
+{
+	struct cgfsng_handler_data *d;
+	const char *cgroup_pattern;
+
+	d = must_alloc(sizeof(*d));
+	memset(d, 0, sizeof(*d));
+
+	d->name = must_copy_string(name);
+
+	cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
+	if (!cgroup_pattern) { // lxc.cgroup.pattern is only NULL on error
+		ERROR("Error getting cgroup pattern");
+		goto out_free;
+	}
+	d->cgroup_pattern = must_copy_string(cgroup_pattern);
+
+	print_init_debuginfo(d);
+
+	return d;
+
+out_free:
+	free_handler_data(d);
+	return NULL;
+}
+
+/*
+ * Concatenate all passed-in strings into one path.  Do not fail.  If any piece is
+ * not prefixed with '/', add a '/'.
+ */
+static char *must_make_path(const char *first, ...)
+{
+	va_list args;
+	char *cur, *dest;
+	size_t full_len = strlen(first);
+
+	dest = must_copy_string(first);
+
+	va_start(args, first);
+	while ((cur = va_arg(args, char *)) != NULL) {
+		full_len += strlen(cur);
+		if (cur[0] != '/')
+			full_len++;
+		dest = must_realloc(dest, full_len + 1);
+		if (cur[0] != '/')
+			strcat(dest, "/");
+		strcat(dest, cur);
+	}
+	va_end(args);
+
+	return dest;
+}
+
+static int cgroup_rmdir(char *dirname)
+{
+	struct dirent dirent, *direntp;
+	DIR *dir;
+	int r = 0;
+
+	dir = opendir(dirname);
+	if (!dir)
+		return -1;
+
+	while (!readdir_r(dir, &dirent, &direntp)) {
+		struct stat mystat;
+		char *pathname;
+
+		if (!direntp)
+			break;
+
+		if (!strcmp(direntp->d_name, ".") ||
+		    !strcmp(direntp->d_name, ".."))
+			continue;
+
+		pathname = must_make_path(dirname, direntp->d_name, NULL);
+
+		if (lstat(pathname, &mystat)) {
+			if (!r)
+				WARN("failed to stat %s", pathname);
+			r = -1;
+			goto next;
+		}
+
+		if (!S_ISDIR(mystat.st_mode))
+			goto next;
+		if (cgroup_rmdir(pathname) < 0)
+			r = -1;
+next:
+		free(pathname);
+	}
+
+	if (rmdir(dirname) < 0) {
+		if (!r)
+			WARN("%s: failed to delete %s: %m", __func__, dirname);
+		r = -1;
+	}
+
+	if (closedir(dir) < 0) {
+		if (!r)
+			WARN("%s: failed to delete %s: %m", __func__, dirname);
+		r = -1;
+	}
+	return r;
+}
+
+static int rmdir_wrapper(void *data)
+{
+	char *path = data;
+
+	if (setresgid(0,0,0) < 0)
+		SYSERROR("Failed to setgid to 0");
+	if (setresuid(0,0,0) < 0)
+		SYSERROR("Failed to setuid to 0");
+	if (setgroups(0, NULL) < 0)
+		SYSERROR("Failed to clear groups");
+
+	return cgroup_rmdir(path);
+}
+
+void recursive_destroy(char *path, struct lxc_conf *conf)
+{
+	int r;
+	if (conf && !lxc_list_empty(&conf->id_map))
+		r = userns_exec_1(conf, rmdir_wrapper, path);
+	else
+		r = cgroup_rmdir(path);
+
+	if (r < 0)
+		ERROR("Error destroying %s", path);
+}
+
+static void cgfsng_destroy(void *hdata, struct lxc_conf *conf)
+{
+	struct cgfsng_handler_data *d = hdata;
+
+	if (!d)
+		return;
+
+	if (d->container_cgroup && hierarchies) {
+		int i;
+		for (i = 0; hierarchies[i]; i++) {
+			struct hierarchy *h = hierarchies[i];
+			if (h->fullcgpath) {
+				recursive_destroy(h->fullcgpath, conf);
+				free(h->fullcgpath);
+				h->fullcgpath = NULL;
+			}
+		}
+	}
+
+	free_handler_data(d);
+}
+
+struct cgroup_ops *cgfsng_ops_init(void)
+{
+	if (!collect_hierarchy_info())
+		return NULL;
+	return &cgfsng_ops;
+}
+
+static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
+{
+	h->fullcgpath = must_make_path(h->mountpoint, h->base_cgroup, cgname, NULL);
+	if (dir_exists(h->fullcgpath)) // it must not already exist
+		return false;
+	if (!handle_cpuset_hierarchy(h, cgname))
+		return false;
+	return mkdir_p(h->fullcgpath, 0755) == 0;
+}
+
+static void remove_path_for_hierarchy(struct hierarchy *h, char *cgname)
+{
+	if (rmdir(h->fullcgpath) < 0)
+		SYSERROR("Failed to clean up cgroup %s from failed creation attempt", h->fullcgpath);
+	free(h->fullcgpath);
+	h->fullcgpath = NULL;
+}
+
+/*
+ * Try to create the same cgroup in all hierarchies.
+ * Start with cgroup_pattern; next cgroup_pattern-1, -2, ..., -999
+ */
+static inline bool cgfsng_create(void *hdata)
+{
+	struct cgfsng_handler_data *d = hdata;
+	char *tmp, *cgname, *offset;
+	int i, idx = 0;
+	size_t len;
+
+	if (!d)
+		return false;
+	if (d->container_cgroup) {
+		WARN("cgfsng_create called a second time");
+		return false;
+	}
+
+	tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
+	if (!tmp) {
+		ERROR("Failed expanding cgroup name pattern");
+		return false;
+	}
+	len = strlen(tmp) + 5; // leave room for -NNN\0
+	cgname = must_alloc(len);
+	strcpy(cgname, tmp);
+	free(tmp);
+	offset = cgname + len - 5;
+
+again:
+	if (idx == 1000) {
+		ERROR("Too many conflicting cgroup names");
+		goto out_free;
+	}
+	if (idx)
+		snprintf(offset, 5, "-%d", idx);
+	for (i = 0; hierarchies[i]; i++) {
+		if (!create_path_for_hierarchy(hierarchies[i], cgname)) {
+			int j;
+			SYSERROR("Failed to create %s: %s", hierarchies[i]->fullcgpath, strerror(errno));
+			free(hierarchies[i]->fullcgpath);
+			hierarchies[i]->fullcgpath = NULL;
+			for (j = 0; j < i; j++)
+				remove_path_for_hierarchy(hierarchies[j], cgname);
+			idx++;
+			goto again;
+		}
+	}
+	/* Done */
+	d->container_cgroup = cgname;
+	return true;
+
+out_free:
+	free(cgname);
+	return false;
+}
+
+static const char *cgfsng_canonical_path(void *hdata)
+{
+	struct cgfsng_handler_data *d = hdata;
+
+	return d->container_cgroup;
+}
+
+static bool cgfsng_enter(void *hdata, pid_t pid)
+{
+	char pidstr[25];
+	int i, len;
+
+	len = snprintf(pidstr, 25, "%d", pid);
+	if (len < 0 || len > 25)
+		return false;
+
+	for (i = 0; hierarchies[i]; i++) {
+		char *fullpath = must_make_path(hierarchies[i]->fullcgpath,
+						"cgroup.procs", NULL);
+		if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
+			SYSERROR("Failed to enter %s", fullpath);
+			free(fullpath);
+			return false;
+		}
+		free(fullpath);
+	}
+
+	return true;
+}
+
+struct chown_data {
+	struct cgfsng_handler_data *d;
+	uid_t origuid; // target uid in parent namespace
+};
+
+/*
+ * chgrp the container cgroups to container group.  We leave
+ * the container owner as cgroup owner.  So we must make the
+ * directories 775 so that the container can create sub-cgroups.
+ *
+ * Also chown the tasks and cgroup.procs files.  Those may not
+ * exist depending on kernel version.
+ */
+static int chown_cgroup_wrapper(void *data)
+{
+	struct chown_data *arg = data;
+	uid_t destuid;
+	int i;
+
+	if (setresgid(0,0,0) < 0)
+		SYSERROR("Failed to setgid to 0");
+	if (setresuid(0,0,0) < 0)
+		SYSERROR("Failed to setuid to 0");
+	if (setgroups(0, NULL) < 0)
+		SYSERROR("Failed to clear groups");
+
+	destuid = get_ns_uid(arg->origuid);
+
+	for (i = 0; hierarchies[i]; i++) {
+		char *fullpath, *path = hierarchies[i]->fullcgpath;
+
+		if (chown(path, destuid, 0) < 0) {
+			SYSERROR("Error chowning %s to %d", path, (int) destuid);
+			return -1;
+		}
+
+		if (chmod(path, 0775) < 0) {
+			SYSERROR("Error chmoding %s", path);
+			return -1;
+		}
+
+		/*
+		 * Failures to chown these are inconvenient but not detrimental
+		 * We leave these owned by the container launcher, so that container
+		 * root can write to the files to attach.  We chmod them 664 so that
+		 * container systemd can write to the files (which systemd in wily
+		 * insists on doing)
+		 */
+		fullpath = must_make_path(path, "tasks", NULL);
+		if (chown(fullpath, destuid, 0) < 0 && errno != ENOENT)
+			WARN("Failed chowning %s to %d: %m", fullpath, (int) destuid);
+		if (chmod(fullpath, 0664) < 0)
+			WARN("Error chmoding %s: %m", path);
+		free(fullpath);
+
+		fullpath = must_make_path(path, "cgroup.procs", NULL);
+		if (chown(fullpath, destuid, 0) < 0 && errno != ENOENT)
+			WARN("Failed chowning %s to %d: %m", fullpath, (int) destuid);
+		if (chmod(fullpath, 0664) < 0)
+			WARN("Error chmoding %s: %m", path);
+		free(fullpath);
+	}
+
+	return 0;
+}
+
+static bool cgfsns_chown(void *hdata, struct lxc_conf *conf)
+{
+	struct cgfsng_handler_data *d = hdata;
+	struct chown_data wrap;
+
+	if (!d)
+		return false;
+
+	if (lxc_list_empty(&conf->id_map))
+		return true;
+
+	wrap.d = d;
+	wrap.origuid = geteuid();
+
+	if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap) < 0) {
+		ERROR("Error requesting cgroup chown in new namespace");
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * We've safe-mounted a tmpfs as parent, so we don't need to protect against
+ * symlinks any more - just use mount
+ */
+
+/* mount cgroup-full if requested */
+static int mount_cgroup_full(int type, struct hierarchy *h, char *dest,
+				   char *container_cgroup)
+{
+	if (type < LXC_AUTO_CGROUP_FULL_RO || type > LXC_AUTO_CGROUP_FULL_MIXED)
+		return 0;
+	if (mount(h->mountpoint, dest, "cgroup", MS_BIND, NULL) < 0) {
+		SYSERROR("Error bind-mounting %s cgroup onto %s", h->mountpoint,
+			 dest);
+		return -1;
+	}
+	if (type != LXC_AUTO_CGROUP_FULL_RW) {
+		unsigned long flags = MS_BIND | MS_NOSUID | MS_NOEXEC | MS_NODEV |
+				      MS_REMOUNT | MS_RDONLY;
+		if (mount(NULL, dest, "cgroup", flags, NULL) < 0) {
+			SYSERROR("Error remounting %s readonly", dest);
+			return -1;
+		}
+	}
+
+	INFO("Bind mounted %s onto %s", h->mountpoint, dest);
+	if (type != LXC_AUTO_CGROUP_FULL_MIXED)
+		return 0;
+
+	/* mount just the container path rw */
+	char *source = must_make_path(h->mountpoint, h->base_cgroup, container_cgroup, NULL);
+	char *rwpath = must_make_path(dest, h->base_cgroup, container_cgroup, NULL);
+	if (mount(source, rwpath, "cgroup", MS_BIND, NULL) < 0)
+		WARN("Failed to mount %s read-write: %m", rwpath);
+	INFO("Made %s read-write", rwpath);
+	free(rwpath);
+	free(source);
+	return 0;
+}
+
+/* cgroup-full:* is done, no need to create subdirs */
+static bool cg_mount_needs_subdirs(int type)
+{
+	if (type >= LXC_AUTO_CGROUP_FULL_RO)
+		return false;
+	return true;
+}
+
+/*
+ * After $rootfs/sys/fs/container/controller/the/cg/path has been
+ * created, remount controller ro if needed and bindmount the
+ * cgroupfs onto controll/the/cg/path
+ */
+static int
+do_secondstage_mounts_if_needed(int type, struct hierarchy *h,
+				char *controllerpath, char *cgpath,
+				const char *container_cgroup)
+{
+	if (type == LXC_AUTO_CGROUP_RO || type == LXC_AUTO_CGROUP_MIXED) {
+		if (mount(controllerpath, controllerpath, "cgroup", MS_BIND, NULL) < 0) {
+			SYSERROR("Error bind-mounting %s", controllerpath);
+			return -1;
+		}
+		if (mount(controllerpath, controllerpath, "cgroup",
+			   MS_REMOUNT | MS_BIND | MS_RDONLY, NULL) < 0) {
+			SYSERROR("Error remounting %s read-only", controllerpath);
+			return -1;
+		}
+		INFO("Remounted %s read-only", controllerpath);
+	}
+	char *sourcepath = must_make_path(h->mountpoint, h->base_cgroup, container_cgroup, NULL);
+	int flags = MS_BIND;
+	if (type == LXC_AUTO_CGROUP_RO)
+		flags |= MS_RDONLY;
+	INFO("Mounting %s onto %s", sourcepath, cgpath);
+	if (mount(sourcepath, cgpath, "cgroup", flags, NULL) < 0) {
+		free(sourcepath);
+		SYSERROR("Error mounting cgroup %s onto %s", h->controllers[0],
+				cgpath);
+		return -1;
+	}
+	free(sourcepath);
+	INFO("Completed second stage cgroup automounts for %s", cgpath);
+	return 0;
+}
+
+static bool cgfsng_mount(void *hdata, const char *root, int type)
+{
+	struct cgfsng_handler_data *d = hdata;
+	char *tmpfspath = NULL;
+	bool retval = false;
+	int i;
+
+	if ((type & LXC_AUTO_CGROUP_MASK) == 0)
+		return true;
+
+	if (cgns_supported())
+		return true;
+
+	tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
+
+	if (type == LXC_AUTO_CGROUP_NOSPEC)
+		type = LXC_AUTO_CGROUP_MIXED;
+	else if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
+		type = LXC_AUTO_CGROUP_FULL_MIXED;
+
+	/* Mount tmpfs */
+	if (safe_mount("cgroup_root", tmpfspath, "tmpfs",
+			MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME,
+			"size=10240k,mode=755",
+			root) < 0)
+		goto  bad;
+
+	for (i = 0; hierarchies[i]; i++) {
+		char *controllerpath, *path2;
+		struct hierarchy *h = hierarchies[i];
+		char *controller = strrchr(h->mountpoint, '/');
+		int r;
+
+		if (!controller)
+			continue;
+		controller++;
+		controllerpath = must_make_path(tmpfspath, controller, NULL);
+		if (dir_exists(controllerpath)) {
+			free(controllerpath);
+			continue;
+		}
+		if (mkdir(controllerpath, 0755) < 0) {
+			SYSERROR("Error creating cgroup path: %s", controllerpath);
+			free(controllerpath);
+			goto bad;
+		}
+		if (mount_cgroup_full(type, h, controllerpath, d->container_cgroup) < 0) {
+			free(controllerpath);
+			goto bad;
+		}
+		if (!cg_mount_needs_subdirs(type)) {
+			free(controllerpath);
+			continue;
+		}
+		path2 = must_make_path(controllerpath, h->base_cgroup, d->container_cgroup, NULL);
+		if (mkdir_p(path2, 0755) < 0) {
+			free(controllerpath);
+			goto bad;
+		}
+
+		r = do_secondstage_mounts_if_needed(type, h, controllerpath, path2,
+						    d->container_cgroup);
+		free(controllerpath);
+		free(path2);
+		if (r < 0)
+			goto bad;
+	}
+	retval = true;
+
+bad:
+	free(tmpfspath);
+	return retval;
+}
+
+static int recursive_count_nrtasks(char *dirname)
+{
+	struct dirent dirent, *direntp;
+	DIR *dir;
+	int count = 0, ret;
+	char *path;
+
+	dir = opendir(dirname);
+	if (!dir)
+		return 0;
+
+	while (!readdir_r(dir, &dirent, &direntp)) {
+		struct stat mystat;
+
+		if (!direntp)
+			break;
+
+		if (!strcmp(direntp->d_name, ".") ||
+		    !strcmp(direntp->d_name, ".."))
+			continue;
+
+		path = must_make_path(dirname, direntp->d_name, NULL);
+
+		if (lstat(path, &mystat))
+			goto next;
+
+		if (!S_ISDIR(mystat.st_mode))
+			goto next;
+
+		count += recursive_count_nrtasks(path);
+next:
+		free(path);
+	}
+
+	path = must_make_path(dirname, "cgroup.procs", NULL);
+	ret = lxc_count_file_lines(path);
+	if (ret != -1)
+		count += ret;
+	free(path);
+
+	(void) closedir(dir);
+
+	return count;
+}
+
+static int cgfsng_nrtasks(void *hdata) {
+	struct cgfsng_handler_data *d = hdata;
+	char *path;
+	int count;
+
+	if (!d || !d->container_cgroup || !hierarchies)
+		return -1;
+	path = must_make_path(hierarchies[0]->fullcgpath, NULL);
+	count = recursive_count_nrtasks(path);
+	free(path);
+	return count;
+}
+
+/* Only root needs to escape to the cgroup of its init */
+static bool cgfsng_escape()
+{
+	struct cgfsng_handler_data *d;
+	int i;
+	bool ret = false;
+
+	if (geteuid())
+		return true;
+
+	d = cgfsng_init("criu-temp-cgfsng");
+	if (!d) {
+		ERROR("cgfsng_init failed");
+		return false;
+	}
+
+	for (i = 0; hierarchies[i]; i++) {
+		char *fullpath = must_make_path(hierarchies[i]->mountpoint,
+						hierarchies[i]->base_cgroup,
+						"cgroup.procs", NULL);
+		if (lxc_write_to_file(fullpath, "0", 2, false) != 0) {
+			SYSERROR("Failed to escape to %s", fullpath);
+			free(fullpath);
+			goto out;
+		}
+		free(fullpath);
+	}
+
+	ret = true;
+out:
+	free_handler_data(d);
+	return ret;
+}
+
+#define THAWED "THAWED"
+#define THAWED_LEN (strlen(THAWED))
+
+static bool cgfsng_unfreeze(void *hdata)
+{
+	char *fullpath;
+	struct hierarchy *h = get_hierarchy("freezer");
+
+	if (!h)
+		return false;
+	fullpath = must_make_path(h->fullcgpath, "freezer.state", NULL);
+	if (lxc_write_to_file(fullpath, THAWED, THAWED_LEN, false) != 0) {
+		free(fullpath);
+		return false;
+	}
+	free(fullpath);
+	return true;
+}
+
+static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem)
+{
+	struct hierarchy *h = get_hierarchy(subsystem);
+	if (!h)
+		return NULL;
+
+	return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
+}
+
+/*
+ * Given a cgroup path returned from lxc_cmd_get_cgroup_path, build a
+ * full path, which must be freed by the caller.
+ */
+static char *build_full_cgpath_from_monitorpath(struct hierarchy *h,
+						const char *inpath,
+						const char *filename)
+{
+	/*
+	 * XXX Remove this case after 2.0 release.  It's for dealing with
+	 * containers spawned under the old buggy cgfsng which wasn't around
+	 * for long.
+	 */
+	if (strncmp(inpath, "/sys/fs/cgroup/", 15) == 0)
+		return must_make_path(inpath, filename, NULL);
+	return must_make_path(h->mountpoint, inpath, filename, NULL);
+}
+
+static bool cgfsng_attach(const char *name, const char *lxcpath, pid_t pid)
+{
+	char pidstr[25];
+	int i, len;
+
+	len = snprintf(pidstr, 25, "%d", pid);
+	if (len < 0 || len > 25)
+		return false;
+
+	for (i = 0; hierarchies[i]; i++) {
+		char *path, *fullpath;
+		struct hierarchy *h = hierarchies[i];
+
+		path = lxc_cmd_get_cgroup_path(name, lxcpath, h->controllers[0]);
+		if (!path) // not running
+			continue;
+
+		fullpath = build_full_cgpath_from_monitorpath(h, path, "cgroup.procs");
+		free(path);
+		if (lxc_write_to_file(fullpath, pidstr, len, false) != 0) {
+			SYSERROR("Failed to attach %d to %s", (int)pid, fullpath);
+			free(fullpath);
+			return false;
+		}
+		free(fullpath);
+	}
+
+	return true;
+}
+
+/*
+ * Called externally (i.e. from 'lxc-cgroup') to query cgroup limits.
+ * Here we don't have a cgroup_data set up, so we ask the running
+ * container through the commands API for the cgroup path
+ */
+static int cgfsng_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+{
+	char *subsystem, *p, *path;
+	struct hierarchy *h;
+	int ret = -1;
+
+	subsystem = alloca(strlen(filename) + 1);
+	strcpy(subsystem, filename);
+	if ((p = strchr(subsystem, '.')) != NULL)
+		*p = '\0';
+
+	path = lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
+	if (!path) // not running
+		return -1;
+
+	h = get_hierarchy(subsystem);
+	if (h) {
+		char *fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
+		ret = lxc_read_from_file(fullpath, value, len);
+		free(fullpath);
+	}
+
+	free(path);
+
+	return ret;
+}
+
+/*
+ * Called externally (i.e. from 'lxc-cgroup') to set new cgroup limits.
+ * Here we don't have a cgroup_data set up, so we ask the running
+ * container through the commands API for the cgroup path
+ */
+static int cgfsng_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+{
+	char *subsystem, *p, *path;
+	struct hierarchy *h;
+	int ret = -1;
+
+	subsystem = alloca(strlen(filename) + 1);
+	strcpy(subsystem, filename);
+	if ((p = strchr(subsystem, '.')) != NULL)
+		*p = '\0';
+
+	path = lxc_cmd_get_cgroup_path(name, lxcpath, subsystem);
+	if (!path) // not running
+		return -1;
+
+	h = get_hierarchy(subsystem);
+	if (h) {
+		char *fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
+		ret = lxc_write_to_file(fullpath, value, strlen(value), false);
+		free(fullpath);
+	}
+
+	free(path);
+
+	return ret;
+}
+
+/*
+ * Called from setup_limits - here we have the container's cgroup_data because
+ * we created the cgroups
+ */
+static int lxc_cgroup_set_data(const char *filename, const char *value, struct cgfsng_handler_data *d)
+{
+	char *subsystem = NULL, *p;
+	int ret = -1;
+	struct hierarchy *h;
+
+	subsystem = alloca(strlen(filename) + 1);
+	strcpy(subsystem, filename);
+	if ((p = strchr(subsystem, '.')) != NULL)
+		*p = '\0';
+
+	h = get_hierarchy(subsystem);
+	if (h) {
+		char *fullpath = must_make_path(h->fullcgpath, filename, NULL);
+		ret = lxc_write_to_file(fullpath, value, strlen(value), false);
+		free(fullpath);
+	}
+	return ret;
+}
+
+static bool cgfsng_setup_limits(void *hdata, struct lxc_list *cgroup_settings,
+				  bool do_devices)
+{
+	struct cgfsng_handler_data *d = hdata;
+	struct lxc_list *iterator, *sorted_cgroup_settings, *next;
+	struct lxc_cgroup *cg;
+	bool ret = false;
+
+	if (lxc_list_empty(cgroup_settings))
+		return true;
+
+	sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
+	if (!sorted_cgroup_settings) {
+		return false;
+	}
+
+	lxc_list_for_each(iterator, sorted_cgroup_settings) {
+		cg = iterator->elem;
+
+		if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
+			if (lxc_cgroup_set_data(cg->subsystem, cg->value, d)) {
+				if (do_devices && (errno == EACCES || errno == EPERM)) {
+					WARN("Error setting %s to %s for %s",
+					      cg->subsystem, cg->value, d->name);
+					continue;
+				}
+				SYSERROR("Error setting %s to %s for %s",
+				      cg->subsystem, cg->value, d->name);
+				goto out;
+			}
+		}
+
+		DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
+	}
+
+	ret = true;
+	INFO("cgroup has been setup");
+out:
+	lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
+		lxc_list_del(iterator);
+		free(iterator);
+	}
+	free(sorted_cgroup_settings);
+	return ret;
+}
+
+static struct cgroup_ops cgfsng_ops = {
+	.init = cgfsng_init,
+	.destroy = cgfsng_destroy,
+	.create = cgfsng_create,
+	.enter = cgfsng_enter,
+	.canonical_path = cgfsng_canonical_path,
+	.escape = cgfsng_escape,
+	.get_cgroup = cgfsng_get_cgroup,
+	.get = cgfsng_get,
+	.set = cgfsng_set,
+	.unfreeze = cgfsng_unfreeze,
+	.setup_limits = cgfsng_setup_limits,
+	.name = "cgroupfs-ng",
+	.attach = cgfsng_attach,
+	.chown = cgfsns_chown,
+	.mount_cgroup = cgfsng_mount,
+	.nrtasks = cgfsng_nrtasks,
+	.driver = CGFSNG,
+
+	/* unsupported */
+	.create_legacy = NULL,
+};
diff --git a/src/lxc/cgroups/cgmanager.c b/src/lxc/cgroups/cgmanager.c
new file mode 100644
index 0000000..4da891d
--- /dev/null
+++ b/src/lxc/cgroups/cgmanager.c
@@ -0,0 +1,1672 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <poll.h>
+
+#include "bdev.h"
+#include "error.h"
+#include "commands.h"
+#include "list.h"
+#include "conf.h"
+#include "utils.h"
+#include "log.h"
+#include "cgroup.h"
+#include "start.h"
+#include "state.h"
+
+#define CGM_SUPPORTS_GET_ABS 3
+#define CGM_SUPPORTS_NAMED 4
+#define CGM_SUPPORTS_MULT_CONTROLLERS 10
+
+#ifdef HAVE_CGMANAGER
+lxc_log_define(lxc_cgmanager, lxc);
+
+#include <nih-dbus/dbus_connection.h>
+#include <cgmanager/cgmanager-client.h>
+#include <nih/alloc.h>
+#include <nih/error.h>
+#include <nih/string.h>
+
+struct cgm_data {
+	char *name;
+	char *cgroup_path;
+	const char *cgroup_pattern;
+};
+
+static pthread_mutex_t cgm_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void lock_mutex(pthread_mutex_t *l)
+{
+	int ret;
+
+	if ((ret = pthread_mutex_lock(l)) != 0) {
+		fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
+		exit(1);
+	}
+}
+
+static void unlock_mutex(pthread_mutex_t *l)
+{
+	int ret;
+
+	if ((ret = pthread_mutex_unlock(l)) != 0) {
+		fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret));
+		exit(1);
+	}
+}
+
+void cgm_lock(void)
+{
+	lock_mutex(&cgm_mutex);
+}
+
+void cgm_unlock(void)
+{
+	unlock_mutex(&cgm_mutex);
+}
+
+#ifdef HAVE_PTHREAD_ATFORK
+__attribute__((constructor))
+static void process_lock_setup_atfork(void)
+{
+	pthread_atfork(cgm_lock, cgm_unlock, cgm_unlock);
+}
+#endif
+
+static NihDBusProxy *cgroup_manager = NULL;
+static int32_t api_version;
+
+static struct cgroup_ops cgmanager_ops;
+static int nr_subsystems;
+static char **subsystems, **subsystems_inone;
+static bool dbus_threads_initialized = false;
+static void cull_user_controllers(void);
+
+static void cgm_dbus_disconnect(void)
+{
+	if (cgroup_manager) {
+		dbus_connection_flush(cgroup_manager->connection);
+		dbus_connection_close(cgroup_manager->connection);
+		nih_free(cgroup_manager);
+	}
+	cgroup_manager = NULL;
+	cgm_unlock();
+}
+
+#define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
+static bool cgm_dbus_connect(void)
+{
+	DBusError dbus_error;
+	static DBusConnection *connection;
+
+	cgm_lock();
+	if (!dbus_threads_initialized) {
+		// tell dbus to do struct locking for thread safety
+		dbus_threads_init_default();
+		dbus_threads_initialized = true;
+	}
+
+	dbus_error_init(&dbus_error);
+
+	connection = dbus_connection_open_private(CGMANAGER_DBUS_SOCK, &dbus_error);
+	if (!connection) {
+		DEBUG("Failed opening dbus connection: %s: %s",
+				dbus_error.name, dbus_error.message);
+		dbus_error_free(&dbus_error);
+		cgm_unlock();
+		return false;
+	}
+	dbus_connection_set_exit_on_disconnect(connection, FALSE);
+	dbus_error_free(&dbus_error);
+	cgroup_manager = nih_dbus_proxy_new(NULL, connection,
+				NULL /* p2p */,
+				"/org/linuxcontainers/cgmanager", NULL, NULL);
+	dbus_connection_unref(connection);
+	if (!cgroup_manager) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("Error opening cgmanager proxy: %s", nerr->message);
+		nih_free(nerr);
+		cgm_dbus_disconnect();
+		return false;
+	}
+
+	// get the api version
+	if (cgmanager_get_api_version_sync(NULL, cgroup_manager, &api_version) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("Error cgroup manager api version: %s", nerr->message);
+		nih_free(nerr);
+		cgm_dbus_disconnect();
+		return false;
+	}
+	if (api_version < CGM_SUPPORTS_NAMED)
+		cull_user_controllers();
+	return true;
+}
+
+static bool cgm_all_controllers_same;
+
+/*
+ * Check whether we can use "all" when talking to cgmanager.
+ * We check two things:
+ * 1. whether cgmanager is new enough to support this.
+ * 2. whether the task we are interested in is in the same
+ *    cgroup for all controllers.
+ * In cgm_init (before an lxc-start) we care about our own
+ * cgroup.  In cgm_attach, we care about the target task's
+ * cgroup.
+ */
+static void check_supports_multiple_controllers(pid_t pid)
+{
+	FILE *f;
+	char *line = NULL, *prevpath = NULL;
+	size_t sz = 0;
+	char path[100];
+
+	cgm_all_controllers_same = false;
+
+	if (pid == -1)
+		sprintf(path, "/proc/self/cgroup");
+	else
+		sprintf(path, "/proc/%d/cgroup", pid);
+	f = fopen(path, "r");
+	if (!f)
+		return;
+
+	cgm_all_controllers_same = true;
+
+	while (getline(&line, &sz, f) != -1) {
+		/* file format: hierarchy:subsystems:group */
+		char *colon;
+		if (!line[0])
+			continue;
+
+		colon = strchr(line, ':');
+		if (!colon)
+			continue;
+		colon = strchr(colon+1, ':');
+		if (!colon)
+			continue;
+		colon++;
+		if (!prevpath) {
+			prevpath = alloca(strlen(colon)+1);
+			strcpy(prevpath, colon);
+			continue;
+		}
+		if (strcmp(prevpath, colon) != 0) {
+			cgm_all_controllers_same = false;
+			break;
+		}
+	}
+
+	fclose(f);
+	free(line);
+}
+
+static int send_creds(int sock, int rpid, int ruid, int rgid)
+{
+	struct msghdr msg = { 0 };
+	struct iovec iov;
+	struct cmsghdr *cmsg;
+	struct ucred cred = {
+		.pid = rpid,
+		.uid = ruid,
+		.gid = rgid,
+	};
+	char cmsgbuf[CMSG_SPACE(sizeof(cred))];
+	char buf[1];
+	buf[0] = 'p';
+
+	msg.msg_control = cmsgbuf;
+	msg.msg_controllen = sizeof(cmsgbuf);
+
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_CREDENTIALS;
+	memcpy(CMSG_DATA(cmsg), &cred, sizeof(cred));
+
+	msg.msg_name = NULL;
+	msg.msg_namelen = 0;
+
+	iov.iov_base = buf;
+	iov.iov_len = sizeof(buf);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	if (sendmsg(sock, &msg, 0) < 0)
+		return -1;
+	return 0;
+}
+
+static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path, int32_t *existed)
+{
+	bool ret = true;
+	if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
+				       cgroup_path, existed) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("call to cgmanager_create_sync failed: %s", nerr->message);
+		nih_free(nerr);
+		ERROR("Failed to create %s:%s", controller, cgroup_path);
+		ret = false;
+	}
+
+	return ret;
+}
+
+/*
+ * Escape to the root cgroup if we are root, so that the container will
+ * be in "/lxc/c1" rather than "/user/..../c1"
+ * called internally with connection already open
+ */
+static bool cgm_escape(void *hdata)
+{
+	bool ret = true, cgm_needs_disconnect = false;
+	pid_t me = getpid();
+	char **slist = subsystems;
+	int i;
+
+	if (!cgroup_manager) {
+		if (!cgm_dbus_connect()) {
+			ERROR("Error connecting to cgroup manager");
+			return false;
+		}
+		cgm_needs_disconnect = true;
+	}
+
+
+	if (cgm_all_controllers_same)
+		slist = subsystems_inone;
+
+	for (i = 0; slist[i]; i++) {
+		if (cgmanager_move_pid_abs_sync(NULL, cgroup_manager,
+					slist[i], "/", me) != 0) {
+			NihError *nerr;
+			nerr = nih_error_get();
+			ERROR("call to cgmanager_move_pid_abs_sync(%s) failed: %s",
+					slist[i], nerr->message);
+			nih_free(nerr);
+			ret = false;
+			break;
+		}
+	}
+
+	if (cgm_needs_disconnect)
+		cgm_dbus_disconnect();
+
+	return ret;
+}
+
+struct chown_data {
+	const char *cgroup_path;
+	uid_t origuid;
+};
+
+static int do_chown_cgroup(const char *controller, const char *cgroup_path,
+		uid_t newuid)
+{
+	int sv[2] = {-1, -1}, optval = 1, ret = -1;
+	char buf[1];
+	struct pollfd fds;
+
+	if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
+		SYSERROR("Error creating socketpair");
+		goto out;
+	}
+	if (setsockopt(sv[1], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
+		SYSERROR("setsockopt failed");
+		goto out;
+	}
+	if (setsockopt(sv[0], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
+		SYSERROR("setsockopt failed");
+		goto out;
+	}
+	if ( cgmanager_chown_scm_sync(NULL, cgroup_manager, controller,
+				       cgroup_path, sv[1]) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("call to cgmanager_chown_scm_sync failed: %s", nerr->message);
+		nih_free(nerr);
+		goto out;
+	}
+	/* now send credentials */
+
+	fds.fd = sv[0];
+	fds.events = POLLIN;
+	fds.revents = 0;
+	if (poll(&fds, 1, -1) <= 0) {
+		ERROR("Error getting go-ahead from server: %s", strerror(errno));
+		goto out;
+	}
+	if (read(sv[0], &buf, 1) != 1) {
+		ERROR("Error getting reply from server over socketpair");
+		goto out;
+	}
+	if (send_creds(sv[0], getpid(), getuid(), getgid())) {
+		SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__);
+		goto out;
+	}
+	fds.fd = sv[0];
+	fds.events = POLLIN;
+	fds.revents = 0;
+	if (poll(&fds, 1, -1) <= 0) {
+		ERROR("Error getting go-ahead from server: %s", strerror(errno));
+		goto out;
+	}
+	if (read(sv[0], &buf, 1) != 1) {
+		ERROR("Error getting reply from server over socketpair");
+		goto out;
+	}
+	if (send_creds(sv[0], getpid(), newuid, 0)) {
+		SYSERROR("%s: Error sending pid over SCM_CREDENTIAL", __func__);
+		goto out;
+	}
+	fds.fd = sv[0];
+	fds.events = POLLIN;
+	fds.revents = 0;
+	if (poll(&fds, 1, -1) <= 0) {
+		ERROR("Error getting go-ahead from server: %s", strerror(errno));
+		goto out;
+	}
+	ret = read(sv[0], buf, 1);
+out:
+	close(sv[0]);
+	close(sv[1]);
+	if (ret == 1 && *buf == '1')
+		return 0;
+	return -1;
+}
+
+static int chown_cgroup_wrapper(void *data)
+{
+	struct chown_data *arg = data;
+	char **slist = subsystems;
+	int i, ret = -1;
+	uid_t destuid;
+
+	if (setresgid(0,0,0) < 0)
+		SYSERROR("Failed to setgid to 0");
+	if (setresuid(0,0,0) < 0)
+		SYSERROR("Failed to setuid to 0");
+	if (setgroups(0, NULL) < 0)
+		SYSERROR("Failed to clear groups");
+	cgm_dbus_disconnect();
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		return -1;
+	}
+	destuid = get_ns_uid(arg->origuid);
+
+	if (cgm_all_controllers_same)
+		slist = subsystems_inone;
+
+	for (i = 0; slist[i]; i++) {
+		if (do_chown_cgroup(slist[i], arg->cgroup_path, destuid) < 0) {
+			ERROR("Failed to chown %s:%s to container root",
+				slist[i], arg->cgroup_path);
+			goto fail;
+		}
+	}
+	ret = 0;
+fail:
+	cgm_dbus_disconnect();
+	return ret;
+}
+
+/* Internal helper.  Must be called with the cgmanager dbus socket open */
+static bool lxc_cgmanager_chmod(const char *controller,
+		const char *cgroup_path, const char *file, int mode)
+{
+	if (cgmanager_chmod_sync(NULL, cgroup_manager, controller,
+			cgroup_path, file, mode) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("call to cgmanager_chmod_sync failed: %s", nerr->message);
+		nih_free(nerr);
+		return false;
+	}
+	return true;
+}
+
+/* Internal helper.  Must be called with the cgmanager dbus socket open */
+static bool chown_cgroup(const char *cgroup_path, struct lxc_conf *conf)
+{
+	struct chown_data data;
+	char **slist = subsystems;
+	int i;
+
+	if (lxc_list_empty(&conf->id_map))
+		/* If there's no mapping then we don't need to chown */
+		return true;
+
+	data.cgroup_path = cgroup_path;
+	data.origuid = geteuid();
+
+	/* Unpriv users can't chown it themselves, so chown from
+	 * a child namespace mapping both our own and the target uid
+	 */
+	if (userns_exec_1(conf, chown_cgroup_wrapper, &data) < 0) {
+		ERROR("Error requesting cgroup chown in new namespace");
+		return false;
+	}
+
+	/*
+	 * Now chmod 775 the directory else the container cannot create cgroups.
+	 * This can't be done in the child namespace because it only group-owns
+	 * the cgroup
+	 */
+	if (cgm_all_controllers_same)
+		slist = subsystems_inone;
+
+	for (i = 0; slist[i]; i++) {
+		if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "", 0775))
+			return false;
+		if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "tasks", 0664))
+			return false;
+		if (!lxc_cgmanager_chmod(slist[i], cgroup_path, "cgroup.procs", 0664))
+			return false;
+	}
+
+	return true;
+}
+
+#define CG_REMOVE_RECURSIVE 1
+/* Internal helper.  Must be called with the cgmanager dbus socket open */
+static void cgm_remove_cgroup(const char *controller, const char *path)
+{
+	int existed;
+	if ( cgmanager_remove_sync(NULL, cgroup_manager, controller,
+				   path, CG_REMOVE_RECURSIVE, &existed) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("call to cgmanager_remove_sync failed: %s", nerr->message);
+		nih_free(nerr);
+		ERROR("Error removing %s:%s", controller, path);
+	}
+	if (existed == -1)
+		INFO("cgroup removal attempt: %s:%s did not exist", controller, path);
+}
+
+static void *cgm_init(const char *name)
+{
+	struct cgm_data *d;
+
+	d = malloc(sizeof(*d));
+	if (!d)
+		return NULL;
+
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		goto err1;
+	}
+
+	memset(d, 0, sizeof(*d));
+	d->name = strdup(name);
+	if (!d->name) {
+		cgm_dbus_disconnect();
+		goto err1;
+	}
+
+	d->cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
+
+	// cgm_create immediately gets called so keep the connection open
+	return d;
+
+err1:
+	free(d);
+	return NULL;
+}
+
+/* Called after a failed container startup */
+static void cgm_destroy(void *hdata, struct lxc_conf *conf)
+{
+	struct cgm_data *d = hdata;
+	char **slist = subsystems;
+	int i;
+
+	if (!d || !d->cgroup_path)
+		return;
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		return;
+	}
+
+	if (cgm_all_controllers_same)
+		slist = subsystems_inone;
+	for (i = 0; slist[i]; i++)
+		cgm_remove_cgroup(slist[i], d->cgroup_path);
+
+	free(d->name);
+	free(d->cgroup_path);
+	free(d);
+	cgm_dbus_disconnect();
+}
+
+/*
+ * remove all the cgroups created
+ * called internally with dbus connection open
+ */
+static inline void cleanup_cgroups(char *path)
+{
+	int i;
+	char **slist = subsystems;
+
+	if (cgm_all_controllers_same)
+		slist = subsystems_inone;
+	for (i = 0; slist[i]; i++)
+		cgm_remove_cgroup(slist[i], path);
+}
+
+static inline bool cgm_create(void *hdata)
+{
+	struct cgm_data *d = hdata;
+	char **slist = subsystems;
+	int i, index=0, baselen, ret;
+	int32_t existed;
+	char result[MAXPATHLEN], *tmp, *cgroup_path;
+
+	if (!d)
+		return false;
+// XXX we should send a hint to the cgmanager that when these
+// cgroups become empty they should be deleted.  Requires a cgmanager
+// extension
+
+	memset(result, 0, MAXPATHLEN);
+	tmp = lxc_string_replace("%n", d->name, d->cgroup_pattern);
+	if (!tmp)
+		goto bad;
+	if (strlen(tmp) >= MAXPATHLEN) {
+		free(tmp);
+		goto bad;
+	}
+	strcpy(result, tmp);
+	baselen = strlen(result);
+	free(tmp);
+	tmp = result;
+	while (*tmp == '/')
+		tmp++;
+again:
+	if (index == 100) { // turn this into a warn later
+		ERROR("cgroup error?  100 cgroups with this name already running");
+		goto bad;
+	}
+	if (index) {
+		ret = snprintf(result+baselen, MAXPATHLEN-baselen, "-%d", index);
+		if (ret < 0 || ret >= MAXPATHLEN-baselen)
+			goto bad;
+	}
+	existed = 0;
+
+	if (cgm_all_controllers_same)
+		slist = subsystems_inone;
+
+	for (i = 0; slist[i]; i++) {
+		if (!lxc_cgmanager_create(slist[i], tmp, &existed)) {
+			ERROR("Error creating cgroup %s:%s", slist[i], result);
+			cleanup_cgroups(tmp);
+			goto bad;
+		}
+		if (existed == 1)
+			goto next;
+	}
+	// success
+	cgroup_path = strdup(tmp);
+	if (!cgroup_path) {
+		cleanup_cgroups(tmp);
+		goto bad;
+	}
+	d->cgroup_path = cgroup_path;
+	cgm_dbus_disconnect();
+	return true;
+
+next:
+	index++;
+	goto again;
+bad:
+	cgm_dbus_disconnect();
+	return false;
+}
+
+/*
+ * Use the cgmanager to move a task into a cgroup for a particular
+ * hierarchy.
+ * All the subsystems in this hierarchy are co-mounted, so we only
+ * need to transition the task into one of the cgroups
+ *
+ * Internal helper, must be called with cgmanager dbus socket open
+ */
+static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
+		const char *cgroup_path, bool abs)
+{
+	int ret;
+
+	if (abs)
+		ret = cgmanager_move_pid_abs_sync(NULL, cgroup_manager,
+			controller, cgroup_path, pid);
+	else
+		ret = cgmanager_move_pid_sync(NULL, cgroup_manager,
+			controller, cgroup_path, pid);
+	if (ret != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		WARN("call to cgmanager_move_pid_%ssync failed: %s",
+			abs ? "abs_" : "", nerr->message);
+		nih_free(nerr);
+		return false;
+	}
+	return true;
+}
+
+static inline bool cgm_enter(void *hdata, pid_t pid)
+{
+	struct cgm_data *d = hdata;
+	char **slist = subsystems;
+	bool ret = false;
+	int i;
+
+	if (!d || !d->cgroup_path)
+		return false;
+
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		return false;
+	}
+
+	if (cgm_all_controllers_same)
+		slist = subsystems_inone;
+
+	for (i = 0; slist[i]; i++) {
+		if (!lxc_cgmanager_enter(pid, slist[i], d->cgroup_path, false))
+			goto out;
+	}
+	ret = true;
+out:
+	cgm_dbus_disconnect();
+	return ret;
+}
+
+static const char *cgm_get_cgroup(void *hdata, const char *subsystem)
+{
+	struct cgm_data *d = hdata;
+
+	if (!d || !d->cgroup_path)
+		return NULL;
+	return d->cgroup_path;
+}
+
+static const char *cgm_canonical_path(void *hdata)
+{
+	struct cgm_data *d = hdata;
+
+	if (!d || !d->cgroup_path)
+		return NULL;
+	return d->cgroup_path;
+}
+
+#if HAVE_CGMANAGER_GET_PID_CGROUP_ABS_SYNC
+static inline bool abs_cgroup_supported(void) {
+	return api_version >= CGM_SUPPORTS_GET_ABS;
+}
+#else
+static inline bool abs_cgroup_supported(void) {
+	return false;
+}
+#define cgmanager_get_pid_cgroup_abs_sync(...) -1
+#endif
+
+static char *try_get_abs_cgroup(const char *name, const char *lxcpath,
+		const char *controller)
+{
+	char *cgroup = NULL;
+
+	if (abs_cgroup_supported()) {
+		/* get the container init pid and ask for its abs cgroup */
+		pid_t pid = lxc_cmd_get_init_pid(name, lxcpath);
+		if (pid < 0)
+			return NULL;
+		if (cgmanager_get_pid_cgroup_abs_sync(NULL, cgroup_manager,
+				controller, pid, &cgroup) != 0) {
+			cgroup = NULL;
+			NihError *nerr;
+			nerr = nih_error_get();
+			nih_free(nerr);
+		} else
+			prune_init_scope(cgroup);
+		return cgroup;
+	}
+
+	/* use the command interface to look for the cgroup */
+	return lxc_cmd_get_cgroup_path(name, lxcpath, controller);
+}
+
+/*
+ * nrtasks is called by the utmp helper by the container monitor.
+ * cgmanager socket was closed after cgroup setup was complete, so we need
+ * to reopen here.
+ *
+ * Return -1 on error.
+ */
+static int cgm_get_nrtasks(void *hdata)
+{
+	struct cgm_data *d = hdata;
+	int32_t *pids;
+	size_t pids_len;
+
+	if (!d || !d->cgroup_path)
+		return -1;
+
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		return -1;
+	}
+	if (cgmanager_get_tasks_sync(NULL, cgroup_manager, subsystems[0],
+				     d->cgroup_path, &pids, &pids_len) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("call to cgmanager_get_tasks_sync failed: %s", nerr->message);
+		nih_free(nerr);
+		pids_len = -1;
+		goto out;
+	}
+	nih_free(pids);
+out:
+	cgm_dbus_disconnect();
+	return pids_len;
+}
+
+#if HAVE_CGMANAGER_LIST_CONTROLLERS
+static bool lxc_list_controllers(char ***list)
+{
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		return false;
+	}
+	if (cgmanager_list_controllers_sync(NULL, cgroup_manager, list) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("call to cgmanager_list_controllers_sync failed: %s", nerr->message);
+		nih_free(nerr);
+		cgm_dbus_disconnect();
+		return false;
+	}
+
+	cgm_dbus_disconnect();
+	return true;
+}
+#else
+static bool lxc_list_controllers(char ***list)
+{
+	return false;
+}
+#endif
+
+static inline void free_abs_cgroup(char *cgroup)
+{
+	if (!cgroup)
+		return;
+	if (abs_cgroup_supported())
+		nih_free(cgroup);
+	else
+		free(cgroup);
+}
+
+static void do_cgm_get(const char *name, const char *lxcpath, const char *filename, int outp, bool sendvalue)
+{
+	char *controller, *key, *cgroup = NULL, *cglast;
+	int len = -1;
+	int ret;
+	nih_local char *result = NULL;
+
+	controller = alloca(strlen(filename)+1);
+	strcpy(controller, filename);
+	key = strchr(controller, '.');
+	if (!key) {
+		ret = write(outp, &len, sizeof(len));
+		if (ret != sizeof(len))
+			WARN("Failed to warn cgm_get of error; parent may hang");
+		exit(1);
+	}
+	*key = '\0';
+
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		ret = write(outp, &len, sizeof(len));
+		if (ret != sizeof(len))
+			WARN("Failed to warn cgm_get of error; parent may hang");
+		exit(1);
+	}
+	cgroup = try_get_abs_cgroup(name, lxcpath, controller);
+	if (!cgroup) {
+		cgm_dbus_disconnect();
+		ret = write(outp, &len, sizeof(len));
+		if (ret != sizeof(len))
+			WARN("Failed to warn cgm_get of error; parent may hang");
+		exit(1);
+	}
+	cglast = strrchr(cgroup, '/');
+	if (!cglast) {
+		cgm_dbus_disconnect();
+		free_abs_cgroup(cgroup);
+		ret = write(outp, &len, sizeof(len));
+		if (ret != sizeof(len))
+			WARN("Failed to warn cgm_get of error; parent may hang");
+		exit(1);
+	}
+	*cglast = '\0';
+	if (!lxc_cgmanager_enter(getpid(), controller, cgroup, abs_cgroup_supported())) {
+		WARN("Failed to enter container cgroup %s:%s", controller, cgroup);
+		ret = write(outp, &len, sizeof(len));
+		if (ret != sizeof(len))
+			WARN("Failed to warn cgm_get of error; parent may hang");
+		cgm_dbus_disconnect();
+		free_abs_cgroup(cgroup);
+		exit(1);
+	}
+	if (cgmanager_get_value_sync(NULL, cgroup_manager, controller, cglast+1, filename, &result) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		nih_free(nerr);
+		free_abs_cgroup(cgroup);
+		cgm_dbus_disconnect();
+		ret = write(outp, &len, sizeof(len));
+		if (ret != sizeof(len))
+			WARN("Failed to warn cgm_get of error; parent may hang");
+		exit(1);
+	}
+	free_abs_cgroup(cgroup);
+	cgm_dbus_disconnect();
+	len = strlen(result);
+	ret = write(outp, &len, sizeof(len));
+	if (ret != sizeof(len)) {
+		WARN("Failed to send length to parent");
+		exit(1);
+	}
+	if (!len || !sendvalue) {
+		exit(0);
+	}
+	ret = write(outp, result, len);
+	if (ret < 0)
+		exit(1);
+	exit(0);
+}
+
+/* cgm_get is called to get container cgroup settings, not during startup */
+static int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+{
+	pid_t pid;
+	int p[2], ret, newlen, readlen;
+
+	if (pipe(p) < 0)
+		return -1;
+	if ((pid = fork()) < 0) {
+		close(p[0]);
+		close(p[1]);
+		return -1;
+	}
+	if (!pid) // do_cgm_get exits
+		do_cgm_get(name, lxcpath, filename, p[1], len && value);
+	close(p[1]);
+	ret = read(p[0], &newlen, sizeof(newlen));
+	if (ret != sizeof(newlen)) {
+		close(p[0]);
+		ret = -1;
+		goto out;
+	}
+	if (!len || !value) {
+		close(p[0]);
+		ret = newlen;
+		goto out;
+	}
+	memset(value, 0, len);
+	if (newlen < 0) { // child is reporting an error
+		close(p[0]);
+		ret = -1;
+		goto out;
+	}
+	if (newlen == 0) { // empty read
+		close(p[0]);
+		ret = 0;
+		goto out;
+	}
+	readlen = newlen > len ? len : newlen;
+	ret = read(p[0], value, readlen);
+	close(p[0]);
+	if (ret != readlen) {
+		ret = -1;
+		goto out;
+	}
+	if (newlen >= len) {
+		value[len-1] = '\0';
+		newlen = len-1;
+	} else if (newlen+1 < len) {
+		// cgmanager doesn't add eol to last entry
+		value[newlen++] = '\n';
+		value[newlen] = '\0';
+	}
+	ret = newlen;
+out:
+	if (wait_for_pid(pid))
+		WARN("do_cgm_get exited with error");
+	return ret;
+}
+
+static void do_cgm_set(const char *name, const char *lxcpath, const char *filename, const char *value, int outp)
+{
+	char *controller, *key, *cgroup = NULL;
+	int retval = 0;  // value we are sending to the parent over outp
+	int ret;
+	char *cglast;
+
+	controller = alloca(strlen(filename)+1);
+	strcpy(controller, filename);
+	key = strchr(controller, '.');
+	if (!key) {
+		ret = write(outp, &retval, sizeof(retval));
+		if (ret != sizeof(retval))
+			WARN("Failed to warn cgm_set of error; parent may hang");
+		exit(1);
+	}
+	*key = '\0';
+
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		ret = write(outp, &retval, sizeof(retval));
+		if (ret != sizeof(retval))
+			WARN("Failed to warn cgm_set of error; parent may hang");
+		exit(1);
+	}
+	cgroup = try_get_abs_cgroup(name, lxcpath, controller);
+	if (!cgroup) {
+		cgm_dbus_disconnect();
+		ret = write(outp, &retval, sizeof(retval));
+		if (ret != sizeof(retval))
+			WARN("Failed to warn cgm_set of error; parent may hang");
+		exit(1);
+	}
+	cglast = strrchr(cgroup, '/');
+	if (!cglast) {
+		cgm_dbus_disconnect();
+		free_abs_cgroup(cgroup);
+		ret = write(outp, &retval, sizeof(retval));
+		if (ret != sizeof(retval))
+			WARN("Failed to warn cgm_set of error; parent may hang");
+		exit(1);
+	}
+	*cglast = '\0';
+	if (!lxc_cgmanager_enter(getpid(), controller, cgroup, abs_cgroup_supported())) {
+		ERROR("Failed to enter container cgroup %s:%s", controller, cgroup);
+		ret = write(outp, &retval, sizeof(retval));
+		if (ret != sizeof(retval))
+			WARN("Failed to warn cgm_set of error; parent may hang");
+		cgm_dbus_disconnect();
+		free_abs_cgroup(cgroup);
+		exit(1);
+	}
+	if (cgmanager_set_value_sync(NULL, cgroup_manager, controller, cglast+1, filename, value) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("Error setting cgroup value %s for %s:%s", filename, controller, cgroup);
+		ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
+		nih_free(nerr);
+		free_abs_cgroup(cgroup);
+		cgm_dbus_disconnect();
+		ret = write(outp, &retval, sizeof(retval));
+		if (ret != sizeof(retval))
+			WARN("Failed to warn cgm_set of error; parent may hang");
+		exit(1);
+	}
+	free_abs_cgroup(cgroup);
+	cgm_dbus_disconnect();
+	/* tell parent that we are done */
+	retval = 1;
+	ret = write(outp, &retval, sizeof(retval));
+	if (ret != sizeof(retval)) {
+		exit(1);
+	}
+	exit(0);
+}
+
+/* cgm_set is called to change cgroup settings, not during startup */
+static int cgm_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+{
+	pid_t pid;
+	int p[2], ret, v;
+
+	if (pipe(p) < 0)
+		return -1;
+	if ((pid = fork()) < 0) {
+		close(p[1]);
+		close(p[0]);
+		return -1;
+	}
+	if (!pid) // do_cgm_set exits
+		do_cgm_set(name, lxcpath, filename, value, p[1]);
+	close(p[1]);
+	ret = read(p[0], &v, sizeof(v));
+	close(p[0]);
+	if (wait_for_pid(pid))
+		WARN("do_cgm_set exited with error");
+	if (ret != sizeof(v) || !v)
+		return -1;
+	return 0;
+}
+
+static void free_subsystems(void)
+{
+	int i;
+
+	for (i = 0; i < nr_subsystems; i++)
+		free(subsystems[i]);
+	free(subsystems);
+	subsystems = NULL;
+	nr_subsystems = 0;
+}
+
+static void cull_user_controllers(void)
+{
+	int i, j;
+
+	for (i = 0;  i < nr_subsystems; i++) {
+		if (strncmp(subsystems[i], "name=", 5) != 0)
+			continue;
+		for (j = i;  j < nr_subsystems-1; j++)
+			subsystems[j] = subsystems[j+1];
+		nr_subsystems--;
+	}
+}
+
+/*
+ * return true if inword is in the comma-delimited list cgroup_use
+ */
+static bool in_comma_list(const char *inword, const char *cgroup_use)
+{
+	char *e;
+	size_t inlen = strlen(inword), len;
+
+	do {
+		e = strchr(cgroup_use, ',');
+		len = e ? e - cgroup_use : strlen(cgroup_use);
+		if (len == inlen && strncmp(inword, cgroup_use, len) == 0)
+			return true;
+		cgroup_use = e + 1;
+	} while (e);
+
+	return false;
+}
+
+/*
+ * inlist is a comma-delimited list of cgroups;  so is checklist.  Return
+ * true if any member of inlist is in checklist.
+ */
+static bool any_in_comma_list(const char *inlist, const char *checklist)
+{
+	char *tmp = alloca(strlen(inlist) + 1), *tok, *saveptr = NULL;
+
+	strcpy(tmp, inlist);
+	for (tok = strtok_r(tmp, ",", &saveptr); tok; tok = strtok_r(NULL, ",", &saveptr)) {
+		if (in_comma_list(tok, checklist))
+			return true;
+	}
+
+	return false;
+}
+
+static bool in_subsystem_list(const char *c)
+{
+	int i;
+
+	for (i = 0; i < nr_subsystems; i++) {
+		if (strcmp(c, subsystems[i]) == 0)
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * If /etc/lxc/lxc.conf specifies lxc.cgroup.use = "freezer,memory",
+ * then clear out any other subsystems, and make sure that freezer
+ * and memory are both enabled
+ */
+static bool verify_and_prune(const char *cgroup_use)
+{
+	const char *p;
+	char *e;
+	int i, j;
+
+	for (p = cgroup_use; p && *p; p = e + 1) {
+		e = strchr(p, ',');
+		if (e)
+			*e = '\0';
+
+		if (!in_subsystem_list(p)) {
+			ERROR("Controller %s required by lxc.cgroup.use but not available\n", p);
+			return false;
+		}
+
+		if (e)
+			*e = ',';
+		if (!e)
+			break;
+	}
+
+	for (i = 0; i < nr_subsystems;) {
+		if (in_comma_list(subsystems[i], cgroup_use)) {
+			i++;
+			continue;
+		}
+		free(subsystems[i]);
+		for (j = i;  j < nr_subsystems-1; j++)
+			subsystems[j] = subsystems[j+1];
+		subsystems[nr_subsystems-1] = NULL;
+		nr_subsystems--;
+	}
+
+	return true;
+}
+
+static void drop_subsystem(int which)
+{
+	int i;
+
+	if (which < 0 || which >= nr_subsystems) {
+		ERROR("code error: dropping invalid subsystem index\n");
+		exit(1);
+	}
+
+	free(subsystems[which]);
+	/* note - we have nr_subsystems+1 entries, last one a NULL */
+	for (i = which; i < nr_subsystems; i++)
+		subsystems[i] = subsystems[i+1];
+	nr_subsystems -= 1;
+}
+
+/*
+ * Check whether we can create the cgroups we would want
+ */
+static bool subsys_is_writeable(const char *controller, const char *probe)
+{
+	int32_t existed;
+	bool ret = true;
+
+	if ( cgmanager_create_sync(NULL, cgroup_manager, controller,
+				       probe, &existed) != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("call to cgmanager_create_sync failed: %s", nerr->message);
+		nih_free(nerr);
+		ERROR("Failed to create %s:%s", controller, probe);
+		ret = false;
+	}
+
+	return ret;
+}
+
+static char *get_last_controller_in_list(char *list)
+{
+	char *p;
+
+	while ((p = strchr(list, ',')) != NULL)
+		list = p + 1;
+
+	return list;
+}
+
+/*
+ * Make sure that all the controllers are writeable.
+ * If any are not, then
+ *   - if they are listed in lxc.cgroup.use, refuse to start
+ *   - else if they are crucial subsystems, refuse to start
+ *   - else warn and do not use them
+ */
+static bool verify_final_subsystems(const char *cgroup_use)
+{
+	int i;
+	bool dropped_any = false;
+	bool bret = false;
+	const char *cgroup_pattern;
+	char tmpnam[50], *probe;
+
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		return false;
+	}
+
+	cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
+	i = snprintf(tmpnam, 50, "lxcprobe-%d", getpid());
+	if (i < 0 || i >= 50) {
+		ERROR("Attack - format string modified?");
+		return false;
+	}
+	probe = lxc_string_replace("%n", tmpnam, cgroup_pattern);
+	if (!probe)
+		goto out;
+
+	i = 0;
+	while (i < nr_subsystems) {
+		char *p = get_last_controller_in_list(subsystems[i]);
+
+		if (!subsys_is_writeable(p, probe)) {
+			if (is_crucial_cgroup_subsystem(p)) {
+				ERROR("Cannot write to crucial subsystem %s\n",
+					subsystems[i]);
+				goto out;
+			}
+			if (cgroup_use && any_in_comma_list(subsystems[i], cgroup_use)) {
+				ERROR("Cannot write to subsystem %s which is requested in lxc.cgroup.use\n",
+					subsystems[i]);
+				goto out;
+			}
+			WARN("Cannot write to subsystem %s, continuing with out it\n",
+				subsystems[i]);
+			dropped_any = true;
+			drop_subsystem(i);
+		} else {
+			cgm_remove_cgroup(subsystems[i], probe);
+			i++;
+		}
+	}
+
+	if (dropped_any)
+		cgm_all_controllers_same = false;
+	bret = true;
+
+out:
+	free(probe);
+	cgm_dbus_disconnect();
+	return bret;
+}
+
+static bool collect_subsystems(void)
+{
+	char *line = NULL;
+	nih_local char **cgm_subsys_list = NULL;
+	size_t sz = 0;
+	FILE *f = NULL;
+
+	if (subsystems) // already initialized
+		return true;
+
+	subsystems_inone = malloc(2 * sizeof(char *));
+	if (!subsystems_inone)
+		return false;
+	subsystems_inone[0] = "all";
+	subsystems_inone[1] = NULL;
+
+	if (lxc_list_controllers(&cgm_subsys_list)) {
+		while (cgm_subsys_list[nr_subsystems]) {
+			char **tmp = NIH_MUST( realloc(subsystems,
+						(nr_subsystems+2)*sizeof(char *)) );
+			tmp[nr_subsystems] = NIH_MUST(
+					strdup(cgm_subsys_list[nr_subsystems++]) );
+			subsystems = tmp;
+		}
+		if (nr_subsystems)
+			subsystems[nr_subsystems] = NULL;
+		goto collected;
+	}
+
+	INFO("cgmanager_list_controllers failed, falling back to /proc/self/cgroups");
+	f = fopen_cloexec("/proc/self/cgroup", "r");
+	if (!f) {
+		f = fopen_cloexec("/proc/1/cgroup", "r");
+		if (!f)
+			return false;
+	}
+	while (getline(&line, &sz, f) != -1) {
+		/* file format: hierarchy:subsystems:group,
+		 * with multiple subsystems being ,-separated */
+		char *slist, *end, *p, *saveptr = NULL, **tmp;
+
+		if (!line[0])
+			continue;
+
+		slist = strchr(line, ':');
+		if (!slist)
+			continue;
+		slist++;
+		end = strchr(slist, ':');
+		if (!end)
+			continue;
+		*end = '\0';
+
+		for (p = strtok_r(slist, ",", &saveptr);
+				p;
+				p = strtok_r(NULL, ",", &saveptr)) {
+			tmp = realloc(subsystems, (nr_subsystems+2)*sizeof(char *));
+			if (!tmp)
+				goto out_free;
+
+			subsystems = tmp;
+			tmp[nr_subsystems] = strdup(p);
+			tmp[nr_subsystems+1] = NULL;
+			if (!tmp[nr_subsystems])
+				goto out_free;
+			nr_subsystems++;
+		}
+	}
+	fclose(f);
+	f = NULL;
+
+	free(line);
+	line = NULL;
+
+collected:
+	if (!nr_subsystems) {
+		ERROR("No cgroup subsystems found");
+		return false;
+	}
+
+	/* make sure that cgroup.use can be and is honored */
+	const char *cgroup_use = lxc_global_config_value("lxc.cgroup.use");
+	if (!cgroup_use && errno != 0)
+		goto final_verify;
+	if (cgroup_use) {
+		if (!verify_and_prune(cgroup_use)) {
+			free_subsystems();
+			return false;
+		}
+		subsystems_inone[0] = NIH_MUST( strdup(cgroup_use) );
+		cgm_all_controllers_same = false;
+	}
+
+final_verify:
+	return verify_final_subsystems(cgroup_use);
+
+out_free:
+	free(line);
+	if (f)
+		fclose(f);
+	free_subsystems();
+	return false;
+}
+
+/*
+ * called during cgroup.c:cgroup_ops_init(), at startup.  No threads.
+ * We check whether we can talk to cgmanager, escape to root cgroup if
+ * we are root, then close the connection.
+ */
+struct cgroup_ops *cgm_ops_init(void)
+{
+	check_supports_multiple_controllers(-1);
+	if (!collect_subsystems())
+		return NULL;
+
+	if (api_version < CGM_SUPPORTS_MULT_CONTROLLERS)
+		cgm_all_controllers_same = false;
+
+	// if root, try to escape to root cgroup
+	if (geteuid() == 0 && !cgm_escape(NULL)) {
+		free_subsystems();
+		return NULL;
+	}
+
+	return &cgmanager_ops;
+}
+
+/* unfreeze is called by the command api after killing a container.  */
+static bool cgm_unfreeze(void *hdata)
+{
+	struct cgm_data *d = hdata;
+	bool ret = true;
+
+	if (!d || !d->cgroup_path)
+		return false;
+
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		return false;
+	}
+	if (cgmanager_set_value_sync(NULL, cgroup_manager, "freezer", d->cgroup_path,
+			"freezer.state", "THAWED") != 0) {
+		NihError *nerr;
+		nerr = nih_error_get();
+		ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
+		nih_free(nerr);
+		ERROR("Error unfreezing %s", d->cgroup_path);
+		ret = false;
+	}
+	cgm_dbus_disconnect();
+	return ret;
+}
+
+static bool cgm_setup_limits(void *hdata, struct lxc_list *cgroup_settings, bool do_devices)
+{
+	struct cgm_data *d = hdata;
+	struct lxc_list *iterator, *sorted_cgroup_settings, *next;
+	struct lxc_cgroup *cg;
+	bool ret = false;
+
+	if (lxc_list_empty(cgroup_settings))
+		return true;
+
+	if (!d || !d->cgroup_path)
+		return false;
+
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		return false;
+	}
+
+	sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
+	if (!sorted_cgroup_settings) {
+		return false;
+	}
+
+	lxc_list_for_each(iterator, sorted_cgroup_settings) {
+		char controller[100], *p;
+		cg = iterator->elem;
+		if (do_devices != !strncmp("devices", cg->subsystem, 7))
+			continue;
+		if (strlen(cg->subsystem) > 100) // i smell a rat
+			goto out;
+		strcpy(controller, cg->subsystem);
+		p = strchr(controller, '.');
+		if (p)
+			*p = '\0';
+		if (cgmanager_set_value_sync(NULL, cgroup_manager, controller,
+					 d->cgroup_path, cg->subsystem, cg->value) != 0) {
+			NihError *nerr;
+			nerr = nih_error_get();
+			if (do_devices) {
+				WARN("call to cgmanager_set_value_sync failed: %s", nerr->message);
+				nih_free(nerr);
+				WARN("Error setting cgroup %s:%s limit type %s", controller,
+					d->cgroup_path, cg->subsystem);
+				continue;
+			}
+
+			ERROR("call to cgmanager_set_value_sync failed: %s", nerr->message);
+			nih_free(nerr);
+			ERROR("Error setting cgroup %s:%s limit type %s", controller,
+				d->cgroup_path, cg->subsystem);
+			goto out;
+		}
+
+		DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
+	}
+
+	ret = true;
+	INFO("cgroup limits have been setup");
+out:
+	lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
+		lxc_list_del(iterator);
+		free(iterator);
+	}
+	free(sorted_cgroup_settings);
+	cgm_dbus_disconnect();
+	return ret;
+}
+
+static bool cgm_chown(void *hdata, struct lxc_conf *conf)
+{
+	struct cgm_data *d = hdata;
+
+	if (!d || !d->cgroup_path)
+		return false;
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		return false;
+	}
+	if (!chown_cgroup(d->cgroup_path, conf))
+		WARN("Failed to chown %s to container root", d->cgroup_path);
+	cgm_dbus_disconnect();
+	return true;
+}
+
+/*
+ * TODO: this should be re-written to use the get_config_item("lxc.id_map")
+ * cmd api instead of getting the idmap from c->lxc_conf.  The reason is
+ * that the id_maps may be different if the container was started with a
+ * -f or -s argument.
+ * The reason I'm punting on that is because we'll need to parse the
+ * idmap results.
+ */
+static bool cgm_attach(const char *name, const char *lxcpath, pid_t pid)
+{
+	bool pass = true;
+	char *cgroup = NULL;
+	char **slist = subsystems;
+	int i;
+
+	if (!cgm_dbus_connect()) {
+		ERROR("Error connecting to cgroup manager");
+		return false;
+	}
+
+	for (i = 0; slist[i]; i++) {
+		cgroup = try_get_abs_cgroup(name, lxcpath, slist[i]);
+		if (!cgroup) {
+			ERROR("Failed to get cgroup for controller %s", slist[i]);
+			cgm_dbus_disconnect();
+			return false;
+		}
+
+		if (!lxc_cgmanager_enter(pid, slist[i], cgroup, abs_cgroup_supported())) {
+			pass = false;
+			break;
+		}
+
+	}
+	cgm_dbus_disconnect();
+	if (!pass)
+		ERROR("Failed to enter group %s", cgroup);
+
+	free_abs_cgroup(cgroup);
+	return pass;
+}
+
+static bool cgm_bind_dir(const char *root, const char *dirname)
+{
+	nih_local char *cgpath = NULL;
+
+	/* /sys should have been mounted by now */
+	cgpath = NIH_MUST( nih_strdup(NULL, root) );
+	NIH_MUST( nih_strcat(&cgpath, NULL, "/sys/fs/cgroup") );
+
+	if (!dir_exists(cgpath)) {
+		ERROR("%s does not exist", cgpath);
+		return false;
+	}
+
+	/* mount a tmpfs there so we can create subdirs */
+	if (safe_mount("cgroup", cgpath, "tmpfs", 0, "size=10000,mode=755", root)) {
+		SYSERROR("Failed to mount tmpfs at %s", cgpath);
+		return false;
+	}
+	NIH_MUST( nih_strcat(&cgpath, NULL, "/cgmanager") );
+
+	if (mkdir(cgpath, 0755) < 0) {
+		SYSERROR("Failed to create %s", cgpath);
+		return false;
+	}
+
+	if (safe_mount(dirname, cgpath, "none", MS_BIND, 0, root)) {
+		SYSERROR("Failed to bind mount %s to %s", dirname, cgpath);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * cgm_mount_cgroup:
+ * If /sys/fs/cgroup/cgmanager.lower/ exists, bind mount that to
+ * /sys/fs/cgroup/cgmanager/ in the container.
+ * Otherwise, if /sys/fs/cgroup/cgmanager exists, bind mount that.
+ * Else do nothing
+ */
+#define CGMANAGER_LOWER_SOCK "/sys/fs/cgroup/cgmanager.lower"
+#define CGMANAGER_UPPER_SOCK "/sys/fs/cgroup/cgmanager"
+static bool cgm_mount_cgroup(void *hdata, const char *root, int type)
+{
+	if (dir_exists(CGMANAGER_LOWER_SOCK))
+		return cgm_bind_dir(root, CGMANAGER_LOWER_SOCK);
+	if (dir_exists(CGMANAGER_UPPER_SOCK))
+		return cgm_bind_dir(root, CGMANAGER_UPPER_SOCK);
+	// Host doesn't have cgmanager running?  Then how did we get here?
+	return false;
+}
+
+static struct cgroup_ops cgmanager_ops = {
+	.init = cgm_init,
+	.destroy = cgm_destroy,
+	.create = cgm_create,
+	.enter = cgm_enter,
+	.create_legacy = NULL,
+	.get_cgroup = cgm_get_cgroup,
+	.canonical_path = cgm_canonical_path,
+	.escape = cgm_escape,
+	.get = cgm_get,
+	.set = cgm_set,
+	.unfreeze = cgm_unfreeze,
+	.setup_limits = cgm_setup_limits,
+	.name = "cgmanager",
+	.chown = cgm_chown,
+	.attach = cgm_attach,
+	.mount_cgroup = cgm_mount_cgroup,
+	.nrtasks = cgm_get_nrtasks,
+	.disconnect = NULL,
+	.driver = CGMANAGER,
+};
+#endif
diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c
new file mode 100644
index 0000000..91ef359
--- /dev/null
+++ b/src/lxc/cgroups/cgroup.c
@@ -0,0 +1,245 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "cgroup.h"
+#include "conf.h"
+#include "log.h"
+#include "start.h"
+
+lxc_log_define(lxc_cgroup, lxc);
+
+static struct cgroup_ops *ops = NULL;
+
+extern struct cgroup_ops *cgfs_ops_init(void);
+extern struct cgroup_ops *cgfsng_ops_init(void);
+extern struct cgroup_ops *cgm_ops_init(void);
+
+__attribute__((constructor))
+void cgroup_ops_init(void)
+{
+	if (ops) {
+		INFO("cgroup driver %s", ops->name);
+		return;
+	}
+
+	DEBUG("cgroup_init");
+	#if HAVE_CGMANAGER
+	ops = cgm_ops_init();
+	#endif
+	if (!ops)
+		ops = cgfsng_ops_init();
+	if (!ops)
+		ops = cgfs_ops_init();
+	if (ops)
+		INFO("Initialized cgroup driver %s", ops->name);
+}
+
+bool cgroup_init(struct lxc_handler *handler)
+{
+	if (handler->cgroup_data) {
+		ERROR("cgroup_init called on already inited handler");
+		return true;
+	}
+
+	if (ops) {
+		INFO("cgroup driver %s initing for %s", ops->name, handler->name);
+		handler->cgroup_data = ops->init(handler->name);
+	}
+	return handler->cgroup_data != NULL;
+}
+
+void cgroup_destroy(struct lxc_handler *handler)
+{
+	if (ops) {
+		ops->destroy(handler->cgroup_data, handler->conf);
+		handler->cgroup_data = NULL;
+	}
+}
+
+/* Create the container cgroups for all requested controllers */
+bool cgroup_create(struct lxc_handler *handler)
+{
+	if (ops)
+		return ops->create(handler->cgroup_data);
+	return false;
+}
+
+/*
+ * Enter the container init into its new cgroups for all
+ * requested controllers
+ */
+bool cgroup_enter(struct lxc_handler *handler)
+{
+	if (ops)
+		return ops->enter(handler->cgroup_data, handler->pid);
+	return false;
+}
+
+bool cgroup_create_legacy(struct lxc_handler *handler)
+{
+	if (ops && ops->create_legacy)
+		return ops->create_legacy(handler->cgroup_data, handler->pid);
+	return true;
+}
+
+const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem)
+{
+	if (ops)
+		return ops->get_cgroup(handler->cgroup_data, subsystem);
+	return NULL;
+}
+
+bool cgroup_escape(struct lxc_handler *handler)
+{
+	if (ops)
+		return ops->escape(handler->cgroup_data);
+	return false;
+}
+
+const char *cgroup_canonical_path(struct lxc_handler *handler)
+{
+	if (geteuid()) {
+		WARN("cgroup_canonical_path only makes sense for privileged containers.\n");
+		return NULL;
+	}
+
+	if (ops)
+		return ops->canonical_path(handler->cgroup_data);
+
+	return NULL;
+}
+
+bool cgroup_unfreeze(struct lxc_handler *handler)
+{
+	if (ops)
+		return ops->unfreeze(handler->cgroup_data);
+	return false;
+}
+
+bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
+{
+	if (ops)
+		return ops->setup_limits(handler->cgroup_data,
+					 &handler->conf->cgroup, with_devices);
+	return false;
+}
+
+bool cgroup_chown(struct lxc_handler *handler)
+{
+	if (ops && ops->chown)
+		return ops->chown(handler->cgroup_data, handler->conf);
+	return true;
+}
+
+bool cgroup_mount(const char *root, struct lxc_handler *handler, int type)
+{
+	if (ops) {
+		return ops->mount_cgroup(handler->cgroup_data, root, type);
+	}
+	return false;
+}
+
+int cgroup_nrtasks(struct lxc_handler *handler)
+{
+	if (ops) {
+		if (ops->nrtasks)
+			return ops->nrtasks(handler->cgroup_data);
+		else
+			WARN("CGROUP driver %s doesn't implement nrtasks", ops->name);
+	}
+	return -1;
+}
+
+bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid)
+{
+	if (ops)
+		return ops->attach(name, lxcpath, pid);
+	return false;
+}
+
+int lxc_cgroup_set(const char *filename, const char *value, const char *name, const char *lxcpath)
+{
+	if (ops)
+		return ops->set(filename, value, name, lxcpath);
+	return -1;
+}
+
+int lxc_cgroup_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
+{
+	if (ops)
+		return ops->get(filename, value, len, name, lxcpath);
+	return -1;
+}
+
+void cgroup_disconnect(void)
+{
+	if (ops && ops->disconnect)
+		ops->disconnect();
+}
+
+cgroup_driver_t cgroup_driver(void)
+{
+	return ops->driver;
+}
+
+#define INIT_SCOPE "/init.scope"
+void prune_init_scope(char *cg)
+{
+	char *point;
+
+	if (!cg)
+		return;
+
+	point = cg + strlen(cg) - strlen(INIT_SCOPE);
+	if (point < cg)
+		return;
+	if (strcmp(point, INIT_SCOPE) == 0) {
+		if (point == cg)
+			*(point+1) = '\0';
+		else
+			*point = '\0';
+	}
+}
+
+/*
+ * Return true if this is a subsystem which we cannot do
+ * without.
+ *
+ * systemd is questionable here.  The way callers currently
+ * use this, if systemd is not mounted then it will be ignored.
+ * But if systemd is mounted, then it must be setup so that lxc
+ * can create cgroups in it, else containers will fail.
+ */
+bool is_crucial_cgroup_subsystem(const char *s)
+{
+	if (strcmp(s, "systemd") == 0)
+		return true;
+	if (strcmp(s, "name=systemd") == 0)
+		return true;
+	if (strcmp(s, "freezer") == 0)
+		return true;
+	return false;
+}
diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h
new file mode 100644
index 0000000..e56a115
--- /dev/null
+++ b/src/lxc/cgroups/cgroup.h
@@ -0,0 +1,89 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_CGROUP_H
+#define __LXC_CGROUP_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+struct lxc_handler;
+struct lxc_conf;
+struct lxc_list;
+
+typedef enum {
+	CGFS,
+	CGMANAGER,
+	CGFSNG,
+} cgroup_driver_t;
+
+struct cgroup_ops {
+	const char *name;
+
+	void *(*init)(const char *name);
+	void (*destroy)(void *hdata, struct lxc_conf *conf);
+	bool (*create)(void *hdata);
+	bool (*enter)(void *hdata, pid_t pid);
+	bool (*create_legacy)(void *hdata, pid_t pid);
+	const char *(*get_cgroup)(void *hdata, const char *subsystem);
+	const char *(*canonical_path)(void *hdata);
+	bool (*escape)();
+	int (*set)(const char *filename, const char *value, const char *name, const char *lxcpath);
+	int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
+	bool (*unfreeze)(void *hdata);
+	bool (*setup_limits)(void *hdata, struct lxc_list *cgroup_conf, bool with_devices);
+	bool (*chown)(void *hdata, struct lxc_conf *conf);
+	bool (*attach)(const char *name, const char *lxcpath, pid_t pid);
+	bool (*mount_cgroup)(void *hdata, const char *root, int type);
+	int (*nrtasks)(void *hdata);
+	void (*disconnect)(void);
+	cgroup_driver_t driver;
+};
+
+extern bool cgroup_attach(const char *name, const char *lxcpath, pid_t pid);
+extern bool cgroup_mount(const char *root, struct lxc_handler *handler, int type);
+extern void cgroup_destroy(struct lxc_handler *handler);
+extern bool cgroup_init(struct lxc_handler *handler);
+extern bool cgroup_create(struct lxc_handler *handler);
+extern bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices);
+extern bool cgroup_chown(struct lxc_handler *handler);
+extern bool cgroup_enter(struct lxc_handler *handler);
+extern void cgroup_cleanup(struct lxc_handler *handler);
+extern bool cgroup_create_legacy(struct lxc_handler *handler);
+extern int cgroup_nrtasks(struct lxc_handler *handler);
+extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
+extern bool cgroup_escape();
+
+/*
+ * Currently, this call  only makes sense for privileged containers.
+ */
+extern const char *cgroup_canonical_path(struct lxc_handler *handler);
+extern bool cgroup_unfreeze(struct lxc_handler *handler);
+extern void cgroup_disconnect(void);
+extern cgroup_driver_t cgroup_driver(void);
+
+extern void prune_init_scope(char *cg);
+extern bool is_crucial_cgroup_subsystem(const char *s);
+
+#endif

From 9296b9d47d66126064a4284fe90f9dcbbee02c82 Mon Sep 17 00:00:00 2001
From: Christian Brauner <cbrauner at suse.de>
Date: Sun, 31 Jul 2016 12:40:49 +0200
Subject: [PATCH 3/3] tools: move lxc commands to common subfolder

Signed-off-by: Christian Brauner <cbrauner at suse.de>
---
 configure.ac                         |    4 +-
 src/lxc/Makefile.am                  |   58 +-
 src/lxc/lxc-checkconfig.in           |  156 -----
 src/lxc/lxc-start-ephemeral.in       |  412 ------------
 src/lxc/lxc-top.lua                  |  243 -------
 src/lxc/lxc_attach.c                 |  440 ------------
 src/lxc/lxc_autostart.c              |  526 ---------------
 src/lxc/lxc_cgroup.c                 |  122 ----
 src/lxc/lxc_checkpoint.c             |  236 -------
 src/lxc/lxc_clone.c                  |  217 ------
 src/lxc/lxc_config.c                 |   81 ---
 src/lxc/lxc_console.c                |  134 ----
 src/lxc/lxc_copy.c                   |  877 ------------------------
 src/lxc/lxc_create.c                 |  326 ---------
 src/lxc/lxc_destroy.c                |  258 --------
 src/lxc/lxc_device.c                 |  178 -----
 src/lxc/lxc_execute.c                |  161 -----
 src/lxc/lxc_freeze.c                 |   92 ---
 src/lxc/lxc_info.c                   |  397 -----------
 src/lxc/lxc_init.c                   |  261 --------
 src/lxc/lxc_ls.c                     | 1213 ----------------------------------
 src/lxc/lxc_monitor.c                |  211 ------
 src/lxc/lxc_snapshot.c               |  284 --------
 src/lxc/lxc_start.c                  |  357 ----------
 src/lxc/lxc_stop.c                   |  246 -------
 src/lxc/lxc_top.c                    |  510 --------------
 src/lxc/lxc_unfreeze.c               |   90 ---
 src/lxc/lxc_unshare.c                |  257 -------
 src/lxc/lxc_usernsexec.c             |  385 -----------
 src/lxc/lxc_wait.c                   |  112 ----
 src/lxc/tools/lxc-checkconfig.in     |  156 +++++
 src/lxc/tools/lxc-start-ephemeral.in |  412 ++++++++++++
 src/lxc/tools/lxc-top.lua            |  243 +++++++
 src/lxc/tools/lxc_attach.c           |  440 ++++++++++++
 src/lxc/tools/lxc_autostart.c        |  526 +++++++++++++++
 src/lxc/tools/lxc_cgroup.c           |  122 ++++
 src/lxc/tools/lxc_checkpoint.c       |  236 +++++++
 src/lxc/tools/lxc_clone.c            |  217 ++++++
 src/lxc/tools/lxc_config.c           |   81 +++
 src/lxc/tools/lxc_console.c          |  134 ++++
 src/lxc/tools/lxc_copy.c             |  877 ++++++++++++++++++++++++
 src/lxc/tools/lxc_create.c           |  326 +++++++++
 src/lxc/tools/lxc_destroy.c          |  258 ++++++++
 src/lxc/tools/lxc_device.c           |  178 +++++
 src/lxc/tools/lxc_execute.c          |  161 +++++
 src/lxc/tools/lxc_freeze.c           |   92 +++
 src/lxc/tools/lxc_info.c             |  397 +++++++++++
 src/lxc/tools/lxc_init.c             |  261 ++++++++
 src/lxc/tools/lxc_ls.c               | 1213 ++++++++++++++++++++++++++++++++++
 src/lxc/tools/lxc_monitor.c          |  211 ++++++
 src/lxc/tools/lxc_snapshot.c         |  284 ++++++++
 src/lxc/tools/lxc_start.c            |  357 ++++++++++
 src/lxc/tools/lxc_stop.c             |  246 +++++++
 src/lxc/tools/lxc_top.c              |  510 ++++++++++++++
 src/lxc/tools/lxc_unfreeze.c         |   90 +++
 src/lxc/tools/lxc_unshare.c          |  257 +++++++
 src/lxc/tools/lxc_usernsexec.c       |  385 +++++++++++
 src/lxc/tools/lxc_wait.c             |  112 ++++
 58 files changed, 8813 insertions(+), 8813 deletions(-)
 delete mode 100644 src/lxc/lxc-checkconfig.in
 delete mode 100644 src/lxc/lxc-start-ephemeral.in
 delete mode 100755 src/lxc/lxc-top.lua
 delete mode 100644 src/lxc/lxc_attach.c
 delete mode 100644 src/lxc/lxc_autostart.c
 delete mode 100644 src/lxc/lxc_cgroup.c
 delete mode 100644 src/lxc/lxc_checkpoint.c
 delete mode 100644 src/lxc/lxc_clone.c
 delete mode 100644 src/lxc/lxc_config.c
 delete mode 100644 src/lxc/lxc_console.c
 delete mode 100644 src/lxc/lxc_copy.c
 delete mode 100644 src/lxc/lxc_create.c
 delete mode 100644 src/lxc/lxc_destroy.c
 delete mode 100644 src/lxc/lxc_device.c
 delete mode 100644 src/lxc/lxc_execute.c
 delete mode 100644 src/lxc/lxc_freeze.c
 delete mode 100644 src/lxc/lxc_info.c
 delete mode 100644 src/lxc/lxc_init.c
 delete mode 100644 src/lxc/lxc_ls.c
 delete mode 100644 src/lxc/lxc_monitor.c
 delete mode 100644 src/lxc/lxc_snapshot.c
 delete mode 100644 src/lxc/lxc_start.c
 delete mode 100644 src/lxc/lxc_stop.c
 delete mode 100644 src/lxc/lxc_top.c
 delete mode 100644 src/lxc/lxc_unfreeze.c
 delete mode 100644 src/lxc/lxc_unshare.c
 delete mode 100644 src/lxc/lxc_usernsexec.c
 delete mode 100644 src/lxc/lxc_wait.c
 create mode 100644 src/lxc/tools/lxc-checkconfig.in
 create mode 100644 src/lxc/tools/lxc-start-ephemeral.in
 create mode 100755 src/lxc/tools/lxc-top.lua
 create mode 100644 src/lxc/tools/lxc_attach.c
 create mode 100644 src/lxc/tools/lxc_autostart.c
 create mode 100644 src/lxc/tools/lxc_cgroup.c
 create mode 100644 src/lxc/tools/lxc_checkpoint.c
 create mode 100644 src/lxc/tools/lxc_clone.c
 create mode 100644 src/lxc/tools/lxc_config.c
 create mode 100644 src/lxc/tools/lxc_console.c
 create mode 100644 src/lxc/tools/lxc_copy.c
 create mode 100644 src/lxc/tools/lxc_create.c
 create mode 100644 src/lxc/tools/lxc_destroy.c
 create mode 100644 src/lxc/tools/lxc_device.c
 create mode 100644 src/lxc/tools/lxc_execute.c
 create mode 100644 src/lxc/tools/lxc_freeze.c
 create mode 100644 src/lxc/tools/lxc_info.c
 create mode 100644 src/lxc/tools/lxc_init.c
 create mode 100644 src/lxc/tools/lxc_ls.c
 create mode 100644 src/lxc/tools/lxc_monitor.c
 create mode 100644 src/lxc/tools/lxc_snapshot.c
 create mode 100644 src/lxc/tools/lxc_start.c
 create mode 100644 src/lxc/tools/lxc_stop.c
 create mode 100644 src/lxc/tools/lxc_top.c
 create mode 100644 src/lxc/tools/lxc_unfreeze.c
 create mode 100644 src/lxc/tools/lxc_unshare.c
 create mode 100644 src/lxc/tools/lxc_usernsexec.c
 create mode 100644 src/lxc/tools/lxc_wait.c

diff --git a/configure.ac b/configure.ac
index 13820ef..2af0735 100644
--- a/configure.ac
+++ b/configure.ac
@@ -842,9 +842,9 @@ AC_CONFIG_FILES([
 
 	src/Makefile
 	src/lxc/Makefile
-	src/lxc/lxc-checkconfig
-	src/lxc/lxc-start-ephemeral
 	src/lxc/lxc.functions
+	src/lxc/tools/lxc-checkconfig
+	src/lxc/tools/lxc-start-ephemeral
 	src/lxc/version.h
 	src/python-lxc/Makefile
 
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 9a87c15..5be5625 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -192,14 +192,14 @@ liblxc_so_LDADD += $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS)
 liblxc_so_CFLAGS += $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) $(NIH_DBUS_CFLAGS)
 endif
 
-bin_SCRIPTS = lxc-checkconfig
+bin_SCRIPTS = tools/lxc-checkconfig
 
 EXTRA_DIST = \
-	lxc-top.lua
+	tools/lxc-top.lua
 
 if ENABLE_DEPRECATED
 if ENABLE_PYTHON
-bin_SCRIPTS += lxc-start-ephemeral
+bin_SCRIPTS += tools/lxc-start-ephemeral
 endif
 endif
 
@@ -243,35 +243,35 @@ AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
 endif
 LDADD=liblxc.so @CAP_LIBS@ @APPARMOR_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@
 
-lxc_attach_SOURCES = lxc_attach.c
-lxc_autostart_SOURCES = lxc_autostart.c
-lxc_cgroup_SOURCES = lxc_cgroup.c
-lxc_config_SOURCES = lxc_config.c
-lxc_console_SOURCES = lxc_console.c
-lxc_destroy_SOURCES = lxc_destroy.c
-lxc_device_SOURCES = lxc_device.c
-lxc_execute_SOURCES = lxc_execute.c
-lxc_freeze_SOURCES = lxc_freeze.c
-lxc_info_SOURCES = lxc_info.c
-init_lxc_SOURCES = lxc_init.c
-lxc_monitor_SOURCES = lxc_monitor.c
-lxc_monitord_SOURCES = lxc_monitord.c
-lxc_ls_SOURCES = lxc_ls.c
-lxc_copy_SOURCES = lxc_copy.c
-lxc_start_SOURCES = lxc_start.c
-lxc_stop_SOURCES = lxc_stop.c
-lxc_top_SOURCES = lxc_top.c
-lxc_unfreeze_SOURCES = lxc_unfreeze.c
-lxc_unshare_SOURCES = lxc_unshare.c
-lxc_wait_SOURCES = lxc_wait.c
-lxc_create_SOURCES = lxc_create.c
-lxc_snapshot_SOURCES = lxc_snapshot.c
-lxc_usernsexec_SOURCES = lxc_usernsexec.c
+lxc_attach_SOURCES = tools/lxc_attach.c
+lxc_autostart_SOURCES = tools/lxc_autostart.c
+lxc_cgroup_SOURCES = tools/lxc_cgroup.c
+lxc_config_SOURCES = tools/lxc_config.c
+lxc_console_SOURCES = tools/lxc_console.c
+lxc_destroy_SOURCES = tools/lxc_destroy.c
+lxc_device_SOURCES = tools/lxc_device.c
+lxc_execute_SOURCES = tools/lxc_execute.c
+lxc_freeze_SOURCES = tools/lxc_freeze.c
+lxc_info_SOURCES = tools/lxc_info.c
+init_lxc_SOURCES = tools/lxc_init.c
+lxc_monitor_SOURCES = tools/lxc_monitor.c
+lxc_ls_SOURCES = tools/lxc_ls.c
+lxc_copy_SOURCES = tools/lxc_copy.c
+lxc_start_SOURCES = tools/lxc_start.c
+lxc_stop_SOURCES = tools/lxc_stop.c
+lxc_top_SOURCES = tools/lxc_top.c
+lxc_unfreeze_SOURCES = tools/lxc_unfreeze.c
+lxc_unshare_SOURCES = tools/lxc_unshare.c
+lxc_wait_SOURCES = tools/lxc_wait.c
+lxc_create_SOURCES = tools/lxc_create.c
+lxc_snapshot_SOURCES = tools/lxc_snapshot.c
+lxc_usernsexec_SOURCES = tools/lxc_usernsexec.c
+lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c
 lxc_user_nic_SOURCES = lxc_user_nic.c network.c network.h
-lxc_checkpoint_SOURCES = lxc_checkpoint.c
+lxc_monitord_SOURCES = lxc_monitord.c
 
 if ENABLE_DEPRECATED
-lxc_clone_SOURCES = lxc_clone.c
+lxc_clone_SOURCES = tools/lxc_clone.c
 endif
 
 if !HAVE_GETSUBOPT
diff --git a/src/lxc/lxc-checkconfig.in b/src/lxc/lxc-checkconfig.in
deleted file mode 100644
index 29586f8..0000000
--- a/src/lxc/lxc-checkconfig.in
+++ /dev/null
@@ -1,156 +0,0 @@
-#!/bin/sh
-
-# Allow environment variables to override config
-: ${CONFIG:=/proc/config.gz}
-: ${MODNAME:=configs}
-
-CAT="cat"
-
-if [ -t 1 ]; then
-    SETCOLOR_SUCCESS="printf \\033[1;32m"
-    SETCOLOR_FAILURE="printf \\033[1;31m"
-    SETCOLOR_WARNING="printf \\033[1;33m"
-    SETCOLOR_NORMAL="printf \\033[0;39m"
-else
-    SETCOLOR_SUCCESS=":"
-    SETCOLOR_FAILURE=":"
-    SETCOLOR_WARNING=":"
-    SETCOLOR_NORMAL=":"
-fi
-
-is_set() {
-    $CAT $CONFIG | grep "$1=[y|m]" > /dev/null
-    return $?
-}
-
-is_enabled() {
-    mandatory=$2
-
-    is_set $1
-    RES=$?
-
-    if [ $RES -eq 0 ]; then
-        $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
-    else
-        if [ ! -z "$mandatory" ] && [ "$mandatory" = yes ]; then
-            $SETCOLOR_FAILURE && echo "required" && $SETCOLOR_NORMAL
-        else
-            $SETCOLOR_WARNING && echo "missing" && $SETCOLOR_NORMAL
-        fi
-    fi
-}
-
-if [ ! -f $CONFIG ]; then
-    echo "Kernel configuration not found at $CONFIG; searching..."
-    KVER="`uname -r`"
-    HEADERS_CONFIG="/lib/modules/$KVER/build/.config"
-    BOOT_CONFIG="/boot/config-$KVER"
-    [ -f "${HEADERS_CONFIG}" ] && CONFIG=${HEADERS_CONFIG}
-    [ -f "${BOOT_CONFIG}" ] && CONFIG=${BOOT_CONFIG}
-    if [ ! -f "$CONFIG" ]; then
-        MODULEFILE=$(modinfo -k $KVER -n $MODNAME 2> /dev/null)
-        # don't want to modprobe, so give user a hint
-        # although scripts/extract-ikconfig could be used to extract contents without loading kernel module
-        # http://svn.pld-linux.org/trac/svn/browser/geninitrd/trunk/geninitrd?rev=12696#L327
-    fi
-    if [ ! -f $CONFIG ]; then
-        echo "$(basename $0): unable to retrieve kernel configuration" >&2
-        echo >&2
-        if [ -f "$MODULEFILE" ]; then
-            echo "Try modprobe $MODNAME module, or" >&2
-        fi
-        echo "Try recompiling with IKCONFIG_PROC, installing the kernel headers," >&2
-        echo "or specifying the kernel configuration path with:" >&2
-        echo "  CONFIG=<path> $(basename $0)" >&2
-        exit 1
-    else
-        echo "Kernel configuration found at $CONFIG"
-    fi
-fi
-
-if gunzip -tq < $CONFIG 2>/dev/null; then
-    CAT="zcat"
-fi
-
-echo "--- Namespaces ---"
-echo -n "Namespaces: " && is_enabled CONFIG_NAMESPACES yes
-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
-echo -n "Network namespace: " && is_enabled CONFIG_NET_NS
-echo -n "Multiple /dev/pts instances: " && is_enabled DEVPTS_MULTIPLE_INSTANCES
-echo
-echo "--- Control groups ---"
-
-print_cgroups() {
-  # print all mountpoints for cgroup filesystems
-  awk '$1 !~ /#/ && $3 == mp { print $2; } ; END { exit(0); } '  "mp=$1" "$2" ;
-}
-
-CGROUP_MNT_PATH=`print_cgroups cgroup /proc/self/mounts | head -n 1`
-KVER_MAJOR=$($CAT $CONFIG | grep '^# Linux.*Kernel Configuration' | \
-    sed -r 's/.* ([0-9])\.[0-9]{1,2}\.[0-9]{1,3}.*/\1/')
-if [ "$KVER_MAJOR" = "2" ]; then
-KVER_MINOR=$($CAT $CONFIG | grep '^# Linux.*Kernel Configuration' | \
-    sed -r 's/.* 2.6.([0-9]{2}).*/\1/')
-else
-KVER_MINOR=$($CAT $CONFIG | grep '^# Linux.*Kernel Configuration' | \
-    sed -r 's/.* [0-9]\.([0-9]{1,3})\.[0-9]{1,3}.*/\1/')
-fi
-
-echo -n "Cgroup: " && is_enabled CONFIG_CGROUPS yes
-
-if [ -f $CGROUP_MNT_PATH/cgroup.clone_children ]; then
-    echo -n "Cgroup clone_children flag: " &&
-    $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
-else
-    echo -n "Cgroup namespace: " && is_enabled CONFIG_CGROUP_NS yes
-fi
-echo -n "Cgroup device: " && is_enabled CONFIG_CGROUP_DEVICE
-echo -n "Cgroup sched: " && is_enabled CONFIG_CGROUP_SCHED
-echo -n "Cgroup cpu account: " && is_enabled CONFIG_CGROUP_CPUACCT
-echo -n "Cgroup memory controller: "
-if ([ $KVER_MAJOR -ge 3 ] && [ $KVER_MINOR -ge 6 ]) || ([ $KVER_MAJOR -gt 3 ]); then
-    is_enabled CONFIG_MEMCG
-else
-    is_enabled CONFIG_CGROUP_MEM_RES_CTLR
-fi
-is_set CONFIG_SMP && echo -n "Cgroup cpuset: " && is_enabled CONFIG_CPUSETS
-echo
-echo "--- Misc ---"
-echo -n "Veth pair device: " && is_enabled CONFIG_VETH
-echo -n "Macvlan: " && is_enabled CONFIG_MACVLAN
-echo -n "Vlan: " && is_enabled CONFIG_VLAN_8021Q
-echo -n "Bridges: " && is_enabled CONFIG_BRIDGE
-echo -n "Advanced netfilter: " && is_enabled CONFIG_NETFILTER_ADVANCED
-echo -n "CONFIG_NF_NAT_IPV4: " && is_enabled CONFIG_NF_NAT_IPV4
-echo -n "CONFIG_NF_NAT_IPV6: " && is_enabled CONFIG_NF_NAT_IPV6
-echo -n "CONFIG_IP_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP_NF_TARGET_MASQUERADE
-echo -n "CONFIG_IP6_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP6_NF_TARGET_MASQUERADE
-echo -n "CONFIG_NETFILTER_XT_TARGET_CHECKSUM: " && is_enabled CONFIG_NETFILTER_XT_TARGET_CHECKSUM
-echo -n "FUSE (for use with lxcfs): " && is_enabled CONFIG_FUSE_FS
-
-echo
-echo "--- Checkpoint/Restore ---"
-echo -n "checkpoint restore: " && is_enabled CONFIG_CHECKPOINT_RESTORE
-echo -n "CONFIG_FHANDLE: " && is_enabled CONFIG_FHANDLE
-echo -n "CONFIG_EVENTFD: " && is_enabled CONFIG_EVENTFD
-echo -n "CONFIG_EPOLL: " && is_enabled CONFIG_EPOLL
-echo -n "CONFIG_UNIX_DIAG: " && is_enabled CONFIG_UNIX_DIAG
-echo -n "CONFIG_INET_DIAG: " && is_enabled CONFIG_INET_DIAG
-echo -n "CONFIG_PACKET_DIAG: " && is_enabled CONFIG_PACKET_DIAG
-echo -n "CONFIG_NETLINK_DIAG: " && is_enabled CONFIG_NETLINK_DIAG
-
-echo -n "File capabilities: " && \
-    ( [ "${KVER_MAJOR}" = 2 ] && [ ${KVER_MINOR} -lt 33 ] && \
-       is_enabled CONFIG_SECURITY_FILE_CAPABILITIES ) || \
-    ( ( [ "${KVER_MAJOR}" = "2" ] && [ ${KVER_MINOR} -gt 32 ] ) || \
-         [ ${KVER_MAJOR} -gt 2 ] && $SETCOLOR_SUCCESS && \
-         echo "enabled" && $SETCOLOR_NORMAL )
-
-echo
-echo "Note : Before booting a new kernel, you can check its configuration"
-echo "usage : CONFIG=/path/to/config $0"
-echo
-
diff --git a/src/lxc/lxc-start-ephemeral.in b/src/lxc/lxc-start-ephemeral.in
deleted file mode 100644
index 7e0c8ea..0000000
--- a/src/lxc/lxc-start-ephemeral.in
+++ /dev/null
@@ -1,412 +0,0 @@
-#!/usr/bin/env python3
-#
-# lxc-start-ephemeral: Start a copy of a container using an overlay
-#
-# This python implementation is based on the work done in the original
-# shell implementation done by Serge Hallyn in Ubuntu (and other contributors)
-#
-# (C) Copyright Canonical Ltd. 2012
-#
-# Authors:
-# Stéphane Graber <stgraber at ubuntu.com>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#
-
-import argparse
-import gettext
-import lxc
-import os
-import sys
-import subprocess
-import tempfile
-
-_ = gettext.gettext
-gettext.textdomain("lxc-start-ephemeral")
-
-# Other functions
-
-
-def printstderr(*args):
-    print("lxc-start-ephemeral is deprecated in favor of lxc-copy\n",
-          *args, file=sys.stderr)
-
-
-def randomMAC():
-    import random
-
-    mac = [0x00, 0x16, 0x3e,
-           random.randint(0x00, 0x7f),
-           random.randint(0x00, 0xff),
-           random.randint(0x00, 0xff)]
-    return ':'.join(map(lambda x: "%02x" % x, mac))
-
-
-def get_rundir():
-    if os.geteuid() == 0:
-        return "@RUNTIME_PATH@"
-
-    if "XDG_RUNTIME_DIR" in os.environ:
-        return os.environ["XDG_RUNTIME_DIR"]
-
-    if "HOME" in os.environ:
-        return "%s/.cache/lxc/run/" % os.environ["HOME"]
-
-    raise Exception("Unable to find a runtime directory")
-
-
-# Inform that lxc-start-ephemeral is deprecated
-printstderr()
-
-# Begin parsing the command line
-parser = argparse.ArgumentParser(description=_(
-                                 "LXC: Start an ephemeral container"),
-                                 formatter_class=argparse.RawTextHelpFormatter,
-                                 epilog=_("If a COMMAND is given, then the "
-                                          """container will run only as long
-as the command runs.
-If no COMMAND is given, this command will attach to tty1 and stop the
-container when exiting (with ctrl-a-q).
-
-If no COMMAND is given and -d is used, the name and IP addresses of the
-container will be printed to the console."""))
-
-parser.add_argument("--lxcpath", "-P", dest="lxcpath", metavar="PATH",
-                    help=_("Use specified container path"), default=None)
-
-parser.add_argument("--orig", "-o", type=str, required=True,
-                    help=_("name of the original container"))
-
-parser.add_argument("--name", "-n", type=str,
-                    help=_("name of the target container"))
-
-parser.add_argument("--bdir", "-b", type=str, action="append", default=[],
-                    help=_("directory to bind mount into container, "
-                           "either --bdir=/src-path or --bdir=/src-path:/dst-path"))
-
-parser.add_argument("--cdir", "-c", type=str, action="append", default=[],
-                    help=_("directory to cow mount into container"))
-
-parser.add_argument("--user", "-u", type=str,
-                    help=_("the user to run the command as"))
-
-parser.add_argument("--key", "-S", type=str,
-                    help=_("the path to the key to use to connect "
-                           "(when using ssh)"))
-
-parser.add_argument("--daemon", "-d", action="store_true",
-                    help=_("run in the background"))
-
-parser.add_argument("--storage-type", "-s", type=str, default=None,
-                    choices=("tmpfs", "dir"),
-                    help=("type of storage use by the container"))
-
-parser.add_argument("--union-type", "-U", type=str, default="overlayfs",
-                    choices=("overlayfs", "aufs"),
-                    help=_("type of union (overlayfs or aufs), "
-                           "defaults to overlayfs."))
-
-parser.add_argument("--keep-data", "-k", action="store_true",
-                    help=_("don't wipe everything clean at the end"))
-
-parser.add_argument("command", metavar='CMD', type=str, nargs="*",
-                    help=_("Run specific command in container "
-                           "(command as argument)"))
-
-parser.add_argument("--version", action="version", version=lxc.version)
-
-args = parser.parse_args()
-
-# Check that -d and CMD aren't used at the same time
-if args.command and args.daemon:
-    parser.error(_("You can't use -d and a command at the same time."))
-
-# Check that -k isn't used with -s tmpfs
-if not args.storage_type:
-    if args.keep_data:
-        args.storage_type = "dir"
-    else:
-        args.storage_type = "tmpfs"
-
-if args.keep_data and args.storage_type == "tmpfs":
-    parser.error(_("You can't use -k with the tmpfs storage type."))
-
-# Load the orig container
-orig = lxc.Container(args.orig, args.lxcpath)
-if not orig.defined:
-    parser.error(_("Source container '%s' doesn't exist." % args.orig))
-
-# Create the new container paths
-if not args.lxcpath:
-    lxc_path = lxc.default_config_path
-else:
-    lxc_path = args.lxcpath
-
-if args.name:
-    if os.path.exists("%s/%s" % (lxc_path, args.name)):
-        parser.error(_("A container named '%s' already exists." % args.name))
-    dest_path = "%s/%s" % (lxc_path, args.name)
-    os.mkdir(dest_path)
-else:
-    dest_path = tempfile.mkdtemp(prefix="%s-" % args.orig, dir=lxc_path)
-os.mkdir(os.path.join(dest_path, "rootfs"))
-os.chmod(dest_path, 0o770)
-
-# Setup the new container's configuration
-dest = lxc.Container(os.path.basename(dest_path), args.lxcpath)
-dest.load_config(orig.config_file_name)
-dest.set_config_item("lxc.utsname", dest.name)
-dest.set_config_item("lxc.rootfs", os.path.join(dest_path, "rootfs"))
-print("setting rootfs to .%s.", os.path.join(dest_path, "rootfs"))
-for nic in dest.network:
-    if hasattr(nic, 'hwaddr'):
-        nic.hwaddr = randomMAC()
-
-overlay_dirs = [(orig.get_config_item("lxc.rootfs"), "%s/rootfs/" % dest_path)]
-
-# Generate a new fstab
-if orig.get_config_item("lxc.mount"):
-    dest.set_config_item("lxc.mount", os.path.join(dest_path, "fstab"))
-    with open(orig.get_config_item("lxc.mount"), "r") as orig_fd:
-        with open(dest.get_config_item("lxc.mount"), "w+") as dest_fd:
-            for line in orig_fd.read().split("\n"):
-                # Start by replacing any reference to the container rootfs
-                line.replace(orig.get_config_item("lxc.rootfs"),
-                             dest.get_config_item("lxc.rootfs"))
-
-                fields = line.split()
-
-                # Skip invalid entries
-                if len(fields) < 4:
-                    continue
-
-                # Non-bind mounts are kept as-is
-                if "bind" not in fields[3]:
-                    dest_fd.write("%s\n" % line)
-                    continue
-
-                # Bind mounts of virtual filesystems are also kept as-is
-                src_path = fields[0].split("/")
-                if len(src_path) > 1 and src_path[1] in ("proc", "sys"):
-                    dest_fd.write("%s\n" % line)
-                    continue
-
-                # Skip invalid mount points
-                dest_mount = os.path.abspath(os.path.join("%s/rootfs/" % (
-                                             dest_path), fields[1]))
-
-                if "%s/rootfs/" % dest_path not in dest_mount:
-                    print(_("Skipping mount entry '%s' as it's outside "
-                            "of the container rootfs.") % line)
-
-                # Setup an overlay for anything remaining
-                overlay_dirs += [(fields[0], dest_mount)]
-
-for entry in args.cdir:
-    if not os.path.exists(entry):
-        print(_("Path '%s' doesn't exist, won't be cow-mounted.") %
-              entry)
-    else:
-        src_path = os.path.abspath(entry)
-        dst_path = "%s/rootfs/%s" % (dest_path, src_path)
-        overlay_dirs += [(src_path, dst_path)]
-
-# do we have the new overlay fs which requires workdir, or the older
-# overlayfs which does not?
-have_new_overlay = False
-with open("/proc/filesystems", "r") as fd:
-    for line in fd:
-        if line == "nodev\toverlay\n":
-            have_new_overlay = True
-
-# Generate pre-mount script
-with open(os.path.join(dest_path, "pre-mount"), "w+") as fd:
-    os.fchmod(fd.fileno(), 0o755)
-    fd.write("""#!/bin/sh
-LXC_DIR="%s"
-LXC_BASE="%s"
-LXC_NAME="%s"
-""" % (dest_path, orig.name, dest.name))
-
-    count = 0
-    for entry in overlay_dirs:
-        tmpdir = "%s/tmpfs" % dest_path
-        fd.write("mkdir -p %s\n" % (tmpdir))
-        if args.storage_type == "tmpfs":
-            fd.write("mount -n -t tmpfs -o mode=0755 none %s\n" % (tmpdir))
-        deltdir = "%s/delta%s" % (tmpdir, count)
-        workdir = "%s/work%s" % (tmpdir, count)
-        fd.write("mkdir -p %s %s\n" % (deltdir, entry[1]))
-        if have_new_overlay:
-            fd.write("mkdir -p %s\n" % workdir)
-
-        fd.write("getfacl -a %s | setfacl --set-file=- %s || true\n" %
-                 (entry[0], deltdir))
-        fd.write("getfacl -a %s | setfacl --set-file=- %s || true\n" %
-                 (entry[0], entry[1]))
-
-        if args.union_type == "overlayfs":
-            if have_new_overlay:
-                fd.write("mount -n -t overlay"
-                         " -oupperdir=%s,lowerdir=%s,workdir=%s none %s\n" % (
-                             deltdir,
-                             entry[0],
-                             workdir,
-                             entry[1]))
-            else:
-                fd.write("mount -n -t overlayfs"
-                         " -oupperdir=%s,lowerdir=%s none %s\n" % (
-                             deltdir,
-                             entry[0],
-                             entry[1]))
-        elif args.union_type == "aufs":
-            xino_path = "/dev/shm/aufs.xino"
-            if not os.path.exists(os.path.basename(xino_path)):
-                os.makedirs(os.path.basename(xino_path))
-
-            fd.write("mount -n -t aufs "
-                     "-o br=%s=rw:%s=ro,noplink,xino=%s none %s\n" % (
-                         deltdir,
-                         entry[0],
-                         xino_path,
-                         entry[1]))
-        count += 1
-
-    for entry in args.bdir:
-        if ':' in entry:
-            src_path, dst_path = entry.split(":")
-        else:
-            src_path = entry
-            dst_path = os.path.abspath(entry)
-
-        if not os.path.exists(src_path):
-            print(_("Path '%s' doesn't exist, won't be bind-mounted.") %
-                  src_path)
-        else:
-            src_path = os.path.abspath(src_path)
-            dst_path = "%s/rootfs/%s" % (dest_path, dst_path)
-            fd.write("mkdir -p %s\nmount -n --bind %s %s\n" % (
-                     dst_path, src_path, dst_path))
-
-    fd.write("""
-[ -e $LXC_DIR/configured ] && exit 0
-for file in $LXC_DIR/rootfs/etc/hostname \\
-            $LXC_DIR/rootfs/etc/hosts \\
-            $LXC_DIR/rootfs/etc/sysconfig/network \\
-            $LXC_DIR/rootfs/etc/sysconfig/network-scripts/ifcfg-eth0; do
-        [ -f "$file" ] && sed -i -e "s/$LXC_BASE/$LXC_NAME/" $file
-done
-touch $LXC_DIR/configured
-""")
-
-dest.set_config_item("lxc.hook.pre-mount",
-                     os.path.join(dest_path, "pre-mount"))
-
-if not args.keep_data:
-    dest.set_config_item("lxc.ephemeral", "1")
-
-dest.save_config()
-
-# Start the container
-if not dest.start() or not dest.wait("RUNNING", timeout=5):
-    print(_("The container '%s' failed to start.") % dest.name)
-    dest.stop()
-    if dest.defined:
-        dest.destroy()
-    sys.exit(1)
-
-# Deal with the case where we just attach to the container's console
-if not args.command and not args.daemon:
-    dest.console()
-    if not dest.shutdown(timeout=5):
-        dest.stop()
-    sys.exit(0)
-
-# Try to get the IP addresses
-ips = dest.get_ips(timeout=10)
-
-# Deal with the case where we just print info about the container
-if args.daemon:
-    print(_("""The ephemeral container is now started.
-
-You can enter it from the command line with: lxc-console -n %s
-The following IP addresses have be found in the container:
-%s""") % (dest.name,
-          "\n".join([" - %s" % entry for entry in ips]
-                    or [" - %s" % _("No address could be found")])))
-    sys.exit(0)
-
-# Now deal with the case where we want to run a command in the container
-if not ips:
-    print(_("Failed to get an IP for container '%s'.") % dest.name)
-    dest.stop()
-    if dest.defined:
-        dest.destroy()
-    sys.exit(1)
-
-if os.path.exists("/proc/self/ns/pid"):
-    def attach_as_user(command):
-        try:
-            username = "root"
-            if args.user:
-                username = args.user
-
-            line = subprocess.check_output(
-                ["getent", "passwd", username],
-                universal_newlines=True).rstrip("\n")
-            _, _, pw_uid, pw_gid, _, pw_dir, _ = line.split(":", 6)
-            pw_uid = int(pw_uid)
-            pw_gid = int(pw_gid)
-            os.setgid(pw_gid)
-            os.initgroups(username, pw_gid)
-            os.setuid(pw_uid)
-            os.chdir(pw_dir)
-            os.environ['HOME'] = pw_dir
-        except:
-            print(_("Unable to switch to user: %s" % username))
-            sys.exit(1)
-
-        return lxc.attach_run_command(command)
-
-    retval = dest.attach_wait(attach_as_user, args.command,
-                              env_policy=lxc.LXC_ATTACH_CLEAR_ENV)
-
-else:
-    cmd = ["ssh",
-           "-o", "StrictHostKeyChecking=no",
-           "-o", "UserKnownHostsFile=/dev/null"]
-
-    if args.user:
-        cmd += ["-l", args.user]
-
-    if args.key:
-        cmd += ["-i", args.key]
-
-    for ip in ips:
-        ssh_cmd = cmd + [ip] + args.command
-        retval = subprocess.call(ssh_cmd, universal_newlines=True)
-        if retval == 255:
-            print(_("SSH failed to connect, trying next IP address."))
-            continue
-
-        if retval != 0:
-            print(_("Command returned with non-zero return code: %s") % retval)
-        break
-
-# Shutdown the container
-if not dest.shutdown(timeout=5):
-    dest.stop()
-
-sys.exit(retval)
diff --git a/src/lxc/lxc-top.lua b/src/lxc/lxc-top.lua
deleted file mode 100755
index b5b3a69..0000000
--- a/src/lxc/lxc-top.lua
+++ /dev/null
@@ -1,243 +0,0 @@
-#!/usr/bin/env lua
---
--- top(1) like monitor for lxc containers
---
--- Copyright © 2012 Oracle.
---
--- Authors:
--- Dwight Engen <dwight.engen at oracle.com>
---
--- This library is free software; you can redistribute it and/or modify
--- it under the terms of the GNU General Public License version 2, as
--- published by the Free Software Foundation.
---
--- This program is distributed in the hope that it will be useful,
--- but WITHOUT ANY WARRANTY; without even the implied warranty of
--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--- GNU General Public License for more details.
---
--- You should have received a copy of the GNU General Public License along
--- with this program; if not, write to the Free Software Foundation, Inc.,
--- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
---
-
-local lxc    = require("lxc")
-local core   = require("lxc.core")
-local getopt = require("alt_getopt")
-
-local USER_HZ   = 100
-local ESC       = string.format("%c", 27)
-local TERMCLEAR = ESC.."[H"..ESC.."[J"
-local TERMNORM  = ESC.."[0m"
-local TERMBOLD  = ESC.."[1m"
-local TERMRVRS  = ESC.."[7m"
-
-local containers = {}
-local stats = {}
-local stats_total = {}
-local max_containers
-
-function printf(...)
-    local function wrapper(...) io.write(string.format(...)) end
-    local status, result = pcall(wrapper, ...)
-    if not status then
-	error(result, 2)
-    end
-end
-
-function string:split(delim, max_cols)
-    local cols = {}
-    local start = 1
-    local nextc
-    repeat
-	nextc = string.find(self, delim, start)
-	if (nextc and #cols ~= max_cols - 1) then
-	    table.insert(cols, string.sub(self, start, nextc-1))
-	    start = nextc + #delim
-	else
-	    table.insert(cols, string.sub(self, start, string.len(self)))
-	    nextc = nil
-	end
-    until nextc == nil or start > #self
-    return cols
-end
-
-function strsisize(size, width)
-    local KiB = 1024
-    local MiB = 1048576
-    local GiB = 1073741824
-    local TiB = 1099511627776
-    local PiB = 1125899906842624
-    local EiB = 1152921504606846976
-    local ZiB = 1180591620717411303424
-
-    if (size >= ZiB) then
-	return string.format("%d.%2.2d ZB", size / ZiB, (math.floor(size % ZiB) * 100) / ZiB)
-    end
-    if (size >= EiB) then
-	return string.format("%d.%2.2d EB", size / EiB, (math.floor(size % EiB) * 100) / EiB)
-    end
-    if (size >= PiB) then
-	return string.format("%d.%2.2d PB", size / PiB, (math.floor(size % PiB) * 100) / PiB)
-    end
-    if (size >= TiB) then
-	return string.format("%d.%2.2d TB", size / TiB, (math.floor(size % TiB) * 100) / TiB)
-    end
-    if (size >= GiB) then
-	return string.format("%d.%2.2d GB", size / GiB, (math.floor(size % GiB) * 100) / GiB)
-    end
-    if (size >= MiB) then
-	return string.format("%d.%2.2d MB", size / MiB, (math.floor(size % MiB) * 1000) / (MiB * 10))
-    end
-    if (size >= KiB) then
-	return string.format("%d.%2.2d KB", size / KiB, (math.floor(size % KiB) * 1000) / (KiB * 10))
-    end
-    return string.format("%3d.00   ", size)
-end
-
-function tty_lines()
-    local rows = 25
-    local f = assert(io.popen("stty -a | head -n 1"))
-    for line in f:lines() do
-	local stty_rows
-	_,_,stty_rows = string.find(line, "rows (%d+)")
-	if (stty_rows ~= nil) then
-	    rows = stty_rows
-	    break
-	end
-    end
-    f:close()
-    return rows
-end
-
-function container_sort(a, b)
-    if (optarg["r"]) then
-	if     (optarg["s"] == "n") then return (a > b)
-	elseif (optarg["s"] == "c") then return (stats[a].cpu_use_nanos < stats[b].cpu_use_nanos)
-	elseif (optarg["s"] == "d") then return (stats[a].blkio < stats[b].blkio)
-	elseif (optarg["s"] == "m") then return (stats[a].mem_used < stats[b].mem_used)
-	elseif (optarg["s"] == "k") then return (stats[a].kmem_used < stats[b].kmem_used)
-	end
-    else
-	if     (optarg["s"] == "n") then return (a < b)
-	elseif (optarg["s"] == "c") then return (stats[a].cpu_use_nanos > stats[b].cpu_use_nanos)
-	elseif (optarg["s"] == "d") then return (stats[a].blkio > stats[b].blkio)
-	elseif (optarg["s"] == "m") then return (stats[a].mem_used > stats[b].mem_used)
-	elseif (optarg["s"] == "k") then return (stats[a].kmem_used > stats[b].kmem_used)
-	end
-    end
-end
-
-function container_list_update()
-    local now_running
-
-    now_running = lxc.containers_running(true)
-
-    -- check for newly started containers
-    for _,v in ipairs(now_running) do
-	if (containers[v] == nil) then
-	    local ct = lxc.container:new(v)
-	    -- note, this is a "mixed" table, ie both dictionary and list
-	    containers[v] = ct
-	    table.insert(containers, v)
-	end
-    end
-
-    -- check for newly stopped containers
-    local indx = 1
-    while (indx <= #containers) do
-	local ctname = containers[indx]
-	if (now_running[ctname] == nil) then
-	    containers[ctname] = nil
-	    stats[ctname] = nil
-	    table.remove(containers, indx)
-	else
-	    indx = indx + 1
-	end
-    end
-
-    -- get stats for all current containers and resort the list
-    lxc.stats_clear(stats_total)
-    for _,ctname in ipairs(containers) do
-	stats[ctname] = containers[ctname]:stats_get(stats_total)
-    end
-    table.sort(containers, container_sort)
-end
-
-function stats_print_header(stats_total)
-    printf(TERMRVRS .. TERMBOLD)
-    printf("%-15s %8s %8s %8s %10s %10s", "Container", "CPU",  "CPU",  "CPU",  "BlkIO", "Mem")
-    if (stats_total.kmem_used > 0) then printf(" %10s", "KMem") end
-    printf("\n")
-
-    printf("%-15s %8s %8s %8s %10s %10s", "Name",      "Used", "Sys",  "User", "Total", "Used")
-    if (stats_total.kmem_used > 0) then printf(" %10s", "Used") end
-    printf("\n")
-    printf(TERMNORM)
-end
-
-function stats_print(name, stats, stats_total)
-    printf("%-15s %8.2f %8.2f %8.2f %10s %10s",
-	   name,
-	   stats.cpu_use_nanos / 1000000000,
-	   stats.cpu_use_sys  / USER_HZ,
-	   stats.cpu_use_user / USER_HZ,
-	   strsisize(stats.blkio),
-	   strsisize(stats.mem_used))
-    if (stats_total.kmem_used > 0) then
-	printf(" %10s", strsisize(stats.kmem_used))
-    end
-end
-
-function usage()
-    printf("Usage: lxc-top [options]\n" ..
-	"  -h|--help      print this help message\n" ..
-	"  -m|--max       display maximum number of containers\n" ..
-	"  -d|--delay     delay in seconds between refreshes (default: 3.0)\n" ..
-	"  -s|--sort      sort by [n,c,d,m] (default: n) where\n" ..
-	"                 n = Name\n" ..
-	"                 c = CPU use\n" ..
-	"                 d = Disk I/O use\n" ..
-	"                 m = Memory use\n" ..
-	"                 k = Kernel memory use\n" ..
-	"  -r|--reverse   sort in reverse (descending) order\n"
-    )
-    os.exit(1)
-end
-
-local long_opts = {
-    help      = "h",
-    delay     = "d",
-    max       = "m",
-    reverse   = "r",
-    sort      = "s",
-}
-
-optarg,optind = alt_getopt.get_opts (arg, "hd:m:rs:", long_opts)
-optarg["d"] = tonumber(optarg["d"]) or 3.0
-optarg["m"] = tonumber(optarg["m"]) or tonumber(tty_lines() - 3)
-optarg["r"] = optarg["r"] or false
-optarg["s"] = optarg["s"] or "n"
-if (optarg["h"] ~= nil) then
-    usage()
-end
-
-while true
-do
-    container_list_update()
-    -- if some terminal we care about doesn't support the simple escapes, we
-    -- may fall back to this, or ncurses. ug.
-    --os.execute("tput clear")
-    printf(TERMCLEAR)
-    stats_print_header(stats_total)
-    for index,ctname in ipairs(containers) do
-	stats_print(ctname, stats[ctname], stats_total)
-	printf("\n")
-	if (index >= optarg["m"]) then
-	    break
-	end
-    end
-    stats_print(string.format("TOTAL (%-2d)", #containers), stats_total, stats_total)
-    io.flush()
-    core.usleep(optarg["d"] * 1000000)
-end
diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c
deleted file mode 100644
index 58f658b..0000000
--- a/src/lxc/lxc_attach.c
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2010
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <termios.h>
-#include <unistd.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "attach.h"
-#include "arguments.h"
-#include "caps.h"
-#include "confile.h"
-#include "console.h"
-#include "log.h"
-#include "list.h"
-#include "mainloop.h"
-#include "utils.h"
-
-#if HAVE_PTY_H
-#include <pty.h>
-#else
-#include <../include/openpty.h>
-#endif
-
-lxc_log_define(lxc_attach_ui, lxc);
-
-static const struct option my_longopts[] = {
-	{"elevated-privileges", optional_argument, 0, 'e'},
-	{"arch", required_argument, 0, 'a'},
-	{"namespaces", required_argument, 0, 's'},
-	{"remount-sys-proc", no_argument, 0, 'R'},
-	/* TODO: decide upon short option names */
-	{"clear-env", no_argument, 0, 500},
-	{"keep-env", no_argument, 0, 501},
-	{"keep-var", required_argument, 0, 502},
-	{"set-var", required_argument, 0, 'v'},
-	{"pty-log", required_argument, 0, 'L'},
-	LXC_COMMON_OPTIONS
-};
-
-static int elevated_privileges = 0;
-static signed long new_personality = -1;
-static int namespace_flags = -1;
-static int remount_sys_proc = 0;
-static lxc_attach_env_policy_t env_policy = LXC_ATTACH_KEEP_ENV;
-static char **extra_env = NULL;
-static ssize_t extra_env_size = 0;
-static char **extra_keep = NULL;
-static ssize_t extra_keep_size = 0;
-
-static int add_to_simple_array(char ***array, ssize_t *capacity, char *value)
-{
-	ssize_t count = 0;
-
-	assert(array);
-
-	if (*array)
-		for (; (*array)[count]; count++);
-
-	/* we have to reallocate */
-	if (count >= *capacity - 1) {
-		ssize_t new_capacity = ((count + 1) / 32 + 1) * 32;
-		char **new_array = realloc((void*)*array, sizeof(char *) * new_capacity);
-		if (!new_array)
-			return -1;
-		memset(&new_array[count], 0, sizeof(char*)*(new_capacity - count));
-		*array = new_array;
-		*capacity = new_capacity;
-	}
-
-	assert(*array);
-
-	(*array)[count] = value;
-	return 0;
-}
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	int ret;
-
-	switch (c) {
-	case 'e':
-		ret = lxc_fill_elevated_privileges(arg, &elevated_privileges);
-		if (ret)
-			return -1;
-		break;
-	case 'R': remount_sys_proc = 1; break;
-	case 'a':
-		new_personality = lxc_config_parse_arch(arg);
-		if (new_personality < 0) {
-			lxc_error(args, "invalid architecture specified: %s", arg);
-			return -1;
-		}
-		break;
-	case 's':
-		namespace_flags = 0;
-		ret = lxc_fill_namespace_flags(arg, &namespace_flags);
-		if (ret)
-			return -1;
-		/* -s implies -e */
-		lxc_fill_elevated_privileges(NULL, &elevated_privileges);
-		break;
-	case 500: /* clear-env */
-		env_policy = LXC_ATTACH_CLEAR_ENV;
-		break;
-	case 501: /* keep-env */
-		env_policy = LXC_ATTACH_KEEP_ENV;
-		break;
-	case 502: /* keep-var */
-		ret = add_to_simple_array(&extra_keep, &extra_keep_size, arg);
-		if (ret < 0) {
-			lxc_error(args, "memory allocation error");
-			return -1;
-		}
-		break;
-	case 'v':
-		ret = add_to_simple_array(&extra_env, &extra_env_size, arg);
-		if (ret < 0) {
-			lxc_error(args, "memory allocation error");
-			return -1;
-		}
-		break;
-	case 'L':
-		args->console_log = arg;
-		break;
-	}
-
-	return 0;
-}
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-attach",
-	.help     = "\
---name=NAME [-- COMMAND]\n\
-\n\
-Execute the specified COMMAND - enter the container NAME\n\
-\n\
-Options :\n\
-  -n, --name=NAME   NAME of the container\n\
-  -e, --elevated-privileges=PRIVILEGES\n\
-                    Use elevated privileges instead of those of the\n\
-                    container. If you don't specify privileges to be\n\
-                    elevated as OR'd list: CAP, CGROUP and LSM (capabilities,\n\
-                    cgroup and restrictions, respectively) then all of them\n\
-                    will be elevated.\n\
-                    WARNING: This may leak privileges into the container.\n\
-                    Use with care.\n\
-  -a, --arch=ARCH   Use ARCH for program instead of container's own\n\
-                    architecture.\n\
-  -s, --namespaces=FLAGS\n\
-                    Don't attach to all the namespaces of the container\n\
-                    but just to the following OR'd list of flags:\n\
-                    MOUNT, PID, UTSNAME, IPC, USER or NETWORK.\n\
-                    WARNING: Using -s implies -e with all privileges\n\
-                    elevated, it may therefore leak privileges into the\n\
-                    container. Use with care.\n\
-  -R, --remount-sys-proc\n\
-                    Remount /sys and /proc if not attaching to the\n\
-                    mount namespace when using -s in order to properly\n\
-                    reflect the correct namespace context. See the\n\
-                    lxc-attach(1) manual page for details.\n\
-      --clear-env   Clear all environment variables before attaching.\n\
-                    The attached shell/program will start with only\n\
-                    container=lxc set.\n\
-      --keep-env    Keep all current environment variables. This\n\
-                    is the current default behaviour, but is likely to\n\
-                    change in the future.\n\
-  -L, --pty-log=FILE\n\
-		    Log pty output to FILE\n\
-  -v, --set-var     Set an additional variable that is seen by the\n\
-                    attached program in the container. May be specified\n\
-                    multiple times.\n\
-      --keep-var    Keep an additional environment variable. Only\n\
-                    applicable if --clear-env is specified. May be used\n\
-                    multiple times.\n",
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = NULL,
-};
-
-struct wrapargs {
-	lxc_attach_options_t *options;
-	lxc_attach_command_t *command;
-	struct lxc_console *console;
-	int ptyfd;
-};
-
-/* Minimalistic login_tty() implementation. */
-static int login_pty(int fd)
-{
-	setsid();
-	if (ioctl(fd, TIOCSCTTY, NULL) < 0)
-		return -1;
-	if (lxc_console_set_stdfds(fd) < 0)
-		return -1;
-	if (fd > STDERR_FILENO)
-		close(fd);
-	return 0;
-}
-
-static int get_pty_on_host_callback(void *p)
-{
-	struct wrapargs *wrap = p;
-
-	close(wrap->console->master);
-	if (login_pty(wrap->console->slave) < 0)
-		return -1;
-
-	if (wrap->command->program)
-		lxc_attach_run_command(wrap->command);
-	else
-		lxc_attach_run_shell(NULL);
-	return -1;
-}
-
-static int get_pty_on_host(struct lxc_container *c, struct wrapargs *wrap, int *pid)
-{
-	int ret = -1;
-	struct wrapargs *args = wrap;
-	struct lxc_epoll_descr descr;
-	struct lxc_conf *conf;
-	struct lxc_tty_state *ts;
-
-	INFO("Trying to allocate a pty on the host");
-
-	if (!isatty(args->ptyfd)) {
-		ERROR("Standard file descriptor does not refer to a pty\n.");
-		return -1;
-	}
-
-	conf = c->lxc_conf;
-	free(conf->console.log_path);
-	if (my_args.console_log)
-		conf->console.log_path = strdup(my_args.console_log);
-	else
-		conf->console.log_path = NULL;
-
-	/* In the case of lxc-attach our peer pty will always be the current
-	 * controlling terminal. We clear whatever was set by the user for
-	 * lxc.console.path here and set it to "/dev/tty". Doing this will (a)
-	 * prevent segfaults when the container has been setup with
-	 * lxc.console = none and (b) provide an easy way to ensure that we
-	 * always do the correct thing. strdup() must be used since console.path
-	 * is free()ed when we call lxc_container_put(). */
-	free(conf->console.path);
-	conf->console.path = strdup("/dev/tty");
-	if (!conf->console.path)
-		return -1;
-
-	/* Create pty on the host. */
-	if (lxc_console_create(conf) < 0)
-		return -1;
-	ts = conf->console.tty_state;
-	conf->console.descr = &descr;
-
-	/* Shift ttys to container. */
-	if (ttys_shift_ids(conf) < 0) {
-		ERROR("Failed to shift tty into container");
-		goto err1;
-	}
-
-	/* Send wrapper function on its way. */
-	wrap->console = &conf->console;
-	if (c->attach(c, get_pty_on_host_callback, wrap, wrap->options, pid) < 0)
-		goto err1;
-	close(conf->console.slave); /* Close slave side. */
-
-	ret = lxc_mainloop_open(&descr);
-	if (ret) {
-		ERROR("failed to create mainloop");
-		goto err2;
-	}
-
-	if (lxc_console_mainloop_add(&descr, conf) < 0) {
-		ERROR("Failed to add handlers to lxc mainloop.");
-		goto err3;
-	}
-
-	ret = lxc_mainloop(&descr, -1);
-	if (ret) {
-		ERROR("mainloop returned an error");
-		goto err3;
-	}
-	ret = 0;
-
-err3:
-	lxc_mainloop_close(&descr);
-err2:
-	if (ts->sigfd != -1)
-		lxc_console_sigwinch_fini(ts);
-err1:
-	lxc_console_delete(&conf->console);
-
-	return ret;
-}
-
-static int stdfd_is_pty(void)
-{
-	if (isatty(STDIN_FILENO))
-		return STDIN_FILENO;
-	if (isatty(STDOUT_FILENO))
-		return STDOUT_FILENO;
-	if (isatty(STDERR_FILENO))
-		return STDERR_FILENO;
-
-	return -1;
-}
-
-int main(int argc, char *argv[])
-{
-	int ret = -1, r;
-	int wexit = 0;
-	pid_t pid;
-	lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
-	lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL};
-
-	r = lxc_caps_init();
-	if (r)
-		exit(EXIT_FAILURE);
-
-	r = lxc_arguments_parse(&my_args, argc, argv);
-	if (r)
-		exit(EXIT_FAILURE);
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	r = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			   my_args.progname, my_args.quiet, my_args.lxcpath[0]);
-	if (r)
-		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
-
-	if (geteuid()) {
-		if (access(my_args.lxcpath[0], O_RDWR) < 0) {
-			if (!my_args.quiet)
-				fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c)
-		exit(EXIT_FAILURE);
-
-	if (!c->may_control(c)) {
-		fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
-		lxc_container_put(c);
-		exit(EXIT_FAILURE);
-	}
-
-	if (!c->is_defined(c)) {
-		fprintf(stderr, "Error: container %s is not defined\n", c->name);
-		lxc_container_put(c);
-		exit(EXIT_FAILURE);
-	}
-
-	if (remount_sys_proc)
-		attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
-	if (elevated_privileges)
-		attach_options.attach_flags &= ~(elevated_privileges);
-	attach_options.namespaces = namespace_flags;
-	attach_options.personality = new_personality;
-	attach_options.env_policy = env_policy;
-	attach_options.extra_env_vars = extra_env;
-	attach_options.extra_keep_env = extra_keep;
-
-	if (my_args.argc > 0) {
-		command.program = my_args.argv[0];
-		command.argv = (char**)my_args.argv;
-	}
-
-	struct wrapargs wrap = (struct wrapargs){
-		.command = &command,
-			.options = &attach_options
-	};
-
-	wrap.ptyfd = stdfd_is_pty();
-	if (wrap.ptyfd >= 0) {
-		if ((!isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) && my_args.console_log) {
-			fprintf(stderr, "-L/--pty-log can only be used when stdout and stderr refer to a pty.\n");
-			goto out;
-		}
-		ret = get_pty_on_host(c, &wrap, &pid);
-	} else {
-		if (my_args.console_log) {
-			fprintf(stderr, "-L/--pty-log can only be used when stdout and stderr refer to a pty.\n");
-			goto out;
-		}
-		if (command.program)
-			ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
-		else
-			ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid);
-	}
-
-	if (ret < 0)
-		goto out;
-
-	ret = lxc_wait_for_pid_status(pid);
-	if (ret < 0)
-		goto out;
-
-	if (WIFEXITED(ret))
-		wexit = WEXITSTATUS(ret);
-out:
-	lxc_container_put(c);
-	if (ret >= 0)
-		exit(wexit);
-	exit(EXIT_FAILURE);
-}
diff --git a/src/lxc/lxc_autostart.c b/src/lxc/lxc_autostart.c
deleted file mode 100644
index eed0f5f..0000000
--- a/src/lxc/lxc_autostart.c
+++ /dev/null
@@ -1,526 +0,0 @@
-/* lxc_autostart
- *
- * Copyright © 2013 Stéphane Graber <stgraber at ubuntu.com>
- * Copyright © 2013 Canonical Ltd.
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
-
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
-
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <string.h>
-#include <unistd.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "arguments.h"
-#include "list.h"
-#include "log.h"
-
-lxc_log_define(lxc_autostart_ui, lxc);
-static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list);
-
-struct lxc_list *cmd_groups_list = NULL;
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	switch (c) {
-	case 'k': args->hardstop = 1; break;
-	case 'L': args->list = 1; break;
-	case 'r': args->reboot = 1; break;
-	case 's': args->shutdown = 1; break;
-	case 'a': args->all = 1; break;
-	case 'A': args->ignore_auto = 1; break;
-	case 'g': cmd_groups_list = accumulate_list( arg, ",", cmd_groups_list); break;
-	case 't': args->timeout = atoi(arg); break;
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	{"kill", no_argument, 0, 'k'},
-	{"list", no_argument, 0, 'L'},
-	{"reboot", no_argument, 0, 'r'},
-	{"shutdown", no_argument, 0, 's'},
-	{"all", no_argument, 0, 'a'},
-	{"ignore-auto", no_argument, 0, 'A'},
-	{"groups", required_argument, 0, 'g'},
-	{"timeout", required_argument, 0, 't'},
-	{"help", no_argument, 0, 'h'},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-autostart",
-	.help     = "\
-\n\
-lxc-autostart managed auto-started containers\n\
-\n\
-Options:\n\
-  -k, --kill        kill the containers instead of starting them\n\
-  -L, --list        list all affected containers and wait delay\n\
-  -r, --reboot      reboot the containers instead of starting them\n\
-  -s, --shutdown    shutdown the containers instead of starting them\n\
-\n\
-  -a, --all         list all auto-started containers (ignore groups)\n\
-  -A, --ignore-auto ignore lxc.start.auto and select all matching containers\n\
-  -g, --groups      list of groups (comma separated) to select\n\
-  -t, --timeout=T   wait T seconds before hard-stopping\n",
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = NULL,
-	.timeout = 60,
-};
-
-int list_contains_entry( char *str_ptr, struct lxc_list *p1 ) {
-	struct lxc_list *it1;
-
-	/*
-	 * If the entry is NULL or the empty string and the list
-	 * is NULL, we have a match
-	 */
-	if (! p1 && ! str_ptr)
-		return 1;
-	if (! p1 && ! *str_ptr)
-		return 1;
-
-	if (!p1)
-		return 0;
-
-	lxc_list_for_each(it1, p1) {
-		if (strcmp(it1->elem, str_ptr) == 0)
-			return 1;
-	}
-
-	return 0;
-}
-
-int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) {
-	struct lxc_list *it1;
-	struct lxc_list *it2;
-
-	if (!p1 && !p2)
-		return 1;
-
-	if (!p1)
-		return 0;
-
-	if (!p2)
-		return 0;
-
-	lxc_list_for_each(it1, p1) {
-		lxc_list_for_each(it2, p2) {
-			if (strcmp(it1->elem, it2->elem) == 0)
-				return 1;
-		}
-	}
-
-	return 0;
-}
-
-/*
- * This is a variation of get_list below it.
- * This version allows two additional features.
- * If a list is passed to it, it adds to it.
- * It allows for empty entries (i.e. "group1,,group2") generating
- * 	and empty list entry.
- */
-static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list) {
-	char *workstr = NULL;
-	char *workptr = NULL;
-	char *next_ptr = NULL;
-	struct lxc_list *worklist;
-	struct lxc_list *workstr_list;
-
-	workstr = strdup(input);
-	if (!workstr) {
-		return NULL;
-	}
-
-	workstr_list = str_list;
-	if ( ! workstr_list ) {
-		workstr_list = malloc(sizeof(*workstr_list));
-		lxc_list_init(workstr_list);
-	}
-
-	for (workptr = workstr; workptr; workptr = next_ptr) {
-		/*
-		 * We can't use strtok_r here because it collapses
-		 * multiple delimiters into 1 making empty fields
-		 * impossible...
-		 */
-		/* token = strtok_r(workptr, delimiter, &sptr); */
-		next_ptr = strchr( workptr, *delimiter );
-
-		if( next_ptr ) {
-			*next_ptr++ = '\0';
-		}
-
-		/*
-		 * At this point, we'd like to check to see if this
-		 * group is already contained in the list and ignore
-		 * it if it is...  This also helps us with any
-		 * corner cases where a string begins or ends with a
-		 * delimiter.
-		 */
-
-		if ( list_contains_entry( workptr, workstr_list ) ) {
-			if ( *workptr ) {
-				fprintf(stderr, "Duplicate group \"%s\" in list - ignoring\n", workptr );
-				fflush(stderr);
-			} else {
-				fprintf(stderr, "Duplicate NULL group in list - ignoring\n" );
-				fflush(stderr);
-			}
-		} else {
-			worklist = malloc(sizeof(*worklist));
-			if (!worklist)
-				break;
-
-			worklist->elem = strdup(workptr);
-			if (!worklist->elem) {
-				free(worklist);
-				break;
-			}
-
-			lxc_list_add_tail(workstr_list, worklist);
-		}
-	}
-
-	free(workstr);
-
-	return workstr_list;
-}
-
-static struct lxc_list *get_list(char *input, char *delimiter) {
-	char *workstr = NULL;
-	char *workptr = NULL;
-	char *sptr = NULL;
-	char *token = NULL;
-	struct lxc_list *worklist;
-	struct lxc_list *workstr_list;
-
-	workstr_list = malloc(sizeof(*workstr_list));
-	lxc_list_init(workstr_list);
-
-	workstr = strdup(input);
-	if (!workstr) {
-		free(workstr_list);
-		return NULL;
-	}
-
-	for (workptr = workstr;;workptr = NULL) {
-		token = strtok_r(workptr, delimiter, &sptr);
-		if (!token) {
-			break;
-		}
-
-		worklist = malloc(sizeof(*worklist));
-		if (!worklist)
-			break;
-
-		worklist->elem = strdup(token);
-		if (!worklist->elem) {
-			free(worklist);
-			break;
-		}
-
-		lxc_list_add_tail(workstr_list, worklist);
-	}
-
-	free(workstr);
-
-	return workstr_list;
-}
-
-static struct lxc_list *get_config_list(struct lxc_container *c, char *key) {
-	int len = 0;
-	char* value = NULL;
-	struct lxc_list *config_list = NULL;
-
-	len = c->get_config_item(c, key, NULL, 0);
-	if (len < 0)
-		return NULL;
-
-	value = (char*) malloc(sizeof(char)*len + 1);
-	if (value == NULL)
-		return NULL;
-
-	if (c->get_config_item(c, key, value, len + 1) != len) {
-		free(value);
-		return NULL;
-	}
-
-	if (strlen(value) == 0) {
-		free(value);
-		return NULL;
-	}
-
-	config_list = get_list(value, "\n");
-	free(value);
-
-	return config_list;
-}
-
-static int get_config_integer(struct lxc_container *c, char *key) {
-	int len = 0;
-	int ret = 0;
-	char* value = NULL;
-
-	len = c->get_config_item(c, key, NULL, 0);
-	if (len < 0)
-		return 0;
-
-	value = (char*) malloc(sizeof(char)*len + 1);
-	if (value == NULL)
-		return 0;
-
-	if (c->get_config_item(c, key, value, len + 1) != len) {
-		free(value);
-		return 0;
-	}
-
-	ret = atoi(value);
-	free(value);
-
-	return ret;
-}
-
-static int cmporder(const void *p1, const void *p2) {
-	struct lxc_container *c1 = *(struct lxc_container **)p1;
-	struct lxc_container *c2 = *(struct lxc_container **)p2;
-
-	int c1_order = get_config_integer(c1, "lxc.start.order");
-	int c2_order = get_config_integer(c2, "lxc.start.order");
-
-	if (c1_order == c2_order)
-		return strcmp(c1->name, c2->name);
-	else
-		return (c1_order - c2_order);
-}
-
-static int toss_list( struct lxc_list *c_groups_list ) {
-	struct lxc_list *it, *next;
-
-	if (c_groups_list) {
-		lxc_list_for_each_safe(it, c_groups_list, next) {
-			lxc_list_del(it);
-			free(it->elem);
-			free(it);
-		}
-		free(c_groups_list);
-	}
-
-	return 1;
-}
-
-int main(int argc, char *argv[])
-{
-	int count = 0;
-	int i = 0;
-	int ret = 0;
-	struct lxc_container **containers = NULL;
-	struct lxc_list **c_groups_lists = NULL;
-	struct lxc_list *cmd_group;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		return 1;
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		return 1;
-	lxc_log_options_no_override();
-
-	count = list_defined_containers(my_args.lxcpath[0], NULL, &containers);
-
-	if (count < 0)
-		return 1;
-
-	if (!my_args.all) {
-		/* Allocate an array for our container group lists */
-		c_groups_lists = calloc( count, sizeof( struct lxc_list * ) );
-	}
-
-	qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder);
-
-	if (cmd_groups_list && my_args.all) {
-		fprintf(stderr, "Specifying -a (all) with -g (groups) doesn't make sense. All option overrides.\n");
-		fflush(stderr);
-	}
-
-	if (!cmd_groups_list) {
-		/*
-		 * We need a default cmd_groups_list even for the -a
-		 * case in order to force a pass through the loop for
-		 * the NULL group.  This, someday, could be taken from
-		 * a config file somewhere...
-		 */
-		cmd_groups_list = accumulate_list( "" , ",", NULL );
-	}
-
-	lxc_list_for_each(cmd_group, cmd_groups_list) {
-
-		/*
-		 * Prograpmmers Note:
-		 * Because we may take several passes through the container list
-		 * We'll switch on if the container pointer is NULL and if we process a
-		 * container (run it or decide to ignore it) and call lxc_container_put
-		 * then we'll NULL it out and not check it again.
-		 */
-		for (i = 0; i < count; i++) {
-			struct lxc_container *c = containers[i];
-
-			if (!c)
-				/* Skip - must have been already processed */
-				continue;
-
-			/*
-			 * We haven't loaded the container groups yet so
-			 * these next two checks don't need to free them
-			 * if they fail.  They'll fail on the first pass.
-			 */
-			if (!c->may_control(c)) {
-				/* We're done with this container */
-				if ( lxc_container_put(c) > 0 )
-					containers[i] = NULL;
-				continue;
-			}
-
-			if (!my_args.ignore_auto &&
-			    get_config_integer(c, "lxc.start.auto") != 1) {
-				/* We're done with this container */
-				if ( lxc_container_put(c) > 0 )
-					containers[i] = NULL;
-				continue;
-			}
-
-			if (!my_args.all) {
-				/* Filter by group */
-				if( ! c_groups_lists[i] ) {
-					/* Now we're loading up a container's groups */
-					c_groups_lists[i] = get_config_list(c, "lxc.group");
-				}
-
-				ret = list_contains_entry(cmd_group->elem, c_groups_lists[i]);
-
-				if ( ret == 0 ) {
-					/* Not in the target group this pass */
-					/* Leave in the list for subsequent passes */
-					continue;
-				}
-			}
-
-			/* We have a candidate continer to process */
-			c->want_daemonize(c, 1);
-
-			if (my_args.shutdown) {
-				/* Shutdown the container */
-				if (c->is_running(c)) {
-					if (my_args.list) {
-						printf("%s\n", c->name);
-						fflush(stdout);
-					}
-					else {
-						if (!c->shutdown(c, my_args.timeout)) {
-							if (!c->stop(c)) {
-								fprintf(stderr, "Error shutting down container: %s\n", c->name);
-								fflush(stderr);
-							}
-						}
-					}
-				}
-			}
-			else if (my_args.hardstop) {
-				/* Kill the container */
-				if (c->is_running(c)) {
-					if (my_args.list) {
-						printf("%s\n", c->name);
-						fflush(stdout);
-					}
-					else {
-						if (!c->stop(c)) {
-							fprintf(stderr, "Error killing container: %s\n", c->name);
-							fflush(stderr);
-						}
-					}
-				}
-			}
-			else if (my_args.reboot) {
-				/* Reboot the container */
-				if (c->is_running(c)) {
-					if (my_args.list) {
-						printf("%s %d\n", c->name,
-						       get_config_integer(c, "lxc.start.delay"));
-						fflush(stdout);
-					}
-					else {
-						if (!c->reboot(c)) {
-							fprintf(stderr, "Error rebooting container: %s\n", c->name);
-							fflush(stderr);
-						}
-						else
-							sleep(get_config_integer(c, "lxc.start.delay"));
-					}
-				}
-			}
-			else {
-				/* Start the container */
-				if (!c->is_running(c)) {
-					if (my_args.list) {
-						printf("%s %d\n", c->name,
-						       get_config_integer(c, "lxc.start.delay"));
-						fflush(stdout);
-					}
-					else {
-						if (!c->start(c, 0, NULL)) {
-							fprintf(stderr, "Error starting container: %s\n", c->name);
-							fflush(stderr);
-						}
-						else
-							sleep(get_config_integer(c, "lxc.start.delay"));
-					}
-				}
-			}
-
-			/*
-			 * If we get this far and we haven't hit any skip "continue"
-			 * then we're done with this container...  We can dump any
-			 * c_groups_list and the container itself.
-			 */
-			if ( lxc_container_put(c) > 0 ) {
-				containers[i] = NULL;
-			}
-			if ( c_groups_lists ) {
-				toss_list(c_groups_lists[i]);
-				c_groups_lists[i] = NULL;
-			}
-		}
-
-	}
-
-	/* clean up any lingering detritus */
-	for (i = 0; i < count; i++) {
-		if ( containers[i] ) {
-			lxc_container_put(containers[i]);
-		}
-		if ( c_groups_lists && c_groups_lists[i] ) {
-			toss_list(c_groups_lists[i]);
-		}
-	}
-
-	free(c_groups_lists);
-	toss_list( cmd_groups_list );
-	free(containers);
-
-	return 0;
-}
diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
deleted file mode 100644
index dd60fd1..0000000
--- a/src/lxc/lxc_cgroup.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <libgen.h>
-#include <sys/types.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "lxc.h"
-#include "log.h"
-#include "arguments.h"
-
-lxc_log_define(lxc_cgroup_ui, lxc);
-
-static int my_checker(const struct lxc_arguments* args)
-{
-	if (!args->argc) {
-		lxc_error(args, "missing state object");
-		return -1;
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-cgroup",
-	.help     = "\
---name=NAME state-object [value]\n\
-\n\
-Get or set the value of a state object (for example, 'cpuset.cpus')\n\
-in the container's cgroup for the corresponding subsystem.\n\
-\n\
-Options :\n\
-  -n, --name=NAME      NAME of the container",
-	.options  = my_longopts,
-	.parser   = NULL,
-	.checker  = my_checker,
-};
-
-int main(int argc, char *argv[])
-{
-	char *state_object = NULL, *value = NULL;
-	struct lxc_container *c;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		return 1;
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		return 1;
-	lxc_log_options_no_override();
-
-	state_object = my_args.argv[0];
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c)
-		return 1;
-
-	if (!c->may_control(c)) {
-		ERROR("Insufficent privileges to control %s:%s", my_args.lxcpath[0], my_args.name);
-		lxc_container_put(c);
-		return 1;
-	}
-
-	if (!c->is_running(c)) {
-		ERROR("'%s:%s' is not running", my_args.lxcpath[0], my_args.name);
-		lxc_container_put(c);
-		return 1;
-	}
-
-	if ((my_args.argc) > 1) {
-		value = my_args.argv[1];
-		if (!c->set_cgroup_item(c, state_object, value)) {
-			ERROR("failed to assign '%s' value to '%s' for '%s'",
-				value, state_object, my_args.name);
-			lxc_container_put(c);
-			return 1;
-		}
-	} else {
-		int len = 4096;
-		char buffer[len];
-		int ret = c->get_cgroup_item(c, state_object, buffer, len);
-		if (ret < 0) {
-			ERROR("failed to retrieve value of '%s' for '%s:%s'",
-			      state_object, my_args.lxcpath[0], my_args.name);
-			lxc_container_put(c);
-			return 1;
-		}
-		printf("%*s", ret, buffer);
-	}
-
-	lxc_container_put(c);
-	return 0;
-}
diff --git a/src/lxc/lxc_checkpoint.c b/src/lxc/lxc_checkpoint.c
deleted file mode 100644
index 7130245..0000000
--- a/src/lxc/lxc_checkpoint.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- *
- * Copyright © 2014 Tycho Andersen <tycho.andersen at canonical.com>.
- * Copyright © 2014 Canonical Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "log.h"
-#include "config.h"
-#include "lxc.h"
-#include "arguments.h"
-#include "utils.h"
-
-static char *checkpoint_dir = NULL;
-static bool stop = false;
-static bool verbose = false;
-static bool do_restore = false;
-static bool daemonize_set = false;
-
-static const struct option my_longopts[] = {
-	{"checkpoint-dir", required_argument, 0, 'D'},
-	{"stop", no_argument, 0, 's'},
-	{"verbose", no_argument, 0, 'v'},
-	{"restore", no_argument, 0, 'r'},
-	{"daemon", no_argument, 0, 'd'},
-	{"foreground", no_argument, 0, 'F'},
-	LXC_COMMON_OPTIONS
-};
-
-static int my_checker(const struct lxc_arguments *args)
-{
-	if (do_restore && stop) {
-		lxc_error(args, "-s not compatible with -r.");
-		return -1;
-
-	} else if (!do_restore && daemonize_set) {
-		lxc_error(args, "-d/-F not compatible with -r.");
-		return -1;
-	}
-
-	if (checkpoint_dir == NULL) {
-		lxc_error(args, "-D is required.");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int my_parser(struct lxc_arguments *args, int c, char *arg)
-{
-	switch (c) {
-	case 'D':
-		checkpoint_dir = strdup(arg);
-		if (!checkpoint_dir)
-			return -1;
-		break;
-	case 's':
-		stop = true;
-		break;
-	case 'v':
-		verbose = true;
-		break;
-	case 'r':
-		do_restore = true;
-		break;
-	case 'd':
-		args->daemonize = 1;
-		daemonize_set = true;
-		break;
-	case 'F':
-		args->daemonize = 0;
-		daemonize_set = true;
-		break;
-	}
-	return 0;
-}
-
-static struct lxc_arguments my_args = {
-	.progname  = "lxc-checkpoint",
-	.help      = "\
---name=NAME\n\
-\n\
-lxc-checkpoint checkpoints and restores a container\n\
-  Serializes a container's running state to disk to allow restoring it in\n\
-  its running state at a later time.\n\
-\n\
-Options :\n\
-  -n, --name=NAME           NAME of the container\n\
-  -r, --restore             Restore container\n\
-  -D, --checkpoint-dir=DIR  directory to save the checkpoint in\n\
-  -v, --verbose             Enable verbose criu logs\n\
-  Checkpoint options:\n\
-  -s, --stop                Stop the container after checkpointing.\n\
-  Restore options:\n\
-  -d, --daemon              Daemonize the container (default)\n\
-  -F, --foreground          Start with the current tty attached to /dev/console\n\
-",
-	.options   = my_longopts,
-	.parser    = my_parser,
-	.daemonize = 1,
-	.checker   = my_checker,
-};
-
-static bool checkpoint(struct lxc_container *c)
-{
-	bool ret;
-
-	if (!c->is_running(c)) {
-		fprintf(stderr, "%s not running, not checkpointing.\n", my_args.name);
-		lxc_container_put(c);
-		return false;
-	}
-
-	ret = c->checkpoint(c, checkpoint_dir, stop, verbose);
-	lxc_container_put(c);
-
-	if (!ret) {
-		fprintf(stderr, "Checkpointing %s failed.\n", my_args.name);
-		return false;
-	}
-
-	return true;
-}
-
-static bool restore_finalize(struct lxc_container *c)
-{
-	bool ret = c->restore(c, checkpoint_dir, verbose);
-	if (!ret) {
-		fprintf(stderr, "Restoring %s failed.\n", my_args.name);
-	}
-
-	lxc_container_put(c);
-	return ret;
-}
-
-static bool restore(struct lxc_container *c)
-{
-	if (c->is_running(c)) {
-		fprintf(stderr, "%s is running, not restoring.\n", my_args.name);
-		lxc_container_put(c);
-		return false;
-	}
-
-	if (my_args.daemonize) {
-		pid_t pid;
-
-		pid = fork();
-		if (pid < 0) {
-			perror("fork");
-			return false;
-		}
-
-		if (pid == 0) {
-			close(0);
-			close(1);
-
-			exit(!restore_finalize(c));
-		} else {
-			return wait_for_pid(pid) == 0;
-		}
-	} else {
-		int status;
-
-		if (!restore_finalize(c))
-			return false;
-
-		if (waitpid(-1, &status, 0) < 0)
-			return false;
-
-		return WIFEXITED(status) && WEXITSTATUS(status) == 0;
-	}
-}
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c;
-	bool ret;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		exit(1);
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		exit(1);
-
-	lxc_log_options_no_override();
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c) {
-		fprintf(stderr, "System error loading %s\n", my_args.name);
-		exit(1);
-	}
-
-	if (!c->may_control(c)) {
-		fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
-		lxc_container_put(c);
-		exit(1);
-	}
-
-	if (!c->is_defined(c)) {
-		fprintf(stderr, "%s is not defined\n", my_args.name);
-		lxc_container_put(c);
-		exit(1);
-	}
-
-
-	if (do_restore)
-		ret = restore(c);
-	else
-		ret = checkpoint(c);
-
-	return !ret;
-}
diff --git a/src/lxc/lxc_clone.c b/src/lxc/lxc_clone.c
deleted file mode 100644
index 6bd2226..0000000
--- a/src/lxc/lxc_clone.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- *
- * Copyright © 2013 Serge Hallyn <serge.hallyn at ubuntu.com>.
- * Copyright © 2013 Canonical Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <unistd.h>
-#include <getopt.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <stdint.h>
-#include <sys/wait.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "log.h"
-#include "config.h"
-#include "lxc.h"
-#include "conf.h"
-#include "state.h"
-
-lxc_log_define(lxc_clone_ui, lxc);
-
-/* we pass fssize in bytes */
-static uint64_t get_fssize(char *s)
-{
-	uint64_t ret;
-	char *end;
-
-	ret = strtoull(s, &end, 0);
-	if (end == s)
-	{
-		fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
-		return 0;
-	}
-	while (isblank(*end))
-		end++;
-	if (*end == '\0')
-		ret *= 1024ULL * 1024ULL; // MB by default
-	else if (*end == 'b' || *end == 'B')
-		ret *= 1ULL;
-	else if (*end == 'k' || *end == 'K')
-		ret *= 1024ULL;
-	else if (*end == 'm' || *end == 'M')
-		ret *= 1024ULL * 1024ULL;
-	else if (*end == 'g' || *end == 'G')
-		ret *= 1024ULL * 1024ULL * 1024ULL;
-	else if (*end == 't' || *end == 'T')
-		ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
-	else
-	{
-		fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s);
-		return 0;
-	}
-	return ret;
-}
-
-static void usage(const char *me)
-{
-	printf("Usage: %s [-s] [-B backingstore] [-L size[unit]] [-K] [-M] [-H]\n", me);
-	printf("          [-p lxcpath] [-P newlxcpath] orig new\n");
-	printf("\n");
-	printf("  -s: snapshot rather than copy\n");
-	printf("  -B: use specified new backingstore.  Default is the same as\n");
-	printf("      the original.  Options include aufs, btrfs, lvm, overlayfs, \n");
-	printf("      dir and loop\n");
-	printf("  -L: for blockdev-backed backingstore, use specified size * specified\n");
-	printf("      unit. Default size is the size of the source blockdev, default\n");
-	printf("      unit is MB\n");
-	printf("  -K: Keep name - do not change the container name\n");
-	printf("  -M: Keep macaddr - do not choose a random new mac address\n");
-	printf("  -p: use container orig from custom lxcpath\n");
-	printf("  -P: create container new in custom lxcpath\n");
-	printf("  -R: rename existing container\n");
-	exit(1);
-}
-
-static struct option options[] = {
-	{ "snapshot", no_argument, 0, 's'},
-	{ "backingstore", required_argument, 0, 'B'},
-	{ "size", required_argument, 0, 'L'},
-	{ "orig", required_argument, 0, 'o'},
-	{ "new", required_argument, 0, 'n'},
-	{ "vgname", required_argument, 0, 'v'},
-	{ "rename", no_argument, 0, 'R'},
-	{ "keepname", no_argument, 0, 'K'},
-	{ "keepmac", no_argument, 0, 'M'},
-	{ "lxcpath", required_argument, 0, 'p'},
-	{ "newpath", required_argument, 0, 'P'},
-	{ "fstype", required_argument, 0, 't'},
-	{ "help", no_argument, 0, 'h'},
-	{ 0, 0, 0, 0 },
-};
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c1 = NULL, *c2 = NULL;
-	int snapshot = 0, keepname = 0, keepmac = 0, rename = 0;
-	int flags = 0, option_index;
-	uint64_t newsize = 0;
-	char *bdevtype = NULL, *lxcpath = NULL, *newpath = NULL, *fstype = NULL;
-	char *orig = NULL, *new = NULL, *vgname = NULL;
-	char **args = NULL;
-	int c;
-	bool ret;
-
-	fprintf(stderr, "lxc-clone is deprecated in favor of lxc-copy.\n\n");
-
-	if (argc < 3)
-		usage(argv[0]);
-
-	while (1) {
-		c = getopt_long(argc, argv, "sB:L:o:n:v:KMHp:P:Rt:h", options, &option_index);
-		if (c == -1)
-			break;
-		switch (c) {
-		case 's': snapshot = 1; break;
-		case 'B': bdevtype = optarg; break;
-		case 'L': newsize = get_fssize(optarg); break;
-		case 'o': orig = optarg; break;
-		case 'n': new = optarg; break;
-		case 'v': vgname = optarg; break;
-		case 'K': keepname = 1; break;
-		case 'M': keepmac = 1; break;
-		case 'p': lxcpath = optarg; break;
-		case 'P': newpath = optarg; break;
-		case 'R': rename = 1; break;
-		case 't': fstype = optarg; break;
-		case 'h': usage(argv[0]);
-		default: break;
-		}
-	}
-    if (optind < argc && !orig)
-		orig = argv[optind++];
-    if (optind < argc && !new)
-		new = argv[optind++];
-	if (optind < argc)
-		/* arguments for the clone hook */
-		args = &argv[optind];
-	if (!new || !orig) {
-		printf("Error: you must provide orig and new names\n");
-		usage(argv[0]);
-	}
-
-	if (snapshot)  flags |= LXC_CLONE_SNAPSHOT;
-	if (keepname)  flags |= LXC_CLONE_KEEPNAME;
-	if (keepmac)   flags |= LXC_CLONE_KEEPMACADDR;
-
-	// vgname and fstype could be supported by sending them through the
-	// bdevdata.  However, they currently are not yet.  I'm not convinced
-	// they are worthwhile.
-	if (vgname) {
-		printf("Error: vgname not supported\n");
-		usage(argv[0]);
-	}
-	if (fstype) {
-		printf("Error: fstype not supported\n");
-		usage(argv[0]);
-	}
-
-	c1 = lxc_container_new(orig, lxcpath);
-	if (!c1)
-		exit(EXIT_FAILURE);
-
-	if (!c1->may_control(c1)) {
-		fprintf(stderr, "Insufficent privileges to control %s\n", orig);
-		lxc_container_put(c1);
-		exit(EXIT_FAILURE);
-	}
-
-	if (!c1->is_defined(c1)) {
-		fprintf(stderr, "Error: container %s is not defined\n", orig);
-		lxc_container_put(c1);
-		exit(EXIT_FAILURE);
-	}
-	if (rename) {
-		ret = c1->rename(c1, new);
-		if (!ret) {
-			fprintf(stderr,
-				"Error: Renaming container %s to %s failed\n",
-				c1->name, new);
-			lxc_container_put(c1);
-			exit(EXIT_FAILURE);
-		}
-	} else {
-		c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize,
-			       args);
-		if (c2 == NULL) {
-			lxc_container_put(c1);
-			fprintf(stderr, "clone failed\n");
-			exit(EXIT_FAILURE);
-		}
-		printf("Created container %s as %s of %s\n", new,
-		       snapshot ? "snapshot" : "copy", orig);
-		lxc_container_put(c2);
-	}
-	lxc_container_put(c1);
-
-	exit(EXIT_SUCCESS);
-}
diff --git a/src/lxc/lxc_config.c b/src/lxc/lxc_config.c
deleted file mode 100644
index d146ad8..0000000
--- a/src/lxc/lxc_config.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/* lxc_config
- *
- * Copyright © 2012 Serge Hallyn <serge.hallyn at ubuntu.com>.
- * Copyright © 2012 Canonical Ltd.
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
-
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
-
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "config.h"
-
-struct lxc_config_items {
-	char *name;
-};
-
-static struct lxc_config_items items[] =
-{
-	{ .name = "lxc.default_config", },
-	{ .name = "lxc.lxcpath", },
-	{ .name = "lxc.bdev.lvm.vg", },
-	{ .name = "lxc.bdev.lvm.thin_pool", },
-	{ .name = "lxc.bdev.zfs.root", },
-	{ .name = "lxc.cgroup.use", },
-	{ .name = "lxc.cgroup.pattern", },
-	{ .name = NULL, },
-};
-
-static void usage(char *me)
-{
-	printf("Usage: %s -l: list all available configuration items\n", me);
-	printf("       %s item: print configuration item\n", me);
-	exit(1);
-}
-
-static void list_config_items(void)
-{
-	struct lxc_config_items *i;
-
-	for (i = &items[0]; i->name; i++)
-		printf("%s\n", i->name);
-	exit(0);
-}
-
-int main(int argc, char *argv[])
-{
-	struct lxc_config_items *i;
-	const char *value;
-
-	if (argc < 2)
-		usage(argv[0]);
-	if (strcmp(argv[1], "-l") == 0)
-		list_config_items();
-	for (i = &items[0]; i->name; i++) {
-		if (strcmp(argv[1], i->name) == 0) {
-			value = lxc_get_global_config_item(i->name);
-			if (value)
-				printf("%s\n", value);
-			else
-				printf("%s is not set.\n", argv[1]);
-			exit(0);
-		}
-	}
-	printf("Unknown configuration item: %s\n", argv[1]);
-	exit(1);
-}
diff --git a/src/lxc/lxc_console.c b/src/lxc/lxc_console.c
deleted file mode 100644
index adbd7e0..0000000
--- a/src/lxc/lxc_console.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#undef _GNU_SOURCE
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <signal.h>
-#include <libgen.h>
-#include <poll.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "error.h"
-#include "lxc.h"
-#include "log.h"
-#include "mainloop.h"
-#include "arguments.h"
-#include "commands.h"
-
-lxc_log_define(lxc_console_ui, lxc);
-
-static char etoc(const char *expr)
-{
-	/* returns "control code" of given expression */
-	char c = expr[0] == '^' ? expr[1] : expr[0];
-	return 1 + ((c > 'Z') ? (c - 'a') : (c - 'Z'));
-}
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	switch (c) {
-	case 't': args->ttynum = atoi(arg); break;
-	case 'e': args->escape = etoc(arg); break;
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	{"tty", required_argument, 0, 't'},
-	{"escape", required_argument, 0, 'e'},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-console",
-	.help     = "\
---name=NAME [--tty NUMBER]\n\
-\n\
-lxc-console logs on the container with the identifier NAME\n\
-\n\
-Options :\n\
-  -n, --name=NAME      NAME of the container\n\
-  -t, --tty=NUMBER     console tty number\n\
-  -e, --escape=PREFIX  prefix for escape command\n",
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = NULL,
-	.ttynum = -1,
-	.escape = 1,
-};
-
-int main(int argc, char *argv[])
-{
-	int ret;
-	struct lxc_container *c;
-
-	ret = lxc_arguments_parse(&my_args, argc, argv);
-	if (ret)
-		return EXIT_FAILURE;
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			   my_args.progname, my_args.quiet, my_args.lxcpath[0]);
-	if (ret)
-		return EXIT_FAILURE;
-	lxc_log_options_no_override();
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c) {
-		fprintf(stderr, "System error loading container\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if (!c->may_control(c)) {
-		fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
-		lxc_container_put(c);
-		exit(EXIT_FAILURE);
-	}
-
-	if (!c->is_running(c)) {
-		fprintf(stderr, "%s is not running\n", my_args.name);
-		lxc_container_put(c);
-		exit(EXIT_FAILURE);
-	}
-
-	ret = c->console(c, my_args.ttynum, 0, 1, 2, my_args.escape);
-	if (ret < 0) {
-		lxc_container_put(c);
-		exit(EXIT_FAILURE);
-	}
-	lxc_container_put(c);
-	return EXIT_SUCCESS;
-}
diff --git a/src/lxc/lxc_copy.c b/src/lxc/lxc_copy.c
deleted file mode 100644
index 9f653e3..0000000
--- a/src/lxc/lxc_copy.c
+++ /dev/null
@@ -1,877 +0,0 @@
-/*
- *
- * Copyright © 2015 Christian Brauner <christian.brauner at mailbox.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "config.h"
-
-#include <unistd.h>
-#include <getopt.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <stdint.h>
-#include <sys/wait.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <time.h>
-#include <stdbool.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "attach.h"
-#include "bdev.h"
-#include "log.h"
-#include "confile.h"
-#include "arguments.h"
-#include "lxc.h"
-#include "conf.h"
-#include "state.h"
-#include "utils.h"
-
-#ifndef HAVE_GETSUBOPT
-#include <../include/getsubopt.h>
-#endif
-
-lxc_log_define(lxc_copy_ui, lxc);
-
-enum mnttype {
-	LXC_MNT_BIND,
-	LXC_MNT_AUFS,
-	LXC_MNT_OVL,
-};
-
-struct mnts {
-	enum mnttype mnt_type;
-	char *src;
-	char *dest;
-	char *options;
-	char *upper;
-	char *workdir;
-	char *lower;
-};
-
-static unsigned int mnt_table_size = 0;
-static struct mnts *mnt_table = NULL;
-
-static int my_parser(struct lxc_arguments *args, int c, char *arg);
-
-static const struct option my_longopts[] = {
-	{ "newname", required_argument, 0, 'N'},
-	{ "newpath", required_argument, 0, 'p'},
-	{ "rename", no_argument, 0, 'R'},
-	{ "snapshot", no_argument, 0, 's'},
-	{ "foreground", no_argument, 0, 'F'},
-	{ "daemon", no_argument, 0, 'd'},
-	{ "ephemeral", no_argument, 0, 'e'},
-	{ "mount", required_argument, 0, 'm'},
-	{ "backingstore", required_argument, 0, 'B'},
-	{ "fssize", required_argument, 0, 'L'},
-	{ "keepdata", no_argument, 0, 'D'},
-	{ "keepname", no_argument, 0, 'K'},
-	{ "keepmac", no_argument, 0, 'M'},
-	{ "tmpfs", no_argument, 0, 't'},
-	LXC_COMMON_OPTIONS
-};
-
-/* mount keys */
-static char *const keys[] = {
-	[LXC_MNT_BIND] = "bind",
-	[LXC_MNT_AUFS] = "aufs",
-	[LXC_MNT_OVL] = "overlay",
-	NULL
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-copy",
-	.help = "\n\
---name=NAME [-P lxcpath] -N newname [-p newpath] [-B backingstorage] [-s] [-K] [-M] [-L size [unit]] -- hook options\n\
---name=NAME [-P lxcpath] [-N newname] [-p newpath] [-B backingstorage] -e [-d] [-D] [-K] [-M] [-m {bind,aufs,overlay}=/src:/dest] -- hook options\n\
---name=NAME [-P lxcpath] -N newname -R\n\
-\n\
-lxc-copy clone a container\n\
-\n\
-Options :\n\
-  -n, --name=NAME           NAME of the container\n\
-  -N, --newname=NEWNAME     NEWNAME for the restored container\n\
-  -p, --newpath=NEWPATH     NEWPATH for the container to be stored\n\
-  -R, --rename		    rename container\n\
-  -s, --snapshot	    create snapshot instead of clone\n\
-  -F, --foreground	    start with current tty attached to /dev/console\n\
-  -d, --daemon		    daemonize the container (default)\n\
-  -e, --ephemeral	    start ephemeral container\n\
-  -m, --mount	            directory to mount into container, either \n\
-			    {bind,aufs,overlay}=/src-path or {bind,aufs,overlay}=/src-path:/dst-path\n\
-  -B, --backingstorage=TYPE backingstorage type for the container\n\
-  -t, --tmpfs		    place ephemeral container on a tmpfs\n\
-			    (WARNING: On reboot all changes made to the container will be lost.)\n\
-  -L, --fssize		    size of the new block device for block device containers\n\
-  -D, --keedata	            pass together with -e start a persistent snapshot \n\
-  -K, --keepname	    keep the hostname of the original container\n\
-  --  hook options	    arguments passed to the hook program\n\
-  -M, --keepmac		    keep the MAC address of the original container\n",
-	.options = my_longopts,
-	.parser = my_parser,
-	.task = CLONE,
-	.daemonize = 1,
-	.quiet = false,
-	.tmpfs = false,
-};
-
-static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num,
-			    enum mnttype type);
-static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num,
-			    struct lxc_arguments *arg);
-static char *construct_path(char *path, bool as_prefix);
-static char *set_mnt_entry(struct mnts *m);
-static int do_clone(struct lxc_container *c, char *newname, char *newpath,
-		    int flags, char *bdevtype, uint64_t fssize, enum task task,
-		    char **args);
-static int do_clone_ephemeral(struct lxc_container *c,
-			      struct lxc_arguments *arg, char **args,
-			      int flags);
-static int do_clone_rename(struct lxc_container *c, char *newname);
-static int do_clone_task(struct lxc_container *c, enum task task, int flags,
-			 char **args);
-static void free_mnts(void);
-static uint64_t get_fssize(char *s);
-
-/* Place an ephemeral container started with -e flag on a tmpfs. Restrictions
- * are that you cannot request the data to be kept while placing the container
- * on a tmpfs and that either overlay or aufs backing storage must be used.
- */
-static char *mount_tmpfs(const char *oldname, const char *newname,
-			 const char *path, struct lxc_arguments *arg);
-static int parse_mntsubopts(char *subopts, char *const *keys,
-			    char *mntparameters);
-static int parse_aufs_mnt(char *mntstring, enum mnttype type);
-static int parse_bind_mnt(char *mntstring, enum mnttype type);
-static int parse_ovl_mnt(char *mntstring, enum mnttype type);
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c;
-	int flags = 0;
-	int ret = EXIT_FAILURE;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		exit(ret);
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		exit(ret);
-	lxc_log_options_no_override();
-
-	if (geteuid()) {
-		if (access(my_args.lxcpath[0], O_RDWR) < 0) {
-			if (!my_args.quiet)
-				fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
-			exit(ret);
-		}
-	}
-
-	if (!my_args.newname && !(my_args.task == DESTROY)) {
-		if (!my_args.quiet)
-			printf("Error: You must provide a NEWNAME for the clone.\n");
-		exit(ret);
-	}
-
-	if (my_args.task == SNAP || my_args.task == DESTROY)
-		flags |= LXC_CLONE_SNAPSHOT;
-	if (my_args.keepname)
-		flags |= LXC_CLONE_KEEPNAME;
-	if (my_args.keepmac)
-		flags |= LXC_CLONE_KEEPMACADDR;
-
-	if (!my_args.newpath)
-		my_args.newpath = (char *)my_args.lxcpath[0];
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c)
-		exit(ret);
-
-	if (!c->may_control(c)) {
-		if (!my_args.quiet)
-			fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
-		goto out;
-	}
-
-	if (!c->is_defined(c)) {
-		if (!my_args.quiet)
-			fprintf(stderr, "Error: container %s is not defined\n", c->name);
-		goto out;
-	}
-
-	ret = do_clone_task(c, my_args.task, flags, &argv[optind]);
-
-out:
-	lxc_container_put(c);
-
-	if (ret == 0)
-		exit(EXIT_SUCCESS);
-	exit(EXIT_FAILURE);
-}
-
-static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num, enum mnttype type)
-{
-	struct mnts *m, *n;
-
-	n = realloc(*mnts, (*num + 1) * sizeof(struct mnts));
-	if (!n)
-		return NULL;
-
-	*mnts = n;
-	m = *mnts + *num;
-	(*num)++;
-
-	*m = (struct mnts) {.mnt_type = type};
-
-	return m;
-}
-
-static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_arguments *arg)
-{
-	char upperdir[MAXPATHLEN];
-	char workdir[MAXPATHLEN];
-	unsigned int i;
-	int ret;
-	struct mnts *m = NULL;
-
-	for (i = 0, m = mnts; i < num; i++, m++) {
-		if ((m->mnt_type == LXC_MNT_OVL) || (m->mnt_type == LXC_MNT_AUFS)) {
-			ret = snprintf(upperdir, MAXPATHLEN, "%s/%s/delta#XXXXXX",
-					arg->newpath, arg->newname);
-			if (ret < 0 || ret >= MAXPATHLEN)
-				return -1;
-			if (!mkdtemp(upperdir))
-				return -1;
-			m->upper = strdup(upperdir);
-			if (!m->upper)
-				return -1;
-		}
-
-		if (m->mnt_type == LXC_MNT_OVL) {
-			ret = snprintf(workdir, MAXPATHLEN, "%s/%s/work#XXXXXX",
-					arg->newpath, arg->newname);
-			if (ret < 0 || ret >= MAXPATHLEN)
-				return -1;
-			if (!mkdtemp(workdir))
-				return -1;
-			m->workdir = strdup(workdir);
-			if (!m->workdir)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-static char *construct_path(char *path, bool as_prefix)
-{
-	char **components = NULL;
-	char *cleanpath = NULL;
-
-	components = lxc_normalize_path(path);
-	if (!components)
-		return NULL;
-
-	cleanpath = lxc_string_join("/", (const char **)components, as_prefix);
-	lxc_free_array((void **)components, free);
-
-	return cleanpath;
-}
-
-static char *set_mnt_entry(struct mnts *m)
-{
-	char *mntentry = NULL;
-	int ret = 0;
-	size_t len = 0;
-
-	if (m->mnt_type == LXC_MNT_AUFS) {
-		len = strlen("  aufs br==rw:=ro,xino=,create=dir") +
-		      2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
-		      strlen(m->workdir) + 1;
-
-		mntentry = malloc(len);
-		if (!mntentry)
-			goto err;
-
-		ret = snprintf(mntentry, len, "%s %s aufs br=%s=rw:%s=ro,xino=%s,create=dir",
-			       m->src, m->dest, m->upper, m->src, m->workdir);
-		if (ret < 0 || (size_t)ret >= len)
-			goto err;
-	} else if (m->mnt_type == LXC_MNT_OVL) {
-		len = strlen("  overlay lowerdir=,upperdir=,workdir=,create=dir") +
-		      2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
-		      strlen(m->workdir) + 1;
-
-		mntentry = malloc(len);
-		if (!mntentry)
-			goto err;
-
-		ret = snprintf(mntentry, len, "%s %s overlay lowerdir=%s,upperdir=%s,workdir=%s,create=dir",
-				m->src, m->dest, m->src, m->upper, m->workdir);
-		if (ret < 0 || (size_t)ret >= len)
-			goto err;
-	} else if (m->mnt_type == LXC_MNT_BIND) {
-		len = strlen("  none bind,optional,, 0 0") +
-		      strlen(is_dir(m->src) ? "create=dir" : "create=file") +
-		      strlen(m->src) + strlen(m->dest) + strlen(m->options) + 1;
-
-		mntentry = malloc(len);
-		if (!mntentry)
-			goto err;
-
-		ret = snprintf(mntentry, len, "%s %s none bind,optional,%s,%s 0 0",
-				m->src,	m->dest, m->options,
-				is_dir(m->src) ? "create=dir" : "create=file");
-		if (ret < 0 || (size_t)ret >= len)
-			goto err;
-	}
-
-	return mntentry;
-
-err:
-	free(mntentry);
-	return NULL;
-}
-
-static int do_clone(struct lxc_container *c, char *newname, char *newpath,
-		    int flags, char *bdevtype, uint64_t fssize, enum task task,
-		    char **args)
-{
-	struct lxc_container *clone;
-
-	clone = c->clone(c, newname, newpath, flags, bdevtype, NULL, fssize,
-			 args);
-	if (!clone) {
-		if (!my_args.quiet)
-			fprintf(stderr, "clone failed\n");
-		return -1;
-	}
-
-	INFO("Created %s as %s of %s\n", newname, task ? "snapshot" : "copy", c->name);
-
-	lxc_container_put(clone);
-
-	return 0;
-}
-
-static int do_clone_ephemeral(struct lxc_container *c,
-		struct lxc_arguments *arg, char **args, int flags)
-{
-	char *bdev;
-	char *premount;
-	char randname[MAXPATHLEN];
-	unsigned int i;
-	int ret = 0;
-	bool bret = true, started = false;
-	struct lxc_container *clone;
-	lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
-	attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
-
-	if (!arg->newname) {
-		ret = snprintf(randname, MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name);
-		if (ret < 0 || ret >= MAXPATHLEN)
-			return -1;
-		if (!mkdtemp(randname))
-			return -1;
-		if (chmod(randname, 0770) < 0) {
-			remove(randname);
-			return -1;
-		}
-		arg->newname = randname + strlen(arg->newpath) + 1;
-	}
-
-	clone = c->clone(c, arg->newname, arg->newpath, flags,
-			 arg->bdevtype, NULL, arg->fssize, args);
-	if (!clone)
-		return -1;
-
-	if (arg->tmpfs) {
-		bdev = c->lxc_conf->rootfs.bdev_type;
-		if (bdev && strcmp(bdev, "dir")) {
-			fprintf(stderr, "Cannot currently use tmpfs with %s storage backend.\n", bdev);
-			goto destroy_and_put;
-		}
-
-		premount = mount_tmpfs(arg->name, arg->newname, arg->newpath, arg);
-		if (!premount)
-			goto destroy_and_put;
-
-		bret = clone->set_config_item(clone, "lxc.hook.pre-mount", premount);
-		free(premount);
-		if (!bret)
-			goto destroy_and_put;
-	}
-
-	if (!arg->keepdata)
-		if (!clone->set_config_item(clone, "lxc.ephemeral", "1"))
-			goto destroy_and_put;
-
-	/* allocate and create random upper- and workdirs for overlay mounts */
-	if (mk_rand_ovl_dirs(mnt_table, mnt_table_size, arg) < 0)
-		goto destroy_and_put;
-
-	/* allocate and set mount entries */
-	struct mnts *n = NULL;
-	for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
-		char *mntentry = NULL;
-		mntentry = set_mnt_entry(n);
-		if (!mntentry)
-			goto destroy_and_put;
-		bret = clone->set_config_item(clone, "lxc.mount.entry", mntentry);
-		free(mntentry);
-		if (!bret)
-			goto destroy_and_put;
-	}
-
-	if (!clone->save_config(clone, NULL))
-		goto destroy_and_put;
-
-	if (!my_args.quiet)
-		printf("Created %s as clone of %s\n", arg->newname, arg->name);
-
-	if (arg->tmpfs && !my_args.quiet)
-		printf("Container is placed on tmpfs.\nRebooting will cause "
-		       "all changes made to it to be lost!");
-
-	if (!arg->daemonize && arg->argc) {
-		clone->want_daemonize(clone, true);
-		arg->daemonize = 1;
-	} else if (!arg->daemonize) {
-		clone->want_daemonize(clone, false);
-	}
-
-	started = clone->start(clone, 0, NULL);
-	if (!started)
-		goto destroy_and_put;
-
-	if (arg->daemonize && arg->argc) {
-		ret = clone->attach_run_wait(clone, &attach_options, arg->argv[0], (const char *const *)arg->argv);
-		if (ret < 0)
-			goto destroy_and_put;
-		clone->shutdown(clone, -1);
-	}
-
-	free_mnts();
-	lxc_container_put(clone);
-	return 0;
-
-destroy_and_put:
-	if (started)
-		clone->shutdown(clone, -1);
-	if (!started || clone->lxc_conf->ephemeral != 1)
-		clone->destroy(clone);
-	free_mnts();
-	lxc_container_put(clone);
-	return -1;
-}
-
-static int do_clone_rename(struct lxc_container *c, char *newname)
-{
-	if (!c->rename(c, newname)) {
-		ERROR("Error: Renaming container %s to %s failed\n", c->name, newname);
-		return -1;
-	}
-
-	INFO("Renamed container %s to %s\n", c->name, newname);
-
-	return 0;
-}
-
-static int do_clone_task(struct lxc_container *c, enum task task, int flags,
-			 char **args)
-{
-	int ret = 0;
-
-	switch (task) {
-	case DESTROY:
-		ret = do_clone_ephemeral(c, &my_args, args, flags);
-		break;
-	case RENAME:
-		ret = do_clone_rename(c, my_args.newname);
-		break;
-	default:
-		ret = do_clone(c, my_args.newname, my_args.newpath, flags,
-			       my_args.bdevtype, my_args.fssize, my_args.task,
-			       args);
-		break;
-	}
-
-	return ret;
-}
-
-static void free_mnts()
-{
-	unsigned int i;
-	struct mnts *n = NULL;
-
-	for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
-		free(n->src);
-		free(n->dest);
-		free(n->options);
-		free(n->upper);
-		free(n->workdir);
-	}
-	free(mnt_table);
-	mnt_table = NULL;
-	mnt_table_size = 0;
-}
-
-/* we pass fssize in bytes */
-static uint64_t get_fssize(char *s)
-{
-	uint64_t ret;
-	char *end;
-
-	ret = strtoull(s, &end, 0);
-	if (end == s) {
-		if (!my_args.quiet)
-			fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
-		return 0;
-	}
-	while (isblank(*end))
-		end++;
-	if (*end == '\0') {
-		ret *= 1024ULL * 1024ULL; // MB by default
-	} else if (*end == 'b' || *end == 'B') {
-		ret *= 1ULL;
-	} else if (*end == 'k' || *end == 'K') {
-		ret *= 1024ULL;
-	} else if (*end == 'm' || *end == 'M') {
-		ret *= 1024ULL * 1024ULL;
-	} else if (*end == 'g' || *end == 'G') {
-		ret *= 1024ULL * 1024ULL * 1024ULL;
-	} else if (*end == 't' || *end == 'T') {
-		ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
-	} else {
-		if (!my_args.quiet)
-			fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', " "using default size\n", *end, s);
-		return 0;
-	}
-
-	return ret;
-}
-
-static int my_parser(struct lxc_arguments *args, int c, char *arg)
-{
-	char *subopts = NULL;
-	char *mntparameters = NULL;
-	switch (c) {
-	case 'N':
-		args->newname = arg;
-		break;
-	case 'p':
-		args->newpath = arg;
-		break;
-	case 'R':
-		args->task = RENAME;
-		break;
-	case 's':
-		args->task = SNAP;
-		break;
-	case 'F':
-		args->daemonize = 0;
-		break;
-	case 'd':
-		args->daemonize = 1;
-		break;
-	case 'e':
-		args->task = DESTROY;
-		break;
-	case 'm':
-		subopts = optarg;
-		if (parse_mntsubopts(subopts, keys, mntparameters) < 0)
-			return -1;
-		break;
-	case 'B':
-		args->bdevtype = arg;
-		break;
-	case 't':
-		args->tmpfs = true;
-		break;
-	case 'L':
-		args->fssize = get_fssize(optarg);
-		break;
-	case 'D':
-		args->keepdata = 1;
-		break;
-	case 'K':
-		args->keepname = 1;
-		break;
-	case 'M':
-		args->keepmac = 1;
-		break;
-	}
-
-	return 0;
-}
-
-static int parse_aufs_mnt(char *mntstring, enum mnttype type)
-{
-	int len = 0;
-	const char *xinopath = "/dev/shm/aufs.xino";
-	char **mntarray = NULL;
-	struct mnts *m = NULL;
-
-	m = add_mnt(&mnt_table, &mnt_table_size, type);
-	if (!m)
-		goto err;
-
-	mntarray = lxc_string_split(mntstring, ':');
-	if (!mntarray)
-		goto err;
-
-	m->src = construct_path(mntarray[0], true);
-	if (!m->src)
-		goto err;
-
-	len = lxc_array_len((void **)mntarray);
-	if (len == 1) /* aufs=src */
-		m->dest = construct_path(mntarray[0], false);
-	else if (len == 2) /* aufs=src:dest */
-		m->dest = construct_path(mntarray[1], false);
-	else
-		INFO("Excess elements in mount specification");
-
-	if (!m->dest)
-		goto err;
-
-	m->workdir = strdup(xinopath);
-	if (!m->workdir)
-		goto err;
-
-	lxc_free_array((void **)mntarray, free);
-	return 0;
-
-err:
-	free_mnts();
-	lxc_free_array((void **)mntarray, free);
-	return -1;
-}
-
-static int parse_bind_mnt(char *mntstring, enum mnttype type)
-{
-	int len = 0;
-	char **mntarray = NULL;
-	struct mnts *m = NULL;
-
-	m = add_mnt(&mnt_table, &mnt_table_size, type);
-	if (!m)
-		goto err;
-
-	mntarray = lxc_string_split(mntstring, ':');
-	if (!mntarray)
-		goto err;
-
-	m->src = construct_path(mntarray[0], true);
-	if (!m->src)
-		goto err;
-
-	len = lxc_array_len((void **)mntarray);
-	if (len == 1) { /* bind=src */
-		m->dest = construct_path(mntarray[0], false);
-	} else if (len == 2) { /* bind=src:option or bind=src:dest */
-		if (strncmp(mntarray[1], "rw", strlen(mntarray[1])) == 0)
-			m->options = strdup("rw");
-
-		if (strncmp(mntarray[1], "ro", strlen(mntarray[1])) == 0)
-			m->options = strdup("ro");
-
-		if (m->options)
-			m->dest = construct_path(mntarray[0], false);
-		else
-			m->dest = construct_path(mntarray[1], false);
-	} else if (len == 3) { /* bind=src:dest:option */
-			m->dest = construct_path(mntarray[1], false);
-			m->options = strdup(mntarray[2]);
-	} else {
-		INFO("Excess elements in mount specification");
-	}
-
-	if (!m->dest)
-		goto err;
-
-	if (!m->options)
-		m->options = strdup("rw");
-
-	if (!m->options || (strncmp(m->options, "rw", strlen(m->options)) &&
-			    strncmp(m->options, "ro", strlen(m->options))))
-		goto err;
-
-	lxc_free_array((void **)mntarray, free);
-	return 0;
-
-err:
-	free_mnts();
-	lxc_free_array((void **)mntarray, free);
-	return -1;
-}
-
-static int parse_mntsubopts(char *subopts, char *const *keys, char *mntparameters)
-{
-	while (*subopts != '\0') {
-		switch (getsubopt(&subopts, keys, &mntparameters)) {
-		case LXC_MNT_BIND:
-			if (parse_bind_mnt(mntparameters, LXC_MNT_BIND) < 0)
-				return -1;
-			break;
-		case LXC_MNT_OVL:
-			if (parse_ovl_mnt(mntparameters, LXC_MNT_OVL) < 0)
-				return -1;
-			break;
-		case LXC_MNT_AUFS:
-			if (parse_aufs_mnt(mntparameters, LXC_MNT_AUFS) < 0)
-				return -1;
-			break;
-		default:
-			break;
-		}
-	}
-	return 0;
-}
-
-static int parse_ovl_mnt(char *mntstring, enum mnttype type)
-{
-	int len = 0;
-	char **mntarray = NULL;
-	struct mnts *m;
-
-	m = add_mnt(&mnt_table, &mnt_table_size, type);
-	if (!m)
-		goto err;
-
-	mntarray = lxc_string_split(mntstring, ':');
-	if (!mntarray)
-		goto err;
-
-	m->src = construct_path(mntarray[0], true);
-	if (!m->src)
-		goto err;
-
-	len = lxc_array_len((void **)mntarray);
-	if (len == 1) /* overlay=src */
-		m->dest = construct_path(mntarray[0], false);
-	else if (len == 2) /* overlay=src:dest */
-		m->dest = construct_path(mntarray[1], false);
-	else
-		INFO("Excess elements in mount specification");
-
-	if (!m->dest)
-		goto err;
-
-	lxc_free_array((void **)mntarray, free);
-	return 0;
-
-err:
-	free_mnts();
-	lxc_free_array((void **)mntarray, free);
-	return -1;
-}
-
-/* For ephemeral snapshots backed by overlay or aufs filesystems, this function
- * mounts a fresh tmpfs over the containers directory if the user requests it.
- * Because we mount a fresh tmpfs over the directory of the container the
- * updated /etc/hostname file created during the clone residing in the upperdir
- * (currently named "delta0" by default) will be hidden. Hence, if the user
- * requests that the old name is not to be kept for the clone, we recreate this
- * file on the tmpfs. This should be all that is required to restore the exact
- * behaviour we would get with a normal clone.
- */
-static char *mount_tmpfs(const char *oldname, const char *newname,
-			 const char *path, struct lxc_arguments *arg)
-{
-	int ret, fd;
-	size_t len;
-	char *premount = NULL;
-	FILE *fp;
-
-	if (arg->tmpfs && arg->keepdata) {
-		fprintf(stderr, "%s\n", "A container can only be placed on a "
-					"tmpfs when storage backend is overlay "
-					"or aufs.");
-		goto err_free;
-	}
-
-	if (arg->tmpfs && !arg->bdevtype) {
-		arg->bdevtype = "overlayfs";
-	} else if (arg->tmpfs && arg->bdevtype && strcmp(arg->bdevtype, "overlayfs") && strcmp(arg->bdevtype, "aufs")) {
-		fprintf(stderr, "%s\n", "A container can only be placed on a "
-					"tmpfs when storage backend is overlay "
-					"or aufs.");
-		goto err_free;
-	}
-
-	len = strlen(path) + strlen(newname) + strlen("pre-start-XXXXXX") + /* //\0 */ 3;
-	premount = malloc(len);
-	if (!premount)
-		goto err_free;
-
-	ret = snprintf(premount, len, "%s/%s/pre-start-XXXXXX", path, newname);
-	if (ret < 0 || (size_t)ret >= len)
-		goto err_free;
-
-	fd = mkstemp(premount);
-	if (fd < 0)
-		goto err_free;
-
-	if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
-		SYSERROR("Failed to set close-on-exec on file descriptor.");
-		goto err_close;
-	}
-
-	if (chmod(premount, 0755) < 0)
-		goto err_close;
-
-	fp = fdopen(fd, "r+");
-	if (!fp)
-		goto err_close;
-	fd = -1;
-
-	ret = fprintf(fp, "#! /bin/sh\n"
-			  "mount -n -t tmpfs -o mode=0755 none %s/%s\n",
-		      path, newname);
-	if (ret < 0)
-		goto err_close;
-
-	if (!arg->keepname) {
-		ret = fprintf(fp, "mkdir -p %s/%s/delta0/etc\n"
-				  "echo %s > %s/%s/delta0/etc/hostname\n",
-			      path, newname, newname, path, newname);
-		if (ret < 0)
-			goto err_close;
-	}
-
-	close(fd);
-	return premount;
-
-err_close:
-	if (fd > 0)
-		close(fd);
-	else
-		fclose(fp);
-err_free:
-	free(premount);
-	return NULL;
-}
diff --git a/src/lxc/lxc_create.c b/src/lxc/lxc_create.c
deleted file mode 100644
index 4b0e9d7..0000000
--- a/src/lxc/lxc_create.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- *
- * Copyright © 2013 Serge Hallyn <serge.hallyn at ubuntu.com>.
- * Copyright © 2013 Canonical Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <lxc/lxccontainer.h>
-#include <sys/types.h>
-
-#include "arguments.h"
-#include "bdev.h"
-#include "log.h"
-#include "lxc.h"
-#include "utils.h"
-
-lxc_log_define(lxc_create_ui, lxc);
-
-static uint64_t get_fssize(char *s)
-{
-	uint64_t ret;
-	char *end;
-
-	ret = strtoull(s, &end, 0);
-	if (end == s)
-	{
-		fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
-		return 0;
-	}
-	while (isblank(*end))
-		end++;
-	if (*end == '\0')
-		ret *= 1024ULL * 1024ULL; // MB by default
-	else if (*end == 'b' || *end == 'B')
-		ret *= 1ULL;
-	else if (*end == 'k' || *end == 'K')
-		ret *= 1024ULL;
-	else if (*end == 'm' || *end == 'M')
-		ret *= 1024ULL * 1024ULL;
-	else if (*end == 'g' || *end == 'G')
-		ret *= 1024ULL * 1024ULL * 1024ULL;
-	else if (*end == 't' || *end == 'T')
-		ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
-	else
-	{
-		fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s);
-		return 0;
-	}
-	return ret;
-}
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	switch (c) {
-	case 'B': args->bdevtype = arg; break;
-	case 'f': args->configfile = arg; break;
-	case 't': args->template = arg; break;
-	case '0': args->lvname = arg; break;
-	case '1': args->vgname = arg; break;
-	case '2': args->thinpool = arg; break;
-	case '3': args->fstype = arg; break;
-	case '4': args->fssize = get_fssize(arg); break;
-	case '5': args->zfsroot = arg; break;
-	case '6': args->dir = arg; break;
-	case '7': args->rbdname = arg; break;
-	case '8': args->rbdpool = arg; break;
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	{"bdev", required_argument, 0, 'B'},
-	{"config", required_argument, 0, 'f'},
-	{"template", required_argument, 0, 't'},
-	{"lvname", required_argument, 0, '0'},
-	{"vgname", required_argument, 0, '1'},
-	{"thinpool", required_argument, 0, '2'},
-	{"fstype", required_argument, 0, '3'},
-	{"fssize", required_argument, 0, '4'},
-	{"zfsroot", required_argument, 0, '5'},
-	{"dir", required_argument, 0, '6'},
-	{"rbdname", required_argument, 0, '7'},
-	{"rbdpool", required_argument, 0, '8'},
-	LXC_COMMON_OPTIONS
-};
-
-static void create_helpfn(const struct lxc_arguments *args)
-{
-	char *argv[3], *path;
-	pid_t pid;
-
-	if (!args->template)
-		return;
-
-	pid = fork();
-	if (pid) {
-		wait_for_pid(pid);
-		return;
-	}
-
-	path = get_template_path(args->template);
-
-	argv[0] = path;
-	argv[1] = "-h";
-	argv[2] = NULL;
-
-	execv(path, argv);
-	ERROR("Error executing %s -h", path);
-	exit(EXIT_FAILURE);
-}
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-create",
-	.helpfn   = create_helpfn,
-	.help     = "\
---name=NAME --template=TEMPLATE [OPTION...]\n\
-\n\
-lxc-create creates a container\n\
-\n\
-Options :\n\
-  -n, --name=NAME               NAME of the container\n\
-  -f, --config=CONFIG           Initial configuration file\n\
-  -t, --template=TEMPLATE       Template to use to setup container\n\
-  -B, --bdev=BDEV               Backing store type to use\n\
-      --dir=DIR                 Place rootfs directory under DIR\n\
-\n\
-  BDEV options for LVM (with -B/--bdev lvm):\n\
-      --lvname=LVNAME           Use LVM lv name LVNAME\n\
-                                (Default: container name)\n\
-      --vgname=VG               Use LVM vg called VG\n\
-                                (Default: lxc)\n\
-      --thinpool=TP             Use LVM thin pool called TP\n\
-                                (Default: lxc)\n\
-\n\
-  BDEV options for Ceph RBD (with -B/--bdev rbd) :\n\
-      --rbdname=RBDNAME         Use Ceph RBD name RBDNAME\n\
-                                (Default: container name)\n\
-      --rbdpool=POOL            Use Ceph RBD pool name POOL\n\
-                                (Default: lxc)\n\
-\n\
-  BDEV option for ZFS (with -B/--bdev zfs) :\n\
-      --zfsroot=PATH            Create zfs under given zfsroot\n\
-                                (Default: tank/lxc)\n\
-\n\
-  BDEV options for LVM or Loop (with -B/--bdev lvm/loop) :\n\
-      --fstype=TYPE             Create fstype TYPE\n\
-                                (Default: ext3)\n\
-      --fssize=SIZE[U]          Create filesystem of\n\
-                                size SIZE * unit U (bBkKmMgGtT)\n\
-                                (Default: 1G, default unit: M)\n",
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = NULL,
-};
-
-static bool validate_bdev_args(struct lxc_arguments *a)
-{
-	if (strcmp(a->bdevtype, "best") != 0) {
-		if (a->fstype || a->fssize) {
-			if (strcmp(a->bdevtype, "lvm") != 0 &&
-			    strcmp(a->bdevtype, "loop") != 0 &&
-			    strcmp(a->bdevtype, "rbd") != 0) {
-				fprintf(stderr, "filesystem type and size are only valid with block devices\n");
-				return false;
-			}
-		}
-		if (strcmp(a->bdevtype, "lvm") != 0) {
-			if (a->lvname || a->vgname || a->thinpool) {
-				fprintf(stderr, "--lvname, --vgname and --thinpool are only valid with -B lvm\n");
-				return false;
-			}
-		}
-		if (strcmp(a->bdevtype, "rbd") != 0) {
-			if (a->rbdname || a->rbdpool) {
-				fprintf(stderr, "--rbdname and --rbdpool are only valid with -B rbd\n");
-				return false;
-			}
-		}
-		if (strcmp(a->bdevtype, "zfs") != 0) {
-			if (a->zfsroot) {
-				fprintf(stderr, "zfsroot is only valid with -B zfs\n");
-				return false;
-			}
-		}
-	}
-	return true;
-}
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c;
-	struct bdev_specs spec;
-	int flags = 0;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		exit(EXIT_FAILURE);
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
-
-	if (!my_args.template) {
-		fprintf(stderr, "A template must be specified.\n");
-		fprintf(stderr, "Use \"none\" if you really want a container without a rootfs.\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if (strcmp(my_args.template, "none") == 0)
-		my_args.template = NULL;
-
-	memset(&spec, 0, sizeof(spec));
-	if (!my_args.bdevtype)
-		my_args.bdevtype = "_unset";
-
-	if (!validate_bdev_args(&my_args))
-		exit(EXIT_FAILURE);
-
-	if (strcmp(my_args.bdevtype, "none") == 0)
-		my_args.bdevtype = "dir";
-
-	// Final check whether the user gave use a valid bdev type.
-	if (strcmp(my_args.bdevtype, "best") &&
-	    strcmp(my_args.bdevtype, "_unset") &&
-	    !is_valid_bdev_type(my_args.bdevtype)) {
-		fprintf(stderr, "%s is not a valid backing storage type.\n", my_args.bdevtype);
-		exit(EXIT_FAILURE);
-	}
-
-	if (geteuid()) {
-		if (mkdir_p(my_args.lxcpath[0], 0755)) {
-			exit(EXIT_FAILURE);
-		}
-		if (access(my_args.lxcpath[0], O_RDWR) < 0) {
-			fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
-			exit(EXIT_FAILURE);
-		}
-		if (strcmp(my_args.bdevtype, "dir") && strcmp(my_args.bdevtype, "_unset") &&
-				strcmp(my_args.bdevtype, "btrfs")) {
-			fprintf(stderr, "Unprivileged users cannot create %s containers", my_args.bdevtype);
-			exit(EXIT_FAILURE);
-		}
-	}
-
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c) {
-		fprintf(stderr, "Failed to create lxc container.\n");
-		exit(EXIT_FAILURE);
-	}
-	if (c->is_defined(c)) {
-		lxc_container_put(c);
-		fprintf(stderr, "Container already exists\n");
-		exit(EXIT_FAILURE);
-	}
-	if (my_args.configfile)
-		c->load_config(c, my_args.configfile);
-	else
-		c->load_config(c, lxc_global_config_value("lxc.default_config"));
-
-	if (my_args.fstype)
-		spec.fstype = my_args.fstype;
-	if (my_args.fssize)
-		spec.fssize = my_args.fssize;
-
-	if ((strcmp(my_args.bdevtype, "zfs") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
-		if (my_args.zfsroot)
-			spec.zfs.zfsroot = my_args.zfsroot;
-	}
-
-	if ((strcmp(my_args.bdevtype, "lvm") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
-		if (my_args.lvname)
-			spec.lvm.lv = my_args.lvname;
-		if (my_args.vgname)
-			spec.lvm.vg = my_args.vgname;
-		if (my_args.thinpool)
-			spec.lvm.thinpool = my_args.thinpool;
-	}
-
-	if ((strcmp(my_args.bdevtype, "rbd") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
-		if (my_args.rbdname)
-			spec.rbd.rbdname = my_args.rbdname;
-		if (my_args.rbdpool)
-			spec.rbd.rbdpool = my_args.rbdpool;
-	}
-
-	if (my_args.dir)
-		spec.dir = my_args.dir;
-
-	if (strcmp(my_args.bdevtype, "_unset") == 0)
-		my_args.bdevtype = NULL;
-
-	if (my_args.quiet)
-		flags = LXC_CREATE_QUIET;
-
-	if (!c->create(c, my_args.template, my_args.bdevtype, &spec, flags, &argv[optind])) {
-		ERROR("Error creating container %s", c->name);
-		lxc_container_put(c);
-		exit(EXIT_FAILURE);
-	}
-
-	lxc_container_put(c);
-	INFO("container %s created", c->name);
-	exit(EXIT_SUCCESS);
-}
diff --git a/src/lxc/lxc_destroy.c b/src/lxc/lxc_destroy.c
deleted file mode 100644
index b521739..0000000
--- a/src/lxc/lxc_destroy.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- *
- * Copyright © 2013 Serge Hallyn <serge.hallyn at ubuntu.com>.
- * Copyright © 2013 Canonical Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "config.h"
-
-#include <libgen.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "arguments.h"
-#include "log.h"
-#include "lxc.h"
-#include "utils.h"
-
-lxc_log_define(lxc_destroy_ui, lxc);
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg);
-static bool quiet;
-
-static const struct option my_longopts[] = {
-	{"force", no_argument, 0, 'f'},
-	{"snapshots", no_argument, 0, 's'},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-destroy",
-	.help     = "\
---name=NAME [-f] [-P lxcpath]\n\
-\n\
-lxc-destroy destroys a container with the identifier NAME\n\
-\n\
-Options :\n\
-  -n, --name=NAME   NAME of the container\n\
-  -s, --snapshots   destroy including all snapshots\n\
-  -f, --force       wait for the container to shut down\n",
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = NULL,
-	.task     = DESTROY,
-};
-
-static bool do_destroy(struct lxc_container *c);
-static bool do_destroy_with_snapshots(struct lxc_container *c);
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c;
-	bool bret;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		exit(EXIT_FAILURE);
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
-	if (my_args.quiet)
-		quiet = true;
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c) {
-		if (!quiet)
-			fprintf(stderr, "System error loading container\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if (!c->may_control(c)) {
-		if (!quiet)
-			fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
-		lxc_container_put(c);
-		exit(EXIT_FAILURE);
-	}
-
-	if (!c->is_defined(c)) {
-		if (!quiet)
-			fprintf(stderr, "Container is not defined\n");
-		lxc_container_put(c);
-		exit(EXIT_FAILURE);
-	}
-
-	if (my_args.task == SNAP) {
-		bret = do_destroy_with_snapshots(c);
-		if (bret && !quiet)
-			printf("Destroyed container %s including snapshots \n", my_args.name);
-	} else {
-		bret = do_destroy(c);
-		if (bret && !quiet)
-			printf("Destroyed container %s\n", my_args.name);
-	}
-
-	lxc_container_put(c);
-
-	if (bret)
-		exit(EXIT_SUCCESS);
-	exit(EXIT_FAILURE);
-}
-
-static int my_parser(struct lxc_arguments *args, int c, char *arg)
-{
-	switch (c) {
-	case 'f': args->force = 1; break;
-	case 's': args->task = SNAP; break;
-	}
-	return 0;
-}
-
-static bool do_destroy(struct lxc_container *c)
-{
-	bool bret = true;
-	char path[MAXPATHLEN];
-
-	/* First check whether the container has dependent clones or snapshots. */
-	int ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
-	if (ret < 0 || ret >= MAXPATHLEN)
-		return false;
-
-	if (file_exists(path)) {
-		if (!quiet)
-			fprintf(stdout, "Destroying %s failed: %s has clones.\n", c->name, c->name);
-		return false;
-	}
-
-	ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
-	if (ret < 0 || ret >= MAXPATHLEN)
-		return false;
-
-	if (dir_exists(path)) {
-		if (!quiet)
-			fprintf(stdout, "Destroying %s failed: %s has snapshots.\n", c->name, c->name);
-		return false;
-	}
-
-	if (c->is_running(c)) {
-		if (!my_args.force && !quiet) {
-			fprintf(stderr, "%s is running\n", my_args.name);
-			return false;
-		}
-		/* If the container was ephemeral it will be removed on shutdown. */
-		c->stop(c);
-	}
-
-	/* If the container was ephemeral we have already removed it when we
-	 * stopped it. */
-	if (c->is_defined(c) && !c->lxc_conf->ephemeral)
-		bret = c->destroy(c);
-
-	if (!bret) {
-		if (!quiet)
-			fprintf(stderr, "Destroying %s failed\n", my_args.name);
-		return false;
-	}
-
-	return true;
-}
-
-static bool do_destroy_with_snapshots(struct lxc_container *c)
-{
-	struct lxc_container *c1;
-	struct stat fbuf;
-	bool bret = false;
-	char path[MAXPATHLEN];
-	char *buf = NULL;
-	char *lxcpath = NULL;
-	char *lxcname = NULL;
-	char *scratch = NULL;
-	int fd;
-	int ret;
-	int counter = 0;
-
-	/* Destroy clones. */
-	ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
-	if (ret < 0 || ret >= MAXPATHLEN)
-		return false;
-
-	fd = open(path, O_RDONLY | O_CLOEXEC);
-	if (fd >= 0) {
-		ret = fstat(fd, &fbuf);
-		if (ret < 0) {
-			close(fd);
-			return false;
-		}
-
-		/* Make sure that the string is \0 terminated. */
-		buf = calloc(fbuf.st_size + 1, sizeof(char));
-		if (!buf) {
-			SYSERROR("failed to allocate memory");
-			close(fd);
-			return false;
-		}
-
-		ret = read(fd, buf, fbuf.st_size);
-		if (ret < 0) {
-			ERROR("could not read %s", path);
-			close(fd);
-			free(buf);
-			return false;
-		}
-		close(fd);
-
-		while ((lxcpath = strtok_r(!counter ? buf : NULL, "\n", &scratch))) {
-			if (!(lxcname = strtok_r(NULL, "\n", &scratch)))
-				break;
-			c1 = lxc_container_new(lxcname, lxcpath);
-			if (!c1) {
-				counter++;
-				continue;
-			}
-			/* We do not destroy recursively. If a clone of a clone
-			 * has clones or snapshots the user should remove it
-			 * explicitly. */
-			if (!do_destroy(c1)) {
-				lxc_container_put(c1);
-				free(buf);
-				return false;
-			}
-			lxc_container_put(c1);
-			counter++;
-		}
-		free(buf);
-	}
-
-	/* Destroy snapshots located in the containers snap/ folder. */
-	ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
-	if (ret < 0 || ret >= MAXPATHLEN)
-		return false;
-
-	if (dir_exists(path))
-		bret = c->destroy_with_snapshots(c);
-	else
-		bret = do_destroy(c);
-
-	return bret;
-}
-
diff --git a/src/lxc/lxc_device.c b/src/lxc/lxc_device.c
deleted file mode 100644
index 0c9e066..0000000
--- a/src/lxc/lxc_device.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * Authors:
- * Dongsheng Yang <yangds.fnst at cn.fujitsu.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <libgen.h>
-#include <string.h>
-#include <limits.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "utils.h"
-#include "lxc.h"
-#include "log.h"
-
-#include "arguments.h"
-
-#if HAVE_IFADDRS_H
-#include <ifaddrs.h>
-#else
-#include <../include/ifaddrs.h>
-#endif
-
-lxc_log_define(lxc_device, lxc);
-
-static const struct option my_longopts[] = {
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-device",
-	.help     = "\
---name=NAME -- add|del DEV\n\
-\n\
-lxc-device attach or detach DEV to or from container.\n\
-\n\
-Options :\n\
-  -n, --name=NAME      NAME of the container",
-	.options  = my_longopts,
-	.parser   = NULL,
-	.checker  = NULL,
-};
-
-static bool is_interface(const char* dev_name, pid_t pid)
-{
-	pid_t p = fork();
-
-	if (p < 0) {
-		SYSERROR("failed to fork task.");
-		exit(1);
-	}
-
-	if (p == 0) {
-		struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
-
-		if (!switch_to_ns(pid, "net")) {
-			ERROR("failed to enter netns of container.");
-			exit(-1);
-		}
-
-		/* Grab the list of interfaces */
-		if (getifaddrs(&interfaceArray)) {
-			ERROR("failed to get interfaces list");
-			exit(-1);
-		}
-
-		/* Iterate through the interfaces */
-		for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) {
-			if (strcmp(tempIfAddr->ifa_name, dev_name) == 0) {
-				exit(0);
-			}
-		}
-		exit(1);
-	}
-
-	if (wait_for_pid(p) == 0) {
-		return true;
-	}
-	return false;
-}
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c;
-	char *cmd, *dev_name, *dst_name;
-	int ret = 1;
-
-	if (geteuid() != 0) {
-		ERROR("%s must be run as root", argv[0]);
-		exit(1);
-	}
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		goto err;
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		goto err;
-	lxc_log_options_no_override();
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c) {
-		ERROR("%s doesn't exist", my_args.name);
-		goto err;
-	}
-
-	if (!c->is_running(c)) {
-		ERROR("Container %s is not running.", c->name);
-		goto err1;
-	}
-
-	if (my_args.argc < 2) {
-		ERROR("Error: no command given (Please see --help output)");
-		goto err1;
-	}
-
-	cmd = my_args.argv[0];
-	dev_name = my_args.argv[1];
-	if (my_args.argc < 3)
-		dst_name = dev_name;
-	else
-		dst_name = my_args.argv[2];
-
-	if (strcmp(cmd, "add") == 0) {
-		if (is_interface(dev_name, 1)) {
-			ret = c->attach_interface(c, dev_name, dst_name);
-		} else {
-			ret = c->add_device_node(c, dev_name, dst_name);
-		}
-		if (ret != true) {
-			ERROR("Failed to add %s to %s.", dev_name, c->name);
-			ret = 1;
-			goto err1;
-		}
-		INFO("Add %s to %s.", dev_name, c->name);
-	} else if (strcmp(cmd, "del") == 0) {
-		if (is_interface(dev_name, c->init_pid(c))) {
-			ret = c->detach_interface(c, dev_name, dst_name);
-		} else {
-			ret = c->remove_device_node(c, dev_name, dst_name);
-		}
-		if (ret != true) {
-			ERROR("Failed to del %s from %s.", dev_name, c->name);
-			ret = 1;
-			goto err1;
-		}
-		INFO("Delete %s from %s.", dev_name, c->name);
-	} else {
-		ERROR("Error: Please use add or del (Please see --help output)");
-		goto err1;
-	}
-	exit(0);
-err1:
-	lxc_container_put(c);
-err:
-	exit(ret);
-}
diff --git a/src/lxc/lxc_execute.c b/src/lxc/lxc_execute.c
deleted file mode 100644
index 50d481f..0000000
--- a/src/lxc/lxc_execute.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <libgen.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-
-#include "caps.h"
-#include "lxc.h"
-#include "log.h"
-#include "conf.h"
-#include "confile.h"
-#include "arguments.h"
-#include "config.h"
-#include "start.h"
-#include "utils.h"
-
-lxc_log_define(lxc_execute_ui, lxc);
-
-static struct lxc_list defines;
-
-static int my_checker(const struct lxc_arguments* args)
-{
-	if (!args->argc) {
-		lxc_error(args, "missing command to execute !");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	switch (c) {
-	case 'f': args->rcfile = arg; break;
-	case 's': return lxc_config_define_add(&defines, arg); break;
-	case 'u': args->uid = atoi(arg); break;
-	case 'g': args->gid = atoi(arg);
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	{"rcfile", required_argument, 0, 'f'},
-	{"define", required_argument, 0, 's'},
-	{"uid", required_argument, 0, 'u'},
-	{"gid", required_argument, 0, 'g'},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-execute",
-	.help     = "\
---name=NAME -- COMMAND\n\
-\n\
-lxc-execute creates a container with the identifier NAME\n\
-and execs COMMAND into this container.\n\
-\n\
-Options :\n\
-  -n, --name=NAME      NAME of the container\n\
-  -f, --rcfile=FILE    Load configuration file FILE\n\
-  -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\
-  -u, --uid=UID Execute COMMAND with UID inside the container\n\
-  -g, --gid=GID Execute COMMAND with GID inside the container\n",
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = my_checker,
-};
-
-int main(int argc, char *argv[])
-{
-	char *rcfile;
-	struct lxc_conf *conf;
-	int ret;
-
-	lxc_list_init(&defines);
-
-	if (lxc_caps_init())
-		return 1;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		return 1;
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		return 1;
-	lxc_log_options_no_override();
-
-	/* rcfile is specified in the cli option */
-	if (my_args.rcfile)
-		rcfile = (char *)my_args.rcfile;
-	else {
-		int rc;
-
-		rc = asprintf(&rcfile, "%s/%s/config", my_args.lxcpath[0], my_args.name);
-		if (rc == -1) {
-			SYSERROR("failed to allocate memory");
-			return 1;
-		}
-
-		/* container configuration does not exist */
-		if (access(rcfile, F_OK)) {
-			free(rcfile);
-			rcfile = NULL;
-		}
-	}
-
-	conf = lxc_conf_init();
-	if (!conf) {
-		ERROR("failed to initialize configuration");
-		return 1;
-	}
-
-	if (rcfile && lxc_config_read(rcfile, conf, NULL)) {
-		ERROR("failed to read configuration file");
-		return 1;
-	}
-
-	if (lxc_config_define_load(&defines, conf))
-		return 1;
-
-	if (my_args.uid)
-		conf->init_uid = my_args.uid;
-
-	if (my_args.gid)
-		conf->init_gid = my_args.gid;
-
-	ret = lxc_execute(my_args.name, my_args.argv, my_args.quiet, conf, my_args.lxcpath[0], false);
-
-	lxc_conf_free(conf);
-
-	if (ret < 0)
-		return 1;
-	return ret;
-}
diff --git a/src/lxc/lxc_freeze.c b/src/lxc/lxc_freeze.c
deleted file mode 100644
index ea8bd3e..0000000
--- a/src/lxc/lxc_freeze.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <libgen.h>
-#include <string.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "lxc.h"
-#include "log.h"
-
-#include "arguments.h"
-
-lxc_log_define(lxc_freeze_ui, lxc);
-
-static const struct option my_longopts[] = {
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-freeze",
-	.help     = "\
---name=NAME\n\
-\n\
-lxc-freeze freezes a container with the identifier NAME\n\
-\n\
-Options :\n\
-  -n, --name=NAME      NAME of the container",
-	.options  = my_longopts,
-	.parser   = NULL,
-	.checker  = NULL,
-};
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		exit(1);
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		exit(1);
-	lxc_log_options_no_override();
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c) {
-		ERROR("No such container: %s:%s", my_args.lxcpath[0], my_args.name);
-		exit(1);
-	}
-
-	if (!c->may_control(c)) {
-		ERROR("Insufficent privileges to control %s:%s", my_args.lxcpath[0], my_args.name);
-		lxc_container_put(c);
-		exit(1);
-	}
-
-	if (!c->freeze(c)) {
-		ERROR("Failed to freeze %s:%s", my_args.lxcpath[0], my_args.name);
-		lxc_container_put(c);
-		exit(1);
-	}
-
-	lxc_container_put(c);
-
-	exit(0);
-}
diff --git a/src/lxc/lxc_info.c b/src/lxc/lxc_info.c
deleted file mode 100644
index 58ff619..0000000
--- a/src/lxc/lxc_info.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <limits.h>
-#include <libgen.h>
-#include <sys/types.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "lxc.h"
-#include "log.h"
-#include "utils.h"
-#include "commands.h"
-#include "arguments.h"
-
-lxc_log_define(lxc_info_ui, lxc);
-
-static bool ips;
-static bool state;
-static bool pid;
-static bool stats;
-static bool humanize = true;
-static char **key = NULL;
-static int keys = 0;
-static int filter_count = 0;
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	char **newk;
-	switch (c) {
-	case 'c':
-		newk = realloc(key, (keys + 1) * sizeof(key[0]));
-		if (!newk)
-			return -1;
-		key = newk;
-		key[keys] = arg;
-		keys++;
-		break;
-	case 'i': ips = true; filter_count += 1; break;
-	case 's': state = true; filter_count += 1; break;
-	case 'p': pid = true; filter_count += 1; break;
-	case 'S': stats = true; filter_count += 5; break;
-	case 'H': humanize = false; break;
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	{"config", required_argument, 0, 'c'},
-	{"ips", no_argument, 0, 'i'},
-	{"state", no_argument, 0, 's'},
-	{"pid", no_argument, 0, 'p'},
-	{"stats", no_argument, 0, 'S'},
-	{"no-humanize", no_argument, 0, 'H'},
-	LXC_COMMON_OPTIONS,
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-info",
-	.help     = "\
---name=NAME\n\
-\n\
-lxc-info display some information about a container with the identifier NAME\n\
-\n\
-Options :\n\
-  -n, --name=NAME       NAME of the container\n\
-  -c, --config=KEY      show configuration variable KEY from running container\n\
-  -i, --ips             shows the IP addresses\n\
-  -p, --pid             shows the process id of the init container\n\
-  -S, --stats           shows usage stats\n\
-  -H, --no-humanize     shows stats as raw numbers, not humanized\n\
-  -s, --state           shows the state of the container\n",
-	.name     = NULL,
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = NULL,
-};
-
-static void str_chomp(char *buf)
-{
-	char *ch;
-
-	/* remove trailing whitespace from buf */
-	for(ch = &buf[strlen(buf)-1];
-	    ch >= buf && (*ch == '\t' || *ch == '\n' || *ch == ' ');
-	    ch--)
-		*ch = '\0';
-}
-
-static void size_humanize(unsigned long long val, char *buf, size_t bufsz)
-{
-	if (val > 1 << 30) {
-		snprintf(buf, bufsz, "%u.%2.2u GiB",
-			    (int)(val >> 30),
-			    (int)(val & ((1 << 30) - 1)) / 10737419);
-	} else if (val > 1 << 20) {
-		int x = val + 5243;  /* for rounding */
-		snprintf(buf, bufsz, "%u.%2.2u MiB",
-			    x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
-	} else if (val > 1 << 10) {
-		int x = val + 5;  /* for rounding */
-		snprintf(buf, bufsz, "%u.%2.2u KiB",
-			    x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
-	} else {
-		snprintf(buf, bufsz, "%u bytes", (int)val);
-	}
-}
-
-static unsigned long long str_size_humanize(char *iobuf, size_t iobufsz)
-{
-	unsigned long long val;
-	char *end = NULL;
-
-	val = strtoull(iobuf, &end, 0);
-	if (humanize) {
-		if (*end == '\0' || *end == '\n')
-			size_humanize(val, iobuf, iobufsz);
-		else
-			*iobuf = '\0';
-	}
-	return val;
-}
-
-static void print_net_stats(struct lxc_container *c)
-{
-	int rc,netnr;
-	unsigned long long rx_bytes = 0, tx_bytes = 0;
-	char *ifname, *type;
-	char path[PATH_MAX];
-	char buf[256];
-
-	for(netnr = 0; ;netnr++) {
-		sprintf(buf, "lxc.network.%d.type", netnr);
-		type = c->get_running_config_item(c, buf);
-		if (!type)
-			break;
-
-		if (!strcmp(type, "veth")) {
-			sprintf(buf, "lxc.network.%d.veth.pair", netnr);
-		} else {
-			sprintf(buf, "lxc.network.%d.link", netnr);
-		}
-		free(type);
-		ifname = c->get_running_config_item(c, buf);
-		if (!ifname)
-			return;
-		printf("%-15s %s\n", "Link:", ifname);
-		fflush(stdout);
-
-		/* XXX: tx and rx are reversed from the host vs container
-		 * perspective, print them from the container perspective
-		 */
-		snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/rx_bytes", ifname);
-		rc = lxc_read_from_file(path, buf, sizeof(buf));
-		if (rc > 0) {
-			str_chomp(buf);
-			rx_bytes = str_size_humanize(buf, sizeof(buf));
-			printf("%-15s %s\n", " TX bytes:", buf);
-			fflush(stdout);
-		}
-
-		snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/tx_bytes", ifname);
-		rc = lxc_read_from_file(path, buf, sizeof(buf));
-		if (rc > 0) {
-			str_chomp(buf);
-			tx_bytes = str_size_humanize(buf, sizeof(buf));
-			printf("%-15s %s\n", " RX bytes:", buf);
-			fflush(stdout);
-		}
-
-		sprintf(buf, "%llu", rx_bytes + tx_bytes);
-		str_size_humanize(buf, sizeof(buf));
-		printf("%-15s %s\n", " Total bytes:", buf);
-		fflush(stdout);
-		free(ifname);
-	}
-}
-
-static void print_stats(struct lxc_container *c)
-{
-	int i, ret;
-	char buf[256];
-
-	ret = c->get_cgroup_item(c, "cpuacct.usage", buf, sizeof(buf));
-	if (ret > 0 && ret < sizeof(buf)) {
-		str_chomp(buf);
-		if (humanize) {
-			float seconds = strtof(buf, NULL) / 1000000000.0;
-			printf("%-15s %.2f seconds\n", "CPU use:", seconds);
-		} else {
-			printf("%-15s %s\n", "CPU use:", buf);
-		}
-		fflush(stdout);
-	}
-
-	ret = c->get_cgroup_item(c, "blkio.throttle.io_service_bytes", buf, sizeof(buf));
-	if (ret > 0 && ret < sizeof(buf)) {
-		char *ch;
-
-		/* put ch on last "Total" line */
-		str_chomp(buf);
-		for(ch = &buf[strlen(buf)-1]; ch > buf && *ch != '\n'; ch--)
-			;
-		if (*ch == '\n')
-			ch++;
-
-		if (strncmp(ch, "Total", 5) == 0) {
-			ch += 6;
-			memmove(buf, ch, strlen(ch)+1);
-			str_size_humanize(buf, sizeof(buf));
-			printf("%-15s %s\n", "BlkIO use:", buf);
-		}
-		fflush(stdout);
-	}
-
-	static const struct {
-		const char *name;
-		const char *file;
-	} lxstat[] = {
-		{ "Memory use:", "memory.usage_in_bytes" },
-		{ "KMem use:",   "memory.kmem.usage_in_bytes" },
-		{ NULL, NULL },
-	};
-
-	for (i = 0; lxstat[i].name; i++) {
-		ret = c->get_cgroup_item(c, lxstat[i].file, buf, sizeof(buf));
-		if (ret > 0 && ret < sizeof(buf)) {
-			str_chomp(buf);
-			str_size_humanize(buf, sizeof(buf));
-			printf("%-15s %s\n", lxstat[i].name, buf);
-			fflush(stdout);
-		}
-	}
-}
-
-static void print_info_msg_int(const char *key, int value)
-{
-	if (humanize)
-		printf("%-15s %d\n", key, value);
-	else {
-		if (filter_count == 1)
-			printf("%d\n", value);
-		else
-			printf("%-15s %d\n", key, value);
-	}
-	fflush(stdout);
-}
-
-static void print_info_msg_str(const char *key, const char *value)
-{
-	if (humanize)
-		printf("%-15s %s\n", key, value);
-	else {
-		if (filter_count == 1)
-			printf("%s\n", value);
-		else
-			printf("%-15s %s\n", key, value);
-	}
-	fflush(stdout);
-}
-
-static int print_info(const char *name, const char *lxcpath)
-{
-	int i;
-	struct lxc_container *c;
-
-	c = lxc_container_new(name, lxcpath);
-	if (!c) {
-		fprintf(stderr, "Failure to retrieve information on %s:%s\n", lxcpath ? lxcpath : "null",
-				name ? name : "null");
-		return -1;
-	}
-
-	if (!c->may_control(c)) {
-		fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
-		lxc_container_put(c);
-		return -1;
-	}
-
-	if (!c->is_running(c) && !c->is_defined(c)) {
-		fprintf(stderr, "%s doesn't exist\n", c->name);
-		lxc_container_put(c);
-		return -1;
-	}
-
-	if (!state && !pid && !ips && !stats && keys <= 0) {
-		state = pid = ips = stats = true;
-		print_info_msg_str("Name:", c->name);
-	}
-
-	if (state) {
-		print_info_msg_str("State:", c->state(c));
-	}
-
-	if (c->is_running(c)) {
-		if (pid) {
-			pid_t initpid;
-
-			initpid = c->init_pid(c);
-			if (initpid >= 0)
-				print_info_msg_int("PID:", initpid);
-		}
-
-		if (ips) {
-			fflush(stdout);
-			char **addresses = c->get_ips(c, NULL, NULL, 0);
-			if (addresses) {
-				char *address;
-				i = 0;
-				while (addresses[i]) {
-					address = addresses[i];
-					print_info_msg_str("IP:", address);
-					i++;
-				}
-			}
-		}
-	}
-
-	if (stats) {
-		print_stats(c);
-		print_net_stats(c);
-	}
-
-	for(i = 0; i < keys; i++) {
-		int len = c->get_config_item(c, key[i], NULL, 0);
-
-		if (len > 0) {
-			char *val = (char*) malloc(sizeof(char)*len + 1);
-
-			if (c->get_config_item(c, key[i], val, len + 1) != len) {
-				fprintf(stderr, "unable to read %s from configuration\n", key[i]);
-			} else {
-				if (!humanize && keys == 1)
-					printf("%s\n", val);
-				else
-					printf("%s = %s\n", key[i], val);
-			}
-			free(val);
-		} else if (len == 0) {
-			if (!humanize && keys == 1)
-				printf("\n");
-			else
-				printf("%s =\n", key[i]);
-		} else {
-			fprintf(stderr, "%s invalid\n", key[i]);
-		}
-		fflush(stdout);
-	}
-
-	lxc_container_put(c);
-	return 0;
-}
-
-int main(int argc, char *argv[])
-{
-	int ret = EXIT_FAILURE;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		return ret;
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		return ret;
-	lxc_log_options_no_override();
-
-	if (print_info(my_args.name, my_args.lxcpath[0]) == 0)
-		ret = EXIT_SUCCESS;
-
-	return ret;
-}
diff --git a/src/lxc/lxc_init.c b/src/lxc/lxc_init.c
deleted file mode 100644
index 5dd29af..0000000
--- a/src/lxc/lxc_init.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <signal.h>
-#include <libgen.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#define _GNU_SOURCE
-#include <getopt.h>
-
-#include "log.h"
-#include "caps.h"
-#include "error.h"
-#include "initutils.h"
-
-lxc_log_define(lxc_init, lxc);
-
-static int quiet;
-
-static const struct option options[] = {
-	{ "name",        required_argument, NULL, 'n' },
-	{ "logpriority", required_argument, NULL, 'l' },
-	{ "quiet",       no_argument,       NULL, 'q' },
-	{ "lxcpath",     required_argument, NULL, 'P' },
-	{ 0, 0, 0, 0 },
-};
-
-static sig_atomic_t was_interrupted = 0;
-
-static void interrupt_handler(int sig)
-{
-	if (!was_interrupted)
-		was_interrupted = sig;
-}
-
-static void usage(void) {
-	fprintf(stderr, "Usage: lxc-init [OPTION]...\n\n"
-		"Common options :\n"
-		"  -n, --name=NAME          NAME of the container\n"
-		"  -l, --logpriority=LEVEL  Set log priority to LEVEL\n"
-		"  -q, --quiet              Don't produce any output\n"
-		"  -P, --lxcpath=PATH       Use specified container path\n"
-		"  -?, --help               Give this help list\n"
-		"\n"
-		"Mandatory or optional arguments to long options are also mandatory or optional\n"
-		"for any corresponding short options.\n"
-		"\n"
-		"NOTE: lxc-init is intended for use by lxc internally\n"
-		"      and does not need to be run by hand\n\n");
-}
-
-int main(int argc, char *argv[])
-{
-	pid_t pid;
-	int err;
-	char **aargv;
-	sigset_t mask, omask;
-	int i, have_status = 0, shutdown = 0;
-	int opt;
-	char *lxcpath = NULL, *name = NULL, *logpriority = NULL;
-
-	while ((opt = getopt_long(argc, argv, "n:l:qP:", options, NULL)) != -1) {
-		switch(opt) {
-		case 'n':
-			name = optarg;
-			break;
-		case 'l':
-			logpriority = optarg;
-			break;
-		case 'q':
-			quiet = 1;
- 			break;
-		case 'P':
-			lxcpath = optarg;
-			break;
-		default: /* '?' */
-			usage();
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	err = lxc_log_init(name, name ? NULL : "none", logpriority,
-			   basename(argv[0]), quiet, lxcpath);
-	if (err < 0)
-		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
-
-	if (!argv[optind]) {
-		ERROR("missing command to launch");
-		exit(EXIT_FAILURE);
-	}
-
-	aargv = &argv[optind];
-
-	/*
-	 * mask all the signals so we are safe to install a
-	 * signal handler and to fork
-	 */
-	if (sigfillset(&mask) ||
-	    sigdelset(&mask, SIGILL) ||
-	    sigdelset(&mask, SIGSEGV) ||
-	    sigdelset(&mask, SIGBUS) ||
-	    sigprocmask(SIG_SETMASK, &mask, &omask)) {
-		SYSERROR("failed to set signal mask");
-		exit(EXIT_FAILURE);
-	}
-
-	for (i = 1; i < NSIG; i++) {
-		struct sigaction act;
-
-		/* Exclude some signals: ILL, SEGV and BUS are likely to
-		 * reveal a bug and we want a core. STOP and KILL cannot be
-		 * handled anyway: they're here for documentation.
-		 */
-		if (i == SIGILL ||
-		    i == SIGSEGV ||
-		    i == SIGBUS ||
-		    i == SIGSTOP ||
-		    i == SIGKILL ||
-		    i == 32 || i == 33)
-			continue;
-
-		if (sigfillset(&act.sa_mask) ||
-		    sigdelset(&act.sa_mask, SIGILL) ||
-		    sigdelset(&act.sa_mask, SIGSEGV) ||
-		    sigdelset(&act.sa_mask, SIGBUS) ||
-		    sigdelset(&act.sa_mask, SIGSTOP) ||
-		    sigdelset(&act.sa_mask, SIGKILL)) {
-			ERROR("failed to set signal");
-			exit(EXIT_FAILURE);
-		}
-
-		act.sa_flags = 0;
-		act.sa_handler = interrupt_handler;
-		if (sigaction(i, &act, NULL) && errno != EINVAL) {
-			SYSERROR("failed to sigaction");
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	lxc_setup_fs();
-
-	pid = fork();
-
-	if (pid < 0)
-		exit(EXIT_FAILURE);
-
-	if (!pid) {
-
-		/* restore default signal handlers */
-		for (i = 1; i < NSIG; i++)
-			signal(i, SIG_DFL);
-
-		if (sigprocmask(SIG_SETMASK, &omask, NULL)) {
-			SYSERROR("failed to set signal mask");
-			exit(EXIT_FAILURE);
-		}
-
-		NOTICE("about to exec '%s'", aargv[0]);
-
-		execvp(aargv[0], aargv);
-		ERROR("failed to exec: '%s' : %m", aargv[0]);
-		exit(err);
-	}
-
-	/* let's process the signals now */
-	if (sigdelset(&omask, SIGALRM) ||
-	    sigprocmask(SIG_SETMASK, &omask, NULL)) {
-		SYSERROR("failed to set signal mask");
-		exit(EXIT_FAILURE);
-	}
-
-	/* no need of other inherited fds but stderr */
-	close(fileno(stdin));
-	close(fileno(stdout));
-
-	err = EXIT_SUCCESS;
-	for (;;) {
-		int status;
-		pid_t waited_pid;
-
-		switch (was_interrupted) {
-
-		case 0:
-			break;
-
-		case SIGPWR:
-		case SIGTERM:
-			if (!shutdown) {
-				shutdown = 1;
-				kill(-1, SIGTERM);
-				alarm(1);
-			}
-			break;
-
-		case SIGALRM:
-			kill(-1, SIGKILL);
-			break;
-
-		default:
-			kill(pid, was_interrupted);
-			break;
-		}
-
-		was_interrupted = 0;
-		waited_pid = wait(&status);
-		if (waited_pid < 0) {
-			if (errno == ECHILD)
-				goto out;
-			if (errno == EINTR)
-				continue;
-
-			ERROR("failed to wait child : %s",
-			      strerror(errno));
-			goto out;
-		}
-
-		/* reset timer each time a process exited */
-		if (shutdown)
-			alarm(1);
-
-		/*
-		 * keep the exit code of started application
-		 * (not wrapped pid) and continue to wait for
-		 * the end of the orphan group.
-		 */
-		if (waited_pid == pid && !have_status) {
-			err = lxc_error_set_and_log(waited_pid, status);
-			have_status = 1;
-		}
-	}
-out:
-	if (err < 0)
-		exit(EXIT_FAILURE);
-	exit(err);
-}
diff --git a/src/lxc/lxc_ls.c b/src/lxc/lxc_ls.c
deleted file mode 100644
index e2a4c34..0000000
--- a/src/lxc/lxc_ls.c
+++ /dev/null
@@ -1,1213 +0,0 @@
-/*
- *
- * Copyright © 2016 Christian Brauner <christian.brauner at mailbox.org>.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-
-#include <getopt.h>
-#include <regex.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <termios.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "arguments.h"
-#include "conf.h"
-#include "confile.h"
-#include "log.h"
-#include "lxc.h"
-#include "utils.h"
-
-lxc_log_define(lxc_ls, lxc);
-
-#define LINELEN 1024
-/* Per default we only allow five levels of recursion to protect the stack at
- * least a little bit. */
-#define MAX_NESTLVL 5
-
-#define LS_FROZEN 1
-#define LS_STOPPED 2
-#define LS_ACTIVE 3
-#define LS_RUNNING 4
-#define LS_NESTING 5
-#define LS_FILTER 6
-
-#ifndef SOCK_CLOEXEC
-#  define SOCK_CLOEXEC                02000000
-#endif
-
-/* Store container info. */
-struct ls {
-	char *name;
-	char *state;
-	char *groups;
-	char *interface;
-	char *ipv4;
-	char *ipv6;
-	unsigned int nestlvl;
-	pid_t init;
-	double ram;
-	double swap;
-	bool autostart;
-	bool running;
-};
-
-/* Keep track of field widths for printing. */
-struct lengths {
-	unsigned int name_length;
-	unsigned int state_length;
-	unsigned int groups_length;
-	unsigned int interface_length;
-	unsigned int ipv4_length;
-	unsigned int ipv6_length;
-	unsigned int init_length;
-	unsigned int ram_length;
-	unsigned int swap_length;
-	unsigned int autostart_length;
-};
-
-static int ls_deserialize(int rpipefd, struct ls **m, size_t *len);
-static void ls_field_width(const struct ls *l, const size_t size,
-		struct lengths *lht);
-static void ls_free(struct ls *l, size_t size);
-static void ls_free_arr(char **arr, size_t size);
-static int ls_get(struct ls **m, size_t *size, const struct lxc_arguments *args,
-		const char *basepath, const char *parent, unsigned int lvl,
-		char **lockpath, size_t len_lockpath, char **grps_must,
-		size_t grps_must_len);
-static char *ls_get_cgroup_item(struct lxc_container *c, const char *item);
-static char *ls_get_config_item(struct lxc_container *c, const char *item,
-		bool running);
-static char *ls_get_groups(struct lxc_container *c, bool running);
-static char *ls_get_ips(struct lxc_container *c, const char *inet);
-static int ls_recv_str(int fd, char **buf);
-static int ls_send_str(int fd, const char *buf);
-
-struct wrapargs {
-	const struct lxc_arguments *args;
-	char **grps_must;
-	size_t grps_must_len;
-	int pipefd[2];
-	size_t *size;
-	const char *parent;
-	unsigned int nestlvl;
-};
-
-/*
- * Takes struct wrapargs as argument.
- */
-static int ls_get_wrapper(void *wrap);
-
-/*
- * To calculate swap usage we should not simply check memory.usage_in_bytes and
- * memory.memsw.usage_in_bytes and then do:
- *	swap = memory.memsw.usage_in_bytes - memory.usage_in_bytes;
- * because we might receive an incorrect/negative value.
- * Instead we check memory.stat and check the "swap" value.
- */
-static double ls_get_swap(struct lxc_container *c);
-static unsigned int ls_get_term_width(void);
-static char *ls_get_interface(struct lxc_container *c);
-static bool ls_has_all_grps(const char *has, char **must, size_t must_len);
-static struct ls *ls_new(struct ls **ls, size_t *size);
-
-/*
- * Print user-specified fancy format.
- */
-static void ls_print_fancy_format(struct ls *l, struct lengths *lht,
-		size_t size, const char *fancy_fmt);
-
-/*
- * Only print names of containers.
- */
-static void ls_print_names(struct ls *l, struct lengths *lht,
-		size_t ls_arr, size_t termwidth);
-
-/*
- * Print default fancy format.
- */
-static void ls_print_table(struct ls *l, struct lengths *lht,
-		size_t size);
-
-/*
- * id can only be 79 + \0 chars long.
- */
-static int ls_remove_lock(const char *path, const char *name,
-		char **lockpath, size_t *len_lockpath, bool recalc);
-static int ls_serialize(int wpipefd, struct ls *n);
-static int my_parser(struct lxc_arguments *args, int c, char *arg);
-
-static const struct option my_longopts[] = {
-	{"line", no_argument, 0, '1'},
-	{"fancy", no_argument, 0, 'f'},
-	{"fancy-format", required_argument, 0, 'F'},
-	{"active", no_argument, 0, LS_ACTIVE},
-	{"running", no_argument, 0, LS_RUNNING},
-	{"frozen", no_argument, 0, LS_FROZEN},
-	{"stopped", no_argument, 0, LS_STOPPED},
-	{"nesting", optional_argument, 0, LS_NESTING},
-	{"groups", required_argument, 0, 'g'},
-	{"filter", required_argument, 0, LS_FILTER},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-ls",
-	.help = "\n\
-[-P lxcpath] [--active] [--running] [--frozen] [--stopped] [--nesting] [-g groups] [--filter regex]\n\
-[-1] [-P lxcpath] [--active] [--running] [--frozen] [--stopped] [--nesting] [-g groups] [--filter regex]\n\
-[-f] [-P lxcpath] [--active] [--running] [--frozen] [--stopped] [--nesting] [-g groups] [--filter regex]\n\
-\n\
-lxc-ls list containers\n\
-\n\
-Options :\n\
-  -1, --line	     show one entry per line\n\
-  -f, --fancy	     column-based output\n\
-  -F, --fancy-format column-based output\n\
-  --active           list only active containers\n\
-  --running          list only running containers\n\
-  --frozen           list only frozen containers\n\
-  --stopped          list only stopped containers\n\
-  --nesting=NUM      list nested containers up to NUM (default is 5) levels of nesting\n\
-  --filter=REGEX     filter container names by regular expression\n\
-  -g --groups        comma separated list of groups a container must have to be displayed\n",
-	.options = my_longopts,
-	.parser = my_parser,
-	.ls_nesting = 0,
-};
-
-int main(int argc, char *argv[])
-{
-	int ret = EXIT_FAILURE;
-	/*
-	 * The lxc parser requires that my_args.name is set. So let's satisfy
-	 * that condition by setting a dummy name which is never used.
-	 */
-	my_args.name  = "";
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		exit(EXIT_FAILURE);
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	/*
-	 * We set the first argument that usually takes my_args.name to NULL so
-	 * that the log is only used when the user specifies a file.
-	 */
-	if (lxc_log_init(NULL, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
-
-	struct lengths max_len = {
-		/* default header length */
-		.name_length = 4,      /* NAME */
-		.state_length = 5,     /* STATE */
-		.groups_length = 6,    /* GROUPS */
-		.interface_length = 9, /* INTERFACE */
-		.ipv4_length = 4,      /* IPV4 */
-		.ipv6_length = 4,      /* IPV6 */
-		.init_length = 3,      /* PID */
-		.ram_length = 3,       /* RAM */
-		.swap_length = 4,      /* SWAP */
-		.autostart_length = 9, /* AUTOSTART */
-	};
-
-	char **grps = NULL;
-	size_t ngrps = 0;
-	if (my_args.groups) {
-		grps = lxc_string_split_and_trim(my_args.groups, ',');
-		ngrps = lxc_array_len((void **)grps);
-	}
-
-	struct ls *ls_arr = NULL;
-	size_t ls_size = 0;
-	/* &(char *){NULL} is no magic. It's just a compound literal which
-	 * avoids having a pointless variable in main() that serves no purpose
-	 * here. */
-	int status = ls_get(&ls_arr, &ls_size, &my_args, "", NULL, 0, &(char *){NULL}, 0, grps, ngrps);
-	if (!ls_arr && status == 0)
-		/* We did not fail. There was just nothing to do. */
-		exit(EXIT_SUCCESS);
-	else if (!ls_arr || status == -1)
-		goto out;
-
-	ls_field_width(ls_arr, ls_size, &max_len);
-	if (my_args.ls_fancy && !my_args.ls_fancy_format) {
-		ls_print_table(ls_arr, &max_len, ls_size);
-	} else if (my_args.ls_fancy && my_args.ls_fancy_format) {
-		ls_print_fancy_format(ls_arr, &max_len, ls_size, my_args.ls_fancy_format);
-	} else {
-		unsigned int cols = 0;
-		if (!my_args.ls_line)
-			cols = ls_get_term_width();
-		ls_print_names(ls_arr, &max_len, ls_size, cols);
-	}
-
-	ret = EXIT_SUCCESS;
-
-out:
-	ls_free(ls_arr, ls_size);
-	lxc_free_array((void **)grps, free);
-
-	exit(ret);
-}
-
-static void ls_free(struct ls *l, size_t size)
-{
-	size_t i;
-	struct ls *m = NULL;
-	for (i = 0, m = l; i < size; i++, m++) {
-		free(m->groups);
-		free(m->interface);
-		free(m->ipv4);
-		free(m->ipv6);
-		free(m->name);
-		free(m->state);
-	}
-	free(l);
-}
-
-static char *ls_get_config_item(struct lxc_container *c, const char *item,
-		bool running)
-{
-	if (running)
-		return c->get_running_config_item(c, item);
-
-	size_t len = c->get_config_item(c, item, NULL, 0);
-	if (len <= 0)
-		return NULL;
-
-	char *val = malloc((len + 1) * sizeof(*val));
-	if (!val)
-		return NULL;
-
-	if ((size_t)c->get_config_item(c, item, val, len + 1) != len) {
-		free(val);
-		val = NULL;
-	}
-
-	return val;
-}
-
-static void ls_free_arr(char **arr, size_t size)
-{
-	size_t i;
-	for (i = 0; i < size; i++)
-		free(arr[i]);
-	free(arr);
-}
-
-static int ls_get(struct ls **m, size_t *size, const struct lxc_arguments *args,
-		const char *basepath, const char *parent, unsigned int lvl,
-		char **lockpath, size_t len_lockpath, char **grps_must,
-		size_t grps_must_len)
-{
-	/* As ls_get() is non-tail recursive we face the inherent danger of
-	 * blowing up the stack at some level of nesting. To have at least some
-	 * security we define MAX_NESTLVL to be 5. That should be sufficient for
-	 * most users. The argument lvl can be used to keep track of the level
-	 * of nesting we are at. If lvl is greater than the allowed default
-	 * level or the level the user specified on the command line we return
-	 * and unwind the stack. */
-	if (lvl > args->ls_nesting)
-		return 0;
-
-	int num = 0, ret = -1;
-	char **containers = NULL;
-	/* If we, at some level of nesting, encounter a stopped container but
-	 * want to retrieve nested containers we need to build an absolute path
-	 * beginning from it. Initially, at nesting level 0, basepath will
-	 * simply be the empty string and path will simply be whatever the
-	 * default lxcpath or the path the user gave us is.  Basepath will also
-	 * be the empty string in case we encounter a running container since we
-	 * can simply attach to its namespace to retrieve nested containers. */
-	char *path = lxc_append_paths(basepath, args->lxcpath[0]);
-	if (!path)
-		goto out;
-
-	if (!dir_exists(path)) {
-		ret = 0;
-		goto out;
-	}
-
-	/* Do not do more work than is necessary right from the start. */
-	if (args->ls_active || (args->ls_active && args->ls_frozen))
-		num = list_active_containers(path, &containers, NULL);
-	else
-		num = list_all_containers(path, &containers, NULL);
-	if (num == -1) {
-		num = 0;
-		goto out;
-	}
-
-	char *tmp = NULL;
-	int check;
-	struct ls *l = NULL;
-	struct lxc_container *c = NULL;
-	size_t i;
-	for (i = 0; i < (size_t)num; i++) {
-		char *name = containers[i];
-
-		/* Filter container names by regex the user gave us. */
-		if (args->ls_filter || args->argc == 1) {
-			regex_t preg;
-			tmp = args->ls_filter ? args->ls_filter : args->argv[0];
-			check = regcomp(&preg, tmp, REG_NOSUB | REG_EXTENDED);
-			if (check == REG_ESPACE) /* we're out of memory */
-				goto out;
-			else if (check != 0)
-				continue;
-			check = regexec(&preg, name, 0, NULL, 0);
-			regfree(&preg);
-			if (check != 0)
-				continue;
-		}
-
- 		errno = 0;
-		c = lxc_container_new(name, path);
- 		if ((errno == ENOMEM) && !c)
- 			goto out;
- 		else if (!c)
- 			continue;
-
-		if (!c->is_defined(c))
-			goto put_and_next;
-
-		/* This does not allocate memory so no worries about freeing it
-		 * when we goto next or out. */
-		const char *state_tmp = c->state(c);
-		if (!state_tmp)
-			state_tmp = "UNKNOWN";
-
-		if (args->ls_running && !c->is_running(c))
-			goto put_and_next;
-
-		if (args->ls_frozen && !args->ls_active && strcmp(state_tmp, "FROZEN"))
-			goto put_and_next;
-
-		if (args->ls_stopped && strcmp(state_tmp, "STOPPED"))
-			goto put_and_next;
-
-		bool running = c->is_running(c);
-
-		char *grp_tmp = ls_get_groups(c, running);
-		if (!ls_has_all_grps(grp_tmp, grps_must, grps_must_len)) {
-			free(grp_tmp);
-			goto put_and_next;
-		}
-
-		/* Now it makes sense to allocate memory. */
-		l = ls_new(m, size);
-		if (!l) {
-			free(grp_tmp);
-			goto put_and_next;
-		}
-
-		/* How deeply nested are we? */
-		l->nestlvl = lvl;
-
-		l->groups = grp_tmp;
-
-		l->running = running;
-
-		if (parent && args->ls_nesting && (args->ls_line || !args->ls_fancy))
-			/* Prepend the name of the container with all its parents when
-			 * the user requests it. */
-			l->name = lxc_append_paths(parent, name);
-		else
-			/* Otherwise simply record the name. */
-			l->name = strdup(name);
-		if (!l->name)
-			goto put_and_next;
-
-		/* Do not record stuff the user did not explictly request. */
-		if (args->ls_fancy) {
-			/* Maybe we should even consider the name sensitive and
-			 * hide it when you're not allowed to control the
-			 * container. */
-			if (!c->may_control(c))
-				goto put_and_next;
-
-			l->state = strdup(state_tmp);
-			if (!l->state)
-				goto put_and_next;
-
-			tmp = ls_get_config_item(c, "lxc.start.auto", running);
-			if (tmp)
-				l->autostart = atoi(tmp);
-			free(tmp);
-
-			if (running) {
-				l->init = c->init_pid(c);
-
-				l->interface = ls_get_interface(c);
-
-				l->ipv4 = ls_get_ips(c, "inet");
-
-				l->ipv6 = ls_get_ips(c, "inet6");
-
-				tmp = ls_get_cgroup_item(c, "memory.usage_in_bytes");
-				if (tmp) {
-					l->ram = strtoull(tmp, NULL, 0);
-					l->ram = l->ram / 1024 /1024;
-					free(tmp);
-				}
-
-				l->swap = ls_get_swap(c);
-			}
-		}
-
-		/* Get nested containers: Only do this after we have gathered
-		 * all other information we need. */
-		if (args->ls_nesting && running) {
-			struct wrapargs wargs = (struct wrapargs){.args = NULL};
-			/* Open a socket so that the child can communicate with us. */
-			check = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wargs.pipefd);
-			if (check == -1)
-				goto put_and_next;
-
-			/* Set the next nesting level. */
-			wargs.nestlvl = lvl + 1;
-			/* Send in the parent for the next nesting level. */
-			wargs.parent = l->name;
-			wargs.args = args;
-			wargs.grps_must = grps_must;
-			wargs.grps_must_len = grps_must_len;
-
-			pid_t out;
-
-			lxc_attach_options_t aopt = LXC_ATTACH_OPTIONS_DEFAULT;
-			aopt.env_policy = LXC_ATTACH_CLEAR_ENV;
-
-			/* fork(): Attach to the namespace of the container and
-			 * run ls_get() in it which is called in ls_get_wrapper(). */
-			check = c->attach(c, ls_get_wrapper, &wargs, &aopt, &out);
-			/* close the socket */
-			close(wargs.pipefd[1]);
-
-			/* Retrieve all information we want from the child. */
-			if (check == 0)
-				if (ls_deserialize(wargs.pipefd[0], m, size) == -1)
-					goto put_and_next;
-
-			/* Wait for the child to finish. */
-			wait_for_pid(out);
-
-			/* We've done all the communication we need so shutdown
-			 * the socket and close it. */
-			shutdown(wargs.pipefd[0], SHUT_RDWR);
-			close(wargs.pipefd[0]);
-		} else if (args->ls_nesting && !running) {
-			/* This way of extracting the rootfs is not safe since
-			 * it will return very different things depending on the
-			 * storage backend that is used for the container. We
-			 * need a path-extractor function. We face the same
-			 * problem with the ovl_mkdir() function in
-			 * lxcoverlay.{c,h}. */
-			char *curr_path = ls_get_config_item(c, "lxc.rootfs", running);
-			if (!curr_path)
-				goto put_and_next;
-
-			/* Since the container is not running and we cannot
-			 * attach to it we need another strategy to retrieve
-			 * nested containers. What we do is simply create a
-			 * growing path which will lead us into the rootfs of
-			 * the next container where it stores its containers. */
-			char *newpath = lxc_append_paths(basepath, curr_path);
-			free(curr_path);
-			if (!newpath)
-				goto put_and_next;
-
-			/* We want to remove all locks we create under
-			 * /run/lxc/lock so we create a string pointing us to
-			 * the lock path for the current container. */
-			if (ls_remove_lock(path, name, lockpath, &len_lockpath, true) == -1)
-				goto put_and_next;
-
-			ls_get(m, size, args, newpath, l->name, lvl + 1, lockpath, len_lockpath, grps_must, grps_must_len);
-			free(newpath);
-
-			/* Remove the lock. No need to check for failure here. */
-			ls_remove_lock(path, name, lockpath, &len_lockpath, false);
-		}
-
-put_and_next:
-		lxc_container_put(c);
-	}
-	ret = 0;
-
-out:
-	ls_free_arr(containers, num);
-	free(path);
-	/* lockpath is shared amongst all non-fork()ing recursive calls to
-	 * ls_get() so only free it on the uppermost level. */
-	if (lvl == 0)
-		free(*lockpath);
-
-	return ret;
-}
-
-static char *ls_get_cgroup_item(struct lxc_container *c, const char *item)
-{
-	size_t len = c->get_cgroup_item(c, item, NULL, 0);
-	if (len <= 0)
-		return NULL;
-
-	char *val = malloc((len + 1) * sizeof(*val));
-	if (!val)
-		return NULL;
-
-	if ((size_t)c->get_cgroup_item(c, item, val, len + 1) != len) {
-		free(val);
-		val = NULL;
-	}
-
-	return val;
-}
-
-static char *ls_get_groups(struct lxc_container *c, bool running)
-{
-	size_t len = 0;
-	char *val = NULL;
-
-	if (running)
-		val = c->get_running_config_item(c, "lxc.group");
-	else
-		len = c->get_config_item(c, "lxc.group", NULL, 0);
-
-	if (!val && (len > 0)) {
-		val = malloc((len + 1) * sizeof(*val));
-		if ((size_t)c->get_config_item(c, "lxc.group", val, len + 1) != len) {
-			free(val);
-			return NULL;
-		}
-	}
-
-	if (val) {
-		char *tmp;
-		if ((tmp = strrchr(val, '\n')))
-			*tmp = '\0';
-
-		tmp = lxc_string_replace("\n", ", ", val);
-		free(val);
-		val = tmp;
-	}
-
-	return val;
-}
-
-static char *ls_get_ips(struct lxc_container *c, const char *inet)
-{
-	char *ips = NULL;
-	char **iptmp = c->get_ips(c, NULL, inet, 0);
-	if (iptmp)
-		ips = lxc_string_join(", ", (const char **)iptmp, false);
-
-	lxc_free_array((void **)iptmp, free);
-
-	return ips;
-}
-
-static char *ls_get_interface(struct lxc_container *c)
-{
-	char **interfaces = c->get_interfaces(c);
-	if (!interfaces)
-		return NULL;
-
-	char *interface = lxc_string_join(", ", (const char **)interfaces, false);
-
-	lxc_free_array((void **)interfaces, free);
-
-	return interface;
-}
-
-/*
- * To calculate swap usage we should not simply check memory.usage_in_bytes and
- * memory.memsw.usage_in_bytes and then do:
- *	swap = memory.memsw.usage_in_bytes - memory.usage_in_bytes;
- * because we might receive an incorrect/negative value.
- * Instead we check memory.stat and check the "swap" value.
- */
-static double ls_get_swap(struct lxc_container *c)
-{
-	unsigned long long int num = 0;
-	char *stat = ls_get_cgroup_item(c, "memory.stat");
-	if (!stat)
-		goto out;
-
-	char *swap = strstr(stat, "\nswap");
-	if (!swap)
-		goto out;
-
-	swap = 1 + swap + 4 + 1; // start_of_swap_value = '\n' + strlen(swap) + ' '
-
-	char *tmp = strchr(swap, '\n'); // find end of swap value
-	if (!tmp)
-		goto out;
-
-	*tmp = '\0';
-
-	num = strtoull(swap, NULL, 0);
-	num = num / 1024 / 1024;
-
-out:
-	free(stat);
-
-	return num;
-}
-
-static unsigned int ls_get_term_width(void)
-{
-	struct winsize ws;
-	if (((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1) &&
-	     (ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1) &&
-	     (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)) ||
-	    (ws.ws_col == 0))
-		return 0;
-
-	return ws.ws_col;
-}
-
-static bool ls_has_all_grps(const char *has, char **must, size_t must_len)
-{
-	bool bret = false;
-
-	if (!has && must)
-		return false;
-	else if (!must)
-		return true;
-
-	char **tmp_has = lxc_string_split_and_trim(has, ',');
-	size_t tmp_has_len = lxc_array_len((void **)tmp_has);
-
-	/* Don't do any unnecessary work. */
-	if (must_len > tmp_has_len)
-		goto out;
-
-	size_t i, j;
-	for (i = 0; i < must_len; i++) {
-		for (j = 0; j < tmp_has_len; j++)
-			if (strcmp(must[i], tmp_has[j]) == 0)
-				break;
-		if (j == tmp_has_len)
-			break;
-	}
-	if (i == must_len)
-		bret = true;
-
-out:
-	lxc_free_array((void **)tmp_has, free);
-
-	return bret;
-}
-
-static struct ls *ls_new(struct ls **ls, size_t *size)
-{
-	struct ls *m, *n;
-
-	n = realloc(*ls, (*size + 1) * sizeof(struct ls));
-	if (!n)
-		return NULL;
-
-	*ls = n;
-	m = *ls + *size;
-	(*size)++;
-
-	*m = (struct ls){.name = NULL, .init = -1};
-
-	return m;
-}
-
-static void ls_print_names(struct ls *l, struct lengths *lht,
-		size_t size, size_t termwidth)
-{
-	/* If list is empty do nothing. */
-	if (size == 0)
-		return;
-
-	size_t i, len = 0;
-	struct ls *m = NULL;
-	for (i = 0, m = l; i < size; i++, m++) {
-		printf("%-*s", lht->name_length, m->name ? m->name : "-");
-		len += lht->name_length;
-		if ((len + lht->name_length) >= termwidth) {
-			printf("\n");
-			len = 0;
-		} else {
-			printf(" ");
-			len++;
-		}
-	}
-	if (len > 0)
-		printf("\n");
-}
-
-static void ls_print_fancy_format(struct ls *l, struct lengths *lht,
-		size_t size, const char *fancy_fmt)
-{
-	/* If list is empty do nothing. */
-	if (size == 0)
-		return;
-
-	char **tmp = lxc_string_split_and_trim(fancy_fmt, ',');
-	if (!tmp)
-		return;
-
-	char **s;
-	/* Check for invalid keys. */
-	for (s = tmp; s && *s; s++) {
-		if (strcasecmp(*s, "NAME") && strcasecmp(*s, "STATE") &&
-				strcasecmp(*s, "PID") && strcasecmp(*s, "RAM") &&
-				strcasecmp(*s, "SWAP") && strcasecmp(*s, "AUTOSTART") &&
-				strcasecmp(*s, "GROUPS") && strcasecmp(*s, "INTERFACE") &&
-				strcasecmp(*s, "IPV4") && strcasecmp(*s, "IPV6")) {
-			fprintf(stderr, "Invalid key: %s\n", *s);
-			return;
-		}
-	}
-
-	/* print header */
-	for (s = tmp; s && *s; s++) {
-		if (strcasecmp(*s, "NAME") == 0)
-			printf("%-*s ", lht->name_length, "NAME");
-		else if (strcasecmp(*s, "STATE") == 0)
-			printf("%-*s ", lht->state_length, "STATE");
-		else if (strcasecmp(*s, "PID") == 0)
-			printf("%-*s ", lht->init_length, "PID");
-		else if (strcasecmp(*s, "RAM") == 0)
-			printf("%-*s ", lht->ram_length + 2, "RAM");
-		else if (strcasecmp(*s, "SWAP") == 0)
-			printf("%-*s ", lht->swap_length + 2, "SWAP");
-		else if (strcasecmp(*s, "AUTOSTART") == 0)
-			printf("%-*s ", lht->autostart_length, "AUTOSTART");
-		else if (strcasecmp(*s, "GROUPS") == 0)
-			printf("%-*s ", lht->groups_length, "GROUPS");
-		else if (strcasecmp(*s, "INTERFACE") == 0)
-			printf("%-*s ", lht->interface_length, "INTERFACE");
-		else if (strcasecmp(*s, "IPV4") == 0)
-			printf("%-*s ", lht->ipv4_length, "IPV4");
-		else if (strcasecmp(*s, "IPV6") == 0)
-			printf("%-*s ", lht->ipv6_length, "IPV6");
-	}
-	printf("\n");
-
-	struct ls *m = NULL;
-	size_t i;
-	for (i = 0, m = l; i < size; i++, m++) {
-		for (s = tmp; s && *s; s++) {
-			if (strcasecmp(*s, "NAME") == 0) {
-				if (m->nestlvl > 0) {
-					printf("%*s", m->nestlvl, "\\");
-					printf("%-*s ", lht->name_length - m->nestlvl, m->name ? m->name : "-");
-				} else {
-					printf("%-*s ", lht->name_length, m->name ? m->name : "-");
-				}
-			} else if (strcasecmp(*s, "STATE") == 0) {
-				printf("%-*s ", lht->state_length, m->state ? m->state : "-");
-			} else if (strcasecmp(*s, "PID") == 0) {
-				if (m->init > 0)
-					printf("%-*d ", lht->init_length, m->init);
-				else
-					printf("%-*s ", lht->init_length, "-");
-			} else if (strcasecmp(*s, "RAM") == 0) {
-				if ((m->ram >= 0) && m->running)
-					printf("%*.2fMB ", lht->ram_length, m->ram);
-				else
-					printf("%-*s   ", lht->ram_length, "-");
-			} else if (strcasecmp(*s, "SWAP") == 0) {
-				if ((m->swap >= 0) && m->running)
-					printf("%*.2fMB ", lht->swap_length, m->swap);
-				else
-					printf("%-*s   ", lht->swap_length, "-");
-			} else if (strcasecmp(*s, "AUTOSTART") == 0) {
-				printf("%-*d ", lht->autostart_length, m->autostart);
-			} else if (strcasecmp(*s, "GROUPS") == 0) {
-				printf("%-*s ", lht->groups_length, m->groups ? m->groups : "-");
-			} else if (strcasecmp(*s, "INTERFACE") == 0) {
-				printf("%-*s ", lht->interface_length, m->interface ? m->interface : "-");
-			} else if (strcasecmp(*s, "IPV4") == 0) {
-				printf("%-*s ", lht->ipv4_length, m->ipv4 ? m->ipv4 : "-");
-			} else if (strcasecmp(*s, "IPV6") == 0) {
-				printf("%-*s ", lht->ipv6_length, m->ipv6 ? m->ipv6 : "-");
-			}
-		}
-		printf("\n");
-	}
-}
-
-static void ls_print_table(struct ls *l, struct lengths *lht,
-		size_t size)
-{
-	/* If list is empty do nothing. */
-	if (size == 0)
-		return;
-
-	struct ls *m = NULL;
-
-	/* print header */
-	printf("%-*s ", lht->name_length, "NAME");
-	printf("%-*s ", lht->state_length, "STATE");
-	printf("%-*s ", lht->autostart_length, "AUTOSTART");
-	printf("%-*s ", lht->groups_length, "GROUPS");
-	printf("%-*s ", lht->ipv4_length, "IPV4");
-	printf("%-*s ", lht->ipv6_length, "IPV6");
-	printf("\n");
-
-	size_t i;
-	for (i = 0, m = l; i < size; i++, m++) {
-		if (m->nestlvl > 0) {
-			printf("%*s", m->nestlvl, "\\");
-			printf("%-*s ", lht->name_length - m->nestlvl, m->name ? m->name : "-");
-		} else {
-		     printf("%-*s ", lht->name_length, m->name ? m->name : "-");
-		}
-		printf("%-*s ", lht->state_length, m->state ? m->state : "-");
-		printf("%-*d ", lht->autostart_length, m->autostart);
-		printf("%-*s ", lht->groups_length, m->groups ? m->groups : "-");
-		printf("%-*s ", lht->ipv4_length, m->ipv4 ? m->ipv4 : "-");
-		printf("%-*s ", lht->ipv6_length, m->ipv6 ? m->ipv6 : "-");
-		printf("\n");
-	}
-}
-
-static int my_parser(struct lxc_arguments *args, int c, char *arg)
-{
-	char *invalid;
-	unsigned long int m, n = MAX_NESTLVL;
-	switch (c) {
-	case '1':
-		args->ls_line = true;
-		break;
-	case 'f':
-		args->ls_fancy = true;
-		break;
-	case LS_ACTIVE:
-		args->ls_active = true;
-		break;
-	case LS_FROZEN:
-		args->ls_frozen = true;
-		break;
-	case LS_RUNNING:
-		args->ls_running = true;
-		break;
-	case LS_STOPPED:
-		args->ls_stopped = true;
-		break;
-	case LS_NESTING:
-		/* In case strtoul() receives a string that represents a
-		 * negative number it will return ULONG_MAX - the number that
-		 * the string represents if the number the string represents is
-		 * < ULONG_MAX and ULONG_MAX otherwise. But it will consider
-		 * this valid input and not set errno. So we check manually if
-		 * the first character of num_string == '-'. Otherwise the
-		 * default level remains set. */
-		if (arg && !(*arg == '-')) {
-			errno = 0;
-			m = strtoul(arg, &invalid, 0);
-			/* ls_nesting has type unsigned int. */
-			if (!errno && (*invalid == '\0') && (m <= UINT_MAX))
-				n = m;
-		}
-		args->ls_nesting = n;
-		break;
-	case 'g':
-		args->groups = arg;
-		break;
-	case LS_FILTER:
-		args->ls_filter = arg;
-		break;
-	case 'F':
-		args->ls_fancy_format = arg;
-		break;
-	}
-
-	return 0;
-}
-
-static int ls_get_wrapper(void *wrap)
-{
-	int ret = -1;
-	size_t len = 0;
-	struct wrapargs *wargs = (struct wrapargs *)wrap;
-	struct ls *m = NULL, *n = NULL;
-
-	/* close pipe */
-	close(wargs->pipefd[0]);
-
-	/* &(char *){NULL} is no magic. It's just a compound literal which
-	 * allows us to avoid keeping a pointless variable around. */
-	ls_get(&m, &len, wargs->args, "", wargs->parent, wargs->nestlvl, &(char *){NULL}, 0, wargs->grps_must, wargs->grps_must_len);
-	if (!m)
-		goto out;
-
-	/* send length */
-	if (lxc_write_nointr(wargs->pipefd[1], &len, sizeof(len)) <= 0)
-		goto out;
-
-	size_t i;
-	for (i = 0, n = m; i < len; i++, n++) {
-		if (ls_serialize(wargs->pipefd[1], n) == -1)
-			goto out;
-	}
-	ret = 0;
-
-out:
-	shutdown(wargs->pipefd[1], SHUT_RDWR);
-	close(wargs->pipefd[1]);
-	ls_free(m, len);
-
-	return ret;
-}
-
-static int ls_remove_lock(const char *path, const char *name,
-		char **lockpath, size_t *len_lockpath, bool recalc)
-{
-	/* Avoid doing unnecessary work if we can. */
-	if (recalc) {
-		size_t newlen = strlen(path) + strlen(name) + strlen(RUNTIME_PATH) + /* / + lxc + / + lock + / + / = */ 11 + 1;
-		if (newlen > *len_lockpath) {
-			char *tmp = realloc(*lockpath, newlen * 2);
-			if (!tmp)
-				return -1;
-			*lockpath = tmp;
-			*len_lockpath = newlen * 2;
-		}
-	}
-
-	int check = snprintf(*lockpath, *len_lockpath, "%s/lxc/lock/%s/%s", RUNTIME_PATH, path, name);
-	if (check < 0 || (size_t)check >= *len_lockpath)
-		return -1;
-
-	lxc_rmdir_onedev(*lockpath, NULL);
-
-	return 0;
-}
-
-static int ls_send_str(int fd, const char *buf)
-{
-	size_t slen = 0;
-	if (buf)
-		slen = strlen(buf);
-	if (lxc_write_nointr(fd, &slen, sizeof(slen)) != sizeof(slen))
-		return -1;
-	if (slen > 0) {
-		if (lxc_write_nointr(fd, buf, slen) != (ssize_t)slen)
-			return -1;
-	}
-	return 0;
-}
-
-static int ls_serialize(int wpipefd, struct ls *n)
-{
-	ssize_t nbytes = sizeof(n->ram);
-	if (lxc_write_nointr(wpipefd, &n->ram, (size_t)nbytes) != nbytes)
-		return -1;
-
-	nbytes = sizeof(n->swap);
-	if (lxc_write_nointr(wpipefd, &n->swap, (size_t)nbytes) != nbytes)
-		return -1;
-
-	nbytes = sizeof(n->init);
-	if (lxc_write_nointr(wpipefd, &n->init, (size_t)nbytes) != nbytes)
-		return -1;
-
-	nbytes = sizeof(n->autostart);
-	if (lxc_write_nointr(wpipefd, &n->autostart, (size_t)nbytes) != nbytes)
-		return -1;
-
-	nbytes = sizeof(n->running);
-	if (lxc_write_nointr(wpipefd, &n->running, (size_t)nbytes) != nbytes)
-		return -1;
-
-	nbytes = sizeof(n->nestlvl);
-	if (lxc_write_nointr(wpipefd, &n->nestlvl, (size_t)nbytes) != nbytes)
-		return -1;
-
-	/* NAME */
-	if (ls_send_str(wpipefd, n->name) < 0)
-		return -1;
-
-	/* STATE */
-	if (ls_send_str(wpipefd, n->state) < 0)
-		return -1;
-
-	/* GROUPS */
-	if (ls_send_str(wpipefd, n->groups) < 0)
-		return -1;
-
-	/* INTERFACE */
-	if (ls_send_str(wpipefd, n->interface) < 0)
-		return -1;
-
-	/* IPV4 */
-	if (ls_send_str(wpipefd, n->ipv4) < 0)
-		return -1;
-
-	/* IPV6 */
-	if (ls_send_str(wpipefd, n->ipv6) < 0)
-		return -1;
-
-	return 0;
-}
-
-static int ls_recv_str(int fd, char **buf)
-{
-	size_t slen = 0;
-	if (lxc_read_nointr(fd, &slen, sizeof(slen)) != sizeof(slen))
-		return -1;
-	if (slen > 0) {
-		*buf = malloc(sizeof(char) * (slen + 1));
-		if (!*buf)
-			return -1;
-		if (lxc_read_nointr(fd, *buf, slen) != (ssize_t)slen)
-			return -1;
-		(*buf)[slen] = '\0';
-	}
-	return 0;
-}
-
-static int ls_deserialize(int rpipefd, struct ls **m, size_t *len)
-{
-	struct ls *n;
-	size_t sublen = 0;
-	ssize_t nbytes = 0;
-
-	/* get length */
-	nbytes = sizeof(sublen);
-	if (lxc_read_nointr(rpipefd, &sublen, (size_t)nbytes) != nbytes)
-		return -1;
-
-	while (sublen-- > 0) {
-		n = ls_new(m, len);
-		if (!n)
-			return -1;
-
-		nbytes = sizeof(n->ram);
-		if (lxc_read_nointr(rpipefd, &n->ram, (size_t)nbytes) != nbytes)
-			return -1;
-
-		nbytes = sizeof(n->swap);
-		if (lxc_read_nointr(rpipefd, &n->swap, (size_t)nbytes) != nbytes)
-			return -1;
-
-		nbytes = sizeof(n->init);
-		if (lxc_read_nointr(rpipefd, &n->init, (size_t)nbytes) != nbytes)
-			return -1;
-
-		nbytes = sizeof(n->autostart);
-		if (lxc_read_nointr(rpipefd, &n->autostart, (size_t)nbytes) != nbytes)
-			return -1;
-
-		nbytes = sizeof(n->running);
-		if (lxc_read_nointr(rpipefd, &n->running, (size_t)nbytes) != nbytes)
-			return -1;
-
-		nbytes = sizeof(n->nestlvl);
-		if (lxc_read_nointr(rpipefd, &n->nestlvl, (size_t)nbytes) != nbytes)
-			return -1;
-
-		/* NAME */
-		if (ls_recv_str(rpipefd, &n->name) < 0)
-			return -1;
-
-		/* STATE */
-		if (ls_recv_str(rpipefd, &n->state) < 0)
-			return -1;
-
-		/* GROUPS */
-		if (ls_recv_str(rpipefd, &n->groups) < 0)
-			return -1;
-
-		/* INTERFACE */
-		if (ls_recv_str(rpipefd, &n->interface) < 0)
-			return -1;
-
-		/* IPV4 */
-		if (ls_recv_str(rpipefd, &n->ipv4) < 0)
-			return -1;
-
-		/* IPV6 */
-		if (ls_recv_str(rpipefd, &n->ipv6) < 0)
-			return -1;
-	}
-
-	return 0;
-}
-
-static void ls_field_width(const struct ls *l, const size_t size,
-		struct lengths *lht)
-{
-	const struct ls *m;
-	size_t i, len = 0;
-	for (i = 0, m = l; i < size; i++, m++) {
-		if (m->name) {
-			len = strlen(m->name) + m->nestlvl;
-			if (len > lht->name_length)
-				lht->name_length = len;
-		}
-
-		if (m->state) {
-			len = strlen(m->state);
-			if (len > lht->state_length)
-				lht->state_length = len;
-		}
-
-		if (m->interface) {
-			len = strlen(m->interface);
-			if (len > lht->interface_length)
-				lht->interface_length = len;
-		}
-
-		if (m->groups) {
-			len = strlen(m->groups);
-			if (len > lht->groups_length)
-				lht->groups_length = len;
-		}
-		if (m->ipv4) {
-			len = strlen(m->ipv4);
-			if (len > lht->ipv4_length)
-				lht->ipv4_length = len;
-		}
-
-		if (m->ipv6) {
-			len = strlen(m->ipv6);
-			if (len > lht->ipv6_length)
-				lht->ipv6_length = len;
-		}
-
-		if ((len = snprintf(NULL, 0, "%.2f", m->ram)) > lht->ram_length)
-			lht->ram_length = len;
-
-		if ((len = snprintf(NULL, 0, "%.2f", m->swap)) > lht->swap_length)
-			lht->swap_length = len;
-
-		if (m->init != -1) {
-			if ((len = snprintf(NULL, 0, "%d", m->init)) > lht->init_length)
-				lht->init_length = len;
-		}
-	}
-}
diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c
deleted file mode 100644
index 797ae8b..0000000
--- a/src/lxc/lxc_monitor.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libgen.h>
-#include <unistd.h>
-#include <regex.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <poll.h>
-
-#include "lxc.h"
-#include "log.h"
-#include "monitor.h"
-#include "arguments.h"
-
-lxc_log_define(lxc_monitor_ui, lxc);
-
-static bool quit_monitord;
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	switch (c) {
-	case 'Q': quit_monitord = true; break;
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	{"quit", no_argument, 0, 'Q'},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-monitor",
-	.help     = "\
-[--name=NAME]\n\
-\n\
-lxc-monitor monitors the state of the NAME container\n\
-\n\
-Options :\n\
-  -n, --name=NAME   NAME of the container\n\
-                    NAME may be a regular expression\n\
-  -Q, --quit        tell lxc-monitord to quit\n",
-	.name     = ".*",
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = NULL,
-	.lxcpath_additional = -1,
-};
-
-static void close_fds(struct pollfd *fds, nfds_t nfds)
-{
-	nfds_t i;
-
-	if (nfds < 1)
-		return;
-
-	for (i = 0; i < nfds; ++i) {
-		close(fds[i].fd);
-	}
-}
-
-int main(int argc, char *argv[])
-{
-	char *regexp;
-	struct lxc_msg msg;
-	regex_t preg;
-	struct pollfd *fds;
-	nfds_t nfds;
-	int len, rc_main, rc_snp, i;
-
-	rc_main = 0;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		return 1;
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		return 1;
-	lxc_log_options_no_override();
-
-	if (quit_monitord) {
-		int ret = EXIT_SUCCESS;
-		for (i = 0; i < my_args.lxcpath_cnt; i++) {
-			int fd;
-
-			fd = lxc_monitor_open(my_args.lxcpath[i]);
-			if (fd < 0) {
-				ERROR("Unable to open monitor on path: %s", my_args.lxcpath[i]);
-				ret = EXIT_FAILURE;
-				continue;
-			}
-			if (write(fd, "quit", 4) < 0) {
-				SYSERROR("Unable to close monitor on path: %s", my_args.lxcpath[i]);
-				ret = EXIT_FAILURE;
-				close(fd);
-				continue;
-			}
-			close(fd);
-		}
-		return ret;
-	}
-
-	len = strlen(my_args.name) + 3;
-	regexp = malloc(len + 3);
-	if (!regexp) {
-		ERROR("failed to allocate memory");
-		return 1;
-	}
-	rc_snp = snprintf(regexp, len, "^%s$", my_args.name);
-	if (rc_snp < 0 || rc_snp >= len) {
-		ERROR("Name too long");
-		rc_main = 1;
-		goto error;
-	}
-
-	if (regcomp(&preg, regexp, REG_NOSUB|REG_EXTENDED)) {
-		ERROR("failed to compile the regex '%s'", my_args.name);
-		rc_main = 1;
-		goto error;
-	}
-
-	fds = malloc(my_args.lxcpath_cnt * sizeof(struct pollfd));
-	if (!fds) {
-		SYSERROR("out of memory");
-		rc_main = -1;
-		goto cleanup;
-	}
-
-	nfds = my_args.lxcpath_cnt;
-	for (i = 0; i < nfds; i++) {
-		int fd;
-
-		lxc_monitord_spawn(my_args.lxcpath[i]);
-
-		fd = lxc_monitor_open(my_args.lxcpath[i]);
-		if (fd < 0) {
-			close_fds(fds, i);
-			rc_main = 1;
-			goto cleanup;
-		}
-		fds[i].fd = fd;
-		fds[i].events = POLLIN;
-		fds[i].revents = 0;
-	}
-
-	setlinebuf(stdout);
-
-	for (;;) {
-		if (lxc_monitor_read_fdset(fds, nfds, &msg, -1) < 0) {
-			rc_main = 1;
-			goto close_and_clean;
-		}
-
-		msg.name[sizeof(msg.name)-1] = '\0';
-		if (regexec(&preg, msg.name, 0, NULL, 0))
-			continue;
-
-		switch (msg.type) {
-		case lxc_msg_state:
-			printf("'%s' changed state to [%s]\n",
-			       msg.name, lxc_state2str(msg.value));
-			break;
-		case lxc_msg_exit_code:
-			printf("'%s' exited with status [%d]\n",
-			       msg.name, WEXITSTATUS(msg.value));
-			break;
-		default:
-			/* ignore garbage */
-			break;
-		}
-	}
-
-close_and_clean:
-	close_fds(fds, nfds);
-
-cleanup:
-	regfree(&preg);
-	free(fds);
-
-error:
-	free(regexp);
-
-	return rc_main;
-}
diff --git a/src/lxc/lxc_snapshot.c b/src/lxc/lxc_snapshot.c
deleted file mode 100644
index 8f44891..0000000
--- a/src/lxc/lxc_snapshot.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- *
- * Copyright © 2013 Serge Hallyn <serge.hallyn at ubuntu.com>.
- * Copyright © 2013 Canonical Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "confile.h"
-#include <stdio.h>
-#include <libgen.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <fcntl.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "bdev.h"
-#include "lxc.h"
-#include "log.h"
-#include "arguments.h"
-#include "utils.h"
-
-lxc_log_define(lxc_snapshot_ui, lxc);
-
-static int my_parser(struct lxc_arguments *args, int c, char *arg);
-
-static const struct option my_longopts[] = {
-	{"list", no_argument, 0, 'L'},
-	{"restore", required_argument, 0, 'r'},
-	{"newname", required_argument, 0, 'N'},
-	{"destroy", required_argument, 0, 'd'},
-	{"comment", required_argument, 0, 'c'},
-	{"showcomments", no_argument, 0, 'C'},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-snapshot",
-	.help = "\
---name=NAME [-P lxcpath] [-L [-C]] [-c commentfile] [-r snapname [-N newname]]\n\
-\n\
-lxc-snapshot snapshots a container\n\
-\n\
-Options :\n\
-  -n, --name=NAME	 NAME of the container\n\
-  -L, --list             list all snapshots\n\
-  -r, --restore=NAME     restore snapshot NAME, e.g. 'snap0'\n\
-  -N, --newname=NEWNAME  NEWNAME for the restored container\n\
-  -d, --destroy=NAME     destroy snapshot NAME, e.g. 'snap0'\n\
-                         use ALL to destroy all snapshots\n\
-  -c, --comment=FILE     add FILE as a comment\n\
-  -C, --showcomments     show snapshot comments\n",
-	.options = my_longopts,
-	.parser = my_parser,
-	.checker = NULL,
-	.task = SNAP,
-};
-
-static int do_snapshot(struct lxc_container *c, char *commentfile);
-static int do_snapshot_destroy(struct lxc_container *c, char *snapname);
-static int do_snapshot_list(struct lxc_container *c, int print_comments);
-static int do_snapshot_restore(struct lxc_container *c,
-			       struct lxc_arguments *args);
-static int do_snapshot_task(struct lxc_container *c, enum task task);
-static void print_file(char *path);
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c;
-	int ret;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		exit(EXIT_FAILURE);
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
-
-	if (geteuid()) {
-		if (access(my_args.lxcpath[0], O_RDWR) < 0) {
-			fprintf(stderr, "You lack access to %s\n",
-				my_args.lxcpath[0]);
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c) {
-		fprintf(stderr, "System error loading container\n");
-		exit(EXIT_FAILURE);
-	}
-
-	if (!c->may_control(c)) {
-		fprintf(stderr, "Insufficent privileges to control %s\n",
-			my_args.name);
-		lxc_container_put(c);
-		exit(EXIT_FAILURE);
-	}
-
-	ret = do_snapshot_task(c, my_args.task);
-
-	lxc_container_put(c);
-
-	if (ret == 0)
-		exit(EXIT_SUCCESS);
-	exit(EXIT_FAILURE);
-}
-
-static int do_snapshot_task(struct lxc_container *c, enum task task)
-{
-	int ret = 0;
-
-	switch (task) {
-	case DESTROY:
-		ret = do_snapshot_destroy(c, my_args.snapname);
-		break;
-	case LIST:
-		ret = do_snapshot_list(c, my_args.print_comments);
-		break;
-	case RESTORE:
-		ret = do_snapshot_restore(c, &my_args);
-		break;
-	case SNAP:
-		ret = do_snapshot(c, my_args.commentfile);
-		break;
-	default:
-		ret = 0;
-		break;
-	}
-
-	return ret;
-}
-
-static int my_parser(struct lxc_arguments *args, int c, char *arg)
-{
-	switch (c) {
-	case 'L':
-		args->task = LIST;
-		break;
-	case 'r':
-		args->task = RESTORE;
-		args->snapname = arg;
-		break;
-	case 'N':
-		args->newname = arg;
-		break;
-	case 'd':
-		args->task = DESTROY;
-		args->snapname = arg;
-		break;
-	case 'c':
-		args->commentfile = arg;
-		break;
-	case 'C':
-		args->print_comments = 1;
-		break;
-	}
-
-	return 0;
-}
-
-static int do_snapshot(struct lxc_container *c, char *commentfile)
-{
-	int ret;
-
-	ret = c->snapshot(c, commentfile);
-	if (ret < 0) {
-		ERROR("Error creating a snapshot");
-		return -1;
-	}
-
-	INFO("Created snapshot snap%d", ret);
-
-	return 0;
-}
-
-static int do_snapshot_destroy(struct lxc_container *c, char *snapname)
-{
-	bool ret;
-
-	if (strcmp(snapname, "ALL") == 0)
-		ret = c->snapshot_destroy_all(c);
-	else
-		ret = c->snapshot_destroy(c, snapname);
-
-	if (!ret) {
-		ERROR("Error destroying snapshot %s", snapname);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int do_snapshot_list(struct lxc_container *c, int print_comments)
-{
-	struct lxc_snapshot *s;
-	int i, n;
-
-	n = c->snapshot_list(c, &s);
-	if (n < 0) {
-		ERROR("Error listing snapshots");
-		return -1;
-	}
-	if (n == 0) {
-		printf("No snapshots\n");
-		return 0;
-	}
-
-	for (i = 0; i < n; i++) {
-		printf("%s (%s) %s\n", s[i].name, s[i].lxcpath, s[i].timestamp);
-		if (print_comments)
-			print_file(s[i].comment_pathname);
-		s[i].free(&s[i]);
-	}
-
-	free(s);
-
-	return 0;
-}
-
-static int do_snapshot_restore(struct lxc_container *c,
-			       struct lxc_arguments *args)
-{
-	int bret;
-
-	/* When restoring  a snapshot, the last optional argument if not given
-	 * explicitly via the corresponding command line option is the name to
-	 * use for the restored container. If no name is given, then the
-	 * original container will be destroyed and the restored container will
-	 * take its place. */
-	if ((!args->newname) && (args->argc > 1)) {
-		lxc_error(args, "Too many arguments");
-		return -1;
-	}
-
-	if ((!args->newname) && (args->argc == 1))
-		args->newname = args->argv[0];
-
-	bret = c->snapshot_restore(c, args->snapname, args->newname);
-	if (!bret) {
-		ERROR("Error restoring snapshot %s", args->snapname);
-		return -1;
-	}
-
-	return 0;
-}
-
-static void print_file(char *path)
-{
-	if (!path)
-		return;
-
-	FILE *f = fopen(path, "r");
-	char *line = NULL;
-	size_t sz = 0;
-
-	if (!f)
-		return;
-
-	while (getline(&line, &sz, f) != -1) {
-		printf("%s", line);
-	}
-
-	free(line);
-	fclose(f);
-}
-
diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c
deleted file mode 100644
index 6b942ac..0000000
--- a/src/lxc/lxc_start.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <libgen.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/param.h>
-#include <sys/utsname.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <net/if.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "log.h"
-#include "caps.h"
-#include "lxc.h"
-#include "conf.h"
-#include "cgroup.h"
-#include "utils.h"
-#include "confile.h"
-#include "arguments.h"
-
-#define OPT_SHARE_NET OPT_USAGE+1
-#define OPT_SHARE_IPC OPT_USAGE+2
-#define OPT_SHARE_UTS OPT_USAGE+3
-
-lxc_log_define(lxc_start_ui, lxc);
-
-static struct lxc_list defines;
-
-static int ensure_path(char **confpath, const char *path)
-{
-	int err = -1, fd;
-	char *fullpath = NULL;
-
-	if (path) {
-		if (access(path, W_OK)) {
-			fd = creat(path, 0600);
-			if (fd < 0 && errno != EEXIST) {
-				SYSERROR("failed to create '%s'", path);
-				goto err;
-			}
-			if (fd >= 0)
-				close(fd);
-		}
-
-		fullpath = realpath(path, NULL);
-		if (!fullpath) {
-			SYSERROR("failed to get the real path of '%s'", path);
-			goto err;
-		}
-
-		*confpath = strdup(fullpath);
-		if (!*confpath) {
-			ERROR("failed to dup string '%s'", fullpath);
-			goto err;
-		}
-	}
-	err = 0;
-
-err:
-	free(fullpath);
-	return err;
-}
-
-static int pid_from_lxcname(const char *lxcname_or_pid, const char *lxcpath) {
-	char *eptr;
-	int pid = strtol(lxcname_or_pid, &eptr, 10);
-	if (*eptr != '\0' || pid < 1) {
-		struct lxc_container *s;
-		s = lxc_container_new(lxcname_or_pid, lxcpath);
-		if (!s) {
-			SYSERROR("'%s' is not a valid pid nor a container name", lxcname_or_pid);
-			return -1;
-		}
-
-		if (!s->may_control(s)) {
-			SYSERROR("Insufficient privileges to control container '%s'", s->name);
-			lxc_container_put(s);
-			return -1;
-		}
-
-		pid = s->init_pid(s);
-		if (pid < 1) {
-			SYSERROR("Is container '%s' running?", s->name);
-			lxc_container_put(s);
-			return -1;
-		}
-
-		lxc_container_put(s);
-	}
-	if (kill(pid, 0) < 0) {
-		SYSERROR("Can't send signal to pid %d", pid);
-		return -1;
-	}
-
-	return pid;
-}
-
-static int open_ns(int pid, const char *ns_proc_name) {
-	int fd;
-	char path[MAXPATHLEN];
-	snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns_proc_name);
-
-	fd = open(path, O_RDONLY);
-	if (fd < 0) {
-		SYSERROR("failed to open %s", path);
-		return -1;
-	}
-	return fd;
-}
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	switch (c) {
-	case 'c': args->console = arg; break;
-	case 'L': args->console_log = arg; break;
-	case 'd': args->daemonize = 1; break;
-	case 'F': args->daemonize = 0; break;
-	case 'f': args->rcfile = arg; break;
-	case 'C': args->close_all_fds = 1; break;
-	case 's': return lxc_config_define_add(&defines, arg);
-	case 'p': args->pidfile = arg; break;
-	case OPT_SHARE_NET: args->share_ns[LXC_NS_NET] = arg; break;
-	case OPT_SHARE_IPC: args->share_ns[LXC_NS_IPC] = arg; break;
-	case OPT_SHARE_UTS: args->share_ns[LXC_NS_UTS] = arg; break;
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	{"daemon", no_argument, 0, 'd'},
-	{"foreground", no_argument, 0, 'F'},
-	{"rcfile", required_argument, 0, 'f'},
-	{"define", required_argument, 0, 's'},
-	{"console", required_argument, 0, 'c'},
-	{"console-log", required_argument, 0, 'L'},
-	{"close-all-fds", no_argument, 0, 'C'},
-	{"pidfile", required_argument, 0, 'p'},
-	{"share-net", required_argument, 0, OPT_SHARE_NET},
-	{"share-ipc", required_argument, 0, OPT_SHARE_IPC},
-	{"share-uts", required_argument, 0, OPT_SHARE_UTS},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-start",
-	.help     = "\
---name=NAME -- COMMAND\n\
-\n\
-lxc-start start COMMAND in specified container NAME\n\
-\n\
-Options :\n\
-  -n, --name=NAME        NAME of the container\n\
-  -d, --daemon           Daemonize the container (default)\n\
-  -F, --foreground       Start with the current tty attached to /dev/console\n\
-  -p, --pidfile=FILE     Create a file with the process id\n\
-  -f, --rcfile=FILE      Load configuration file FILE\n\
-  -c, --console=FILE     Use specified FILE for the container console\n\
-  -L, --console-log=FILE Log container console output to FILE\n\
-  -C, --close-all-fds    If any fds are inherited, close them\n\
-                         If not specified, exit with failure instead\n\
-                         Note: --daemon implies --close-all-fds\n\
-  -s, --define KEY=VAL   Assign VAL to configuration variable KEY\n\
-      --share-[net|ipc|uts]=NAME Share a namespace with another container or pid\n\
-",
-	.options   = my_longopts,
-	.parser    = my_parser,
-	.checker   = NULL,
-	.daemonize = 1,
-	.pidfile = NULL,
-};
-
-int main(int argc, char *argv[])
-{
-	int err = 1;
-	struct lxc_conf *conf;
-	char *const *args;
-	char *rcfile = NULL;
-	char *const default_args[] = {
-		"/sbin/init",
-		NULL,
-	};
-	struct lxc_container *c;
-
-	lxc_list_init(&defines);
-
-	if (lxc_caps_init())
-		return err;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		return err;
-
-	if (!my_args.argc)
-		args = default_args;
-	else
-		args = my_args.argv;
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		return err;
-	lxc_log_options_no_override();
-
-	const char *lxcpath = my_args.lxcpath[0];
-
-	/*
-	 * rcfile possibilities:
-	 * 1. rcfile from random path specified in cli option
-	 * 2. rcfile not specified, use $lxcpath/$lxcname/config
-	 * 3. rcfile not specified and does not exist.
-	 */
-	/* rcfile is specified in the cli option */
-	if (my_args.rcfile) {
-		rcfile = (char *)my_args.rcfile;
-		c = lxc_container_new(my_args.name, lxcpath);
-		if (!c) {
-			ERROR("Failed to create lxc_container");
-			return err;
-		}
-		c->clear_config(c);
-		if (!c->load_config(c, rcfile)) {
-			ERROR("Failed to load rcfile");
-			lxc_container_put(c);
-			return err;
-		}
-	} else {
-		int rc;
-
-		rc = asprintf(&rcfile, "%s/%s/config", lxcpath, my_args.name);
-		if (rc == -1) {
-			SYSERROR("failed to allocate memory");
-			return err;
-		}
-		INFO("using rcfile %s", rcfile);
-
-		/* container configuration does not exist */
-		if (access(rcfile, F_OK)) {
-			free(rcfile);
-			rcfile = NULL;
-		}
-		c = lxc_container_new(my_args.name, lxcpath);
-		if (!c) {
-			ERROR("Failed to create lxc_container");
-			return err;
-		}
-	}
-
-	if (c->is_running(c)) {
-		ERROR("Container is already running.");
-		err = 0;
-		goto out;
-	}
-	/*
-	 * We should use set_config_item() over &defines, which would handle
-	 * unset c->lxc_conf for us and let us not use lxc_config_define_load()
-	 */
-	if (!c->lxc_conf)
-		c->lxc_conf = lxc_conf_init();
-	conf = c->lxc_conf;
-
-	if (lxc_config_define_load(&defines, conf))
-		goto out;
-
-	if (!rcfile && !strcmp("/sbin/init", args[0])) {
-		ERROR("Executing '/sbin/init' with no configuration file may crash the host");
-		goto out;
-	}
-
-	if (ensure_path(&conf->console.path, my_args.console) < 0) {
-		ERROR("failed to ensure console path '%s'", my_args.console);
-		goto out;
-	}
-
-	if (ensure_path(&conf->console.log_path, my_args.console_log) < 0) {
-		ERROR("failed to ensure console log '%s'", my_args.console_log);
-		goto out;
-	}
-
-	if (my_args.pidfile != NULL) {
-		if (ensure_path(&c->pidfile, my_args.pidfile) < 0) {
-			ERROR("failed to ensure pidfile '%s'", my_args.pidfile);
-			goto out;
-		}
-	}
-
-	int i;
-	for (i = 0; i < LXC_NS_MAX; i++) {
-		if (my_args.share_ns[i] == NULL)
-			continue;
-
-		int pid = pid_from_lxcname(my_args.share_ns[i], lxcpath);
-		if (pid < 1)
-			goto out;
-
-		int fd = open_ns(pid, ns_info[i].proc_name);
-		if (fd < 0)
-			goto out;
-		conf->inherit_ns_fd[i] = fd;
-	}
-
-	if (!my_args.daemonize) {
-		c->want_daemonize(c, false);
-	}
-
-	if (my_args.close_all_fds)
-		c->want_close_all_fds(c, true);
-
-	if (args == default_args)
-		err = c->start(c, 0, NULL) ? 0 : 1;
-	else
-		err = c->start(c, 0, args) ? 0 : 1;
-
-	if (err) {
-		ERROR("The container failed to start.");
-		if (my_args.daemonize)
-			ERROR("To get more details, run the container in foreground mode.");
-		ERROR("Additional information can be obtained by setting the "
-		      "--logfile and --logpriority options.");
-		err = c->error_num;
-		lxc_container_put(c);
-		return err;
-	}
-
-out:
-	lxc_container_put(c);
-	return err;
-}
diff --git a/src/lxc/lxc_stop.c b/src/lxc/lxc_stop.c
deleted file mode 100644
index 10ddce6..0000000
--- a/src/lxc/lxc_stop.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <stdio.h>
-#include <libgen.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "lxc.h"
-#include "log.h"
-#include "arguments.h"
-#include "commands.h"
-#include "utils.h"
-
-#define OPT_NO_LOCK OPT_USAGE+1
-#define OPT_NO_KILL OPT_USAGE+2
-
-lxc_log_define(lxc_stop_ui, lxc);
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	switch (c) {
-	case 'r': args->reboot = 1; break;
-	case 'W': args->nowait = 1; break;
-	case 't': args->timeout = atoi(arg); break;
-	case 'k': args->hardstop = 1; break;
-	case OPT_NO_LOCK: args->nolock = 1; break;
-	case OPT_NO_KILL: args->nokill = 1; break;
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	{"reboot", no_argument, 0, 'r'},
-	{"nowait", no_argument, 0, 'W'},
-	{"timeout", required_argument, 0, 't'},
-	{"kill", no_argument, 0, 'k'},
-	{"nokill", no_argument, 0, OPT_NO_KILL},
-	{"nolock", no_argument, 0, OPT_NO_LOCK},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-stop",
-	.help     = "\
---name=NAME\n\
-\n\
-lxc-stop stops a container with the identifier NAME\n\
-\n\
-Options :\n\
-  -n, --name=NAME   NAME of the container\n\
-  -r, --reboot      reboot the container\n\
-  -W, --nowait      don't wait for shutdown or reboot to complete\n\
-  -t, --timeout=T   wait T seconds before hard-stopping\n\
-  -k, --kill        kill container rather than request clean shutdown\n\
-      --nolock      Avoid using API locks\n\
-      --nokill      Only request clean shutdown, don't force kill after timeout\n",
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = NULL,
-	.timeout  = -2,
-};
-
-/* returns -1 on failure, 0 on success */
-static int do_reboot_and_check(struct lxc_arguments *a, struct lxc_container *c)
-{
-	int ret;
-	pid_t pid;
-	pid_t newpid;
-	int timeout = a->timeout;
-
-	pid = c->init_pid(c);
-	if (pid == -1)
-		return -1;
-	if (!c->reboot(c))
-		return -1;
-	if (a->nowait)
-		return 0;
-	if (timeout == 0)
-		goto out;
-
-	for (;;) {
-		/* can we use c-> wait for this, assuming it will
-		 * re-enter RUNNING?  For now just sleep */
-		int elapsed_time, curtime = 0;
-		struct timeval tv;
-
-		newpid = c->init_pid(c);
-		if (newpid != -1 && newpid != pid)
-			return 0;
-
-		if (timeout != -1) {
-			ret = gettimeofday(&tv, NULL);
-			if (ret)
-				break;
-			curtime = tv.tv_sec;
-		}
-
-		sleep(1);
-		if (timeout != -1) {
-			ret = gettimeofday(&tv, NULL);
-			if (ret)
-				break;
-			elapsed_time = tv.tv_sec - curtime;
-			if (timeout - elapsed_time <= 0)
-				break;
-			timeout -= elapsed_time;
-		}
-	}
-
-out:
-	newpid = c->init_pid(c);
-	if (newpid == -1 || newpid == pid) {
-		printf("Reboot did not complete before timeout\n");
-		return -1;
-	}
-	return 0;
-}
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c;
-	bool s;
-	int ret = 1;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		return 1;
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		return 1;
-	lxc_log_options_no_override();
-
-	/* Set default timeout */
-	if (my_args.timeout == -2) {
-		if (my_args.hardstop) {
-			my_args.timeout = 0;
-		}
-		else {
-			my_args.timeout = 60;
-		}
-	}
-
-	if (my_args.nowait) {
-		my_args.timeout = 0;
-	}
-
-	/* some checks */
-	if (!my_args.hardstop && my_args.timeout < -1) {
-		fprintf(stderr, "invalid timeout\n");
-		return 1;
-	}
-
-	if (my_args.hardstop && my_args.nokill) {
-		fprintf(stderr, "-k can't be used with --nokill\n");
-		return 1;
-	}
-
-	if (my_args.hardstop && my_args.reboot) {
-		fprintf(stderr, "-k can't be used with -r\n");
-		return 1;
-	}
-
-	if (my_args.hardstop && my_args.timeout) {
-		fprintf(stderr, "-k doesn't allow timeouts\n");
-		return 1;
-	}
-
-	if (my_args.nolock && !my_args.hardstop) {
-		fprintf(stderr, "--nolock may only be used with -k\n");
-		return 1;
-	}
-
-	/* shortcut - if locking is bogus, we should be able to kill
-	 * containers at least */
-	if (my_args.nolock)
-		return lxc_cmd_stop(my_args.name, my_args.lxcpath[0]);
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c) {
-		fprintf(stderr, "Error opening container\n");
-		goto out;
-	}
-
-	if (!c->may_control(c)) {
-		fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
-		goto out;
-	}
-
-	if (!c->is_running(c)) {
-		fprintf(stderr, "%s is not running\n", c->name);
-		ret = 2;
-		goto out;
-	}
-
-	/* kill */
-	if (my_args.hardstop) {
-		ret = c->stop(c) ? 0 : 1;
-		goto out;
-	}
-
-	/* reboot */
-	if (my_args.reboot) {
-		ret = do_reboot_and_check(&my_args, c);
-		goto out;
-	}
-
-	/* shutdown */
-	s = c->shutdown(c, my_args.timeout);
-	if (!s) {
-		if (my_args.timeout == 0)
-			ret = 0;
-		else if (my_args.nokill)
-			ret = 1;
-		else
-			ret = c->stop(c) ? 0 : 1;
-	} else
-		ret = 0;
-
-out:
-	lxc_container_put(c);
-	if (ret < 0)
-		return 1;
-	return ret;
-}
diff --git a/src/lxc/lxc_top.c b/src/lxc/lxc_top.c
deleted file mode 100644
index c4cb871..0000000
--- a/src/lxc/lxc_top.c
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * Copyright © 2014 Oracle.
- *
- * Authors:
- * Dwight Engen <dwight.engen at oracle.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <errno.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <termios.h>
-#include <unistd.h>
-#include <sys/epoll.h>
-#include <sys/ioctl.h>
-#include <lxc/lxccontainer.h>
-
-#include "arguments.h"
-#include "log.h"
-#include "lxc.h"
-#include "mainloop.h"
-#include "utils.h"
-
-lxc_log_define(lxc_top_ui, lxc);
-
-#define USER_HZ   100
-#define ESC       "\033"
-#define TERMCLEAR ESC "[H" ESC "[J"
-#define TERMNORM  ESC "[0m"
-#define TERMBOLD  ESC "[1m"
-#define TERMRVRS  ESC "[7m"
-
-struct stats {
-	uint64_t mem_used;
-	uint64_t mem_limit;
-	uint64_t kmem_used;
-	uint64_t kmem_limit;
-	uint64_t cpu_use_nanos;
-	uint64_t cpu_use_user;
-	uint64_t cpu_use_sys;
-	uint64_t blkio;
-};
-
-struct ct {
-	struct lxc_container *c;
-	struct stats *stats;
-};
-
-static int delay = 3;
-static char sort_by = 'n';
-static int sort_reverse = 0;
-
-static struct termios oldtios;
-static struct ct *ct = NULL;
-static int ct_alloc_cnt = 0;
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	switch (c) {
-	case 'd': delay = atoi(arg); break;
-	case 's': sort_by = arg[0]; break;
-	case 'r': sort_reverse = 1; break;
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	{"delay",   required_argument, 0, 'd'},
-	{"sort",    required_argument, 0, 's'},
-	{"reverse", no_argument,       0, 'r'},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-top",
-	.help     = "\
-[--name=NAME]\n\
-\n\
-lxc-top monitors the state of the active containers\n\
-\n\
-Options :\n\
-  -d, --delay     delay in seconds between refreshes (default: 3.0)\n\
-  -s, --sort      sort by [n,c,b,m] (default: n) where\n\
-                  n = Name\n\
-                  c = CPU use\n\
-                  b = Block I/O use\n\
-                  m = Memory use\n\
-                  k = Kernel memory use\n\
-  -r, --reverse   sort in reverse (descending) order\n",
-	.name     = ".*",
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = NULL,
-	.lxcpath_additional = -1,
-};
-
-static void stdin_tios_restore(void)
-{
-	tcsetattr(0, TCSAFLUSH, &oldtios);
-	fprintf(stderr, "\n");
-}
-
-static int stdin_tios_setup(void)
-{
-	struct termios newtios;
-
-	if (!isatty(0)) {
-		ERROR("stdin is not a tty");
-		return -1;
-	}
-
-	if (tcgetattr(0, &oldtios)) {
-		SYSERROR("failed to get current terminal settings");
-		return -1;
-	}
-
-	newtios = oldtios;
-
-	/* turn off echo and line buffering */
-	newtios.c_iflag &= ~IGNBRK;
-	newtios.c_iflag &= BRKINT;
-	newtios.c_lflag &= ~(ECHO|ICANON);
-	newtios.c_cc[VMIN] = 1;
-	newtios.c_cc[VTIME] = 0;
-
-	if (tcsetattr(0, TCSAFLUSH, &newtios)) {
-		ERROR("failed to set new terminal settings");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int stdin_tios_rows(void)
-{
-	struct winsize wsz;
-	if (isatty(0) && ioctl(0, TIOCGWINSZ, &wsz) == 0)
-		return wsz.ws_row;
-	return 25;
-}
-
-static int stdin_handler(int fd, uint32_t events, void *data,
-			 struct lxc_epoll_descr *descr)
-{
-	char *in_char = data;
-
-	if (events & EPOLLIN) {
-		int rc;
-
-		rc = read(fd, in_char, sizeof(*in_char));
-		if (rc <= 0)
-			*in_char = '\0';
-	}
-
-	if (events & EPOLLHUP)
-		*in_char = 'q';
-	return 1;
-}
-
-static void sig_handler(int sig)
-{
-	exit(EXIT_SUCCESS);
-}
-
-static void size_humanize(unsigned long long val, char *buf, size_t bufsz)
-{
-	if (val > 1 << 30) {
-		snprintf(buf, bufsz, "%u.%2.2u GB",
-			    (int)(val >> 30),
-			    (int)(val & ((1 << 30) - 1)) / 10737419);
-	} else if (val > 1 << 20) {
-		int x = val + 5243;  /* for rounding */
-		snprintf(buf, bufsz, "%u.%2.2u MB",
-			    x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
-	} else if (val > 1 << 10) {
-		int x = val + 5;  /* for rounding */
-		snprintf(buf, bufsz, "%u.%2.2u KB",
-			    x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
-	} else {
-		snprintf(buf, bufsz, "%3u.00   ", (int)val);
-	}
-}
-
-static uint64_t stat_get_int(struct lxc_container *c, const char *item)
-{
-	char buf[80];
-	int len;
-	uint64_t val;
-
-	len = c->get_cgroup_item(c, item, buf, sizeof(buf));
-	if (len <= 0) {
-		ERROR("unable to read cgroup item %s", item);
-		return 0;
-	}
-
-	val = strtoull(buf, NULL, 0);
-	return val;
-}
-
-static uint64_t stat_match_get_int(struct lxc_container *c, const char *item,
-				   const char *match, int column)
-{
-	char buf[4096];
-	int i,j,len;
-	uint64_t val = 0;
-	char **lines, **cols;
-	size_t matchlen;
-
-	len = c->get_cgroup_item(c, item, buf, sizeof(buf));
-	if (len <= 0) {
-		ERROR("unable to read cgroup item %s", item);
-		goto out;
-	}
-
-	lines = lxc_string_split_and_trim(buf, '\n');
-	if (!lines)
-		goto out;
-
-	matchlen = strlen(match);
-	for (i = 0; lines[i]; i++) {
-		if (strncmp(lines[i], match, matchlen) == 0) {
-			cols = lxc_string_split_and_trim(lines[i], ' ');
-			if (!cols)
-				goto err1;
-			for (j = 0; cols[j]; j++) {
-				if (j == column) {
-					val = strtoull(cols[j], NULL, 0);
-					break;
-				}
-			}
-			lxc_free_array((void **)cols, free);
-			break;
-		}
-	}
-err1:
-	lxc_free_array((void **)lines, free);
-out:
-	return val;
-}
-
-static void stats_get(struct lxc_container *c, struct ct *ct, struct stats *total)
-{
-	ct->c = c;
-	ct->stats->mem_used      = stat_get_int(c, "memory.usage_in_bytes");
-	ct->stats->mem_limit     = stat_get_int(c, "memory.limit_in_bytes");
-	ct->stats->kmem_used     = stat_get_int(c, "memory.kmem.usage_in_bytes");
-	ct->stats->kmem_limit    = stat_get_int(c, "memory.kmem.limit_in_bytes");
-	ct->stats->cpu_use_nanos = stat_get_int(c, "cpuacct.usage");
-	ct->stats->cpu_use_user  = stat_match_get_int(c, "cpuacct.stat", "user", 1);
-	ct->stats->cpu_use_sys   = stat_match_get_int(c, "cpuacct.stat", "system", 1);
-	ct->stats->blkio         = stat_match_get_int(c, "blkio.throttle.io_service_bytes", "Total", 1);
-
-	if (total) {
-		total->mem_used      = total->mem_used      + ct->stats->mem_used;
-		total->mem_limit     = total->mem_limit     + ct->stats->mem_limit;
-		total->kmem_used     = total->kmem_used     + ct->stats->kmem_used;
-		total->kmem_limit    = total->kmem_limit    + ct->stats->kmem_limit;
-		total->cpu_use_nanos = total->cpu_use_nanos + ct->stats->cpu_use_nanos;
-		total->cpu_use_user  = total->cpu_use_user  + ct->stats->cpu_use_user;
-		total->cpu_use_sys   = total->cpu_use_sys   + ct->stats->cpu_use_sys;
-		total->blkio         = total->blkio         + ct->stats->blkio;
-	}
-}
-
-static void stats_print_header(struct stats *stats)
-{
-	printf(TERMRVRS TERMBOLD);
-	printf("%-18s %12s %12s %12s %14s %10s", "Container", "CPU",  "CPU",  "CPU",  "BlkIO", "Mem");
-	if (stats->kmem_used > 0)
-		printf(" %10s", "KMem");
-	printf("\n");
-
-	printf("%-18s %12s %12s %12s %14s %10s", "Name",      "Used", "Sys",  "User", "Total", "Used");
-	if (stats->kmem_used > 0)
-		printf(" %10s", "Used");
-	printf("\n");
-	printf(TERMNORM);
-}
-
-static void stats_print(const char *name, const struct stats *stats,
-			const struct stats *total)
-{
-	char blkio_str[20];
-	char mem_used_str[20];
-	char kmem_used_str[20];
-
-	size_humanize(stats->blkio, blkio_str, sizeof(blkio_str));
-	size_humanize(stats->mem_used, mem_used_str, sizeof(mem_used_str));
-
-	printf("%-18.18s %12.2f %12.2f %12.2f %14s %10s",
-	       name,
-	       (float)stats->cpu_use_nanos / 1000000000,
-	       (float)stats->cpu_use_sys  / USER_HZ,
-	       (float)stats->cpu_use_user / USER_HZ,
-	       blkio_str,
-	       mem_used_str);
-	if (total->kmem_used > 0) {
-		size_humanize(stats->kmem_used, kmem_used_str, sizeof(kmem_used_str));
-		printf(" %10s", kmem_used_str);
-	}
-}
-
-static int cmp_name(const void *sct1, const void *sct2)
-{
-	const struct ct *ct1 = sct1;
-	const struct ct *ct2 = sct2;
-
-	if (sort_reverse)
-		return strcmp(ct2->c->name, ct1->c->name);
-	return strcmp(ct1->c->name, ct2->c->name);
-}
-
-static int cmp_cpuuse(const void *sct1, const void *sct2)
-{
-	const struct ct *ct1 = sct1;
-	const struct ct *ct2 = sct2;
-
-	if (sort_reverse)
-		return ct2->stats->cpu_use_nanos < ct1->stats->cpu_use_nanos;
-	return ct1->stats->cpu_use_nanos < ct2->stats->cpu_use_nanos;
-}
-
-static int cmp_blkio(const void *sct1, const void *sct2)
-{
-	const struct ct *ct1 = sct1;
-	const struct ct *ct2 = sct2;
-
-	if (sort_reverse)
-		return ct2->stats->blkio < ct1->stats->blkio;
-	return ct1->stats->blkio < ct2->stats->blkio;
-}
-
-static int cmp_memory(const void *sct1, const void *sct2)
-{
-	const struct ct *ct1 = sct1;
-	const struct ct *ct2 = sct2;
-
-	if (sort_reverse)
-		return ct2->stats->mem_used < ct1->stats->mem_used;
-	return ct1->stats->mem_used < ct2->stats->mem_used;
-}
-
-static int cmp_kmemory(const void *sct1, const void *sct2)
-{
-	const struct ct *ct1 = sct1;
-	const struct ct *ct2 = sct2;
-
-	if (sort_reverse)
-		return ct2->stats->kmem_used < ct1->stats->kmem_used;
-	return ct1->stats->kmem_used < ct2->stats->kmem_used;
-}
-
-static void ct_sort(int active)
-{
-	int (*cmp_func)(const void *, const void *);
-
-	switch(sort_by) {
-	default:
-	case 'n': cmp_func = cmp_name; break;
-	case 'c': cmp_func = cmp_cpuuse; break;
-	case 'b': cmp_func = cmp_blkio; break;
-	case 'm': cmp_func = cmp_memory; break;
-	case 'k': cmp_func = cmp_kmemory; break;
-	}
-	qsort(ct, active, sizeof(*ct), (int (*)(const void *,const void *))cmp_func);
-}
-
-static void ct_free(void)
-{
-	int i;
-
-	for (i = 0; i < ct_alloc_cnt; i++) {
-		if (ct[i].c) {
-			lxc_container_put(ct[i].c);
-			ct[i].c = NULL;
-		}
-		free(ct[i].stats);
-		ct[i].stats = NULL;
-	}
-}
-
-static void ct_realloc(int active_cnt)
-{
-	int i;
-
-	if (active_cnt > ct_alloc_cnt) {
-		ct_free();
-		ct = realloc(ct, sizeof(*ct) * active_cnt);
-		if (!ct) {
-			ERROR("cannot alloc mem");
-			exit(EXIT_FAILURE);
-		}
-		for (i = 0; i < active_cnt; i++) {
-			ct[i].stats = malloc(sizeof(*ct[0].stats));
-			if (!ct[i].stats) {
-				ERROR("cannot alloc mem");
-				exit(EXIT_FAILURE);
-			}
-		}
-		ct_alloc_cnt = active_cnt;
-	}
-}
-
-int main(int argc, char *argv[])
-{
-	struct lxc_epoll_descr descr;
-	int ret, ct_print_cnt;
-	char in_char;
-
-	ret = EXIT_FAILURE;
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		goto out;
-
-	ct_print_cnt = stdin_tios_rows() - 3; /* 3 -> header and total */
-	if (stdin_tios_setup() < 0) {
-		ERROR("failed to setup terminal");
-		goto out;
-	}
-
-	/* ensure the terminal gets restored */
-	atexit(stdin_tios_restore);
-	signal(SIGINT, sig_handler);
-	signal(SIGQUIT, sig_handler);
-
-	if (lxc_mainloop_open(&descr)) {
-		ERROR("failed to create mainloop");
-		goto out;
-	}
-
-	ret = lxc_mainloop_add_handler(&descr, 0, stdin_handler, &in_char);
-	if (ret) {
-		ERROR("failed to add stdin handler");
-		ret = EXIT_FAILURE;
-		goto err1;
-	}
-
-	for(;;) {
-		struct lxc_container **active;
-		int i, active_cnt;
-		struct stats total;
-		char total_name[30];
-
-		active_cnt = list_active_containers(my_args.lxcpath[0], NULL, &active);
-		ct_realloc(active_cnt);
-
-		memset(&total, 0, sizeof(total));
-		for (i = 0; i < active_cnt; i++)
-			stats_get(active[i], &ct[i], &total);
-
-		ct_sort(active_cnt);
-
-		printf(TERMCLEAR);
-		stats_print_header(&total);
-		for (i = 0; i < active_cnt && i < ct_print_cnt; i++) {
-			stats_print(ct[i].c->name, ct[i].stats, &total);
-			printf("\n");
-		}
-		sprintf(total_name, "TOTAL %d of %d", i, active_cnt);
-		stats_print(total_name, &total, &total);
-		fflush(stdout);
-
-		for (i = 0; i < active_cnt; i++) {
-			lxc_container_put(ct[i].c);
-			ct[i].c = NULL;
-		}
-
-		in_char = '\0';
-		ret = lxc_mainloop(&descr, 1000 * delay);
-		if (ret != 0 || in_char == 'q')
-			break;
-		switch(in_char) {
-		case 'r':
-			sort_reverse ^= 1;
-			break;
-		case 'n':
-		case 'c':
-		case 'b':
-		case 'm':
-		case 'k':
-			if (sort_by == in_char)
-				sort_reverse ^= 1;
-			else
-				sort_reverse = 0;
-			sort_by = in_char;
-		}
-	}
-	ret = EXIT_SUCCESS;
-
-err1:
-	lxc_mainloop_close(&descr);
-out:
-	return ret;
-}
diff --git a/src/lxc/lxc_unfreeze.c b/src/lxc/lxc_unfreeze.c
deleted file mode 100644
index 3a13d37..0000000
--- a/src/lxc/lxc_unfreeze.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <stdio.h>
-#include <unistd.h>
-#include <libgen.h>
-#include <sys/types.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "lxc.h"
-#include "log.h"
-#include "arguments.h"
-
-lxc_log_define(lxc_unfreeze_ui, lxc);
-
-static const struct option my_longopts[] = {
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-unfreeze",
-	.help     = "\
---name=NAME\n\
-\n\
-lxc-unfreeze unfreezes a container with the identifier NAME\n\
-\n\
-Options :\n\
-  -n, --name=NAME   NAME of the container\n",
-	.options  = my_longopts,
-	.parser   = NULL,
-	.checker  = NULL,
-};
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		exit(1);
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		exit(1);
-	lxc_log_options_no_override();
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c) {
-		ERROR("No such container: %s:%s", my_args.lxcpath[0], my_args.name);
-		exit(1);
-	}
-
-	if (!c->may_control(c)) {
-		ERROR("Insufficent privileges to control %s:%s", my_args.lxcpath[0], my_args.name);
-		lxc_container_put(c);
-		exit(1);
-	}
-
-	if (!c->unfreeze(c)) {
-		ERROR("Failed to unfreeze %s:%s", my_args.lxcpath[0], my_args.name);
-		lxc_container_put(c);
-		exit(1);
-	}
-
-	lxc_container_put(c);
-
-	exit(0);
-}
diff --git a/src/lxc/lxc_unshare.c b/src/lxc/lxc_unshare.c
deleted file mode 100644
index e629525..0000000
--- a/src/lxc/lxc_unshare.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <errno.h>
-#include <getopt.h>
-#include <libgen.h>
-#include <netinet/in.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "caps.h"
-#include "cgroup.h"
-#include "error.h"
-#include "log.h"
-#include "namespace.h"
-#include "network.h"
-#include "utils.h"
-
-/* Define sethostname() if missing from the C library */
-#ifndef HAVE_SETHOSTNAME
-static int sethostname(const char * name, size_t len)
-{
-#ifdef __NR_sethostname
-return syscall(__NR_sethostname, name, len);
-#else
-errno = ENOSYS;
-return -1;
-#endif
-}
-#endif
-
-lxc_log_define(lxc_unshare_ui, lxc);
-
-struct my_iflist
-{
-	char *mi_ifname;
-	struct my_iflist *mi_next;
-};
-
-static void usage(char *cmd)
-{
-	fprintf(stderr, "%s <options> command [command_arguments]\n", basename(cmd));
-	fprintf(stderr, "Options are:\n");
-	fprintf(stderr, "\t -s flags   : ORed list of flags to unshare:\n" \
-			"\t           MOUNT, PID, UTSNAME, IPC, USER, NETWORK\n");
-	fprintf(stderr, "\t -u <id>      : new id to be set if -s USER is specified\n");
-	fprintf(stderr, "\t -i <iface>   : Interface name to be moved into container (presumably with NETWORK unsharing set)\n");
-	fprintf(stderr, "\t -H <hostname>: Set the hostname in the container\n");
-	fprintf(stderr, "\t -d           : Daemonize (do not wait for container to exit)\n");
-	fprintf(stderr, "\t -M           : reMount default fs inside container (/proc /dev/shm /dev/mqueue)\n");
-	_exit(1);
-}
-
-static bool lookup_user(const char *optarg, uid_t *uid)
-{
-	char name[sysconf(_SC_LOGIN_NAME_MAX)];
-	struct passwd *pwent = NULL;
-
-	if (!optarg || (optarg[0] == '\0'))
-		return false;
-
-	if (sscanf(optarg, "%u", uid) < 1) {
-		/* not a uid -- perhaps a username */
-		if (sscanf(optarg, "%s", name) < 1)
-			return false;
-
-		pwent = getpwnam(name);
-		if (!pwent) {
-			ERROR("invalid username %s", name);
-			return false;
-		}
-		*uid = pwent->pw_uid;
-	} else {
-		pwent = getpwuid(*uid);
-		if (!pwent) {
-			ERROR("invalid uid %u", *uid);
-			return false;
-		}
-	}
-	return true;
-}
-
-
-struct start_arg {
-	char ***args;
-	int *flags;
-	uid_t *uid;
-	bool setuid;
-	int want_default_mounts;
-	const char *want_hostname;
-};
-
-static int do_start(void *arg)
-{
-	struct start_arg *start_arg = arg;
-	char **args = *start_arg->args;
-	int flags = *start_arg->flags;
-	uid_t uid = *start_arg->uid;
-	int want_default_mounts = start_arg->want_default_mounts;
-	const char *want_hostname = start_arg->want_hostname;
-
-	if ((flags & CLONE_NEWNS) && want_default_mounts)
-		lxc_setup_fs();
-
-	if ((flags & CLONE_NEWUTS) && want_hostname)
-		if (sethostname(want_hostname, strlen(want_hostname)) < 0) {
-			ERROR("failed to set hostname %s: %s", want_hostname, strerror(errno));
-			exit(1);
-		}
-
-	// Setuid is useful even without a new user id space
-	if (start_arg->setuid && setuid(uid)) {
-		ERROR("failed to set uid %d: %s", uid, strerror(errno));
-		exit(1);
-	}
-
-	execvp(args[0], args);
-
-	ERROR("failed to exec: '%s': %s", args[0], strerror(errno));
-	return 1;
-}
-
-int main(int argc, char *argv[])
-{
-	int opt, status;
-	int ret;
-	char *namespaces = NULL;
-	char **args;
-	int flags = 0;
-	int daemonize = 0;
-	uid_t uid = 0; /* valid only if (flags & CLONE_NEWUSER) */
-	pid_t pid;
-	struct my_iflist *tmpif, *my_iflist = NULL;
-	struct start_arg start_arg = {
-		.args = &args,
-		.uid = &uid,
-		.setuid = false,
-		.flags = &flags,
-		.want_hostname = NULL,
-		.want_default_mounts = 0,
-	};
-
-	while ((opt = getopt(argc, argv, "s:u:hH:i:dM")) != -1) {
-		switch (opt) {
-		case 's':
-			namespaces = optarg;
-			break;
-		case 'i':
-			if (!(tmpif = malloc(sizeof(*tmpif)))) {
-				perror("malloc");
-				exit(1);
-			}
-			tmpif->mi_ifname = optarg;
-			tmpif->mi_next = my_iflist;
-			my_iflist = tmpif;
-			break;
-		case 'd':
-			daemonize = 1;
-			break;
-		case 'M':
-			start_arg.want_default_mounts = 1;
-			break;
-		case 'H':
-			start_arg.want_hostname = optarg;
-			break;
-		case 'h':
-			usage(argv[0]);
-			break;
-		case 'u':
-			if (!lookup_user(optarg, &uid))
-				return 1;
-			start_arg.setuid = true;
-		}
-	}
-
-	if (argv[optind] == NULL) {
-		ERROR("a command to execute in the new namespace is required");
-		return 1;
-	}
-
-	args = &argv[optind];
-
-	ret = lxc_caps_init();
-	if (ret)
-		return 1;
-
-	ret = lxc_fill_namespace_flags(namespaces, &flags);
-	if (ret)
-		usage(argv[0]);
-
-	if (!(flags & CLONE_NEWNET) && my_iflist) {
-		ERROR("-i <interfacename> needs -s NETWORK option");
-		return 1;
-	}
-
-	if (!(flags & CLONE_NEWUTS) && start_arg.want_hostname) {
-		ERROR("-H <hostname> needs -s UTSNAME option");
-		return 1;
-	}
-
-	if (!(flags & CLONE_NEWNS) && start_arg.want_default_mounts) {
-		ERROR("-M needs -s MOUNT option");
-		return 1;
-	}
-
-	pid = lxc_clone(do_start, &start_arg, flags);
-	if (pid < 0) {
-		ERROR("failed to clone");
-		return 1;
-	}
-
-	if (my_iflist) {
-		for (tmpif = my_iflist; tmpif; tmpif = tmpif->mi_next) {
-			if (lxc_netdev_move_by_name(tmpif->mi_ifname, pid, NULL) < 0)
-				fprintf(stderr,"Could not move interface %s into container %d: %s\n", tmpif->mi_ifname, pid, strerror(errno));
-		}
-	}
-
-	if (daemonize)
-		exit(0);
-
-	if (waitpid(pid, &status, 0) < 0) {
-		ERROR("failed to wait for '%d'", pid);
-		return 1;
-	}
-
-	return  lxc_error_set_and_log(pid, status);
-}
diff --git a/src/lxc/lxc_usernsexec.c b/src/lxc/lxc_usernsexec.c
deleted file mode 100644
index 6745ac3..0000000
--- a/src/lxc/lxc_usernsexec.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * (C) Copyright IBM Corp. 2008
- * (C) Copyright Canonical, Inc 2010-2013
- *
- * Authors:
- * Serge Hallyn <serge.hallyn at ubuntu.com>
- * (Once upon a time, this was based on nsexec from the IBM
- *  container tools)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sched.h>
-#include <sys/syscall.h>
-#include <signal.h>
-#include <string.h>
-#include <errno.h>
-#include <libgen.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mount.h>
-#include <sys/wait.h>
-#include <sched.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include "conf.h"
-#include "namespace.h"
-#include "utils.h"
-
-#ifndef MS_REC
-#define MS_REC 16384
-#endif
-
-#ifndef MS_SLAVE
-#define MS_SLAVE (1<<19)
-#endif
-
-int unshare(int flags);
-
-static void usage(const char *name)
-{
-	printf("usage: %s [-h] [-m <uid-maps>] -- [command [arg ..]]\n", name);
-	printf("\n");
-	printf("  -h		this message\n");
-	printf("\n");
-	printf("  -m <uid-maps> uid maps to use\n");
-	printf("\n");
-	printf("  uid-maps: [u|g|b]:ns_id:host_id:range\n");
-	printf("            [u|g|b]: map user id, group id, or both\n");
-	printf("            ns_id: the base id in the new namespace\n");
-	printf("            host_id: the base id in the parent namespace\n");
-	printf("            range: how many ids to map\n");
-	printf("  Note: This program uses newuidmap(2) and newgidmap(2).\n");
-	printf("        As such, /etc/subuid and /etc/subgid must grant the\n");
-	printf("        calling user permission to use the mapped ranges\n");
-	exit(1);
-}
-
-static void opentty(const char * tty, int which) {
-	int fd, flags;
-
-	if (tty[0] == '\0')
-		return;
-
-	fd = open(tty, O_RDWR | O_NONBLOCK);
-	if (fd == -1) {
-		printf("WARN: could not reopen tty: %s\n", strerror(errno));
-		return;
-	}
-
-	flags = fcntl(fd, F_GETFL);
-	flags &= ~O_NONBLOCK;
-	if (fcntl(fd, F_SETFL, flags) < 0) {
-		printf("WARN: could not set fd flags: %s\n", strerror(errno));
-		return;
-	}
-
-	close(which);
-	if (fd != which) {
-		dup2(fd, which);
-		close(fd);
-	}
-}
-// Code copy end
-
-static int do_child(void *vargv)
-{
-	char **argv = (char **)vargv;
-
-	// Assume we want to become root
-	if (setgid(0) < 0) {
-		perror("setgid");
-		return -1;
-	}
-	if (setuid(0) < 0) {
-		perror("setuid");
-		return -1;
-	}
-	if (setgroups(0, NULL) < 0) {
-		perror("setgroups");
-		return -1;
-	}
-	if (unshare(CLONE_NEWNS) < 0) {
-		perror("unshare CLONE_NEWNS");
-		return -1;
-	}
-	if (detect_shared_rootfs()) {
-		if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
-			printf("Failed to make / rslave");
-			return -1;
-		}
-	}
-	execvp(argv[0], argv);
-	perror("execvpe");
-	return -1;
-}
-
-static struct lxc_list active_map;
-
-/*
- * given a string like "b:0:100000:10", map both uids and gids
- * 0-10 to 100000 to 100010
- */
-static int parse_map(char *map)
-{
-	struct id_map *newmap;
-	struct lxc_list *tmp = NULL;
-	int ret;
-	int i;
-	char types[2] = {'u', 'g'};
-	char which;
-	long host_id, ns_id, range;
-
-	if (!map)
-		return -1;
-
-	ret = sscanf(map, "%c:%ld:%ld:%ld", &which, &ns_id, &host_id, &range);
-	if (ret != 4)
-		return -1;
-
-	if (which != 'b' && which != 'u' && which != 'g')
-		return -1;
-
-	for (i = 0; i < 2; i++) {
-		if (which != types[i] && which != 'b')
-			continue;
-
-		newmap = malloc(sizeof(*newmap));
-		if (!newmap)
-			return -1;
-
-		newmap->hostid = host_id;
-		newmap->nsid = ns_id;
-		newmap->range = range;
-
-		if (types[i] == 'u')
-			newmap->idtype = ID_TYPE_UID;
-		else
-			newmap->idtype = ID_TYPE_GID;
-
-		tmp = malloc(sizeof(*tmp));
-		if (!tmp) {
-			free(newmap);
-			return -1;
-		}
-
-		tmp->elem = newmap;
-		lxc_list_add_tail(&active_map, tmp);
-	}
-
-	return 0;
-}
-
-/*
- * This is called if the user did not pass any uid ranges in
- * through -m flags.  It's called once to get the default uid
- * map, and once for the default gid map.
- * Go through /etc/subuids and /etc/subgids to find this user's
- * allowed map.  We only use the first one for each of uid and
- * gid, because otherwise we're not sure which entries the user
- * wanted.
- */
-static int read_default_map(char *fnam, int which, char *username)
-{
-	FILE *fin;
-	char *line = NULL;
-	size_t sz = 0;
-	struct id_map *newmap;
-	struct lxc_list *tmp = NULL;
-	char *p1, *p2;
-
-	fin = fopen(fnam, "r");
-	if (!fin)
-		return -1;
-	while (getline(&line, &sz, fin) != -1) {
-		if (sz <= strlen(username) ||
-		    strncmp(line, username, strlen(username)) != 0 ||
-		    line[strlen(username)] != ':')
-			continue;
-		p1 = strchr(line, ':');
-		if (!p1)
-			continue;
-		p2 = strchr(p1+1, ':');
-		if (!p2)
-			continue;
-		newmap = malloc(sizeof(*newmap));
-		if (!newmap)  {
-			fclose(fin);
-			free(line);
-			return -1;
-		}
-		newmap->hostid = atol(p1+1);
-		newmap->range = atol(p2+1);
-		newmap->nsid = 0;
-		newmap->idtype = which;
-
-		tmp = malloc(sizeof(*tmp));
-		if (!tmp) {
-			fclose(fin);
-			free(line);
-			free(newmap);
-			return -1;
-		}
-
-		tmp->elem = newmap;
-		lxc_list_add_tail(&active_map, tmp);
-		break;
-	}
-
-	free(line);
-	fclose(fin);
-	return 0;
-}
-
-static int find_default_map(void)
-{
-	struct passwd *p = getpwuid(getuid());
-	if (!p)
-		return -1;
-	if (read_default_map(subuidfile, ID_TYPE_UID, p->pw_name) < 0)
-		return -1;
-	if (read_default_map(subgidfile, ID_TYPE_GID, p->pw_name) < 0)
-		return -1;
-    return 0;
-}
-
-int main(int argc, char *argv[])
-{
-	int c;
-	unsigned long flags = CLONE_NEWUSER | CLONE_NEWNS;
-	char ttyname0[256], ttyname1[256], ttyname2[256];
-	int status;
-	int ret;
-	int pid;
-	char *default_args[] = {"/bin/sh", NULL};
-	char buf[1];
-	int pipe1[2],  // child tells parent it has unshared
-	    pipe2[2];  // parent tells child it is mapped and may proceed
-
-	memset(ttyname0, '\0', sizeof(ttyname0));
-	memset(ttyname1, '\0', sizeof(ttyname1));
-	memset(ttyname2, '\0', sizeof(ttyname2));
-	if (isatty(0)) {
-		ret = readlink("/proc/self/fd/0", ttyname0, sizeof(ttyname0));
-		if (ret < 0) {
-			perror("unable to open stdin.");
-			exit(1);
-		}
-		ret = readlink("/proc/self/fd/1", ttyname1, sizeof(ttyname1));
-		if (ret < 0) {
-			printf("Warning: unable to open stdout, continuing.");
-			memset(ttyname1, '\0', sizeof(ttyname1));
-		}
-		ret = readlink("/proc/self/fd/2", ttyname2, sizeof(ttyname2));
-		if (ret < 0) {
-			printf("Warning: unable to open stderr, continuing.");
-			memset(ttyname2, '\0', sizeof(ttyname2));
-		}
-	}
-
-	lxc_list_init(&active_map);
-
-	while ((c = getopt(argc, argv, "m:h")) != EOF) {
-		switch (c) {
-			case 'm': if (parse_map(optarg)) usage(argv[0]); break;
-			case 'h':
-			default:
-				  usage(argv[0]);
-		}
-	};
-
-	if (lxc_list_empty(&active_map)) {
-		if (find_default_map()) {
-			fprintf(stderr, "You have no allocated subuids or subgids\n");
-			exit(1);
-		}
-	}
-
-	argv = &argv[optind];
-	argc = argc - optind;
-	if (argc < 1) {
-		argv = default_args;
-		argc = 1;
-	}
-
-	if (pipe(pipe1) < 0 || pipe(pipe2) < 0) {
-		perror("pipe");
-		exit(1);
-	}
-	if ((pid = fork()) == 0) {
-		// Child.
-
-		close(pipe1[0]);
-		close(pipe2[1]);
-		opentty(ttyname0, 0);
-		opentty(ttyname1, 1);
-		opentty(ttyname2, 2);
-
-		ret = unshare(flags);
-		if (ret < 0) {
-			perror("unshare");
-			return 1;
-		}
-		buf[0] = '1';
-		if (write(pipe1[1], buf, 1) < 1) {
-			perror("write pipe");
-			exit(1);
-		}
-		if (read(pipe2[0], buf, 1) < 1) {
-			perror("read pipe");
-			exit(1);
-		}
-		if (buf[0] != '1') {
-			fprintf(stderr, "parent had an error, child exiting\n");
-			exit(1);
-		}
-
-		close(pipe1[1]);
-		close(pipe2[0]);
-		return do_child((void*)argv);
-	}
-
-	close(pipe1[1]);
-	close(pipe2[0]);
-	if (read(pipe1[0], buf, 1) < 1) {
-		perror("read pipe");
-		exit(1);
-	}
-
-	buf[0] = '1';
-
-	if (lxc_map_ids(&active_map, pid)) {
-		fprintf(stderr, "error mapping child\n");
-		ret = 0;
-	}
-	if (write(pipe2[1], buf, 1) < 0) {
-		perror("write to pipe");
-		exit(1);
-	}
-
-	if ((ret = waitpid(pid, &status, __WALL)) < 0) {
-		printf("waitpid() returns %d, errno %d\n", ret, errno);
-		exit(1);
-	}
-
-	exit(WEXITSTATUS(status));
-}
diff --git a/src/lxc/lxc_wait.c b/src/lxc/lxc_wait.c
deleted file mode 100644
index 712ba52..0000000
--- a/src/lxc/lxc_wait.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * lxc: linux Container library
- *
- * (C) Copyright IBM Corp. 2007, 2008
- *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <stdio.h>
-#include <string.h>
-#include <libgen.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/types.h>
-
-#include <lxc/lxccontainer.h>
-
-#include "lxc.h"
-#include "log.h"
-#include "arguments.h"
-
-lxc_log_define(lxc_wait_ui, lxc);
-
-static int my_checker(const struct lxc_arguments* args)
-{
-	if (!args->states) {
-		lxc_error(args, "missing state option to wait for.");
-		return -1;
-	}
-	return 0;
-}
-
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
-{
-	switch (c) {
-	case 's': args->states = optarg; break;
-	case 't': args->timeout = atol(optarg); break;
-	}
-	return 0;
-}
-
-static const struct option my_longopts[] = {
-	{"state", required_argument, 0, 's'},
-	{"timeout", required_argument, 0, 't'},
-	LXC_COMMON_OPTIONS
-};
-
-static struct lxc_arguments my_args = {
-	.progname = "lxc-wait",
-	.help     = "\
---name=NAME --state=STATE\n\
-\n\
-lxc-wait waits for NAME container state to reach STATE\n\
-\n\
-Options :\n\
-  -n, --name=NAME   NAME of the container\n\
-  -s, --state=STATE ORed states to wait for\n\
-                    STOPPED, STARTING, RUNNING, STOPPING,\n\
-                    ABORTING, FREEZING, FROZEN, THAWED\n\
-  -t, --timeout=TMO Seconds to wait for state changes\n",
-	.options  = my_longopts,
-	.parser   = my_parser,
-	.checker  = my_checker,
-	.timeout = -1,
-};
-
-int main(int argc, char *argv[])
-{
-	struct lxc_container *c;
-
-	if (lxc_arguments_parse(&my_args, argc, argv))
-		return 1;
-
-	if (!my_args.log_file)
-		my_args.log_file = "none";
-
-	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
-			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
-		return 1;
-	lxc_log_options_no_override();
-
-	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
-	if (!c)
-		return 1;
-
-	if (!c->may_control(c)) {
-		fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
-		lxc_container_put(c);
-		return 1;
-	}
-
-	if (!c->wait(c, my_args.states, my_args.timeout)) {
-		lxc_container_put(c);
-		return 1;
-	}
-	return 0;
-}
diff --git a/src/lxc/tools/lxc-checkconfig.in b/src/lxc/tools/lxc-checkconfig.in
new file mode 100644
index 0000000..29586f8
--- /dev/null
+++ b/src/lxc/tools/lxc-checkconfig.in
@@ -0,0 +1,156 @@
+#!/bin/sh
+
+# Allow environment variables to override config
+: ${CONFIG:=/proc/config.gz}
+: ${MODNAME:=configs}
+
+CAT="cat"
+
+if [ -t 1 ]; then
+    SETCOLOR_SUCCESS="printf \\033[1;32m"
+    SETCOLOR_FAILURE="printf \\033[1;31m"
+    SETCOLOR_WARNING="printf \\033[1;33m"
+    SETCOLOR_NORMAL="printf \\033[0;39m"
+else
+    SETCOLOR_SUCCESS=":"
+    SETCOLOR_FAILURE=":"
+    SETCOLOR_WARNING=":"
+    SETCOLOR_NORMAL=":"
+fi
+
+is_set() {
+    $CAT $CONFIG | grep "$1=[y|m]" > /dev/null
+    return $?
+}
+
+is_enabled() {
+    mandatory=$2
+
+    is_set $1
+    RES=$?
+
+    if [ $RES -eq 0 ]; then
+        $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
+    else
+        if [ ! -z "$mandatory" ] && [ "$mandatory" = yes ]; then
+            $SETCOLOR_FAILURE && echo "required" && $SETCOLOR_NORMAL
+        else
+            $SETCOLOR_WARNING && echo "missing" && $SETCOLOR_NORMAL
+        fi
+    fi
+}
+
+if [ ! -f $CONFIG ]; then
+    echo "Kernel configuration not found at $CONFIG; searching..."
+    KVER="`uname -r`"
+    HEADERS_CONFIG="/lib/modules/$KVER/build/.config"
+    BOOT_CONFIG="/boot/config-$KVER"
+    [ -f "${HEADERS_CONFIG}" ] && CONFIG=${HEADERS_CONFIG}
+    [ -f "${BOOT_CONFIG}" ] && CONFIG=${BOOT_CONFIG}
+    if [ ! -f "$CONFIG" ]; then
+        MODULEFILE=$(modinfo -k $KVER -n $MODNAME 2> /dev/null)
+        # don't want to modprobe, so give user a hint
+        # although scripts/extract-ikconfig could be used to extract contents without loading kernel module
+        # http://svn.pld-linux.org/trac/svn/browser/geninitrd/trunk/geninitrd?rev=12696#L327
+    fi
+    if [ ! -f $CONFIG ]; then
+        echo "$(basename $0): unable to retrieve kernel configuration" >&2
+        echo >&2
+        if [ -f "$MODULEFILE" ]; then
+            echo "Try modprobe $MODNAME module, or" >&2
+        fi
+        echo "Try recompiling with IKCONFIG_PROC, installing the kernel headers," >&2
+        echo "or specifying the kernel configuration path with:" >&2
+        echo "  CONFIG=<path> $(basename $0)" >&2
+        exit 1
+    else
+        echo "Kernel configuration found at $CONFIG"
+    fi
+fi
+
+if gunzip -tq < $CONFIG 2>/dev/null; then
+    CAT="zcat"
+fi
+
+echo "--- Namespaces ---"
+echo -n "Namespaces: " && is_enabled CONFIG_NAMESPACES yes
+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
+echo -n "Network namespace: " && is_enabled CONFIG_NET_NS
+echo -n "Multiple /dev/pts instances: " && is_enabled DEVPTS_MULTIPLE_INSTANCES
+echo
+echo "--- Control groups ---"
+
+print_cgroups() {
+  # print all mountpoints for cgroup filesystems
+  awk '$1 !~ /#/ && $3 == mp { print $2; } ; END { exit(0); } '  "mp=$1" "$2" ;
+}
+
+CGROUP_MNT_PATH=`print_cgroups cgroup /proc/self/mounts | head -n 1`
+KVER_MAJOR=$($CAT $CONFIG | grep '^# Linux.*Kernel Configuration' | \
+    sed -r 's/.* ([0-9])\.[0-9]{1,2}\.[0-9]{1,3}.*/\1/')
+if [ "$KVER_MAJOR" = "2" ]; then
+KVER_MINOR=$($CAT $CONFIG | grep '^# Linux.*Kernel Configuration' | \
+    sed -r 's/.* 2.6.([0-9]{2}).*/\1/')
+else
+KVER_MINOR=$($CAT $CONFIG | grep '^# Linux.*Kernel Configuration' | \
+    sed -r 's/.* [0-9]\.([0-9]{1,3})\.[0-9]{1,3}.*/\1/')
+fi
+
+echo -n "Cgroup: " && is_enabled CONFIG_CGROUPS yes
+
+if [ -f $CGROUP_MNT_PATH/cgroup.clone_children ]; then
+    echo -n "Cgroup clone_children flag: " &&
+    $SETCOLOR_SUCCESS && echo "enabled" && $SETCOLOR_NORMAL
+else
+    echo -n "Cgroup namespace: " && is_enabled CONFIG_CGROUP_NS yes
+fi
+echo -n "Cgroup device: " && is_enabled CONFIG_CGROUP_DEVICE
+echo -n "Cgroup sched: " && is_enabled CONFIG_CGROUP_SCHED
+echo -n "Cgroup cpu account: " && is_enabled CONFIG_CGROUP_CPUACCT
+echo -n "Cgroup memory controller: "
+if ([ $KVER_MAJOR -ge 3 ] && [ $KVER_MINOR -ge 6 ]) || ([ $KVER_MAJOR -gt 3 ]); then
+    is_enabled CONFIG_MEMCG
+else
+    is_enabled CONFIG_CGROUP_MEM_RES_CTLR
+fi
+is_set CONFIG_SMP && echo -n "Cgroup cpuset: " && is_enabled CONFIG_CPUSETS
+echo
+echo "--- Misc ---"
+echo -n "Veth pair device: " && is_enabled CONFIG_VETH
+echo -n "Macvlan: " && is_enabled CONFIG_MACVLAN
+echo -n "Vlan: " && is_enabled CONFIG_VLAN_8021Q
+echo -n "Bridges: " && is_enabled CONFIG_BRIDGE
+echo -n "Advanced netfilter: " && is_enabled CONFIG_NETFILTER_ADVANCED
+echo -n "CONFIG_NF_NAT_IPV4: " && is_enabled CONFIG_NF_NAT_IPV4
+echo -n "CONFIG_NF_NAT_IPV6: " && is_enabled CONFIG_NF_NAT_IPV6
+echo -n "CONFIG_IP_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP_NF_TARGET_MASQUERADE
+echo -n "CONFIG_IP6_NF_TARGET_MASQUERADE: " && is_enabled CONFIG_IP6_NF_TARGET_MASQUERADE
+echo -n "CONFIG_NETFILTER_XT_TARGET_CHECKSUM: " && is_enabled CONFIG_NETFILTER_XT_TARGET_CHECKSUM
+echo -n "FUSE (for use with lxcfs): " && is_enabled CONFIG_FUSE_FS
+
+echo
+echo "--- Checkpoint/Restore ---"
+echo -n "checkpoint restore: " && is_enabled CONFIG_CHECKPOINT_RESTORE
+echo -n "CONFIG_FHANDLE: " && is_enabled CONFIG_FHANDLE
+echo -n "CONFIG_EVENTFD: " && is_enabled CONFIG_EVENTFD
+echo -n "CONFIG_EPOLL: " && is_enabled CONFIG_EPOLL
+echo -n "CONFIG_UNIX_DIAG: " && is_enabled CONFIG_UNIX_DIAG
+echo -n "CONFIG_INET_DIAG: " && is_enabled CONFIG_INET_DIAG
+echo -n "CONFIG_PACKET_DIAG: " && is_enabled CONFIG_PACKET_DIAG
+echo -n "CONFIG_NETLINK_DIAG: " && is_enabled CONFIG_NETLINK_DIAG
+
+echo -n "File capabilities: " && \
+    ( [ "${KVER_MAJOR}" = 2 ] && [ ${KVER_MINOR} -lt 33 ] && \
+       is_enabled CONFIG_SECURITY_FILE_CAPABILITIES ) || \
+    ( ( [ "${KVER_MAJOR}" = "2" ] && [ ${KVER_MINOR} -gt 32 ] ) || \
+         [ ${KVER_MAJOR} -gt 2 ] && $SETCOLOR_SUCCESS && \
+         echo "enabled" && $SETCOLOR_NORMAL )
+
+echo
+echo "Note : Before booting a new kernel, you can check its configuration"
+echo "usage : CONFIG=/path/to/config $0"
+echo
+
diff --git a/src/lxc/tools/lxc-start-ephemeral.in b/src/lxc/tools/lxc-start-ephemeral.in
new file mode 100644
index 0000000..7e0c8ea
--- /dev/null
+++ b/src/lxc/tools/lxc-start-ephemeral.in
@@ -0,0 +1,412 @@
+#!/usr/bin/env python3
+#
+# lxc-start-ephemeral: Start a copy of a container using an overlay
+#
+# This python implementation is based on the work done in the original
+# shell implementation done by Serge Hallyn in Ubuntu (and other contributors)
+#
+# (C) Copyright Canonical Ltd. 2012
+#
+# Authors:
+# Stéphane Graber <stgraber at ubuntu.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+import argparse
+import gettext
+import lxc
+import os
+import sys
+import subprocess
+import tempfile
+
+_ = gettext.gettext
+gettext.textdomain("lxc-start-ephemeral")
+
+# Other functions
+
+
+def printstderr(*args):
+    print("lxc-start-ephemeral is deprecated in favor of lxc-copy\n",
+          *args, file=sys.stderr)
+
+
+def randomMAC():
+    import random
+
+    mac = [0x00, 0x16, 0x3e,
+           random.randint(0x00, 0x7f),
+           random.randint(0x00, 0xff),
+           random.randint(0x00, 0xff)]
+    return ':'.join(map(lambda x: "%02x" % x, mac))
+
+
+def get_rundir():
+    if os.geteuid() == 0:
+        return "@RUNTIME_PATH@"
+
+    if "XDG_RUNTIME_DIR" in os.environ:
+        return os.environ["XDG_RUNTIME_DIR"]
+
+    if "HOME" in os.environ:
+        return "%s/.cache/lxc/run/" % os.environ["HOME"]
+
+    raise Exception("Unable to find a runtime directory")
+
+
+# Inform that lxc-start-ephemeral is deprecated
+printstderr()
+
+# Begin parsing the command line
+parser = argparse.ArgumentParser(description=_(
+                                 "LXC: Start an ephemeral container"),
+                                 formatter_class=argparse.RawTextHelpFormatter,
+                                 epilog=_("If a COMMAND is given, then the "
+                                          """container will run only as long
+as the command runs.
+If no COMMAND is given, this command will attach to tty1 and stop the
+container when exiting (with ctrl-a-q).
+
+If no COMMAND is given and -d is used, the name and IP addresses of the
+container will be printed to the console."""))
+
+parser.add_argument("--lxcpath", "-P", dest="lxcpath", metavar="PATH",
+                    help=_("Use specified container path"), default=None)
+
+parser.add_argument("--orig", "-o", type=str, required=True,
+                    help=_("name of the original container"))
+
+parser.add_argument("--name", "-n", type=str,
+                    help=_("name of the target container"))
+
+parser.add_argument("--bdir", "-b", type=str, action="append", default=[],
+                    help=_("directory to bind mount into container, "
+                           "either --bdir=/src-path or --bdir=/src-path:/dst-path"))
+
+parser.add_argument("--cdir", "-c", type=str, action="append", default=[],
+                    help=_("directory to cow mount into container"))
+
+parser.add_argument("--user", "-u", type=str,
+                    help=_("the user to run the command as"))
+
+parser.add_argument("--key", "-S", type=str,
+                    help=_("the path to the key to use to connect "
+                           "(when using ssh)"))
+
+parser.add_argument("--daemon", "-d", action="store_true",
+                    help=_("run in the background"))
+
+parser.add_argument("--storage-type", "-s", type=str, default=None,
+                    choices=("tmpfs", "dir"),
+                    help=("type of storage use by the container"))
+
+parser.add_argument("--union-type", "-U", type=str, default="overlayfs",
+                    choices=("overlayfs", "aufs"),
+                    help=_("type of union (overlayfs or aufs), "
+                           "defaults to overlayfs."))
+
+parser.add_argument("--keep-data", "-k", action="store_true",
+                    help=_("don't wipe everything clean at the end"))
+
+parser.add_argument("command", metavar='CMD', type=str, nargs="*",
+                    help=_("Run specific command in container "
+                           "(command as argument)"))
+
+parser.add_argument("--version", action="version", version=lxc.version)
+
+args = parser.parse_args()
+
+# Check that -d and CMD aren't used at the same time
+if args.command and args.daemon:
+    parser.error(_("You can't use -d and a command at the same time."))
+
+# Check that -k isn't used with -s tmpfs
+if not args.storage_type:
+    if args.keep_data:
+        args.storage_type = "dir"
+    else:
+        args.storage_type = "tmpfs"
+
+if args.keep_data and args.storage_type == "tmpfs":
+    parser.error(_("You can't use -k with the tmpfs storage type."))
+
+# Load the orig container
+orig = lxc.Container(args.orig, args.lxcpath)
+if not orig.defined:
+    parser.error(_("Source container '%s' doesn't exist." % args.orig))
+
+# Create the new container paths
+if not args.lxcpath:
+    lxc_path = lxc.default_config_path
+else:
+    lxc_path = args.lxcpath
+
+if args.name:
+    if os.path.exists("%s/%s" % (lxc_path, args.name)):
+        parser.error(_("A container named '%s' already exists." % args.name))
+    dest_path = "%s/%s" % (lxc_path, args.name)
+    os.mkdir(dest_path)
+else:
+    dest_path = tempfile.mkdtemp(prefix="%s-" % args.orig, dir=lxc_path)
+os.mkdir(os.path.join(dest_path, "rootfs"))
+os.chmod(dest_path, 0o770)
+
+# Setup the new container's configuration
+dest = lxc.Container(os.path.basename(dest_path), args.lxcpath)
+dest.load_config(orig.config_file_name)
+dest.set_config_item("lxc.utsname", dest.name)
+dest.set_config_item("lxc.rootfs", os.path.join(dest_path, "rootfs"))
+print("setting rootfs to .%s.", os.path.join(dest_path, "rootfs"))
+for nic in dest.network:
+    if hasattr(nic, 'hwaddr'):
+        nic.hwaddr = randomMAC()
+
+overlay_dirs = [(orig.get_config_item("lxc.rootfs"), "%s/rootfs/" % dest_path)]
+
+# Generate a new fstab
+if orig.get_config_item("lxc.mount"):
+    dest.set_config_item("lxc.mount", os.path.join(dest_path, "fstab"))
+    with open(orig.get_config_item("lxc.mount"), "r") as orig_fd:
+        with open(dest.get_config_item("lxc.mount"), "w+") as dest_fd:
+            for line in orig_fd.read().split("\n"):
+                # Start by replacing any reference to the container rootfs
+                line.replace(orig.get_config_item("lxc.rootfs"),
+                             dest.get_config_item("lxc.rootfs"))
+
+                fields = line.split()
+
+                # Skip invalid entries
+                if len(fields) < 4:
+                    continue
+
+                # Non-bind mounts are kept as-is
+                if "bind" not in fields[3]:
+                    dest_fd.write("%s\n" % line)
+                    continue
+
+                # Bind mounts of virtual filesystems are also kept as-is
+                src_path = fields[0].split("/")
+                if len(src_path) > 1 and src_path[1] in ("proc", "sys"):
+                    dest_fd.write("%s\n" % line)
+                    continue
+
+                # Skip invalid mount points
+                dest_mount = os.path.abspath(os.path.join("%s/rootfs/" % (
+                                             dest_path), fields[1]))
+
+                if "%s/rootfs/" % dest_path not in dest_mount:
+                    print(_("Skipping mount entry '%s' as it's outside "
+                            "of the container rootfs.") % line)
+
+                # Setup an overlay for anything remaining
+                overlay_dirs += [(fields[0], dest_mount)]
+
+for entry in args.cdir:
+    if not os.path.exists(entry):
+        print(_("Path '%s' doesn't exist, won't be cow-mounted.") %
+              entry)
+    else:
+        src_path = os.path.abspath(entry)
+        dst_path = "%s/rootfs/%s" % (dest_path, src_path)
+        overlay_dirs += [(src_path, dst_path)]
+
+# do we have the new overlay fs which requires workdir, or the older
+# overlayfs which does not?
+have_new_overlay = False
+with open("/proc/filesystems", "r") as fd:
+    for line in fd:
+        if line == "nodev\toverlay\n":
+            have_new_overlay = True
+
+# Generate pre-mount script
+with open(os.path.join(dest_path, "pre-mount"), "w+") as fd:
+    os.fchmod(fd.fileno(), 0o755)
+    fd.write("""#!/bin/sh
+LXC_DIR="%s"
+LXC_BASE="%s"
+LXC_NAME="%s"
+""" % (dest_path, orig.name, dest.name))
+
+    count = 0
+    for entry in overlay_dirs:
+        tmpdir = "%s/tmpfs" % dest_path
+        fd.write("mkdir -p %s\n" % (tmpdir))
+        if args.storage_type == "tmpfs":
+            fd.write("mount -n -t tmpfs -o mode=0755 none %s\n" % (tmpdir))
+        deltdir = "%s/delta%s" % (tmpdir, count)
+        workdir = "%s/work%s" % (tmpdir, count)
+        fd.write("mkdir -p %s %s\n" % (deltdir, entry[1]))
+        if have_new_overlay:
+            fd.write("mkdir -p %s\n" % workdir)
+
+        fd.write("getfacl -a %s | setfacl --set-file=- %s || true\n" %
+                 (entry[0], deltdir))
+        fd.write("getfacl -a %s | setfacl --set-file=- %s || true\n" %
+                 (entry[0], entry[1]))
+
+        if args.union_type == "overlayfs":
+            if have_new_overlay:
+                fd.write("mount -n -t overlay"
+                         " -oupperdir=%s,lowerdir=%s,workdir=%s none %s\n" % (
+                             deltdir,
+                             entry[0],
+                             workdir,
+                             entry[1]))
+            else:
+                fd.write("mount -n -t overlayfs"
+                         " -oupperdir=%s,lowerdir=%s none %s\n" % (
+                             deltdir,
+                             entry[0],
+                             entry[1]))
+        elif args.union_type == "aufs":
+            xino_path = "/dev/shm/aufs.xino"
+            if not os.path.exists(os.path.basename(xino_path)):
+                os.makedirs(os.path.basename(xino_path))
+
+            fd.write("mount -n -t aufs "
+                     "-o br=%s=rw:%s=ro,noplink,xino=%s none %s\n" % (
+                         deltdir,
+                         entry[0],
+                         xino_path,
+                         entry[1]))
+        count += 1
+
+    for entry in args.bdir:
+        if ':' in entry:
+            src_path, dst_path = entry.split(":")
+        else:
+            src_path = entry
+            dst_path = os.path.abspath(entry)
+
+        if not os.path.exists(src_path):
+            print(_("Path '%s' doesn't exist, won't be bind-mounted.") %
+                  src_path)
+        else:
+            src_path = os.path.abspath(src_path)
+            dst_path = "%s/rootfs/%s" % (dest_path, dst_path)
+            fd.write("mkdir -p %s\nmount -n --bind %s %s\n" % (
+                     dst_path, src_path, dst_path))
+
+    fd.write("""
+[ -e $LXC_DIR/configured ] && exit 0
+for file in $LXC_DIR/rootfs/etc/hostname \\
+            $LXC_DIR/rootfs/etc/hosts \\
+            $LXC_DIR/rootfs/etc/sysconfig/network \\
+            $LXC_DIR/rootfs/etc/sysconfig/network-scripts/ifcfg-eth0; do
+        [ -f "$file" ] && sed -i -e "s/$LXC_BASE/$LXC_NAME/" $file
+done
+touch $LXC_DIR/configured
+""")
+
+dest.set_config_item("lxc.hook.pre-mount",
+                     os.path.join(dest_path, "pre-mount"))
+
+if not args.keep_data:
+    dest.set_config_item("lxc.ephemeral", "1")
+
+dest.save_config()
+
+# Start the container
+if not dest.start() or not dest.wait("RUNNING", timeout=5):
+    print(_("The container '%s' failed to start.") % dest.name)
+    dest.stop()
+    if dest.defined:
+        dest.destroy()
+    sys.exit(1)
+
+# Deal with the case where we just attach to the container's console
+if not args.command and not args.daemon:
+    dest.console()
+    if not dest.shutdown(timeout=5):
+        dest.stop()
+    sys.exit(0)
+
+# Try to get the IP addresses
+ips = dest.get_ips(timeout=10)
+
+# Deal with the case where we just print info about the container
+if args.daemon:
+    print(_("""The ephemeral container is now started.
+
+You can enter it from the command line with: lxc-console -n %s
+The following IP addresses have be found in the container:
+%s""") % (dest.name,
+          "\n".join([" - %s" % entry for entry in ips]
+                    or [" - %s" % _("No address could be found")])))
+    sys.exit(0)
+
+# Now deal with the case where we want to run a command in the container
+if not ips:
+    print(_("Failed to get an IP for container '%s'.") % dest.name)
+    dest.stop()
+    if dest.defined:
+        dest.destroy()
+    sys.exit(1)
+
+if os.path.exists("/proc/self/ns/pid"):
+    def attach_as_user(command):
+        try:
+            username = "root"
+            if args.user:
+                username = args.user
+
+            line = subprocess.check_output(
+                ["getent", "passwd", username],
+                universal_newlines=True).rstrip("\n")
+            _, _, pw_uid, pw_gid, _, pw_dir, _ = line.split(":", 6)
+            pw_uid = int(pw_uid)
+            pw_gid = int(pw_gid)
+            os.setgid(pw_gid)
+            os.initgroups(username, pw_gid)
+            os.setuid(pw_uid)
+            os.chdir(pw_dir)
+            os.environ['HOME'] = pw_dir
+        except:
+            print(_("Unable to switch to user: %s" % username))
+            sys.exit(1)
+
+        return lxc.attach_run_command(command)
+
+    retval = dest.attach_wait(attach_as_user, args.command,
+                              env_policy=lxc.LXC_ATTACH_CLEAR_ENV)
+
+else:
+    cmd = ["ssh",
+           "-o", "StrictHostKeyChecking=no",
+           "-o", "UserKnownHostsFile=/dev/null"]
+
+    if args.user:
+        cmd += ["-l", args.user]
+
+    if args.key:
+        cmd += ["-i", args.key]
+
+    for ip in ips:
+        ssh_cmd = cmd + [ip] + args.command
+        retval = subprocess.call(ssh_cmd, universal_newlines=True)
+        if retval == 255:
+            print(_("SSH failed to connect, trying next IP address."))
+            continue
+
+        if retval != 0:
+            print(_("Command returned with non-zero return code: %s") % retval)
+        break
+
+# Shutdown the container
+if not dest.shutdown(timeout=5):
+    dest.stop()
+
+sys.exit(retval)
diff --git a/src/lxc/tools/lxc-top.lua b/src/lxc/tools/lxc-top.lua
new file mode 100755
index 0000000..b5b3a69
--- /dev/null
+++ b/src/lxc/tools/lxc-top.lua
@@ -0,0 +1,243 @@
+#!/usr/bin/env lua
+--
+-- top(1) like monitor for lxc containers
+--
+-- Copyright © 2012 Oracle.
+--
+-- Authors:
+-- Dwight Engen <dwight.engen at oracle.com>
+--
+-- This library is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License version 2, as
+-- published by the Free Software Foundation.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along
+-- with this program; if not, write to the Free Software Foundation, Inc.,
+-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+--
+
+local lxc    = require("lxc")
+local core   = require("lxc.core")
+local getopt = require("alt_getopt")
+
+local USER_HZ   = 100
+local ESC       = string.format("%c", 27)
+local TERMCLEAR = ESC.."[H"..ESC.."[J"
+local TERMNORM  = ESC.."[0m"
+local TERMBOLD  = ESC.."[1m"
+local TERMRVRS  = ESC.."[7m"
+
+local containers = {}
+local stats = {}
+local stats_total = {}
+local max_containers
+
+function printf(...)
+    local function wrapper(...) io.write(string.format(...)) end
+    local status, result = pcall(wrapper, ...)
+    if not status then
+	error(result, 2)
+    end
+end
+
+function string:split(delim, max_cols)
+    local cols = {}
+    local start = 1
+    local nextc
+    repeat
+	nextc = string.find(self, delim, start)
+	if (nextc and #cols ~= max_cols - 1) then
+	    table.insert(cols, string.sub(self, start, nextc-1))
+	    start = nextc + #delim
+	else
+	    table.insert(cols, string.sub(self, start, string.len(self)))
+	    nextc = nil
+	end
+    until nextc == nil or start > #self
+    return cols
+end
+
+function strsisize(size, width)
+    local KiB = 1024
+    local MiB = 1048576
+    local GiB = 1073741824
+    local TiB = 1099511627776
+    local PiB = 1125899906842624
+    local EiB = 1152921504606846976
+    local ZiB = 1180591620717411303424
+
+    if (size >= ZiB) then
+	return string.format("%d.%2.2d ZB", size / ZiB, (math.floor(size % ZiB) * 100) / ZiB)
+    end
+    if (size >= EiB) then
+	return string.format("%d.%2.2d EB", size / EiB, (math.floor(size % EiB) * 100) / EiB)
+    end
+    if (size >= PiB) then
+	return string.format("%d.%2.2d PB", size / PiB, (math.floor(size % PiB) * 100) / PiB)
+    end
+    if (size >= TiB) then
+	return string.format("%d.%2.2d TB", size / TiB, (math.floor(size % TiB) * 100) / TiB)
+    end
+    if (size >= GiB) then
+	return string.format("%d.%2.2d GB", size / GiB, (math.floor(size % GiB) * 100) / GiB)
+    end
+    if (size >= MiB) then
+	return string.format("%d.%2.2d MB", size / MiB, (math.floor(size % MiB) * 1000) / (MiB * 10))
+    end
+    if (size >= KiB) then
+	return string.format("%d.%2.2d KB", size / KiB, (math.floor(size % KiB) * 1000) / (KiB * 10))
+    end
+    return string.format("%3d.00   ", size)
+end
+
+function tty_lines()
+    local rows = 25
+    local f = assert(io.popen("stty -a | head -n 1"))
+    for line in f:lines() do
+	local stty_rows
+	_,_,stty_rows = string.find(line, "rows (%d+)")
+	if (stty_rows ~= nil) then
+	    rows = stty_rows
+	    break
+	end
+    end
+    f:close()
+    return rows
+end
+
+function container_sort(a, b)
+    if (optarg["r"]) then
+	if     (optarg["s"] == "n") then return (a > b)
+	elseif (optarg["s"] == "c") then return (stats[a].cpu_use_nanos < stats[b].cpu_use_nanos)
+	elseif (optarg["s"] == "d") then return (stats[a].blkio < stats[b].blkio)
+	elseif (optarg["s"] == "m") then return (stats[a].mem_used < stats[b].mem_used)
+	elseif (optarg["s"] == "k") then return (stats[a].kmem_used < stats[b].kmem_used)
+	end
+    else
+	if     (optarg["s"] == "n") then return (a < b)
+	elseif (optarg["s"] == "c") then return (stats[a].cpu_use_nanos > stats[b].cpu_use_nanos)
+	elseif (optarg["s"] == "d") then return (stats[a].blkio > stats[b].blkio)
+	elseif (optarg["s"] == "m") then return (stats[a].mem_used > stats[b].mem_used)
+	elseif (optarg["s"] == "k") then return (stats[a].kmem_used > stats[b].kmem_used)
+	end
+    end
+end
+
+function container_list_update()
+    local now_running
+
+    now_running = lxc.containers_running(true)
+
+    -- check for newly started containers
+    for _,v in ipairs(now_running) do
+	if (containers[v] == nil) then
+	    local ct = lxc.container:new(v)
+	    -- note, this is a "mixed" table, ie both dictionary and list
+	    containers[v] = ct
+	    table.insert(containers, v)
+	end
+    end
+
+    -- check for newly stopped containers
+    local indx = 1
+    while (indx <= #containers) do
+	local ctname = containers[indx]
+	if (now_running[ctname] == nil) then
+	    containers[ctname] = nil
+	    stats[ctname] = nil
+	    table.remove(containers, indx)
+	else
+	    indx = indx + 1
+	end
+    end
+
+    -- get stats for all current containers and resort the list
+    lxc.stats_clear(stats_total)
+    for _,ctname in ipairs(containers) do
+	stats[ctname] = containers[ctname]:stats_get(stats_total)
+    end
+    table.sort(containers, container_sort)
+end
+
+function stats_print_header(stats_total)
+    printf(TERMRVRS .. TERMBOLD)
+    printf("%-15s %8s %8s %8s %10s %10s", "Container", "CPU",  "CPU",  "CPU",  "BlkIO", "Mem")
+    if (stats_total.kmem_used > 0) then printf(" %10s", "KMem") end
+    printf("\n")
+
+    printf("%-15s %8s %8s %8s %10s %10s", "Name",      "Used", "Sys",  "User", "Total", "Used")
+    if (stats_total.kmem_used > 0) then printf(" %10s", "Used") end
+    printf("\n")
+    printf(TERMNORM)
+end
+
+function stats_print(name, stats, stats_total)
+    printf("%-15s %8.2f %8.2f %8.2f %10s %10s",
+	   name,
+	   stats.cpu_use_nanos / 1000000000,
+	   stats.cpu_use_sys  / USER_HZ,
+	   stats.cpu_use_user / USER_HZ,
+	   strsisize(stats.blkio),
+	   strsisize(stats.mem_used))
+    if (stats_total.kmem_used > 0) then
+	printf(" %10s", strsisize(stats.kmem_used))
+    end
+end
+
+function usage()
+    printf("Usage: lxc-top [options]\n" ..
+	"  -h|--help      print this help message\n" ..
+	"  -m|--max       display maximum number of containers\n" ..
+	"  -d|--delay     delay in seconds between refreshes (default: 3.0)\n" ..
+	"  -s|--sort      sort by [n,c,d,m] (default: n) where\n" ..
+	"                 n = Name\n" ..
+	"                 c = CPU use\n" ..
+	"                 d = Disk I/O use\n" ..
+	"                 m = Memory use\n" ..
+	"                 k = Kernel memory use\n" ..
+	"  -r|--reverse   sort in reverse (descending) order\n"
+    )
+    os.exit(1)
+end
+
+local long_opts = {
+    help      = "h",
+    delay     = "d",
+    max       = "m",
+    reverse   = "r",
+    sort      = "s",
+}
+
+optarg,optind = alt_getopt.get_opts (arg, "hd:m:rs:", long_opts)
+optarg["d"] = tonumber(optarg["d"]) or 3.0
+optarg["m"] = tonumber(optarg["m"]) or tonumber(tty_lines() - 3)
+optarg["r"] = optarg["r"] or false
+optarg["s"] = optarg["s"] or "n"
+if (optarg["h"] ~= nil) then
+    usage()
+end
+
+while true
+do
+    container_list_update()
+    -- if some terminal we care about doesn't support the simple escapes, we
+    -- may fall back to this, or ncurses. ug.
+    --os.execute("tput clear")
+    printf(TERMCLEAR)
+    stats_print_header(stats_total)
+    for index,ctname in ipairs(containers) do
+	stats_print(ctname, stats[ctname], stats_total)
+	printf("\n")
+	if (index >= optarg["m"]) then
+	    break
+	end
+    end
+    stats_print(string.format("TOTAL (%-2d)", #containers), stats_total, stats_total)
+    io.flush()
+    core.usleep(optarg["d"] * 1000000)
+end
diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
new file mode 100644
index 0000000..58f658b
--- /dev/null
+++ b/src/lxc/tools/lxc_attach.c
@@ -0,0 +1,440 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2010
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "attach.h"
+#include "arguments.h"
+#include "caps.h"
+#include "confile.h"
+#include "console.h"
+#include "log.h"
+#include "list.h"
+#include "mainloop.h"
+#include "utils.h"
+
+#if HAVE_PTY_H
+#include <pty.h>
+#else
+#include <../include/openpty.h>
+#endif
+
+lxc_log_define(lxc_attach_ui, lxc);
+
+static const struct option my_longopts[] = {
+	{"elevated-privileges", optional_argument, 0, 'e'},
+	{"arch", required_argument, 0, 'a'},
+	{"namespaces", required_argument, 0, 's'},
+	{"remount-sys-proc", no_argument, 0, 'R'},
+	/* TODO: decide upon short option names */
+	{"clear-env", no_argument, 0, 500},
+	{"keep-env", no_argument, 0, 501},
+	{"keep-var", required_argument, 0, 502},
+	{"set-var", required_argument, 0, 'v'},
+	{"pty-log", required_argument, 0, 'L'},
+	LXC_COMMON_OPTIONS
+};
+
+static int elevated_privileges = 0;
+static signed long new_personality = -1;
+static int namespace_flags = -1;
+static int remount_sys_proc = 0;
+static lxc_attach_env_policy_t env_policy = LXC_ATTACH_KEEP_ENV;
+static char **extra_env = NULL;
+static ssize_t extra_env_size = 0;
+static char **extra_keep = NULL;
+static ssize_t extra_keep_size = 0;
+
+static int add_to_simple_array(char ***array, ssize_t *capacity, char *value)
+{
+	ssize_t count = 0;
+
+	assert(array);
+
+	if (*array)
+		for (; (*array)[count]; count++);
+
+	/* we have to reallocate */
+	if (count >= *capacity - 1) {
+		ssize_t new_capacity = ((count + 1) / 32 + 1) * 32;
+		char **new_array = realloc((void*)*array, sizeof(char *) * new_capacity);
+		if (!new_array)
+			return -1;
+		memset(&new_array[count], 0, sizeof(char*)*(new_capacity - count));
+		*array = new_array;
+		*capacity = new_capacity;
+	}
+
+	assert(*array);
+
+	(*array)[count] = value;
+	return 0;
+}
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	int ret;
+
+	switch (c) {
+	case 'e':
+		ret = lxc_fill_elevated_privileges(arg, &elevated_privileges);
+		if (ret)
+			return -1;
+		break;
+	case 'R': remount_sys_proc = 1; break;
+	case 'a':
+		new_personality = lxc_config_parse_arch(arg);
+		if (new_personality < 0) {
+			lxc_error(args, "invalid architecture specified: %s", arg);
+			return -1;
+		}
+		break;
+	case 's':
+		namespace_flags = 0;
+		ret = lxc_fill_namespace_flags(arg, &namespace_flags);
+		if (ret)
+			return -1;
+		/* -s implies -e */
+		lxc_fill_elevated_privileges(NULL, &elevated_privileges);
+		break;
+	case 500: /* clear-env */
+		env_policy = LXC_ATTACH_CLEAR_ENV;
+		break;
+	case 501: /* keep-env */
+		env_policy = LXC_ATTACH_KEEP_ENV;
+		break;
+	case 502: /* keep-var */
+		ret = add_to_simple_array(&extra_keep, &extra_keep_size, arg);
+		if (ret < 0) {
+			lxc_error(args, "memory allocation error");
+			return -1;
+		}
+		break;
+	case 'v':
+		ret = add_to_simple_array(&extra_env, &extra_env_size, arg);
+		if (ret < 0) {
+			lxc_error(args, "memory allocation error");
+			return -1;
+		}
+		break;
+	case 'L':
+		args->console_log = arg;
+		break;
+	}
+
+	return 0;
+}
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-attach",
+	.help     = "\
+--name=NAME [-- COMMAND]\n\
+\n\
+Execute the specified COMMAND - enter the container NAME\n\
+\n\
+Options :\n\
+  -n, --name=NAME   NAME of the container\n\
+  -e, --elevated-privileges=PRIVILEGES\n\
+                    Use elevated privileges instead of those of the\n\
+                    container. If you don't specify privileges to be\n\
+                    elevated as OR'd list: CAP, CGROUP and LSM (capabilities,\n\
+                    cgroup and restrictions, respectively) then all of them\n\
+                    will be elevated.\n\
+                    WARNING: This may leak privileges into the container.\n\
+                    Use with care.\n\
+  -a, --arch=ARCH   Use ARCH for program instead of container's own\n\
+                    architecture.\n\
+  -s, --namespaces=FLAGS\n\
+                    Don't attach to all the namespaces of the container\n\
+                    but just to the following OR'd list of flags:\n\
+                    MOUNT, PID, UTSNAME, IPC, USER or NETWORK.\n\
+                    WARNING: Using -s implies -e with all privileges\n\
+                    elevated, it may therefore leak privileges into the\n\
+                    container. Use with care.\n\
+  -R, --remount-sys-proc\n\
+                    Remount /sys and /proc if not attaching to the\n\
+                    mount namespace when using -s in order to properly\n\
+                    reflect the correct namespace context. See the\n\
+                    lxc-attach(1) manual page for details.\n\
+      --clear-env   Clear all environment variables before attaching.\n\
+                    The attached shell/program will start with only\n\
+                    container=lxc set.\n\
+      --keep-env    Keep all current environment variables. This\n\
+                    is the current default behaviour, but is likely to\n\
+                    change in the future.\n\
+  -L, --pty-log=FILE\n\
+		    Log pty output to FILE\n\
+  -v, --set-var     Set an additional variable that is seen by the\n\
+                    attached program in the container. May be specified\n\
+                    multiple times.\n\
+      --keep-var    Keep an additional environment variable. Only\n\
+                    applicable if --clear-env is specified. May be used\n\
+                    multiple times.\n",
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = NULL,
+};
+
+struct wrapargs {
+	lxc_attach_options_t *options;
+	lxc_attach_command_t *command;
+	struct lxc_console *console;
+	int ptyfd;
+};
+
+/* Minimalistic login_tty() implementation. */
+static int login_pty(int fd)
+{
+	setsid();
+	if (ioctl(fd, TIOCSCTTY, NULL) < 0)
+		return -1;
+	if (lxc_console_set_stdfds(fd) < 0)
+		return -1;
+	if (fd > STDERR_FILENO)
+		close(fd);
+	return 0;
+}
+
+static int get_pty_on_host_callback(void *p)
+{
+	struct wrapargs *wrap = p;
+
+	close(wrap->console->master);
+	if (login_pty(wrap->console->slave) < 0)
+		return -1;
+
+	if (wrap->command->program)
+		lxc_attach_run_command(wrap->command);
+	else
+		lxc_attach_run_shell(NULL);
+	return -1;
+}
+
+static int get_pty_on_host(struct lxc_container *c, struct wrapargs *wrap, int *pid)
+{
+	int ret = -1;
+	struct wrapargs *args = wrap;
+	struct lxc_epoll_descr descr;
+	struct lxc_conf *conf;
+	struct lxc_tty_state *ts;
+
+	INFO("Trying to allocate a pty on the host");
+
+	if (!isatty(args->ptyfd)) {
+		ERROR("Standard file descriptor does not refer to a pty\n.");
+		return -1;
+	}
+
+	conf = c->lxc_conf;
+	free(conf->console.log_path);
+	if (my_args.console_log)
+		conf->console.log_path = strdup(my_args.console_log);
+	else
+		conf->console.log_path = NULL;
+
+	/* In the case of lxc-attach our peer pty will always be the current
+	 * controlling terminal. We clear whatever was set by the user for
+	 * lxc.console.path here and set it to "/dev/tty". Doing this will (a)
+	 * prevent segfaults when the container has been setup with
+	 * lxc.console = none and (b) provide an easy way to ensure that we
+	 * always do the correct thing. strdup() must be used since console.path
+	 * is free()ed when we call lxc_container_put(). */
+	free(conf->console.path);
+	conf->console.path = strdup("/dev/tty");
+	if (!conf->console.path)
+		return -1;
+
+	/* Create pty on the host. */
+	if (lxc_console_create(conf) < 0)
+		return -1;
+	ts = conf->console.tty_state;
+	conf->console.descr = &descr;
+
+	/* Shift ttys to container. */
+	if (ttys_shift_ids(conf) < 0) {
+		ERROR("Failed to shift tty into container");
+		goto err1;
+	}
+
+	/* Send wrapper function on its way. */
+	wrap->console = &conf->console;
+	if (c->attach(c, get_pty_on_host_callback, wrap, wrap->options, pid) < 0)
+		goto err1;
+	close(conf->console.slave); /* Close slave side. */
+
+	ret = lxc_mainloop_open(&descr);
+	if (ret) {
+		ERROR("failed to create mainloop");
+		goto err2;
+	}
+
+	if (lxc_console_mainloop_add(&descr, conf) < 0) {
+		ERROR("Failed to add handlers to lxc mainloop.");
+		goto err3;
+	}
+
+	ret = lxc_mainloop(&descr, -1);
+	if (ret) {
+		ERROR("mainloop returned an error");
+		goto err3;
+	}
+	ret = 0;
+
+err3:
+	lxc_mainloop_close(&descr);
+err2:
+	if (ts->sigfd != -1)
+		lxc_console_sigwinch_fini(ts);
+err1:
+	lxc_console_delete(&conf->console);
+
+	return ret;
+}
+
+static int stdfd_is_pty(void)
+{
+	if (isatty(STDIN_FILENO))
+		return STDIN_FILENO;
+	if (isatty(STDOUT_FILENO))
+		return STDOUT_FILENO;
+	if (isatty(STDERR_FILENO))
+		return STDERR_FILENO;
+
+	return -1;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = -1, r;
+	int wexit = 0;
+	pid_t pid;
+	lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
+	lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL};
+
+	r = lxc_caps_init();
+	if (r)
+		exit(EXIT_FAILURE);
+
+	r = lxc_arguments_parse(&my_args, argc, argv);
+	if (r)
+		exit(EXIT_FAILURE);
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	r = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			   my_args.progname, my_args.quiet, my_args.lxcpath[0]);
+	if (r)
+		exit(EXIT_FAILURE);
+	lxc_log_options_no_override();
+
+	if (geteuid()) {
+		if (access(my_args.lxcpath[0], O_RDWR) < 0) {
+			if (!my_args.quiet)
+				fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c)
+		exit(EXIT_FAILURE);
+
+	if (!c->may_control(c)) {
+		fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+		lxc_container_put(c);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!c->is_defined(c)) {
+		fprintf(stderr, "Error: container %s is not defined\n", c->name);
+		lxc_container_put(c);
+		exit(EXIT_FAILURE);
+	}
+
+	if (remount_sys_proc)
+		attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
+	if (elevated_privileges)
+		attach_options.attach_flags &= ~(elevated_privileges);
+	attach_options.namespaces = namespace_flags;
+	attach_options.personality = new_personality;
+	attach_options.env_policy = env_policy;
+	attach_options.extra_env_vars = extra_env;
+	attach_options.extra_keep_env = extra_keep;
+
+	if (my_args.argc > 0) {
+		command.program = my_args.argv[0];
+		command.argv = (char**)my_args.argv;
+	}
+
+	struct wrapargs wrap = (struct wrapargs){
+		.command = &command,
+			.options = &attach_options
+	};
+
+	wrap.ptyfd = stdfd_is_pty();
+	if (wrap.ptyfd >= 0) {
+		if ((!isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) && my_args.console_log) {
+			fprintf(stderr, "-L/--pty-log can only be used when stdout and stderr refer to a pty.\n");
+			goto out;
+		}
+		ret = get_pty_on_host(c, &wrap, &pid);
+	} else {
+		if (my_args.console_log) {
+			fprintf(stderr, "-L/--pty-log can only be used when stdout and stderr refer to a pty.\n");
+			goto out;
+		}
+		if (command.program)
+			ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
+		else
+			ret = c->attach(c, lxc_attach_run_shell, NULL, &attach_options, &pid);
+	}
+
+	if (ret < 0)
+		goto out;
+
+	ret = lxc_wait_for_pid_status(pid);
+	if (ret < 0)
+		goto out;
+
+	if (WIFEXITED(ret))
+		wexit = WEXITSTATUS(ret);
+out:
+	lxc_container_put(c);
+	if (ret >= 0)
+		exit(wexit);
+	exit(EXIT_FAILURE);
+}
diff --git a/src/lxc/tools/lxc_autostart.c b/src/lxc/tools/lxc_autostart.c
new file mode 100644
index 0000000..eed0f5f
--- /dev/null
+++ b/src/lxc/tools/lxc_autostart.c
@@ -0,0 +1,526 @@
+/* lxc_autostart
+ *
+ * Copyright © 2013 Stéphane Graber <stgraber at ubuntu.com>
+ * Copyright © 2013 Canonical Ltd.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <string.h>
+#include <unistd.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "arguments.h"
+#include "list.h"
+#include "log.h"
+
+lxc_log_define(lxc_autostart_ui, lxc);
+static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list);
+
+struct lxc_list *cmd_groups_list = NULL;
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	switch (c) {
+	case 'k': args->hardstop = 1; break;
+	case 'L': args->list = 1; break;
+	case 'r': args->reboot = 1; break;
+	case 's': args->shutdown = 1; break;
+	case 'a': args->all = 1; break;
+	case 'A': args->ignore_auto = 1; break;
+	case 'g': cmd_groups_list = accumulate_list( arg, ",", cmd_groups_list); break;
+	case 't': args->timeout = atoi(arg); break;
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	{"kill", no_argument, 0, 'k'},
+	{"list", no_argument, 0, 'L'},
+	{"reboot", no_argument, 0, 'r'},
+	{"shutdown", no_argument, 0, 's'},
+	{"all", no_argument, 0, 'a'},
+	{"ignore-auto", no_argument, 0, 'A'},
+	{"groups", required_argument, 0, 'g'},
+	{"timeout", required_argument, 0, 't'},
+	{"help", no_argument, 0, 'h'},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-autostart",
+	.help     = "\
+\n\
+lxc-autostart managed auto-started containers\n\
+\n\
+Options:\n\
+  -k, --kill        kill the containers instead of starting them\n\
+  -L, --list        list all affected containers and wait delay\n\
+  -r, --reboot      reboot the containers instead of starting them\n\
+  -s, --shutdown    shutdown the containers instead of starting them\n\
+\n\
+  -a, --all         list all auto-started containers (ignore groups)\n\
+  -A, --ignore-auto ignore lxc.start.auto and select all matching containers\n\
+  -g, --groups      list of groups (comma separated) to select\n\
+  -t, --timeout=T   wait T seconds before hard-stopping\n",
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = NULL,
+	.timeout = 60,
+};
+
+int list_contains_entry( char *str_ptr, struct lxc_list *p1 ) {
+	struct lxc_list *it1;
+
+	/*
+	 * If the entry is NULL or the empty string and the list
+	 * is NULL, we have a match
+	 */
+	if (! p1 && ! str_ptr)
+		return 1;
+	if (! p1 && ! *str_ptr)
+		return 1;
+
+	if (!p1)
+		return 0;
+
+	lxc_list_for_each(it1, p1) {
+		if (strcmp(it1->elem, str_ptr) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) {
+	struct lxc_list *it1;
+	struct lxc_list *it2;
+
+	if (!p1 && !p2)
+		return 1;
+
+	if (!p1)
+		return 0;
+
+	if (!p2)
+		return 0;
+
+	lxc_list_for_each(it1, p1) {
+		lxc_list_for_each(it2, p2) {
+			if (strcmp(it1->elem, it2->elem) == 0)
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This is a variation of get_list below it.
+ * This version allows two additional features.
+ * If a list is passed to it, it adds to it.
+ * It allows for empty entries (i.e. "group1,,group2") generating
+ * 	and empty list entry.
+ */
+static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list) {
+	char *workstr = NULL;
+	char *workptr = NULL;
+	char *next_ptr = NULL;
+	struct lxc_list *worklist;
+	struct lxc_list *workstr_list;
+
+	workstr = strdup(input);
+	if (!workstr) {
+		return NULL;
+	}
+
+	workstr_list = str_list;
+	if ( ! workstr_list ) {
+		workstr_list = malloc(sizeof(*workstr_list));
+		lxc_list_init(workstr_list);
+	}
+
+	for (workptr = workstr; workptr; workptr = next_ptr) {
+		/*
+		 * We can't use strtok_r here because it collapses
+		 * multiple delimiters into 1 making empty fields
+		 * impossible...
+		 */
+		/* token = strtok_r(workptr, delimiter, &sptr); */
+		next_ptr = strchr( workptr, *delimiter );
+
+		if( next_ptr ) {
+			*next_ptr++ = '\0';
+		}
+
+		/*
+		 * At this point, we'd like to check to see if this
+		 * group is already contained in the list and ignore
+		 * it if it is...  This also helps us with any
+		 * corner cases where a string begins or ends with a
+		 * delimiter.
+		 */
+
+		if ( list_contains_entry( workptr, workstr_list ) ) {
+			if ( *workptr ) {
+				fprintf(stderr, "Duplicate group \"%s\" in list - ignoring\n", workptr );
+				fflush(stderr);
+			} else {
+				fprintf(stderr, "Duplicate NULL group in list - ignoring\n" );
+				fflush(stderr);
+			}
+		} else {
+			worklist = malloc(sizeof(*worklist));
+			if (!worklist)
+				break;
+
+			worklist->elem = strdup(workptr);
+			if (!worklist->elem) {
+				free(worklist);
+				break;
+			}
+
+			lxc_list_add_tail(workstr_list, worklist);
+		}
+	}
+
+	free(workstr);
+
+	return workstr_list;
+}
+
+static struct lxc_list *get_list(char *input, char *delimiter) {
+	char *workstr = NULL;
+	char *workptr = NULL;
+	char *sptr = NULL;
+	char *token = NULL;
+	struct lxc_list *worklist;
+	struct lxc_list *workstr_list;
+
+	workstr_list = malloc(sizeof(*workstr_list));
+	lxc_list_init(workstr_list);
+
+	workstr = strdup(input);
+	if (!workstr) {
+		free(workstr_list);
+		return NULL;
+	}
+
+	for (workptr = workstr;;workptr = NULL) {
+		token = strtok_r(workptr, delimiter, &sptr);
+		if (!token) {
+			break;
+		}
+
+		worklist = malloc(sizeof(*worklist));
+		if (!worklist)
+			break;
+
+		worklist->elem = strdup(token);
+		if (!worklist->elem) {
+			free(worklist);
+			break;
+		}
+
+		lxc_list_add_tail(workstr_list, worklist);
+	}
+
+	free(workstr);
+
+	return workstr_list;
+}
+
+static struct lxc_list *get_config_list(struct lxc_container *c, char *key) {
+	int len = 0;
+	char* value = NULL;
+	struct lxc_list *config_list = NULL;
+
+	len = c->get_config_item(c, key, NULL, 0);
+	if (len < 0)
+		return NULL;
+
+	value = (char*) malloc(sizeof(char)*len + 1);
+	if (value == NULL)
+		return NULL;
+
+	if (c->get_config_item(c, key, value, len + 1) != len) {
+		free(value);
+		return NULL;
+	}
+
+	if (strlen(value) == 0) {
+		free(value);
+		return NULL;
+	}
+
+	config_list = get_list(value, "\n");
+	free(value);
+
+	return config_list;
+}
+
+static int get_config_integer(struct lxc_container *c, char *key) {
+	int len = 0;
+	int ret = 0;
+	char* value = NULL;
+
+	len = c->get_config_item(c, key, NULL, 0);
+	if (len < 0)
+		return 0;
+
+	value = (char*) malloc(sizeof(char)*len + 1);
+	if (value == NULL)
+		return 0;
+
+	if (c->get_config_item(c, key, value, len + 1) != len) {
+		free(value);
+		return 0;
+	}
+
+	ret = atoi(value);
+	free(value);
+
+	return ret;
+}
+
+static int cmporder(const void *p1, const void *p2) {
+	struct lxc_container *c1 = *(struct lxc_container **)p1;
+	struct lxc_container *c2 = *(struct lxc_container **)p2;
+
+	int c1_order = get_config_integer(c1, "lxc.start.order");
+	int c2_order = get_config_integer(c2, "lxc.start.order");
+
+	if (c1_order == c2_order)
+		return strcmp(c1->name, c2->name);
+	else
+		return (c1_order - c2_order);
+}
+
+static int toss_list( struct lxc_list *c_groups_list ) {
+	struct lxc_list *it, *next;
+
+	if (c_groups_list) {
+		lxc_list_for_each_safe(it, c_groups_list, next) {
+			lxc_list_del(it);
+			free(it->elem);
+			free(it);
+		}
+		free(c_groups_list);
+	}
+
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	int count = 0;
+	int i = 0;
+	int ret = 0;
+	struct lxc_container **containers = NULL;
+	struct lxc_list **c_groups_lists = NULL;
+	struct lxc_list *cmd_group;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		return 1;
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		return 1;
+	lxc_log_options_no_override();
+
+	count = list_defined_containers(my_args.lxcpath[0], NULL, &containers);
+
+	if (count < 0)
+		return 1;
+
+	if (!my_args.all) {
+		/* Allocate an array for our container group lists */
+		c_groups_lists = calloc( count, sizeof( struct lxc_list * ) );
+	}
+
+	qsort(&containers[0], count, sizeof(struct lxc_container *), cmporder);
+
+	if (cmd_groups_list && my_args.all) {
+		fprintf(stderr, "Specifying -a (all) with -g (groups) doesn't make sense. All option overrides.\n");
+		fflush(stderr);
+	}
+
+	if (!cmd_groups_list) {
+		/*
+		 * We need a default cmd_groups_list even for the -a
+		 * case in order to force a pass through the loop for
+		 * the NULL group.  This, someday, could be taken from
+		 * a config file somewhere...
+		 */
+		cmd_groups_list = accumulate_list( "" , ",", NULL );
+	}
+
+	lxc_list_for_each(cmd_group, cmd_groups_list) {
+
+		/*
+		 * Prograpmmers Note:
+		 * Because we may take several passes through the container list
+		 * We'll switch on if the container pointer is NULL and if we process a
+		 * container (run it or decide to ignore it) and call lxc_container_put
+		 * then we'll NULL it out and not check it again.
+		 */
+		for (i = 0; i < count; i++) {
+			struct lxc_container *c = containers[i];
+
+			if (!c)
+				/* Skip - must have been already processed */
+				continue;
+
+			/*
+			 * We haven't loaded the container groups yet so
+			 * these next two checks don't need to free them
+			 * if they fail.  They'll fail on the first pass.
+			 */
+			if (!c->may_control(c)) {
+				/* We're done with this container */
+				if ( lxc_container_put(c) > 0 )
+					containers[i] = NULL;
+				continue;
+			}
+
+			if (!my_args.ignore_auto &&
+			    get_config_integer(c, "lxc.start.auto") != 1) {
+				/* We're done with this container */
+				if ( lxc_container_put(c) > 0 )
+					containers[i] = NULL;
+				continue;
+			}
+
+			if (!my_args.all) {
+				/* Filter by group */
+				if( ! c_groups_lists[i] ) {
+					/* Now we're loading up a container's groups */
+					c_groups_lists[i] = get_config_list(c, "lxc.group");
+				}
+
+				ret = list_contains_entry(cmd_group->elem, c_groups_lists[i]);
+
+				if ( ret == 0 ) {
+					/* Not in the target group this pass */
+					/* Leave in the list for subsequent passes */
+					continue;
+				}
+			}
+
+			/* We have a candidate continer to process */
+			c->want_daemonize(c, 1);
+
+			if (my_args.shutdown) {
+				/* Shutdown the container */
+				if (c->is_running(c)) {
+					if (my_args.list) {
+						printf("%s\n", c->name);
+						fflush(stdout);
+					}
+					else {
+						if (!c->shutdown(c, my_args.timeout)) {
+							if (!c->stop(c)) {
+								fprintf(stderr, "Error shutting down container: %s\n", c->name);
+								fflush(stderr);
+							}
+						}
+					}
+				}
+			}
+			else if (my_args.hardstop) {
+				/* Kill the container */
+				if (c->is_running(c)) {
+					if (my_args.list) {
+						printf("%s\n", c->name);
+						fflush(stdout);
+					}
+					else {
+						if (!c->stop(c)) {
+							fprintf(stderr, "Error killing container: %s\n", c->name);
+							fflush(stderr);
+						}
+					}
+				}
+			}
+			else if (my_args.reboot) {
+				/* Reboot the container */
+				if (c->is_running(c)) {
+					if (my_args.list) {
+						printf("%s %d\n", c->name,
+						       get_config_integer(c, "lxc.start.delay"));
+						fflush(stdout);
+					}
+					else {
+						if (!c->reboot(c)) {
+							fprintf(stderr, "Error rebooting container: %s\n", c->name);
+							fflush(stderr);
+						}
+						else
+							sleep(get_config_integer(c, "lxc.start.delay"));
+					}
+				}
+			}
+			else {
+				/* Start the container */
+				if (!c->is_running(c)) {
+					if (my_args.list) {
+						printf("%s %d\n", c->name,
+						       get_config_integer(c, "lxc.start.delay"));
+						fflush(stdout);
+					}
+					else {
+						if (!c->start(c, 0, NULL)) {
+							fprintf(stderr, "Error starting container: %s\n", c->name);
+							fflush(stderr);
+						}
+						else
+							sleep(get_config_integer(c, "lxc.start.delay"));
+					}
+				}
+			}
+
+			/*
+			 * If we get this far and we haven't hit any skip "continue"
+			 * then we're done with this container...  We can dump any
+			 * c_groups_list and the container itself.
+			 */
+			if ( lxc_container_put(c) > 0 ) {
+				containers[i] = NULL;
+			}
+			if ( c_groups_lists ) {
+				toss_list(c_groups_lists[i]);
+				c_groups_lists[i] = NULL;
+			}
+		}
+
+	}
+
+	/* clean up any lingering detritus */
+	for (i = 0; i < count; i++) {
+		if ( containers[i] ) {
+			lxc_container_put(containers[i]);
+		}
+		if ( c_groups_lists && c_groups_lists[i] ) {
+			toss_list(c_groups_lists[i]);
+		}
+	}
+
+	free(c_groups_lists);
+	toss_list( cmd_groups_list );
+	free(containers);
+
+	return 0;
+}
diff --git a/src/lxc/tools/lxc_cgroup.c b/src/lxc/tools/lxc_cgroup.c
new file mode 100644
index 0000000..dd60fd1
--- /dev/null
+++ b/src/lxc/tools/lxc_cgroup.c
@@ -0,0 +1,122 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <sys/types.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "lxc.h"
+#include "log.h"
+#include "arguments.h"
+
+lxc_log_define(lxc_cgroup_ui, lxc);
+
+static int my_checker(const struct lxc_arguments* args)
+{
+	if (!args->argc) {
+		lxc_error(args, "missing state object");
+		return -1;
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-cgroup",
+	.help     = "\
+--name=NAME state-object [value]\n\
+\n\
+Get or set the value of a state object (for example, 'cpuset.cpus')\n\
+in the container's cgroup for the corresponding subsystem.\n\
+\n\
+Options :\n\
+  -n, --name=NAME      NAME of the container",
+	.options  = my_longopts,
+	.parser   = NULL,
+	.checker  = my_checker,
+};
+
+int main(int argc, char *argv[])
+{
+	char *state_object = NULL, *value = NULL;
+	struct lxc_container *c;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		return 1;
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		return 1;
+	lxc_log_options_no_override();
+
+	state_object = my_args.argv[0];
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c)
+		return 1;
+
+	if (!c->may_control(c)) {
+		ERROR("Insufficent privileges to control %s:%s", my_args.lxcpath[0], my_args.name);
+		lxc_container_put(c);
+		return 1;
+	}
+
+	if (!c->is_running(c)) {
+		ERROR("'%s:%s' is not running", my_args.lxcpath[0], my_args.name);
+		lxc_container_put(c);
+		return 1;
+	}
+
+	if ((my_args.argc) > 1) {
+		value = my_args.argv[1];
+		if (!c->set_cgroup_item(c, state_object, value)) {
+			ERROR("failed to assign '%s' value to '%s' for '%s'",
+				value, state_object, my_args.name);
+			lxc_container_put(c);
+			return 1;
+		}
+	} else {
+		int len = 4096;
+		char buffer[len];
+		int ret = c->get_cgroup_item(c, state_object, buffer, len);
+		if (ret < 0) {
+			ERROR("failed to retrieve value of '%s' for '%s:%s'",
+			      state_object, my_args.lxcpath[0], my_args.name);
+			lxc_container_put(c);
+			return 1;
+		}
+		printf("%*s", ret, buffer);
+	}
+
+	lxc_container_put(c);
+	return 0;
+}
diff --git a/src/lxc/tools/lxc_checkpoint.c b/src/lxc/tools/lxc_checkpoint.c
new file mode 100644
index 0000000..7130245
--- /dev/null
+++ b/src/lxc/tools/lxc_checkpoint.c
@@ -0,0 +1,236 @@
+/*
+ *
+ * Copyright © 2014 Tycho Andersen <tycho.andersen at canonical.com>.
+ * Copyright © 2014 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "log.h"
+#include "config.h"
+#include "lxc.h"
+#include "arguments.h"
+#include "utils.h"
+
+static char *checkpoint_dir = NULL;
+static bool stop = false;
+static bool verbose = false;
+static bool do_restore = false;
+static bool daemonize_set = false;
+
+static const struct option my_longopts[] = {
+	{"checkpoint-dir", required_argument, 0, 'D'},
+	{"stop", no_argument, 0, 's'},
+	{"verbose", no_argument, 0, 'v'},
+	{"restore", no_argument, 0, 'r'},
+	{"daemon", no_argument, 0, 'd'},
+	{"foreground", no_argument, 0, 'F'},
+	LXC_COMMON_OPTIONS
+};
+
+static int my_checker(const struct lxc_arguments *args)
+{
+	if (do_restore && stop) {
+		lxc_error(args, "-s not compatible with -r.");
+		return -1;
+
+	} else if (!do_restore && daemonize_set) {
+		lxc_error(args, "-d/-F not compatible with -r.");
+		return -1;
+	}
+
+	if (checkpoint_dir == NULL) {
+		lxc_error(args, "-D is required.");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg)
+{
+	switch (c) {
+	case 'D':
+		checkpoint_dir = strdup(arg);
+		if (!checkpoint_dir)
+			return -1;
+		break;
+	case 's':
+		stop = true;
+		break;
+	case 'v':
+		verbose = true;
+		break;
+	case 'r':
+		do_restore = true;
+		break;
+	case 'd':
+		args->daemonize = 1;
+		daemonize_set = true;
+		break;
+	case 'F':
+		args->daemonize = 0;
+		daemonize_set = true;
+		break;
+	}
+	return 0;
+}
+
+static struct lxc_arguments my_args = {
+	.progname  = "lxc-checkpoint",
+	.help      = "\
+--name=NAME\n\
+\n\
+lxc-checkpoint checkpoints and restores a container\n\
+  Serializes a container's running state to disk to allow restoring it in\n\
+  its running state at a later time.\n\
+\n\
+Options :\n\
+  -n, --name=NAME           NAME of the container\n\
+  -r, --restore             Restore container\n\
+  -D, --checkpoint-dir=DIR  directory to save the checkpoint in\n\
+  -v, --verbose             Enable verbose criu logs\n\
+  Checkpoint options:\n\
+  -s, --stop                Stop the container after checkpointing.\n\
+  Restore options:\n\
+  -d, --daemon              Daemonize the container (default)\n\
+  -F, --foreground          Start with the current tty attached to /dev/console\n\
+",
+	.options   = my_longopts,
+	.parser    = my_parser,
+	.daemonize = 1,
+	.checker   = my_checker,
+};
+
+static bool checkpoint(struct lxc_container *c)
+{
+	bool ret;
+
+	if (!c->is_running(c)) {
+		fprintf(stderr, "%s not running, not checkpointing.\n", my_args.name);
+		lxc_container_put(c);
+		return false;
+	}
+
+	ret = c->checkpoint(c, checkpoint_dir, stop, verbose);
+	lxc_container_put(c);
+
+	if (!ret) {
+		fprintf(stderr, "Checkpointing %s failed.\n", my_args.name);
+		return false;
+	}
+
+	return true;
+}
+
+static bool restore_finalize(struct lxc_container *c)
+{
+	bool ret = c->restore(c, checkpoint_dir, verbose);
+	if (!ret) {
+		fprintf(stderr, "Restoring %s failed.\n", my_args.name);
+	}
+
+	lxc_container_put(c);
+	return ret;
+}
+
+static bool restore(struct lxc_container *c)
+{
+	if (c->is_running(c)) {
+		fprintf(stderr, "%s is running, not restoring.\n", my_args.name);
+		lxc_container_put(c);
+		return false;
+	}
+
+	if (my_args.daemonize) {
+		pid_t pid;
+
+		pid = fork();
+		if (pid < 0) {
+			perror("fork");
+			return false;
+		}
+
+		if (pid == 0) {
+			close(0);
+			close(1);
+
+			exit(!restore_finalize(c));
+		} else {
+			return wait_for_pid(pid) == 0;
+		}
+	} else {
+		int status;
+
+		if (!restore_finalize(c))
+			return false;
+
+		if (waitpid(-1, &status, 0) < 0)
+			return false;
+
+		return WIFEXITED(status) && WEXITSTATUS(status) == 0;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c;
+	bool ret;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		exit(1);
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		exit(1);
+
+	lxc_log_options_no_override();
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		fprintf(stderr, "System error loading %s\n", my_args.name);
+		exit(1);
+	}
+
+	if (!c->may_control(c)) {
+		fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
+		lxc_container_put(c);
+		exit(1);
+	}
+
+	if (!c->is_defined(c)) {
+		fprintf(stderr, "%s is not defined\n", my_args.name);
+		lxc_container_put(c);
+		exit(1);
+	}
+
+
+	if (do_restore)
+		ret = restore(c);
+	else
+		ret = checkpoint(c);
+
+	return !ret;
+}
diff --git a/src/lxc/tools/lxc_clone.c b/src/lxc/tools/lxc_clone.c
new file mode 100644
index 0000000..6bd2226
--- /dev/null
+++ b/src/lxc/tools/lxc_clone.c
@@ -0,0 +1,217 @@
+/*
+ *
+ * Copyright © 2013 Serge Hallyn <serge.hallyn at ubuntu.com>.
+ * Copyright © 2013 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <unistd.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "log.h"
+#include "config.h"
+#include "lxc.h"
+#include "conf.h"
+#include "state.h"
+
+lxc_log_define(lxc_clone_ui, lxc);
+
+/* we pass fssize in bytes */
+static uint64_t get_fssize(char *s)
+{
+	uint64_t ret;
+	char *end;
+
+	ret = strtoull(s, &end, 0);
+	if (end == s)
+	{
+		fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
+		return 0;
+	}
+	while (isblank(*end))
+		end++;
+	if (*end == '\0')
+		ret *= 1024ULL * 1024ULL; // MB by default
+	else if (*end == 'b' || *end == 'B')
+		ret *= 1ULL;
+	else if (*end == 'k' || *end == 'K')
+		ret *= 1024ULL;
+	else if (*end == 'm' || *end == 'M')
+		ret *= 1024ULL * 1024ULL;
+	else if (*end == 'g' || *end == 'G')
+		ret *= 1024ULL * 1024ULL * 1024ULL;
+	else if (*end == 't' || *end == 'T')
+		ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
+	else
+	{
+		fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s);
+		return 0;
+	}
+	return ret;
+}
+
+static void usage(const char *me)
+{
+	printf("Usage: %s [-s] [-B backingstore] [-L size[unit]] [-K] [-M] [-H]\n", me);
+	printf("          [-p lxcpath] [-P newlxcpath] orig new\n");
+	printf("\n");
+	printf("  -s: snapshot rather than copy\n");
+	printf("  -B: use specified new backingstore.  Default is the same as\n");
+	printf("      the original.  Options include aufs, btrfs, lvm, overlayfs, \n");
+	printf("      dir and loop\n");
+	printf("  -L: for blockdev-backed backingstore, use specified size * specified\n");
+	printf("      unit. Default size is the size of the source blockdev, default\n");
+	printf("      unit is MB\n");
+	printf("  -K: Keep name - do not change the container name\n");
+	printf("  -M: Keep macaddr - do not choose a random new mac address\n");
+	printf("  -p: use container orig from custom lxcpath\n");
+	printf("  -P: create container new in custom lxcpath\n");
+	printf("  -R: rename existing container\n");
+	exit(1);
+}
+
+static struct option options[] = {
+	{ "snapshot", no_argument, 0, 's'},
+	{ "backingstore", required_argument, 0, 'B'},
+	{ "size", required_argument, 0, 'L'},
+	{ "orig", required_argument, 0, 'o'},
+	{ "new", required_argument, 0, 'n'},
+	{ "vgname", required_argument, 0, 'v'},
+	{ "rename", no_argument, 0, 'R'},
+	{ "keepname", no_argument, 0, 'K'},
+	{ "keepmac", no_argument, 0, 'M'},
+	{ "lxcpath", required_argument, 0, 'p'},
+	{ "newpath", required_argument, 0, 'P'},
+	{ "fstype", required_argument, 0, 't'},
+	{ "help", no_argument, 0, 'h'},
+	{ 0, 0, 0, 0 },
+};
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c1 = NULL, *c2 = NULL;
+	int snapshot = 0, keepname = 0, keepmac = 0, rename = 0;
+	int flags = 0, option_index;
+	uint64_t newsize = 0;
+	char *bdevtype = NULL, *lxcpath = NULL, *newpath = NULL, *fstype = NULL;
+	char *orig = NULL, *new = NULL, *vgname = NULL;
+	char **args = NULL;
+	int c;
+	bool ret;
+
+	fprintf(stderr, "lxc-clone is deprecated in favor of lxc-copy.\n\n");
+
+	if (argc < 3)
+		usage(argv[0]);
+
+	while (1) {
+		c = getopt_long(argc, argv, "sB:L:o:n:v:KMHp:P:Rt:h", options, &option_index);
+		if (c == -1)
+			break;
+		switch (c) {
+		case 's': snapshot = 1; break;
+		case 'B': bdevtype = optarg; break;
+		case 'L': newsize = get_fssize(optarg); break;
+		case 'o': orig = optarg; break;
+		case 'n': new = optarg; break;
+		case 'v': vgname = optarg; break;
+		case 'K': keepname = 1; break;
+		case 'M': keepmac = 1; break;
+		case 'p': lxcpath = optarg; break;
+		case 'P': newpath = optarg; break;
+		case 'R': rename = 1; break;
+		case 't': fstype = optarg; break;
+		case 'h': usage(argv[0]);
+		default: break;
+		}
+	}
+    if (optind < argc && !orig)
+		orig = argv[optind++];
+    if (optind < argc && !new)
+		new = argv[optind++];
+	if (optind < argc)
+		/* arguments for the clone hook */
+		args = &argv[optind];
+	if (!new || !orig) {
+		printf("Error: you must provide orig and new names\n");
+		usage(argv[0]);
+	}
+
+	if (snapshot)  flags |= LXC_CLONE_SNAPSHOT;
+	if (keepname)  flags |= LXC_CLONE_KEEPNAME;
+	if (keepmac)   flags |= LXC_CLONE_KEEPMACADDR;
+
+	// vgname and fstype could be supported by sending them through the
+	// bdevdata.  However, they currently are not yet.  I'm not convinced
+	// they are worthwhile.
+	if (vgname) {
+		printf("Error: vgname not supported\n");
+		usage(argv[0]);
+	}
+	if (fstype) {
+		printf("Error: fstype not supported\n");
+		usage(argv[0]);
+	}
+
+	c1 = lxc_container_new(orig, lxcpath);
+	if (!c1)
+		exit(EXIT_FAILURE);
+
+	if (!c1->may_control(c1)) {
+		fprintf(stderr, "Insufficent privileges to control %s\n", orig);
+		lxc_container_put(c1);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!c1->is_defined(c1)) {
+		fprintf(stderr, "Error: container %s is not defined\n", orig);
+		lxc_container_put(c1);
+		exit(EXIT_FAILURE);
+	}
+	if (rename) {
+		ret = c1->rename(c1, new);
+		if (!ret) {
+			fprintf(stderr,
+				"Error: Renaming container %s to %s failed\n",
+				c1->name, new);
+			lxc_container_put(c1);
+			exit(EXIT_FAILURE);
+		}
+	} else {
+		c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize,
+			       args);
+		if (c2 == NULL) {
+			lxc_container_put(c1);
+			fprintf(stderr, "clone failed\n");
+			exit(EXIT_FAILURE);
+		}
+		printf("Created container %s as %s of %s\n", new,
+		       snapshot ? "snapshot" : "copy", orig);
+		lxc_container_put(c2);
+	}
+	lxc_container_put(c1);
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/src/lxc/tools/lxc_config.c b/src/lxc/tools/lxc_config.c
new file mode 100644
index 0000000..d146ad8
--- /dev/null
+++ b/src/lxc/tools/lxc_config.c
@@ -0,0 +1,81 @@
+/* lxc_config
+ *
+ * Copyright © 2012 Serge Hallyn <serge.hallyn at ubuntu.com>.
+ * Copyright © 2012 Canonical Ltd.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "config.h"
+
+struct lxc_config_items {
+	char *name;
+};
+
+static struct lxc_config_items items[] =
+{
+	{ .name = "lxc.default_config", },
+	{ .name = "lxc.lxcpath", },
+	{ .name = "lxc.bdev.lvm.vg", },
+	{ .name = "lxc.bdev.lvm.thin_pool", },
+	{ .name = "lxc.bdev.zfs.root", },
+	{ .name = "lxc.cgroup.use", },
+	{ .name = "lxc.cgroup.pattern", },
+	{ .name = NULL, },
+};
+
+static void usage(char *me)
+{
+	printf("Usage: %s -l: list all available configuration items\n", me);
+	printf("       %s item: print configuration item\n", me);
+	exit(1);
+}
+
+static void list_config_items(void)
+{
+	struct lxc_config_items *i;
+
+	for (i = &items[0]; i->name; i++)
+		printf("%s\n", i->name);
+	exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+	struct lxc_config_items *i;
+	const char *value;
+
+	if (argc < 2)
+		usage(argv[0]);
+	if (strcmp(argv[1], "-l") == 0)
+		list_config_items();
+	for (i = &items[0]; i->name; i++) {
+		if (strcmp(argv[1], i->name) == 0) {
+			value = lxc_get_global_config_item(i->name);
+			if (value)
+				printf("%s\n", value);
+			else
+				printf("%s is not set.\n", argv[1]);
+			exit(0);
+		}
+	}
+	printf("Unknown configuration item: %s\n", argv[1]);
+	exit(1);
+}
diff --git a/src/lxc/tools/lxc_console.c b/src/lxc/tools/lxc_console.c
new file mode 100644
index 0000000..adbd7e0
--- /dev/null
+++ b/src/lxc/tools/lxc_console.c
@@ -0,0 +1,134 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <libgen.h>
+#include <poll.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "error.h"
+#include "lxc.h"
+#include "log.h"
+#include "mainloop.h"
+#include "arguments.h"
+#include "commands.h"
+
+lxc_log_define(lxc_console_ui, lxc);
+
+static char etoc(const char *expr)
+{
+	/* returns "control code" of given expression */
+	char c = expr[0] == '^' ? expr[1] : expr[0];
+	return 1 + ((c > 'Z') ? (c - 'a') : (c - 'Z'));
+}
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	switch (c) {
+	case 't': args->ttynum = atoi(arg); break;
+	case 'e': args->escape = etoc(arg); break;
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	{"tty", required_argument, 0, 't'},
+	{"escape", required_argument, 0, 'e'},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-console",
+	.help     = "\
+--name=NAME [--tty NUMBER]\n\
+\n\
+lxc-console logs on the container with the identifier NAME\n\
+\n\
+Options :\n\
+  -n, --name=NAME      NAME of the container\n\
+  -t, --tty=NUMBER     console tty number\n\
+  -e, --escape=PREFIX  prefix for escape command\n",
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = NULL,
+	.ttynum = -1,
+	.escape = 1,
+};
+
+int main(int argc, char *argv[])
+{
+	int ret;
+	struct lxc_container *c;
+
+	ret = lxc_arguments_parse(&my_args, argc, argv);
+	if (ret)
+		return EXIT_FAILURE;
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	ret = lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			   my_args.progname, my_args.quiet, my_args.lxcpath[0]);
+	if (ret)
+		return EXIT_FAILURE;
+	lxc_log_options_no_override();
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		fprintf(stderr, "System error loading container\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (!c->may_control(c)) {
+		fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
+		lxc_container_put(c);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!c->is_running(c)) {
+		fprintf(stderr, "%s is not running\n", my_args.name);
+		lxc_container_put(c);
+		exit(EXIT_FAILURE);
+	}
+
+	ret = c->console(c, my_args.ttynum, 0, 1, 2, my_args.escape);
+	if (ret < 0) {
+		lxc_container_put(c);
+		exit(EXIT_FAILURE);
+	}
+	lxc_container_put(c);
+	return EXIT_SUCCESS;
+}
diff --git a/src/lxc/tools/lxc_copy.c b/src/lxc/tools/lxc_copy.c
new file mode 100644
index 0000000..9f653e3
--- /dev/null
+++ b/src/lxc/tools/lxc_copy.c
@@ -0,0 +1,877 @@
+/*
+ *
+ * Copyright © 2015 Christian Brauner <christian.brauner at mailbox.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+
+#include <unistd.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdbool.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "attach.h"
+#include "bdev.h"
+#include "log.h"
+#include "confile.h"
+#include "arguments.h"
+#include "lxc.h"
+#include "conf.h"
+#include "state.h"
+#include "utils.h"
+
+#ifndef HAVE_GETSUBOPT
+#include <../include/getsubopt.h>
+#endif
+
+lxc_log_define(lxc_copy_ui, lxc);
+
+enum mnttype {
+	LXC_MNT_BIND,
+	LXC_MNT_AUFS,
+	LXC_MNT_OVL,
+};
+
+struct mnts {
+	enum mnttype mnt_type;
+	char *src;
+	char *dest;
+	char *options;
+	char *upper;
+	char *workdir;
+	char *lower;
+};
+
+static unsigned int mnt_table_size = 0;
+static struct mnts *mnt_table = NULL;
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg);
+
+static const struct option my_longopts[] = {
+	{ "newname", required_argument, 0, 'N'},
+	{ "newpath", required_argument, 0, 'p'},
+	{ "rename", no_argument, 0, 'R'},
+	{ "snapshot", no_argument, 0, 's'},
+	{ "foreground", no_argument, 0, 'F'},
+	{ "daemon", no_argument, 0, 'd'},
+	{ "ephemeral", no_argument, 0, 'e'},
+	{ "mount", required_argument, 0, 'm'},
+	{ "backingstore", required_argument, 0, 'B'},
+	{ "fssize", required_argument, 0, 'L'},
+	{ "keepdata", no_argument, 0, 'D'},
+	{ "keepname", no_argument, 0, 'K'},
+	{ "keepmac", no_argument, 0, 'M'},
+	{ "tmpfs", no_argument, 0, 't'},
+	LXC_COMMON_OPTIONS
+};
+
+/* mount keys */
+static char *const keys[] = {
+	[LXC_MNT_BIND] = "bind",
+	[LXC_MNT_AUFS] = "aufs",
+	[LXC_MNT_OVL] = "overlay",
+	NULL
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-copy",
+	.help = "\n\
+--name=NAME [-P lxcpath] -N newname [-p newpath] [-B backingstorage] [-s] [-K] [-M] [-L size [unit]] -- hook options\n\
+--name=NAME [-P lxcpath] [-N newname] [-p newpath] [-B backingstorage] -e [-d] [-D] [-K] [-M] [-m {bind,aufs,overlay}=/src:/dest] -- hook options\n\
+--name=NAME [-P lxcpath] -N newname -R\n\
+\n\
+lxc-copy clone a container\n\
+\n\
+Options :\n\
+  -n, --name=NAME           NAME of the container\n\
+  -N, --newname=NEWNAME     NEWNAME for the restored container\n\
+  -p, --newpath=NEWPATH     NEWPATH for the container to be stored\n\
+  -R, --rename		    rename container\n\
+  -s, --snapshot	    create snapshot instead of clone\n\
+  -F, --foreground	    start with current tty attached to /dev/console\n\
+  -d, --daemon		    daemonize the container (default)\n\
+  -e, --ephemeral	    start ephemeral container\n\
+  -m, --mount	            directory to mount into container, either \n\
+			    {bind,aufs,overlay}=/src-path or {bind,aufs,overlay}=/src-path:/dst-path\n\
+  -B, --backingstorage=TYPE backingstorage type for the container\n\
+  -t, --tmpfs		    place ephemeral container on a tmpfs\n\
+			    (WARNING: On reboot all changes made to the container will be lost.)\n\
+  -L, --fssize		    size of the new block device for block device containers\n\
+  -D, --keedata	            pass together with -e start a persistent snapshot \n\
+  -K, --keepname	    keep the hostname of the original container\n\
+  --  hook options	    arguments passed to the hook program\n\
+  -M, --keepmac		    keep the MAC address of the original container\n",
+	.options = my_longopts,
+	.parser = my_parser,
+	.task = CLONE,
+	.daemonize = 1,
+	.quiet = false,
+	.tmpfs = false,
+};
+
+static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num,
+			    enum mnttype type);
+static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num,
+			    struct lxc_arguments *arg);
+static char *construct_path(char *path, bool as_prefix);
+static char *set_mnt_entry(struct mnts *m);
+static int do_clone(struct lxc_container *c, char *newname, char *newpath,
+		    int flags, char *bdevtype, uint64_t fssize, enum task task,
+		    char **args);
+static int do_clone_ephemeral(struct lxc_container *c,
+			      struct lxc_arguments *arg, char **args,
+			      int flags);
+static int do_clone_rename(struct lxc_container *c, char *newname);
+static int do_clone_task(struct lxc_container *c, enum task task, int flags,
+			 char **args);
+static void free_mnts(void);
+static uint64_t get_fssize(char *s);
+
+/* Place an ephemeral container started with -e flag on a tmpfs. Restrictions
+ * are that you cannot request the data to be kept while placing the container
+ * on a tmpfs and that either overlay or aufs backing storage must be used.
+ */
+static char *mount_tmpfs(const char *oldname, const char *newname,
+			 const char *path, struct lxc_arguments *arg);
+static int parse_mntsubopts(char *subopts, char *const *keys,
+			    char *mntparameters);
+static int parse_aufs_mnt(char *mntstring, enum mnttype type);
+static int parse_bind_mnt(char *mntstring, enum mnttype type);
+static int parse_ovl_mnt(char *mntstring, enum mnttype type);
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c;
+	int flags = 0;
+	int ret = EXIT_FAILURE;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		exit(ret);
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		exit(ret);
+	lxc_log_options_no_override();
+
+	if (geteuid()) {
+		if (access(my_args.lxcpath[0], O_RDWR) < 0) {
+			if (!my_args.quiet)
+				fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
+			exit(ret);
+		}
+	}
+
+	if (!my_args.newname && !(my_args.task == DESTROY)) {
+		if (!my_args.quiet)
+			printf("Error: You must provide a NEWNAME for the clone.\n");
+		exit(ret);
+	}
+
+	if (my_args.task == SNAP || my_args.task == DESTROY)
+		flags |= LXC_CLONE_SNAPSHOT;
+	if (my_args.keepname)
+		flags |= LXC_CLONE_KEEPNAME;
+	if (my_args.keepmac)
+		flags |= LXC_CLONE_KEEPMACADDR;
+
+	if (!my_args.newpath)
+		my_args.newpath = (char *)my_args.lxcpath[0];
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c)
+		exit(ret);
+
+	if (!c->may_control(c)) {
+		if (!my_args.quiet)
+			fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+		goto out;
+	}
+
+	if (!c->is_defined(c)) {
+		if (!my_args.quiet)
+			fprintf(stderr, "Error: container %s is not defined\n", c->name);
+		goto out;
+	}
+
+	ret = do_clone_task(c, my_args.task, flags, &argv[optind]);
+
+out:
+	lxc_container_put(c);
+
+	if (ret == 0)
+		exit(EXIT_SUCCESS);
+	exit(EXIT_FAILURE);
+}
+
+static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num, enum mnttype type)
+{
+	struct mnts *m, *n;
+
+	n = realloc(*mnts, (*num + 1) * sizeof(struct mnts));
+	if (!n)
+		return NULL;
+
+	*mnts = n;
+	m = *mnts + *num;
+	(*num)++;
+
+	*m = (struct mnts) {.mnt_type = type};
+
+	return m;
+}
+
+static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_arguments *arg)
+{
+	char upperdir[MAXPATHLEN];
+	char workdir[MAXPATHLEN];
+	unsigned int i;
+	int ret;
+	struct mnts *m = NULL;
+
+	for (i = 0, m = mnts; i < num; i++, m++) {
+		if ((m->mnt_type == LXC_MNT_OVL) || (m->mnt_type == LXC_MNT_AUFS)) {
+			ret = snprintf(upperdir, MAXPATHLEN, "%s/%s/delta#XXXXXX",
+					arg->newpath, arg->newname);
+			if (ret < 0 || ret >= MAXPATHLEN)
+				return -1;
+			if (!mkdtemp(upperdir))
+				return -1;
+			m->upper = strdup(upperdir);
+			if (!m->upper)
+				return -1;
+		}
+
+		if (m->mnt_type == LXC_MNT_OVL) {
+			ret = snprintf(workdir, MAXPATHLEN, "%s/%s/work#XXXXXX",
+					arg->newpath, arg->newname);
+			if (ret < 0 || ret >= MAXPATHLEN)
+				return -1;
+			if (!mkdtemp(workdir))
+				return -1;
+			m->workdir = strdup(workdir);
+			if (!m->workdir)
+				return -1;
+		}
+	}
+
+	return 0;
+}
+
+static char *construct_path(char *path, bool as_prefix)
+{
+	char **components = NULL;
+	char *cleanpath = NULL;
+
+	components = lxc_normalize_path(path);
+	if (!components)
+		return NULL;
+
+	cleanpath = lxc_string_join("/", (const char **)components, as_prefix);
+	lxc_free_array((void **)components, free);
+
+	return cleanpath;
+}
+
+static char *set_mnt_entry(struct mnts *m)
+{
+	char *mntentry = NULL;
+	int ret = 0;
+	size_t len = 0;
+
+	if (m->mnt_type == LXC_MNT_AUFS) {
+		len = strlen("  aufs br==rw:=ro,xino=,create=dir") +
+		      2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
+		      strlen(m->workdir) + 1;
+
+		mntentry = malloc(len);
+		if (!mntentry)
+			goto err;
+
+		ret = snprintf(mntentry, len, "%s %s aufs br=%s=rw:%s=ro,xino=%s,create=dir",
+			       m->src, m->dest, m->upper, m->src, m->workdir);
+		if (ret < 0 || (size_t)ret >= len)
+			goto err;
+	} else if (m->mnt_type == LXC_MNT_OVL) {
+		len = strlen("  overlay lowerdir=,upperdir=,workdir=,create=dir") +
+		      2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
+		      strlen(m->workdir) + 1;
+
+		mntentry = malloc(len);
+		if (!mntentry)
+			goto err;
+
+		ret = snprintf(mntentry, len, "%s %s overlay lowerdir=%s,upperdir=%s,workdir=%s,create=dir",
+				m->src, m->dest, m->src, m->upper, m->workdir);
+		if (ret < 0 || (size_t)ret >= len)
+			goto err;
+	} else if (m->mnt_type == LXC_MNT_BIND) {
+		len = strlen("  none bind,optional,, 0 0") +
+		      strlen(is_dir(m->src) ? "create=dir" : "create=file") +
+		      strlen(m->src) + strlen(m->dest) + strlen(m->options) + 1;
+
+		mntentry = malloc(len);
+		if (!mntentry)
+			goto err;
+
+		ret = snprintf(mntentry, len, "%s %s none bind,optional,%s,%s 0 0",
+				m->src,	m->dest, m->options,
+				is_dir(m->src) ? "create=dir" : "create=file");
+		if (ret < 0 || (size_t)ret >= len)
+			goto err;
+	}
+
+	return mntentry;
+
+err:
+	free(mntentry);
+	return NULL;
+}
+
+static int do_clone(struct lxc_container *c, char *newname, char *newpath,
+		    int flags, char *bdevtype, uint64_t fssize, enum task task,
+		    char **args)
+{
+	struct lxc_container *clone;
+
+	clone = c->clone(c, newname, newpath, flags, bdevtype, NULL, fssize,
+			 args);
+	if (!clone) {
+		if (!my_args.quiet)
+			fprintf(stderr, "clone failed\n");
+		return -1;
+	}
+
+	INFO("Created %s as %s of %s\n", newname, task ? "snapshot" : "copy", c->name);
+
+	lxc_container_put(clone);
+
+	return 0;
+}
+
+static int do_clone_ephemeral(struct lxc_container *c,
+		struct lxc_arguments *arg, char **args, int flags)
+{
+	char *bdev;
+	char *premount;
+	char randname[MAXPATHLEN];
+	unsigned int i;
+	int ret = 0;
+	bool bret = true, started = false;
+	struct lxc_container *clone;
+	lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
+	attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
+
+	if (!arg->newname) {
+		ret = snprintf(randname, MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name);
+		if (ret < 0 || ret >= MAXPATHLEN)
+			return -1;
+		if (!mkdtemp(randname))
+			return -1;
+		if (chmod(randname, 0770) < 0) {
+			remove(randname);
+			return -1;
+		}
+		arg->newname = randname + strlen(arg->newpath) + 1;
+	}
+
+	clone = c->clone(c, arg->newname, arg->newpath, flags,
+			 arg->bdevtype, NULL, arg->fssize, args);
+	if (!clone)
+		return -1;
+
+	if (arg->tmpfs) {
+		bdev = c->lxc_conf->rootfs.bdev_type;
+		if (bdev && strcmp(bdev, "dir")) {
+			fprintf(stderr, "Cannot currently use tmpfs with %s storage backend.\n", bdev);
+			goto destroy_and_put;
+		}
+
+		premount = mount_tmpfs(arg->name, arg->newname, arg->newpath, arg);
+		if (!premount)
+			goto destroy_and_put;
+
+		bret = clone->set_config_item(clone, "lxc.hook.pre-mount", premount);
+		free(premount);
+		if (!bret)
+			goto destroy_and_put;
+	}
+
+	if (!arg->keepdata)
+		if (!clone->set_config_item(clone, "lxc.ephemeral", "1"))
+			goto destroy_and_put;
+
+	/* allocate and create random upper- and workdirs for overlay mounts */
+	if (mk_rand_ovl_dirs(mnt_table, mnt_table_size, arg) < 0)
+		goto destroy_and_put;
+
+	/* allocate and set mount entries */
+	struct mnts *n = NULL;
+	for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
+		char *mntentry = NULL;
+		mntentry = set_mnt_entry(n);
+		if (!mntentry)
+			goto destroy_and_put;
+		bret = clone->set_config_item(clone, "lxc.mount.entry", mntentry);
+		free(mntentry);
+		if (!bret)
+			goto destroy_and_put;
+	}
+
+	if (!clone->save_config(clone, NULL))
+		goto destroy_and_put;
+
+	if (!my_args.quiet)
+		printf("Created %s as clone of %s\n", arg->newname, arg->name);
+
+	if (arg->tmpfs && !my_args.quiet)
+		printf("Container is placed on tmpfs.\nRebooting will cause "
+		       "all changes made to it to be lost!");
+
+	if (!arg->daemonize && arg->argc) {
+		clone->want_daemonize(clone, true);
+		arg->daemonize = 1;
+	} else if (!arg->daemonize) {
+		clone->want_daemonize(clone, false);
+	}
+
+	started = clone->start(clone, 0, NULL);
+	if (!started)
+		goto destroy_and_put;
+
+	if (arg->daemonize && arg->argc) {
+		ret = clone->attach_run_wait(clone, &attach_options, arg->argv[0], (const char *const *)arg->argv);
+		if (ret < 0)
+			goto destroy_and_put;
+		clone->shutdown(clone, -1);
+	}
+
+	free_mnts();
+	lxc_container_put(clone);
+	return 0;
+
+destroy_and_put:
+	if (started)
+		clone->shutdown(clone, -1);
+	if (!started || clone->lxc_conf->ephemeral != 1)
+		clone->destroy(clone);
+	free_mnts();
+	lxc_container_put(clone);
+	return -1;
+}
+
+static int do_clone_rename(struct lxc_container *c, char *newname)
+{
+	if (!c->rename(c, newname)) {
+		ERROR("Error: Renaming container %s to %s failed\n", c->name, newname);
+		return -1;
+	}
+
+	INFO("Renamed container %s to %s\n", c->name, newname);
+
+	return 0;
+}
+
+static int do_clone_task(struct lxc_container *c, enum task task, int flags,
+			 char **args)
+{
+	int ret = 0;
+
+	switch (task) {
+	case DESTROY:
+		ret = do_clone_ephemeral(c, &my_args, args, flags);
+		break;
+	case RENAME:
+		ret = do_clone_rename(c, my_args.newname);
+		break;
+	default:
+		ret = do_clone(c, my_args.newname, my_args.newpath, flags,
+			       my_args.bdevtype, my_args.fssize, my_args.task,
+			       args);
+		break;
+	}
+
+	return ret;
+}
+
+static void free_mnts()
+{
+	unsigned int i;
+	struct mnts *n = NULL;
+
+	for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
+		free(n->src);
+		free(n->dest);
+		free(n->options);
+		free(n->upper);
+		free(n->workdir);
+	}
+	free(mnt_table);
+	mnt_table = NULL;
+	mnt_table_size = 0;
+}
+
+/* we pass fssize in bytes */
+static uint64_t get_fssize(char *s)
+{
+	uint64_t ret;
+	char *end;
+
+	ret = strtoull(s, &end, 0);
+	if (end == s) {
+		if (!my_args.quiet)
+			fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
+		return 0;
+	}
+	while (isblank(*end))
+		end++;
+	if (*end == '\0') {
+		ret *= 1024ULL * 1024ULL; // MB by default
+	} else if (*end == 'b' || *end == 'B') {
+		ret *= 1ULL;
+	} else if (*end == 'k' || *end == 'K') {
+		ret *= 1024ULL;
+	} else if (*end == 'm' || *end == 'M') {
+		ret *= 1024ULL * 1024ULL;
+	} else if (*end == 'g' || *end == 'G') {
+		ret *= 1024ULL * 1024ULL * 1024ULL;
+	} else if (*end == 't' || *end == 'T') {
+		ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
+	} else {
+		if (!my_args.quiet)
+			fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', " "using default size\n", *end, s);
+		return 0;
+	}
+
+	return ret;
+}
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg)
+{
+	char *subopts = NULL;
+	char *mntparameters = NULL;
+	switch (c) {
+	case 'N':
+		args->newname = arg;
+		break;
+	case 'p':
+		args->newpath = arg;
+		break;
+	case 'R':
+		args->task = RENAME;
+		break;
+	case 's':
+		args->task = SNAP;
+		break;
+	case 'F':
+		args->daemonize = 0;
+		break;
+	case 'd':
+		args->daemonize = 1;
+		break;
+	case 'e':
+		args->task = DESTROY;
+		break;
+	case 'm':
+		subopts = optarg;
+		if (parse_mntsubopts(subopts, keys, mntparameters) < 0)
+			return -1;
+		break;
+	case 'B':
+		args->bdevtype = arg;
+		break;
+	case 't':
+		args->tmpfs = true;
+		break;
+	case 'L':
+		args->fssize = get_fssize(optarg);
+		break;
+	case 'D':
+		args->keepdata = 1;
+		break;
+	case 'K':
+		args->keepname = 1;
+		break;
+	case 'M':
+		args->keepmac = 1;
+		break;
+	}
+
+	return 0;
+}
+
+static int parse_aufs_mnt(char *mntstring, enum mnttype type)
+{
+	int len = 0;
+	const char *xinopath = "/dev/shm/aufs.xino";
+	char **mntarray = NULL;
+	struct mnts *m = NULL;
+
+	m = add_mnt(&mnt_table, &mnt_table_size, type);
+	if (!m)
+		goto err;
+
+	mntarray = lxc_string_split(mntstring, ':');
+	if (!mntarray)
+		goto err;
+
+	m->src = construct_path(mntarray[0], true);
+	if (!m->src)
+		goto err;
+
+	len = lxc_array_len((void **)mntarray);
+	if (len == 1) /* aufs=src */
+		m->dest = construct_path(mntarray[0], false);
+	else if (len == 2) /* aufs=src:dest */
+		m->dest = construct_path(mntarray[1], false);
+	else
+		INFO("Excess elements in mount specification");
+
+	if (!m->dest)
+		goto err;
+
+	m->workdir = strdup(xinopath);
+	if (!m->workdir)
+		goto err;
+
+	lxc_free_array((void **)mntarray, free);
+	return 0;
+
+err:
+	free_mnts();
+	lxc_free_array((void **)mntarray, free);
+	return -1;
+}
+
+static int parse_bind_mnt(char *mntstring, enum mnttype type)
+{
+	int len = 0;
+	char **mntarray = NULL;
+	struct mnts *m = NULL;
+
+	m = add_mnt(&mnt_table, &mnt_table_size, type);
+	if (!m)
+		goto err;
+
+	mntarray = lxc_string_split(mntstring, ':');
+	if (!mntarray)
+		goto err;
+
+	m->src = construct_path(mntarray[0], true);
+	if (!m->src)
+		goto err;
+
+	len = lxc_array_len((void **)mntarray);
+	if (len == 1) { /* bind=src */
+		m->dest = construct_path(mntarray[0], false);
+	} else if (len == 2) { /* bind=src:option or bind=src:dest */
+		if (strncmp(mntarray[1], "rw", strlen(mntarray[1])) == 0)
+			m->options = strdup("rw");
+
+		if (strncmp(mntarray[1], "ro", strlen(mntarray[1])) == 0)
+			m->options = strdup("ro");
+
+		if (m->options)
+			m->dest = construct_path(mntarray[0], false);
+		else
+			m->dest = construct_path(mntarray[1], false);
+	} else if (len == 3) { /* bind=src:dest:option */
+			m->dest = construct_path(mntarray[1], false);
+			m->options = strdup(mntarray[2]);
+	} else {
+		INFO("Excess elements in mount specification");
+	}
+
+	if (!m->dest)
+		goto err;
+
+	if (!m->options)
+		m->options = strdup("rw");
+
+	if (!m->options || (strncmp(m->options, "rw", strlen(m->options)) &&
+			    strncmp(m->options, "ro", strlen(m->options))))
+		goto err;
+
+	lxc_free_array((void **)mntarray, free);
+	return 0;
+
+err:
+	free_mnts();
+	lxc_free_array((void **)mntarray, free);
+	return -1;
+}
+
+static int parse_mntsubopts(char *subopts, char *const *keys, char *mntparameters)
+{
+	while (*subopts != '\0') {
+		switch (getsubopt(&subopts, keys, &mntparameters)) {
+		case LXC_MNT_BIND:
+			if (parse_bind_mnt(mntparameters, LXC_MNT_BIND) < 0)
+				return -1;
+			break;
+		case LXC_MNT_OVL:
+			if (parse_ovl_mnt(mntparameters, LXC_MNT_OVL) < 0)
+				return -1;
+			break;
+		case LXC_MNT_AUFS:
+			if (parse_aufs_mnt(mntparameters, LXC_MNT_AUFS) < 0)
+				return -1;
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+static int parse_ovl_mnt(char *mntstring, enum mnttype type)
+{
+	int len = 0;
+	char **mntarray = NULL;
+	struct mnts *m;
+
+	m = add_mnt(&mnt_table, &mnt_table_size, type);
+	if (!m)
+		goto err;
+
+	mntarray = lxc_string_split(mntstring, ':');
+	if (!mntarray)
+		goto err;
+
+	m->src = construct_path(mntarray[0], true);
+	if (!m->src)
+		goto err;
+
+	len = lxc_array_len((void **)mntarray);
+	if (len == 1) /* overlay=src */
+		m->dest = construct_path(mntarray[0], false);
+	else if (len == 2) /* overlay=src:dest */
+		m->dest = construct_path(mntarray[1], false);
+	else
+		INFO("Excess elements in mount specification");
+
+	if (!m->dest)
+		goto err;
+
+	lxc_free_array((void **)mntarray, free);
+	return 0;
+
+err:
+	free_mnts();
+	lxc_free_array((void **)mntarray, free);
+	return -1;
+}
+
+/* For ephemeral snapshots backed by overlay or aufs filesystems, this function
+ * mounts a fresh tmpfs over the containers directory if the user requests it.
+ * Because we mount a fresh tmpfs over the directory of the container the
+ * updated /etc/hostname file created during the clone residing in the upperdir
+ * (currently named "delta0" by default) will be hidden. Hence, if the user
+ * requests that the old name is not to be kept for the clone, we recreate this
+ * file on the tmpfs. This should be all that is required to restore the exact
+ * behaviour we would get with a normal clone.
+ */
+static char *mount_tmpfs(const char *oldname, const char *newname,
+			 const char *path, struct lxc_arguments *arg)
+{
+	int ret, fd;
+	size_t len;
+	char *premount = NULL;
+	FILE *fp;
+
+	if (arg->tmpfs && arg->keepdata) {
+		fprintf(stderr, "%s\n", "A container can only be placed on a "
+					"tmpfs when storage backend is overlay "
+					"or aufs.");
+		goto err_free;
+	}
+
+	if (arg->tmpfs && !arg->bdevtype) {
+		arg->bdevtype = "overlayfs";
+	} else if (arg->tmpfs && arg->bdevtype && strcmp(arg->bdevtype, "overlayfs") && strcmp(arg->bdevtype, "aufs")) {
+		fprintf(stderr, "%s\n", "A container can only be placed on a "
+					"tmpfs when storage backend is overlay "
+					"or aufs.");
+		goto err_free;
+	}
+
+	len = strlen(path) + strlen(newname) + strlen("pre-start-XXXXXX") + /* //\0 */ 3;
+	premount = malloc(len);
+	if (!premount)
+		goto err_free;
+
+	ret = snprintf(premount, len, "%s/%s/pre-start-XXXXXX", path, newname);
+	if (ret < 0 || (size_t)ret >= len)
+		goto err_free;
+
+	fd = mkstemp(premount);
+	if (fd < 0)
+		goto err_free;
+
+	if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
+		SYSERROR("Failed to set close-on-exec on file descriptor.");
+		goto err_close;
+	}
+
+	if (chmod(premount, 0755) < 0)
+		goto err_close;
+
+	fp = fdopen(fd, "r+");
+	if (!fp)
+		goto err_close;
+	fd = -1;
+
+	ret = fprintf(fp, "#! /bin/sh\n"
+			  "mount -n -t tmpfs -o mode=0755 none %s/%s\n",
+		      path, newname);
+	if (ret < 0)
+		goto err_close;
+
+	if (!arg->keepname) {
+		ret = fprintf(fp, "mkdir -p %s/%s/delta0/etc\n"
+				  "echo %s > %s/%s/delta0/etc/hostname\n",
+			      path, newname, newname, path, newname);
+		if (ret < 0)
+			goto err_close;
+	}
+
+	close(fd);
+	return premount;
+
+err_close:
+	if (fd > 0)
+		close(fd);
+	else
+		fclose(fp);
+err_free:
+	free(premount);
+	return NULL;
+}
diff --git a/src/lxc/tools/lxc_create.c b/src/lxc/tools/lxc_create.c
new file mode 100644
index 0000000..4b0e9d7
--- /dev/null
+++ b/src/lxc/tools/lxc_create.c
@@ -0,0 +1,326 @@
+/*
+ *
+ * Copyright © 2013 Serge Hallyn <serge.hallyn at ubuntu.com>.
+ * Copyright © 2013 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <lxc/lxccontainer.h>
+#include <sys/types.h>
+
+#include "arguments.h"
+#include "bdev.h"
+#include "log.h"
+#include "lxc.h"
+#include "utils.h"
+
+lxc_log_define(lxc_create_ui, lxc);
+
+static uint64_t get_fssize(char *s)
+{
+	uint64_t ret;
+	char *end;
+
+	ret = strtoull(s, &end, 0);
+	if (end == s)
+	{
+		fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
+		return 0;
+	}
+	while (isblank(*end))
+		end++;
+	if (*end == '\0')
+		ret *= 1024ULL * 1024ULL; // MB by default
+	else if (*end == 'b' || *end == 'B')
+		ret *= 1ULL;
+	else if (*end == 'k' || *end == 'K')
+		ret *= 1024ULL;
+	else if (*end == 'm' || *end == 'M')
+		ret *= 1024ULL * 1024ULL;
+	else if (*end == 'g' || *end == 'G')
+		ret *= 1024ULL * 1024ULL * 1024ULL;
+	else if (*end == 't' || *end == 'T')
+		ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
+	else
+	{
+		fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s);
+		return 0;
+	}
+	return ret;
+}
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	switch (c) {
+	case 'B': args->bdevtype = arg; break;
+	case 'f': args->configfile = arg; break;
+	case 't': args->template = arg; break;
+	case '0': args->lvname = arg; break;
+	case '1': args->vgname = arg; break;
+	case '2': args->thinpool = arg; break;
+	case '3': args->fstype = arg; break;
+	case '4': args->fssize = get_fssize(arg); break;
+	case '5': args->zfsroot = arg; break;
+	case '6': args->dir = arg; break;
+	case '7': args->rbdname = arg; break;
+	case '8': args->rbdpool = arg; break;
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	{"bdev", required_argument, 0, 'B'},
+	{"config", required_argument, 0, 'f'},
+	{"template", required_argument, 0, 't'},
+	{"lvname", required_argument, 0, '0'},
+	{"vgname", required_argument, 0, '1'},
+	{"thinpool", required_argument, 0, '2'},
+	{"fstype", required_argument, 0, '3'},
+	{"fssize", required_argument, 0, '4'},
+	{"zfsroot", required_argument, 0, '5'},
+	{"dir", required_argument, 0, '6'},
+	{"rbdname", required_argument, 0, '7'},
+	{"rbdpool", required_argument, 0, '8'},
+	LXC_COMMON_OPTIONS
+};
+
+static void create_helpfn(const struct lxc_arguments *args)
+{
+	char *argv[3], *path;
+	pid_t pid;
+
+	if (!args->template)
+		return;
+
+	pid = fork();
+	if (pid) {
+		wait_for_pid(pid);
+		return;
+	}
+
+	path = get_template_path(args->template);
+
+	argv[0] = path;
+	argv[1] = "-h";
+	argv[2] = NULL;
+
+	execv(path, argv);
+	ERROR("Error executing %s -h", path);
+	exit(EXIT_FAILURE);
+}
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-create",
+	.helpfn   = create_helpfn,
+	.help     = "\
+--name=NAME --template=TEMPLATE [OPTION...]\n\
+\n\
+lxc-create creates a container\n\
+\n\
+Options :\n\
+  -n, --name=NAME               NAME of the container\n\
+  -f, --config=CONFIG           Initial configuration file\n\
+  -t, --template=TEMPLATE       Template to use to setup container\n\
+  -B, --bdev=BDEV               Backing store type to use\n\
+      --dir=DIR                 Place rootfs directory under DIR\n\
+\n\
+  BDEV options for LVM (with -B/--bdev lvm):\n\
+      --lvname=LVNAME           Use LVM lv name LVNAME\n\
+                                (Default: container name)\n\
+      --vgname=VG               Use LVM vg called VG\n\
+                                (Default: lxc)\n\
+      --thinpool=TP             Use LVM thin pool called TP\n\
+                                (Default: lxc)\n\
+\n\
+  BDEV options for Ceph RBD (with -B/--bdev rbd) :\n\
+      --rbdname=RBDNAME         Use Ceph RBD name RBDNAME\n\
+                                (Default: container name)\n\
+      --rbdpool=POOL            Use Ceph RBD pool name POOL\n\
+                                (Default: lxc)\n\
+\n\
+  BDEV option for ZFS (with -B/--bdev zfs) :\n\
+      --zfsroot=PATH            Create zfs under given zfsroot\n\
+                                (Default: tank/lxc)\n\
+\n\
+  BDEV options for LVM or Loop (with -B/--bdev lvm/loop) :\n\
+      --fstype=TYPE             Create fstype TYPE\n\
+                                (Default: ext3)\n\
+      --fssize=SIZE[U]          Create filesystem of\n\
+                                size SIZE * unit U (bBkKmMgGtT)\n\
+                                (Default: 1G, default unit: M)\n",
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = NULL,
+};
+
+static bool validate_bdev_args(struct lxc_arguments *a)
+{
+	if (strcmp(a->bdevtype, "best") != 0) {
+		if (a->fstype || a->fssize) {
+			if (strcmp(a->bdevtype, "lvm") != 0 &&
+			    strcmp(a->bdevtype, "loop") != 0 &&
+			    strcmp(a->bdevtype, "rbd") != 0) {
+				fprintf(stderr, "filesystem type and size are only valid with block devices\n");
+				return false;
+			}
+		}
+		if (strcmp(a->bdevtype, "lvm") != 0) {
+			if (a->lvname || a->vgname || a->thinpool) {
+				fprintf(stderr, "--lvname, --vgname and --thinpool are only valid with -B lvm\n");
+				return false;
+			}
+		}
+		if (strcmp(a->bdevtype, "rbd") != 0) {
+			if (a->rbdname || a->rbdpool) {
+				fprintf(stderr, "--rbdname and --rbdpool are only valid with -B rbd\n");
+				return false;
+			}
+		}
+		if (strcmp(a->bdevtype, "zfs") != 0) {
+			if (a->zfsroot) {
+				fprintf(stderr, "zfsroot is only valid with -B zfs\n");
+				return false;
+			}
+		}
+	}
+	return true;
+}
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c;
+	struct bdev_specs spec;
+	int flags = 0;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		exit(EXIT_FAILURE);
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		exit(EXIT_FAILURE);
+	lxc_log_options_no_override();
+
+	if (!my_args.template) {
+		fprintf(stderr, "A template must be specified.\n");
+		fprintf(stderr, "Use \"none\" if you really want a container without a rootfs.\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (strcmp(my_args.template, "none") == 0)
+		my_args.template = NULL;
+
+	memset(&spec, 0, sizeof(spec));
+	if (!my_args.bdevtype)
+		my_args.bdevtype = "_unset";
+
+	if (!validate_bdev_args(&my_args))
+		exit(EXIT_FAILURE);
+
+	if (strcmp(my_args.bdevtype, "none") == 0)
+		my_args.bdevtype = "dir";
+
+	// Final check whether the user gave use a valid bdev type.
+	if (strcmp(my_args.bdevtype, "best") &&
+	    strcmp(my_args.bdevtype, "_unset") &&
+	    !is_valid_bdev_type(my_args.bdevtype)) {
+		fprintf(stderr, "%s is not a valid backing storage type.\n", my_args.bdevtype);
+		exit(EXIT_FAILURE);
+	}
+
+	if (geteuid()) {
+		if (mkdir_p(my_args.lxcpath[0], 0755)) {
+			exit(EXIT_FAILURE);
+		}
+		if (access(my_args.lxcpath[0], O_RDWR) < 0) {
+			fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
+			exit(EXIT_FAILURE);
+		}
+		if (strcmp(my_args.bdevtype, "dir") && strcmp(my_args.bdevtype, "_unset") &&
+				strcmp(my_args.bdevtype, "btrfs")) {
+			fprintf(stderr, "Unprivileged users cannot create %s containers", my_args.bdevtype);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		fprintf(stderr, "Failed to create lxc container.\n");
+		exit(EXIT_FAILURE);
+	}
+	if (c->is_defined(c)) {
+		lxc_container_put(c);
+		fprintf(stderr, "Container already exists\n");
+		exit(EXIT_FAILURE);
+	}
+	if (my_args.configfile)
+		c->load_config(c, my_args.configfile);
+	else
+		c->load_config(c, lxc_global_config_value("lxc.default_config"));
+
+	if (my_args.fstype)
+		spec.fstype = my_args.fstype;
+	if (my_args.fssize)
+		spec.fssize = my_args.fssize;
+
+	if ((strcmp(my_args.bdevtype, "zfs") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
+		if (my_args.zfsroot)
+			spec.zfs.zfsroot = my_args.zfsroot;
+	}
+
+	if ((strcmp(my_args.bdevtype, "lvm") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
+		if (my_args.lvname)
+			spec.lvm.lv = my_args.lvname;
+		if (my_args.vgname)
+			spec.lvm.vg = my_args.vgname;
+		if (my_args.thinpool)
+			spec.lvm.thinpool = my_args.thinpool;
+	}
+
+	if ((strcmp(my_args.bdevtype, "rbd") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
+		if (my_args.rbdname)
+			spec.rbd.rbdname = my_args.rbdname;
+		if (my_args.rbdpool)
+			spec.rbd.rbdpool = my_args.rbdpool;
+	}
+
+	if (my_args.dir)
+		spec.dir = my_args.dir;
+
+	if (strcmp(my_args.bdevtype, "_unset") == 0)
+		my_args.bdevtype = NULL;
+
+	if (my_args.quiet)
+		flags = LXC_CREATE_QUIET;
+
+	if (!c->create(c, my_args.template, my_args.bdevtype, &spec, flags, &argv[optind])) {
+		ERROR("Error creating container %s", c->name);
+		lxc_container_put(c);
+		exit(EXIT_FAILURE);
+	}
+
+	lxc_container_put(c);
+	INFO("container %s created", c->name);
+	exit(EXIT_SUCCESS);
+}
diff --git a/src/lxc/tools/lxc_destroy.c b/src/lxc/tools/lxc_destroy.c
new file mode 100644
index 0000000..b521739
--- /dev/null
+++ b/src/lxc/tools/lxc_destroy.c
@@ -0,0 +1,258 @@
+/*
+ *
+ * Copyright © 2013 Serge Hallyn <serge.hallyn at ubuntu.com>.
+ * Copyright © 2013 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+
+#include <libgen.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "arguments.h"
+#include "log.h"
+#include "lxc.h"
+#include "utils.h"
+
+lxc_log_define(lxc_destroy_ui, lxc);
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg);
+static bool quiet;
+
+static const struct option my_longopts[] = {
+	{"force", no_argument, 0, 'f'},
+	{"snapshots", no_argument, 0, 's'},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-destroy",
+	.help     = "\
+--name=NAME [-f] [-P lxcpath]\n\
+\n\
+lxc-destroy destroys a container with the identifier NAME\n\
+\n\
+Options :\n\
+  -n, --name=NAME   NAME of the container\n\
+  -s, --snapshots   destroy including all snapshots\n\
+  -f, --force       wait for the container to shut down\n",
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = NULL,
+	.task     = DESTROY,
+};
+
+static bool do_destroy(struct lxc_container *c);
+static bool do_destroy_with_snapshots(struct lxc_container *c);
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c;
+	bool bret;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		exit(EXIT_FAILURE);
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		exit(EXIT_FAILURE);
+	lxc_log_options_no_override();
+	if (my_args.quiet)
+		quiet = true;
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		if (!quiet)
+			fprintf(stderr, "System error loading container\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (!c->may_control(c)) {
+		if (!quiet)
+			fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name);
+		lxc_container_put(c);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!c->is_defined(c)) {
+		if (!quiet)
+			fprintf(stderr, "Container is not defined\n");
+		lxc_container_put(c);
+		exit(EXIT_FAILURE);
+	}
+
+	if (my_args.task == SNAP) {
+		bret = do_destroy_with_snapshots(c);
+		if (bret && !quiet)
+			printf("Destroyed container %s including snapshots \n", my_args.name);
+	} else {
+		bret = do_destroy(c);
+		if (bret && !quiet)
+			printf("Destroyed container %s\n", my_args.name);
+	}
+
+	lxc_container_put(c);
+
+	if (bret)
+		exit(EXIT_SUCCESS);
+	exit(EXIT_FAILURE);
+}
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg)
+{
+	switch (c) {
+	case 'f': args->force = 1; break;
+	case 's': args->task = SNAP; break;
+	}
+	return 0;
+}
+
+static bool do_destroy(struct lxc_container *c)
+{
+	bool bret = true;
+	char path[MAXPATHLEN];
+
+	/* First check whether the container has dependent clones or snapshots. */
+	int ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
+	if (ret < 0 || ret >= MAXPATHLEN)
+		return false;
+
+	if (file_exists(path)) {
+		if (!quiet)
+			fprintf(stdout, "Destroying %s failed: %s has clones.\n", c->name, c->name);
+		return false;
+	}
+
+	ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
+	if (ret < 0 || ret >= MAXPATHLEN)
+		return false;
+
+	if (dir_exists(path)) {
+		if (!quiet)
+			fprintf(stdout, "Destroying %s failed: %s has snapshots.\n", c->name, c->name);
+		return false;
+	}
+
+	if (c->is_running(c)) {
+		if (!my_args.force && !quiet) {
+			fprintf(stderr, "%s is running\n", my_args.name);
+			return false;
+		}
+		/* If the container was ephemeral it will be removed on shutdown. */
+		c->stop(c);
+	}
+
+	/* If the container was ephemeral we have already removed it when we
+	 * stopped it. */
+	if (c->is_defined(c) && !c->lxc_conf->ephemeral)
+		bret = c->destroy(c);
+
+	if (!bret) {
+		if (!quiet)
+			fprintf(stderr, "Destroying %s failed\n", my_args.name);
+		return false;
+	}
+
+	return true;
+}
+
+static bool do_destroy_with_snapshots(struct lxc_container *c)
+{
+	struct lxc_container *c1;
+	struct stat fbuf;
+	bool bret = false;
+	char path[MAXPATHLEN];
+	char *buf = NULL;
+	char *lxcpath = NULL;
+	char *lxcname = NULL;
+	char *scratch = NULL;
+	int fd;
+	int ret;
+	int counter = 0;
+
+	/* Destroy clones. */
+	ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
+	if (ret < 0 || ret >= MAXPATHLEN)
+		return false;
+
+	fd = open(path, O_RDONLY | O_CLOEXEC);
+	if (fd >= 0) {
+		ret = fstat(fd, &fbuf);
+		if (ret < 0) {
+			close(fd);
+			return false;
+		}
+
+		/* Make sure that the string is \0 terminated. */
+		buf = calloc(fbuf.st_size + 1, sizeof(char));
+		if (!buf) {
+			SYSERROR("failed to allocate memory");
+			close(fd);
+			return false;
+		}
+
+		ret = read(fd, buf, fbuf.st_size);
+		if (ret < 0) {
+			ERROR("could not read %s", path);
+			close(fd);
+			free(buf);
+			return false;
+		}
+		close(fd);
+
+		while ((lxcpath = strtok_r(!counter ? buf : NULL, "\n", &scratch))) {
+			if (!(lxcname = strtok_r(NULL, "\n", &scratch)))
+				break;
+			c1 = lxc_container_new(lxcname, lxcpath);
+			if (!c1) {
+				counter++;
+				continue;
+			}
+			/* We do not destroy recursively. If a clone of a clone
+			 * has clones or snapshots the user should remove it
+			 * explicitly. */
+			if (!do_destroy(c1)) {
+				lxc_container_put(c1);
+				free(buf);
+				return false;
+			}
+			lxc_container_put(c1);
+			counter++;
+		}
+		free(buf);
+	}
+
+	/* Destroy snapshots located in the containers snap/ folder. */
+	ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
+	if (ret < 0 || ret >= MAXPATHLEN)
+		return false;
+
+	if (dir_exists(path))
+		bret = c->destroy_with_snapshots(c);
+	else
+		bret = do_destroy(c);
+
+	return bret;
+}
+
diff --git a/src/lxc/tools/lxc_device.c b/src/lxc/tools/lxc_device.c
new file mode 100644
index 0000000..0c9e066
--- /dev/null
+++ b/src/lxc/tools/lxc_device.c
@@ -0,0 +1,178 @@
+/*
+ * lxc: linux Container library
+ *
+ * Authors:
+ * Dongsheng Yang <yangds.fnst at cn.fujitsu.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <libgen.h>
+#include <string.h>
+#include <limits.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "utils.h"
+#include "lxc.h"
+#include "log.h"
+
+#include "arguments.h"
+
+#if HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#else
+#include <../include/ifaddrs.h>
+#endif
+
+lxc_log_define(lxc_device, lxc);
+
+static const struct option my_longopts[] = {
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-device",
+	.help     = "\
+--name=NAME -- add|del DEV\n\
+\n\
+lxc-device attach or detach DEV to or from container.\n\
+\n\
+Options :\n\
+  -n, --name=NAME      NAME of the container",
+	.options  = my_longopts,
+	.parser   = NULL,
+	.checker  = NULL,
+};
+
+static bool is_interface(const char* dev_name, pid_t pid)
+{
+	pid_t p = fork();
+
+	if (p < 0) {
+		SYSERROR("failed to fork task.");
+		exit(1);
+	}
+
+	if (p == 0) {
+		struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
+
+		if (!switch_to_ns(pid, "net")) {
+			ERROR("failed to enter netns of container.");
+			exit(-1);
+		}
+
+		/* Grab the list of interfaces */
+		if (getifaddrs(&interfaceArray)) {
+			ERROR("failed to get interfaces list");
+			exit(-1);
+		}
+
+		/* Iterate through the interfaces */
+		for (tempIfAddr = interfaceArray; tempIfAddr != NULL; tempIfAddr = tempIfAddr->ifa_next) {
+			if (strcmp(tempIfAddr->ifa_name, dev_name) == 0) {
+				exit(0);
+			}
+		}
+		exit(1);
+	}
+
+	if (wait_for_pid(p) == 0) {
+		return true;
+	}
+	return false;
+}
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c;
+	char *cmd, *dev_name, *dst_name;
+	int ret = 1;
+
+	if (geteuid() != 0) {
+		ERROR("%s must be run as root", argv[0]);
+		exit(1);
+	}
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		goto err;
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		goto err;
+	lxc_log_options_no_override();
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		ERROR("%s doesn't exist", my_args.name);
+		goto err;
+	}
+
+	if (!c->is_running(c)) {
+		ERROR("Container %s is not running.", c->name);
+		goto err1;
+	}
+
+	if (my_args.argc < 2) {
+		ERROR("Error: no command given (Please see --help output)");
+		goto err1;
+	}
+
+	cmd = my_args.argv[0];
+	dev_name = my_args.argv[1];
+	if (my_args.argc < 3)
+		dst_name = dev_name;
+	else
+		dst_name = my_args.argv[2];
+
+	if (strcmp(cmd, "add") == 0) {
+		if (is_interface(dev_name, 1)) {
+			ret = c->attach_interface(c, dev_name, dst_name);
+		} else {
+			ret = c->add_device_node(c, dev_name, dst_name);
+		}
+		if (ret != true) {
+			ERROR("Failed to add %s to %s.", dev_name, c->name);
+			ret = 1;
+			goto err1;
+		}
+		INFO("Add %s to %s.", dev_name, c->name);
+	} else if (strcmp(cmd, "del") == 0) {
+		if (is_interface(dev_name, c->init_pid(c))) {
+			ret = c->detach_interface(c, dev_name, dst_name);
+		} else {
+			ret = c->remove_device_node(c, dev_name, dst_name);
+		}
+		if (ret != true) {
+			ERROR("Failed to del %s from %s.", dev_name, c->name);
+			ret = 1;
+			goto err1;
+		}
+		INFO("Delete %s from %s.", dev_name, c->name);
+	} else {
+		ERROR("Error: Please use add or del (Please see --help output)");
+		goto err1;
+	}
+	exit(0);
+err1:
+	lxc_container_put(c);
+err:
+	exit(ret);
+}
diff --git a/src/lxc/tools/lxc_execute.c b/src/lxc/tools/lxc_execute.c
new file mode 100644
index 0000000..50d481f
--- /dev/null
+++ b/src/lxc/tools/lxc_execute.c
@@ -0,0 +1,161 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <libgen.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include "caps.h"
+#include "lxc.h"
+#include "log.h"
+#include "conf.h"
+#include "confile.h"
+#include "arguments.h"
+#include "config.h"
+#include "start.h"
+#include "utils.h"
+
+lxc_log_define(lxc_execute_ui, lxc);
+
+static struct lxc_list defines;
+
+static int my_checker(const struct lxc_arguments* args)
+{
+	if (!args->argc) {
+		lxc_error(args, "missing command to execute !");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	switch (c) {
+	case 'f': args->rcfile = arg; break;
+	case 's': return lxc_config_define_add(&defines, arg); break;
+	case 'u': args->uid = atoi(arg); break;
+	case 'g': args->gid = atoi(arg);
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	{"rcfile", required_argument, 0, 'f'},
+	{"define", required_argument, 0, 's'},
+	{"uid", required_argument, 0, 'u'},
+	{"gid", required_argument, 0, 'g'},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-execute",
+	.help     = "\
+--name=NAME -- COMMAND\n\
+\n\
+lxc-execute creates a container with the identifier NAME\n\
+and execs COMMAND into this container.\n\
+\n\
+Options :\n\
+  -n, --name=NAME      NAME of the container\n\
+  -f, --rcfile=FILE    Load configuration file FILE\n\
+  -s, --define KEY=VAL Assign VAL to configuration variable KEY\n\
+  -u, --uid=UID Execute COMMAND with UID inside the container\n\
+  -g, --gid=GID Execute COMMAND with GID inside the container\n",
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = my_checker,
+};
+
+int main(int argc, char *argv[])
+{
+	char *rcfile;
+	struct lxc_conf *conf;
+	int ret;
+
+	lxc_list_init(&defines);
+
+	if (lxc_caps_init())
+		return 1;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		return 1;
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		return 1;
+	lxc_log_options_no_override();
+
+	/* rcfile is specified in the cli option */
+	if (my_args.rcfile)
+		rcfile = (char *)my_args.rcfile;
+	else {
+		int rc;
+
+		rc = asprintf(&rcfile, "%s/%s/config", my_args.lxcpath[0], my_args.name);
+		if (rc == -1) {
+			SYSERROR("failed to allocate memory");
+			return 1;
+		}
+
+		/* container configuration does not exist */
+		if (access(rcfile, F_OK)) {
+			free(rcfile);
+			rcfile = NULL;
+		}
+	}
+
+	conf = lxc_conf_init();
+	if (!conf) {
+		ERROR("failed to initialize configuration");
+		return 1;
+	}
+
+	if (rcfile && lxc_config_read(rcfile, conf, NULL)) {
+		ERROR("failed to read configuration file");
+		return 1;
+	}
+
+	if (lxc_config_define_load(&defines, conf))
+		return 1;
+
+	if (my_args.uid)
+		conf->init_uid = my_args.uid;
+
+	if (my_args.gid)
+		conf->init_gid = my_args.gid;
+
+	ret = lxc_execute(my_args.name, my_args.argv, my_args.quiet, conf, my_args.lxcpath[0], false);
+
+	lxc_conf_free(conf);
+
+	if (ret < 0)
+		return 1;
+	return ret;
+}
diff --git a/src/lxc/tools/lxc_freeze.c b/src/lxc/tools/lxc_freeze.c
new file mode 100644
index 0000000..ea8bd3e
--- /dev/null
+++ b/src/lxc/tools/lxc_freeze.c
@@ -0,0 +1,92 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <libgen.h>
+#include <string.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "lxc.h"
+#include "log.h"
+
+#include "arguments.h"
+
+lxc_log_define(lxc_freeze_ui, lxc);
+
+static const struct option my_longopts[] = {
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-freeze",
+	.help     = "\
+--name=NAME\n\
+\n\
+lxc-freeze freezes a container with the identifier NAME\n\
+\n\
+Options :\n\
+  -n, --name=NAME      NAME of the container",
+	.options  = my_longopts,
+	.parser   = NULL,
+	.checker  = NULL,
+};
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		exit(1);
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		exit(1);
+	lxc_log_options_no_override();
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		ERROR("No such container: %s:%s", my_args.lxcpath[0], my_args.name);
+		exit(1);
+	}
+
+	if (!c->may_control(c)) {
+		ERROR("Insufficent privileges to control %s:%s", my_args.lxcpath[0], my_args.name);
+		lxc_container_put(c);
+		exit(1);
+	}
+
+	if (!c->freeze(c)) {
+		ERROR("Failed to freeze %s:%s", my_args.lxcpath[0], my_args.name);
+		lxc_container_put(c);
+		exit(1);
+	}
+
+	lxc_container_put(c);
+
+	exit(0);
+}
diff --git a/src/lxc/tools/lxc_info.c b/src/lxc/tools/lxc_info.c
new file mode 100644
index 0000000..58ff619
--- /dev/null
+++ b/src/lxc/tools/lxc_info.c
@@ -0,0 +1,397 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <libgen.h>
+#include <sys/types.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "lxc.h"
+#include "log.h"
+#include "utils.h"
+#include "commands.h"
+#include "arguments.h"
+
+lxc_log_define(lxc_info_ui, lxc);
+
+static bool ips;
+static bool state;
+static bool pid;
+static bool stats;
+static bool humanize = true;
+static char **key = NULL;
+static int keys = 0;
+static int filter_count = 0;
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	char **newk;
+	switch (c) {
+	case 'c':
+		newk = realloc(key, (keys + 1) * sizeof(key[0]));
+		if (!newk)
+			return -1;
+		key = newk;
+		key[keys] = arg;
+		keys++;
+		break;
+	case 'i': ips = true; filter_count += 1; break;
+	case 's': state = true; filter_count += 1; break;
+	case 'p': pid = true; filter_count += 1; break;
+	case 'S': stats = true; filter_count += 5; break;
+	case 'H': humanize = false; break;
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	{"config", required_argument, 0, 'c'},
+	{"ips", no_argument, 0, 'i'},
+	{"state", no_argument, 0, 's'},
+	{"pid", no_argument, 0, 'p'},
+	{"stats", no_argument, 0, 'S'},
+	{"no-humanize", no_argument, 0, 'H'},
+	LXC_COMMON_OPTIONS,
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-info",
+	.help     = "\
+--name=NAME\n\
+\n\
+lxc-info display some information about a container with the identifier NAME\n\
+\n\
+Options :\n\
+  -n, --name=NAME       NAME of the container\n\
+  -c, --config=KEY      show configuration variable KEY from running container\n\
+  -i, --ips             shows the IP addresses\n\
+  -p, --pid             shows the process id of the init container\n\
+  -S, --stats           shows usage stats\n\
+  -H, --no-humanize     shows stats as raw numbers, not humanized\n\
+  -s, --state           shows the state of the container\n",
+	.name     = NULL,
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = NULL,
+};
+
+static void str_chomp(char *buf)
+{
+	char *ch;
+
+	/* remove trailing whitespace from buf */
+	for(ch = &buf[strlen(buf)-1];
+	    ch >= buf && (*ch == '\t' || *ch == '\n' || *ch == ' ');
+	    ch--)
+		*ch = '\0';
+}
+
+static void size_humanize(unsigned long long val, char *buf, size_t bufsz)
+{
+	if (val > 1 << 30) {
+		snprintf(buf, bufsz, "%u.%2.2u GiB",
+			    (int)(val >> 30),
+			    (int)(val & ((1 << 30) - 1)) / 10737419);
+	} else if (val > 1 << 20) {
+		int x = val + 5243;  /* for rounding */
+		snprintf(buf, bufsz, "%u.%2.2u MiB",
+			    x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
+	} else if (val > 1 << 10) {
+		int x = val + 5;  /* for rounding */
+		snprintf(buf, bufsz, "%u.%2.2u KiB",
+			    x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
+	} else {
+		snprintf(buf, bufsz, "%u bytes", (int)val);
+	}
+}
+
+static unsigned long long str_size_humanize(char *iobuf, size_t iobufsz)
+{
+	unsigned long long val;
+	char *end = NULL;
+
+	val = strtoull(iobuf, &end, 0);
+	if (humanize) {
+		if (*end == '\0' || *end == '\n')
+			size_humanize(val, iobuf, iobufsz);
+		else
+			*iobuf = '\0';
+	}
+	return val;
+}
+
+static void print_net_stats(struct lxc_container *c)
+{
+	int rc,netnr;
+	unsigned long long rx_bytes = 0, tx_bytes = 0;
+	char *ifname, *type;
+	char path[PATH_MAX];
+	char buf[256];
+
+	for(netnr = 0; ;netnr++) {
+		sprintf(buf, "lxc.network.%d.type", netnr);
+		type = c->get_running_config_item(c, buf);
+		if (!type)
+			break;
+
+		if (!strcmp(type, "veth")) {
+			sprintf(buf, "lxc.network.%d.veth.pair", netnr);
+		} else {
+			sprintf(buf, "lxc.network.%d.link", netnr);
+		}
+		free(type);
+		ifname = c->get_running_config_item(c, buf);
+		if (!ifname)
+			return;
+		printf("%-15s %s\n", "Link:", ifname);
+		fflush(stdout);
+
+		/* XXX: tx and rx are reversed from the host vs container
+		 * perspective, print them from the container perspective
+		 */
+		snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/rx_bytes", ifname);
+		rc = lxc_read_from_file(path, buf, sizeof(buf));
+		if (rc > 0) {
+			str_chomp(buf);
+			rx_bytes = str_size_humanize(buf, sizeof(buf));
+			printf("%-15s %s\n", " TX bytes:", buf);
+			fflush(stdout);
+		}
+
+		snprintf(path, sizeof(path), "/sys/class/net/%s/statistics/tx_bytes", ifname);
+		rc = lxc_read_from_file(path, buf, sizeof(buf));
+		if (rc > 0) {
+			str_chomp(buf);
+			tx_bytes = str_size_humanize(buf, sizeof(buf));
+			printf("%-15s %s\n", " RX bytes:", buf);
+			fflush(stdout);
+		}
+
+		sprintf(buf, "%llu", rx_bytes + tx_bytes);
+		str_size_humanize(buf, sizeof(buf));
+		printf("%-15s %s\n", " Total bytes:", buf);
+		fflush(stdout);
+		free(ifname);
+	}
+}
+
+static void print_stats(struct lxc_container *c)
+{
+	int i, ret;
+	char buf[256];
+
+	ret = c->get_cgroup_item(c, "cpuacct.usage", buf, sizeof(buf));
+	if (ret > 0 && ret < sizeof(buf)) {
+		str_chomp(buf);
+		if (humanize) {
+			float seconds = strtof(buf, NULL) / 1000000000.0;
+			printf("%-15s %.2f seconds\n", "CPU use:", seconds);
+		} else {
+			printf("%-15s %s\n", "CPU use:", buf);
+		}
+		fflush(stdout);
+	}
+
+	ret = c->get_cgroup_item(c, "blkio.throttle.io_service_bytes", buf, sizeof(buf));
+	if (ret > 0 && ret < sizeof(buf)) {
+		char *ch;
+
+		/* put ch on last "Total" line */
+		str_chomp(buf);
+		for(ch = &buf[strlen(buf)-1]; ch > buf && *ch != '\n'; ch--)
+			;
+		if (*ch == '\n')
+			ch++;
+
+		if (strncmp(ch, "Total", 5) == 0) {
+			ch += 6;
+			memmove(buf, ch, strlen(ch)+1);
+			str_size_humanize(buf, sizeof(buf));
+			printf("%-15s %s\n", "BlkIO use:", buf);
+		}
+		fflush(stdout);
+	}
+
+	static const struct {
+		const char *name;
+		const char *file;
+	} lxstat[] = {
+		{ "Memory use:", "memory.usage_in_bytes" },
+		{ "KMem use:",   "memory.kmem.usage_in_bytes" },
+		{ NULL, NULL },
+	};
+
+	for (i = 0; lxstat[i].name; i++) {
+		ret = c->get_cgroup_item(c, lxstat[i].file, buf, sizeof(buf));
+		if (ret > 0 && ret < sizeof(buf)) {
+			str_chomp(buf);
+			str_size_humanize(buf, sizeof(buf));
+			printf("%-15s %s\n", lxstat[i].name, buf);
+			fflush(stdout);
+		}
+	}
+}
+
+static void print_info_msg_int(const char *key, int value)
+{
+	if (humanize)
+		printf("%-15s %d\n", key, value);
+	else {
+		if (filter_count == 1)
+			printf("%d\n", value);
+		else
+			printf("%-15s %d\n", key, value);
+	}
+	fflush(stdout);
+}
+
+static void print_info_msg_str(const char *key, const char *value)
+{
+	if (humanize)
+		printf("%-15s %s\n", key, value);
+	else {
+		if (filter_count == 1)
+			printf("%s\n", value);
+		else
+			printf("%-15s %s\n", key, value);
+	}
+	fflush(stdout);
+}
+
+static int print_info(const char *name, const char *lxcpath)
+{
+	int i;
+	struct lxc_container *c;
+
+	c = lxc_container_new(name, lxcpath);
+	if (!c) {
+		fprintf(stderr, "Failure to retrieve information on %s:%s\n", lxcpath ? lxcpath : "null",
+				name ? name : "null");
+		return -1;
+	}
+
+	if (!c->may_control(c)) {
+		fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+		lxc_container_put(c);
+		return -1;
+	}
+
+	if (!c->is_running(c) && !c->is_defined(c)) {
+		fprintf(stderr, "%s doesn't exist\n", c->name);
+		lxc_container_put(c);
+		return -1;
+	}
+
+	if (!state && !pid && !ips && !stats && keys <= 0) {
+		state = pid = ips = stats = true;
+		print_info_msg_str("Name:", c->name);
+	}
+
+	if (state) {
+		print_info_msg_str("State:", c->state(c));
+	}
+
+	if (c->is_running(c)) {
+		if (pid) {
+			pid_t initpid;
+
+			initpid = c->init_pid(c);
+			if (initpid >= 0)
+				print_info_msg_int("PID:", initpid);
+		}
+
+		if (ips) {
+			fflush(stdout);
+			char **addresses = c->get_ips(c, NULL, NULL, 0);
+			if (addresses) {
+				char *address;
+				i = 0;
+				while (addresses[i]) {
+					address = addresses[i];
+					print_info_msg_str("IP:", address);
+					i++;
+				}
+			}
+		}
+	}
+
+	if (stats) {
+		print_stats(c);
+		print_net_stats(c);
+	}
+
+	for(i = 0; i < keys; i++) {
+		int len = c->get_config_item(c, key[i], NULL, 0);
+
+		if (len > 0) {
+			char *val = (char*) malloc(sizeof(char)*len + 1);
+
+			if (c->get_config_item(c, key[i], val, len + 1) != len) {
+				fprintf(stderr, "unable to read %s from configuration\n", key[i]);
+			} else {
+				if (!humanize && keys == 1)
+					printf("%s\n", val);
+				else
+					printf("%s = %s\n", key[i], val);
+			}
+			free(val);
+		} else if (len == 0) {
+			if (!humanize && keys == 1)
+				printf("\n");
+			else
+				printf("%s =\n", key[i]);
+		} else {
+			fprintf(stderr, "%s invalid\n", key[i]);
+		}
+		fflush(stdout);
+	}
+
+	lxc_container_put(c);
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		return ret;
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		return ret;
+	lxc_log_options_no_override();
+
+	if (print_info(my_args.name, my_args.lxcpath[0]) == 0)
+		ret = EXIT_SUCCESS;
+
+	return ret;
+}
diff --git a/src/lxc/tools/lxc_init.c b/src/lxc/tools/lxc_init.c
new file mode 100644
index 0000000..5dd29af
--- /dev/null
+++ b/src/lxc/tools/lxc_init.c
@@ -0,0 +1,261 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include "log.h"
+#include "caps.h"
+#include "error.h"
+#include "initutils.h"
+
+lxc_log_define(lxc_init, lxc);
+
+static int quiet;
+
+static const struct option options[] = {
+	{ "name",        required_argument, NULL, 'n' },
+	{ "logpriority", required_argument, NULL, 'l' },
+	{ "quiet",       no_argument,       NULL, 'q' },
+	{ "lxcpath",     required_argument, NULL, 'P' },
+	{ 0, 0, 0, 0 },
+};
+
+static sig_atomic_t was_interrupted = 0;
+
+static void interrupt_handler(int sig)
+{
+	if (!was_interrupted)
+		was_interrupted = sig;
+}
+
+static void usage(void) {
+	fprintf(stderr, "Usage: lxc-init [OPTION]...\n\n"
+		"Common options :\n"
+		"  -n, --name=NAME          NAME of the container\n"
+		"  -l, --logpriority=LEVEL  Set log priority to LEVEL\n"
+		"  -q, --quiet              Don't produce any output\n"
+		"  -P, --lxcpath=PATH       Use specified container path\n"
+		"  -?, --help               Give this help list\n"
+		"\n"
+		"Mandatory or optional arguments to long options are also mandatory or optional\n"
+		"for any corresponding short options.\n"
+		"\n"
+		"NOTE: lxc-init is intended for use by lxc internally\n"
+		"      and does not need to be run by hand\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+	pid_t pid;
+	int err;
+	char **aargv;
+	sigset_t mask, omask;
+	int i, have_status = 0, shutdown = 0;
+	int opt;
+	char *lxcpath = NULL, *name = NULL, *logpriority = NULL;
+
+	while ((opt = getopt_long(argc, argv, "n:l:qP:", options, NULL)) != -1) {
+		switch(opt) {
+		case 'n':
+			name = optarg;
+			break;
+		case 'l':
+			logpriority = optarg;
+			break;
+		case 'q':
+			quiet = 1;
+ 			break;
+		case 'P':
+			lxcpath = optarg;
+			break;
+		default: /* '?' */
+			usage();
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	err = lxc_log_init(name, name ? NULL : "none", logpriority,
+			   basename(argv[0]), quiet, lxcpath);
+	if (err < 0)
+		exit(EXIT_FAILURE);
+	lxc_log_options_no_override();
+
+	if (!argv[optind]) {
+		ERROR("missing command to launch");
+		exit(EXIT_FAILURE);
+	}
+
+	aargv = &argv[optind];
+
+	/*
+	 * mask all the signals so we are safe to install a
+	 * signal handler and to fork
+	 */
+	if (sigfillset(&mask) ||
+	    sigdelset(&mask, SIGILL) ||
+	    sigdelset(&mask, SIGSEGV) ||
+	    sigdelset(&mask, SIGBUS) ||
+	    sigprocmask(SIG_SETMASK, &mask, &omask)) {
+		SYSERROR("failed to set signal mask");
+		exit(EXIT_FAILURE);
+	}
+
+	for (i = 1; i < NSIG; i++) {
+		struct sigaction act;
+
+		/* Exclude some signals: ILL, SEGV and BUS are likely to
+		 * reveal a bug and we want a core. STOP and KILL cannot be
+		 * handled anyway: they're here for documentation.
+		 */
+		if (i == SIGILL ||
+		    i == SIGSEGV ||
+		    i == SIGBUS ||
+		    i == SIGSTOP ||
+		    i == SIGKILL ||
+		    i == 32 || i == 33)
+			continue;
+
+		if (sigfillset(&act.sa_mask) ||
+		    sigdelset(&act.sa_mask, SIGILL) ||
+		    sigdelset(&act.sa_mask, SIGSEGV) ||
+		    sigdelset(&act.sa_mask, SIGBUS) ||
+		    sigdelset(&act.sa_mask, SIGSTOP) ||
+		    sigdelset(&act.sa_mask, SIGKILL)) {
+			ERROR("failed to set signal");
+			exit(EXIT_FAILURE);
+		}
+
+		act.sa_flags = 0;
+		act.sa_handler = interrupt_handler;
+		if (sigaction(i, &act, NULL) && errno != EINVAL) {
+			SYSERROR("failed to sigaction");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	lxc_setup_fs();
+
+	pid = fork();
+
+	if (pid < 0)
+		exit(EXIT_FAILURE);
+
+	if (!pid) {
+
+		/* restore default signal handlers */
+		for (i = 1; i < NSIG; i++)
+			signal(i, SIG_DFL);
+
+		if (sigprocmask(SIG_SETMASK, &omask, NULL)) {
+			SYSERROR("failed to set signal mask");
+			exit(EXIT_FAILURE);
+		}
+
+		NOTICE("about to exec '%s'", aargv[0]);
+
+		execvp(aargv[0], aargv);
+		ERROR("failed to exec: '%s' : %m", aargv[0]);
+		exit(err);
+	}
+
+	/* let's process the signals now */
+	if (sigdelset(&omask, SIGALRM) ||
+	    sigprocmask(SIG_SETMASK, &omask, NULL)) {
+		SYSERROR("failed to set signal mask");
+		exit(EXIT_FAILURE);
+	}
+
+	/* no need of other inherited fds but stderr */
+	close(fileno(stdin));
+	close(fileno(stdout));
+
+	err = EXIT_SUCCESS;
+	for (;;) {
+		int status;
+		pid_t waited_pid;
+
+		switch (was_interrupted) {
+
+		case 0:
+			break;
+
+		case SIGPWR:
+		case SIGTERM:
+			if (!shutdown) {
+				shutdown = 1;
+				kill(-1, SIGTERM);
+				alarm(1);
+			}
+			break;
+
+		case SIGALRM:
+			kill(-1, SIGKILL);
+			break;
+
+		default:
+			kill(pid, was_interrupted);
+			break;
+		}
+
+		was_interrupted = 0;
+		waited_pid = wait(&status);
+		if (waited_pid < 0) {
+			if (errno == ECHILD)
+				goto out;
+			if (errno == EINTR)
+				continue;
+
+			ERROR("failed to wait child : %s",
+			      strerror(errno));
+			goto out;
+		}
+
+		/* reset timer each time a process exited */
+		if (shutdown)
+			alarm(1);
+
+		/*
+		 * keep the exit code of started application
+		 * (not wrapped pid) and continue to wait for
+		 * the end of the orphan group.
+		 */
+		if (waited_pid == pid && !have_status) {
+			err = lxc_error_set_and_log(waited_pid, status);
+			have_status = 1;
+		}
+	}
+out:
+	if (err < 0)
+		exit(EXIT_FAILURE);
+	exit(err);
+}
diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c
new file mode 100644
index 0000000..e2a4c34
--- /dev/null
+++ b/src/lxc/tools/lxc_ls.c
@@ -0,0 +1,1213 @@
+/*
+ *
+ * Copyright © 2016 Christian Brauner <christian.brauner at mailbox.org>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <getopt.h>
+#include <regex.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "arguments.h"
+#include "conf.h"
+#include "confile.h"
+#include "log.h"
+#include "lxc.h"
+#include "utils.h"
+
+lxc_log_define(lxc_ls, lxc);
+
+#define LINELEN 1024
+/* Per default we only allow five levels of recursion to protect the stack at
+ * least a little bit. */
+#define MAX_NESTLVL 5
+
+#define LS_FROZEN 1
+#define LS_STOPPED 2
+#define LS_ACTIVE 3
+#define LS_RUNNING 4
+#define LS_NESTING 5
+#define LS_FILTER 6
+
+#ifndef SOCK_CLOEXEC
+#  define SOCK_CLOEXEC                02000000
+#endif
+
+/* Store container info. */
+struct ls {
+	char *name;
+	char *state;
+	char *groups;
+	char *interface;
+	char *ipv4;
+	char *ipv6;
+	unsigned int nestlvl;
+	pid_t init;
+	double ram;
+	double swap;
+	bool autostart;
+	bool running;
+};
+
+/* Keep track of field widths for printing. */
+struct lengths {
+	unsigned int name_length;
+	unsigned int state_length;
+	unsigned int groups_length;
+	unsigned int interface_length;
+	unsigned int ipv4_length;
+	unsigned int ipv6_length;
+	unsigned int init_length;
+	unsigned int ram_length;
+	unsigned int swap_length;
+	unsigned int autostart_length;
+};
+
+static int ls_deserialize(int rpipefd, struct ls **m, size_t *len);
+static void ls_field_width(const struct ls *l, const size_t size,
+		struct lengths *lht);
+static void ls_free(struct ls *l, size_t size);
+static void ls_free_arr(char **arr, size_t size);
+static int ls_get(struct ls **m, size_t *size, const struct lxc_arguments *args,
+		const char *basepath, const char *parent, unsigned int lvl,
+		char **lockpath, size_t len_lockpath, char **grps_must,
+		size_t grps_must_len);
+static char *ls_get_cgroup_item(struct lxc_container *c, const char *item);
+static char *ls_get_config_item(struct lxc_container *c, const char *item,
+		bool running);
+static char *ls_get_groups(struct lxc_container *c, bool running);
+static char *ls_get_ips(struct lxc_container *c, const char *inet);
+static int ls_recv_str(int fd, char **buf);
+static int ls_send_str(int fd, const char *buf);
+
+struct wrapargs {
+	const struct lxc_arguments *args;
+	char **grps_must;
+	size_t grps_must_len;
+	int pipefd[2];
+	size_t *size;
+	const char *parent;
+	unsigned int nestlvl;
+};
+
+/*
+ * Takes struct wrapargs as argument.
+ */
+static int ls_get_wrapper(void *wrap);
+
+/*
+ * To calculate swap usage we should not simply check memory.usage_in_bytes and
+ * memory.memsw.usage_in_bytes and then do:
+ *	swap = memory.memsw.usage_in_bytes - memory.usage_in_bytes;
+ * because we might receive an incorrect/negative value.
+ * Instead we check memory.stat and check the "swap" value.
+ */
+static double ls_get_swap(struct lxc_container *c);
+static unsigned int ls_get_term_width(void);
+static char *ls_get_interface(struct lxc_container *c);
+static bool ls_has_all_grps(const char *has, char **must, size_t must_len);
+static struct ls *ls_new(struct ls **ls, size_t *size);
+
+/*
+ * Print user-specified fancy format.
+ */
+static void ls_print_fancy_format(struct ls *l, struct lengths *lht,
+		size_t size, const char *fancy_fmt);
+
+/*
+ * Only print names of containers.
+ */
+static void ls_print_names(struct ls *l, struct lengths *lht,
+		size_t ls_arr, size_t termwidth);
+
+/*
+ * Print default fancy format.
+ */
+static void ls_print_table(struct ls *l, struct lengths *lht,
+		size_t size);
+
+/*
+ * id can only be 79 + \0 chars long.
+ */
+static int ls_remove_lock(const char *path, const char *name,
+		char **lockpath, size_t *len_lockpath, bool recalc);
+static int ls_serialize(int wpipefd, struct ls *n);
+static int my_parser(struct lxc_arguments *args, int c, char *arg);
+
+static const struct option my_longopts[] = {
+	{"line", no_argument, 0, '1'},
+	{"fancy", no_argument, 0, 'f'},
+	{"fancy-format", required_argument, 0, 'F'},
+	{"active", no_argument, 0, LS_ACTIVE},
+	{"running", no_argument, 0, LS_RUNNING},
+	{"frozen", no_argument, 0, LS_FROZEN},
+	{"stopped", no_argument, 0, LS_STOPPED},
+	{"nesting", optional_argument, 0, LS_NESTING},
+	{"groups", required_argument, 0, 'g'},
+	{"filter", required_argument, 0, LS_FILTER},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-ls",
+	.help = "\n\
+[-P lxcpath] [--active] [--running] [--frozen] [--stopped] [--nesting] [-g groups] [--filter regex]\n\
+[-1] [-P lxcpath] [--active] [--running] [--frozen] [--stopped] [--nesting] [-g groups] [--filter regex]\n\
+[-f] [-P lxcpath] [--active] [--running] [--frozen] [--stopped] [--nesting] [-g groups] [--filter regex]\n\
+\n\
+lxc-ls list containers\n\
+\n\
+Options :\n\
+  -1, --line	     show one entry per line\n\
+  -f, --fancy	     column-based output\n\
+  -F, --fancy-format column-based output\n\
+  --active           list only active containers\n\
+  --running          list only running containers\n\
+  --frozen           list only frozen containers\n\
+  --stopped          list only stopped containers\n\
+  --nesting=NUM      list nested containers up to NUM (default is 5) levels of nesting\n\
+  --filter=REGEX     filter container names by regular expression\n\
+  -g --groups        comma separated list of groups a container must have to be displayed\n",
+	.options = my_longopts,
+	.parser = my_parser,
+	.ls_nesting = 0,
+};
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+	/*
+	 * The lxc parser requires that my_args.name is set. So let's satisfy
+	 * that condition by setting a dummy name which is never used.
+	 */
+	my_args.name  = "";
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		exit(EXIT_FAILURE);
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	/*
+	 * We set the first argument that usually takes my_args.name to NULL so
+	 * that the log is only used when the user specifies a file.
+	 */
+	if (lxc_log_init(NULL, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		exit(EXIT_FAILURE);
+	lxc_log_options_no_override();
+
+	struct lengths max_len = {
+		/* default header length */
+		.name_length = 4,      /* NAME */
+		.state_length = 5,     /* STATE */
+		.groups_length = 6,    /* GROUPS */
+		.interface_length = 9, /* INTERFACE */
+		.ipv4_length = 4,      /* IPV4 */
+		.ipv6_length = 4,      /* IPV6 */
+		.init_length = 3,      /* PID */
+		.ram_length = 3,       /* RAM */
+		.swap_length = 4,      /* SWAP */
+		.autostart_length = 9, /* AUTOSTART */
+	};
+
+	char **grps = NULL;
+	size_t ngrps = 0;
+	if (my_args.groups) {
+		grps = lxc_string_split_and_trim(my_args.groups, ',');
+		ngrps = lxc_array_len((void **)grps);
+	}
+
+	struct ls *ls_arr = NULL;
+	size_t ls_size = 0;
+	/* &(char *){NULL} is no magic. It's just a compound literal which
+	 * avoids having a pointless variable in main() that serves no purpose
+	 * here. */
+	int status = ls_get(&ls_arr, &ls_size, &my_args, "", NULL, 0, &(char *){NULL}, 0, grps, ngrps);
+	if (!ls_arr && status == 0)
+		/* We did not fail. There was just nothing to do. */
+		exit(EXIT_SUCCESS);
+	else if (!ls_arr || status == -1)
+		goto out;
+
+	ls_field_width(ls_arr, ls_size, &max_len);
+	if (my_args.ls_fancy && !my_args.ls_fancy_format) {
+		ls_print_table(ls_arr, &max_len, ls_size);
+	} else if (my_args.ls_fancy && my_args.ls_fancy_format) {
+		ls_print_fancy_format(ls_arr, &max_len, ls_size, my_args.ls_fancy_format);
+	} else {
+		unsigned int cols = 0;
+		if (!my_args.ls_line)
+			cols = ls_get_term_width();
+		ls_print_names(ls_arr, &max_len, ls_size, cols);
+	}
+
+	ret = EXIT_SUCCESS;
+
+out:
+	ls_free(ls_arr, ls_size);
+	lxc_free_array((void **)grps, free);
+
+	exit(ret);
+}
+
+static void ls_free(struct ls *l, size_t size)
+{
+	size_t i;
+	struct ls *m = NULL;
+	for (i = 0, m = l; i < size; i++, m++) {
+		free(m->groups);
+		free(m->interface);
+		free(m->ipv4);
+		free(m->ipv6);
+		free(m->name);
+		free(m->state);
+	}
+	free(l);
+}
+
+static char *ls_get_config_item(struct lxc_container *c, const char *item,
+		bool running)
+{
+	if (running)
+		return c->get_running_config_item(c, item);
+
+	size_t len = c->get_config_item(c, item, NULL, 0);
+	if (len <= 0)
+		return NULL;
+
+	char *val = malloc((len + 1) * sizeof(*val));
+	if (!val)
+		return NULL;
+
+	if ((size_t)c->get_config_item(c, item, val, len + 1) != len) {
+		free(val);
+		val = NULL;
+	}
+
+	return val;
+}
+
+static void ls_free_arr(char **arr, size_t size)
+{
+	size_t i;
+	for (i = 0; i < size; i++)
+		free(arr[i]);
+	free(arr);
+}
+
+static int ls_get(struct ls **m, size_t *size, const struct lxc_arguments *args,
+		const char *basepath, const char *parent, unsigned int lvl,
+		char **lockpath, size_t len_lockpath, char **grps_must,
+		size_t grps_must_len)
+{
+	/* As ls_get() is non-tail recursive we face the inherent danger of
+	 * blowing up the stack at some level of nesting. To have at least some
+	 * security we define MAX_NESTLVL to be 5. That should be sufficient for
+	 * most users. The argument lvl can be used to keep track of the level
+	 * of nesting we are at. If lvl is greater than the allowed default
+	 * level or the level the user specified on the command line we return
+	 * and unwind the stack. */
+	if (lvl > args->ls_nesting)
+		return 0;
+
+	int num = 0, ret = -1;
+	char **containers = NULL;
+	/* If we, at some level of nesting, encounter a stopped container but
+	 * want to retrieve nested containers we need to build an absolute path
+	 * beginning from it. Initially, at nesting level 0, basepath will
+	 * simply be the empty string and path will simply be whatever the
+	 * default lxcpath or the path the user gave us is.  Basepath will also
+	 * be the empty string in case we encounter a running container since we
+	 * can simply attach to its namespace to retrieve nested containers. */
+	char *path = lxc_append_paths(basepath, args->lxcpath[0]);
+	if (!path)
+		goto out;
+
+	if (!dir_exists(path)) {
+		ret = 0;
+		goto out;
+	}
+
+	/* Do not do more work than is necessary right from the start. */
+	if (args->ls_active || (args->ls_active && args->ls_frozen))
+		num = list_active_containers(path, &containers, NULL);
+	else
+		num = list_all_containers(path, &containers, NULL);
+	if (num == -1) {
+		num = 0;
+		goto out;
+	}
+
+	char *tmp = NULL;
+	int check;
+	struct ls *l = NULL;
+	struct lxc_container *c = NULL;
+	size_t i;
+	for (i = 0; i < (size_t)num; i++) {
+		char *name = containers[i];
+
+		/* Filter container names by regex the user gave us. */
+		if (args->ls_filter || args->argc == 1) {
+			regex_t preg;
+			tmp = args->ls_filter ? args->ls_filter : args->argv[0];
+			check = regcomp(&preg, tmp, REG_NOSUB | REG_EXTENDED);
+			if (check == REG_ESPACE) /* we're out of memory */
+				goto out;
+			else if (check != 0)
+				continue;
+			check = regexec(&preg, name, 0, NULL, 0);
+			regfree(&preg);
+			if (check != 0)
+				continue;
+		}
+
+ 		errno = 0;
+		c = lxc_container_new(name, path);
+ 		if ((errno == ENOMEM) && !c)
+ 			goto out;
+ 		else if (!c)
+ 			continue;
+
+		if (!c->is_defined(c))
+			goto put_and_next;
+
+		/* This does not allocate memory so no worries about freeing it
+		 * when we goto next or out. */
+		const char *state_tmp = c->state(c);
+		if (!state_tmp)
+			state_tmp = "UNKNOWN";
+
+		if (args->ls_running && !c->is_running(c))
+			goto put_and_next;
+
+		if (args->ls_frozen && !args->ls_active && strcmp(state_tmp, "FROZEN"))
+			goto put_and_next;
+
+		if (args->ls_stopped && strcmp(state_tmp, "STOPPED"))
+			goto put_and_next;
+
+		bool running = c->is_running(c);
+
+		char *grp_tmp = ls_get_groups(c, running);
+		if (!ls_has_all_grps(grp_tmp, grps_must, grps_must_len)) {
+			free(grp_tmp);
+			goto put_and_next;
+		}
+
+		/* Now it makes sense to allocate memory. */
+		l = ls_new(m, size);
+		if (!l) {
+			free(grp_tmp);
+			goto put_and_next;
+		}
+
+		/* How deeply nested are we? */
+		l->nestlvl = lvl;
+
+		l->groups = grp_tmp;
+
+		l->running = running;
+
+		if (parent && args->ls_nesting && (args->ls_line || !args->ls_fancy))
+			/* Prepend the name of the container with all its parents when
+			 * the user requests it. */
+			l->name = lxc_append_paths(parent, name);
+		else
+			/* Otherwise simply record the name. */
+			l->name = strdup(name);
+		if (!l->name)
+			goto put_and_next;
+
+		/* Do not record stuff the user did not explictly request. */
+		if (args->ls_fancy) {
+			/* Maybe we should even consider the name sensitive and
+			 * hide it when you're not allowed to control the
+			 * container. */
+			if (!c->may_control(c))
+				goto put_and_next;
+
+			l->state = strdup(state_tmp);
+			if (!l->state)
+				goto put_and_next;
+
+			tmp = ls_get_config_item(c, "lxc.start.auto", running);
+			if (tmp)
+				l->autostart = atoi(tmp);
+			free(tmp);
+
+			if (running) {
+				l->init = c->init_pid(c);
+
+				l->interface = ls_get_interface(c);
+
+				l->ipv4 = ls_get_ips(c, "inet");
+
+				l->ipv6 = ls_get_ips(c, "inet6");
+
+				tmp = ls_get_cgroup_item(c, "memory.usage_in_bytes");
+				if (tmp) {
+					l->ram = strtoull(tmp, NULL, 0);
+					l->ram = l->ram / 1024 /1024;
+					free(tmp);
+				}
+
+				l->swap = ls_get_swap(c);
+			}
+		}
+
+		/* Get nested containers: Only do this after we have gathered
+		 * all other information we need. */
+		if (args->ls_nesting && running) {
+			struct wrapargs wargs = (struct wrapargs){.args = NULL};
+			/* Open a socket so that the child can communicate with us. */
+			check = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wargs.pipefd);
+			if (check == -1)
+				goto put_and_next;
+
+			/* Set the next nesting level. */
+			wargs.nestlvl = lvl + 1;
+			/* Send in the parent for the next nesting level. */
+			wargs.parent = l->name;
+			wargs.args = args;
+			wargs.grps_must = grps_must;
+			wargs.grps_must_len = grps_must_len;
+
+			pid_t out;
+
+			lxc_attach_options_t aopt = LXC_ATTACH_OPTIONS_DEFAULT;
+			aopt.env_policy = LXC_ATTACH_CLEAR_ENV;
+
+			/* fork(): Attach to the namespace of the container and
+			 * run ls_get() in it which is called in ls_get_wrapper(). */
+			check = c->attach(c, ls_get_wrapper, &wargs, &aopt, &out);
+			/* close the socket */
+			close(wargs.pipefd[1]);
+
+			/* Retrieve all information we want from the child. */
+			if (check == 0)
+				if (ls_deserialize(wargs.pipefd[0], m, size) == -1)
+					goto put_and_next;
+
+			/* Wait for the child to finish. */
+			wait_for_pid(out);
+
+			/* We've done all the communication we need so shutdown
+			 * the socket and close it. */
+			shutdown(wargs.pipefd[0], SHUT_RDWR);
+			close(wargs.pipefd[0]);
+		} else if (args->ls_nesting && !running) {
+			/* This way of extracting the rootfs is not safe since
+			 * it will return very different things depending on the
+			 * storage backend that is used for the container. We
+			 * need a path-extractor function. We face the same
+			 * problem with the ovl_mkdir() function in
+			 * lxcoverlay.{c,h}. */
+			char *curr_path = ls_get_config_item(c, "lxc.rootfs", running);
+			if (!curr_path)
+				goto put_and_next;
+
+			/* Since the container is not running and we cannot
+			 * attach to it we need another strategy to retrieve
+			 * nested containers. What we do is simply create a
+			 * growing path which will lead us into the rootfs of
+			 * the next container where it stores its containers. */
+			char *newpath = lxc_append_paths(basepath, curr_path);
+			free(curr_path);
+			if (!newpath)
+				goto put_and_next;
+
+			/* We want to remove all locks we create under
+			 * /run/lxc/lock so we create a string pointing us to
+			 * the lock path for the current container. */
+			if (ls_remove_lock(path, name, lockpath, &len_lockpath, true) == -1)
+				goto put_and_next;
+
+			ls_get(m, size, args, newpath, l->name, lvl + 1, lockpath, len_lockpath, grps_must, grps_must_len);
+			free(newpath);
+
+			/* Remove the lock. No need to check for failure here. */
+			ls_remove_lock(path, name, lockpath, &len_lockpath, false);
+		}
+
+put_and_next:
+		lxc_container_put(c);
+	}
+	ret = 0;
+
+out:
+	ls_free_arr(containers, num);
+	free(path);
+	/* lockpath is shared amongst all non-fork()ing recursive calls to
+	 * ls_get() so only free it on the uppermost level. */
+	if (lvl == 0)
+		free(*lockpath);
+
+	return ret;
+}
+
+static char *ls_get_cgroup_item(struct lxc_container *c, const char *item)
+{
+	size_t len = c->get_cgroup_item(c, item, NULL, 0);
+	if (len <= 0)
+		return NULL;
+
+	char *val = malloc((len + 1) * sizeof(*val));
+	if (!val)
+		return NULL;
+
+	if ((size_t)c->get_cgroup_item(c, item, val, len + 1) != len) {
+		free(val);
+		val = NULL;
+	}
+
+	return val;
+}
+
+static char *ls_get_groups(struct lxc_container *c, bool running)
+{
+	size_t len = 0;
+	char *val = NULL;
+
+	if (running)
+		val = c->get_running_config_item(c, "lxc.group");
+	else
+		len = c->get_config_item(c, "lxc.group", NULL, 0);
+
+	if (!val && (len > 0)) {
+		val = malloc((len + 1) * sizeof(*val));
+		if ((size_t)c->get_config_item(c, "lxc.group", val, len + 1) != len) {
+			free(val);
+			return NULL;
+		}
+	}
+
+	if (val) {
+		char *tmp;
+		if ((tmp = strrchr(val, '\n')))
+			*tmp = '\0';
+
+		tmp = lxc_string_replace("\n", ", ", val);
+		free(val);
+		val = tmp;
+	}
+
+	return val;
+}
+
+static char *ls_get_ips(struct lxc_container *c, const char *inet)
+{
+	char *ips = NULL;
+	char **iptmp = c->get_ips(c, NULL, inet, 0);
+	if (iptmp)
+		ips = lxc_string_join(", ", (const char **)iptmp, false);
+
+	lxc_free_array((void **)iptmp, free);
+
+	return ips;
+}
+
+static char *ls_get_interface(struct lxc_container *c)
+{
+	char **interfaces = c->get_interfaces(c);
+	if (!interfaces)
+		return NULL;
+
+	char *interface = lxc_string_join(", ", (const char **)interfaces, false);
+
+	lxc_free_array((void **)interfaces, free);
+
+	return interface;
+}
+
+/*
+ * To calculate swap usage we should not simply check memory.usage_in_bytes and
+ * memory.memsw.usage_in_bytes and then do:
+ *	swap = memory.memsw.usage_in_bytes - memory.usage_in_bytes;
+ * because we might receive an incorrect/negative value.
+ * Instead we check memory.stat and check the "swap" value.
+ */
+static double ls_get_swap(struct lxc_container *c)
+{
+	unsigned long long int num = 0;
+	char *stat = ls_get_cgroup_item(c, "memory.stat");
+	if (!stat)
+		goto out;
+
+	char *swap = strstr(stat, "\nswap");
+	if (!swap)
+		goto out;
+
+	swap = 1 + swap + 4 + 1; // start_of_swap_value = '\n' + strlen(swap) + ' '
+
+	char *tmp = strchr(swap, '\n'); // find end of swap value
+	if (!tmp)
+		goto out;
+
+	*tmp = '\0';
+
+	num = strtoull(swap, NULL, 0);
+	num = num / 1024 / 1024;
+
+out:
+	free(stat);
+
+	return num;
+}
+
+static unsigned int ls_get_term_width(void)
+{
+	struct winsize ws;
+	if (((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1) &&
+	     (ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1) &&
+	     (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)) ||
+	    (ws.ws_col == 0))
+		return 0;
+
+	return ws.ws_col;
+}
+
+static bool ls_has_all_grps(const char *has, char **must, size_t must_len)
+{
+	bool bret = false;
+
+	if (!has && must)
+		return false;
+	else if (!must)
+		return true;
+
+	char **tmp_has = lxc_string_split_and_trim(has, ',');
+	size_t tmp_has_len = lxc_array_len((void **)tmp_has);
+
+	/* Don't do any unnecessary work. */
+	if (must_len > tmp_has_len)
+		goto out;
+
+	size_t i, j;
+	for (i = 0; i < must_len; i++) {
+		for (j = 0; j < tmp_has_len; j++)
+			if (strcmp(must[i], tmp_has[j]) == 0)
+				break;
+		if (j == tmp_has_len)
+			break;
+	}
+	if (i == must_len)
+		bret = true;
+
+out:
+	lxc_free_array((void **)tmp_has, free);
+
+	return bret;
+}
+
+static struct ls *ls_new(struct ls **ls, size_t *size)
+{
+	struct ls *m, *n;
+
+	n = realloc(*ls, (*size + 1) * sizeof(struct ls));
+	if (!n)
+		return NULL;
+
+	*ls = n;
+	m = *ls + *size;
+	(*size)++;
+
+	*m = (struct ls){.name = NULL, .init = -1};
+
+	return m;
+}
+
+static void ls_print_names(struct ls *l, struct lengths *lht,
+		size_t size, size_t termwidth)
+{
+	/* If list is empty do nothing. */
+	if (size == 0)
+		return;
+
+	size_t i, len = 0;
+	struct ls *m = NULL;
+	for (i = 0, m = l; i < size; i++, m++) {
+		printf("%-*s", lht->name_length, m->name ? m->name : "-");
+		len += lht->name_length;
+		if ((len + lht->name_length) >= termwidth) {
+			printf("\n");
+			len = 0;
+		} else {
+			printf(" ");
+			len++;
+		}
+	}
+	if (len > 0)
+		printf("\n");
+}
+
+static void ls_print_fancy_format(struct ls *l, struct lengths *lht,
+		size_t size, const char *fancy_fmt)
+{
+	/* If list is empty do nothing. */
+	if (size == 0)
+		return;
+
+	char **tmp = lxc_string_split_and_trim(fancy_fmt, ',');
+	if (!tmp)
+		return;
+
+	char **s;
+	/* Check for invalid keys. */
+	for (s = tmp; s && *s; s++) {
+		if (strcasecmp(*s, "NAME") && strcasecmp(*s, "STATE") &&
+				strcasecmp(*s, "PID") && strcasecmp(*s, "RAM") &&
+				strcasecmp(*s, "SWAP") && strcasecmp(*s, "AUTOSTART") &&
+				strcasecmp(*s, "GROUPS") && strcasecmp(*s, "INTERFACE") &&
+				strcasecmp(*s, "IPV4") && strcasecmp(*s, "IPV6")) {
+			fprintf(stderr, "Invalid key: %s\n", *s);
+			return;
+		}
+	}
+
+	/* print header */
+	for (s = tmp; s && *s; s++) {
+		if (strcasecmp(*s, "NAME") == 0)
+			printf("%-*s ", lht->name_length, "NAME");
+		else if (strcasecmp(*s, "STATE") == 0)
+			printf("%-*s ", lht->state_length, "STATE");
+		else if (strcasecmp(*s, "PID") == 0)
+			printf("%-*s ", lht->init_length, "PID");
+		else if (strcasecmp(*s, "RAM") == 0)
+			printf("%-*s ", lht->ram_length + 2, "RAM");
+		else if (strcasecmp(*s, "SWAP") == 0)
+			printf("%-*s ", lht->swap_length + 2, "SWAP");
+		else if (strcasecmp(*s, "AUTOSTART") == 0)
+			printf("%-*s ", lht->autostart_length, "AUTOSTART");
+		else if (strcasecmp(*s, "GROUPS") == 0)
+			printf("%-*s ", lht->groups_length, "GROUPS");
+		else if (strcasecmp(*s, "INTERFACE") == 0)
+			printf("%-*s ", lht->interface_length, "INTERFACE");
+		else if (strcasecmp(*s, "IPV4") == 0)
+			printf("%-*s ", lht->ipv4_length, "IPV4");
+		else if (strcasecmp(*s, "IPV6") == 0)
+			printf("%-*s ", lht->ipv6_length, "IPV6");
+	}
+	printf("\n");
+
+	struct ls *m = NULL;
+	size_t i;
+	for (i = 0, m = l; i < size; i++, m++) {
+		for (s = tmp; s && *s; s++) {
+			if (strcasecmp(*s, "NAME") == 0) {
+				if (m->nestlvl > 0) {
+					printf("%*s", m->nestlvl, "\\");
+					printf("%-*s ", lht->name_length - m->nestlvl, m->name ? m->name : "-");
+				} else {
+					printf("%-*s ", lht->name_length, m->name ? m->name : "-");
+				}
+			} else if (strcasecmp(*s, "STATE") == 0) {
+				printf("%-*s ", lht->state_length, m->state ? m->state : "-");
+			} else if (strcasecmp(*s, "PID") == 0) {
+				if (m->init > 0)
+					printf("%-*d ", lht->init_length, m->init);
+				else
+					printf("%-*s ", lht->init_length, "-");
+			} else if (strcasecmp(*s, "RAM") == 0) {
+				if ((m->ram >= 0) && m->running)
+					printf("%*.2fMB ", lht->ram_length, m->ram);
+				else
+					printf("%-*s   ", lht->ram_length, "-");
+			} else if (strcasecmp(*s, "SWAP") == 0) {
+				if ((m->swap >= 0) && m->running)
+					printf("%*.2fMB ", lht->swap_length, m->swap);
+				else
+					printf("%-*s   ", lht->swap_length, "-");
+			} else if (strcasecmp(*s, "AUTOSTART") == 0) {
+				printf("%-*d ", lht->autostart_length, m->autostart);
+			} else if (strcasecmp(*s, "GROUPS") == 0) {
+				printf("%-*s ", lht->groups_length, m->groups ? m->groups : "-");
+			} else if (strcasecmp(*s, "INTERFACE") == 0) {
+				printf("%-*s ", lht->interface_length, m->interface ? m->interface : "-");
+			} else if (strcasecmp(*s, "IPV4") == 0) {
+				printf("%-*s ", lht->ipv4_length, m->ipv4 ? m->ipv4 : "-");
+			} else if (strcasecmp(*s, "IPV6") == 0) {
+				printf("%-*s ", lht->ipv6_length, m->ipv6 ? m->ipv6 : "-");
+			}
+		}
+		printf("\n");
+	}
+}
+
+static void ls_print_table(struct ls *l, struct lengths *lht,
+		size_t size)
+{
+	/* If list is empty do nothing. */
+	if (size == 0)
+		return;
+
+	struct ls *m = NULL;
+
+	/* print header */
+	printf("%-*s ", lht->name_length, "NAME");
+	printf("%-*s ", lht->state_length, "STATE");
+	printf("%-*s ", lht->autostart_length, "AUTOSTART");
+	printf("%-*s ", lht->groups_length, "GROUPS");
+	printf("%-*s ", lht->ipv4_length, "IPV4");
+	printf("%-*s ", lht->ipv6_length, "IPV6");
+	printf("\n");
+
+	size_t i;
+	for (i = 0, m = l; i < size; i++, m++) {
+		if (m->nestlvl > 0) {
+			printf("%*s", m->nestlvl, "\\");
+			printf("%-*s ", lht->name_length - m->nestlvl, m->name ? m->name : "-");
+		} else {
+		     printf("%-*s ", lht->name_length, m->name ? m->name : "-");
+		}
+		printf("%-*s ", lht->state_length, m->state ? m->state : "-");
+		printf("%-*d ", lht->autostart_length, m->autostart);
+		printf("%-*s ", lht->groups_length, m->groups ? m->groups : "-");
+		printf("%-*s ", lht->ipv4_length, m->ipv4 ? m->ipv4 : "-");
+		printf("%-*s ", lht->ipv6_length, m->ipv6 ? m->ipv6 : "-");
+		printf("\n");
+	}
+}
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg)
+{
+	char *invalid;
+	unsigned long int m, n = MAX_NESTLVL;
+	switch (c) {
+	case '1':
+		args->ls_line = true;
+		break;
+	case 'f':
+		args->ls_fancy = true;
+		break;
+	case LS_ACTIVE:
+		args->ls_active = true;
+		break;
+	case LS_FROZEN:
+		args->ls_frozen = true;
+		break;
+	case LS_RUNNING:
+		args->ls_running = true;
+		break;
+	case LS_STOPPED:
+		args->ls_stopped = true;
+		break;
+	case LS_NESTING:
+		/* In case strtoul() receives a string that represents a
+		 * negative number it will return ULONG_MAX - the number that
+		 * the string represents if the number the string represents is
+		 * < ULONG_MAX and ULONG_MAX otherwise. But it will consider
+		 * this valid input and not set errno. So we check manually if
+		 * the first character of num_string == '-'. Otherwise the
+		 * default level remains set. */
+		if (arg && !(*arg == '-')) {
+			errno = 0;
+			m = strtoul(arg, &invalid, 0);
+			/* ls_nesting has type unsigned int. */
+			if (!errno && (*invalid == '\0') && (m <= UINT_MAX))
+				n = m;
+		}
+		args->ls_nesting = n;
+		break;
+	case 'g':
+		args->groups = arg;
+		break;
+	case LS_FILTER:
+		args->ls_filter = arg;
+		break;
+	case 'F':
+		args->ls_fancy_format = arg;
+		break;
+	}
+
+	return 0;
+}
+
+static int ls_get_wrapper(void *wrap)
+{
+	int ret = -1;
+	size_t len = 0;
+	struct wrapargs *wargs = (struct wrapargs *)wrap;
+	struct ls *m = NULL, *n = NULL;
+
+	/* close pipe */
+	close(wargs->pipefd[0]);
+
+	/* &(char *){NULL} is no magic. It's just a compound literal which
+	 * allows us to avoid keeping a pointless variable around. */
+	ls_get(&m, &len, wargs->args, "", wargs->parent, wargs->nestlvl, &(char *){NULL}, 0, wargs->grps_must, wargs->grps_must_len);
+	if (!m)
+		goto out;
+
+	/* send length */
+	if (lxc_write_nointr(wargs->pipefd[1], &len, sizeof(len)) <= 0)
+		goto out;
+
+	size_t i;
+	for (i = 0, n = m; i < len; i++, n++) {
+		if (ls_serialize(wargs->pipefd[1], n) == -1)
+			goto out;
+	}
+	ret = 0;
+
+out:
+	shutdown(wargs->pipefd[1], SHUT_RDWR);
+	close(wargs->pipefd[1]);
+	ls_free(m, len);
+
+	return ret;
+}
+
+static int ls_remove_lock(const char *path, const char *name,
+		char **lockpath, size_t *len_lockpath, bool recalc)
+{
+	/* Avoid doing unnecessary work if we can. */
+	if (recalc) {
+		size_t newlen = strlen(path) + strlen(name) + strlen(RUNTIME_PATH) + /* / + lxc + / + lock + / + / = */ 11 + 1;
+		if (newlen > *len_lockpath) {
+			char *tmp = realloc(*lockpath, newlen * 2);
+			if (!tmp)
+				return -1;
+			*lockpath = tmp;
+			*len_lockpath = newlen * 2;
+		}
+	}
+
+	int check = snprintf(*lockpath, *len_lockpath, "%s/lxc/lock/%s/%s", RUNTIME_PATH, path, name);
+	if (check < 0 || (size_t)check >= *len_lockpath)
+		return -1;
+
+	lxc_rmdir_onedev(*lockpath, NULL);
+
+	return 0;
+}
+
+static int ls_send_str(int fd, const char *buf)
+{
+	size_t slen = 0;
+	if (buf)
+		slen = strlen(buf);
+	if (lxc_write_nointr(fd, &slen, sizeof(slen)) != sizeof(slen))
+		return -1;
+	if (slen > 0) {
+		if (lxc_write_nointr(fd, buf, slen) != (ssize_t)slen)
+			return -1;
+	}
+	return 0;
+}
+
+static int ls_serialize(int wpipefd, struct ls *n)
+{
+	ssize_t nbytes = sizeof(n->ram);
+	if (lxc_write_nointr(wpipefd, &n->ram, (size_t)nbytes) != nbytes)
+		return -1;
+
+	nbytes = sizeof(n->swap);
+	if (lxc_write_nointr(wpipefd, &n->swap, (size_t)nbytes) != nbytes)
+		return -1;
+
+	nbytes = sizeof(n->init);
+	if (lxc_write_nointr(wpipefd, &n->init, (size_t)nbytes) != nbytes)
+		return -1;
+
+	nbytes = sizeof(n->autostart);
+	if (lxc_write_nointr(wpipefd, &n->autostart, (size_t)nbytes) != nbytes)
+		return -1;
+
+	nbytes = sizeof(n->running);
+	if (lxc_write_nointr(wpipefd, &n->running, (size_t)nbytes) != nbytes)
+		return -1;
+
+	nbytes = sizeof(n->nestlvl);
+	if (lxc_write_nointr(wpipefd, &n->nestlvl, (size_t)nbytes) != nbytes)
+		return -1;
+
+	/* NAME */
+	if (ls_send_str(wpipefd, n->name) < 0)
+		return -1;
+
+	/* STATE */
+	if (ls_send_str(wpipefd, n->state) < 0)
+		return -1;
+
+	/* GROUPS */
+	if (ls_send_str(wpipefd, n->groups) < 0)
+		return -1;
+
+	/* INTERFACE */
+	if (ls_send_str(wpipefd, n->interface) < 0)
+		return -1;
+
+	/* IPV4 */
+	if (ls_send_str(wpipefd, n->ipv4) < 0)
+		return -1;
+
+	/* IPV6 */
+	if (ls_send_str(wpipefd, n->ipv6) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int ls_recv_str(int fd, char **buf)
+{
+	size_t slen = 0;
+	if (lxc_read_nointr(fd, &slen, sizeof(slen)) != sizeof(slen))
+		return -1;
+	if (slen > 0) {
+		*buf = malloc(sizeof(char) * (slen + 1));
+		if (!*buf)
+			return -1;
+		if (lxc_read_nointr(fd, *buf, slen) != (ssize_t)slen)
+			return -1;
+		(*buf)[slen] = '\0';
+	}
+	return 0;
+}
+
+static int ls_deserialize(int rpipefd, struct ls **m, size_t *len)
+{
+	struct ls *n;
+	size_t sublen = 0;
+	ssize_t nbytes = 0;
+
+	/* get length */
+	nbytes = sizeof(sublen);
+	if (lxc_read_nointr(rpipefd, &sublen, (size_t)nbytes) != nbytes)
+		return -1;
+
+	while (sublen-- > 0) {
+		n = ls_new(m, len);
+		if (!n)
+			return -1;
+
+		nbytes = sizeof(n->ram);
+		if (lxc_read_nointr(rpipefd, &n->ram, (size_t)nbytes) != nbytes)
+			return -1;
+
+		nbytes = sizeof(n->swap);
+		if (lxc_read_nointr(rpipefd, &n->swap, (size_t)nbytes) != nbytes)
+			return -1;
+
+		nbytes = sizeof(n->init);
+		if (lxc_read_nointr(rpipefd, &n->init, (size_t)nbytes) != nbytes)
+			return -1;
+
+		nbytes = sizeof(n->autostart);
+		if (lxc_read_nointr(rpipefd, &n->autostart, (size_t)nbytes) != nbytes)
+			return -1;
+
+		nbytes = sizeof(n->running);
+		if (lxc_read_nointr(rpipefd, &n->running, (size_t)nbytes) != nbytes)
+			return -1;
+
+		nbytes = sizeof(n->nestlvl);
+		if (lxc_read_nointr(rpipefd, &n->nestlvl, (size_t)nbytes) != nbytes)
+			return -1;
+
+		/* NAME */
+		if (ls_recv_str(rpipefd, &n->name) < 0)
+			return -1;
+
+		/* STATE */
+		if (ls_recv_str(rpipefd, &n->state) < 0)
+			return -1;
+
+		/* GROUPS */
+		if (ls_recv_str(rpipefd, &n->groups) < 0)
+			return -1;
+
+		/* INTERFACE */
+		if (ls_recv_str(rpipefd, &n->interface) < 0)
+			return -1;
+
+		/* IPV4 */
+		if (ls_recv_str(rpipefd, &n->ipv4) < 0)
+			return -1;
+
+		/* IPV6 */
+		if (ls_recv_str(rpipefd, &n->ipv6) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+static void ls_field_width(const struct ls *l, const size_t size,
+		struct lengths *lht)
+{
+	const struct ls *m;
+	size_t i, len = 0;
+	for (i = 0, m = l; i < size; i++, m++) {
+		if (m->name) {
+			len = strlen(m->name) + m->nestlvl;
+			if (len > lht->name_length)
+				lht->name_length = len;
+		}
+
+		if (m->state) {
+			len = strlen(m->state);
+			if (len > lht->state_length)
+				lht->state_length = len;
+		}
+
+		if (m->interface) {
+			len = strlen(m->interface);
+			if (len > lht->interface_length)
+				lht->interface_length = len;
+		}
+
+		if (m->groups) {
+			len = strlen(m->groups);
+			if (len > lht->groups_length)
+				lht->groups_length = len;
+		}
+		if (m->ipv4) {
+			len = strlen(m->ipv4);
+			if (len > lht->ipv4_length)
+				lht->ipv4_length = len;
+		}
+
+		if (m->ipv6) {
+			len = strlen(m->ipv6);
+			if (len > lht->ipv6_length)
+				lht->ipv6_length = len;
+		}
+
+		if ((len = snprintf(NULL, 0, "%.2f", m->ram)) > lht->ram_length)
+			lht->ram_length = len;
+
+		if ((len = snprintf(NULL, 0, "%.2f", m->swap)) > lht->swap_length)
+			lht->swap_length = len;
+
+		if (m->init != -1) {
+			if ((len = snprintf(NULL, 0, "%d", m->init)) > lht->init_length)
+				lht->init_length = len;
+		}
+	}
+}
diff --git a/src/lxc/tools/lxc_monitor.c b/src/lxc/tools/lxc_monitor.c
new file mode 100644
index 0000000..797ae8b
--- /dev/null
+++ b/src/lxc/tools/lxc_monitor.c
@@ -0,0 +1,211 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <regex.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <poll.h>
+
+#include "lxc.h"
+#include "log.h"
+#include "monitor.h"
+#include "arguments.h"
+
+lxc_log_define(lxc_monitor_ui, lxc);
+
+static bool quit_monitord;
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	switch (c) {
+	case 'Q': quit_monitord = true; break;
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	{"quit", no_argument, 0, 'Q'},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-monitor",
+	.help     = "\
+[--name=NAME]\n\
+\n\
+lxc-monitor monitors the state of the NAME container\n\
+\n\
+Options :\n\
+  -n, --name=NAME   NAME of the container\n\
+                    NAME may be a regular expression\n\
+  -Q, --quit        tell lxc-monitord to quit\n",
+	.name     = ".*",
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = NULL,
+	.lxcpath_additional = -1,
+};
+
+static void close_fds(struct pollfd *fds, nfds_t nfds)
+{
+	nfds_t i;
+
+	if (nfds < 1)
+		return;
+
+	for (i = 0; i < nfds; ++i) {
+		close(fds[i].fd);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	char *regexp;
+	struct lxc_msg msg;
+	regex_t preg;
+	struct pollfd *fds;
+	nfds_t nfds;
+	int len, rc_main, rc_snp, i;
+
+	rc_main = 0;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		return 1;
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		return 1;
+	lxc_log_options_no_override();
+
+	if (quit_monitord) {
+		int ret = EXIT_SUCCESS;
+		for (i = 0; i < my_args.lxcpath_cnt; i++) {
+			int fd;
+
+			fd = lxc_monitor_open(my_args.lxcpath[i]);
+			if (fd < 0) {
+				ERROR("Unable to open monitor on path: %s", my_args.lxcpath[i]);
+				ret = EXIT_FAILURE;
+				continue;
+			}
+			if (write(fd, "quit", 4) < 0) {
+				SYSERROR("Unable to close monitor on path: %s", my_args.lxcpath[i]);
+				ret = EXIT_FAILURE;
+				close(fd);
+				continue;
+			}
+			close(fd);
+		}
+		return ret;
+	}
+
+	len = strlen(my_args.name) + 3;
+	regexp = malloc(len + 3);
+	if (!regexp) {
+		ERROR("failed to allocate memory");
+		return 1;
+	}
+	rc_snp = snprintf(regexp, len, "^%s$", my_args.name);
+	if (rc_snp < 0 || rc_snp >= len) {
+		ERROR("Name too long");
+		rc_main = 1;
+		goto error;
+	}
+
+	if (regcomp(&preg, regexp, REG_NOSUB|REG_EXTENDED)) {
+		ERROR("failed to compile the regex '%s'", my_args.name);
+		rc_main = 1;
+		goto error;
+	}
+
+	fds = malloc(my_args.lxcpath_cnt * sizeof(struct pollfd));
+	if (!fds) {
+		SYSERROR("out of memory");
+		rc_main = -1;
+		goto cleanup;
+	}
+
+	nfds = my_args.lxcpath_cnt;
+	for (i = 0; i < nfds; i++) {
+		int fd;
+
+		lxc_monitord_spawn(my_args.lxcpath[i]);
+
+		fd = lxc_monitor_open(my_args.lxcpath[i]);
+		if (fd < 0) {
+			close_fds(fds, i);
+			rc_main = 1;
+			goto cleanup;
+		}
+		fds[i].fd = fd;
+		fds[i].events = POLLIN;
+		fds[i].revents = 0;
+	}
+
+	setlinebuf(stdout);
+
+	for (;;) {
+		if (lxc_monitor_read_fdset(fds, nfds, &msg, -1) < 0) {
+			rc_main = 1;
+			goto close_and_clean;
+		}
+
+		msg.name[sizeof(msg.name)-1] = '\0';
+		if (regexec(&preg, msg.name, 0, NULL, 0))
+			continue;
+
+		switch (msg.type) {
+		case lxc_msg_state:
+			printf("'%s' changed state to [%s]\n",
+			       msg.name, lxc_state2str(msg.value));
+			break;
+		case lxc_msg_exit_code:
+			printf("'%s' exited with status [%d]\n",
+			       msg.name, WEXITSTATUS(msg.value));
+			break;
+		default:
+			/* ignore garbage */
+			break;
+		}
+	}
+
+close_and_clean:
+	close_fds(fds, nfds);
+
+cleanup:
+	regfree(&preg);
+	free(fds);
+
+error:
+	free(regexp);
+
+	return rc_main;
+}
diff --git a/src/lxc/tools/lxc_snapshot.c b/src/lxc/tools/lxc_snapshot.c
new file mode 100644
index 0000000..8f44891
--- /dev/null
+++ b/src/lxc/tools/lxc_snapshot.c
@@ -0,0 +1,284 @@
+/*
+ *
+ * Copyright © 2013 Serge Hallyn <serge.hallyn at ubuntu.com>.
+ * Copyright © 2013 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "confile.h"
+#include <stdio.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "bdev.h"
+#include "lxc.h"
+#include "log.h"
+#include "arguments.h"
+#include "utils.h"
+
+lxc_log_define(lxc_snapshot_ui, lxc);
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg);
+
+static const struct option my_longopts[] = {
+	{"list", no_argument, 0, 'L'},
+	{"restore", required_argument, 0, 'r'},
+	{"newname", required_argument, 0, 'N'},
+	{"destroy", required_argument, 0, 'd'},
+	{"comment", required_argument, 0, 'c'},
+	{"showcomments", no_argument, 0, 'C'},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-snapshot",
+	.help = "\
+--name=NAME [-P lxcpath] [-L [-C]] [-c commentfile] [-r snapname [-N newname]]\n\
+\n\
+lxc-snapshot snapshots a container\n\
+\n\
+Options :\n\
+  -n, --name=NAME	 NAME of the container\n\
+  -L, --list             list all snapshots\n\
+  -r, --restore=NAME     restore snapshot NAME, e.g. 'snap0'\n\
+  -N, --newname=NEWNAME  NEWNAME for the restored container\n\
+  -d, --destroy=NAME     destroy snapshot NAME, e.g. 'snap0'\n\
+                         use ALL to destroy all snapshots\n\
+  -c, --comment=FILE     add FILE as a comment\n\
+  -C, --showcomments     show snapshot comments\n",
+	.options = my_longopts,
+	.parser = my_parser,
+	.checker = NULL,
+	.task = SNAP,
+};
+
+static int do_snapshot(struct lxc_container *c, char *commentfile);
+static int do_snapshot_destroy(struct lxc_container *c, char *snapname);
+static int do_snapshot_list(struct lxc_container *c, int print_comments);
+static int do_snapshot_restore(struct lxc_container *c,
+			       struct lxc_arguments *args);
+static int do_snapshot_task(struct lxc_container *c, enum task task);
+static void print_file(char *path);
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c;
+	int ret;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		exit(EXIT_FAILURE);
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		exit(EXIT_FAILURE);
+	lxc_log_options_no_override();
+
+	if (geteuid()) {
+		if (access(my_args.lxcpath[0], O_RDWR) < 0) {
+			fprintf(stderr, "You lack access to %s\n",
+				my_args.lxcpath[0]);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		fprintf(stderr, "System error loading container\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (!c->may_control(c)) {
+		fprintf(stderr, "Insufficent privileges to control %s\n",
+			my_args.name);
+		lxc_container_put(c);
+		exit(EXIT_FAILURE);
+	}
+
+	ret = do_snapshot_task(c, my_args.task);
+
+	lxc_container_put(c);
+
+	if (ret == 0)
+		exit(EXIT_SUCCESS);
+	exit(EXIT_FAILURE);
+}
+
+static int do_snapshot_task(struct lxc_container *c, enum task task)
+{
+	int ret = 0;
+
+	switch (task) {
+	case DESTROY:
+		ret = do_snapshot_destroy(c, my_args.snapname);
+		break;
+	case LIST:
+		ret = do_snapshot_list(c, my_args.print_comments);
+		break;
+	case RESTORE:
+		ret = do_snapshot_restore(c, &my_args);
+		break;
+	case SNAP:
+		ret = do_snapshot(c, my_args.commentfile);
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+
+	return ret;
+}
+
+static int my_parser(struct lxc_arguments *args, int c, char *arg)
+{
+	switch (c) {
+	case 'L':
+		args->task = LIST;
+		break;
+	case 'r':
+		args->task = RESTORE;
+		args->snapname = arg;
+		break;
+	case 'N':
+		args->newname = arg;
+		break;
+	case 'd':
+		args->task = DESTROY;
+		args->snapname = arg;
+		break;
+	case 'c':
+		args->commentfile = arg;
+		break;
+	case 'C':
+		args->print_comments = 1;
+		break;
+	}
+
+	return 0;
+}
+
+static int do_snapshot(struct lxc_container *c, char *commentfile)
+{
+	int ret;
+
+	ret = c->snapshot(c, commentfile);
+	if (ret < 0) {
+		ERROR("Error creating a snapshot");
+		return -1;
+	}
+
+	INFO("Created snapshot snap%d", ret);
+
+	return 0;
+}
+
+static int do_snapshot_destroy(struct lxc_container *c, char *snapname)
+{
+	bool ret;
+
+	if (strcmp(snapname, "ALL") == 0)
+		ret = c->snapshot_destroy_all(c);
+	else
+		ret = c->snapshot_destroy(c, snapname);
+
+	if (!ret) {
+		ERROR("Error destroying snapshot %s", snapname);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int do_snapshot_list(struct lxc_container *c, int print_comments)
+{
+	struct lxc_snapshot *s;
+	int i, n;
+
+	n = c->snapshot_list(c, &s);
+	if (n < 0) {
+		ERROR("Error listing snapshots");
+		return -1;
+	}
+	if (n == 0) {
+		printf("No snapshots\n");
+		return 0;
+	}
+
+	for (i = 0; i < n; i++) {
+		printf("%s (%s) %s\n", s[i].name, s[i].lxcpath, s[i].timestamp);
+		if (print_comments)
+			print_file(s[i].comment_pathname);
+		s[i].free(&s[i]);
+	}
+
+	free(s);
+
+	return 0;
+}
+
+static int do_snapshot_restore(struct lxc_container *c,
+			       struct lxc_arguments *args)
+{
+	int bret;
+
+	/* When restoring  a snapshot, the last optional argument if not given
+	 * explicitly via the corresponding command line option is the name to
+	 * use for the restored container. If no name is given, then the
+	 * original container will be destroyed and the restored container will
+	 * take its place. */
+	if ((!args->newname) && (args->argc > 1)) {
+		lxc_error(args, "Too many arguments");
+		return -1;
+	}
+
+	if ((!args->newname) && (args->argc == 1))
+		args->newname = args->argv[0];
+
+	bret = c->snapshot_restore(c, args->snapname, args->newname);
+	if (!bret) {
+		ERROR("Error restoring snapshot %s", args->snapname);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void print_file(char *path)
+{
+	if (!path)
+		return;
+
+	FILE *f = fopen(path, "r");
+	char *line = NULL;
+	size_t sz = 0;
+
+	if (!f)
+		return;
+
+	while (getline(&line, &sz, f) != -1) {
+		printf("%s", line);
+	}
+
+	free(line);
+	fclose(f);
+}
+
diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c
new file mode 100644
index 0000000..6b942ac
--- /dev/null
+++ b/src/lxc/tools/lxc_start.c
@@ -0,0 +1,357 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <net/if.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "log.h"
+#include "caps.h"
+#include "lxc.h"
+#include "conf.h"
+#include "cgroup.h"
+#include "utils.h"
+#include "confile.h"
+#include "arguments.h"
+
+#define OPT_SHARE_NET OPT_USAGE+1
+#define OPT_SHARE_IPC OPT_USAGE+2
+#define OPT_SHARE_UTS OPT_USAGE+3
+
+lxc_log_define(lxc_start_ui, lxc);
+
+static struct lxc_list defines;
+
+static int ensure_path(char **confpath, const char *path)
+{
+	int err = -1, fd;
+	char *fullpath = NULL;
+
+	if (path) {
+		if (access(path, W_OK)) {
+			fd = creat(path, 0600);
+			if (fd < 0 && errno != EEXIST) {
+				SYSERROR("failed to create '%s'", path);
+				goto err;
+			}
+			if (fd >= 0)
+				close(fd);
+		}
+
+		fullpath = realpath(path, NULL);
+		if (!fullpath) {
+			SYSERROR("failed to get the real path of '%s'", path);
+			goto err;
+		}
+
+		*confpath = strdup(fullpath);
+		if (!*confpath) {
+			ERROR("failed to dup string '%s'", fullpath);
+			goto err;
+		}
+	}
+	err = 0;
+
+err:
+	free(fullpath);
+	return err;
+}
+
+static int pid_from_lxcname(const char *lxcname_or_pid, const char *lxcpath) {
+	char *eptr;
+	int pid = strtol(lxcname_or_pid, &eptr, 10);
+	if (*eptr != '\0' || pid < 1) {
+		struct lxc_container *s;
+		s = lxc_container_new(lxcname_or_pid, lxcpath);
+		if (!s) {
+			SYSERROR("'%s' is not a valid pid nor a container name", lxcname_or_pid);
+			return -1;
+		}
+
+		if (!s->may_control(s)) {
+			SYSERROR("Insufficient privileges to control container '%s'", s->name);
+			lxc_container_put(s);
+			return -1;
+		}
+
+		pid = s->init_pid(s);
+		if (pid < 1) {
+			SYSERROR("Is container '%s' running?", s->name);
+			lxc_container_put(s);
+			return -1;
+		}
+
+		lxc_container_put(s);
+	}
+	if (kill(pid, 0) < 0) {
+		SYSERROR("Can't send signal to pid %d", pid);
+		return -1;
+	}
+
+	return pid;
+}
+
+static int open_ns(int pid, const char *ns_proc_name) {
+	int fd;
+	char path[MAXPATHLEN];
+	snprintf(path, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns_proc_name);
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0) {
+		SYSERROR("failed to open %s", path);
+		return -1;
+	}
+	return fd;
+}
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	switch (c) {
+	case 'c': args->console = arg; break;
+	case 'L': args->console_log = arg; break;
+	case 'd': args->daemonize = 1; break;
+	case 'F': args->daemonize = 0; break;
+	case 'f': args->rcfile = arg; break;
+	case 'C': args->close_all_fds = 1; break;
+	case 's': return lxc_config_define_add(&defines, arg);
+	case 'p': args->pidfile = arg; break;
+	case OPT_SHARE_NET: args->share_ns[LXC_NS_NET] = arg; break;
+	case OPT_SHARE_IPC: args->share_ns[LXC_NS_IPC] = arg; break;
+	case OPT_SHARE_UTS: args->share_ns[LXC_NS_UTS] = arg; break;
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	{"daemon", no_argument, 0, 'd'},
+	{"foreground", no_argument, 0, 'F'},
+	{"rcfile", required_argument, 0, 'f'},
+	{"define", required_argument, 0, 's'},
+	{"console", required_argument, 0, 'c'},
+	{"console-log", required_argument, 0, 'L'},
+	{"close-all-fds", no_argument, 0, 'C'},
+	{"pidfile", required_argument, 0, 'p'},
+	{"share-net", required_argument, 0, OPT_SHARE_NET},
+	{"share-ipc", required_argument, 0, OPT_SHARE_IPC},
+	{"share-uts", required_argument, 0, OPT_SHARE_UTS},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-start",
+	.help     = "\
+--name=NAME -- COMMAND\n\
+\n\
+lxc-start start COMMAND in specified container NAME\n\
+\n\
+Options :\n\
+  -n, --name=NAME        NAME of the container\n\
+  -d, --daemon           Daemonize the container (default)\n\
+  -F, --foreground       Start with the current tty attached to /dev/console\n\
+  -p, --pidfile=FILE     Create a file with the process id\n\
+  -f, --rcfile=FILE      Load configuration file FILE\n\
+  -c, --console=FILE     Use specified FILE for the container console\n\
+  -L, --console-log=FILE Log container console output to FILE\n\
+  -C, --close-all-fds    If any fds are inherited, close them\n\
+                         If not specified, exit with failure instead\n\
+                         Note: --daemon implies --close-all-fds\n\
+  -s, --define KEY=VAL   Assign VAL to configuration variable KEY\n\
+      --share-[net|ipc|uts]=NAME Share a namespace with another container or pid\n\
+",
+	.options   = my_longopts,
+	.parser    = my_parser,
+	.checker   = NULL,
+	.daemonize = 1,
+	.pidfile = NULL,
+};
+
+int main(int argc, char *argv[])
+{
+	int err = 1;
+	struct lxc_conf *conf;
+	char *const *args;
+	char *rcfile = NULL;
+	char *const default_args[] = {
+		"/sbin/init",
+		NULL,
+	};
+	struct lxc_container *c;
+
+	lxc_list_init(&defines);
+
+	if (lxc_caps_init())
+		return err;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		return err;
+
+	if (!my_args.argc)
+		args = default_args;
+	else
+		args = my_args.argv;
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		return err;
+	lxc_log_options_no_override();
+
+	const char *lxcpath = my_args.lxcpath[0];
+
+	/*
+	 * rcfile possibilities:
+	 * 1. rcfile from random path specified in cli option
+	 * 2. rcfile not specified, use $lxcpath/$lxcname/config
+	 * 3. rcfile not specified and does not exist.
+	 */
+	/* rcfile is specified in the cli option */
+	if (my_args.rcfile) {
+		rcfile = (char *)my_args.rcfile;
+		c = lxc_container_new(my_args.name, lxcpath);
+		if (!c) {
+			ERROR("Failed to create lxc_container");
+			return err;
+		}
+		c->clear_config(c);
+		if (!c->load_config(c, rcfile)) {
+			ERROR("Failed to load rcfile");
+			lxc_container_put(c);
+			return err;
+		}
+	} else {
+		int rc;
+
+		rc = asprintf(&rcfile, "%s/%s/config", lxcpath, my_args.name);
+		if (rc == -1) {
+			SYSERROR("failed to allocate memory");
+			return err;
+		}
+		INFO("using rcfile %s", rcfile);
+
+		/* container configuration does not exist */
+		if (access(rcfile, F_OK)) {
+			free(rcfile);
+			rcfile = NULL;
+		}
+		c = lxc_container_new(my_args.name, lxcpath);
+		if (!c) {
+			ERROR("Failed to create lxc_container");
+			return err;
+		}
+	}
+
+	if (c->is_running(c)) {
+		ERROR("Container is already running.");
+		err = 0;
+		goto out;
+	}
+	/*
+	 * We should use set_config_item() over &defines, which would handle
+	 * unset c->lxc_conf for us and let us not use lxc_config_define_load()
+	 */
+	if (!c->lxc_conf)
+		c->lxc_conf = lxc_conf_init();
+	conf = c->lxc_conf;
+
+	if (lxc_config_define_load(&defines, conf))
+		goto out;
+
+	if (!rcfile && !strcmp("/sbin/init", args[0])) {
+		ERROR("Executing '/sbin/init' with no configuration file may crash the host");
+		goto out;
+	}
+
+	if (ensure_path(&conf->console.path, my_args.console) < 0) {
+		ERROR("failed to ensure console path '%s'", my_args.console);
+		goto out;
+	}
+
+	if (ensure_path(&conf->console.log_path, my_args.console_log) < 0) {
+		ERROR("failed to ensure console log '%s'", my_args.console_log);
+		goto out;
+	}
+
+	if (my_args.pidfile != NULL) {
+		if (ensure_path(&c->pidfile, my_args.pidfile) < 0) {
+			ERROR("failed to ensure pidfile '%s'", my_args.pidfile);
+			goto out;
+		}
+	}
+
+	int i;
+	for (i = 0; i < LXC_NS_MAX; i++) {
+		if (my_args.share_ns[i] == NULL)
+			continue;
+
+		int pid = pid_from_lxcname(my_args.share_ns[i], lxcpath);
+		if (pid < 1)
+			goto out;
+
+		int fd = open_ns(pid, ns_info[i].proc_name);
+		if (fd < 0)
+			goto out;
+		conf->inherit_ns_fd[i] = fd;
+	}
+
+	if (!my_args.daemonize) {
+		c->want_daemonize(c, false);
+	}
+
+	if (my_args.close_all_fds)
+		c->want_close_all_fds(c, true);
+
+	if (args == default_args)
+		err = c->start(c, 0, NULL) ? 0 : 1;
+	else
+		err = c->start(c, 0, args) ? 0 : 1;
+
+	if (err) {
+		ERROR("The container failed to start.");
+		if (my_args.daemonize)
+			ERROR("To get more details, run the container in foreground mode.");
+		ERROR("Additional information can be obtained by setting the "
+		      "--logfile and --logpriority options.");
+		err = c->error_num;
+		lxc_container_put(c);
+		return err;
+	}
+
+out:
+	lxc_container_put(c);
+	return err;
+}
diff --git a/src/lxc/tools/lxc_stop.c b/src/lxc/tools/lxc_stop.c
new file mode 100644
index 0000000..10ddce6
--- /dev/null
+++ b/src/lxc/tools/lxc_stop.c
@@ -0,0 +1,246 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdio.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "lxc.h"
+#include "log.h"
+#include "arguments.h"
+#include "commands.h"
+#include "utils.h"
+
+#define OPT_NO_LOCK OPT_USAGE+1
+#define OPT_NO_KILL OPT_USAGE+2
+
+lxc_log_define(lxc_stop_ui, lxc);
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	switch (c) {
+	case 'r': args->reboot = 1; break;
+	case 'W': args->nowait = 1; break;
+	case 't': args->timeout = atoi(arg); break;
+	case 'k': args->hardstop = 1; break;
+	case OPT_NO_LOCK: args->nolock = 1; break;
+	case OPT_NO_KILL: args->nokill = 1; break;
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	{"reboot", no_argument, 0, 'r'},
+	{"nowait", no_argument, 0, 'W'},
+	{"timeout", required_argument, 0, 't'},
+	{"kill", no_argument, 0, 'k'},
+	{"nokill", no_argument, 0, OPT_NO_KILL},
+	{"nolock", no_argument, 0, OPT_NO_LOCK},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-stop",
+	.help     = "\
+--name=NAME\n\
+\n\
+lxc-stop stops a container with the identifier NAME\n\
+\n\
+Options :\n\
+  -n, --name=NAME   NAME of the container\n\
+  -r, --reboot      reboot the container\n\
+  -W, --nowait      don't wait for shutdown or reboot to complete\n\
+  -t, --timeout=T   wait T seconds before hard-stopping\n\
+  -k, --kill        kill container rather than request clean shutdown\n\
+      --nolock      Avoid using API locks\n\
+      --nokill      Only request clean shutdown, don't force kill after timeout\n",
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = NULL,
+	.timeout  = -2,
+};
+
+/* returns -1 on failure, 0 on success */
+static int do_reboot_and_check(struct lxc_arguments *a, struct lxc_container *c)
+{
+	int ret;
+	pid_t pid;
+	pid_t newpid;
+	int timeout = a->timeout;
+
+	pid = c->init_pid(c);
+	if (pid == -1)
+		return -1;
+	if (!c->reboot(c))
+		return -1;
+	if (a->nowait)
+		return 0;
+	if (timeout == 0)
+		goto out;
+
+	for (;;) {
+		/* can we use c-> wait for this, assuming it will
+		 * re-enter RUNNING?  For now just sleep */
+		int elapsed_time, curtime = 0;
+		struct timeval tv;
+
+		newpid = c->init_pid(c);
+		if (newpid != -1 && newpid != pid)
+			return 0;
+
+		if (timeout != -1) {
+			ret = gettimeofday(&tv, NULL);
+			if (ret)
+				break;
+			curtime = tv.tv_sec;
+		}
+
+		sleep(1);
+		if (timeout != -1) {
+			ret = gettimeofday(&tv, NULL);
+			if (ret)
+				break;
+			elapsed_time = tv.tv_sec - curtime;
+			if (timeout - elapsed_time <= 0)
+				break;
+			timeout -= elapsed_time;
+		}
+	}
+
+out:
+	newpid = c->init_pid(c);
+	if (newpid == -1 || newpid == pid) {
+		printf("Reboot did not complete before timeout\n");
+		return -1;
+	}
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c;
+	bool s;
+	int ret = 1;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		return 1;
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		return 1;
+	lxc_log_options_no_override();
+
+	/* Set default timeout */
+	if (my_args.timeout == -2) {
+		if (my_args.hardstop) {
+			my_args.timeout = 0;
+		}
+		else {
+			my_args.timeout = 60;
+		}
+	}
+
+	if (my_args.nowait) {
+		my_args.timeout = 0;
+	}
+
+	/* some checks */
+	if (!my_args.hardstop && my_args.timeout < -1) {
+		fprintf(stderr, "invalid timeout\n");
+		return 1;
+	}
+
+	if (my_args.hardstop && my_args.nokill) {
+		fprintf(stderr, "-k can't be used with --nokill\n");
+		return 1;
+	}
+
+	if (my_args.hardstop && my_args.reboot) {
+		fprintf(stderr, "-k can't be used with -r\n");
+		return 1;
+	}
+
+	if (my_args.hardstop && my_args.timeout) {
+		fprintf(stderr, "-k doesn't allow timeouts\n");
+		return 1;
+	}
+
+	if (my_args.nolock && !my_args.hardstop) {
+		fprintf(stderr, "--nolock may only be used with -k\n");
+		return 1;
+	}
+
+	/* shortcut - if locking is bogus, we should be able to kill
+	 * containers at least */
+	if (my_args.nolock)
+		return lxc_cmd_stop(my_args.name, my_args.lxcpath[0]);
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		fprintf(stderr, "Error opening container\n");
+		goto out;
+	}
+
+	if (!c->may_control(c)) {
+		fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+		goto out;
+	}
+
+	if (!c->is_running(c)) {
+		fprintf(stderr, "%s is not running\n", c->name);
+		ret = 2;
+		goto out;
+	}
+
+	/* kill */
+	if (my_args.hardstop) {
+		ret = c->stop(c) ? 0 : 1;
+		goto out;
+	}
+
+	/* reboot */
+	if (my_args.reboot) {
+		ret = do_reboot_and_check(&my_args, c);
+		goto out;
+	}
+
+	/* shutdown */
+	s = c->shutdown(c, my_args.timeout);
+	if (!s) {
+		if (my_args.timeout == 0)
+			ret = 0;
+		else if (my_args.nokill)
+			ret = 1;
+		else
+			ret = c->stop(c) ? 0 : 1;
+	} else
+		ret = 0;
+
+out:
+	lxc_container_put(c);
+	if (ret < 0)
+		return 1;
+	return ret;
+}
diff --git a/src/lxc/tools/lxc_top.c b/src/lxc/tools/lxc_top.c
new file mode 100644
index 0000000..c4cb871
--- /dev/null
+++ b/src/lxc/tools/lxc_top.c
@@ -0,0 +1,510 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2014 Oracle.
+ *
+ * Authors:
+ * Dwight Engen <dwight.engen at oracle.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <lxc/lxccontainer.h>
+
+#include "arguments.h"
+#include "log.h"
+#include "lxc.h"
+#include "mainloop.h"
+#include "utils.h"
+
+lxc_log_define(lxc_top_ui, lxc);
+
+#define USER_HZ   100
+#define ESC       "\033"
+#define TERMCLEAR ESC "[H" ESC "[J"
+#define TERMNORM  ESC "[0m"
+#define TERMBOLD  ESC "[1m"
+#define TERMRVRS  ESC "[7m"
+
+struct stats {
+	uint64_t mem_used;
+	uint64_t mem_limit;
+	uint64_t kmem_used;
+	uint64_t kmem_limit;
+	uint64_t cpu_use_nanos;
+	uint64_t cpu_use_user;
+	uint64_t cpu_use_sys;
+	uint64_t blkio;
+};
+
+struct ct {
+	struct lxc_container *c;
+	struct stats *stats;
+};
+
+static int delay = 3;
+static char sort_by = 'n';
+static int sort_reverse = 0;
+
+static struct termios oldtios;
+static struct ct *ct = NULL;
+static int ct_alloc_cnt = 0;
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	switch (c) {
+	case 'd': delay = atoi(arg); break;
+	case 's': sort_by = arg[0]; break;
+	case 'r': sort_reverse = 1; break;
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	{"delay",   required_argument, 0, 'd'},
+	{"sort",    required_argument, 0, 's'},
+	{"reverse", no_argument,       0, 'r'},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-top",
+	.help     = "\
+[--name=NAME]\n\
+\n\
+lxc-top monitors the state of the active containers\n\
+\n\
+Options :\n\
+  -d, --delay     delay in seconds between refreshes (default: 3.0)\n\
+  -s, --sort      sort by [n,c,b,m] (default: n) where\n\
+                  n = Name\n\
+                  c = CPU use\n\
+                  b = Block I/O use\n\
+                  m = Memory use\n\
+                  k = Kernel memory use\n\
+  -r, --reverse   sort in reverse (descending) order\n",
+	.name     = ".*",
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = NULL,
+	.lxcpath_additional = -1,
+};
+
+static void stdin_tios_restore(void)
+{
+	tcsetattr(0, TCSAFLUSH, &oldtios);
+	fprintf(stderr, "\n");
+}
+
+static int stdin_tios_setup(void)
+{
+	struct termios newtios;
+
+	if (!isatty(0)) {
+		ERROR("stdin is not a tty");
+		return -1;
+	}
+
+	if (tcgetattr(0, &oldtios)) {
+		SYSERROR("failed to get current terminal settings");
+		return -1;
+	}
+
+	newtios = oldtios;
+
+	/* turn off echo and line buffering */
+	newtios.c_iflag &= ~IGNBRK;
+	newtios.c_iflag &= BRKINT;
+	newtios.c_lflag &= ~(ECHO|ICANON);
+	newtios.c_cc[VMIN] = 1;
+	newtios.c_cc[VTIME] = 0;
+
+	if (tcsetattr(0, TCSAFLUSH, &newtios)) {
+		ERROR("failed to set new terminal settings");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int stdin_tios_rows(void)
+{
+	struct winsize wsz;
+	if (isatty(0) && ioctl(0, TIOCGWINSZ, &wsz) == 0)
+		return wsz.ws_row;
+	return 25;
+}
+
+static int stdin_handler(int fd, uint32_t events, void *data,
+			 struct lxc_epoll_descr *descr)
+{
+	char *in_char = data;
+
+	if (events & EPOLLIN) {
+		int rc;
+
+		rc = read(fd, in_char, sizeof(*in_char));
+		if (rc <= 0)
+			*in_char = '\0';
+	}
+
+	if (events & EPOLLHUP)
+		*in_char = 'q';
+	return 1;
+}
+
+static void sig_handler(int sig)
+{
+	exit(EXIT_SUCCESS);
+}
+
+static void size_humanize(unsigned long long val, char *buf, size_t bufsz)
+{
+	if (val > 1 << 30) {
+		snprintf(buf, bufsz, "%u.%2.2u GB",
+			    (int)(val >> 30),
+			    (int)(val & ((1 << 30) - 1)) / 10737419);
+	} else if (val > 1 << 20) {
+		int x = val + 5243;  /* for rounding */
+		snprintf(buf, bufsz, "%u.%2.2u MB",
+			    x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
+	} else if (val > 1 << 10) {
+		int x = val + 5;  /* for rounding */
+		snprintf(buf, bufsz, "%u.%2.2u KB",
+			    x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
+	} else {
+		snprintf(buf, bufsz, "%3u.00   ", (int)val);
+	}
+}
+
+static uint64_t stat_get_int(struct lxc_container *c, const char *item)
+{
+	char buf[80];
+	int len;
+	uint64_t val;
+
+	len = c->get_cgroup_item(c, item, buf, sizeof(buf));
+	if (len <= 0) {
+		ERROR("unable to read cgroup item %s", item);
+		return 0;
+	}
+
+	val = strtoull(buf, NULL, 0);
+	return val;
+}
+
+static uint64_t stat_match_get_int(struct lxc_container *c, const char *item,
+				   const char *match, int column)
+{
+	char buf[4096];
+	int i,j,len;
+	uint64_t val = 0;
+	char **lines, **cols;
+	size_t matchlen;
+
+	len = c->get_cgroup_item(c, item, buf, sizeof(buf));
+	if (len <= 0) {
+		ERROR("unable to read cgroup item %s", item);
+		goto out;
+	}
+
+	lines = lxc_string_split_and_trim(buf, '\n');
+	if (!lines)
+		goto out;
+
+	matchlen = strlen(match);
+	for (i = 0; lines[i]; i++) {
+		if (strncmp(lines[i], match, matchlen) == 0) {
+			cols = lxc_string_split_and_trim(lines[i], ' ');
+			if (!cols)
+				goto err1;
+			for (j = 0; cols[j]; j++) {
+				if (j == column) {
+					val = strtoull(cols[j], NULL, 0);
+					break;
+				}
+			}
+			lxc_free_array((void **)cols, free);
+			break;
+		}
+	}
+err1:
+	lxc_free_array((void **)lines, free);
+out:
+	return val;
+}
+
+static void stats_get(struct lxc_container *c, struct ct *ct, struct stats *total)
+{
+	ct->c = c;
+	ct->stats->mem_used      = stat_get_int(c, "memory.usage_in_bytes");
+	ct->stats->mem_limit     = stat_get_int(c, "memory.limit_in_bytes");
+	ct->stats->kmem_used     = stat_get_int(c, "memory.kmem.usage_in_bytes");
+	ct->stats->kmem_limit    = stat_get_int(c, "memory.kmem.limit_in_bytes");
+	ct->stats->cpu_use_nanos = stat_get_int(c, "cpuacct.usage");
+	ct->stats->cpu_use_user  = stat_match_get_int(c, "cpuacct.stat", "user", 1);
+	ct->stats->cpu_use_sys   = stat_match_get_int(c, "cpuacct.stat", "system", 1);
+	ct->stats->blkio         = stat_match_get_int(c, "blkio.throttle.io_service_bytes", "Total", 1);
+
+	if (total) {
+		total->mem_used      = total->mem_used      + ct->stats->mem_used;
+		total->mem_limit     = total->mem_limit     + ct->stats->mem_limit;
+		total->kmem_used     = total->kmem_used     + ct->stats->kmem_used;
+		total->kmem_limit    = total->kmem_limit    + ct->stats->kmem_limit;
+		total->cpu_use_nanos = total->cpu_use_nanos + ct->stats->cpu_use_nanos;
+		total->cpu_use_user  = total->cpu_use_user  + ct->stats->cpu_use_user;
+		total->cpu_use_sys   = total->cpu_use_sys   + ct->stats->cpu_use_sys;
+		total->blkio         = total->blkio         + ct->stats->blkio;
+	}
+}
+
+static void stats_print_header(struct stats *stats)
+{
+	printf(TERMRVRS TERMBOLD);
+	printf("%-18s %12s %12s %12s %14s %10s", "Container", "CPU",  "CPU",  "CPU",  "BlkIO", "Mem");
+	if (stats->kmem_used > 0)
+		printf(" %10s", "KMem");
+	printf("\n");
+
+	printf("%-18s %12s %12s %12s %14s %10s", "Name",      "Used", "Sys",  "User", "Total", "Used");
+	if (stats->kmem_used > 0)
+		printf(" %10s", "Used");
+	printf("\n");
+	printf(TERMNORM);
+}
+
+static void stats_print(const char *name, const struct stats *stats,
+			const struct stats *total)
+{
+	char blkio_str[20];
+	char mem_used_str[20];
+	char kmem_used_str[20];
+
+	size_humanize(stats->blkio, blkio_str, sizeof(blkio_str));
+	size_humanize(stats->mem_used, mem_used_str, sizeof(mem_used_str));
+
+	printf("%-18.18s %12.2f %12.2f %12.2f %14s %10s",
+	       name,
+	       (float)stats->cpu_use_nanos / 1000000000,
+	       (float)stats->cpu_use_sys  / USER_HZ,
+	       (float)stats->cpu_use_user / USER_HZ,
+	       blkio_str,
+	       mem_used_str);
+	if (total->kmem_used > 0) {
+		size_humanize(stats->kmem_used, kmem_used_str, sizeof(kmem_used_str));
+		printf(" %10s", kmem_used_str);
+	}
+}
+
+static int cmp_name(const void *sct1, const void *sct2)
+{
+	const struct ct *ct1 = sct1;
+	const struct ct *ct2 = sct2;
+
+	if (sort_reverse)
+		return strcmp(ct2->c->name, ct1->c->name);
+	return strcmp(ct1->c->name, ct2->c->name);
+}
+
+static int cmp_cpuuse(const void *sct1, const void *sct2)
+{
+	const struct ct *ct1 = sct1;
+	const struct ct *ct2 = sct2;
+
+	if (sort_reverse)
+		return ct2->stats->cpu_use_nanos < ct1->stats->cpu_use_nanos;
+	return ct1->stats->cpu_use_nanos < ct2->stats->cpu_use_nanos;
+}
+
+static int cmp_blkio(const void *sct1, const void *sct2)
+{
+	const struct ct *ct1 = sct1;
+	const struct ct *ct2 = sct2;
+
+	if (sort_reverse)
+		return ct2->stats->blkio < ct1->stats->blkio;
+	return ct1->stats->blkio < ct2->stats->blkio;
+}
+
+static int cmp_memory(const void *sct1, const void *sct2)
+{
+	const struct ct *ct1 = sct1;
+	const struct ct *ct2 = sct2;
+
+	if (sort_reverse)
+		return ct2->stats->mem_used < ct1->stats->mem_used;
+	return ct1->stats->mem_used < ct2->stats->mem_used;
+}
+
+static int cmp_kmemory(const void *sct1, const void *sct2)
+{
+	const struct ct *ct1 = sct1;
+	const struct ct *ct2 = sct2;
+
+	if (sort_reverse)
+		return ct2->stats->kmem_used < ct1->stats->kmem_used;
+	return ct1->stats->kmem_used < ct2->stats->kmem_used;
+}
+
+static void ct_sort(int active)
+{
+	int (*cmp_func)(const void *, const void *);
+
+	switch(sort_by) {
+	default:
+	case 'n': cmp_func = cmp_name; break;
+	case 'c': cmp_func = cmp_cpuuse; break;
+	case 'b': cmp_func = cmp_blkio; break;
+	case 'm': cmp_func = cmp_memory; break;
+	case 'k': cmp_func = cmp_kmemory; break;
+	}
+	qsort(ct, active, sizeof(*ct), (int (*)(const void *,const void *))cmp_func);
+}
+
+static void ct_free(void)
+{
+	int i;
+
+	for (i = 0; i < ct_alloc_cnt; i++) {
+		if (ct[i].c) {
+			lxc_container_put(ct[i].c);
+			ct[i].c = NULL;
+		}
+		free(ct[i].stats);
+		ct[i].stats = NULL;
+	}
+}
+
+static void ct_realloc(int active_cnt)
+{
+	int i;
+
+	if (active_cnt > ct_alloc_cnt) {
+		ct_free();
+		ct = realloc(ct, sizeof(*ct) * active_cnt);
+		if (!ct) {
+			ERROR("cannot alloc mem");
+			exit(EXIT_FAILURE);
+		}
+		for (i = 0; i < active_cnt; i++) {
+			ct[i].stats = malloc(sizeof(*ct[0].stats));
+			if (!ct[i].stats) {
+				ERROR("cannot alloc mem");
+				exit(EXIT_FAILURE);
+			}
+		}
+		ct_alloc_cnt = active_cnt;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	struct lxc_epoll_descr descr;
+	int ret, ct_print_cnt;
+	char in_char;
+
+	ret = EXIT_FAILURE;
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		goto out;
+
+	ct_print_cnt = stdin_tios_rows() - 3; /* 3 -> header and total */
+	if (stdin_tios_setup() < 0) {
+		ERROR("failed to setup terminal");
+		goto out;
+	}
+
+	/* ensure the terminal gets restored */
+	atexit(stdin_tios_restore);
+	signal(SIGINT, sig_handler);
+	signal(SIGQUIT, sig_handler);
+
+	if (lxc_mainloop_open(&descr)) {
+		ERROR("failed to create mainloop");
+		goto out;
+	}
+
+	ret = lxc_mainloop_add_handler(&descr, 0, stdin_handler, &in_char);
+	if (ret) {
+		ERROR("failed to add stdin handler");
+		ret = EXIT_FAILURE;
+		goto err1;
+	}
+
+	for(;;) {
+		struct lxc_container **active;
+		int i, active_cnt;
+		struct stats total;
+		char total_name[30];
+
+		active_cnt = list_active_containers(my_args.lxcpath[0], NULL, &active);
+		ct_realloc(active_cnt);
+
+		memset(&total, 0, sizeof(total));
+		for (i = 0; i < active_cnt; i++)
+			stats_get(active[i], &ct[i], &total);
+
+		ct_sort(active_cnt);
+
+		printf(TERMCLEAR);
+		stats_print_header(&total);
+		for (i = 0; i < active_cnt && i < ct_print_cnt; i++) {
+			stats_print(ct[i].c->name, ct[i].stats, &total);
+			printf("\n");
+		}
+		sprintf(total_name, "TOTAL %d of %d", i, active_cnt);
+		stats_print(total_name, &total, &total);
+		fflush(stdout);
+
+		for (i = 0; i < active_cnt; i++) {
+			lxc_container_put(ct[i].c);
+			ct[i].c = NULL;
+		}
+
+		in_char = '\0';
+		ret = lxc_mainloop(&descr, 1000 * delay);
+		if (ret != 0 || in_char == 'q')
+			break;
+		switch(in_char) {
+		case 'r':
+			sort_reverse ^= 1;
+			break;
+		case 'n':
+		case 'c':
+		case 'b':
+		case 'm':
+		case 'k':
+			if (sort_by == in_char)
+				sort_reverse ^= 1;
+			else
+				sort_reverse = 0;
+			sort_by = in_char;
+		}
+	}
+	ret = EXIT_SUCCESS;
+
+err1:
+	lxc_mainloop_close(&descr);
+out:
+	return ret;
+}
diff --git a/src/lxc/tools/lxc_unfreeze.c b/src/lxc/tools/lxc_unfreeze.c
new file mode 100644
index 0000000..3a13d37
--- /dev/null
+++ b/src/lxc/tools/lxc_unfreeze.c
@@ -0,0 +1,90 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <sys/types.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "lxc.h"
+#include "log.h"
+#include "arguments.h"
+
+lxc_log_define(lxc_unfreeze_ui, lxc);
+
+static const struct option my_longopts[] = {
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-unfreeze",
+	.help     = "\
+--name=NAME\n\
+\n\
+lxc-unfreeze unfreezes a container with the identifier NAME\n\
+\n\
+Options :\n\
+  -n, --name=NAME   NAME of the container\n",
+	.options  = my_longopts,
+	.parser   = NULL,
+	.checker  = NULL,
+};
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		exit(1);
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		exit(1);
+	lxc_log_options_no_override();
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c) {
+		ERROR("No such container: %s:%s", my_args.lxcpath[0], my_args.name);
+		exit(1);
+	}
+
+	if (!c->may_control(c)) {
+		ERROR("Insufficent privileges to control %s:%s", my_args.lxcpath[0], my_args.name);
+		lxc_container_put(c);
+		exit(1);
+	}
+
+	if (!c->unfreeze(c)) {
+		ERROR("Failed to unfreeze %s:%s", my_args.lxcpath[0], my_args.name);
+		lxc_container_put(c);
+		exit(1);
+	}
+
+	lxc_container_put(c);
+
+	exit(0);
+}
diff --git a/src/lxc/tools/lxc_unshare.c b/src/lxc/tools/lxc_unshare.c
new file mode 100644
index 0000000..e629525
--- /dev/null
+++ b/src/lxc/tools/lxc_unshare.c
@@ -0,0 +1,257 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <netinet/in.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "caps.h"
+#include "cgroup.h"
+#include "error.h"
+#include "log.h"
+#include "namespace.h"
+#include "network.h"
+#include "utils.h"
+
+/* Define sethostname() if missing from the C library */
+#ifndef HAVE_SETHOSTNAME
+static int sethostname(const char * name, size_t len)
+{
+#ifdef __NR_sethostname
+return syscall(__NR_sethostname, name, len);
+#else
+errno = ENOSYS;
+return -1;
+#endif
+}
+#endif
+
+lxc_log_define(lxc_unshare_ui, lxc);
+
+struct my_iflist
+{
+	char *mi_ifname;
+	struct my_iflist *mi_next;
+};
+
+static void usage(char *cmd)
+{
+	fprintf(stderr, "%s <options> command [command_arguments]\n", basename(cmd));
+	fprintf(stderr, "Options are:\n");
+	fprintf(stderr, "\t -s flags   : ORed list of flags to unshare:\n" \
+			"\t           MOUNT, PID, UTSNAME, IPC, USER, NETWORK\n");
+	fprintf(stderr, "\t -u <id>      : new id to be set if -s USER is specified\n");
+	fprintf(stderr, "\t -i <iface>   : Interface name to be moved into container (presumably with NETWORK unsharing set)\n");
+	fprintf(stderr, "\t -H <hostname>: Set the hostname in the container\n");
+	fprintf(stderr, "\t -d           : Daemonize (do not wait for container to exit)\n");
+	fprintf(stderr, "\t -M           : reMount default fs inside container (/proc /dev/shm /dev/mqueue)\n");
+	_exit(1);
+}
+
+static bool lookup_user(const char *optarg, uid_t *uid)
+{
+	char name[sysconf(_SC_LOGIN_NAME_MAX)];
+	struct passwd *pwent = NULL;
+
+	if (!optarg || (optarg[0] == '\0'))
+		return false;
+
+	if (sscanf(optarg, "%u", uid) < 1) {
+		/* not a uid -- perhaps a username */
+		if (sscanf(optarg, "%s", name) < 1)
+			return false;
+
+		pwent = getpwnam(name);
+		if (!pwent) {
+			ERROR("invalid username %s", name);
+			return false;
+		}
+		*uid = pwent->pw_uid;
+	} else {
+		pwent = getpwuid(*uid);
+		if (!pwent) {
+			ERROR("invalid uid %u", *uid);
+			return false;
+		}
+	}
+	return true;
+}
+
+
+struct start_arg {
+	char ***args;
+	int *flags;
+	uid_t *uid;
+	bool setuid;
+	int want_default_mounts;
+	const char *want_hostname;
+};
+
+static int do_start(void *arg)
+{
+	struct start_arg *start_arg = arg;
+	char **args = *start_arg->args;
+	int flags = *start_arg->flags;
+	uid_t uid = *start_arg->uid;
+	int want_default_mounts = start_arg->want_default_mounts;
+	const char *want_hostname = start_arg->want_hostname;
+
+	if ((flags & CLONE_NEWNS) && want_default_mounts)
+		lxc_setup_fs();
+
+	if ((flags & CLONE_NEWUTS) && want_hostname)
+		if (sethostname(want_hostname, strlen(want_hostname)) < 0) {
+			ERROR("failed to set hostname %s: %s", want_hostname, strerror(errno));
+			exit(1);
+		}
+
+	// Setuid is useful even without a new user id space
+	if (start_arg->setuid && setuid(uid)) {
+		ERROR("failed to set uid %d: %s", uid, strerror(errno));
+		exit(1);
+	}
+
+	execvp(args[0], args);
+
+	ERROR("failed to exec: '%s': %s", args[0], strerror(errno));
+	return 1;
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, status;
+	int ret;
+	char *namespaces = NULL;
+	char **args;
+	int flags = 0;
+	int daemonize = 0;
+	uid_t uid = 0; /* valid only if (flags & CLONE_NEWUSER) */
+	pid_t pid;
+	struct my_iflist *tmpif, *my_iflist = NULL;
+	struct start_arg start_arg = {
+		.args = &args,
+		.uid = &uid,
+		.setuid = false,
+		.flags = &flags,
+		.want_hostname = NULL,
+		.want_default_mounts = 0,
+	};
+
+	while ((opt = getopt(argc, argv, "s:u:hH:i:dM")) != -1) {
+		switch (opt) {
+		case 's':
+			namespaces = optarg;
+			break;
+		case 'i':
+			if (!(tmpif = malloc(sizeof(*tmpif)))) {
+				perror("malloc");
+				exit(1);
+			}
+			tmpif->mi_ifname = optarg;
+			tmpif->mi_next = my_iflist;
+			my_iflist = tmpif;
+			break;
+		case 'd':
+			daemonize = 1;
+			break;
+		case 'M':
+			start_arg.want_default_mounts = 1;
+			break;
+		case 'H':
+			start_arg.want_hostname = optarg;
+			break;
+		case 'h':
+			usage(argv[0]);
+			break;
+		case 'u':
+			if (!lookup_user(optarg, &uid))
+				return 1;
+			start_arg.setuid = true;
+		}
+	}
+
+	if (argv[optind] == NULL) {
+		ERROR("a command to execute in the new namespace is required");
+		return 1;
+	}
+
+	args = &argv[optind];
+
+	ret = lxc_caps_init();
+	if (ret)
+		return 1;
+
+	ret = lxc_fill_namespace_flags(namespaces, &flags);
+	if (ret)
+		usage(argv[0]);
+
+	if (!(flags & CLONE_NEWNET) && my_iflist) {
+		ERROR("-i <interfacename> needs -s NETWORK option");
+		return 1;
+	}
+
+	if (!(flags & CLONE_NEWUTS) && start_arg.want_hostname) {
+		ERROR("-H <hostname> needs -s UTSNAME option");
+		return 1;
+	}
+
+	if (!(flags & CLONE_NEWNS) && start_arg.want_default_mounts) {
+		ERROR("-M needs -s MOUNT option");
+		return 1;
+	}
+
+	pid = lxc_clone(do_start, &start_arg, flags);
+	if (pid < 0) {
+		ERROR("failed to clone");
+		return 1;
+	}
+
+	if (my_iflist) {
+		for (tmpif = my_iflist; tmpif; tmpif = tmpif->mi_next) {
+			if (lxc_netdev_move_by_name(tmpif->mi_ifname, pid, NULL) < 0)
+				fprintf(stderr,"Could not move interface %s into container %d: %s\n", tmpif->mi_ifname, pid, strerror(errno));
+		}
+	}
+
+	if (daemonize)
+		exit(0);
+
+	if (waitpid(pid, &status, 0) < 0) {
+		ERROR("failed to wait for '%d'", pid);
+		return 1;
+	}
+
+	return  lxc_error_set_and_log(pid, status);
+}
diff --git a/src/lxc/tools/lxc_usernsexec.c b/src/lxc/tools/lxc_usernsexec.c
new file mode 100644
index 0000000..6745ac3
--- /dev/null
+++ b/src/lxc/tools/lxc_usernsexec.c
@@ -0,0 +1,385 @@
+/*
+ * (C) Copyright IBM Corp. 2008
+ * (C) Copyright Canonical, Inc 2010-2013
+ *
+ * Authors:
+ * Serge Hallyn <serge.hallyn at ubuntu.com>
+ * (Once upon a time, this was based on nsexec from the IBM
+ *  container tools)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <libgen.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
+#include <sched.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "conf.h"
+#include "namespace.h"
+#include "utils.h"
+
+#ifndef MS_REC
+#define MS_REC 16384
+#endif
+
+#ifndef MS_SLAVE
+#define MS_SLAVE (1<<19)
+#endif
+
+int unshare(int flags);
+
+static void usage(const char *name)
+{
+	printf("usage: %s [-h] [-m <uid-maps>] -- [command [arg ..]]\n", name);
+	printf("\n");
+	printf("  -h		this message\n");
+	printf("\n");
+	printf("  -m <uid-maps> uid maps to use\n");
+	printf("\n");
+	printf("  uid-maps: [u|g|b]:ns_id:host_id:range\n");
+	printf("            [u|g|b]: map user id, group id, or both\n");
+	printf("            ns_id: the base id in the new namespace\n");
+	printf("            host_id: the base id in the parent namespace\n");
+	printf("            range: how many ids to map\n");
+	printf("  Note: This program uses newuidmap(2) and newgidmap(2).\n");
+	printf("        As such, /etc/subuid and /etc/subgid must grant the\n");
+	printf("        calling user permission to use the mapped ranges\n");
+	exit(1);
+}
+
+static void opentty(const char * tty, int which) {
+	int fd, flags;
+
+	if (tty[0] == '\0')
+		return;
+
+	fd = open(tty, O_RDWR | O_NONBLOCK);
+	if (fd == -1) {
+		printf("WARN: could not reopen tty: %s\n", strerror(errno));
+		return;
+	}
+
+	flags = fcntl(fd, F_GETFL);
+	flags &= ~O_NONBLOCK;
+	if (fcntl(fd, F_SETFL, flags) < 0) {
+		printf("WARN: could not set fd flags: %s\n", strerror(errno));
+		return;
+	}
+
+	close(which);
+	if (fd != which) {
+		dup2(fd, which);
+		close(fd);
+	}
+}
+// Code copy end
+
+static int do_child(void *vargv)
+{
+	char **argv = (char **)vargv;
+
+	// Assume we want to become root
+	if (setgid(0) < 0) {
+		perror("setgid");
+		return -1;
+	}
+	if (setuid(0) < 0) {
+		perror("setuid");
+		return -1;
+	}
+	if (setgroups(0, NULL) < 0) {
+		perror("setgroups");
+		return -1;
+	}
+	if (unshare(CLONE_NEWNS) < 0) {
+		perror("unshare CLONE_NEWNS");
+		return -1;
+	}
+	if (detect_shared_rootfs()) {
+		if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
+			printf("Failed to make / rslave");
+			return -1;
+		}
+	}
+	execvp(argv[0], argv);
+	perror("execvpe");
+	return -1;
+}
+
+static struct lxc_list active_map;
+
+/*
+ * given a string like "b:0:100000:10", map both uids and gids
+ * 0-10 to 100000 to 100010
+ */
+static int parse_map(char *map)
+{
+	struct id_map *newmap;
+	struct lxc_list *tmp = NULL;
+	int ret;
+	int i;
+	char types[2] = {'u', 'g'};
+	char which;
+	long host_id, ns_id, range;
+
+	if (!map)
+		return -1;
+
+	ret = sscanf(map, "%c:%ld:%ld:%ld", &which, &ns_id, &host_id, &range);
+	if (ret != 4)
+		return -1;
+
+	if (which != 'b' && which != 'u' && which != 'g')
+		return -1;
+
+	for (i = 0; i < 2; i++) {
+		if (which != types[i] && which != 'b')
+			continue;
+
+		newmap = malloc(sizeof(*newmap));
+		if (!newmap)
+			return -1;
+
+		newmap->hostid = host_id;
+		newmap->nsid = ns_id;
+		newmap->range = range;
+
+		if (types[i] == 'u')
+			newmap->idtype = ID_TYPE_UID;
+		else
+			newmap->idtype = ID_TYPE_GID;
+
+		tmp = malloc(sizeof(*tmp));
+		if (!tmp) {
+			free(newmap);
+			return -1;
+		}
+
+		tmp->elem = newmap;
+		lxc_list_add_tail(&active_map, tmp);
+	}
+
+	return 0;
+}
+
+/*
+ * This is called if the user did not pass any uid ranges in
+ * through -m flags.  It's called once to get the default uid
+ * map, and once for the default gid map.
+ * Go through /etc/subuids and /etc/subgids to find this user's
+ * allowed map.  We only use the first one for each of uid and
+ * gid, because otherwise we're not sure which entries the user
+ * wanted.
+ */
+static int read_default_map(char *fnam, int which, char *username)
+{
+	FILE *fin;
+	char *line = NULL;
+	size_t sz = 0;
+	struct id_map *newmap;
+	struct lxc_list *tmp = NULL;
+	char *p1, *p2;
+
+	fin = fopen(fnam, "r");
+	if (!fin)
+		return -1;
+	while (getline(&line, &sz, fin) != -1) {
+		if (sz <= strlen(username) ||
+		    strncmp(line, username, strlen(username)) != 0 ||
+		    line[strlen(username)] != ':')
+			continue;
+		p1 = strchr(line, ':');
+		if (!p1)
+			continue;
+		p2 = strchr(p1+1, ':');
+		if (!p2)
+			continue;
+		newmap = malloc(sizeof(*newmap));
+		if (!newmap)  {
+			fclose(fin);
+			free(line);
+			return -1;
+		}
+		newmap->hostid = atol(p1+1);
+		newmap->range = atol(p2+1);
+		newmap->nsid = 0;
+		newmap->idtype = which;
+
+		tmp = malloc(sizeof(*tmp));
+		if (!tmp) {
+			fclose(fin);
+			free(line);
+			free(newmap);
+			return -1;
+		}
+
+		tmp->elem = newmap;
+		lxc_list_add_tail(&active_map, tmp);
+		break;
+	}
+
+	free(line);
+	fclose(fin);
+	return 0;
+}
+
+static int find_default_map(void)
+{
+	struct passwd *p = getpwuid(getuid());
+	if (!p)
+		return -1;
+	if (read_default_map(subuidfile, ID_TYPE_UID, p->pw_name) < 0)
+		return -1;
+	if (read_default_map(subgidfile, ID_TYPE_GID, p->pw_name) < 0)
+		return -1;
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int c;
+	unsigned long flags = CLONE_NEWUSER | CLONE_NEWNS;
+	char ttyname0[256], ttyname1[256], ttyname2[256];
+	int status;
+	int ret;
+	int pid;
+	char *default_args[] = {"/bin/sh", NULL};
+	char buf[1];
+	int pipe1[2],  // child tells parent it has unshared
+	    pipe2[2];  // parent tells child it is mapped and may proceed
+
+	memset(ttyname0, '\0', sizeof(ttyname0));
+	memset(ttyname1, '\0', sizeof(ttyname1));
+	memset(ttyname2, '\0', sizeof(ttyname2));
+	if (isatty(0)) {
+		ret = readlink("/proc/self/fd/0", ttyname0, sizeof(ttyname0));
+		if (ret < 0) {
+			perror("unable to open stdin.");
+			exit(1);
+		}
+		ret = readlink("/proc/self/fd/1", ttyname1, sizeof(ttyname1));
+		if (ret < 0) {
+			printf("Warning: unable to open stdout, continuing.");
+			memset(ttyname1, '\0', sizeof(ttyname1));
+		}
+		ret = readlink("/proc/self/fd/2", ttyname2, sizeof(ttyname2));
+		if (ret < 0) {
+			printf("Warning: unable to open stderr, continuing.");
+			memset(ttyname2, '\0', sizeof(ttyname2));
+		}
+	}
+
+	lxc_list_init(&active_map);
+
+	while ((c = getopt(argc, argv, "m:h")) != EOF) {
+		switch (c) {
+			case 'm': if (parse_map(optarg)) usage(argv[0]); break;
+			case 'h':
+			default:
+				  usage(argv[0]);
+		}
+	};
+
+	if (lxc_list_empty(&active_map)) {
+		if (find_default_map()) {
+			fprintf(stderr, "You have no allocated subuids or subgids\n");
+			exit(1);
+		}
+	}
+
+	argv = &argv[optind];
+	argc = argc - optind;
+	if (argc < 1) {
+		argv = default_args;
+		argc = 1;
+	}
+
+	if (pipe(pipe1) < 0 || pipe(pipe2) < 0) {
+		perror("pipe");
+		exit(1);
+	}
+	if ((pid = fork()) == 0) {
+		// Child.
+
+		close(pipe1[0]);
+		close(pipe2[1]);
+		opentty(ttyname0, 0);
+		opentty(ttyname1, 1);
+		opentty(ttyname2, 2);
+
+		ret = unshare(flags);
+		if (ret < 0) {
+			perror("unshare");
+			return 1;
+		}
+		buf[0] = '1';
+		if (write(pipe1[1], buf, 1) < 1) {
+			perror("write pipe");
+			exit(1);
+		}
+		if (read(pipe2[0], buf, 1) < 1) {
+			perror("read pipe");
+			exit(1);
+		}
+		if (buf[0] != '1') {
+			fprintf(stderr, "parent had an error, child exiting\n");
+			exit(1);
+		}
+
+		close(pipe1[1]);
+		close(pipe2[0]);
+		return do_child((void*)argv);
+	}
+
+	close(pipe1[1]);
+	close(pipe2[0]);
+	if (read(pipe1[0], buf, 1) < 1) {
+		perror("read pipe");
+		exit(1);
+	}
+
+	buf[0] = '1';
+
+	if (lxc_map_ids(&active_map, pid)) {
+		fprintf(stderr, "error mapping child\n");
+		ret = 0;
+	}
+	if (write(pipe2[1], buf, 1) < 0) {
+		perror("write to pipe");
+		exit(1);
+	}
+
+	if ((ret = waitpid(pid, &status, __WALL)) < 0) {
+		printf("waitpid() returns %d, errno %d\n", ret, errno);
+		exit(1);
+	}
+
+	exit(WEXITSTATUS(status));
+}
diff --git a/src/lxc/tools/lxc_wait.c b/src/lxc/tools/lxc_wait.c
new file mode 100644
index 0000000..712ba52
--- /dev/null
+++ b/src/lxc/tools/lxc_wait.c
@@ -0,0 +1,112 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdio.h>
+#include <string.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/types.h>
+
+#include <lxc/lxccontainer.h>
+
+#include "lxc.h"
+#include "log.h"
+#include "arguments.h"
+
+lxc_log_define(lxc_wait_ui, lxc);
+
+static int my_checker(const struct lxc_arguments* args)
+{
+	if (!args->states) {
+		lxc_error(args, "missing state option to wait for.");
+		return -1;
+	}
+	return 0;
+}
+
+static int my_parser(struct lxc_arguments* args, int c, char* arg)
+{
+	switch (c) {
+	case 's': args->states = optarg; break;
+	case 't': args->timeout = atol(optarg); break;
+	}
+	return 0;
+}
+
+static const struct option my_longopts[] = {
+	{"state", required_argument, 0, 's'},
+	{"timeout", required_argument, 0, 't'},
+	LXC_COMMON_OPTIONS
+};
+
+static struct lxc_arguments my_args = {
+	.progname = "lxc-wait",
+	.help     = "\
+--name=NAME --state=STATE\n\
+\n\
+lxc-wait waits for NAME container state to reach STATE\n\
+\n\
+Options :\n\
+  -n, --name=NAME   NAME of the container\n\
+  -s, --state=STATE ORed states to wait for\n\
+                    STOPPED, STARTING, RUNNING, STOPPING,\n\
+                    ABORTING, FREEZING, FROZEN, THAWED\n\
+  -t, --timeout=TMO Seconds to wait for state changes\n",
+	.options  = my_longopts,
+	.parser   = my_parser,
+	.checker  = my_checker,
+	.timeout = -1,
+};
+
+int main(int argc, char *argv[])
+{
+	struct lxc_container *c;
+
+	if (lxc_arguments_parse(&my_args, argc, argv))
+		return 1;
+
+	if (!my_args.log_file)
+		my_args.log_file = "none";
+
+	if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
+			 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
+		return 1;
+	lxc_log_options_no_override();
+
+	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
+	if (!c)
+		return 1;
+
+	if (!c->may_control(c)) {
+		fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+		lxc_container_put(c);
+		return 1;
+	}
+
+	if (!c->wait(c, my_args.states, my_args.timeout)) {
+		lxc_container_put(c);
+		return 1;
+	}
+	return 0;
+}


More information about the lxc-devel mailing list