]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
overlay and aufs clone_paths: be more robust
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Thu, 16 Oct 2014 15:10:21 +0000 (15:10 +0000)
committerStéphane Graber <stgraber@ubuntu.com>
Mon, 27 Oct 2014 21:38:13 +0000 (17:38 -0400)
Currently when we clone a container, bdev_copy passes NULL as dst argument
of bdev_init, then sees bdev->dest (as a result) is NULL, and sets
bdev->dest to $lxcpath/$name/rootfs.  so $ops->clone_paths() can
assume that "/rootfs" is at the end of the path.  The overlayfs and
aufs clonepaths do assume that and index to endofstring-6 and append
delta0.  Let's be more robust by actually finding the last / in
the path.

Then, instead of always setting oldbdev->dest to $lxcpath/$name/rootfs,
set it to oldbdev->src.  Else dir_clonepaths fails when mounting src
onto dest bc dest does not exist.  We could also fix that by creating
bdev->dest if needed, but that addes an empty directory to the old
container.

This fixes 'lxc-clone -o x1 -n x2' if x1 has lxc.rootfs = /var/lib/lxc/x1/x
and makes the overlayfs and aufs paths less fragile should something else
change.

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
src/lxc/bdev.c

index 4fc10f2aa189da39a051eab1dfae8e8daaad2556..8a819abed9f47902ac833183005e6ba49f90afca 100644 (file)
@@ -2265,20 +2265,24 @@ static int overlayfs_clonepaths(struct bdev *orig, struct bdev *new, const char
                WARN("Failed to update ownership of %s", new->dest);
 
        if (strcmp(orig->type, "dir") == 0) {
-               char *delta;
-               int ret, len;
+               char *delta, *lastslash;
+               int ret, len, lastslashidx;
 
                // if we have /var/lib/lxc/c2/rootfs, then delta will be
                //            /var/lib/lxc/c2/delta0
-               delta = strdup(new->dest);
-               if (!delta) {
-                       return -1;
-               }
-               if (strlen(delta) < 6) {
-                       free(delta);
+               lastslash = strrchr(new->dest, '/');
+               if (!lastslash)
                        return -22;
-               }
-               strcpy(&delta[strlen(delta)-6], "delta0");
+               if (strlen(lastslash) < 7)
+                       return -22;
+               lastslash++;
+               lastslashidx = lastslash - new->dest;
+
+               delta = malloc(lastslashidx + 7);
+               if (!delta)
+                       return -1;
+               strncpy(delta, new->dest, lastslashidx+1);
+               strcpy(delta+lastslashidx, "delta0");
                if ((ret = mkdir(delta, 0755)) < 0) {
                        SYSERROR("error: mkdir %s", delta);
                        free(delta);
@@ -2319,7 +2323,7 @@ static int overlayfs_clonepaths(struct bdev *orig, struct bdev *new, const char
                        free(osrc);
                        return -ENOMEM;
                }
-               if ((ret = mkdir(ndelta, 0755)) < 0) {
+               if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
                        SYSERROR("error: mkdir %s", ndelta);
                        free(osrc);
                        free(ndelta);
@@ -2560,20 +2564,24 @@ static int aufs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldn
                return -1;
 
        if (strcmp(orig->type, "dir") == 0) {
-               char *delta;
-               int ret, len;
+               char *delta, *lastslash;
+               int ret, len, lastslashidx;
 
                // if we have /var/lib/lxc/c2/rootfs, then delta will be
                //            /var/lib/lxc/c2/delta0
-               delta = strdup(new->dest);
-               if (!delta) {
-                       return -1;
-               }
-               if (strlen(delta) < 6) {
-                       free(delta);
+               lastslash = strrchr(new->dest, '/');
+               if (!lastslash)
                        return -22;
-               }
-               strcpy(&delta[strlen(delta)-6], "delta0");
+               if (strlen(lastslash) < 7)
+                       return -22;
+               lastslash++;
+               lastslashidx = lastslash - new->dest;
+
+               delta = malloc(lastslashidx + 7);
+               if (!delta)
+                       return -1;
+               strncpy(delta, new->dest, lastslashidx+1);
+               strcpy(delta+lastslashidx, "delta0");
                if ((ret = mkdir(delta, 0755)) < 0) {
                        SYSERROR("error: mkdir %s", delta);
                        free(delta);
@@ -3248,28 +3256,12 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
                return NULL;
        }
 
-       orig = bdev_init(c0->lxc_conf, src, NULL, NULL);
+       orig = bdev_init(c0->lxc_conf, src, src, NULL);
        if (!orig) {
                ERROR("failed to detect blockdev type for %s", src);
                return NULL;
        }
 
-       if (!orig->dest) {
-               int ret;
-               orig->dest = malloc(MAXPATHLEN);
-               if (!orig->dest) {
-                       ERROR("out of memory");
-                       bdev_put(orig);
-                       return NULL;
-               }
-               ret = snprintf(orig->dest, MAXPATHLEN, "%s/%s/rootfs", oldpath, oldname);
-               if (ret < 0 || ret >= MAXPATHLEN) {
-                       ERROR("rootfs path too long");
-                       bdev_put(orig);
-                       return NULL;
-               }
-       }
-
        /*
         * special case for snapshot - if caller requested maybe_snapshot and
         * keepbdevtype and backing store is directory, then proceed with a copy