<p dir="ltr">I'm working on a couple of small bug fixes brought to my attention by additional tests. Furthermore, since we allow all backingstorages that allow snapshots to be started as ephemeral containers it makes sense to allow users to directly specify the type of the union mounts he wants. So the current -m union=/src:/dest gets split into -m aufs=/src:/dest and -m overlay=/src:/dest.</p>
<div class="gmail_quote">On Sep 23, 2015 11:20 AM, "Christian Brauner" <<a href="mailto:christianvanbrauner@gmail.com">christianvanbrauner@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This is a complete reimplementation of lxc-clone and lxc-start-ephemeral.<br>
<br>
Signed-off-by: Christian Brauner <<a href="mailto:christianvanbrauner@gmail.com">christianvanbrauner@gmail.com</a>><br>
---<br>
 src/lxc/Makefile.am |   2 +<br>
 src/lxc/arguments.h |   6 +-<br>
 src/lxc/lxc_copy.c  | 723 ++++++++++++++++++++++++++++++++++++++++++++++++++++<br>
 3 files changed, 730 insertions(+), 1 deletion(-)<br>
 create mode 100644 src/lxc/lxc_copy.c<br>
<br>
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am<br>
index ce46495..72f1e9b 100644<br>
--- a/src/lxc/Makefile.am<br>
+++ b/src/lxc/Makefile.am<br>
@@ -183,6 +183,7 @@ bin_PROGRAMS = \<br>
        lxc-cgroup \<br>
        lxc-checkpoint \<br>
        lxc-clone \<br>
+       lxc-copy \<br>
        lxc-config \<br>
        lxc-console \<br>
        lxc-create \<br>
@@ -226,6 +227,7 @@ init_lxc_SOURCES = lxc_init.c<br>
 lxc_monitor_SOURCES = lxc_monitor.c<br>
 lxc_monitord_SOURCES = lxc_monitord.c<br>
 lxc_clone_SOURCES = lxc_clone.c<br>
+lxc_copy_SOURCES = lxc_copy.c<br>
 lxc_start_SOURCES = lxc_start.c<br>
 lxc_stop_SOURCES = lxc_stop.c<br>
 lxc_top_SOURCES = lxc_top.c<br>
diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h<br>
index bf03dc5..a2f4b93 100644<br>
--- a/src/lxc/arguments.h<br>
+++ b/src/lxc/arguments.h<br>
@@ -98,8 +98,9 @@ struct lxc_arguments {<br>
        int list;<br>
        char *groups;<br>
<br>
-       /* lxc-snapshot and lxc-clone */<br>
+       /* lxc-snapshot and lxc-copy */<br>
        enum task {<br>
+               CLONE,<br>
                DESTROY,<br>
                LIST,<br>
                RESTORE,<br>
@@ -111,6 +112,9 @@ struct lxc_arguments {<br>
        char *newname;<br>
        char *newpath;<br>
        char *snapname;<br>
+       char **mntlist;<br>
+       char **mnttype;<br>
+       int keepdata;<br>
        int keepname;<br>
        int keepmac;<br>
<br>
diff --git a/src/lxc/lxc_copy.c b/src/lxc/lxc_copy.c<br>
new file mode 100644<br>
index 0000000..aa4f1fa<br>
--- /dev/null<br>
+++ b/src/lxc/lxc_copy.c<br>
@@ -0,0 +1,723 @@<br>
+/*<br>
+ *<br>
+ * Copyright © 2015 Christian Brauner <<a href="mailto:christianvanbrauner@gmail.com">christianvanbrauner@gmail.com</a>>.<br>
+ *<br>
+ * This program is free software; you can redistribute it and/or modify<br>
+ * it under the terms of the GNU General Public License version 2, as<br>
+ * published by the Free Software Foundation.<br>
+ *<br>
+ * This program is distributed in the hope that it will be useful,<br>
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>
+ * GNU General Public License for more details.<br>
+ *<br>
+ * You should have received a copy of the GNU General Public License along<br>
+ * with this program; if not, write to the Free Software Foundation, Inc.,<br>
+ * 51 Franklin Street, Fifth Floor, Boston, MA <a href="tel:02110-1301" value="+4921101301">02110-1301</a> USA.<br>
+ */<br>
+<br>
+#define _GNU_SOURCE<br>
+#include <unistd.h><br>
+#include <getopt.h><br>
+#include <signal.h><br>
+#include <stdio.h><br>
+#include <sys/types.h><br>
+#include <stdint.h><br>
+#include <sys/wait.h><br>
+#include <stdlib.h><br>
+#include <errno.h><br>
+#include <ctype.h><br>
+#include <sys/stat.h><br>
+#include <fcntl.h><br>
+#include <time.h><br>
+<br>
+#include <lxc/lxccontainer.h><br>
+<br>
+#include "attach.h"<br>
+#include "log.h"<br>
+#include "confile.h"<br>
+#include "arguments.h"<br>
+#include "lxc.h"<br>
+#include "conf.h"<br>
+#include "state.h"<br>
+#include "utils.h"<br>
+#include "bdev.h"<br>
+<br>
+#define DOUBLE_INFO(...) {           \<br>
+               printf(__VA_ARGS__); \<br>
+               INFO(__VA_ARGS__);   \<br>
+       }<br>
+<br>
+lxc_log_define(lxc_copy_ui, lxc);<br>
+<br>
+static int my_parser(struct lxc_arguments *args, int c, char *arg);<br>
+<br>
+static const struct option my_longopts[] = {<br>
+       { "newname", required_argument, 0, 'N'},<br>
+       { "newpath", required_argument, 0, 'p'},<br>
+       { "rename", no_argument, 0, 'R'},<br>
+       { "snapshot", no_argument, 0, 's'},<br>
+       { "daemonize", no_argument, 0, 'd'},<br>
+       { "ephemeral", no_argument, 0, 'e'},<br>
+       { "mount", required_argument, 0, 'm'},<br>
+       { "backingstore", required_argument, 0, 'B'},<br>
+       { "fssize", required_argument, 0, 'L'},<br>
+       { "keepdata", no_argument, 0, 'D'},<br>
+       { "keepname", no_argument, 0, 'K'},<br>
+       { "keepmac", no_argument, 0, 'M'},<br>
+       LXC_COMMON_OPTIONS<br>
+};<br>
+<br>
+/* mount keys */<br>
+static char *const keys[] = {<br>
+       [0] = "bind",<br>
+       [1] = "union",<br>
+       NULL<br>
+};<br>
+<br>
+static struct lxc_arguments my_args = {<br>
+       .progname = "lxc-copy",<br>
+       .help = "\<br>
+--name=NAME [-P lxcpath] -N newname [-p newpath] [-B backingstorage] [-s] [-K] [-M] [-L size [unit]]\n\<br>
+\n\<br>
+lxc-copy clone a container\n\<br>
+\n\<br>
+Options :\n\<br>
+  -n, --name=NAME           NAME of the container\n\<br>
+  -N, --newname=NEWNAME     NEWNAME for the restored container\n\<br>
+  -p, --newpath=NEWPATH     NEWPATH for the container to be stored\n\<br>
+  -R, --rename             rename container\n\<br>
+  -s, --snapshot           create snapshot instead of clone\n\<br>
+  -d, --daemonize          start container in background\n\<br>
+  -e, --ephemeral          start ephemeral container\n\<br>
+  -m, --mount              directory to mount into container, either \n\<br>
+                           {bind,union}=/src-path or {bind,union}=/src-path:/dst-path\n\<br>
+  -B, --backingstorage=TYPE backingstorage type for the container\n\<br>
+  -L, --fssize             size of the new block device for block device containers\n\<br>
+  -K, --keepname           keep the hostname of the original container\n\<br>
+  -M, --keepmac                    keep the MAC address of the original container\n",<br>
+       .options = my_longopts,<br>
+       .parser = my_parser,<br>
+       .task = CLONE,<br>
+};<br>
+<br>
+static int mntindex = 0;<br>
+<br>
+static char *construct_path(char *path, bool as_prefix);<br>
+static int create_mntlist(struct lxc_arguments *args, char *mntparameters,<br>
+                         char *mnttype);<br>
+static int do_clone(struct lxc_container *c, char *newname, char *newpath,<br>
+                   int flags, char *bdevtype, uint64_t fssize, enum task task,<br>
+                   char **args);<br>
+static int do_clone_ephemeral(struct lxc_container *c, char *newname,<br>
+                             char *newpath, int flags, char *bdevtype,<br>
+                             uint64_t fssize, char **args);<br>
+static int do_clone_rename(struct lxc_container *c, char *newname);<br>
+static int do_clone_task(struct lxc_container *c, enum task task, int flags,<br>
+                        char **args);<br>
+static char *generate_random_name(const char *name, const char *path);<br>
+static uint64_t get_fssize(char *s);<br>
+static int mkdir_userns_wrapper(void *arg);<br>
+static int mkdir_wrapper(struct lxc_container *c, char *arg);<br>
+static int parse_mntsubopts(struct lxc_arguments *args, char *subopts,<br>
+                           char *const *keys, char *mntparameters);<br>
+static int set_bind_mount(struct lxc_container *c, char *mntstring);<br>
+static int set_union_mount(struct lxc_container *c, char *newpath,<br>
+                          char *mntstring, int index, char *uniontype);<br>
+<br>
+int main(int argc, char *argv[])<br>
+{<br>
+       struct lxc_container *c;<br>
+       int flags = 0;<br>
+       int ret;<br>
+<br>
+       if (lxc_arguments_parse(&my_args, argc, argv))<br>
+               exit(EXIT_FAILURE);<br>
+<br>
+       if (!my_args.log_file)<br>
+               my_args.log_file = "none";<br>
+<br>
+       if (lxc_log_init(<a href="http://my_args.name" rel="noreferrer" target="_blank">my_args.name</a>, my_args.log_file, my_args.log_priority,<br>
+                        my_args.progname, my_args.quiet, my_args.lxcpath[0]))<br>
+               exit(EXIT_FAILURE);<br>
+       lxc_log_options_no_override();<br>
+<br>
+       if (geteuid()) {<br>
+               if (access(my_args.lxcpath[0], O_RDWR) < 0) {<br>
+                       fprintf(stderr, "You lack access to %s\n",<br>
+                               my_args.lxcpath[0]);<br>
+                       exit(EXIT_FAILURE);<br>
+               }<br>
+       }<br>
+<br>
+       if (!my_args.newname && !(my_args.task == DESTROY)) {<br>
+               printf("Error: You must provide a NEWNAME for the clone.\n");<br>
+               exit(EXIT_FAILURE);<br>
+       }<br>
+<br>
+       if (my_args.task == SNAP || my_args.task == DESTROY)<br>
+               flags |= LXC_CLONE_SNAPSHOT;<br>
+       if (my_args.keepname)<br>
+               flags |= LXC_CLONE_KEEPNAME;<br>
+       if (my_args.keepmac)<br>
+               flags |= LXC_CLONE_KEEPMACADDR;<br>
+<br>
+       c = lxc_container_new(<a href="http://my_args.name" rel="noreferrer" target="_blank">my_args.name</a>, my_args.lxcpath[0]);<br>
+       if (!c)<br>
+               exit(EXIT_FAILURE);<br>
+<br>
+       if (!c->may_control(c)) {<br>
+               fprintf(stderr, "Insufficent privileges to control %s\n",<br>
+                       c->name);<br>
+               lxc_container_put(c);<br>
+               exit(EXIT_FAILURE);<br>
+       }<br>
+<br>
+       if (!c->is_defined(c)) {<br>
+               fprintf(stderr, "Error: container %s is not defined\n",<br>
+                       c->name);<br>
+               lxc_container_put(c);<br>
+               exit(EXIT_FAILURE);<br>
+       }<br>
+<br>
+       ret = do_clone_task(c, my_args.task, flags, &argv[optind]);<br>
+<br>
+       lxc_container_put(c);<br>
+<br>
+       if (ret == 0)<br>
+               exit(EXIT_SUCCESS);<br>
+       exit(EXIT_FAILURE);<br>
+}<br>
+<br>
+static int my_parser(struct lxc_arguments *args, int c, char *arg)<br>
+{<br>
+       char *subopts = NULL;<br>
+       char *mntparameters = NULL;<br>
+       switch (c) {<br>
+       case 'N':<br>
+               args->newname = arg;<br>
+               break;<br>
+       case 'p':<br>
+               args->newpath = arg;<br>
+               break;<br>
+       case 'R':<br>
+               args->task = RENAME;<br>
+               break;<br>
+       case 's':<br>
+               args->task = SNAP;<br>
+               break;<br>
+       case 'd':<br>
+               args->daemonize = 1;<br>
+               break;<br>
+       case 'e':<br>
+               args->task = DESTROY;<br>
+               break;<br>
+       case 'm':<br>
+               subopts = optarg;<br>
+               if (parse_mntsubopts(args, subopts, keys, mntparameters) < 0)<br>
+                       return -1;<br>
+               break;<br>
+       case 'B':<br>
+               args->bdevtype = arg;<br>
+               break;<br>
+       case 'L':<br>
+               args->fssize = get_fssize(optarg);<br>
+               break;<br>
+       case 'D':<br>
+               args->keepdata = 1;<br>
+               break;<br>
+       case 'K':<br>
+               args->keepname = 1;<br>
+               break;<br>
+       case 'M':<br>
+               args->keepmac = 1;<br>
+               break;<br>
+       }<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static int do_clone(struct lxc_container *c, char *newname, char *newpath,<br>
+                   int flags, char *bdevtype, uint64_t fssize, enum task task,<br>
+                   char **args)<br>
+{<br>
+       struct lxc_container *clone;<br>
+<br>
+       clone = c->clone(c, newname, newpath, flags, bdevtype, NULL, fssize,<br>
+                        args);<br>
+       if (!clone) {<br>
+               fprintf(stderr, "clone failed\n");<br>
+               return -1;<br>
+       }<br>
+<br>
+       DOUBLE_INFO("Created container %s as %s of %s\n", newname,<br>
+                   task ? "snapshot" : "copy", c->name);<br>
+<br>
+       lxc_container_put(clone);<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static int do_clone_ephemeral(struct lxc_container *c, char *newname,<br>
+                             char *newpath, int flags, char *bdevtype,<br>
+                             uint64_t fssize, char **args)<br>
+{<br>
+       int i;<br>
+       int index = 0;<br>
+       int ret = 0;<br>
+       struct lxc_container *clone;<br>
+       char *randname = NULL;<br>
+       lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;<br>
+       attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;<br>
+<br>
+       if (!newname) {<br>
+               randname = generate_random_name(c->name, newpath ? newpath : my_args.lxcpath[0]);<br>
+               if (randname)<br>
+                       clone = c->clone(c, randname, newpath, flags, bdevtype,<br>
+                                        NULL, fssize, args);<br>
+               else<br>
+                       return -1;<br>
+       } else {<br>
+               clone = c->clone(c, newname, newpath, flags, bdevtype, NULL,<br>
+                                fssize, args);<br>
+       }<br>
+<br>
+       if (!clone) {<br>
+               fprintf(stderr, "Creating clone of %s failed\n", c->name);<br>
+               return -1;<br>
+       }<br>
+<br>
+       if (!my_args.keepdata) {<br>
+               if (!clone->set_config_item(clone, "lxc.ephemeral", "1")) {<br>
+                       fprintf(stderr, "Error setting config item\n");<br>
+                       clone->destroy(clone);<br>
+                       lxc_container_put(clone);<br>
+                       return -1;<br>
+               }<br>
+<br>
+               if (!clone->save_config(clone, NULL)) {<br>
+                       clone->destroy(clone);<br>
+                       lxc_container_put(clone);<br>
+                       fprintf(stderr, "Error saving config item\n");<br>
+                       return -1;<br>
+               }<br>
+       }<br>
+<br>
+       for (i = 0; i < mntindex; i++) {<br>
+               if (strncmp(my_args.mnttype[i], "bind", 4) == 0) {<br>
+                       if (set_bind_mount(clone, my_args.mntlist[i]) < 0)<br>
+                               return -1;<br>
+               } else {<br>
+                       if (strncmp(clone->lxc_conf->rootfs.path, "overlayfs:", 10) == 0) {<br>
+                               if (set_union_mount(clone, newpath,<br>
+                                                   my_args.mntlist[i], index,<br>
+                                                   "overlay") < 0)<br>
+                                       return -1;<br>
+                       } else if (strncmp(clone->lxc_conf->rootfs.path, "aufs:", 5) == 0) {<br>
+                               if (set_union_mount(clone, newpath,<br>
+                                                   my_args.mntlist[i], index,<br>
+                                                   "aufs") < 0)<br>
+                                       return -1;<br>
+                       }<br>
+                       index++;<br>
+               }<br>
+       }<br>
+<br>
+       if (!clone->save_config(clone, NULL)) {<br>
+               clone->destroy(clone);<br>
+               lxc_container_put(clone);<br>
+               fprintf(stderr, "Error saving config item\n");<br>
+               return -1;<br>
+       }<br>
+<br>
+<br>
+       DOUBLE_INFO("Created %s as %s of %s\n", newname ? newname : randname,<br>
+                   my_args.keepdata ? "clone" : "ephemeral clone", c->name);<br>
+<br>
+       if (!my_args.daemonize && my_args.argc) {<br>
+               clone->want_daemonize(clone, true);<br>
+       } else if (!my_args.daemonize) {<br>
+               clone->want_daemonize(clone, false);<br>
+       }<br>
+<br>
+       if (!clone->start(clone, 0, NULL)) {<br>
+               clone->destroy(clone);<br>
+               lxc_container_put(clone);<br>
+               fprintf(stderr, "Error starting container\n");<br>
+       }<br>
+<br>
+       if (!my_args.daemonize && my_args.argc) {<br>
+               ret = clone->attach_run_wait(clone, &attach_options,<br>
+                                            my_args.argv[0],<br>
+                                            (const char *const *)my_args.argv);<br>
+               if (ret < 0) {<br>
+                       lxc_container_put(clone);<br>
+                       return -1;<br>
+               } else {<br>
+                       clone->shutdown(clone, true);<br>
+               }<br>
+       }<br>
+<br>
+       lxc_container_put(clone);<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static int do_clone_rename(struct lxc_container *c, char *newname)<br>
+{<br>
+       if (!c->rename(c, newname)) {<br>
+               ERROR("Error: Renaming container %s to %s failed\n", c->name, newname);<br>
+               return -1;<br>
+       }<br>
+<br>
+       INFO("Renamed container %s to %s\n", c->name, newname);<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static int do_clone_task(struct lxc_container *c, enum task task, int flags,<br>
+                        char **args)<br>
+{<br>
+       int ret = 0;<br>
+<br>
+       switch (task) {<br>
+       case DESTROY:<br>
+               ret = do_clone_ephemeral(c, my_args.newname, my_args.newpath,<br>
+                                        flags, my_args.bdevtype,<br>
+                                        my_args.fssize, args);<br>
+               break;<br>
+       case RENAME:<br>
+               ret = do_clone_rename(c, my_args.newname);<br>
+               break;<br>
+       default:<br>
+               ret = do_clone(c, my_args.newname, my_args.newpath, flags,<br>
+                              my_args.bdevtype, my_args.fssize, my_args.task,<br>
+                              args);<br>
+               break;<br>
+       }<br>
+<br>
+       return ret;<br>
+}<br>
+<br>
+static char *construct_path(char *path, bool as_prefix)<br>
+{<br>
+       char **components = NULL;<br>
+       char *cleanpath = NULL;<br>
+<br>
+       components = lxc_normalize_path(path);<br>
+       if (!components)<br>
+               return NULL;<br>
+<br>
+       cleanpath = lxc_string_join("/", (const char **)components, as_prefix);<br>
+       lxc_free_array((void **)components, free);<br>
+<br>
+       return cleanpath;<br>
+}<br>
+<br>
+static int create_mntlist(struct lxc_arguments *args, char *mntparameters,<br>
+                         char *mnttype)<br>
+{<br>
+       char **tmpchar1;<br>
+       char **tmpchar2;<br>
+       tmpchar1 = realloc(args->mntlist, (mntindex + 1) * sizeof(args->mntlist[0]));<br>
+       if (!tmpchar1)<br>
+               return -1;<br>
+       args->mntlist = tmpchar1;<br>
+       args->mntlist[mntindex] = mntparameters;<br>
+       tmpchar2 = realloc(args->mnttype, (mntindex + 1) * sizeof(args->mnttype[0]));<br>
+       if (!tmpchar2)<br>
+               return -1;<br>
+       args->mnttype = tmpchar2;<br>
+       args->mnttype[mntindex] = mnttype;<br>
+       mntindex++;<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static char *generate_random_name(const char *name, const char *path)<br>
+{<br>
+       char testpath[MAXPATHLEN];<br>
+       static char randname[MAXPATHLEN];<br>
+       int ret;<br>
+       int suffix;<br>
+       unsigned int seed;<br>
+<br>
+       do {<br>
+#ifndef HAVE_RAND_R<br>
+               seed = randseed(true);<br>
+#endif<br>
+<br>
+#ifdef HAVE_RAND_R<br>
+               seed = randseed(false);<br>
+               suffix = rand_r(&seed);<br>
+#else<br>
+               suffix = rand();<br>
+#endif<br>
+<br>
+               ret = snprintf(randname, MAXPATHLEN, "%s_%08x", name, suffix);<br>
+               if (ret < 0 || ret >= MAXPATHLEN) {<br>
+                       ERROR("Generating a random name for the clone of %s " "failed", name);<br>
+                       return NULL;<br>
+               }<br>
+<br>
+               ret = snprintf(testpath, MAXPATHLEN, "%s/%s", path, randname);<br>
+               if (ret < 0 || ret >= MAXPATHLEN) {<br>
+                       ERROR("Generating a random name for the clone of %s " "failed", name);<br>
+                       return NULL;<br>
+               }<br>
+       } while (dir_exists(testpath));<br>
+<br>
+       return randname;<br>
+}<br>
+<br>
+/* we pass fssize in bytes */<br>
+static uint64_t get_fssize(char *s)<br>
+{<br>
+       uint64_t ret;<br>
+       char *end;<br>
+<br>
+       ret = strtoull(s, &end, 0);<br>
+       if (end == s) {<br>
+               fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);<br>
+               return 0;<br>
+       }<br>
+       while (isblank(*end))<br>
+               end++;<br>
+       if (*end == '\0') {<br>
+               ret *= 1024ULL * 1024ULL; // MB by default<br>
+       } else if (*end == 'b' || *end == 'B') {<br>
+               ret *= 1ULL;<br>
+       } else if (*end == 'k' || *end == 'K') {<br>
+               ret *= 1024ULL;<br>
+       } else if (*end == 'm' || *end == 'M') {<br>
+               ret *= 1024ULL * 1024ULL;<br>
+       } else if (*end == 'g' || *end == 'G') {<br>
+               ret *= 1024ULL * 1024ULL * 1024ULL;<br>
+       } else if (*end == 't' || *end == 'T') {<br>
+               ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;<br>
+       } else {<br>
+               fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', " "using default size\n", *end, s);<br>
+               return 0;<br>
+       }<br>
+<br>
+       return ret;<br>
+}<br>
+<br>
+static int mkdir_userns_wrapper(void *arg)<br>
+{<br>
+       const char *dir = (const char *)arg;<br>
+       return mkdir_p(dir, 0755);<br>
+}<br>
+<br>
+static int mkdir_wrapper(struct lxc_container *c, char *arg)<br>
+{<br>
+       if (am_unpriv()) {<br>
+               if (userns_exec_1(c->lxc_conf, mkdir_userns_wrapper, (void *)arg) < 0)<br>
+                       return -1;<br>
+               if (chown_mapped_root(arg, c->lxc_conf) < 0)<br>
+                       return -1;<br>
+       } else {<br>
+               if (mkdir_p(arg, 0755) < 0)<br>
+                       return -1;<br>
+       }<br>
+       return 0;<br>
+}<br>
+<br>
+static int parse_mntsubopts(struct lxc_arguments *args, char *subopts,<br>
+                           char *const *keys, char *mntparameters)<br>
+{<br>
+       while (*subopts != '\0') {<br>
+               switch (getsubopt(&subopts, keys, &mntparameters)) {<br>
+               case 0:<br>
+                       if (create_mntlist(args, mntparameters, "bind") < 0)<br>
+                               return -1;<br>
+                       break;<br>
+               case 1:<br>
+                       if (create_mntlist(args, mntparameters, "union") < 0)<br>
+                               return -1;<br>
+                       break;<br>
+               default:<br>
+                       break;<br>
+               }<br>
+       }<br>
+       return 0;<br>
+}<br>
+<br>
+static int set_bind_mount(struct lxc_container *c, char *mntstring)<br>
+{<br>
+       int len = 0;<br>
+       int ret = 0;<br>
+       char *mntentry = NULL;<br>
+       char *options = NULL;<br>
+       char *src = NULL;<br>
+       char *dest = NULL;<br>
+       char **mntarray = NULL;<br>
+<br>
+       mntarray = lxc_string_split(mntstring, ':');<br>
+       if (!mntarray)<br>
+               goto err;<br>
+<br>
+       src = construct_path(mntarray[0], true);<br>
+       if (!src)<br>
+               goto err;<br>
+<br>
+       len = lxc_array_len((void **)mntarray);<br>
+       if (len == 1) { /* bind=src */<br>
+               dest = construct_path(mntarray[0], false);<br>
+       } else if (len == 2) { /* bind=src:option or bind=src:dest */<br>
+               if (strncmp(mntarray[1], "rw", strlen(mntarray[1])) == 0)<br>
+                       options = "rw";<br>
+<br>
+               if (strncmp(mntarray[1], "ro", strlen(mntarray[1])) == 0)<br>
+                       options = "ro";<br>
+<br>
+               if (options)<br>
+                       dest = construct_path(mntarray[0], false);<br>
+               else<br>
+                       dest = construct_path(mntarray[1], false);<br>
+       } else if (len == 3) { /* bind=src:dest:option */<br>
+                       dest = construct_path(mntarray[1], false);<br>
+                       options = mntarray[2];<br>
+       } else {<br>
+               INFO("Excess elements in mount specification");<br>
+               goto err;<br>
+       }<br>
+       if (!dest)<br>
+               goto err;<br>
+<br>
+       if (!options)<br>
+               options = "rw";<br>
+<br>
+       len = strlen(src) + strlen(dest) + strlen(options) +<br>
+             strlen("  none bind,optional,, 0 0") +<br>
+             strlen(is_dir(src) ? "create=dir" : "create=file") + 1;<br>
+       mntentry = malloc(len);<br>
+       if (!mntentry)<br>
+               goto err;<br>
+<br>
+       ret = snprintf(mntentry, MAXPATHLEN,<br>
+                      "%s %s none bind,optional,%s,%s 0 0", src, dest, options,<br>
+                      is_dir(src) ? "create=dir" : "create=file");<br>
+       if (ret < 0 || ret >= MAXPATHLEN)<br>
+               goto err;<br>
+<br>
+       if (!c->set_config_item(c, "lxc.mount.entry", mntentry)) {<br>
+               fprintf(stderr, "Error setting config item\n");<br>
+               goto err;<br>
+       }<br>
+<br>
+       return 0;<br>
+<br>
+err:<br>
+       free(src);<br>
+       free(dest);<br>
+       free(mntentry);<br>
+       lxc_free_array((void **)mntarray, free);<br>
+       return -1;<br>
+}<br>
+<br>
+static int set_union_mount(struct lxc_container *c, char *newpath,<br>
+                          char *mntstring, int index, char *uniontype)<br>
+{<br>
+       int len = 0;<br>
+       int ret = 0;<br>
+       char *mntentry = NULL;<br>
+       char *src = NULL;<br>
+       char *dest = NULL;<br>
+       const char *xinopath = "/dev/shm/aufs.xino";<br>
+       char **mntarray = NULL;<br>
+       char tmpfs[MAXPATHLEN];<br>
+       char upperdir[MAXPATHLEN];<br>
+       char workdir[MAXPATHLEN];<br>
+<br>
+       mntarray = lxc_string_split(mntstring, ':');<br>
+       if (!mntarray)<br>
+               goto err;<br>
+<br>
+       src = construct_path(mntarray[0], true);<br>
+       if (!src)<br>
+               goto err;<br>
+<br>
+       len = lxc_array_len((void **)mntarray);<br>
+       if (len == 1) { /* union=src */<br>
+               dest = construct_path(mntarray[0], false);<br>
+       } else if (len == 2) { /* bind=src:dest */<br>
+               dest = construct_path(mntarray[1], false);<br>
+       } else {<br>
+               INFO("Excess elements in mount specification");<br>
+               goto err;<br>
+       }<br>
+       if (!dest)<br>
+               goto err;<br>
+<br>
+       /* Create tmpfs folder under which we create the delta and workdir<br>
+        * directories */<br>
+       ret = snprintf(tmpfs, MAXPATHLEN, "%s/%s/tmpfs",<br>
+                      newpath ? newpath : my_args.lxcpath[0], c->name);<br>
+       if (ret < 0 || ret >= MAXPATHLEN)<br>
+               goto err;<br>
+<br>
+       if (mkdir_wrapper(c, tmpfs) < 0)<br>
+               goto err;<br>
+<br>
+       /* Create upperdir for both aufs and overlay */<br>
+       ret = snprintf(upperdir, MAXPATHLEN, "%s/%s/tmpfs/delta%d",<br>
+                      newpath ? newpath : my_args.lxcpath[0], c->name, index);<br>
+       if (ret < 0 || ret >= MAXPATHLEN)<br>
+               goto err;<br>
+<br>
+       if (mkdir_wrapper(c, upperdir) < 0)<br>
+               goto err;<br>
+<br>
+       if (strncmp(uniontype, "overlay", 7) == 0) {<br>
+               /* Create workdir */<br>
+               ret = snprintf(workdir, MAXPATHLEN, "%s/%s/tmpfs/workdir%d",<br>
+                              newpath ? newpath : my_args.lxcpath[0], c->name, index);<br>
+               if (ret < 0 || ret >= MAXPATHLEN)<br>
+                       goto err;<br>
+<br>
+               if (mkdir_wrapper(c, workdir) < 0)<br>
+                       goto err;<br>
+<br>
+               len = 2 * strlen(src) + strlen(dest) + strlen(upperdir) +<br>
+                     strlen(workdir) +<br>
+                     strlen("  overlay lowerdir=,upperdir=,workdir=,create=dir") + 1;<br>
+               mntentry = malloc(len);<br>
+               if (!mntentry)<br>
+                       goto err;<br>
+<br>
+               ret = snprintf(mntentry, len, "%s %s overlay lowerdir=%s,upperdir=%s,workdir=%s,create=dir",<br>
+                              src, dest, src, upperdir, workdir);<br>
+               if (ret < 0 || ret >= len)<br>
+                       goto err;<br>
+       } else if (strncmp(uniontype, "aufs", 4) == 0) {<br>
+               len = 2 * strlen(src) + strlen(dest) + strlen(upperdir) +<br>
+                     strlen(xinopath) +<br>
+                     strlen("  aufs br==rw:=ro,xino=,create=dir") + 1;<br>
+<br>
+               mntentry = malloc(len);<br>
+               if (!mntentry)<br>
+                       goto err;<br>
+<br>
+               ret = snprintf(mntentry, len, "%s %s aufs br=%s=rw:%s=ro,xino=%s,create=dir",<br>
+                              src, dest, upperdir, src, xinopath);<br>
+               if (ret < 0 || ret >= len)<br>
+                       goto err;<br>
+       }<br>
+<br>
+       if (!c->set_config_item(c, "lxc.mount.entry", mntentry)) {<br>
+               fprintf(stderr, "Error setting config item\n");<br>
+               goto err;<br>
+       }<br>
+<br>
+       return 0;<br>
+<br>
+err:<br>
+       free(src);<br>
+       free(dest);<br>
+       free(mntentry);<br>
+       lxc_free_array((void **)mntarray, free);<br>
+       return -1;<br>
+}<br>
+<br>
+<br>
--<br>
2.5.3<br>
<br>
</blockquote></div>