]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
overlay: rework overlay storage driver
authorChristian Brauner <christian.brauner@ubuntu.com>
Fri, 28 Jul 2017 13:21:44 +0000 (15:21 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Mon, 31 Jul 2017 21:34:17 +0000 (23:34 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/bdev/lxcoverlay.c
src/lxc/lxccontainer.c

index 5e4fde5e76b7063a099fceb109ebb0380e6e4278..02868c88fdaf6e64979f9d4d72372345b7d76733 100644 (file)
@@ -45,8 +45,6 @@ static char *ovl_version[] = {"overlay", "overlayfs"};
 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 rsync_data *data);
-static int ovl_rsync_wrapper(void *data);
 static int ovl_remount_on_enodev(const char *lower, const char *target,
                                 const char *name, unsigned long mountflags,
                                 const void *options);
@@ -55,61 +53,80 @@ 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)
 {
-        char *src;
+       int ret;
+       char *src;
 
        if (!snap) {
-               ERROR("overlay is only for snapshot clones");
+               ERROR("The overlay storage driver can only be used for "
+                     "snapshots");
                return -22;
        }
 
        if (!orig->src || !orig->dest)
                return -1;
 
-       new->dest = lxc_string_join(
-           "/", (const char *[]){lxcpath, cname, "rootfs", NULL}, false);
-       if (!new->dest)
-               return -1;
+       new->dest = must_make_path(lxcpath, cname, "rootfs", NULL);
 
-       if (mkdir_p(new->dest, 0755) < 0)
+       ret = mkdir_p(new->dest, 0755);
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", new->dest);
                return -1;
+       }
 
-       if (am_unpriv() && chown_mapped_root(new->dest, conf) < 0)
-               WARN("Failed to update ownership of %s", new->dest);
+       if (am_unpriv()) {
+               ret = chown_mapped_root(new->dest, conf);
+               if (ret < 0)
+                       WARN("Failed to update ownership of %s", new->dest);
+       }
 
        if (strcmp(orig->type, "dir") == 0) {
                char *delta, *lastslash;
                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)
+               if (!lastslash) {
+                       ERROR("Failed to detect \"/\" in string \"%s\"",
+                             new->dest);
                        return -22;
-               if (strlen(lastslash) < 7)
+               }
+
+               if (strlen(lastslash) < (sizeof("/rootfs") - 1)) {
+                       ERROR("Failed to detect \"/rootfs\" in string \"%s\"",
+                             new->dest);
                        return -22;
+               }
+
                lastslash++;
                lastslashidx = lastslash - new->dest;
 
                delta = malloc(lastslashidx + 7);
-               if (!delta)
+               if (!delta) {
+                       ERROR("Failed to allocate memory");
                        return -1;
+               }
+
                strncpy(delta, new->dest, lastslashidx + 1);
