mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-08 12:18:51 +00:00
logs: introduce a thread-local 'current' lxc_config
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@ubuntu.com> Acked-by: Stéphane Graber <stgraber@ubuntu.com>
This commit is contained in:
parent
0dbb4b2d3d
commit
42e56013ea
@ -248,6 +248,7 @@ endif
|
|||||||
|
|
||||||
init_lxc_static_LDFLAGS = -static
|
init_lxc_static_LDFLAGS = -static
|
||||||
init_lxc_static_LDADD = @CAP_LIBS@
|
init_lxc_static_LDADD = @CAP_LIBS@
|
||||||
|
init_lxc_static_CFLAGS = $(AM_CFLAGS) -DNO_LXC_CONF
|
||||||
endif
|
endif
|
||||||
|
|
||||||
install-exec-local: install-soPROGRAMS
|
install-exec-local: install-soPROGRAMS
|
||||||
|
@ -178,6 +178,17 @@ struct caps_opt {
|
|||||||
int value;
|
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. */
|
/* Declare this here, since we don't want to reshuffle the whole file. */
|
||||||
static int in_caplist(int cap, struct lxc_list *caps);
|
static int in_caplist(int cap, struct lxc_list *caps);
|
||||||
|
|
||||||
@ -2563,6 +2574,7 @@ struct lxc_conf *lxc_conf_init(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
new->kmsg = 0;
|
new->kmsg = 0;
|
||||||
|
new->logfd = -1;
|
||||||
lxc_list_init(&new->cgroup);
|
lxc_list_init(&new->cgroup);
|
||||||
lxc_list_init(&new->network);
|
lxc_list_init(&new->network);
|
||||||
lxc_list_init(&new->mount_list);
|
lxc_list_init(&new->mount_list);
|
||||||
@ -4236,6 +4248,8 @@ void lxc_conf_free(struct lxc_conf *conf)
|
|||||||
free(conf->rootfs.path);
|
free(conf->rootfs.path);
|
||||||
free(conf->rootfs.pivot);
|
free(conf->rootfs.pivot);
|
||||||
free(conf->logfile);
|
free(conf->logfile);
|
||||||
|
if (conf->logfd != -1)
|
||||||
|
close(conf->logfd);
|
||||||
free(conf->utsname);
|
free(conf->utsname);
|
||||||
free(conf->ttydir);
|
free(conf->ttydir);
|
||||||
free(conf->fstab);
|
free(conf->fstab);
|
||||||
|
@ -335,6 +335,7 @@ struct lxc_conf {
|
|||||||
// store the config file specified values here.
|
// store the config file specified values here.
|
||||||
char *logfile; // the logfile as specifed in config
|
char *logfile; // the logfile as specifed in config
|
||||||
int loglevel; // loglevel as specifed in config (if any)
|
int loglevel; // loglevel as specifed in config (if any)
|
||||||
|
int logfd;
|
||||||
|
|
||||||
int inherit_ns_fd[LXC_NS_MAX];
|
int inherit_ns_fd[LXC_NS_MAX];
|
||||||
|
|
||||||
@ -364,6 +365,12 @@ struct lxc_conf {
|
|||||||
char *init_cmd;
|
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,
|
int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
|
||||||
const char *lxcpath, char *argv[]);
|
const char *lxcpath, char *argv[]);
|
||||||
|
|
||||||
|
@ -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,
|
static int config_logfile(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf)
|
struct lxc_conf *c)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
// store these values in the lxc_conf, and then try to set for
|
// store these values in the lxc_conf, and then try to set for
|
||||||
// actual current logging.
|
// actual current logging.
|
||||||
ret = config_path_item(&lxc_conf->logfile, value);
|
ret = config_path_item(&c->logfile, value);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = lxc_log_set_file(lxc_conf->logfile);
|
ret = lxc_log_set_file(&c->logfd, c->logfile);
|
||||||
return ret;
|
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
|
// store these values in the lxc_conf, and then try to set for
|
||||||
// actual current logging.
|
// actual current logging.
|
||||||
lxc_conf->loglevel = newlevel;
|
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,
|
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)
|
else if (strcmp(key, "lxc.se_context") == 0)
|
||||||
v = c->lsm_se_context;
|
v = c->lsm_se_context;
|
||||||
else if (strcmp(key, "lxc.logfile") == 0)
|
else if (strcmp(key, "lxc.logfile") == 0)
|
||||||
v = lxc_log_get_file();
|
v = c->logfile;
|
||||||
else if (strcmp(key, "lxc.loglevel") == 0)
|
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
|
else if (strcmp(key, "lxc.cgroup") == 0) // all cgroup info
|
||||||
return lxc_get_cgroup_entry(c, retv, inlen, "all");
|
return lxc_get_cgroup_entry(c, retv, inlen, "all");
|
||||||
else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info
|
else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info
|
||||||
|
114
src/lxc/log.c
114
src/lxc/log.c
@ -27,6 +27,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
#define __USE_GNU /* for *_CLOEXEC */
|
#define __USE_GNU /* for *_CLOEXEC */
|
||||||
|
|
||||||
@ -40,27 +41,44 @@
|
|||||||
#define LXC_LOG_PREFIX_SIZE 32
|
#define LXC_LOG_PREFIX_SIZE 32
|
||||||
#define LXC_LOG_BUFFER_SIZE 512
|
#define LXC_LOG_BUFFER_SIZE 512
|
||||||
|
|
||||||
#ifdef HAVE_TLS
|
static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
__thread int lxc_log_fd = -1;
|
static void lock_mutex(pthread_mutex_t *l)
|
||||||
static __thread char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
|
{
|
||||||
static __thread char *log_fname = NULL;
|
int ret;
|
||||||
/* command line values for logfile or logpriority should always override
|
|
||||||
* values from the configuration file or defaults
|
if ((ret = pthread_mutex_lock(l)) != 0) {
|
||||||
*/
|
fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
|
||||||
static __thread int lxc_logfile_specified = 0;
|
exit(1);
|
||||||
static __thread int lxc_loglevel_specified = 0;
|
}
|
||||||
static __thread int lxc_quiet_specified = 0;
|
}
|
||||||
#else
|
|
||||||
|
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_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_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
|
||||||
static char *log_fname = NULL;
|
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);
|
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];
|
char buffer[LXC_LOG_BUFFER_SIZE];
|
||||||
int n;
|
int n;
|
||||||
int ms;
|
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;
|
return 0;
|
||||||
|
|
||||||
ms = event->timestamp.tv_usec / 1000;
|
ms = event->timestamp.tv_usec / 1000;
|
||||||
@ -111,7 +138,7 @@ static int log_append_logfile(const struct lxc_log_appender *appender,
|
|||||||
|
|
||||||
buffer[n] = '\n';
|
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 = {
|
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 = {
|
struct lxc_log_category lxc_log_category_lxc = {
|
||||||
.name = "lxc",
|
.name = "lxc",
|
||||||
.priority = LXC_LOG_PRIORITY_ERROR,
|
.priority = LXC_LOG_PRIORITY_ERROR,
|
||||||
.appender = &log_appender_stderr,
|
.appender = &log_appender_logfile,
|
||||||
.parent = &log_root
|
.parent = &log_root
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -305,6 +332,11 @@ static int _lxc_log_set_file(const char *name, const char *lxcpath, int create_d
|
|||||||
return ret;
|
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,
|
extern int lxc_log_init(const char *name, const char *file,
|
||||||
const char *priority, const char *prefix, int quiet,
|
const char *priority, const char *prefix, int quiet,
|
||||||
const char *lxcpath)
|
const char *lxcpath)
|
||||||
@ -320,10 +352,12 @@ extern int lxc_log_init(const char *name, const char *file,
|
|||||||
if (priority)
|
if (priority)
|
||||||
lxc_priority = lxc_log_priority_to_int(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) {
|
if (!lxc_quiet_specified) {
|
||||||
lxc_log_category_lxc.appender = &log_appender_logfile;
|
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
lxc_log_category_lxc.appender->next = &log_appender_stderr;
|
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)
|
if (strcmp(file, "none") == 0)
|
||||||
return 0;
|
return 0;
|
||||||
ret = __lxc_log_set_file(file, 1);
|
ret = __lxc_log_set_file(file, 1);
|
||||||
|
lxc_log_use_global_fd = 1;
|
||||||
} else {
|
} else {
|
||||||
/* if no name was specified, there nothing to do */
|
/* if no name was specified, there nothing to do */
|
||||||
if (!name)
|
if (!name)
|
||||||
@ -385,15 +420,13 @@ extern void lxc_log_close(void)
|
|||||||
* happens after processing command line arguments, which override the .conf
|
* happens after processing command line arguments, which override the .conf
|
||||||
* settings. So only set the level if previously unset.
|
* 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) {
|
if (level < 0 || level >= LXC_LOG_PRIORITY_NOTSET) {
|
||||||
ERROR("invalid log priority %d", level);
|
ERROR("invalid log priority %d", level);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
lxc_log_category_lxc.priority = level;
|
*dest = level;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,11 +448,23 @@ extern bool lxc_log_has_valid_level(void)
|
|||||||
* happens after processing command line arguments, which override the .conf
|
* happens after processing command line arguments, which override the .conf
|
||||||
* settings. So only set the file if previously unset.
|
* 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)
|
if (*fd != -1) {
|
||||||
return 0;
|
close(*fd);
|
||||||
return __lxc_log_set_file(fname, 0);
|
*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)
|
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()
|
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_quiet_specified = 1;
|
||||||
|
lxc_loglevel_specified = 1;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,8 @@
|
|||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "conf.h"
|
||||||
|
|
||||||
#ifndef O_CLOEXEC
|
#ifndef O_CLOEXEC
|
||||||
#define O_CLOEXEC 02000000
|
#define O_CLOEXEC 02000000
|
||||||
#endif
|
#endif
|
||||||
@ -104,6 +106,10 @@ struct lxc_log_category {
|
|||||||
const struct lxc_log_category *parent;
|
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
|
* Returns true if the chained priority is equal to or higher than
|
||||||
* given priority.
|
* given priority.
|
||||||
@ -116,7 +122,14 @@ lxc_log_priority_is_enabled(const struct lxc_log_category* category,
|
|||||||
category->parent)
|
category->parent)
|
||||||
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__); \
|
ERROR("%s - " format, strerror(errno), ##__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#ifdef HAVE_TLS
|
|
||||||
extern __thread int lxc_log_fd;
|
|
||||||
#else
|
|
||||||
extern int lxc_log_fd;
|
extern int lxc_log_fd;
|
||||||
#endif
|
|
||||||
|
|
||||||
extern int lxc_log_init(const char *name, const char *file,
|
extern int lxc_log_init(const char *name, const char *file,
|
||||||
const char *priority, const char *prefix, int quiet,
|
const char *priority, const char *prefix, int quiet,
|
||||||
const char *lxcpath);
|
const char *lxcpath);
|
||||||
|
|
||||||
extern int lxc_log_set_file(const char *fname);
|
extern int lxc_log_set_file(int *fd, const char *fname);
|
||||||
extern int lxc_log_set_level(int level);
|
extern int lxc_log_set_level(int *dest, int level);
|
||||||
extern void lxc_log_set_prefix(const char *prefix);
|
extern void lxc_log_set_prefix(const char *prefix);
|
||||||
extern const char *lxc_log_get_file(void);
|
extern const char *lxc_log_get_file(void);
|
||||||
extern int lxc_log_get_level(void);
|
extern int lxc_log_get_level(void);
|
||||||
|
@ -85,6 +85,15 @@ return -1;
|
|||||||
|
|
||||||
lxc_log_define(lxc_container, lxc);
|
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)
|
static bool config_file_exists(const char *lxcpath, const char *cname)
|
||||||
{
|
{
|
||||||
/* $lxcpath + '/' + $cname + '/config' + \0 */
|
/* $lxcpath + '/' + $cname + '/config' + \0 */
|
||||||
@ -301,7 +310,7 @@ int lxc_container_put(struct lxc_container *c)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lxcapi_is_defined(struct lxc_container *c)
|
static bool do_lxcapi_is_defined(struct lxc_container *c)
|
||||||
{
|
{
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
@ -324,7 +333,53 @@ out:
|
|||||||
return ret;
|
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;
|
lxc_state_t s;
|
||||||
|
|
||||||
@ -334,6 +389,8 @@ static const char *lxcapi_state(struct lxc_container *c)
|
|||||||
return lxc_state2str(s);
|
return lxc_state2str(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API(const char *, lxcapi_state)
|
||||||
|
|
||||||
static bool is_stopped(struct lxc_container *c)
|
static bool is_stopped(struct lxc_container *c)
|
||||||
{
|
{
|
||||||
lxc_state_t s;
|
lxc_state_t s;
|
||||||
@ -341,19 +398,21 @@ static bool is_stopped(struct lxc_container *c)
|
|||||||
return (s == STOPPED);
|
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;
|
const char *s;
|
||||||
|
|
||||||
if (!c)
|
if (!c)
|
||||||
return false;
|
return false;
|
||||||
s = lxcapi_state(c);
|
s = do_lxcapi_state(c);
|
||||||
if (!s || strcmp(s, "STOPPED") == 0)
|
if (!s || strcmp(s, "STOPPED") == 0)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
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;
|
int ret;
|
||||||
if (!c)
|
if (!c)
|
||||||
@ -365,7 +424,9 @@ static bool lxcapi_freeze(struct lxc_container *c)
|
|||||||
return true;
|
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;
|
int ret;
|
||||||
if (!c)
|
if (!c)
|
||||||
@ -377,7 +438,9 @@ static bool lxcapi_unfreeze(struct lxc_container *c)
|
|||||||
return true;
|
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;
|
int ttyfd;
|
||||||
if (!c)
|
if (!c)
|
||||||
@ -387,13 +450,20 @@ static int lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *maste
|
|||||||
return ttyfd;
|
return ttyfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API_2(int, lxcapi_console_getfd, int *, int *)
|
||||||
|
|
||||||
static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
|
static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
|
||||||
int stdoutfd, int stderrfd, int escape)
|
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)
|
if (!c)
|
||||||
return -1;
|
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);
|
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)
|
static bool load_config_locked(struct lxc_container *c, const char *fname)
|
||||||
{
|
{
|
||||||
if (!c->lxc_conf)
|
if (!c->lxc_conf)
|
||||||
@ -412,7 +484,7 @@ static bool load_config_locked(struct lxc_container *c, const char *fname)
|
|||||||
return true;
|
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;
|
bool ret = false, need_disklock = false;
|
||||||
int lret;
|
int lret;
|
||||||
@ -449,7 +521,9 @@ static bool lxcapi_load_config(struct lxc_container *c, const char *alt_file)
|
|||||||
return ret;
|
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)
|
if (!c || !c->lxc_conf)
|
||||||
return false;
|
return false;
|
||||||
@ -462,7 +536,9 @@ static bool lxcapi_want_daemonize(struct lxc_container *c, bool state)
|
|||||||
return true;
|
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)
|
if (!c || !c->lxc_conf)
|
||||||
return false;
|
return false;
|
||||||
@ -475,7 +551,9 @@ static bool lxcapi_want_close_all_fds(struct lxc_container *c, bool state)
|
|||||||
return true;
|
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;
|
int ret;
|
||||||
|
|
||||||
@ -486,8 +564,9 @@ static bool lxcapi_wait(struct lxc_container *c, const char *state, int timeout)
|
|||||||
return ret == 0;
|
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? */
|
/* we'll probably want to make this timeout configurable? */
|
||||||
int timeout = 5, ret, status;
|
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);
|
ret = waitpid(pid, &status, 0);
|
||||||
if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||||
DEBUG("failed waiting for first dual-fork child");
|
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)
|
static bool am_single_threaded(void)
|
||||||
{
|
{
|
||||||
struct dirent dirent, *direntp;
|
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 '...',
|
* 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)
|
* 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;
|
int ret;
|
||||||
struct lxc_conf *conf;
|
struct lxc_conf *conf;
|
||||||
@ -559,7 +640,7 @@ static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv
|
|||||||
}
|
}
|
||||||
if (ret == 2) {
|
if (ret == 2) {
|
||||||
ERROR("Error: %s creation was not completed", c->name);
|
ERROR("Error: %s creation was not completed", c->name);
|
||||||
c->destroy(c);
|
do_lxcapi_destroy(c);
|
||||||
return false;
|
return false;
|
||||||
} else if (ret == 1) {
|
} else if (ret == 1) {
|
||||||
ERROR("Error: creation of %s is ongoing", c->name);
|
ERROR("Error: creation of %s is ongoing", c->name);
|
||||||
@ -702,6 +783,16 @@ out:
|
|||||||
return (ret == 0 ? true : false);
|
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
|
* note there MUST be an ending NULL
|
||||||
*/
|
*/
|
||||||
@ -715,6 +806,9 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
|
|||||||
if (!c)
|
if (!c)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
struct lxc_conf *old = current_config;
|
||||||
|
current_config = c->lxc_conf;
|
||||||
|
|
||||||
va_start(ap, useinit);
|
va_start(ap, useinit);
|
||||||
inargs = lxc_va_arg_list_to_argv(ap, 0, 1);
|
inargs = lxc_va_arg_list_to_argv(ap, 0, 1);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@ -725,7 +819,7 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* pass NULL if no arguments were supplied */
|
/* 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:
|
out:
|
||||||
if (inargs) {
|
if (inargs) {
|
||||||
@ -735,10 +829,11 @@ out:
|
|||||||
free(inargs);
|
free(inargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current_config = old;
|
||||||
return bret;
|
return bret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lxcapi_stop(struct lxc_container *c)
|
static bool do_lxcapi_stop(struct lxc_container *c)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -750,6 +845,8 @@ static bool lxcapi_stop(struct lxc_container *c)
|
|||||||
return ret == 0;
|
return ret == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API(bool, lxcapi_stop)
|
||||||
|
|
||||||
static int do_create_container_dir(const char *path, struct lxc_conf *conf)
|
static int do_create_container_dir(const char *path, struct lxc_conf *conf)
|
||||||
{
|
{
|
||||||
int ret = -1, lasterr;
|
int ret = -1, lasterr;
|
||||||
@ -797,9 +894,6 @@ static bool create_container_dir(struct lxc_container *c)
|
|||||||
return ret == 0;
|
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(),
|
* do_bdev_create: thin wrapper around bdev_create(). Like bdev_create(),
|
||||||
* it returns a mounted bdev on success, NULL on error.
|
* 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);
|
dest = alloca(len);
|
||||||
ret = snprintf(dest, len, "%s", rpath);
|
ret = snprintf(dest, len, "%s", rpath);
|
||||||
} else {
|
} 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;
|
len = strlen(c->name) + strlen(lxcpath) + 9;
|
||||||
dest = alloca(len);
|
dest = alloca(len);
|
||||||
ret = snprintf(dest, len, "%s/%s/rootfs", lxcpath, c->name);
|
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;
|
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
|
/* if we are not root, chown the rootfs dir to root in the
|
||||||
* target uidmap */
|
* target uidmap */
|
||||||
@ -1210,9 +1304,8 @@ static void lxcapi_clear_config(struct lxc_container *c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool lxcapi_destroy(struct lxc_container *c);
|
#define do_lxcapi_clear_config(c) lxcapi_clear_config(c)
|
||||||
static bool container_destroy(struct lxc_container *c);
|
|
||||||
static bool get_snappath_dir(struct lxc_container *c, char *snappath);
|
|
||||||
/*
|
/*
|
||||||
* lxcapi_create:
|
* lxcapi_create:
|
||||||
* create a container with the given parameters.
|
* 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
|
* @argv: the arguments to pass to the template, terminated by NULL. If no
|
||||||
* arguments, you can just pass NULL.
|
* 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,
|
const char *bdevtype, struct bdev_specs *specs, int flags,
|
||||||
char *const argv[])
|
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
|
* an existing container. Return an error, but do NOT delete the
|
||||||
* container.
|
* 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) {
|
access(c->lxc_conf->rootfs.path, F_OK) == 0 && tpath) {
|
||||||
ERROR("Container %s:%s already exists", c->config_path, c->name);
|
ERROR("Container %s:%s already exists", c->config_path, c->name);
|
||||||
goto free_tpath;
|
goto free_tpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c->lxc_conf) {
|
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"));
|
ERROR("Error loading default configuration file %s", lxc_global_config_value("lxc.default_config"));
|
||||||
goto free_tpath;
|
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)
|
if (c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) != 0)
|
||||||
/* rootfs passed into configuration, but does not exist: error */
|
/* rootfs passed into configuration, but does not exist: error */
|
||||||
goto out;
|
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
|
/* Rootfs already existed, user just wanted to save the
|
||||||
* loaded configuration */
|
* loaded configuration */
|
||||||
ret = true;
|
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 */
|
/* 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);
|
ERROR("failed to save starting configuration for %s", c->name);
|
||||||
// parent task won't see bdev in config so we delete it
|
// parent task won't see bdev in config so we delete it
|
||||||
bdev->ops->umount(bdev);
|
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
|
// now clear out the lxc_conf we have, reload from the created
|
||||||
// container
|
// container
|
||||||
lxcapi_clear_config(c);
|
do_lxcapi_clear_config(c);
|
||||||
|
|
||||||
if (t) {
|
if (t) {
|
||||||
if (!prepend_lxc_header(c->configfile, tpath, argv)) {
|
if (!prepend_lxc_header(c->configfile, tpath, argv)) {
|
||||||
@ -1360,16 +1453,28 @@ free_tpath:
|
|||||||
return ret;
|
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;
|
pid_t pid;
|
||||||
int rebootsignal = SIGINT;
|
int rebootsignal = SIGINT;
|
||||||
|
|
||||||
if (!c)
|
if (!c)
|
||||||
return false;
|
return false;
|
||||||
if (!c->is_running(c))
|
if (!do_lxcapi_is_running(c))
|
||||||
return false;
|
return false;
|
||||||
pid = c->init_pid(c);
|
pid = do_lxcapi_init_pid(c);
|
||||||
if (pid <= 0)
|
if (pid <= 0)
|
||||||
return false;
|
return false;
|
||||||
if (c->lxc_conf && c->lxc_conf->rebootsignal)
|
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;
|
bool retv;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
@ -1389,18 +1496,20 @@ static bool lxcapi_shutdown(struct lxc_container *c, int timeout)
|
|||||||
if (!c)
|
if (!c)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!c->is_running(c))
|
if (!do_lxcapi_is_running(c))
|
||||||
return true;
|
return true;
|
||||||
pid = c->init_pid(c);
|
pid = do_lxcapi_init_pid(c);
|
||||||
if (pid <= 0)
|
if (pid <= 0)
|
||||||
return true;
|
return true;
|
||||||
if (c->lxc_conf && c->lxc_conf->haltsignal)
|
if (c->lxc_conf && c->lxc_conf->haltsignal)
|
||||||
haltsignal = c->lxc_conf->haltsignal;
|
haltsignal = c->lxc_conf->haltsignal;
|
||||||
kill(pid, haltsignal);
|
kill(pid, haltsignal);
|
||||||
retv = c->wait(c, "STOPPED", timeout);
|
retv = do_lxcapi_wait(c, "STOPPED", timeout);
|
||||||
return retv;
|
return retv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API_1(bool, lxcapi_shutdown, int)
|
||||||
|
|
||||||
static bool lxcapi_createl(struct lxc_container *c, const char *t,
|
static bool lxcapi_createl(struct lxc_container *c, const char *t,
|
||||||
const char *bdevtype, struct bdev_specs *specs, int flags, ...)
|
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)
|
if (!c)
|
||||||
return false;
|
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
|
* since we're going to wait for create to finish, I don't think we
|
||||||
* need to get a copy of the arguments.
|
* 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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bret = c->create(c, t, bdevtype, specs, flags, args);
|
bret = do_lxcapi_create(c, t, bdevtype, specs, flags, args);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free(args);
|
free(args);
|
||||||
|
current_config = old;
|
||||||
return bret;
|
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);
|
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;
|
int ret;
|
||||||
|
|
||||||
@ -1459,9 +1572,11 @@ static bool lxcapi_clear_config_item(struct lxc_container *c, const char *key)
|
|||||||
return ret == 0;
|
return ret == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API_1(bool, lxcapi_clear_config_item, const char *)
|
||||||
|
|
||||||
static inline bool enter_net_ns(struct lxc_container *c)
|
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 ((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"))
|
if (!switch_to_ns(pid, "user"))
|
||||||
@ -1541,7 +1656,7 @@ static bool remove_from_array(char ***names, char *cname, int size)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char** lxcapi_get_interfaces(struct lxc_container *c)
|
static char ** do_lxcapi_get_interfaces(struct lxc_container *c)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int i, count = 0, pipefd[2];
|
int i, count = 0, pipefd[2];
|
||||||
@ -1628,7 +1743,9 @@ static char** lxcapi_get_interfaces(struct lxc_container *c)
|
|||||||
return interfaces;
|
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;
|
pid_t pid;
|
||||||
int i, count = 0, pipefd[2];
|
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;
|
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;
|
int ret;
|
||||||
|
|
||||||
@ -1758,7 +1877,9 @@ static int lxcapi_get_config_item(struct lxc_container *c, const char *key, char
|
|||||||
return ret;
|
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;
|
char *ret;
|
||||||
|
|
||||||
@ -1766,12 +1887,14 @@ static char* lxcapi_get_running_config_item(struct lxc_container *c, const char
|
|||||||
return NULL;
|
return NULL;
|
||||||
if (container_mem_lock(c))
|
if (container_mem_lock(c))
|
||||||
return NULL;
|
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);
|
container_mem_unlock(c);
|
||||||
return ret;
|
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)
|
if (!key)
|
||||||
return lxc_listconfigs(retv, inlen);
|
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;
|
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;
|
FILE *fout;
|
||||||
bool ret = false, need_disklock = false;
|
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 we haven't yet loaded a config, load the stock config
|
||||||
if (!c->lxc_conf) {
|
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);
|
ERROR("Error loading default configuration file %s while saving %s", lxc_global_config_value("lxc.default_config"), c->name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1844,6 +1969,8 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API_1(bool, lxcapi_save_config, const char *)
|
||||||
|
|
||||||
static bool mod_rdep(struct lxc_container *c, bool inc)
|
static bool mod_rdep(struct lxc_container *c, bool inc)
|
||||||
{
|
{
|
||||||
char path[MAXPATHLEN];
|
char path[MAXPATHLEN];
|
||||||
@ -2032,7 +2159,7 @@ static bool container_destroy(struct lxc_container *c)
|
|||||||
bool bret = false;
|
bool bret = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!c || !lxcapi_is_defined(c))
|
if (!c || !do_lxcapi_is_defined(c))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (container_disk_lock(c))
|
if (container_disk_lock(c))
|
||||||
@ -2057,7 +2184,7 @@ static bool container_destroy(struct lxc_container *c)
|
|||||||
|
|
||||||
mod_all_rdeps(c, false);
|
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);
|
char *path = alloca(strlen(p1) + strlen(c->name) + 2);
|
||||||
sprintf(path, "%s/%s", p1, c->name);
|
sprintf(path, "%s/%s", p1, c->name);
|
||||||
if (am_unpriv())
|
if (am_unpriv())
|
||||||
@ -2075,7 +2202,7 @@ out:
|
|||||||
return bret;
|
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))
|
if (!c || !lxcapi_is_defined(c))
|
||||||
return false;
|
return false;
|
||||||
@ -2092,9 +2219,9 @@ static bool lxcapi_destroy(struct lxc_container *c)
|
|||||||
return container_destroy(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))
|
if (!c || !lxcapi_is_defined(c))
|
||||||
return false;
|
return false;
|
||||||
@ -2105,6 +2232,8 @@ static bool lxcapi_destroy_with_snapshots(struct lxc_container *c)
|
|||||||
return lxcapi_destroy(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)
|
static bool set_config_item_locked(struct lxc_container *c, const char *key, const char *v)
|
||||||
{
|
{
|
||||||
struct lxc_config_t *config;
|
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);
|
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;
|
bool b = false;
|
||||||
|
|
||||||
@ -2137,6 +2266,8 @@ static bool lxcapi_set_config_item(struct lxc_container *c, const char *key, con
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API_2(bool, lxcapi_set_config_item, const char *, const char *)
|
||||||
|
|
||||||
static char *lxcapi_config_file_name(struct lxc_container *c)
|
static char *lxcapi_config_file_name(struct lxc_container *c)
|
||||||
{
|
{
|
||||||
if (!c || !c->configfile)
|
if (!c || !c->configfile)
|
||||||
@ -2184,7 +2315,7 @@ static bool set_config_filename(struct lxc_container *c)
|
|||||||
return true;
|
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;
|
char *p;
|
||||||
bool b = false;
|
bool b = false;
|
||||||
@ -2222,8 +2353,9 @@ err:
|
|||||||
return b;
|
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;
|
int ret;
|
||||||
|
|
||||||
@ -2242,7 +2374,9 @@ static bool lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsys,
|
|||||||
return ret == 0;
|
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;
|
int ret;
|
||||||
|
|
||||||
@ -2261,6 +2395,8 @@ static int lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys, c
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API_3(int, lxcapi_get_cgroup_item, const char *, char *, int)
|
||||||
|
|
||||||
const char *lxc_get_global_config_item(const char *key)
|
const char *lxc_get_global_config_item(const char *key)
|
||||||
{
|
{
|
||||||
return lxc_global_config_value(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");
|
ERROR("Error saving new hooks in clone");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
c->save_config(c, NULL);
|
do_lxcapi_save_config(c, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2649,7 +2785,7 @@ static int create_file_dirname(char *path, struct lxc_conf *conf)
|
|||||||
return ret;
|
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 *lxcpath, int flags,
|
||||||
const char *bdevtype, const char *bdevdata, uint64_t newsize,
|
const char *bdevtype, const char *bdevdata, uint64_t newsize,
|
||||||
char **hookargs)
|
char **hookargs)
|
||||||
@ -2662,7 +2798,7 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
|
|||||||
FILE *fout;
|
FILE *fout;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
if (!c || !c->is_defined(c))
|
if (!c || !do_lxcapi_is_defined(c))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (container_mem_lock(c))
|
if (container_mem_lock(c))
|
||||||
@ -2677,7 +2813,7 @@ static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *n
|
|||||||
if (!newname)
|
if (!newname)
|
||||||
newname = c->name;
|
newname = c->name;
|
||||||
if (!lxcpath)
|
if (!lxcpath)
|
||||||
lxcpath = c->get_config_path(c);
|
lxcpath = do_lxcapi_get_config_path(c);
|
||||||
ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", lxcpath, newname);
|
ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", lxcpath, newname);
|
||||||
if (ret < 0 || ret >= MAXPATHLEN) {
|
if (ret < 0 || ret >= MAXPATHLEN) {
|
||||||
SYSERROR("clone: failed making config pathname");
|
SYSERROR("clone: failed making config pathname");
|
||||||
@ -2806,7 +2942,20 @@ out:
|
|||||||
return NULL;
|
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 bdev *bdev;
|
||||||
struct lxc_container *newc;
|
struct lxc_container *newc;
|
||||||
@ -2841,15 +2990,24 @@ static bool lxcapi_rename(struct lxc_container *c, const char *newname)
|
|||||||
return true;
|
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)
|
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)
|
if (!c)
|
||||||
return -1;
|
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;
|
lxc_attach_command_t command;
|
||||||
pid_t pid;
|
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);
|
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)
|
static int get_next_index(const char *lxcpath, char *cname)
|
||||||
{
|
{
|
||||||
char *fname;
|
char *fname;
|
||||||
@ -2911,7 +3079,7 @@ static bool get_snappath_dir(struct lxc_container *c, char *snappath)
|
|||||||
return true;
|
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;
|
int i, flags, ret;
|
||||||
struct lxc_container *c2;
|
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.");
|
ERROR("and keep the original container pristine.");
|
||||||
flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT;
|
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) {
|
if (!c2) {
|
||||||
ERROR("clone of %s:%s failed", c->config_path, c->name);
|
ERROR("clone of %s:%s failed", c->config_path, c->name);
|
||||||
return -1;
|
return -1;
|
||||||
@ -3001,6 +3169,8 @@ static int lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API_1(int, lxcapi_snapshot, const char *)
|
||||||
|
|
||||||
static void lxcsnap_free(struct lxc_snapshot *s)
|
static void lxcsnap_free(struct lxc_snapshot *s)
|
||||||
{
|
{
|
||||||
free(s->name);
|
free(s->name);
|
||||||
@ -3055,7 +3225,7 @@ static char *get_timestamp(char* snappath, char *name)
|
|||||||
return s;
|
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];
|
char snappath[MAXPATHLEN], path2[MAXPATHLEN];
|
||||||
int count = 0, ret;
|
int count = 0, ret;
|
||||||
@ -3131,7 +3301,9 @@ out_free:
|
|||||||
return -1;
|
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];
|
char clonelxcpath[MAXPATHLEN];
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
@ -3192,6 +3364,8 @@ static bool lxcapi_snapshot_restore(struct lxc_container *c, const char *snapnam
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API_2(bool, lxcapi_snapshot_restore, const char *, const char *)
|
||||||
|
|
||||||
static bool do_snapshot_destroy(const char *snapname, const char *clonelxcpath)
|
static bool do_snapshot_destroy(const char *snapname, const char *clonelxcpath)
|
||||||
{
|
{
|
||||||
struct lxc_container *snap = NULL;
|
struct lxc_container *snap = NULL;
|
||||||
@ -3203,7 +3377,7 @@ static bool do_snapshot_destroy(const char *snapname, const char *clonelxcpath)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lxcapi_destroy(snap)) {
|
if (!do_lxcapi_destroy(snap)) {
|
||||||
ERROR("Could not destroy snapshot %s", snapname);
|
ERROR("Could not destroy snapshot %s", snapname);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -3247,7 +3421,7 @@ static bool remove_all_snapshots(const char *path)
|
|||||||
return bret;
|
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];
|
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);
|
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];
|
char clonelxcpath[MAXPATHLEN];
|
||||||
|
|
||||||
@ -3273,11 +3449,15 @@ static bool lxcapi_snapshot_destroy_all(struct lxc_container *c)
|
|||||||
return remove_all_snapshots(clonelxcpath);
|
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;
|
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,
|
static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
|
||||||
struct stat *st)
|
struct stat *st)
|
||||||
{
|
{
|
||||||
@ -3341,7 +3521,7 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
|
|||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
/* make sure container is running */
|
/* make sure container is running */
|
||||||
if (!c->is_running(c)) {
|
if (!do_lxcapi_is_running(c)) {
|
||||||
ERROR("container is not running");
|
ERROR("container is not running");
|
||||||
return false;
|
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)
|
if (ret < 0 || ret >= MAX_BUFFER)
|
||||||
return false;
|
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;
|
return false;
|
||||||
|
|
||||||
/* add or remove device to/from cgroup access list */
|
/* add or remove device to/from cgroup access list */
|
||||||
if (add) {
|
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");
|
ERROR("set_cgroup_item failed while adding the device node");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} 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");
|
ERROR("set_cgroup_item failed while removing the device node");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3384,7 +3564,7 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
|
|||||||
return true;
|
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()) {
|
if (am_unpriv()) {
|
||||||
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
|
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);
|
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()) {
|
if (am_unpriv()) {
|
||||||
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
|
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);
|
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)
|
const char *dst_ifname)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -3425,7 +3609,7 @@ static bool lxcapi_attach_interface(struct lxc_container *c, const char *ifname,
|
|||||||
goto err;
|
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)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@ -3435,7 +3619,9 @@ err:
|
|||||||
return false;
|
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)
|
const char *dst_ifname)
|
||||||
{
|
{
|
||||||
pid_t pid, pid_outside;
|
pid_t pid, pid_outside;
|
||||||
@ -3490,6 +3676,8 @@ static bool lxcapi_detach_interface(struct lxc_container *c, const char *ifname,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WRAP_API_2(bool, lxcapi_detach_interface, const char *, const char *)
|
||||||
|
|
||||||
struct criu_opts {
|
struct criu_opts {
|
||||||
/* The type of criu invocation, one of "dump" or "restore" */
|
/* The type of criu invocation, one of "dump" or "restore" */
|
||||||
char *action;
|
char *action;
|
||||||
@ -3781,7 +3969,7 @@ out:
|
|||||||
return true;
|
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;
|
pid_t pid;
|
||||||
int status;
|
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)
|
static bool restore_net_info(struct lxc_container *c)
|
||||||
{
|
{
|
||||||
struct lxc_list *it;
|
struct lxc_list *it;
|
||||||
@ -3853,7 +4043,7 @@ out_unlock:
|
|||||||
return !has_error;
|
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;
|
pid_t pid;
|
||||||
struct lxc_rootfs *rootfs;
|
struct lxc_rootfs *rootfs;
|
||||||
@ -3982,6 +4172,8 @@ out_fini_handler:
|
|||||||
return !has_error;
|
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, ...)
|
static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char *arg, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@ -3991,18 +4183,24 @@ static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t
|
|||||||
if (!c)
|
if (!c)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
struct lxc_conf *old = current_config;
|
||||||
|
current_config = c->lxc_conf;
|
||||||
|
|
||||||
va_start(ap, arg);
|
va_start(ap, arg);
|
||||||
argv = lxc_va_arg_list_to_argv_const(ap, 1);
|
argv = lxc_va_arg_list_to_argv_const(ap, 1);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
if (!argv) {
|
if (!argv) {
|
||||||
ERROR("Memory allocation error.");
|
ERROR("Memory allocation error.");
|
||||||
return -1;
|
ret = -1;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
argv[0] = arg;
|
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);
|
free((void*)argv);
|
||||||
|
out:
|
||||||
|
current_config = old;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4119,12 +4317,6 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
|
|||||||
c->checkpoint = lxcapi_checkpoint;
|
c->checkpoint = lxcapi_checkpoint;
|
||||||
c->restore = lxcapi_restore;
|
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;
|
return c;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@ -4198,7 +4390,7 @@ int list_defined_containers(const char *lxcpath, char ***names, struct lxc_conta
|
|||||||
goto free_bad;
|
goto free_bad;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!lxcapi_is_defined(c)) {
|
if (!do_lxcapi_is_defined(c)) {
|
||||||
INFO("Container %s:%s has a config but is not defined",
|
INFO("Container %s:%s has a config but is not defined",
|
||||||
lxcpath, direntp->d_name);
|
lxcpath, direntp->d_name);
|
||||||
if (names)
|
if (names)
|
||||||
|
Loading…
Reference in New Issue
Block a user