* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
#include <arpa/inet.h>
#include <dirent.h>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>
+#include "../include/netns_ifaddrs.h"
#include "af_unix.h"
#include "api_extensions.h"
#include "attach.h"
#include "lxc.h"
#include "lxccontainer.h"
#include "lxclock.h"
+#include "memory_utils.h"
#include "monitor.h"
#include "namespace.h"
#include "network.h"
#include "parse.h"
+#include "raw_syscalls.h"
#include "start.h"
#include "state.h"
#include "storage.h"
#include "storage/overlay.h"
#include "storage_utils.h"
#include "sync.h"
+#include "syscall_wrappers.h"
#include "terminal.h"
#include "utils.h"
#include "version.h"
+#if HAVE_OPENSSL
+#include <openssl/evp.h>
+#endif
+
/* major()/minor() */
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#endif
-#if HAVE_IFADDRS_H
-#include <ifaddrs.h>
-#else
-#include <../include/ifaddrs.h>
-#endif
-
#if IS_BIONIC
#include <../include/lxcmntent.h>
#else
static bool config_file_exists(const char *lxcpath, const char *cname)
{
+ __do_free char *fname = NULL;
int ret;
size_t len;
- char *fname;
/* $lxcpath + '/' + $cname + '/config' + \0 */
len = strlen(lxcpath) + strlen(cname) + 9;
- fname = alloca(len);
+ fname = must_realloc(NULL, 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
+/*
+ * 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)
{
- int fd, ret;
- size_t len;
- char *path;
+ __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 = alloca(len);
+ 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 = NULL;
int fd, ret;
size_t len;
- char *path;
struct flock lk = {0};
/* $lxcpath + '/' + $name + '/partial' + \0 */
len = strlen(c->config_path) + strlen(c->name) + 10;
- path = alloca(len);
+ 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;
static void remove_partial(struct lxc_container *c, int fd)
{
+ __do_free char *path = NULL;
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);
+ 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;
static bool do_lxcapi_freeze(struct lxc_container *c)
{
- int ret;
+ lxc_state_t s;
- if (!c)
+ if (!c || !c->lxc_conf)
return false;
- ret = lxc_freeze(c->lxc_conf, c->name, c->config_path);
- if (ret < 0)
- return false;
+ s = lxc_getstate(c->name, c->config_path);
+ if (s != FROZEN)
+ return lxc_freeze(c->lxc_conf, c->name, c->config_path) == 0;
return true;
}
static bool do_lxcapi_unfreeze(struct lxc_container *c)
{
- int ret;
+ lxc_state_t s;
- if (!c)
+ if (!c || !c->lxc_conf)
return false;
- ret = lxc_unfreeze(c->lxc_conf, c->name, c->config_path);
- if (ret < 0)
- return false;
+ s = lxc_getstate(c->name, c->config_path);
+ if (s == FROZEN)
+ return lxc_unfreeze(c->lxc_conf, c->name, c->config_path) == 0;
return true;
}
static char **split_init_cmd(const char *incmd)
{
- size_t len, retlen;
- char *copy, *p;
+ __do_free char *copy = NULL;
+ char *p;
char **argv;
int nargs = 0;
if (!incmd)
return NULL;
- len = strlen(incmd) + 1;
- copy = alloca(len);
- retlen = strlcpy(copy, incmd, len);
- if (retlen >= len)
- return NULL;
+ copy = must_copy_string(incmd);
do {
argv = malloc(sizeof(char *));
} while (!argv);
argv[0] = NULL;
- lxc_iterate_parts(p, copy, " ")
+ lxc_iterate_parts (p, copy, " ")
push_arg(&argv, p, &nargs);
if (nargs == 0) {
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;
* right PID.
*/
if (c->pidfile) {
- int ret, w;
+ int w;
char pidstr[INTTYPE_TO_STRLEN(pid_t)];
w = snprintf(pidstr, sizeof(pidstr), "%d", lxc_raw_getpid());
static int do_create_container_dir(const char *path, struct lxc_conf *conf)
{
+ __do_free char *p = NULL;
int lasterr;
- size_t len;
- char *p;
int ret = -1;
mode_t mask = umask(0002);
ret = 0;
}
- len = strlen(path);
- p = alloca(len + 1);
- (void)strlcpy(p, path, len + 1);
+ p = must_copy_string(path);
if (!lxc_list_empty(&conf->id_map)) {
ret = chown_mapped_root(p, conf);
const char *type,
struct bdev_specs *specs)
{
+ __do_free char *dest = NULL;
int ret;
size_t len;
- char *dest;
struct lxc_storage *bdev;
/* rootfs.path or lxcpath/lxcname/rootfs */
(access(c->lxc_conf->rootfs.path, F_OK) == 0)) {
const char *rpath = c->lxc_conf->rootfs.path;
len = strlen(rpath) + 1;
- dest = alloca(len);
+ dest = must_realloc(NULL, len);
ret = snprintf(dest, len, "%s", rpath);
} else {
const char *lxcpath = do_lxcapi_get_config_path(c);
len = strlen(c->name) + strlen(lxcpath) + 9;
- dest = alloca(len);
+ dest = must_realloc(NULL, len);
ret = snprintf(dest, len, "%s/%s/rootfs", lxcpath, c->name);
}
if (ret < 0 || (size_t)ret >= len)
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
int partial_fd;
mode_t mask;
pid_t pid;
- bool ret = false;
+ bool ret = false, rootfs_managed = true;
char *tpath = NULL;
if (!c)
if (!create_container_dir(c))
goto free_tpath;
+ if (c->lxc_conf->rootfs.path)
+ rootfs_managed = false;
+
/* If both template and rootfs.path are set, template is setup as
* rootfs.path. The container is already created if we have a config and
* rootfs.path is accessible
out_unlock:
umask(mask);
- if (partial_fd >= 0)
- remove_partial(c, partial_fd);
+ remove_partial(c, partial_fd);
out:
- if (!ret)
+ if (!ret) {
+ bool reset_managed = c->lxc_conf->rootfs.managed;
+
+ /*
+ * Ensure that we don't destroy storage we didn't create
+ * ourselves.
+ */
+ if (!rootfs_managed)
+ c->lxc_conf->rootfs.managed = false;
container_destroy(c, NULL);
+ c->lxc_conf->rootfs.managed = reset_managed;
+ }
free_tpath:
free(tpath);
{
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"))
if (!newnames[pos])
return false;
- /* Sort the arrray as we will use binary search on it. */
+ /* Sort the array as we will use binary search on it. */
qsort(newnames, pos + 1, sizeof(char *),
(int (*)(const void *, const void *))string_cmp);
*list = newlist;
newlist[pos] = c;
- /* Sort the arrray as we will use binary search on it. */
+ /* Sort the array as we will use binary search on it. */
if (sort)
qsort(newlist, pos + 1, sizeof(struct lxc_container *),
(int (*)(const void *, const void *))container_cmp);
if (pid == 0) { /* child */
int ret = 1, nbytes;
- struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
+ struct netns_ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
/* close the read-end of the pipe */
close(pipefd[0]);
}
/* Grab the list of interfaces */
- if (getifaddrs(&interfaceArray)) {
+ if (netns_getifaddrs(&interfaceArray, -1, &(bool){false})) {
SYSERROR("Failed to get interfaces list");
goto out;
}
out:
if (interfaceArray)
- freeifaddrs(interfaceArray);
+ netns_freeifaddrs(interfaceArray);
/* close the write-end of the pipe, thus sending EOF to the reader */
close(pipefd[1]);
if (pid == 0) {
ssize_t nbytes;
char addressOutputBuffer[INET6_ADDRSTRLEN];
- int ret = 1;
- char *address = NULL;
+ char *address_ptr = NULL;
void *tempAddrPtr = NULL;
- struct ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
+ struct netns_ifaddrs *interfaceArray = NULL, *tempIfAddr = NULL;
/* close the read-end of the pipe */
close(pipefd[0]);
}
/* Grab the list of interfaces */
- if (getifaddrs(&interfaceArray)) {
+ if (netns_getifaddrs(&interfaceArray, -1, &(bool){false})) {
SYSERROR("Failed to get interfaces list");
goto out;
}
if (tempIfAddr->ifa_addr == NULL)
continue;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+
if (tempIfAddr->ifa_addr->sa_family == AF_INET) {
if (family && strcmp(family, "inet"))
continue;
tempAddrPtr = &((struct sockaddr_in6 *)tempIfAddr->ifa_addr)->sin6_addr;
}
+#pragma GCC diagnostic pop
+
if (interface && strcmp(interface, tempIfAddr->ifa_name))
continue;
else if (!interface && strcmp("lo", tempIfAddr->ifa_name) == 0)
continue;
- address = (char *)inet_ntop(tempIfAddr->ifa_addr->sa_family,
+ address_ptr = (char *)inet_ntop(tempIfAddr->ifa_addr->sa_family,
tempAddrPtr, addressOutputBuffer,
sizeof(addressOutputBuffer));
- if (!address)
+ if (!address_ptr)
continue;
- nbytes = lxc_write_nointr(pipefd[1], address, INET6_ADDRSTRLEN);
+ nbytes = lxc_write_nointr(pipefd[1], address_ptr, INET6_ADDRSTRLEN);
if (nbytes != INET6_ADDRSTRLEN) {
SYSERROR("Failed to send ipv6 address \"%s\"",
- address);
+ address_ptr);
goto out;
}
out:
if (interfaceArray)
- freeifaddrs(interfaceArray);
+ netns_freeifaddrs(interfaceArray);
/* close the write-end of the pipe, thus sending EOF to the reader */
close(pipefd[1]);
struct stat fbuf;
void *buf = NULL;
char *del = NULL;
- char path[MAXPATHLEN];
- char newpath[MAXPATHLEN];
+ char path[PATH_MAX];
+ char newpath[PATH_MAX];
int fd, ret, n = 0, v = 0;
bool bret = false;
size_t len = 0, bytes = 0;
if (container_disk_lock(c0))
return false;
- ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c0->config_path, c0->name);
- if (ret < 0 || ret > MAXPATHLEN)
+ ret = snprintf(path, PATH_MAX, "%s/%s/lxc_snapshots", c0->config_path, c0->name);
+ if (ret < 0 || ret > PATH_MAX)
goto out;
- ret = snprintf(newpath, MAXPATHLEN, "%s\n%s\n", c->config_path, c->name);
- if (ret < 0 || ret > MAXPATHLEN)
+ ret = snprintf(newpath, PATH_MAX, "%s\n%s\n", c->config_path, c->name);
+ if (ret < 0 || ret > PATH_MAX)
goto out;
/* If we find an lxc-snapshot file using the old format only listing the
void mod_all_rdeps(struct lxc_container *c, bool inc)
{
struct lxc_container *p;
- char *lxcpath = NULL, *lxcname = NULL, path[MAXPATHLEN];
+ char *lxcpath = NULL, *lxcname = NULL, path[PATH_MAX];
size_t pathlen = 0, namelen = 0;
FILE *f;
int ret;
- ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_rdepends",
+ ret = snprintf(path, PATH_MAX, "%s/%s/lxc_rdepends",
c->config_path, c->name);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ if (ret < 0 || ret >= PATH_MAX) {
ERROR("Path name too long");
return;
}
static bool has_fs_snapshots(struct lxc_container *c)
{
FILE *f;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
int ret, v;
struct stat fbuf;
bool bret = false;
- ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_snapshots", c->config_path,
+ ret = snprintf(path, PATH_MAX, "%s/%s/lxc_snapshots", c->config_path,
c->name);
- if (ret < 0 || ret > MAXPATHLEN)
+ if (ret < 0 || ret > PATH_MAX)
goto out;
/* If the file doesn't exist there are no snapshots. */
static bool has_snapshots(struct lxc_container *c)
{
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
struct dirent *direntp;
int count=0;
DIR *dir;
return -1;
}
- while (1) {
+ for (;;) {
len = lxc_read_nointr(in, buf, 8096);
if (len < 0) {
SYSERROR("Error reading old file %s", old);
static int copyhooks(struct lxc_container *oldc, struct lxc_container *c)
{
+ __do_free char *cpath = NULL;
int i, len, ret;
struct lxc_list *it;
- char *cpath;
len = strlen(oldc->config_path) + strlen(oldc->name) + 3;
- cpath = alloca(len);
+ cpath = must_realloc(NULL, len);
ret = snprintf(cpath, len, "%s/%s/", oldc->config_path, oldc->name);
if (ret < 0 || ret >= len)
return -1;
lxc_list_for_each(it, &c->lxc_conf->hooks[i]) {
char *hookname = it->elem;
char *fname = strrchr(hookname, '/');
- char tmppath[MAXPATHLEN];
+ char tmppath[PATH_MAX];
if (!fname) /* relative path - we don't support, but maybe we should */
return 0;
}
/* copy the script, and change the entry in confile */
- ret = snprintf(tmppath, MAXPATHLEN, "%s/%s/%s",
+ ret = snprintf(tmppath, PATH_MAX, "%s/%s/%s",
c->config_path, c->name, fname+1);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return -1;
ret = copy_file(it->elem, tmppath);
static int copy_fstab(struct lxc_container *oldc, struct lxc_container *c)
{
- char newpath[MAXPATHLEN];
+ char newpath[PATH_MAX];
char *oldpath = oldc->lxc_conf->fstab;
int ret;
if (!p)
return -1;
- ret = snprintf(newpath, MAXPATHLEN, "%s/%s%s",
+ ret = snprintf(newpath, PATH_MAX, "%s/%s%s",
c->config_path, c->name, p);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ if (ret < 0 || ret >= PATH_MAX) {
ERROR("error printing new path for %s", oldpath);
return -1;
}
static void copy_rdepends(struct lxc_container *c, struct lxc_container *c0)
{
- char path0[MAXPATHLEN], path1[MAXPATHLEN];
+ char path0[PATH_MAX], path1[PATH_MAX];
int ret;
- ret = snprintf(path0, MAXPATHLEN, "%s/%s/lxc_rdepends", c0->config_path,
+ ret = snprintf(path0, PATH_MAX, "%s/%s/lxc_rdepends", c0->config_path,
c0->name);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ if (ret < 0 || ret >= PATH_MAX) {
WARN("Error copying reverse dependencies");
return;
}
- ret = snprintf(path1, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path,
+ ret = snprintf(path1, PATH_MAX, "%s/%s/lxc_rdepends", c->config_path,
c->name);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ if (ret < 0 || ret >= PATH_MAX) {
WARN("Error copying reverse dependencies");
return;
}
static bool add_rdepends(struct lxc_container *c, struct lxc_container *c0)
{
int ret;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
FILE *f;
bool bret;
- ret = snprintf(path, MAXPATHLEN, "%s/%s/lxc_rdepends", c->config_path,
+ ret = snprintf(path, PATH_MAX, "%s/%s/lxc_rdepends", c->config_path,
c->name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return false;
f = fopen(path, "a");
bool should_default_to_snapshot(struct lxc_container *c0,
struct lxc_container *c1)
{
+ __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;
- char *p0 = alloca(l0 + 1);
- char *p1 = alloca(l1 + 1);
char *rootfs = c0->lxc_conf->rootfs.path;
+ p0 = must_realloc(NULL, l0 + 1);
+ p1 = must_realloc(NULL, l1 + 1);
ret = snprintf(p0, l0, "%s/%s", c0->config_path, c0->name);
if (ret < 0 || ret >= l0)
return false;
int flags = data->flags;
char **hookargs = data->hookargs;
int ret = -1;
- char path[MAXPATHLEN];
+ char path[PATH_MAX];
struct lxc_storage *bdev;
FILE *fout;
struct lxc_conf *conf = c->lxc_conf;
}
} else { /* TODO come up with a better way */
free(bdev->dest);
- bdev->dest = strdup(bdev->src);
+ bdev->dest = strdup(lxc_storage_get_path(bdev->src, bdev->type));
}
if (!lxc_list_empty(&conf->hooks[LXCHOOK_CLONE])) {
}
if (!(flags & LXC_CLONE_KEEPNAME)) {
- ret = snprintf(path, MAXPATHLEN, "%s/etc/hostname", bdev->dest);
+ ret = snprintf(path, PATH_MAX, "%s/etc/hostname", bdev->dest);
storage_put(bdev);
- if (ret < 0 || ret >= MAXPATHLEN)
+ if (ret < 0 || ret >= PATH_MAX)
return -1;
if (!file_exists(path))
const char *bdevtype, const char *bdevdata, uint64_t newsize,
char **hookargs)
{
- char newpath[MAXPATHLEN];
+ char newpath[PATH_MAX];
int fd, ret;
struct clone_update_data data;
size_t saved_unexp_len;
if (container_mem_lock(c))
return NULL;
-
- if (!is_stopped(c)) {
- ERROR("error: Original container (%s) is running", c->name);
+ if (!is_stopped(c) && !(flags & LXC_CLONE_ALLOW_RUNNING)) {
+ ERROR("error: Original container (%s) is running. Use --allowrunning if you want to force a snapshot of the running container.", c->name);
goto out;
}
if (!lxcpath)
lxcpath = do_lxcapi_get_config_path(c);
- ret = snprintf(newpath, MAXPATHLEN, "%s/%s/config", lxcpath, newname);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ ret = snprintf(newpath, PATH_MAX, "%s/%s/config", lxcpath, newname);
+ if (ret < 0 || ret >= PATH_MAX) {
SYSERROR("clone: failed making config pathname");
goto out;
}
saved_unexp_conf = NULL;
c->lxc_conf->unexpanded_len = saved_unexp_len;
- ret = snprintf(newpath, MAXPATHLEN, "%s/%s/rootfs", lxcpath, newname);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ ret = snprintf(newpath, PATH_MAX, "%s/%s/rootfs", lxcpath, newname);
+ if (ret < 0 || ret >= PATH_MAX) {
SYSERROR("clone: failed making rootfs pathname");
goto out;
}
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)
{
- char *fname;
+ __do_free char *fname = NULL;
struct stat sb;
int i = 0, ret;
- fname = alloca(strlen(lxcpath) + 20);
+ fname = must_realloc(NULL, strlen(lxcpath) + 20);
- while (1) {
+ for (;;) {
sprintf(fname, "%s/snap%d", lxcpath, i);
ret = stat(fname, &sb);
* If the old style snapshot path exists, use it
* /var/lib/lxc -> /var/lib/lxcsnaps
*/
- ret = snprintf(snappath, MAXPATHLEN, "%ssnaps", c->config_path);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(snappath, PATH_MAX, "%ssnaps", c->config_path);
+ if (ret < 0 || ret >= PATH_MAX)
return false;
if (dir_exists(snappath)) {
- ret = snprintf(snappath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(snappath, PATH_MAX, "%ssnaps/%s", c->config_path, c->name);
+ if (ret < 0 || ret >= PATH_MAX)
return false;
return true;
* Use the new style path
* /var/lib/lxc -> /var/lib/lxc + c->name + /snaps + \0
*/
- ret = snprintf(snappath, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(snappath, PATH_MAX, "%s/%s/snaps", c->config_path, c->name);
+ if (ret < 0 || ret >= PATH_MAX)
return false;
return true;
static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
{
+ __do_free char *dfnam = NULL;
int i, flags, ret;
time_t timer;
struct tm tm_info;
struct lxc_container *c2;
- char snappath[MAXPATHLEN], newname[20];
+ char snappath[PATH_MAX], newname[20];
char buffer[25];
FILE *f;
strftime(buffer, 25, "%Y:%m:%d %H:%M:%S", &tm_info);
- char *dfnam = alloca(strlen(snappath) + strlen(newname) + 5);
+ dfnam = must_realloc(NULL, strlen(snappath) + strlen(newname) + 5);
sprintf(dfnam, "%s/%s/ts", snappath, newname);
f = fopen(dfnam, "w");
if (!f) {
}
if (commentfile) {
+ __do_free char *path = NULL;
/* $p / $name / comment \0 */
int len = strlen(snappath) + strlen(newname) + 10;
- char *path = alloca(len);
+ path = must_realloc(NULL, len);
sprintf(path, "%s/%s/comment", snappath, newname);
return copy_file(commentfile, path) < 0 ? -1 : i;
}
static char *get_timestamp(char* snappath, char *name)
{
- char path[MAXPATHLEN], *s = NULL;
+ char path[PATH_MAX], *s = NULL;
int ret, len;
FILE *fin;
- ret = snprintf(path, MAXPATHLEN, "%s/%s/ts", snappath, name);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(path, PATH_MAX, "%s/%s/ts", snappath, name);
+ if (ret < 0 || ret >= PATH_MAX)
return NULL;
fin = fopen(path, "r");
static int do_lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps)
{
- char snappath[MAXPATHLEN], path2[MAXPATHLEN];
+ char snappath[PATH_MAX], path2[PATH_MAX];
int count = 0, ret;
struct dirent *direntp;
struct lxc_snapshot *snaps =NULL, *nsnaps;
if (!strcmp(direntp->d_name, ".."))
continue;
- ret = snprintf(path2, MAXPATHLEN, "%s/%s/config", snappath, direntp->d_name);
- if (ret < 0 || ret >= MAXPATHLEN) {
+ ret = snprintf(path2, PATH_MAX, "%s/%s/config", snappath, direntp->d_name);
+ if (ret < 0 || ret >= PATH_MAX) {
ERROR("pathname too long");
goto out_free;
}
static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snapname, const char *newname)
{
- char clonelxcpath[MAXPATHLEN];
+ char clonelxcpath[PATH_MAX];
int flags = 0;
struct lxc_container *snap, *rest;
struct lxc_storage *bdev;
static bool do_lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname)
{
- char clonelxcpath[MAXPATHLEN];
+ char clonelxcpath[PATH_MAX];
if (!c || !c->name || !c->config_path || !snapname)
return false;
static bool do_lxcapi_snapshot_destroy_all(struct lxc_container *c)
{
- char clonelxcpath[MAXPATHLEN];
+ char clonelxcpath[PATH_MAX];
if (!c || !c->name || !c->config_path)
return false;
int ret;
char *tmp;
pid_t pid;
- char chrootpath[MAXPATHLEN];
+ char chrootpath[PATH_MAX];
char *directory_path = NULL;
pid = fork();
}
/* prepare the path */
- ret = snprintf(chrootpath, MAXPATHLEN, "/proc/%d/root", init_pid);
- if (ret < 0 || ret >= MAXPATHLEN)
+ ret = snprintf(chrootpath, PATH_MAX, "/proc/%d/root", init_pid);
+ if (ret < 0 || ret >= PATH_MAX)
return false;
ret = chroot(chrootpath);
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);
ret = mkdir(dest, 0000);
else
ret = mknod(dest, S_IFREG | 0000, 0);
- if (ret < 0) {
+
+ if (ret == 0)
+ TRACE("Created mount target \"%s\"", dest);
+ else if (ret < 0 && errno != EEXIST) {
SYSERROR("Failed to create mount target \"%s\"", dest);
return -1;
}
struct lxc_mount *mnt)
{
char *suff, *sret;
- char template[MAXPATHLEN], path[MAXPATHLEN];
+ char template[PATH_MAX], path[PATH_MAX];
pid_t pid, init_pid;
struct stat sb;
+ bool is_dir;
int ret = -1, fd = -EBADF;
if (!c || !c->lxc_conf) {
}
}
- if (S_ISDIR(sb.st_mode)) {
+ is_dir = (S_ISDIR(sb.st_mode) != 0);
+ if (is_dir) {
sret = mkdtemp(template);
if (!sret) {
SYSERROR("Could not create shmounts temporary dir");
/* Enter the container namespaces */
if (!lxc_list_empty(&c->lxc_conf->id_map)) {
- if (!switch_to_ns(init_pid, "user")){
+ if (!switch_to_ns(init_pid, "user")) {
ERROR("Failed to enter user namespace");
_exit(EXIT_FAILURE);
}
+
+ if (!lxc_switch_uid_gid(0, 0))
+ _exit(EXIT_FAILURE);
}
if (!switch_to_ns(init_pid, "mnt")) {
ret = create_mount_target(target, sb.st_mode);
if (ret < 0)
_exit(EXIT_FAILURE);
- TRACE("Created mount target \"%s\"", target);
suff = strrchr(template, '/');
if (!suff)
ret = 0;
(void)umount2(template, MNT_DETACH);
- (void)unlink(template);
+ if (is_dir)
+ (void)rmdir(template);
+ else
+ (void)unlink(template);
out:
if (fd >= 0)
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;