[lxc-devel] [PATCH 1/1] logs: introduce a thread-local 'current' lxc_config

S.Çağlar Onur caglar at 10ur.org
Mon Apr 6 16:24:46 UTC 2015


On Mon, Apr 6, 2015 at 11:48 AM, Stéphane Graber <stgraber at ubuntu.com> wrote:
> On Wed, Mar 11, 2015 at 10:10:55PM +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.
>>
>> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
>
> Haven't heard back from Caglar, but given the scope of this, I think the
> best way to shake any bug out is to just merge it and use it.

Oh I'm so sorry! I thought I sent my Ack to the list but looks like I didn't.

It worked fine for me when I tested ~2 weeks ago

Acked-and-Tested-by: S.Çağlar Onur <caglar at 10ur.org>

> Acked-by: Stéphane Graber <stgraber at ubuntu.com>
>
>> ---
>>  src/lxc/Makefile.am    |   1 +
>>  src/lxc/conf.c         |  14 ++
>>  src/lxc/conf.h         |   7 +
>>  src/lxc/confile.c      |  12 +-
>>  src/lxc/log.c          | 114 ++++++++++-----
>>  src/lxc/log.h          |  23 ++-
>>  src/lxc/lxccontainer.c | 382 +++++++++++++++++++++++++++++++++++++------------
>>  7 files changed, 408 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 2868708..9a58ee0 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);
>>
>> @@ -2563,6 +2574,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);
>> @@ -4230,6 +4242,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 334ea70..ae475ed 100644
>> --- a/src/lxc/conf.h
>> +++ b/src/lxc/conf.h
>> @@ -335,6 +335,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];
>>
>> @@ -364,6 +365,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..04ba2cc 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,44 @@
>>  #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
>> +static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
>> +static void lock_mutex(pthread_mutex_t *l)
>> +{
>> +     int ret;
>> +
>> +     if ((ret = pthread_mutex_lock(l)) != 0) {
>> +             fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
>> +             exit(1);
>> +     }
>> +}
>> +
>> +static void unlock_mutex(pthread_mutex_t *l)
>> +{
>> +     int ret;
>> +
>> +     if ((ret = pthread_mutex_unlock(l)) != 0) {
>> +             fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret));
>> +             exit(1);
>> +     }
>> +}
>> +
>> +void log_lock(void)
>> +{
>> +     lock_mutex(&log_mutex);
>> +}
>> +
>> +void log_unlock(void)
>> +{
>> +     unlock_mutex(&log_mutex);
>> +}
>> +
>>  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 +103,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 +138,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 +163,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 +332,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 +352,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 +369,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 +420,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 +448,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 +485,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 4422f4a..1eadc63 100644
>> --- a/src/lxc/lxccontainer.c
>> +++ b/src/lxc/lxccontainer.c
>> @@ -85,6 +85,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 */
>> @@ -301,7 +310,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;
>> @@ -324,7 +333,53 @@ 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;                                                    \
>> +     struct lxc_conf *old = current_config;                          \
>> +     current_config = c ? c->lxc_conf : NULL;                        \
>> +     ret = do_##fnname(c);                                           \
>> +     current_config = old;                                           \
>> +     return ret;                                                     \
>> +}
>> +
>> +#define WRAP_API_1(rettype, fnname, t1)                                      \
>> +static rettype fnname(struct lxc_container *c, t1 a1)                        \
>> +{                                                                    \
>> +     rettype ret;                                                    \
>> +     struct lxc_conf *old = current_config;                          \
>> +     current_config = c ? c->lxc_conf : NULL;                        \
>> +     ret = do_##fnname(c, a1);                                       \
>> +     current_config = old;                                           \
>> +     return ret;                                                     \
>> +}
>> +
>> +#define WRAP_API_2(rettype, fnname, t1, t2)                          \
>> +static rettype fnname(struct lxc_container *c, t1 a1, t2 a2)         \
>> +{                                                                    \
>> +     rettype ret;                                                    \
>> +     struct lxc_conf *old = current_config;                          \
>> +     current_config = c ? c->lxc_conf : NULL;                        \
>> +     ret = do_##fnname(c, a1, a2);                                   \
>> +     current_config = old;                                           \
>> +     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;                                                    \
>> +     struct lxc_conf *old = current_config;                          \
>> +     current_config = c ? c->lxc_conf : NULL;                        \
>> +     ret = do_##fnname(c, a1, a2, a3);                               \
>> +     current_config = old;                                           \
>> +     return ret;                                                     \
>> +}
>> +
>> +WRAP_API(bool, lxcapi_is_defined)
>> +
>> +static const char *do_lxcapi_state(struct lxc_container *c)
>>  {
>>       lxc_state_t s;
>>
>> @@ -334,6 +389,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;
>> @@ -341,19 +398,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)
>> @@ -365,7 +424,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)
>> @@ -377,7 +438,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)
>> @@ -387,13 +450,20 @@ 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;
>> +     struct lxc_conf *old = current_config;
>> +     current_config = c ? c->lxc_conf : NULL;
>> +     ret = lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape);
>> +     current_config = old;
>> +     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;
>> @@ -401,6 +471,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)
>> @@ -412,7 +484,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;
>> @@ -449,7 +521,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;
>> @@ -462,7 +536,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;
>> @@ -475,7 +551,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;
>>
>> @@ -486,8 +564,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;
>> @@ -499,9 +578,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;
>> @@ -534,7 +615,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;
>> @@ -559,7 +640,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);
>> @@ -702,6 +783,16 @@ out:
>>               return (ret == 0 ? true : false);
>>  }
>>
>> +static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[])
>> +{
>> +     bool ret;
>> +     struct lxc_conf *old = current_config;
>> +     current_config = c ? c->lxc_conf : NULL;
>> +     ret = do_lxcapi_start(c, useinit, argv);
>> +     current_config = old;
>> +     return ret;
>> +}
>> +
>>  /*
>>   * note there MUST be an ending NULL
>>   */
>> @@ -715,6 +806,9 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
>>       if (!c)
>>               return false;
>>
>> +     struct lxc_conf *old = current_config;
>> +     current_config = c->lxc_conf;
>> +
>>       va_start(ap, useinit);
>>       inargs = lxc_va_arg_list_to_argv(ap, 0, 1);
>>       va_end(ap);
>> @@ -725,7 +819,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) {
>> @@ -735,10 +829,11 @@ out:
>>               free(inargs);
>>       }
>>
>> +     current_config = old;
>>       return bret;
>>  }
>>
>> -static bool lxcapi_stop(struct lxc_container *c)
>> +static bool do_lxcapi_stop(struct lxc_container *c)
>>  {
>>       int ret;
>>
>> @@ -750,6 +845,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;
>> @@ -797,9 +894,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.
>> @@ -819,7 +913,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);
>> @@ -833,7 +927,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 */
>> @@ -1210,9 +1304,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.
>> @@ -1227,7 +1320,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[])
>>  {
>> @@ -1253,14 +1346,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;
>>               }
>> @@ -1280,7 +1373,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;
>> @@ -1316,7 +1409,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);
>> @@ -1339,7 +1432,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)) {
>> @@ -1360,16 +1453,28 @@ 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;
>> +     struct lxc_conf *old = current_config;
>> +     current_config = c ? c->lxc_conf : NULL;
>> +     ret = do_lxcapi_create(c, t, bdevtype, specs, flags, argv);
>> +     current_config = old;
>> +     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)
>> @@ -1380,7 +1485,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;
>> @@ -1389,18 +1496,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, ...)
>>  {
>> @@ -1411,6 +1520,9 @@ static bool lxcapi_createl(struct lxc_container *c, const char *t,
>>       if (!c)
>>               return false;
>>
>> +     struct lxc_conf *old = current_config;
>> +     current_config = c ? c->lxc_conf : NULL;
>> +
>>       /*
>>        * since we're going to wait for create to finish, I don't think we
>>        * need to get a copy of the arguments.
>> @@ -1423,10 +1535,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 = old;
>>       return bret;
>>  }
>>
>> @@ -1444,7 +1557,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;
>>
>> @@ -1459,9 +1572,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"))
>> @@ -1541,7 +1656,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];
>> @@ -1628,7 +1743,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];
>> @@ -1745,7 +1862,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;
>>
>> @@ -1758,7 +1877,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;
>>
>> @@ -1766,12 +1887,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);
>> @@ -1791,7 +1914,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;
>> @@ -1804,7 +1929,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;
>>               }
>> @@ -1844,6 +1969,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];
>> @@ -2032,7 +2159,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))
>> @@ -2057,7 +2184,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())
>> @@ -2075,7 +2202,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;
>> @@ -2092,9 +2219,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;
>> @@ -2105,6 +2232,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;
>> @@ -2121,7 +2250,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;
>>
>> @@ -2137,6 +2266,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)
>> @@ -2184,7 +2315,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;
>> @@ -2222,8 +2353,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;
>>
>> @@ -2242,7 +2374,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;
>>
>> @@ -2261,6 +2395,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);
>> @@ -2377,7 +2513,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;
>>  }
>>
>> @@ -2649,7 +2785,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)
>> @@ -2662,7 +2798,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))
>> @@ -2677,7 +2813,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");
>> @@ -2806,7 +2942,20 @@ 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;
>> +     struct lxc_conf *old = current_config;
>> +     current_config = c ? c->lxc_conf : NULL;
>> +     ret = do_lxcapi_clone(c, newname, lxcpath, flags, bdevtype, bdevdata, newsize, hookargs);
>> +     current_config = old;
>> +     return ret;
>> +}
>> +
>> +static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
>>  {
>>       struct bdev *bdev;
>>       struct lxc_container *newc;
>> @@ -2841,15 +2990,24 @@ 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)
>>  {
>> +     struct lxc_conf *old = current_config;
>> +     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 = old;
>> +     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;
>> @@ -2868,6 +3026,16 @@ 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;
>> +     struct lxc_conf *old = current_config;
>> +     current_config = c ? c->lxc_conf : NULL;
>> +     ret = do_lxcapi_attach_run_wait(c, options, program, argv);
>> +     current_config = old;
>> +     return ret;
>> +}
>> +
>>  static int get_next_index(const char *lxcpath, char *cname)
>>  {
>>       char *fname;
>> @@ -2911,7 +3079,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;
>> @@ -2953,7 +3121,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;
>> @@ -3001,6 +3169,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);
>> @@ -3055,7 +3225,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;
>> @@ -3131,7 +3301,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;
>> @@ -3192,6 +3364,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;
>> @@ -3203,7 +3377,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;
>>       }
>> @@ -3247,7 +3421,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];
>>
>> @@ -3260,7 +3434,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];
>>
>> @@ -3273,11 +3449,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)
>>  {
>> @@ -3341,7 +3521,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;
>>       }
>> @@ -3365,17 +3545,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;
>>               }
>> @@ -3384,7 +3564,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__);
>> @@ -3393,7 +3573,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__);
>> @@ -3402,7 +3584,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;
>> @@ -3425,7 +3609,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;
>>
>> @@ -3435,7 +3619,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;
>> @@ -3490,6 +3676,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;
>> @@ -3781,7 +3969,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;
>> @@ -3826,6 +4014,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;
>> @@ -3853,7 +4043,7 @@ out_unlock:
>>       return !has_error;
>>  }
>>
>> -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;
>>       struct lxc_rootfs *rootfs;
>> @@ -3982,6 +4172,8 @@ out_fini_handler:
>>       return !has_error;
>>  }
>>
>> +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;
>> @@ -3991,18 +4183,24 @@ static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t
>>       if (!c)
>>               return -1;
>>
>> +     struct lxc_conf *old = current_config;
>> +     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 = old;
>>       return ret;
>>  }
>>
>> @@ -4119,12 +4317,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:
>> @@ -4198,7 +4390,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)
>> --
>> 2.1.4
>>
>> _______________________________________________
>> 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
>
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel
>



-- 
S.Çağlar Onur <caglar at 10ur.org>


More information about the lxc-devel mailing list