From patchwork Tue Jan 26 13:34:19 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= X-Patchwork-Id: 573250 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id A09841402BF for ; Wed, 27 Jan 2016 00:40:35 +1100 (AEDT) Received: from localhost ([::1]:43883 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aO3rF-0005Ws-Is for incoming@patchwork.ozlabs.org; Tue, 26 Jan 2016 08:40:33 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55120) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aO3lu-0004VH-Si for qemu-devel@nongnu.org; Tue, 26 Jan 2016 08:35:08 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aO3lr-00014F-T7 for qemu-devel@nongnu.org; Tue, 26 Jan 2016 08:35:02 -0500 Received: from mx1.redhat.com ([209.132.183.28]:42503) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aO3lh-000109-Fm; Tue, 26 Jan 2016 08:34:49 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (Postfix) with ESMTPS id 23DE4C09FA8F; Tue, 26 Jan 2016 13:34:49 +0000 (UTC) Received: from t530wlan.home.berrange.com.com (vpn1-4-241.ams2.redhat.com [10.36.4.241]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u0QDYTrd004585; Tue, 26 Jan 2016 08:34:47 -0500 From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Tue, 26 Jan 2016 13:34:19 +0000 Message-Id: <1453815262-13440-8-git-send-email-berrange@redhat.com> In-Reply-To: <1453815262-13440-1-git-send-email-berrange@redhat.com> References: <1453815262-13440-1-git-send-email-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Kevin Wolf , qemu-block@nongnu.org, Markus Armbruster , Paolo Bonzini , =?UTF-8?q?Andreas=20F=C3=A4rber?= Subject: [Qemu-devel] [PATCH v4 07/10] qemu-img: allow specifying image as a set of options args X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Currently qemu-img allows an image filename to be passed on the command line, but unless using the JSON format, it 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 --image-opts arg that indicates that the positional filename should be interpreted as a full option string, not just a filename. qemu-img info --source driver=http,url=https://127.0.0.1/images,sslverify=off This flag is mutually exclusive with the '-f' / '-F' flags. Signed-off-by: Daniel P. Berrange --- qemu-img-cmds.hx | 44 ++++---- qemu-img.c | 304 +++++++++++++++++++++++++++++++++++++++++++++++++------ qemu-img.texi | 6 ++ 3 files changed, 303 insertions(+), 51 deletions(-) diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 5bb1de7..ee5c770 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -10,68 +10,68 @@ STEXI ETEXI DEF("check", img_check, - "check [-q] [--object objectdef] [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] filename") + "check [-q] [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] filename") STEXI -@item check [--object objectdef] [-q] [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] [-T @var{src_cache}] @var{filename} +@item check [--object objectdef] [--image-opts] [-q] [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] [-T @var{src_cache}] @var{filename} ETEXI DEF("create", img_create, - "create [-q] [--object objectdef] [-f fmt] [-o options] filename [size]") + "create [-q] [--object objectdef] [--image-opts] [-f fmt] [-o options] filename [size]") STEXI -@item create [--object objectdef] [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] +@item create [--object objectdef] [--image-opts] [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}] ETEXI DEF("commit", img_commit, - "commit [-q] [--object objectdef] [-f fmt] [-t cache] [-b base] [-d] [-p] filename") + "commit [-q] [--object objectdef] [--image-opts] [-f fmt] [-t cache] [-b base] [-d] [-p] filename") STEXI -@item commit [--object objectdef] [-q] [-f @var{fmt}] [-t @var{cache}] [-b @var{base}] [-d] [-p] @var{filename} +@item commit [--object objectdef] [--image-opts] [-q] [-f @var{fmt}] [-t @var{cache}] [-b @var{base}] [-d] [-p] @var{filename} ETEXI DEF("compare", img_compare, - "compare [--object objectdef] [-f fmt] [-F fmt] [-T src_cache] [-p] [-q] [-s] filename1 filename2") + "compare [--object objectdef] [--image-opts] [-f fmt] [-F fmt] [-T src_cache] [-p] [-q] [-s] filename1 filename2") STEXI -@item compare [--object objectdef] [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-q] [-s] @var{filename1} @var{filename2} +@item compare [--object objectdef] [--image-opts] [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-q] [-s] @var{filename1} @var{filename2} ETEXI DEF("convert", img_convert, - "convert [--object objectdef] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename [filename2 [...]] output_filename") + "convert [--object objectdef] [--image-opts] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename [filename2 [...]] output_filename") STEXI -@item convert [--object objectdef] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [--object objectdef] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI DEF("info", img_info, - "info [--object objectdef] [-f fmt] [--output=ofmt] [--backing-chain] filename") + "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] filename") STEXI -@item info [--object objectdef] [-f @var{fmt}] [--output=@var{ofmt}] [--backing-chain] @var{filename} +@item info [--object objectdef] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [--backing-chain] @var{filename} ETEXI DEF("map", img_map, - "map [--object objectdef] [-f fmt] [--output=ofmt] filename") + "map [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] filename") STEXI -@item map [--object objectdef] [-f @var{fmt}] [--output=@var{ofmt}] @var{filename} +@item map [--object objectdef] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] @var{filename} ETEXI DEF("snapshot", img_snapshot, - "snapshot [--object objectdef] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename") + "snapshot [--object objectdef] [--image-opts] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename") STEXI -@item snapshot [--object objectdef] [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename} +@item snapshot [--object objectdef] [--image-opts] [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename} ETEXI DEF("rebase", img_rebase, - "rebase [--object objectdef] [-q] [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b backing_file [-F backing_fmt] filename") + "rebase [--object objectdef] [--image-opts] [-q] [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b backing_file [-F backing_fmt] filename") STEXI -@item rebase [--object objectdef] [-q] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} +@item rebase [--object objectdef] [--image-opts] [-q] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} ETEXI DEF("resize", img_resize, - "resize [--object objectdef] [-q] filename [+ | -]size") + "resize [--object objectdef] [--image-opts] [-q] filename [+ | -]size") STEXI -@item resize [--object objectdef] [-q] @var{filename} [+ | -]@var{size} +@item resize [--object objectdef] [--image-opts] [-q] @var{filename} [+ | -]@var{size} ETEXI DEF("amend", img_amend, - "amend [--object objectdef] [-p] [-q] [-f fmt] [-t cache] -o options filename") + "amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt] [-t cache] -o options filename") STEXI -@item amend [--object objectdef] [-p] [-q] [-f @var{fmt}] [-t @var{cache}] -o @var{options} @var{filename} +@item amend [--object objectdef] [--image-opts] [-p] [-q] [-f @var{fmt}] [-t @var{cache}] -o @var{options} @var{filename} @end table ETEXI diff --git a/qemu-img.c b/qemu-img.c index 6aa9725..b8af186 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -51,6 +51,7 @@ enum { OPTION_OUTPUT = 256, OPTION_BACKING_CHAIN = 257, OPTION_OBJECT = 258, + OPTION_IMAGE_OPTS = 259, }; typedef enum OutputFormat { @@ -171,6 +172,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; @@ -232,9 +243,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; @@ -549,6 +582,7 @@ static int img_check(int argc, char **argv) bool quiet = false; QemuOpts *opts; Error *local_err = NULL; + bool image_opts = false; fmt = NULL; output = NULL; @@ -561,6 +595,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}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hf:r:T:q", @@ -604,6 +639,9 @@ static int img_check(int argc, char **argv) exit(1); } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } if (optind != argc - 1) { @@ -633,7 +671,20 @@ static int img_check(int argc, char **argv) return 1; } - blk = img_open("image", filename, fmt, flags, true, quiet); + if (image_opts) { + if (fmt) { + error_report("--image-opts and --format are mutually exclusive"); + exit(1); + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename, true); + if (!opts) { + exit(1); + } + blk = img_open_opts("image", opts, flags); + } else { + blk = img_open_file("image", filename, fmt, flags, true, quiet); + } if (!blk) { return 1; } @@ -746,6 +797,7 @@ static int img_commit(int argc, char **argv) Error *local_err = NULL; CommonBlockJobCBInfo cbi; QemuOpts *opts; + bool image_opts = false; fmt = NULL; cache = BDRV_DEFAULT_CACHE; @@ -755,6 +807,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}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:ht:b:dpq", @@ -794,6 +847,9 @@ static int img_commit(int argc, char **argv) exit(1); } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -821,7 +877,20 @@ static int img_commit(int argc, char **argv) return 1; } - blk = img_open("image", filename, fmt, flags, true, quiet); + if (image_opts) { + if (fmt) { + error_report("--image-opts and --format are mutually exclusive"); + exit(1); + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename, true); + if (!opts) { + exit(1); + } + blk = img_open_opts("image", opts, flags); + } else { + blk = img_open_file("image", filename, fmt, flags, true, quiet); + } if (!blk) { return 1; } @@ -1072,6 +1141,7 @@ static int img_compare(int argc, char **argv) uint64_t progress_base; QemuOpts *opts; Error *local_err = NULL; + bool image_opts = false; cache = BDRV_DEFAULT_CACHE; for (;;) { @@ -1079,6 +1149,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}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hf:F:T:pqs", @@ -1116,6 +1187,9 @@ static int img_compare(int argc, char **argv) exit(1); } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -1149,18 +1223,49 @@ 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); + if (image_opts) { + if (fmt1 || fmt2) { + error_report("--image-opts and -f or -F are mutually exclusive"); + goto out3; + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename1, true); + if (!opts) { + ret = 2; + goto out3; + } + blk1 = img_open_opts("image_1", opts, flags); + if (!blk1) { + ret = 2; + goto out3; + } - blk2 = img_open("image_2", filename2, fmt2, flags, true, quiet); - if (!blk2) { - ret = 2; - goto out2; + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename2, true); + if (!opts) { + ret = 2; + goto out2; + } + + blk2 = img_open_opts("image_2", 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); @@ -1663,6 +1768,7 @@ static int img_convert(int argc, char **argv) Error *local_err = NULL; QemuOpts *sn_opts = NULL; ImgConvertState state; + bool image_opts = false; fmt = NULL; out_fmt = "raw"; @@ -1676,6 +1782,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}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hf:O:B:ce6o:s:l:S:pt:T:qn", @@ -1777,6 +1884,9 @@ static int img_convert(int argc, char **argv) exit(1); } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -1793,7 +1903,6 @@ 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; @@ -1831,8 +1940,23 @@ static int img_convert(int argc, char **argv) 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 (image_opts) { + if (fmt) { + error_report("--image-opts and -f are mutually exclusive"); + ret = -1; + goto out; + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + argv[optind + bs_i], true); + if (!opts) { + ret = -1; + goto out; + } + blk[bs_i] = img_open_opts(id, opts, src_flags); + } 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; @@ -1973,7 +2097,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 should allow --image-opts to trigger use of + * 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; @@ -2140,7 +2269,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(bool image_opts, + const char *filename, const char *fmt, bool chain) { @@ -2148,6 +2278,7 @@ static ImageInfoList *collect_image_info_list(const char *filename, ImageInfoList **last = &head; GHashTable *filenames; Error *err = NULL; + QemuOpts *opts; filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL); @@ -2164,8 +2295,24 @@ 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 (image_opts) { + if (fmt) { + error_report("--image-opts and -f are mutually exclusive"); + goto err; + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename, true); + if (!opts) { + 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; } @@ -2218,6 +2365,7 @@ static int img_info(int argc, char **argv) ImageInfoList *list; QemuOpts *opts; Error *local_err = NULL; + bool image_opts = false; fmt = NULL; output = NULL; @@ -2229,6 +2377,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}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:h", @@ -2257,6 +2406,9 @@ static int img_info(int argc, char **argv) exit(1); } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } if (optind != argc - 1) { @@ -2280,7 +2432,7 @@ static int img_info(int argc, char **argv) exit(1); } - list = collect_image_info_list(filename, fmt, chain); + list = collect_image_info_list(image_opts, filename, fmt, chain); if (!list) { return 1; } @@ -2405,6 +2557,7 @@ static int img_map(int argc, char **argv) int ret = 0; QemuOpts *opts; Error *local_err = NULL; + bool image_opts = false; fmt = NULL; output = NULL; @@ -2415,6 +2568,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}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:h", @@ -2440,6 +2594,9 @@ static int img_map(int argc, char **argv) exit(1); } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } if (optind != argc - 1) { @@ -2463,7 +2620,20 @@ static int img_map(int argc, char **argv) exit(1); } - blk = img_open("image", filename, fmt, BDRV_O_FLAGS, true, false); + if (image_opts) { + if (fmt) { + error_report("--image-opts and -f are mutually exclusive"); + exit(1); + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename, true); + if (!opts) { + exit(1); + } + 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; } @@ -2529,6 +2699,7 @@ static int img_snapshot(int argc, char **argv) bool quiet = false; Error *err = NULL; QemuOpts *opts; + bool image_opts = false; bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR; /* Parse commandline parameters */ @@ -2537,6 +2708,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}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "la:c:d:hq", @@ -2591,6 +2763,9 @@ static int img_snapshot(int argc, char **argv) exit(1); } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -2607,7 +2782,16 @@ static int img_snapshot(int argc, char **argv) } /* Open the image */ - blk = img_open("image", filename, NULL, bdrv_oflags, true, quiet); + if (image_opts) { + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename, true); + if (!opts) { + exit(1); + } + blk = img_open_opts("image", opts, bdrv_oflags); + } else { + blk = img_open_file("image", filename, NULL, bdrv_oflags, true, quiet); + } if (!blk) { return 1; } @@ -2672,6 +2856,7 @@ static int img_rebase(int argc, char **argv) bool quiet = false; Error *local_err = NULL; QemuOpts *opts; + bool image_opts = false; /* Parse commandline parameters */ fmt = NULL; @@ -2684,6 +2869,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}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hf:F:b:upt:T:q", @@ -2727,6 +2913,9 @@ static int img_rebase(int argc, char **argv) exit(1); } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -2737,6 +2926,7 @@ static int img_rebase(int argc, char **argv) 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)"); } @@ -2772,7 +2962,22 @@ 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); + if (image_opts) { + if (fmt) { + error_report("--image-opts and --format are mutually exclusive"); + ret = -1; + goto out; + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename, true); + if (!opts) { + 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; @@ -3025,6 +3230,7 @@ static int img_resize(int argc, char **argv) } }, }; + bool image_opts = false; /* Remove size from argv manually so that negative numbers are not treated * as options by getopt. */ @@ -3042,6 +3248,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}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:hq", @@ -3067,6 +3274,9 @@ static int img_resize(int argc, char **argv) exit(1); } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } if (optind != argc - 1) { @@ -3108,8 +3318,23 @@ 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); + if (image_opts) { + if (fmt) { + error_report("--image-opts and --format are mutually exclusive"); + ret = -1; + goto out; + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename, true); + if (!opts) { + 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; @@ -3169,6 +3394,7 @@ static int img_amend(int argc, char **argv) BlockBackend *blk = NULL; BlockDriverState *bs = NULL; Error *local_err = NULL; + bool image_opts = false; cache = BDRV_DEFAULT_CACHE; for (;;) { @@ -3176,6 +3402,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}, + {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "ho:f:t:pq", @@ -3222,6 +3449,9 @@ static int img_amend(int argc, char **argv) exit(1); } break; + case OPTION_IMAGE_OPTS: + image_opts = true; + break; } } @@ -3262,7 +3492,22 @@ static int img_amend(int argc, char **argv) goto out; } - blk = img_open("image", filename, fmt, flags, true, quiet); + if (image_opts) { + if (fmt) { + error_report("--image-opts and --format are mutually exclusive"); + ret = -1; + goto out; + } + opts = qemu_opts_parse_noisily(qemu_find_opts("source"), + filename, true); + if (!opts) { + 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; @@ -3360,6 +3605,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/qemu-img.texi b/qemu-img.texi index da93272..f31e726 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -32,6 +32,12 @@ page for a description of the object properties. The only object type that it makes sense to define is the @code{secret} object, which is used to supply passwords and/or encryption keys. +@item --image-opts + +Indicates that the @var{filename} parameter is to be interpreted as a +full option string, not a plain filename. This parameter is mutually +exclusive with the @var{-f} and @var{-F} parameters. + @item fmt is the disk image format. It is guessed automatically in most cases. See below for a description of the supported disk formats.