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 */
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;
return ret;
}
-static const char *lxcapi_state(struct lxc_container *c)
+#define WRAP_API(rettype, fnname) \
+static rettype fnname(struct lxc_container *c) \
+{ \
+ rettype ret; \
+ current_config = c ? c->lxc_conf : NULL; \
+ ret = do_##fnname(c); \
+ current_config = NULL; \
+ return ret; \
+}
+
+#define WRAP_API_1(rettype, fnname, t1) \
+static rettype fnname(struct lxc_container *c, t1 a1) \
+{ \
+ rettype ret; \
+ current_config = c ? c->lxc_conf : NULL; \
+ ret = do_##fnname(c, a1); \
+ current_config = NULL; \
+ return ret; \
+}
+
+#define WRAP_API_2(rettype, fnname, t1, t2) \
+static rettype fnname(struct lxc_container *c, t1 a1, t2 a2) \
+{ \
+ rettype ret; \
+ current_config = c ? c->lxc_conf : NULL; \
+ ret = do_##fnname(c, a1, a2); \
+ current_config = NULL; \
+ return ret; \
+}
+
+#define WRAP_API_3(rettype, fnname, t1, t2, t3) \
+static rettype fnname(struct lxc_container *c, t1 a1, t2 a2, t3 a3) \
+{ \
+ rettype ret; \
+ current_config = c ? c->lxc_conf : NULL; \
+ ret = do_##fnname(c, a1, a2, a3); \
+ current_config = NULL; \
+ return ret; \
+}
+
+WRAP_API(bool, lxcapi_is_defined)
+
+static const char *do_lxcapi_state(struct lxc_container *c)
{
lxc_state_t s;
return lxc_state2str(s);
}
+WRAP_API(const char *, lxcapi_state)
+
static bool is_stopped(struct lxc_container *c)
{
lxc_state_t s;
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)
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)
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)
return ttyfd;
}
+WRAP_API_2(int, lxcapi_console_getfd, int *, int *)
+
static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
int stdoutfd, int stderrfd, int escape)
{
- return lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape);
+ int ret;
+
+ if (!c)
+ return -1;
+
+ current_config = c->lxc_conf;
+ ret = lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape);
+ current_config = NULL;
+ return ret;
}
-static pid_t lxcapi_init_pid(struct lxc_container *c)
+static pid_t do_lxcapi_init_pid(struct lxc_container *c)
{
if (!c)
return -1;
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)
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;
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;
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;
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;
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;
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;
* 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;
}
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);
pid = fork();
if (pid < 0) {
SYSERROR("Error doing dual-fork");
- return false;
+ exit(1);
}
if (pid != 0)
exit(0);
/* like daemon(), chdir to / and redirect 0,1,2 to /dev/null */
if (chdir("/")) {
SYSERROR("Error chdir()ing to /.");
- return false;
+ exit(1);
}
lxc_check_inherited(conf, true, -1);
+ if (null_stdfds() < 0) {
+ ERROR("failed to close fds");
+ exit(1);
+ }
setsid();
} else {
if (!am_single_threaded()) {
if (pid_fp == NULL) {
SYSERROR("Failed to create pidfile '%s' for '%s'",
c->pidfile, c->name);
+ if (daemonize)
+ exit(1);
return false;
}
SYSERROR("Failed to write '%s'", c->pidfile);
fclose(pid_fp);
pid_fp = NULL;
+ if (daemonize)
+ exit(1);
return false;
}
pid_fp = NULL;
}
-reboot:
conf->reboot = 0;
+reboot:
if (lxc_check_inherited(conf, daemonize, -1)) {
ERROR("Inherited fds found");
ret = 1;
ret = lxc_start(c->name, argv, conf, c->config_path, daemonize);
c->error_num = ret;
- if (conf->reboot) {
+ if (conf->reboot == 1) {
INFO("container requested reboot");
- conf->reboot = 0;
+ conf->reboot = 2;
goto reboot;
}
return (ret == 0 ? true : false);
}
+static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[])
+{
+ bool ret;
+ current_config = c ? c->lxc_conf : NULL;
+ ret = do_lxcapi_start(c, useinit, argv);
+ current_config = NULL;
+ return ret;
+}
+
/*
* note there MUST be an ending NULL
*/
if (!c)
return false;
+ current_config = c->lxc_conf;
+
va_start(ap, useinit);
inargs = lxc_va_arg_list_to_argv(ap, 0, 1);
va_end(ap);
}
/* 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) {
free(inargs);
}
+ current_config = NULL;
return bret;
}
-static bool lxcapi_stop(struct lxc_container *c)
+static bool do_lxcapi_stop(struct lxc_container *c)
{
int ret;
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;
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.
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);
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 */
return p;
}
-static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet,
+static bool create_run_template(struct lxc_container *c, char *tpath, bool need_null_stdfds,
char *const argv[])
{
pid_t pid;
char **newargv;
struct lxc_conf *conf = c->lxc_conf;
- if (quiet) {
- close(0);
- close(1);
- close(2);
- open("/dev/zero", O_RDONLY);
- open("/dev/null", O_RDWR);
- open("/dev/null", O_RDWR);
+ if (need_null_stdfds && null_stdfds() < 0) {
+ exit(1);
}
src = c->lxc_conf->rootfs.path;
}
}
-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.
* @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[])
{
* 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;
}
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;
}
/* 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);
// 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)) {
return ret;
}
-static bool lxcapi_reboot(struct lxc_container *c)
+static bool lxcapi_create(struct lxc_container *c, const char *t,
+ const char *bdevtype, struct bdev_specs *specs, int flags,
+ char *const argv[])
+{
+ bool ret;
+ current_config = c ? c->lxc_conf : NULL;
+ ret = do_lxcapi_create(c, t, bdevtype, specs, flags, argv);
+ current_config = NULL;
+ return ret;
+}
+
+static bool do_lxcapi_reboot(struct lxc_container *c)
{
pid_t pid;
int rebootsignal = SIGINT;
if (!c)
return false;
- if (!c->is_running(c))
+ if (!do_lxcapi_is_running(c))
return false;
- pid = c->init_pid(c);
+ pid = do_lxcapi_init_pid(c);
if (pid <= 0)
return false;
if (c->lxc_conf && c->lxc_conf->rebootsignal)
}
-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;
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, ...)
{
if (!c)
return false;
+ current_config = c->lxc_conf;
+
/*
* since we're going to wait for create to finish, I don't think we
* need to get a copy of the arguments.
goto out;
}
- bret = c->create(c, t, bdevtype, specs, flags, args);
+ bret = do_lxcapi_create(c, t, bdevtype, specs, flags, args);
out:
free(args);
+ current_config = NULL;
return bret;
}
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;
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"))
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];
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];
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;
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;
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);
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;
// 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;
}
return ret;
}
+WRAP_API_1(bool, lxcapi_save_config, const char *)
+
static bool mod_rdep(struct lxc_container *c, bool inc)
{
char path[MAXPATHLEN];
{
bool bret = false;
int ret;
+ struct lxc_conf *conf;
- if (!c || !lxcapi_is_defined(c))
+ if (!c || !do_lxcapi_is_defined(c))
return false;
+ conf = c->lxc_conf;
if (container_disk_lock(c))
return false;
goto out;
}
- if (c->lxc_conf && c->lxc_conf->rootfs.path && c->lxc_conf->rootfs.mount) {
+ if (conf && !lxc_list_empty(&conf->hooks[LXCHOOK_DESTROY])) {
+ /* Start of environment variable setup for hooks */
+ if (setenv("LXC_NAME", c->name, 1)) {
+ SYSERROR("failed to set environment variable for container name");
+ }
+ if (setenv("LXC_CONFIG_FILE", conf->rcfile, 1)) {
+ SYSERROR("failed to set environment variable for config path");
+ }
+ if (setenv("LXC_ROOTFS_MOUNT", conf->rootfs.mount, 1)) {
+ SYSERROR("failed to set environment variable for rootfs mount");
+ }
+ if (setenv("LXC_ROOTFS_PATH", conf->rootfs.path, 1)) {
+ SYSERROR("failed to set environment variable for rootfs mount");
+ }
+ if (conf->console.path && setenv("LXC_CONSOLE", conf->console.path, 1)) {
+ SYSERROR("failed to set environment variable for console path");
+ }
+ if (conf->console.log_path && setenv("LXC_CONSOLE_LOGPATH", conf->console.log_path, 1)) {
+ SYSERROR("failed to set environment variable for console log");
+ }
+ /* End of environment variable setup for hooks */
+
+ if (run_lxc_hooks(c->name, "destroy", conf, c->get_config_path(c), NULL)) {
+ ERROR("Error executing clone hook for %s", c->name);
+ goto out;
+ }
+ }
+
+ if (current_config && conf == current_config) {
+ current_config = NULL;
+ if (conf->logfd != -1) {
+ close(conf->logfd);
+ conf->logfd = -1;
+ }
+ }
+
+ if (conf && conf->rootfs.path && conf->rootfs.mount) {
if (am_unpriv())
- ret = userns_exec_1(c->lxc_conf, bdev_destroy_wrapper, c->lxc_conf);
+ ret = userns_exec_1(conf, bdev_destroy_wrapper, conf);
else
- ret = do_bdev_destroy(c->lxc_conf);
+ ret = do_bdev_destroy(conf);
if (ret < 0) {
ERROR("Error destroying rootfs for %s", c->name);
goto out;
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())
- ret = userns_exec_1(c->lxc_conf, lxc_rmdir_onedev_wrapper, path);
+ ret = userns_exec_1(conf, lxc_rmdir_onedev_wrapper, path);
else
ret = lxc_rmdir_onedev(path, "snaps");
if (ret < 0) {
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;
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;
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;
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;
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)
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;
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;
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;
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);
ERROR("Error saving new hooks in clone");
return -1;
}
- c->save_config(c, NULL);
+ do_lxcapi_save_config(c, NULL);
return 0;
}
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)
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))
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");
return NULL;
}
-static bool lxcapi_rename(struct lxc_container *c, const char *newname)
+static struct lxc_container *lxcapi_clone(struct lxc_container *c, const char *newname,
+ const char *lxcpath, int flags,
+ const char *bdevtype, const char *bdevdata, uint64_t newsize,
+ char **hookargs)
+{
+ struct lxc_container * ret;
+ current_config = c ? c->lxc_conf : NULL;
+ ret = do_lxcapi_clone(c, newname, lxcpath, flags, bdevtype, bdevdata, newsize, hookargs);
+ current_config = NULL;
+ return ret;
+}
+
+static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
{
struct bdev *bdev;
struct lxc_container *newc;
return true;
}
+WRAP_API_1(bool, lxcapi_rename, const char *)
+
static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process)
{
+ int ret;
+
if (!c)
return -1;
- return lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process);
+ current_config = c->lxc_conf;
+
+ ret = lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process);
+ current_config = NULL;
+ return ret;
}
-static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
+static int do_lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
{
lxc_attach_command_t command;
pid_t pid;
return lxc_wait_for_pid_status(pid);
}
+static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
+{
+ int ret;
+ current_config = c ? c->lxc_conf : NULL;
+ ret = do_lxcapi_attach_run_wait(c, options, program, argv);
+ current_config = NULL;
+ return ret;
+}
+
static int get_next_index(const char *lxcpath, char *cname)
{
char *fname;
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;
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;
return i;
}
+WRAP_API_1(int, lxcapi_snapshot, const char *)
+
static void lxcsnap_free(struct lxc_snapshot *s)
{
free(s->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;
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;
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;
goto err;
}
- if (!lxcapi_destroy(snap)) {
+ if (!do_lxcapi_destroy(snap)) {
ERROR("Could not destroy snapshot %s", snapname);
goto err;
}
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];
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];
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)
{
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;
}
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;
}
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__);
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__);
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;
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;
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;
return true;
}
-static bool lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose)
+WRAP_API_2(bool, lxcapi_detach_interface, const char *, const char *)
+
+static bool do_lxcapi_checkpoint(struct lxc_container *c, char *directory, bool stop, bool verbose)
{
pid_t pid;
int status;
+ char path[PATH_MAX];
if (!criu_ok(c))
return false;
if (mkdir(directory, 0700) < 0 && errno != EEXIST)
return false;
+ status = snprintf(path, sizeof(path), "%s/inventory.img", directory);
+ if (status < 0 || status >= sizeof(path))
+ return false;
+
+ if (access(path, F_OK) == 0) {
+ ERROR("please use a fresh directory for the dump directory\n");
+ return false;
+ }
+
if (!dump_net_info(c, directory))
return false;
}
}
-static bool lxcapi_restore(struct lxc_container *c, char *directory, bool verbose)
+WRAP_API_3(bool, lxcapi_checkpoint, char *, bool, bool)
+
+static bool do_lxcapi_restore(struct lxc_container *c, char *directory, bool verbose)
{
pid_t pid;
int status, nread;
return false;
}
+WRAP_API_2(bool, lxcapi_restore, char *, bool)
+
static int lxcapi_attach_run_waitl(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char *arg, ...)
{
va_list ap;
if (!c)
return -1;
+ current_config = c->lxc_conf;
+
va_start(ap, arg);
argv = lxc_va_arg_list_to_argv_const(ap, 1);
va_end(ap);
if (!argv) {
ERROR("Memory allocation error.");
- return -1;
+ ret = -1;
+ goto out;
}
argv[0] = arg;
- ret = lxcapi_attach_run_wait(c, options, program, (const char * const *)argv);
+ ret = do_lxcapi_attach_run_wait(c, options, program, (const char * const *)argv);
free((void*)argv);
+out:
+ current_config = NULL;
return ret;
}
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:
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)