[lxc-devel] [PATCH] Add lxc-copy executable lxc-copy merges lxc-clone + lxc-start-ephemeral into one (Christian Brauner)

Christian Brauner christianvanbrauner at gmail.com
Mon Sep 28 20:05:13 UTC 2015


Note that I've already sent an updated patch for review ([lxc-devel] [PATCH] Add
lxc-copy executable (v2)). You should disregard this one.

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


> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20150928/7651a238/attachment-0001.sig>


More information about the lxc-devel mailing list