[lxc-devel] [PATCH] logs: introduce a thread-local 'current' lxc_config (v2)

Serge Hallyn serge.hallyn at ubuntu.com
Tue Apr 21 20:09:12 UTC 2015


The logging code uses a global log_fd and log_level to direct
logging (ERROR(), etc).  While the container configuration file allows
for lxc.loglevel and lxc.logfile, those are only used at configuration
file read time to set the global variables.  This works ok in the
lxc front-end programs, but becomes a problem with threaded API users.

The simplest solution would be to not allow per-container configuration
files, but it'd be nice to avoid that.

Passing a logfd or lxc_conf into every ERROR/INFO/etc call is "possible",
but would be a huge complication as there are many functions, including
struct member functions and callbacks, which don't have that info and
would need to get it from somewhere.

So the approach I'm taking here is to say that all real container work
is done inside api calls, and therefore the API calls themselves can
set a thread-local variable indicating which log info to use.  If
unset, then use the global values.  The lxc-* programs, when called
with a '-o logfile' argument, set a global variable to indicate that
the user-specified value should be used.

In this patch:

If the lxc container configuration specifies a loglevel/logfile, only
set the lxc_config's logfd and loglevel according to those, not the
global values.

Each API call is wrapped to set/unset the current_config.  (The few
exceptions are calls which do not result in any log actions)

Update logfile appender to use the logfile specified in lxc_conf if (a)
current_config is set and (b) the lxc-* command did not override it.

Changelog (2015-04-21):
	. always re-set current_config to NULL at end of an API
	  call, rather than storing the previous value.  We don't
	  nest API calls.
	. remove the log_lock stuff which wasn't used
	. lxc_conf_free: if the config is current_config, set
	  current_config to NULL.  (It can't be another thread's
	  current_config, or we wouldn't be freeing it)
	. lxc_check_inherited: don't close fd if it is the
	  current_config->logfd.  Note this is only called when
	  starting a container, so we have no other threads at
	  this point.

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 src/lxc/Makefile.am    |   1 +
 src/lxc/conf.c         |  16 +++
 src/lxc/conf.h         |   7 +
 src/lxc/confile.c      |  12 +-
 src/lxc/log.c          |  83 ++++++-----
 src/lxc/log.h          |  23 ++-
 src/lxc/lxccontainer.c | 373 ++++++++++++++++++++++++++++++++++++-------------
 src/lxc/start.c        |   3 +
 8 files changed, 373 insertions(+), 145 deletions(-)

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index b1e56b9..8b79c40 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -248,6 +248,7 @@ endif
 
 init_lxc_static_LDFLAGS = -static
 init_lxc_static_LDADD = @CAP_LIBS@
+init_lxc_static_CFLAGS = $(AM_CFLAGS) -DNO_LXC_CONF
 endif
 
 install-exec-local: install-soPROGRAMS
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index d4855fd..3a7a52a 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -178,6 +178,17 @@ struct caps_opt {
 	int value;
 };
 
+/*
+ * The lxc_conf of the container currently being worked on in an
+ * API call
+ * This is used in the error calls
+ */
+#ifdef HAVE_TLS
+__thread struct lxc_conf *current_config;
+#else
+struct lxc_conf *current_config;
+#endif
+
 /* Declare this here, since we don't want to reshuffle the whole file. */
 static int in_caplist(int cap, struct lxc_list *caps);
 
@@ -2573,6 +2584,7 @@ struct lxc_conf *lxc_conf_init(void)
 		return NULL;
 	}
 	new->kmsg = 0;
+	new->logfd = -1;
 	lxc_list_init(&new->cgroup);
 	lxc_list_init(&new->network);
 	lxc_list_init(&new->mount_list);
@@ -4239,6 +4251,8 @@ void lxc_conf_free(struct lxc_conf *conf)
 {
 	if (!conf)
 		return;
+	if (current_config == conf)
+		current_config = NULL;
 	free(conf->console.log_path);
 	free(conf->console.path);
 	free(conf->rootfs.mount);
@@ -4246,6 +4260,8 @@ void lxc_conf_free(struct lxc_conf *conf)
 	free(conf->rootfs.path);
 	free(conf->rootfs.pivot);
 	free(conf->logfile);
+	if (conf->logfd != -1)
+		close(conf->logfd);
 	free(conf->utsname);
 	free(conf->ttydir);
 	free(conf->fstab);
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 4b66045..0c0475e 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -336,6 +336,7 @@ struct lxc_conf {
 	// store the config file specified values here.
 	char *logfile;  // the logfile as specifed in config
 	int loglevel;   // loglevel as specifed in config (if any)
+	int logfd;
 
 	int inherit_ns_fd[LXC_NS_MAX];
 
@@ -365,6 +366,12 @@ struct lxc_conf {
 	char *init_cmd;
 };
 
+#ifdef HAVE_TLS
+extern __thread struct lxc_conf *current_config;
+#else
+extern struct lxc_conf *current_config;
+#endif
+
 int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
 		  const char *lxcpath, char *argv[]);
 
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index e3be6a6..7e8b6a2 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -1171,15 +1171,15 @@ static int config_lsm_se_context(const char *key, const char *value,
 }
 
 static int config_logfile(const char *key, const char *value,
-			     struct lxc_conf *lxc_conf)
+			     struct lxc_conf *c)
 {
 	int ret;
 
 	// store these values in the lxc_conf, and then try to set for
 	// actual current logging.
-	ret = config_path_item(&lxc_conf->logfile, value);
+	ret = config_path_item(&c->logfile, value);
 	if (ret == 0)
-		ret = lxc_log_set_file(lxc_conf->logfile);
+		ret = lxc_log_set_file(&c->logfd, c->logfile);
 	return ret;
 }
 
