]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/tools/lxc_copy.c
added allowrunning command line option for snapshotting alive containers
[mirror_lxc.git] / src / lxc / tools / lxc_copy.c
index 1718f84a748b5c25363a89b726ecb2feb599382d..5a94de452ea230975096ee58b5cecccf08289b2a 100644 (file)
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#define _GNU_SOURCE
-#include "config.h"
-
-#include <unistd.h>
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
 #include <signal.h>
-#include <stdio.h>
-#include <sys/types.h>
+#include <stdbool.h>
 #include <stdint.h>
-#include <sys/wait.h>
+#include <stdio.h>
 #include <stdlib.h>
-#include <errno.h>
-#include <ctype.h>
+#include <string.h>
 #include <sys/stat.h>
-#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <time.h>
-#include <stdbool.h>
+#include <unistd.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 "storage.h"
+#include "config.h"
+#include "log.h"
+#include "storage_utils.h"
 #include "utils.h"
 
 #ifndef HAVE_GETSUBOPT
-#include <../include/getsubopt.h>
+#include "include/getsubopt.h"
 #endif
 
+lxc_log_define(lxc_copy, lxc);
+
 enum mnttype {
        LXC_MNT_BIND,
-       LXC_MNT_AUFS,
        LXC_MNT_OVL,
 };
 
