From: Christian Brauner Date: Tue, 15 Dec 2015 14:19:08 +0000 (+0100) Subject: Move remaining overlay helpers to overlay.{c,h} X-Git-Tag: lxc-2.0.0.beta1~6^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F724%2Fhead;p=thirdparty%2Flxc.git 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: Christian Brauner --- diff --git a/src/lxc/bdev/overlay.c b/src/lxc/bdev/overlay.c index 26a7238f0..5aa197387 100644 --- a/src/lxc/bdev/overlay.c +++ b/src/lxc/bdev/overlay.c @@ -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); +} + diff --git a/src/lxc/bdev/overlay.h b/src/lxc/bdev/overlay.h index 338fb86ba..8ef277b83 100644 --- a/src/lxc/bdev/overlay.h +++ b/src/lxc/bdev/overlay.h @@ -29,6 +29,12 @@ #include #include +#if IS_BIONIC +#include <../include/lxcmntent.h> +#else +#include +#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 */ diff --git a/src/lxc/conf.c b/src/lxc/conf.c index c9cfcc205..24420693a 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -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)