1
0
Fork 0
qemu/debian/patches/qemu-img-options.patch
Daniel Baumann 665688c177
Adding debian version 1:10.0.2+ds-1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 14:27:18 +02:00

2092 lines
75 KiB
Diff

From: Michael Tokarev <mjt@tls.msk.ru>
Subject: qemu-img options rework
Forwarded: https://lore.kernel.org/qemu-devel/20240927061121.573271-1-mjt@tls.msk.ru/
This is a patchset which has been sent to qemu upstream for review
a number of times, but the review stalled.
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -257,5 +257,5 @@ Parameters to snapshot subcommand:
.. option:: -l
- Lists all snapshots in the given image
+ Lists all snapshots in the given image (default action)
Command description:
@@ -664,5 +664,5 @@ Command description:
to copy.
-.. option:: snapshot [--object OBJECTDEF] [--image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME
+.. option:: snapshot [--object OBJECTDEF] [-f FMT | --image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME
List, apply, create or delete snapshots in image *FILENAME*.
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -85,7 +85,7 @@ ERST
DEF("snapshot", img_snapshot,
- "snapshot [--object objectdef] [--image-opts] [-U] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
+ "snapshot [--object objectdef] [-f fmt | --image-opts] [-U] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
SRST
-.. option:: snapshot [--object OBJECTDEF] [--image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME
+.. option:: snapshot [--object OBJECTDEF] [-f FMT | --image-opts] [-U] [-q] [-l | -a SNAPSHOT | -c SNAPSHOT | -d SNAPSHOT] FILENAME
ERST
diff --git a/qemu-img.c b/qemu-img.c
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -61,10 +61,10 @@
typedef struct img_cmd_t {
const char *name;
- int (*handler)(int argc, char **argv);
+ int (*handler)(const struct img_cmd_t *ccmd, int argc, char **argv);
+ const char *description;
} img_cmd_t;
enum {
OPTION_OUTPUT = 256,
- OPTION_BACKING_CHAIN = 257,
OPTION_OBJECT = 258,
OPTION_IMAGE_OPTS = 259,
@@ -73,5 +73,4 @@ enum {
OPTION_NO_DRAIN = 262,
OPTION_TARGET_IMAGE_OPTS = 263,
- OPTION_SIZE = 264,
OPTION_PREALLOCATION = 265,
OPTION_SHRINK = 266,
@@ -97,11 +96,13 @@ typedef enum OutputFormat {
#define BDRV_DEFAULT_CACHE "writeback"
-static void format_print(void *opaque, const char *name)
+static G_NORETURN
+void tryhelp(const char *argv0)
{
- printf(" %s", name);
+ error_printf("Try '%s --help' for more info\n", argv0);
+ exit(EXIT_FAILURE);
}
-static G_NORETURN G_GNUC_PRINTF(1, 2)
-void error_exit(const char *fmt, ...)
+static G_NORETURN G_GNUC_PRINTF(2, 3)
+void error_exit(const char *argv0, const char *fmt, ...)
{
va_list ap;
@@ -111,126 +112,43 @@ void error_exit(const char *fmt, ...)
va_end(ap);
- error_printf("Try 'qemu-img --help' for more information\n");
- exit(EXIT_FAILURE);
-}
-
-static G_NORETURN
-void missing_argument(const char *option)
-{
- error_exit("missing argument for option '%s'", option);
+ tryhelp(argv0);
}
+/*
+ * Print --help output for a command and exit.
+ * syntax and description are multi-line with trailing EOL
+ * (to allow easy extending of the text)
+ * syntax has each subsequent line indented by 8 chars.
+ * desrciption is indented by 2 chars for argument on each own line,
+ * and with 5 chars for argument description (like -h arg below).
+ */
static G_NORETURN
-void unrecognized_option(const char *option)
+void cmd_help(const img_cmd_t *ccmd,
+ const char *syntax, const char *arguments)
{
- error_exit("unrecognized option '%s'", option);
+ printf(
+"Usage:\n"
+"%s. Usage:\n"
+"\n"
+" %s %s %s"
+"\n"
+"Arguments:\n"
+" -h, --help\n"
+" print this help and exit\n"
+"%s\n",
+ ccmd->description, "qemu-img", ccmd->name,
+ syntax, arguments);
+ exit(EXIT_SUCCESS);
}
-/* Please keep in synch with docs/tools/qemu-img.rst */
-static G_NORETURN
-void help(void)
+static OutputFormat parse_output_format(const char *argv0, const char *arg)
{
- const char *help_msg =
- QEMU_IMG_VERSION
- "usage: qemu-img [standard options] command [command options]\n"
- "QEMU disk image utility\n"
- "\n"
- " '-h', '--help' display this help and exit\n"
- " '-V', '--version' output version information and exit\n"
- " '-T', '--trace' [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
- " specify tracing options\n"
- "\n"
- "Command syntax:\n"
-#define DEF(option, callback, arg_string) \
- " " arg_string "\n"
-#include "qemu-img-cmds.h"
-#undef DEF
- "\n"
- "Command parameters:\n"
- " 'filename' is a disk image filename\n"
- " 'objectdef' is a QEMU user creatable object definition. See the qemu(1)\n"
- " manual page for a description of the object properties. The most common\n"
- " object type is a 'secret', which is used to supply passwords and/or\n"
- " encryption keys.\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"
- " 'src_cache' is the cache mode used to read input disk images, the valid\n"
- " options are the same as for the 'cache' option\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 help for an overview of the options supported by\n"
- " the 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"
- " '-c' indicates that target image must be compressed (qcow format only)\n"
- " '-u' allows unsafe backing chains. For rebasing, it is assumed that old and\n"
- " new backing file match exactly. The image doesn't need a working\n"
- " backing file before rebasing in this case (useful for renaming the\n"
- " backing file). For image creation, allow creating without attempting\n"
- " to open 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 bitmap subcommand:\n"
- " 'bitmap' is the name of the bitmap to manipulate, through one or more\n"
- " actions from '--add', '--remove', '--clear', '--enable', '--disable',\n"
- " or '--merge source'\n"
- " '-g granularity' sets the granularity for '--add' actions\n"
- " '-b source' and '-F src_fmt' tell '--merge' actions to find the source\n"
- " bitmaps from an alternative file\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 convert subcommand:\n"
- " '--bitmaps' copies all top-level persistent bitmaps to destination\n"
- " '-m' specifies how many coroutines work in parallel during the convert\n"
- " process (defaults to 8)\n"
- " '-W' allow to write to the target out of order rather than sequential\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"
- "\n"
- "Parameters to dd subcommand:\n"
- " 'bs=BYTES' read and write up to BYTES bytes at a time "
- "(default: 512)\n"
- " 'count=N' copy only N input blocks\n"
- " 'if=FILE' read from FILE\n"
- " 'of=FILE' write to FILE\n"
- " 'skip=N' skip N bs-sized blocks at the start of input\n";
-
- printf("%s\nSupported formats:", help_msg);
- bdrv_iterate_format(format_print, NULL, false);
- printf("\n\n" QEMU_HELP_BOTTOM "\n");
- exit(EXIT_SUCCESS);
+ if (!strcmp(arg, "json")) {
+ return OFORMAT_JSON;
+ } else if (!strcmp(arg, "human")) {
+ return OFORMAT_HUMAN;
+ } else {
+ error_exit(argv0, "--output expects 'human' or 'json' not '%s'", arg);
+ }
}
@@ -482,16 +400,14 @@ static int add_old_style_options(const char *fmt, QemuOpts *opts,
}
-static int64_t cvtnum_full(const char *name, const char *value, int64_t min,
- int64_t max)
+static int64_t cvtnum_full(const char *name, const char *value,
+ bool issize, int64_t min, int64_t max)
{
int err;
uint64_t res;
- err = qemu_strtosz(value, NULL, &res);
+ err = issize ? qemu_strtosz(value, NULL, &res) :
+ qemu_strtou64(value, NULL, 0, &res);
if (err < 0 && err != -ERANGE) {
- error_report("Invalid %s specified. You may use "
- "k, M, G, T, P or E suffixes for", name);
- error_report("kilobytes, megabytes, gigabytes, terabytes, "
- "petabytes and exabytes.");
+ error_report("Invalid %s specified: '%s'.", name, value);
return err;
}
@@ -504,13 +420,13 @@ static int64_t cvtnum_full(const char *name, const char *value, int64_t min,
}
-static int64_t cvtnum(const char *name, const char *value)
+static int64_t cvtnum(const char *name, const char *value, bool issize)
{
- return cvtnum_full(name, value, 0, INT64_MAX);
+ return cvtnum_full(name, value, issize, 0, INT64_MAX);
}
-static int img_create(int argc, char **argv)
+static int img_create(const img_cmd_t *ccmd, int argc, char **argv)
{
int c;
- uint64_t img_size = -1;
+ int64_t img_size = -1;
const char *fmt = "raw";
const char *base_fmt = NULL;
@@ -525,8 +441,14 @@ static int img_create(int argc, char **argv)
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
+ {"quiet", no_argument, 0, 'q'},
{"object", required_argument, 0, OPTION_OBJECT},
+ {"format", required_argument, 0, 'f'},
+ {"backing", required_argument, 0, 'b'},
+ {"backing-format", required_argument, 0, 'F'},
+ {"backing-unsafe", no_argument, 0, 'u'},
+ {"options", required_argument, 0, 'o'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":F:b:f:ho:qu",
+ c = getopt_long(argc, argv, "F:b:f:ho:qu",
long_options, NULL);
if (c == -1) {
@@ -534,12 +456,31 @@ static int img_create(int argc, char **argv)
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd,
+"[-f FMT] [-o FMT_OPTS] [-b BACKING_FILENAME [-F BACKING_FMT]]\n"
+" [--object OBJDEF] [-u] FILENAME [SIZE[bkKMGTPE]]\n"
+,
+" -q, --quiet\n"
+" quiet operations\n"
+" -f, --format FMT\n"
+" specifies format of the new image, default is raw\n"
+" -o, --options FMT_OPTS\n"
+" format-specific options ('-o list' for list)\n"
+" -b, --backing BACKING_FILENAME\n"
+" stack new image on top of BACKING_FILENAME\n"
+" (for formats which support stacking)\n"
+" -F, --backing-format BACKING_FMT\n"
+" specify format of BACKING_FILENAME\n"
+" -u, --backing-unsafe\n"
+" do not fail if BACKING_FMT can not be read\n"
+" --object OBJDEF\n"
+" QEMU user-creatable object (eg encryption key)\n"
+" FILENAME\n"
+" image file to create. It will be overridden if exists\n"
+" SIZE\n"
+" image size with optional suffix (multiplies in 1024)\n"
+" SIZE is required unless BACKING_IMG is specified,\n"
+" in which case it will be the same as size of BACKING_IMG\n"
+);
break;
case 'F':
@@ -566,4 +507,6 @@ static int img_create(int argc, char **argv)
user_creatable_process_cmdline(optarg);
break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -577,5 +520,5 @@ static int img_create(int argc, char **argv)
if (optind >= argc) {
- error_exit("Expecting image file name");
+ error_exit(argv[0], "Expecting image file name");
}
optind++;
@@ -583,14 +526,11 @@ static int img_create(int argc, char **argv)
/* Get image size, if specified */
if (optind < argc) {
- int64_t sval;
-
- sval = cvtnum("image size", argv[optind++]);
- if (sval < 0) {
+ img_size = cvtnum("image size", argv[optind++], true);
+ if (img_size < 0) {
goto fail;
}
- img_size = (uint64_t)sval;
}
if (optind != argc) {
- error_exit("Unexpected argument: %s", argv[optind]);
+ error_exit(argv[0], "Unexpected argument: %s", argv[optind]);
}
@@ -717,9 +657,9 @@ static int collect_image_check(BlockDriverState *bs,
* 63 - Checks are not supported by the image format
*/
-static int img_check(int argc, char **argv)
+static int img_check(const img_cmd_t *ccmd, int argc, char **argv)
{
int c, ret;
OutputFormat output_format = OFORMAT_HUMAN;
- const char *filename, *fmt, *output, *cache;
+ const char *filename, *fmt, *cache;
BlockBackend *blk;
BlockDriverState *bs;
@@ -733,5 +673,4 @@ static int img_check(int argc, char **argv)
fmt = NULL;
- output = NULL;
cache = BDRV_DEFAULT_CACHE;
@@ -740,5 +679,7 @@ static int img_check(int argc, char **argv)
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
+ {"quiet", no_argument, 0, 'q'},
{"format", required_argument, 0, 'f'},
+ {"cache", required_argument, 0, 'T'},
{"repair", required_argument, 0, 'r'},
{"output", required_argument, 0, OPTION_OUTPUT},
@@ -748,5 +689,5 @@ static int img_check(int argc, char **argv)
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hf:r:T:qU",
+ c = getopt_long(argc, argv, "hf:r:T:qU",
long_options, &option_index);
if (c == -1) {
@@ -754,12 +695,30 @@ static int img_check(int argc, char **argv)
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd,
+"[-f FMT | --image-opts] [-T CACHE_MODE] [-r] [-u]\n"
+" [--output human|json] [--object OBJDEF] FILENAME\n"
+,
+" -q, --quiet\n"
+" quiet operations\n"
+" -f, --format FMT\n"
+" specifies format of the image explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -T, --cache CACHE_MODE\n"
+" image cache mode (" BDRV_DEFAULT_CACHE ")\n"
+" -U, --force-share\n"
+" open image in shared mode for concurrent access\n"
+" --output human|json\n"
+" output format\n"
+" -r, --repair leaks|all\n"
+" repair particular aspect of the image\n"
+" (image will be open in read-write mode, incompatible with --force-share)\n"
+" --object OBJDEF\n"
+" QEMU user-creatable object (eg encryption key)\n"
+" FILENAME\n"
+" the image file (or image specification) to operate on\n"
+);
break;
case 'f':
@@ -774,10 +733,11 @@ static int img_check(int argc, char **argv)
fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
} else {
- error_exit("Unknown option value for -r "
- "(expecting 'leaks' or 'all'): %s", optarg);
+ error_exit(argv[0],
+ "--repair (-r) expects 'leaks' or 'all' not '%s'",
+ optarg);
}
break;
case OPTION_OUTPUT:
- output = optarg;
+ output_format = parse_output_format(argv[0], optarg);
break;
case 'T':
@@ -796,20 +756,13 @@ static int img_check(int argc, char **argv)
image_opts = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[optind++];
- if (output && !strcmp(output, "json")) {
- output_format = OFORMAT_JSON;
- } else if (output && !strcmp(output, "human")) {
- output_format = OFORMAT_HUMAN;
- } else if (output) {
- error_report("--output must be used with human or json as argument.");
- return 1;
- }
-
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
if (ret < 0) {
@@ -949,5 +902,5 @@ static void run_block_job(BlockJob *job, Error **errp)
}
-static int img_commit(int argc, char **argv)
+static int img_commit(const img_cmd_t *ccmd, int argc, char **argv)
{
int c, ret, flags;
@@ -969,9 +922,16 @@ static int img_commit(int argc, char **argv)
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
+ {"quiet", no_argument, 0, 'q'},
{"object", required_argument, 0, OPTION_OBJECT},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"cache", required_argument, 0, 't'},
+ {"drop", no_argument, 0, 'd'},
+ {"base", required_argument, 0, 'b'},
+ {"progress", no_argument, 0, 'p'},
+ {"rate", required_argument, 0, 'r'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":f:ht:b:dpqr:",
+ c = getopt_long(argc, argv, "f:ht:b:dpqr:",
long_options, NULL);
if (c == -1) {
@@ -979,12 +939,31 @@ static int img_commit(int argc, char **argv)
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd,
+"[-f FMT | --image-opts] [-t CACHE_MODE] [-b BASE_IMG] [-d]\n"
+" [-r RATE] [--object OBJDEF] FILENAME\n"
+,
+" -q, --quiet\n"
+" quiet operations\n"
+" -p, --progress\n"
+" show operation progress\n"
+" -f, --format FMT\n"
+" specify FILENAME image format explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -t, --cache CACHE_MODE image cache mode (" BDRV_DEFAULT_CACHE ")\n"
+" -d, --drop\n"
+" skip emptying FILENAME on completion\n"
+" -b, --base BASE_IMG\n"
+" image in the backing chain to which to commit changes\n"
+" instead of the previous one (implies --drop)\n"
+" -r, --rate RATE\n"
+" I/O rate limit\n"
+" --object OBJDEF\n"
+" QEMU user-creatable object (eg encryption key)\n"
+" FILENAME\n"
+" name of the image file to operate on\n"
+);
break;
case 'f':
@@ -1009,5 +988,5 @@ static int img_commit(int argc, char **argv)
break;
case 'r':
- rate_limit = cvtnum("rate limit", optarg);
+ rate_limit = cvtnum("rate limit", optarg, true);
if (rate_limit < 0) {
return 1;
@@ -1020,4 +999,6 @@ static int img_commit(int argc, char **argv)
image_opts = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -1029,5 +1010,5 @@ static int img_commit(int argc, char **argv)
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[optind++];
@@ -1356,5 +1337,5 @@ static int check_empty_sectors(BlockBackend *blk, int64_t offset,
* >1 - Error occurred
*/
-static int img_compare(int argc, char **argv)
+static int img_compare(const img_cmd_t *ccmd, int argc, char **argv)
{
const char *fmt1 = NULL, *fmt2 = NULL, *cache, *filename1, *filename2;
@@ -1381,10 +1362,18 @@ static int img_compare(int argc, char **argv)
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
+ {"quiet", no_argument, 0, 'q'},
{"object", required_argument, 0, OPTION_OBJECT},
+ {"cache", required_argument, 0, 'T'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"a-format", required_argument, 0, 'f'},
+ {"left-format", required_argument, 0, 'f'},
+ {"b-format", required_argument, 0, 'F'},
+ {"right-format", required_argument, 0, 'F'},
{"force-share", no_argument, 0, 'U'},
+ {"strict", no_argument, 0, 's'},
+ {"progress", no_argument, 0, 'p'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hf:F:T:pqsU",
+ c = getopt_long(argc, argv, "hf:F:T:pqsU",
long_options, NULL);
if (c == -1) {
@@ -1392,12 +1381,31 @@ static int img_compare(int argc, char **argv)
}
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd,
+"[--image-opts | [-f FMT] [-F FMT]] [-s]\n"
+" [-T CACHE] [-U] [--object OBJDEF] FILENAME1 FILENAME2\n"
+,
+" -q, --quiet\n"
+" quiet operation\n"
+" -p, --progress\n"
+" show operation progress\n"
+" -f, --a-format FMT\n"
+" specify FILENAME1 image format explicitly\n"
+" -F, --b-format FMT\n"
+" specify FILENAME2 image format explicitly\n"
+" --image-opts\n"
+" indicates that FILENAMEs are complete image specifications\n"
+" instead of file names (incompatible with --a-format and --b-format)\n"
+" -s, --strict\n"
+" strict mode, also check if sizes are equal\n"
+" -T, --cache CACHE_MODE\n"
+" images caching mode (" BDRV_DEFAULT_CACHE ")\n"
+" -U, --force-share\n"
+" open images in shared mode for concurrent access\n"
+" --object OBJDEF\n"
+" QEMU user-creatable object (eg encryption key)\n"
+" FILENAME1, FILENAME2\n"
+" image files (or specifications) to compare\n"
+);
break;
case 'f':
@@ -1440,4 +1448,6 @@ static int img_compare(int argc, char **argv)
image_opts = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -1450,5 +1460,5 @@ static int img_compare(int argc, char **argv)
if (optind != argc - 2) {
- error_exit("Expecting two image file names");
+ error_exit(argv[0], "Expecting two image file names");
}
filename1 = argv[optind++];
@@ -2232,5 +2242,5 @@ static void set_rate_limit(BlockBackend *blk, int64_t rate_limit)
}
-static int img_convert(int argc, char **argv)
+static int img_convert(const img_cmd_t *ccmd, int argc, char **argv)
{
int c, bs_i, flags, src_flags = BDRV_O_NO_SHARE;
@@ -2268,6 +2278,17 @@ static int img_convert(int argc, char **argv)
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
+ {"quiet", no_argument, 0, 'q'},
{"object", required_argument, 0, OPTION_OBJECT},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"source-image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"source-format", required_argument, 0, 'f'},
+ {"source-cache", required_argument, 0, 'T'},
+ {"snapshot", required_argument, 0, 'l'},
+ {"sparse-size", required_argument, 0, 'S'},
+ {"output-format", required_argument, 0, 'O'},
+ {"options", required_argument, 0, 'o'},
+ {"output-cache", required_argument, 0, 't'},
+ {"backing", required_argument, 0, 'B'},
+ {"backing-format", required_argument, 0, 'F'},
{"force-share", no_argument, 0, 'U'},
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
@@ -2276,20 +2297,79 @@ static int img_convert(int argc, char **argv)
{"bitmaps", no_argument, 0, OPTION_BITMAPS},
{"skip-broken-bitmaps", no_argument, 0, OPTION_SKIP_BROKEN},
+ {"rate", required_argument, 0, 'r'},
+ {"parallel", required_argument, 0, 'm'},
+ {"oob-writes", no_argument, 0, 'W'},
+ {"copy-range-offloading", no_argument, 0, 'C'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hf:O:B:CcF:o:l:S:pt:T:qnm:WUr:",
+ c = getopt_long(argc, argv, "hf:O:B:CcF:o:l:S:pt:T:qnm:WUr:",
long_options, NULL);
if (c == -1) {
break;
}
- switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
+ switch (c) {
case 'h':
- help();
+ cmd_help(ccmd,
+"[-f SRC_FMT|--image-opts] [-T SRC_CACHE] [--bitmaps [--skip-broken-bitmaps]]\n"
+" [-o TGT_OPTS|--target-image-opts] [-t TGT_CACHE] [-n]\n"
+" [-B BACKING_FILENAME [-F BACKING_FMT]]\n"
+" SRC_FILENAME [SRC_FILENAME2 [...]] TGT_FILENAME\n"
+,
+" -q, --quiet\n"
+" quiet operations\n"
+" -p, --progress\n"
+" show operation progress\n"
+" -f, --source-format SRC_FMT\n"
+" specify SRC_FILENAME source image format explicitly\n"
+" --source-image-opts\n"
+" indicates that SRC_FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --source-format)\n"
+" -l, --source-snapshot SNAPSHOT_PARAMS\n"
+" specify source snapshot parameters\n"
+" -T, --source-cache SRC_CACHE\n"
+" source image(s) cache mode (" BDRV_DEFAULT_CACHE ")\n"
+" -O, --target-format TGT_FMT\n"
+" specify TGT_FILENAME image format (default is raw)\n"
+" --target-image-opts\n"
+" indicates that TGT_FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --output-format)\n"
+" -o, --target-options TGT_OPTS\n"
+" TARGET_FMT-specific options\n"
+" -c, --compress\n"
+" create compressed output image (qcow and qcow2 format only)\n"
+" -t, --target-cache TGT_CACHE\n"
+" cache mode when opening output image (unsafe)\n"
+" -B, --backing BACKING_FILENAME\n"
+" create output to be a CoW on top of BACKING_FILENAME\n"
+" -F, --backing-format BACKING_FMT\n"
+" specify BACKING_FILENAME image format explicitly\n"
+" -n, --no-create\n"
+" omit target volume creation (eg on rbd)\n"
+" --target-is-zero\n"
+" -S, --sparse-size SPARSE_SIZE\n"
+" XXX todo\n"
+" --bitmaps\n"
+" also copy any persistent bitmaps present in source\n"
+" --skip-broken-bitmaps\n"
+" skip (do not error out) any broken bitmaps\n"
+" -U, --force-share\n"
+" open images in shared mode for concurrent access\n"
+" -r, --rate RATE\n"
+" I/O rate limit\n"
+" -m, --parallel NUM_COROUTINES\n"
+" specify parallelism (default 8)\n"
+" -C, --copy-range-offloading\n"
+" use copy_range offloading\n"
+" --salvage\n"
+" XXX todo\n"
+" -W, --oob-writes\n"
+" enable out-of-order writes to improve performance\n"
+" --object OBJDEF\n"
+" QEMU user-creatable object (eg encryption key)\n"
+" SRC_FILENAME\n"
+" source image file name (or specification with --image-opts)\n"
+" TGT_FILENAME\n"
+" target (output) image file name\n"
+);
break;
case 'f':
@@ -2333,5 +2413,5 @@ static int img_convert(int argc, char **argv)
int64_t sval;
- sval = cvtnum("buffer size for sparse output", optarg);
+ sval = cvtnum("buffer size for sparse output", optarg, true);
if (sval < 0) {
goto fail_getopt;
@@ -2365,8 +2445,7 @@ static int img_convert(int argc, char **argv)
break;
case 'm':
- if (qemu_strtol(optarg, NULL, 0, &s.num_coroutines) ||
- s.num_coroutines < 1 || s.num_coroutines > MAX_COROUTINES) {
- error_report("Invalid number of coroutines. Allowed number of"
- " coroutines is between 1 and %d", MAX_COROUTINES);
+ s.num_coroutines = cvtnum_full("number of coroutines", optarg,
+ false, 1, MAX_COROUTINES);
+ if (s.num_coroutines < 0) {
goto fail_getopt;
}
@@ -2379,5 +2458,5 @@ static int img_convert(int argc, char **argv)
break;
case 'r':
- rate_limit = cvtnum("rate limit", optarg);
+ rate_limit = cvtnum("rate limit", optarg, true);
if (rate_limit < 0) {
goto fail_getopt;
@@ -2410,4 +2489,6 @@ static int img_convert(int argc, char **argv)
skip_broken = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -3000,10 +3081,10 @@ err:
}
-static int img_info(int argc, char **argv)
+static int img_info(const img_cmd_t *ccmd, int argc, char **argv)
{
int c;
OutputFormat output_format = OFORMAT_HUMAN;
bool chain = false;
- const char *filename, *fmt, *output;
+ const char *filename, *fmt;
BlockGraphInfoList *list;
bool image_opts = false;
@@ -3011,12 +3092,10 @@ static int img_info(int argc, char **argv)
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},
+ {"backing-chain", no_argument, 0, 'b'},
{"object", required_argument, 0, OPTION_OBJECT},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
@@ -3024,18 +3103,32 @@ static int img_info(int argc, char **argv)
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":f:hU",
- long_options, &option_index);
+ c = getopt_long(argc, argv, "f:hbU",
+ long_options, NULL);
if (c == -1) {
break;
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd,
+"[-f FMT | --image-opts] [-b] [-U] [--object OBJDEF]\n"
+" [--output human|json] FILENAME\n"
+,
+" -f, --format FMT\n"
+" specify FILENAME image format explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -b, --backing-chain\n"
+" display information about backing chaing\n"
+" (in case the image is stacked\n"
+" -U, --force-share\n"
+" open image in shared mode for concurrent access\n"
+" --object OBJDEF\n"
+" QEMU user-creatable object (eg encryption key)\n"
+" --output human|json\n"
+" specify output format name (default human)\n"
+" FILENAME\n"
+" image file name (or specification with --image-opts)\n"
+);
break;
case 'f':
@@ -3046,7 +3139,7 @@ static int img_info(int argc, char **argv)
break;
case OPTION_OUTPUT:
- output = optarg;
+ output_format = parse_output_format(argv[0], optarg);
break;
- case OPTION_BACKING_CHAIN:
+ case 'b':
chain = true;
break;
@@ -3057,20 +3150,13 @@ static int img_info(int argc, char **argv)
image_opts = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[optind++];
- if (output && !strcmp(output, "json")) {
- output_format = OFORMAT_JSON;
- } else if (output && !strcmp(output, "human")) {
- output_format = OFORMAT_HUMAN;
- } else if (output) {
- error_report("--output must be used with human or json as argument.");
- return 1;
- }
-
list = collect_image_info_list(image_opts, filename, fmt, chain,
force_share);
@@ -3225,5 +3311,5 @@ static inline bool entry_mergeable(const MapEntry *curr, const MapEntry *next)
}
-static int img_map(int argc, char **argv)
+static int img_map(const img_cmd_t *ccmd, int argc, char **argv)
{
int c;
@@ -3231,5 +3317,5 @@ static int img_map(int argc, char **argv)
BlockBackend *blk;
BlockDriverState *bs;
- const char *filename, *fmt, *output;
+ const char *filename, *fmt;
int64_t length;
MapEntry curr = { .length = 0 }, next;
@@ -3241,7 +3327,5 @@ static int img_map(int argc, char **argv)
fmt = NULL;
- output = NULL;
for (;;) {
- int option_index = 0;
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
@@ -3255,18 +3339,31 @@ static int img_map(int argc, char **argv)
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":f:s:l:hU",
- long_options, &option_index);
+ c = getopt_long(argc, argv, "f:s:l:hU",
+ long_options, NULL);
if (c == -1) {
break;
}
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd,
+"[-f FMT | --image-opts] [--object OBJDEF] [--output human|json]\n"
+" [--start-offset OFFSET] [--max-length LENGTH] [-U] FILENAME\n"
+,
+" -f, --format FMT\n"
+" specify FILENAME image format explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" --start-offset OFFSET\n"
+" --max-length LENGTH\n"
+" --output human|json\n"
+" specify output format name (default human)\n"
+" -U, --force-share\n"
+" open image in shared mode for concurrent access\n"
+" --object OBJDEF\n"
+" QEMU user-creatable object (eg encryption key)\n"
+" FILENAME\n"
+" image file name (or specification with --image-opts)\n"
+);
break;
case 'f':
@@ -3277,8 +3374,8 @@ static int img_map(int argc, char **argv)
break;
case OPTION_OUTPUT:
- output = optarg;
+ output_format = parse_output_format(argv[0], optarg);
break;
case 's':
- start_offset = cvtnum("start offset", optarg);
+ start_offset = cvtnum("start offset", optarg, true);
if (start_offset < 0) {
return 1;
@@ -3286,5 +3383,5 @@ static int img_map(int argc, char **argv)
break;
case 'l':
- max_length = cvtnum("max length", optarg);
+ max_length = cvtnum("max length", optarg, true);
if (max_length < 0) {
return 1;
@@ -3297,20 +3394,13 @@ static int img_map(int argc, char **argv)
image_opts = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[optind];
- if (output && !strcmp(output, "json")) {
- output_format = OFORMAT_JSON;
- } else if (output && !strcmp(output, "human")) {
- output_format = OFORMAT_HUMAN;
- } else if (output) {
- error_report("--output must be used with human or json as argument.");
- return 1;
- }
-
blk = img_open(image_opts, filename, fmt, 0, false, false, force_share);
if (!blk) {
@@ -3369,16 +3459,17 @@ out:
}
-#define SNAPSHOT_LIST 1
-#define SNAPSHOT_CREATE 2
-#define SNAPSHOT_APPLY 3
-#define SNAPSHOT_DELETE 4
+/* the same as options */
+#define SNAPSHOT_LIST 'l'
+#define SNAPSHOT_CREATE 'c'
+#define SNAPSHOT_APPLY 'a'
+#define SNAPSHOT_DELETE 'd'
-static int img_snapshot(int argc, char **argv)
+static int img_snapshot(const img_cmd_t *ccmd, int argc, char **argv)
{
BlockBackend *blk;
BlockDriverState *bs;
QEMUSnapshotInfo sn;
- char *filename, *snapshot_name = NULL;
- int c, ret = 0, bdrv_oflags;
+ char *filename, *fmt = NULL, *snapshot_name = NULL;
+ int c, ret = 0;
int action = 0;
bool quiet = false;
@@ -3388,15 +3479,20 @@ static int img_snapshot(int argc, char **argv)
int64_t rt;
- bdrv_oflags = BDRV_O_RDWR;
/* Parse commandline parameters */
for(;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
+ {"quiet", no_argument, 0, 'q'},
{"object", required_argument, 0, OPTION_OBJECT},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"force-share", no_argument, 0, 'U'},
+ {"list", no_argument, 0, SNAPSHOT_LIST},
+ {"apply", no_argument, 0, SNAPSHOT_APPLY},
+ {"create", no_argument, 0, SNAPSHOT_CREATE},
+ {"delete", no_argument, 0, SNAPSHOT_DELETE},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":la:c:d:hqU",
+ c = getopt_long(argc, argv, "la:c:d:f:hqU",
long_options, NULL);
if (c == -1) {
@@ -3404,43 +3500,44 @@ static int img_snapshot(int argc, char **argv)
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
- return 0;
- case 'l':
- if (action) {
- error_exit("Cannot mix '-l', '-a', '-c', '-d'");
- return 0;
- }
- action = SNAPSHOT_LIST;
- bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
+ cmd_help(ccmd,
+"[-f FMT | --image-opts] [-l | -a|-c|-d SNAPSHOT]\n"
+" [-U] [--object OBJDEF] FILENAME\n"
+,
+" -q, --quiet\n"
+" quiet operations\n"
+" -f, --format FMT\n"
+" specify FILENAME format explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -U, --force-share\n"
+" open image in shared mode for concurrent access\n"
+" --object OBJDEF\n"
+" QEMU user-creatable object (eg encryption key)\n"
+" Operation, one of:\n"
+" -l, --list\n"
+" list snapshots in FILENAME (the default)\n"
+" -c, --create SNAPSHOT\n"
+" create named snapshot\n"
+" -a, --apply SNAPSHOT\n"
+" apply named snapshot to the base\n"
+" -d, --delete SNAPSHOT\n"
+" delete named snapshot\n"
+" FILENAME - image file name (or specification with --image-opts)\n"
+);
break;
- case 'a':
- if (action) {
- error_exit("Cannot mix '-l', '-a', '-c', '-d'");
- return 0;
- }
- action = SNAPSHOT_APPLY;
- snapshot_name = optarg;
+ case 'f':
+ fmt = optarg;
break;
- case 'c':
+ case SNAPSHOT_LIST:
+ case SNAPSHOT_APPLY:
+ case SNAPSHOT_CREATE:
+ case SNAPSHOT_DELETE:
if (action) {
- error_exit("Cannot mix '-l', '-a', '-c', '-d'");
+ error_exit(argv[0], "Cannot mix '-l', '-a', '-c', '-d'");
return 0;
}
- action = SNAPSHOT_CREATE;
- snapshot_name = optarg;
- break;
- case 'd':
- if (action) {
- error_exit("Cannot mix '-l', '-a', '-c', '-d'");
- return 0;
- }
- action = SNAPSHOT_DELETE;
+ action = c;
snapshot_name = optarg;
break;
@@ -3457,15 +3554,22 @@ static int img_snapshot(int argc, char **argv)
image_opts = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[optind++];
+ if (!action) {
+ action = SNAPSHOT_LIST;
+ }
+
/* Open the image */
- blk = img_open(image_opts, filename, NULL, bdrv_oflags, false, quiet,
- force_share);
+ blk = img_open(image_opts, filename, fmt,
+ action == SNAPSHOT_LIST ? 0 : BDRV_O_RDWR,
+ false, quiet, force_share);
if (!blk) {
return 1;
@@ -3532,5 +3636,5 @@ static int img_snapshot(int argc, char **argv)
}
-static int img_rebase(int argc, char **argv)
+static int img_rebase(const img_cmd_t *ccmd, int argc, char **argv)
{
BlockBackend *blk = NULL, *blk_old_backing = NULL, *blk_new_backing = NULL;
@@ -3563,24 +3667,59 @@ static int img_rebase(int argc, char **argv)
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
+ {"quiet", no_argument, 0, 'q'},
+ {"progress", no_argument, 0, 'p'},
{"object", required_argument, 0, OPTION_OBJECT},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"force-share", no_argument, 0, 'U'},
+ {"format", required_argument, 0, 'f'},
+ {"cache", required_argument, 0, 't'},
{"compress", no_argument, 0, 'c'},
+ {"backing", required_argument, 0, 'b'},
+ {"backing-format", required_argument, 0, 'F'},
+ {"backing-cache", required_argument, 0, 'T'},
+ {"backing-unsafe", no_argument, 0, 'u'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hf:F:b:upt:T:qUc",
+ c = getopt_long(argc, argv, "hf:F:b:upt:T:qUc",
long_options, NULL);
if (c == -1) {
break;
}
- switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
+ switch (c) {
case 'h':
- help();
+ cmd_help(ccmd,
+"[-f FMT | --image-opts] [-t CACHE] [-q] [-U] [-p]\n"
+" [-b BACKING_FILENAME [-F BACKING_FMT] [-T BACKING_CACHE]] [-u]\n"
+" [--object OBJDEF] [-c] FILENAME\n"
+"Rebases FILENAME on top of BACKING_FILENAME or no backing file\n"
+,
+" -q, --quiet\n"
+" quiet operation\n"
+" -p, --progress\n"
+" show progress indicator\n"
+" -f, --format FMT\n"
+" specify FILENAME format explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -t, --cache CACHE\n"
+" cache mode for FILENAME (" BDRV_DEFAULT_CACHE ")\n"
+" -b, --backing BACKING_FILENAME|\"\"\n"
+" rebase onto this file (or no backing file)\n"
+" -F, --backing-format BACKING_FMT\n"
+" specify format for BACKING_FILENAME\n"
+" -T, --backing-cache CACHE\n"
+" BACKING_FILENAME cache mode (" BDRV_DEFAULT_CACHE ")\n"
+" -u, --backing-unsafe\n"
+" do not fail if BACKING_FILENAME can not be read\n"
+" -c, --compress\n"
+" compress image (when image supports this)\n"
+" -U, --force-share\n"
+" open image in shared mode for concurrent access\n"
+" --object OBJDEF\n"
+" QEMU user-creatable object (eg encryption key)\n"
+" FILENAME\n"
+" image file name (or specification with --image-opts)\n"
+);
return 0;
case 'f':
@@ -3620,4 +3759,6 @@ static int img_rebase(int argc, char **argv)
compress = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -3628,8 +3769,9 @@ static int img_rebase(int argc, char **argv)
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
if (!unsafe && !out_baseimg) {
- error_exit("Must specify backing file (-b) or use unsafe mode (-u)");
+ error_exit(argv[0],
+ "Must specify backing file (-b) or use unsafe mode (-u)");
}
filename = argv[optind++];
@@ -4025,9 +4167,9 @@ out:
}
-static int img_resize(int argc, char **argv)
+static int img_resize(const img_cmd_t *ccmd, int argc, char **argv)
{
Error *err = NULL;
int c, ret, relative;
- const char *filename, *fmt, *size;
+ const char *filename = NULL, *fmt = NULL, *size = NULL;
int64_t n, total_size, current_size;
bool quiet = false;
@@ -4052,19 +4194,11 @@ static int img_resize(int argc, char **argv)
bool shrink = false;
- /* Remove size from argv manually so that negative numbers are not treated
- * as options by getopt. */
- if (argc < 3) {
- error_exit("Not enough arguments");
- return 1;
- }
-
- size = argv[--argc];
-
/* Parse getopt arguments */
- fmt = NULL;
for(;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
+ {"quiet", no_argument, 0, 'q'},
{"object", required_argument, 0, OPTION_OBJECT},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"preallocation", required_argument, 0, OPTION_PREALLOCATION},
@@ -4072,5 +4206,5 @@ static int img_resize(int argc, char **argv)
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":f:hq",
+ c = getopt_long(argc, argv, "-f:hq",
long_options, NULL);
if (c == -1) {
@@ -4078,13 +4212,29 @@ static int img_resize(int argc, char **argv)
}
switch(c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
- break;
+ cmd_help(ccmd,
+"[-f FMT | --image-opts] [--preallocation PREALLOC] [--shrink]\n"
+" [--object OBJECTDEF] [-q] FILENAME [+-]SIZE[bkKMGTPE]\n"
+,
+" -q, --quiet\n"
+" quiet operation\n"
+" -f, --format FMT\n"
+" specify FILENAME format explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" --shrink\n"
+" allow operation when new size is smaller than original\n"
+" --preallocation PREALLOC\n"
+" specify preallocation type for the new areas\n"
+" --object OBJDEF\n"
+" QEMU user-creatable object (eg encryption key)\n"
+" FILENAME\n"
+" image file (specification) to resize\n"
+" [+-]SIZE[bkKMGTPE]\n"
+" new image size or amount by which to shrink/grow,\n"
+" with optional suffix (1024-based multiplies)\n"
+);
+ return 0;
case 'f':
fmt = optarg;
@@ -4110,10 +4260,35 @@ static int img_resize(int argc, char **argv)
shrink = true;
break;
+ case 1: /* a non-optional argument */
+ if (!filename) {
+ filename = optarg;
+ /* see if we have -size (number) next to filename */
+ if (optind < argc) {
+ size = argv[optind];
+ if (size[0] == '-' && size[1] >= '0' && size[1] <= '9') {
+ ++optind;
+ } else {
+ size = NULL;
+ }
+ }
+ } else if (!size) {
+ size = optarg;
+ } else {
+ error_exit(argv[0], "Extra argument(s) in command line");
+ }
+ break;
+ default:
+ tryhelp(argv[0]);
}
}
- if (optind != argc - 1) {
- error_exit("Expecting image file name and size");
+ if (!filename && optind < argc) {
+ filename = argv[optind++];
+ }
+ if (!size && optind < argc) {
+ size = argv[optind++];
+ }
+ if (!filename || !size || optind < argc) {
+ error_exit(argv[0], "Expecting image file name and size");
}
- filename = argv[optind++];
/* Choose grow, shrink, or absolute resize mode */
@@ -4238,5 +4413,5 @@ static int print_amend_option_help(const char *format)
}
-static int img_amend(int argc, char **argv)
+static int img_amend(const img_cmd_t *ccmd, int argc, char **argv)
{
Error *err = NULL;
@@ -4258,10 +4433,15 @@ static int img_amend(int argc, char **argv)
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
+ {"quiet", no_argument, 0, 'q'},
+ {"progress", no_argument, 0, 'p'},
{"object", required_argument, 0, OPTION_OBJECT},
+ {"format", required_argument, 0, 'f'},
+ {"cache", required_argument, 0, 't'},
+ {"options", required_argument, 0, 'o'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{"force", no_argument, 0, OPTION_FORCE},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":ho:f:t:pq",
+ c = getopt_long(argc, argv, "ho:f:t:pq",
long_options, NULL);
if (c == -1) {
@@ -4270,12 +4450,23 @@ static int img_amend(int argc, char **argv)
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd,
+"[-f FMT | --image-opts] [t CACHE] [--force] [-p] [-q]\n"
+" [--object OBJDEF -o OPTIONS FILENAME\n"
+,
+" -q, --quiet\n"
+" quiet operation\n"
+" -p, --progres\n"
+" show progress\n"
+" -f, --format FMT\n"
+" specify FILENAME format explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -t, --cache CACHE\n"
+" cache mode for FILENAME (" BDRV_DEFAULT_CACHE ")\n"
+" --force\n"
+" allow certain unsafe operations\n"
+);
break;
case 'o':
@@ -4306,9 +4497,11 @@ static int img_amend(int argc, char **argv)
force = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
if (!options) {
- error_exit("Must specify options (-o)");
+ error_exit(argv[0], "Must specify options (-o)");
}
@@ -4502,5 +4695,5 @@ static void bench_cb(void *opaque, int ret)
}
-static int img_bench(int argc, char **argv)
+static int img_bench(const img_cmd_t *ccmd, int argc, char **argv)
{
int c, ret = 0;
@@ -4512,7 +4705,7 @@ static int img_bench(int argc, char **argv)
int depth = 64;
int64_t offset = 0;
- size_t bufsize = 4096;
+ ssize_t bufsize = 4096;
int pattern = 0;
- size_t step = 0;
+ ssize_t step = 0;
int flush_interval = 0;
bool drain_on_flush = true;
@@ -4530,13 +4723,23 @@ static int img_bench(int argc, char **argv)
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
- {"flush-interval", required_argument, 0, OPTION_FLUSH_INTERVAL},
+ {"format", required_argument, 0, 'f'},
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"cache", required_argument, 0, 't'},
+ {"count", required_argument, 0, 'c'},
+ {"depth", required_argument, 0, 'd'},
+ {"offset", required_argument, 0, 'o'},
+ {"buffer-size", required_argument, 0, 's'},
+ {"step-size", required_argument, 0, 'S'},
+ {"aio", required_argument, 0, 'i'},
+ {"native", no_argument, 0, 'n'},
+ {"write", no_argument, 0, 'w'},
{"pattern", required_argument, 0, OPTION_PATTERN},
+ {"flush-interval", required_argument, 0, OPTION_FLUSH_INTERVAL},
{"no-drain", no_argument, 0, OPTION_NO_DRAIN},
{"force-share", no_argument, 0, 'U'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":hc:d:f:ni:o:qs:S:t:wU", long_options,
- NULL);
+ c = getopt_long(argc, argv, "hc:d:f:ni:o:qs:S:t:wU",
+ long_options, NULL);
if (c == -1) {
break;
@@ -4544,35 +4747,57 @@ static int img_bench(int argc, char **argv)
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd,
+"[-f FMT | --image-opts] [-t CACHE] [-c COUNT] [-d DEPTH]\n"
+" [-o OFFSET] [-s BUFFER_SIZE] [-S STEP_SIZE] [-i AIO] [-n]\n"
+" [-w [--pattern PATTERN] [--flush-interval INTERVAL [--no-drain]]]\n"
+,
+" -q, --quiet\n"
+" quiet operations\n"
+" -f, --format FMT\n"
+" specify FILENAME format explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -t, --cache CACHE\n"
+" cache mode for FILENAME (" BDRV_DEFAULT_CACHE ")\n"
+" -c, --count COUNT\n"
+" number of I/O requests to perform\n"
+" -s, --buffer-size BUFFER_SIZE\n"
+" size of each I/O request\n"
+" -d, --depth DEPTH\n"
+" number of requests to perform in parallel\n"
+" -o, --offset OFFSET\n"
+" start first request at this OFFSET\n"
+" -S, --step-size STEP_SIZE\n"
+" each next request offset increment\n"
+" -i, --aio AIO\n"
+" async-io backend (threads, native, io_uring)\n"
+" -n, --native\n"
+" use native AIO backend if possible\n"
+" -w, --write\n"
+" perform write test (default is read)\n"
+" --pattern PATTERN\n"
+" write this pattern byte instead of zero\n"
+" --flush-interval FLUSH_INTERVAL\n"
+" issue flush after this number of requests\n"
+" --no-drain\n"
+" do not wait when flushing pending requests\n"
+" -U, --force-share\n"
+" open images in shared mode for concurrent access\n"
+);
break;
case 'c':
- {
- unsigned long res;
-
- if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > INT_MAX) {
- error_report("Invalid request count specified");
+ count = cvtnum_full("request count", optarg, false, 1, INT_MAX);
+ if (count < 0) {
return 1;
}
- count = res;
break;
- }
case 'd':
- {
- unsigned long res;
-
- if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > INT_MAX) {
- error_report("Invalid queue depth specified");
+ depth = cvtnum_full("queue depth", optarg, false, 1, INT_MAX);
+ if (depth < 0) {
return 1;
}
- depth = res;
break;
- }
case 'f':
fmt = optarg;
@@ -4590,39 +4815,24 @@ static int img_bench(int argc, char **argv)
break;
case 'o':
- {
- offset = cvtnum("offset", optarg);
+ offset = cvtnum("offset", optarg, true);
if (offset < 0) {
return 1;
}
break;
- }
- break;
case 'q':
quiet = true;
break;
case 's':
- {
- int64_t sval;
-
- sval = cvtnum_full("buffer size", optarg, 0, INT_MAX);
- if (sval < 0) {
+ bufsize = cvtnum_full("buffer size", optarg, true, 1, INT_MAX);
+ if (bufsize < 0) {
return 1;
}
-
- bufsize = sval;
break;
- }
case 'S':
- {
- int64_t sval;
-
- sval = cvtnum_full("step_size", optarg, 0, INT_MAX);
- if (sval < 0) {
+ step = cvtnum_full("step size", optarg, true, 0, INT_MAX);
+ if (step < 0) {
return 1;
}
-
- step = sval;
break;
- }
case 't':
ret = bdrv_parse_cache_mode(optarg, &flags, &writethrough);
@@ -4641,25 +4851,16 @@ static int img_bench(int argc, char **argv)
break;
case OPTION_PATTERN:
- {
- unsigned long res;
-
- if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > 0xff) {
- error_report("Invalid pattern byte specified");
+ pattern = cvtnum_full("pattern byte", optarg, false, 0, 0xff);
+ if (pattern < 0) {
return 1;
}
- pattern = res;
break;
- }
case OPTION_FLUSH_INTERVAL:
- {
- unsigned long res;
-
- if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > INT_MAX) {
- error_report("Invalid flush interval specified");
+ flush_interval = cvtnum_full("flush interval", optarg,
+ false, 0, INT_MAX);
+ if (flush_interval < 0) {
return 1;
}
- flush_interval = res;
break;
- }
case OPTION_NO_DRAIN:
drain_on_flush = false;
@@ -4668,9 +4869,11 @@ static int img_bench(int argc, char **argv)
image_opts = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
if (optind != argc - 1) {
- error_exit("Expecting one image file name");
+ error_exit(argv[0], "Expecting one image file name");
}
filename = argv[argc - 1];
@@ -4772,5 +4975,5 @@ typedef struct ImgBitmapAction {
} ImgBitmapAction;
-static int img_bitmap(int argc, char **argv)
+static int img_bitmap(const img_cmd_t *ccmd, int argc, char **argv)
{
Error *err = NULL;
@@ -4807,5 +5010,6 @@ static int img_bitmap(int argc, char **argv)
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, ":b:f:F:g:h", long_options, NULL);
+ c = getopt_long(argc, argv, "b:f:F:g:h",
+ long_options, NULL);
if (c == -1) {
break;
@@ -4813,12 +5017,33 @@ static int img_bitmap(int argc, char **argv)
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
case 'h':
- help();
+ cmd_help(ccmd,
+"( --merge SOURCE | --add | --remove | --clear |\n"
+" --enable | --disable ).. [-f FMT | --image-opts]\n"
+" [ -b SRC_FILENAME [-F SOURCE_FMT]] [-g SIZE[KMGTPE]] [--object OBJDEF]\n"
+" FILENAME BITMAP\n"
+,
+" -f, --format FMT\n"
+" specify FILENAME format explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" --add\n"
+" creates BITMAP, enables to record future edits\n"
+" -g, --granularity SIZE[KMGTPE]\n"
+" sets non-default bitmap granularity for --add to this size\n"
+" --remove\n"
+" removes BITMAP\n"
+" --clear\n"
+" clears BITMAP\n"
+" --enable, --disable\n"
+" starts and stops recording future edits to BITMAP\n"
+" --merge SRC_FILENAME\n"
+" merges contents of SRC_FILENAME bitmap into BITMAP\n"
+" -b, --source-file SRC_FILENAME\n"
+" select alternative source file for --merge\n"
+" -F, --source-format SRC_FMT\n"
+" specify format for SRC_FILENAME explicitly\n"
+);
break;
case 'b':
@@ -4832,5 +5057,5 @@ static int img_bitmap(int argc, char **argv)
break;
case 'g':
- granularity = cvtnum("granularity", optarg);
+ granularity = cvtnum("granularity", optarg, true);
if (granularity < 0) {
return 1;
@@ -4876,4 +5101,6 @@ static int img_bitmap(int argc, char **argv)
image_opts = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -5018,5 +5245,5 @@ static int img_dd_bs(const char *arg,
int64_t res;
- res = cvtnum_full("bs", arg, 1, INT_MAX);
+ res = cvtnum_full("bs", arg, true, 1, INT_MAX);
if (res < 0) {
@@ -5032,5 +5259,5 @@ static int img_dd_count(const char *arg,
struct DdInfo *dd)
{
- dd->count = cvtnum("count", arg);
+ dd->count = cvtnum("count", arg, false);
if (dd->count < 0) {
@@ -5063,5 +5290,5 @@ static int img_dd_skip(const char *arg,
struct DdInfo *dd)
{
- in->offset = cvtnum("skip", arg);
+ in->offset = cvtnum("skip", arg, false);
if (in->offset < 0) {
@@ -5072,5 +5299,5 @@ static int img_dd_skip(const char *arg,
}
-static int img_dd(int argc, char **argv)
+static int img_dd(const img_cmd_t *ccmd, int argc, char **argv)
{
int ret = 0;
@@ -5117,4 +5344,6 @@ static int img_dd(int argc, char **argv)
{ "help", no_argument, 0, 'h'},
{ "object", required_argument, 0, OPTION_OBJECT},
+ { "format", required_argument, 0, 'f'},
+ { "output-format", required_argument, 0, 'O'},
{ "image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
{ "force-share", no_argument, 0, 'U'},
@@ -5122,9 +5351,33 @@ static int img_dd(int argc, char **argv)
};
- while ((c = getopt_long(argc, argv, ":hf:O:U", long_options, NULL))) {
+ while ((c = getopt_long(argc, argv, "hf:O:U", long_options, NULL))) {
if (c == EOF) {
break;
}
switch (c) {
+ case 'h':
+ cmd_help(ccmd,
+"[-f FMT|--image-opts] [-O OUTPUT_FMT] [-U]\n"
+" [bs=BLOCK_SIZE] [count=BLOCKS] if=INPUT of=OUTPUT\n"
+,
+" -f, --format FMT\n"
+" specify format for INPUT explicitly\n"
+" --image-opts\n"
+" indicates that INPUT is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -O, --output-format OUTPUT_FMT\n"
+" format of the OUTPUT (default raw)\n"
+" -U, --force-share\n"
+" open images in shared mode for concurrent access\n"
+" bs=BLOCK_SIZE[kKMGTP]\n"
+" size of I/O block (default 512)\n"
+" count=COUNT\n"
+" number of blocks to convert (default whole INPUT)\n"
+" if=INPUT\n"
+" input file name (or image specification with --image-opts)\n"
+" of=OUTPUT\n"
+" output file name to create\n"
+);
+ break;
case 'O':
out_fmt = optarg;
@@ -5133,13 +5386,4 @@ static int img_dd(int argc, char **argv)
fmt = optarg;
break;
- case ':':
- missing_argument(argv[optind - 1]);
- break;
- case '?':
- unrecognized_option(argv[optind - 1]);
- break;
- case 'h':
- help();
- break;
case 'U':
force_share = true;
@@ -5151,4 +5395,6 @@ static int img_dd(int argc, char **argv)
image_opts = true;
break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -5340,15 +5586,6 @@ static void dump_json_block_measure_info(BlockMeasureInfo *info)
}
-static int img_measure(int argc, char **argv)
+static int img_measure(const img_cmd_t *ccmd, int argc, char **argv)
{
- static const struct option long_options[] = {
- {"help", no_argument, 0, 'h'},
- {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
- {"object", required_argument, 0, OPTION_OBJECT},
- {"output", required_argument, 0, OPTION_OUTPUT},
- {"size", required_argument, 0, OPTION_SIZE},
- {"force-share", no_argument, 0, 'U'},
- {0, 0, 0, 0}
- };
OutputFormat output_format = OFORMAT_HUMAN;
BlockBackend *in_blk = NULL;
@@ -5365,5 +5602,5 @@ static int img_measure(int argc, char **argv)
QemuOptsList *create_opts = NULL;
bool image_opts = false;
- uint64_t img_size = UINT64_MAX;
+ int64_t img_size = -1;
BlockMeasureInfo *info = NULL;
Error *local_err = NULL;
@@ -5371,10 +5608,45 @@ static int img_measure(int argc, char **argv)
int c;
+ static const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"target-format", required_argument, 0, 'O'},
+ {"format", required_argument, 0, 'f'},
+ {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
+ {"options", required_argument, 0, 'o'},
+ {"snapshot", required_argument, 0, 'l'},
+ {"object", required_argument, 0, OPTION_OBJECT},
+ {"output", required_argument, 0, OPTION_OUTPUT},
+ {"size", required_argument, 0, 's'},
+ {"force-share", no_argument, 0, 'U'},
+ {0, 0, 0, 0}
+ };
+
while ((c = getopt_long(argc, argv, "hf:O:o:l:U",
long_options, NULL)) != -1) {
switch (c) {
- case '?':
case 'h':
- help();
+ cmd_help(ccmd,
+"[-f FMT|--image-opts] [-o OPTIONS] [-O OUTPUT_FMT]\n"
+" [--output OFMT] [--object OBJDEF] [-l SNAPSHOT_PARAM]\n"
+" (--size SIZE | FILENAME)\n"
+,
+" -O, --target-format FMT\n"
+" desired target/output image format (default raw)\n"
+" -s, --size SIZE\n"
+" measure file size for given image size\n"
+" FILENAME\n"
+" measure file size required to convert from FILENAME\n"
+" -f, --format\n"
+" specify format of FILENAME explicitly\n"
+" --image-opts\n"
+" indicates that FILENAME is a complete image specification\n"
+" instead of a file name (incompatible with --format)\n"
+" -l, --snapshot SNAPSHOT\n"
+" use this snapshot in FILENAME as source\n"
+" --output human|json\n"
+" output format\n"
+" -U, --force-share\n"
+" open images in shared mode for concurrent access\n"
+);
break;
case 'f':
@@ -5412,25 +5684,14 @@ static int img_measure(int argc, char **argv)
break;
case OPTION_OUTPUT:
- if (!strcmp(optarg, "json")) {
- output_format = OFORMAT_JSON;
- } else if (!strcmp(optarg, "human")) {
- output_format = OFORMAT_HUMAN;
- } else {
- error_report("--output must be used with human or json "
- "as argument.");
- goto out;
- }
+ output_format = parse_output_format(argv[0], optarg);
break;
- case OPTION_SIZE:
- {
- int64_t sval;
-
- sval = cvtnum("image size", optarg);
- if (sval < 0) {
+ case 's':
+ img_size = cvtnum("image size", optarg, true);
+ if (img_size < 0) {
goto out;
}
- img_size = (uint64_t)sval;
- }
- break;
+ break;
+ default:
+ tryhelp(argv[0]);
}
}
@@ -5447,9 +5708,9 @@ static int img_measure(int argc, char **argv)
goto out;
}
- if (filename && img_size != UINT64_MAX) {
+ if (filename && img_size != -1) {
error_report("--size N cannot be used together with a filename.");
goto out;
}
- if (!filename && img_size == UINT64_MAX) {
+ if (!filename && img_size == -1) {
error_report("Either --size N or one filename must be specified.");
goto out;
@@ -5499,5 +5760,5 @@ static int img_measure(int argc, char **argv)
}
}
- if (img_size != UINT64_MAX) {
+ if (img_size != -1) {
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, &error_abort);
}
@@ -5533,11 +5794,47 @@ out:
static const img_cmd_t img_cmds[] = {
-#define DEF(option, callback, arg_string) \
- { option, callback },
-#include "qemu-img-cmds.h"
-#undef DEF
+ { "amend", img_amend,
+ "Update format-specific options of the image" },
+ { "bench", img_bench,
+ "Run simple image benchmark" },
+ { "bitmap", img_bitmap,
+ "Perform modifications of the persistent bitmap in the image" },
+ { "check", img_check,
+ "Check basic image integrity" },
+ { "commit", img_commit,
+ "Commit image to its backing file" },
+ { "compare", img_compare,
+ "Check if two images have the same contents" },
+ { "convert", img_convert,
+ "Copy one image to another with optional format conversion" },
+ { "create", img_create,
+ "Create and format new image file" },
+ { "dd", img_dd,
+ "Copy input to output with optional format conversion" },
+ { "info", img_info,
+ "Display information about image" },
+ { "map", img_map,
+ "Dump image metadata" },
+ { "measure", img_measure,
+ "Calculate file size requred for a new image" },
+ { "rebase", img_rebase,
+ "Change backing file of the image" },
+ { "resize", img_resize,
+ "Resize the image to the new size" },
+ { "snapshot", img_snapshot,
+ "List or manipulate snapshots within image" },
{ NULL, NULL, },
};
+static void format_print(void *opaque, const char *name)
+{
+ int *np = opaque;
+ if (*np + strlen(name) > 75) {
+ printf("\n ");
+ *np = 1;
+ }
+ *np += printf(" %s", name);
+}
+
int main(int argc, char **argv)
{
@@ -5567,21 +5864,37 @@ int main(int argc, char **argv)
module_call_init(MODULE_INIT_QOM);
bdrv_init();
- if (argc < 2) {
- error_exit("Not enough arguments");
- }
qemu_add_opts(&qemu_source_opts);
qemu_add_opts(&qemu_trace_opts);
- while ((c = getopt_long(argc, argv, "+:hVT:", long_options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "+hVT:", long_options, NULL)) != -1) {
switch (c) {
- case ':':
- missing_argument(argv[optind - 1]);
- return 0;
- case '?':
- unrecognized_option(argv[optind - 1]);
- return 0;
case 'h':
- help();
+ printf(
+QEMU_IMG_VERSION
+"QEMU disk image utility. Usage:\n"
+"\n"
+" qemu-img [standard options] COMMAND [--help | command options]\n"
+"\n"
+"Standard options:\n"
+" -h, --help\n"
+" display this help and exit\n"
+" -V, --version\n"
+" display version info and exit\n"
+" -T,--trace TRACE\n"
+" specify tracing options:\n"
+" [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
+"\n"
+"Recognized commands (run qemu-img COMMAND --help for command-specific help):\n\n");
+ for (cmd = img_cmds; cmd->name != NULL; cmd++) {
+ printf(" %s - %s\n", cmd->name, cmd->description);
+ }
+ printf("\nSupported image formats:\n");
+ c = 99; /* force a newline */
+ bdrv_iterate_format(format_print, &c, false);
+ if (c) {
+ printf("\n");
+ }
+ printf("\n" QEMU_HELP_BOTTOM "\n");
return 0;
case 'V':
@@ -5591,16 +5904,14 @@ int main(int argc, char **argv)
trace_opt_parse(optarg);
break;
+ default:
+ tryhelp(argv[0]);
}
}
- cmdname = argv[optind];
-
- /* reset getopt_long scanning */
- argc -= optind;
- if (argc < 1) {
- return 0;
+ if (optind >= argc) {
+ error_exit(argv[0], "Not enough arguments");
}
- argv += optind;
- qemu_reset_optind();
+
+ cmdname = argv[optind];
if (!trace_init_backends()) {
@@ -5613,9 +5924,15 @@ int main(int argc, char **argv)
for (cmd = img_cmds; cmd->name != NULL; cmd++) {
if (!strcmp(cmdname, cmd->name)) {
- return cmd->handler(argc, argv);
+ g_autofree char *argv0 = g_strdup_printf("%s %s", argv[0], cmdname);
+ /* reset options and getopt processing (incl return order) */
+ argv += optind;
+ argc -= optind;
+ qemu_reset_optind();
+ argv[0] = argv0;
+ return cmd->handler(cmd, argc, argv);
}
}
/* not found */
- error_exit("Command not found: %s", cmdname);
+ error_exit(argv[0], "Command not found: %s", cmdname);
}
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
--- a/tests/qemu-iotests/049.out
+++ b/tests/qemu-iotests/049.out
@@ -99,6 +99,5 @@ qemu-img: TEST_DIR/t.qcow2: Value '-1024' is out of range for parameter 'size'
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1k
-qemu-img: Invalid image size specified. You may use k, M, G, T, P or E suffixes for
-qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
+qemu-img: Invalid image size specified: '-1k'.
qemu-img create -f qcow2 -o size=-1k TEST_DIR/t.qcow2
@@ -108,6 +107,5 @@ and exabytes, respectively.
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte
-qemu-img: Invalid image size specified. You may use k, M, G, T, P or E suffixes for
-qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
+qemu-img: Invalid image size specified: '1kilobyte'.
qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2
@@ -117,6 +115,5 @@ and exabytes, respectively.
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar
-qemu-img: Invalid image size specified. You may use k, M, G, T, P or E suffixes for
-qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
+qemu-img: Invalid image size specified: 'foobar'.
qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2