@@ -76,6 +73,7 @@ static const struct option my_longopts[] = {
        { "newpath", required_argument, 0, 'p'},
        { "rename", no_argument, 0, 'R'},
        { "snapshot", no_argument, 0, 's'},
+       { "allowrunning", no_argument, 0, 'a'},
        { "foreground", no_argument, 0, 'F'},
        { "daemon", no_argument, 0, 'd'},
        { "ephemeral", no_argument, 0, 'e'},
@@ -92,7 +90,6 @@ static const struct option my_longopts[] = {
 /* mount keys */
 static char *const keys[] = {
        [LXC_MNT_BIND] = "bind",
-       [LXC_MNT_AUFS] = "aufs",
        [LXC_MNT_OVL] = "overlay",
        NULL
 };
@@ -101,7 +98,7 @@ static struct lxc_arguments my_args = {
        .progname = "lxc-copy",
        .help = "\n\
 --name=NAME [-P lxcpath] -N newname [-p newpath] [-B backingstorage] [-s] [-K] [-M] [-L size [unit]] -- hook options\n\
---name=NAME [-P lxcpath] [-N newname] [-p newpath] [-B backingstorage] -e [-d] [-D] [-K] [-M] [-m {bind,aufs,overlay}=/src:/dest] -- hook options\n\
+--name=NAME [-P lxcpath] [-N newname] [-p newpath] [-B backingstorage] -e [-d] [-D] [-K] [-M] [-m {bind,overlay}=/src:/dest] -- hook options\n\
 --name=NAME [-P lxcpath] -N newname -R\n\
 \n\
 lxc-copy clone a container\n\
@@ -112,11 +109,12 @@ Options :\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\
+  -a, --allowrunning        allow snapshot creation even if source container is running\n\
   -F, --foreground          start with current tty attached to /dev/console\n\
   -d, --daemon              daemonize the container (default)\n\
   -e, --ephemeral           start ephemeral container\n\
   -m, --mount               directory to mount into container, either \n\
-                            {bind,aufs,overlay}=/src-path or {bind,aufs,overlay}=/src-path:/dst-path\n\
+                            {bind,overlay}=/src-path or {bind,overlay}=/src-path:/dst-path\n\
   -B, --backingstorage=TYPE backingstorage type for the container\n\
   -t, --tmpfs               place ephemeral container on a tmpfs\n\
                             (WARNING: On reboot all changes made to the container will be lost.)\n\
@@ -150,17 +148,15 @@ 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 void free_mnts(void);
-static uint64_t get_fssize(char *s);
 
 /* Place an ephemeral container started with -e flag on a tmpfs. Restrictions
  * are that you cannot request the data to be kept while placing the container
- * on a tmpfs and that either overlay or aufs backing storage must be used.
+ * on a tmpfs and that either overlay storage driver must be used.
  */
 static char *mount_tmpfs(const char *oldname, const char *newname,
                         const char *path, struct lxc_arguments *arg);
 static int parse_mntsubopts(char *subopts, char *const *keys,
                            char *mntparameters);
-static int parse_aufs_mnt(char *mntstring, enum mnttype type);
 static int parse_bind_mnt(char *mntstring, enum mnttype type);
 static int parse_ovl_mnt(char *mntstring, enum mnttype type);
 
@@ -174,41 +170,38 @@ int main(int argc, char *argv[])
        if (lxc_arguments_parse(&my_args, argc, argv))
                exit(ret);
 
-       if (!my_args.log_file)
-               my_args.log_file = "none";
+       /* Only create log if explicitly instructed */
+       if (my_args.log_file || my_args.log_priority) {
+               log.name = my_args.name;
+               log.file = my_args.log_file;
+               log.level = my_args.log_priority;
+               log.prefix = my_args.progname;
+               log.quiet = my_args.quiet;
+               log.lxcpath = my_args.lxcpath[0];
 
-       log.name = my_args.name;
-       log.file = my_args.log_file;
-       log.level = my_args.log_priority;
-       log.prefix = my_args.progname;
-       log.quiet = my_args.quiet;
-       log.lxcpath = my_args.lxcpath[0];
-
-       if (lxc_log_init(&log))
-               exit(ret);
-       lxc_log_options_no_override();
-
-       /* REMOVE IN LXC 3.0 */
-       setenv("LXC_UPDATE_CONFIG_FORMAT", "1", 0);
+               if (lxc_log_init(&log))
+                       exit(ret);
+       }
 
        if (geteuid()) {
                if (access(my_args.lxcpath[0], O_RDONLY) < 0) {
-                       if (!my_args.quiet)
-                               fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
+                       ERROR("You lack access to %s", my_args.lxcpath[0]);
                        exit(ret);
                }
        }
 
        if (!my_args.newname && !(my_args.task == DESTROY)) {
-               if (!my_args.quiet)
-                       printf("Error: You must provide a NEWNAME for the clone.\n");
+               ERROR("You must provide a NEWNAME for the clone");
                exit(ret);
        }
 
        if (my_args.task == SNAP || my_args.task == DESTROY)
                flags |= LXC_CLONE_SNAPSHOT;
+       if (my_args.allowrunning)
+               flags |= LXC_CLONE_ALLOW_RUNNING;
        if (my_args.keepname)
                flags |= LXC_CLONE_KEEPNAME;
+
        if (my_args.keepmac)
                flags |= LXC_CLONE_KEEPMACADDR;
 
@@ -221,26 +214,26 @@ int main(int argc, char *argv[])
 
        if (my_args.rcfile) {
                c->clear_config(c);
+
                if (!c->load_config(c, my_args.rcfile)) {
-                       fprintf(stderr, "Failed to load rcfile\n");
+                       ERROR("Failed to load rcfile");
                        goto out;
                }
+
                c->configfile = strdup(my_args.rcfile);
                if (!c->configfile) {
-                       fprintf(stderr, "Out of memory setting new config filename\n");
+                       ERROR("Out of memory setting new config filename");
                        goto out;
                }
        }
 
        if (!c->may_control(c)) {
-               if (!my_args.quiet)
-                       fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
+               ERROR("Insufficent privileges to control %s", c->name);
                goto out;
        }
 
        if (!c->is_defined(c)) {
-               if (!my_args.quiet)
-                       fprintf(stderr, "Error: container %s is not defined\n", c->name);
+               ERROR("Container %s is not defined", c->name);
                goto out;
        }
 
@@ -273,32 +266,36 @@ static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num, enum mnttype
 
 static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_arguments *arg)
 {
-       char upperdir[MAXPATHLEN];
-       char workdir[MAXPATHLEN];
+       char upperdir[PATH_MAX];
+       char workdir[PATH_MAX];
        unsigned int i;
        int ret;
        struct mnts *m = NULL;
 
        for (i = 0, m = mnts; i < num; i++, m++) {
-               if ((m->mnt_type == LXC_MNT_OVL) || (m->mnt_type == LXC_MNT_AUFS)) {
-                       ret = snprintf(upperdir, MAXPATHLEN, "%s/%s/delta#XXXXXX",
+               if (m->mnt_type == LXC_MNT_OVL) {
+                       ret = snprintf(upperdir, PATH_MAX, "%s/%s/delta#XXXXXX",
                                        arg->newpath, arg->newname);
-                       if (ret < 0 || ret >= MAXPATHLEN)
+                       if (ret < 0 || ret >= PATH_MAX)
                                return -1;
+
                        if (!mkdtemp(upperdir))
                                return -1;
+
                        m->upper = strdup(upperdir);
                        if (!m->upper)
                                return -1;
                }
 
                if (m->mnt_type == LXC_MNT_OVL) {
-                       ret = snprintf(workdir, MAXPATHLEN, "%s/%s/work#XXXXXX",
+                       ret = snprintf(workdir, PATH_MAX, "%s/%s/work#XXXXXX",
                                        arg->newpath, arg->newname);
-                       if (ret < 0 || ret >= MAXPATHLEN)
+                       if (ret < 0 || ret >= PATH_MAX)
                                return -1;
+
                        if (!mkdtemp(workdir))
                                return -1;
+
                        m->workdir = strdup(workdir);
                        if (!m->workdir)
                                return -1;
@@ -329,20 +326,7 @@ static char *set_mnt_entry(struct mnts *m)
        int ret = 0;
        size_t len = 0;
 
-       if (m->mnt_type == LXC_MNT_AUFS) {
-               len = strlen("  aufs br==rw:=ro,xino=,create=dir") +
-                     2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
-                     strlen(m->workdir) + 1;
-
-               mntentry = malloc(len);
-               if (!mntentry)
-                       goto err;
-
-               ret = snprintf(mntentry, len, "%s %s aufs br=%s=rw:%s=ro,xino=%s,create=dir",
-                              m->src, m->dest, m->upper, m->src, m->workdir);
-               if (ret < 0 || (size_t)ret >= len)
-                       goto err;
-       } else if (m->mnt_type == LXC_MNT_OVL) {
+       if (m->mnt_type == LXC_MNT_OVL) {
                len = strlen("  overlay lowerdir=,upperdir=,workdir=,create=dir") +
                      2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
                      strlen(m->workdir) + 1;
@@ -387,8 +371,7 @@ static int do_clone(struct lxc_container *c, char *newname, char *newpath,
        clone = c->clone(c, newname, newpath, flags, bdevtype, NULL, fssize,
                         args);
        if (!clone) {
-               if (!my_args.quiet)
-                       fprintf(stderr, "clone failed\n");
+               ERROR("Failed to clone");
                return -1;
        }
 
@@ -400,26 +383,29 @@ static int do_clone(struct lxc_container *c, char *newname, char *newpath,
 static int do_clone_ephemeral(struct lxc_container *c,
                struct lxc_arguments *arg, char **args, int flags)
 {
-       char *bdev;
        char *premount;
-       char randname[MAXPATHLEN];
+       char randname[PATH_MAX];
        unsigned int i;
        int ret = 0;
        bool bret = true, started = false;
+       char *tmp_buf = randname;
        struct lxc_container *clone;
        lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
        attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
 
        if (!arg->newname) {
-               ret = snprintf(randname, MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name);
-               if (ret < 0 || ret >= MAXPATHLEN)
+               ret = snprintf(randname, PATH_MAX, "%s/%s_XXXXXX", arg->newpath, arg->name);
+               if (ret < 0 || ret >= PATH_MAX)
                        return -1;
+
                if (!mkdtemp(randname))
                        return -1;
+
                if (chmod(randname, 0770) < 0) {
                        (void)remove(randname);
                        return -1;
                }
+
                arg->newname = randname + strlen(arg->newpath) + 1;
        }
 
@@ -429,12 +415,6 @@ static int do_clone_ephemeral(struct lxc_container *c,
                return -1;
 
        if (arg->tmpfs) {
-               bdev = c->lxc_conf->rootfs.bdev_type;
-               if (bdev && strcmp(bdev, "dir")) {
-                       fprintf(stderr, "Cannot currently use tmpfs with %s storage backend.\n", bdev);
-                       goto destroy_and_put;
-               }
-
                premount = mount_tmpfs(arg->name, arg->newname, arg->newpath, arg);
                if (!premount)
                        goto destroy_and_put;
@@ -457,9 +437,11 @@ static int do_clone_ephemeral(struct lxc_container *c,
        struct mnts *n = NULL;
        for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
                char *mntentry = NULL;
+
                mntentry = set_mnt_entry(n);
                if (!mntentry)
                        goto destroy_and_put;
+
                bret = clone->set_config_item(clone, "lxc.mount.entry", mntentry);
                free(mntentry);
                if (!bret)
@@ -501,8 +483,11 @@ static int do_clone_ephemeral(struct lxc_container *c,
 destroy_and_put:
        if (started)
                clone->shutdown(clone, -1);
-       if (!started || clone->lxc_conf->ephemeral != 1)
+
+       ret = clone->get_config_item(clone, "lxc.ephemeral", tmp_buf, PATH_MAX);
+       if (ret > 0 && strcmp(tmp_buf, "0"))
                clone->destroy(clone);
+
        free_mnts();
        lxc_container_put(clone);
        return -1;
@@ -511,7 +496,7 @@ destroy_and_put:
 static int do_clone_rename(struct lxc_container *c, char *newname)
 {
        if (!c->rename(c, newname)) {
-               fprintf(stderr, "Error: Renaming container %s to %s failed\n", c->name, newname);
+               ERROR("Renaming container %s to %s failed", c->name, newname);
                return -1;
        }
 
@@ -552,46 +537,12 @@ static void free_mnts()
                free(n->upper);
                free(n->workdir);
        }
+
        free(mnt_table);
        mnt_table = NULL;
        mnt_table_size = 0;
 }
 
-/* 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) {
-               if (!my_args.quiet)
-                       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 {
-               if (!my_args.quiet)
-                       fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', " "using default size\n", *end, s);
-               return 0;
-       }
-
-       return ret;
-}
-
 static int my_parser(struct lxc_arguments *args, int c, char *arg)
 {
        char *subopts = NULL;
@@ -609,6 +560,9 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
        case 's':
                args->task = SNAP;
                break;
+       case 'a':
+               args->allowrunning = 1;
+               break;
        case 'F':
                args->daemonize = 0;
                break;
@@ -624,7 +578,7 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
                        return -1;
                break;
        case 'B':
-               if (strcmp(arg, "overlay") == 0)
+               if (strncmp(arg, "overlay", strlen(arg)) == 0)
                        arg = "overlayfs";
                args->bdevtype = arg;
                break;
@@ -648,49 +602,6 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
        return 0;
 }
 
-static int parse_aufs_mnt(char *mntstring, enum mnttype type)
-{
-       int len = 0;
-       const char *xinopath = "/dev/shm/aufs.xino";
-       char **mntarray = NULL;
-       struct mnts *m = NULL;
-
-       m = add_mnt(&mnt_table, &mnt_table_size, type);
-       if (!m)
-               goto err;
-
-       mntarray = lxc_string_split(mntstring, ':');
-       if (!mntarray)
-               goto err;
-
-       m->src = construct_path(mntarray[0], true);
-       if (!m->src)
-               goto err;
-
-       len = lxc_array_len((void **)mntarray);
-       if (len == 1) /* aufs=src */
-               m->dest = construct_path(mntarray[0], false);
-       else if (len == 2) /* aufs=src:dest */
-               m->dest = construct_path(mntarray[1], false);
-       else
-               printf("Excess elements in mount specification\n");
-
-       if (!m->dest)
-               goto err;
-
-       m->workdir = strdup(xinopath);
-       if (!m->workdir)
-               goto err;
-
-       lxc_free_array((void **)mntarray, free);
-       return 0;
-
-err:
-       free_mnts();
-       lxc_free_array((void **)mntarray, free);
-       return -1;
-}
-
 static int parse_bind_mnt(char *mntstring, enum mnttype type)
 {
        int len = 0;
@@ -736,8 +647,8 @@ static int parse_bind_mnt(char *mntstring, enum mnttype type)
        if (!m->options)
                m->options = strdup("rw");
 
-       if (!m->options || (strncmp(m->options, "rw", strlen(m->options)) &&
-                           strncmp(m->options, "ro", strlen(m->options))))
+       if (!m->options || (strncmp(m->options, "rw", strlen(m->options)) != 0 &&
+                           strncmp(m->options, "ro", strlen(m->options)) != 0))
                goto err;
 
        lxc_free_array((void **)mntarray, free);
@@ -761,14 +672,11 @@ static int parse_mntsubopts(char *subopts, char *const *keys, char *mntparameter
                        if (parse_ovl_mnt(mntparameters, LXC_MNT_OVL) < 0)
                                return -1;
                        break;
-               case LXC_MNT_AUFS:
-                       if (parse_aufs_mnt(mntparameters, LXC_MNT_AUFS) < 0)
-                               return -1;
-                       break;
                default:
                        break;
                }
        }
+
        return 0;
 }
 
@@ -810,7 +718,7 @@ err:
        return -1;
 }
 
-/* For ephemeral snapshots backed by overlay or aufs filesystems, this function
+/* For ephemeral snapshots backed by the overlay filesystem, this function
  * mounts a fresh tmpfs over the containers directory if the user requests it.
  * Because we mount a fresh tmpfs over the directory of the container the
  * updated /etc/hostname file created during the clone residing in the upperdir
@@ -824,22 +732,24 @@ static char *mount_tmpfs(const char *oldname, const char *newname,
 {
        int ret, fd;
        size_t len;
+       mode_t msk;
        char *premount = NULL;
-       FILE *fp;
+       FILE *fp = NULL;
 
        if (arg->tmpfs && arg->keepdata) {
-               fprintf(stderr, "%s\n", "A container can only be placed on a "
-                                       "tmpfs when storage backend is overlay "
-                                       "or aufs.");
+               ERROR("%s",
+                     "A container can only be placed on a tmpfs when the "
+                     "overlay storage driver is used");
                goto err_free;
        }
 
        if (arg->tmpfs && !arg->bdevtype) {
                arg->bdevtype = "overlayfs";
-       } else if (arg->tmpfs && arg->bdevtype && strcmp(arg->bdevtype, "overlayfs") && strcmp(arg->bdevtype, "aufs")) {
-               fprintf(stderr, "%s\n", "A container can only be placed on a "
-                                       "tmpfs when storage backend is overlay "
-                                       "or aufs.");
+       } else if (arg->tmpfs && arg->bdevtype &&
+                  strncmp(arg->bdevtype, "overlayfs", strlen(arg->bdevtype)) != 0) {
+               ERROR("%s",
+                     "A container can only be placed on a tmpfs when the "
+                     "overlay storage driver is used");
                goto err_free;
        }
 
@@ -852,12 +762,14 @@ static char *mount_tmpfs(const char *oldname, const char *newname,
        if (ret < 0 || (size_t)ret >= len)
                goto err_free;
 
+       msk = umask(0022);
        fd = mkstemp(premount);
+       umask(msk);
        if (fd < 0)
                goto err_free;
 
        if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
-               fprintf(stderr, "Failed to set close-on-exec on file descriptor.\n");
+               ERROR("Failed to set close-on-exec on file descriptor");
                goto err_close;
        }
 
@@ -889,8 +801,9 @@ static char *mount_tmpfs(const char *oldname, const char *newname,
 err_close:
        if (fd > 0)
                close(fd);
-       else
+       else if (fp)
                fclose(fp);
+
 err_free:
        free(premount);
        return NULL;