-               strcpy(delta + lastslashidx, "delta0");
-               if ((ret = mkdir(delta, 0755)) < 0) {
-                       SYSERROR("error: mkdir %s", delta);
+               strncpy(delta + lastslashidx, "delta0", sizeof("delta0") - 1);
+               delta[lastslashidx + sizeof("delta0")] = '\0';
+
+               ret = mkdir(delta, 0755);
+               if (ret < 0 && errno != EEXIST) {
+                       SYSERROR("Failed to create directory \"%s\"", delta);
                        free(delta);
                        return -1;
                }
-               if (am_unpriv() && chown_mapped_root(delta, conf) < 0)
-                       WARN("Failed to update ownership of %s", delta);
 
-               /*
-                * Make workdir for overlayfs.v22 or higher:
+               if (am_unpriv()) {
+                       ret = chown_mapped_root(delta, conf);
+                       if (ret < 0)
+                               WARN("Failed to update ownership of %s", delta);
+               }
+
+               /* 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
@@ -119,86 +136,103 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
                 */
                work = malloc(lastslashidx + 7);
                if (!work) {
+                       ERROR("Failed to allocate memory");
                        free(delta);
                        return -1;
                }
+
                strncpy(work, new->dest, lastslashidx + 1);
-               strcpy(work + lastslashidx, "olwork");
+               strncpy(work + lastslashidx, "olwork", sizeof("olwork") - 1);
+               work[lastslashidx + sizeof("olwork")] = '\0';
+
                if (mkdir(work, 0755) < 0) {
                        SYSERROR("error: mkdir %s", work);
                        free(delta);
                        free(work);
                        return -1;
                }
-               if (am_unpriv() && chown_mapped_root(work, conf) < 0)
-                       WARN("Failed to update ownership of %s", work);
+
+               if (am_unpriv()) {
+                       ret = chown_mapped_root(work, conf);
+                       if (ret < 0)
+                               WARN("Failed to update ownership of %s", work);
+               }
                free(work);
 
+               /* strlen("overlay:") = 8
+                * +
+                * strlen(delta)
+                * +
+                * :
+                * +
+                * strlen(src)
+                * +
+                * \0
+                */
                src = lxc_storage_get_path(orig->src, orig->type);
-               // the src will be 'overlayfs:lowerdir:upperdir'
-               len = strlen(delta) + strlen(src) + 12;
+               len = 8 + strlen(delta) + 1 + strlen(src) + 1;
                new->src = malloc(len);
                if (!new->src) {
+                       ERROR("Failed to allocate memory");
                        free(delta);
                        return -ENOMEM;
                }
+
                ret = snprintf(new->src, len, "overlay:%s:%s", src, delta);
                free(delta);
-               if (ret < 0 || ret >= len)
+               if (ret < 0 || (size_t)ret >= len) {
+                       ERROR("Failed to create string");
                        return -1;
-       } else if (!strcmp(orig->type, "overlayfs") || !strcmp(orig->type, "overlay")) {
-               /*
-                * 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
-                */
+               }
+       } else if (!strcmp(orig->type, "overlayfs") ||
+                  !strcmp(orig->type, "overlay")) {
                char *osrc, *odelta, *nsrc, *ndelta, *work;
                char *lastslash;
-               int len, ret, lastslashidx;
+               int ret, lastslashidx;
+               size_t len;
 
                osrc = strdup(orig->src);
                if (!osrc) {
-                        SYSERROR("Failed to duplicate \"%s\"", orig->src);
+                       ERROR("Failed to duplicate string \"%s\"", orig->src);
                        return -22;
-                }
+               }
 
                nsrc = strchr(osrc, ':') + 1;
                if ((nsrc != osrc + 8) && (nsrc != osrc + 10)) {
                        free(osrc);
-                        ERROR("Detected \":\" in \"%s\" at wrong position", osrc);
+                       ERROR("Detected \":\" in \"%s\" at wrong position",
+                             osrc);
                        return -22;
-                }
+               }
 
                odelta = strchr(nsrc, ':');
                if (!odelta) {
                        free(osrc);
-                        ERROR("Failed to find \":\" in \"%s\"", nsrc);
+                       ERROR("Failed to find \":\" in \"%s\"", nsrc);
                        return -22;
                }
 
                *odelta = '\0';
                odelta++;
-                ndelta = lxc_string_join("/", (const char *[]){lxcpath, cname, "rootfs", NULL}, false);
-                if (!ndelta) {
-                       free(osrc);
-                        ERROR("Failed to create new path");
-                       return -ENOMEM;
-                }
+               ndelta = must_make_path(lxcpath, cname, "delta0", NULL);
 
                ret = mkdir(ndelta, 0755);
                if (ret < 0 && errno != EEXIST) {
                        free(osrc);
                        free(ndelta);
-                       SYSERROR("Failed to create \"%s\"", ndelta);
+                       SYSERROR("Failed to create directory \"%s\"", ndelta);
                        return -1;
                }
 
-               if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
-                       WARN("Failed to update ownership of %s", ndelta);
+               if (am_unpriv()) {
+                       ret = chown_mapped_root(ndelta, conf);
+                       if (ret < 0)
+                               WARN("Failed to update ownership of %s",
+                                    ndelta);
+               }
 
