Unverified Commit be459e99 by Serge Hallyn Committed by GitHub

Merge pull request #1950 from brauner/2017-11-27/criu_fixes

bugfixes
parents f6812e7f 1c7222c0
...@@ -1191,7 +1191,7 @@ static int lxc_setup_rootfs(struct lxc_conf *conf) ...@@ -1191,7 +1191,7 @@ static int lxc_setup_rootfs(struct lxc_conf *conf)
return -1; return -1;
} }
bdev = storage_init(conf, rootfs->path, rootfs->mount, rootfs->options); bdev = storage_init(conf);
if (!bdev) { if (!bdev) {
ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\".", ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\".",
rootfs->path, rootfs->mount, rootfs->path, rootfs->mount,
...@@ -2725,7 +2725,7 @@ int chown_mapped_root_exec_wrapper(void *args) ...@@ -2725,7 +2725,7 @@ int chown_mapped_root_exec_wrapper(void *args)
* root is privileged with respect to hostuid/hostgid X, allowing * root is privileged with respect to hostuid/hostgid X, allowing
* him to do the chown. * him to do the chown.
*/ */
int chown_mapped_root(char *path, struct lxc_conf *conf) int chown_mapped_root(const char *path, struct lxc_conf *conf)
{ {
uid_t rootuid, rootgid; uid_t rootuid, rootgid;
unsigned long val; unsigned long val;
...@@ -2733,14 +2733,14 @@ int chown_mapped_root(char *path, struct lxc_conf *conf) ...@@ -2733,14 +2733,14 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
struct stat sb; struct stat sb;
char map1[100], map2[100], map3[100], map4[100], map5[100]; char map1[100], map2[100], map3[100], map4[100], map5[100];
char ugid[100]; char ugid[100];
char *args1[] = {"lxc-usernsexec", const char *args1[] = {"lxc-usernsexec",
"-m", map1, "-m", map1,
"-m", map2, "-m", map2,
"-m", map3, "-m", map3,
"-m", map5, "-m", map5,
"--", "chown", ugid, path, "--", "chown", ugid, path,
NULL}; NULL};
char *args2[] = {"lxc-usernsexec", const char *args2[] = {"lxc-usernsexec",
"-m", map1, "-m", map1,
"-m", map2, "-m", map2,
"-m", map3, "-m", map3,
......
...@@ -410,7 +410,7 @@ extern int setup_resource_limits(struct lxc_list *limits, pid_t pid); ...@@ -410,7 +410,7 @@ extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype); extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype);
extern int mapped_hostid(unsigned id, struct lxc_conf *conf, extern int mapped_hostid(unsigned id, struct lxc_conf *conf,
enum idtype idtype); enum idtype idtype);
extern int chown_mapped_root(char *path, struct lxc_conf *conf); extern int chown_mapped_root(const char *path, struct lxc_conf *conf);
extern int lxc_ttys_shift_ids(struct lxc_conf *c); extern int lxc_ttys_shift_ids(struct lxc_conf *c);
extern int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data, extern int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
const char *fn_name); const char *fn_name);
......
...@@ -1910,7 +1910,41 @@ static int set_config_includefiles(const char *key, const char *value, ...@@ -1910,7 +1910,41 @@ static int set_config_includefiles(const char *key, const char *value,
static int set_config_rootfs_path(const char *key, const char *value, static int set_config_rootfs_path(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data) struct lxc_conf *lxc_conf, void *data)
{ {
return set_config_path_item(&lxc_conf->rootfs.path, value); int ret;
char *dup, *tmp;
const char *container_path;
if (lxc_config_value_empty(value)) {
free(lxc_conf->rootfs.path);
lxc_conf->rootfs.path = NULL;
return 0;
}
dup = strdup(value);
if (!dup)
return -1;
/* Split <storage type>:<container path> into <storage type> and
* <container path>. Set "rootfs.bdev_type" to <storage type> and
* "rootfs.path" to <container path>.
*/
tmp = strchr(dup, ':');
if (tmp) {
*tmp = '\0';
ret = set_config_path_item(&lxc_conf->rootfs.bdev_type, dup);
if (ret < 0) {
free(dup);
return -1;
}
tmp++;
container_path = tmp;
} else {
container_path = value;
}
ret = set_config_path_item(&lxc_conf->rootfs.path, container_path);
free(dup);
return ret;
} }
static int set_config_rootfs_mount(const char *key, const char *value, static int set_config_rootfs_mount(const char *key, const char *value,
......
...@@ -564,6 +564,8 @@ static void exec_criu(struct criu_opts *opts) ...@@ -564,6 +564,8 @@ static void exec_criu(struct criu_opts *opts)
switch (n->type) { switch (n->type) {
case LXC_NET_VETH: case LXC_NET_VETH:
veth = n->priv.veth_attr.pair; veth = n->priv.veth_attr.pair;
if (veth[0] == '\0')
veth = n->priv.veth_attr.veth1;
if (n->link[0] != '\0') { if (n->link[0] != '\0') {
if (external_not_veth) if (external_not_veth)
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#include "start.h" #include "start.h"
#include "state.h" #include "state.h"
#include "storage.h" #include "storage.h"
#include "storage_utils.h"
#include "storage/btrfs.h" #include "storage/btrfs.h"
#include "storage/overlay.h" #include "storage/overlay.h"
#include "sync.h" #include "sync.h"
...@@ -1172,13 +1173,14 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c, ...@@ -1172,13 +1173,14 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c,
const char *type, const char *type,
struct bdev_specs *specs) struct bdev_specs *specs)
{ {
char *dest; int ret;
size_t len; size_t len;
char *dest;
struct lxc_storage *bdev; struct lxc_storage *bdev;
int ret;
/* rootfs.path or lxcpath/lxcname/rootfs */ /* rootfs.path or lxcpath/lxcname/rootfs */
if (c->lxc_conf->rootfs.path && !access(c->lxc_conf->rootfs.path, F_OK)) { if (c->lxc_conf->rootfs.path &&
(access(c->lxc_conf->rootfs.path, F_OK) == 0)) {
const char *rpath = c->lxc_conf->rootfs.path; const char *rpath = c->lxc_conf->rootfs.path;
len = strlen(rpath) + 1; len = strlen(rpath) + 1;
dest = alloca(len); dest = alloca(len);
...@@ -1189,27 +1191,28 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c, ...@@ -1189,27 +1191,28 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c,
dest = alloca(len); dest = alloca(len);
ret = snprintf(dest, len, "%s/%s/rootfs", lxcpath, c->name); ret = snprintf(dest, len, "%s/%s/rootfs", lxcpath, c->name);
} }
if (ret < 0 || ret >= len) if (ret < 0 || (size_t)ret >= len)
return NULL; return NULL;
bdev = storage_create(dest, type, c->name, specs); bdev = storage_create(dest, type, c->name, specs);
if (!bdev) { if (!bdev) {
ERROR("Failed to create backing store type %s", type); ERROR("Failed to create \"%s\" storage", type);
return NULL; return NULL;
} }
if (!c->set_config_item(c, "lxc.rootfs.path", bdev->src)) { if (!c->set_config_item(c, "lxc.rootfs.path", bdev->src)) {
ERROR("Failed to set config item \"lxc.rootfs.path\" to \"%s\"", ERROR("Failed to set \"lxc.rootfs.path = %s\"", bdev->src);
bdev->src);
return NULL; return NULL;
} }
/* If we are not root, chown the rootfs dir to root in the /* If we are not root, chown the rootfs dir to root in the target user
* target uidmap. * namespace.
*/ */
if (geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) { ret = geteuid();
if (chown_mapped_root(bdev->dest, c->lxc_conf) < 0) { if (ret != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) {
ERROR("Error chowning %s to container root", bdev->dest); ret = chown_mapped_root(bdev->dest, c->lxc_conf);
if (ret < 0) {
ERROR("Error chowning \"%s\" to container root", bdev->dest);
suggest_default_idmap(); suggest_default_idmap();
storage_put(bdev); storage_put(bdev);
return NULL; return NULL;
...@@ -1253,7 +1256,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ ...@@ -1253,7 +1256,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
exit(1); exit(1);
} }
bdev = storage_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL); bdev = storage_init(c->lxc_conf);
if (!bdev) { if (!bdev) {
ERROR("Error opening rootfs"); ERROR("Error opening rootfs");
exit(1); exit(1);
...@@ -1315,7 +1318,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ ...@@ -1315,7 +1318,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
} }
} }
} else { /* TODO come up with a better way here! */ } else { /* TODO come up with a better way here! */
char *src; const char *src;
free(bdev->dest); free(bdev->dest);
src = lxc_storage_get_path(bdev->src, bdev->type); src = lxc_storage_get_path(bdev->src, bdev->type);
bdev->dest = strdup(src); bdev->dest = strdup(src);
...@@ -1623,10 +1626,10 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, ...@@ -1623,10 +1626,10 @@ 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, int flags,
char *const argv[]) char *const argv[])
{ {
bool ret = false; int partial_fd;
pid_t pid; pid_t pid;
bool ret = false;
char *tpath = NULL; char *tpath = NULL;
int partial_fd;
if (!c) if (!c)
return false; return false;
...@@ -1634,26 +1637,26 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, ...@@ -1634,26 +1637,26 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
if (t) { if (t) {
tpath = get_template_path(t); tpath = get_template_path(t);
if (!tpath) { if (!tpath) {
ERROR("bad template: %s", t); ERROR("Unknown template \"%s\"", t);
goto out; goto out;
} }
} }
/* /* If a template is passed in, and the rootfs already is defined in the
* If a template is passed in, and the rootfs already is defined in * container config and exists, then the caller is trying to create an
* the container config and exists, then * caller is trying to create * existing container. Return an error, but do NOT delete the container.
* an existing container. Return an error, but do NOT delete the
* container.
*/ */
if (do_lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path && if (do_lxcapi_is_defined(c) && c->lxc_conf && c->lxc_conf->rootfs.path &&
access(c->lxc_conf->rootfs.path, F_OK) == 0 && tpath) { access(c->lxc_conf->rootfs.path, F_OK) == 0 && tpath) {
ERROR("Container %s:%s already exists", c->config_path, c->name); ERROR("Container \"%s\" already exists in \"%s\"", c->name,
c->config_path);
goto free_tpath; goto free_tpath;
} }
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", lxc_global_config_value("lxc.default_config")); ERROR("Error loading default configuration file %s",
lxc_global_config_value("lxc.default_config"));
goto free_tpath; goto free_tpath;
} }
} }
...@@ -1661,39 +1664,42 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, ...@@ -1661,39 +1664,42 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
if (!create_container_dir(c)) if (!create_container_dir(c))
goto free_tpath; goto free_tpath;
/* /* If both template and rootfs.path are set, template is setup as
* if both template and rootfs.path are set, template is setup as rootfs.path. * rootfs.path. The container is already created if we have a config and
* container is already created if we have a config and rootfs.path is accessible * rootfs.path is accessible
*/ */
if (!c->lxc_conf->rootfs.path && !tpath) { if (!c->lxc_conf->rootfs.path && !tpath) {
/* no template passed in and rootfs does not exist */ /* No template passed in and rootfs does not exist. */
if (!c->save_config(c, NULL)) { if (!c->save_config(c, NULL)) {
ERROR("failed to save starting configuration for %s\n", c->name); ERROR("Failed to save initial config for \"%s\"", c->name);
goto out; goto out;
} }
ret = true; ret = true;
goto out; goto out;
} }
/* Rootfs passed into configuration, but does not exist. */
if (c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) != 0) if (c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) != 0)
/* rootfs passed into configuration, but does not exist: error */
goto out; goto out;
if (do_lxcapi_is_defined(c) && c->lxc_conf->rootfs.path && !tpath) { if (do_lxcapi_is_defined(c) && c->lxc_conf->rootfs.path && !tpath) {
/* Rootfs already existed, user just wanted to save the /* Rootfs already existed, user just wanted to save the loaded
* loaded configuration */ * configuration.
*/
if (!c->save_config(c, NULL)) if (!c->save_config(c, NULL))
ERROR("failed to save starting configuration for %s\n", c->name); ERROR("Failed to save initial config for \"%s\"", c->name);
ret = true; ret = true;
goto out; goto out;
} }
/* Mark that this container is being created */ /* Mark that this container is being created */
if ((partial_fd = create_partial(c)) < 0) partial_fd = create_partial(c);
if (partial_fd < 0)
goto out; goto out;
/* no need to get disk lock bc we have the partial locked */ /* No need to get disk lock bc we have the partial lock. */
/* /* Create the storage.
* Create the backing store
* Note we can't do this in the same task as we use to execute the * Note we can't do this in the same task as we use to execute the
* template because of the way zfs works. * template because of the way zfs works.
* After you 'zfs create', zfs mounts the fs only in the initial * After you 'zfs create', zfs mounts the fs only in the initial
...@@ -1701,7 +1707,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, ...@@ -1701,7 +1707,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
*/ */
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");
goto out_unlock; goto out_unlock;
} }
...@@ -1710,15 +1716,17 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, ...@@ -1710,15 +1716,17 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
bdev = do_storage_create(c, bdevtype, specs); bdev = do_storage_create(c, bdevtype, specs);
if (!bdev) { if (!bdev) {
ERROR("Error creating backing store type %s 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. */
if (!do_lxcapi_save_config(c, NULL)) { if (!do_lxcapi_save_config(c, NULL)) {
ERROR("failed to save starting configuration for %s", c->name); ERROR("Failed to save initial config for %s", c->name);
/* Parent task won't see bdev in config so we delete it. */ /* Parent task won't see the storage driver in the
* config so we delete it.
*/
bdev->ops->umount(bdev); bdev->ops->umount(bdev);
bdev->ops->destroy(bdev); bdev->ops->destroy(bdev);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
...@@ -1728,7 +1736,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, ...@@ -1728,7 +1736,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
if (wait_for_pid(pid) != 0) if (wait_for_pid(pid) != 0)
goto out_unlock; goto out_unlock;
/* reload config to get the rootfs */ /* Reload config to get the rootfs. */
lxc_conf_free(c->lxc_conf); lxc_conf_free(c->lxc_conf);
c->lxc_conf = NULL; c->lxc_conf = NULL;
if (!load_config_locked(c, c->configfile)) if (!load_config_locked(c, c->configfile))
...@@ -1744,7 +1752,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t, ...@@ -1744,7 +1752,7 @@ static bool do_lxcapi_create(struct lxc_container *c, const char *t,
if (t) { if (t) {
if (!prepend_lxc_header(c->configfile, tpath, argv)) { if (!prepend_lxc_header(c->configfile, tpath, argv)) {
ERROR("Error prepending header to configuration file"); ERROR("Failed to prepend header to config file");
goto out_unlock; goto out_unlock;
} }
} }
...@@ -1762,8 +1770,8 @@ free_tpath: ...@@ -1762,8 +1770,8 @@ free_tpath:
} }
static bool lxcapi_create(struct lxc_container *c, const char *t, static bool 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[])
{ {
bool ret; bool ret;
current_config = c ? c->lxc_conf : NULL; current_config = c ? c->lxc_conf : NULL;
...@@ -1954,7 +1962,7 @@ static bool lxcapi_createl(struct lxc_container *c, const char *t, ...@@ -1954,7 +1962,7 @@ static bool lxcapi_createl(struct lxc_container *c, const char *t,
args = lxc_va_arg_list_to_argv(ap, 0, 0); args = lxc_va_arg_list_to_argv(ap, 0, 0);
va_end(ap); va_end(ap);
if (!args) { if (!args) {
ERROR("Memory allocation error."); ERROR("Failed to allocate memory");
goto out; goto out;
} }
...@@ -3408,7 +3416,7 @@ static int clone_update_rootfs(struct clone_update_data *data) ...@@ -3408,7 +3416,7 @@ static int clone_update_rootfs(struct clone_update_data *data)
if (unshare(CLONE_NEWNS) < 0) if (unshare(CLONE_NEWNS) < 0)
return -1; return -1;
bdev = storage_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL); bdev = storage_init(c->lxc_conf);
if (!bdev) if (!bdev)
return -1; return -1;
if (strcmp(bdev->type, "dir") != 0) { if (strcmp(bdev->type, "dir") != 0) {
...@@ -3739,7 +3747,7 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname) ...@@ -3739,7 +3747,7 @@ static bool do_lxcapi_rename(struct lxc_container *c, const char *newname)
ERROR("Renaming a container with snapshots is not supported"); ERROR("Renaming a container with snapshots is not supported");
return false; return false;
} }
bdev = storage_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL); bdev = storage_init(c->lxc_conf);
if (!bdev) { if (!bdev) {
ERROR("Failed to find original backing store type"); ERROR("Failed to find original backing store type");
return false; return false;
...@@ -3884,7 +3892,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile) ...@@ -3884,7 +3892,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
*/ */
flags = LXC_CLONE_SNAPSHOT | LXC_CLONE_KEEPMACADDR | LXC_CLONE_KEEPNAME | flags = LXC_CLONE_SNAPSHOT | LXC_CLONE_KEEPMACADDR | LXC_CLONE_KEEPNAME |
LXC_CLONE_KEEPBDEVTYPE | LXC_CLONE_MAYBE_SNAPSHOT; LXC_CLONE_KEEPBDEVTYPE | LXC_CLONE_MAYBE_SNAPSHOT;
if (storage_is_dir(c->lxc_conf, c->lxc_conf->rootfs.path)) { if (storage_is_dir(c->lxc_conf)) {
ERROR("Snapshot of directory-backed container requested."); ERROR("Snapshot of directory-backed container requested.");
ERROR("Making a copy-clone. If you do want snapshots, then"); ERROR("Making a copy-clone. If you do want snapshots, then");
ERROR("please create an aufs or overlay clone first, snapshot that"); ERROR("please create an aufs or overlay clone first, snapshot that");
...@@ -4089,8 +4097,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap ...@@ -4089,8 +4097,7 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
return false; return false;
} }
bdev = storage_init(c->lxc_conf, c->lxc_conf->rootfs.path, bdev = storage_init(c->lxc_conf);
c->lxc_conf->rootfs.mount, NULL);
if (!bdev) { if (!bdev) {
ERROR("Failed to find original backing store type"); ERROR("Failed to find original backing store type");
return false; return false;
...@@ -4136,8 +4143,8 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap ...@@ -4136,8 +4143,8 @@ static bool do_lxcapi_snapshot_restore(struct lxc_container *c, const char *snap
if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs")) if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs"))
flags |= LXC_STORAGE_INTERNAL_OVERLAY_RESTORE; flags |= LXC_STORAGE_INTERNAL_OVERLAY_RESTORE;
rest = lxcapi_clone(snap, newname, c->config_path, flags, rest = lxcapi_clone(snap, newname, c->config_path, flags, bdev->type,
bdev->type, NULL, 0, NULL); NULL, 0, NULL);
storage_put(bdev); storage_put(bdev);
if (rest && lxcapi_is_defined(rest)) if (rest && lxcapi_is_defined(rest))
b = true; b = true;
...@@ -4601,7 +4608,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath ...@@ -4601,7 +4608,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
c = malloc(sizeof(*c)); c = malloc(sizeof(*c));
if (!c) { if (!c) {
fprintf(stderr, "failed to malloc lxc_container\n"); fprintf(stderr, "Failed to allocate memory for %s\n", name);
return NULL; return NULL;
} }
memset(c, 0, sizeof(*c)); memset(c, 0, sizeof(*c));
...@@ -4612,39 +4619,43 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath ...@@ -4612,39 +4619,43 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
c->config_path = strdup(lxc_global_config_value("lxc.lxcpath")); c->config_path = strdup(lxc_global_config_value("lxc.lxcpath"));
if (!c->config_path) { if (!c->config_path) {
fprintf(stderr, "Out of memory\n"); fprintf(stderr, "Failed to allocate memory for %s\n", name);
goto err; goto err;
} }
remove_trailing_slashes(c->config_path); remove_trailing_slashes(c->config_path);
c->name = malloc(strlen(name)+1); c->name = malloc(strlen(name)+1);
if (!c->name) { if (!c->name) {
fprintf(stderr, "Error allocating lxc_container name\n"); fprintf(stderr, "Failed to allocate memory for %s\n", name);
goto err; goto err;
} }
strcpy(c->name, name); strcpy(c->name, name);
c->numthreads = 1; c->numthreads = 1;
if (!(c->slock = lxc_newlock(c->config_path, name))) { c->slock = lxc_newlock(c->config_path, name);
fprintf(stderr, "failed to create lock\n"); if (!c->slock) {
fprintf(stderr, "Failed to create lock for %s\n", name);
goto err; goto err;
} }
if (!(c->privlock = lxc_newlock(NULL, NULL))) { c->privlock = lxc_newlock(NULL, NULL);
fprintf(stderr, "failed to alloc privlock\n"); if (!c->privlock) {
fprintf(stderr, "Failed to create private lock for %s\n", name);
goto err; goto err;
} }
if (!set_config_filename(c)) { if (!set_config_filename(c)) {
fprintf(stderr, "Error allocating config file pathname\n"); fprintf(stderr, "Failed to create config file name for %s\n", name);
goto err; goto err;
} }
if (file_exists(c->configfile) && !lxcapi_load_config(c, NULL)) if (file_exists(c->configfile) && !lxcapi_load_config(c, NULL)) {
fprintf(stderr, "Failed to load config for %s\n", name);
goto err; goto err;
}
if (ongoing_create(c) == 2) { if (ongoing_create(c) == 2) {
ERROR("Error: %s creation was not completed", c->name); ERROR("Failed to complete container creation for %s", c->name);
container_destroy(c, NULL); container_destroy(c, NULL);
lxcapi_clear_config(c); lxcapi_clear_config(c);
} }
......
...@@ -187,7 +187,8 @@ bool btrfs_detect(const char *path) ...@@ -187,7 +187,8 @@ bool btrfs_detect(const char *path)
int btrfs_mount(struct lxc_storage *bdev) int btrfs_mount(struct lxc_storage *bdev)
{ {
unsigned long mntflags; unsigned long mntflags;
char *mntdata, *src; char *mntdata;
const char *src;
int ret; int ret;
if (strcmp(bdev->type, "btrfs")) if (strcmp(bdev->type, "btrfs"))
...@@ -348,7 +349,7 @@ out: ...@@ -348,7 +349,7 @@ out:
int btrfs_snapshot_wrapper(void *data) int btrfs_snapshot_wrapper(void *data)
{ {
char *src; const char *src;
struct rsync_data_char *arg = data; struct rsync_data_char *arg = data;
if (setgid(0) < 0) { if (setgid(0) < 0) {
...@@ -372,7 +373,7 @@ int btrfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, ...@@ -372,7 +373,7 @@ int btrfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
const char *oldpath, const char *lxcpath, int snap, const char *oldpath, const char *lxcpath, int snap,
uint64_t newsize, struct lxc_conf *conf) uint64_t newsize, struct lxc_conf *conf)
{ {
char *src; const char *src;
if (!orig->dest || !orig->src) if (!orig->dest || !orig->src)
return -1; return -1;
...@@ -483,7 +484,7 @@ bool btrfs_create_snapshot(struct lxc_conf *conf, struct lxc_storage *orig, ...@@ -483,7 +484,7 @@ bool btrfs_create_snapshot(struct lxc_conf *conf, struct lxc_storage *orig,
return true; return true;
} }
ret = btrfs_snapshot(orig->dest, new->dest); ret = btrfs_snapshot(orig->src, new->dest);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to create btrfs snapshot \"%s\" from \"%s\"", SYSERROR("Failed to create btrfs snapshot \"%s\" from \"%s\"",
new->dest, orig->dest); new->dest, orig->dest);
...@@ -821,7 +822,7 @@ bool btrfs_try_remove_subvol(const char *path) ...@@ -821,7 +822,7 @@ bool btrfs_try_remove_subvol(const char *path)
int btrfs_destroy(struct lxc_storage *orig) int btrfs_destroy(struct lxc_storage *orig)
{ {
char *src; const char *src;
src = lxc_storage_get_path(orig->src, "btrfs"); src = lxc_storage_get_path(orig->src, "btrfs");
......
...@@ -39,7 +39,7 @@ int dir_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, ...@@ -39,7 +39,7 @@ int dir_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
const char *lxcpath, int snap, uint64_t newsize, const char *lxcpath, int snap, uint64_t newsize,
struct lxc_conf *conf) struct lxc_conf *conf)
{ {
char *src_no_prefix; const char *src_no_prefix;
int ret; int ret;
size_t len; size_t len;
...@@ -121,7 +121,7 @@ int dir_create(struct lxc_storage *bdev, const char *dest, const char *n, ...@@ -121,7 +121,7 @@ int dir_create(struct lxc_storage *bdev, const char *dest, const char *n,
int dir_destroy(struct lxc_storage *orig) int dir_destroy(struct lxc_storage *orig)
{ {
int ret; int ret;
char *src; const char *src;
src = lxc_storage_get_path(orig->src, orig->src); src = lxc_storage_get_path(orig->src, orig->src);
...@@ -149,7 +149,8 @@ int dir_mount(struct lxc_storage *bdev) ...@@ -149,7 +149,8 @@ int dir_mount(struct lxc_storage *bdev)
{ {
int ret; int ret;
unsigned long mflags, mntflags; unsigned long mflags, mntflags;
char *src, *mntdata; char *mntdata;
const char *src;
if (strcmp(bdev->type, "dir")) if (strcmp(bdev->type, "dir"))
return -22; return -22;
......
...@@ -204,7 +204,13 @@ int loop_create(struct lxc_storage *bdev, const char *dest, const char *n, ...@@ -204,7 +204,13 @@ int loop_create(struct lxc_storage *bdev, const char *dest, const char *n,
} }
int loop_destroy(struct lxc_storage *orig) { int loop_destroy(struct lxc_storage *orig) {
return unlink(orig->src + 5); char *dir;
dir = orig->src;
if (strncmp(orig->src, "loop:", 5) == 0)
dir += 5;
return unlink(dir);
} }
bool loop_detect(const char *path) bool loop_detect(const char *path)
...@@ -229,7 +235,7 @@ int loop_mount(struct lxc_storage *bdev) ...@@ -229,7 +235,7 @@ int loop_mount(struct lxc_storage *bdev)
{ {
int ret, loopfd; int ret, loopfd;
char loname[MAXPATHLEN]; char loname[MAXPATHLEN];
char *src; const char *src;
if (strcmp(bdev->type, "loop")) if (strcmp(bdev->type, "loop"))
return -22; return -22;
......
...@@ -235,7 +235,7 @@ bool lvm_detect(const char *path) ...@@ -235,7 +235,7 @@ bool lvm_detect(const char *path)
int lvm_mount(struct lxc_storage *bdev) int lvm_mount(struct lxc_storage *bdev)
{ {
char *src; const char *src;
if (strcmp(bdev->type, "lvm")) if (strcmp(bdev->type, "lvm"))
return -22; return -22;
...@@ -330,11 +330,12 @@ static int lvm_snapshot_create_new_uuid_wrapper(void *data) ...@@ -330,11 +330,12 @@ static int lvm_snapshot_create_new_uuid_wrapper(void *data)
static int lvm_snapshot(struct lxc_storage *orig, const char *path, uint64_t size) static int lvm_snapshot(struct lxc_storage *orig, const char *path, uint64_t size)
{ {
int ret; int ret;
char *origsrc, *pathdup, *lv; char *lv, *pathdup;
char sz[24]; char sz[24];
char fstype[100]; char fstype[100];
char cmd_output[MAXPATHLEN]; char cmd_output[MAXPATHLEN];
char repairchar; char repairchar;
const char *origsrc;
struct lvcreate_args cmd_args = {0}; struct lvcreate_args cmd_args = {0};
ret = snprintf(sz, 24, "%" PRIu64 "b", size); ret = snprintf(sz, 24, "%" PRIu64 "b", size);
...@@ -433,7 +434,8 @@ int lvm_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, ...@@ -433,7 +434,8 @@ int lvm_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
(const char *[]){"lvm:", "dev", vg, cname, NULL}, (const char *[]){"lvm:", "dev", vg, cname, NULL},
false); false);
} else { } else {
char *dup, *slider, *src; const char *src;
char *dup, *slider;
src = lxc_storage_get_path(orig->src, orig->type); src = lxc_storage_get_path(orig->src, orig->type);
...@@ -497,11 +499,11 @@ int lvm_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, ...@@ -497,11 +499,11 @@ int lvm_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
bool lvm_create_clone(struct lxc_conf *conf, struct lxc_storage *orig, bool lvm_create_clone(struct lxc_conf *conf, struct lxc_storage *orig,
struct lxc_storage *new, uint64_t newsize) struct lxc_storage *new, uint64_t newsize)
{ {
char *src;
const char *thinpool;
int ret; int ret;
const char *src;
const char *thinpool;
struct rsync_data data; struct rsync_data data;
char *cmd_args[2]; const char *cmd_args[2];
char cmd_output[MAXPATHLEN] = {0}; char cmd_output[MAXPATHLEN] = {0};
char fstype[100] = "ext4"; char fstype[100] = "ext4";
uint64_t size = newsize; uint64_t size = newsize;
...@@ -560,7 +562,7 @@ bool lvm_create_snapshot(struct lxc_conf *conf, struct lxc_storage *orig, ...@@ -560,7 +562,7 @@ bool lvm_create_snapshot(struct lxc_conf *conf, struct lxc_storage *orig,
struct lxc_storage *new, uint64_t newsize) struct lxc_storage *new, uint64_t newsize)
{ {
int ret; int ret;
char *newsrc; const char *newsrc;
uint64_t size = newsize; uint64_t size = newsize;
if (is_blktype(orig)) { if (is_blktype(orig)) {
......
...@@ -118,7 +118,7 @@ bool nbd_detect(const char *path) ...@@ -118,7 +118,7 @@ bool nbd_detect(const char *path)
int nbd_mount(struct lxc_storage *bdev) int nbd_mount(struct lxc_storage *bdev)
{ {
int ret = -1, partition; int ret = -1, partition;
char *src; const char *src;
char path[50]; char path[50];
if (strcmp(bdev->type, "nbd")) if (strcmp(bdev->type, "nbd"))
......
...@@ -54,7 +54,7 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char ...@@ -54,7 +54,7 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char
int snap, uint64_t newsize, struct lxc_conf *conf) int snap, uint64_t newsize, struct lxc_conf *conf)
{ {
int ret; int ret;
char *src; const char *src;
if (!snap) { if (!snap) {
ERROR("The overlay storage driver can only be used for " ERROR("The overlay storage driver can only be used for "
...@@ -199,12 +199,11 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char ...@@ -199,12 +199,11 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char
return -22; return -22;
} }
nsrc = strchr(osrc, ':') + 1; nsrc = osrc;
if ((nsrc != osrc + 8) && (nsrc != osrc + 10)) { if (strncmp(osrc, "overlay:", 8) == 0)
ERROR("Detected \":\" in \"%s\" at wrong position", osrc); nsrc += 8;
free(osrc); else if (strncmp(osrc, "overlayfs:", 10) == 0)
return -22; nsrc += 10;
}
odelta = strchr(nsrc, ':'); odelta = strchr(nsrc, ':');
if (!odelta) { if (!odelta) {
...@@ -457,22 +456,17 @@ int ovl_create(struct lxc_storage *bdev, const char *dest, const char *n, ...@@ -457,22 +456,17 @@ int ovl_create(struct lxc_storage *bdev, const char *dest, const char *n,
int ovl_destroy(struct lxc_storage *orig) int ovl_destroy(struct lxc_storage *orig)
{ {
bool ovl;
char *upper = orig->src; char *upper = orig->src;
ovl = !strncmp(upper, "overlay:", 8);
if (!ovl && strncmp(upper, "overlayfs:", 10))
return -22;
/* For an overlay container the rootfs is considered immutable /* For an overlay container the rootfs is considered immutable
* and cannot be removed when restoring from a snapshot. * and cannot be removed when restoring from a snapshot.
*/ */
if (orig->flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE) if (orig->flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE)
return 0; return 0;
if (ovl) if (strncmp(upper, "overlay:", 8) == 0)
upper += 8; upper += 8;
else else if (strncmp(upper, "overlayfs:", 10) == 0)
upper += 10; upper += 10;
upper = strchr(upper, ':'); upper = strchr(upper, ':');
...@@ -485,10 +479,10 @@ int ovl_destroy(struct lxc_storage *orig) ...@@ -485,10 +479,10 @@ int ovl_destroy(struct lxc_storage *orig)
bool ovl_detect(const char *path) bool ovl_detect(const char *path)
{ {
if (!strncmp(path, "overlayfs:", 10)) if (!strncmp(path, "overlay:", 8))
return true; return true;
if (!strncmp(path, "overlay:", 8)) if (!strncmp(path, "overlayfs:", 10))
return true; return true;
return false; return false;
...@@ -521,18 +515,19 @@ int ovl_mount(struct lxc_storage *bdev) ...@@ -521,18 +515,19 @@ int ovl_mount(struct lxc_storage *bdev)
ERROR("Failed to allocate memory"); ERROR("Failed to allocate memory");
return -1; return -1;
} }
upper = dup;
lower = dup;
/* support multiple lower layers */ if (strncmp(dup, "overlay:", 8) == 0)
lower = strstr(dup, ":/"); lower += 8;
if (!lower) { else if (strncmp(dup, "overlayfs:", 10) == 0)
ERROR("Failed to detect \":/\" in string \"%s\"", dup); lower += 10;
free(dup); if (upper != lower)
return -22; upper = lower;
}
lower++; /* support multiple lower layers */
upper = lower; while ((tmp = strstr(upper, ":/"))) {
while ((tmp = strstr(++upper, ":/"))) { tmp++;
upper = tmp; upper = tmp;
} }
...@@ -688,14 +683,14 @@ int ovl_umount(struct lxc_storage *bdev) ...@@ -688,14 +683,14 @@ int ovl_umount(struct lxc_storage *bdev)
return ret; return ret;
} }
char *ovl_get_lower(const char *rootfs_path) const char *ovl_get_lower(const char *rootfs_path)
{ {
char *s1; const char *s1 = rootfs_path;
s1 = strstr(rootfs_path, ":/"); if (strncmp(rootfs_path, "overlay:", 8) == 0)
if (!s1) s1 += 8;
return NULL; else if (strncmp(rootfs_path, "overlayfs:", 10) == 0)
s1++; s1 += 10;
s1 = strstr(s1, ":/"); s1 = strstr(s1, ":/");
if (!s1) if (!s1)
...@@ -719,16 +714,20 @@ char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen) ...@@ -719,16 +714,20 @@ char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen)
if (!s1) if (!s1)
return NULL; return NULL;
s2 = strstr(s1, ":/"); s2 = s1;
if (s2) { if (strncmp(rootfs_path, "overlay:", 8) == 0)
s2 = s2 + 1; s2 += 8;
if ((s3 = strstr(s2, ":/"))) else if (strncmp(rootfs_path, "overlayfs:", 10) == 0)
*s3 = '\0'; s2 += 10;
rootfsdir = strdup(s2);
if (!rootfsdir) { s3 = strstr(s2, ":/");
free(s1); if (s3)
return NULL; *s3 = '\0';
}
rootfsdir = strdup(s2);
if (!rootfsdir) {
free(s1);
return NULL;
} }
if (!rootfsdir) if (!rootfsdir)
......
...@@ -66,7 +66,7 @@ extern int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path, ...@@ -66,7 +66,7 @@ extern int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
/* To be called from functions in lxccontainer.c: Get lower directory for /* To be called from functions in lxccontainer.c: Get lower directory for
* overlay rootfs. * overlay rootfs.
*/ */
extern char *ovl_get_lower(const char *rootfs_path); extern const char *ovl_get_lower(const char *rootfs_path);
/* Get rootfs path for overlay backed containers. Allocated memory must be freed /* Get rootfs path for overlay backed containers. Allocated memory must be freed
* by caller. * by caller.
......
...@@ -189,7 +189,7 @@ int rbd_create(struct lxc_storage *bdev, const char *dest, const char *n, ...@@ -189,7 +189,7 @@ int rbd_create(struct lxc_storage *bdev, const char *dest, const char *n,
int rbd_destroy(struct lxc_storage *orig) int rbd_destroy(struct lxc_storage *orig)
{ {
int ret; int ret;
char *src; const char *src;
char *rbdfullname; char *rbdfullname;
char cmd_output[MAXPATHLEN]; char cmd_output[MAXPATHLEN];
struct rbd_args args = {0}; struct rbd_args args = {0};
...@@ -233,7 +233,7 @@ bool rbd_detect(const char *path) ...@@ -233,7 +233,7 @@ bool rbd_detect(const char *path)
int rbd_mount(struct lxc_storage *bdev) int rbd_mount(struct lxc_storage *bdev)
{ {
char *src; const char *src;
if (strcmp(bdev->type, "rbd")) if (strcmp(bdev->type, "rbd"))
return -22; return -22;
......
...@@ -87,7 +87,7 @@ int lxc_rsync_exec(const char *src, const char *dest) ...@@ -87,7 +87,7 @@ int lxc_rsync_exec(const char *src, const char *dest)
int lxc_rsync(struct rsync_data *data) int lxc_rsync(struct rsync_data *data)
{ {
int ret; int ret;
char *dest, *src; const char *dest, *src;
struct lxc_storage *orig = data->orig, *new = data->new; struct lxc_storage *orig = data->orig, *new = data->new;
ret = unshare(CLONE_NEWNS); ret = unshare(CLONE_NEWNS);
......
...@@ -213,17 +213,27 @@ static const struct lxc_storage_type bdevs[] = { ...@@ -213,17 +213,27 @@ static const struct lxc_storage_type bdevs[] = {
static const size_t numbdevs = sizeof(bdevs) / sizeof(struct lxc_storage_type); static const size_t numbdevs = sizeof(bdevs) / sizeof(struct lxc_storage_type);
static const struct lxc_storage_type *get_storage_by_name(const char *name) static const struct lxc_storage_type *get_storage_by_name(const char *path,
const char *type)
{ {
int ret;
size_t i, cmplen; size_t i, cmplen;
cmplen = strcspn(name, ":"); if (type)
cmplen = strlen(type);
else
cmplen = strcspn(path, ":");
if (cmplen == 0) if (cmplen == 0)
return NULL; return NULL;
for (i = 0; i < numbdevs; i++) for (i = 0; i < numbdevs; i++) {
if (strncmp(bdevs[i].name, name, cmplen) == 0) if (type)
ret = strncmp(bdevs[i].name, type, cmplen);
else
ret = strncmp(bdevs[i].name, path, cmplen);
if (ret == 0)
break; break;
}
if (i == numbdevs) if (i == numbdevs)
return NULL; return NULL;
...@@ -232,18 +242,19 @@ static const struct lxc_storage_type *get_storage_by_name(const char *name) ...@@ -232,18 +242,19 @@ static const struct lxc_storage_type *get_storage_by_name(const char *name)
return &bdevs[i]; return &bdevs[i];
} }
const struct lxc_storage_type *storage_query(struct lxc_conf *conf, static const struct lxc_storage_type *storage_query(struct lxc_conf *conf)
const char *src)
{ {
size_t i; size_t i;
const struct lxc_storage_type *bdev; const struct lxc_storage_type *bdev;
const char *path = conf->rootfs.path;
const char *type = conf->rootfs.bdev_type;
bdev = get_storage_by_name(src); bdev = get_storage_by_name(path, type);
if (bdev) if (bdev)
return bdev; return bdev;
for (i = 0; i < numbdevs; i++) for (i = 0; i < numbdevs; i++)
if (bdevs[i].ops->detect(src)) if (bdevs[i].ops->detect(path))
break; break;
if (i == numbdevs) if (i == numbdevs)
...@@ -258,10 +269,9 @@ struct lxc_storage *storage_get(const char *type) ...@@ -258,10 +269,9 @@ struct lxc_storage *storage_get(const char *type)
size_t i; size_t i;
struct lxc_storage *bdev; struct lxc_storage *bdev;
for (i = 0; i < numbdevs; i++) { for (i = 0; i < numbdevs; i++)
if (strcmp(bdevs[i].name, type) == 0) if (strcmp(bdevs[i].name, type) == 0)
break; break;
}
if (i == numbdevs) if (i == numbdevs)
return NULL; return NULL;
...@@ -274,7 +284,7 @@ struct lxc_storage *storage_get(const char *type) ...@@ -274,7 +284,7 @@ struct lxc_storage *storage_get(const char *type)
bdev->ops = bdevs[i].ops; bdev->ops = bdevs[i].ops;
bdev->type = bdevs[i].name; bdev->type = bdevs[i].name;
if (!strcmp(bdev->type, "aufs")) if (strcmp(bdev->type, "aufs") == 0)
WARN("The \"aufs\" driver will is deprecated and will soon be " WARN("The \"aufs\" driver will is deprecated and will soon be "
"removed. For similar functionality see the \"overlay\" " "removed. For similar functionality see the \"overlay\" "
"storage driver"); "storage driver");
...@@ -286,7 +296,7 @@ static struct lxc_storage *do_storage_create(const char *dest, const char *type, ...@@ -286,7 +296,7 @@ static struct lxc_storage *do_storage_create(const char *dest, const char *type,
const char *cname, const char *cname,
struct bdev_specs *specs) struct bdev_specs *specs)
{ {
int ret;
struct lxc_storage *bdev; struct lxc_storage *bdev;
if (!type) if (!type)
...@@ -296,7 +306,8 @@ static struct lxc_storage *do_storage_create(const char *dest, const char *type, ...@@ -296,7 +306,8 @@ static struct lxc_storage *do_storage_create(const char *dest, const char *type,
if (!bdev) if (!bdev)
return NULL; return NULL;
if (bdev->ops->create(bdev, dest, cname, specs) < 0) { ret = bdev->ops->create(bdev, dest, cname, specs);
if (ret < 0) {
storage_put(bdev); storage_put(bdev);
return NULL; return NULL;
} }
...@@ -306,9 +317,10 @@ static struct lxc_storage *do_storage_create(const char *dest, const char *type, ...@@ -306,9 +317,10 @@ static struct lxc_storage *do_storage_create(const char *dest, const char *type,
bool storage_can_backup(struct lxc_conf *conf) bool storage_can_backup(struct lxc_conf *conf)
{ {
struct lxc_storage *bdev = storage_init(conf, NULL, NULL, NULL);
bool ret; bool ret;
struct lxc_storage *bdev;
bdev = storage_init(conf);
if (!bdev) if (!bdev)
return false; return false;
...@@ -326,16 +338,16 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname, ...@@ -326,16 +338,16 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
uint64_t newsize, bool *needs_rdep) uint64_t newsize, bool *needs_rdep)
{ {
int ret; int ret;
struct lxc_storage *orig, *new; const char *src_no_prefix;
char *src_no_prefix; struct lxc_storage *new, *orig;
bool snap = flags & LXC_CLONE_SNAPSHOT; bool snap = (flags & LXC_CLONE_SNAPSHOT);
bool maybe_snap = flags & LXC_CLONE_MAYBE_SNAPSHOT; bool maybe_snap = (flags & LXC_CLONE_MAYBE_SNAPSHOT);
bool keepbdevtype = flags & LXC_CLONE_KEEPBDEVTYPE; bool keepbdevtype = (flags & LXC_CLONE_KEEPBDEVTYPE);
const char *src = c->lxc_conf->rootfs.path; const char *src = c->lxc_conf->rootfs.path;
const char *oldname = c->name; const char *oldname = c->name;
const char *oldpath = c->config_path; const char *oldpath = c->config_path;
struct rsync_data data = {0};
char cmd_output[MAXPATHLEN] = {0}; char cmd_output[MAXPATHLEN] = {0};
struct rsync_data data = {0};
if (!src) { if (!src) {
ERROR("No rootfs specified"); ERROR("No rootfs specified");
...@@ -351,9 +363,9 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname, ...@@ -351,9 +363,9 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
return NULL; return NULL;
} }
orig = storage_init(c->lxc_conf, src, NULL, NULL); orig = storage_init(c->lxc_conf);
if (!orig) { if (!orig) {
ERROR("Failed to detect storage driver for \"%s\"", src); ERROR("Failed to detect storage driver for \"%s\"", oldname);
return NULL; return NULL;
} }
...@@ -422,11 +434,11 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname, ...@@ -422,11 +434,11 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
/* get new bdev type */ /* get new bdev type */
new = storage_get(bdevtype); new = storage_get(bdevtype);
if (!new) { if (!new) {
ERROR("Failed to initialize \"%s\" storage driver", ERROR("Failed to initialize %s storage driver",
bdevtype ? bdevtype : orig->type); bdevtype ? bdevtype : orig->type);
goto on_error_put_orig; goto on_error_put_orig;
} }
TRACE("Initialized \"%s\" storage driver", new->type); TRACE("Initialized %s storage driver", new->type);
/* create new paths */ /* create new paths */
ret = new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath, ret = new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath,
...@@ -440,14 +452,15 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname, ...@@ -440,14 +452,15 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
* snapshot directory under "<lxcpath>/<name>/snaps/" we don't need to * snapshot directory under "<lxcpath>/<name>/snaps/" we don't need to
* record a dependency. If we would restore would also fail. * record a dependency. If we would restore would also fail.
*/ */
if ((!strcmp(new->type, "overlay") || if ((strcmp(new->type, "overlay") == 0 ||
!strcmp(new->type, "overlayfs")) && strcmp(new->type, "overlayfs") == 0) &&
ret == LXC_CLONE_SNAPSHOT) ret == LXC_CLONE_SNAPSHOT)
*needs_rdep = false; *needs_rdep = false;
/* btrfs */ /* btrfs */
if (!strcmp(orig->type, "btrfs") && !strcmp(new->type, "btrfs")) { if (!strcmp(orig->type, "btrfs") && !strcmp(new->type, "btrfs")) {
bool bret = false; bool bret;
if (snap || btrfs_same_fs(orig->dest, new->dest) == 0) if (snap || btrfs_same_fs(orig->dest, new->dest) == 0)
bret = new->ops->snapshot(c->lxc_conf, orig, new, 0); bret = new->ops->snapshot(c->lxc_conf, orig, new, 0);
else else
...@@ -460,10 +473,10 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname, ...@@ -460,10 +473,10 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
/* lvm */ /* lvm */
if (!strcmp(orig->type, "lvm") && !strcmp(new->type, "lvm")) { if (!strcmp(orig->type, "lvm") && !strcmp(new->type, "lvm")) {
bool bret = false; bool bret;
if (snap) if (snap)
bret = new->ops->snapshot(c->lxc_conf, orig, bret = new->ops->snapshot(c->lxc_conf, orig, new, newsize);
new, newsize);
else else
bret = new->ops->copy(c->lxc_conf, orig, new, newsize); bret = new->ops->copy(c->lxc_conf, orig, new, newsize);
if (!bret) if (!bret)
...@@ -474,11 +487,10 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname, ...@@ -474,11 +487,10 @@ struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
/* zfs */ /* zfs */
if (!strcmp(orig->type, "zfs") && !strcmp(new->type, "zfs")) { if (!strcmp(orig->type, "zfs") && !strcmp(new->type, "zfs")) {
bool bret = false; bool bret;
if (snap) if (snap)
bret = new->ops->snapshot(c->lxc_conf, orig, new, bret = new->ops->snapshot(c->lxc_conf, orig, new, newsize);
newsize);
else else
bret = new->ops->copy(c->lxc_conf, orig, new, newsize); bret = new->ops->copy(c->lxc_conf, orig, new, newsize);
if (!bret) if (!bret)
...@@ -547,20 +559,21 @@ on_error_put_orig: ...@@ -547,20 +559,21 @@ on_error_put_orig:
struct lxc_storage *storage_create(const char *dest, const char *type, struct lxc_storage *storage_create(const char *dest, const char *type,
const char *cname, struct bdev_specs *specs) const char *cname, struct bdev_specs *specs)
{ {
int ret;
struct lxc_storage *bdev; struct lxc_storage *bdev;
char *best_options[] = {"btrfs", "zfs", "lvm", "dir", "rbd", NULL}; char *best_options[] = {"btrfs", "zfs", "lvm", "dir", "rbd", NULL};
if (!type) if (!type)
return do_storage_create(dest, "dir", cname, specs); return do_storage_create(dest, "dir", cname, specs);
if (strcmp(type, "best") == 0) { ret = strcmp(type, "best");
if (ret == 0) {
int i; int i;
/* Try for the best backing store type, according to our /* Try for the best backing store type, according to our
* opinionated preferences. * opinionated preferences.
*/ */
for (i = 0; best_options[i]; i++) { for (i = 0; best_options[i]; i++) {
bdev = do_storage_create(dest, best_options[i], cname, bdev = do_storage_create(dest, best_options[i], cname, specs);
specs);
if (bdev) if (bdev)
return bdev; return bdev;
} }
...@@ -569,12 +582,16 @@ struct lxc_storage *storage_create(const char *dest, const char *type, ...@@ -569,12 +582,16 @@ struct lxc_storage *storage_create(const char *dest, const char *type,
} }
/* -B lvm,dir */ /* -B lvm,dir */
if (strchr(type, ',') != NULL) { if (strchr(type, ',')) {
char *dup = alloca(strlen(type) + 1), *saveptr = NULL, *token; char *dup, *token;
char *saveptr = NULL;
dup = alloca(strlen(type) + 1);
strcpy(dup, type); strcpy(dup, type);
for (token = strtok_r(dup, ",", &saveptr); token; for (token = strtok_r(dup, ",", &saveptr); token;
token = strtok_r(NULL, ",", &saveptr)) { token = strtok_r(NULL, ",", &saveptr)) {
if ((bdev = do_storage_create(dest, token, cname, specs))) bdev = do_storage_create(dest, token, cname, specs);
if (bdev)
return bdev; return bdev;
} }
} }
...@@ -587,32 +604,32 @@ bool storage_destroy(struct lxc_conf *conf) ...@@ -587,32 +604,32 @@ bool storage_destroy(struct lxc_conf *conf)
struct lxc_storage *r; struct lxc_storage *r;
bool ret = false; bool ret = false;
r = storage_init(conf, conf->rootfs.path, conf->rootfs.mount, NULL); r = storage_init(conf);
if (!r) if (!r)
return ret; return ret;
if (r->ops->destroy(r) == 0) ret = r->ops->destroy(r);
if (ret == 0)
ret = true; ret = true;
storage_put(r); storage_put(r);
return ret; return ret;
} }
struct lxc_storage *storage_init(struct lxc_conf *conf, const char *src, struct lxc_storage *storage_init(struct lxc_conf *conf)
const char *dst, const char *mntopts)
{ {
struct lxc_storage *bdev; struct lxc_storage *bdev;
const struct lxc_storage_type *q; const struct lxc_storage_type *q;
const char *src = conf->rootfs.path;
const char *dst = conf->rootfs.mount;
const char *mntopts = conf->rootfs.options;
BUILD_BUG_ON(LXC_STORAGE_INTERNAL_OVERLAY_RESTORE <= LXC_CLONE_MAXFLAGS); BUILD_BUG_ON(LXC_STORAGE_INTERNAL_OVERLAY_RESTORE <= LXC_CLONE_MAXFLAGS);
if (!src) if (!src)
src = conf->rootfs.path;
if (!src)
return NULL; return NULL;
q = storage_query(conf, src); q = storage_query(conf);
if (!q) if (!q)
return NULL; return NULL;
...@@ -621,18 +638,23 @@ struct lxc_storage *storage_init(struct lxc_conf *conf, const char *src, ...@@ -621,18 +638,23 @@ struct lxc_storage *storage_init(struct lxc_conf *conf, const char *src,
return NULL; return NULL;
memset(bdev, 0, sizeof(struct lxc_storage)); memset(bdev, 0, sizeof(struct lxc_storage));
bdev->ops = q->ops; bdev->ops = q->ops;
bdev->type = q->name; bdev->type = q->name;
if (mntopts) if (mntopts)
bdev->mntopts = strdup(mntopts); bdev->mntopts = strdup(mntopts);
if (src) if (src)
bdev->src = strdup(src); bdev->src = strdup(src);
if (dst) if (dst)
bdev->dest = strdup(dst); bdev->dest = strdup(dst);
if (strcmp(bdev->type, "nbd") == 0) if (strcmp(bdev->type, "nbd") == 0)
bdev->nbd_idx = conf->nbd_idx; bdev->nbd_idx = conf->nbd_idx;
if (!strcmp(bdev->type, "aufs")) if (strcmp(bdev->type, "aufs") == 0)
WARN("The \"aufs\" driver will is deprecated and will soon be " WARN("The \"aufs\" driver will is deprecated and will soon be "
"removed. For similar functionality see the \"overlay\" " "removed. For similar functionality see the \"overlay\" "
"storage driver"); "storage driver");
...@@ -640,12 +662,16 @@ struct lxc_storage *storage_init(struct lxc_conf *conf, const char *src, ...@@ -640,12 +662,16 @@ struct lxc_storage *storage_init(struct lxc_conf *conf, const char *src,
return bdev; return bdev;
} }
bool storage_is_dir(struct lxc_conf *conf, const char *path) bool storage_is_dir(struct lxc_conf *conf)
{ {
struct lxc_storage *orig; struct lxc_storage *orig;
char *type = conf->rootfs.bdev_type;
bool bret = false; bool bret = false;
orig = storage_init(conf, path, NULL, NULL); if (type)
return (strcmp(type, "dir") == 0);
orig = storage_init(conf);
if (!orig) if (!orig)
return bret; return bret;
...@@ -678,7 +704,7 @@ bool rootfs_is_blockdev(struct lxc_conf *conf) ...@@ -678,7 +704,7 @@ bool rootfs_is_blockdev(struct lxc_conf *conf)
if (ret == 0 && S_ISBLK(st.st_mode)) if (ret == 0 && S_ISBLK(st.st_mode))
return true; return true;
q = storage_query(conf, conf->rootfs.path); q = storage_query(conf);
if (!q) if (!q)
return false; return false;
...@@ -692,7 +718,7 @@ bool rootfs_is_blockdev(struct lxc_conf *conf) ...@@ -692,7 +718,7 @@ bool rootfs_is_blockdev(struct lxc_conf *conf)
return false; return false;
} }
char *lxc_storage_get_path(char *src, const char *prefix) const char *lxc_storage_get_path(char *src, const char *prefix)
{ {
size_t prefix_len; size_t prefix_len;
......
...@@ -109,23 +109,24 @@ struct lxc_storage { ...@@ -109,23 +109,24 @@ struct lxc_storage {
int flags; int flags;
}; };
extern bool storage_is_dir(struct lxc_conf *conf, const char *path); /**
* storage_is_dir : Check whether the roots is a directory. This function will
* trust the config file. If the config file key
* lxc.rootfs.path is set to <storage type>:<container path>
* the confile parser will have split this into <storage type>
* and <container path> and set the <bdev_type> member in the
* lxc_rootfs struct to <storage type> and the <path> member
* will be set to a clean <container path> without the <storage
* type> prefix. This is the new, clean way of handling storage
* type specifications. If the <storage type> prefix is not
* detected liblxc will try to detect the storage type.
*/
extern bool storage_is_dir(struct lxc_conf *conf);
extern bool storage_can_backup(struct lxc_conf *conf); extern bool storage_can_backup(struct lxc_conf *conf);
/* Instantiate a lxc_storage object. The src is used to determine which blockdev extern struct lxc_storage *storage_init(struct lxc_conf *conf);
* type this should be. The dst and data are optional, and will be used in case
* of mount/umount.
*
* The source will be "dir:/var/lib/lxc/c1" or "lvm:/dev/lxc/c1". For other
* backing stores, this will allow additional options. In particular,
* "overlayfs:/var/lib/lxc/canonical/rootfs:/var/lib/lxc/c1/delta" will mean use
* /var/lib/lxc/canonical/rootfs as lower dir, and /var/lib/lxc/c1/delta as the
* upper, writeable layer.
*/
extern struct lxc_storage *storage_init(struct lxc_conf *conf, const char *src,
const char *dst, const char *data);
extern struct lxc_storage *storage_copy(struct lxc_container *c0, extern struct lxc_storage *storage_copy(struct lxc_container *c,
const char *cname, const char *lxcpath, const char *cname, const char *lxcpath,
const char *bdevtype, int flags, const char *bdevtype, int flags,
const char *bdevdata, uint64_t newsize, const char *bdevdata, uint64_t newsize,
...@@ -135,9 +136,7 @@ extern struct lxc_storage *storage_create(const char *dest, const char *type, ...@@ -135,9 +136,7 @@ extern struct lxc_storage *storage_create(const char *dest, const char *type,
struct bdev_specs *specs); struct bdev_specs *specs);
extern void storage_put(struct lxc_storage *bdev); extern void storage_put(struct lxc_storage *bdev);
extern bool storage_destroy(struct lxc_conf *conf); extern bool storage_destroy(struct lxc_conf *conf);
extern int storage_destroy_wrapper(void *data);
extern bool rootfs_is_blockdev(struct lxc_conf *conf); extern bool rootfs_is_blockdev(struct lxc_conf *conf);
extern char *lxc_storage_get_path(char *src, const char *prefix); extern const char *lxc_storage_get_path(char *src, const char *prefix);
#endif /* #define __LXC_STORAGE_H */ #endif /* #define __LXC_STORAGE_H */
...@@ -133,7 +133,7 @@ bool attach_block_device(struct lxc_conf *conf) ...@@ -133,7 +133,7 @@ bool attach_block_device(struct lxc_conf *conf)
int blk_getsize(struct lxc_storage *bdev, uint64_t *size) int blk_getsize(struct lxc_storage *bdev, uint64_t *size)
{ {
int fd, ret; int fd, ret;
char *src; const char *src;
src = lxc_storage_get_path(bdev->src, bdev->type); src = lxc_storage_get_path(bdev->src, bdev->type);
fd = open(src, O_RDONLY); fd = open(src, O_RDONLY);
...@@ -162,11 +162,15 @@ void detach_block_device(struct lxc_conf *conf) ...@@ -162,11 +162,15 @@ void detach_block_device(struct lxc_conf *conf)
*/ */
int detect_fs(struct lxc_storage *bdev, char *type, int len) int detect_fs(struct lxc_storage *bdev, char *type, int len)
{ {
int p[2], ret; int ret;
int p[2];
size_t linelen; size_t linelen;
pid_t pid; pid_t pid;
FILE *f; FILE *f;
char *sp1, *sp2, *sp3, *srcdev, *line = NULL; char *sp1, *sp2, *sp3;
const char *l, *srcdev;
char devpath[MAXPATHLEN];
char *line = NULL;
if (!bdev || !bdev->src || !bdev->dest) if (!bdev || !bdev->src || !bdev->dest)
return -1; return -1;
...@@ -218,9 +222,7 @@ int detect_fs(struct lxc_storage *bdev, char *type, int len) ...@@ -218,9 +222,7 @@ int detect_fs(struct lxc_storage *bdev, char *type, int len)
exit(1); exit(1);
} }
/* if symlink, get the real dev name */ l = linkderef(srcdev, devpath);
char devpath[MAXPATHLEN];
char *l = linkderef(srcdev, devpath);
if (!l) if (!l)
exit(1); exit(1);
f = fopen("/proc/self/mounts", "r"); f = fopen("/proc/self/mounts", "r");
...@@ -383,7 +385,7 @@ int find_fstype_cb(char *buffer, void *data) ...@@ -383,7 +385,7 @@ int find_fstype_cb(char *buffer, void *data)
return 1; return 1;
} }
char *linkderef(char *path, char *dest) const char *linkderef(const char *path, char *dest)
{ {
struct stat sbuf; struct stat sbuf;
ssize_t ret; ssize_t ret;
......
...@@ -45,7 +45,7 @@ extern int is_blktype(struct lxc_storage *b); ...@@ -45,7 +45,7 @@ extern int is_blktype(struct lxc_storage *b);
extern int mount_unknown_fs(const char *rootfs, const char *target, extern int mount_unknown_fs(const char *rootfs, const char *target,
const char *options); const char *options);
extern int find_fstype_cb(char *buffer, void *data); extern int find_fstype_cb(char *buffer, void *data);
extern char *linkderef(char *path, char *dest); extern const char *linkderef(const char *path, char *dest);
extern bool unpriv_snap_allowed(struct lxc_storage *b, const char *t, bool snap, extern bool unpriv_snap_allowed(struct lxc_storage *b, const char *t, bool snap,
bool maybesnap); bool maybesnap);
extern bool is_valid_storage_type(const char *type); extern bool is_valid_storage_type(const char *type);
......
...@@ -180,7 +180,8 @@ int zfs_mount(struct lxc_storage *bdev) ...@@ -180,7 +180,8 @@ int zfs_mount(struct lxc_storage *bdev)
{ {
int ret; int ret;
size_t oldlen, newlen, totallen; size_t oldlen, newlen, totallen;
char *mntdata, *src, *tmp; char *mntdata, *tmp;
const char *src;
unsigned long mntflags; unsigned long mntflags;
char cmd_output[MAXPATHLEN] = {0}; char cmd_output[MAXPATHLEN] = {0};
...@@ -287,13 +288,13 @@ bool zfs_copy(struct lxc_conf *conf, struct lxc_storage *orig, ...@@ -287,13 +288,13 @@ bool zfs_copy(struct lxc_conf *conf, struct lxc_storage *orig,
char cmd_output[MAXPATHLEN], option[MAXPATHLEN]; char cmd_output[MAXPATHLEN], option[MAXPATHLEN];
struct rsync_data data = {0, 0}; struct rsync_data data = {0, 0};
struct zfs_args cmd_args = {0}; struct zfs_args cmd_args = {0};
char *argv[] = {"zfs", /* 0 */ const char *argv[] = {"zfs", /* 0 */
"create", /* 1 */ "create", /* 1 */
"-o", "", /* 2, 3 */ "-o", "", /* 2, 3 */
"-o", "canmount=noauto", /* 4, 5 */ "-o", "canmount=noauto", /* 4, 5 */
"-p", /* 6 */ "-p", /* 6 */
"", /* 7 */ "", /* 7 */
NULL}; NULL};
/* mountpoint */ /* mountpoint */
ret = snprintf(option, MAXPATHLEN, "mountpoint=%s", new->dest); ret = snprintf(option, MAXPATHLEN, "mountpoint=%s", new->dest);
...@@ -342,7 +343,8 @@ bool zfs_snapshot(struct lxc_conf *conf, struct lxc_storage *orig, ...@@ -342,7 +343,8 @@ bool zfs_snapshot(struct lxc_conf *conf, struct lxc_storage *orig,
{ {
int ret; int ret;
size_t snapshot_len, len; size_t snapshot_len, len;
char *orig_src, *tmp, *snap_name, *snapshot; char *tmp, *snap_name, *snapshot;
const char *orig_src;
struct zfs_args cmd_args = {0}; struct zfs_args cmd_args = {0};
char cmd_output[MAXPATHLEN] = {0}, option[MAXPATHLEN]; char cmd_output[MAXPATHLEN] = {0}, option[MAXPATHLEN];
...@@ -447,8 +449,9 @@ int zfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, ...@@ -447,8 +449,9 @@ int zfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
const char *lxcpath, int snap, uint64_t newsize, const char *lxcpath, int snap, uint64_t newsize,
struct lxc_conf *conf) struct lxc_conf *conf)
{ {
char *dataset, *orig_src, *tmp;
int ret; int ret;
char *dataset, *tmp;
const char *orig_src;
size_t dataset_len, len; size_t dataset_len, len;
char cmd_output[MAXPATHLEN] = {0}; char cmd_output[MAXPATHLEN] = {0};
...@@ -576,7 +579,8 @@ int zfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, ...@@ -576,7 +579,8 @@ int zfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
int zfs_destroy(struct lxc_storage *orig) int zfs_destroy(struct lxc_storage *orig)
{ {
int ret; int ret;
char *dataset, *src, *tmp; char *dataset, *tmp;
const char *src;
bool found; bool found;
char *parent_snapshot = NULL; char *parent_snapshot = NULL;
struct zfs_args cmd_args = {0}; struct zfs_args cmd_args = {0};
...@@ -709,13 +713,13 @@ int zfs_create(struct lxc_storage *bdev, const char *dest, const char *n, ...@@ -709,13 +713,13 @@ int zfs_create(struct lxc_storage *bdev, const char *dest, const char *n,
size_t len; size_t len;
struct zfs_args cmd_args = {0}; struct zfs_args cmd_args = {0};
char cmd_output[MAXPATHLEN], option[MAXPATHLEN]; char cmd_output[MAXPATHLEN], option[MAXPATHLEN];
char *argv[] = {"zfs", /* 0 */ const char *argv[] = {"zfs", /* 0 */
"create", /* 1 */ "create", /* 1 */
"-o", "", /* 2, 3 */ "-o", "", /* 2, 3 */
"-o", "canmount=noauto", /* 4, 5 */ "-o", "canmount=noauto", /* 4, 5 */
"-p", /* 6 */ "-p", /* 6 */
"", /* 7 */ "", /* 7 */
NULL}; NULL};
if (!specs || !specs->zfs.zfsroot) if (!specs || !specs->zfs.zfsroot)
zfsroot = lxc_global_config_value("lxc.bdev.zfs.root"); zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
......
...@@ -65,7 +65,7 @@ lxc_log_define(lxc_utils, lxc); ...@@ -65,7 +65,7 @@ lxc_log_define(lxc_utils, lxc);
*/ */
extern bool btrfs_try_remove_subvol(const char *path); extern bool btrfs_try_remove_subvol(const char *path);
static int _recursive_rmdir(char *dirname, dev_t pdev, static int _recursive_rmdir(const char *dirname, dev_t pdev,
const char *exclude, int level, bool onedev) const char *exclude, int level, bool onedev)
{ {
struct dirent *direntp; struct dirent *direntp;
...@@ -180,18 +180,18 @@ static bool is_native_overlayfs(const char *path) ...@@ -180,18 +180,18 @@ static bool is_native_overlayfs(const char *path)
} }
/* returns 0 on success, -1 if there were any failures */ /* returns 0 on success, -1 if there were any failures */
extern int lxc_rmdir_onedev(char *path, const char *exclude) extern int lxc_rmdir_onedev(const char *path, const char *exclude)
{ {
struct stat mystat; struct stat mystat;
bool onedev = true; bool onedev = true;
if (is_native_overlayfs(path)) { if (is_native_overlayfs(path))
onedev = false; onedev = false;
}
if (lstat(path, &mystat) < 0) { if (lstat(path, &mystat) < 0) {
if (errno == ENOENT) if (errno == ENOENT)
return 0; return 0;
ERROR("Failed to stat %s", path); ERROR("Failed to stat %s", path);
return -1; return -1;
} }
......
...@@ -93,7 +93,7 @@ ...@@ -93,7 +93,7 @@
#define LXC_IDMAPLEN 4096 #define LXC_IDMAPLEN 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(char *path, const char *exclude); extern int lxc_rmdir_onedev(const char *path, const char *exclude);
extern int get_u16(unsigned short *val, const char *arg, int base); extern int get_u16(unsigned short *val, const char *arg, int base);
extern int mkdir_p(const char *dir, mode_t mode); extern int mkdir_p(const char *dir, mode_t mode);
extern char *get_rundir(void); extern char *get_rundir(void);
......
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