Currently qemu-img allows an image filename to be passed on the command line, but does not have a way to set any options except the format eg
qemu-img info https://127.0.0.1/images/centos7.iso This adds a --source arg (that is mutually exclusive with a positional filename arg and -f arg) that accepts a full option string, as well as the original syntax eg qemu-img info --source driver=http,url=https://127.0.0.1/images,sslverify=off Signed-off-by: Daniel P. Berrange <berra...@redhat.com> --- include/qemu/option.h | 1 + qemu-img.c | 474 ++++++++++++++++++++++++++++++++++++++++++-------- util/qemu-option.c | 6 + 3 files changed, 407 insertions(+), 74 deletions(-) diff --git a/include/qemu/option.h b/include/qemu/option.h index 71f5f27..caf5a3b 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -104,6 +104,7 @@ int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque, Error **errp); QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id); +QemuOpts *qemu_opts_next(QemuOpts *opts); QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists, Error **errp); void qemu_opts_reset(QemuOptsList *list); diff --git a/qemu-img.c b/qemu-img.c index 47f0006..7a6ce81 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -38,6 +38,7 @@ #include "block/blockjob.h" #include "block/qapi.h" #include <getopt.h> +#include <err.h> #define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION QEMU_PKGVERSION \ ", Copyright (c) 2004-2008 Fabrice Bellard\n" @@ -51,6 +52,8 @@ enum { OPTION_OUTPUT = 256, OPTION_BACKING_CHAIN = 257, OPTION_OBJECT = 258, + OPTION_SOURCE = 259, + OPTION_TARGET = 260, }; typedef enum OutputFormat { @@ -172,6 +175,16 @@ static QemuOptsList qemu_object_opts = { }, }; +static QemuOptsList qemu_source_opts = { + .name = "source", + .implied_opt_name = "file", + .head = QTAILQ_HEAD_INITIALIZER(qemu_source_opts.head), + .desc = { + { } + }, +}; + + static int object_create(void *opaque, QemuOpts *opts, Error **errp) { Error *err = NULL; @@ -266,9 +279,31 @@ static int print_block_option_help(const char *filename, const char *fmt) return 0; } -static BlockBackend *img_open(const char *id, const char *filename, - const char *fmt, int flags, - bool require_io, bool quiet) +static BlockBackend *img_open_opts(const char *id, + QemuOpts *opts, int flags) +{ + QDict *options; + Error *local_err = NULL; + char *file = NULL; + BlockBackend *blk; + file = g_strdup(qemu_opt_get(opts, "file")); + qemu_opt_unset(opts, "file"); + options = qemu_opts_to_qdict(opts, NULL); + blk = blk_new_open(id, file, NULL, options, flags, &local_err); + if (!blk) { + error_report("Could not open '%s': %s", file ? file : "", + error_get_pretty(local_err)); + g_free(file); + error_free(local_err); + return NULL; + } + g_free(file); + return blk; +} + +static BlockBackend *img_open_file(const char *id, const char *filename, + const char *fmt, int flags, + bool require_io, bool quiet) { BlockBackend *blk; BlockDriverState *bs; @@ -576,7 +611,7 @@ static int img_check(int argc, char **argv) { int c, ret; OutputFormat output_format = OFORMAT_HUMAN; - const char *filename, *fmt, *output, *cache; + const char *filename = NULL, *fmt, *output, *cache; BlockBackend *blk; BlockDriverState *bs; int fix = 0; @@ -596,6 +631,7 @@ static int img_check(int argc, char **argv) {"repair", required_argument, 0, 'r'}, {"output", required_argument, 0, OPTION_OUTPUT}, {"object", required_argument, 0, OPTION_OBJECT}, + {"source", required_argument, 0, OPTION_SOURCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hf:r:T:q", @@ -639,12 +675,29 @@ static int img_check(int argc, char **argv) exit(1); } break; + case OPTION_SOURCE: + if (filename) { + errx(EXIT_FAILURE, "--source can only be specified once"); + } + filename = optarg; + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + optarg, true); + if (!opts) { + exit(1); + } + break; } } - if (optind != argc - 1) { - error_exit("Expecting one image file name"); + if (filename) { + if (optind != argc) { + error_exit("--source and filename are mutually exclusive"); + } + } else { + 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; @@ -667,7 +720,15 @@ static int img_check(int argc, char **argv) return 1; } - blk = img_open("image", filename, fmt, flags, true, quiet); + opts = qemu_opts_find(&qemu_source_opts, NULL); + if (opts) { + if (fmt) { + errx(EXIT_FAILURE, "--source and --format are mutually exclusive"); + } + blk = img_open_opts("image", opts, flags); + } else { + blk = img_open_file("image", filename, fmt, flags, true, quiet); + } if (!blk) { return 1; } @@ -773,7 +834,7 @@ static void run_block_job(BlockJob *job, Error **errp) static int img_commit(int argc, char **argv) { int c, ret, flags; - const char *filename, *fmt, *cache, *base; + const char *filename = NULL, *fmt, *cache, *base; BlockBackend *blk; BlockDriverState *bs, *base_bs; bool progress = false, quiet = false, drop = false; @@ -789,6 +850,7 @@ static int img_commit(int argc, char **argv) static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"object", required_argument, 0, OPTION_OBJECT}, + {"source", required_argument, 0, OPTION_SOURCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:ht:b:dpq", @@ -828,6 +890,17 @@ static int img_commit(int argc, char **argv) exit(1); } break; + case OPTION_SOURCE: + if (filename) { + errx(EXIT_FAILURE, "--source can only be specified once"); + } + filename = optarg; + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + optarg, true); + if (!opts) { + exit(1); + } + break; } } @@ -836,10 +909,16 @@ static int img_commit(int argc, char **argv) progress = false; } - if (optind != argc - 1) { - error_exit("Expecting one image file name"); + if (filename) { + if (optind != argc) { + error_exit("--source and filename are mutually exclusive"); + } + } else { + if (optind != argc - 1) { + error_exit("Expecting one image file name"); + } + filename = argv[optind++]; } - filename = argv[optind++]; if (qemu_opts_foreach(qemu_find_opts("object"), object_create, @@ -854,7 +933,15 @@ static int img_commit(int argc, char **argv) return 1; } - blk = img_open("image", filename, fmt, flags, true, quiet); + opts = qemu_opts_find(&qemu_source_opts, NULL); + if (opts) { + if (fmt) { + errx(EXIT_FAILURE, "--source and --format are mutually exclusive"); + } + blk = img_open_opts("image", opts, flags); + } else { + blk = img_open_file("image", filename, fmt, flags, true, quiet); + } if (!blk) { return 1; } @@ -1088,7 +1175,8 @@ static int check_empty_sectors(BlockBackend *blk, int64_t sect_num, */ static int img_compare(int argc, char **argv) { - const char *fmt1 = NULL, *fmt2 = NULL, *cache, *filename1, *filename2; + const char *fmt1 = NULL, *fmt2 = NULL, *cache, + *filename1 = NULL, *filename2 = NULL; BlockBackend *blk1, *blk2; BlockDriverState *bs1, *bs2; int64_t total_sectors1, total_sectors2; @@ -1111,6 +1199,7 @@ static int img_compare(int argc, char **argv) static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"object", required_argument, 0, OPTION_OBJECT}, + {"source", required_argument, 0, OPTION_SOURCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hf:F:T:pqs", @@ -1148,6 +1237,20 @@ static int img_compare(int argc, char **argv) exit(1); } break; + case OPTION_SOURCE: + if (filename2) { + errx(EXIT_FAILURE, "--source can only be specified twice"); + } else if (filename1) { + filename2 = optarg; + } else { + filename1 = optarg; + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + optarg, true); + if (!opts) { + exit(1); + } + break; } } @@ -1156,12 +1259,20 @@ static int img_compare(int argc, char **argv) progress = false; } - - if (optind != argc - 2) { - error_exit("Expecting two image file names"); + if (filename1) { + if (optind != argc) { + error_exit("--source and filenames are mutually exclusive"); + } + if (!filename2) { + error_exit("Expecting two --source arguments"); + } + } else { + if (optind != argc - 2) { + error_exit("Expecting two image file names"); + } + filename1 = argv[optind++]; + filename2 = argv[optind++]; } - filename1 = argv[optind++]; - filename2 = argv[optind++]; if (qemu_opts_foreach(qemu_find_opts("object"), object_create, @@ -1180,18 +1291,38 @@ static int img_compare(int argc, char **argv) goto out3; } - blk1 = img_open("image_1", filename1, fmt1, flags, true, quiet); - if (!blk1) { - ret = 2; - goto out3; - } - bs1 = blk_bs(blk1); + opts = qemu_opts_find(&qemu_source_opts, NULL); + if (opts) { + if (fmt1 || fmt2) { + error_report("--source and -f or -F are mutuall exclusive"); + goto out3; + } - blk2 = img_open("image_2", filename2, fmt2, flags, true, quiet); - if (!blk2) { - ret = 2; - goto out2; + blk1 = img_open_opts("image_1", opts, flags); + if (!blk1) { + ret = 2; + goto out3; + } + + blk2 = img_open_opts("image_2", qemu_opts_next(opts), flags); + if (!blk2) { + ret = 2; + goto out3; + } + } else { + blk1 = img_open_file("image_1", filename1, fmt1, flags, true, quiet); + if (!blk1) { + ret = 2; + goto out3; + } + + blk2 = img_open_file("image_2", filename2, fmt2, flags, true, quiet); + if (!blk2) { + ret = 2; + goto out2; + } } + bs1 = blk_bs(blk1); bs2 = blk_bs(blk2); buf1 = blk_blockalign(blk1, IO_BUF_SIZE); @@ -1658,10 +1789,11 @@ fail: static int img_convert(int argc, char **argv) { - int c, bs_n, bs_i, compress, cluster_sectors, skip_create; + int c, bs_n = 0, bs_i, compress, cluster_sectors, skip_create; int64_t ret = 0; int progress = 0, flags, src_flags; - const char *fmt, *out_fmt, *cache, *src_cache, *out_baseimg, *out_filename; + const char *fmt, *out_fmt, *cache, *src_cache, + *out_baseimg, *out_filename = NULL; BlockDriver *drv, *proto_drv; BlockBackend **blk = NULL, *out_blk = NULL; BlockDriverState **bs = NULL, *out_bs = NULL; @@ -1692,6 +1824,7 @@ static int img_convert(int argc, char **argv) static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"object", required_argument, 0, OPTION_OBJECT}, + {"source", required_argument, 0, OPTION_SOURCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hf:O:B:ce6o:s:l:S:pt:T:qn", @@ -1793,6 +1926,14 @@ static int img_convert(int argc, char **argv) exit(1); } break; + case OPTION_SOURCE: + bs_n++; + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + optarg, true); + if (!opts) { + exit(1); + } + break; } } @@ -1808,20 +1949,33 @@ static int img_convert(int argc, char **argv) } qemu_progress_init(progress, 1.0); - - bs_n = argc - optind - 1; - out_filename = bs_n >= 1 ? argv[argc - 1] : NULL; + if (!bs_n) { + out_filename = (argc - optind - 1) >= 1 ? argv[argc - 1] : NULL; + } if (options && has_help_option(options)) { ret = print_block_option_help(out_filename, out_fmt); goto out; } - if (bs_n < 1) { - error_exit("Must specify image file name"); + if (bs_n) { + if (argc > (optind + 1)) { + error_exit("--source and filenames are mutually exclusive"); + } + if (argc != (optind + 1)) { + error_exit("Must specify target image file name"); + } + if (!bs_n) { + error_exit("At least one --source arg is expected with --target"); + } + out_filename = argv[argc - 1]; + } else { + bs_n = argc - optind - 1; + if (bs_n < 1) { + error_exit("Must specify image file name"); + } } - if (bs_n > 1 && out_baseimg) { error_report("-B makes no sense when concatenating multiple input " "images"); @@ -1843,11 +1997,21 @@ static int img_convert(int argc, char **argv) bs_sectors = g_new(int64_t, bs_n); total_sectors = 0; + opts = qemu_opts_find(&qemu_source_opts, NULL); for (bs_i = 0; bs_i < bs_n; bs_i++) { char *id = bs_n > 1 ? g_strdup_printf("source_%d", bs_i) : g_strdup("source"); - blk[bs_i] = img_open(id, argv[optind + bs_i], fmt, src_flags, - true, quiet); + if (opts) { + if (fmt) { + error_report("--source and -f are mutually exclusive"); + goto out; + } + blk[bs_i] = img_open_opts(id, opts, src_flags); + opts = qemu_opts_next(opts); + } else { + blk[bs_i] = img_open_file(id, argv[optind + bs_i], fmt, src_flags, + true, quiet); + } g_free(id); if (!blk[bs_i]) { ret = -1; @@ -1991,7 +2155,12 @@ static int img_convert(int argc, char **argv) goto out; } - out_blk = img_open("target", out_filename, out_fmt, flags, true, quiet); + /* XXX we could allow a --target OPTSRING and then use + * img_open_opts here, but then we have trouble with + * the bdrv_create() call which takes different params + */ + out_blk = img_open_file("target", out_filename, + out_fmt, flags, true, quiet); if (!out_blk) { ret = -1; goto out; @@ -2158,7 +2327,8 @@ static gboolean str_equal_func(gconstpointer a, gconstpointer b) * image file. If there was an error a message will have been printed to * stderr. */ -static ImageInfoList *collect_image_info_list(const char *filename, +static ImageInfoList *collect_image_info_list(QemuOpts *opts, + const char *filename, const char *fmt, bool chain) { @@ -2182,8 +2352,19 @@ static ImageInfoList *collect_image_info_list(const char *filename, } g_hash_table_insert(filenames, (gpointer)filename, NULL); - blk = img_open("image", filename, fmt, - BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false); + if (opts) { + if (fmt) { + error_report("--source and -f are mutually exclusive"); + goto err; + } + blk = img_open_opts("image", opts, + BDRV_O_FLAGS | BDRV_O_NO_BACKING); + opts = NULL; + } else { + blk = img_open_file("image", filename, fmt, + BDRV_O_FLAGS | BDRV_O_NO_BACKING, + false, false); + } if (!blk) { goto err; } @@ -2232,7 +2413,7 @@ static int img_info(int argc, char **argv) int c; OutputFormat output_format = OFORMAT_HUMAN; bool chain = false; - const char *filename, *fmt, *output; + const char *filename = NULL, *fmt, *output; ImageInfoList *list; QemuOpts *opts; @@ -2246,6 +2427,7 @@ static int img_info(int argc, char **argv) {"output", required_argument, 0, OPTION_OUTPUT}, {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN}, {"object", required_argument, 0, OPTION_OBJECT}, + {"source", required_argument, 0, OPTION_SOURCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:h", @@ -2274,12 +2456,29 @@ static int img_info(int argc, char **argv) exit(1); } break; + case OPTION_SOURCE: + if (filename) { + error_exit("--source can only be specified once"); + } + filename = optarg; + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + optarg, true); + if (!opts) { + exit(1); + } + break; } } - if (optind != argc - 1) { - error_exit("Expecting one image file name"); + if (filename) { + if (optind != argc) { + error_exit("--source and filename are mutually exclusive"); + } + } else { + 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; @@ -2296,7 +2495,8 @@ static int img_info(int argc, char **argv) exit(1); } - list = collect_image_info_list(filename, fmt, chain); + list = collect_image_info_list(qemu_opts_find(&qemu_source_opts, NULL), + filename, fmt, chain); if (!list) { return 1; } @@ -2415,7 +2615,7 @@ static int img_map(int argc, char **argv) OutputFormat output_format = OFORMAT_HUMAN; BlockBackend *blk; BlockDriverState *bs; - const char *filename, *fmt, *output; + const char *filename = NULL, *fmt, *output; int64_t length; MapEntry curr = { .length = 0 }, next; int ret = 0; @@ -2430,6 +2630,7 @@ static int img_map(int argc, char **argv) {"format", required_argument, 0, 'f'}, {"output", required_argument, 0, OPTION_OUTPUT}, {"object", required_argument, 0, OPTION_OBJECT}, + {"source", required_argument, 0, OPTION_SOURCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:h", @@ -2455,12 +2656,29 @@ static int img_map(int argc, char **argv) exit(1); } break; + case OPTION_SOURCE: + if (filename) { + error_exit("--source can only be specified once"); + } + filename = optarg; + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + optarg, true); + if (!opts) { + exit(1); + } + break; } } - if (optind != argc - 1) { - error_exit("Expecting one image file name"); + if (filename) { + if (optind != argc) { + error_exit("--source and filename are mutually exclusive"); + } + } else { + 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; @@ -2477,7 +2695,15 @@ static int img_map(int argc, char **argv) exit(1); } - blk = img_open("image", filename, fmt, BDRV_O_FLAGS, true, false); + opts = qemu_opts_find(&qemu_source_opts, NULL); + if (opts) { + if (fmt) { + errx(EXIT_FAILURE, "--source and --format are mutually exclusive"); + } + blk = img_open_opts("image", opts, BDRV_O_FLAGS); + } else { + blk = img_open_file("image", filename, fmt, BDRV_O_FLAGS, true, false); + } if (!blk) { return 1; } @@ -2536,7 +2762,7 @@ static int img_snapshot(int argc, char **argv) BlockBackend *blk; BlockDriverState *bs; QEMUSnapshotInfo sn; - char *filename, *snapshot_name = NULL; + char *filename = NULL, *snapshot_name = NULL; int c, ret = 0, bdrv_oflags; int action = 0; qemu_timeval tv; @@ -2551,6 +2777,7 @@ static int img_snapshot(int argc, char **argv) static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"object", required_argument, 0, OPTION_OBJECT}, + {"source", required_argument, 0, OPTION_SOURCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "la:c:d:hq", @@ -2605,13 +2832,30 @@ static int img_snapshot(int argc, char **argv) exit(1); } break; + case OPTION_SOURCE: + if (filename) { + error_exit("--source can only be specified once"); + } + filename = optarg; + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + optarg, true); + if (!opts) { + exit(1); + } + break; } } - if (optind != argc - 1) { - error_exit("Expecting one image file name"); + if (filename) { + if (optind != argc) { + error_exit("--source and filename are mutually exclusive"); + } + } else { + if (optind != argc - 1) { + error_exit("Expecting one image file name"); + } + filename = argv[optind++]; } - filename = argv[optind++]; if (qemu_opts_foreach(qemu_find_opts("object"), object_create, @@ -2620,7 +2864,12 @@ static int img_snapshot(int argc, char **argv) } /* Open the image */ - blk = img_open("image", filename, NULL, bdrv_oflags, true, quiet); + opts = qemu_opts_find(&qemu_source_opts, NULL); + if (opts) { + blk = img_open_opts("image", opts, bdrv_oflags); + } else { + blk = img_open_file("image", filename, NULL, bdrv_oflags, true, quiet); + } if (!blk) { return 1; } @@ -2678,7 +2927,7 @@ static int img_rebase(int argc, char **argv) { BlockBackend *blk = NULL, *blk_old_backing = NULL, *blk_new_backing = NULL; BlockDriverState *bs = NULL; - char *filename; + char *filename = NULL; const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg; int c, flags, src_flags, ret; int unsafe = 0; @@ -2698,6 +2947,7 @@ static int img_rebase(int argc, char **argv) static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"object", required_argument, 0, OPTION_OBJECT}, + {"source", required_argument, 0, OPTION_SOURCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hf:F:b:upt:T:q", @@ -2741,6 +2991,13 @@ static int img_rebase(int argc, char **argv) exit(1); } break; + case OPTION_SOURCE: + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + optarg, true); + if (!opts) { + exit(1); + } + break; } } @@ -2748,13 +3005,20 @@ static int img_rebase(int argc, char **argv) progress = 0; } - if (optind != argc - 1) { - error_exit("Expecting one image file name"); + if (filename) { + if (optind != argc) { + error_exit("--source and filename are mutually exclusive"); + } + } else { + if (optind != argc - 1) { + error_exit("Expecting one image file name"); + } + filename = argv[optind++]; } + if (!unsafe && !out_baseimg) { error_exit("Must specify backing file (-b) or use unsafe mode (-u)"); } - filename = argv[optind++]; if (qemu_opts_foreach(qemu_find_opts("object"), object_create, @@ -2785,7 +3049,17 @@ 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. */ - blk = img_open("image", filename, fmt, flags, true, quiet); + opts = qemu_opts_find(&qemu_source_opts, NULL); + if (opts) { + if (fmt) { + error_report("--source and --format are mutually exclusive"); + ret = -1; + goto out; + } + blk = img_open_opts("image", opts, flags); + } else { + blk = img_open_file("image", filename, fmt, flags, true, quiet); + } if (!blk) { ret = -1; goto out; @@ -3017,7 +3291,7 @@ static int img_resize(int argc, char **argv) { Error *err = NULL; int c, ret, relative; - const char *filename, *fmt, *size; + const char *filename = NULL, *fmt, *size; int64_t n, total_size; bool quiet = false; BlockBackend *blk = NULL; @@ -3053,6 +3327,7 @@ static int img_resize(int argc, char **argv) static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"object", required_argument, 0, OPTION_OBJECT}, + {"source", required_argument, 0, OPTION_SOURCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:hq", @@ -3078,12 +3353,25 @@ static int img_resize(int argc, char **argv) exit(1); } break; + case OPTION_SOURCE: + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + optarg, true); + if (!opts) { + exit(1); + } + break; } } - if (optind != argc - 1) { - error_exit("Expecting one image file name"); + if (filename) { + if (optind != argc) { + error_exit("--source and filename are mutually exclusive"); + } + } else { + if (optind != argc - 1) { + error_exit("Expecting one image file name"); + } + filename = argv[optind++]; } - filename = argv[optind++]; if (qemu_opts_foreach(qemu_find_opts("object"), object_create, @@ -3118,8 +3406,18 @@ static int img_resize(int argc, char **argv) n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0); qemu_opts_del(param); - blk = img_open("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, - true, quiet); + opts = qemu_opts_find(&qemu_source_opts, NULL); + if (opts) { + if (fmt) { + error_report("--source and --format are mutually exclusive"); + ret = -1; + goto out; + } + blk = img_open_opts("image", opts, BDRV_O_FLAGS | BDRV_O_RDWR); + } else { + blk = img_open_file("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, + true, quiet); + } if (!blk) { ret = -1; goto out; @@ -3173,7 +3471,7 @@ static int img_amend(int argc, char **argv) char *options = NULL; QemuOptsList *create_opts = NULL; QemuOpts *opts = NULL; - const char *fmt = NULL, *filename, *cache; + const char *fmt = NULL, *filename = NULL, *cache; int flags; bool quiet = false, progress = false; BlockBackend *blk = NULL; @@ -3185,6 +3483,7 @@ static int img_amend(int argc, char **argv) static const struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"object", required_argument, 0, OPTION_OBJECT}, + {"source", required_argument, 0, OPTION_SOURCE}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "ho:f:t:pq", @@ -3231,6 +3530,13 @@ static int img_amend(int argc, char **argv) exit(1); } break; + case OPTION_SOURCE: + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + optarg, true); + if (!opts) { + exit(1); + } + break; } } @@ -3238,6 +3544,12 @@ static int img_amend(int argc, char **argv) error_exit("Must specify options (-o)"); } + if (filename) { + if (optind != argc) { + error_exit("--source and filename are mutually exclusive"); + } + } + if (qemu_opts_foreach(qemu_find_opts("object"), object_create, NULL, NULL)) { @@ -3249,7 +3561,9 @@ static int img_amend(int argc, char **argv) } qemu_progress_init(progress, 1.0); - filename = (optind == argc - 1) ? argv[argc - 1] : NULL; + if (!filename) { + filename = (optind == argc - 1) ? argv[argc - 1] : NULL; + } if (fmt && has_help_option(options)) { /* If a format is explicitly specified (and possibly no filename is * given), print option help here */ @@ -3257,8 +3571,9 @@ static int img_amend(int argc, char **argv) goto out; } - if (optind != argc - 1) { - error_report("Expecting one image file name"); + if (!filename && + (optind != argc - 1)) { + error_exit("Expecting one image file name"); ret = -1; goto out; } @@ -3270,7 +3585,17 @@ static int img_amend(int argc, char **argv) goto out; } - blk = img_open("image", filename, fmt, flags, true, quiet); + opts = qemu_opts_find(&qemu_source_opts, NULL); + if (opts) { + if (fmt) { + error_report("--source and --format are mutually exclusive"); + ret = -1; + goto out; + } + blk = img_open_opts("image", opts, BDRV_O_FLAGS | BDRV_O_RDWR); + } else { + blk = img_open_file("image", filename, fmt, flags, true, quiet); + } if (!blk) { ret = -1; goto out; @@ -3368,6 +3693,7 @@ int main(int argc, char **argv) module_call_init(MODULE_INIT_QOM); qemu_add_opts(&qemu_object_opts); + qemu_add_opts(&qemu_source_opts); /* find the command */ for (cmd = img_cmds; cmd->name != NULL; cmd++) { diff --git a/util/qemu-option.c b/util/qemu-option.c index a50ecea..48e1cc5 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -637,6 +637,12 @@ QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id) return NULL; } + +QemuOpts *qemu_opts_next(QemuOpts *opts) +{ + return QTAILQ_NEXT(opts, next); +} + QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists, Error **errp) { -- 2.5.0