-               /*
-                * make workdir for overlayfs.v22 or higher (see comment further
-                * up)
+               /* Make workdir for overlayfs.v22 or higher (See the comment
+                * further up.).
                 */
                lastslash = strrchr(ndelta, '/');
                if (!lastslash) {
@@ -217,22 +251,38 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
                        ERROR("Failed to allocate memory");
                        return -1;
                }
+
                strncpy(work, ndelta, lastslashidx + 1);
-               strcpy(work + lastslashidx, "olwork");
+               strncpy(work + lastslashidx, "olwork", sizeof("olwork") - 1);
+               work[lastslashidx + sizeof("olwork")] = '\0';
+
                ret = mkdir(work, 0755);
                if (ret < 0 && errno != EEXIST) {
                        free(osrc);
                        free(ndelta);
                        free(work);
-                       SYSERROR("Failed to create \"%s\"", ndelta);
+                       SYSERROR("Failed to create directory \"%s\"", ndelta);
                        return -1;
                }
 
-               if (am_unpriv() && chown_mapped_root(work, conf) < 0)
-                       WARN("Failed to update ownership of %s", work);
+               if (am_unpriv()) {
+                       ret = chown_mapped_root(work, conf);
+                       if (ret < 0)
+                               WARN("Failed to update ownership of %s", work);
+               }
                free(work);
 
-               len = strlen(nsrc) + strlen(ndelta) + 10;
+               /* strlen("overlay:") = 8
+                * +
+                * strlen(delta)
+                * +
+                * :
+                * +
+                * strlen(src)
+                * +
+                * \0
+                */
+               len = 8 + strlen(ndelta) + 1 + strlen(nsrc) + 1;
                new->src = malloc(len);
                if (!new->src) {
                        free(osrc);
@@ -243,17 +293,16 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
                ret = snprintf(new->src, len, "overlay:%s:%s", nsrc, ndelta);
                free(osrc);
                free(ndelta);
-               if (ret < 0 || ret >= len) {
+               if (ret < 0 || (size_t)ret >= len) {
                        ERROR("Failed to create string");
                        return -1;
-                }
+               }
 
                return ovl_do_rsync(orig, new, conf);
        } else {
                ERROR("overlay clone of %s container is not yet supported",
                      orig->type);
-               /*
-                * Note, supporting this will require ovl_mount supporting
+               /* Note, supporting this will require ovl_mount supporting
                 * mounting of the underlay. No big deal, just needs to be done.
                 */
                return -1;
@@ -262,67 +311,86 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
        return 0;
 }
 
