From 5d5da49be4dc5603c56042bf6f4393151e27c321 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Thu, 6 Aug 2015 14:54:25 +0200 Subject: [PATCH 1/5] Refactor lxc-snapshot - lxc_snapshot.c lacked necessary members in the associated lxc_arguments struct in arguments.h. This commit extends the lxc_arguments struct to include several parameters used by lxc-snapshot which allows a rewrite that is more consistent with the rest of the lxc-* executables. - All tests have been moved beyond the call to lxc_log_init() to allow for the messages to be printed or saved. - Some small changes to the my_args struct. (The enum task is set to SNAP (for snapshot) per default and variables illustrating the usage of the command line flags are written in all caps.) - arguments.h has been extended to accommodate a rewrite of lxc-clone Signed-off-by: Christian Brauner --- src/lxc/arguments.h | 16 ++ src/lxc/lxc_snapshot.c | 329 +++++++++++++++++++++++------------------ 2 files changed, 199 insertions(+), 146 deletions(-) diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h index cc85f863f..30aa06a21 100644 --- a/src/lxc/arguments.h +++ b/src/lxc/arguments.h @@ -94,6 +94,22 @@ struct lxc_arguments { int list; char *groups; + /* lxc-snapshot and lxc-clone */ + enum task { + DESTROY, + LIST, + RESTORE, + SNAP, + RENAME, + } task; + int print_comments; + char *commentfile; + char *newname; + char *newpath; + char *snapname; + int keepname; + int keepmac; + /* remaining arguments */ char *const *argv; int argc; diff --git a/src/lxc/lxc_snapshot.c b/src/lxc/lxc_snapshot.c index a03c0c09b..9ffbeb4dd 100644 --- a/src/lxc/lxc_snapshot.c +++ b/src/lxc/lxc_snapshot.c @@ -16,8 +16,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "config.h" +#include "confile.h" #include #include #include @@ -35,18 +35,149 @@ lxc_log_define(lxc_snapshot_ui, lxc); -static char *newname; -static char *snapshot; +static int my_parser(struct lxc_arguments *args, int c, char *arg); -#define DO_SNAP 0 -#define DO_LIST 1 -#define DO_RESTORE 2 -#define DO_DESTROY 3 -static int action; -static int print_comments; -static char *commentfile; +static const struct option my_longopts[] = { + {"list", no_argument, 0, 'L'}, + {"restore", required_argument, 0, 'r'}, + {"newname", required_argument, 0, 'N'}, + {"destroy", required_argument, 0, 'd'}, + {"comment", required_argument, 0, 'c'}, + {"showcomments", no_argument, 0, 'C'}, + LXC_COMMON_OPTIONS +}; -static int do_snapshot(struct lxc_container *c) +static struct lxc_arguments my_args = { + .progname = "lxc-snapshot", + .help = "\ +--name=NAME [-P lxcpath] [-L [-C]] [-c commentfile] [-r snapname [-N newname]]\n\ +\n\ +lxc-snapshot snapshots a container\n\ +\n\ +Options :\n\ + -n, --name=NAME NAME of the container\n\ + -L, --list list all snapshots\n\ + -r, --restore=NAME restore snapshot NAME, e.g. 'snap0'\n\ + -N, --newname=NEWNAME NEWNAME for the restored container\n\ + -d, --destroy=NAME destroy snapshot NAME, e.g. 'snap0'\n\ + use ALL to destroy all snapshots\n\ + -c, --comment=FILE add FILE as a comment\n\ + -C, --showcomments show snapshot comments\n", + .options = my_longopts, + .parser = my_parser, + .checker = NULL, + .task = SNAP, +}; + +static int do_destroy_snapshots(struct lxc_container *c, char *snapname); +static int do_list_snapshots(struct lxc_container *c, int print_comments); +static int do_restore_snapshots(struct lxc_container *c, char *snapname, + char *newname); +static int do_snapshot(struct lxc_container *c, char *commentfile); +static int do_snapshot_task(struct lxc_container *c, enum task task); +static void print_file(char *path); + +int main(int argc, char *argv[]) +{ + struct lxc_container *c; + 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); + } + } + + c = lxc_container_new(my_args.name, my_args.lxcpath[0]); + if (!c) { + fprintf(stderr, "System error loading container\n"); + exit(EXIT_FAILURE); + } + + if (!c->may_control(c)) { + fprintf(stderr, "Insufficent privileges to control %s\n", + my_args.name); + lxc_container_put(c); + exit(EXIT_FAILURE); + } + + ret = do_snapshot_task(c, my_args.task); + + lxc_container_put(c); + + if (ret == 0) + exit(EXIT_SUCCESS); + exit(EXIT_FAILURE); +} + +static int do_snapshot_task(struct lxc_container *c, enum task task) +{ + int ret = 0; + + switch (task) { + case DESTROY: + ret = do_destroy_snapshots(c, my_args.snapname); + break; + case LIST: + ret = do_list_snapshots(c, my_args.print_comments); + break; + case RESTORE: + ret = + do_restore_snapshots(c, my_args.snapname, my_args.newname); + break; + case SNAP: + ret = do_snapshot(c, my_args.commentfile); + break; + default: + ret = 0; + break; + } + + return ret; +} + +static int my_parser(struct lxc_arguments *args, int c, char *arg) +{ + switch (c) { + case 'L': + args->task = LIST; + break; + case 'r': + args->task = RESTORE; + args->snapname = arg; + break; + case 'N': + args->newname = arg; + break; + case 'd': + args->task = DESTROY; + args->snapname = arg; + break; + case 'c': + args->commentfile = arg; + break; + case 'C': + args->print_comments = 1; + break; + } + + return 0; +} + +static int do_snapshot(struct lxc_container *c, char *commentfile) { int ret; @@ -57,26 +188,11 @@ static int do_snapshot(struct lxc_container *c) } INFO("Created snapshot snap%d", ret); + return 0; } -static void print_file(char *path) -{ - if (!path) - return; - FILE *f = fopen(path, "r"); - char *line = NULL; - size_t sz = 0; - if (!f) - return; - while (getline(&line, &sz, f) != -1) { - printf("%s", line); - } - free(line); - fclose(f); -} - -static int do_list_snapshots(struct lxc_container *c) +static int do_list_snapshots(struct lxc_container *c, int print_comments) { struct lxc_snapshot *s; int i, n; @@ -90,148 +206,69 @@ static int do_list_snapshots(struct lxc_container *c) printf("No snapshots\n"); return 0; } - for (i=0; isnapshot_restore(c, snapshot, newname)) + if (!newname) { + printf("Error: You must provide a NEWNAME for the container\n"); + return -1; + } + + if (c->snapshot_restore(c, snapname, newname)) return 0; - ERROR("Error restoring snapshot %s", snapshot); + ERROR("Error restoring snapshot %s", snapname); + return -1; } -static int do_destroy_snapshots(struct lxc_container *c) +static int do_destroy_snapshots(struct lxc_container *c, char *snapname) { - bool bret; - if (strcmp(snapshot, "ALL") == 0) - bret = c->snapshot_destroy_all(c); + bool ret; + + if (strcmp(snapname, "ALL") == 0) + ret = c->snapshot_destroy_all(c); else - bret = c->snapshot_destroy(c, snapshot); + ret = c->snapshot_destroy(c, snapname); - if (bret) + if (ret) return 0; - ERROR("Error destroying snapshot %s", snapshot); + ERROR("Error destroying snapshot %s", snapname); + return -1; } -static int my_parser(struct lxc_arguments* args, int c, char* arg) +static void print_file(char *path) { - switch (c) { - case 'L': action = DO_LIST; break; - case 'r': snapshot = arg; action = DO_RESTORE; break; - case 'd': snapshot = arg; action = DO_DESTROY; break; - case 'c': commentfile = arg; break; - case 'C': print_comments = true; break; + if (!path) + return; + + FILE *f = fopen(path, "r"); + char *line = NULL; + size_t sz = 0; + + if (!f) + return; + + while (getline(&line, &sz, f) != -1) { + printf("%s", line); } - return 0; + + free(line); + fclose(f); } -static const struct option my_longopts[] = { - {"list", no_argument, 0, 'L'}, - {"restore", required_argument, 0, 'r'}, - {"destroy", required_argument, 0, 'd'}, - {"comment", required_argument, 0, 'c'}, - {"showcomments", no_argument, 0, 'C'}, - LXC_COMMON_OPTIONS -}; - - -static struct lxc_arguments my_args = { - .progname = "lxc-snapshot", - .help = "\ ---name=NAME [-P lxcpath] [-L [-C]] [-c commentfile] [-r snapname [newname]]\n\ -\n\ -lxc-snapshot snapshots a container\n\ -\n\ -Options :\n\ - -n, --name=NAME NAME for name of the container\n\ - -L, --list list snapshots\n\ - -C, --showcomments show snapshot comments in list\n\ - -c, --comment=file add file as a comment\n\ - -r, --restore=name restore snapshot name, i.e. 'snap0'\n\ - -d, --destroy=name destroy snapshot name, i.e. 'snap0'\n\ - use ALL to destroy all snapshots\n", - .options = my_longopts, - .parser = my_parser, - .checker = NULL, -}; - -/* - * lxc-snapshot -P lxcpath -n container - * lxc-snapshot -P lxcpath -n container -l - * lxc-snapshot -P lxcpath -n container -r snap3 recovered_1 - */ - -int main(int argc, char *argv[]) -{ - struct lxc_container *c; - int ret = 0; - - if (lxc_arguments_parse(&my_args, argc, argv)) - exit(1); - - if (!my_args.log_file) - my_args.log_file = "none"; - - if (my_args.argc > 1) { - ERROR("Too many arguments"); - exit(1); - } - if (my_args.argc == 1) - newname = my_args.argv[0]; - - 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(1); - 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(1); - } - } - - c = lxc_container_new(my_args.name, my_args.lxcpath[0]); - if (!c) { - fprintf(stderr, "System error loading container\n"); - exit(1); - } - - if (!c->may_control(c)) { - fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name); - lxc_container_put(c); - exit(1); - } - - switch(action) { - case DO_SNAP: - ret = do_snapshot(c); - break; - case DO_LIST: - ret = do_list_snapshots(c); - break; - case DO_RESTORE: - ret = do_restore_snapshots(c); - break; - case DO_DESTROY: - ret = do_destroy_snapshots(c); - break; - } - - lxc_container_put(c); - - if (ret == 0) - exit(EXIT_SUCCESS); - exit(EXIT_FAILURE); -} From 840d2afe82f6987e2506264ed3473d785c4ee2eb Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sat, 8 Aug 2015 01:25:41 +0200 Subject: [PATCH 2/5] Refactor lxc-clone - 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 --- src/lxc/lxc_clone.c | 345 ++++++++++++++++++++++++-------------------- 1 file changed, 192 insertions(+), 153 deletions(-) diff --git a/src/lxc/lxc_clone.c b/src/lxc/lxc_clone.c index e88c18bc3..610e316a0 100644 --- a/src/lxc/lxc_clone.c +++ b/src/lxc/lxc_clone.c @@ -27,17 +27,198 @@ #include #include #include +#include +#include #include #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); +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'}, + { "backingstore", required_argument, 0, 'B'}, + { "fssize", required_argument, 0, 'L'}, + { "keepname", no_argument, 0, 'K'}, + { "keepmac", no_argument, 0, 'M'}, + 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 *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) { + printf("Error: You must provide a NEWNAME for the clone.\n"); + exit(EXIT_FAILURE); + } + + 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 (!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); + } + + if (my_args.task == RENAME) { + ret = do_clone_rename(c, my_args.newname); + } else { + ret = do_clone(c, my_args.newname, my_args.newpath, flags, + my_args.bdevtype, my_args.fssize, &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) +{ + 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) { @@ -45,171 +226,29 @@ static uint64_t get_fssize(char *s) char *end; ret = strtoull(s, &end, 0); - if (end == s) - { + if (end == s) { fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s); return 0; } while (isblank(*end)) end++; - if (*end == '\0') + if (*end == '\0') { ret *= 1024ULL * 1024ULL; // MB by default - else if (*end == 'b' || *end == 'B') + } else if (*end == 'b' || *end == 'B') { ret *= 1ULL; - else if (*end == 'k' || *end == 'K') + } else if (*end == 'k' || *end == 'K') { ret *= 1024ULL; - else if (*end == 'm' || *end == 'M') + } else if (*end == 'm' || *end == 'M') { ret *= 1024ULL * 1024ULL; - else if (*end == 'g' || *end == 'G') + } else if (*end == 'g' || *end == 'G') { ret *= 1024ULL * 1024ULL * 1024ULL; - else if (*end == 't' || *end == 'T') + } 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); + } 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 struct option options[] = { - { "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'}, - { "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 }, -}; - -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; - - 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 (snapshot) flags |= LXC_CLONE_SNAPSHOT; - if (keepname) flags |= LXC_CLONE_KEEPNAME; - if (keepmac) flags |= LXC_CLONE_KEEPMACADDR; - - // 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 (fstype) { - printf("Error: fstype not supported\n"); - usage(argv[0]); - } - - c1 = lxc_container_new(orig, lxcpath); - if (!c1) - exit(EXIT_FAILURE); - - if (!c1->may_control(c1)) { - fprintf(stderr, "Insufficent privileges to control %s\n", orig); - lxc_container_put(c1); - exit(EXIT_FAILURE); - } - - if (!c1->is_defined(c1)) { - fprintf(stderr, "Error: container %s is not defined\n", orig); - lxc_container_put(c1); - 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); - } - } 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); - } - lxc_container_put(c1); - - exit(EXIT_SUCCESS); -} From eab218fbf7c70ab3143440ef1165e5bdd4f51a71 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sat, 8 Aug 2015 01:31:21 +0200 Subject: [PATCH 3/5] Make LXC_CLONE_KEEPNAME work Passing the LXC_CLONE_KEEPNAME flag to do_lxcapi_clone() was not respected. We wrap clear_unexp_config_line() and set_config_item_line() in an appropriate if-condition. Signed-off-by: Christian Brauner --- src/lxc/lxccontainer.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 1c103e828..bf942ac1f 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -2906,12 +2906,15 @@ static struct lxc_container *do_lxcapi_clone(struct lxc_container *c, const char if (ret < 0) goto out; - clear_unexp_config_line(c2->lxc_conf, "lxc.utsname", false); // update utsname - if (!set_config_item_locked(c2, "lxc.utsname", newname)) { - ERROR("Error setting new hostname"); - goto out; + if (!(flags & LXC_CLONE_KEEPNAME)) { + clear_unexp_config_line(c2->lxc_conf, "lxc.utsname", false); + + if (!set_config_item_locked(c2, "lxc.utsname", newname)) { + ERROR("Error setting new hostname"); + goto out; + } } // copy hooks From b2966d59acb9bfb8d02fe1e6427cdf27cbd9686b Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sat, 8 Aug 2015 02:34:18 +0200 Subject: [PATCH 4/5] Fix grammar in some of the executables "NAME for name of the container" becomes "NAME of the container" Signed-off-by: Christian Brauner --- src/lxc/lxc_attach.c | 2 +- src/lxc/lxc_checkpoint.c | 2 +- src/lxc/lxc_console.c | 2 +- src/lxc/lxc_create.c | 4 ++-- src/lxc/lxc_destroy.c | 2 +- src/lxc/lxc_device.c | 2 +- src/lxc/lxc_execute.c | 2 +- src/lxc/lxc_freeze.c | 2 +- src/lxc/lxc_info.c | 2 +- src/lxc/lxc_init.c | 2 +- src/lxc/lxc_monitor.c | 2 +- src/lxc/lxc_start.c | 2 +- src/lxc/lxc_stop.c | 2 +- src/lxc/lxc_unfreeze.c | 2 +- src/lxc/lxc_wait.c | 2 +- 15 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c index d28b22c7a..94f0f7a14 100644 --- a/src/lxc/lxc_attach.c +++ b/src/lxc/lxc_attach.c @@ -146,7 +146,7 @@ static struct lxc_arguments my_args = { Execute the specified COMMAND - enter the container NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -e, --elevated-privileges=PRIVILEGES\n\ Use elevated privileges instead of those of the\n\ container. If you don't specify privileges to be\n\ diff --git a/src/lxc/lxc_checkpoint.c b/src/lxc/lxc_checkpoint.c index 2e76c2ec4..3e5de4a3c 100644 --- a/src/lxc/lxc_checkpoint.c +++ b/src/lxc/lxc_checkpoint.c @@ -105,7 +105,7 @@ lxc-checkpoint checkpoints and restores a container\n\ its running state at a later time.\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -r, --restore Restore container\n\ -D, --checkpoint-dir=DIR directory to save the checkpoint in\n\ -v, --verbose Enable verbose criu logs\n\ diff --git a/src/lxc/lxc_console.c b/src/lxc/lxc_console.c index b22322b1e..adbd7e019 100644 --- a/src/lxc/lxc_console.c +++ b/src/lxc/lxc_console.c @@ -78,7 +78,7 @@ static struct lxc_arguments my_args = { lxc-console logs on the container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -t, --tty=NUMBER console tty number\n\ -e, --escape=PREFIX prefix for escape command\n", .options = my_longopts, diff --git a/src/lxc/lxc_create.c b/src/lxc/lxc_create.c index 8f46db941..f1094fba8 100644 --- a/src/lxc/lxc_create.c +++ b/src/lxc/lxc_create.c @@ -61,7 +61,7 @@ static uint64_t get_fssize(char *s) 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; } @@ -131,7 +131,7 @@ static struct lxc_arguments my_args = { lxc-create creates a container\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -f, --config=file Initial configuration file\n\ -t, --template=t Template to use to setup container\n\ -B, --bdev=BDEV Backing store type to use\n\ diff --git a/src/lxc/lxc_destroy.c b/src/lxc/lxc_destroy.c index 955fc23f7..ffae907c7 100644 --- a/src/lxc/lxc_destroy.c +++ b/src/lxc/lxc_destroy.c @@ -52,7 +52,7 @@ static struct lxc_arguments my_args = { lxc-destroy destroys a container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -f, --force wait for the container to shut down\n", .options = my_longopts, .parser = my_parser, diff --git a/src/lxc/lxc_device.c b/src/lxc/lxc_device.c index 6d715d36c..0c9e06648 100644 --- a/src/lxc/lxc_device.c +++ b/src/lxc/lxc_device.c @@ -53,7 +53,7 @@ static struct lxc_arguments my_args = { lxc-device attach or detach DEV to or from container.\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container", + -n, --name=NAME NAME of the container", .options = my_longopts, .parser = NULL, .checker = NULL, diff --git a/src/lxc/lxc_execute.c b/src/lxc/lxc_execute.c index 4f1e1f674..d2c1248cd 100644 --- a/src/lxc/lxc_execute.c +++ b/src/lxc/lxc_execute.c @@ -79,7 +79,7 @@ lxc-execute creates a container with the identifier NAME\n\ and execs COMMAND into this container.\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -f, --rcfile=FILE Load configuration file FILE\n\ -s, --define KEY=VAL Assign VAL to configuration variable KEY\n", .options = my_longopts, diff --git a/src/lxc/lxc_freeze.c b/src/lxc/lxc_freeze.c index 0744c82ea..ea8bd3eae 100644 --- a/src/lxc/lxc_freeze.c +++ b/src/lxc/lxc_freeze.c @@ -47,7 +47,7 @@ static struct lxc_arguments my_args = { lxc-freeze freezes a container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container", + -n, --name=NAME NAME of the container", .options = my_longopts, .parser = NULL, .checker = NULL, diff --git a/src/lxc/lxc_info.c b/src/lxc/lxc_info.c index b360aa8f7..9f1c46991 100644 --- a/src/lxc/lxc_info.c +++ b/src/lxc/lxc_info.c @@ -87,7 +87,7 @@ static struct lxc_arguments my_args = { lxc-info display some information about a container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -c, --config=KEY show configuration variable KEY from running container\n\ -i, --ips shows the IP addresses\n\ -p, --pid shows the process id of the init container\n\ diff --git a/src/lxc/lxc_init.c b/src/lxc/lxc_init.c index 62ed4ad1b..f4b120db0 100644 --- a/src/lxc/lxc_init.c +++ b/src/lxc/lxc_init.c @@ -61,7 +61,7 @@ static void interrupt_handler(int sig) static void usage(void) { fprintf(stderr, "Usage: lxc-init [OPTION]...\n\n" "Common options :\n" - " -n, --name=NAME NAME for name of the container\n" + " -n, --name=NAME NAME of the container\n" " -l, --logpriority=LEVEL Set log priority to LEVEL\n" " -q, --quiet Don't produce any output\n" " -P, --lxcpath=PATH Use specified container path\n" diff --git a/src/lxc/lxc_monitor.c b/src/lxc/lxc_monitor.c index 3f967028f..6ccc55a88 100644 --- a/src/lxc/lxc_monitor.c +++ b/src/lxc/lxc_monitor.c @@ -61,7 +61,7 @@ static struct lxc_arguments my_args = { lxc-monitor monitors the state of the NAME container\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ NAME may be a regular expression\n\ -Q, --quit tell lxc-monitord to quit\n", .name = ".*", diff --git a/src/lxc/lxc_start.c b/src/lxc/lxc_start.c index b9d1add19..ec6ee219c 100644 --- a/src/lxc/lxc_start.c +++ b/src/lxc/lxc_start.c @@ -181,7 +181,7 @@ static struct lxc_arguments my_args = { lxc-start start COMMAND in specified container NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -d, --daemon Daemonize the container (default)\n\ -F, --foreground Start with the current tty attached to /dev/console\n\ -p, --pidfile=FILE Create a file with the process id\n\ diff --git a/src/lxc/lxc_stop.c b/src/lxc/lxc_stop.c index 705453266..10ddce6a9 100644 --- a/src/lxc/lxc_stop.c +++ b/src/lxc/lxc_stop.c @@ -69,7 +69,7 @@ static struct lxc_arguments my_args = { lxc-stop stops a container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -r, --reboot reboot the container\n\ -W, --nowait don't wait for shutdown or reboot to complete\n\ -t, --timeout=T wait T seconds before hard-stopping\n\ diff --git a/src/lxc/lxc_unfreeze.c b/src/lxc/lxc_unfreeze.c index 6a40ed74d..3a13d3723 100644 --- a/src/lxc/lxc_unfreeze.c +++ b/src/lxc/lxc_unfreeze.c @@ -45,7 +45,7 @@ static struct lxc_arguments my_args = { lxc-unfreeze unfreezes a container with the identifier NAME\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n", + -n, --name=NAME NAME of the container\n", .options = my_longopts, .parser = NULL, .checker = NULL, diff --git a/src/lxc/lxc_wait.c b/src/lxc/lxc_wait.c index 897d0ea3d..712ba52d6 100644 --- a/src/lxc/lxc_wait.c +++ b/src/lxc/lxc_wait.c @@ -68,7 +68,7 @@ static struct lxc_arguments my_args = { lxc-wait waits for NAME container state to reach STATE\n\ \n\ Options :\n\ - -n, --name=NAME NAME for name of the container\n\ + -n, --name=NAME NAME of the container\n\ -s, --state=STATE ORed states to wait for\n\ STOPPED, STARTING, RUNNING, STOPPING,\n\ ABORTING, FREEZING, FROZEN, THAWED\n\ From 7909bb03e6fcc3f49e62aa455b903fdc74ddb6dd Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sat, 8 Aug 2015 14:51:11 +0200 Subject: [PATCH 5/5] lxc-destroy: Remove container with all snapshots - This enables the user to destroy a container with all its snapshots without having to use lxc-snapshot first to destroy all snapshots. (The enum values DESTROY and SNAP from the previous commit are reused here again.) - Some unification regarding the usage of exit() and return has been done. Signed-off-by: Christian Brauner --- src/lxc/lxc_destroy.c | 74 ++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/src/lxc/lxc_destroy.c b/src/lxc/lxc_destroy.c index ffae907c7..32bd2b42d 100644 --- a/src/lxc/lxc_destroy.c +++ b/src/lxc/lxc_destroy.c @@ -31,16 +31,11 @@ lxc_log_define(lxc_destroy_ui, lxc); -static int my_parser(struct lxc_arguments* args, int c, char* arg) -{ - switch (c) { - case 'f': args->force = 1; break; - } - return 0; -} +static int my_parser(struct lxc_arguments* args, int c, char* arg); static const struct option my_longopts[] = { {"force", no_argument, 0, 'f'}, + {"snapshots", no_argument, 0, 's'}, LXC_COMMON_OPTIONS }; @@ -53,60 +48,103 @@ lxc-destroy destroys a container with the identifier NAME\n\ \n\ Options :\n\ -n, --name=NAME NAME of the container\n\ + -s, --snapshots destroy including all snapshots\n\ -f, --force wait for the container to shut down\n", .options = my_longopts, .parser = my_parser, .checker = NULL, + .task = DESTROY, }; +static int do_destroy(struct lxc_container *c); +static int do_destroy_with_snapshots(struct lxc_container *c); + int main(int argc, char *argv[]) { struct lxc_container *c; + int ret; if (lxc_arguments_parse(&my_args, argc, argv)) - exit(1); + 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(1); + exit(EXIT_FAILURE); lxc_log_options_no_override(); c = lxc_container_new(my_args.name, my_args.lxcpath[0]); if (!c) { fprintf(stderr, "System error loading container\n"); - exit(1); + exit(EXIT_FAILURE); } if (!c->may_control(c)) { fprintf(stderr, "Insufficent privileges to control %s\n", my_args.name); lxc_container_put(c); - exit(1); + exit(EXIT_FAILURE); } if (!c->is_defined(c)) { fprintf(stderr, "Container is not defined\n"); lxc_container_put(c); - exit(1); + exit(EXIT_FAILURE); } if (c->is_running(c)) { if (!my_args.force) { fprintf(stderr, "%s is running\n", my_args.name); lxc_container_put(c); - exit(1); + exit(EXIT_FAILURE); } c->stop(c); } - if (!c->destroy(c)) { - fprintf(stderr, "Destroying %s failed\n", my_args.name); - lxc_container_put(c); - exit(1); + if (my_args.task == SNAP) { + ret = do_destroy_with_snapshots(c); + } else { + ret = do_destroy(c); } lxc_container_put(c); - exit(0); + + if (ret == 0) + exit(EXIT_SUCCESS); + exit(EXIT_FAILURE); } + +static int my_parser(struct lxc_arguments *args, int c, char *arg) +{ + switch (c) { + case 'f': args->force = 1; break; + case 's': args->task = SNAP; break; + } + return 0; +} + +static int do_destroy(struct lxc_container *c) +{ + if (!c->destroy(c)) { + fprintf(stderr, "Destroying %s failed\n", my_args.name); + return -1; + } + + printf("Destroyed container %s\n", my_args.name); + + return 0; +} + +static int do_destroy_with_snapshots(struct lxc_container *c) +{ + if (!c->destroy_with_snapshots(c)) { + fprintf(stderr, "Destroying %s failed\n", my_args.name); + return -1; + } + + printf("Destroyed container including snapshots %s\n", my_args.name); + + return 0; +} +