@@ -1198,7 +1198,7 @@ static int config_loglevel(const char *key, const char *value,
 	// store these values in the lxc_conf, and then try to set for
 	// actual current logging.
 	lxc_conf->loglevel = newlevel;
-	return lxc_log_set_level(newlevel);
+	return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
 }
 
 static int config_autodev(const char *key, const char *value,
@@ -2381,9 +2381,9 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
 	else if (strcmp(key, "lxc.se_context") == 0)
 		v = c->lsm_se_context;
 	else if (strcmp(key, "lxc.logfile") == 0)
-		v = lxc_log_get_file();
+		v = c->logfile;
 	else if (strcmp(key, "lxc.loglevel") == 0)
-		v = lxc_log_priority_to_string(lxc_log_get_level());
+		v = lxc_log_priority_to_string(c->loglevel);
 	else if (strcmp(key, "lxc.cgroup") == 0) // all cgroup info
 		return lxc_get_cgroup_entry(c, retv, inlen, "all");
 	else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info
diff --git a/src/lxc/log.c b/src/lxc/log.c
index 6633e62..a257f67 100644
--- a/src/lxc/log.c
+++ b/src/lxc/log.c
@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <string.h>
+#include <pthread.h>
 
 #define __USE_GNU /* for *_CLOEXEC */
 
@@ -40,27 +41,13 @@
 #define LXC_LOG_PREFIX_SIZE	32
 #define LXC_LOG_BUFFER_SIZE	512
 
-#ifdef HAVE_TLS
-__thread int lxc_log_fd = -1;
-static __thread char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
-static __thread char *log_fname = NULL;
-/* command line values for logfile or logpriority should always override
- * values from the configuration file or defaults
- */
-static __thread int lxc_logfile_specified = 0;
-static __thread int lxc_loglevel_specified = 0;
-static __thread int lxc_quiet_specified = 0;
-#else
 int lxc_log_fd = -1;
+int lxc_quiet_specified;
+int lxc_log_use_global_fd;
+static int lxc_loglevel_specified;
+
 static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
 static char *log_fname = NULL;
-static int lxc_quiet_specified = 0;
-/* command line values for logfile or logpriority should always override
- * values from the configuration file or defaults
- */
-static int lxc_logfile_specified = 0;
-static int lxc_loglevel_specified = 0;
-#endif
 
 lxc_log_define(lxc_log, lxc);
 
@@ -85,8 +72,17 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
 	char buffer[LXC_LOG_BUFFER_SIZE];
 	int n;
 	int ms;
+	int fd_to_use = -1;
 
-	if (lxc_log_fd == -1)
+#ifndef NO_LXC_CONF
+	if (!lxc_log_use_global_fd && current_config)
+		fd_to_use = current_config->logfd;
+#endif
+
+	if (fd_to_use == -1)
+		fd_to_use = lxc_log_fd;
+
+	if (fd_to_use == -1)
 		return 0;
 
 	ms = event->timestamp.tv_usec / 1000;
@@ -111,7 +107,7 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
 
 	buffer[n] = '\n';
 
-	return write(lxc_log_fd, buffer, n + 1);
+	return write(fd_to_use, buffer, n + 1);
 }
 
 static struct lxc_log_appender log_appender_stderr = {
@@ -136,7 +132,7 @@ static struct lxc_log_category log_root = {
 struct lxc_log_category lxc_log_category_lxc = {
 	.name		= "lxc",
 	.priority	= LXC_LOG_PRIORITY_ERROR,
-	.appender	= &log_appender_stderr,
+	.appender	= &log_appender_logfile,
 	.parent		= &log_root
 };
 
@@ -305,6 +301,11 @@ static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_d
 	return ret;
 }
 
+/*
+ * lxc_log_init:
+ * Called from lxc front-end programs (like lxc-create, lxc-start) to
+ * initalize the log defaults.
+ */
 extern int lxc_log_init(const char *name, const char *file,
 			const char *priority, const char *prefix, int quiet,
 			const char *lxcpath)
@@ -320,10 +321,12 @@ extern int lxc_log_init(const char *name, const char *file,
 	if (priority)
 		lxc_priority = lxc_log_priority_to_int(priority);
 
-	lxc_log_category_lxc.priority = lxc_priority;
+	if (!lxc_loglevel_specified) {
+		lxc_log_category_lxc.priority = lxc_priority;
+		lxc_loglevel_specified = 1;
+	}
 
 	if (!lxc_quiet_specified) {
-		lxc_log_category_lxc.appender = &log_appender_logfile;
 		if (!quiet)
 			lxc_log_category_lxc.appender->next = &log_appender_stderr;
 	}
@@ -335,6 +338,7 @@ extern int lxc_log_init(const char *name, const char *file,
 		if (strcmp(file, "none") == 0)
 			return 0;
 		ret = __lxc_log_set_file(file, 1);
+		lxc_log_use_global_fd = 1;
 	} else {
 		/* if no name was specified, there nothing to do */
 		if (!name)
@@ -385,15 +389,13 @@ extern void lxc_log_close(void)
  * happens after processing command line arguments, which override the .conf
  * settings.  So only set the level if previously unset.
  */
-extern int lxc_log_set_level(int level)
+extern int lxc_log_set_level(int *dest, int level)
 {
-	if (lxc_loglevel_specified)
-		return 0;
 	if (level < 0 || level >= LXC_LOG_PRIORITY_NOTSET) {
 		ERROR("invalid log priority %d", level);
 		return -1;
 	}
-	lxc_log_category_lxc.priority = level;
+	*dest = level;
 	return 0;
 }
 
@@ -415,11 +417,23 @@ extern bool lxc_log_has_valid_level(void)
  * happens after processing command line arguments, which override the .conf
  * settings.  So only set the file if previously unset.
  */
-extern int lxc_log_set_file(const char *fname)
+extern int lxc_log_set_file(int *fd, const char *fname)
 {
-	if (lxc_logfile_specified)
-		return 0;
-	return __lxc_log_set_file(fname, 0);
+	if (*fd != -1) {
+		close(*fd);
+		*fd = -1;
+	}
+
+	if (build_dir(fname)) {
+		ERROR("failed to create dir for log file \"%s\" : %s", fname,
+				strerror(errno));
+		return -1;
+	}
+
+	*fd = log_open(fname);
+	if (*fd == -1)
+		return -errno;
+	return 0;
 }
 
 extern const char *lxc_log_get_file(void)
@@ -440,11 +454,6 @@ extern const char *lxc_log_get_prefix(void)
 
 extern void lxc_log_options_no_override()
 {
-	if (lxc_log_get_file())
-		lxc_logfile_specified = 1;
-
-	if (lxc_log_get_level() != LXC_LOG_PRIORITY_NOTSET)
-		lxc_loglevel_specified = 1;
-
 	lxc_quiet_specified = 1;
+	lxc_loglevel_specified = 1;
 }
diff --git a/src/lxc/log.h b/src/lxc/log.h
index b47f120..76bd4df 100644
--- a/src/lxc/log.h
+++ b/src/lxc/log.h
@@ -33,6 +33,8 @@
 #include <strings.h>
 #include <stdbool.h>
 
+#include "conf.h"
+
 #ifndef O_CLOEXEC
 #define O_CLOEXEC 02000000
 #endif
@@ -104,6 +106,10 @@ struct lxc_log_category {
 	const struct lxc_log_category	*parent;
 };
 
+#ifndef NO_LXC_CONF
+extern int lxc_log_use_global_fd;
+#endif
+
 /*
  * Returns true if the chained priority is equal to or higher than
  * given priority.
@@ -116,7 +122,14 @@ lxc_log_priority_is_enabled(const struct lxc_log_category* category,
 	       category->parent)
 		category = category->parent;
 
-	return priority >= category->priority;
+	int cmp_prio = category->priority;
+#ifndef NO_LXC_CONF
+	if (!lxc_log_use_global_fd && current_config &&
+			current_config->loglevel != LXC_LOG_PRIORITY_NOTSET)
+		cmp_prio = current_config->loglevel;
+#endif
+
+	return priority >= cmp_prio;
 }
 
 /*
@@ -294,18 +307,14 @@ ATTR_UNUSED static inline void LXC_##PRIORITY(struct lxc_log_locinfo* locinfo,	\
 	ERROR("%s - " format, strerror(errno), ##__VA_ARGS__);		\
 } while (0)
 
-#ifdef HAVE_TLS
-extern __thread int lxc_log_fd;
-#else
 extern int lxc_log_fd;
-#endif
 
 extern int lxc_log_init(const char *name, const char *file,
 			const char *priority, const char *prefix, int quiet,
 			const char *lxcpath);
 
-extern int lxc_log_set_file(const char *fname);
-extern int lxc_log_set_level(int level);
+extern int lxc_log_set_file(int *fd, const char *fname);
+extern int lxc_log_set_level(int *dest, int level);
 extern void lxc_log_set_prefix(const char *prefix);
 extern const char *lxc_log_get_file(void);
 extern int lxc_log_get_level(void);
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index e2586de..1fae6d9 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -91,6 +91,15 @@ return -1;
 
 lxc_log_define(lxc_container, lxc);
 
+static bool do_lxcapi_destroy(struct lxc_container *c);
+static const char *lxcapi_get_config_path(struct lxc_container *c);
+#define do_lxcapi_get_config_path(c) lxcapi_get_config_path(c)
+static bool do_lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v);
+static bool container_destroy(struct lxc_container *c);
+static bool get_snappath_dir(struct lxc_container *c, char *snappath);
+static bool lxcapi_snapshot_destroy_all(struct lxc_container *c);
+static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file);
+
 static bool config_file_exists(const char *lxcpath, const char *cname)
 {
 	/* $lxcpath + '/' + $cname + '/config' + \0 */
@@ -307,7 +316,7 @@ int lxc_container_put(struct lxc_container *c)
 	return 0;
 }
 
-static bool lxcapi_is_defined(struct lxc_container *c)
+static bool do_lxcapi_is_defined(struct lxc_container *c)
 {
 	struct stat statbuf;
 	bool ret = false;
@@ -330,7 +339,49 @@ out:
 	return ret;
 }
 
-static const char *lxcapi_state(struct lxc_container *c)
+#define WRAP_API(rettype, fnname)					\
+static rettype fnname(struct lxc_container *c)				\
+{									\
+	rettype ret;							\
+	current_config = c ? c->lxc_conf : NULL;			\
+	ret = do_##fnname(c);						\
+	current_config = NULL;						\
+	return ret;							\
+}
+
+#define WRAP_API_1(rettype, fnname, t1)					\
+static rettype fnname(struct lxc_container *c, t1 a1)			\
+{									\
+	rettype ret;							\
+	current_config = c ? c->lxc_conf : NULL;			\
+	ret = do_##fnname(c, a1);					\
+	current_config = NULL;						\
+	return ret;							\
+}
+
+#define WRAP_API_2(rettype, fnname, t1, t2)				\
+static rettype fnname(struct lxc_container *c, t1 a1, t2 a2)		\
+{									\
+	rettype ret;							\
+	current_config = c ? c->lxc_conf : NULL;			\
+	ret = do_##fnname(c, a1, a2);					\
+	current_config = NULL;						\
+	return ret;							\
+}
+
+#define WRAP_API_3(rettype, fnname, t1, t2, t3)				\
+static rettype fnname(struct lxc_container *c, t1 a1, t2 a2, t3 a3)	\
+{									\
+	rettype ret;							\
+	current_config = c ? c->lxc_conf : NULL;			\
+	ret = do_##fnname(c, a1, a2, a3);				\
+	current_config = NULL;						\
+	return ret;							\
+}
+
+WRAP_API(bool, lxcapi_is_defined)
+
+static const char *do_lxcapi_state(struct lxc_container *c)
 {
 	lxc_state_t s;
 
@@ -340,6 +391,8 @@ static const char *lxcapi_state(struct lxc_container *c)
 	return lxc_state2str(s);
 }
 
+WRAP_API(const char *, lxcapi_state)
+
 static bool is_stopped(struct lxc_container *c)
 {
 	lxc_state_t s;
@@ -347,19 +400,21 @@ static bool is_stopped(struct lxc_container *c)
 	return (s == STOPPED);
 }
 
-static bool lxcapi_is_running(struct lxc_container *c)
+static bool do_lxcapi_is_running(struct lxc_container *c)
 {
 	const char *s;
 
 	if (!c)
 		return false;
-	s = lxcapi_state(c);
+	s = do_lxcapi_state(c);
 	if (!s || strcmp(s, "STOPPED") == 0)
 		return false;
 	return true;
 }
 
-static bool lxcapi_freeze(struct lxc_container *c)
+WRAP_API(bool, lxcapi_is_running)
+
+static bool do_lxcapi_freeze(struct lxc_container *c)
 {
 	int ret;
 	if (!c)
@@ -371,7 +426,9 @@ static bool lxcapi_freeze(struct lxc_container *c)
 	return true;
 }
 
-static bool lxcapi_unfreeze(struct lxc_container *c)
+WRAP_API(bool, lxcapi_freeze)
+
+static bool do_lxcapi_unfreeze(struct lxc_container *c)
 {
 	int ret;
 	if (!c)
@@ -383,7 +440,9 @@ static bool lxcapi_unfreeze(struct lxc_container *c)
 	return true;
 }
 
-static int lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
+WRAP_API(bool, lxcapi_unfreeze)
+
+static int do_lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
 {
 	int ttyfd;
 	if (!c)
@@ -393,13 +452,23 @@ static int lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *maste
 	return ttyfd;
 }
 
+WRAP_API_2(int, lxcapi_console_getfd, int *, int *)
+
 static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
 			  int stdoutfd, int stderrfd, int escape)
 {
-	return lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape);
+	int ret;
+
+	if (!c)
+		return -1;
+
+	current_config = c->lxc_conf;
+	ret = lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape);
+	current_config = NULL;
+	return ret;
 }
 