-/*
- * to say 'lxc-create -t ubuntu -n o1 -B overlay' means you want
- * $lxcpath/$lxcname/rootfs to have the created container, while all
- * changes after starting the container are written to
- * $lxcpath/$lxcname/delta0
+/* To say "lxc-create -t ubuntu -n o1 -B overlay" means you want
+ * "<lxcpath>/<lxcname>/rootfs" to have the created container, while all changes
+ * after starting the container are written to "<lxcpath>/<lxcname>/delta0".
  */
 int ovl_create(struct bdev *bdev, const char *dest, const char *n,
-                       struct bdev_specs *specs)
+              struct bdev_specs *specs)
 {
        char *delta;
-       int ret, len = strlen(dest), newlen;
+       int ret;
+       size_t len, newlen;
 
-       if (len < 8 || strcmp(dest + len - 7, "/rootfs") != 0)
+       len = strlen(dest);
+       if (len < 8 || strcmp(dest + len - 7, "/rootfs")) {
+               ERROR("Failed to detect \"/rootfs\" in \"%s\"", dest);
                return -1;
+       }
 
-       if (!(bdev->dest = strdup(dest))) {
-               ERROR("Out of memory");
+       bdev->dest = strdup(dest);
+       if (!bdev->dest) {
+               ERROR("Failed to duplicate string \"%s\"", dest);
                return -1;
        }
 
-       delta = alloca(strlen(dest) + 1);
-       strcpy(delta, dest);
-       strcpy(delta + len - 6, "delta0");
+       delta = malloc(len + 1);
+       if (!delta) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
+       strncpy(delta, dest, len);
+       strncpy(delta + len - 6, "delta0", sizeof("delta0") - 1);
+       delta[len + sizeof("delta0")] = '\0';
 
-       if (mkdir_p(delta, 0755) < 0) {
-               ERROR("Error creating %s", delta);
+       ret = mkdir_p(delta, 0755);
+       if (ret < 0) {
+               SYSERROR("Failed to create directory \"%s\"", delta);
+               free(delta);
                return -1;
        }
 
-       // overlay:lower:upper
+       /* overlay:lower:upper */
        newlen = (2 * len) + strlen("overlay:") + 2;
        bdev->src = malloc(newlen);
        if (!bdev->src) {
-               ERROR("Out of memory");
+               ERROR("Failed to allocate memory");
+               free(delta);
                return -1;
        }
+
        ret = snprintf(bdev->src, newlen, "overlay:%s:%s", dest, delta);
-       if (ret < 0 || ret >= newlen)
+       if (ret < 0 || (size_t)ret >= newlen) {
+               ERROR("Failed to create string");
+               free(delta);
                return -1;
+       }
 
-       if (mkdir_p(bdev->dest, 0755) < 0) {
-               ERROR("Error creating %s", bdev->dest);
+       ret = mkdir_p(bdev->dest, 0755);
+       if (ret < 0) {
+               SYSERROR("Failed to create directory \"%s\"", bdev->dest);
+               free(delta);
                return -1;
        }
 
+       free(delta);
        return 0;
 }
 
 int ovl_destroy(struct bdev *orig)
 {
-        bool ovl;
+       bool ovl;
        char *upper = orig->src;
 
-        ovl = !strncmp(upper, "overlay:", 8);
+       ovl = !strncmp(upper, "overlay:", 8);
        if (!ovl && strncmp(upper, "overlayfs:", 10))
                return -22;
 
-        if (ovl)
-                upper += 8;
-        else
-                upper += 10;
+       if (ovl)
+               upper += 8;
+       else
+               upper += 10;
 
        upper = strchr(upper, ':');
        if (!upper)
@@ -348,7 +416,7 @@ int ovl_mount(struct bdev *bdev)
        char *tmp, *options, *dup, *lower, *upper;
        char *options_work, *work, *lastslash;
        int lastslashidx;
-       int len, len2;
+       size_t len, len2;
        unsigned long mntflags;
        char *mntdata;
        int ret, ret2;
@@ -362,53 +430,87 @@ int ovl_mount(struct bdev *bdev)
        if (!ovl_name)
                ovl_name = ovl_detect_name();
 
-       /*
-        * separately mount it first:
-        * mount -t overlayfs * -oupperdir=${upper},lowerdir=${lower} lower dest
+       /* Separately mount it first:
+        * mount -t overlay * -o upperdir=${upper},lowerdir=${lower} lower dest
         */
-       dup = alloca(strlen(bdev->src) + 1);
-       strcpy(dup, bdev->src);
+       dup = strdup(bdev->src);
+       if (!dup) {
+               ERROR("Failed to allocate memory");
+               return -1;
+       }
+
        /* support multiple lower layers */
-       if (!(lower = strstr(dup, ":/")))
-                       return -22;
+       lower = strstr(dup, ":/");
+       if (!lower) {
+               ERROR("Failed to detect \":/\" in string \"%s\"", dup);
+               free(dup);
+               return -22;
+       }
+
        lower++;
        upper = lower;
        while ((tmp = strstr(++upper, ":/"))) {
                upper = tmp;
        }
-       if (--upper == lower)
+
+       upper--;
+       if (upper == lower) {
+               free(dup);
                return -22;
+       }
        *upper = '\0';
        upper++;
 
-       // if delta doesn't yet exist, create it
-       if (mkdir_p(upper, 0755) < 0 && errno != EEXIST)
+       /* if delta doesn't yet exist, create it */
+       ret = mkdir_p(upper, 0755) < 0;
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", upper);
+               free(dup);
                return -22;
+       }
 
-       /*
-        * overlayfs.v22 or higher needs workdir option:
+       /* 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)
+       if (!lastslash) {
+               ERROR("Failed to detect \"/\" in string \"%s\"", upper);
+               free(dup);
                return -22;
+       }
+
        lastslash++;
        lastslashidx = lastslash - upper;
 
-       work = alloca(lastslashidx + 7);
-       strncpy(work, upper, lastslashidx + 7);
-       strcpy(work + lastslashidx, "olwork");
+       work = malloc(lastslashidx + 7);
+       if (!work) {
+               ERROR("Failed to allocate memory");
+               free(dup);
+               return -22;
+       }
 
-       if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
+       strncpy(work, upper, lastslashidx + 1);
+       strncpy(work + lastslashidx, "olwork", sizeof("olwork") - 1);
+       work[lastslashidx + sizeof("olwork")] = '\0';
+
+       ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata);
+       if (ret < 0) {
+               ERROR("Failed to parse mount options");
                free(mntdata);
+               free(dup);
+               free(work);
                return -22;
        }
 
-       if (mkdir_p(work, 0755) < 0 && errno != EEXIST) {
+       ret = mkdir_p(work, 0755);
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", work);
                free(mntdata);
+               free(dup);
+               free(work);
                return -22;
        }
 
@@ -419,72 +521,94 @@ int ovl_mount(struct bdev *bdev)
         */
 
        if (mntdata) {
-               len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
+               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);
+               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;
+               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);
+               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;
+               len = strlen(lower) + strlen(upper) +
+                     strlen("upperdir=,lowerdir=") + 1;
                options = alloca(len);
-               ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
+               ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper,
+                              lower);
 
-               len2 = strlen(lower) + strlen(upper) + strlen(work)
-                       + strlen("upperdir=,lowerdir=,workdir=") + 1;
+               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);
+               ret2 = snprintf(options_work, len2,
+                               "upperdir=%s,lowerdir=%s,workdir=%s", upper,
+                               lower, work);
        }
 
        if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
