Commit 5c484f79 by Christian Brauner

Move remaining overlay helpers to overlay.{c,h}

Move - ovl_get_rootfs_dir() - mount_entry_create_overlay_dirs() from conf.h to overlay.{c,h} where they belong. Rename - mount_entry_create_overlay_dirs() --> ovl_mkdir() in accordance with the ovl_ prefix naming scheme for types and functions associated with overlay. Take the chance to add whitespace between operators where missing. Signed-off-by: 's avatarChristian Brauner <christian.brauner@mailbox.org>
parent 83e79752
......@@ -37,6 +37,8 @@
lxc_log_define(overlay, lxc);
static char *ovl_name;
struct ovl_rsync_data {
struct bdev *orig;
struct bdev *new;
......@@ -49,228 +51,10 @@ extern int do_rsync(const char *src, const char *dest);
extern char *dir_new_path(char *src, const char *oldname, const char *name,
const char *oldpath, const char *lxcpath);
char *ovl_getlower(char *p)
{
char *p1 = strchr(p, ':');
if (p1)
*p1 = '\0';
return p;
}
int ovl_detect(const char *path)
{
if (strncmp(path, "overlayfs:", 10) == 0)
return 1; // take their word for it
return 0;
}
static char *ovl_name;
static char *ovl_detect_name(void)
{
char *v = "overlayfs";
char *line = NULL;
size_t len = 0;
FILE *f = fopen("/proc/filesystems", "r");
if (!f)
return v;
while (getline(&line, &len, f) != -1) {
if (strcmp(line, "nodev\toverlay\n") == 0) {
v = "overlay";
break;
}
}
fclose(f);
free(line);
return v;
}
/* XXXXXXX plain directory bind mount ops */
int ovl_mount(struct bdev *bdev)
{
char *options, *dup, *lower, *upper;
char *options_work, *work, *lastslash;
int lastslashidx;
int len, len2;
unsigned long mntflags;
char *mntdata;
int ret, ret2;
if (strcmp(bdev->type, "overlayfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
if (!ovl_name)
ovl_name = ovl_detect_name();
// separately mount it first
// mount -t overlayfs -oupperdir=${upper},lowerdir=${lower} lower dest
dup = alloca(strlen(bdev->src)+1);
strcpy(dup, bdev->src);
if (!(lower = strchr(dup, ':')))
return -22;
if (!(upper = strchr(++lower, ':')))
return -22;
*upper = '\0';
upper++;
// if delta doesn't yet exist, create it
if (mkdir_p(upper, 0755) < 0 && errno != EEXIST)
return -22;
// overlayfs.v22 or higher needs workdir option
// if upper is /var/lib/lxc/c2/delta0,
// then workdir is /var/lib/lxc/c2/olwork
lastslash = strrchr(upper, '/');
if (!lastslash)
return -22;
lastslash++;
lastslashidx = lastslash - upper;
work = alloca(lastslashidx + 7);
strncpy(work, upper, lastslashidx+7);
strcpy(work+lastslashidx, "olwork");
if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
free(mntdata);
return -22;
}
if (mkdir_p(work, 0755) < 0 && errno != EEXIST) {
free(mntdata);
return -22;
}
// TODO We should check whether bdev->src is a blockdev, and if so
// but for now, only support overlays of a basic directory
if (mntdata) {
len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
options = alloca(len);
ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s", upper, lower, mntdata);
len2 = strlen(lower) + strlen(upper) + strlen(work)
+ strlen("upperdir=,lowerdir=,workdir=") + strlen(mntdata) + 1;
options_work = alloca(len2);
ret2 = snprintf(options, len2, "upperdir=%s,lowerdir=%s,workdir=%s,%s",
upper, lower, work, mntdata);
}
else {
len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1;
options = alloca(len);
ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
len2 = strlen(lower) + strlen(upper) + strlen(work)
+ strlen("upperdir=,lowerdir=,workdir=") + 1;
options_work = alloca(len2);
ret2 = snprintf(options_work, len2, "upperdir=%s,lowerdir=%s,workdir=%s",
upper, lower, work);
}
if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
free(mntdata);
return -1;
}
// mount without workdir option for overlayfs before v21
ret = mount(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options);
if (ret < 0) {
INFO("overlayfs: error mounting %s onto %s options %s. retry with workdir",
lower, bdev->dest, options);
// retry with workdir option for overlayfs v22 and higher
ret = mount(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options_work);
if (ret < 0)
SYSERROR("overlayfs: error mounting %s onto %s options %s",
lower, bdev->dest, options_work);
else
INFO("overlayfs: mounted %s onto %s options %s",
lower, bdev->dest, options_work);
}
else
INFO("overlayfs: mounted %s onto %s options %s",
lower, bdev->dest, options);
return ret;
}
int ovl_umount(struct bdev *bdev)
{
if (strcmp(bdev->type, "overlayfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
return umount(bdev->dest);
}
static int ovl_rsync(struct ovl_rsync_data *data)
{
int ret;
if (setgid(0) < 0) {
ERROR("Failed to setgid to 0");
return -1;
}
if (setgroups(0, NULL) < 0)
WARN("Failed to clear groups");
if (setuid(0) < 0) {
ERROR("Failed to setuid to 0");
return -1;
}
if (unshare(CLONE_NEWNS) < 0) {
SYSERROR("Unable to unshare mounts ns");
return -1;
}
if (detect_shared_rootfs()) {
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
SYSERROR("Failed to make / rslave");
ERROR("Continuing...");
}
}
if (ovl_mount(data->orig) < 0) {
ERROR("Failed mounting original container fs");
return -1;
}
if (ovl_mount(data->new) < 0) {
ERROR("Failed mounting new container fs");
return -1;
}
ret = do_rsync(data->orig->dest, data->new->dest);
ovl_umount(data->new);
ovl_umount(data->orig);
if (ret < 0) {
ERROR("rsyncing %s to %s", data->orig->dest, data->new->dest);
return -1;
}
return 0;
}
static int ovl_rsync_wrapper(void *data)
{
struct ovl_rsync_data *arg = data;
return ovl_rsync(arg);
}
static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf)
{
int ret = -1;
struct ovl_rsync_data rdata;
rdata.orig = orig;
rdata.new = new;
if (am_unpriv())
ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata);
else
ret = ovl_rsync(&rdata);
if (ret)
ERROR("copying overlayfs delta");
return ret;
}
static char *ovl_detect_name(void);
static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf);
static int ovl_rsync(struct ovl_rsync_data *data);
static int ovl_rsync_wrapper(void *data);
int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath,
......@@ -298,8 +82,12 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
char *work;
int ret, len, lastslashidx;
// if we have /var/lib/lxc/c2/rootfs, then delta will be
// /var/lib/lxc/c2/delta0
/*
* if we have
* /var/lib/lxc/c2/rootfs
* then delta will be
* /var/lib/lxc/c2/delta0
*/
lastslash = strrchr(new->dest, '/');
if (!lastslash)
return -22;
......@@ -311,8 +99,8 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
delta = malloc(lastslashidx + 7);
if (!delta)
return -1;
strncpy(delta, new->dest, lastslashidx+1);
strcpy(delta+lastslashidx, "delta0");
strncpy(delta, new->dest, lastslashidx + 1);
strcpy(delta + lastslashidx, "delta0");
if ((ret = mkdir(delta, 0755)) < 0) {
SYSERROR("error: mkdir %s", delta);
free(delta);
......@@ -321,18 +109,22 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
WARN("Failed to update ownership of %s", delta);
// make workdir for overlayfs.v22 or higher
// workdir is /var/lib/lxc/c2/olwork
// it is used to prepare files before atomically swithing with destination,
// and needs to be on the same filesystem as upperdir,
// so it's OK for it to be empty.
/*
* Make workdir for overlayfs.v22 or higher:
* The workdir will be
* /var/lib/lxc/c2/olwork
* and is used to prepare files before they are atomically
* switched to the overlay destination. Workdirs need to be on
* the same filesystem as the upperdir so it's OK for it to be
* empty.
*/
work = malloc(lastslashidx + 7);
if (!work) {
free(delta);
return -1;
}
strncpy(work, new->dest, lastslashidx+1);
strcpy(work+lastslashidx, "olwork");
strncpy(work, new->dest, lastslashidx + 1);
strcpy(work + lastslashidx, "olwork");
if (mkdir(work, 0755) < 0) {
SYSERROR("error: mkdir %s", work);
free(delta);
......@@ -355,10 +147,11 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
if (ret < 0 || ret >= len)
return -ENOMEM;
} else if (strcmp(orig->type, "overlayfs") == 0) {
// What exactly do we want to do here?
// I think we want to use the original lowerdir, with a
// private delta which is originally rsynced from the
// original delta
/*
* What exactly do we want to do here? I think we want to use
* the original lowerdir, with a private delta which is
* originally rsynced from the original delta
*/
char *osrc, *odelta, *nsrc, *ndelta, *work;
char *lastslash;
int len, ret, lastslashidx;
......@@ -385,8 +178,10 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
WARN("Failed to update ownership of %s", ndelta);
// make workdir for overlayfs.v22 or higher
// for details, see above.
/*
* make workdir for overlayfs.v22 or higher (see comment further
* up)
*/
lastslash = strrchr(ndelta, '/');
if (!lastslash)
return -1;
......@@ -396,8 +191,8 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
work = malloc(lastslashidx + 7);
if (!work)
return -1;
strncpy(work, ndelta, lastslashidx+1);
strcpy(work+lastslashidx, "olwork");
strncpy(work, ndelta, lastslashidx + 1);
strcpy(work + lastslashidx, "olwork");
if ((mkdir(work, 0755) < 0) && errno != EEXIST) {
SYSERROR("error: mkdir %s", work);
free(work);
......@@ -423,28 +218,17 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
return ovl_do_rsync(orig, new, conf);
} else {
ERROR("overlayfs clone of %s container is not yet supported",
orig->type);
// Note, supporting this will require ovl_mount supporting
// mounting of the underlay. No big deal, just needs to be done.
orig->type);
/*
* Note, supporting this will require ovl_mount supporting
* mounting of the underlay. No big deal, just needs to be done.
*/
return -1;
}
return 0;
}
int ovl_destroy(struct bdev *orig)
{
char *upper;
if (strncmp(orig->src, "overlayfs:", 10) != 0)
return -22;
upper = strchr(orig->src + 10, ':');
if (!upper)
return -22;
upper++;
return lxc_rmdir_onedev(upper, NULL);
}
/*
* to say 'lxc-create -t ubuntu -n o1 -B overlayfs' means you want
* $lxcpath/$lxcname/rootfs to have the created container, while all
......@@ -457,7 +241,7 @@ int ovl_create(struct bdev *bdev, const char *dest, const char *n,
char *delta;
int ret, len = strlen(dest), newlen;
if (len < 8 || strcmp(dest+len-7, "/rootfs") != 0)
if (len < 8 || strcmp(dest + len - 7, "/rootfs") != 0)
return -1;
if (!(bdev->dest = strdup(dest))) {
......@@ -465,16 +249,16 @@ int ovl_create(struct bdev *bdev, const char *dest, const char *n,
return -1;
}
delta = alloca(strlen(dest)+1);
delta = alloca(strlen(dest) + 1);
strcpy(delta, dest);
strcpy(delta+len-6, "delta0");
strcpy(delta + len - 6, "delta0");
if (mkdir_p(delta, 0755) < 0) {
ERROR("Error creating %s", delta);
return -1;
}
/* overlayfs:lower:upper */
// overlayfs:lower:upper
newlen = (2 * len) + strlen("overlayfs:") + 2;
bdev->src = malloc(newlen);
if (!bdev->src) {
......@@ -493,6 +277,260 @@ int ovl_create(struct bdev *bdev, const char *dest, const char *n,
return 0;
}
int ovl_destroy(struct bdev *orig)
{
char *upper;
if (strncmp(orig->src, "overlayfs:", 10) != 0)
return -22;
upper = strchr(orig->src + 10, ':');
if (!upper)
return -22;
upper++;
return lxc_rmdir_onedev(upper, NULL);
}
int ovl_detect(const char *path)
{
if (strncmp(path, "overlayfs:", 10) == 0)
return 1; // take their word for it
return 0;
}
char *ovl_getlower(char *p)
{
char *p1 = strchr(p, ':');
if (p1)
*p1 = '\0';
return p;
}
int ovl_mount(struct bdev *bdev)
{
char *options, *dup, *lower, *upper;
char *options_work, *work, *lastslash;
int lastslashidx;
int len, len2;
unsigned long mntflags;
char *mntdata;
int ret, ret2;
if (strcmp(bdev->type, "overlayfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
if (!ovl_name)
ovl_name = ovl_detect_name();
/*
* separately mount it first:
* mount -t overlayfs * -oupperdir=${upper},lowerdir=${lower} lower dest
*/
dup = alloca(strlen(bdev->src) + 1);
strcpy(dup, bdev->src);
if (!(lower = strchr(dup, ':')))
return -22;
if (!(upper = strchr(++lower, ':')))
return -22;
*upper = '\0';
upper++;
// if delta doesn't yet exist, create it
if (mkdir_p(upper, 0755) < 0 && errno != EEXIST)
return -22;
/*
* overlayfs.v22 or higher needs workdir option:
* if upper is
* /var/lib/lxc/c2/delta0
* then workdir is
* /var/lib/lxc/c2/olwork
*/
lastslash = strrchr(upper, '/');
if (!lastslash)
return -22;
lastslash++;
lastslashidx = lastslash - upper;
work = alloca(lastslashidx + 7);
strncpy(work, upper, lastslashidx + 7);
strcpy(work + lastslashidx, "olwork");
if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
free(mntdata);
return -22;
}
if (mkdir_p(work, 0755) < 0 && errno != EEXIST) {
free(mntdata);
return -22;
}
/*
* TODO:
* We should check whether bdev->src is a blockdev but for now only
* support overlays of a basic directory
*/
if (mntdata) {
len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
options = alloca(len);
ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s", upper, lower, mntdata);
len2 = strlen(lower) + strlen(upper) + strlen(work)
+ strlen("upperdir=,lowerdir=,workdir=") + strlen(mntdata) + 1;
options_work = alloca(len2);
ret2 = snprintf(options, len2, "upperdir=%s,lowerdir=%s,workdir=%s,%s",
upper, lower, work, mntdata);
} else {
len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1;
options = alloca(len);
ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
len2 = strlen(lower) + strlen(upper) + strlen(work)
+ strlen("upperdir=,lowerdir=,workdir=") + 1;
options_work = alloca(len2);
ret2 = snprintf(options_work, len2, "upperdir=%s,lowerdir=%s,workdir=%s",
upper, lower, work);
}
if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
free(mntdata);
return -1;
}
// mount without workdir option for overlayfs before v21
ret = mount(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options);
if (ret < 0) {
INFO("overlayfs: error mounting %s onto %s options %s. retry with workdir",
lower, bdev->dest, options);
// retry with workdir option for overlayfs v22 and higher
ret = mount(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options_work);
if (ret < 0)
SYSERROR("overlayfs: error mounting %s onto %s options %s",
lower, bdev->dest, options_work);
else
INFO("overlayfs: mounted %s onto %s options %s",
lower, bdev->dest, options_work);
} else {
INFO("overlayfs: mounted %s onto %s options %s",
lower, bdev->dest, options);
}
return ret;
}
int ovl_umount(struct bdev *bdev)
{
if (strcmp(bdev->type, "overlayfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
return umount(bdev->dest);
}
char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen)
{
char *rootfsdir = NULL;
char *s1 = NULL;
char *s2 = NULL;
char *s3 = NULL;
if (!rootfs_path || !rootfslen)
return NULL;
s1 = strdup(rootfs_path);
if (!s1)
return NULL;
if ((s2 = strstr(s1, ":/"))) {
s2 = s2 + 1;
if ((s3 = strstr(s2, ":/")))
*s3 = '\0';
rootfsdir = strdup(s2);
if (!rootfsdir) {
free(s1);
return NULL;
}
}
if (!rootfsdir)
rootfsdir = s1;
else
free(s1);
*rootfslen = strlen(rootfsdir);
return rootfsdir;
}
int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
const char *lxc_name, const char *lxc_path)
{
char lxcpath[MAXPATHLEN];
char *rootfsdir = NULL;
char *upperdir = NULL;
char *workdir = NULL;
char **opts = NULL;
int fret = -1;
int ret = 0;
size_t arrlen = 0;
size_t dirlen = 0;
size_t i;
size_t len = 0;
size_t rootfslen = 0;
if (!rootfs->path || !lxc_name || !lxc_path)
goto err;
opts = lxc_string_split(mntent->mnt_opts, ',');
if (opts)
arrlen = lxc_array_len((void **)opts);
else
goto err;
for (i = 0; i < arrlen; i++) {
if (strstr(opts[i], "upperdir=") && (strlen(opts[i]) > (len = strlen("upperdir="))))
upperdir = opts[i] + len;
else if (strstr(opts[i], "workdir=") && (strlen(opts[i]) > (len = strlen("workdir="))))
workdir = opts[i] + len;
}
ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
if (ret < 0 || ret >= MAXPATHLEN)
goto err;
rootfsdir = ovl_get_rootfs(rootfs->path, &rootfslen);
if (!rootfsdir)
goto err;
dirlen = strlen(lxcpath);
/*
* We neither allow users to create upperdirs and workdirs outside the
* containerdir nor inside the rootfs. The latter might be debatable.
*/
if (upperdir)
if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
if (mkdir_p(upperdir, 0755) < 0) {
WARN("Failed to create upperdir");
}
if (workdir)
if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0))
if (mkdir_p(workdir, 0755) < 0) {
WARN("Failed to create workdir");
}
fret = 0;
err:
free(rootfsdir);
lxc_free_array((void **)opts, free);
return fret;
}
/*
* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
* with overlay lxc.mount.entry entries we need to update absolute paths for
......@@ -522,8 +560,10 @@ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
remove_trailing_slashes(cleanpath);
/* We have to update lxc_conf->unexpanded_config separately from
* lxc_conf->mount_list. */
/*
* We have to update lxc_conf->unexpanded_config separately from
* lxc_conf->mount_list.
*/
for (i = 0; i < sizeof(ovl_dirs) / sizeof(ovl_dirs[0]); i++) {
if (!clone_update_unexp_ovl_paths(lxc_conf, lxc_path, newpath,
lxc_name, newname,
......@@ -591,3 +631,93 @@ err:
return fret;
}
static int ovl_rsync(struct ovl_rsync_data *data)
{
int ret;
if (setgid(0) < 0) {
ERROR("Failed to setgid to 0");
return -1;
}
if (setgroups(0, NULL) < 0)
WARN("Failed to clear groups");
if (setuid(0) < 0) {
ERROR("Failed to setuid to 0");
return -1;
}
if (unshare(CLONE_NEWNS) < 0) {
SYSERROR("Unable to unshare mounts ns");
return -1;
}
if (detect_shared_rootfs()) {
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) {
SYSERROR("Failed to make / rslave");
ERROR("Continuing...");
}
}
if (ovl_mount(data->orig) < 0) {
ERROR("Failed mounting original container fs");
return -1;
}
if (ovl_mount(data->new) < 0) {
ERROR("Failed mounting new container fs");
return -1;
}
ret = do_rsync(data->orig->dest, data->new->dest);
ovl_umount(data->new);
ovl_umount(data->orig);
if (ret < 0) {
ERROR("rsyncing %s to %s", data->orig->dest, data->new->dest);
return -1;
}
return 0;
}
static char *ovl_detect_name(void)
{
char *v = "overlayfs";
char *line = NULL;
size_t len = 0;
FILE *f = fopen("/proc/filesystems", "r");
if (!f)
return v;
while (getline(&line, &len, f) != -1) {
if (strcmp(line, "nodev\toverlay\n") == 0) {
v = "overlay";
break;
}
}
fclose(f);
free(line);
return v;
}
static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf)
{
int ret = -1;
struct ovl_rsync_data rdata;
rdata.orig = orig;
rdata.new = new;
if (am_unpriv())
ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata);
else
ret = ovl_rsync(&rdata);
if (ret)
ERROR("copying overlayfs delta");
return ret;
}
static int ovl_rsync_wrapper(void *data)
{
struct ovl_rsync_data *arg = data;
return ovl_rsync(arg);
}
......@@ -29,6 +29,12 @@
#include <unistd.h>
#include <sys/types.h>
#if IS_BIONIC
#include <../include/lxcmntent.h>
#else
#include <mntent.h>
#endif
/* defined in bdev.h */
struct bdev;
......@@ -38,15 +44,21 @@ struct bdev_specs;
/* defined conf.h */
struct lxc_conf;
int ovl_detect(const char *path);
int ovl_mount(struct bdev *bdev);
int ovl_umount(struct bdev *bdev);
/* defined in conf.h */
struct lxc_rootfs;
/*
* Functions associated with an overlay bdev struct.
*/
int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath,
int snap, uint64_t newsize, struct lxc_conf *conf);
int ovl_destroy(struct bdev *orig);
int ovl_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs);
int ovl_destroy(struct bdev *orig);
int ovl_detect(const char *path);
int ovl_mount(struct bdev *bdev);
int ovl_umount(struct bdev *bdev);
/*
* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
......@@ -66,4 +78,16 @@ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
*/
char *ovl_getlower(char *p);
/*
* Get rootfs path for overlay backed containers. Allocated memory must be freed
* by caller.
*/
char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen);
/*
* Create upper- and workdirs for overlay mounts.
*/
int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
const char *lxc_name, const char *lxc_path);
#endif /* __LXC_OVERLAY_H */
......@@ -72,6 +72,7 @@
#include "log.h"
#include "caps.h" /* for lxc_caps_last_cap() */
#include "bdev/bdev.h"
#include "bdev/overlay.h"
#include "cgroup.h"
#include "lxclock.h"
#include "namespace.h"
......@@ -1815,107 +1816,6 @@ static void cull_mntent_opt(struct mntent *mntent)
}
}
static char *ovl_get_rootfs_dir(const char *rootfs_path, size_t *rootfslen)
{
char *rootfsdir = NULL;
char *s1 = NULL;
char *s2 = NULL;
char *s3 = NULL;
if (!rootfs_path || !rootfslen)
return NULL;
s1 = strdup(rootfs_path);
if (!s1)
return NULL;
if ((s2 = strstr(s1, ":/"))) {
s2 = s2 + 1;
if ((s3 = strstr(s2, ":/")))
*s3 = '\0';
rootfsdir = strdup(s2);
if (!rootfsdir) {
free(s1);
return NULL;
}
}
if (!rootfsdir)
rootfsdir = s1;
else
free(s1);
*rootfslen = strlen(rootfsdir);
return rootfsdir;
}
static int mount_entry_create_overlay_dirs(const struct mntent *mntent,
const struct lxc_rootfs *rootfs,
const char *lxc_name,
const char *lxc_path)
{
char lxcpath[MAXPATHLEN];
char *rootfsdir = NULL;
char *upperdir = NULL;
char *workdir = NULL;
char **opts = NULL;
int fret = -1;
int ret = 0;
size_t arrlen = 0;
size_t dirlen = 0;
size_t i;
size_t len = 0;
size_t rootfslen = 0;
if (!rootfs->path || !lxc_name || !lxc_path)
goto err;
opts = lxc_string_split(mntent->mnt_opts, ',');
if (opts)
arrlen = lxc_array_len((void **)opts);
else
goto err;
for (i = 0; i < arrlen; i++) {
if (strstr(opts[i], "upperdir=") && (strlen(opts[i]) > (len = strlen("upperdir="))))
upperdir = opts[i] + len;
else if (strstr(opts[i], "workdir=") && (strlen(opts[i]) > (len = strlen("workdir="))))
workdir = opts[i] + len;
}
ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
if (ret < 0 || ret >= MAXPATHLEN)
goto err;
rootfsdir = ovl_get_rootfs_dir(rootfs->path, &rootfslen);
if (!rootfsdir)
goto err;
dirlen = strlen(lxcpath);
/* We neither allow users to create upperdirs and workdirs outside the
* containerdir nor inside the rootfs. The latter might be debatable. */
if (upperdir)
if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
if (mkdir_p(upperdir, 0755) < 0) {
WARN("Failed to create upperdir");
}
if (workdir)
if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0))
if (mkdir_p(workdir, 0755) < 0) {
WARN("Failed to create workdir");
}
fret = 0;
err:
free(rootfsdir);
lxc_free_array((void **)opts, free);
return fret;
}
static int mount_entry_create_aufs_dirs(const struct mntent *mntent,
const struct lxc_rootfs *rootfs,
const char *lxc_name,
......@@ -1958,7 +1858,7 @@ static int mount_entry_create_aufs_dirs(const struct mntent *mntent,
if (ret < 0 || ret >= MAXPATHLEN)
goto err;
rootfsdir = ovl_get_rootfs_dir(rootfs->path, &rootfslen);
rootfsdir = ovl_get_rootfs(rootfs->path, &rootfslen);
if (!rootfsdir)
goto err;
......@@ -1987,7 +1887,7 @@ static int mount_entry_create_dir_file(const struct mntent *mntent,
FILE *pathfile = NULL;
if (strncmp(mntent->mnt_type, "overlay", 7) == 0) {
if (mount_entry_create_overlay_dirs(mntent, rootfs, lxc_name, lxc_path) < 0)
if (ovl_mkdir(mntent, rootfs, lxc_name, lxc_path) < 0)
return -1;
} else if (strncmp(mntent->mnt_type, "aufs", 4) == 0) {
if (mount_entry_create_aufs_dirs(mntent, rootfs, lxc_name, lxc_path) < 0)
......
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