qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH RFC 2/2] qemu-img: migrate to use qemu-arg


From: Leandro Dorileo
Subject: [Qemu-devel] [PATCH RFC 2/2] qemu-img: migrate to use qemu-arg
Date: Sat, 8 Mar 2014 15:47:18 -0300

Remove the arg parsing implementations using getopt and use qemu-arg.
Also remove the qemu-img-cmds.hx since it's now generated on building time,
adapted the build system to generate the .hx file using the qemu-img itself
using the qemu-arg internal command generate-hx.

Signed-off-by: Leandro Dorileo <address@hidden>
---
 .gitignore       |    1 +
 Makefile         |   12 +-
 qemu-img-cmds.hx |   77 ----
 qemu-img-descs.h |  128 ++++++
 qemu-img.c       | 1184 ++++++++++++++++++------------------------------------
 5 files changed, 531 insertions(+), 871 deletions(-)
 delete mode 100644 qemu-img-cmds.hx
 create mode 100644 qemu-img-descs.h

diff --git a/.gitignore b/.gitignore
index ef7019f..700e92d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -116,3 +116,4 @@ cscope.*
 tags
 TAGS
 *~
+qemu-img-cmds.hx
diff --git a/Makefile b/Makefile
index bd9cd4f..0f2f102 100644
--- a/Makefile
+++ b/Makefile
@@ -214,8 +214,6 @@ util/module.o-cflags = 
-D'CONFIG_BLOCK_MODULES=$(block-modules)'
 
 ######################################################################
 
-qemu-img.o: qemu-img-cmds.h
-
 qemu-img$(EXESUF): qemu-img.o $(block-obj-y) libqemuutil.a libqemustub.a
 qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) libqemuutil.a libqemustub.a
 qemu-io$(EXESUF): qemu-io.o $(block-obj-y) libqemuutil.a libqemustub.a
@@ -225,9 +223,6 @@ qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
 fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o 
fsdev/virtio-9p-marshal.o libqemuutil.a libqemustub.a
 fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
 
-qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
-       $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"  GEN  
 $@")
-
 qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
 qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated
 
@@ -272,7 +267,7 @@ clean:
        rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* 
*.pod *~ */*~
        rm -f fsdev/*.pod
        rm -rf .libs */.libs
-       rm -f qemu-img-cmds.h
+       rm -f qemu-img-cmds.hx
        @# May not be present in GENERATED_HEADERS
        rm -f trace/generated-tracers-dtrace.dtrace*
        rm -f trace/generated-tracers-dtrace.h*
@@ -442,7 +437,10 @@ qemu-monitor.texi: $(SRC_PATH)/hmp-commands.hx
 qmp-commands.txt: $(SRC_PATH)/qmp-commands.hx
        $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -q < $< > $@,"  GEN  
 $@")
 
-qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx
+qemu-img-cmds.hx: qemu-img$(EXESUF)
+       $(call quiet-command,$(SRC_PATH)/qemu-img generate-hx -h > 
$(SRC_PATH)/$@,"  GEN   $@")
+
+qemu-img-cmds.texi: qemu-img-cmds.hx
        $(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"  GEN  
 $@")
 
 qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
deleted file mode 100644
index d029609..0000000
--- a/qemu-img-cmds.hx
+++ /dev/null
@@ -1,77 +0,0 @@
-HXCOMM Use DEFHEADING() to define headings in both help text and texi
-HXCOMM Text between STEXI and ETEXI are copied to texi version and
-HXCOMM discarded from C version
-HXCOMM DEF(command, callback, arg_string) is used to construct
-HXCOMM command structures and help message.
-HXCOMM HXCOMM can be used for comments, discarded from both texi and C
-
-STEXI
address@hidden @option
-ETEXI
-
-DEF("check", img_check,
-    "check [-q] [-f fmt] [--output=ofmt]  [-r [leaks | all]] filename")
-STEXI
address@hidden check [-q] [-f @var{fmt}] address@hidden [-r [leaks | all]] 
@var{filename}
-ETEXI
-
-DEF("create", img_create,
-    "create [-q] [-f fmt] [-o options] filename [size]")
-STEXI
address@hidden create [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} 
address@hidden
-ETEXI
-
-DEF("commit", img_commit,
-    "commit [-q] [-f fmt] [-t cache] filename")
-STEXI
address@hidden commit [-q] [-f @var{fmt}] [-t @var{cache}] @var{filename}
-ETEXI
-
-DEF("compare", img_compare,
-    "compare [-f fmt] [-F fmt] [-p] [-q] [-s] filename1 filename2")
-STEXI
address@hidden compare [-f @var{fmt}] [-F @var{fmt}] [-p] [-q] [-s] 
@var{filename1} @var{filename2}
-ETEXI
-
-DEF("convert", img_convert,
-    "convert [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-O output_fmt] [-o 
options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename 
[filename2 [...]] output_filename")
-STEXI
address@hidden convert [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-O 
@var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l 
@var{snapshot_param}] [-S @var{sparse_size}] @var{filename} address@hidden 
[...]] @var{output_filename}
-ETEXI
-
-DEF("info", img_info,
-    "info [-f fmt] [--output=ofmt] [--backing-chain] filename")
-STEXI
address@hidden info [-f @var{fmt}] address@hidden [--backing-chain] 
@var{filename}
-ETEXI
-
-DEF("map", img_map,
-    "map [-f fmt] [--output=ofmt] filename")
-STEXI
address@hidden map [-f @var{fmt}] address@hidden @var{filename}
-ETEXI
-
-DEF("snapshot", img_snapshot,
-    "snapshot [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
-STEXI
address@hidden snapshot [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d 
@var{snapshot}] @var{filename}
-ETEXI
-
-DEF("rebase", img_rebase,
-    "rebase [-q] [-f fmt] [-t cache] [-p] [-u] -b backing_file [-F 
backing_fmt] filename")
-STEXI
address@hidden rebase [-q] [-f @var{fmt}] [-t @var{cache}] [-p] [-u] -b 
@var{backing_file} [-F @var{backing_fmt}] @var{filename}
-ETEXI
-
-DEF("resize", img_resize,
-    "resize [-q] filename [+ | -]size")
-STEXI
address@hidden resize [-q] @var{filename} [+ | address@hidden
-ETEXI
-
-DEF("amend", img_amend,
-    "amend [-q] [-f fmt] -o options filename")
-STEXI
address@hidden amend [-q] [-f @var{fmt}] -o @var{options} @var{filename}
address@hidden table
-ETEXI
diff --git a/qemu-img-descs.h b/qemu-img-descs.h
new file mode 100644
index 0000000..5725161
--- /dev/null
+++ b/qemu-img-descs.h
@@ -0,0 +1,128 @@
+#ifndef _QEMU_IMG_DESCS_H_
+#define _QEMU_IMG_DESCS_H_
+
+#define OPT_POS_FILENAME_HELP                   \
+    "the specified disk image file name"        \
+
+#define OPT_POS_SIZE_HELP                                               \
+    "the disk image size in bytes. Optional suffixes 'k' or 'K' "       \
+    "(kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M), "  \
+    "'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E'"              \
+    " (exabyte, 1024P)  are supported. 'b' is ignored"                 \
+
+#define OPT_INC_SHIK_HELP                                               \
+    "grow or shrink the image size i.e +1G to increase it 1G or -1G "   \
+    "to shirink it 1G"                                                  \
+
+#define OPT_BACKING_FILE_HELP                   \
+    "the backing file name"                     \
+
+#define OPT_BACKING_FMT_HELP "the backing file format"
+
+#define OPT_FMT_HELP                                                    \
+    "the disk image format. It is automatically guessed in most cases"  \
+
+#define OPT_SPARSE_SIZE_HELP                                            \
+    "indicates the consecutive number of bytes that must contain only " \
+    "zeros for qemu-img to create a sparse image during conversion. "   \
+    "This value is rounded down to the nearest 512 bytes. You may"      \
+    "use the common size suffixes like \"k\" for kilobytes."            \
+
+#define OPT_SNAPSHOT_ID_NAME_HELP "a snapshot id or name"
+
+#define OPT_OPTIONS                                                     \
+    "a comma separated list of format specific options "                \
+    "in a name=value format. Use -o ? for an overview of the options "  \
+    "supported by the used format"                                      \
+
+#define OPT_CACHE_HELP                                                  \
+    "the cache mode used to write the output disk image, the valid "    \
+    "options are: 'none', 'writeback' (default, except for convert), "  \
+    "'writethrough', 'directsync' and 'unsafe' (default for convert)"   \
+
+
+#define OPT_COMPRESS_HELP                                               \
+    "indicates that target image must be compressed (qcow format only)" \
+
+#define OPT_OFMT_HELP                           \
+    "the output format"                         \
+
+#define OPT_OUT_BASE_IMG_HELP                   \
+    "the output base image"                     \
+
+#define OPT_SNAPSHOT_OPT_HELP                   \
+    "snapshot option like snapshot.*"           \
+
+#define OPT_OUTPUT_HELP                                                 \
+    "takes the format in which the output must be "                     \
+    "done (human or json)"                                              \
+
+#define OPT_BACKING_CHAIN_HELP                                          \
+    "will enumerate information about backing files in a disk"          \
+    "image chain"                                                       \
+
+#define OPT_QUIET_HELP                                                  \
+    "use Quiet mode - do not print any output (except errors)"          \
+
+#define OPT_REPAIR_HELP                                                 \
+    "tries to repair any inconsistencies that are found during "        \
+    "the check. '-r leaks' repairs only cluster leaks, whereas "        \
+    "'-r all' fixes all kinds of errors, with a higher risk of "        \
+    "choosing the wrong fix or hiding corruption that has "             \
+    "already occurred."                                                 \
+
+#define OPT_FMT2_HELP                           \
+    "second image format"                       \
+
+#define OPT_PROGRESS_HELP                       \
+    "show progress of command"                  \
+
+#define OPT_STRICT_HELP                                                 \
+    "run in Strict mode - fail on different image size or "             \
+    "sector allocation"                                                 \
+
+#define OPT_SKIP_HELP                                                 \
+    "skips the target volume creation (useful if the volume "         \
+    "is created prior to running qemu-img)"                           \
+
+#define OPT_SNAPSHOT_PARAM_HELP                 \
+    "the snapshot params"                       \
+
+#define OPT_SNAPSHOT_LIST_HELP                  \
+    "lists all snapshots in the given image"    \
+
+#define OPT_SNAPSHOT_APPLY_HELP                         \
+    "applies a snapshot (revert disk to saved state)"   \
+
+#define OPT_SNAPSHOT_CREATE_HELP                \
+    "create a snapshot"                         \
+
+#define OPT_SNAPSHOT_DELETE_HELP                \
+    "delete a snapshot"                         \
+
+#define OPT_UNSAFE_HELP                                                 \
+    "enables unsafe rebasing. It is assumed that old "                  \
+    "and new backing file match exactly. The image doesn't "            \
+    "need a working backing file before rebasing in this case "         \
+    "(useful for renaming the backing file) "                           \
+
+#define OPT_CREATE_E_DEP_HELP                                           \
+    "option -e is deprecated, please use \'-o encryption\' instead"     \
+
+#define OPT_CREATE_6_DEP_HELP                                           \
+    "option -6 is deprecated, please use \'-o compat6\' instead"        \
+
+#define QEMU_IMG_CHECK_HELP "check image integrity/consistency"
+#define QEMU_IMG_CREATE_HELP "create a new image file"
+#define QEMU_IMG_COMMIT_HELP "commit COW file into raw image"
+#define QEMU_IMG_COMPARE_HELP "compare 2 image files"
+#define QEMU_IMG_CONVERT_HELP "convert N image files or snapshot to"    \
+    " a new format"                                                     \
+#define QEMU_IMG_INFO_HELP "show image file informations"
+#define QEMU_IMG_MAP_HELP "dump the image file metadata"
+#define QEMU_IMG_SNAPSHOT_HELP "list, apply, create or delete snapshots"
+#define QEMU_IMG_REBASE_HELP "changes the backing file of an image"
+#define QEMU_IMG_RESIZE_HELP "resize an image file"
+#define QEMU_IMG_AMEND_HELP "amend the image format"
+
+#endif /* _QEMU_IMG_DESCS_H_ */
diff --git a/qemu-img.c b/qemu-img.c
index 2e40cc1..bafe439 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -31,6 +31,8 @@
 #include "sysemu/sysemu.h"
 #include "block/block_int.h"
 #include "block/qapi.h"
+#include "qemu/qemu-arg.h"
+#include "qemu-img-descs.h"
 #include <getopt.h>
 
 typedef struct img_cmd_t {
@@ -52,85 +54,151 @@ 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)
-{
-    printf(" %s", name);
-}
+static bool _quiet, _progress, _strict, _skip_create, _backing_chain;
+static bool _snapshot_list, _unsafe, _compress;
+
+static char *_filename, *_filename2, *_fmt, *_ofmt, *_fmt2;
+static char *_rep, *_options, *_size, *_cache, *_sparse_size;
+static char *_snapshot_name, *_snapshot_apply, *_snapshot_create;
+static char *_snapshot_delete;
+static char *_backing_file, *_backing_fmt, *_output, *_out_baseimg;
+static char *_out_basefmt, **_filename_list;
+
+#define PROLOGUE                                                        \
+    "qemu-img version "QEMU_VERSION", Copyright (c) 2004-2008 "         \
+    "Fabrice Bellard\nQEMU disk image utility"                          \
+
+static QemuArgOpt _check_args[] = {
+    OPT_BOOL('q', NULL, OPT_QUIET_HELP, &_quiet, false),
+    OPT_STR('f', "format", "fmt", OPT_FMT_HELP, &_fmt, NULL),
+    OPT_STR(0, "output", "ofmt", OPT_OUTPUT_HELP, &_output, "human"),
+    OPT_STR('r', "repair", "[leaks | all]", OPT_REPAIR_HELP, &_rep, "all"),
+    OPT_POS_REQ("filename", OPT_POS_FILENAME_HELP, &_filename, NULL),
+    OPT_SENTINEL
+};
 
-/* Please keep in synch with qemu-img.texi */
-static void help(void)
-{
-    const char *help_msg =
-           "qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice 
Bellard\n"
-           "usage: qemu-img command [command options]\n"
-           "QEMU disk image utility\n"
-           "\n"
-           "Command syntax:\n"
-#define DEF(option, callback, arg_string)        \
-           "  " arg_string "\n"
-#include "qemu-img-cmds.h"
-#undef DEF
-#undef GEN_DOCS
-           "\n"
-           "Command parameters:\n"
-           "  'filename' is a disk image filename\n"
-           "  'fmt' is the disk image format. It is guessed automatically in 
most cases\n"
-           "  'cache' is the cache mode used to write the output disk image, 
the valid\n"
-           "    options are: 'none', 'writeback' (default, except for 
convert), 'writethrough',\n"
-           "    'directsync' and 'unsafe' (default for convert)\n"
-           "  'size' is the disk image size in bytes. Optional suffixes\n"
-           "    'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' 
(gigabyte, 1024M),\n"
-           "    'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E' (exabyte, 
1024P)  are\n"
-           "    supported. 'b' is ignored.\n"
-           "  'output_filename' is the destination disk image filename\n"
-           "  'output_fmt' is the destination format\n"
-           "  'options' is a comma separated list of format specific options 
in a\n"
-           "    name=value format. Use -o ? for an overview of the options 
supported by the\n"
-           "    used format\n"
-           "  'snapshot_param' is param used for internal snapshot, format\n"
-           "    is 'snapshot.id=[ID],snapshot.name=[NAME]', or\n"
-           "    '[ID_OR_NAME]'\n"
-           "  'snapshot_id_or_name' is deprecated, use 'snapshot_param'\n"
-           "    instead\n"
-           "  '-c' indicates that target image must be compressed (qcow format 
only)\n"
-           "  '-u' enables unsafe rebasing. It is assumed that old and new 
backing file\n"
-           "       match exactly. The image doesn't need a working backing 
file before\n"
-           "       rebasing in this case (useful for renaming the backing 
file)\n"
-           "  '-h' with or without a command shows this help and lists the 
supported formats\n"
-           "  '-p' show progress of command (only certain commands)\n"
-           "  '-q' use Quiet mode - do not print any output (except errors)\n"
-           "  '-S' indicates the consecutive number of bytes (defaults to 4k) 
that must\n"
-           "       contain only zeros for qemu-img to create a sparse image 
during\n"
-           "       conversion. If the number of bytes is 0, the source will 
not be scanned for\n"
-           "       unallocated or zero sectors, and the destination image will 
always be\n"
-           "       fully allocated\n"
-           "  '--output' takes the format in which the output must be done 
(human or json)\n"
-           "  '-n' skips the target volume creation (useful if the volume is 
created\n"
-           "       prior to running qemu-img)\n"
-           "\n"
-           "Parameters to check subcommand:\n"
-           "  '-r' tries to repair any inconsistencies that are found during 
the check.\n"
-           "       '-r leaks' repairs only cluster leaks, whereas '-r all' 
fixes all\n"
-           "       kinds of errors, with a higher risk of choosing the wrong 
fix or\n"
-           "       hiding corruption that has already occurred.\n"
-           "\n"
-           "Parameters to snapshot subcommand:\n"
-           "  'snapshot' is the name of the snapshot to create, apply or 
delete\n"
-           "  '-a' applies a snapshot (revert disk to saved state)\n"
-           "  '-c' creates a snapshot\n"
-           "  '-d' deletes a snapshot\n"
-           "  '-l' lists all snapshots in the given image\n"
-           "\n"
-           "Parameters to compare subcommand:\n"
-           "  '-f' first image format\n"
-           "  '-F' second image format\n"
-           "  '-s' run in Strict mode - fail on different image size or sector 
allocation\n";
-
-    printf("%s\nSupported formats:", help_msg);
-    bdrv_iterate_format(format_print, NULL);
-    printf("\n");
-    exit(1);
-}
+static QemuArgOpt _create_args[] = {
+    OPT_BOOL('q', NULL, OPT_QUIET_HELP, &_quiet, NULL),
+    OPT_STR('F', NULL, "fmt", OPT_BACKING_FMT_HELP, &_backing_fmt, NULL),
+    OPT_STR('b', NULL, "filename", OPT_BACKING_FILE_HELP, &_backing_file, 
NULL),
+    OPT_STR('f', NULL, "fmt", OPT_FMT_HELP, &_fmt, "raw"),
+    OPT_CUMUL_STR('o', NULL, "options", OPT_OPTIONS, &_options, NULL),
+    OPT_DEP('e', NULL, OPT_CREATE_E_DEP_HELP),
+    OPT_DEP('6', NULL, OPT_CREATE_6_DEP_HELP),
+    OPT_POS_REQ("filename", OPT_POS_FILENAME_HELP, &_filename, NULL),
+    OPT_POS_REQ("size", OPT_POS_SIZE_HELP, &_size, NULL),
+    OPT_SENTINEL
+};
+
+static QemuArgOpt _commit_args[] = {
+    OPT_BOOL('q', NULL, OPT_QUIET_HELP, &_quiet, false),
+    OPT_STR('f', NULL, "fmt", OPT_FMT_HELP, &_fmt, NULL),
+    OPT_STR('t', NULL, "cache", OPT_CACHE_HELP, &_cache, BDRV_DEFAULT_CACHE),
+    OPT_POS_REQ("filename", OPT_POS_FILENAME_HELP, &_filename, NULL),
+    OPT_SENTINEL
+};
+
+static QemuArgOpt _compare_args[] = {
+    OPT_STR('f', NULL, "fmt", OPT_FMT_HELP, &_fmt, NULL),
+    OPT_STR('F', NULL, "fmt", OPT_FMT2_HELP, &_fmt2, NULL),
+    OPT_BOOL('p', NULL, OPT_PROGRESS_HELP, &_progress, false),
+    OPT_BOOL('q', NULL, OPT_QUIET_HELP, &_quiet, false),
+    OPT_BOOL('s', NULL, OPT_STRICT_HELP, &_strict, false),
+    OPT_POS_REQ("filename1", OPT_POS_FILENAME_HELP, &_filename, NULL),
+    OPT_POS_REQ("filename2", OPT_POS_FILENAME_HELP, &_filename2, NULL),
+    OPT_SENTINEL
+};
+
+static QemuArgOpt _convert_args[] = {
+    OPT_STR('f', NULL, "fmt", OPT_FMT_HELP, &_fmt, NULL),
+    OPT_STR('O', NULL, "output_fmt", OPT_OFMT_HELP, &_ofmt, "raw"),
+    OPT_STR('B', NULL, "output_base_img", OPT_OUT_BASE_IMG_HELP,
+            &_out_baseimg, NULL),
+    OPT_BOOL('c', NULL, OPT_COMPRESS_HELP, &_compress, false),
+    OPT_DEP('e', NULL, OPT_CREATE_E_DEP_HELP),
+    OPT_DEP('6', NULL, OPT_CREATE_6_DEP_HELP),
+    OPT_CUMUL_STR('o', NULL, "options", OPT_OPTIONS, &_options, NULL),
+    OPT_CUMUL_STR('s', NULL, "snapshot_name", OPT_SNAPSHOT_ID_NAME_HELP,
+                  &_snapshot_name, NULL),
+    OPT_CUMUL_STR('l', NULL, "snapshot_opt", OPT_SNAPSHOT_OPT_HELP,
+                  &_snapshot_name, NULL),
+    OPT_CUMUL_STR('S', NULL, "sparse_size", OPT_SPARSE_SIZE_HELP, 
&_sparse_size,
+                  NULL),
+    OPT_BOOL('p', NULL, OPT_PROGRESS_HELP, &_progress, false),
+    OPT_STR('t', NULL, "cache", OPT_CACHE_HELP, &_cache, "unsafe"),
+    OPT_BOOL('q', NULL, OPT_QUIET_HELP, &_quiet, false),
+    OPT_BOOL('n', NULL, OPT_SKIP_HELP, &_skip_create, false),
+    OPT_POS_LIST("filename [filename2 [...]] output_filename",
+                 OPT_POS_FILENAME_HELP, &_filename_list, NULL),
+    OPT_SENTINEL
+};
+
+static QemuArgOpt _info_args[] = {
+    OPT_STR('f', NULL, "fmt", OPT_FMT_HELP, &_fmt, NULL),
+    OPT_STR(0, "output", "ofmt", OPT_OUTPUT_HELP, &_ofmt, NULL),
+    OPT_BOOL(0, "backing-chain", OPT_BACKING_CHAIN_HELP, &_backing_chain,
+             false),
+    OPT_POS("filename", OPT_POS_FILENAME_HELP, &_filename, NULL),
+    OPT_SENTINEL
+};
+
+static QemuArgOpt _map_args[] = {
+    OPT_STR('f', NULL, "fmt", OPT_FMT_HELP, &_fmt, NULL),
+    OPT_STR(0, "output", "ofmt", OPT_OUTPUT_HELP, &_ofmt, NULL),
+    OPT_POS_REQ("filename", OPT_POS_FILENAME_HELP, &_filename, NULL),
+    OPT_SENTINEL
+};
+
+static QemuArgOpt _snapshot_action_args[] = {
+    OPT_BOOL('l', NULL, OPT_SNAPSHOT_LIST_HELP, &_snapshot_list, false),
+    OPT_STR('a', NULL, "snapshot", OPT_SNAPSHOT_APPLY_HELP,
+            &_snapshot_apply, NULL),
+    OPT_STR('c', NULL, "snapshot", OPT_SNAPSHOT_CREATE_HELP, &_snapshot_create,
+            NULL),
+    OPT_STR('d', NULL, "snapshot", OPT_SNAPSHOT_DELETE_HELP, &_snapshot_delete,
+            NULL),
+    OPT_SENTINEL
+};
+
+static QemuArgOpt _snapshot_args[] = {
+    OPT_BOOL('q', NULL, OPT_QUIET_HELP, &_quiet, false),
+    OPT_POS_REQ("filename", OPT_POS_FILENAME_HELP, &_filename, NULL),
+    OPT_SENTINEL
+};
+
+static QemuArgOpt *_snapshot_mutual_groups[] = {
+    _snapshot_action_args,
+    OPT_MUTUAL_GROUP_SENTINEL
+};
+
+static QemuArgOpt _rebase_args[] = {
+    OPT_BOOL('q', NULL, OPT_QUIET_HELP, &_quiet, false),
+    OPT_STR('f', NULL, "fmt", OPT_FMT_HELP, &_fmt, NULL),
+    OPT_STR('t', NULL, "cache", OPT_CACHE_HELP, &_cache, BDRV_DEFAULT_CACHE),
+    OPT_BOOL('p', NULL, OPT_PROGRESS_HELP, &_progress, false),
+    OPT_BOOL('u', NULL, OPT_UNSAFE_HELP, &_unsafe, false),
+    OPT_STR('b', NULL, "backing_file", OPT_BACKING_FILE_HELP, &_backing_file,
+            NULL),
+    OPT_STR('F', NULL, "backing_fmt", OPT_BACKING_FMT_HELP, &_out_basefmt,
+            NULL),
+    OPT_POS_REQ("filename", OPT_POS_FILENAME_HELP, &_filename, NULL),
+    OPT_SENTINEL
+};
+
+static QemuArgOpt _resize_args[] = {
+    OPT_BOOL('q', NULL, OPT_QUIET_HELP, &_quiet, false),
+    OPT_POS_REQ("filename", OPT_POS_FILENAME_HELP, &_filename, NULL),
+    OPT_POS_REQ("[+ | -]size", OPT_INC_SHIK_HELP, &_size, NULL),
+    OPT_SENTINEL
+};
+
+static QemuArgOpt _amend_args[] = {
+    OPT_BOOL('q', NULL, OPT_QUIET_HELP, &_quiet, false),
+    OPT_STR('f', NULL, "fmt", OPT_FMT_HELP, &_fmt, NULL),
+    OPT_CUMUL_STR_REQ('o', NULL, "options", OPT_OPTIONS, &_options, NULL),
+    OPT_POS_REQ("filename", OPT_POS_FILENAME_HELP, &_filename, NULL),
+    OPT_SENTINEL
+};
 
 static int GCC_FMT_ATTR(2, 3) qprintf(bool quiet, const char *fmt, ...)
 {
@@ -332,81 +400,19 @@ static int add_old_style_options(const char *fmt, 
QEMUOptionParameter *list,
     return 0;
 }
 
-static int img_create(int argc, char **argv)
+static int img_create(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
-    int c;
     uint64_t img_size = -1;
-    const char *fmt = "raw";
-    const char *base_fmt = NULL;
-    const char *filename;
-    const char *base_filename = NULL;
-    char *options = NULL;
     Error *local_err = NULL;
-    bool quiet = false;
 
-    for(;;) {
-        c = getopt(argc, argv, "F:b:f:he6o:q");
-        if (c == -1) {
-            break;
-        }
-        switch(c) {
-        case '?':
-        case 'h':
-            help();
-            break;
-        case 'F':
-            base_fmt = optarg;
-            break;
-        case 'b':
-            base_filename = optarg;
-            break;
-        case 'f':
-            fmt = optarg;
-            break;
-        case 'e':
-            error_report("option -e is deprecated, please use \'-o "
-                  "encryption\' instead!");
-            goto fail;
-        case '6':
-            error_report("option -6 is deprecated, please use \'-o "
-                  "compat6\' instead!");
-            goto fail;
-        case 'o':
-            if (!is_valid_option_list(optarg)) {
-                error_report("Invalid option list: %s", optarg);
-                goto fail;
-            }
-            if (!options) {
-                options = g_strdup(optarg);
-            } else {
-                char *old_options = options;
-                options = g_strdup_printf("%s,%s", options, optarg);
-                g_free(old_options);
-            }
-            break;
-        case 'q':
-            quiet = true;
-            break;
-        }
-    }
-
-    /* Get the filename */
-    filename = (optind < argc) ? argv[optind] : NULL;
-    if (options && has_help_option(options)) {
-        g_free(options);
-        return print_block_option_help(filename, fmt);
+    if (_options && has_help_option(_options)) {
+        return print_block_option_help(_filename, _fmt);
     }
 
-    if (optind >= argc) {
-        help();
-    }
-    optind++;
-
-    /* Get image size, if specified */
-    if (optind < argc) {
+    if (_size) {
         int64_t sval;
         char *end;
-        sval = strtosz_suffix(argv[optind++], &end, STRTOSZ_DEFSUFFIX_B);
+        sval = strtosz_suffix(_size, &end, STRTOSZ_DEFSUFFIX_B);
         if (sval < 0 || *end) {
             if (sval == -ERANGE) {
                 error_report("Image size must be less than 8 EiB!");
@@ -420,23 +426,18 @@ static int img_create(int argc, char **argv)
         }
         img_size = (uint64_t)sval;
     }
-    if (optind != argc) {
-        help();
-    }
 
-    bdrv_img_create(filename, fmt, base_filename, base_fmt,
-                    options, img_size, BDRV_O_FLAGS, &local_err, quiet);
+    bdrv_img_create(_filename, _fmt, _backing_file, _backing_fmt,
+                    _options, img_size, BDRV_O_FLAGS, &local_err, _quiet);
     if (local_err) {
-        error_report("%s: %s", filename, error_get_pretty(local_err));
+        error_report("%s: %s", _filename, error_get_pretty(local_err));
         error_free(local_err);
         goto fail;
     }
 
-    g_free(options);
     return 0;
 
 fail:
-    g_free(options);
     return 1;
 }
 
@@ -547,81 +548,44 @@ static int collect_image_check(BlockDriverState *bs,
  * 2 - Check completed, image is corrupted
  * 3 - Check completed, image has leaked clusters, but is good otherwise
  */
-static int img_check(int argc, char **argv)
+static int img_check(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
-    int c, ret;
+    int ret;
     OutputFormat output_format = OFORMAT_HUMAN;
-    const char *filename, *fmt, *output;
     BlockDriverState *bs;
     int fix = 0;
     int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
     ImageCheck *check;
-    bool quiet = false;
 
-    fmt = NULL;
-    output = NULL;
-    for(;;) {
-        int option_index = 0;
-        static const struct option long_options[] = {
-            {"help", no_argument, 0, 'h'},
-            {"format", required_argument, 0, 'f'},
-            {"repair", no_argument, 0, 'r'},
-            {"output", required_argument, 0, OPTION_OUTPUT},
-            {0, 0, 0, 0}
-        };
-        c = getopt_long(argc, argv, "f:hr:q",
-                        long_options, &option_index);
-        if (c == -1) {
-            break;
-        }
-        switch(c) {
-        case '?':
-        case 'h':
-            help();
-            break;
-        case 'f':
-            fmt = optarg;
-            break;
-        case 'r':
-            flags |= BDRV_O_RDWR;
-
-            if (!strcmp(optarg, "leaks")) {
-                fix = BDRV_FIX_LEAKS;
-            } else if (!strcmp(optarg, "all")) {
-                fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
-            } else {
-                help();
-            }
-            break;
-        case OPTION_OUTPUT:
-            output = optarg;
-            break;
-        case 'q':
-            quiet = true;
-            break;
+    if (_rep) {
+        flags |= BDRV_O_RDWR;
+        if (!strcmp(_rep, "leaks")) {
+            fix = BDRV_FIX_LEAKS;
+        } else if (!strcmp(_rep, "all")) {
+            fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
+        } else {
+            error_report("[-r | --repair] must be used with leak or all as "
+                         "argument.");
+            return -1;
         }
     }
-    if (optind != argc - 1) {
-        help();
-    }
-    filename = argv[optind++];
 
-    if (output && !strcmp(output, "json")) {
+    if (!strcmp(_output, "json")) {
         output_format = OFORMAT_JSON;
-    } else if (output && !strcmp(output, "human")) {
+    } else if (!strcmp(_output, "human")) {
         output_format = OFORMAT_HUMAN;
-    } else if (output) {
+    } else if (_output) {
         error_report("--output must be used with human or json as argument.");
-        return 1;
+        return -1;
     }
 
-    bs = bdrv_new_open(filename, fmt, flags, true, quiet);
+    bs = bdrv_new_open(_filename, _fmt, flags, true, _quiet);
     if (!bs) {
-        return 1;
+        return -1;
     }
 
     check = g_new0(ImageCheck, 1);
-    ret = collect_image_check(bs, check, filename, fmt, fix);
+    ret = collect_image_check(bs, check, _filename, _fmt, fix);
 
     if (ret == -ENOTSUP) {
         if (output_format == OFORMAT_HUMAN) {
@@ -638,7 +602,7 @@ static int img_check(int argc, char **argv)
         corruptions_fixed   = check->corruptions_fixed;
 
         if (output_format == OFORMAT_HUMAN) {
-            qprintf(quiet,
+            qprintf(_quiet,
                     "The following inconsistencies were found and 
repaired:\n\n"
                     "    %" PRId64 " leaked clusters\n"
                     "    %" PRId64 " corruptions\n\n"
@@ -647,7 +611,7 @@ static int img_check(int argc, char **argv)
                     check->corruptions_fixed);
         }
 
-        ret = collect_image_check(bs, check, filename, fmt, 0);
+        ret = collect_image_check(bs, check, _filename, _fmt, 0);
 
         check->leaks_fixed          = leaks_fixed;
         check->corruptions_fixed    = corruptions_fixed;
@@ -655,10 +619,10 @@ static int img_check(int argc, char **argv)
 
     switch (output_format) {
     case OFORMAT_HUMAN:
-        dump_human_image_check(check, quiet);
+        dump_human_image_check(check, _quiet);
         break;
     case OFORMAT_JSON:
-        dump_json_image_check(check, quiet);
+        dump_json_image_check(check, _quiet);
         break;
     }
 
@@ -682,56 +646,26 @@ fail:
     return ret;
 }
 
-static int img_commit(int argc, char **argv)
+static int img_commit(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
-    int c, ret, flags;
-    const char *filename, *fmt, *cache;
+    int ret, flags;
     BlockDriverState *bs;
-    bool quiet = false;
-
-    fmt = NULL;
-    cache = BDRV_DEFAULT_CACHE;
-    for(;;) {
-        c = getopt(argc, argv, "f:ht:q");
-        if (c == -1) {
-            break;
-        }
-        switch(c) {
-        case '?':
-        case 'h':
-            help();
-            break;
-        case 'f':
-            fmt = optarg;
-            break;
-        case 't':
-            cache = optarg;
-            break;
-        case 'q':
-            quiet = true;
-            break;
-        }
-    }
-    if (optind != argc - 1) {
-        help();
-    }
-    filename = argv[optind++];
 
     flags = BDRV_O_RDWR;
-    ret = bdrv_parse_cache_flags(cache, &flags);
+    ret = bdrv_parse_cache_flags(_cache, &flags);
     if (ret < 0) {
-        error_report("Invalid cache option: %s", cache);
+        error_report("Invalid cache option: %s", _cache);
         return -1;
     }
 
-    bs = bdrv_new_open(filename, fmt, flags, true, quiet);
+    bs = bdrv_new_open(_filename, _fmt, flags, true, _quiet);
     if (!bs) {
         return 1;
     }
     ret = bdrv_commit(bs);
     switch(ret) {
     case 0:
-        qprintf(quiet, "Image committed.\n");
+        qprintf(_quiet, "Image committed.\n");
         break;
     case -ENOENT:
         error_report("No disk inserted");
@@ -907,76 +841,39 @@ static int check_empty_sectors(BlockDriverState *bs, 
int64_t sect_num,
  * 1 - Images differ
  * >1 - Error occurred
  */
-static int img_compare(int argc, char **argv)
+static int img_compare(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
-    const char *fmt1 = NULL, *fmt2 = NULL, *filename1, *filename2;
     BlockDriverState *bs1, *bs2;
     int64_t total_sectors1, total_sectors2;
     uint8_t *buf1 = NULL, *buf2 = NULL;
     int pnum1, pnum2;
     int allocated1, allocated2;
     int ret = 0; /* return value - 0 Ident, 1 Different, >1 Error */
-    bool progress = false, quiet = false, strict = false;
     int64_t total_sectors;
     int64_t sector_num = 0;
     int64_t nb_sectors;
-    int c, pnum;
+    int pnum;
     uint64_t bs_sectors;
     uint64_t progress_base;
 
-    for (;;) {
-        c = getopt(argc, argv, "hpf:F:sq");
-        if (c == -1) {
-            break;
-        }
-        switch (c) {
-        case '?':
-        case 'h':
-            help();
-            break;
-        case 'f':
-            fmt1 = optarg;
-            break;
-        case 'F':
-            fmt2 = optarg;
-            break;
-        case 'p':
-            progress = true;
-            break;
-        case 'q':
-            quiet = true;
-            break;
-        case 's':
-            strict = true;
-            break;
-        }
-    }
-
     /* Progress is not shown in Quiet mode */
-    if (quiet) {
-        progress = false;
-    }
-
-
-    if (optind != argc - 2) {
-        help();
+    if (_quiet) {
+        _progress = false;
     }
-    filename1 = argv[optind++];
-    filename2 = argv[optind++];
 
     /* Initialize before goto out */
-    qemu_progress_init(progress, 2.0);
+    qemu_progress_init(_progress, 2.0);
 
-    bs1 = bdrv_new_open(filename1, fmt1, BDRV_O_FLAGS, true, quiet);
+    bs1 = bdrv_new_open(_filename, _fmt, BDRV_O_FLAGS, true, _quiet);
     if (!bs1) {
-        error_report("Can't open file %s", filename1);
+        error_report("Can't open file %s", _filename);
         ret = 2;
         goto out3;
     }
 
-    bs2 = bdrv_new_open(filename2, fmt2, BDRV_O_FLAGS, true, quiet);
+    bs2 = bdrv_new_open(_filename2, _fmt2, BDRV_O_FLAGS, true, _quiet);
     if (!bs2) {
-        error_report("Can't open file %s", filename2);
+        error_report("Can't open file %s", _filename2);
         ret = 2;
         goto out2;
     }
@@ -992,9 +889,9 @@ static int img_compare(int argc, char **argv)
 
     qemu_progress_print(0, 100);
 
-    if (strict && total_sectors1 != total_sectors2) {
+    if (_strict && total_sectors1 != total_sectors2) {
         ret = 1;
-        qprintf(quiet, "Strict mode: Image size mismatch!\n");
+        qprintf(_quiet, "Strict mode: Image size mismatch!\n");
         goto out;
     }
 
@@ -1007,7 +904,7 @@ static int img_compare(int argc, char **argv)
                                              &pnum1);
         if (allocated1 < 0) {
             ret = 3;
-            error_report("Sector allocation test failed for %s", filename1);
+            error_report("Sector allocation test failed for %s", _filename);
             goto out;
         }
 
@@ -1015,7 +912,7 @@ static int img_compare(int argc, char **argv)
                                              &pnum2);
         if (allocated2 < 0) {
             ret = 3;
-            error_report("Sector allocation test failed for %s", filename2);
+            error_report("Sector allocation test failed for %s", _filename2);
             goto out;
         }
         nb_sectors = MIN(pnum1, pnum2);
@@ -1025,7 +922,7 @@ static int img_compare(int argc, char **argv)
                 ret = bdrv_read(bs1, sector_num, buf1, nb_sectors);
                 if (ret < 0) {
                     error_report("Error while reading offset %" PRId64 " of 
%s:"
-                                 " %s", sectors_to_bytes(sector_num), 
filename1,
+                                 " %s", sectors_to_bytes(sector_num), 
_filename,
                                  strerror(-ret));
                     ret = 4;
                     goto out;
@@ -1034,13 +931,13 @@ static int img_compare(int argc, char **argv)
                 if (ret < 0) {
                     error_report("Error while reading offset %" PRId64
                                  " of %s: %s", sectors_to_bytes(sector_num),
-                                 filename2, strerror(-ret));
+                                 _filename2, strerror(-ret));
                     ret = 4;
                     goto out;
                 }
                 ret = compare_sectors(buf1, buf2, nb_sectors, &pnum);
                 if (ret || pnum != nb_sectors) {
-                    qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
+                    qprintf(_quiet, "Content mismatch at offset %" PRId64 
"!\n",
                             sectors_to_bytes(
                                 ret ? sector_num : sector_num + pnum));
                     ret = 1;
@@ -1048,9 +945,9 @@ static int img_compare(int argc, char **argv)
                 }
             }
         } else {
-            if (strict) {
+            if (_strict) {
                 ret = 1;
-                qprintf(quiet, "Strict mode: Offset %" PRId64
+                qprintf(_quiet, "Strict mode: Offset %" PRId64
                         " allocation mismatch!\n",
                         sectors_to_bytes(sector_num));
                 goto out;
@@ -1058,10 +955,10 @@ static int img_compare(int argc, char **argv)
 
             if (allocated1) {
                 ret = check_empty_sectors(bs1, sector_num, nb_sectors,
-                                          filename1, buf1, quiet);
+                                          _filename, buf1, _quiet);
             } else {
                 ret = check_empty_sectors(bs2, sector_num, nb_sectors,
-                                          filename2, buf1, quiet);
+                                          _filename2, buf1, _quiet);
             }
             if (ret) {
                 if (ret < 0) {
@@ -1081,15 +978,15 @@ static int img_compare(int argc, char **argv)
         int64_t total_sectors_over;
         const char *filename_over;
 
-        qprintf(quiet, "Warning: Image size mismatch!\n");
+        qprintf(_quiet, "Warning: Image size mismatch!\n");
         if (total_sectors1 > total_sectors2) {
             total_sectors_over = total_sectors1;
             bs_over = bs1;
-            filename_over = filename1;
+            filename_over = _filename;
         } else {
             total_sectors_over = total_sectors2;
             bs_over = bs2;
-            filename_over = filename2;
+            filename_over = _filename2;
         }
 
         for (;;) {
@@ -1109,7 +1006,7 @@ static int img_compare(int argc, char **argv)
             nb_sectors = pnum;
             if (ret) {
                 ret = check_empty_sectors(bs_over, sector_num, nb_sectors,
-                                          filename_over, buf1, quiet);
+                                          filename_over, buf1, _quiet);
                 if (ret) {
                     if (ret < 0) {
                         error_report("Error while reading offset %" PRId64
@@ -1125,7 +1022,7 @@ static int img_compare(int argc, char **argv)
         }
     }
 
-    qprintf(quiet, "Images are identical.\n");
+    qprintf(_quiet, "Images are identical.\n");
     ret = 0;
 
 out:
@@ -1139,12 +1036,13 @@ out3:
     return ret;
 }
 
-static int img_convert(int argc, char **argv)
+static int img_convert(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
-    int c, n, n1, bs_n, bs_i, compress, cluster_sectors, skip_create;
+    int n, n1, bs_n, bs_i, cluster_sectors;
     int64_t ret = 0;
-    int progress = 0, flags;
-    const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
+    int flags;
+    char **curr;
+    const char *out_filename;
     BlockDriver *drv, *proto_drv;
     BlockDriverState **bs = NULL, *out_bs = NULL;
     int64_t total_sectors, nb_sectors, sector_num, bs_offset;
@@ -1155,131 +1053,57 @@ static int img_convert(int argc, char **argv)
     BlockDriverInfo bdi;
     QEMUOptionParameter *param = NULL, *create_options = NULL;
     QEMUOptionParameter *out_baseimg_param;
-    char *options = NULL;
-    const char *snapshot_name = NULL;
     int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
-    bool quiet = false;
     Error *local_err = NULL;
     QemuOpts *sn_opts = NULL;
 
-    fmt = NULL;
-    out_fmt = "raw";
-    cache = "unsafe";
-    out_baseimg = NULL;
-    compress = 0;
-    skip_create = 0;
-    for(;;) {
-        c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:qnl:");
-        if (c == -1) {
-            break;
-        }
-        switch(c) {
-        case '?':
-        case 'h':
-            help();
-            break;
-        case 'f':
-            fmt = optarg;
-            break;
-        case 'O':
-            out_fmt = optarg;
-            break;
-        case 'B':
-            out_baseimg = optarg;
-            break;
-        case 'c':
-            compress = 1;
-            break;
-        case 'e':
-            error_report("option -e is deprecated, please use \'-o "
-                  "encryption\' instead!");
-            ret = -1;
-            goto fail_getopt;
-        case '6':
-            error_report("option -6 is deprecated, please use \'-o "
-                  "compat6\' instead!");
-            ret = -1;
-            goto fail_getopt;
-        case 'o':
-            if (!is_valid_option_list(optarg)) {
-                error_report("Invalid option list: %s", optarg);
-                ret = -1;
-                goto fail_getopt;
-            }
-            if (!options) {
-                options = g_strdup(optarg);
-            } else {
-                char *old_options = options;
-                options = g_strdup_printf("%s,%s", options, optarg);
-                g_free(old_options);
-            }
-            break;
-        case 's':
-            snapshot_name = optarg;
-            break;
-        case 'l':
-            if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
-                sn_opts = qemu_opts_parse(&internal_snapshot_opts, optarg, 0);
-                if (!sn_opts) {
-                    error_report("Failed in parsing snapshot param '%s'",
-                                 optarg);
-                    ret = -1;
-                    goto fail_getopt;
-                }
-            } else {
-                snapshot_name = optarg;
-            }
-            break;
-        case 'S':
-        {
-            int64_t sval;
-            char *end;
-            sval = strtosz_suffix(optarg, &end, STRTOSZ_DEFSUFFIX_B);
-            if (sval < 0 || *end) {
-                error_report("Invalid minimum zero buffer size for sparse 
output specified");
-                ret = -1;
-                goto fail_getopt;
-            }
+    bs_n = qemu_arg_get_command_positional_list_cnt(cmd) - 1;
 
-            min_sparse = sval / BDRV_SECTOR_SIZE;
-            break;
-        }
-        case 'p':
-            progress = 1;
-            break;
-        case 't':
-            cache = optarg;
-            break;
-        case 'q':
-            quiet = true;
-            break;
-        case 'n':
-            skip_create = 1;
-            break;
-        }
+    if (bs_n < 1) {
+        error_report("At least an image and an output image file name must be"
+                     " provided");
+        return -1;
     }
 
-    /* Initialize before goto out */
-    if (quiet) {
-        progress = 0;
+    out_filename = _filename_list[bs_n];
+    if (_options && has_help_option(_options)) {
+        ret = print_block_option_help(out_filename, _ofmt);
+        goto out;
     }
-    qemu_progress_init(progress, 1.0);
 
+    if (_snapshot_name) {
+        if (strstart(_snapshot_name, SNAPSHOT_OPT_BASE, NULL)) {
+            sn_opts = qemu_opts_parse(&internal_snapshot_opts,
+                                      _snapshot_name, 0);
+            if (!sn_opts) {
+                error_report("Failed in parsing snapshot param '%s'",
+                             optarg);
+                return -1;
+            }
+        }
+    }
 
-    bs_n = argc - optind - 1;
-    out_filename = bs_n >= 1 ? argv[argc - 1] : NULL;
+    if (_sparse_size) {
+        int64_t sval;
+        char *end;
+        sval = strtosz_suffix(_sparse_size, &end, STRTOSZ_DEFSUFFIX_B);
+        if (sval < 0 || *end) {
+            error_report("Invalid minimum zero buffer size for sparse output "
+                         "specified");
+            return -1;
+        }
 
-    if (options && has_help_option(options)) {
-        ret = print_block_option_help(out_filename, out_fmt);
-        goto out;
+        min_sparse = sval / BDRV_SECTOR_SIZE;
     }
 
-    if (bs_n < 1) {
-        help();
+    if (_quiet) {
+        _progress = 0;
     }
 
+    /* Initialize before goto out */
+    qemu_progress_init(_progress, 1.0);
 
-    if (bs_n > 1 && out_baseimg) {
+    if (bs_n > 1 && _out_baseimg) {
         error_report("-B makes no sense when concatenating multiple input "
                      "images");
         ret = -1;
@@ -1291,11 +1115,11 @@ static int img_convert(int argc, char **argv)
     bs = g_malloc0(bs_n * sizeof(BlockDriverState *));
 
     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);
+    for (bs_i = 0, curr = _filename_list; *curr && *curr != out_filename;
+         curr++, bs_i++) {
+        bs[bs_i] = bdrv_new_open(*curr, _fmt, BDRV_O_FLAGS, true, _quiet);
         if (!bs[bs_i]) {
-            error_report("Could not open '%s'", argv[optind + bs_i]);
+            error_report("Could not open '%s'", *curr);
             ret = -1;
             goto out;
         }
@@ -1308,14 +1132,14 @@ static int img_convert(int argc, char **argv)
                                      qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
                                      qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
                                      &local_err);
-    } else if (snapshot_name != NULL) {
+    } else if (_snapshot_name != NULL) {
         if (bs_n > 1) {
             error_report("No support for concatenating multiple snapshot");
             ret = -1;
             goto out;
         }
 
-        bdrv_snapshot_load_tmp_by_id_or_name(bs[0], snapshot_name, &local_err);
+        bdrv_snapshot_load_tmp_by_id_or_name(bs[0], _snapshot_name, 
&local_err);
     }
     if (local_err) {
         error_report("Failed to load snapshot: %s",
@@ -1326,9 +1150,9 @@ static int img_convert(int argc, char **argv)
     }
 
     /* Find driver and parse its options */
-    drv = bdrv_find_format(out_fmt);
+    drv = bdrv_find_format(_ofmt);
     if (!drv) {
-        error_report("Unknown file format '%s'", out_fmt);
+        error_report("Unknown file format '%s'", _ofmt);
         ret = -1;
         goto out;
     }
@@ -1345,10 +1169,10 @@ static int img_convert(int argc, char **argv)
     create_options = append_option_parameters(create_options,
                                               proto_drv->create_options);
 
-    if (options) {
-        param = parse_option_parameters(options, create_options, param);
+    if (_options) {
+        param = parse_option_parameters(_options, create_options, param);
         if (param == NULL) {
-            error_report("Invalid options for file format '%s'.", out_fmt);
+            error_report("Invalid options for file format '%s'.", _ofmt);
             ret = -1;
             goto out;
         }
@@ -1357,7 +1181,7 @@ static int img_convert(int argc, char **argv)
     }
 
     set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
-    ret = add_old_style_options(out_fmt, param, out_baseimg, NULL);
+    ret = add_old_style_options(_ofmt, param, _out_baseimg, NULL);
     if (ret < 0) {
         goto out;
     }
@@ -1365,11 +1189,11 @@ static int img_convert(int argc, char **argv)
     /* Get backing file name if -o backing_file was used */
     out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
     if (out_baseimg_param) {
-        out_baseimg = out_baseimg_param->value.s;
+        _out_baseimg = out_baseimg_param->value.s;
     }
 
     /* Check if compression is supported */
-    if (compress) {
+    if (_compress) {
         QEMUOptionParameter *encryption =
             get_option_parameter(param, BLOCK_OPT_ENCRYPT);
         QEMUOptionParameter *preallocation =
@@ -1398,25 +1222,25 @@ static int img_convert(int argc, char **argv)
         }
     }
 
-    if (!skip_create) {
+    if (!_skip_create) {
         /* Create the new image */
         ret = bdrv_create(drv, out_filename, param, &local_err);
         if (ret < 0) {
             error_report("%s: error while converting %s: %s",
-                         out_filename, out_fmt, error_get_pretty(local_err));
+                         out_filename, _ofmt, error_get_pretty(local_err));
             error_free(local_err);
             goto out;
         }
     }
 
     flags = min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;
-    ret = bdrv_parse_cache_flags(cache, &flags);
+    ret = bdrv_parse_cache_flags(_cache, &flags);
     if (ret < 0) {
-        error_report("Invalid cache option: %s", cache);
+        error_report("Invalid cache option: %s", _cache);
         return -1;
     }
 
-    out_bs = bdrv_new_open(out_filename, out_fmt, flags, true, quiet);
+    out_bs = bdrv_new_open(out_filename, _ofmt, flags, true, _quiet);
     if (!out_bs) {
         ret = -1;
         goto out;
@@ -1436,7 +1260,7 @@ static int img_convert(int argc, char **argv)
 
     buf = qemu_blockalign(out_bs, bufsectors * BDRV_SECTOR_SIZE);
 
-    if (skip_create) {
+    if (_skip_create) {
         int64_t output_length = bdrv_getlength(out_bs);
         if (output_length < 0) {
             error_report("unable to get output image length: %s\n",
@@ -1453,7 +1277,7 @@ static int img_convert(int argc, char **argv)
     cluster_sectors = 0;
     ret = bdrv_get_info(out_bs, &bdi);
     if (ret < 0) {
-        if (compress) {
+        if (_compress) {
             error_report("could not get block driver info");
             goto out;
         }
@@ -1461,7 +1285,7 @@ static int img_convert(int argc, char **argv)
         cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
     }
 
-    if (compress) {
+    if (_compress) {
         if (cluster_sectors <= 0 || cluster_sectors > bufsectors) {
             error_report("invalid cluster size");
             ret = -1;
@@ -1545,7 +1369,7 @@ static int img_convert(int argc, char **argv)
         }
 
         sectors_to_read = total_sectors;
-        count_allocated_sectors = progress && (out_baseimg || has_zero_init);
+        count_allocated_sectors = _progress && (_out_baseimg || has_zero_init);
 restart:
         sector_num = 0; // total number of sectors converted so far
         sectors_read = 0;
@@ -1573,7 +1397,7 @@ restart:
                    sector_num, bs_i, bs_offset, bs_sectors); */
             }
 
-            if ((out_baseimg || has_zero_init) &&
+            if ((_out_baseimg || has_zero_init) &&
                 sector_num >= sector_num_next_status) {
                 n = nb_sectors > INT_MAX ? INT_MAX : nb_sectors;
                 ret = bdrv_get_block_status(bs[bs_i], sector_num - bs_offset,
@@ -1587,7 +1411,7 @@ restart:
                 /* If the output image is zero initialized, we are not working
                  * on a shared base and the input is zero we can skip the next
                  * n1 sectors */
-                if (has_zero_init && !out_baseimg && (ret & BDRV_BLOCK_ZERO)) {
+                if (has_zero_init && !_out_baseimg && (ret & BDRV_BLOCK_ZERO)) 
{
                     sector_num += n1;
                     continue;
                 }
@@ -1595,7 +1419,7 @@ restart:
                  * image, assume that sectors which are unallocated in the
                  * input image are present in both the output's and input's
                  * base images (no need to copy them). */
-                if (out_baseimg) {
+                if (_out_baseimg) {
                     if (!(ret & BDRV_BLOCK_DATA)) {
                         sector_num += n1;
                         continue;
@@ -1681,8 +1505,6 @@ out:
         }
         g_free(bs);
     }
-fail_getopt:
-    g_free(options);
 
     if (ret) {
         return 1;
@@ -1840,61 +1662,21 @@ err:
     return NULL;
 }
 
-static int img_info(int argc, char **argv)
+static int img_info(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
-    int c;
     OutputFormat output_format = OFORMAT_HUMAN;
-    bool chain = false;
-    const char *filename, *fmt, *output;
     ImageInfoList *list;
 
-    fmt = NULL;
-    output = NULL;
-    for(;;) {
-        int option_index = 0;
-        static const struct option long_options[] = {
-            {"help", no_argument, 0, 'h'},
-            {"format", required_argument, 0, 'f'},
-            {"output", required_argument, 0, OPTION_OUTPUT},
-            {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
-            {0, 0, 0, 0}
-        };
-        c = getopt_long(argc, argv, "f:h",
-                        long_options, &option_index);
-        if (c == -1) {
-            break;
-        }
-        switch(c) {
-        case '?':
-        case 'h':
-            help();
-            break;
-        case 'f':
-            fmt = optarg;
-            break;
-        case OPTION_OUTPUT:
-            output = optarg;
-            break;
-        case OPTION_BACKING_CHAIN:
-            chain = true;
-            break;
-        }
-    }
-    if (optind != argc - 1) {
-        help();
-    }
-    filename = argv[optind++];
-
-    if (output && !strcmp(output, "json")) {
+    if (_ofmt && !strcmp(_ofmt, "json")) {
         output_format = OFORMAT_JSON;
-    } else if (output && !strcmp(output, "human")) {
+    } else if (_ofmt && !strcmp(_ofmt, "human")) {
         output_format = OFORMAT_HUMAN;
-    } else if (output) {
+    } else if (_ofmt) {
         error_report("--output must be used with human or json as argument.");
         return 1;
     }
 
-    list = collect_image_info_list(filename, fmt, chain);
+    list = collect_image_info_list(_filename, _fmt, _backing_chain);
     if (!list) {
         return 1;
     }
@@ -1904,7 +1686,7 @@ static int img_info(int argc, char **argv)
         dump_human_image_info_list(list);
         break;
     case OFORMAT_JSON:
-        if (chain) {
+        if (_backing_chain) {
             dump_json_image_info_list(list);
         } else {
             dump_json_image_info(list->value);
@@ -1916,7 +1698,6 @@ static int img_info(int argc, char **argv)
     return 0;
 }
 
-
 typedef struct MapEntry {
     int flags;
     int depth;
@@ -2007,59 +1788,24 @@ static int get_block_status(BlockDriverState *bs, 
int64_t sector_num,
     return 0;
 }
 
-static int img_map(int argc, char **argv)
+static int img_map(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
-    int c;
     OutputFormat output_format = OFORMAT_HUMAN;
     BlockDriverState *bs;
-    const char *filename, *fmt, *output;
     int64_t length;
     MapEntry curr = { .length = 0 }, next;
     int ret = 0;
 
-    fmt = NULL;
-    output = NULL;
-    for (;;) {
-        int option_index = 0;
-        static const struct option long_options[] = {
-            {"help", no_argument, 0, 'h'},
-            {"format", required_argument, 0, 'f'},
-            {"output", required_argument, 0, OPTION_OUTPUT},
-            {0, 0, 0, 0}
-        };
-        c = getopt_long(argc, argv, "f:h",
-                        long_options, &option_index);
-        if (c == -1) {
-            break;
-        }
-        switch (c) {
-        case '?':
-        case 'h':
-            help();
-            break;
-        case 'f':
-            fmt = optarg;
-            break;
-        case OPTION_OUTPUT:
-            output = optarg;
-            break;
-        }
-    }
-    if (optind >= argc) {
-        help();
-    }
-    filename = argv[optind++];
-
-    if (output && !strcmp(output, "json")) {
+    if (_ofmt && !strcmp(_ofmt, "json")) {
         output_format = OFORMAT_JSON;
-    } else if (output && !strcmp(output, "human")) {
+    } else if (_ofmt && !strcmp(_ofmt, "human")) {
         output_format = OFORMAT_HUMAN;
-    } else if (output) {
+    } else if (_ofmt) {
         error_report("--output must be used with human or json as argument.");
         return 1;
     }
 
-    bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS, true, false);
+    bs = bdrv_new_open(_filename, _fmt, BDRV_O_FLAGS, true, false);
     if (!bs) {
         return 1;
     }
@@ -2112,74 +1858,34 @@ out:
 #define SNAPSHOT_APPLY  3
 #define SNAPSHOT_DELETE 4
 
-static int img_snapshot(int argc, char **argv)
+static int img_snapshot(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
     BlockDriverState *bs;
     QEMUSnapshotInfo sn;
-    char *filename, *snapshot_name = NULL;
-    int c, ret = 0, bdrv_oflags;
+    char *snapshot_name = NULL;
+    int ret = 0, bdrv_oflags;
     int action = 0;
     qemu_timeval tv;
-    bool quiet = false;
     Error *err = NULL;
 
     bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
-    /* Parse commandline parameters */
-    for(;;) {
-        c = getopt(argc, argv, "la:c:d:hq");
-        if (c == -1) {
-            break;
-        }
-        switch(c) {
-        case '?':
-        case 'h':
-            help();
-            return 0;
-        case 'l':
-            if (action) {
-                help();
-                return 0;
-            }
-            action = SNAPSHOT_LIST;
-            bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
-            break;
-        case 'a':
-            if (action) {
-                help();
-                return 0;
-            }
-            action = SNAPSHOT_APPLY;
-            snapshot_name = optarg;
-            break;
-        case 'c':
-            if (action) {
-                help();
-                return 0;
-            }
-            action = SNAPSHOT_CREATE;
-            snapshot_name = optarg;
-            break;
-        case 'd':
-            if (action) {
-                help();
-                return 0;
-            }
-            action = SNAPSHOT_DELETE;
-            snapshot_name = optarg;
-            break;
-        case 'q':
-            quiet = true;
-            break;
-        }
-    }
 
-    if (optind != argc - 1) {
-        help();
+    if (_snapshot_list) {
+        action = SNAPSHOT_LIST;
+        bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
+    } else if (_snapshot_apply) {
+        action = SNAPSHOT_APPLY;
+        snapshot_name = _snapshot_apply;
+    } else if (_snapshot_create) {
+        action = SNAPSHOT_CREATE;
+        snapshot_name = _snapshot_create;
+    } else if (_snapshot_delete) {
+        action = SNAPSHOT_DELETE;
+        snapshot_name = _snapshot_delete;
     }
-    filename = argv[optind++];
 
     /* Open the image */
-    bs = bdrv_new_open(filename, NULL, bdrv_oflags, true, quiet);
+    bs = bdrv_new_open(_filename, NULL, bdrv_oflags, true, _quiet);
     if (!bs) {
         return 1;
     }
@@ -2232,73 +1938,29 @@ static int img_snapshot(int argc, char **argv)
     return 0;
 }
 
-static int img_rebase(int argc, char **argv)
+static int img_rebase(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
     BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL;
     BlockDriver *old_backing_drv, *new_backing_drv;
-    char *filename;
-    const char *fmt, *cache, *out_basefmt, *out_baseimg;
-    int c, flags, ret;
-    int unsafe = 0;
-    int progress = 0;
-    bool quiet = false;
+    int flags, ret;
     Error *local_err = NULL;
 
-    /* Parse commandline parameters */
-    fmt = NULL;
-    cache = BDRV_DEFAULT_CACHE;
-    out_baseimg = NULL;
-    out_basefmt = NULL;
-    for(;;) {
-        c = getopt(argc, argv, "uhf:F:b:pt:q");
-        if (c == -1) {
-            break;
-        }
-        switch(c) {
-        case '?':
-        case 'h':
-            help();
-            return 0;
-        case 'f':
-            fmt = optarg;
-            break;
-        case 'F':
-            out_basefmt = optarg;
-            break;
-        case 'b':
-            out_baseimg = optarg;
-            break;
-        case 'u':
-            unsafe = 1;
-            break;
-        case 'p':
-            progress = 1;
-            break;
-        case 't':
-            cache = optarg;
-            break;
-        case 'q':
-            quiet = true;
-            break;
-        }
-    }
-
-    if (quiet) {
-        progress = 0;
+    if (_quiet) {
+        _progress = 0;
     }
 
-    if ((optind != argc - 1) || (!unsafe && !out_baseimg)) {
-        help();
+    if (!_unsafe && !_out_baseimg) {
+        qemu_arg_print_command_help(ctx, cmd);
+        return -1;
     }
-    filename = argv[optind++];
 
-    qemu_progress_init(progress, 2.0);
+    qemu_progress_init(_progress, 2.0);
     qemu_progress_print(0, 100);
 
-    flags = BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
-    ret = bdrv_parse_cache_flags(cache, &flags);
+    flags = BDRV_O_RDWR | (_unsafe ? BDRV_O_NO_BACKING : 0);
+    ret = bdrv_parse_cache_flags(_cache, &flags);
     if (ret < 0) {
-        error_report("Invalid cache option: %s", cache);
+        error_report("Invalid cache option: %s", _cache);
         return -1;
     }
 
@@ -2308,7 +1970,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(_filename, _fmt, flags, true, _quiet);
     if (!bs) {
         return 1;
     }
@@ -2317,7 +1979,7 @@ static int img_rebase(int argc, char **argv)
     old_backing_drv = NULL;
     new_backing_drv = NULL;
 
-    if (!unsafe && bs->backing_format[0] != '\0') {
+    if (!_unsafe && bs->backing_format[0] != '\0') {
         old_backing_drv = bdrv_find_format(bs->backing_format);
         if (old_backing_drv == NULL) {
             error_report("Invalid format name: '%s'", bs->backing_format);
@@ -2326,17 +1988,17 @@ static int img_rebase(int argc, char **argv)
         }
     }
 
-    if (out_basefmt != NULL) {
-        new_backing_drv = bdrv_find_format(out_basefmt);
+    if (_out_basefmt != NULL) {
+        new_backing_drv = bdrv_find_format(_out_basefmt);
         if (new_backing_drv == NULL) {
-            error_report("Invalid format name: '%s'", out_basefmt);
+            error_report("Invalid format name: '%s'", _out_basefmt);
             ret = -1;
             goto out;
         }
     }
 
     /* For safe rebasing we need to compare old and new backing file */
-    if (unsafe) {
+    if (_unsafe) {
         /* Make the compiler happy */
         bs_old_backing = NULL;
         bs_new_backing = NULL;
@@ -2353,13 +2015,13 @@ static int img_rebase(int argc, char **argv)
             error_free(local_err);
             goto out;
         }
-        if (out_baseimg[0]) {
+        if (_out_baseimg[0]) {
             bs_new_backing = bdrv_new("new_backing");
-            ret = bdrv_open(&bs_new_backing, out_baseimg, NULL, NULL,
+            ret = bdrv_open(&bs_new_backing, _out_baseimg, NULL, NULL,
                             BDRV_O_FLAGS, new_backing_drv, &local_err);
             if (ret) {
                 error_report("Could not open new backing file '%s': %s",
-                             out_baseimg, error_get_pretty(local_err));
+                             _out_baseimg, error_get_pretty(local_err));
                 error_free(local_err);
                 goto out;
             }
@@ -2375,7 +2037,7 @@ static int img_rebase(int argc, char **argv)
      * If qemu-img crashes during this step, no harm is done. The content of
      * the image is the same as the original one at any time.
      */
-    if (!unsafe) {
+    if (!_unsafe) {
         uint64_t num_sectors;
         uint64_t old_backing_num_sectors;
         uint64_t new_backing_num_sectors = 0;
@@ -2483,18 +2145,18 @@ static int img_rebase(int argc, char **argv)
      * backing file are overwritten in the COW file now, so the visible content
      * doesn't change when we switch the backing file.
      */
-    if (out_baseimg && *out_baseimg) {
-        ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt);
+    if (_out_baseimg && *_out_baseimg) {
+        ret = bdrv_change_backing_file(bs, _out_baseimg, _out_basefmt);
     } else {
         ret = bdrv_change_backing_file(bs, NULL, NULL);
     }
 
     if (ret == -ENOSPC) {
         error_report("Could not change the backing file to '%s': No "
-                     "space left in the file header", out_baseimg);
+                     "space left in the file header", _out_baseimg);
     } else if (ret < 0) {
         error_report("Could not change the backing file to '%s': %s",
-            out_baseimg, strerror(-ret));
+            _out_baseimg, strerror(-ret));
     }
 
     qemu_progress_print(100, 0);
@@ -2507,7 +2169,7 @@ static int img_rebase(int argc, char **argv)
 out:
     qemu_progress_end();
     /* Cleanup */
-    if (!unsafe) {
+    if (!_unsafe) {
         if (bs_old_backing != NULL) {
             bdrv_unref(bs_old_backing);
         }
@@ -2523,10 +2185,9 @@ out:
     return 0;
 }
 
-static int img_resize(int argc, char **argv)
+static int img_resize(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
-    int c, ret, relative;
-    const char *filename, *fmt, *size;
+    int ret, relative;
     int64_t n, total_size;
     bool quiet = false;
     BlockDriverState *bs = NULL;
@@ -2545,49 +2206,15 @@ 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();
-        return 1;
-    }
-
-    size = argv[--argc];
-
-    /* Parse getopt arguments */
-    fmt = NULL;
-    for(;;) {
-        c = getopt(argc, argv, "f:hq");
-        if (c == -1) {
-            break;
-        }
-        switch(c) {
-        case '?':
-        case 'h':
-            help();
-            break;
-        case 'f':
-            fmt = optarg;
-            break;
-        case 'q':
-            quiet = true;
-            break;
-        }
-    }
-    if (optind != argc - 1) {
-        help();
-    }
-    filename = argv[optind++];
-
     /* Choose grow, shrink, or absolute resize mode */
-    switch (size[0]) {
+    switch (_size[0]) {
     case '+':
         relative = 1;
-        size++;
+        _size++;
         break;
     case '-':
         relative = -1;
-        size++;
+        _size++;
         break;
     default:
         relative = 0;
@@ -2596,7 +2223,7 @@ static int img_resize(int argc, char **argv)
 
     /* Parse size */
     param = qemu_opts_create(&resize_options, NULL, 0, &error_abort);
-    if (qemu_opt_set(param, BLOCK_OPT_SIZE, size)) {
+    if (qemu_opt_set(param, BLOCK_OPT_SIZE, _size)) {
         /* Error message already printed when size parsing fails */
         ret = -1;
         qemu_opts_del(param);
@@ -2605,7 +2232,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(_filename, _fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true,
+                       _quiet);
     if (!bs) {
         ret = -1;
         goto out;
@@ -2647,86 +2275,41 @@ out:
     return 0;
 }
 
-static int img_amend(int argc, char **argv)
+static int img_amend(const QemuArgContext *ctx, const QemuArgCommand *cmd)
 {
-    int c, ret = 0;
-    char *options = NULL;
+    int ret = 0;
     QEMUOptionParameter *create_options = NULL, *options_param = NULL;
-    const char *fmt = NULL, *filename;
-    bool quiet = false;
     BlockDriverState *bs = NULL;
 
-    for (;;) {
-        c = getopt(argc, argv, "hqf:o:");
-        if (c == -1) {
-            break;
-        }
-
-        switch (c) {
-            case 'h':
-            case '?':
-                help();
-                break;
-            case 'o':
-                if (!is_valid_option_list(optarg)) {
-                    error_report("Invalid option list: %s", optarg);
-                    ret = -1;
-                    goto out;
-                }
-                if (!options) {
-                    options = g_strdup(optarg);
-                } else {
-                    char *old_options = options;
-                    options = g_strdup_printf("%s,%s", options, optarg);
-                    g_free(old_options);
-                }
-                break;
-            case 'f':
-                fmt = optarg;
-                break;
-            case 'q':
-                quiet = true;
-                break;
-        }
-    }
-
-    if (!options) {
-        help();
-    }
-
-    filename = (optind == argc - 1) ? argv[argc - 1] : NULL;
-    if (fmt && has_help_option(options)) {
+    if (_fmt && has_help_option(_options)) {
         /* If a format is explicitly specified (and possibly no filename is
          * given), print option help here */
-        ret = print_block_option_help(filename, fmt);
+        ret = print_block_option_help(_filename, _fmt);
         goto out;
     }
 
-    if (optind != argc - 1) {
-        help();
-    }
-
-    bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet);
+    bs = bdrv_new_open(_filename, _fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true,
+                       _quiet);
     if (!bs) {
-        error_report("Could not open image '%s'", filename);
+        error_report("Could not open image '%s'", _filename);
         ret = -1;
         goto out;
     }
 
-    fmt = bs->drv->format_name;
+    _fmt = (char *)bs->drv->format_name;
 
-    if (has_help_option(options)) {
+    if (has_help_option(_options)) {
         /* If the format was auto-detected, print option help here */
-        ret = print_block_option_help(filename, fmt);
+        ret = print_block_option_help(_filename, _fmt);
         goto out;
     }
 
     create_options = append_option_parameters(create_options,
             bs->drv->create_options);
-    options_param = parse_option_parameters(options, create_options,
+    options_param = parse_option_parameters(_options, create_options,
             options_param);
     if (options_param == NULL) {
-        error_report("Invalid options for file format '%s'", fmt);
+        error_report("Invalid options for file format '%s'", _fmt);
         ret = -1;
         goto out;
     }
@@ -2743,7 +2326,6 @@ out:
     }
     free_option_parameters(create_options);
     free_option_parameters(options_param);
-    g_free(options);
 
     if (ret) {
         return 1;
@@ -2751,19 +2333,46 @@ out:
     return 0;
 }
 
-static const img_cmd_t img_cmds[] = {
-#define DEF(option, callback, arg_string)        \
-    { option, callback },
-#include "qemu-img-cmds.h"
-#undef DEF
-#undef GEN_DOCS
-    { NULL, NULL, },
+static const QemuArgCommand _cmds[] = {
+    OPT_CMD("check", QEMU_IMG_CHECK_HELP, _check_args, NULL, img_check),
+    OPT_CMD("create", QEMU_IMG_CREATE_HELP, _create_args, NULL, img_create),
+    OPT_CMD("commit", QEMU_IMG_COMMIT_HELP, _commit_args, NULL, img_commit),
+    OPT_CMD("compare", QEMU_IMG_COMPARE_HELP, _compare_args, NULL, 
img_compare),
+    OPT_CMD("convert", QEMU_IMG_CONVERT_HELP, _convert_args, NULL, 
img_convert),
+    OPT_CMD("info", QEMU_IMG_INFO_HELP, _info_args, NULL, img_info),
+    OPT_CMD("map", QEMU_IMG_MAP_HELP, _map_args, NULL, img_map),
+    OPT_CMD("snapshot", QEMU_IMG_SNAPSHOT_HELP, _snapshot_args,
+            _snapshot_mutual_groups, img_snapshot),
+    OPT_CMD("rebase", QEMU_IMG_REBASE_HELP, _rebase_args, NULL, img_rebase),
+    OPT_CMD("resize", QEMU_IMG_RESIZE_HELP, _resize_args, NULL, img_resize),
+    OPT_CMD("amend", QEMU_IMG_AMEND_HELP, _amend_args, NULL, img_amend),
+    CMD_SENTINEL
 };
 
+static void format_print(void *opaque, const char *name)
+{
+    char **str = opaque;
+    char *cp;
+
+    if (*str) {
+        cp = g_strdup(*str);
+        free(*str);
+
+        *str = g_malloc0(strlen(cp) + strlen(name) + 1);
+        sprintf(*str, "%s %s", cp, name);
+
+        free(cp);
+    } else {
+        *str = g_malloc0(strlen(name) + 1);
+        sprintf(*str, "%s", name);
+    }
+}
+
 int main(int argc, char **argv)
 {
-    const img_cmd_t *cmd;
-    const char *cmdname;
+    int ret;
+    char *formats = NULL, *epilogue = NULL;
+    const char *pref = "Supported formats: ";
 
 #ifdef CONFIG_POSIX
     signal(SIGPIPE, SIG_IGN);
@@ -2774,19 +2383,20 @@ int main(int argc, char **argv)
 
     qemu_init_main_loop();
     bdrv_init();
-    if (argc < 2)
-        help();
-    cmdname = argv[1];
-    argc--; argv++;
 
-    /* find the command */
-    for(cmd = img_cmds; cmd->name != NULL; cmd++) {
-        if (!strcmp(cmdname, cmd->name)) {
-            return cmd->handler(argc, argv);
-        }
-    }
+    bdrv_iterate_format(format_print, &formats);
 
-    /* not found */
-    help();
-    return 0;
+    epilogue = g_malloc0(strlen(formats) + strlen(pref));
+    sprintf(epilogue, "%s%s", pref, formats);
+
+    OPT_CTX(ctx, PROLOGUE, epilogue, "qemu-img", _cmds, NULL, NULL,
+            OPT_DECORATE_LONG);
+
+    ret = qemu_arg_parse(argc, argv, &ctx);
+    qemu_arg_context_cleanup(&ctx);
+
+    free(formats);
+    free(epilogue);
+
+    return ret;
 }
-- 
1.9.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]