[lxc-devel] [lxc/master] tools: remove non api symbols

brauner on Github lxc-bot at linuxcontainers.org
Wed Jan 17 23:45:50 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 381 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180117/524dfeed/attachment.bin>
-------------- next part --------------
From aa697c89b751c1e76f89f5aa1c313ce74ae7af33 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 13:13:09 +0100
Subject: [PATCH 01/30] tools: move lxc-attach to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/Makefile.am           |   6 +-
 src/lxc/confile.c             |  41 ------
 src/lxc/confile.h             |   2 -
 src/lxc/tools/arguments.c     |   9 +-
 src/lxc/tools/lxc_attach.c    |  12 +-
 src/lxc/tools/lxc_autostart.c |   1 -
 src/lxc/tools/tool_utils.c    | 336 ++++++++++++++++++++++++++++++++++++++++++
 src/lxc/tools/tool_utils.h    |  56 +++++++
 8 files changed, 406 insertions(+), 57 deletions(-)
 create mode 100644 src/lxc/tools/tool_utils.c
 create mode 100644 src/lxc/tools/tool_utils.h

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 895684e0b..75037a5fa 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -4,7 +4,6 @@ pkginclude_HEADERS = \
 	version.h
 
 noinst_HEADERS = \
-	tools/arguments.h \
 	attach.h \
 	storage/storage.h \
 	storage/aufs.h \
@@ -18,6 +17,9 @@ noinst_HEADERS = \
 	storage/rsync.h \
 	storage/zfs.h \
 	storage/storage_utils.h \
+	tools/arguments.h \
+	tools/tool_utils.h \
+	tools/tool_list.h \
 	cgroups/cgroup.h \
 	cgroups/cgroup_utils.h \
 	caps.h \
@@ -266,7 +268,7 @@ AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir)
 endif
 LDADD=liblxc.la @CAP_LIBS@ @APPARMOR_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@
 
-lxc_attach_SOURCES = tools/lxc_attach.c tools/arguments.c
+lxc_attach_SOURCES = tools/lxc_attach.c tools/arguments.c tools/tool_utils.c
 lxc_autostart_SOURCES = tools/lxc_autostart.c tools/arguments.c
 lxc_cgroup_SOURCES = tools/lxc_cgroup.c tools/arguments.c
 lxc_config_SOURCES = tools/lxc_config.c tools/arguments.c
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 3deec58bf..5980d8664 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -2380,47 +2380,6 @@ signed long lxc_config_parse_arch(const char *arch)
 	return -1;
 }
 
