Unverified Commit c8a5adcd by Stéphane Graber Committed by GitHub

Merge pull request #2186 from brauner/2018-02-22/make_confile_reading_thread_safe

tree-wide: thread-safety improvements
parents 1401329e 106f1f38
...@@ -278,7 +278,7 @@ lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c tools/tool_uti ...@@ -278,7 +278,7 @@ lxc_checkpoint_SOURCES = tools/lxc_checkpoint.c tools/arguments.c tools/tool_uti
# Binaries shipping with liblxc # Binaries shipping with liblxc
init_lxc_SOURCES = cmd/lxc_init.c init_lxc_SOURCES = cmd/lxc_init.c
lxc_monitord_SOURCES = cmd/lxc_monitord.c lxc_monitord_SOURCES = cmd/lxc_monitord.c
lxc_user_nic_SOURCES = cmd/lxc_user_nic.c namespace.c network.c lxc_user_nic_SOURCES = cmd/lxc_user_nic.c namespace.c network.c parse.c
lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c lxc_usernsexec_SOURCES = cmd/lxc_usernsexec.c
if ENABLE_DEPRECATED if ENABLE_DEPRECATED
......
...@@ -327,7 +327,7 @@ struct hierarchy *get_hierarchy(const char *c) ...@@ -327,7 +327,7 @@ struct hierarchy *get_hierarchy(const char *c)
!hierarchies[i]->controllers[0]) !hierarchies[i]->controllers[0])
return hierarchies[i]; return hierarchies[i];
return NULL; continue;
} }
if (string_in_list(hierarchies[i]->controllers, c)) if (string_in_list(hierarchies[i]->controllers, c))
...@@ -1306,8 +1306,11 @@ static bool cg_hybrid_init(void) ...@@ -1306,8 +1306,11 @@ static bool cg_hybrid_init(void)
controller_list = cg_unified_get_controllers(cgv2_ctrl_path); controller_list = cg_unified_get_controllers(cgv2_ctrl_path);
free(cgv2_ctrl_path); free(cgv2_ctrl_path);
if (!controller_list) if (!controller_list) {
controller_list = cg_unified_make_empty_controller(); controller_list = cg_unified_make_empty_controller();
CGFSNG_DEBUG("No controllers are enabled for "
"delegation in the unified hierarchy\n");
}
} }
new = add_hierarchy(controller_list, mountpoint, base_cgroup, type); new = add_hierarchy(controller_list, mountpoint, base_cgroup, type);
...@@ -2365,13 +2368,16 @@ static bool cgfsng_unfreeze(void *hdata) ...@@ -2365,13 +2368,16 @@ static bool cgfsng_unfreeze(void *hdata)
return true; return true;
} }
static const char *cgfsng_get_cgroup(void *hdata, const char *subsystem) static const char *cgfsng_get_cgroup(void *hdata, const char *controller)
{ {
struct hierarchy *h; struct hierarchy *h;
h = get_hierarchy(subsystem); h = get_hierarchy(controller);
if (!h) if (!h) {
SYSERROR("Failed to find hierarchy for controller \"%s\"",
controller ? controller : "(null)");
return NULL; return NULL;
}
return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL; return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
} }
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include "config.h" #include "config.h"
#include "namespace.h" #include "namespace.h"
#include "network.h" #include "network.h"
#include "parse.h"
#include "utils.h" #include "utils.h"
#define usernic_debug_stream(stream, format, ...) \ #define usernic_debug_stream(stream, format, ...) \
......
...@@ -2334,7 +2334,7 @@ int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include) ...@@ -2334,7 +2334,7 @@ int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
if (!conf->rcfile) if (!conf->rcfile)
conf->rcfile = strdup(file); conf->rcfile = strdup(file);
return lxc_file_for_each_line(file, parse_line, &c); return lxc_file_for_each_line_mmap(file, parse_line, &c);
} }
int lxc_config_define_add(struct lxc_list *defines, char *arg) int lxc_config_define_add(struct lxc_list *defines, char *arg)
...@@ -2417,17 +2417,21 @@ signed long lxc_config_parse_arch(const char *arch) ...@@ -2417,17 +2417,21 @@ signed long lxc_config_parse_arch(const char *arch)
} }
/* Write out a configuration file. */ /* Write out a configuration file. */
void write_config(FILE *fout, struct lxc_conf *c) int write_config(int fd, const struct lxc_conf *conf)
{ {
int ret; int ret;
size_t len = c->unexpanded_len; size_t len = conf->unexpanded_len;
if (!len) if (len == 0)
return; return 0;
ret = fwrite(c->unexpanded_config, 1, len, fout); ret = lxc_write_nointr(fd, conf->unexpanded_config, len);
if (ret != len) if (ret < 0) {
SYSERROR("Failed to write configuration file"); SYSERROR("Failed to write configuration file");
return -1;
}
return 0;
} }
bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key, bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
......
...@@ -93,7 +93,7 @@ extern signed long lxc_config_parse_arch(const char *arch); ...@@ -93,7 +93,7 @@ extern signed long lxc_config_parse_arch(const char *arch);
extern int lxc_clear_config_item(struct lxc_conf *c, const char *key); extern int lxc_clear_config_item(struct lxc_conf *c, const char *key);
extern void write_config(FILE *fout, struct lxc_conf *c); extern int write_config(int fd, const struct lxc_conf *conf);
extern bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key, extern bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
const char *v); const char *v);
......
...@@ -717,13 +717,13 @@ bool __criu_check_feature(uint64_t *features_to_check) ...@@ -717,13 +717,13 @@ bool __criu_check_feature(uint64_t *features_to_check)
* LXC checking only for 'uffd' makes not much sense. */ * LXC checking only for 'uffd' makes not much sense. */
args[3] = "uffd-noncoop"; args[3] = "uffd-noncoop";
else else
exit(1); _exit(EXIT_FAILURE);
null_stdfds(); null_stdfds();
execvp("criu", args); execvp("criu", args);
SYSERROR("Failed to exec \"criu\""); SYSERROR("Failed to exec \"criu\"");
exit(1); _exit(EXIT_FAILURE);
} }
ret = wait_for_pid(pid); ret = wait_for_pid(pid);
...@@ -785,14 +785,14 @@ static bool criu_version_ok(char **version) ...@@ -785,14 +785,14 @@ static bool criu_version_ok(char **version)
close(STDERR_FILENO); close(STDERR_FILENO);
if (dup2(pipes[1], STDOUT_FILENO) < 0) if (dup2(pipes[1], STDOUT_FILENO) < 0)
exit(1); _exit(EXIT_FAILURE);
path = on_path("criu", NULL); path = on_path("criu", NULL);
if (!path) if (!path)
exit(1); _exit(EXIT_FAILURE);
execv(path, args); execv(path, args);
exit(1); _exit(EXIT_FAILURE);
} else { } else {
FILE *f; FILE *f;
char *tmp; char *tmp;
...@@ -923,7 +923,7 @@ out_unlock: ...@@ -923,7 +923,7 @@ out_unlock:
} }
/* do_restore never returns, the calling process is used as the monitor process. /* do_restore never returns, the calling process is used as the monitor process.
* do_restore calls exit() if it fails. * do_restore calls _exit() if it fails.
*/ */
static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_opts *opts, char *criu_version) static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_opts *opts, char *criu_version)
{ {
...@@ -1140,7 +1140,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_ ...@@ -1140,7 +1140,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
if (ret) if (ret)
lxc_abort(c->name, handler); lxc_abort(c->name, handler);
lxc_fini(c->name, handler); lxc_fini(c->name, handler);
exit(ret); _exit(ret);
} }
out_fini_handler: out_fini_handler:
...@@ -1165,7 +1165,7 @@ out: ...@@ -1165,7 +1165,7 @@ out:
close(status_pipe); close(status_pipe);
} }
exit(1); _exit(EXIT_FAILURE);
} }
static int save_tty_major_minor(char *directory, struct lxc_container *c, char *tty_id, int len) static int save_tty_major_minor(char *directory, struct lxc_container *c, char *tty_id, int len)
...@@ -1256,7 +1256,7 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op ...@@ -1256,7 +1256,7 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
h.name = c->name; h.name = c->name;
if (!cgroup_init(&h)) { if (!cgroup_init(&h)) {
ERROR("failed to cgroup_init()"); ERROR("failed to cgroup_init()");
exit(1); _exit(EXIT_FAILURE);
} }
os.pipefd = criuout[1]; os.pipefd = criuout[1];
...@@ -1269,13 +1269,13 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op ...@@ -1269,13 +1269,13 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
ret = save_tty_major_minor(opts->directory, c, os.tty_id, sizeof(os.tty_id)); ret = save_tty_major_minor(opts->directory, c, os.tty_id, sizeof(os.tty_id));
if (ret < 0) { if (ret < 0) {
free(criu_version); free(criu_version);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* exec_criu() returning is an error */ /* exec_criu() returning is an error */
exec_criu(&os); exec_criu(&os);
free(criu_version); free(criu_version);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} else { } else {
int status; int status;
ssize_t n; ssize_t n;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define __LXC_ERROR_H #define __LXC_ERROR_H
#define LXC_CLONE_ERROR "Failed to clone a new set of namespaces" #define LXC_CLONE_ERROR "Failed to clone a new set of namespaces"
#define LXC_UNPRIV_EOPNOTSUPP "the requested function %s is not currently supported with unprivileged containers"
extern int lxc_error_set_and_log(int pid, int status); extern int lxc_error_set_and_log(int pid, int status);
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "confile_utils.h" #include "confile_utils.h"
#include "console.h" #include "console.h"
#include "criu.h" #include "criu.h"
#include "error.h"
#include "initutils.h" #include "initutils.h"
#include "log.h" #include "log.h"
#include "lxc.h" #include "lxc.h"
...@@ -57,6 +58,7 @@ ...@@ -57,6 +58,7 @@
#include "monitor.h" #include "monitor.h"
#include "namespace.h" #include "namespace.h"
#include "network.h" #include "network.h"
#include "parse.h"
#include "start.h" #include "start.h"
#include "state.h" #include "state.h"
#include "storage.h" #include "storage.h"
...@@ -69,7 +71,7 @@ ...@@ -69,7 +71,7 @@
/* major()/minor() */ /* major()/minor() */
#ifdef MAJOR_IN_MKDEV #ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h> #include <sys/mkdev.h>
#endif #endif
#if HAVE_IFADDRS_H #if HAVE_IFADDRS_H
...@@ -84,19 +86,15 @@ ...@@ -84,19 +86,15 @@
#include <mntent.h> #include <mntent.h>
#endif #endif
#define MAX_BUFFER 4096
#define NOT_SUPPORTED_ERROR "the requested function %s is not currently supported with unprivileged containers"
/* Define faccessat() if missing from the C library */ /* Define faccessat() if missing from the C library */
#ifndef HAVE_FACCESSAT #ifndef HAVE_FACCESSAT
static int faccessat(int __fd, const char *__file, int __type, int __flag) static int faccessat(int __fd, const char *__file, int __type, int __flag)
{ {
#ifdef __NR_faccessat #ifdef __NR_faccessat
return syscall(__NR_faccessat, __fd, __file, __type, __flag); return syscall(__NR_faccessat, __fd, __file, __type, __flag);
#else #else
errno = ENOSYS; errno = ENOSYS;
return -1; return -1;
#endif #endif
} }
#endif #endif
...@@ -115,85 +113,91 @@ static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file) ...@@ -115,85 +113,91 @@ 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 */ int ret;
int ret, len = strlen(lxcpath) + strlen(cname) + 9; size_t len;
char *fname = alloca(len); char *fname;
ret = snprintf(fname, len, "%s/%s/config", lxcpath, cname); /* $lxcpath + '/' + $cname + '/config' + \0 */
if (ret < 0 || ret >= len) len = strlen(lxcpath) + strlen(cname) + 9;
fname = alloca(len);
ret = snprintf(fname, len, "%s/%s/config", lxcpath, cname);
if (ret < 0 || (size_t)ret >= len)
return false; return false;
return file_exists(fname); return file_exists(fname);
} }
/* /* A few functions to help detect when a container creation failed. If a
* A few functions to help detect when a container creation failed. * container creation was killed partway through, then trying to actually start
* If a container creation was killed partway through, then trying * that container could harm the host. We detect this by creating a 'partial'
* to actually start that container could harm the host. We detect * file under the container directory, and keeping an advisory lock. When
* this by creating a 'partial' file under the container directory, * container creation completes, we remove that file. When we load or try to
* and keeping an advisory lock. When container creation completes, * start a container, if we find that file, without a flock, we remove the
* we remove that file. When we load or try to start a container, if * container.
* we find that file, without a flock, we remove the container.
*/ */
static int ongoing_create(struct lxc_container *c) static int ongoing_create(struct lxc_container *c)
{ {
int len = strlen(c->config_path) + strlen(c->name) + 10;
char *path = alloca(len);
int fd, ret; int fd, ret;
size_t len;
char *path;
struct flock lk; struct flock lk;
len = strlen(c->config_path) + strlen(c->name) + 10;
path = alloca(len);
ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name); ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name);
if (ret < 0 || ret >= len) { if (ret < 0 || (size_t)ret >= len)
ERROR("Error writing partial pathname");
return -1; return -1;
}
if (!file_exists(path)) if (!file_exists(path))
return 0; return 0;
fd = open(path, O_RDWR); fd = open(path, O_RDWR);
if (fd < 0) { if (fd < 0)
/* give benefit of the doubt */
SYSERROR("Error opening partial file");
return 0; return 0;
}
lk.l_type = F_WRLCK; lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET; lk.l_whence = SEEK_SET;
lk.l_start = 0; lk.l_start = 0;
lk.l_len = 0; lk.l_len = 0;
lk.l_pid = -1; lk.l_pid = -1;
if (fcntl(fd, F_GETLK, &lk) == 0 && lk.l_pid != -1) {
ret = fcntl(fd, F_GETLK, &lk);
close(fd);
if (ret == 0 && lk.l_pid != -1) {
/* create is still ongoing */ /* create is still ongoing */
close(fd);
return 1; return 1;
} }
/* create completed but partial is still there. */
close(fd); /* Create completed but partial is still there. */
return 2; return 2;
} }
static int create_partial(struct lxc_container *c) static int create_partial(struct lxc_container *c)
{ {
/* $lxcpath + '/' + $name + '/partial' + \0 */
int len = strlen(c->config_path) + strlen(c->name) + 10;
char *path = alloca(len);
int fd, ret; int fd, ret;
size_t len;
char *path;
struct flock lk; struct flock lk;
/* $lxcpath + '/' + $name + '/partial' + \0 */
len = strlen(c->config_path) + strlen(c->name) + 10;
path = alloca(len);
ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name); ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name);
if (ret < 0 || ret >= len) { if (ret < 0 || (size_t)ret >= len)
ERROR("Error writing partial pathname");
return -1; return -1;
}
if ((fd=open(path, O_RDWR | O_CREAT | O_EXCL, 0755)) < 0) { fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0755);
SYSERROR("Error creating partial file"); if (fd < 0)
return -1; return -1;
}
lk.l_type = F_WRLCK; lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET; lk.l_whence = SEEK_SET;
lk.l_start = 0; lk.l_start = 0;
lk.l_len = 0; lk.l_len = 0;
if (fcntl(fd, F_SETLKW, &lk) < 0) {
SYSERROR("Error locking partial file %s", path); ret = fcntl(fd, F_SETLKW, &lk);
if (ret < 0) {
SYSERROR("Failed to lock partial file %s", path);
close(fd); close(fd);
return -1; return -1;
} }
...@@ -203,19 +207,21 @@ static int create_partial(struct lxc_container *c) ...@@ -203,19 +207,21 @@ static int create_partial(struct lxc_container *c)
static void remove_partial(struct lxc_container *c, int fd) static void remove_partial(struct lxc_container *c, int fd)
{ {
/* $lxcpath + '/' + $name + '/partial' + \0 */
int len = strlen(c->config_path) + strlen(c->name) + 10;
char *path = alloca(len);
int ret; int ret;
size_t len;
char *path;
close(fd); close(fd);
/* $lxcpath + '/' + $name + '/partial' + \0 */
len = strlen(c->config_path) + strlen(c->name) + 10;
path = alloca(len);
ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name); ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name);
if (ret < 0 || ret >= len) { if (ret < 0 || (size_t)ret >= len)
ERROR("Error writing partial pathname");
return; return;
}
if (unlink(path) < 0) ret = unlink(path);
SYSERROR("Error unlink partial file %s", path); if (ret < 0)
SYSERROR("Failed to remove partial file %s", path);
} }
/* LOCKING /* LOCKING
...@@ -247,41 +253,49 @@ static void lxc_container_free(struct lxc_container *c) ...@@ -247,41 +253,49 @@ static void lxc_container_free(struct lxc_container *c)
free(c->configfile); free(c->configfile);
c->configfile = NULL; c->configfile = NULL;
free(c->error_string); free(c->error_string);
c->error_string = NULL; c->error_string = NULL;
if (c->slock) { if (c->slock) {
lxc_putlock(c->slock); lxc_putlock(c->slock);
c->slock = NULL; c->slock = NULL;
} }
if (c->privlock) { if (c->privlock) {
lxc_putlock(c->privlock); lxc_putlock(c->privlock);
c->privlock = NULL; c->privlock = NULL;
} }
free(c->name); free(c->name);
c->name = NULL; c->name = NULL;
if (c->lxc_conf) { if (c->lxc_conf) {
lxc_conf_free(c->lxc_conf); lxc_conf_free(c->lxc_conf);
c->lxc_conf = NULL; c->lxc_conf = NULL;
} }
free(c->config_path); free(c->config_path);
c->config_path = NULL; c->config_path = NULL;
free(c); free(c);
} }
/* /* Consider the following case:
* Consider the following case: *
freer | racing get()er * |====================================================================|
================================================================== * | freer | racing get()er |
lxc_container_put() | lxc_container_get() * |====================================================================|
\ lxclock(c->privlock) | c->numthreads < 1? (no) * | lxc_container_put() | lxc_container_get() |
\ c->numthreads = 0 | \ lxclock(c->privlock) -> waits * | \ lxclock(c->privlock) | c->numthreads < 1? (no) |
\ lxcunlock() | \ * | \ c->numthreads = 0 | \ lxclock(c->privlock) -> waits |
\ lxc_container_free() | \ lxclock() returns * | \ lxcunlock() | \ |
| \ c->numthreads < 1 -> return 0 * | \ lxc_container_free() | \ lxclock() returns |
\ \ (free stuff) | * | | \ c->numthreads < 1 -> return 0 |
\ \ sem_destroy(privlock) | * | \ \ (free stuff) | |
* | \ \ sem_destroy(privlock) | |
* |_______________________________|____________________________________|
*
* When the get()er checks numthreads the first time, one of the following * When the get()er checks numthreads the first time, one of the following
* is true: * is true:
* 1. freer has set numthreads = 0. get() returns 0 * 1. freer has set numthreads = 0. get() returns 0
...@@ -314,6 +328,7 @@ int lxc_container_get(struct lxc_container *c) ...@@ -314,6 +328,7 @@ int lxc_container_get(struct lxc_container *c)
c->numthreads++; c->numthreads++;
container_mem_unlock(c); container_mem_unlock(c);
return 1; return 1;
} }
...@@ -321,37 +336,45 @@ int lxc_container_put(struct lxc_container *c) ...@@ -321,37 +336,45 @@ int lxc_container_put(struct lxc_container *c)
{ {
if (!c) if (!c)
return -1; return -1;
if (container_mem_lock(c)) if (container_mem_lock(c))
return -1; return -1;
if (--c->numthreads < 1) { if (--c->numthreads < 1) {
container_mem_unlock(c); container_mem_unlock(c);
lxc_container_free(c); lxc_container_free(c);
return 1; return 1;
} }
container_mem_unlock(c); container_mem_unlock(c);
return 0; return 0;
} }
static bool do_lxcapi_is_defined(struct lxc_container *c) static bool do_lxcapi_is_defined(struct lxc_container *c)
{ {
int statret;
struct stat statbuf; struct stat statbuf;
bool ret = false; bool ret = false;
int statret;
if (!c) if (!c)
return false; return false;
if (container_mem_lock(c)) if (container_mem_lock(c))
return false; return false;
if (!c->configfile) if (!c->configfile)
goto out; goto on_error;
statret = stat(c->configfile, &statbuf); statret = stat(c->configfile, &statbuf);
if (statret != 0) if (statret != 0)
goto out; goto on_error;
ret = true; ret = true;
out: on_error:
container_mem_unlock(c); container_mem_unlock(c);
return ret; return ret;
} }
...@@ -435,6 +458,7 @@ static const char *do_lxcapi_state(struct lxc_container *c) ...@@ -435,6 +458,7 @@ static const char *do_lxcapi_state(struct lxc_container *c)
if (!c) if (!c)
return NULL; return NULL;
s = lxc_getstate(c->name, c->config_path); s = lxc_getstate(c->name, c->config_path);
return lxc_state2str(s); return lxc_state2str(s);
} }
...@@ -444,6 +468,7 @@ WRAP_API(const char *, lxcapi_state) ...@@ -444,6 +468,7 @@ 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;
s = lxc_getstate(c->name, c->config_path); s = lxc_getstate(c->name, c->config_path);
return (s == STOPPED); return (s == STOPPED);
} }
...@@ -454,9 +479,11 @@ static bool do_lxcapi_is_running(struct lxc_container *c) ...@@ -454,9 +479,11 @@ static bool do_lxcapi_is_running(struct lxc_container *c)
if (!c) if (!c)
return false; return false;
s = do_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;
} }
...@@ -465,12 +492,14 @@ WRAP_API(bool, lxcapi_is_running) ...@@ -465,12 +492,14 @@ WRAP_API(bool, lxcapi_is_running)
static bool do_lxcapi_freeze(struct lxc_container *c) static bool do_lxcapi_freeze(struct lxc_container *c)
{ {
int ret; int ret;
if (!c) if (!c)
return false; return false;
ret = lxc_freeze(c->name, c->config_path); ret = lxc_freeze(c->name, c->config_path);
if (ret) if (ret)
return false; return false;
return true; return true;
} }
...@@ -479,12 +508,14 @@ WRAP_API(bool, lxcapi_freeze) ...@@ -479,12 +508,14 @@ WRAP_API(bool, lxcapi_freeze)
static bool do_lxcapi_unfreeze(struct lxc_container *c) static bool do_lxcapi_unfreeze(struct lxc_container *c)
{ {
int ret; int ret;
if (!c) if (!c)
return false; return false;
ret = lxc_unfreeze(c->name, c->config_path); ret = lxc_unfreeze(c->name, c->config_path);
if (ret) if (ret)
return false; return false;
return true; return true;
} }
...@@ -492,12 +523,10 @@ WRAP_API(bool, lxcapi_unfreeze) ...@@ -492,12 +523,10 @@ WRAP_API(bool, lxcapi_unfreeze)
static int do_lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd) static int do_lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
{ {
int ttyfd;
if (!c) if (!c)
return -1; return -1;
ttyfd = lxc_console_getfd(c, ttynum, masterfd); return lxc_console_getfd(c, ttynum, masterfd);
return ttyfd;
} }
WRAP_API_2(int, lxcapi_console_getfd, int *, int *) WRAP_API_2(int, lxcapi_console_getfd, int *, int *)
...@@ -513,6 +542,7 @@ static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd, ...@@ -513,6 +542,7 @@ static int lxcapi_console(struct lxc_container *c, int ttynum, int stdinfd,
current_config = c->lxc_conf; current_config = c->lxc_conf;
ret = lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape); ret = lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape);
current_config = NULL; current_config = NULL;
return ret; return ret;
} }
...@@ -553,18 +583,22 @@ static bool load_config_locked(struct lxc_container *c, const char *fname) ...@@ -553,18 +583,22 @@ static bool load_config_locked(struct lxc_container *c, const char *fname)
{ {
if (!c->lxc_conf) if (!c->lxc_conf)
c->lxc_conf = lxc_conf_init(); c->lxc_conf = lxc_conf_init();
if (!c->lxc_conf) if (!c->lxc_conf)
return false; return false;
if (lxc_config_read(fname, c->lxc_conf, false) != 0) if (lxc_config_read(fname, c->lxc_conf, false) != 0)
return false; return false;
return true; return true;
} }
static bool do_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; int lret;
const char *fname; const char *fname;
bool need_disklock = false, ret = false;
if (!c) if (!c)
return false; return false;
...@@ -573,10 +607,10 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file) ...@@ -573,10 +607,10 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file)
fname = alt_file; fname = alt_file;
if (!fname) if (!fname)
return false; return false;
/*
* If we're reading something other than the container's config, /* If we're reading something other than the container's config, we only
* we only need to lock the in-memory container. If loading the * need to lock the in-memory container. If loading the container's
* container's config file, take the disk lock. * config file, take the disk lock.
*/ */
if (strcmp(fname, c->configfile) == 0) if (strcmp(fname, c->configfile) == 0)
need_disklock = true; need_disklock = true;
...@@ -594,6 +628,7 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file) ...@@ -594,6 +628,7 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file)
container_disk_unlock(c); container_disk_unlock(c);
else else
container_mem_unlock(c); container_mem_unlock(c);
return ret; return ret;
} }
...@@ -603,12 +638,13 @@ static bool do_lxcapi_want_daemonize(struct lxc_container *c, bool state) ...@@ -603,12 +638,13 @@ 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;
if (container_mem_lock(c)) {
ERROR("Error getting mem lock"); if (container_mem_lock(c))
return false; return false;
}
c->daemonize = state; c->daemonize = state;
container_mem_unlock(c); container_mem_unlock(c);
return true; return true;
} }
...@@ -618,18 +654,20 @@ static bool do_lxcapi_want_close_all_fds(struct lxc_container *c, bool state) ...@@ -618,18 +654,20 @@ 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;
if (container_mem_lock(c)) {
ERROR("Error getting mem lock"); if (container_mem_lock(c))
return false; return false;
}
c->lxc_conf->close_all_fds = state; c->lxc_conf->close_all_fds = state;
container_mem_unlock(c); container_mem_unlock(c);
return true; return true;
} }
WRAP_API_1(bool, lxcapi_want_close_all_fds, bool) WRAP_API_1(bool, lxcapi_want_close_all_fds, bool)
static bool do_lxcapi_wait(struct lxc_container *c, const char *state, int timeout) static bool do_lxcapi_wait(struct lxc_container *c, const char *state,
int timeout)
{ {
int ret; int ret;
...@@ -646,13 +684,11 @@ static bool am_single_threaded(void) ...@@ -646,13 +684,11 @@ static bool am_single_threaded(void)
{ {
struct dirent *direntp; struct dirent *direntp;
DIR *dir; DIR *dir;
int count=0; int count = 0;
dir = opendir("/proc/self/task"); dir = opendir("/proc/self/task");
if (!dir) { if (!dir)
INFO("failed to open /proc/self/task");
return false; return false;
}
while ((direntp = readdir(dir))) { while ((direntp = readdir(dir))) {
if (!strcmp(direntp->d_name, ".")) if (!strcmp(direntp->d_name, "."))
...@@ -660,24 +696,28 @@ static bool am_single_threaded(void) ...@@ -660,24 +696,28 @@ static bool am_single_threaded(void)
if (!strcmp(direntp->d_name, "..")) if (!strcmp(direntp->d_name, ".."))
continue; continue;
if (++count > 1) if (++count > 1)
break; break;
} }
closedir(dir); closedir(dir);
return count == 1; return count == 1;
} }
static void push_arg(char ***argp, char *arg, int *nargs) static void push_arg(char ***argp, char *arg, int *nargs)
{ {
char **argv;
char *copy; char *copy;
char **argv;
do { do {
copy = strdup(arg); copy = strdup(arg);
} while (!copy); } while (!copy);
do { do {
argv = realloc(*argp, (*nargs + 2) * sizeof(char *)); argv = realloc(*argp, (*nargs + 2) * sizeof(char *));
} while (!argv); } while (!argv);
*argp = argv; *argp = argv;
argv[*nargs] = copy; argv[*nargs] = copy;
(*nargs)++; (*nargs)++;
...@@ -687,9 +727,10 @@ static void push_arg(char ***argp, char *arg, int *nargs) ...@@ -687,9 +727,10 @@ static void push_arg(char ***argp, char *arg, int *nargs)
static char **split_init_cmd(const char *incmd) static char **split_init_cmd(const char *incmd)
{ {
size_t len; size_t len;
int nargs = 0; char *copy, *p;
char *copy, *p, *saveptr = NULL;
char **argv; char **argv;
int nargs = 0;
char *saveptr = NULL;
if (!incmd) if (!incmd)
return NULL; return NULL;
...@@ -697,20 +738,21 @@ static char **split_init_cmd(const char *incmd) ...@@ -697,20 +738,21 @@ static char **split_init_cmd(const char *incmd)
len = strlen(incmd) + 1; len = strlen(incmd) + 1;
copy = alloca(len); copy = alloca(len);
strncpy(copy, incmd, len); strncpy(copy, incmd, len);
copy[len-1] = '\0'; copy[len - 1] = '\0';
do { do {
argv = malloc(sizeof(char *)); argv = malloc(sizeof(char *));
} while (!argv); } while (!argv);
argv[0] = NULL; argv[0] = NULL;
for (p = strtok_r(copy, " ", &saveptr); p != NULL; for (; (p = strtok_r(copy, " ", &saveptr)); copy = NULL)
p = strtok_r(NULL, " ", &saveptr))
push_arg(&argv, p, &nargs); push_arg(&argv, p, &nargs);
if (nargs == 0) { if (nargs == 0) {
free(argv); free(argv);
return NULL; return NULL;
} }
return argv; return argv;
} }
...@@ -720,8 +762,10 @@ static void free_init_cmd(char **argv) ...@@ -720,8 +762,10 @@ static void free_init_cmd(char **argv)
if (!argv) if (!argv)
return; return;
while (argv[i]) while (argv[i])
free(argv[i++]); free(argv[i++]);
free(argv); free(argv);
} }
...@@ -902,14 +946,14 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a ...@@ -902,14 +946,14 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
SYSERROR("Failed to fork first child process"); SYSERROR("Failed to fork first child process");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* second parent */ /* second parent */
if (pid != 0) { if (pid != 0) {
free_init_cmd(init_cmd); free_init_cmd(init_cmd);
lxc_free_handler(handler); lxc_free_handler(handler);
exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
} }
/* second child */ /* second child */
...@@ -918,7 +962,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a ...@@ -918,7 +962,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
ret = chdir("/"); ret = chdir("/");
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to change to \"/\" directory"); SYSERROR("Failed to change to \"/\" directory");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
keepfds[0] = handler->conf->maincmd_fd; keepfds[0] = handler->conf->maincmd_fd;
...@@ -927,13 +971,13 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a ...@@ -927,13 +971,13 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
ret = lxc_check_inherited(conf, true, keepfds, ret = lxc_check_inherited(conf, true, keepfds,
sizeof(keepfds) / sizeof(keepfds[0])); sizeof(keepfds) / sizeof(keepfds[0]));
if (ret < 0) if (ret < 0)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
/* redirect std{in,out,err} to /dev/null */ /* redirect std{in,out,err} to /dev/null */
ret = null_stdfds(); ret = null_stdfds();
if (ret < 0) { if (ret < 0) {
ERROR("Failed to redirect std{in,out,err} to /dev/null"); ERROR("Failed to redirect std{in,out,err} to /dev/null");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* become session leader */ /* become session leader */
...@@ -960,7 +1004,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a ...@@ -960,7 +1004,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
free_init_cmd(init_cmd); free_init_cmd(init_cmd);
lxc_free_handler(handler); lxc_free_handler(handler);
if (daemonize) if (daemonize)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
return false; return false;
} }
...@@ -971,7 +1015,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a ...@@ -971,7 +1015,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
free_init_cmd(init_cmd); free_init_cmd(init_cmd);
lxc_free_handler(handler); lxc_free_handler(handler);
if (daemonize) if (daemonize)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
return false; return false;
} }
...@@ -1042,9 +1086,9 @@ on_error: ...@@ -1042,9 +1086,9 @@ on_error:
free_init_cmd(init_cmd); free_init_cmd(init_cmd);
if (daemonize && ret != 0) if (daemonize && ret != 0)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
else if (daemonize) else if (daemonize)
exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
if (ret != 0) if (ret != 0)
return false; return false;
...@@ -1052,18 +1096,19 @@ on_error: ...@@ -1052,18 +1096,19 @@ on_error:
return true; return true;
} }
static bool lxcapi_start(struct lxc_container *c, int useinit, char * const argv[]) static bool lxcapi_start(struct lxc_container *c, int useinit,
char *const argv[])
{ {
bool ret; bool ret;
current_config = c ? c->lxc_conf : NULL; current_config = c ? c->lxc_conf : NULL;
ret = do_lxcapi_start(c, useinit, argv); ret = do_lxcapi_start(c, useinit, argv);
current_config = NULL; current_config = NULL;
return ret; return ret;
} }
/* /* Note, there MUST be an ending NULL. */
* note there MUST be an ending NULL
*/
static bool lxcapi_startl(struct lxc_container *c, int useinit, ...) static bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
{ {
va_list ap; va_list ap;
...@@ -1079,16 +1124,13 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...) ...@@ -1079,16 +1124,13 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
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);
if (!inargs)
if (!inargs) { goto on_error;
ERROR("Memory allocation error.");
goto out;
}
/* pass NULL if no arguments were supplied */ /* pass NULL if no arguments were supplied */
bret = do_lxcapi_start(c, useinit, *inargs ? inargs : NULL); bret = do_lxcapi_start(c, useinit, *inargs ? inargs : NULL);
out: on_error:
if (inargs) { if (inargs) {
char **arg; char **arg;
for (arg = inargs; *arg; arg++) for (arg = inargs; *arg; arg++)
...@@ -1097,6 +1139,7 @@ out: ...@@ -1097,6 +1139,7 @@ out:
} }
current_config = NULL; current_config = NULL;
return bret; return bret;
} }
...@@ -1116,48 +1159,56 @@ WRAP_API(bool, lxcapi_stop) ...@@ -1116,48 +1159,56 @@ 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 lasterr;
char *p = alloca(strlen(path)+1); size_t len;
char *p;
int ret = -1;
mode_t mask = umask(0002); mode_t mask = umask(0002);
ret = mkdir(path, 0770); ret = mkdir(path, 0770);
lasterr = errno; lasterr = errno;
umask(mask); umask(mask);
errno = lasterr; errno = lasterr;
if (ret) { if (ret) {
if (errno == EEXIST) if (errno != EEXIST)
ret = 0;
else {
SYSERROR("failed to create container path %s", path);
return -1; return -1;
}
ret = 0;
} }
len = strlen(path);
p = alloca(len + 1);
strcpy(p, path); strcpy(p, path);
if (!lxc_list_empty(&conf->id_map) && chown_mapped_root(p, conf) != 0) { if (!lxc_list_empty(&conf->id_map)) {
ERROR("Failed to chown container dir"); ret = chown_mapped_root(p, conf);
ret = -1; if (ret < 0)
ret = -1;
} }
return ret; return ret;
} }
/* /* Create the standard expected container dir. */
* create the standard expected container dir
*/
static bool create_container_dir(struct lxc_container *c) static bool create_container_dir(struct lxc_container *c)
{ {
int ret;
size_t len;
char *s; char *s;
int len, ret;
len = strlen(c->config_path) + strlen(c->name) + 2; len = strlen(c->config_path) + strlen(c->name) + 2;
s = malloc(len); s = malloc(len);
if (!s) if (!s)
return false; return false;
ret = snprintf(s, len, "%s/%s", c->config_path, c->name); ret = snprintf(s, len, "%s/%s", c->config_path, c->name);
if (ret < 0 || ret >= len) { if (ret < 0 || (size_t)ret >= len) {
free(s); free(s);
return false; return false;
} }
ret = do_create_container_dir(s, c->lxc_conf); ret = do_create_container_dir(s, c->lxc_conf);
free(s); free(s);
return ret == 0; return ret == 0;
} }
...@@ -1219,15 +1270,19 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c, ...@@ -1219,15 +1270,19 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c,
static char *lxcbasename(char *path) static char *lxcbasename(char *path)
{ {
char *p = path + strlen(path) - 1; char *p;
p = path + strlen(path) - 1;
while (*p != '/' && p > path) while (*p != '/' && p > path)
p--; p--;
return p; return p;
} }
static bool create_run_template(struct lxc_container *c, char *tpath, bool need_null_stdfds, static bool create_run_template(struct lxc_container *c, char *tpath,
char *const argv[]) bool need_null_stdfds, char *const argv[])
{ {
int ret;
pid_t pid; pid_t pid;
if (!tpath) if (!tpath)
...@@ -1235,47 +1290,58 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ ...@@ -1235,47 +1290,58 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
SYSERROR("failed to fork task for container creation template"); SYSERROR("Failed to fork task for container creation template");
return false; return false;
} }
if (pid == 0) { /* child */ if (pid == 0) { /* child */
char *patharg, *namearg, *rootfsarg; int i, len;
struct lxc_storage *bdev = NULL; char *namearg, *patharg, *rootfsarg;
int i;
int ret, len, nargs = 0;
char **newargv; char **newargv;
int nargs = 0;
struct lxc_storage *bdev = NULL;
struct lxc_conf *conf = c->lxc_conf; struct lxc_conf *conf = c->lxc_conf;
uid_t euid;
if (need_null_stdfds && null_stdfds() < 0) { if (need_null_stdfds) {
exit(1); ret = null_stdfds();
if (ret < 0)
_exit(EXIT_FAILURE);
} }
bdev = storage_init(c->lxc_conf); bdev = storage_init(c->lxc_conf);
if (!bdev) { if (!bdev) {
ERROR("Error opening rootfs"); ERROR("Failed to initialize storage");
exit(1); _exit(EXIT_FAILURE);
} }
if (geteuid() == 0) { euid = geteuid();
if (unshare(CLONE_NEWNS) < 0) { if (euid == 0) {
ERROR("error unsharing mounts"); ret = unshare(CLONE_NEWNS);
exit(1); if (ret < 0) {
ERROR("Failed to unshare CLONE_NEWNS");
_exit(EXIT_FAILURE);
} }
if (detect_shared_rootfs()) {
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { ret = detect_shared_rootfs();
SYSERROR("Failed to make / rslave to run template"); if (ret == 1) {
ret = mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL);
if (ret < 0) {
SYSERROR("Failed to make \"/\" rslave");
ERROR("Continuing..."); ERROR("Continuing...");
} }
} }
} }
if (strcmp(bdev->type, "dir") && strcmp(bdev->type, "btrfs")) {
if (geteuid() != 0) { if (strcmp(bdev->type, "dir") != 0 && strcmp(bdev->type, "btrfs") != 0) {
ERROR("non-root users can only create btrfs and directory-backed containers"); if (euid != 0) {
exit(EXIT_FAILURE); ERROR("Unprivileged users can only create "
"btrfs and directory-backed containers");
_exit(EXIT_FAILURE);
} }
if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs")) { if (strcmp(bdev->type, "overlay") == 0 ||
strcmp(bdev->type, "overlayfs") == 0) {
/* If we create an overlay container we need to /* If we create an overlay container we need to
* rsync the contents into * rsync the contents into
* <container-path>/<container-name>/rootfs. * <container-path>/<container-name>/rootfs.
...@@ -1298,7 +1364,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ ...@@ -1298,7 +1364,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
src = ovl_get_rootfs(bdev->src, &(size_t){0}); src = ovl_get_rootfs(bdev->src, &(size_t){0});
if (!src) { if (!src) {
ERROR("Failed to get rootfs"); ERROR("Failed to get rootfs");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC, NULL); ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC, NULL);
...@@ -1307,9 +1373,10 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ ...@@ -1307,9 +1373,10 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
return -1; return -1;
} }
} else { } else {
if (bdev->ops->mount(bdev) < 0) { ret = bdev->ops->mount(bdev);
if (ret < 0) {
ERROR("Failed to mount rootfs"); ERROR("Failed to mount rootfs");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
} }
} else { /* TODO come up with a better way here! */ } else { /* TODO come up with a better way here! */
...@@ -1319,76 +1386,80 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ ...@@ -1319,76 +1386,80 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
bdev->dest = strdup(src); bdev->dest = strdup(src);
} }
/* /* Create our new array, pre-pend the template name and base
* create our new array, pre-pend the template name and * args.
* base args
*/ */
if (argv) if (argv)
for (nargs = 0; argv[nargs]; nargs++) ; for (nargs = 0; argv[nargs]; nargs++) {
nargs += 4; /* template, path, rootfs and name args */ ;
}
/* template, path, rootfs and name args */
nargs += 4;
newargv = malloc(nargs * sizeof(*newargv)); newargv = malloc(nargs * sizeof(*newargv));
if (!newargv) if (!newargv)
exit(1); _exit(EXIT_FAILURE);
newargv[0] = lxcbasename(tpath); newargv[0] = lxcbasename(tpath);
/* --path */
len = strlen(c->config_path) + strlen(c->name) + strlen("--path=") + 2; len = strlen(c->config_path) + strlen(c->name) + strlen("--path=") + 2;
patharg = malloc(len); patharg = malloc(len);
if (!patharg) if (!patharg)
exit(1); _exit(EXIT_FAILURE);
ret = snprintf(patharg, len, "--path=%s/%s", c->config_path, c->name); ret = snprintf(patharg, len, "--path=%s/%s", c->config_path, c->name);
if (ret < 0 || ret >= len) if (ret < 0 || ret >= len)
exit(1); _exit(EXIT_FAILURE);
newargv[1] = patharg; newargv[1] = patharg;
/* --name */
len = strlen("--name=") + strlen(c->name) + 1; len = strlen("--name=") + strlen(c->name) + 1;
namearg = malloc(len); namearg = malloc(len);
if (!namearg) if (!namearg)
exit(1); _exit(EXIT_FAILURE);
ret = snprintf(namearg, len, "--name=%s", c->name); ret = snprintf(namearg, len, "--name=%s", c->name);
if (ret < 0 || ret >= len) if (ret < 0 || ret >= len)
exit(1); _exit(EXIT_FAILURE);
newargv[2] = namearg; newargv[2] = namearg;
/* --rootfs */
len = strlen("--rootfs=") + 1 + strlen(bdev->dest); len = strlen("--rootfs=") + 1 + strlen(bdev->dest);
rootfsarg = malloc(len); rootfsarg = malloc(len);
if (!rootfsarg) if (!rootfsarg)
exit(1); _exit(EXIT_FAILURE);
ret = snprintf(rootfsarg, len, "--rootfs=%s", bdev->dest); ret = snprintf(rootfsarg, len, "--rootfs=%s", bdev->dest);
if (ret < 0 || ret >= len) if (ret < 0 || ret >= len)
exit(1); _exit(EXIT_FAILURE);
newargv[3] = rootfsarg; newargv[3] = rootfsarg;
/* add passed-in args */ /* add passed-in args */
if (argv) if (argv)
for (i = 4; i < nargs; i++) for (i = 4; i < nargs; i++)
newargv[i] = argv[i-4]; newargv[i] = argv[i - 4];
/* add trailing NULL */ /* add trailing NULL */
nargs++; nargs++;
newargv = realloc(newargv, nargs * sizeof(*newargv)); newargv = realloc(newargv, nargs * sizeof(*newargv));
if (!newargv) if (!newargv)
exit(1); _exit(EXIT_FAILURE);
newargv[nargs - 1] = NULL; newargv[nargs - 1] = NULL;
/* /* If we're running the template in a mapped userns, then we
* If we're running the template in a mapped userns, then * prepend the template command with: lxc-usernsexec <-m map1>
* we prepend the template command with: * ... <-m mapn> -- and we append "--mapped-uid x", where x is
* lxc-usernsexec <-m map1> ... <-m mapn> -- * the mapped uid for our geteuid()
* and we append "--mapped-uid x", where x is the mapped uid
* for our geteuid()
*/ */
if (!lxc_list_empty(&conf->id_map)) { if (!lxc_list_empty(&conf->id_map)) {
int n2args = 1; int extraargs, hostuid_mapped, hostgid_mapped;
char txtuid[20]; char **n2;
char txtgid[20]; char txtuid[20], txtgid[20];
char **n2 = malloc(n2args * sizeof(*n2));
struct lxc_list *it; struct lxc_list *it;
struct id_map *map; struct id_map *map;
int n2args = 1;
n2 = malloc(n2args * sizeof(*n2));
if (!n2)
_exit(EXIT_FAILURE);
if (!n2) {
SYSERROR("out of memory");
exit(1);
}
newargv[0] = tpath; newargv[0] = tpath;
tpath = "lxc-usernsexec"; tpath = "lxc-usernsexec";
n2[0] = "lxc-usernsexec"; n2[0] = "lxc-usernsexec";
...@@ -1397,97 +1468,103 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ ...@@ -1397,97 +1468,103 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
n2args += 2; n2args += 2;
n2 = realloc(n2, n2args * sizeof(char *)); n2 = realloc(n2, n2args * sizeof(char *));
if (!n2) if (!n2)
exit(1); _exit(EXIT_FAILURE);
n2[n2args-2] = "-m";
n2[n2args-1] = malloc(200); n2[n2args - 2] = "-m";
if (!n2[n2args-1]) n2[n2args - 1] = malloc(200);
exit(1); if (!n2[n2args - 1])
ret = snprintf(n2[n2args-1], 200, "%c:%lu:%lu:%lu", _exit(EXIT_FAILURE);
map->idtype == ID_TYPE_UID ? 'u' : 'g',
map->nsid, map->hostid, map->range); ret = snprintf(n2[n2args - 1], 200, "%c:%lu:%lu:%lu",
map->idtype == ID_TYPE_UID ? 'u' : 'g',
map->nsid, map->hostid, map->range);
if (ret < 0 || ret >= 200) if (ret < 0 || ret >= 200)
exit(1); _exit(EXIT_FAILURE);
} }
int hostid_mapped = mapped_hostid(geteuid(), conf, ID_TYPE_UID);
int extraargs = hostid_mapped >= 0 ? 1 : 3; hostuid_mapped = mapped_hostid(geteuid(), conf, ID_TYPE_UID);
extraargs = hostuid_mapped >= 0 ? 1 : 3;
n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(char *)); n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(char *));
if (!n2) if (!n2)
exit(1); _exit(EXIT_FAILURE);
if (hostid_mapped < 0) {
hostid_mapped = find_unmapped_nsid(conf, ID_TYPE_UID); if (hostuid_mapped < 0) {
hostuid_mapped = find_unmapped_nsid(conf, ID_TYPE_UID);
n2[n2args++] = "-m"; n2[n2args++] = "-m";
if (hostid_mapped < 0) { if (hostuid_mapped < 0) {
ERROR("Could not find free uid to map"); ERROR("Failed to find free uid to map");
exit(1); _exit(EXIT_FAILURE);
} }
n2[n2args++] = malloc(200); n2[n2args++] = malloc(200);
if (!n2[n2args-1]) { if (!n2[n2args - 1]) {
SYSERROR("out of memory"); SYSERROR("out of memory");
exit(1); _exit(EXIT_FAILURE);
}
ret = snprintf(n2[n2args-1], 200, "u:%d:%d:1",
hostid_mapped, geteuid());
if (ret < 0 || ret >= 200) {
ERROR("string too long");
exit(1);
} }
ret = snprintf(n2[n2args - 1], 200, "u:%d:%d:1",
hostuid_mapped, geteuid());
if (ret < 0 || ret >= 200)
_exit(EXIT_FAILURE);
} }
int hostgid_mapped = mapped_hostid(getegid(), conf, ID_TYPE_GID);
hostgid_mapped = mapped_hostid(getegid(), conf, ID_TYPE_GID);
extraargs = hostgid_mapped >= 0 ? 1 : 3; extraargs = hostgid_mapped >= 0 ? 1 : 3;
n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(char *)); n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(char *));
if (!n2) if (!n2)
exit(1); _exit(EXIT_FAILURE);
if (hostgid_mapped < 0) { if (hostgid_mapped < 0) {
hostgid_mapped = find_unmapped_nsid(conf, ID_TYPE_GID); hostgid_mapped = find_unmapped_nsid(conf, ID_TYPE_GID);
n2[n2args++] = "-m"; n2[n2args++] = "-m";
if (hostgid_mapped < 0) { if (hostgid_mapped < 0) {
ERROR("Could not find free uid to map"); ERROR("Failed to find free gid to map");
exit(1); _exit(EXIT_FAILURE);
} }
n2[n2args++] = malloc(200); n2[n2args++] = malloc(200);
if (!n2[n2args-1]) { if (!n2[n2args - 1]) {
SYSERROR("out of memory"); SYSERROR("out of memory");
exit(1); _exit(EXIT_FAILURE);
}
ret = snprintf(n2[n2args-1], 200, "g:%d:%d:1",
hostgid_mapped, getegid());
if (ret < 0 || ret >= 200) {
ERROR("string too long");
exit(1);
} }
ret = snprintf(n2[n2args - 1], 200, "g:%d:%d:1",
hostgid_mapped, getegid());
if (ret < 0 || ret >= 200)
_exit(EXIT_FAILURE);
} }
n2[n2args++] = "--"; n2[n2args++] = "--";
for (i = 0; i < nargs; i++) for (i = 0; i < nargs; i++)
n2[i + n2args] = newargv[i]; n2[i + n2args] = newargv[i];
n2args += nargs; n2args += nargs;
/* Finally add "--mapped-uid $uid" to tell template
* what to chown cached images to. /* Finally add "--mapped-uid $uid" to tell template what
* to chown cached images to.
*/ */
n2args += 4; n2args += 4;
n2 = realloc(n2, n2args * sizeof(char *)); n2 = realloc(n2, n2args * sizeof(char *));
if (!n2) { if (!n2)
SYSERROR("out of memory"); _exit(EXIT_FAILURE);
exit(1);
}
/* note n2[n2args-1] is NULL */ /* note n2[n2args-1] is NULL */
n2[n2args-5] = "--mapped-uid"; n2[n2args - 5] = "--mapped-uid";
snprintf(txtuid, 20, "%d", hostid_mapped); snprintf(txtuid, 20, "%d", hostuid_mapped);
n2[n2args-4] = txtuid; n2[n2args - 4] = txtuid;
n2[n2args-3] = "--mapped-gid"; n2[n2args - 3] = "--mapped-gid";
snprintf(txtgid, 20, "%d", hostgid_mapped); snprintf(txtgid, 20, "%d", hostgid_mapped);
n2[n2args-2] = txtgid; n2[n2args - 2] = txtgid;
n2[n2args-1] = NULL; n2[n2args - 1] = NULL;
free(newargv); free(newargv);
newargv = n2; newargv = n2;
} }
/* execute */
execvp(tpath, newargv); execvp(tpath, newargv);
SYSERROR("Failed to execute template %s", tpath); SYSERROR("Failed to execute template %s", tpath);
exit(1); _exit(EXIT_FAILURE);
} }
if (wait_for_pid(pid) != 0) { ret = wait_for_pid(pid);
ERROR("container creation template for %s failed", c->name); if (ret != 0) {
ERROR("Failed to create container from template");
return false; return false;
} }
...@@ -1618,8 +1695,8 @@ static void lxcapi_clear_config(struct lxc_container *c) ...@@ -1618,8 +1695,8 @@ static void lxcapi_clear_config(struct lxc_container *c)
* arguments, you can just pass NULL. * arguments, you can just pass NULL.
*/ */
static bool do_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,
char *const argv[]) int flags, char *const argv[])
{ {
int partial_fd; int partial_fd;
pid_t pid; pid_t pid;
...@@ -1713,7 +1790,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, ...@@ -1713,7 +1790,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
if (!bdev) { if (!bdev) {
ERROR("Failed to create %s storage for %s", ERROR("Failed to create %s storage for %s",
bdevtype ? bdevtype : "(none)", c->name); bdevtype ? bdevtype : "(none)", c->name);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* Save config file again to store the new rootfs location. */ /* Save config file again to store the new rootfs location. */
...@@ -1724,9 +1801,9 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, ...@@ -1724,9 +1801,9 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
*/ */
bdev->ops->umount(bdev); bdev->ops->umount(bdev);
bdev->ops->destroy(bdev); bdev->ops->destroy(bdev);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
} }
if (wait_for_pid(pid) != 0) if (wait_for_pid(pid) != 0)
goto out_unlock; goto out_unlock;
...@@ -2165,7 +2242,7 @@ static char ** do_lxcapi_get_interfaces(struct lxc_container *c) ...@@ -2165,7 +2242,7 @@ static char ** do_lxcapi_get_interfaces(struct lxc_container *c)
/* close the write-end of the pipe, thus sending EOF to the reader */ /* close the write-end of the pipe, thus sending EOF to the reader */
close(pipefd[1]); close(pipefd[1]);
exit(ret); _exit(ret);
} }
/* close the write-end of the pipe */ /* close the write-end of the pipe */
...@@ -2290,7 +2367,7 @@ static char** do_lxcapi_get_ips(struct lxc_container *c, const char* interface, ...@@ -2290,7 +2367,7 @@ static char** do_lxcapi_get_ips(struct lxc_container *c, const char* interface,
/* close the write-end of the pipe, thus sending EOF to the reader */ /* close the write-end of the pipe, thus sending EOF to the reader */
close(pipefd[1]); close(pipefd[1]);
exit(ret); _exit(ret);
} }
/* close the write-end of the pipe */ /* close the write-end of the pipe */
...@@ -2391,9 +2468,8 @@ WRAP_API_3(int, lxcapi_get_keys, const char *, char *, int) ...@@ -2391,9 +2468,8 @@ 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) static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file)
{ {
FILE *fout; int fd, lret;
bool ret = false, need_disklock = false; bool ret = false, need_disklock = false;
int lret;
if (!alt_file) if (!alt_file)
alt_file = c->configfile; alt_file = c->configfile;
...@@ -2403,7 +2479,10 @@ static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file) ...@@ -2403,7 +2479,10 @@ static bool do_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 (!do_lxcapi_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;
} }
} }
...@@ -2426,18 +2505,24 @@ static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file) ...@@ -2426,18 +2505,24 @@ static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file)
if (lret) if (lret)
return false; return false;
fout = fopen(alt_file, "w"); fd = open(alt_file, O_WRONLY | O_CREAT | O_CLOEXEC,
if (!fout) S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
goto out; if (fd < 0)
write_config(fout, c->lxc_conf); goto on_error;
fclose(fout);
lret = write_config(fd, c->lxc_conf);
close(fd);
if (lret < 0)
goto on_error;
ret = true; ret = true;
out: on_error:
if (need_disklock) if (need_disklock)
container_disk_unlock(c); container_disk_unlock(c);
else else
container_mem_unlock(c); container_mem_unlock(c);
return ret; return ret;
} }
...@@ -3488,10 +3573,9 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char ...@@ -3488,10 +3573,9 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
char **hookargs) char **hookargs)
{ {
char newpath[MAXPATHLEN]; char newpath[MAXPATHLEN];
int ret; int fd, ret;
struct clone_update_data data; struct clone_update_data data;
size_t saved_unexp_len; size_t saved_unexp_len;
FILE *fout;
pid_t pid; pid_t pid;
int storage_copied = 0; int storage_copied = 0;
char *origroot = NULL, *saved_unexp_conf = NULL; char *origroot = NULL, *saved_unexp_conf = NULL;
...@@ -3535,9 +3619,11 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char ...@@ -3535,9 +3619,11 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
origroot = c->lxc_conf->rootfs.path; origroot = c->lxc_conf->rootfs.path;
c->lxc_conf->rootfs.path = NULL; c->lxc_conf->rootfs.path = NULL;
} }
fout = fopen(newpath, "w");
if (!fout) { fd = open(newpath, O_WRONLY | O_CREAT | O_CLOEXEC,
SYSERROR("open %s", newpath); S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (fd < 0) {
SYSERROR("Failed to open \"%s\"", newpath);
goto out; goto out;
} }
...@@ -3545,14 +3631,13 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char ...@@ -3545,14 +3631,13 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
saved_unexp_len = c->lxc_conf->unexpanded_len; saved_unexp_len = c->lxc_conf->unexpanded_len;
c->lxc_conf->unexpanded_config = strdup(saved_unexp_conf); c->lxc_conf->unexpanded_config = strdup(saved_unexp_conf);
if (!c->lxc_conf->unexpanded_config) { if (!c->lxc_conf->unexpanded_config) {
ERROR("Out of memory"); close(fd);
fclose(fout);
goto out; goto out;
} }
clear_unexp_config_line(c->lxc_conf, "lxc.rootfs.path", false); clear_unexp_config_line(c->lxc_conf, "lxc.rootfs.path", false);
write_config(fout, c->lxc_conf); write_config(fd, c->lxc_conf);
fclose(fout); close(fd);
c->lxc_conf->rootfs.path = origroot; c->lxc_conf->rootfs.path = origroot;
free(c->lxc_conf->unexpanded_config); free(c->lxc_conf->unexpanded_config);
c->lxc_conf->unexpanded_config = saved_unexp_conf; c->lxc_conf->unexpanded_config = saved_unexp_conf;
...@@ -3662,10 +3747,10 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char ...@@ -3662,10 +3747,10 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
else else
ret = clone_update_rootfs(&data); ret = clone_update_rootfs(&data);
if (ret < 0) if (ret < 0)
exit(1); _exit(EXIT_FAILURE);
container_mem_unlock(c); container_mem_unlock(c);
exit(0); _exit(EXIT_SUCCESS);
out: out:
container_mem_unlock(c); container_mem_unlock(c);
...@@ -4235,11 +4320,11 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add, ...@@ -4235,11 +4320,11 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
ret = chroot(chrootpath); ret = chroot(chrootpath);
if (ret < 0) if (ret < 0)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
ret = chdir("/"); ret = chdir("/");
if (ret < 0) if (ret < 0)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
/* remove path if it exists */ /* remove path if it exists */
ret = faccessat(AT_FDCWD, path, F_OK, AT_SYMLINK_NOFOLLOW); ret = faccessat(AT_FDCWD, path, F_OK, AT_SYMLINK_NOFOLLOW);
...@@ -4247,24 +4332,24 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add, ...@@ -4247,24 +4332,24 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
ret = unlink(path); ret = unlink(path);
if (ret < 0) { if (ret < 0) {
ERROR("%s - Failed to remove \"%s\"", strerror(errno), path); ERROR("%s - Failed to remove \"%s\"", strerror(errno), path);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
} }
if (!add) if (!add)
exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
/* create any missing directories */ /* create any missing directories */
tmp = strdup(path); tmp = strdup(path);
if (!tmp) if (!tmp)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
directory_path = dirname(tmp); directory_path = dirname(tmp);
ret = mkdir_p(directory_path, 0755); ret = mkdir_p(directory_path, 0755);
if (ret < 0 && errno != EEXIST) { if (ret < 0 && errno != EEXIST) {
ERROR("%s - Failed to create path \"%s\"", strerror(errno), directory_path); ERROR("%s - Failed to create path \"%s\"", strerror(errno), directory_path);
free(tmp); free(tmp);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* create the device node */ /* create the device node */
...@@ -4272,17 +4357,17 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add, ...@@ -4272,17 +4357,17 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
free(tmp); free(tmp);
if (ret < 0) { if (ret < 0) {
ERROR("%s - Failed to create device node at \"%s\"", strerror(errno), path); ERROR("%s - Failed to create device node at \"%s\"", strerror(errno), path);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
} }
static bool add_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path, bool add) static bool add_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path, bool add)
{ {
int ret; int ret;
struct stat st; struct stat st;
char value[MAX_BUFFER]; char value[LXC_MAX_BUFFER];
const char *p; const char *p;
/* make sure container is running */ /* make sure container is running */
...@@ -4300,14 +4385,14 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path ...@@ -4300,14 +4385,14 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
/* continue if path is character device or block device */ /* continue if path is character device or block device */
if (S_ISCHR(st.st_mode)) if (S_ISCHR(st.st_mode))
ret = snprintf(value, MAX_BUFFER, "c %d:%d rwm", major(st.st_rdev), minor(st.st_rdev)); ret = snprintf(value, LXC_MAX_BUFFER, "c %d:%d rwm", major(st.st_rdev), minor(st.st_rdev));
else if (S_ISBLK(st.st_mode)) else if (S_ISBLK(st.st_mode))
ret = snprintf(value, MAX_BUFFER, "b %d:%d rwm", major(st.st_rdev), minor(st.st_rdev)); ret = snprintf(value, LXC_MAX_BUFFER, "b %d:%d rwm", major(st.st_rdev), minor(st.st_rdev));
else else
return false; return false;
/* check snprintf return code */ /* check snprintf return code */
if (ret < 0 || ret >= MAX_BUFFER) if (ret < 0 || ret >= LXC_MAX_BUFFER)
return false; return false;
if (!do_add_remove_node(do_lxcapi_init_pid(c), p, add, &st)) if (!do_add_remove_node(do_lxcapi_init_pid(c), p, add, &st))
...@@ -4333,7 +4418,7 @@ static bool do_lxcapi_add_device_node(struct lxc_container *c, const char *src_p ...@@ -4333,7 +4418,7 @@ static bool do_lxcapi_add_device_node(struct lxc_container *c, const char *src_p
{ {
// cannot mknod if we're not privileged wrt init_user_ns // cannot mknod if we're not privileged wrt init_user_ns
if (am_host_unpriv()) { if (am_host_unpriv()) {
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__); ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__);
return false; return false;
} }
return add_remove_device_node(c, src_path, dest_path, true); return add_remove_device_node(c, src_path, dest_path, true);
...@@ -4344,7 +4429,7 @@ WRAP_API_2(bool, lxcapi_add_device_node, const char *, const char *) ...@@ -4344,7 +4429,7 @@ 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) static bool do_lxcapi_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path)
{ {
if (am_guest_unpriv()) { if (am_guest_unpriv()) {
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__); ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__);
return false; return false;
} }
return add_remove_device_node(c, src_path, dest_path, false); return add_remove_device_node(c, src_path, dest_path, false);
...@@ -4360,7 +4445,7 @@ static bool do_lxcapi_attach_interface(struct lxc_container *c, ...@@ -4360,7 +4445,7 @@ static bool do_lxcapi_attach_interface(struct lxc_container *c,
int ret = 0; int ret = 0;
if (am_guest_unpriv()) { if (am_guest_unpriv()) {
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__); ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__);
return false; return false;
} }
...@@ -4403,7 +4488,7 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c, ...@@ -4403,7 +4488,7 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c,
* But for other types guest privilege suffices. * But for other types guest privilege suffices.
*/ */
if (am_guest_unpriv()) { if (am_guest_unpriv()) {
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__); ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__);
return false; return false;
} }
...@@ -4425,13 +4510,13 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c, ...@@ -4425,13 +4510,13 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c,
init_pid = do_lxcapi_init_pid(c); init_pid = do_lxcapi_init_pid(c);
if (!switch_to_ns(init_pid, "net")) { if (!switch_to_ns(init_pid, "net")) {
ERROR("Failed to enter network namespace"); ERROR("Failed to enter network namespace");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
ret = lxc_netdev_isup(ifname); ret = lxc_netdev_isup(ifname);
if (ret < 0) { if (ret < 0) {
ERROR("Failed to determine whether network device \"%s\" is up", ifname); ERROR("Failed to determine whether network device \"%s\" is up", ifname);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* netdev of ifname is up. */ /* netdev of ifname is up. */
...@@ -4439,7 +4524,7 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c, ...@@ -4439,7 +4524,7 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c,
ret = lxc_netdev_down(ifname); ret = lxc_netdev_down(ifname);
if (ret) { if (ret) {
ERROR("Failed to set network device \"%s\" down", ifname); ERROR("Failed to set network device \"%s\" down", ifname);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
} }
...@@ -4450,10 +4535,10 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c, ...@@ -4450,10 +4535,10 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c,
ERROR("Network device \"%s\" not found", ifname); ERROR("Network device \"%s\" not found", ifname);
else else
ERROR("Failed to remove network device \"%s\"", ifname); ERROR("Failed to remove network device \"%s\"", ifname);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
} }
ret = wait_for_pid(pid); ret = wait_for_pid(pid);
......
...@@ -72,10 +72,11 @@ static void lock_mutex(pthread_mutex_t *l) ...@@ -72,10 +72,11 @@ static void lock_mutex(pthread_mutex_t *l)
{ {
int ret; int ret;
if ((ret = pthread_mutex_lock(l)) != 0) { ret = pthread_mutex_lock(l);
fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret)); if (ret != 0) {
fprintf(stderr, "%s - Failed acquire mutex", strerror(ret));
dump_stacktrace(); dump_stacktrace();
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
} }
...@@ -83,11 +84,11 @@ static void unlock_mutex(pthread_mutex_t *l) ...@@ -83,11 +84,11 @@ static void unlock_mutex(pthread_mutex_t *l)
{ {
int ret; int ret;
if ((ret = pthread_mutex_unlock(l)) != 0) { ret = pthread_mutex_unlock(l);
fprintf(stderr, "%s: pthread_mutex_unlock returned:%d %s\n", if (ret != 0) {
__FILE__, ret, strerror(ret)); fprintf(stderr, "%s - Failed to release mutex", strerror(ret));
dump_stacktrace(); dump_stacktrace();
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
} }
......
...@@ -635,7 +635,7 @@ static int lxc_netdev_rename_by_name_in_netns(pid_t pid, const char *old, ...@@ -635,7 +635,7 @@ static int lxc_netdev_rename_by_name_in_netns(pid_t pid, const char *old,
if (!switch_to_ns(pid, "net")) if (!switch_to_ns(pid, "net"))
return -1; return -1;
exit(lxc_netdev_rename_by_name(old, new)); _exit(lxc_netdev_rename_by_name(old, new));
} }
static int lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid, static int lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid,
...@@ -663,7 +663,7 @@ static int lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid, ...@@ -663,7 +663,7 @@ static int lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid,
sprintf(pidstr, "%d", pid); sprintf(pidstr, "%d", pid);
execlp("iw", "iw", "phy", physname, "set", "netns", pidstr, execlp("iw", "iw", "phy", physname, "set", "netns", pidstr,
(char *)NULL); (char *)NULL);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
if (wait_for_pid(fpid)) if (wait_for_pid(fpid))
...@@ -2126,7 +2126,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna ...@@ -2126,7 +2126,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
close(pipefd[1]); close(pipefd[1]);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to duplicate std{err,out} file descriptor"); SYSERROR("Failed to duplicate std{err,out} file descriptor");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
if (netdev->link[0] != '\0') if (netdev->link[0] != '\0')
...@@ -2136,7 +2136,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna ...@@ -2136,7 +2136,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid); ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
if (ret < 0 || ret >= LXC_NUMSTRLEN64) if (ret < 0 || ret >= LXC_NUMSTRLEN64)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
pidstr[LXC_NUMSTRLEN64 - 1] = '\0'; pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
INFO("Execing lxc-user-nic create %s %s %s veth %s %s", lxcpath, INFO("Execing lxc-user-nic create %s %s %s veth %s %s", lxcpath,
...@@ -2151,7 +2151,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna ...@@ -2151,7 +2151,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
lxcpath, lxcname, pidstr, "veth", netdev_link, lxcpath, lxcname, pidstr, "veth", netdev_link,
(char *)NULL); (char *)NULL);
SYSERROR("Failed to execute lxc-user-nic"); SYSERROR("Failed to execute lxc-user-nic");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* close the write-end of the pipe */ /* close the write-end of the pipe */
...@@ -2269,7 +2269,7 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna ...@@ -2269,7 +2269,7 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
close(pipefd[1]); close(pipefd[1]);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to duplicate std{err,out} file descriptor"); SYSERROR("Failed to duplicate std{err,out} file descriptor");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
if (netdev->priv.veth_attr.pair[0] != '\0') if (netdev->priv.veth_attr.pair[0] != '\0')
...@@ -2278,13 +2278,13 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna ...@@ -2278,13 +2278,13 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
hostveth = netdev->priv.veth_attr.veth1; hostveth = netdev->priv.veth_attr.veth1;
if (hostveth[0] == '\0') { if (hostveth[0] == '\0') {
SYSERROR("Host side veth device name is missing"); SYSERROR("Host side veth device name is missing");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
if (netdev->link[0] == '\0') { if (netdev->link[0] == '\0') {
SYSERROR("Network link for network device \"%s\" is " SYSERROR("Network link for network device \"%s\" is "
"missing", netdev->priv.veth_attr.veth1); "missing", netdev->priv.veth_attr.veth1);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
INFO("Execing lxc-user-nic delete %s %s %s veth %s %s", lxcpath, INFO("Execing lxc-user-nic delete %s %s %s veth %s %s", lxcpath,
...@@ -2293,7 +2293,7 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna ...@@ -2293,7 +2293,7 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
lxcname, netns_path, "veth", netdev->link, hostveth, lxcname, netns_path, "veth", netdev->link, hostveth,
(char *)NULL); (char *)NULL);
SYSERROR("Failed to exec lxc-user-nic."); SYSERROR("Failed to exec lxc-user-nic.");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
close(pipefd[1]); close(pipefd[1]);
......
...@@ -20,13 +20,15 @@ ...@@ -20,13 +20,15 @@
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#undef _GNU_SOURCE #undef _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include "parse.h" #include "parse.h"
#include "config.h" #include "config.h"
...@@ -35,6 +37,77 @@ ...@@ -35,6 +37,77 @@
lxc_log_define(lxc_parse, lxc); lxc_log_define(lxc_parse, lxc);
void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset)
{
void *tmp = NULL, *overlap = NULL;
/* We establish an anonymous mapping that is one byte larger than the
* underlying file. The pages handed to us are zero filled. */
tmp = mmap(addr, length + 1, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (tmp == MAP_FAILED)
return tmp;
/* Now we establish a fixed-address mapping starting at the address we
* received from our anonymous mapping and replace all bytes excluding
* the additional \0-byte with the file. This allows us to use normal
* string-handling functions. */
overlap = mmap(tmp, length, prot, MAP_FIXED | flags, fd, offset);
if (overlap == MAP_FAILED)
munmap(tmp, length + 1);
return overlap;
}
int lxc_strmunmap(void *addr, size_t length)
{
return munmap(addr, length + 1);
}
int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback,
void *data)
{
int fd, ret;
char *buf, *line;
struct stat st;
char *saveptr = NULL;
fd = open(file, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return -1;
ret = fstat(fd, &st);
if (ret < 0) {
close(fd);
return -1;
}
if (st.st_size == 0)
return 0;
buf = lxc_strmmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (buf == MAP_FAILED) {
close(fd);
return -1;
}
for (; (line = strtok_r(buf, "\n\0", &saveptr)); buf = NULL) {
ret = callback(line, data);
if (ret) {
/* Callback rv > 0 means stop here callback rv < 0 means
* error.
*/
if (ret < 0)
ERROR("Failed to parse config: %s", line);
break;
}
}
lxc_strmunmap(buf, st.st_size);
close(fd);
return 0;
}
int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data) int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data)
{ {
FILE *f; FILE *f;
......
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
#ifndef __LXC_PARSE_H #ifndef __LXC_PARSE_H
#define __LXC_PARSE_H #define __LXC_PARSE_H
#include <stdio.h>
#include <sys/types.h>
typedef int (*lxc_dir_cb)(const char *name, const char *directory, typedef int (*lxc_dir_cb)(const char *name, const char *directory,
const char *file, void *data); const char *file, void *data);
...@@ -31,10 +34,20 @@ typedef int (*lxc_file_cb)(char *buffer, void *data); ...@@ -31,10 +34,20 @@ typedef int (*lxc_file_cb)(char *buffer, void *data);
extern int lxc_file_for_each_line(const char *file, lxc_file_cb callback, extern int lxc_file_for_each_line(const char *file, lxc_file_cb callback,
void* data); void* data);
extern int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback,
void *data);
extern int lxc_char_left_gc(const char *buffer, size_t len); extern int lxc_char_left_gc(const char *buffer, size_t len);
extern int lxc_char_right_gc(const char *buffer, size_t len); extern int lxc_char_right_gc(const char *buffer, size_t len);
extern int lxc_is_line_empty(const char *line); extern int lxc_is_line_empty(const char *line);
/* mmap() wrapper. lxc_strmmap() will take care to \0-terminate files so that
* normal string-handling functions can be used on the buffer. */
extern void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset);
/* munmap() wrapper. Use it to free memory mmap()ed with lxc_strmmap(). */
extern int lxc_strmunmap(void *addr, size_t length);
#endif #endif
...@@ -478,7 +478,7 @@ struct lxc_popen_FILE *lxc_popen(const char *command) ...@@ -478,7 +478,7 @@ struct lxc_popen_FILE *lxc_popen(const char *command)
ret = fcntl(pipe_fds[1], F_SETFD, 0); ret = fcntl(pipe_fds[1], F_SETFD, 0);
if (ret < 0) { if (ret < 0) {
close(pipe_fds[1]); close(pipe_fds[1]);
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* duplicate stderr */ /* duplicate stderr */
...@@ -488,19 +488,19 @@ struct lxc_popen_FILE *lxc_popen(const char *command) ...@@ -488,19 +488,19 @@ struct lxc_popen_FILE *lxc_popen(const char *command)
ret = fcntl(pipe_fds[1], F_SETFD, 0); ret = fcntl(pipe_fds[1], F_SETFD, 0);
close(pipe_fds[1]); close(pipe_fds[1]);
if (ret < 0) if (ret < 0)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
/* unblock all signals */ /* unblock all signals */
ret = sigfillset(&mask); ret = sigfillset(&mask);
if (ret < 0) if (ret < 0)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
ret = sigprocmask(SIG_UNBLOCK, &mask, NULL); ret = sigprocmask(SIG_UNBLOCK, &mask, NULL);
if (ret < 0) if (ret < 0)
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
execl("/bin/sh", "sh", "-c", command, (char *)NULL); execl("/bin/sh", "sh", "-c", command, (char *)NULL);
exit(127); _exit(127);
} }
close(pipe_fds[1]); close(pipe_fds[1]);
...@@ -1810,33 +1810,6 @@ int lxc_count_file_lines(const char *fn) ...@@ -1810,33 +1810,6 @@ int lxc_count_file_lines(const char *fn)
return n; return n;
} }
void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset)
{
void *tmp = NULL, *overlap = NULL;
/* We establish an anonymous mapping that is one byte larger than the
* underlying file. The pages handed to us are zero filled. */
tmp = mmap(addr, length + 1, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (tmp == MAP_FAILED)
return tmp;
/* Now we establish a fixed-address mapping starting at the address we
* received from our anonymous mapping and replace all bytes excluding
* the additional \0-byte with the file. This allows us to use normal
* string-handling functions. */
overlap = mmap(tmp, length, prot, MAP_FIXED | flags, fd, offset);
if (overlap == MAP_FAILED)
munmap(tmp, length + 1);
return overlap;
}
int lxc_strmunmap(void *addr, size_t length)
{
return munmap(addr, length + 1);
}
/* Check whether a signal is blocked by a process. */ /* Check whether a signal is blocked by a process. */
/* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */ /* /proc/pid-to-str/status\0 = (5 + 21 + 7 + 1) */
#define __PROC_STATUS_LEN (5 + (LXC_NUMSTRLEN64) + 7 + 1) #define __PROC_STATUS_LEN (5 + (LXC_NUMSTRLEN64) + 7 + 1)
...@@ -2269,13 +2242,13 @@ int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args) ...@@ -2269,13 +2242,13 @@ int run_command(char *buf, size_t buf_size, int (*child_fn)(void *), void *args)
if (ret < 0) { if (ret < 0) {
SYSERROR("failed to duplicate std{err,out} file descriptor"); SYSERROR("failed to duplicate std{err,out} file descriptor");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* Does not return. */ /* Does not return. */
child_fn(args); child_fn(args);
ERROR("failed to exec command"); ERROR("failed to exec command");
exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* close the write-end of the pipe */ /* close the write-end of the pipe */
......
...@@ -100,6 +100,7 @@ ...@@ -100,6 +100,7 @@
#define LXC_NUMSTRLEN64 21 #define LXC_NUMSTRLEN64 21
#define LXC_LINELEN 4096 #define LXC_LINELEN 4096
#define LXC_IDMAPLEN 4096 #define LXC_IDMAPLEN 4096
#define LXC_MAX_BUFFER 4096
/* returns 1 on success, 0 if there were any failures */ /* returns 1 on success, 0 if there were any failures */
extern int lxc_rmdir_onedev(const char *path, const char *exclude); extern int lxc_rmdir_onedev(const char *path, const char *exclude);
...@@ -426,13 +427,6 @@ extern size_t lxc_array_len(void **array); ...@@ -426,13 +427,6 @@ extern size_t lxc_array_len(void **array);
extern void **lxc_append_null_to_array(void **array, size_t count); extern void **lxc_append_null_to_array(void **array, size_t count);
/* mmap() wrapper. lxc_strmmap() will take care to \0-terminate files so that
* normal string-handling functions can be used on the buffer. */
extern void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset);
/* munmap() wrapper. Use it to free memory mmap()ed with lxc_strmmap(). */
extern int lxc_strmunmap(void *addr, size_t length);
/* initialize rand with urandom */ /* initialize rand with urandom */
extern int randseed(bool); extern int randseed(bool);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment