]> git.proxmox.com Git - mirror_lxc.git/commitdiff
Refactor lxc-clone
authorChristian Brauner <christianvanbrauner@gmail.com>
Fri, 7 Aug 2015 23:25:41 +0000 (01:25 +0200)
committerChristian Brauner <christianvanbrauner@gmail.com>
Sat, 8 Aug 2015 00:34:56 +0000 (02:34 +0200)
- This commit adapts lxc-clone to be similiar in usage and feel to the other
  lxc-* executables. It builds on the previous extension of the lxc_argument
  struct and now uses the default lxc_arguments_parse() function.
- Options which were not used have been removed.
- The LXC_CLONE_KEEPNAME flag was not respected in the previous version of
  lxc-clone. The culprit is a missing if-condition in lxccontainer.c. As this
  requires a change in one of the API functions in lxccontainer.c it will be
  addressed in a follow-up commit.

Signed-off-by: Christian Brauner <christianvanbrauner@gmail.com>
src/lxc/lxc_clone.c

index e88c18bc3f79ba3e342f200a7992e970578a2934..610e316a0aaf25b29945d51211996004a3a4d599 100644 (file)
 #include <stdlib.h>
 #include <errno.h>
 #include <ctype.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 #include <lxc/lxccontainer.h>
 
 #include "log.h"
-#include "config.h"
+#include "confile.h"
+#include "arguments.h"
 #include "lxc.h"
 #include "conf.h"
 #include "state.h"
 
 lxc_log_define(lxc_clone_ui, lxc);
 
-/* 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 void usage(const char *me)
-{
-       printf("Usage: %s [-s] [-B backingstore] [-L size[unit]] [-K] [-M] [-H]\n", me);
-       printf("          [-p lxcpath] [-P newlxcpath] orig new\n");
-       printf("\n");
-       printf("  -s: snapshot rather than copy\n");
-       printf("  -B: use specified new backingstore.  Default is the same as\n");
-       printf("      the original.  Options include aufs, btrfs, lvm, overlayfs, \n");
-       printf("      dir and loop\n");
-       printf("  -L: for blockdev-backed backingstore, use specified size * specified\n");
-       printf("      unit. Default size is the size of the source blockdev, default\n");
-       printf("      unit is MB\n");
-       printf("  -K: Keep name - do not change the container name\n");
-       printf("  -M: Keep macaddr - do not choose a random new mac address\n");
-       printf("  -p: use container orig from custom lxcpath\n");
-       printf("  -P: create container new in custom lxcpath\n");
-       printf("  -R: rename existing container\n");
-       exit(1);
-}
+static int my_parser(struct lxc_arguments *args, int c, char *arg);
 
-static struct option options[] = {
+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'},
        { "backingstore", required_argument, 0, 'B'},
-       { "size", required_argument, 0, 'L'},
-       { "orig", required_argument, 0, 'o'},
-       { "new", required_argument, 0, 'n'},
-       { "vgname", required_argument, 0, 'v'},
-       { "rename", no_argument, 0, 'R'},
+       { "fssize", required_argument, 0, 'L'},
        { "keepname", no_argument, 0, 'K'},
        { "keepmac", no_argument, 0, 'M'},
-       { "lxcpath", required_argument, 0, 'p'},
-       { "newpath", required_argument, 0, 'P'},
-       { "fstype", required_argument, 0, 't'},
-       { "help", no_argument, 0, 'h'},
-       { 0, 0, 0, 0 },
+       LXC_COMMON_OPTIONS
 };
 
+static struct lxc_arguments my_args = {
+       .progname = "lxc-clone",
+       .help = "\
+--name=NAME [-P lxcpath] -N newname [-p newpath] [-B backingstorage] [-s] [-K] [-M] [-L size [unit]]\n\
+\n\
+lxc-lcone 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\
+  -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,
+       .checker = NULL,
+};
+
+static int do_clone(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 uint64_t get_fssize(char *s);
+
 int main(int argc, char *argv[])
 {
-       struct lxc_container *c1 = NULL, *c2 = NULL;
-       int snapshot = 0, keepname = 0, keepmac = 0, rename = 0;
-       int flags = 0, option_index;
-       uint64_t newsize = 0;
-       char *bdevtype = NULL, *lxcpath = NULL, *newpath = NULL, *fstype = NULL;
-       char *orig = NULL, *new = NULL, *vgname = NULL;
-       char **args = NULL;
-       int c;
-       bool ret;
+       struct lxc_container *c;
+       int flags = 0;
+       int ret;
 
-       if (argc < 3)
-               usage(argv[0]);
-
-       while (1) {
-               c = getopt_long(argc, argv, "sB:L:o:n:v:KMHp:P:Rt:h", options, &option_index);
-               if (c == -1)
-                       break;
-               switch (c) {
-               case 's': snapshot = 1; break;
-               case 'B': bdevtype = optarg; break;
-               case 'L': newsize = get_fssize(optarg); break;
-               case 'o': orig = optarg; break;
-               case 'n': new = optarg; break;
-               case 'v': vgname = optarg; break;
-               case 'K': keepname = 1; break;
-               case 'M': keepmac = 1; break;
-               case 'p': lxcpath = optarg; break;
-               case 'P': newpath = optarg; break;
-               case 'R': rename = 1; break;
-               case 't': fstype = optarg; break;
-               case 'h': usage(argv[0]);
-               default: break;
-               }
-       }
-    if (optind < argc && !orig)
-               orig = argv[optind++];
-    if (optind < argc && !new)
-               new = argv[optind++];
-       if (optind < argc)
-               /* arguments for the clone hook */
-               args = &argv[optind];
-       if (!new || !orig) {
-               printf("Error: you must provide orig and new names\n");
-               usage(argv[0]);
-       }
+       if (lxc_arguments_parse(&my_args, argc, argv))
+               exit(EXIT_FAILURE);
+
+       if (!my_args.log_file)
+               my_args.log_file = "none";
 
