#include "utils.h"
#include "version.h"
+#if HAVE_OPENSSL
+#include <openssl/evp.h>
+#endif
+
/* major()/minor() */
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
static bool config_file_exists(const char *lxcpath, const char *cname)
{
- __do_free char *fname;
+ __do_free char *fname = NULL;
int ret;
size_t len;
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. 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
* start a container, if we find that file, without a flock, we remove the
* container.
*/
+enum {
+ LXC_CREATE_FAILED = -1,
+ LXC_CREATE_SUCCESS = 0,
+ LXC_CREATE_ONGOING = 1,
+ LXC_CREATE_INCOMPLETE = 2,
+};
+
static int ongoing_create(struct lxc_container *c)
{
- __do_free char *path;
- int fd, ret;
- size_t len;
+ __do_close_prot_errno int fd = -EBADF;
+ __do_free char *path = NULL;
struct flock lk = {0};
+ int ret;
+ size_t len;
len = strlen(c->config_path) + strlen(c->name) + 10;
path = must_realloc(NULL, len);
ret = snprintf(path, len, "%s/%s/partial", c->config_path, c->name);
if (ret < 0 || (size_t)ret >= len)
- return -1;
+ return LXC_CREATE_FAILED;
fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) {
if (errno != ENOENT)
- return -1;
+ return LXC_CREATE_FAILED;
- return 0;
+ return LXC_CREATE_SUCCESS;
}
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
- /* F_OFD_GETLK requires that l_pid be set to 0 otherwise the kernel
+ /*
+ * F_OFD_GETLK requires that l_pid be set to 0 otherwise the kernel
* will EINVAL us.
*/
lk.l_pid = 0;
ret = 0;
}
- close(fd);
-
/* F_OFD_GETLK will not send us back a pid so don't check it. */
if (ret == 0)
/* Create is still ongoing. */
- return 1;
+ return LXC_CREATE_ONGOING;
/* Create completed but partial is still there. */
- return 2;
+ return LXC_CREATE_INCOMPLETE;
}
static int create_partial(struct lxc_container *c)
{
- __do_free char *path;
+ __do_free char *path = NULL;
int fd, ret;
size_t len;
struct flock lk = {0};
static void remove_partial(struct lxc_container *c, int fd)
{
- __do_free char *path;
+ __do_free char *path = NULL;
int ret;
size_t len;
static bool do_lxcapi_freeze(struct lxc_container *c)
{
- int ret;
lxc_state_t s;
if (!c || !c->lxc_conf)
static bool do_lxcapi_unfreeze(struct lxc_container *c)
{
- int ret;
lxc_state_t s;
if (!c || !c->lxc_conf)
return false;
ret = ongoing_create(c);
- if (ret < 0) {
+ switch (ret) {
+ case LXC_CREATE_FAILED:
ERROR("Failed checking for incomplete container creation");
return false;
- } else if (ret == 1) {
+ case LXC_CREATE_ONGOING:
ERROR("Ongoing container creation detected");
return false;
- } else if (ret == 2) {
+ case LXC_CREATE_INCOMPLETE:
ERROR("Failed to create container");
do_lxcapi_destroy(c);
return false;
{
__do_free char *p = NULL;
int lasterr;
- size_t len;
int ret = -1;
mode_t mask = umask(0002);
const char *type,
struct bdev_specs *specs)
{
- __do_free char *dest;
+ __do_free char *dest = NULL;
int ret;
size_t len;
struct lxc_storage *bdev;
if (!c->set_config_item(c, "lxc.rootfs.path", bdev->src)) {
ERROR("Failed to set \"lxc.rootfs.path = %s\"", bdev->src);
+ storage_put(bdev);
return NULL;
}
return bdev;
}
-static char *lxcbasename(char *path)
+/* Strip path and return name of file for argv[0] passed to execvp */
+static char *lxctemplatefilename(char *tpath)
{
char *p;
- p = path + strlen(path) - 1;
- while (*p != '/' && p > path)
+ p = tpath + strlen(tpath) - 1;
+ while ( (p-1) >= tpath && *(p-1) != '/')
p--;
return p;
newargv = malloc(nargs * sizeof(*newargv));
if (!newargv)
_exit(EXIT_FAILURE);
- newargv[0] = lxcbasename(tpath);
+ newargv[0] = lxctemplatefilename(tpath);
/* --path */
len = strlen(c->config_path) + strlen(c->name) + strlen("--path=") + 2;
char *contents;
FILE *f;
int ret = -1;
-#if HAVE_LIBGNUTLS
- int i;
- unsigned char md_value[SHA_DIGEST_LENGTH];
+#if HAVE_OPENSSL
+ int i, md_len = 0;
+ unsigned char md_value[EVP_MAX_MD_SIZE];
char *tpath;
#endif
if (ret < 0)
goto out_free_contents;
-#if HAVE_LIBGNUTLS
+#if HAVE_OPENSSL
tpath = get_template_path(t);
if (!tpath) {
ERROR("Invalid template \"%s\" specified", t);
goto out_free_contents;
}
- ret = sha1sum_file(tpath, md_value);
+ ret = sha1sum_file(tpath, md_value, &md_len);
if (ret < 0) {
ERROR("Failed to get sha1sum of %s", tpath);
free(tpath);
fprintf(f, "\n");
}
-#if HAVE_LIBGNUTLS
+#if HAVE_OPENSSL
fprintf(f, "# Template script checksum (SHA-1): ");
- for (i=0; i<SHA_DIGEST_LENGTH; i++)
+ for (i=0; i<md_len; i++)
fprintf(f, "%02x", md_value[i]);
fprintf(f, "\n");
#endif
{
pid_t pid = do_lxcapi_init_pid(c);
+ if (pid < 0)
+ return false;
+
if ((geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) &&
(access("/proc/self/ns/user", F_OK) == 0))
if (!switch_to_ns(pid, "user"))
static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
{
- __do_free char *cpath;
+ __do_free char *cpath = NULL;
int i, len, ret;
struct lxc_list *it;
bool should_default_to_snapshot(struct lxc_container *c0,
struct lxc_container *c1)
{
- __do_free char *p0, *p1;
+ __do_free char *p0 = NULL, *p1 = NULL;
int ret;
size_t l0 = strlen(c0->config_path) + strlen(c0->name) + 2;
size_t l1 = strlen(c1->config_path) + strlen(c1->name) + 2;
WRAP_API_1(bool, lxcapi_rename, const char *)
-static int lxcapi_attach(struct lxc_container *c, lxc_attach_exec_t exec_function, void *exec_payload, lxc_attach_options_t *options, pid_t *attached_process)
+static int lxcapi_attach(struct lxc_container *c,
+ lxc_attach_exec_t exec_function, void *exec_payload,
+ lxc_attach_options_t *options, pid_t *attached_process)
{
int ret;
current_config = c->lxc_conf;
- ret = lxc_attach(c->name, c->config_path, exec_function, exec_payload, options, attached_process);
+ ret = lxc_attach(c, exec_function, exec_payload, options,
+ attached_process);
current_config = NULL;
return ret;
}
-static int do_lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
+static int do_lxcapi_attach_run_wait(struct lxc_container *c,
+ lxc_attach_options_t *options,
+ const char *program,
+ const char *const argv[])
{
lxc_attach_command_t command;
pid_t pid;
- int r;
+ int ret;
if (!c)
return -1;
- command.program = (char*)program;
- command.argv = (char**)argv;
+ command.program = (char *)program;
+ command.argv = (char **)argv;
- r = lxc_attach(c->name, c->config_path, lxc_attach_run_command, &command, options, &pid);
- if (r < 0) {
- ERROR("ups");
- return r;
- }
+ ret = lxc_attach(c, lxc_attach_run_command, &command, options, &pid);
+ if (ret < 0)
+ return ret;
return lxc_wait_for_pid_status(pid);
}
-static int lxcapi_attach_run_wait(struct lxc_container *c, lxc_attach_options_t *options, const char *program, const char * const argv[])
+static int lxcapi_attach_run_wait(struct lxc_container *c,
+ lxc_attach_options_t *options,
+ const char *program, const char *const argv[])
{
int ret;
static int get_next_index(const char *lxcpath, char *cname)
{
- __do_free char *fname;
+ __do_free char *fname = NULL;
struct stat sb;
int i = 0, ret;
}
if (commentfile) {
- __do_free char *path;
+ __do_free char *path = NULL;
/* $p / $name / comment \0 */
int len = strlen(snappath) + strlen(newname) + 10;
struct stat st;
char value[LXC_MAX_BUFFER];
const char *p;
+ pid_t init_pid;
/* make sure container is running */
if (!do_lxcapi_is_running(c)) {
if (ret < 0 || ret >= LXC_MAX_BUFFER)
return false;
- if (!do_add_remove_node(do_lxcapi_init_pid(c), p, add, &st))
+ init_pid = do_lxcapi_init_pid(c);
+ if (init_pid < 0) {
+ ERROR("Failed to get init pid");
+ return false;
+ }
+
+ if (!do_add_remove_node(init_pid, p, add, &st))
return false;
/* add or remove device to/from cgroup access list */
}
init_pid = do_lxcapi_init_pid(c);
+ if (init_pid < 0) {
+ ERROR("Failed to get init pid");
+ goto err;
+ }
+
ret = lxc_netdev_move_by_name(ifname, init_pid, dst_ifname);
if (ret)
goto err;
pid_t init_pid;
init_pid = do_lxcapi_init_pid(c);
+ if (init_pid < 0) {
+ ERROR("Failed to get init pid");
+ _exit(EXIT_FAILURE);
+ }
if (!switch_to_ns(init_pid, "net")) {
ERROR("Failed to enter network namespace");
_exit(EXIT_FAILURE);
return ret;
}
+static int do_lxcapi_seccomp_notify_fd(struct lxc_container *c)
+{
+ if (!c || !c->lxc_conf)
+ return minus_one_set_errno(-EINVAL);
+
+ return lxc_seccomp_get_notify_fd(&c->lxc_conf->seccomp);
+}
+
+WRAP_API(int, lxcapi_seccomp_notify_fd)
+
struct lxc_container *lxc_container_new(const char *name, const char *configpath)
{
struct lxc_container *c;
size_t len;
+ int rc;
if (!name)
return NULL;
goto err;
}
- if (ongoing_create(c) == 2) {
- ERROR("Failed to complete container creation for %s", c->name);
+ rc = ongoing_create(c);
+ switch (rc) {
+ case LXC_CREATE_INCOMPLETE:
+ SYSERROR("Failed to complete container creation for %s", c->name);
container_destroy(c, NULL);
lxcapi_clear_config(c);
+ break;
+ case LXC_CREATE_ONGOING:
+ /* container creation going on */
+ break;
+ case LXC_CREATE_FAILED:
+ /* container creation failed */
+ if (errno != EACCES && errno != EPERM) {
+ /* insufficient privileges */
+ SYSERROR("Failed checking for incomplete container %s creation", c->name);
+ goto err;
+ }
+ break;
}
c->daemonize = true;
c->console_log = lxcapi_console_log;
c->mount = lxcapi_mount;
c->umount = lxcapi_umount;
+ c->seccomp_notify_fd = lxcapi_seccomp_notify_fd;
return c;