-static pid_t lxcapi_init_pid(struct lxc_container *c)
+static pid_t do_lxcapi_init_pid(struct lxc_container *c)
 {
 	if (!c)
 		return -1;
@@ -407,6 +476,8 @@ static pid_t lxcapi_init_pid(struct lxc_container *c)
 	return lxc_cmd_get_init_pid(c->name, c->config_path);
 }
 
+WRAP_API(pid_t, lxcapi_init_pid)
+
 static bool load_config_locked(struct lxc_container *c, const char *fname)
 {
 	if (!c->lxc_conf)
@@ -418,7 +489,7 @@ static bool load_config_locked(struct lxc_container *c, const char *fname)
 	return true;
 }
 
-static bool lxcapi_load_config(struct lxc_container *c, const char *alt_file)
+static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file)
 {
 	bool ret = false, need_disklock = false;
 	int lret;
@@ -455,7 +526,9 @@ static bool lxcapi_load_config(struct lxc_container *c, const char *alt_file)
 	return ret;
 }
 
-static bool lxcapi_want_daemonize(struct lxc_container *c, bool state)
+WRAP_API_1(bool, lxcapi_load_config, const char *)
+
+static bool do_lxcapi_want_daemonize(struct lxc_container *c, bool state)
 {
 	if (!c || !c->lxc_conf)
 		return false;
@@ -468,7 +541,9 @@ static bool lxcapi_want_daemonize(struct lxc_container *c, bool state)
 	return true;
 }
 