+               ERROR("Failed to create string");
                free(mntdata);
+               free(dup);
+               free(work);
                return -1;
        }
 
-        /* Assume we need a workdir as we are on a overlay version >= v22. */
+       /* Assume we need a workdir as we are on a overlay version >= v22. */
        ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
                                    MS_MGC_VAL | mntflags, options_work);
        if (ret < 0) {
-               INFO("Overlay: Error mounting %s onto %s with options %s. "
-                    "Retrying without workdir: %s.",
+               INFO("Failed to mount \"%s\" on \"%s\" with options \"%s\". "
+                    "Retrying without workdir: %s",
                     lower, bdev->dest, options_work, strerror(errno));
 
-                /* Assume we cannot use a workdir as we are on a version <= v21. */
+               /* Assume we cannot use a workdir as we are on a version <= v21.
+                */
                ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
-                                         MS_MGC_VAL | mntflags, options);
+                                           MS_MGC_VAL | mntflags, options);
                if (ret < 0)
-                       SYSERROR("Overlay: Error mounting %s onto %s with "
-                                "options %s: %s.",
-                                lower, bdev->dest, options,
-                                strerror(errno));
+                       SYSERROR("Failed to mount \"%s\" on \"%s\" with "
+                                "options \"%s\": %s",
+                                lower, bdev->dest, options, strerror(errno));
                else
-                       INFO("Overlay: Mounted %s onto %s with options %s.",
+                       INFO("Mounted \"%s\" on \"%s\" with options \"%s\"",
                             lower, bdev->dest, options);
        } else {
-               INFO("Overlay: Mounted %s onto %s with options %s.", lower,
+               INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower,
                     bdev->dest, options_work);
        }
