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
# Binaries shipping with liblxc
init_lxc_SOURCES = cmd/lxc_init.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
if ENABLE_DEPRECATED
......
......@@ -327,7 +327,7 @@ struct hierarchy *get_hierarchy(const char *c)
!hierarchies[i]->controllers[0])
return hierarchies[i];
return NULL;
continue;
}
if (string_in_list(hierarchies[i]->controllers, c))
......@@ -1306,8 +1306,11 @@ static bool cg_hybrid_init(void)
controller_list = cg_unified_get_controllers(cgv2_ctrl_path);
free(cgv2_ctrl_path);
if (!controller_list)
if (!controller_list) {
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);
......@@ -2365,13 +2368,16 @@ static bool cgfsng_unfreeze(void *hdata)
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;
h = get_hierarchy(subsystem);
if (!h)
h = get_hierarchy(controller);
if (!h) {
SYSERROR("Failed to find hierarchy for controller \"%s\"",
controller ? controller : "(null)");
return NULL;
}
return h->fullcgpath ? h->fullcgpath + strlen(h->mountpoint) : NULL;
}
......
......@@ -48,6 +48,7 @@
#include "config.h"
#include "namespace.h"
#include "network.h"
#include "parse.h"
#include "utils.h"
#define usernic_debug_stream(stream, format, ...) \
......
......@@ -2334,7 +2334,7 @@ int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
if (!conf->rcfile)
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)
......@@ -2417,17 +2417,21 @@ signed long lxc_config_parse_arch(const char *arch)
}
/* 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;
size_t len = c->unexpanded_len;
size_t len = conf->unexpanded_len;
if (!len)
return;
if (len == 0)
return 0;
ret = fwrite(c->unexpanded_config, 1, len, fout);
if (ret != len)
ret = lxc_write_nointr(fd, conf->unexpanded_config, len);
if (ret < 0) {
SYSERROR("Failed to write configuration file");
return -1;
}
return 0;
}
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);
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,
const char *v);
......
......@@ -717,13 +717,13 @@ bool __criu_check_feature(uint64_t *features_to_check)
* LXC checking only for 'uffd' makes not much sense. */
args[3] = "uffd-noncoop";
else
exit(1);
_exit(EXIT_FAILURE);
null_stdfds();
execvp("criu", args);
SYSERROR("Failed to exec \"criu\"");
exit(1);
_exit(EXIT_FAILURE);
}
ret = wait_for_pid(pid);
......@@ -785,14 +785,14 @@ static bool criu_version_ok(char **version)
close(STDERR_FILENO);
if (dup2(pipes[1], STDOUT_FILENO) < 0)
exit(1);
_exit(EXIT_FAILURE);
path = on_path("criu", NULL);
if (!path)
exit(1);
_exit(EXIT_FAILURE);
execv(path, args);
exit(1);
_exit(EXIT_FAILURE);
} else {
FILE *f;
char *tmp;
......@@ -923,7 +923,7 @@ out_unlock:
}
/* 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)
{
......@@ -1140,7 +1140,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
if (ret)
lxc_abort(c->name, handler);
lxc_fini(c->name, handler);
exit(ret);
_exit(ret);
}
out_fini_handler:
......@@ -1165,7 +1165,7 @@ out:
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)
......@@ -1256,7 +1256,7 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
h.name = c->name;
if (!cgroup_init(&h)) {
ERROR("failed to cgroup_init()");
exit(1);
_exit(EXIT_FAILURE);
}
os.pipefd = criuout[1];
......@@ -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));
if (ret < 0) {
free(criu_version);
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
/* exec_criu() returning is an error */
exec_criu(&os);
free(criu_version);
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
} else {
int status;
ssize_t n;
......
......@@ -24,6 +24,7 @@
#define __LXC_ERROR_H
#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);
......
......@@ -49,6 +49,7 @@
#include "confile_utils.h"
#include "console.h"
#include "criu.h"
#include "error.h"
#include "initutils.h"
#include "log.h"
#include "lxc.h"
......@@ -57,6 +58,7 @@
#include "monitor.h"
#include "namespace.h"
#include "network.h"
#include "parse.h"
#include "start.h"
#include "state.h"
#include "storage.h"
......@@ -69,7 +71,7 @@
/* major()/minor() */
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
#include <sys/mkdev.h>
#endif
#if HAVE_IFADDRS_H
......@@ -84,19 +86,15 @@
#include <mntent.h>
#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 */
#ifndef HAVE_FACCESSAT
static int faccessat(int __fd, const char *__file, int __type, int __flag)
{
#ifdef __NR_faccessat
return syscall(__NR_faccessat, __fd, __file, __type, __flag);
return syscall(__NR_faccessat, __fd, __file, __type, __flag);
#else
errno = ENOSYS;
return -1;
errno = ENOSYS;
return -1;
#endif
}
#endif
......@@ -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)
{
/* $lxcpath + '/' + $cname + '/config' + \0 */
int ret, len = strlen(lxcpath) + strlen(cname) + 9;
char *fname = alloca(len);
int ret;
size_t len;
char *fname;
ret = snprintf(fname, len, "%s/%s/config", lxcpath, cname);
if (ret < 0 || ret >= len)
/* $lxcpath + '/' + $cname + '/config' + \0 */
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 file_exists(fname);
}
/*
* A few functions to help detect when a container creation failed.
* If a container creation was killed partway through, then trying
* to actually start that container could harm the host. We detect
* this by creating a 'partial' file under the container directory,
* and keeping an advisory lock. When container creation completes,
* we remove that file. When we load or try to start a container, if
* we find that file, without a flock, we remove the container.
/* A few functions to help detect when a container creation failed. If a
* container creation was killed partway through, then trying to actually start
* that container could harm the host. We detect this by creating a 'partial'
* file under the container directory, and keeping an advisory lock. When
* container creation completes, we remove that file. When we load or try to
* start a container, if we find that file, without a flock, we remove the
* container.
*/
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;
size_t len;
char *path;
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);
if (ret < 0 || ret >= len) {
ERROR("Error writing partial pathname");
if (ret < 0 || (size_t)ret >= len)
return -1;
}
if (!file_exists(path))
return 0;
fd = open(path, O_RDWR);
if (fd < 0) {
/* give benefit of the doubt */
SYSERROR("Error opening partial file");
if (fd < 0)
return 0;
}
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
lk.l_start = 0;
lk.l_len = 0;
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 */
close(fd);
return 1;
}
/* create completed but partial is still there. */
close(fd);
/* Create completed but partial is still there. */
return 2;
}
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;
size_t len;
char *path;
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);
if (ret < 0 || ret >= len) {
ERROR("Error writing partial pathname");
if (ret < 0 || (size_t)ret >= len)
return -1;
}
if ((fd=open(path, O_RDWR | O_CREAT | O_EXCL, 0755)) < 0) {
SYSERROR("Error creating partial file");
fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0755);
if (fd < 0)
return -1;
}
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
lk.l_start = 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);
return -1;
}
......@@ -203,19 +207,21 @@ static int create_partial(struct lxc_container *c)
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;
size_t len;
char *path;
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);
if (ret < 0 || ret >= len) {
ERROR("Error writing partial pathname");
if (ret < 0 || (size_t)ret >= len)
return;
}
if (unlink(path) < 0)
SYSERROR("Error unlink partial file %s", path);
ret = unlink(path);
if (ret < 0)
SYSERROR("Failed to remove partial file %s", path);
}
/* LOCKING
......@@ -247,41 +253,49 @@ static void lxc_container_free(struct lxc_container *c)
free(c->configfile);
c->configfile = NULL;
free(c->error_string);
c->error_string = NULL;
if (c->slock) {
lxc_putlock(c->slock);
c->slock = NULL;
}
if (c->privlock) {
lxc_putlock(c->privlock);
c->privlock = NULL;
}
free(c->name);
c->name = NULL;
if (c->lxc_conf) {
lxc_conf_free(c->lxc_conf);
c->lxc_conf = NULL;
}
free(c->config_path);
c->config_path = NULL;
free(c);
}
/*
* Consider the following case:
freer | racing get()er
==================================================================
lxc_container_put() | lxc_container_get()
\ lxclock(c->privlock) | c->numthreads < 1? (no)
\ c->numthreads = 0 | \ lxclock(c->privlock) -> waits
\ lxcunlock() | \
\ lxc_container_free() | \ lxclock() returns
| \ c->numthreads < 1 -> return 0
\ \ (free stuff) |
\ \ sem_destroy(privlock) |
/* Consider the following case:
*
* |====================================================================|
* | freer | racing get()er |
* |====================================================================|
* | lxc_container_put() | lxc_container_get() |
* | \ lxclock(c->privlock) | c->numthreads < 1? (no) |
* | \ c->numthreads = 0 | \ lxclock(c->privlock) -> waits |
* | \ lxcunlock() | \ |
* | \ lxc_container_free() | \ lxclock() returns |
* | | \ c->numthreads < 1 -> return 0 |
* | \ \ (free stuff) | |
* | \ \ sem_destroy(privlock) | |
* |_______________________________|____________________________________|
*
* When the get()er checks numthreads the first time, one of the following
* is true:
* 1. freer has set numthreads = 0. get() returns 0
......@@ -314,6 +328,7 @@ int lxc_container_get(struct lxc_container *c)
c->numthreads++;
container_mem_unlock(c);
return 1;
}
......@@ -321,37 +336,45 @@ int lxc_container_put(struct lxc_container *c)
{
if (!c)
return -1;
if (container_mem_lock(c))
return -1;
if (--c->numthreads < 1) {
container_mem_unlock(c);
lxc_container_free(c);
return 1;
}
container_mem_unlock(c);
return 0;
}
static bool do_lxcapi_is_defined(struct lxc_container *c)
{
int statret;
struct stat statbuf;
bool ret = false;
int statret;
if (!c)
return false;
if (container_mem_lock(c))
return false;
if (!c->configfile)
goto out;
goto on_error;
statret = stat(c->configfile, &statbuf);
if (statret != 0)
goto out;
goto on_error;
ret = true;
out:
on_error:
container_mem_unlock(c);
return ret;
}
......@@ -435,6 +458,7 @@ static const char *do_lxcapi_state(struct lxc_container *c)
if (!c)
return NULL;
s = lxc_getstate(c->name, c->config_path);
return lxc_state2str(s);
}
......@@ -444,6 +468,7 @@ WRAP_API(const char *, lxcapi_state)
static bool is_stopped(struct lxc_container *c)
{
lxc_state_t s;
s = lxc_getstate(c->name, c->config_path);
return (s == STOPPED);
}
......@@ -454,9 +479,11 @@ static bool do_lxcapi_is_running(struct lxc_container *c)
if (!c)
return false;
s = do_lxcapi_state(c);
if (!s || strcmp(s, "STOPPED") == 0)
return false;
return true;
}
......@@ -465,12 +492,14 @@ WRAP_API(bool, lxcapi_is_running)
static bool do_lxcapi_freeze(struct lxc_container *c)
{
int ret;
if (!c)
return false;
ret = lxc_freeze(c->name, c->config_path);
if (ret)
return false;
return true;
}
......@@ -479,12 +508,14 @@ WRAP_API(bool, lxcapi_freeze)
static bool do_lxcapi_unfreeze(struct lxc_container *c)
{
int ret;
if (!c)
return false;
ret = lxc_unfreeze(c->name, c->config_path);
if (ret)
return false;
return true;
}
......@@ -492,12 +523,10 @@ WRAP_API(bool, lxcapi_unfreeze)
static int do_lxcapi_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
{
int ttyfd;
if (!c)
return -1;
ttyfd = lxc_console_getfd(c, ttynum, masterfd);
return ttyfd;
return lxc_console_getfd(c, ttynum, masterfd);
}
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,
current_config = c->lxc_conf;
ret = lxc_console(c, ttynum, stdinfd, stdoutfd, stderrfd, escape);
current_config = NULL;
return ret;
}
......@@ -553,18 +583,22 @@ static bool load_config_locked(struct lxc_container *c, const char *fname)
{
if (!c->lxc_conf)
c->lxc_conf = lxc_conf_init();
if (!c->lxc_conf)
return false;
if (lxc_config_read(fname, c->lxc_conf, false) != 0)
return false;
return true;
}
static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file)
{
bool ret = false, need_disklock = false;
int lret;
const char *fname;
bool need_disklock = false, ret = false;
if (!c)
return false;
......@@ -573,10 +607,10 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file)
fname = alt_file;
if (!fname)
return false;
/*
* If we're reading something other than the container's config,
* we only need to lock the in-memory container. If loading the
* container's config file, take the disk lock.
/* If we're reading something other than the container's config, we only
* need to lock the in-memory container. If loading the container's
* config file, take the disk lock.
*/
if (strcmp(fname, c->configfile) == 0)
need_disklock = true;
......@@ -594,6 +628,7 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file)
container_disk_unlock(c);
else
container_mem_unlock(c);
return ret;
}
......@@ -603,12 +638,13 @@ static bool do_lxcapi_want_daemonize(struct lxc_container *c, bool state)
{
if (!c || !c->lxc_conf)
return false;
if (container_mem_lock(c)) {
ERROR("Error getting mem lock");
if (container_mem_lock(c))
return false;
}
c->daemonize = state;
container_mem_unlock(c);
return true;
}
......@@ -618,18 +654,20 @@ static bool do_lxcapi_want_close_all_fds(struct lxc_container *c, bool state)
{
if (!c || !c->lxc_conf)
return false;
if (container_mem_lock(c)) {
ERROR("Error getting mem lock");
if (container_mem_lock(c))
return false;
}
c->lxc_conf->close_all_fds = state;
container_mem_unlock(c);
return true;
}
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;
......@@ -646,13 +684,11 @@ static bool am_single_threaded(void)
{
struct dirent *direntp;
DIR *dir;
int count=0;
int count = 0;
dir = opendir("/proc/self/task");
if (!dir) {
INFO("failed to open /proc/self/task");
if (!dir)
return false;
}
while ((direntp = readdir(dir))) {
if (!strcmp(direntp->d_name, "."))
......@@ -660,24 +696,28 @@ static bool am_single_threaded(void)
if (!strcmp(direntp->d_name, ".."))
continue;
if (++count > 1)
break;
}
closedir(dir);
return count == 1;
}
static void push_arg(char ***argp, char *arg, int *nargs)
{
char **argv;
char *copy;
char **argv;
do {
copy = strdup(arg);
} while (!copy);
do {
argv = realloc(*argp, (*nargs + 2) * sizeof(char *));
} while (!argv);
*argp = argv;
argv[*nargs] = copy;
(*nargs)++;
......@@ -687,9 +727,10 @@ static void push_arg(char ***argp, char *arg, int *nargs)
static char **split_init_cmd(const char *incmd)
{
size_t len;
int nargs = 0;
char *copy, *p, *saveptr = NULL;
char *copy, *p;
char **argv;
int nargs = 0;
char *saveptr = NULL;
if (!incmd)
return NULL;
......@@ -697,20 +738,21 @@ static char **split_init_cmd(const char *incmd)
len = strlen(incmd) + 1;
copy = alloca(len);
strncpy(copy, incmd, len);
copy[len-1] = '\0';
copy[len - 1] = '\0';
do {
argv = malloc(sizeof(char *));
} while (!argv);
argv[0] = NULL;
for (p = strtok_r(copy, " ", &saveptr); p != NULL;
p = strtok_r(NULL, " ", &saveptr))
for (; (p = strtok_r(copy, " ", &saveptr)); copy = NULL)
push_arg(&argv, p, &nargs);
if (nargs == 0) {
free(argv);
return NULL;
}
return argv;
}
......@@ -720,8 +762,10 @@ static void free_init_cmd(char **argv)
if (!argv)
return;
while (argv[i])
free(argv[i++]);
free(argv);
}
......@@ -902,14 +946,14 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
pid = fork();
if (pid < 0) {
SYSERROR("Failed to fork first child process");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
/* second parent */
if (pid != 0) {
free_init_cmd(init_cmd);
lxc_free_handler(handler);
exit(EXIT_SUCCESS);
_exit(EXIT_SUCCESS);
}
/* second child */
......@@ -918,7 +962,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
ret = chdir("/");
if (ret < 0) {
SYSERROR("Failed to change to \"/\" directory");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
keepfds[0] = handler->conf->maincmd_fd;
......@@ -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,
sizeof(keepfds) / sizeof(keepfds[0]));
if (ret < 0)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
/* redirect std{in,out,err} to /dev/null */
ret = null_stdfds();
if (ret < 0) {
ERROR("Failed to redirect std{in,out,err} to /dev/null");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
/* become session leader */
......@@ -960,7 +1004,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
free_init_cmd(init_cmd);
lxc_free_handler(handler);
if (daemonize)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
return false;
}
......@@ -971,7 +1015,7 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a
free_init_cmd(init_cmd);
lxc_free_handler(handler);
if (daemonize)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
return false;
}
......@@ -1042,9 +1086,9 @@ on_error:
free_init_cmd(init_cmd);
if (daemonize && ret != 0)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
else if (daemonize)
exit(EXIT_SUCCESS);
_exit(EXIT_SUCCESS);
if (ret != 0)
return false;
......@@ -1052,18 +1096,19 @@ on_error:
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;
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
*/
/* Note, there MUST be an ending NULL. */
static bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
{
va_list ap;
......@@ -1079,16 +1124,13 @@ static bool lxcapi_startl(struct lxc_container *c, int useinit, ...)
va_start(ap, useinit);
inargs = lxc_va_arg_list_to_argv(ap, 0, 1);
va_end(ap);
if (!inargs) {
ERROR("Memory allocation error.");
goto out;
}
if (!inargs)
goto on_error;
/* pass NULL if no arguments were supplied */
bret = do_lxcapi_start(c, useinit, *inargs ? inargs : NULL);
out:
on_error:
if (inargs) {
char **arg;
for (arg = inargs; *arg; arg++)
......@@ -1097,6 +1139,7 @@ out:
}
current_config = NULL;
return bret;
}
......@@ -1116,48 +1159,56 @@ WRAP_API(bool, lxcapi_stop)
static int do_create_container_dir(const char *path, struct lxc_conf *conf)
{
int ret = -1, lasterr;
char *p = alloca(strlen(path)+1);
int lasterr;
size_t len;
char *p;
int ret = -1;
mode_t mask = umask(0002);
ret = mkdir(path, 0770);
lasterr = errno;
umask(mask);
errno = lasterr;
if (ret) {
if (errno == EEXIST)
ret = 0;
else {
SYSERROR("failed to create container path %s", path);
if (errno != EEXIST)
return -1;
}
ret = 0;
}
len = strlen(path);
p = alloca(len + 1);
strcpy(p, path);
if (!lxc_list_empty(&conf->id_map) && chown_mapped_root(p, conf) != 0) {
ERROR("Failed to chown container dir");
ret = -1;
if (!lxc_list_empty(&conf->id_map)) {
ret = chown_mapped_root(p, conf);
if (ret < 0)
ret = -1;
}
return ret;
}
/*
* create the standard expected container dir
*/
/* Create the standard expected container dir. */
static bool create_container_dir(struct lxc_container *c)
{
int ret;
size_t len;
char *s;
int len, ret;
len = strlen(c->config_path) + strlen(c->name) + 2;
s = malloc(len);
if (!s)
return false;
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);
return false;
}
ret = do_create_container_dir(s, c->lxc_conf);
free(s);
return ret == 0;
}
......@@ -1219,15 +1270,19 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c,
static char *lxcbasename(char *path)
{
char *p = path + strlen(path) - 1;
char *p;
p = path + strlen(path) - 1;
while (*p != '/' && p > path)
p--;
return p;
}
static bool create_run_template(struct lxc_container *c, char *tpath, bool need_null_stdfds,
char *const argv[])
static bool create_run_template(struct lxc_container *c, char *tpath,
bool need_null_stdfds, char *const argv[])
{
int ret;
pid_t pid;
if (!tpath)
......@@ -1235,47 +1290,58 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
pid = fork();
if (pid < 0) {
SYSERROR("failed to fork task for container creation template");
SYSERROR("Failed to fork task for container creation template");
return false;
}
if (pid == 0) { /* child */
char *patharg, *namearg, *rootfsarg;
struct lxc_storage *bdev = NULL;
int i;
int ret, len, nargs = 0;
int i, len;
char *namearg, *patharg, *rootfsarg;
char **newargv;
int nargs = 0;
struct lxc_storage *bdev = NULL;
struct lxc_conf *conf = c->lxc_conf;
uid_t euid;
if (need_null_stdfds && null_stdfds() < 0) {
exit(1);
if (need_null_stdfds) {
ret = null_stdfds();
if (ret < 0)
_exit(EXIT_FAILURE);
}
bdev = storage_init(c->lxc_conf);
if (!bdev) {
ERROR("Error opening rootfs");
exit(1);
ERROR("Failed to initialize storage");
_exit(EXIT_FAILURE);
}
if (geteuid() == 0) {
if (unshare(CLONE_NEWNS) < 0) {
ERROR("error unsharing mounts");
exit(1);
euid = geteuid();
if (euid == 0) {
ret = unshare(CLONE_NEWNS);
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)) {
SYSERROR("Failed to make / rslave to run template");
ret = detect_shared_rootfs();
if (ret == 1) {
ret = mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL);
if (ret < 0) {
SYSERROR("Failed to make \"/\" rslave");
ERROR("Continuing...");
}
}
}
if (strcmp(bdev->type, "dir") && strcmp(bdev->type, "btrfs")) {
if (geteuid() != 0) {
ERROR("non-root users can only create btrfs and directory-backed containers");
exit(EXIT_FAILURE);
if (strcmp(bdev->type, "dir") != 0 && strcmp(bdev->type, "btrfs") != 0) {
if (euid != 0) {
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
* rsync the contents into
* <container-path>/<container-name>/rootfs.
......@@ -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});
if (!src) {
ERROR("Failed to get rootfs");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
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_
return -1;
}
} else {
if (bdev->ops->mount(bdev) < 0) {
ret = bdev->ops->mount(bdev);
if (ret < 0) {
ERROR("Failed to mount rootfs");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
}
} 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_
bdev->dest = strdup(src);
}
/*
* create our new array, pre-pend the template name and
* base args
/* Create our new array, pre-pend the template name and base
* args.
*/
if (argv)
for (nargs = 0; argv[nargs]; nargs++) ;
nargs += 4; /* template, path, rootfs and name args */
for (nargs = 0; argv[nargs]; nargs++) {
;
}
/* template, path, rootfs and name args */
nargs += 4;
newargv = malloc(nargs * sizeof(*newargv));
if (!newargv)
exit(1);
_exit(EXIT_FAILURE);
newargv[0] = lxcbasename(tpath);
/* --path */
len = strlen(c->config_path) + strlen(c->name) + strlen("--path=") + 2;
patharg = malloc(len);
if (!patharg)
exit(1);
_exit(EXIT_FAILURE);
ret = snprintf(patharg, len, "--path=%s/%s", c->config_path, c->name);
if (ret < 0 || ret >= len)
exit(1);
_exit(EXIT_FAILURE);
newargv[1] = patharg;
/* --name */
len = strlen("--name=") + strlen(c->name) + 1;
namearg = malloc(len);
if (!namearg)
exit(1);
_exit(EXIT_FAILURE);
ret = snprintf(namearg, len, "--name=%s", c->name);
if (ret < 0 || ret >= len)
exit(1);
_exit(EXIT_FAILURE);
newargv[2] = namearg;
/* --rootfs */
len = strlen("--rootfs=") + 1 + strlen(bdev->dest);
rootfsarg = malloc(len);
if (!rootfsarg)
exit(1);
_exit(EXIT_FAILURE);
ret = snprintf(rootfsarg, len, "--rootfs=%s", bdev->dest);
if (ret < 0 || ret >= len)
exit(1);
_exit(EXIT_FAILURE);
newargv[3] = rootfsarg;
/* add passed-in args */
if (argv)
for (i = 4; i < nargs; i++)
newargv[i] = argv[i-4];
newargv[i] = argv[i - 4];
/* add trailing NULL */
nargs++;
newargv = realloc(newargv, nargs * sizeof(*newargv));
if (!newargv)
exit(1);
_exit(EXIT_FAILURE);
newargv[nargs - 1] = NULL;
/*
* If we're running the template in a mapped userns, then
* we prepend the template command with:
* lxc-usernsexec <-m map1> ... <-m mapn> --
* and we append "--mapped-uid x", where x is the mapped uid
* for our geteuid()
/* If we're running the template in a mapped userns, then we
* prepend the template command with: lxc-usernsexec <-m map1>
* ... <-m mapn> -- and we append "--mapped-uid x", where x is
* the mapped uid for our geteuid()
*/
if (!lxc_list_empty(&conf->id_map)) {
int n2args = 1;
char txtuid[20];
char txtgid[20];
char **n2 = malloc(n2args * sizeof(*n2));
int extraargs, hostuid_mapped, hostgid_mapped;
char **n2;
char txtuid[20], txtgid[20];
struct lxc_list *it;
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;
tpath = "lxc-usernsexec";
n2[0] = "lxc-usernsexec";
......@@ -1397,97 +1468,103 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
n2args += 2;
n2 = realloc(n2, n2args * sizeof(char *));
if (!n2)
exit(1);
n2[n2args-2] = "-m";
n2[n2args-1] = malloc(200);
if (!n2[n2args-1])
exit(1);
ret = snprintf(n2[n2args-1], 200, "%c:%lu:%lu:%lu",
map->idtype == ID_TYPE_UID ? 'u' : 'g',
map->nsid, map->hostid, map->range);
_exit(EXIT_FAILURE);
n2[n2args - 2] = "-m";
n2[n2args - 1] = malloc(200);
if (!n2[n2args - 1])
_exit(EXIT_FAILURE);
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)
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 *));
if (!n2)
exit(1);
if (hostid_mapped < 0) {
hostid_mapped = find_unmapped_nsid(conf, ID_TYPE_UID);
_exit(EXIT_FAILURE);
if (hostuid_mapped < 0) {
hostuid_mapped = find_unmapped_nsid(conf, ID_TYPE_UID);
n2[n2args++] = "-m";
if (hostid_mapped < 0) {
ERROR("Could not find free uid to map");
exit(1);
if (hostuid_mapped < 0) {
ERROR("Failed to find free uid to map");
_exit(EXIT_FAILURE);
}
n2[n2args++] = malloc(200);
if (!n2[n2args-1]) {
if (!n2[n2args - 1]) {
SYSERROR("out of memory");
exit(1);
}
ret = snprintf(n2[n2args-1], 200, "u:%d:%d:1",
hostid_mapped, geteuid());
if (ret < 0 || ret >= 200) {
ERROR("string too long");
exit(1);
_exit(EXIT_FAILURE);
}
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;
n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(char *));
if (!n2)
exit(1);
_exit(EXIT_FAILURE);
if (hostgid_mapped < 0) {
hostgid_mapped = find_unmapped_nsid(conf, ID_TYPE_GID);
n2[n2args++] = "-m";
if (hostgid_mapped < 0) {
ERROR("Could not find free uid to map");
exit(1);
ERROR("Failed to find free gid to map");
_exit(EXIT_FAILURE);
}
n2[n2args++] = malloc(200);
if (!n2[n2args-1]) {
if (!n2[n2args - 1]) {
SYSERROR("out of memory");
exit(1);
}
ret = snprintf(n2[n2args-1], 200, "g:%d:%d:1",
hostgid_mapped, getegid());
if (ret < 0 || ret >= 200) {
ERROR("string too long");
exit(1);
_exit(EXIT_FAILURE);
}
ret = snprintf(n2[n2args - 1], 200, "g:%d:%d:1",
hostgid_mapped, getegid());
if (ret < 0 || ret >= 200)
_exit(EXIT_FAILURE);
}
n2[n2args++] = "--";
for (i = 0; i < nargs; i++)
n2[i + n2args] = newargv[i];
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;
n2 = realloc(n2, n2args * sizeof(char *));
if (!n2) {
SYSERROR("out of memory");
exit(1);
}
if (!n2)
_exit(EXIT_FAILURE);
/* note n2[n2args-1] is NULL */
n2[n2args-5] = "--mapped-uid";
snprintf(txtuid, 20, "%d", hostid_mapped);
n2[n2args-4] = txtuid;
n2[n2args-3] = "--mapped-gid";
n2[n2args - 5] = "--mapped-uid";
snprintf(txtuid, 20, "%d", hostuid_mapped);
n2[n2args - 4] = txtuid;
n2[n2args - 3] = "--mapped-gid";
snprintf(txtgid, 20, "%d", hostgid_mapped);
n2[n2args-2] = txtgid;
n2[n2args-1] = NULL;
n2[n2args - 2] = txtgid;
n2[n2args - 1] = NULL;
free(newargv);
newargv = n2;
}
/* execute */
execvp(tpath, newargv);
SYSERROR("Failed to execute template %s", tpath);
exit(1);
_exit(EXIT_FAILURE);
}
if (wait_for_pid(pid) != 0) {
ERROR("container creation template for %s failed", c->name);
ret = wait_for_pid(pid);
if (ret != 0) {
ERROR("Failed to create container from template");
return false;
}
......@@ -1618,8 +1695,8 @@ static void lxcapi_clear_config(struct lxc_container *c)
* arguments, you can just pass NULL.
*/
static bool do_lxcapi_create(struct lxc_container *c, const char *t,
const char *bdevtype, struct bdev_specs *specs, int flags,
char *const argv[])
const char *bdevtype, struct bdev_specs *specs,
int flags, char *const argv[])
{
int partial_fd;
pid_t pid;
......@@ -1713,7 +1790,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
if (!bdev) {
ERROR("Failed to create %s storage for %s",
bdevtype ? bdevtype : "(none)", c->name);
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
/* 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,
*/
bdev->ops->umount(bdev);
bdev->ops->destroy(bdev);
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
_exit(EXIT_SUCCESS);
}
if (wait_for_pid(pid) != 0)
goto out_unlock;
......@@ -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(pipefd[1]);
exit(ret);
_exit(ret);
}
/* close the write-end of the pipe */
......@@ -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(pipefd[1]);
exit(ret);
_exit(ret);
}
/* close the write-end of the pipe */
......@@ -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)
{
FILE *fout;
int fd, lret;
bool ret = false, need_disklock = false;
int lret;
if (!alt_file)
alt_file = c->configfile;
......@@ -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 (!c->lxc_conf) {
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;
}
}
......@@ -2426,18 +2505,24 @@ static bool do_lxcapi_save_config(struct lxc_container *c, const char *alt_file)
if (lret)
return false;
fout = fopen(alt_file, "w");
if (!fout)
goto out;
write_config(fout, c->lxc_conf);
fclose(fout);
fd = open(alt_file, O_WRONLY | O_CREAT | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (fd < 0)
goto on_error;
lret = write_config(fd, c->lxc_conf);
close(fd);
if (lret < 0)
goto on_error;
ret = true;
out:
on_error:
if (need_disklock)
container_disk_unlock(c);
else
container_mem_unlock(c);
return ret;
}
......@@ -3488,10 +3573,9 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
char **hookargs)
{
char newpath[MAXPATHLEN];
int ret;
int fd, ret;
struct clone_update_data data;
size_t saved_unexp_len;
FILE *fout;
pid_t pid;
int storage_copied = 0;
char *origroot = NULL, *saved_unexp_conf = NULL;
......@@ -3535,9 +3619,11 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char
origroot = c->lxc_conf->rootfs.path;
c->lxc_conf->rootfs.path = NULL;
}
fout = fopen(newpath, "w");
if (!fout) {
SYSERROR("open %s", newpath);
fd = open(newpath, O_WRONLY | O_CREAT | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (fd < 0) {
SYSERROR("Failed to open \"%s\"", newpath);
goto out;
}
......@@ -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;
c->lxc_conf->unexpanded_config = strdup(saved_unexp_conf);
if (!c->lxc_conf->unexpanded_config) {
ERROR("Out of memory");
fclose(fout);
close(fd);
goto out;
}
clear_unexp_config_line(c->lxc_conf, "lxc.rootfs.path", false);
write_config(fout, c->lxc_conf);
fclose(fout);
write_config(fd, c->lxc_conf);
close(fd);
c->lxc_conf->rootfs.path = origroot;
free(c->lxc_conf->unexpanded_config);
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
else
ret = clone_update_rootfs(&data);
if (ret < 0)
exit(1);
_exit(EXIT_FAILURE);
container_mem_unlock(c);
exit(0);
_exit(EXIT_SUCCESS);
out:
container_mem_unlock(c);
......@@ -4235,11 +4320,11 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
ret = chroot(chrootpath);
if (ret < 0)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
ret = chdir("/");
if (ret < 0)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
/* remove path if it exists */
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,
ret = unlink(path);
if (ret < 0) {
ERROR("%s - Failed to remove \"%s\"", strerror(errno), path);
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
}
if (!add)
exit(EXIT_SUCCESS);
_exit(EXIT_SUCCESS);
/* create any missing directories */
tmp = strdup(path);
if (!tmp)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
directory_path = dirname(tmp);
ret = mkdir_p(directory_path, 0755);
if (ret < 0 && errno != EEXIST) {
ERROR("%s - Failed to create path \"%s\"", strerror(errno), directory_path);
free(tmp);
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
/* create the device node */
......@@ -4272,17 +4357,17 @@ static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
free(tmp);
if (ret < 0) {
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)
{
int ret;
struct stat st;
char value[MAX_BUFFER];
char value[LXC_MAX_BUFFER];
const char *p;
/* make sure container is running */
......@@ -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 */
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))
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
return false;
/* check snprintf return code */
if (ret < 0 || ret >= MAX_BUFFER)
if (ret < 0 || ret >= LXC_MAX_BUFFER)
return false;
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
{
// cannot mknod if we're not privileged wrt init_user_ns
if (am_host_unpriv()) {
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__);
return false;
}
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 *)
static bool do_lxcapi_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path)
{
if (am_guest_unpriv()) {
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__);
return 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,
int ret = 0;
if (am_guest_unpriv()) {
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__);
return false;
}
......@@ -4403,7 +4488,7 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c,
* But for other types guest privilege suffices.
*/
if (am_guest_unpriv()) {
ERROR(NOT_SUPPORTED_ERROR, __FUNCTION__);
ERROR(LXC_UNPRIV_EOPNOTSUPP, __FUNCTION__);
return false;
}
......@@ -4425,13 +4510,13 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c,
init_pid = do_lxcapi_init_pid(c);
if (!switch_to_ns(init_pid, "net")) {
ERROR("Failed to enter network namespace");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
ret = lxc_netdev_isup(ifname);
if (ret < 0) {
ERROR("Failed to determine whether network device \"%s\" is up", ifname);
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
/* netdev of ifname is up. */
......@@ -4439,7 +4524,7 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c,
ret = lxc_netdev_down(ifname);
if (ret) {
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,
ERROR("Network device \"%s\" not found", ifname);
else
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);
......
......@@ -72,10 +72,11 @@ static void lock_mutex(pthread_mutex_t *l)
{
int ret;
if ((ret = pthread_mutex_lock(l)) != 0) {
fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
ret = pthread_mutex_lock(l);
if (ret != 0) {
fprintf(stderr, "%s - Failed acquire mutex", strerror(ret));
dump_stacktrace();
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
}
......@@ -83,11 +84,11 @@ static void unlock_mutex(pthread_mutex_t *l)
{
int ret;
if ((ret = pthread_mutex_unlock(l)) != 0) {
fprintf(stderr, "%s: pthread_mutex_unlock returned:%d %s\n",
__FILE__, ret, strerror(ret));
ret = pthread_mutex_unlock(l);
if (ret != 0) {
fprintf(stderr, "%s - Failed to release mutex", strerror(ret));
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,
if (!switch_to_ns(pid, "net"))
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,
......@@ -663,7 +663,7 @@ static int lxc_netdev_move_wlan(char *physname, const char *ifname, pid_t pid,
sprintf(pidstr, "%d", pid);
execlp("iw", "iw", "phy", physname, "set", "netns", pidstr,
(char *)NULL);
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
if (wait_for_pid(fpid))
......@@ -2126,7 +2126,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
close(pipefd[1]);
if (ret < 0) {
SYSERROR("Failed to duplicate std{err,out} file descriptor");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
if (netdev->link[0] != '\0')
......@@ -2136,7 +2136,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
if (ret < 0 || ret >= LXC_NUMSTRLEN64)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
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
lxcpath, lxcname, pidstr, "veth", netdev_link,
(char *)NULL);
SYSERROR("Failed to execute lxc-user-nic");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
/* close the write-end of the pipe */
......@@ -2269,7 +2269,7 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
close(pipefd[1]);
if (ret < 0) {
SYSERROR("Failed to duplicate std{err,out} file descriptor");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
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
hostveth = netdev->priv.veth_attr.veth1;
if (hostveth[0] == '\0') {
SYSERROR("Host side veth device name is missing");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
if (netdev->link[0] == '\0') {
SYSERROR("Network link for network device \"%s\" is "
"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,
......@@ -2293,7 +2293,7 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
lxcname, netns_path, "veth", netdev->link, hostveth,
(char *)NULL);
SYSERROR("Failed to exec lxc-user-nic.");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
close(pipefd[1]);
......
......@@ -20,13 +20,15 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define _GNU_SOURCE
#include <stdio.h>
#undef _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include "parse.h"
#include "config.h"
......@@ -35,6 +37,77 @@
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)
{
FILE *f;
......
......@@ -23,6 +23,9 @@
#ifndef __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,
const char *file, 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,
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_right_gc(const char *buffer, size_t len);
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
......@@ -478,7 +478,7 @@ struct lxc_popen_FILE *lxc_popen(const char *command)
ret = fcntl(pipe_fds[1], F_SETFD, 0);
if (ret < 0) {
close(pipe_fds[1]);
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
/* duplicate stderr */
......@@ -488,19 +488,19 @@ struct lxc_popen_FILE *lxc_popen(const char *command)
ret = fcntl(pipe_fds[1], F_SETFD, 0);
close(pipe_fds[1]);
if (ret < 0)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
/* unblock all signals */
ret = sigfillset(&mask);
if (ret < 0)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
ret = sigprocmask(SIG_UNBLOCK, &mask, NULL);
if (ret < 0)
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
execl("/bin/sh", "sh", "-c", command, (char *)NULL);
exit(127);
_exit(127);
}
close(pipe_fds[1]);
......@@ -1810,33 +1810,6 @@ int lxc_count_file_lines(const char *fn)
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. */
/* /proc/pid-to-str/status\0 = (5 + 21 + 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)
if (ret < 0) {
SYSERROR("failed to duplicate std{err,out} file descriptor");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
/* Does not return. */
child_fn(args);
ERROR("failed to exec command");
exit(EXIT_FAILURE);
_exit(EXIT_FAILURE);
}
/* close the write-end of the pipe */
......
......@@ -100,6 +100,7 @@
#define LXC_NUMSTRLEN64 21
#define LXC_LINELEN 4096
#define LXC_IDMAPLEN 4096
#define LXC_MAX_BUFFER 4096
/* returns 1 on success, 0 if there were any failures */
extern int lxc_rmdir_onedev(const char *path, const char *exclude);
......@@ -426,13 +427,6 @@ extern size_t lxc_array_len(void **array);
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 */
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