-int lxc_fill_elevated_privileges(char *flaglist, int *flags)
-{
-	char *token, *saveptr = NULL;
-	int i, aflag;
-	struct {
-		const char *token;
-		int flag;
-	} all_privs[] = {
-		{ "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP    },
-		{ "CAP",    LXC_ATTACH_DROP_CAPABILITIES },
-		{ "LSM",    LXC_ATTACH_LSM_EXEC          },
-		{ NULL,     0                            }
-	};
-
-	if (!flaglist) {
-		/* For the sake of backward compatibility, drop all privileges
-		*  if none is specified.
-		 */
-		for (i = 0; all_privs[i].token; i++)
-			*flags |= all_privs[i].flag;
-
-		return 0;
-	}
-
-	token = strtok_r(flaglist, "|", &saveptr);
-	while (token) {
-		aflag = -1;
-		for (i = 0; all_privs[i].token; i++)
-			if (!strcmp(all_privs[i].token, token))
-				aflag = all_privs[i].flag;
-		if (aflag < 0)
-			return -1;
-
-		*flags |= aflag;
-
-		token = strtok_r(NULL, "|", &saveptr);
-	}
-
-	return 0;
-}
-
 /* Write out a configuration file. */
 void write_config(FILE *fout, struct lxc_conf *c)
 {
diff --git a/src/lxc/confile.h b/src/lxc/confile.h
index d50217860..6c69bc7a5 100644
--- a/src/lxc/confile.h
+++ b/src/lxc/confile.h
@@ -92,8 +92,6 @@ extern int lxc_config_define_load(struct lxc_list *defines,
 /* needed for lxc-attach */
 extern signed long lxc_config_parse_arch(const char *arch);
 
-extern int lxc_fill_elevated_privileges(char *flaglist, int *flags);
-
 extern int lxc_clear_config_item(struct lxc_conf *c, const char *key);
 
 extern void write_config(FILE *fout, struct lxc_conf *c);
diff --git a/src/lxc/tools/arguments.c b/src/lxc/tools/arguments.c
index 30fb714fd..7116dd6bc 100644
--- a/src/lxc/tools/arguments.c
+++ b/src/lxc/tools/arguments.c
@@ -182,6 +182,13 @@ static int lxc_arguments_lxcpath_add(struct lxc_arguments *args,
 	return 0;
 }
 
+void remove_trailing_slashes(char *p)
+{
+	int l = strlen(p);
+	while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
+		p[l] = '\0';
+}
+
 extern int lxc_arguments_parse(struct lxc_arguments *args, int argc,
 			       char *const argv[])
 {
@@ -250,7 +257,7 @@ extern int lxc_arguments_parse(struct lxc_arguments *args, int argc,
 	/* If no lxcpaths were given, use default */
 	if (!args->lxcpath_cnt) {
 		ret = lxc_arguments_lxcpath_add(
-		    args, lxc_global_config_value("lxc.lxcpath"));
+		    args, lxc_get_global_config_item("lxc.lxcpath"));
 		if (ret < 0)
 			return ret;
 	}
diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
index 926bf079e..b2c405d3a 100644
--- a/src/lxc/tools/lxc_attach.c
+++ b/src/lxc/tools/lxc_attach.c
@@ -27,6 +27,7 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <termios.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
@@ -36,16 +37,8 @@
 
 #include <lxc/lxccontainer.h>
 
-#include "attach.h"
 #include "arguments.h"
-#include "caps.h"
-#include "conf.h"
-#include "confile.h"
-#include "console.h"
-#include "log.h"
-#include "list.h"
-#include "mainloop.h"
-#include "utils.h"
+#include "tool_utils.h"
 
 static const struct option my_longopts[] = {
 	{"elevated-privileges", optional_argument, 0, 'e'},
@@ -290,7 +283,6 @@ int main(int argc, char *argv[])
 	r = lxc_log_init(&log);
 	if (r)
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
 
 	if (geteuid()) {
 		if (access(my_args.lxcpath[0], O_RDONLY) < 0) {
diff --git a/src/lxc/tools/lxc_autostart.c b/src/lxc/tools/lxc_autostart.c
index 48727b9f1..a3d4a8a8a 100644
--- a/src/lxc/tools/lxc_autostart.c
+++ b/src/lxc/tools/lxc_autostart.c
@@ -24,7 +24,6 @@
 #include <lxc/lxccontainer.h>
 
 #include "arguments.h"
-#include "list.h"
 #include "log.h"
 #include "utils.h"
 
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
new file mode 100644
index 000000000..39b388161
--- /dev/null
+++ b/src/lxc/tools/tool_utils.c
@@ -0,0 +1,336 @@
+/* liblxcapi
+ *
+ * Copyright © 2018 Christian Brauner <christian.brauner at ubuntu.com>.
+ * Copyright © 2018 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 __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <linux/sched.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#if HAVE_SYS_PERSONALITY_H
+#include <sys/personality.h>
+#endif
+
+#include <lxc/lxccontainer.h>
+
+#include "tool_utils.h"
+
+int lxc_fill_elevated_privileges(char *flaglist, int *flags)
+{
+	char *token, *saveptr = NULL;
+	int i, aflag;
+	struct {
+		const char *token;
+		int flag;
+	} all_privs[] = {
+		{ "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP    },
+		{ "CAP",    LXC_ATTACH_DROP_CAPABILITIES },
+		{ "LSM",    LXC_ATTACH_LSM_EXEC          },
+		{ NULL,     0                            }
+	};
+
+	if (!flaglist) {
+		/* For the sake of backward compatibility, drop all privileges
+		*  if none is specified.
+		 */
+		for (i = 0; all_privs[i].token; i++)
+			*flags |= all_privs[i].flag;
+
+		return 0;
+	}
+
+	token = strtok_r(flaglist, "|", &saveptr);
+	while (token) {
+		aflag = -1;
+		for (i = 0; all_privs[i].token; i++)
+			if (!strcmp(all_privs[i].token, token))
+				aflag = all_privs[i].flag;
+		if (aflag < 0)
+			return -1;
+
+		*flags |= aflag;
+
+		token = strtok_r(NULL, "|", &saveptr);
+	}
+
+	return 0;
+}
+
+signed long lxc_config_parse_arch(const char *arch)
+{
+#if HAVE_SYS_PERSONALITY_H
+	size_t i;
+	struct per_name {
+		char *name;
+		unsigned long per;
+	} pername[] = {
+	    { "x86",       PER_LINUX32 },
+	    { "linux32",   PER_LINUX32 },
+	    { "i386",      PER_LINUX32 },
+	    { "i486",      PER_LINUX32 },
+	    { "i586",      PER_LINUX32 },
+	    { "i686",      PER_LINUX32 },
+	    { "athlon",    PER_LINUX32 },
+	    { "mips",      PER_LINUX32 },
+	    { "mipsel",    PER_LINUX32 },
+	    { "ppc",       PER_LINUX32 },
+	    { "arm",       PER_LINUX32 },
+	    { "armv7l",    PER_LINUX32 },
+	    { "armhf",     PER_LINUX32 },
+	    { "armel",     PER_LINUX32 },
+	    { "powerpc",   PER_LINUX32 },
+	    { "linux64",   PER_LINUX   },
+	    { "x86_64",    PER_LINUX   },
+	    { "amd64",     PER_LINUX   },
+	    { "mips64",    PER_LINUX   },
+	    { "mips64el",  PER_LINUX   },
+	    { "ppc64",     PER_LINUX   },
+	    { "ppc64le",   PER_LINUX   },
+	    { "ppc64el",   PER_LINUX   },
+	    { "powerpc64", PER_LINUX   },
+	    { "s390x",     PER_LINUX   },
+	    { "aarch64",   PER_LINUX   },
+	    { "arm64",     PER_LINUX   },
+	};
+	size_t len = sizeof(pername) / sizeof(pername[0]);
+
+	for (i = 0; i < len; i++) {
+		if (!strcmp(pername[i].name, arch))
+			return pername[i].per;
+	}
+#endif
+
+	return -1;
+}
+
+enum {
+	LXC_NS_USER,
+	LXC_NS_MNT,
+	LXC_NS_PID,
+	LXC_NS_UTS,
+	LXC_NS_IPC,
+	LXC_NS_NET,
+	LXC_NS_CGROUP,
+	LXC_NS_MAX
+};
+
+const static struct ns_info {
+	const char *proc_name;
+	int clone_flag;
+} ns_info[LXC_NS_MAX]   = {
+	[LXC_NS_USER]   = { "user",   CLONE_NEWUSER   },
+	[LXC_NS_MNT]    = { "mnt",    CLONE_NEWNS     },
+	[LXC_NS_PID]    = { "pid",    CLONE_NEWPID    },
+	[LXC_NS_UTS]    = { "uts",    CLONE_NEWUTS    },
+	[LXC_NS_IPC]    = { "ipc",    CLONE_NEWIPC    },
+	[LXC_NS_NET]    = { "net",    CLONE_NEWNET    },
+	[LXC_NS_CGROUP] = { "cgroup", CLONE_NEWCGROUP }
+};
+
+int lxc_namespace_2_cloneflag(const char *namespace)
+{
+	int i;
+	for (i = 0; i < LXC_NS_MAX; i++)
+		if (!strcasecmp(ns_info[i].proc_name, namespace))
+			return ns_info[i].clone_flag;
+
+	fprintf(stderr, "Invalid namespace name \"%s\"", namespace);
+	return -EINVAL;
+}
+
+int lxc_fill_namespace_flags(char *flaglist, int *flags)
+{
+	char *token, *saveptr = NULL;
+	int aflag;
+
+	if (!flaglist) {
+		fprintf(stderr, "At least one namespace is needed\n");
+		return -1;
+	}
+
+	token = strtok_r(flaglist, "|", &saveptr);
+	while (token) {
+
+		aflag = lxc_namespace_2_cloneflag(token);
+		if (aflag < 0)
+			return -1;
+
+		*flags |= aflag;
+
+		token = strtok_r(NULL, "|", &saveptr);
+	}
+
+	return 0;
+}
+
+#if HAVE_LIBCAP
+
+#ifndef PR_CAPBSET_READ
+#define PR_CAPBSET_READ 23
+#endif
+
+int lxc_caps_init(void)
+{
+	uid_t uid = getuid();
+	gid_t gid = getgid();
+	uid_t euid = geteuid();
+
+	if (!uid)
+		return 0;
+
+	if (uid && !euid) {
+		if (prctl(PR_SET_KEEPCAPS, 1)) {
+			fprintf(stderr, "%s - Failed to set PR_SET_KEEPCAPS\n", strerror(errno));
+			return -1;
+		}
+
+		if (setresgid(gid, gid, gid)) {
+			fprintf(stderr, "%s - Failed to change gid to %d\n", strerror(errno), gid);
+			return -1;
+		}
+
+		if (setresuid(uid, uid, uid)) {
+			fprintf(stderr, "%s - Failed to change uid to %d\n", strerror(errno), uid);
+			return -1;
+		}
+
+		if (lxc_caps_up()) {
+			fprintf(stderr, "%s - Failed to restore capabilities\n", strerror(errno));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int lxc_caps_up(void)
+{
+	cap_t caps;
+	cap_value_t cap;
+	int ret;
+
+	/* when we are run as root, we don't want to play
+	 * with the capabilities */
+	if (!getuid())
+		return 0;
+
+	caps = cap_get_proc();
+	if (!caps) {
+		fprintf(stderr, "%s - Failed to cap_get_proc\n", strerror(errno));
+		return -1;
+	}
+
+	for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
+		cap_flag_value_t flag;
+
+		ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
+		if (ret) {
+			if (errno == EINVAL) {
+				break;
+			} else {
+				fprintf(stderr, "%s- Failed to call cap_get_flag\n", strerror(errno));
+				goto out;
+			}
+		}
+
+		ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
+		if (ret) {
+			fprintf(stderr, "%s - Failed to call cap_set_flag", strerror(errno));
+			goto out;
+		}
+	}
+
+	ret = cap_set_proc(caps);
+	if (ret) {
+		fprintf(stderr, "%s - Failed to cap_set_proc", strerror(errno));
+		goto out;
+	}
+
+out:
+	cap_free(caps);
+	return 0;
+}
+
+#endif
+
+int lxc_wait_for_pid_status(pid_t pid)
+{
+	int status, ret;
+
+again:
+	ret = waitpid(pid, &status, 0);
+	if (ret == -1) {
+		if (errno == EINTR)
+			goto again;
+		return -1;
+	}
+	if (ret != pid)
+		goto again;
+	return status;
+}
+
+int lxc_safe_int(const char *numstr, int *converted)
+{
+	char *err = NULL;
+	signed long int sli;
+
+	errno = 0;
+	sli = strtol(numstr, &err, 0);
+	if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
+		return -ERANGE;
+
+	if (errno != 0 && sli == 0)
+		return -EINVAL;
+
+	if (err == numstr || *err != '\0')
+		return -EINVAL;
+
+	if (sli > INT_MAX || sli < INT_MIN)
+		return -ERANGE;
+
+	*converted = (int)sli;
+	return 0;
+}
+
+int lxc_safe_long(const char *numstr, long int *converted)
+{
+	char *err = NULL;
+	signed long int sli;
+
+	errno = 0;
+	sli = strtol(numstr, &err, 0);
+	if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
+		return -ERANGE;
+
+	if (errno != 0 && sli == 0)
+		return -EINVAL;
+
+	if (err == numstr || *err != '\0')
+		return -EINVAL;
+
+	*converted = sli;
+	return 0;
+}
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
new file mode 100644
index 000000000..59479dfa0
--- /dev/null
+++ b/src/lxc/tools/tool_utils.h
@@ -0,0 +1,56 @@
+/* liblxcapi
+ *
+ * Copyright © 2018 Christian Brauner <christian.brauner at ubuntu.com>.
+ * Copyright © 2018 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.
+ */
+
+#ifndef __LXC_UTILS_H
+#define __LXC_UTILS_H
+
+/* Properly support loop devices on 32bit systems. */
+#define _FILE_OFFSET_BITS 64
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+extern int lxc_fill_elevated_privileges(char *flaglist, int *flags);
+extern signed long lxc_config_parse_arch(const char *arch);
+extern int lxc_namespace_2_cloneflag(const char *namespace);
+extern int lxc_fill_namespace_flags(char *flaglist, int *flags);
+
+#if HAVE_LIBCAP
+#include <sys/capability.h>
+
+extern int lxc_caps_up(void);
+extern int lxc_caps_init(void);
+#else
+static inline int lxc_caps_up(void) {
+	return 0;
+}
+
+static inline int lxc_caps_init(void) {
+	return 0;
+}
+#endif
+
+extern int lxc_wait_for_pid_status(pid_t pid);
+extern int lxc_safe_int(const char *numstr, int *converted);
+extern int lxc_safe_long(const char *numstr, long int *converted);
+
+#endif /* __LXC_UTILS_H */

From cb52863038b72e7747b502d7fa958444ef807e8b Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 13:25:15 +0100
Subject: [PATCH 02/30] tools: lxc-autostart: non-functional changes

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_autostart.c | 180 +++++++++++++++++++-----------------------
 1 file changed, 80 insertions(+), 100 deletions(-)

diff --git a/src/lxc/tools/lxc_autostart.c b/src/lxc/tools/lxc_autostart.c
index a3d4a8a8a..b3823af2f 100644
--- a/src/lxc/tools/lxc_autostart.c
+++ b/src/lxc/tools/lxc_autostart.c
@@ -18,6 +18,8 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
@@ -144,14 +146,13 @@ int lists_contain_common_entry(struct lxc_list *p1, struct lxc_list *p2) {
 	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.
+/* 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) {
+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;
@@ -159,45 +160,33 @@ static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc
 	struct lxc_list *workstr_list;
 
 	workstr = strdup(input);
-	if (!workstr) {
+	if (!workstr)
 		return NULL;
-	}
 
 	workstr_list = str_list;
-	if ( ! workstr_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...
+		/* 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 = 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.
+		/* 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);
-			}
+		if (list_contains_entry(workptr, workstr_list)) {
+			if (*workptr)
+				fprintf(stderr, "Duplicate group \"%s\" in list - ignoring\n", workptr);
+			else
+				fprintf(stderr, "Duplicate NULL group in list - ignoring\n");
 		} else {
 			worklist = malloc(sizeof(*worklist));
 			if (!worklist)
@@ -218,7 +207,8 @@ static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc
 	return workstr_list;
 }
 
-static struct lxc_list *get_list(char *input, char *delimiter) {
+static struct lxc_list *get_list(char *input, char *delimiter)
+{
 	char *workstr = NULL;
 	char *workptr = NULL;
 	char *sptr = NULL;
@@ -235,11 +225,10 @@ static struct lxc_list *get_list(char *input, char *delimiter) {
 		return NULL;
 	}
 
-	for (workptr = workstr;;workptr = NULL) {
+	for (workptr = workstr;; workptr = NULL) {
 		token = strtok_r(workptr, delimiter, &sptr);
-		if (!token) {
+		if (!token)
 			break;
-		}
 
 		worklist = malloc(sizeof(*worklist));
 		if (!worklist)
@@ -259,16 +248,17 @@ static struct lxc_list *get_list(char *input, char *delimiter) {
 	return workstr_list;
 }
 
-static struct lxc_list *get_config_list(struct lxc_container *c, char *key) {
+static struct lxc_list *get_config_list(struct lxc_container *c, char *key)
+{
 	int len = 0;
-	char* value = NULL;
+	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);
+	value = (char *)malloc(sizeof(char) * len + 1);
 	if (value == NULL)
 		return NULL;
 
@@ -288,16 +278,16 @@ static struct lxc_list *get_config_list(struct lxc_container *c, char *key) {
 	return config_list;
 }
 
-static int get_config_integer(struct lxc_container *c, char *key) {
-	int len = 0;
-	int ret = 0;
-	char* value = NULL;
+static int get_config_integer(struct lxc_container *c, char *key)
+{
+	int len = 0, 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);
+	value = (char *)malloc(sizeof(char) * len + 1);
 	if (value == NULL)
 		return 0;
 
@@ -314,7 +304,8 @@ static int get_config_integer(struct lxc_container *c, char *key) {
 	return ret;
 }
 
-static int cmporder(const void *p1, const void *p2) {
+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;
 
@@ -323,33 +314,33 @@ static int cmporder(const void *p1, const void *p2) {
 
 	if (c1_order == c2_order)
 		return strcmp(c1->name, c2->name);
-	else
-		return (c1_order - c2_order);
+
+	return (c1_order - c2_order);
 }
 
-static int toss_list( struct lxc_list *c_groups_list ) {
+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);
+	if (!c_groups_list)
+		return 1;
+
+	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;
+	int count = 0, i = 0, ret = 0;
+	struct lxc_list *cmd_group;
 	struct lxc_container **containers = NULL;
 	struct lxc_list **c_groups_lists = NULL;
-	struct lxc_list *cmd_group;
 	struct lxc_log log;
 
 	if (lxc_arguments_parse(&my_args, argc, argv))
@@ -374,36 +365,29 @@ int main(int argc, char *argv[])
 	if (count < 0)
 		exit(EXIT_FAILURE);
 
-	if (!my_args.all) {
-		/* Allocate an array for our container group lists */
+	/* Allocate an array for our container group lists */
+	if (!my_args.all)
 		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) {
+	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...
-		 */
+	/* 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...
+	 */
+	if (!cmd_groups_list)
 		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.
+		/* 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];
@@ -412,10 +396,9 @@ int main(int argc, char *argv[])
 				/* 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.
+			/* 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 */
@@ -442,8 +425,10 @@ int main(int argc, char *argv[])
 				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 */
+					/* Not in the target group this pass so
+					 * leave in the list for subsequent
+					 * passes.
+					 */
 					continue;
 				}
 			}
@@ -467,8 +452,7 @@ int main(int argc, char *argv[])
 						}
 					}
 				}
-			}
-			else if (my_args.hardstop) {
+			} else if (my_args.hardstop) {
 				/* Kill the container */
 				if (c->is_running(c)) {
 					if (my_args.list) {
@@ -482,8 +466,7 @@ int main(int argc, char *argv[])
 						}
 					}
 				}
-			}
-			else if (my_args.reboot) {
+			} else if (my_args.reboot) {
 				/* Reboot the container */
 				if (c->is_running(c)) {
 					if (my_args.list) {
@@ -500,8 +483,7 @@ int main(int argc, char *argv[])
 							sleep(get_config_integer(c, "lxc.start.delay"));
 					}
 				}
-			}
-			else {
+			} else {
 				/* Start the container */
 				if (!c->is_running(c)) {
 					if (my_args.list) {
@@ -525,9 +507,8 @@ int main(int argc, char *argv[])
 			 * then we're done with this container...  We can dump any
 			 * c_groups_list and the container itself.
 			 */
-			if ( lxc_container_put(c) > 0 ) {
+			if ( lxc_container_put(c) > 0 )
 				containers[i] = NULL;
-			}
 			if ( c_groups_lists ) {
 				toss_list(c_groups_lists[i]);
 				c_groups_lists[i] = NULL;
@@ -538,12 +519,11 @@ int main(int argc, char *argv[])
 
 	/* clean up any lingering detritus */
 	for (i = 0; i < count; i++) {
-		if ( containers[i] ) {
+		if (containers[i])
 			lxc_container_put(containers[i]);
-		}
-		if ( c_groups_lists && c_groups_lists[i] ) {
+
+		if (c_groups_lists && c_groups_lists[i])
 			toss_list(c_groups_lists[i]);
-		}
 	}
 
 	free(c_groups_lists);

From 61c8f526d083cd2a368b7b19889c0852998b0160 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 13:32:04 +0100
Subject: [PATCH 03/30] tools: move lxc-autostart to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_autostart.c |   6 +-
 src/lxc/tools/tool_list.h     | 167 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+), 3 deletions(-)
 create mode 100644 src/lxc/tools/tool_list.h

diff --git a/src/lxc/tools/lxc_autostart.c b/src/lxc/tools/lxc_autostart.c
index b3823af2f..41d2e4b57 100644
--- a/src/lxc/tools/lxc_autostart.c
+++ b/src/lxc/tools/lxc_autostart.c
@@ -18,6 +18,7 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -26,8 +27,8 @@
 #include <lxc/lxccontainer.h>
 
 #include "arguments.h"
-#include "log.h"
-#include "utils.h"
+#include "tool_list.h"
+#include "tool_utils.h"
 
 static struct lxc_list *accumulate_list(char *input, char *delimiter, struct lxc_list *str_list);
 
@@ -355,7 +356,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
diff --git a/src/lxc/tools/tool_list.h b/src/lxc/tools/tool_list.h
new file mode 100644
index 000000000..9858081ab
--- /dev/null
+++ b/src/lxc/tools/tool_list.h
@@ -0,0 +1,167 @@
+/*
+ * 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_LIST_H
+#define __LXC_LIST_H
+
+#include <stdio.h>
+
+struct lxc_list {
+	void *elem;
+	struct lxc_list *next;
+	struct lxc_list *prev;
+};
+
+#define lxc_init_list(l)                                                       \
+	{                                                                      \
+		.next = l, .prev = l                                           \
+	}
+
+/*
+ * Iterate through an lxc list. An example for an idiom would be:
+ *
+ * struct lxc_list *iterator;
+ * lxc_list_for_each(iterator, list) {
+ *        type *tmp;
+ * 	  tmp = iterator->elem;
+ * }
+ */
+#define lxc_list_for_each(__iterator, __list)                                  \
+	for (__iterator = (__list)->next; __iterator != __list;                \
+	     __iterator = __iterator->next)
+
+/* Iterate safely through an lxc list. An example for an appropriate use case
+ * would be:
+ *
+ * struct lxc_list *cur, *next;
+ * lxc_list_for_each_safe(cur, list, next) {
+ *        type *tmp;
+ * 	  tmp = cur->elem;
+ * }
+ */
+#define lxc_list_for_each_safe(__iterator, __list, __next)                     \
+	for (__iterator = (__list)->next, __next = __iterator->next;           \
+	     __iterator != __list; __iterator = __next, __next = __next->next)
+
+/* Initalize list. */
+static inline void lxc_list_init(struct lxc_list *list)
+{
+	list->elem = NULL;
+	list->next = list->prev = list;
+}
+
+/* Add an element to a list. See lxc_list_add() and lxc_list_add_tail() for an
+ * idiom.
+ */
+static inline void lxc_list_add_elem(struct lxc_list *list, void *elem)
+{
+	list->elem = elem;
+}
+
+/* Retrieve first element of list. */
+static inline void *lxc_list_first_elem(struct lxc_list *list)
+{
+	return list->next->elem;
+}
+
+/* Retrieve last element of list. */
+static inline void *lxc_list_last_elem(struct lxc_list *list)
+{
+	return list->prev->elem;
+}
+
+/* Determine if list is empty. */
+static inline int lxc_list_empty(struct lxc_list *list)
+{
+	return list == list->next;
+}
+
+/* Workhorse to be called from lxc_list_add() and lxc_list_add_tail(). */
+static inline void __lxc_list_add(struct lxc_list *new, struct lxc_list *prev,
+				  struct lxc_list *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/* Idiom to add an element to the beginning of an lxc list:
+ *
+ *	struct lxc_list *tmp = malloc(sizeof(*tmp));
+ *	if (tmp == NULL)
+ *		return 1;
+ *	lxc_list_add_elem(tmp, elem);
+ *	lxc_list_add(list, tmp);
+ */
+static inline void lxc_list_add(struct lxc_list *head, struct lxc_list *list)
+{
+	__lxc_list_add(list, head, head->next);
+}
+
+/* Idiom to add an element to the end of an lxc list:
+ *
+ *	struct lxc_list *tmp = malloc(sizeof(*tmp));
+ *	if (tmp == NULL)
+ *		return 1;
+ *	lxc_list_add_elem(tmp, elem);
+ *	lxc_list_add_tail(list, tmp);
+ */
+static inline void lxc_list_add_tail(struct lxc_list *head,
+				     struct lxc_list *list)
+{
+	__lxc_list_add(list, head->prev, head);
+}
+
+/* Idiom to remove an element from a list:
+ * struct lxc_list *cur, *next;
+ * lxc_list_for_each_safe(cur, list, next) {
+ * 	  lxc_list_del(cur);
+ * 	  free(cur->elem);
+ * 	  free(cur);
+ * }
+ */
+static inline void lxc_list_del(struct lxc_list *list)
+{
+	struct lxc_list *next, *prev;
+
+	next = list->next;
+	prev = list->prev;
+	next->prev = prev;
+	prev->next = next;
+}
+
+/* Return length of the list. */
+static inline size_t lxc_list_len(struct lxc_list *list)
+{
+	 size_t i = 0;
+	 struct lxc_list *iter;
+
+	 lxc_list_for_each(iter, list) {
+		i++;
+	 }
+
+	 return i;
+}
+
+#endif /* __LXC_LIST_H */

From 87cf87aae59448d3e42a5a368849360de7c87915 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 13:36:12 +0100
Subject: [PATCH 04/30] tools: move lxc-cgroup to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/arguments.h  |  1 +
 src/lxc/tools/lxc_cgroup.c | 10 +++++-----
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h
index 15941bcc3..bd491a32b 100644
--- a/src/lxc/tools/arguments.h
+++ b/src/lxc/tools/arguments.h
@@ -31,6 +31,7 @@
 #include <sys/types.h>
 #include <lxc/lxccontainer.h>
 
+#define TOOL_MAXPATHLEN 4096
 struct lxc_arguments;
 
 typedef int (*lxc_arguments_parser_t)(struct lxc_arguments *, int, char *);
diff --git a/src/lxc/tools/lxc_cgroup.c b/src/lxc/tools/lxc_cgroup.c
index cfd14bd8f..3624e80b7 100644
--- a/src/lxc/tools/lxc_cgroup.c
+++ b/src/lxc/tools/lxc_cgroup.c
@@ -21,17 +21,17 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#define _GNU_SOURCE
 #include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/types.h>
 
 #include <lxc/lxccontainer.h>
 
 #include "arguments.h"
-#include "log.h"
-#include "lxc.h"
 
 static int my_checker(const struct lxc_arguments* args)
 {
@@ -39,6 +39,7 @@ static int my_checker(const struct lxc_arguments* args)
 		lxc_error(args, "missing state object");
 		return -1;
 	}
+
 	return 0;
 }
 
@@ -83,7 +84,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
@@ -130,8 +130,8 @@ int main(int argc, char *argv[])
 			exit(EXIT_FAILURE);
 		}
 	} else {
-		char buffer[MAXPATHLEN];
-		int ret = c->get_cgroup_item(c, state_object, buffer, MAXPATHLEN);
+		char buffer[TOOL_MAXPATHLEN];
+		int ret = c->get_cgroup_item(c, state_object, buffer, TOOL_MAXPATHLEN);
 		if (ret < 0) {
 			fprintf(stderr, "failed to retrieve value of '%s' for '%s:%s'\n",
 			      state_object, my_args.lxcpath[0], my_args.name);

From 44f811f424051b942542df248132ad4d7e54f8fa Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 13:46:30 +0100
Subject: [PATCH 05/30] cmd: move lxc-lxc_usernsexec

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/Makefile.am                     | 4 +++-
 src/lxc/{tools => cmd}/lxc_usernsexec.c | 0
 2 files changed, 3 insertions(+), 1 deletion(-)
 rename src/lxc/{tools => cmd}/lxc_usernsexec.c (100%)

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 75037a5fa..b2cc37a2d 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -290,11 +290,13 @@ lxc_unshare_SOURCES = tools/lxc_unshare.c tools/arguments.c
 lxc_wait_SOURCES = tools/lxc_wait.c tools/arguments.c
 lxc_create_SOURCES = tools/lxc_create.c tools/arguments.c
 lxc_snapshot_SOURCES = tools/lxc_snapshot.c tools/arguments.c
-lxc_usernsexec_SOURCES = tools/lxc_usernsexec.c tools/arguments.c
 lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c
 lxc_user_nic_SOURCES = lxc_user_nic.c namespace.c network.c tools/arguments.c
 lxc_monitord_SOURCES = lxc_monitord.c tools/arguments.c
 
+# Binaries shipping with liblxc
+lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c
+
 if ENABLE_DEPRECATED
 lxc_clone_SOURCES = tools/lxc_clone.c tools/arguments.c
 endif
diff --git a/src/lxc/tools/lxc_usernsexec.c b/src/lxc/cmd/lxc_usernsexec.c
similarity index 100%
rename from src/lxc/tools/lxc_usernsexec.c
rename to src/lxc/cmd/lxc_usernsexec.c

From aefeb7f7e1b801e70019aea20d416fbb3c9b3853 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 13:48:07 +0100
Subject: [PATCH 06/30] cmd: move init.lxc{.static}

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/Makefile.am          | 4 ++--
 src/lxc/{ => cmd}/lxc_init.c | 0
 2 files changed, 2 insertions(+), 2 deletions(-)
 rename src/lxc/{ => cmd}/lxc_init.c (100%)

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index b2cc37a2d..46f94f010 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -278,7 +278,6 @@ lxc_device_SOURCES = tools/lxc_device.c tools/arguments.c
 lxc_execute_SOURCES = tools/lxc_execute.c tools/arguments.c
 lxc_freeze_SOURCES = tools/lxc_freeze.c tools/arguments.c
 lxc_info_SOURCES = tools/lxc_info.c tools/arguments.c
-init_lxc_SOURCES = lxc_init.c
 lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c
 lxc_ls_SOURCES = tools/lxc_ls.c tools/arguments.c
 lxc_copy_SOURCES = tools/lxc_copy.c tools/arguments.c
@@ -295,6 +294,7 @@ lxc_user_nic_SOURCES = lxc_user_nic.c namespace.c network.c tools/arguments.c
 lxc_monitord_SOURCES = lxc_monitord.c tools/arguments.c
 
 # Binaries shipping with liblxc
+init_lxc_SOURCES = cmd/lxc_init.c
 lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c
 
 if ENABLE_DEPRECATED
@@ -308,7 +308,7 @@ endif
 if HAVE_STATIC_LIBCAP
 sbin_PROGRAMS += init.lxc.static
 
-init_lxc_static_SOURCES = lxc_init.c error.c log.c initutils.c caps.c parse.c namespace.c
+init_lxc_static_SOURCES = cmd/lxc_init.c error.c log.c initutils.c caps.c parse.c namespace.c
 
 if !HAVE_GETLINE
 if HAVE_FGETLN
diff --git a/src/lxc/lxc_init.c b/src/lxc/cmd/lxc_init.c
similarity index 100%
rename from src/lxc/lxc_init.c
rename to src/lxc/cmd/lxc_init.c

From a3b425a915ef48952f78d3e0942aaea0c0ff4b91 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 13:49:55 +0100
Subject: [PATCH 07/30] cmd: move lxc-checkconfig

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 configure.ac                              | 2 +-
 src/lxc/Makefile.am                       | 2 +-
 src/lxc/{tools => cmd}/lxc-checkconfig.in | 0
 3 files changed, 2 insertions(+), 2 deletions(-)
 rename src/lxc/{tools => cmd}/lxc-checkconfig.in (100%)

diff --git a/configure.ac b/configure.ac
index 0bcd75a28..a841f9b9f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -939,7 +939,7 @@ AC_CONFIG_FILES([
 	src/Makefile
 	src/lxc/Makefile
 	src/lxc/lxc.functions
-	src/lxc/tools/lxc-checkconfig
+	src/lxc/cmd/lxc-checkconfig
 	src/lxc/tools/lxc-start-ephemeral
 	src/lxc/tools/lxc-update-config
 	src/lxc/version.h
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 46f94f010..c8c5bb910 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -216,7 +216,7 @@ liblxc_la_LIBADD += $(CGMANAGER_LIBS) $(DBUS_LIBS) $(NIH_LIBS) $(NIH_DBUS_LIBS)
 liblxc_la_CFLAGS += $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) $(NIH_DBUS_CFLAGS)
 endif
 
-bin_SCRIPTS = tools/lxc-checkconfig \
+bin_SCRIPTS = cmd/lxc-checkconfig \
 	      tools/lxc-update-config
 
 EXTRA_DIST = \
diff --git a/src/lxc/tools/lxc-checkconfig.in b/src/lxc/cmd/lxc-checkconfig.in
similarity index 100%
rename from src/lxc/tools/lxc-checkconfig.in
rename to src/lxc/cmd/lxc-checkconfig.in

From b880b5f2fc722dd96e1f8247bf31e685e3e6b6d9 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 13:53:10 +0100
Subject: [PATCH 08/30] cmd: move lxc-user-nic

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/Makefile.am              | 2 +-
 src/lxc/{ => cmd}/lxc_user_nic.c | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename src/lxc/{ => cmd}/lxc_user_nic.c (100%)

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index c8c5bb910..e1eaabf99 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -290,11 +290,11 @@ lxc_wait_SOURCES = tools/lxc_wait.c tools/arguments.c
 lxc_create_SOURCES = tools/lxc_create.c tools/arguments.c
 lxc_snapshot_SOURCES = tools/lxc_snapshot.c tools/arguments.c
 lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c
-lxc_user_nic_SOURCES = lxc_user_nic.c namespace.c network.c tools/arguments.c
 lxc_monitord_SOURCES = lxc_monitord.c tools/arguments.c
 
 # Binaries shipping with liblxc
 init_lxc_SOURCES = cmd/lxc_init.c
+lxc_user_nic_SOURCES = cmd/lxc_user_nic.c namespace.c network.c
 lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c
 
 if ENABLE_DEPRECATED
diff --git a/src/lxc/lxc_user_nic.c b/src/lxc/cmd/lxc_user_nic.c
similarity index 100%
rename from src/lxc/lxc_user_nic.c
rename to src/lxc/cmd/lxc_user_nic.c

From e0eb8b38a1d54388ff4677a31d6310c1535f5b55 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 13:54:30 +0100
Subject: [PATCH 09/30] cmd: move lxc-monitord

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/Makefile.am              | 2 +-
 src/lxc/{ => cmd}/lxc_monitord.c | 0
 2 files changed, 1 insertion(+), 1 deletion(-)
 rename src/lxc/{ => cmd}/lxc_monitord.c (100%)

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index e1eaabf99..aa4e41c26 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -290,10 +290,10 @@ lxc_wait_SOURCES = tools/lxc_wait.c tools/arguments.c
 lxc_create_SOURCES = tools/lxc_create.c tools/arguments.c
 lxc_snapshot_SOURCES = tools/lxc_snapshot.c tools/arguments.c
 lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c
-lxc_monitord_SOURCES = lxc_monitord.c tools/arguments.c
 
 # Binaries shipping with liblxc
 init_lxc_SOURCES = cmd/lxc_init.c
+lxc_monitord_SOURCES = cmd/lxc_monitord.c
 lxc_user_nic_SOURCES = cmd/lxc_user_nic.c namespace.c network.c
 lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c
 
diff --git a/src/lxc/lxc_monitord.c b/src/lxc/cmd/lxc_monitord.c
similarity index 100%
rename from src/lxc/lxc_monitord.c
rename to src/lxc/cmd/lxc_monitord.c

From 258d0a0026287269ce018fdb2eb0cec32d014826 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 13:56:37 +0100
Subject: [PATCH 10/30] cmd: move lxc-update-config

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 configure.ac                                | 2 +-
 src/lxc/Makefile.am                         | 2 +-
 src/lxc/{tools => cmd}/lxc-update-config.in | 0
 3 files changed, 2 insertions(+), 2 deletions(-)
 rename src/lxc/{tools => cmd}/lxc-update-config.in (100%)

diff --git a/configure.ac b/configure.ac
index a841f9b9f..6bfed1017 100644
--- a/configure.ac
+++ b/configure.ac
@@ -940,8 +940,8 @@ AC_CONFIG_FILES([
 	src/lxc/Makefile
 	src/lxc/lxc.functions
 	src/lxc/cmd/lxc-checkconfig
+	src/lxc/cmd/lxc-update-config
 	src/lxc/tools/lxc-start-ephemeral
-	src/lxc/tools/lxc-update-config
 	src/lxc/version.h
 	src/python-lxc/Makefile
 
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index aa4e41c26..68dfb6cb9 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -217,7 +217,7 @@ liblxc_la_CFLAGS += $(CGMANAGER_CFLAGS) $(DBUS_CFLAGS) $(NIH_CFLAGS) $(NIH_DBUS_
 endif
 
 bin_SCRIPTS = cmd/lxc-checkconfig \
-	      tools/lxc-update-config
+	      cmd/lxc-update-config
 
 EXTRA_DIST = \
 	tools/lxc-top.lua
diff --git a/src/lxc/tools/lxc-update-config.in b/src/lxc/cmd/lxc-update-config.in
similarity index 100%
rename from src/lxc/tools/lxc-update-config.in
rename to src/lxc/cmd/lxc-update-config.in

From 1d598589f1ad6d67e3d96478ecc69ba969a6cfaf Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 14:02:10 +0100
Subject: [PATCH 11/30] tools: move lxc-checkpoint to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_checkpoint.c | 12 ++++--------
 src/lxc/tools/tool_utils.c     | 18 ++++++++++++++++++
 src/lxc/tools/tool_utils.h     |  1 +
 3 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/src/lxc/tools/lxc_checkpoint.c b/src/lxc/tools/lxc_checkpoint.c
index 8f93934b3..f3f9e7415 100644
--- a/src/lxc/tools/lxc_checkpoint.c
+++ b/src/lxc/tools/lxc_checkpoint.c
@@ -1,5 +1,4 @@
 /*
- *
  * Copyright © 2014 Tycho Andersen <tycho.andersen at canonical.com>.
  * Copyright © 2014 Canonical Ltd.
  *
@@ -17,19 +16,18 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include <stdio.h>
+#define _GNU_SOURCE
 #include <errno.h>
+#include <stdio.h>
+#include <string.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"
+#include "tool_utils.h"
 
 static char *checkpoint_dir = NULL;
 static bool stop = false;
@@ -253,8 +251,6 @@ int main(int argc, char *argv[])
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
 
-	lxc_log_options_no_override();
-
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
 
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
index 39b388161..4b4dad0b4 100644
--- a/src/lxc/tools/tool_utils.c
+++ b/src/lxc/tools/tool_utils.c
@@ -276,6 +276,24 @@ int lxc_caps_up(void)
 
 #endif
 
+int wait_for_pid(pid_t pid)
+{
+	int status, ret;
+
+again:
+	ret = waitpid(pid, &status, 0);
+	if (ret == -1) {
+		if (errno == EINTR)
+			goto again;
+		return -1;
+	}
+	if (ret != pid)
+		goto again;
+	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+		return -1;
+	return 0;
+}
+
 int lxc_wait_for_pid_status(pid_t pid)
 {
 	int status, ret;
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
index 59479dfa0..976995103 100644
--- a/src/lxc/tools/tool_utils.h
+++ b/src/lxc/tools/tool_utils.h
@@ -49,6 +49,7 @@ static inline int lxc_caps_init(void) {
 }
 #endif
 
+extern int wait_for_pid(pid_t pid);
 extern int lxc_wait_for_pid_status(pid_t pid);
 extern int lxc_safe_int(const char *numstr, int *converted);
 extern int lxc_safe_long(const char *numstr, long int *converted);

From 940d8166247ee73c3e5bc4eac58254bef6942ed0 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 14:05:21 +0100
Subject: [PATCH 12/30] tools: move lxc-clone to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_clone.c | 124 ++++++++++++++++++++++++++++------------------
 1 file changed, 77 insertions(+), 47 deletions(-)

diff --git a/src/lxc/tools/lxc_clone.c b/src/lxc/tools/lxc_clone.c
index 3aed40739..4dca80b7b 100644
--- a/src/lxc/tools/lxc_clone.c
+++ b/src/lxc/tools/lxc_clone.c
@@ -17,25 +17,19 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
 #include <getopt.h>
 #include <signal.h>
+#include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <unistd.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"
-
 /* we pass fssize in bytes */
 static uint64_t get_fssize(char *s)
 {
@@ -43,30 +37,33 @@ static uint64_t get_fssize(char *s)
 	char *end;
 
 	ret = strtoull(s, &end, 0);
-	if (end == s)
-	{
-		fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
+	if (end == s) {
+		fprintf(stderr,
+			"Invalid blockdev size '%s', using default size\n", s);
 		return 0;
 	}
+
 	while (isblank(*end))
 		end++;
-	if (*end == '\0')
+	if (*end == '\0') {
 		ret *= 1024ULL * 1024ULL; /* MB by default */
-	else if (*end == 'b' || *end == 'B')
+	} else if (*end == 'b' || *end == 'B') {
 		ret *= 1ULL;
-	else if (*end == 'k' || *end == 'K')
+	} else if (*end == 'k' || *end == 'K') {
 		ret *= 1024ULL;
-	else if (*end == 'm' || *end == 'M')
+	} else if (*end == 'm' || *end == 'M') {
 		ret *= 1024ULL * 1024ULL;
-	else if (*end == 'g' || *end == 'G')
+	} else if (*end == 'g' || *end == 'G') {
 		ret *= 1024ULL * 1024ULL * 1024ULL;
-	else if (*end == 't' || *end == 'T')
+	} 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);
+	} else {
+		fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', "
+				"using default size\n",
+			*end, s);
 		return 0;
 	}
+
 	return ret;
 }
 
@@ -124,42 +121,76 @@ int main(int argc, char *argv[])
 	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);
+	while (true) {
+		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;
+		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)
+
+	if (optind < argc && !orig)
 		orig = argv[optind++];
-    if (optind < argc && !new)
+
+	if (optind < argc && !new)
 		new = argv[optind++];
+
+	/* arguments for the clone hook */
 	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;
+	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
@@ -201,8 +232,7 @@ int main(int argc, char *argv[])
 			exit(EXIT_FAILURE);
 		}
 	} else {
-		c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize,
-			       args);
+		c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize, args);
 		if (c2 == NULL) {
 			lxc_container_put(c1);
 			fprintf(stderr, "clone failed\n");

From ace4a05a58a91ec49288c917e2b4f57534d3f571 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 14:08:43 +0100
Subject: [PATCH 13/30] cmd: move lxc-config to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_config.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/lxc/tools/lxc_config.c b/src/lxc/tools/lxc_config.c
index 86187bd57..682257f3d 100644
--- a/src/lxc/tools/lxc_config.c
+++ b/src/lxc/tools/lxc_config.c
@@ -23,8 +23,6 @@
 
 #include <lxc/lxccontainer.h>
 
-#include "config.h"
-
 struct lxc_config_items {
 	char *name;
 };

From fbea3cbdb31e2d596419c07a845eee9feb1497cd Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 14:11:21 +0100
Subject: [PATCH 14/30] cmd: move lxc-console to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_console.c |  8 +-------
 src/lxc/tools/tool_utils.c  | 28 ++++++++++++++++++++++++++++
 src/lxc/tools/tool_utils.h  |  1 +
 3 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/src/lxc/tools/lxc_console.c b/src/lxc/tools/lxc_console.c
index 876cbce58..f847811cb 100644
--- a/src/lxc/tools/lxc_console.c
+++ b/src/lxc/tools/lxc_console.c
@@ -39,12 +39,7 @@
 #include <lxc/lxccontainer.h>
 
 #include "arguments.h"
-#include "commands.h"
-#include "error.h"
-#include "log.h"
-#include "lxc.h"
-#include "mainloop.h"
-#include "utils.h"
+#include "tool_utils.h"
 
 static char etoc(const char *expr)
 {
@@ -115,7 +110,6 @@ int main(int argc, char *argv[])
 	ret = lxc_log_init(&log);
 	if (ret)
 		return EXIT_FAILURE;
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
index 4b4dad0b4..00181ab65 100644
--- a/src/lxc/tools/tool_utils.c
+++ b/src/lxc/tools/tool_utils.c
@@ -17,7 +17,9 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#define _GNU_SOURCE
 #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
+#include <ctype.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdio.h>
@@ -310,6 +312,32 @@ int lxc_wait_for_pid_status(pid_t pid)
 	return status;
 }
 
+int lxc_safe_uint(const char *numstr, unsigned int *converted)
+{
+	char *err = NULL;
+	unsigned long int uli;
+
+	while (isspace(*numstr))
+		numstr++;
+
+	if (*numstr == '-')
+		return -EINVAL;
+
+	errno = 0;
+	uli = strtoul(numstr, &err, 0);
+	if (errno == ERANGE && uli == ULONG_MAX)
+		return -ERANGE;
+
+	if (err == numstr || *err != '\0')
+		return -EINVAL;
+
+	if (uli > UINT_MAX)
+		return -ERANGE;
+
+	*converted = (unsigned int)uli;
+	return 0;
+}
+
 int lxc_safe_int(const char *numstr, int *converted)
 {
 	char *err = NULL;
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
index 976995103..26633ae5c 100644
--- a/src/lxc/tools/tool_utils.h
+++ b/src/lxc/tools/tool_utils.h
@@ -51,6 +51,7 @@ static inline int lxc_caps_init(void) {
 
 extern int wait_for_pid(pid_t pid);
 extern int lxc_wait_for_pid_status(pid_t pid);
+extern int lxc_safe_uint(const char *numstr, unsigned int *converted);
 extern int lxc_safe_int(const char *numstr, int *converted);
 extern int lxc_safe_long(const char *numstr, long int *converted);
 

From ab17b3e1023aa51c5539a42a2e3f2b765da7e602 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 14:27:23 +0100
Subject: [PATCH 15/30] tools: move lxc-copy to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/include/getsubopt.c |  89 +++++++++++++++++++++
 src/lxc/tools/include/getsubopt.h |   4 +
 src/lxc/tools/lxc_copy.c          |  62 ++++++---------
 src/lxc/tools/tool_utils.c        | 159 ++++++++++++++++++++++++++++++++++++++
 src/lxc/tools/tool_utils.h        |  12 +++
 5 files changed, 288 insertions(+), 38 deletions(-)
 create mode 100644 src/lxc/tools/include/getsubopt.c
 create mode 100644 src/lxc/tools/include/getsubopt.h

diff --git a/src/lxc/tools/include/getsubopt.c b/src/lxc/tools/include/getsubopt.c
new file mode 100644
index 000000000..b75497b1a
--- /dev/null
+++ b/src/lxc/tools/include/getsubopt.c
@@ -0,0 +1,89 @@
+/*
+ * Android c-library does not have getsubopt,
+ * so code lifted from uClibc
+ * http://git.uclibc.org/uClibc/tree/libc/unistd/getsubopt.c
+ */
+
+/* Parse comma separate list into words.
+   Copyright (C) 1996, 1997, 1999, 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper at cygnus.com>, 1996.
+   The GNU C 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.
+   The GNU C 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+char *strchrnul(const char *s, int c)
+{
+    char *result;
+
+    result = strchr( s, c );
+
+    if( !result )
+    {
+        result = (char *)s + strlen( s );
+    }
+
+    return( result );
+}
+
+/* Parse comma separated suboption from *OPTIONP and match against
+   strings in TOKENS.  If found return index and set *VALUEP to
+   optional value introduced by an equal sign.  If the suboption is
+   not part of TOKENS return in *VALUEP beginning of unknown
+   suboption.  On exit *OPTIONP is set to the beginning of the next
+   token or at the terminating NUL character.  */
+int
+getsubopt (char **optionp, char *const *tokens, char **valuep)
+{
+  char *endp, *vstart;
+  int cnt;
+
+  if (**optionp == '\0')
+    return -1;
+
+  /* Find end of next token.  */
+  endp = strchrnul (*optionp, ',');
+
+  /* Find start of value.  */
+  vstart = memchr (*optionp, '=', endp - *optionp);
+  if (vstart == NULL)
+    vstart = endp;
+
+  /* Try to match the characters between *OPTIONP and VSTART against
+     one of the TOKENS.  */
+  for (cnt = 0; tokens[cnt] != NULL; ++cnt)
+    if (strncmp (*optionp, tokens[cnt], vstart - *optionp) == 0
+    && tokens[cnt][vstart - *optionp] == '\0')
+      {
+    /* We found the current option in TOKENS.  */
+    *valuep = vstart != endp ? vstart + 1 : NULL;
+
+    if (*endp != '\0')
+      *endp++ = '\0';
+    *optionp = endp;
+
+    return cnt;
+      }
+
+  /* The current suboption does not match any option.  */
+  *valuep = *optionp;
+
+  if (*endp != '\0')
+    *endp++ = '\0';
+  *optionp = endp;
+
+  return -1;
+}
diff --git a/src/lxc/tools/include/getsubopt.h b/src/lxc/tools/include/getsubopt.h
new file mode 100644
index 000000000..e45cf66b0
--- /dev/null
+++ b/src/lxc/tools/include/getsubopt.h
@@ -0,0 +1,4 @@
+#ifndef _GETSUBOPT_H
+#define _GETSUBOPT_H
+int getsubopt (char **optionp, char *const *tokens, char **valuep);
+#endif
diff --git a/src/lxc/tools/lxc_copy.c b/src/lxc/tools/lxc_copy.c
index 1718f84a7..ae8b81021 100644
--- a/src/lxc/tools/lxc_copy.c
+++ b/src/lxc/tools/lxc_copy.c
@@ -17,37 +17,29 @@
  */
 
 #define _GNU_SOURCE
-#include "config.h"
-
-#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
 #include <signal.h>
-#include <stdio.h>
-#include <sys/types.h>
+#include <stdbool.h>
 #include <stdint.h>
-#include <sys/wait.h>
+#include <stdio.h>
 #include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+#include <string.h>
 #include <time.h>
-#include <stdbool.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
 #include <lxc/lxccontainer.h>
 
-#include "attach.h"
-#include "log.h"
-#include "confile.h"
 #include "arguments.h"
-#include "lxc.h"
-#include "conf.h"
-#include "state.h"
-#include "storage.h"
-#include "utils.h"
+#include "tool_utils.h"
 
 #ifndef HAVE_GETSUBOPT
-#include <../include/getsubopt.h>
+#include "include/getsubopt.h"
 #endif
 
 enum mnttype {
@@ -186,7 +178,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(ret);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
@@ -273,17 +264,17 @@ static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num, enum mnttype
 
 static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_arguments *arg)
 {
-	char upperdir[MAXPATHLEN];
-	char workdir[MAXPATHLEN];
+	char upperdir[TOOL_MAXPATHLEN];
+	char workdir[TOOL_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",
+			ret = snprintf(upperdir, TOOL_MAXPATHLEN, "%s/%s/delta#XXXXXX",
 					arg->newpath, arg->newname);
-			if (ret < 0 || ret >= MAXPATHLEN)
+			if (ret < 0 || ret >= TOOL_MAXPATHLEN)
 				return -1;
 			if (!mkdtemp(upperdir))
 				return -1;
@@ -293,9 +284,9 @@ static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_argu
 		}
 
 		if (m->mnt_type == LXC_MNT_OVL) {
-			ret = snprintf(workdir, MAXPATHLEN, "%s/%s/work#XXXXXX",
+			ret = snprintf(workdir, TOOL_MAXPATHLEN, "%s/%s/work#XXXXXX",
 					arg->newpath, arg->newname);
-			if (ret < 0 || ret >= MAXPATHLEN)
+			if (ret < 0 || ret >= TOOL_MAXPATHLEN)
 				return -1;
 			if (!mkdtemp(workdir))
 				return -1;
@@ -400,19 +391,19 @@ static int do_clone(struct lxc_container *c, char *newname, char *newpath,
 static int do_clone_ephemeral(struct lxc_container *c,
 		struct lxc_arguments *arg, char **args, int flags)
 {
-	char *bdev;
 	char *premount;
-	char randname[MAXPATHLEN];
+	char randname[TOOL_MAXPATHLEN];
 	unsigned int i;
 	int ret = 0;
 	bool bret = true, started = false;
+	char *tmp_buf = randname;
 	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)
+		ret = snprintf(randname, TOOL_MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name);
+		if (ret < 0 || ret >= TOOL_MAXPATHLEN)
 			return -1;
 		if (!mkdtemp(randname))
 			return -1;
@@ -429,12 +420,6 @@ static int do_clone_ephemeral(struct lxc_container *c,
 		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;
@@ -501,7 +486,8 @@ static int do_clone_ephemeral(struct lxc_container *c,
 destroy_and_put:
 	if (started)
 		clone->shutdown(clone, -1);
-	if (!started || clone->lxc_conf->ephemeral != 1)
+	ret = clone->get_config_item(clone, "lxc.ephemeral", tmp_buf, TOOL_MAXPATHLEN);
+	if (ret > 0 && strcmp(tmp_buf, "0"))
 		clone->destroy(clone);
 	free_mnts();
 	lxc_container_put(clone);
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
index 00181ab65..29adc6776 100644
--- a/src/lxc/tools/tool_utils.c
+++ b/src/lxc/tools/tool_utils.c
@@ -29,6 +29,7 @@
 #include <unistd.h>
 #include <linux/sched.h>
 #include <sys/prctl.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
@@ -380,3 +381,161 @@ int lxc_safe_long(const char *numstr, long int *converted)
 	*converted = sli;
 	return 0;
 }
+
+void lxc_free_array(void **array, lxc_free_fn element_free_fn)
+{
+	void **p;
+	for (p = array; p && *p; p++)
+		element_free_fn(*p);
+	free((void*)array);
+}
+
+int lxc_grow_array(void ***array, size_t* capacity, size_t new_size, size_t capacity_increment)
+{
+	size_t new_capacity;
+	void **new_array;
+
+	/* first time around, catch some trivial mistakes of the user
+	 * only initializing one of these */
+	if (!*array || !*capacity) {
+		*array = NULL;
+		*capacity = 0;
+	}
+
+	new_capacity = *capacity;
+	while (new_size + 1 > new_capacity)
+		new_capacity += capacity_increment;
+	if (new_capacity != *capacity) {
+		/* we have to reallocate */
+		new_array = realloc(*array, new_capacity * sizeof(void *));
+		if (!new_array)
+			return -1;
+		memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * sizeof(void *));
+		*array = new_array;
+		*capacity = new_capacity;
+	}
+
+	/* array has sufficient elements */
+	return 0;
+}
+
+char **lxc_string_split(const char *string, char _sep)
+{
+	char *token, *str, *saveptr = NULL;
+	char sep[2] = {_sep, '\0'};
+	char **tmp = NULL, **result = NULL;
+	size_t result_capacity = 0;
+	size_t result_count = 0;
+	int r, saved_errno;
+
+	if (!string)
+		return calloc(1, sizeof(char *));
+
+	str = alloca(strlen(string) + 1);
+	strcpy(str, string);
+	for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
+		r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
+		if (r < 0)
+			goto error_out;
+		result[result_count] = strdup(token);
+		if (!result[result_count])
+			goto error_out;
+		result_count++;
+	}
+
+	/* if we allocated too much, reduce it */
+	tmp = realloc(result, (result_count + 1) * sizeof(char *));
+	if (!tmp)
+		goto error_out;
+	result = tmp;
+	/* Make sure we don't return uninitialized memory. */
+	if (result_count == 0)
+		*result = NULL;
+	return result;
+error_out:
+	saved_errno = errno;
+	lxc_free_array((void **)result, free);
+	errno = saved_errno;
+	return NULL;
+}
+
+char **lxc_normalize_path(const char *path)
+{
+	char **components;
+	char **p;
+	size_t components_len = 0;
+	size_t pos = 0;
+
+	components = lxc_string_split(path, '/');
+	if (!components)
+		return NULL;
+	for (p = components; *p; p++)
+		components_len++;
+
+	/* resolve '.' and '..' */
+	for (pos = 0; pos < components_len; ) {
+		if (!strcmp(components[pos], ".") || (!strcmp(components[pos], "..") && pos == 0)) {
+			/* eat this element */
+			free(components[pos]);
+			memmove(&components[pos], &components[pos+1], sizeof(char *) * (components_len - pos));
+			components_len--;
+		} else if (!strcmp(components[pos], "..")) {
+			/* eat this and the previous element */
+			free(components[pos - 1]);
+			free(components[pos]);
+			memmove(&components[pos-1], &components[pos+1], sizeof(char *) * (components_len - pos));
+			components_len -= 2;
+			pos--;
+		} else {
+			pos++;
+		}
+	}
+
+	return components;
+}
+
+char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix)
+{
+	char *result;
+	char **p;
+	size_t sep_len = strlen(sep);
+	size_t result_len = use_as_prefix * sep_len;
+
+	/* calculate new string length */
+	for (p = (char **)parts; *p; p++)
+		result_len += (p > (char **)parts) * sep_len + strlen(*p);
+
+	result = calloc(result_len + 1, 1);
+	if (!result)
+		return NULL;
+
+	if (use_as_prefix)
+		strcpy(result, sep);
+	for (p = (char **)parts; *p; p++) {
+		if (p > (char **)parts)
+			strcat(result, sep);
+		strcat(result, *p);
+	}
+
+	return result;
+}
+
+int is_dir(const char *path)
+{
+	struct stat statbuf;
+	int ret = stat(path, &statbuf);
+	if (ret == 0 && S_ISDIR(statbuf.st_mode))
+		return 1;
+	return 0;
+}
+
+size_t lxc_array_len(void **array)
+{
+	void **p;
+	size_t result = 0;
+
+	for (p = array; p && *p; p++)
+		result++;
+
+	return result;
+}
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
index 26633ae5c..12ef11819 100644
--- a/src/lxc/tools/tool_utils.h
+++ b/src/lxc/tools/tool_utils.h
@@ -55,4 +55,16 @@ extern int lxc_safe_uint(const char *numstr, unsigned int *converted);
 extern int lxc_safe_int(const char *numstr, int *converted);
 extern int lxc_safe_long(const char *numstr, long int *converted);
 
+typedef void (*lxc_free_fn)(void *);
+extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
+extern size_t lxc_array_len(void **array);
+extern int lxc_grow_array(void ***array, size_t *capacity, size_t new_size,
+			  size_t capacity_increment);
+extern char **lxc_string_split(const char *string, char _sep);
+extern char **lxc_normalize_path(const char *path);
+extern char *lxc_string_join(const char *sep, const char **parts,
+			     bool use_as_prefix);
+
+extern int is_dir(const char *path);
+
 #endif /* __LXC_UTILS_H */

From d5ae8d2d13764a567878182f1c7431a3032c3fc6 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 14:33:06 +0100
Subject: [PATCH 16/30] tools: move lxc-create to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_create.c | 30 +++++++++++++++++-------
 src/lxc/tools/tool_utils.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/tools/tool_utils.h |  3 +++
 3 files changed, 82 insertions(+), 8 deletions(-)

diff --git a/src/lxc/tools/lxc_create.c b/src/lxc/tools/lxc_create.c
index f702c2ba7..9a4640316 100644
--- a/src/lxc/tools/lxc_create.c
+++ b/src/lxc/tools/lxc_create.c
@@ -22,16 +22,14 @@
 #include <libgen.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <string.h>
 #include <unistd.h>
-#include <lxc/lxccontainer.h>
 #include <sys/types.h>
 
+#include <lxc/lxccontainer.h>
+
 #include "arguments.h"
-#include "log.h"
-#include "lxc.h"
-#include "storage.h"
-#include "storage_utils.h"
-#include "utils.h"
+#include "tool_utils.h"
 
 static uint64_t get_fssize(char *s)
 {
@@ -203,6 +201,23 @@ static bool validate_bdev_args(struct lxc_arguments *a)
 	return true;
 }
 
+static bool is_valid_storage_type(const char *type)
+{
+	if (strcmp(type, "dir") == 0 ||
+	    strcmp(type, "btrfs") == 0 ||
+	    strcmp(type, "aufs") == 0 ||
+	    strcmp(type, "loop") == 0 ||
+	    strcmp(type, "lvm") == 0 ||
+	    strcmp(type, "nbd") == 0 ||
+	    strcmp(type, "overlay") == 0 ||
+	    strcmp(type, "overlayfs") == 0 ||
+	    strcmp(type, "rbd") == 0 ||
+	    strcmp(type, "zfs") == 0)
+		return true;
+
+	return false;
+}
+
 int main(int argc, char *argv[])
 {
 	struct lxc_container *c;
@@ -225,7 +240,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
@@ -286,7 +300,7 @@ int main(int argc, char *argv[])
 	if (my_args.configfile)
 		c->load_config(c, my_args.configfile);
 	else
-		c->load_config(c, lxc_global_config_value("lxc.default_config"));
+		c->load_config(c, lxc_get_global_config_item("lxc.default_config"));
 
 	if (my_args.fstype)
 		spec.fstype = my_args.fstype;
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
index 29adc6776..94f118e63 100644
--- a/src/lxc/tools/tool_utils.c
+++ b/src/lxc/tools/tool_utils.c
@@ -539,3 +539,60 @@ size_t lxc_array_len(void **array)
 
 	return result;
 }
+
+/*
+ * Given the '-t' template option to lxc-create, figure out what to
+ * do.  If the template is a full executable path, use that.  If it
+ * is something like 'sshd', then return $templatepath/lxc-sshd.
+ * On success return the template, on error return NULL.
+ */
+char *get_template_path(const char *t)
+{
+	int ret, len;
+	char *tpath;
+
+	if (t[0] == '/' && access(t, X_OK) == 0) {
+		tpath = strdup(t);
+		return tpath;
+	}
+
+	len = strlen(LXCTEMPLATEDIR) + strlen(t) + strlen("/lxc-") + 1;
+	tpath = malloc(len);
+	if (!tpath)
+		return NULL;
+	ret = snprintf(tpath, len, "%s/lxc-%s", LXCTEMPLATEDIR, t);
+	if (ret < 0 || ret >= len) {
+		free(tpath);
+		return NULL;
+	}
+	if (access(tpath, X_OK) < 0) {
+		fprintf(stderr, "Bad template: %s\n", t);
+		free(tpath);
+		return NULL;
+	}
+
+	return tpath;
+}
+
+int mkdir_p(const char *dir, mode_t mode)
+{
+	const char *tmp = dir;
+	const char *orig = dir;
+	char *makeme;
+
+	do {
+		dir = tmp + strspn(tmp, "/");
+		tmp = dir + strcspn(dir, "/");
+		makeme = strndup(orig, dir - orig);
+		if (*makeme) {
+			if (mkdir(makeme, mode) && errno != EEXIST) {
+				fprintf(stderr, "Failed to create directory \"%s\"\n", makeme);
+				free(makeme);
+				return -1;
+			}
+		}
+		free(makeme);
+	} while(tmp != dir);
+
+	return 0;
+}
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
index 12ef11819..258f4223c 100644
--- a/src/lxc/tools/tool_utils.h
+++ b/src/lxc/tools/tool_utils.h
@@ -65,6 +65,9 @@ extern char **lxc_normalize_path(const char *path);
 extern char *lxc_string_join(const char *sep, const char **parts,
 			     bool use_as_prefix);
 
+extern int mkdir_p(const char *dir, mode_t mode);
 extern int is_dir(const char *path);
 
+extern char *get_template_path(const char *t);
+
 #endif /* __LXC_UTILS_H */

From 442d6e6cfbb9cf7d8cbddacc3e6ed6e0aec16e1b Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 14:39:21 +0100
Subject: [PATCH 17/30] tools: move lxc-destroy to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_destroy.c | 40 ++++++++++++++++++++++------------------
 src/lxc/tools/tool_utils.c  |  7 +++++++
 src/lxc/tools/tool_utils.h  |  1 +
 3 files changed, 30 insertions(+), 18 deletions(-)

diff --git a/src/lxc/tools/lxc_destroy.c b/src/lxc/tools/lxc_destroy.c
index 1c3f7dc50..48484a6be 100644
--- a/src/lxc/tools/lxc_destroy.c
+++ b/src/lxc/tools/lxc_destroy.c
@@ -18,19 +18,18 @@
  */
 
 #define _GNU_SOURCE
-#include "config.h"
-
+#include <fcntl.h>
 #include <libgen.h>
 #include <stdio.h>
+#include <string.h>
 #include <unistd.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 
 #include <lxc/lxccontainer.h>
 
 #include "arguments.h"
-#include "log.h"
-#include "lxc.h"
-#include "utils.h"
+#include "tool_utils.h"
 
 static int my_parser(struct lxc_arguments* args, int c, char* arg);
 static bool quiet;
@@ -83,7 +82,7 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
+
 	if (my_args.quiet)
 		quiet = true;
 
@@ -155,11 +154,11 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
 static bool do_destroy(struct lxc_container *c)
 {
 	bool bret = true;
-	char path[MAXPATHLEN];
+	char path[TOOL_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)
+	int ret = snprintf(path, TOOL_MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
+	if (ret < 0 || ret >= TOOL_MAXPATHLEN)
 		return false;
 
 	if (file_exists(path)) {
@@ -168,8 +167,8 @@ static bool do_destroy(struct lxc_container *c)
 		return false;
 	}
 
-	ret = snprintf(path, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
-	if (ret < 0 || ret >= MAXPATHLEN)
+	ret = snprintf(path, TOOL_MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
+	if (ret < 0 || ret >= TOOL_MAXPATHLEN)
 		return false;
 
 	if (rmdir(path) < 0 && errno != ENOENT) {
@@ -189,8 +188,13 @@ static bool do_destroy(struct lxc_container *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 (c->is_defined(c)) {
+		char buf[256];
+		ret = c->get_config_item(c, "lxc.ephemeral", buf, 256);
+		if (ret > 0 && strcmp(buf, "0") == 0) {
+			bret = c->destroy(c);
+		}
+	}
 
 	if (!bret) {
 		if (!quiet)
@@ -206,7 +210,7 @@ static bool do_destroy_with_snapshots(struct lxc_container *c)
 	struct lxc_container *c1;
 	struct stat fbuf;
 	bool bret = false;
-	char path[MAXPATHLEN];
+	char path[TOOL_MAXPATHLEN];
 	char *buf = NULL;
 	char *lxcpath = NULL;
 	char *lxcname = NULL;
@@ -216,8 +220,8 @@ static bool do_destroy_with_snapshots(struct lxc_container *c)
 	int counter = 0;
 
 	/* Destroy clones. */
-	ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
-	if (ret < 0 || ret >= MAXPATHLEN)
+	ret = snprintf(path, TOOL_MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path, c->name);
+	if (ret < 0 || ret >= TOOL_MAXPATHLEN)
 		return false;
 
 	fd = open(path, O_RDONLY | O_CLOEXEC);
@@ -268,8 +272,8 @@ static bool do_destroy_with_snapshots(struct lxc_container *c)
 	}
 
 	/* 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)
+	ret = snprintf(path, TOOL_MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
+	if (ret < 0 || ret >= TOOL_MAXPATHLEN)
 		return false;
 
 	if (rmdir(path) < 0 && errno != ENOENT)
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
index 94f118e63..e50f50273 100644
--- a/src/lxc/tools/tool_utils.c
+++ b/src/lxc/tools/tool_utils.c
@@ -596,3 +596,10 @@ int mkdir_p(const char *dir, mode_t mode)
 
 	return 0;
 }
+
+bool file_exists(const char *f)
+{
+	struct stat statbuf;
+
+	return stat(f, &statbuf) == 0;
+}
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
index 258f4223c..1ba18f6d9 100644
--- a/src/lxc/tools/tool_utils.h
+++ b/src/lxc/tools/tool_utils.h
@@ -66,6 +66,7 @@ extern char *lxc_string_join(const char *sep, const char **parts,
 			     bool use_as_prefix);
 
 extern int mkdir_p(const char *dir, mode_t mode);
+extern bool file_exists(const char *f);
 extern int is_dir(const char *path);
 
 extern char *get_template_path(const char *t);

From 39ab625671e21f135a6429a67e26b291f714cadc Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 14:46:46 +0100
Subject: [PATCH 18/30] tools: move lxc-device to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/arguments.h       |   1 -
 src/lxc/tools/include/ifaddrs.c | 599 ++++++++++++++++++++++++++++++++++++++++
 src/lxc/tools/include/ifaddrs.h |  54 ++++
 src/lxc/tools/lxc_cgroup.c      |   1 +
 src/lxc/tools/lxc_device.c      |  16 +-
 src/lxc/tools/tool_utils.c      |  27 ++
 src/lxc/tools/tool_utils.h      |   4 +
 7 files changed, 692 insertions(+), 10 deletions(-)
 create mode 100644 src/lxc/tools/include/ifaddrs.c
 create mode 100644 src/lxc/tools/include/ifaddrs.h

diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h
index bd491a32b..15941bcc3 100644
--- a/src/lxc/tools/arguments.h
+++ b/src/lxc/tools/arguments.h
@@ -31,7 +31,6 @@
 #include <sys/types.h>
 #include <lxc/lxccontainer.h>
 
-#define TOOL_MAXPATHLEN 4096
 struct lxc_arguments;
 
 typedef int (*lxc_arguments_parser_t)(struct lxc_arguments *, int, char *);
diff --git a/src/lxc/tools/include/ifaddrs.c b/src/lxc/tools/include/ifaddrs.c
new file mode 100644
index 000000000..1f954dd7d
--- /dev/null
+++ b/src/lxc/tools/include/ifaddrs.c
@@ -0,0 +1,599 @@
+/*
+Copyright (c) 2013, Kenneth MacKay
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "ifaddrs.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+typedef struct NetlinkList
+{
+    struct NetlinkList *m_next;
+    struct nlmsghdr *m_data;
+    unsigned int m_size;
+} NetlinkList;
+
+static int netlink_socket(void)
+{
+    int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+    if(l_socket < 0)
+    {
+        return -1;
+    }
+
+    struct sockaddr_nl l_addr;
+    memset(&l_addr, 0, sizeof(l_addr));
+    l_addr.nl_family = AF_NETLINK;
+    if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
+    {
+        close(l_socket);
+        return -1;
+    }
+
+    return l_socket;
+}
+
+static int netlink_send(int p_socket, int p_request)
+{
+    char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
+    memset(l_buffer, 0, sizeof(l_buffer));
+    struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer;
+    struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
+
+    l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
+    l_hdr->nlmsg_type = p_request;
+    l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+    l_hdr->nlmsg_pid = 0;
+    l_hdr->nlmsg_seq = p_socket;
+    l_msg->rtgen_family = AF_UNSPEC;
+
+    struct sockaddr_nl l_addr;
+    memset(&l_addr, 0, sizeof(l_addr));
+    l_addr.nl_family = AF_NETLINK;
+    return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
+}
+
+static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
+{
+    struct msghdr l_msg;
+    struct iovec l_iov = { p_buffer, p_len };
+    struct sockaddr_nl l_addr;
+
+    for(;;)
+    {
+        l_msg.msg_name = (void *)&l_addr;
+        l_msg.msg_namelen = sizeof(l_addr);
+        l_msg.msg_iov = &l_iov;
+        l_msg.msg_iovlen = 1;
+        l_msg.msg_control = NULL;
+        l_msg.msg_controllen = 0;
+        l_msg.msg_flags = 0;
+        int l_result = recvmsg(p_socket, &l_msg, 0);
+
+        if(l_result < 0)
+        {
+            if(errno == EINTR)
+            {
+                continue;
+            }
+            return -2;
+        }
+
+        if(l_msg.msg_flags & MSG_TRUNC)
+        { // buffer was too small
+            return -1;
+        }
+        return l_result;
+    }
+}
+
+static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
+{
+    size_t l_size = 4096;
+    void *l_buffer = NULL;
+
+    for(;;)
+    {
+        free(l_buffer);
+        l_buffer = malloc(l_size);
+
+        int l_read = netlink_recv(p_socket, l_buffer, l_size);
+        *p_size = l_read;
+        if(l_read == -2)
+        {
+            free(l_buffer);
+            return NULL;
+        }
+        if(l_read >= 0)
+        {
+            pid_t l_pid = getpid();
+            struct nlmsghdr *l_hdr;
+            for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
+            {
+                if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+                {
+                    continue;
+                }
+
+                if(l_hdr->nlmsg_type == NLMSG_DONE)
+                {
+                    *p_done = 1;
+                    break;
+                }
+
+                if(l_hdr->nlmsg_type == NLMSG_ERROR)
+                {
+                    free(l_buffer);
+                    return NULL;
+                }
+            }
+            return l_buffer;
+        }
+
+        l_size *= 2;
+    }
+}
+
+static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
+{
+    NetlinkList *l_item = malloc(sizeof(NetlinkList));
+    l_item->m_next = NULL;
+    l_item->m_data = p_data;
+    l_item->m_size = p_size;
+    return l_item;
+}
+
+static void freeResultList(NetlinkList *p_list)
+{
+    NetlinkList *l_cur;
+    while(p_list)
+    {
+        l_cur = p_list;
+        p_list = p_list->m_next;
+        free(l_cur->m_data);
+        free(l_cur);
+    }
+}
+
+static NetlinkList *getResultList(int p_socket, int p_request)
+{
+    if(netlink_send(p_socket, p_request) < 0)
+    {
+        return NULL;
+    }
+
+    NetlinkList *l_list = NULL;
+    NetlinkList *l_end = NULL;
+    int l_size;
+    int l_done = 0;
+    while(!l_done)
+    {
+        struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
+        if(!l_hdr)
+        { // error
+            freeResultList(l_list);
+            return NULL;
+        }
+
+        NetlinkList *l_item = newListItem(l_hdr, l_size);
+        if(!l_list)
+        {
+            l_list = l_item;
+        }
+        else
+        {
+            l_end->m_next = l_item;
+        }
+        l_end = l_item;
+    }
+    return l_list;
+}
+
+static size_t maxSize(size_t a, size_t b)
+{
+    return (a > b ? a : b);
+}
+
+static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
+{
+    switch(p_family)
+    {
+        case AF_INET:
+            return sizeof(struct sockaddr_in);
+        case AF_INET6:
+            return sizeof(struct sockaddr_in6);
+        case AF_PACKET:
+            return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
+        default:
+            return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
+    }
+}
+
+static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
+{
+    switch(p_family)
+    {
+        case AF_INET:
+            memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
+            break;
+        case AF_INET6:
+            memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
+            break;
+        case AF_PACKET:
+            memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
+            ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
+            break;
+        default:
+            memcpy(p_dest->sa_data, p_data, p_size);
+            break;
+    }
+    p_dest->sa_family = p_family;
+}
+
+static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
+{
+    if(!*p_resultList)
+    {
+        *p_resultList = p_entry;
+    }
+    else
+    {
+        struct ifaddrs *l_cur = *p_resultList;
+        while(l_cur->ifa_next)
+        {
+            l_cur = l_cur->ifa_next;
+        }
+        l_cur->ifa_next = p_entry;
+    }
+}
+
+static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
+{
+    struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
+
+    size_t l_nameSize = 0;
+    size_t l_addrSize = 0;
+    size_t l_dataSize = 0;
+
+    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
+    struct rtattr *l_rta;
+    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+    {
+        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+        switch(l_rta->rta_type)
+        {
+            case IFLA_ADDRESS:
+            case IFLA_BROADCAST:
+                l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
+                break;
+            case IFLA_IFNAME:
+                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+                break;
+            case IFLA_STATS:
+                l_dataSize += NLMSG_ALIGN(l_rtaSize);
+                break;
+            default:
+                break;
+        }
+    }
+
+    struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize);
+    memset(l_entry, 0, sizeof(struct ifaddrs));
+    l_entry->ifa_name = "";
+
+    char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
+    char *l_addr = l_name + l_nameSize;
+    char *l_data = l_addr + l_addrSize;
+
+    l_entry->ifa_flags = l_info->ifi_flags;
+
+    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
+    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+    {
+        void *l_rtaData = RTA_DATA(l_rta);
+        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+        switch(l_rta->rta_type)
+        {
+            case IFLA_ADDRESS:
+            case IFLA_BROADCAST:
+            {
+                size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
+                makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
+                ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
+                ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
+                if(l_rta->rta_type == IFLA_ADDRESS)
+                {
+                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
+                }
+                else
+                {
+                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
+                }
+                l_addr += NLMSG_ALIGN(l_addrLen);
+                break;
+            }
+            case IFLA_IFNAME:
+                strncpy(l_name, l_rtaData, l_rtaDataSize);
+                l_name[l_rtaDataSize] = '\0';
+                l_entry->ifa_name = l_name;
+                break;
+            case IFLA_STATS:
+                memcpy(l_data, l_rtaData, l_rtaDataSize);
+                l_entry->ifa_data = l_data;
+                break;
+            default:
+                break;
+        }
+    }
+
+    addToEnd(p_resultList, l_entry);
+    p_links[l_info->ifi_index - 1] = l_entry;
+}
+
+static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
+{
+    struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
+
+    size_t l_nameSize = 0;
+    size_t l_addrSize = 0;
+
+    int l_addedNetmask = 0;
+
+    size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
+    struct rtattr *l_rta;
+    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+    {
+        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+        if(l_info->ifa_family == AF_PACKET)
+        {
+            continue;
+        }
+
+        switch(l_rta->rta_type)
+        {
+            case IFA_ADDRESS:
+            case IFA_LOCAL:
+                if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
+                { // make room for netmask
+                    l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
+                    l_addedNetmask = 1;
+                }
+            case IFA_BROADCAST:
+                l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
+                break;
+            case IFA_LABEL:
+                l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+                break;
+            default:
+                break;
+        }
+    }
+
+    struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
+    memset(l_entry, 0, sizeof(struct ifaddrs));
+    l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name;
+
+    char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
+    char *l_addr = l_name + l_nameSize;
+
+    l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags;
+
+    l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
+    for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+    {
+        void *l_rtaData = RTA_DATA(l_rta);
+        size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+        switch(l_rta->rta_type)
+        {
+            case IFA_ADDRESS:
+            case IFA_BROADCAST:
+            case IFA_LOCAL:
+            {
+                size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
+                makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
+                if(l_info->ifa_family == AF_INET6)
+                {
+                    if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
+                    {
+                        ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
+                    }
+                }
+
+                if(l_rta->rta_type == IFA_ADDRESS)
+                { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address
+                    if(l_entry->ifa_addr)
+                    {
+                        l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
+                    }
+                    else
+                    {
+                        l_entry->ifa_addr = (struct sockaddr *)l_addr;
+                    }
+                }
+                else if(l_rta->rta_type == IFA_LOCAL)
+                {
+                    if(l_entry->ifa_addr)
+                    {
+                        l_entry->ifa_dstaddr = l_entry->ifa_addr;
+                    }
+                    l_entry->ifa_addr = (struct sockaddr *)l_addr;
+                }
+                else
+                {
+                    l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
+                }
+                l_addr += NLMSG_ALIGN(l_addrLen);
+                break;
+            }
+            case IFA_LABEL:
+                strncpy(l_name, l_rtaData, l_rtaDataSize);
+                l_name[l_rtaDataSize] = '\0';
+                l_entry->ifa_name = l_name;
+                break;
+            default:
+                break;
+        }
+    }
+
+    if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
+    {
+        unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
+        unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
+        char l_mask[16] = {0};
+        unsigned i;
+        for(i=0; i<(l_prefix/8); ++i)
+        {
+            l_mask[i] = 0xff;
+        }
+        if (l_prefix % 8) {
+            l_mask[i] = 0xff << (8 - (l_prefix % 8));
+        }
+
+        makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
+        l_entry->ifa_netmask = (struct sockaddr *)l_addr;
+    }
+
+    addToEnd(p_resultList, l_entry);
+}
+
+static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList)
+{
+    pid_t l_pid = getpid();
+    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
+    {
+        unsigned int l_nlsize = p_netlinkList->m_size;
+        struct nlmsghdr *l_hdr;
+        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
+        {
+            if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+            {
+                continue;
+            }
+
+            if(l_hdr->nlmsg_type == NLMSG_DONE)
+            {
+                break;
+            }
+
+            if(l_hdr->nlmsg_type == RTM_NEWLINK)
+            {
+                interpretLink(l_hdr, p_links, p_resultList);
+            }
+            else if(l_hdr->nlmsg_type == RTM_NEWADDR)
+            {
+                interpretAddr(l_hdr, p_links, p_resultList);
+            }
+        }
+    }
+}
+
+static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList)
+{
+    unsigned l_links = 0;
+    pid_t l_pid = getpid();
+    for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
+    {
+        unsigned int l_nlsize = p_netlinkList->m_size;
+        struct nlmsghdr *l_hdr;
+        for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
+        {
+            if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+            {
+                continue;
+            }
+
+            if(l_hdr->nlmsg_type == NLMSG_DONE)
+            {
+                break;
+            }
+
+            if(l_hdr->nlmsg_type == RTM_NEWLINK)
+            {
+                ++l_links;
+            }
+        }
+    }
+
+    return l_links;
+}
+
+int getifaddrs(struct ifaddrs **ifap)
+{
+    if(!ifap)
+    {
+        return -1;
+    }
+    *ifap = NULL;
+
+    int l_socket = netlink_socket();
+    if(l_socket < 0)
+    {
+        return -1;
+    }
+
+    NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
+    if(!l_linkResults)
+    {
+        close(l_socket);
+        return -1;
+    }
+
+    NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
+    if(!l_addrResults)
+    {
+        close(l_socket);
+        freeResultList(l_linkResults);
+        return -1;
+    }
+
+    unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults);
+    struct ifaddrs *l_links[l_numLinks];
+    memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *));
+
+    interpret(l_socket, l_linkResults, l_links, ifap);
+    interpret(l_socket, l_addrResults, l_links, ifap);
+
+    freeResultList(l_linkResults);
+    freeResultList(l_addrResults);
+    close(l_socket);
+    return 0;
+}
+
+void freeifaddrs(struct ifaddrs *ifa)
+{
+    struct ifaddrs *l_cur;
+    while(ifa)
+    {
+        l_cur = ifa;
+        ifa = ifa->ifa_next;
+        free(l_cur);
+    }
+}
diff --git a/src/lxc/tools/include/ifaddrs.h b/src/lxc/tools/include/ifaddrs.h
new file mode 100644
index 000000000..9cd19fec1
--- /dev/null
+++ b/src/lxc/tools/include/ifaddrs.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 1999
+ *	Berkeley Software Design, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
+ */
+
+#ifndef	_IFADDRS_H_
+#define	_IFADDRS_H_
+
+struct ifaddrs {
+	struct ifaddrs  *ifa_next;
+	char		*ifa_name;
+	unsigned int	 ifa_flags;
+	struct sockaddr	*ifa_addr;
+	struct sockaddr	*ifa_netmask;
+	struct sockaddr	*ifa_dstaddr;
+	void		*ifa_data;
+};
+
+/*
+ * This may have been defined in <net/if.h>.  Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef	ifa_broadaddr
+#define	ifa_broadaddr	ifa_dstaddr	/* broadcast address interface */
+#endif
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int getifaddrs(struct ifaddrs **ifap);
+extern void freeifaddrs(struct ifaddrs *ifa);
+__END_DECLS
+
+#endif
diff --git a/src/lxc/tools/lxc_cgroup.c b/src/lxc/tools/lxc_cgroup.c
index 3624e80b7..231cc7b7c 100644
--- a/src/lxc/tools/lxc_cgroup.c
+++ b/src/lxc/tools/lxc_cgroup.c
@@ -32,6 +32,7 @@
 #include <lxc/lxccontainer.h>
 
 #include "arguments.h"
+#include "tool_utils.h"
 
 static int my_checker(const struct lxc_arguments* args)
 {
diff --git a/src/lxc/tools/lxc_device.c b/src/lxc/tools/lxc_device.c
index f73e8c2cb..501bc99a0 100644
--- a/src/lxc/tools/lxc_device.c
+++ b/src/lxc/tools/lxc_device.c
@@ -18,25 +18,24 @@
  * 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 <libgen.h>
+#include <limits.h>
 #include <stdio.h>
+#include <string.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"
+#include "tool_utils.h"
 
 #if HAVE_IFADDRS_H
 #include <ifaddrs.h>
 #else
-#include <../include/ifaddrs.h>
+#include "include/ifaddrs.h"
 #endif
 
 static const struct option my_longopts[] = {
@@ -123,7 +122,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		goto err;
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
index e50f50273..42be4d249 100644
--- a/src/lxc/tools/tool_utils.c
+++ b/src/lxc/tools/tool_utils.c
@@ -21,7 +21,9 @@
 #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
 #include <ctype.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <limits.h>
+#include <sched.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -603,3 +605,28 @@ bool file_exists(const char *f)
 
 	return stat(f, &statbuf) == 0;
 }
+
+bool switch_to_ns(pid_t pid, const char *ns) {
+	int fd, ret;
+	char nspath[TOOL_MAXPATHLEN];
+
+	/* Switch to new ns */
+	ret = snprintf(nspath, TOOL_MAXPATHLEN, "/proc/%d/ns/%s", pid, ns);
+	if (ret < 0 || ret >= TOOL_MAXPATHLEN)
+		return false;
+
+	fd = open(nspath, O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Failed to open %s\n", nspath);
+		return false;
+	}
+
+	ret = setns(fd, 0);
+	if (ret) {
+		fprintf(stderr, "Failed to set process %d to %s of %d\n", pid, ns, fd);
+		close(fd);
+		return false;
+	}
+	close(fd);
+	return true;
+}
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
index 1ba18f6d9..2ce2afd0a 100644
--- a/src/lxc/tools/tool_utils.h
+++ b/src/lxc/tools/tool_utils.h
@@ -29,6 +29,8 @@
 #include <stdbool.h>
 #include <unistd.h>
 
+#define TOOL_MAXPATHLEN 4096
+
 extern int lxc_fill_elevated_privileges(char *flaglist, int *flags);
 extern signed long lxc_config_parse_arch(const char *arch);
 extern int lxc_namespace_2_cloneflag(const char *namespace);
@@ -71,4 +73,6 @@ extern int is_dir(const char *path);
 
 extern char *get_template_path(const char *t);
 
+extern bool switch_to_ns(pid_t pid, const char *ns);
+
 #endif /* __LXC_UTILS_H */

From 52cba15dc85f85390dc9b3297af89717e9e4a4c0 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 15:31:03 +0100
Subject: [PATCH 19/30] tools: move lxc-execute to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/Makefile.am         |  14 +--
 src/lxc/tools/arguments.c   |   7 +-
 src/lxc/tools/lxc_execute.c |  76 +++++++++++-----
 src/lxc/tools/tool_utils.c  | 215 +++++++++++++++++++++++++++++++++++++++++---
 src/lxc/tools/tool_utils.h  |  29 ++++++
 5 files changed, 296 insertions(+), 45 deletions(-)

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 68dfb6cb9..7194216ef 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -269,13 +269,13 @@ endif
 LDADD=liblxc.la @CAP_LIBS@ @APPARMOR_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@
 
 lxc_attach_SOURCES = tools/lxc_attach.c tools/arguments.c tools/tool_utils.c
-lxc_autostart_SOURCES = tools/lxc_autostart.c tools/arguments.c
-lxc_cgroup_SOURCES = tools/lxc_cgroup.c tools/arguments.c
-lxc_config_SOURCES = tools/lxc_config.c tools/arguments.c
-lxc_console_SOURCES = tools/lxc_console.c tools/arguments.c
-lxc_destroy_SOURCES = tools/lxc_destroy.c tools/arguments.c
-lxc_device_SOURCES = tools/lxc_device.c tools/arguments.c
-lxc_execute_SOURCES = tools/lxc_execute.c tools/arguments.c
+lxc_autostart_SOURCES = tools/lxc_autostart.c tools/arguments.c tools/tool_utils.c
+lxc_cgroup_SOURCES = tools/lxc_cgroup.c tools/arguments.c tools/tool_utils.c
+lxc_config_SOURCES = tools/lxc_config.c tools/arguments.c tools/tool_utils.c
+lxc_console_SOURCES = tools/lxc_console.c tools/arguments.c tools/tool_utils.c
+lxc_destroy_SOURCES = tools/lxc_destroy.c tools/arguments.c tools/tool_utils.c
+lxc_device_SOURCES = tools/lxc_device.c tools/arguments.c tools/tool_utils.c
+lxc_execute_SOURCES = tools/lxc_execute.c tools/arguments.c tools/tool_utils.c
 lxc_freeze_SOURCES = tools/lxc_freeze.c tools/arguments.c
 lxc_info_SOURCES = tools/lxc_info.c tools/arguments.c
 lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c
diff --git a/src/lxc/tools/arguments.c b/src/lxc/tools/arguments.c
index 7116dd6bc..889140984 100644
--- a/src/lxc/tools/arguments.c
+++ b/src/lxc/tools/arguments.c
@@ -22,6 +22,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#define _GNU_SOURCE
 #include <ctype.h>
 #include <errno.h>
 #include <limits.h>
@@ -32,10 +33,10 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <lxc/version.h>
+
 #include "arguments.h"
-#include "utils.h"
-#include "version.h"
-#include "namespace.h"
+#include "tool_utils.h"
 
 static int build_shortopts(const struct option *a_options, char *a_shortopts,
 			   size_t a_size)
diff --git a/src/lxc/tools/lxc_execute.c b/src/lxc/tools/lxc_execute.c
index dc1f504e7..af418fe87 100644
--- a/src/lxc/tools/lxc_execute.c
+++ b/src/lxc/tools/lxc_execute.c
@@ -20,32 +20,30 @@
  * 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 <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <lxc/lxccontainer.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <lxc/lxccontainer.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"
+#include "tool_list.h"
+#include "tool_utils.h"
 
 static struct lxc_list defines;
 
 static int my_parser(struct lxc_arguments* args, int c, char* arg)
 {
+	int ret;
+
 	switch (c) {
 	case 'd':
 		args->daemonize = 1;
@@ -54,7 +52,9 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
 		args->rcfile = arg;
 		break;
 	case 's':
-		return lxc_config_define_add(&defines, arg);
+		ret = lxc_config_define_add(&defines, arg);
+		if (ret < 0)
+			lxc_config_define_free(&defines);
 		break;
 	case 'u':
 		if (lxc_safe_uint(arg, &args->uid) < 0)
@@ -112,14 +112,17 @@ Options :\n\
 	.daemonize = 0,
 };
 
-static bool set_argv(struct lxc_conf *conf, struct lxc_arguments *args)
+static bool set_argv(struct lxc_container *c, struct lxc_arguments *args)
 {
+	int ret;
+	char buf[TOOL_MAXPATHLEN];
 	char **components, **p;
 
-	if (!conf->execute_cmd)
+	ret = c->get_config_item(c, "lxc.execute.cmd", buf, TOOL_MAXPATHLEN);
+	if (ret < 0)
 		return false;
 
-	components = lxc_string_split_quoted(conf->execute_cmd);
+	components = lxc_string_split_quoted(buf);
 	if (!components)
 		return false;
 
@@ -154,7 +157,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
@@ -187,24 +189,50 @@ int main(int argc, char *argv[])
 	}
 
 	if (my_args.argc == 0) {
-		if (!set_argv(c->lxc_conf, &my_args)) {
+		if (!set_argv(c, &my_args)) {
 			fprintf(stderr, "missing command to execute!\n");
 			lxc_container_put(c);
 			exit(EXIT_FAILURE);
 		}
 	}
 
-	ret = lxc_config_define_load(&defines, c->lxc_conf);
+	ret = lxc_config_define_load(&defines, c);
 	if (ret) {
 		lxc_container_put(c);
 		exit(EXIT_FAILURE);
 	}
 
-	if (my_args.uid)
-		c->lxc_conf->init_uid = my_args.uid;
+	if (my_args.uid) {
+		char buf[256];
 
-	if (my_args.gid)
-		c->lxc_conf->init_gid = my_args.gid;
+		ret = snprintf(buf, 256, "%d", my_args.uid);
+		if (ret < 0 || (size_t)ret >= 256) {
+			lxc_container_put(c);
+			exit(EXIT_FAILURE);
+		}
+
+		ret = c->set_config_item(c, "lxc.init.uid", buf);
+		if (ret < 0) {
+			lxc_container_put(c);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (my_args.gid) {
+		char buf[256];
+
+		ret = snprintf(buf, 256, "%d", my_args.gid);
+		if (ret < 0 || (size_t)ret >= 256) {
+			lxc_container_put(c);
+			exit(EXIT_FAILURE);
+		}
+
+		ret = c->set_config_item(c, "lxc.init.gid", buf);
+		if (ret < 0) {
+			lxc_container_put(c);
+			exit(EXIT_FAILURE);
+		}
+	}
 
 	if (!lxc_setup_shared_ns(&my_args, c)) {
 		lxc_container_put(c);
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
index 42be4d249..b1557a18e 100644
--- a/src/lxc/tools/tool_utils.c
+++ b/src/lxc/tools/tool_utils.c
@@ -131,17 +131,6 @@ signed long lxc_config_parse_arch(const char *arch)
 	return -1;
 }
 
-enum {
-	LXC_NS_USER,
-	LXC_NS_MNT,
-	LXC_NS_PID,
-	LXC_NS_UTS,
-	LXC_NS_IPC,
-	LXC_NS_NET,
-	LXC_NS_CGROUP,
-	LXC_NS_MAX
-};
-
 const static struct ns_info {
 	const char *proc_name;
 	int clone_flag;
@@ -630,3 +619,207 @@ bool switch_to_ns(pid_t pid, const char *ns) {
 	close(fd);
 	return true;
 }
+
+static bool complete_word(char ***result, char *start, char *end, size_t *cap, size_t *cnt)
+{
+	int r;
+
+	r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16);
+	if (r < 0)
+		return false;
+	(*result)[*cnt] = strndup(start, end - start);
+	if (!(*result)[*cnt])
+		return false;
+	(*cnt)++;
+
+	return true;
+}
+
+/*
+ * Given a a string 'one two "three four"', split into three words,
+ * one, two, and "three four"
+ */
+char **lxc_string_split_quoted(char *string)
+{
+	char *nextword = string, *p, state;
+	char **result = NULL;
+	size_t result_capacity = 0;
+	size_t result_count = 0;
+
+	if (!string || !*string)
+		return calloc(1, sizeof(char *));
+
+	// TODO I'm *not* handling escaped quote
+	state = ' ';
+	for (p = string; *p; p++) {
+		switch(state) {
+		case ' ':
+			if (isspace(*p))
+				continue;
+			else if (*p == '"' || *p == '\'') {
+				nextword = p;
+				state = *p;
+				continue;
+			}
+			nextword = p;
+			state = 'a';
+			continue;
+		case 'a':
+			if (isspace(*p)) {
+				complete_word(&result, nextword, p, &result_capacity, &result_count);
+				state = ' ';
+				continue;
+			}
+			continue;
+		case '"':
+		case '\'':
+			if (*p == state) {
+				complete_word(&result, nextword+1, p, &result_capacity, &result_count);
+				state = ' ';
+				continue;
+			}
+			continue;
+		}
+	}
+
+	if (state == 'a')
+		complete_word(&result, nextword, p, &result_capacity, &result_count);
+
+	return realloc(result, (result_count + 1) * sizeof(char *));
+}
+
+int lxc_char_left_gc(const char *buffer, size_t len)
+{
+	size_t i;
+	for (i = 0; i < len; i++) {
+		if (buffer[i] == ' ' ||
+		    buffer[i] == '\t')
+			continue;
+		return i;
+	}
+	return 0;
+}
+
+int lxc_char_right_gc(const char *buffer, size_t len)
+{
+	int i;
+	for (i = len - 1; i >= 0; i--) {
+		if (buffer[i] == ' '  ||
+		    buffer[i] == '\t' ||
+		    buffer[i] == '\n' ||
+		    buffer[i] == '\0')
+			continue;
+		return i + 1;
+	}
+	return 0;
+}
+
+struct new_config_item *parse_line(char *buffer)
+{
+	char *dot, *key, *line, *linep, *value;
+	int ret = 0;
+	char *dup = buffer;
+    struct new_config_item *new = NULL;
+
+	linep = line = strdup(dup);
+	if (!line)
+		return NULL;
+
+	line += lxc_char_left_gc(line, strlen(line));
+
+	/* martian option - don't add it to the config itself */
+	if (strncmp(line, "lxc.", 4))
+		goto on_error;
+
+	ret = -1;
+	dot = strchr(line, '=');
+	if (!dot) {
+		fprintf(stderr, "Invalid configuration item: %s\n", line);
+		goto on_error;
+	}
+
+	*dot = '\0';
+	value = dot + 1;
+
+	key = line;
+	key[lxc_char_right_gc(key, strlen(key))] = '\0';
+
+	value += lxc_char_left_gc(value, strlen(value));
+	value[lxc_char_right_gc(value, strlen(value))] = '\0';
+
+	if (*value == '\'' || *value == '\"') {
+		size_t len;
+
+		len = strlen(value);
+		if (len > 1 && value[len - 1] == *value) {
+			value[len - 1] = '\0';
+			value++;
+		}
+	}
+
+    ret = -1;
+    new = malloc(sizeof(struct new_config_item));
+    if (!new)
+            goto on_error;
+
+    new->key = strdup(key);
+    new->val = strdup(value);
+    if (!new->val || !new->key)
+            goto on_error;
+    ret = 0;
+
+on_error:
+	free(linep);
+    if (ret < 0 && new) {
+            free(new->key);
+            free(new->val);
+            free(new);
+            new = NULL;
+    }
+
+	return new;
+}
+
+int lxc_config_define_add(struct lxc_list *defines, char *arg)
+{
+	struct lxc_list *dent;
+
+	dent = malloc(sizeof(struct lxc_list));
+	if (!dent)
+		return -1;
+
+	dent->elem = parse_line(arg);
+	if (!dent->elem)
+		return -1;
+	lxc_list_add_tail(defines, dent);
+	return 0;
+}
+
+int lxc_config_define_load(struct lxc_list *defines, struct lxc_container *c)
+{
+	struct lxc_list *it;
+	int ret = 0;
+
+	lxc_list_for_each(it, defines) {
+		struct new_config_item *new_item = it->elem;
+		ret = c->set_config_item(c, new_item->key, new_item->val);
+		if (ret < 0)
+			break;
+	}
+
+	lxc_config_define_free(defines);
+	return ret;
+}
+
+void lxc_config_define_free(struct lxc_list *defines)
+{
+	struct lxc_list *it, *next;
+
+	lxc_list_for_each_safe(it, defines, next) {
+		struct new_config_item *new_item = it->elem;
+		free(new_item->key);
+		free(new_item->val);
+		lxc_list_del(it);
+		free(it);
+	}
+}
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
index 2ce2afd0a..0184bd843 100644
--- a/src/lxc/tools/tool_utils.h
+++ b/src/lxc/tools/tool_utils.h
@@ -29,8 +29,23 @@
 #include <stdbool.h>
 #include <unistd.h>
 
+#include <lxc/lxccontainer.h>
+
+#include "tool_list.h"
+
 #define TOOL_MAXPATHLEN 4096
 
+enum {
+	LXC_NS_USER,
+	LXC_NS_MNT,
+	LXC_NS_PID,
+	LXC_NS_UTS,
+	LXC_NS_IPC,
+	LXC_NS_NET,
+	LXC_NS_CGROUP,
+	LXC_NS_MAX
+};
+
 extern int lxc_fill_elevated_privileges(char *flaglist, int *flags);
 extern signed long lxc_config_parse_arch(const char *arch);
 extern int lxc_namespace_2_cloneflag(const char *namespace);
@@ -66,6 +81,7 @@ extern char **lxc_string_split(const char *string, char _sep);
 extern char **lxc_normalize_path(const char *path);
 extern char *lxc_string_join(const char *sep, const char **parts,
 			     bool use_as_prefix);
+extern char **lxc_string_split_quoted(char *string);
 
 extern int mkdir_p(const char *dir, mode_t mode);
 extern bool file_exists(const char *f);
@@ -75,4 +91,17 @@ extern char *get_template_path(const char *t);
 
 extern bool switch_to_ns(pid_t pid, const char *ns);
 
+extern int lxc_config_define_add(struct lxc_list *defines, char *arg);
+extern int lxc_config_define_load(struct lxc_list *defines,
+				  struct lxc_container *c);
+extern void lxc_config_define_free(struct lxc_list *defines);
+extern int lxc_char_left_gc(const char *buffer, size_t len);
+extern int lxc_char_right_gc(const char *buffer, size_t len);
+
+struct new_config_item {
+        char *key;
+        char *val;
+};
+extern struct new_config_item *parse_line(char *buffer);
+
 #endif /* __LXC_UTILS_H */

From 0520a267fdc9a858798dbb20c646b6212dc49962 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 15:32:07 +0100
Subject: [PATCH 20/30] tools: move lxc-freeze to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_freeze.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/src/lxc/tools/lxc_freeze.c b/src/lxc/tools/lxc_freeze.c
index aab2b6fe3..09c21b30e 100644
--- a/src/lxc/tools/lxc_freeze.c
+++ b/src/lxc/tools/lxc_freeze.c
@@ -20,17 +20,17 @@
  * 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 <libgen.h>
 #include <stdio.h>
+#include <string.h>
+#include <unistd.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"
 
 static const struct option my_longopts[] = {
@@ -72,7 +72,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);

From d57e0fd36f69b838015d15ac6b0f4b105bef882a Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 15:36:15 +0100
Subject: [PATCH 21/30] tools: move lxc-info to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_info.c   | 20 +++++++++-----------
 src/lxc/tools/tool_utils.c | 27 +++++++++++++++++++++++++++
 src/lxc/tools/tool_utils.h |  1 +
 3 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/src/lxc/tools/lxc_info.c b/src/lxc/tools/lxc_info.c
index 3c7f6b398..de8f57463 100644
--- a/src/lxc/tools/lxc_info.c
+++ b/src/lxc/tools/lxc_info.c
@@ -21,21 +21,20 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include <stdio.h>
+#define _GNU_SOURCE
+#include <libgen.h>
+#include <limits.h>
 #include <stdbool.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.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"
+#include "tool_utils.h"
 
 static bool ips;
 static bool state;
@@ -205,7 +204,7 @@ static void print_stats(struct lxc_container *c)
 	char buf[4096];
 
 	ret = c->get_cgroup_item(c, "cpuacct.usage", buf, sizeof(buf));
-	if (ret > 0 && ret < sizeof(buf)) {
+	if (ret > 0 && (size_t)ret < sizeof(buf)) {
 		str_chomp(buf);
 		if (humanize) {
 			float seconds = strtof(buf, NULL) / 1000000000.0;
@@ -217,7 +216,7 @@ static void print_stats(struct lxc_container *c)
 	}
 
 	ret = c->get_cgroup_item(c, "blkio.throttle.io_service_bytes", buf, sizeof(buf));
-	if (ret > 0 && ret < sizeof(buf)) {
+	if (ret > 0 && (size_t)ret < sizeof(buf)) {
 		char *ch;
 
 		/* put ch on last "Total" line */
@@ -247,7 +246,7 @@ static void print_stats(struct lxc_container *c)
 
 	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)) {
+		if (ret > 0 && (size_t)ret < sizeof(buf)) {
 			str_chomp(buf);
 			str_size_humanize(buf, sizeof(buf));
 			printf("%-15s %s\n", lxstat[i].name, buf);
@@ -409,7 +408,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(ret);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
index b1557a18e..462a07a22 100644
--- a/src/lxc/tools/tool_utils.c
+++ b/src/lxc/tools/tool_utils.c
@@ -823,3 +823,30 @@ void lxc_config_define_free(struct lxc_list *defines)
 		free(it);
 	}
 }
+
+int lxc_read_from_file(const char *filename, void* buf, size_t count)
+{
+	int fd = -1, saved_errno;
+	ssize_t ret;
+
+	fd = open(filename, O_RDONLY | O_CLOEXEC);
+	if (fd < 0)
+		return -1;
+
+	if (!buf || !count) {
+		char buf2[100];
+		size_t count2 = 0;
+		while ((ret = read(fd, buf2, 100)) > 0)
+			count2 += ret;
+		if (ret >= 0)
+			ret = count2;
+	} else {
+		memset(buf, 0, count);
+		ret = read(fd, buf, count);
+	}
+
+	saved_errno = errno;
+	close(fd);
+	errno = saved_errno;
+	return ret;
+}
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
index 0184bd843..ac4fb8a0b 100644
--- a/src/lxc/tools/tool_utils.h
+++ b/src/lxc/tools/tool_utils.h
@@ -86,6 +86,7 @@ extern char **lxc_string_split_quoted(char *string);
 extern int mkdir_p(const char *dir, mode_t mode);
 extern bool file_exists(const char *f);
 extern int is_dir(const char *path);
+extern int lxc_read_from_file(const char *filename, void* buf, size_t count);
 
 extern char *get_template_path(const char *t);
 

From 5f05387b3b97316a4876c29eac6a541bbe1515df Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 15:47:32 +0100
Subject: [PATCH 22/30] tools: move lxc-ls to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/Makefile.am        |  28 ++---
 src/lxc/tools/lxc_ls.c     |  13 +--
 src/lxc/tools/tool_utils.c | 281 +++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/tools/tool_utils.h |  14 +++
 4 files changed, 313 insertions(+), 23 deletions(-)

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 7194216ef..02ae0e753 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -276,20 +276,20 @@ lxc_console_SOURCES = tools/lxc_console.c tools/arguments.c tools/tool_utils.c
 lxc_destroy_SOURCES = tools/lxc_destroy.c tools/arguments.c tools/tool_utils.c
 lxc_device_SOURCES = tools/lxc_device.c tools/arguments.c tools/tool_utils.c
 lxc_execute_SOURCES = tools/lxc_execute.c tools/arguments.c tools/tool_utils.c
-lxc_freeze_SOURCES = tools/lxc_freeze.c tools/arguments.c
-lxc_info_SOURCES = tools/lxc_info.c tools/arguments.c
-lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c
-lxc_ls_SOURCES = tools/lxc_ls.c tools/arguments.c
-lxc_copy_SOURCES = tools/lxc_copy.c tools/arguments.c
-lxc_start_SOURCES = tools/lxc_start.c tools/arguments.c
-lxc_stop_SOURCES = tools/lxc_stop.c tools/arguments.c
-lxc_top_SOURCES = tools/lxc_top.c tools/arguments.c
-lxc_unfreeze_SOURCES = tools/lxc_unfreeze.c tools/arguments.c
-lxc_unshare_SOURCES = tools/lxc_unshare.c tools/arguments.c
-lxc_wait_SOURCES = tools/lxc_wait.c tools/arguments.c
-lxc_create_SOURCES = tools/lxc_create.c tools/arguments.c
-lxc_snapshot_SOURCES = tools/lxc_snapshot.c tools/arguments.c
-lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c
+lxc_freeze_SOURCES = tools/lxc_freeze.c tools/arguments.c tools/tool_utils.c
+lxc_info_SOURCES = tools/lxc_info.c tools/arguments.c tools/tool_utils.c
+lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c tools/tool_utils.c
+lxc_ls_SOURCES = tools/lxc_ls.c tools/arguments.c tools/tool_utils.c
+lxc_copy_SOURCES = tools/lxc_copy.c tools/arguments.c tools/tool_utils.c
+lxc_start_SOURCES = tools/lxc_start.c tools/arguments.c tools/tool_utils.c
+lxc_stop_SOURCES = tools/lxc_stop.c tools/arguments.c tools/tool_utils.c
+lxc_top_SOURCES = tools/lxc_top.c tools/arguments.c tools/tool_utils.c
+lxc_unfreeze_SOURCES = tools/lxc_unfreeze.c tools/arguments.c tools/tool_utils.c
+lxc_unshare_SOURCES = tools/lxc_unshare.c tools/arguments.c tools/tool_utils.c
+lxc_wait_SOURCES = tools/lxc_wait.c tools/arguments.c tools/tool_utils.c
+lxc_create_SOURCES = tools/lxc_create.c tools/arguments.c tools/tool_utils.c
+lxc_snapshot_SOURCES = tools/lxc_snapshot.c tools/arguments.c tools/tool_utils.c
+lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c tools/tool_utils.c
 
 # Binaries shipping with liblxc
 init_lxc_SOURCES = cmd/lxc_init.c
diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c
index c7f25cbfe..9719f7832 100644
--- a/src/lxc/tools/lxc_ls.c
+++ b/src/lxc/tools/lxc_ls.c
@@ -16,9 +16,9 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "config.h"
-
+#define _GNU_SOURCE
 #include <getopt.h>
+#include <limits.h>
 #include <regex.h>
 #include <stdbool.h>
 #include <stdio.h>
@@ -35,11 +35,7 @@
 #include <lxc/lxccontainer.h>
 
 #include "arguments.h"
-#include "conf.h"
-#include "confile.h"
-#include "log.h"
-#include "lxc.h"
-#include "utils.h"
+#include "tool_utils.h"
 
 /* Per default we only allow five levels of recursion to protect the stack at
  * least a little bit. */
@@ -229,7 +225,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
@@ -1049,7 +1044,7 @@ static int ls_remove_lock(const char *path, const char *name,
 	if (check < 0 || (size_t)check >= *len_lockpath)
 		goto out;
 
-	lxc_rmdir_onedev(*lockpath, NULL);
+	(void)rm_r(*lockpath);
 	ret = 0;
 
 out:
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
index 462a07a22..71b499659 100644
--- a/src/lxc/tools/tool_utils.c
+++ b/src/lxc/tools/tool_utils.c
@@ -20,6 +20,7 @@
 #define _GNU_SOURCE
 #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
 #include <ctype.h>
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
@@ -850,3 +851,283 @@ int lxc_read_from_file(const char *filename, void* buf, size_t count)
 	errno = saved_errno;
 	return ret;
 }
+
+char **lxc_string_split_and_trim(const char *string, char _sep)
+{
+	char *token, *str, *saveptr = NULL;
+	char sep[2] = { _sep, '\0' };
+	char **result = NULL;
+	size_t result_capacity = 0;
+	size_t result_count = 0;
+	int r, saved_errno;
+	size_t i = 0;
+
+	if (!string)
+		return calloc(1, sizeof(char *));
+
+	str = alloca(strlen(string)+1);
+	strcpy(str, string);
+	for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
+		while (token[0] == ' ' || token[0] == '\t')
+			token++;
+		i = strlen(token);
+		while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
+			token[i - 1] = '\0';
+			i--;
+		}
+		r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
+		if (r < 0)
+			goto error_out;
+		result[result_count] = strdup(token);
+		if (!result[result_count])
+			goto error_out;
+		result_count++;
+	}
+
+	/* if we allocated too much, reduce it */
+	return realloc(result, (result_count + 1) * sizeof(char *));
+error_out:
+	saved_errno = errno;
+	lxc_free_array((void **)result, free);
+	errno = saved_errno;
+	return NULL;
+}
+
+char *lxc_append_paths(const char *first, const char *second)
+{
+	int ret;
+	size_t len;
+	char *result = NULL;
+	const char *pattern = "%s%s";
+
+	len = strlen(first) + strlen(second) + 1;
+	if (second[0] != '/') {
+		len += 1;
+		pattern = "%s/%s";
+	}
+
+	result = calloc(1, len);
+	if (!result)
+		return NULL;
+
+	ret = snprintf(result, len, pattern, first, second);
+	if (ret < 0 || (size_t)ret >= len) {
+		free(result);
+		return NULL;
+	}
+
+	return result;
+}
+
+bool dir_exists(const char *path)
+{
+	struct stat sb;
+	int ret;
+
+	ret = stat(path, &sb);
+	if (ret < 0)
+		/* Could be something other than eexist, just say "no". */
+		return false;
+	return S_ISDIR(sb.st_mode);
+}
+
+char *lxc_string_replace(const char *needle, const char *replacement,
+			 const char *haystack)
+{
+	ssize_t len = -1, saved_len = -1;
+	char *result = NULL;
+	size_t replacement_len = strlen(replacement);
+	size_t needle_len = strlen(needle);
+
+	/* should be executed exactly twice */
+	while (len == -1 || result == NULL) {
+		char *p;
+		char *last_p;
+		ssize_t part_len;
+
+		if (len != -1) {
+			result = calloc(1, len + 1);
+			if (!result)
+				return NULL;
+			saved_len = len;
+		}
+
+		len = 0;
+
+		for (last_p = (char *)haystack, p = strstr(last_p, needle); p; last_p = p, p = strstr(last_p, needle)) {
+			part_len = (ssize_t)(p - last_p);
+			if (result && part_len > 0)
+				memcpy(&result[len], last_p, part_len);
+			len += part_len;
+			if (result && replacement_len > 0)
+				memcpy(&result[len], replacement, replacement_len);
+			len += replacement_len;
+			p += needle_len;
+		}
+		part_len = strlen(last_p);
+		if (result && part_len > 0)
+			memcpy(&result[len], last_p, part_len);
+		len += part_len;
+	}
+
+	/* make sure we did the same thing twice,
+	 * once for calculating length, the other
+	 * time for copying data */
+	if (saved_len != len) {
+		free(result);
+		return NULL;
+	}
+	/* make sure we didn't overwrite any buffer,
+	 * due to calloc the string should be 0-terminated */
+	if (result[len] != '\0') {
+		free(result);
+		return NULL;
+	}
+
+	return result;
+}
+
+ssize_t lxc_write_nointr(int fd, const void* buf, size_t count)
+{
+	ssize_t ret;
+again:
+	ret = write(fd, buf, count);
+	if (ret < 0 && errno == EINTR)
+		goto again;
+	return ret;
+}
+
+char *get_rundir()
+{
+	char *rundir;
+	const char *homedir;
+
+	if (geteuid() == 0) {
+		rundir = strdup(RUNTIME_PATH);
+		return rundir;
+	}
+
+	rundir = getenv("XDG_RUNTIME_DIR");
+	if (rundir) {
+		rundir = strdup(rundir);
+		return rundir;
+	}
+
+	homedir = getenv("HOME");
+	if (!homedir)
+		return NULL;
+
+	rundir = malloc(sizeof(char) * (17 + strlen(homedir)));
+	sprintf(rundir, "%s/.cache/lxc/run/", homedir);
+
+	return rundir;
+}
+
+char *must_copy_string(const char *entry)
+{
+	char *ret;
+
+	if (!entry)
+		return NULL;
+	do {
+		ret = strdup(entry);
+	} while (!ret);
+
+	return ret;
+}
+
+
+void *must_realloc(void *orig, size_t sz)
+{
+	void *ret;
+
+	do {
+		ret = realloc(orig, sz);
+	} while (!ret);
+
+	return ret;
+}
+
+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;
+}
+
+int rm_r(char *dirname)
+{
+	int ret;
+	struct dirent *direntp;
+	DIR *dir;
+	int r = 0;
+
+	dir = opendir(dirname);
+	if (!dir)
+		return -1;
+
+	while ((direntp = readdir(dir))) {
+		char *pathname;
+		struct stat mystat;
+
+		if (!direntp)
+			break;
+
+		if (!strcmp(direntp->d_name, ".") ||
+		    !strcmp(direntp->d_name, ".."))
+			continue;
+
+		pathname = must_make_path(dirname, direntp->d_name, NULL);
+
+		ret = lstat(pathname, &mystat);
+		if (ret < 0) {
+			r = -1;
+			goto next;
+		}
+
+		if (!S_ISDIR(mystat.st_mode))
+			goto next;
+
+		ret = rm_r(pathname);
+		if (ret < 0)
+			r = -1;
+	next:
+		free(pathname);
+	}
+
+	ret = rmdir(dirname);
+	if (ret < 0)
+		r = -1;
+
+	ret = closedir(dir);
+	if (ret < 0)
+		r = -1;
+
+	return r;
+}
+
+ssize_t lxc_read_nointr(int fd, void* buf, size_t count)
+{
+	ssize_t ret;
+again:
+	ret = read(fd, buf, count);
+	if (ret < 0 && errno == EINTR)
+		goto again;
+	return ret;
+}
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
index ac4fb8a0b..db43fa49d 100644
--- a/src/lxc/tools/tool_utils.h
+++ b/src/lxc/tools/tool_utils.h
@@ -82,9 +82,18 @@ extern char **lxc_normalize_path(const char *path);
 extern char *lxc_string_join(const char *sep, const char **parts,
 			     bool use_as_prefix);
 extern char **lxc_string_split_quoted(char *string);
+extern char **lxc_string_split_and_trim(const char *string, char _sep);
+extern char *lxc_append_paths(const char *first, const char *second);
+extern char *lxc_string_replace(const char *needle, const char *replacement,
+				const char *haystack);
+extern char *must_copy_string(const char *entry);
+extern void *must_realloc(void *orig, size_t sz);
+extern char *must_make_path(const char *first, ...);
 
 extern int mkdir_p(const char *dir, mode_t mode);
+extern int rm_r(char *dirname);
 extern bool file_exists(const char *f);
+extern bool dir_exists(const char *path);
 extern int is_dir(const char *path);
 extern int lxc_read_from_file(const char *filename, void* buf, size_t count);
 
@@ -105,4 +114,9 @@ struct new_config_item {
 };
 extern struct new_config_item *parse_line(char *buffer);
 
+extern ssize_t lxc_read_nointr(int fd, void* buf, size_t count);
+extern ssize_t lxc_write_nointr(int fd, const void* buf, size_t count);
+
+extern char *get_rundir();
+
 #endif /* __LXC_UTILS_H */

From c1fc010e48832a38dfc57b6aa9fb2b83bf94d2d9 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 16:01:10 +0100
Subject: [PATCH 23/30] tools: move lxc-snapshot to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_snapshot.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/src/lxc/tools/lxc_snapshot.c b/src/lxc/tools/lxc_snapshot.c
index 0c0ea3ada..7c8255c2c 100644
--- a/src/lxc/tools/lxc_snapshot.c
+++ b/src/lxc/tools/lxc_snapshot.c
@@ -17,21 +17,20 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "confile.h"
-#include <stdio.h>
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <fcntl.h>
 #include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
-#include <ctype.h>
 #include <sys/types.h>
-#include <fcntl.h>
 
 #include <lxc/lxccontainer.h>
 
-#include "lxc.h"
-#include "log.h"
 #include "arguments.h"
-#include "storage.h"
-#include "utils.h"
+#include "tool_utils.h"
 
 static int my_parser(struct lxc_arguments *args, int c, char *arg);
 
@@ -97,7 +96,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);

From 5962d017473debdc1c6aaeb61977b8b336bf712d Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 16:04:28 +0100
Subject: [PATCH 24/30] tools: move lxc-start to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_start.c | 93 ++++++++++++++++++++++++++++-------------------
 1 file changed, 55 insertions(+), 38 deletions(-)

diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c
index 5a422923f..31a7cd690 100644
--- a/src/lxc/tools/lxc_start.c
+++ b/src/lxc/tools/lxc_start.c
@@ -20,35 +20,30 @@
  * 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>
+#define _GNU_SOURCE
 #include <errno.h>
 #include <fcntl.h>
+#include <libgen.h>
+#include <net/if.h>
 #include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netinet/in.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 <sys/types.h>
+#include <sys/utsname.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"
+#include "tool_list.h"
+#include "tool_utils.h"
 
 static struct lxc_list defines;
 
@@ -82,21 +77,44 @@ static int ensure_path(char **confpath, const char *path)
 	return err;
 }
 
-static int my_parser(struct lxc_arguments* args, int c, char* arg)
+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;
-	case OPT_SHARE_PID: args->share_ns[LXC_NS_PID] = arg; break;
+	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;
+	case OPT_SHARE_PID:
+		args->share_ns[LXC_NS_PID] = arg;
+		break;
 	}
 	return 0;
 }
@@ -147,11 +165,10 @@ Options :\n\
 
 int main(int argc, char *argv[])
 {
-	struct lxc_conf *conf;
-	struct lxc_log log;
 	const char *lxcpath;
 	char *const *args;
 	struct lxc_container *c;
+	struct lxc_log log;
 	int err = EXIT_FAILURE;
 	char *rcfile = NULL;
 	char *const default_args[] = {
@@ -181,7 +198,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(err);
-	lxc_log_options_no_override();
 
 	lxcpath = my_args.lxcpath[0];
 	if (access(lxcpath, O_RDONLY) < 0) {
@@ -259,11 +275,12 @@ int main(int argc, char *argv[])
 	 * 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 (!c->lxc_conf) {
+		fprintf(stderr, "No container config specified\n");
+		goto out;
+	}
 
-	if (lxc_config_define_load(&defines, conf))
+	if (lxc_config_define_load(&defines, c))
 		goto out;
 
 	if (!rcfile && !strcmp("/sbin/init", args[0])) {

From dd18b7d6ba9b45e7ac5eddb41e9cb335ab69cb32 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 16:17:46 +0100
Subject: [PATCH 25/30] tools: move lxc-stop to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_stop.c | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/src/lxc/tools/lxc_stop.c b/src/lxc/tools/lxc_stop.c
index 9d2ba6ed1..f133c9977 100644
--- a/src/lxc/tools/lxc_stop.c
+++ b/src/lxc/tools/lxc_stop.c
@@ -20,18 +20,18 @@
  * 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>
+
+#define _GNU_SOURCE
 #include <libgen.h>
-#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include <lxc/lxccontainer.h>
 
-#include "lxc.h"
-#include "log.h"
 #include "arguments.h"
-#include "commands.h"
-#include "utils.h"
+#include "tool_utils.h"
 
 #define OPT_NO_LOCK OPT_USAGE + 1
 #define OPT_NO_KILL OPT_USAGE + 2
@@ -113,7 +113,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(ret);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
@@ -155,13 +154,6 @@ int main(int argc, char *argv[])
 		exit(ret);
 	}
 
-	/* shortcut - if locking is bogus, we should be able to kill
-	 * containers at least */
-	if (my_args.nolock) {
-		ret = lxc_cmd_stop(my_args.name, my_args.lxcpath[0]);
-		exit(ret);
-	}
-
 	c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
 	if (!c) {
 		fprintf(stderr, "Error opening container\n");

From cac8f6431b14832ea0395a52963b5b1f56944093 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 16:29:46 +0100
Subject: [PATCH 26/30] tools: move lxc-top to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_top.c | 172 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 146 insertions(+), 26 deletions(-)

diff --git a/src/lxc/tools/lxc_top.c b/src/lxc/tools/lxc_top.c
index 5d5c08a25..868693866 100644
--- a/src/lxc/tools/lxc_top.c
+++ b/src/lxc/tools/lxc_top.c
@@ -21,25 +21,26 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#define _GNU_SOURCE
 #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
 #include <errno.h>
 #include <inttypes.h>
 #include <signal.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdint.h>
+#include <string.h>
 #include <termios.h>
 #include <unistd.h>
 #include <sys/epoll.h>
 #include <sys/ioctl.h>
+#include <sys/time.h>
+
 #include <lxc/lxccontainer.h>
 
 #include "arguments.h"
-#include "log.h"
-#include "lxc.h"
-#include "mainloop.h"
-#include "utils.h"
+#include "tool_utils.h"
 
 #define USER_HZ   100
 #define ESC       "\033"
@@ -181,24 +182,6 @@ static int stdin_tios_rows(void)
 	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);
@@ -310,7 +293,7 @@ static void stat_get_blk_stats(struct lxc_container *c, const char *item,
 	char **lines, **cols;
 
 	len = c->get_cgroup_item(c, item, buf, sizeof(buf));
-	if (len <= 0 || len >= sizeof(buf)) {
+	if (len <= 0 || (size_t)len >= sizeof(buf)) {
 		fprintf(stderr, "unable to read cgroup item %s\n", item);
 		return;
 	}
@@ -409,7 +392,7 @@ static void stats_print(const char *name, const struct stats *stats,
 		size_humanize(stats->mem_used, mem_used_str, sizeof(mem_used_str));
 
 		ret = snprintf(iosb_str, sizeof(iosb_str), "%s(%s/%s)", iosb_total_str, iosb_read_str, iosb_write_str);
-		if (ret < 0 || ret >= sizeof(iosb_str))
+		if (ret < 0 || (size_t)ret >= sizeof(iosb_str))
 			printf("snprintf'd too many characters: %d\n", ret);
 
 		printf("%-18.18s %12.2f %12.2f %12.2f %36s %10s",
@@ -429,7 +412,7 @@ static void stats_print(const char *name, const struct stats *stats,
 			printf(" %10s", kmem_used_str);
 		}
 	} else {
-		gettimeofday(&time_val, NULL);
+		(void)gettimeofday(&time_val, NULL);
 		time_ms = (unsigned long long) (time_val.tv_sec) * 1000 + (unsigned long long) (time_val.tv_usec) / 1000;
 		printf("%" PRIu64 ",%s,%" PRIu64 ",%" PRIu64 ",%" PRIu64
 		       ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64,
@@ -554,6 +537,143 @@ static void ct_realloc(int active_cnt)
 	}
 }
 
+#define LXC_MAINLOOP_CONTINUE 0
+#define LXC_MAINLOOP_CLOSE 1
+
+struct lxc_epoll_descr {
+	int epfd;
+	struct lxc_list handlers;
+};
+
+typedef int (*lxc_mainloop_callback_t)(int fd, uint32_t event, void *data,
+				       struct lxc_epoll_descr *descr);
+
+struct mainloop_handler {
+	lxc_mainloop_callback_t callback;
+	int fd;
+	void *data;
+};
+
+#define MAX_EVENTS 10
+
+int lxc_mainloop(struct lxc_epoll_descr *descr, int timeout_ms)
+{
+	int i, nfds, ret;
+	struct mainloop_handler *handler;
+	struct epoll_event events[MAX_EVENTS];
+
+	for (;;) {
+		nfds = epoll_wait(descr->epfd, events, MAX_EVENTS, timeout_ms);
+		if (nfds < 0) {
+			if (errno == EINTR)
+				continue;
+
+			return -1;
+		}
+
+		for (i = 0; i < nfds; i++) {
+			handler = events[i].data.ptr;
+
+			/* If the handler returns a positive value, exit the
+			 * mainloop.
+			 */
+			ret = handler->callback(handler->fd, events[i].events,
+						handler->data, descr);
+			if (ret == LXC_MAINLOOP_CLOSE)
+				return 0;
+		}
+
+		if (nfds == 0)
+			return 0;
+
+		if (lxc_list_empty(&descr->handlers))
+			return 0;
+	}
+}
+
+int lxc_mainloop_open(struct lxc_epoll_descr *descr)
+{
+	/* hint value passed to epoll create */
+	descr->epfd = epoll_create1(EPOLL_CLOEXEC);
+	if (descr->epfd < 0)
+		return -1;
+
+	lxc_list_init(&descr->handlers);
+	return 0;
+}
+
+int lxc_mainloop_add_handler(struct lxc_epoll_descr *descr, int fd,
+			     lxc_mainloop_callback_t callback, void *data)
+{
+	struct epoll_event ev;
+	struct mainloop_handler *handler;
+	struct lxc_list *item;
+
+	handler = malloc(sizeof(*handler));
+	if (!handler)
+		return -1;
+
+	handler->callback = callback;
+	handler->fd = fd;
+	handler->data = data;
+
+	ev.events = EPOLLIN;
+	ev.data.ptr = handler;
+
+	if (epoll_ctl(descr->epfd, EPOLL_CTL_ADD, fd, &ev) < 0)
+		goto out_free_handler;
+
+	item = malloc(sizeof(*item));
+	if (!item)
+		goto out_free_handler;
+
+	item->elem = handler;
+	lxc_list_add(&descr->handlers, item);
+	return 0;
+
+out_free_handler:
+	free(handler);
+	return -1;
+}
+
+int lxc_mainloop_close(struct lxc_epoll_descr *descr)
+{
+	struct lxc_list *iterator, *next;
+
+	iterator = descr->handlers.next;
+	while (iterator != &descr->handlers) {
+		next = iterator->next;
+
+		lxc_list_del(iterator);
+		free(iterator->elem);
+		free(iterator);
+		iterator = next;
+	}
+
+	if (descr->epfd >= 0)
+		return close(descr->epfd);
+
+	return 0;
+}
+
+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;
+}
+
 int main(int argc, char *argv[])
 {
 	struct lxc_epoll_descr descr;

From 69e7cb1628fc6297dedd18ae038936ff5d6eea0f Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 16:30:38 +0100
Subject: [PATCH 27/30] tools: move lxc-unfreeze to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_unfreeze.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/lxc/tools/lxc_unfreeze.c b/src/lxc/tools/lxc_unfreeze.c
index 5027d28e6..f12b5d57a 100644
--- a/src/lxc/tools/lxc_unfreeze.c
+++ b/src/lxc/tools/lxc_unfreeze.c
@@ -20,16 +20,18 @@
  * 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 <libgen.h>
 #include <stdio.h>
+#include <string.h>
 #include <unistd.h>
-#include <libgen.h>
 #include <sys/types.h>
 
 #include <lxc/lxccontainer.h>
 
-#include "lxc.h"
-#include "log.h"
 #include "arguments.h"
+#include "tool_utils.h"
 
 static const struct option my_longopts[] = {
 	LXC_COMMON_OPTIONS
@@ -71,7 +73,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);

From 10f47c300980f6bd06689e6401ad64292ee90194 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 16:36:12 +0100
Subject: [PATCH 28/30] tools: move lxc-wait to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_wait.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/lxc/tools/lxc_wait.c b/src/lxc/tools/lxc_wait.c
index 62b7c01b5..6186bce05 100644
--- a/src/lxc/tools/lxc_wait.c
+++ b/src/lxc/tools/lxc_wait.c
@@ -20,6 +20,8 @@
  * 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 <string.h>
 #include <libgen.h>
@@ -30,9 +32,8 @@
 
 #include <lxc/lxccontainer.h>
 
-#include "lxc.h"
-#include "log.h"
 #include "arguments.h"
+#include "tool_utils.h"
 
 static int my_checker(const struct lxc_arguments* args)
 {
@@ -98,7 +99,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(EXIT_FAILURE);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);

From 7cc90ec4d7cf5480948ba1bf175252b996fd5a41 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 17:06:42 +0100
Subject: [PATCH 29/30] tools: move lxc-unshare to API symbols only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_unshare.c | 77 ++++++++++++++++++++++++++++++++++-----------
 src/lxc/tools/tool_utils.c  | 63 +++++++++++++++++++++++++++++++++++++
 src/lxc/tools/tool_utils.h  | 24 ++++++++++++++
 3 files changed, 146 insertions(+), 18 deletions(-)

diff --git a/src/lxc/tools/lxc_unshare.c b/src/lxc/tools/lxc_unshare.c
index 9e062a0ca..98143d662 100644
--- a/src/lxc/tools/lxc_unshare.c
+++ b/src/lxc/tools/lxc_unshare.c
@@ -20,30 +20,27 @@
  * 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>
+#define _GNU_SOURCE
 #include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
 #include <libgen.h>
-#include <netinet/in.h>
 #include <pwd.h>
+#include <sched.h>
 #include <signal.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <netinet/in.h>
+#include <unistd.h>
 #include <sys/eventfd.h>
 #include <sys/socket.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"
+#include "arguments.h"
+#include "tool_utils.h"
 
 struct my_iflist
 {
@@ -67,7 +64,7 @@ static void usage(char *cmd)
 
 static bool lookup_user(const char *optarg, uid_t *uid)
 {
-	char name[MAXPATHLEN];
+	char name[TOOL_MAXPATHLEN];
 	struct passwd *pwent = NULL;
 
 	if (!optarg || (optarg[0] == '\0'))
@@ -147,11 +144,34 @@ static int do_start(void *arg)
 	return 1;
 }
 
+int write_id_mapping(pid_t pid, const char *buf, size_t buf_size)
+{
+	char path[TOOL_MAXPATHLEN];
+	int fd, ret;
+
+
+	ret = snprintf(path, TOOL_MAXPATHLEN, "/proc/%d/uid_map", pid);
+	if (ret < 0 || ret >= TOOL_MAXPATHLEN)
+		return -E2BIG;
+
+	fd = open(path, O_WRONLY);
+	if (fd < 0)
+		return -1;
+
+	errno = 0;
+	ret = lxc_write_nointr(fd, buf, buf_size);
+	close(fd);
+	if (ret < 0 || (size_t)ret != buf_size)
+		return -1;
+
+	return 0;
+}
+
 int main(int argc, char *argv[])
 {
 	char *del;
 	char **it, **args;
-	int opt, status;
+	int opt;
 	int ret;
 	char *namespaces = NULL;
 	int flags = 0, daemonize = 0;
@@ -284,7 +304,7 @@ int main(int argc, char *argv[])
 			exit(EXIT_FAILURE);
 		}
 
-		ret = write_id_mapping(ID_TYPE_UID, pid, umap, strlen(umap));
+		ret = write_id_mapping(pid, umap, strlen(umap));
 		if (ret < 0) {
 			close(start_arg.wait_fd);
 			fprintf(stderr, "uid mapping failed\n");
@@ -301,19 +321,40 @@ int main(int argc, char *argv[])
 
 	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));
+			pid_t pid;
+
+			pid = fork();
+			if (pid < 0)
+				fprintf(stderr, "Failed to move network device "
+						"\"%s\" to network namespace\n",
+					tmpif->mi_ifname);
+
+			if (pid == 0) {
+				char buf[256];
+
+				ret = snprintf(buf, 256, "%d", pid);
+				if (ret < 0 || ret >= 256)
+					exit(EXIT_FAILURE);
+
+				execlp("ip", "ip", "link", "set", "dev", tmpif->mi_ifname, "netns", buf, (char *)NULL);
+				exit(EXIT_FAILURE);
+			}
+
+			if (wait_for_pid(pid) != 0)
+				fprintf(stderr, "Could not move interface %s "
+						"into container %d: %s\n",
+					tmpif->mi_ifname, pid, strerror(errno));
 		}
 	}
 
 	if (daemonize)
 		exit(EXIT_SUCCESS);
 
-	if (waitpid(pid, &status, 0) < 0) {
+	if (wait_for_pid(pid) != 0) {
 		fprintf(stderr, "failed to wait for '%d'\n", pid);
 		exit(EXIT_FAILURE);
 	}
 
 	/* Call exit() directly on this function because it retuns an exit code. */
-	exit(lxc_error_set_and_log(pid, status));
+	exit(EXIT_SUCCESS);
 }
diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c
index 71b499659..7279b3d4c 100644
--- a/src/lxc/tools/tool_utils.c
+++ b/src/lxc/tools/tool_utils.c
@@ -31,6 +31,7 @@
 #include <strings.h>
 #include <unistd.h>
 #include <linux/sched.h>
+#include <sys/mount.h>
 #include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -42,6 +43,7 @@
 
 #include <lxc/lxccontainer.h>
 
+#include "arguments.h"
 #include "tool_utils.h"
 
 int lxc_fill_elevated_privileges(char *flaglist, int *flags)
@@ -1131,3 +1133,64 @@ ssize_t lxc_read_nointr(int fd, void* buf, size_t count)
 		goto again;
 	return ret;
 }
+
+static int mount_fs(const char *source, const char *target, const char *type)
+{
+	/* the umount may fail */
+	if (umount(target) < 0)
+
+	if (mount(source, target, type, 0, NULL) < 0)
+		return -1;
+
+	return 0;
+}
+
+void lxc_setup_fs(void)
+{
+	(void)mount_fs("proc", "/proc", "proc");
+
+	/* if /dev has been populated by us, /dev/shm does not exist */
+	if (access("/dev/shm", F_OK))
+		(void)mkdir("/dev/shm", 0777);
+
+	/* if we can't mount /dev/shm, continue anyway */
+	(void)mount_fs("shmfs", "/dev/shm", "tmpfs");
+
+	/* If we were able to mount /dev/shm, then /dev exists */
+	/* Sure, but it's read-only per config :) */
+	if (access("/dev/mqueue", F_OK))
+		(void)mkdir("/dev/mqueue", 0666);
+
+	/* continue even without posix message queue support */
+	(void)mount_fs("mqueue", "/dev/mqueue", "mqueue");
+}
+
+struct clone_arg {
+	int (*fn)(void *);
+	void *arg;
+};
+
+static int do_clone(void *arg)
+{
+	struct clone_arg *clone_arg = arg;
+	return clone_arg->fn(clone_arg->arg);
+}
+
+pid_t lxc_clone(int (*fn)(void *), void *arg, int flags)
+{
+	struct clone_arg clone_arg = {
+		.fn = fn,
+		.arg = arg,
+	};
+
+	size_t stack_size = lxc_getpagesize();
+	void *stack = alloca(stack_size);
+	pid_t ret;
+
+#ifdef __ia64__
+	ret = __clone2(do_clone, stack, stack_size, flags | SIGCHLD, &clone_arg);
+#else
+	ret = clone(do_clone, stack  + stack_size, flags | SIGCHLD, &clone_arg);
+#endif
+	return ret;
+}
diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h
index db43fa49d..5ebb4542c 100644
--- a/src/lxc/tools/tool_utils.h
+++ b/src/lxc/tools/tool_utils.h
@@ -119,4 +119,28 @@ extern ssize_t lxc_write_nointr(int fd, const void* buf, size_t count);
 
 extern char *get_rundir();
 
+extern void lxc_setup_fs(void);
+
+static inline uint64_t lxc_getpagesize(void)
+{
+	int64_t pgsz;
+
+	pgsz = sysconf(_SC_PAGESIZE);
+	if (pgsz <= 0)
+		pgsz = 1 << 12;
+
+	return pgsz;
+}
+
+#if defined(__ia64__)
+int __clone2(int (*__fn) (void *__arg), void *__child_stack_base,
+             size_t __child_stack_size, int __flags, void *__arg, ...);
+#else
+int clone(int (*fn)(void *), void *child_stack,
+	int flags, void *arg, ...
+	/* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
+#endif
+
+extern pid_t lxc_clone(int (*fn)(void *), void *arg, int flags);
+
 #endif /* __LXC_UTILS_H */

From 4daf1def0e032afc6ff1038b5e35c72d43d55ff8 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Fri, 12 Jan 2018 17:29:01 +0100
Subject: [PATCH 30/30] tools: move lxc-monitor to API only

Closes #2073.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/Makefile.am          |   2 +-
 src/lxc/commands.c           |   1 -
 src/lxc/lxccontainer.c       |   1 -
 src/lxc/state.c              |   1 -
 src/lxc/tools/lxc_monitor.c  |  21 +--
 src/lxc/tools/tool_monitor.c | 392 +++++++++++++++++++++++++++++++++++++++++++
 src/lxc/tools/tool_monitor.h | 115 +++++++++++++
 7 files changed, 519 insertions(+), 14 deletions(-)
 create mode 100644 src/lxc/tools/tool_monitor.c
 create mode 100644 src/lxc/tools/tool_monitor.h

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index 02ae0e753..95f9040c6 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -278,7 +278,7 @@ lxc_device_SOURCES = tools/lxc_device.c tools/arguments.c tools/tool_utils.c
 lxc_execute_SOURCES = tools/lxc_execute.c tools/arguments.c tools/tool_utils.c
 lxc_freeze_SOURCES = tools/lxc_freeze.c tools/arguments.c tools/tool_utils.c
 lxc_info_SOURCES = tools/lxc_info.c tools/arguments.c tools/tool_utils.c
-lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c tools/tool_utils.c
+lxc_monitor_SOURCES = tools/lxc_monitor.c tools/arguments.c tools/tool_utils.c tools/tool_monitor.c
 lxc_ls_SOURCES = tools/lxc_ls.c tools/arguments.c tools/tool_utils.c
 lxc_copy_SOURCES = tools/lxc_copy.c tools/arguments.c tools/tool_utils.c
 lxc_start_SOURCES = tools/lxc_start.c tools/arguments.c tools/tool_utils.c
diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index 8ce658363..f8c9d8c7c 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -47,7 +47,6 @@
 #include "lxc.h"
 #include "lxclock.h"
 #include "mainloop.h"
-#include "monitor.h"
 #include "start.h"
 #include "utils.h"
 
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 2a4bb51f3..65acadd14 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -55,7 +55,6 @@
 #include "lxc.h"
 #include "lxccontainer.h"
 #include "lxclock.h"
-#include "monitor.h"
 #include "namespace.h"
 #include "network.h"
 #include "start.h"
diff --git a/src/lxc/state.c b/src/lxc/state.c
index 9c9bf8318..afe29e427 100644
--- a/src/lxc/state.c
+++ b/src/lxc/state.c
@@ -40,7 +40,6 @@
 #include "config.h"
 #include "log.h"
 #include "lxc.h"
-#include "monitor.h"
 #include "start.h"
 
 lxc_log_define(lxc_state, lxc);
diff --git a/src/lxc/tools/lxc_monitor.c b/src/lxc/tools/lxc_monitor.c
index 0b094af11..75ce8c2b9 100644
--- a/src/lxc/tools/lxc_monitor.c
+++ b/src/lxc/tools/lxc_monitor.c
@@ -20,22 +20,24 @@
  * 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 <errno.h>
+#include <libgen.h>
+#include <poll.h>
+#include <regex.h>
 #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 <lxc/lxccontainer.h>
+
 #include "arguments.h"
-#include "lxccontainer.h"
+#include "tool_utils.h"
+#include "tool_monitor.h"
 
 static bool quit_monitord;
 
@@ -109,7 +111,6 @@ int main(int argc, char *argv[])
 
 	if (lxc_log_init(&log))
 		exit(rc_main);
-	lxc_log_options_no_override();
 
 	/* REMOVE IN LXC 3.0 */
 	setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
@@ -160,7 +161,7 @@ int main(int argc, char *argv[])
 	}
 
 	nfds = my_args.lxcpath_cnt;
-	for (i = 0; i < nfds; i++) {
+	for (i = 0; (unsigned long)i < nfds; i++) {
 		int fd;
 
 		lxc_monitord_spawn(my_args.lxcpath[i]);
diff --git a/src/lxc/tools/tool_monitor.c b/src/lxc/tools/tool_monitor.c
new file mode 100644
index 000000000..6dcdd340d
--- /dev/null
+++ b/src/lxc/tools/tool_monitor.c
@@ -0,0 +1,392 @@
+/*
+ * lxc: linux Container library
+ *
+ * (C) Copyright IBM Corp. 2007, 2008
+ *
+ * Authors:
+ * Daniel Lezcano <daniel.lezcano at free.fr>
+ * 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 <fcntl.h>
+#include <inttypes.h>
+#include <poll.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "config.h"
+#include "af_unix.h"
+#include "error.h"
+#include "log.h"
+#include "lxclock.h"
+#include "monitor.h"
+#include "state.h"
+#include "utils.h"
+
+lxc_log_define(lxc_monitor, lxc);
+
+/* routines used by monitor publishers (containers) */
+int lxc_monitor_fifo_name(const char *lxcpath, char *fifo_path, size_t fifo_path_sz,
+			  int do_mkdirp)
+{
+	int ret;
+	char *rundir;
+
+	rundir = get_rundir();
+	if (!rundir)
+		return -1;
+
+	if (do_mkdirp) {
+		ret = snprintf(fifo_path, fifo_path_sz, "%s/lxc/%s", rundir, lxcpath);
+		if (ret < 0 || (size_t)ret >= fifo_path_sz) {
+			ERROR("rundir/lxcpath (%s/%s) too long for monitor fifo.", rundir, lxcpath);
+			free(rundir);
+			return -1;
+		}
+		ret = mkdir_p(fifo_path, 0755);
+		if (ret < 0) {
+			ERROR("Unable to create monitor fifo directory %s.", fifo_path);
+			free(rundir);
+			return ret;
+		}
+	}
+	ret = snprintf(fifo_path, fifo_path_sz, "%s/lxc/%s/monitor-fifo", rundir, lxcpath);
+	if (ret < 0 || (size_t)ret >= fifo_path_sz) {
+		ERROR("rundir/lxcpath (%s/%s) too long for monitor fifo.", rundir, lxcpath);
+		free(rundir);
+		return -1;
+	}
+	free(rundir);
+	return 0;
+}
+
+static void lxc_monitor_fifo_send(struct lxc_msg *msg, const char *lxcpath)
+{
+	int fd,ret;
+	char fifo_path[PATH_MAX];
+
+	BUILD_BUG_ON(sizeof(*msg) > PIPE_BUF); /* write not guaranteed atomic */
+
+	ret = lxc_monitor_fifo_name(lxcpath, fifo_path, sizeof(fifo_path), 0);
+	if (ret < 0)
+		return;
+
+	/* Open the fifo nonblock in case the monitor is dead, we don't want the
+	 * open to wait for a reader since it may never come.
+	 */
+	fd = open(fifo_path, O_WRONLY | O_NONBLOCK);
+	if (fd < 0) {
+		/* It is normal for this open() to fail with ENXIO when there is
+		 * no monitor running, so we don't log it.
+		 */
+		if (errno == ENXIO || errno == ENOENT)
+			return;
+
+		WARN("%s - Failed to open fifo to send message", strerror(errno));
+		return;
+	}
+
+	if (fcntl(fd, F_SETFL, O_WRONLY) < 0) {
+		close(fd);
+		return;
+	}
+
+	ret = write(fd, msg, sizeof(*msg));
+	if (ret != sizeof(*msg)) {
+		close(fd);
+		SYSERROR("Failed to write to monitor fifo \"%s\".", fifo_path);
+		return;
+	}
+
+	close(fd);
+}
+
+void lxc_monitor_send_state(const char *name, lxc_state_t state,
+			    const char *lxcpath)
+{
+	struct lxc_msg msg = {.type = lxc_msg_state, .value = state};
+	strncpy(msg.name, name, sizeof(msg.name));
+	msg.name[sizeof(msg.name) - 1] = 0;
+
+	lxc_monitor_fifo_send(&msg, lxcpath);
+}
+
+void lxc_monitor_send_exit_code(const char *name, int exit_code,
+				const char *lxcpath)
+{
+	struct lxc_msg msg = {.type = lxc_msg_exit_code, .value = exit_code};
+	strncpy(msg.name, name, sizeof(msg.name));
+	msg.name[sizeof(msg.name) - 1] = 0;
+
+	lxc_monitor_fifo_send(&msg, lxcpath);
+}
+
+/* routines used by monitor subscribers (lxc-monitor) */
+int lxc_monitor_close(int fd)
+{
+	return close(fd);
+}
+
+/* Enforces \0-termination for the abstract unix socket. This is not required
+ * but allows us to print it out.
+ *
+ * Older version of liblxc only allowed for 105 bytes to be used for the
+ * abstract unix domain socket name because the code for our abstract unix
+ * socket handling performed invalid checks. Since we \0-terminate we could now
+ * have a maximum of 106 chars. But to not break backwards compatibility we keep
+ * the limit at 105.
+ */
+int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr) {
+	size_t len;
+	int ret;
+	char *path;
+	uint64_t hash;
+
+	/* addr.sun_path is only 108 bytes, so we hash the full name and
+	 * then append as much of the name as we can fit.
+	 */
+	memset(addr, 0, sizeof(*addr));
+	addr->sun_family = AF_UNIX;
+
+	/* strlen("lxc/") + strlen("/monitor-sock") + 1 = 18 */
+	len = strlen(lxcpath) + 18;
+	path = alloca(len);
+	ret = snprintf(path, len, "lxc/%s/monitor-sock", lxcpath);
+	if (ret < 0 || (size_t)ret >= len) {
+		ERROR("failed to create name for monitor socket");
+		return -1;
+	}
+
+	/* Note: snprintf() will \0-terminate addr->sun_path on the 106th byte
+	 * and so the abstract socket name has 105 "meaningful" characters. This
+	 * is absolutely intentional. For further info read the comment for this
+	 * function above!
+	 */
+	len = sizeof(addr->sun_path) - 1;
+	hash = fnv_64a_buf(path, ret, FNV1A_64_INIT);
+	ret = snprintf(addr->sun_path, len, "@lxc/%016" PRIx64 "/%s", hash, lxcpath);
+	if (ret < 0) {
+		ERROR("failed to create hashed name for monitor socket");
+		return -1;
+	}
+
+	/* replace @ with \0 */
+	addr->sun_path[0] = '\0';
+	INFO("using monitor socket name \"%s\" (length of socket name %zu must be <= %zu)", &addr->sun_path[1], strlen(&addr->sun_path[1]), sizeof(addr->sun_path) - 3);
+
+	return 0;
+}
+
+int lxc_monitor_open(const char *lxcpath)
+{
+	struct sockaddr_un addr;
+	int fd;
+	size_t retry;
+	size_t len;
+	int ret = -1;
+	int backoff_ms[] = {10, 50, 100};
+
+	if (lxc_monitor_sock_name(lxcpath, &addr) < 0)
+		return -1;
+
+	fd = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0) {
+		ERROR("Failed to create socket: %s.", strerror(errno));
+		return -errno;
+	}
+
+	len = strlen(&addr.sun_path[1]);
+	DEBUG("opening monitor socket %s with len %zu", &addr.sun_path[1], len);
+	if (len >= sizeof(addr.sun_path) - 1) {
+		errno = ENAMETOOLONG;
+		ret = -errno;
+		ERROR("name of monitor socket too long (%zu bytes): %s", len, strerror(errno));
+		goto on_error;
+	}
+
+	for (retry = 0; retry < sizeof(backoff_ms) / sizeof(backoff_ms[0]); retry++) {
+		fd = lxc_abstract_unix_connect(addr.sun_path);
+		if (fd != -1 || errno != ECONNREFUSED)
+			break;
+		ERROR("Failed to connect to monitor socket. Retrying in %d ms: %s", backoff_ms[retry], strerror(errno));
+		usleep(backoff_ms[retry] * 1000);
+	}
+
+	if (fd < 0) {
+		ret = -errno;
+		ERROR("Failed to connect to monitor socket: %s.", strerror(errno));
+		goto on_error;
+	}
+
+	return fd;
+
+on_error:
+	close(fd);
+	return ret;
+}
+
+int lxc_monitor_read_fdset(struct pollfd *fds, nfds_t nfds, struct lxc_msg *msg,
+			   int timeout)
+{
+	long i;
+	int ret;
+
+	ret = poll(fds, nfds, timeout * 1000);
+	if (ret == -1)
+		return -1;
+	else if (ret == 0)
+		return -2;  /* timed out */
+
+	/* Only read from the first ready fd, the others will remain ready for
+	 * when this routine is called again.
+	 */
+	for (i = 0; i < nfds; i++) {
+		if (fds[i].revents != 0) {
+			fds[i].revents = 0;
+			ret = recv(fds[i].fd, msg, sizeof(*msg), 0);
+			if (ret <= 0) {
+				SYSERROR("Failed to receive message. Did monitord die?: %s.", strerror(errno));
+				return -1;
+			}
+			return ret;
+		}
+	}
+
+	SYSERROR("No ready fd found.");
+
+	return -1;
+}
+
+int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout)
+{
+	struct pollfd fds;
+
+	fds.fd = fd;
+	fds.events = POLLIN | POLLPRI;
+	fds.revents = 0;
+
+	return lxc_monitor_read_fdset(&fds, 1, msg, timeout);
+}
+
+int lxc_monitor_read(int fd, struct lxc_msg *msg)
+{
+	return lxc_monitor_read_timeout(fd, msg, -1);
+}
+
+#define LXC_MONITORD_PATH LIBEXECDIR "/lxc/lxc-monitord"
+
+/* Used to spawn a monitord either on startup of a daemon container, or when
+ * lxc-monitor starts.
+ */
+int lxc_monitord_spawn(const char *lxcpath)
+{
+	int ret;
+	int pipefd[2];
+	char pipefd_str[LXC_NUMSTRLEN64];
+	pid_t pid1, pid2;
+
+	char *const args[] = {
+	    LXC_MONITORD_PATH,
+	    (char *)lxcpath,
+	    pipefd_str,
+	    NULL,
+	};
+
+	/* double fork to avoid zombies when monitord exits */
+	pid1 = fork();
+	if (pid1 < 0) {
+		SYSERROR("Failed to fork().");
+		return -1;
+	}
+
+	if (pid1) {
+		DEBUG("Going to wait for pid %d.", pid1);
+		if (waitpid(pid1, NULL, 0) != pid1)
+			return -1;
+		DEBUG("Finished waiting on pid %d.", pid1);
+		return 0;
+	}
+
+	if (pipe(pipefd) < 0) {
+		SYSERROR("Failed to create pipe.");
+		exit(EXIT_FAILURE);
+	}
+
+	pid2 = fork();
+	if (pid2 < 0) {
+		SYSERROR("Failed to fork().");
+		exit(EXIT_FAILURE);
+	}
+
+	if (pid2) {
+		DEBUG("Trying to sync with child process.");
+		char c;
+		/* Wait for daemon to create socket. */
+		close(pipefd[1]);
+
+		/* Sync with child, we're ignoring the return from read
+		 * because regardless if it works or not, either way we've
+		 * synced with the child process. the if-empty-statement
+		 * construct is to quiet the warn-unused-result warning.
+		 */
+		if (read(pipefd[0], &c, 1))
+			;
+
+		close(pipefd[0]);
+
+		DEBUG("Successfully synced with child process.");
+		exit(EXIT_SUCCESS);
+	}
+
+	if (setsid() < 0) {
+		SYSERROR("Failed to setsid().");
+		exit(EXIT_FAILURE);
+	}
+
+	lxc_check_inherited(NULL, true, &pipefd[1], 1);
+	if (null_stdfds() < 0) {
+		SYSERROR("Failed to dup2() standard file descriptors to /dev/null.");
+		exit(EXIT_FAILURE);
+	}
+
+	close(pipefd[0]);
+
+	ret = snprintf(pipefd_str, LXC_NUMSTRLEN64, "%d", pipefd[1]);
+	if (ret < 0 || ret >= LXC_NUMSTRLEN64) {
+		ERROR("Failed to create pid argument to pass to monitord.");
+		exit(EXIT_FAILURE);
+	}
+
+	DEBUG("Using pipe file descriptor %d for monitord.", pipefd[1]);
+
+	execvp(args[0], args);
+	SYSERROR("failed to exec lxc-monitord");
+
+	exit(EXIT_FAILURE);
+}
diff --git a/src/lxc/tools/tool_monitor.h b/src/lxc/tools/tool_monitor.h
new file mode 100644
index 000000000..33c3a345a
--- /dev/null
+++ b/src/lxc/tools/tool_monitor.h
@@ -0,0 +1,115 @@
+/*
+ * 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_MONITOR_H
+#define __LXC_MONITOR_H
+
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/un.h>
+#include <poll.h>
+
+typedef enum {
+	lxc_msg_state,
+	lxc_msg_priority,
+	lxc_msg_exit_code,
+} lxc_msg_type_t;
+
+struct lxc_msg {
+	lxc_msg_type_t type;
+	char name[NAME_MAX+1];
+	int value;
+};
+
+typedef enum {
+	STOPPED,
+	STARTING,
+	RUNNING,
+	STOPPING,
+	ABORTING,
+	FREEZING,
+	FROZEN,
+	THAWED,
+	MAX_STATE,
+} lxc_state_t;
+
+const char *const strstate[] = {
+    "STOPPED",  "STARTING", "RUNNING", "STOPPING",
+    "ABORTING", "FREEZING", "FROZEN",  "THAWED",
+};
+
+static inline const char *lxc_state2str(lxc_state_t state)
+{
+	if (state < STOPPED || state > MAX_STATE - 1)
+		return NULL;
+	return strstate[state];
+}
+
+extern int lxc_monitor_sock_name(const char *lxcpath, struct sockaddr_un *addr);
+extern int lxc_monitor_fifo_name(const char *lxcpath, char *fifo_path,
+				 size_t fifo_path_sz, int do_mkdirp);
+extern void lxc_monitor_send_state(const char *name, lxc_state_t state,
+			    const char *lxcpath);
+extern void lxc_monitor_send_exit_code(const char *name, int exit_code,
+			    const char *lxcpath);
+extern int lxc_monitord_spawn(const char *lxcpath);
+
+/*
+ * Open the monitoring mechanism for a specific container
+ * The function will return an fd corresponding to the events
+ * Returns a file descriptor on success, < 0 otherwise
+ */
+extern int lxc_monitor_open(const char *lxcpath);
+
+/*
+ * Blocking read for the next container state change
+ * @fd  : the file descriptor provided by lxc_monitor_open
+ * @msg : the variable which will be filled with the state
+ * Returns 0 if the monitored container has exited, > 0 if
+ * data was read, < 0 otherwise
+ */
+extern int lxc_monitor_read(int fd, struct lxc_msg *msg);
+
+/*
+ * Blocking read for the next container state change with timeout
+ * @fd      : the file descriptor provided by lxc_monitor_open
+ * @msg     : the variable which will be filled with the state
+ * @timeout : the timeout in seconds to wait for a state change
+ * Returns 0 if the monitored container has exited, > 0 if
+ * data was read, < 0 otherwise
+ */
+extern int lxc_monitor_read_timeout(int fd, struct lxc_msg *msg, int timeout);
+
+/*
+ * Blocking read from multiple monitors for the next container state
+ * change with timeout
+ * @fds     : struct pollfd descripting the fds to use
+ * @nfds    : the number of entries in fds
+ * @msg     : the variable which will be filled with the state
+ * @timeout : the timeout in seconds to wait for a state change
+ * Returns 0 if the monitored container has exited, > 0 if
+ * data was read, < 0 otherwise
+ */
+extern int lxc_monitor_read_fdset(struct pollfd *fds, nfds_t nfds, struct lxc_msg *msg,
+			   int timeout);
+
+#endif


More information about the lxc-devel mailing list