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

Stéphane Graber stgraber at ubuntu.com
Wed Apr 22 16:38:06 UTC 2015


On Tue, Apr 21, 2015 at 08:09:12PM +0000, Serge Hallyn wrote:
> 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.
> 

Let's try that again :)

Acked-by: Stéphane Graber <stgraber at ubuntu.com>

> 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
> 
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20150422/ae543b2c/attachment-0001.sig>


More information about the lxc-devel mailing list