diff options
Diffstat (limited to 'qemu-img.c')
-rw-r--r-- | qemu-img.c | 286 |
1 files changed, 169 insertions, 117 deletions
diff --git a/qemu-img.c b/qemu-img.c index 8455994c6..d4518e724 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -32,6 +32,10 @@ #include "block/block_int.h" #include "block/qapi.h" #include <getopt.h> +#include <glib.h> + +#define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION \ + ", Copyright (c) 2004-2008 Fabrice Bellard\n" typedef struct img_cmd_t { const char *name; @@ -52,16 +56,43 @@ typedef enum OutputFormat { #define BDRV_O_FLAGS BDRV_O_CACHE_WB #define BDRV_DEFAULT_CACHE "writeback" -static void format_print(void *opaque, const char *name) +static gint compare_data(gconstpointer a, gconstpointer b, gpointer user) { - printf(" %s", name); + return g_strcmp0(a, b); +} + +static void print_format(gpointer data, gpointer user) +{ + printf(" %s", (char *)data); +} + +static void add_format_to_seq(void *opaque, const char *fmt_name) +{ + GSequence *seq = opaque; + + g_sequence_insert_sorted(seq, (gpointer)fmt_name, + compare_data, NULL); +} + +static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...) +{ + va_list ap; + + error_printf("qemu-img: "); + + va_start(ap, fmt); + error_vprintf(fmt, ap); + va_end(ap); + + error_printf("\nTry 'qemu-img --help' for more information\n"); + exit(EXIT_FAILURE); } /* Please keep in synch with qemu-img.texi */ -static void help(void) +static void QEMU_NORETURN help(void) { const char *help_msg = - "qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n" + QEMU_IMG_VERSION "usage: qemu-img command [command options]\n" "QEMU disk image utility\n" "\n" @@ -125,11 +156,16 @@ static void help(void) " '-f' first image format\n" " '-F' second image format\n" " '-s' run in Strict mode - fail on different image size or sector allocation\n"; + GSequence *seq; printf("%s\nSupported formats:", help_msg); - bdrv_iterate_format(format_print, NULL); + seq = g_sequence_new(NULL); + bdrv_iterate_format(add_format_to_seq, seq); + g_sequence_foreach(seq, print_format, NULL); printf("\n"); - exit(1); + g_sequence_free(seq); + + exit(EXIT_SUCCESS); } static int GCC_FMT_ATTR(2, 3) qprintf(bool quiet, const char *fmt, ...) @@ -210,7 +246,6 @@ static int read_password(char *buf, int buf_size) if (errno == EAGAIN || errno == EINTR) { continue; } else { - ret = -1; break; } } else if (ret == 0) { @@ -235,7 +270,7 @@ static int read_password(char *buf, int buf_size) static int print_block_option_help(const char *filename, const char *fmt) { BlockDriver *drv, *proto_drv; - QEMUOptionParameter *create_options = NULL; + QemuOptsList *create_opts = NULL; /* Find driver and parse its options */ drv = bdrv_find_format(fmt); @@ -244,25 +279,24 @@ static int print_block_option_help(const char *filename, const char *fmt) return 1; } - create_options = append_option_parameters(create_options, - drv->create_options); - + create_opts = qemu_opts_append(create_opts, drv->create_opts); if (filename) { proto_drv = bdrv_find_protocol(filename, true); if (!proto_drv) { error_report("Unknown protocol '%s'", filename); + qemu_opts_free(create_opts); return 1; } - create_options = append_option_parameters(create_options, - proto_drv->create_options); + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); } - print_option_help(create_options); - free_option_parameters(create_options); + qemu_opts_print_help(create_opts); + qemu_opts_free(create_opts); return 0; } -static BlockDriverState *bdrv_new_open(const char *filename, +static BlockDriverState *bdrv_new_open(const char *id, + const char *filename, const char *fmt, int flags, bool require_io, @@ -274,7 +308,7 @@ static BlockDriverState *bdrv_new_open(const char *filename, Error *local_err = NULL; int ret; - bs = bdrv_new("image"); + bs = bdrv_new(id, &error_abort); if (fmt) { drv = bdrv_find_format(fmt); @@ -311,19 +345,19 @@ fail: return NULL; } -static int add_old_style_options(const char *fmt, QEMUOptionParameter *list, +static int add_old_style_options(const char *fmt, QemuOpts *opts, const char *base_filename, const char *base_fmt) { if (base_filename) { - if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) { + if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, base_filename)) { error_report("Backing file not supported for file format '%s'", fmt); return -1; } } if (base_fmt) { - if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) { + if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) { error_report("Backing file format not supported for file " "format '%s'", fmt); return -1; @@ -398,7 +432,7 @@ static int img_create(int argc, char **argv) } if (optind >= argc) { - help(); + error_exit("Expecting image file name"); } optind++; @@ -421,7 +455,7 @@ static int img_create(int argc, char **argv) img_size = (uint64_t)sval; } if (optind != argc) { - help(); + error_exit("Unexpected argument: %s", argv[optind]); } bdrv_img_create(filename, fmt, base_filename, base_fmt, @@ -442,12 +476,12 @@ fail: static void dump_json_image_check(ImageCheck *check, bool quiet) { - Error *errp = NULL; + Error *local_err = NULL; QString *str; QmpOutputVisitor *ov = qmp_output_visitor_new(); QObject *obj; visit_type_ImageCheck(qmp_output_get_visitor(ov), - &check, NULL, &errp); + &check, NULL, &local_err); obj = qmp_output_get_qobject(ov); str = qobject_to_json_pretty(obj); assert(str != NULL); @@ -542,10 +576,11 @@ static int collect_image_check(BlockDriverState *bs, /* * Checks an image for consistency. Exit codes: * - * 0 - Check completed, image is good - * 1 - Check not completed because of internal errors - * 2 - Check completed, image is corrupted - * 3 - Check completed, image has leaked clusters, but is good otherwise + * 0 - Check completed, image is good + * 1 - Check not completed because of internal errors + * 2 - Check completed, image is corrupted + * 3 - Check completed, image has leaked clusters, but is good otherwise + * 63 - Checks are not supported by the image format */ static int img_check(int argc, char **argv) { @@ -590,7 +625,8 @@ static int img_check(int argc, char **argv) } else if (!strcmp(optarg, "all")) { fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS; } else { - help(); + error_exit("Unknown option value for -r " + "(expecting 'leaks' or 'all'): %s", optarg); } break; case OPTION_OUTPUT: @@ -602,7 +638,7 @@ static int img_check(int argc, char **argv) } } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } filename = argv[optind++]; @@ -615,7 +651,7 @@ static int img_check(int argc, char **argv) return 1; } - bs = bdrv_new_open(filename, fmt, flags, true, quiet); + bs = bdrv_new_open("image", filename, fmt, flags, true, quiet); if (!bs) { return 1; } @@ -624,9 +660,7 @@ static int img_check(int argc, char **argv) ret = collect_image_check(bs, check, filename, fmt, fix); if (ret == -ENOTSUP) { - if (output_format == OFORMAT_HUMAN) { - error_report("This image format does not support checks"); - } + error_report("This image format does not support checks"); ret = 63; goto fail; } @@ -713,7 +747,7 @@ static int img_commit(int argc, char **argv) } } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } filename = argv[optind++]; @@ -724,7 +758,7 @@ static int img_commit(int argc, char **argv) return -1; } - bs = bdrv_new_open(filename, fmt, flags, true, quiet); + bs = bdrv_new_open("image", filename, fmt, flags, true, quiet); if (!bs) { return 1; } @@ -959,7 +993,7 @@ static int img_compare(int argc, char **argv) if (optind != argc - 2) { - help(); + error_exit("Expecting two image file names"); } filename1 = argv[optind++]; filename2 = argv[optind++]; @@ -967,14 +1001,14 @@ static int img_compare(int argc, char **argv) /* Initialize before goto out */ qemu_progress_init(progress, 2.0); - bs1 = bdrv_new_open(filename1, fmt1, BDRV_O_FLAGS, true, quiet); + bs1 = bdrv_new_open("image 1", filename1, fmt1, BDRV_O_FLAGS, true, quiet); if (!bs1) { error_report("Can't open file %s", filename1); ret = 2; goto out3; } - bs2 = bdrv_new_open(filename2, fmt2, BDRV_O_FLAGS, true, quiet); + bs2 = bdrv_new_open("image 2", filename2, fmt2, BDRV_O_FLAGS, true, quiet); if (!bs2) { error_report("Can't open file %s", filename2); ret = 2; @@ -1153,8 +1187,9 @@ static int img_convert(int argc, char **argv) size_t bufsectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE; const uint8_t *buf1; BlockDriverInfo bdi; - QEMUOptionParameter *param = NULL, *create_options = NULL; - QEMUOptionParameter *out_baseimg_param; + QemuOpts *opts = NULL; + QemuOptsList *create_opts = NULL; + const char *out_baseimg_param; char *options = NULL; const char *snapshot_name = NULL; int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */ @@ -1275,7 +1310,7 @@ static int img_convert(int argc, char **argv) } if (bs_n < 1) { - help(); + error_exit("Must specify image file name"); } @@ -1292,8 +1327,11 @@ static int img_convert(int argc, char **argv) total_sectors = 0; for (bs_i = 0; bs_i < bs_n; bs_i++) { - bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true, - quiet); + char *id = bs_n > 1 ? g_strdup_printf("source %d", bs_i) + : g_strdup("source"); + bs[bs_i] = bdrv_new_open(id, argv[optind + bs_i], fmt, BDRV_O_FLAGS, + true, quiet); + g_free(id); if (!bs[bs_i]) { error_report("Could not open '%s'", argv[optind + bs_i]); ret = -1; @@ -1340,40 +1378,34 @@ static int img_convert(int argc, char **argv) goto out; } - create_options = append_option_parameters(create_options, - drv->create_options); - create_options = append_option_parameters(create_options, - proto_drv->create_options); + create_opts = qemu_opts_append(create_opts, drv->create_opts); + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); - if (options) { - param = parse_option_parameters(options, create_options, param); - if (param == NULL) { - error_report("Invalid options for file format '%s'.", out_fmt); - ret = -1; - goto out; - } - } else { - param = parse_option_parameters("", create_options, param); + opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + if (options && qemu_opts_do_parse(opts, options, NULL)) { + error_report("Invalid options for file format '%s'", out_fmt); + ret = -1; + goto out; } - set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512); - ret = add_old_style_options(out_fmt, param, out_baseimg, NULL); + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_sectors * 512); + ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL); if (ret < 0) { goto out; } /* Get backing file name if -o backing_file was used */ - out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE); + out_baseimg_param = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE); if (out_baseimg_param) { - out_baseimg = out_baseimg_param->value.s; + out_baseimg = out_baseimg_param; } /* Check if compression is supported */ if (compress) { - QEMUOptionParameter *encryption = - get_option_parameter(param, BLOCK_OPT_ENCRYPT); - QEMUOptionParameter *preallocation = - get_option_parameter(param, BLOCK_OPT_PREALLOC); + bool encryption = + qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false); + const char *preallocation = + qemu_opt_get(opts, BLOCK_OPT_PREALLOC); if (!drv->bdrv_write_compressed) { error_report("Compression not supported for this file format"); @@ -1381,15 +1413,15 @@ static int img_convert(int argc, char **argv) goto out; } - if (encryption && encryption->value.n) { + if (encryption) { error_report("Compression and encryption not supported at " "the same time"); ret = -1; goto out; } - if (preallocation && preallocation->value.s - && strcmp(preallocation->value.s, "off")) + if (preallocation + && strcmp(preallocation, "off")) { error_report("Compression and preallocation not supported at " "the same time"); @@ -1400,7 +1432,7 @@ static int img_convert(int argc, char **argv) if (!skip_create) { /* Create the new image */ - ret = bdrv_create(drv, out_filename, param, &local_err); + ret = bdrv_create(drv, out_filename, opts, &local_err); if (ret < 0) { error_report("%s: error while converting %s: %s", out_filename, out_fmt, error_get_pretty(local_err)); @@ -1413,10 +1445,10 @@ static int img_convert(int argc, char **argv) ret = bdrv_parse_cache_flags(cache, &flags); if (ret < 0) { error_report("Invalid cache option: %s", cache); - return -1; + goto out; } - out_bs = bdrv_new_open(out_filename, out_fmt, flags, true, quiet); + out_bs = bdrv_new_open("target", out_filename, out_fmt, flags, true, quiet); if (!out_bs) { ret = -1; goto out; @@ -1458,6 +1490,7 @@ static int img_convert(int argc, char **argv) goto out; } } else { + compress = compress || bdi.needs_compressed_writes; cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE; } @@ -1664,8 +1697,8 @@ out: qemu_progress_print(100, 0); } qemu_progress_end(); - free_option_parameters(create_options); - free_option_parameters(param); + qemu_opts_del(opts); + qemu_opts_free(create_opts); qemu_vfree(buf); if (sn_opts) { qemu_opts_del(sn_opts); @@ -1712,12 +1745,12 @@ static void dump_snapshots(BlockDriverState *bs) static void dump_json_image_info_list(ImageInfoList *list) { - Error *errp = NULL; + Error *local_err = NULL; QString *str; QmpOutputVisitor *ov = qmp_output_visitor_new(); QObject *obj; visit_type_ImageInfoList(qmp_output_get_visitor(ov), - &list, NULL, &errp); + &list, NULL, &local_err); obj = qmp_output_get_qobject(ov); str = qobject_to_json_pretty(obj); assert(str != NULL); @@ -1729,12 +1762,12 @@ static void dump_json_image_info_list(ImageInfoList *list) static void dump_json_image_info(ImageInfo *info) { - Error *errp = NULL; + Error *local_err = NULL; QString *str; QmpOutputVisitor *ov = qmp_output_visitor_new(); QObject *obj; visit_type_ImageInfo(qmp_output_get_visitor(ov), - &info, NULL, &errp); + &info, NULL, &local_err); obj = qmp_output_get_qobject(ov); str = qobject_to_json_pretty(obj); assert(str != NULL); @@ -1799,8 +1832,8 @@ static ImageInfoList *collect_image_info_list(const char *filename, } g_hash_table_insert(filenames, (gpointer)filename, NULL); - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING, - false, false); + bs = bdrv_new_open("image", filename, fmt, + BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false); if (!bs) { goto err; } @@ -1882,7 +1915,7 @@ static int img_info(int argc, char **argv) } } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } filename = argv[optind++]; @@ -2046,10 +2079,10 @@ static int img_map(int argc, char **argv) break; } } - if (optind >= argc) { - help(); + if (optind != argc - 1) { + error_exit("Expecting one image file name"); } - filename = argv[optind++]; + filename = argv[optind]; if (output && !strcmp(output, "json")) { output_format = OFORMAT_JSON; @@ -2060,7 +2093,7 @@ static int img_map(int argc, char **argv) return 1; } - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS, true, false); + bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS, true, false); if (!bs) { return 1; } @@ -2138,7 +2171,7 @@ static int img_snapshot(int argc, char **argv) return 0; case 'l': if (action) { - help(); + error_exit("Cannot mix '-l', '-a', '-c', '-d'"); return 0; } action = SNAPSHOT_LIST; @@ -2146,7 +2179,7 @@ static int img_snapshot(int argc, char **argv) break; case 'a': if (action) { - help(); + error_exit("Cannot mix '-l', '-a', '-c', '-d'"); return 0; } action = SNAPSHOT_APPLY; @@ -2154,7 +2187,7 @@ static int img_snapshot(int argc, char **argv) break; case 'c': if (action) { - help(); + error_exit("Cannot mix '-l', '-a', '-c', '-d'"); return 0; } action = SNAPSHOT_CREATE; @@ -2162,7 +2195,7 @@ static int img_snapshot(int argc, char **argv) break; case 'd': if (action) { - help(); + error_exit("Cannot mix '-l', '-a', '-c', '-d'"); return 0; } action = SNAPSHOT_DELETE; @@ -2175,12 +2208,12 @@ static int img_snapshot(int argc, char **argv) } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } filename = argv[optind++]; /* Open the image */ - bs = bdrv_new_open(filename, NULL, bdrv_oflags, true, quiet); + bs = bdrv_new_open("image", filename, NULL, bdrv_oflags, true, quiet); if (!bs) { return 1; } @@ -2288,8 +2321,11 @@ static int img_rebase(int argc, char **argv) progress = 0; } - if ((optind != argc - 1) || (!unsafe && !out_baseimg)) { - help(); + if (optind != argc - 1) { + error_exit("Expecting one image file name"); + } + if (!unsafe && !out_baseimg) { + error_exit("Must specify backing file (-b) or use unsafe mode (-u)"); } filename = argv[optind++]; @@ -2309,7 +2345,7 @@ static int img_rebase(int argc, char **argv) * Ignore the old backing file for unsafe rebase in case we want to correct * the reference to a renamed or moved backing file. */ - bs = bdrv_new_open(filename, fmt, flags, true, quiet); + bs = bdrv_new_open("image", filename, fmt, flags, true, quiet); if (!bs) { return 1; } @@ -2344,7 +2380,7 @@ static int img_rebase(int argc, char **argv) } else { char backing_name[1024]; - bs_old_backing = bdrv_new("old_backing"); + bs_old_backing = bdrv_new("old_backing", &error_abort); bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name)); ret = bdrv_open(&bs_old_backing, backing_name, NULL, NULL, BDRV_O_FLAGS, old_backing_drv, &local_err); @@ -2355,7 +2391,7 @@ static int img_rebase(int argc, char **argv) goto out; } if (out_baseimg[0]) { - bs_new_backing = bdrv_new("new_backing"); + bs_new_backing = bdrv_new("new_backing", &error_abort); ret = bdrv_open(&bs_new_backing, out_baseimg, NULL, NULL, BDRV_O_FLAGS, new_backing_drv, &local_err); if (ret) { @@ -2549,7 +2585,7 @@ static int img_resize(int argc, char **argv) /* Remove size from argv manually so that negative numbers are not treated * as options by getopt. */ if (argc < 3) { - help(); + error_exit("Not enough arguments"); return 1; } @@ -2576,7 +2612,7 @@ static int img_resize(int argc, char **argv) } } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } filename = argv[optind++]; @@ -2606,7 +2642,8 @@ static int img_resize(int argc, char **argv) n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0); qemu_opts_del(param); - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet); + bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, + true, quiet); if (!bs) { ret = -1; goto out; @@ -2652,7 +2689,8 @@ static int img_amend(int argc, char **argv) { int c, ret = 0; char *options = NULL; - QEMUOptionParameter *create_options = NULL, *options_param = NULL; + QemuOptsList *create_opts = NULL; + QemuOpts *opts = NULL; const char *fmt = NULL, *filename; bool quiet = false; BlockDriverState *bs = NULL; @@ -2692,7 +2730,7 @@ static int img_amend(int argc, char **argv) } if (!options) { - help(); + error_exit("Must specify options (-o)"); } filename = (optind == argc - 1) ? argv[argc - 1] : NULL; @@ -2704,10 +2742,11 @@ static int img_amend(int argc, char **argv) } if (optind != argc - 1) { - help(); + error_exit("Expecting one image file name"); } - bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet); + bs = bdrv_new_open("image", filename, fmt, + BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet); if (!bs) { error_report("Could not open image '%s'", filename); ret = -1; @@ -2722,17 +2761,15 @@ static int img_amend(int argc, char **argv) goto out; } - create_options = append_option_parameters(create_options, - bs->drv->create_options); - options_param = parse_option_parameters(options, create_options, - options_param); - if (options_param == NULL) { + create_opts = qemu_opts_append(create_opts, bs->drv->create_opts); + opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); + if (options && qemu_opts_do_parse(opts, options, NULL)) { error_report("Invalid options for file format '%s'", fmt); ret = -1; goto out; } - ret = bdrv_amend_options(bs, options_param); + ret = bdrv_amend_options(bs, opts); if (ret < 0) { error_report("Error while amending options: %s", strerror(-ret)); goto out; @@ -2742,8 +2779,8 @@ out: if (bs) { bdrv_unref(bs); } - free_option_parameters(create_options); - free_option_parameters(options_param); + qemu_opts_del(opts); + qemu_opts_free(create_opts); g_free(options); if (ret) { @@ -2765,6 +2802,12 @@ int main(int argc, char **argv) { const img_cmd_t *cmd; const char *cmdname; + int c; + static const struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; #ifdef CONFIG_POSIX signal(SIGPIPE, SIG_IGN); @@ -2775,19 +2818,28 @@ int main(int argc, char **argv) qemu_init_main_loop(); bdrv_init(); - if (argc < 2) - help(); + if (argc < 2) { + error_exit("Not enough arguments"); + } cmdname = argv[1]; - argc--; argv++; /* find the command */ - for(cmd = img_cmds; cmd->name != NULL; cmd++) { + for (cmd = img_cmds; cmd->name != NULL; cmd++) { if (!strcmp(cmdname, cmd->name)) { - return cmd->handler(argc, argv); + return cmd->handler(argc - 1, argv + 1); } } + c = getopt_long(argc, argv, "h", long_options, NULL); + + if (c == 'h') { + help(); + } + if (c == 'v') { + printf(QEMU_IMG_VERSION); + return 0; + } + /* not found */ - help(); - return 0; + error_exit("Command not found: %s", cmdname); } |