-static bool lxcapi_want_close_all_fds(struct lxc_container *c, bool state)
+WRAP_API_1(bool, lxcapi_want_daemonize, bool)
+
+static bool do_lxcapi_want_close_all_fds(struct lxc_container *c, bool state)
 {
 	if (!c || !c->lxc_conf)
 		return false;
@@ -481,7 +556,9 @@ static bool lxcapi_want_close_all_fds(struct lxc_container *c, bool state)
 	return true;
 }
 
-static bool lxcapi_wait(struct lxc_container *c, const char *state, int timeout)
+WRAP_API_1(bool, lxcapi_want_close_all_fds, bool)
+
+static bool do_lxcapi_wait(struct lxc_container *c, const char *state, int timeout)
 {
 	int ret;
 
@@ -492,8 +569,9 @@ static bool lxcapi_wait(struct lxc_container *c, const char *state, int timeout)
 	return ret == 0;
 }
 
+WRAP_API_2(bool, lxcapi_wait, const char *, int)
 
-static bool wait_on_daemonized_start(struct lxc_container *c, int pid)
+static bool do_wait_on_daemonized_start(struct lxc_container *c, int pid)
 {
 	/* we'll probably want to make this timeout configurable? */
 	int timeout = 5, ret, status;
@@ -505,9 +583,11 @@ static bool wait_on_daemonized_start(struct lxc_container *c, int pid)
 	ret = waitpid(pid, &status, 0);
 	if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
 		DEBUG("failed waiting for first dual-fork child");
-	return lxcapi_wait(c, "RUNNING", timeout);
+	return do_lxcapi_wait(c, "RUNNING", timeout);
 }
 
+WRAP_API_1(bool, wait_on_daemonized_start, int)
+
 static bool am_single_threaded(void)
 {
 	struct dirent dirent, *direntp;
@@ -540,7 +620,7 @@ static bool am_single_threaded(void)
  * I can't decide if it'd be more convenient for callers if we accept '...',
  * or a null-terminated array (i.e. execl vs execv)
  */
-static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[])
+static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const argv[])
 {
 	int ret;
 	struct lxc_conf *conf;
@@ -565,7 +645,7 @@ static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv
 	}
 	if (ret == 2) {
 		ERROR("Error: %s creation was not completed", c->name);
-		c->destroy(c);
+		do_lxcapi_destroy(c);
 		return false;
 	} else if (ret == 1) {
 		ERROR("Error: creation of %s is ongoing", c->name);
@@ -708,6 +788,15 @@ out:
 		return (ret == 0 ? true : false);
 }
 
+static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[])
+{
+	bool ret;
+	current_config = c ? c->lxc_conf : NULL;
+	ret = do_lxcapi_start(c, useinit, argv);
+	current_config = NULL;
+	return ret;
+}
+
 /*
  * note there MUST be an ending NULL
  */
@@ -721,6 +810,8 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
 	if (!c)
 		return false;
 
+	current_config = c->lxc_conf;
+
 	va_start(ap, useinit);
 	inargs = lxc_va_arg_list_to_argv(ap, 0, 1);
 	va_end(ap);
@@ -731,7 +822,7 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
 	}
 
 	/* pass NULL if no arguments were supplied */
-	bret = lxcapi_start(c, useinit, *inargs ? inargs : NULL);
+	bret = do_lxcapi_start(c, useinit, *inargs ? inargs : NULL);
 
 out:
 	if (inargs) {
@@ -741,10 +832,11 @@ out:
 		free(inargs);
 	}
 
+	current_config = NULL;
 	return bret;
 }
 
-static bool lxcapi_stop(struct lxc_container *c)
+static bool do_lxcapi_stop(struct lxc_container *c)
 {
 	int ret;
 
@@ -756,6 +848,8 @@ static bool lxcapi_stop(struct lxc_container *c)
 	return ret == 0;
 }
 
+WRAP_API(bool, lxcapi_stop)
+
 static int do_create_container_dir(const char *path, struct lxc_conf *conf)
 {
 	int ret = -1, lasterr;
@@ -803,9 +897,6 @@ static bool create_container_dir(struct lxc_container *c)
 	return ret == 0;
 }
 
-static const char *lxcapi_get_config_path(struct lxc_container *c);
-static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v);
-
 /*
  * do_bdev_create: thin wrapper around bdev_create().  Like bdev_create(),
  * it returns a mounted bdev on success, NULL on error.
@@ -825,7 +916,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
 		dest = alloca(len);
 		ret = snprintf(dest, len, "%s", rpath);
 	} else {
-		const char *lxcpath = lxcapi_get_config_path(c);
+		const char *lxcpath = do_lxcapi_get_config_path(c);
 		len = strlen(c->name) + strlen(lxcpath) + 9;
 		dest = alloca(len);
 		ret = snprintf(dest, len, "%s/%s/rootfs", lxcpath, c->name);
@@ -839,7 +930,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
 		return NULL;
 	}
 
-	lxcapi_set_config_item(c, "lxc.rootfs", bdev->src);
+	do_lxcapi_set_config_item(c, "lxc.rootfs", bdev->src);
 
 	/* if we are not root, chown the rootfs dir to root in the
 	 * target uidmap */
@@ -1216,9 +1307,8 @@ static void lxcapi_clear_config(struct lxc_container *c)
 	}
 }
 
-static bool lxcapi_destroy(struct lxc_container *c);
-static bool container_destroy(struct lxc_container *c);
-static bool get_snappath_dir(struct lxc_container *c, char *snappath);
+#define do_lxcapi_clear_config(c) lxcapi_clear_config(c)
+
 /*
  * lxcapi_create:
  * create a container with the given parameters.
@@ -1233,7 +1323,7 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath);
  * @argv: the arguments to pass to the template, terminated by NULL.  If no
  * arguments, you can just pass NULL.
  */