+
+       free(dup);
+       free(work);
        return ret;
 }
 
 int ovl_umount(struct bdev *bdev)
 {
+       int ret;
+
        if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs"))
                return -22;
 
        if (!bdev->src || !bdev->dest)
                return -22;
 
-       return umount(bdev->dest);
+       ret = umount(bdev->dest);
+       if (ret < 0)
+               SYSERROR("Failed to unmount \"%s\"", bdev->dest);
+       else
+               TRACE("Unmounted \"%s\"", bdev->dest);
+
+       return ret;
 }
 
 char *ovl_get_lower(const char *rootfs_path)
 {
        char *s1;
+
        s1 = strstr(rootfs_path, ":/");
        if (!s1)
                return NULL;
@@ -512,7 +636,8 @@ char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen)
        if (!s1)
                return NULL;
 
-       if ((s2 = strstr(s1, ":/"))) {
+       s2 = strstr(s1, ":/");
+       if (s2) {
                s2 = s2 + 1;
                if ((s3 = strstr(s2, ":/")))
                        *s3 = '\0';
@@ -537,18 +662,12 @@ int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
              const char *lxc_name, const char *lxc_path)
 {
        char lxcpath[MAXPATHLEN];
-       char *rootfs_path = NULL;
-       char *rootfsdir = NULL;
-       char *upperdir = NULL;
-       char *workdir = NULL;
-       char **opts = NULL;
+       char **opts;
+       int ret;
+       size_t arrlen, dirlen, i, len, rootfslen;
        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;
+       char *rootfs_dir = NULL, *rootfs_path = NULL, *upperdir = NULL,
+            *workdir = NULL;
 
        /* When rootfs == NULL we have a container without a rootfs. */
        if (rootfs && rootfs->path)
@@ -561,19 +680,22 @@ int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
                goto err;
 
        for (i = 0; i < arrlen; i++) {
-               if (strstr(opts[i], "upperdir=") && (strlen(opts[i]) > (len = strlen("upperdir="))))
+               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="))))
+               else if (strstr(opts[i], "workdir=") &&
+                        (strlen(opts[i]) > (len = strlen("workdir="))))
                        workdir = opts[i] + len;
        }
 
        if (rootfs_path) {
-               ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
+               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)
+               rootfs_dir = ovl_get_rootfs(rootfs_path, &rootfslen);
+               if (!rootfs_dir)
                        goto err;
 
                dirlen = strlen(lxcpath);
@@ -588,51 +710,52 @@ int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
        if (upperdir) {
                if (!rootfs_path)
                        ret = mkdir_p(upperdir, 0755);
-               else if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
+               else if (!strncmp(upperdir, lxcpath, dirlen) &&
+                        strncmp(upperdir, rootfs_dir, rootfslen))
                        ret = mkdir_p(upperdir, 0755);
                if (ret < 0)
-                       WARN("Failed to create upperdir");
+                       WARN("Failed to create directory \"%s\": %s", upperdir,
+                            strerror(errno));
        }
 
        ret = 0;
        if (workdir) {
                if (!rootfs_path)
                        ret = mkdir_p(workdir, 0755);
-               else if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0))
+               else if (!strncmp(workdir, lxcpath, dirlen) &&
+                        strncmp(workdir, rootfs_dir, rootfslen))
                        ret = mkdir_p(workdir, 0755);
                if (ret < 0)
-                       WARN("Failed to create workdir");
+                       WARN("Failed to create directory \"%s\": %s", workdir,
+                            strerror(errno));
        }
 
        fret = 0;
 
 err:
-       free(rootfsdir);
+       free(rootfs_dir);
        lxc_free_array((void **)opts, free);
        return fret;
 }
 
-/*
- * To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
+/* 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
  * upper- and workdir. This update is done in two locations:
  * lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done
- * independent of each other since lxc_conf->mountlist may container more mount
- * entries (e.g. from other included files) than lxc_conf->unexpanded_config .
+ * independent of each other since lxc_conf->mountlist may contain more mount
+ * entries (e.g. from other included files) than lxc_conf->unexpanded_config.
  */
 int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
                         const char *lxc_name, const char *newpath,
                         const char *newname)
 {
-       char new_upper[MAXPATHLEN];
-       char new_work[MAXPATHLEN];
-       char old_upper[MAXPATHLEN];
-       char old_work[MAXPATHLEN];
-       char *cleanpath = NULL;
+       char new_upper[MAXPATHLEN], new_work[MAXPATHLEN], old_upper[MAXPATHLEN],
+           old_work[MAXPATHLEN];
        size_t i;
+       struct lxc_list *iterator;
+       char *cleanpath = NULL;
        int fret = -1;
        int ret = 0;
-       struct lxc_list *iterator;
        const char *ovl_dirs[] = {"br", "upperdir", "workdir"};
 
        cleanpath = strdup(newpath);
@@ -652,19 +775,20 @@ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
                        goto err;
        }
 