-       if (snapshot)  flags |= LXC_CLONE_SNAPSHOT;
-       if (keepname)  flags |= LXC_CLONE_KEEPNAME;
-       if (keepmac)   flags |= LXC_CLONE_KEEPMACADDR;
+       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();
 
-       // vgname and fstype could be supported by sending them through the
-       // bdevdata.  However, they currently are not yet.  I'm not convinced
-       // they are worthwhile.
-       if (vgname) {
-               printf("Error: vgname not supported\n");
-               usage(argv[0]);
+       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 (fstype) {
-               printf("Error: fstype not supported\n");
-               usage(argv[0]);
+
+       if (!my_args.newname) {
+               printf("Error: You must provide a NEWNAME for the clone.\n");
+               exit(EXIT_FAILURE);
        }
 
-       c1 = lxc_container_new(orig, lxcpath);
-       if (!c1)
+       if (my_args.task == SNAP)
+               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 (!c1->may_control(c1)) {
-               fprintf(stderr, "Insufficent privileges to control %s\n", orig);
-               lxc_container_put(c1);
+       if (!c->may_control(c)) {
+               fprintf(stderr, "Insufficent privileges to control %s\n",
+                       c->name);
+               lxc_container_put(c);
                exit(EXIT_FAILURE);
        }
 
-       if (!c1->is_defined(c1)) {
-               fprintf(stderr, "Error: container %s is not defined\n", orig);
-               lxc_container_put(c1);
+       if (!c->is_defined(c)) {
+               fprintf(stderr, "Error: container %s is not defined\n",
+                       c->name);
+               lxc_container_put(c);
                exit(EXIT_FAILURE);
        }
-       if (rename) {
-               ret = c1->rename(c1, new);
-               if (!ret) {
-                       fprintf(stderr,
-                               "Error: Renaming container %s to %s failed\n",
-                               c1->name, new);
-                       lxc_container_put(c1);
-                       exit(EXIT_FAILURE);
-               }
+
+       if (my_args.task == RENAME) {
+               ret = do_clone_rename(c, my_args.newname);
        } else {
-               c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize,
-                              args);
-               if (c2 == NULL) {
-                       lxc_container_put(c1);
-                       fprintf(stderr, "clone failed\n");
-                       exit(EXIT_FAILURE);
-               }
-               printf("Created container %s as %s of %s\n", new,
-                      snapshot ? "snapshot" : "copy", orig);
-               lxc_container_put(c2);
+               ret = do_clone(c, my_args.newname, my_args.newpath, flags,
+                              my_args.bdevtype, my_args.fssize, &argv[optind]);
        }
-       lxc_container_put(c1);
 
-       exit(EXIT_SUCCESS);
+       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)
+{
+       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 'B':
+               args->bdevtype = arg;
+               break;
+       case 'L':
+               args->fssize = get_fssize(optarg);
+               break;
+       case 'K':
+               args->keepname = 1;
+               break;
+       case 'M':
+               args->keepmac = 1;
+               break;
+       }
+
+       return 0;
+}
+
+static int do_clone_rename(struct lxc_container *c, char *newname)
+{
+       bool ret;
+
+       ret = c->rename(c, newname);
+       if (!ret) {
+               ERROR("Error: Renaming container %s to %s failed\n", c->name,
+                     my_args.newname);
+               return -1;
+       }
+
+       INFO("Renamed container %s to %s\n", c->name, newname);
+
+       return 0;
+}
+
+static int do_clone(struct lxc_container *c, char *newname, char *newpath,
+                   int flags, char *bdevtype, uint64_t fssize, char **args)
+{
+       struct lxc_container *clone;
+
+       clone = c->clone(c, newname, newpath, flags, bdevtype, NULL, fssize,
+                        args);
+       if (clone == NULL) {
+               fprintf(stderr, "clone failed\n");
+               return -1;
+       }
+
+       INFO("Created container %s as %s of %s\n", newname,
+            my_args.task ? "snapshot" : "copy", c->name);
+
+       lxc_container_put(clone);
+
+       return 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) {
+               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;
+}
+