]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
Move remaining overlay helpers to overlay.{c,h} 724/head
authorChristian Brauner <christian.brauner@mailbox.org>
Tue, 15 Dec 2015 14:19:08 +0000 (15:19 +0100)
committerChristian Brauner <christian.brauner@mailbox.org>
Tue, 15 Dec 2015 16:03:58 +0000 (17:03 +0100)
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 <christian.brauner@mailbox.org>
src/lxc/bdev/overlay.c
src/lxc/bdev/overlay.h
src/lxc/conf.c

index 26a7238f09593e34e672a0699fd324e99c0dc0d7..5aa197387cbb97a8859b53e468cc912bc704d45a 100644 (file)
@@ -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);
+}
+
index 338fb86baedfb1d90f26dfced2232846e21252ba..8ef277b833389f9bd0dcc3c317d88cf748fc5b5f 100644 (file)
 #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 */
index c9cfcc2052da36286214ca8afd6171c5d566ab5e..24420693ac0973b01be698880829d1a3f3243bbe 100644 (file)
@@ -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)