-       ret = snprintf(old_work, MAXPATHLEN, "workdir=%s/%s", lxc_path, lxc_name);
+       ret =
+           snprintf(old_work, MAXPATHLEN, "workdir=%s/%s", lxc_path, lxc_name);
        if (ret < 0 || ret >= MAXPATHLEN)
                goto err;
 
-       ret = snprintf(new_work, MAXPATHLEN, "workdir=%s/%s", cleanpath, newname);
+       ret =
+           snprintf(new_work, MAXPATHLEN, "workdir=%s/%s", cleanpath, newname);
        if (ret < 0 || ret >= MAXPATHLEN)
                goto err;
 
        lxc_list_for_each(iterator, &lxc_conf->mount_list) {
-               char *mnt_entry = NULL;
-               char *new_mnt_entry = NULL;
-               char *tmp = NULL;
-               char *tmp_mnt_entry = NULL;
+               char *mnt_entry = NULL, *new_mnt_entry = NULL, *tmp = NULL,
+                    *tmp_mnt_entry = NULL;
+
                mnt_entry = iterator->elem;
 
                if (strstr(mnt_entry, "overlay"))
@@ -675,23 +799,28 @@ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
                if (!tmp)
                        continue;
 
-               ret = snprintf(old_upper, MAXPATHLEN, "%s=%s/%s", tmp, lxc_path, lxc_name);
+               ret = snprintf(old_upper, MAXPATHLEN, "%s=%s/%s", tmp, lxc_path,
+                              lxc_name);
                if (ret < 0 || ret >= MAXPATHLEN)
                        goto err;
 
-               ret = snprintf(new_upper, MAXPATHLEN, "%s=%s/%s", tmp, cleanpath, newname);
+               ret = snprintf(new_upper, MAXPATHLEN, "%s=%s/%s", tmp,
+                              cleanpath, newname);
                if (ret < 0 || ret >= MAXPATHLEN)
                        goto err;
 
                if (strstr(mnt_entry, old_upper)) {
-                       tmp_mnt_entry = lxc_string_replace(old_upper, new_upper, mnt_entry);
+                       tmp_mnt_entry =
+                           lxc_string_replace(old_upper, new_upper, mnt_entry);
                }
 
                if (strstr(mnt_entry, old_work)) {
                        if (tmp_mnt_entry)
-                               new_mnt_entry = lxc_string_replace(old_work, new_work, tmp_mnt_entry);
+                               new_mnt_entry = lxc_string_replace(
+                                   old_work, new_work, tmp_mnt_entry);
                        else
-                               new_mnt_entry = lxc_string_replace(old_work, new_work, mnt_entry);
+                               new_mnt_entry = lxc_string_replace(
+                                   old_work, new_work, mnt_entry);
                }
 
                if (new_mnt_entry) {
@@ -716,68 +845,24 @@ static int ovl_remount_on_enodev(const char *lower, const char *target,
                                 const char *name, unsigned long mountflags,
                                 const void *options)
 {
-        int ret;
-        ret = mount(lower, target, ovl_name, MS_MGC_VAL | mountflags, options);
-        if (ret < 0 && errno == ENODEV) /* Try other module name. */
+       int ret;
+       ret = mount(lower, target, ovl_name, MS_MGC_VAL | mountflags, options);
+       if (ret < 0 && errno == ENODEV) /* Try other module name. */
                ret = mount(lower, target,
                            ovl_name == ovl_version[0] ? ovl_version[1]
                                                       : ovl_version[0],
                            MS_MGC_VAL | mountflags, options);
-        return ret;
-}
-
-static int ovl_rsync(struct 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;
+       return ret;
 }
 
 static char *ovl_detect_name(void)
 {
+       FILE *f;
        char *v = ovl_version[0];
        char *line = NULL;
        size_t len = 0;
-       FILE *f = fopen("/proc/filesystems", "r");
+
+       f = fopen("/proc/filesystems", "r");
        if (!f)
                return v;
 
@@ -793,27 +878,28 @@ static char *ovl_detect_name(void)
        return v;
 }
 
-static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf)
+static int ovl_do_rsync(struct bdev *orig, struct bdev *new,
+                       struct lxc_conf *conf)
 {
        int ret = -1;
-       struct rsync_data rdata;
+       struct rsync_data rdata = {0, 0};
+       char cmd_output[MAXPATHLEN] = {0};
 
        rdata.orig = orig;
        rdata.new = new;
-       if (am_unpriv())
-               ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata,
-                                   "ovl_rsync_wrapper");
-       else
-               ret = ovl_rsync(&rdata);
-       if (ret)
-               ERROR("copying overlay delta");
+       if (am_unpriv()) {
+               ret = userns_exec_1(conf, lxc_rsync_exec_wrapper, &rdata,
+                                   "lxc_rsync_exec_wrapper");
+               if (ret < 0)
+                       ERROR("Failed to rsync from \"%s\" into \"%s\"",
+                             orig->dest, new->dest);
+       } else {
+               ret = run_command(cmd_output, sizeof(cmd_output),
+                                 lxc_rsync_exec_wrapper, (void *)&rdata);
+               if (ret < 0)
+                       ERROR("Failed to rsync from \"%s\" into \"%s\": %s",
+                             orig->dest, new->dest, cmd_output);
+       }
 
        return ret;
 }