-static bool lxcapi_create(struct lxc_container *c, const char *t,
+static bool do_lxcapi_create(struct lxc_container *c, const char *t,
 		const char *bdevtype, struct bdev_specs *specs, int flags,
 		char *const argv[])
 {
@@ -1259,14 +1349,14 @@ static bool lxcapi_create(struct lxc_container *c, const char *t,
 	 * an existing container.  Return an error, but do NOT delete the
 	 * container.
 	 */
-	if (lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path &&
+	if (do_lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path &&
 			access(c->lxc_conf->rootfs.path, F_OK) == 0 && tpath) {
 		ERROR("Container %s:%s already exists", c->config_path, c->name);
 		goto free_tpath;
 	}
 
 	if (!c->lxc_conf) {
-		if (!c->load_config(c, lxc_global_config_value("lxc.default_config"))) {
+		if (!do_lxcapi_load_config(c, lxc_global_config_value("lxc.default_config"))) {
 			ERROR("Error loading default configuration file %s", lxc_global_config_value("lxc.default_config"));
 			goto free_tpath;
 		}
@@ -1286,7 +1376,7 @@ static bool lxcapi_create(struct lxc_container *c, const char *t,
 	if (c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) != 0)
 		/* rootfs passed into configuration, but does not exist: error */
 		goto out;
-	if (lxcapi_is_defined(c) && c->lxc_conf->rootfs.path && !tpath) {
+	if (do_lxcapi_is_defined(c) && c->lxc_conf->rootfs.path && !tpath) {
 		/* Rootfs already existed, user just wanted to save the
 		 * loaded configuration */
 		ret = true;
@@ -1322,7 +1412,7 @@ static bool lxcapi_create(struct lxc_container *c, const char *t,
 		}
 
 		/* save config file again to store the new rootfs location */
-		if (!c->save_config(c, NULL)) {
+		if (!do_lxcapi_save_config(c, NULL)) {
 			ERROR("failed to save starting configuration for %s", c->name);
 			// parent task won't see bdev in config so we delete it
 			bdev->ops->umount(bdev);
@@ -1345,7 +1435,7 @@ static bool lxcapi_create(struct lxc_container *c, const char *t,
 
 	// now clear out the lxc_conf we have, reload from the created
 	// container
-	lxcapi_clear_config(c);
+	do_lxcapi_clear_config(c);
 
 	if (t) {
 		if (!prepend_lxc_header(c->configfile, tpath, argv)) {
@@ -1366,16 +1456,27 @@ free_tpath:
 	return ret;
 }
 
-static bool lxcapi_reboot(struct lxc_container *c)
+static bool lxcapi_create(struct lxc_container *c, const char *t,
+		const char *bdevtype, struct bdev_specs *specs, int flags,
+		char *const argv[])
+{
+	bool ret;
+	current_config = c ? c->lxc_conf : NULL;
+	ret = do_lxcapi_create(c, t, bdevtype, specs, flags, argv);
+	current_config = NULL;
+	return ret;
+}
+
+static bool do_lxcapi_reboot(struct lxc_container *c)
 {
 	pid_t pid;
 	int rebootsignal = SIGINT;
 
 	if (!c)
 		return false;
-	if (!c->is_running(c))
+	if (!do_lxcapi_is_running(c))
 		return false;
-	pid = c->init_pid(c);
+	pid = do_lxcapi_init_pid(c);
 	if (pid <= 0)
 		return false;
 	if (c->lxc_conf && c->lxc_conf->rebootsignal)
@@ -1386,7 +1487,9 @@ static bool lxcapi_reboot(struct lxc_container *c)
 
 }
 
-static bool lxcapi_shutdown(struct lxc_container *c, int timeout)
+WRAP_API(bool, lxcapi_reboot)
+
+static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout)
 {
 	bool retv;
 	pid_t pid;
@@ -1395,18 +1498,20 @@ static bool lxcapi_shutdown(struct lxc_container *c, int timeout)
 	if (!c)
 		return false;
 
-	if (!c->is_running(c))
+	if (!do_lxcapi_is_running(c))
 		return true;
-	pid = c->init_pid(c);
+	pid = do_lxcapi_init_pid(c);
 	if (pid <= 0)
 		return true;
 	if (c->lxc_conf && c->lxc_conf->haltsignal)
 		haltsignal = c->lxc_conf->haltsignal;
 	kill(pid, haltsignal);
-	retv = c->wait(c, "STOPPED", timeout);
+	retv = do_lxcapi_wait(c, "STOPPED", timeout);
 	return retv;
 }
 
+WRAP_API_1(bool, lxcapi_shutdown, int)
+
 static bool lxcapi_createl(struct lxc_container *c, const char *t,
 		const char *bdevtype, struct bdev_specs *specs, int flags, ...)
 {
@@ -1417,6 +1522,8 @@ static bool lxcapi_createl(struct lxc_container *c, const char *t,
 	if (!c)
 		return false;
 
+	current_config = c->lxc_conf;
+
 	/*
 	 * since we're going to wait for create to finish, I don't think we
 	 * need to get a copy of the arguments.
@@ -1429,10 +1536,11 @@ static bool lxcapi_createl(struct lxc_container *c, const char *t,
 		goto out;
 	}
 
-	bret = c->create(c, t, bdevtype, specs, flags, args);
+	bret = do_lxcapi_create(c, t, bdevtype, specs, flags, args);
 
 out:
 	free(args);
+	current_config = NULL;
 	return bret;
 }
 
@@ -1450,7 +1558,7 @@ static void do_clear_unexp_config_line(struct lxc_conf *conf, const char *key)
 		WARN("Error clearing configuration for %s", key);
 }
 
-static bool lxcapi_clear_config_item(struct lxc_container *c, const char *key)
+static bool do_lxcapi_clear_config_item(struct lxc_container *c, const char *key)
 {
 	int ret;
 
@@ -1465,9 +1573,11 @@ static bool lxcapi_clear_config_item(struct lxc_container *c, const char *key)
 	return ret == 0;
 }
 
+WRAP_API_1(bool, lxcapi_clear_config_item, const char *)
+
 static inline bool enter_net_ns(struct lxc_container *c)
 {
-	pid_t pid = c->init_pid(c);
+	pid_t pid = do_lxcapi_init_pid(c);
 
 	if ((geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) && access("/proc/self/ns/user", F_OK) == 0) {
 		if (!switch_to_ns(pid, "user"))
@@ -1547,7 +1657,7 @@ static bool remove_from_array(char ***names, char *cname, int size)
 	return false;
 }
 
-static char** lxcapi_get_interfaces(struct lxc_container *c)
+static char ** do_lxcapi_get_interfaces(struct lxc_container *c)
 {
 	pid_t pid;
 	int i, count = 0, pipefd[2];
@@ -1634,7 +1744,9 @@ static char** lxcapi_get_interfaces(struct lxc_container *c)
 	return interfaces;
 }
 
-static char** lxcapi_get_ips(struct lxc_container *c, const char* interface, const char* family, int scope)
+WRAP_API(char **, lxcapi_get_interfaces)
+
+static char** do_lxcapi_get_ips(struct lxc_container *c, const char* interface, const char* family, int scope)
 {
 	pid_t pid;
 	int i, count = 0, pipefd[2];
@@ -1751,7 +1863,9 @@ static char** lxcapi_get_ips(struct lxc_container *c, const char* interface, con
 	return addresses;
 }
 
-static int lxcapi_get_config_item(struct lxc_container *c, const char *key, char *retv, int inlen)
+WRAP_API_3(char **, lxcapi_get_ips, const char *, const char *, int)
+
+static int do_lxcapi_get_config_item(struct lxc_container *c, const char *key, char *retv, int inlen)
 {
 	int ret;
 
@@ -1764,7 +1878,9 @@ static int lxcapi_get_config_item(struct lxc_container *c, const char *key, char
 	return ret;
 }
 
-static char* lxcapi_get_running_config_item(struct lxc_container *c, const char *key)
+WRAP_API_3(int, lxcapi_get_config_item, const char *, char *, int)
+
+static char* do_lxcapi_get_running_config_item(struct lxc_container *c, const char *key)
 {
 	char *ret;
 
@@ -1772,12 +1888,14 @@ static char* lxcapi_get_running_config_item(struct lxc_container *c, const char
 		return NULL;
 	if (container_mem_lock(c))
 		return NULL;
-	ret = lxc_cmd_get_config_item(c->name, key, c->get_config_path(c));
+	ret = lxc_cmd_get_config_item(c->name, key, do_lxcapi_get_config_path(c));
 	container_mem_unlock(c);
 	return ret;
 }
 
-static int lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv, int inlen)
+WRAP_API_1(char *, lxcapi_get_running_config_item, const char *)
+
+static int do_lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv, int inlen)
 {
 	if (!key)
 		return lxc_listconfigs(retv, inlen);
@@ -1797,7 +1915,9 @@ static int lxcapi_get_keys(struct lxc_container *c, const char *key, char *retv,
 	return ret;
 }
 
-static bool lxcapi_save_config(struct lxc_container *c, const char *alt_file)
+WRAP_API_3(int, lxcapi_get_keys, const char *, char *, int)
+
+static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file)
 {
 	FILE *fout;
 	bool ret = false, need_disklock = false;
@@ -1810,7 +1930,7 @@ static bool lxcapi_save_config(struct lxc_container *c, const char *alt_file)
 
 	// If we haven't yet loaded a config, load the stock config
 	if (!c->lxc_conf) {
-		if (!c->load_config(c, lxc_global_config_value("lxc.default_config"))) {
+		if (!do_lxcapi_load_config(c, lxc_global_config_value("lxc.default_config"))) {
 			ERROR("Error loading default configuration file %s while saving %s", lxc_global_config_value("lxc.default_config"), c->name);
 			return false;
 		}
@@ -1850,6 +1970,8 @@ out:
 	return ret;
 }
 
+WRAP_API_1(bool, lxcapi_save_config, const char *)
+
 static bool mod_rdep(struct lxc_container *c, bool inc)
 {
 	char path[MAXPATHLEN];
@@ -2038,7 +2160,7 @@ static bool container_destroy(struct lxc_container *c)
 	bool bret = false;
 	int ret;
 
-	if (!c || !lxcapi_is_defined(c))
+	if (!c || !do_lxcapi_is_defined(c))
 		return false;
 
 	if (container_disk_lock(c))
@@ -2063,7 +2185,7 @@ static bool container_destroy(struct lxc_container *c)
 
 	mod_all_rdeps(c, false);
 
-	const char *p1 = lxcapi_get_config_path(c);
+	const char *p1 = do_lxcapi_get_config_path(c);
 	char *path = alloca(strlen(p1) + strlen(c->name) + 2);
 	sprintf(path, "%s/%s", p1, c->name);
 	if (am_unpriv())
@@ -2081,7 +2203,7 @@ out:
 	return bret;
 }
 
-static bool lxcapi_destroy(struct lxc_container *c)
+static bool do_lxcapi_destroy(struct lxc_container *c)
 {
 	if (!c || !lxcapi_is_defined(c))
 		return false;
@@ -2098,9 +2220,9 @@ static bool lxcapi_destroy(struct lxc_container *c)
 	return container_destroy(c);
 }
 
-static bool lxcapi_snapshot_destroy_all(struct lxc_container *c);
+WRAP_API(bool, lxcapi_destroy)
 
-static bool lxcapi_destroy_with_snapshots(struct lxc_container *c)
+static bool do_lxcapi_destroy_with_snapshots(struct lxc_container *c)
 {
 	if (!c || !lxcapi_is_defined(c))
 		return false;
@@ -2111,6 +2233,8 @@ static bool lxcapi_destroy_with_snapshots(struct lxc_container *c)
 	return lxcapi_destroy(c);
 }
 
+WRAP_API(bool, lxcapi_destroy_with_snapshots)
+
 static bool set_config_item_locked(struct lxc_container *c, const char *key, const char *v)
 {
 	struct lxc_config_t *config;
@@ -2127,7 +2251,7 @@ static bool set_config_item_locked(struct lxc_container *c, const char *key, con
 	return do_append_unexp_config_line(c->lxc_conf, key, v);
 }
 
-static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v)
+static bool do_lxcapi_set_config_item(struct lxc_container *c, const char *key, const char *v)
 {
 	bool b = false;
 
@@ -2143,6 +2267,8 @@ static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, con
 	return b;
 }
 
+WRAP_API_2(bool, lxcapi_set_config_item, const char *, const char *)
+
 static char *lxcapi_config_file_name(struct lxc_container *c)
 {
 	if (!c || !c->configfile)
@@ -2190,7 +2316,7 @@ static bool set_config_filename(struct lxc_container *c)
 	return true;
 }
 
-static bool lxcapi_set_config_path(struct lxc_container *c, const char *path)
+static bool do_lxcapi_set_config_path(struct lxc_container *c, const char *path)
 {
 	char *p;
 	bool b = false;
@@ -2228,8 +2354,9 @@ err:
 	return b;
 }
 
+WRAP_API_1(bool, lxcapi_set_config_path, const char *)
 
-static bool lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value)
+static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys, const char *value)
 {
 	int ret;
 
@@ -2248,7 +2375,9 @@ static bool lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys,
 	return ret == 0;
 }
 
-static int lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen)
+WRAP_API_2(bool, lxcapi_set_cgroup_item, const char *, const char *)
+
+static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, char *retv, int inlen)
 {
 	int ret;
 
@@ -2267,6 +2396,8 @@ static int lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, c
 	return ret;
 }
 
+WRAP_API_3(int, lxcapi_get_cgroup_item, const char *, char *, int)
+
 const char *lxc_get_global_config_item(const char *key)
 {
 	return lxc_global_config_value(key);
@@ -2383,7 +2514,7 @@ static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
 		ERROR("Error saving new hooks in clone");
 		return -1;
 	}
-	c->save_config(c, NULL);
+	do_lxcapi_save_config(c, NULL);
 	return 0;
 }
 
@@ -2655,7 +2786,7 @@ static int create_file_dirname(char *path, struct lxc_conf *conf)
 	return ret;
 }
 
-static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *newname,
+static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char *newname,
 		const char *lxcpath, int flags,
 		const char *bdevtype, const char *bdevdata, uint64_t newsize,
 		char **hookargs)
@@ -2668,7 +2799,7 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
 	FILE *fout;
 	pid_t pid;
 
-	if (!c || !c->is_defined(c))
+	if (!c || !do_lxcapi_is_defined(c))
 		return NULL;
 
 	if (container_mem_lock(c))
@@ -2683,7 +2814,7 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
 	if (!newname)
 		newname = c->name;
 	if (!lxcpath)
-		lxcpath = c->get_config_path(c);
+		lxcpath = do_lxcapi_get_config_path(c);
 	ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", lxcpath, newname);
 	if (ret < 0 || ret >= MAXPATHLEN) {
 		SYSERROR("clone: failed making config pathname");
@@ -2812,7 +2943,19 @@ out:
 	return NULL;
 }
 
-static bool lxcapi_rename(struct lxc_container *c, const char *newname)
+static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *newname,
+		const char *lxcpath, int flags,
+		const char *bdevtype, const char *bdevdata, uint64_t newsize,
+		char **hookargs)
+{
+	struct lxc_container * ret;
+	current_config = c ? c->lxc_conf : NULL;
+	ret = do_lxcapi_clone(c, newname, lxcpath, flags, bdevtype, bdevdata, newsize, hookargs);
+	current_config = NULL;
+	return ret;
+}
+
+static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
 {
 	struct bdev *bdev;
 	struct lxc_container *newc;
@@ -2847,15 +2990,23 @@ static bool lxcapi_rename(struct lxc_container *c, const char *newname)
 	return true;
 }
 
+WRAP_API_1(bool, lxcapi_rename, const char *)
+
 static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process)
 {
+	int ret;
+
 	if (!c)
 		return -1;
 
-	return lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process);
+	current_config = c->lxc_conf;
+
+	ret = lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process);
+	current_config = NULL;
+	return ret;
 }
 
-static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
+static int do_lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
 {
 	lxc_attach_command_t command;
 	pid_t pid;
@@ -2874,6 +3025,15 @@ static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t
 	return lxc_wait_for_pid_status(pid);
 }
 
+static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
+{
+	int ret;
+	current_config = c ? c->lxc_conf : NULL;
+	ret = do_lxcapi_attach_run_wait(c, options, program, argv);
+	current_config = NULL;
+	return ret;
+}
+
 static int get_next_index(const char *lxcpath, char *cname)
 {
 	char *fname;
@@ -2917,7 +3077,7 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath)
 	return true;
 }
 
-static int lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
+static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
 {
 	int i, flags, ret;
 	struct lxc_container *c2;
@@ -2959,7 +3119,7 @@ static int lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
 		ERROR("and keep the original container pristine.");
 		flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT;
 	}
-	c2 = c->clone(c, newname, snappath, flags, NULL, NULL, 0, NULL);
+	c2 = do_lxcapi_clone(c, newname, snappath, flags, NULL, NULL, 0, NULL);
 	if (!c2) {
 		ERROR("clone of %s:%s failed", c->config_path, c->name);
 		return -1;
@@ -3007,6 +3167,8 @@ static int lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
 	return i;
 }
 
+WRAP_API_1(int, lxcapi_snapshot, const char *)
+
 static void lxcsnap_free(struct lxc_snapshot *s)
 {
 	free(s->name);
@@ -3061,7 +3223,7 @@ static char *get_timestamp(char* snappath, char *name)
 	return s;
 }
 
-static int lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps)
+static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps)
 {
 	char snappath[MAXPATHLEN], path2[MAXPATHLEN];
 	int count = 0, ret;
@@ -3137,7 +3299,9 @@ out_free:
 	return -1;
 }
 
-static bool lxcapi_snapshot_restore(struct lxc_container *c, const char *snapname, const char *newname)
+WRAP_API_1(int, lxcapi_snapshot_list, struct lxc_snapshot **)
+
+static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snapname, const char *newname)
 {
 	char clonelxcpath[MAXPATHLEN];
 	int flags = 0;
@@ -3198,6 +3362,8 @@ static bool lxcapi_snapshot_restore(struct lxc_container *c, const char *snapnam
 	return b;
 }
 
+WRAP_API_2(bool, lxcapi_snapshot_restore, const char *, const char *)
+
 static bool do_snapshot_destroy(const char *snapname, const char *clonelxcpath)
 {
 	struct lxc_container *snap = NULL;
@@ -3209,7 +3375,7 @@ static bool do_snapshot_destroy(const char *snapname, const char *clonelxcpath)
 		goto err;
 	}
 
-	if (!lxcapi_destroy(snap)) {
+	if (!do_lxcapi_destroy(snap)) {
 		ERROR("Could not destroy snapshot %s", snapname);
 		goto err;
 	}
@@ -3253,7 +3419,7 @@ static bool remove_all_snapshots(const char *path)
 	return bret;
 }
 
-static bool lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname)
+static bool do_lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname)
 {
 	char clonelxcpath[MAXPATHLEN];
 
@@ -3266,7 +3432,9 @@ static bool lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapnam
 	return do_snapshot_destroy(snapname, clonelxcpath);
 }
 
-static bool lxcapi_snapshot_destroy_all(struct lxc_container *c)
+WRAP_API_1(bool, lxcapi_snapshot_destroy, const char *)
+
+static bool do_lxcapi_snapshot_destroy_all(struct lxc_container *c)
 {
 	char clonelxcpath[MAXPATHLEN];
 
@@ -3279,11 +3447,15 @@ static bool lxcapi_snapshot_destroy_all(struct lxc_container *c)
 	return remove_all_snapshots(clonelxcpath);
 }
 
-static bool lxcapi_may_control(struct lxc_container *c)
+WRAP_API(bool, lxcapi_snapshot_destroy_all)
+
+static bool do_lxcapi_may_control(struct lxc_container *c)
 {
 	return lxc_try_cmd(c->name, c->config_path) == 0;
 }
 
+WRAP_API(bool, lxcapi_may_control)
+
 static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
 		struct stat *st)
 {
@@ -3347,7 +3519,7 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
 	const char *p;
 
 	/* make sure container is running */
-	if (!c->is_running(c)) {
+	if (!do_lxcapi_is_running(c)) {
 		ERROR("container is not running");
 		return false;
 	}
@@ -3371,17 +3543,17 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
 	if (ret < 0 || ret >= MAX_BUFFER)
 		return false;
 
-	if (!do_add_remove_node(c->init_pid(c), p, add, &st))
+	if (!do_add_remove_node(do_lxcapi_init_pid(c), p, add, &st))
 		return false;
 
 	/* add or remove device to/from cgroup access list */
 	if (add) {
-		if (!c->set_cgroup_item(c, "devices.allow", value)) {
+		if (!do_lxcapi_set_cgroup_item(c, "devices.allow", value)) {
 			ERROR("set_cgroup_item failed while adding the device node");
 			return false;
 		}
 	} else {
-		if (!c->set_cgroup_item(c, "devices.deny", value)) {
+		if (!do_lxcapi_set_cgroup_item(c, "devices.deny", value)) {
 			ERROR("set_cgroup_item failed while removing the device node");
 			return false;
 		}
@@ -3390,7 +3562,7 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
 	return true;
 }
 
-static bool lxcapi_add_device_node(struct lxc_container *c, const char *src_path, const char *dest_path)
+static bool do_lxcapi_add_device_node(struct lxc_container *c, const char *src_path, const char *dest_path)
 {
 	if (am_unpriv()) {
 		ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
@@ -3399,7 +3571,9 @@ static bool lxcapi_add_device_node(struct lxc_container *c, const char *src_path
 	return add_remove_device_node(c, src_path, dest_path, true);
 }
 
-static bool lxcapi_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path)
+WRAP_API_2(bool, lxcapi_add_device_node, const char *, const char *)
+
+static bool do_lxcapi_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path)
 {
 	if (am_unpriv()) {
 		ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
@@ -3408,7 +3582,9 @@ static bool lxcapi_remove_device_node(struct lxc_container *c, const char *src_p
 	return add_remove_device_node(c, src_path, dest_path, false);
 }
 
-static bool lxcapi_attach_interface(struct lxc_container *c, const char *ifname,
+WRAP_API_2(bool, lxcapi_remove_device_node, const char *, const char *)
+
+static bool do_lxcapi_attach_interface(struct lxc_container *c, const char *ifname,
 				const char *dst_ifname)
 {
 	int ret = 0;
@@ -3431,7 +3607,7 @@ static bool lxcapi_attach_interface(struct lxc_container *c, const char *ifname,
 			goto err;
 	}
 
-	ret = lxc_netdev_move_by_name(ifname, c->init_pid(c), dst_ifname);
+	ret = lxc_netdev_move_by_name(ifname, do_lxcapi_init_pid(c), dst_ifname);
 	if (ret)
 		goto err;
 
@@ -3441,7 +3617,9 @@ err:
 	return false;
 }
 
-static bool lxcapi_detach_interface(struct lxc_container *c, const char *ifname,
+WRAP_API_2(bool, lxcapi_attach_interface, const char *, const char *)
+
+static bool do_lxcapi_detach_interface(struct lxc_container *c, const char *ifname,
 					const char *dst_ifname)
 {
 	pid_t pid, pid_outside;
@@ -3496,6 +3674,8 @@ static bool lxcapi_detach_interface(struct lxc_container *c, const char *ifname,
 	return true;
 }
 
+WRAP_API_2(bool, lxcapi_detach_interface, const char *, const char *)
+
 struct criu_opts {
 	/* The type of criu invocation, one of "dump" or "restore" */
 	char *action;
@@ -3857,7 +4037,7 @@ out:
 	return true;
 }
 
-static bool lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose)
+static bool do_lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose)
 {
 	pid_t pid;
 	int status;
@@ -3902,6 +4082,8 @@ static bool lxcapi_checkpoint(struct lxc_container *c, char *directory, bool sto
 	}
 }
 
+WRAP_API_3(bool, lxcapi_checkpoint, char *, bool, bool)
+
 static bool restore_net_info(struct lxc_container *c)
 {
 	struct lxc_list *it;
@@ -4080,7 +4262,7 @@ out:
 	exit(1);
 }
 
-static bool lxcapi_restore(struct lxc_container *c, char *directory, bool verbose)
+static bool do_lxcapi_restore(struct lxc_container *c, char *directory, bool verbose)
 {
 	pid_t pid;
 	int status, nread;
@@ -4134,6 +4316,8 @@ err_wait:
 	return false;
 }
 
+WRAP_API_2(bool, lxcapi_restore, char *, bool)
+
 static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char *arg, ...)
 {
 	va_list ap;
@@ -4143,18 +4327,23 @@ static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t
 	if (!c)
 		return -1;
 
+	current_config = c->lxc_conf;
+
 	va_start(ap, arg);
 	argv = lxc_va_arg_list_to_argv_const(ap, 1);
 	va_end(ap);
 
 	if (!argv) {
 		ERROR("Memory allocation error.");
-		return -1;
+		ret = -1;
+		goto out;
 	}
 	argv[0] = arg;
 
-	ret = lxcapi_attach_run_wait(c, options, program, (const char * const *)argv);
+	ret = do_lxcapi_attach_run_wait(c, options, program, (const char * const *)argv);
 	free((void*)argv);
+out:
+	current_config = NULL;
 	return ret;
 }
 
@@ -4271,12 +4460,6 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
 	c->checkpoint = lxcapi_checkpoint;
 	c->restore = lxcapi_restore;
 
-	/* we'll allow the caller to update these later */
-	if (lxc_log_init(NULL, "none", NULL, "lxc_container", 0, c->config_path)) {
-		fprintf(stderr, "failed to open log\n");
-		goto err;
-	}
-
 	return c;
 
 err:
@@ -4350,7 +4533,7 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta
 					goto free_bad;
 			continue;
 		}
-		if (!lxcapi_is_defined(c)) {
+		if (!do_lxcapi_is_defined(c)) {
 			INFO("Container %s:%s has a config but is not defined",
 				lxcpath, direntp->d_name);
 			if (names)
diff --git a/src/lxc/start.c b/src/lxc/start.c
index d615375..0f70591 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -212,6 +212,9 @@ restart:
 		if (fd == fddir || fd == lxc_log_fd || fd == fd_to_ignore)
 			continue;
 
+		if (current_config && fd == current_config->logfd)
+			continue;
+
 		if (match_fd(fd))
 			continue;
 
-- 
1.9.1



More information about the lxc-devel mailing list