2092 lines
75 KiB
Diff
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
|