-
-static int ovl_rsync_wrapper(void *data)
-{
-       struct rsync_data *arg = data;
-       return ovl_rsync(arg);
-}
-
index 4818eb644102bb4ecf97474596b0917b3fa37bdf..4c00187f4d432473ae3128b0cbc273e9cbc4b5af 100644 (file)
@@ -1263,11 +1263,45 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
                if (strcmp(bdev->type, "dir") && strcmp(bdev->type, "btrfs")) {
                        if (geteuid() != 0) {
                                ERROR("non-root users can only create btrfs and directory-backed containers");
-                               exit(1);
+                               exit(EXIT_FAILURE);
                        }
-                       if (bdev->ops->mount(bdev) < 0) {
-                               ERROR("Error mounting rootfs");
-                               exit(1);
+
+                       if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs")) {
+                               /* If we create an overlay container we need to
+                                * rsync the contents into
+                                * <container-path>/<container-name>/rootfs.
+                                * However, the overlay mount function will
+                                * mount will mount
+                                * <container-path>/<container-name>/delta0
+                                * over
+                                * <container-path>/<container-name>/rootfs
+                                * which means we would rsync the rootfs into
+                                * the delta directory. That doesn't make sense
+                                * since the delta directory only exists to
+                                * record the differences to
+                                * <container-path>/<container-name>/rootfs. So
+                                * let's simply bind-mount here and then rsync
+                                * directly into
+                                * <container-path>/<container-name>/rootfs.
+                                */
+                               char *src;
+
+                               src = ovl_get_rootfs(bdev->src, &(size_t){0});
+                               if (!src) {
+                                       ERROR("Failed to get rootfs");
+                                       exit(EXIT_FAILURE);
+                               }
+
+                               ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC, NULL);
+                               if (ret < 0) {
+                                       ERROR("Failed to mount rootfs");
+                                       return -1;
+                               }
+                       } else {
+                               if (bdev->ops->mount(bdev) < 0) {
+                                       ERROR("Failed to mount rootfs");
+                                       exit(EXIT_FAILURE);
+                               }
                        }
                } else { // TODO come up with a better way here!
                        char *src;