Re: [PATCH v3 00/27] qemu-img: refersh options and --help handling, cleanups

2024-05-31 Thread Michael Tokarev

A friendly ping?

It took me quite some time and energy for all this.  It'd be sad if
it gets lost.

/mjt

24.04.2024 11:50, Michael Tokarev wrote:

Quite big patchset trying to implement normal, readable qemu-img --help
(and qemu-img COMMAND --help) output with readable descriptions, and
adding many long options in the process.

In the end I stopped using qemu-img-opts.hx in qemu-img.c, perhaps
this can be avoided, with only list of commands and their desrciptions
kept there, but I don't see big advantage here.  The same list should
be included in docs/tools/qemu-img.rst, - this is not done now.

Also each command syntax isn't reflected in the doc for now, because
I want to give good names for options first, - and there, we've quite
some inconsistences and questions.  For example, measure --output=OFMT
-O OFMT, - this is priceless :)  I've no idea why we have this ugly
--output=json thing, why not have --json? ;)  I gave the desired
format long name --target-format to avoid clash with --output.

For rebase, src vs tgt probably should be renamed in local variables
too, and I'm not even sure I've got the caches right. For caches,
the thing is inconsistent across commands.

For compare, I used --a-format/--b-format (for -f/-F), - this can
be made --souce-format and --target-format, to compare source (file1)
with target (file2).

For bitmap, things are scary, I'm not sure what -b SRC_FILENAME
really means, - for now I gave it --source option, but this does
not make it more clear, suggestions welcome.

There are many other inconsistencies, I can't fix them all in one go.

Changes since v2:

  - added Dan's R-Bs
  - refined couple cvtnum conversions
  - dropped "stop printing error twice in a few places"

Michael Tokarev (27):
   qemu-img: measure: convert img_size to signed, simplify handling
   qemu-img: create: convert img_size to signed, simplify handling
   qemu-img: global option processing and error printing
   qemu-img: pass current cmd info into command handlers
   qemu-img: create: refresh options/--help
   qemu-img: factor out parse_output_format() and use it in the code
   qemu-img: check: refresh options/--help
   qemu-img: simplify --repair error message
   qemu-img: commit: refresh options/--help
   qemu-img: compare: refresh options/--help
   qemu-img: convert: refresh options/--help
   qemu-img: info: refresh options/--help
   qemu-img: map: refresh options/--help
   qemu-img: snapshot: allow specifying -f fmt
   qemu-img: snapshot: make -l (list) the default, simplify option
 handling
   qemu-img: snapshot: refresh options/--help
   qemu-img: rebase: refresh options/--help
   qemu-img: resize: do not always eat last argument
   qemu-img: resize: refresh options/--help
   qemu-img: amend: refresh options/--help
   qemu-img: bench: refresh options/--help
   qemu-img: bitmap: refresh options/--help
   qemu-img: dd: refresh options/--help
   qemu-img: measure: refresh options/--help
   qemu-img: implement short --help, remove global help() function
   qemu-img: inline list of supported commands, remove qemu-img-cmds.h
 include
   qemu-img: extend cvtnum() and use it in more places

  docs/tools/qemu-img.rst|4 +-
  qemu-img-cmds.hx   |4 +-
  qemu-img.c | 1311 ++--
  tests/qemu-iotests/049.out |9 +-
  4 files changed, 821 insertions(+), 507 deletions(-)



--
GPG Key transition (from rsa2048 to rsa4096) since 2024-04-24.
New key: rsa4096/61AD3D98ECDF2C8E  9D8B E14E 3F2A 9DD7 9199  28F1 61AD 3D98 
ECDF 2C8E
Old key: rsa2048/457CE0A0804465C5  6EE1 95D1 886E 8FFB 810D  4324 457C E0A0 
8044 65C5
Transition statement: http://www.corpit.ru/mjt/gpg-transition-2024.txt




Re: [PULL 1/1] hw/ufs: Fix buffer overflow bug

2024-04-29 Thread Michael Tokarev

29.04.2024 06:25, Jeuk Kim wrote:

From: Jeuk Kim 

It fixes the buffer overflow vulnerability in the ufs device.
The bug was detected by sanitizers.


...

Resolves: #2299
Fixes: 329f16624499 ("hw/ufs: Support for Query Transfer Requests")
Reported-by: Zheyu Ma 
Signed-off-by: Jeuk Kim 


Cc: qemu-stable@ for 8.2 and 9.0 series.

Please do not forget to Cc qemu-stable@ for relevant changes.

Thanks,

/mjt



[PATCH 14/27] qemu-img: snapshot: allow specifying -f fmt

2024-04-24 Thread Michael Tokarev
For consistency with other commands, and since it already
accepts --image-opts, allow specifying -f fmt too.

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 docs/tools/qemu-img.rst | 2 +-
 qemu-img-cmds.hx| 4 ++--
 qemu-img.c  | 9 ++---
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 3653adb963..9b628c4da5 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -663,7 +663,7 @@ Command description:
   bitmap support, or 0 if bitmaps are supported but there is nothing
   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
index c9dd70a892..2c5a8a28f9 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -84,9 +84,9 @@ SRST
 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
 
 DEF("rebase", img_rebase,
diff --git a/qemu-img.c b/qemu-img.c
index 84e2e53fb7..8adc324496 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3595,7 +3595,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 BlockBackend *blk;
 BlockDriverState *bs;
 QEMUSnapshotInfo sn;
-char *filename, *snapshot_name = NULL;
+char *filename, *fmt = NULL, *snapshot_name = NULL;
 int c, ret = 0, bdrv_oflags;
 int action = 0;
 bool quiet = false;
@@ -3614,7 +3614,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"force-share", no_argument, 0, 'U'},
 {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) {
 break;
@@ -3629,6 +3629,9 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 case 'h':
 help();
 return 0;
+case 'f':
+fmt = optarg;
+break;
 case 'l':
 if (action) {
 error_exit(argv[0], "Cannot mix '-l', '-a', '-c', '-d'");
@@ -3682,7 +3685,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 filename = argv[optind++];
 
 /* Open the image */
-blk = img_open(image_opts, filename, NULL, bdrv_oflags, false, quiet,
+blk = img_open(image_opts, filename, fmt, bdrv_oflags, false, quiet,
force_share);
 if (!blk) {
 return 1;
-- 
2.39.2




[PATCH 17/27] qemu-img: rebase: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

Options added:
 --format, --cache - for the image in question
 --backing, --backing-format, --backing-cache, --backing-unsafe -
   for the new backing file
(was eg CACHE vs SRC_CACHE, which is unclear).

Probably should rename local variables.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 55 +-
 1 file changed, 46 insertions(+), 9 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 62f9ce4069..47dfa137c1 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3793,26 +3793,61 @@ static int img_rebase(const img_cmd_t *ccmd, int argc, 
char **argv)
 for(;;) {
 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':
 fmt = optarg;
@@ -3850,6 +3885,8 @@ static int img_rebase(const img_cmd_t *ccmd, int argc, 
char **argv)
 case 'c':
 compress = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 19/27] qemu-img: resize: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 38 +-
 1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index da10fafffc..688c01722c 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4324,27 +4324,45 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 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},
 {"shrink", no_argument, 0, OPTION_SHRINK},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, "-:f:hq",
+c = getopt_long(argc, argv, "-f:hq",
 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();
-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;
 break;
@@ -4386,6 +4404,8 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 error_exit(argv[0], "Extra argument(s) in command line");
 }
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 if (!filename && optind < argc) {
-- 
2.39.2




[PATCH 23/27] qemu-img: dd: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 39 +--
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 7c20a5772d..b3e521bc09 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -5504,31 +5504,48 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char 
**argv)
 const struct option long_options[] = {
 { "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'},
 { 0, 0, 0, 0 }
 };
 
-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;
 break;
 case 'f':
 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;
 break;
@@ -5538,6 +,8 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 15/27] qemu-img: snapshot: make -l (list) the default, simplify option handling

2024-04-24 Thread Michael Tokarev
When no -l/-a/-c/-d specified, assume -l (list).

Use the same values for SNAPSHOT_LIST/etc constants as the
option chars (lacd), this makes it possible to simplify
option handling a lot, combining cases for 4 options into
one.

Also remove bdrv_oflags handling (only list can use RO mode).

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 docs/tools/qemu-img.rst |  2 +-
 qemu-img.c  | 52 ++---
 2 files changed, 19 insertions(+), 35 deletions(-)

diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 9b628c4da5..df184d15b9 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -256,7 +256,7 @@ Parameters to snapshot subcommand:
 
 .. option:: -l
 
-  Lists all snapshots in the given image
+  Lists all snapshots in the given image (default action)
 
 Command description:
 
diff --git a/qemu-img.c b/qemu-img.c
index 8adc324496..967f6343de 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3585,10 +3585,11 @@ out:
 return ret < 0;
 }
 
-#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(const img_cmd_t *ccmd, int argc, char **argv)
 {
@@ -3596,7 +3597,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 BlockDriverState *bs;
 QEMUSnapshotInfo sn;
 char *filename, *fmt = NULL, *snapshot_name = NULL;
-int c, ret = 0, bdrv_oflags;
+int c, ret = 0;
 int action = 0;
 bool quiet = false;
 Error *err = NULL;
@@ -3604,7 +3605,6 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 bool force_share = false;
 int64_t rt;
 
-bdrv_oflags = BDRV_O_RDWR;
 /* Parse commandline parameters */
 for(;;) {
 static const struct option long_options[] = {
@@ -3632,36 +3632,15 @@ static int img_snapshot(const img_cmd_t *ccmd, int 
argc, char **argv)
 case 'f':
 fmt = optarg;
 break;
-case 'l':
-if (action) {
-error_exit(argv[0], "Cannot mix '-l', '-a', '-c', '-d'");
-return 0;
-}
-action = SNAPSHOT_LIST;
-bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
-break;
-case 'a':
+case SNAPSHOT_LIST:
+case SNAPSHOT_APPLY:
+case SNAPSHOT_CREATE:
+case SNAPSHOT_DELETE:
 if (action) {
 error_exit(argv[0], "Cannot mix '-l', '-a', '-c', '-d'");
 return 0;
 }
-action = SNAPSHOT_APPLY;
-snapshot_name = optarg;
-break;
-case 'c':
-if (action) {
-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(argv[0], "Cannot mix '-l', '-a', '-c', '-d'");
-return 0;
-}
-action = SNAPSHOT_DELETE;
+action = c;
 snapshot_name = optarg;
 break;
 case 'q':
@@ -3684,9 +3663,14 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 }
 filename = argv[optind++];
 
+if (!action) {
+action = SNAPSHOT_LIST;
+}
+
 /* Open the image */
-blk = img_open(image_opts, filename, fmt, 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;
 }
-- 
2.39.2




[PATCH 25/27] qemu-img: implement short --help, remove global help() function

2024-04-24 Thread Michael Tokarev
now once all individual subcommands has --help support, remove
the large unreadable help() thing and replace it with small
global --help, which refers to individual command --help for
more info.

While at it, also line-wrap list of formats after 75 chars.

Since missing_argument() and unrecognized_option() are now unused,
remove them.

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 qemu-img.c | 172 -
 1 file changed, 39 insertions(+), 133 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 3721cf070b..39dfaa5144 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -94,11 +94,6 @@ typedef enum OutputFormat {
 /* Default to cache=writeback as data integrity is not important for qemu-img 
*/
 #define BDRV_DEFAULT_CACHE "writeback"
 
-static void format_print(void *opaque, const char *name)
-{
-printf(" %s", name);
-}
-
 static G_NORETURN
 void tryhelp(const char *argv0)
 {
@@ -118,18 +113,6 @@ void error_exit(const char *argv0, const char *fmt, ...)
 tryhelp(argv0);
 }
 
-static G_NORETURN
-void missing_argument(const char *option)
-{
-error_exit("qemu-img", "missing argument for option '%s'", option);
-}
-
-static G_NORETURN
-void unrecognized_option(const char *option)
-{
-error_exit("qemu-img", "unrecognized option '%s'", option);
-}
-
 /*
  * Print --help output for a command and exit.
  * syntax and description are multi-line with trailing EOL
@@ -167,114 +150,6 @@ static OutputFormat parse_output_format(const char 
*argv0, const char *arg)
 }
 }
 
-/* Please keep in synch with docs/tools/qemu-img.rst */
-static G_NORETURN
-void help(void)
-{
-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=]][,events=][,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 w

[PATCH 20/27] qemu-img: amend: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 34 ++
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 688c01722c..76000c485c 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4559,26 +4559,42 @@ static int img_amend(const img_cmd_t *ccmd, int argc, 
char **argv)
 for (;;) {
 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) {
 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] [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':
 if (accumulate_options(, optarg) < 0) {
@@ -4607,6 +4623,8 @@ static int img_amend(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_FORCE:
 force = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 09/27] qemu-img: commit: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 44 
 1 file changed, 36 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 9157a6b45d..7a111bce72 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1048,24 +1048,50 @@ static int img_commit(const img_cmd_t *ccmd, int argc, 
char **argv)
 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},
+{"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) {
 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] [-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':
 fmt = optarg;
@@ -1099,6 +1125,8 @@ static int img_commit(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 08/27] qemu-img: simplify --repair error message

2024-04-24 Thread Michael Tokarev
Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 qemu-img.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 1bd88fcf63..9157a6b45d 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -859,8 +859,9 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 } else if (!strcmp(optarg, "all")) {
 fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
 } else {
-error_exit(argv[0], "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:
-- 
2.39.2




[PATCH 04/27] qemu-img: pass current cmd info into command handlers

2024-04-24 Thread Michael Tokarev
This info will be used to generate --help output.

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 qemu-img.c | 34 +-
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 130188e287..e8234104e5 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -60,7 +60,7 @@
 
 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);
 } img_cmd_t;
 
 enum {
@@ -514,7 +514,7 @@ static int64_t cvtnum(const char *name, const char *value)
 return cvtnum_full(name, value, 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;
 int64_t img_size = -1;
@@ -719,7 +719,7 @@ static int collect_image_check(BlockDriverState *bs,
  *  3 - Check completed, image has leaked clusters, but is good otherwise
  * 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;
@@ -951,7 +951,7 @@ 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;
 const char *filename, *fmt, *cache, *base;
@@ -1358,7 +1358,7 @@ static int check_empty_sectors(BlockBackend *blk, int64_t 
offset,
  * 1 - Images differ
  * >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;
 BlockBackend *blk1, *blk2;
@@ -2234,7 +2234,7 @@ static void set_rate_limit(BlockBackend *blk, int64_t 
rate_limit)
 blk_set_io_limits(blk, );
 }
 
-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;
 const char *fmt = NULL, *out_fmt = NULL, *cache = "unsafe",
@@ -3002,7 +3002,7 @@ err:
 return NULL;
 }
 
-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;
@@ -3227,7 +3227,7 @@ static inline bool entry_mergeable(const MapEntry *curr, 
const MapEntry *next)
 return true;
 }
 
-static int img_map(int argc, char **argv)
+static int img_map(const img_cmd_t *ccmd, int argc, char **argv)
 {
 int c;
 OutputFormat output_format = OFORMAT_HUMAN;
@@ -3376,7 +3376,7 @@ out:
 #define SNAPSHOT_APPLY  3
 #define SNAPSHOT_DELETE 4
 
-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;
@@ -3534,7 +3534,7 @@ static int img_snapshot(int argc, char **argv)
 return 0;
 }
 
-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;
 uint8_t *buf_old = NULL;
@@ -4028,7 +4028,7 @@ out:
 return 0;
 }
 
-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;
@@ -4241,7 +4241,7 @@ static int print_amend_option_help(const char *format)
 return 0;
 }
 
-static int img_amend(int argc, char **argv)
+static int img_amend(const img_cmd_t *ccmd, int argc, char **argv)
 {
 Error *err = NULL;
 int c, ret = 0;
@@ -4505,7 +4505,7 @@ 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;
 const char *fmt = NULL, *filename;
@@ -4775,7 +4775,7 @@ typedef struct ImgBitmapAction {
 QSIMPLEQ_ENTRY(ImgBitmapAction) next;
 } 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;
 int c, ret = 1;
@@ -5075,7 +5075,7 @@ static int img_dd_skip(const char *arg,
 return 0;
 }
 
-static int img_dd(int argc, char **argv)
+static int img_dd(const img_cmd_t *ccmd, int argc, char **argv)
 {
 int ret = 0;
 char *arg = NULL;
@@ -5343,7 +5343,7 @@ static void dump_json_block_measure_info(BlockMeasureInfo 
*info)
 g_string_free(str, true);
 }
 
-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'},
@@ -5610,7 +5610,7 @@ int main(int argc, char **argv)

[PATCH 26/27] qemu-img: inline list of supported commands, remove qemu-img-cmds.h include

2024-04-24 Thread Michael Tokarev
also add short description to each command and use it in --help

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 qemu-img.c | 40 ++--
 1 file changed, 34 insertions(+), 6 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 39dfaa5144..694647f6ff 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -61,6 +61,7 @@
 typedef struct img_cmd_t {
 const char *name;
 int (*handler)(const struct img_cmd_t *ccmd, int argc, char **argv);
+const char *description;
 } img_cmd_t;
 
 enum {
@@ -127,6 +128,7 @@ void cmd_help(const img_cmd_t *ccmd,
 {
 printf(
 "Usage:\n"
+"%s.  Usage:\n"
 "\n"
 "  %s %s %s"
 "\n"
@@ -134,7 +136,7 @@ void cmd_help(const img_cmd_t *ccmd,
 "  -h, --help\n"
 " print this help and exit\n"
 "%s\n",
-   "qemu-img", ccmd->name,
+   ccmd->description, "qemu-img", ccmd->name,
syntax, arguments);
 exit(EXIT_SUCCESS);
 }
@@ -5828,10 +5830,36 @@ 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, },
 };
 
@@ -5896,7 +5924,7 @@ QEMU_IMG_VERSION
 "\n"
 "Recognized commands (run qemu-img COMMAND --help for command-specific 
help):\n\n");
 for (cmd = img_cmds; cmd->name != NULL; cmd++) {
-printf("  %s\n", cmd->name);
+printf("  %s - %s\n", cmd->name, cmd->description);
 }
 printf("\nSupported image formats:\n");
 c = 99; /* force a newline */
-- 
2.39.2




[PATCH 12/27] qemu-img: info: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.
Also add -b short option for --backing-chain, and remove
now-unused OPTION_BACKING_CHAIN.

While at it, remove unused option_index variable.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 40 +++-
 1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 0a32d890e3..34c4cd86de 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -65,7 +65,6 @@ typedef struct img_cmd_t {
 
 enum {
 OPTION_OUTPUT = 256,
-OPTION_BACKING_CHAIN = 257,
 OPTION_OBJECT = 258,
 OPTION_IMAGE_OPTS = 259,
 OPTION_PATTERN = 260,
@@ -3220,31 +3219,44 @@ static int img_info(const img_cmd_t *ccmd, int argc, 
char **argv)
 
 fmt = 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},
 {"force-share", no_argument, 0, 'U'},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, ":f:hU",
-long_options, _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':
 fmt = optarg;
@@ -3255,7 +3267,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_OUTPUT:
 output_format = parse_output_format(argv[0], optarg);
 break;
-case OPTION_BACKING_CHAIN:
+case 'b':
 chain = true;
 break;
 case OPTION_OBJECT:
@@ -3264,6 +3276,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 if (optind != argc - 1) {
-- 
2.39.2




[PATCH 27/27] qemu-img: extend cvtnum() and use it in more places

2024-04-24 Thread Michael Tokarev
cvtnum() expects input string to specify some sort of size
(optionally with KMG... suffix).  However, there are a lot
of other number conversions in there (using qemu_strtol ),
also, not all conversions which use cvtnum, actually expects
size, - like dd count=nn.

Add bool issize argument to cvtnum() to specify if it should
treat the argument as a size or something else, - this changes
conversion routine in use and error text.

Use the new cvtnum() in more places (like where strtol were used),
since it never return negative number in successful conversion.
When it makes sense, also specify upper or lower bounds at the
same time.  This simplifies option processing in multiple places,
removing the need of local temporary variables and longer error
reporting code.

While at it, fix errors, like depth in measure must be >= 1,
while the previous code allowed it to be 0.

In a few places, change unsigned variables (like of type size_t)
to be signed instead, - to avoid the need of temporary conversion
variable.  All these variables are okay to be signed, we never
assign <0 value to them except of the cases of conversion error,
where we return immediately.

While at it, remove allowed size suffixes from the error message
as it makes no sense most of the time (should be in help instead).

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 qemu-img.c | 111 +
 tests/qemu-iotests/049.out |   9 +--
 2 files changed, 40 insertions(+), 80 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 694647f6ff..dbbf3495e8 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -399,18 +399,16 @@ static int add_old_style_options(const char *fmt, 
QemuOpts *opts,
 return 0;
 }
 
-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, );
+err = issize ? qemu_strtosz(value, NULL, ) :
+   qemu_strtou64(value, NULL, 0, );
 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;
 }
 if (err == -ERANGE || res > max || res < min) {
@@ -421,9 +419,9 @@ static int64_t cvtnum_full(const char *name, const char 
*value, int64_t min,
 return res;
 }
 
-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(const img_cmd_t *ccmd, int argc, char **argv)
@@ -527,7 +525,7 @@ static int img_create(const img_cmd_t *ccmd, int argc, char 
**argv)
 
 /* Get image size, if specified */
 if (optind < argc) {
-img_size = cvtnum("image size", argv[optind++]);
+img_size = cvtnum("image size", argv[optind++], true);
 if (img_size < 0) {
 goto fail;
 }
@@ -989,7 +987,7 @@ static int img_commit(const img_cmd_t *ccmd, int argc, char 
**argv)
 quiet = true;
 break;
 case 'r':
-rate_limit = cvtnum("rate limit", optarg);
+rate_limit = cvtnum("rate limit", optarg, true);
 if (rate_limit < 0) {
 return 1;
 }
@@ -2414,7 +2412,7 @@ static int img_convert(const img_cmd_t *ccmd, 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;
 } else if (!QEMU_IS_ALIGNED(sval, BDRV_SECTOR_SIZE) ||
@@ -2446,10 +2444,9 @@ static int img_convert(const img_cmd_t *ccmd, int argc, 
char **argv)
 skip_create = true;
 break;
 case 'm':
-if (qemu_strtol(optarg, NULL, 0, _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) {
  

[PATCH 05/27] qemu-img: create: refresh options/--help

2024-04-24 Thread Michael Tokarev
Create helper function cmd_help() to display command-specific
help text, and use it to print --help for 'create' subcommand.

Add missing long options (eg --format) in img_create().

Remove usage of missing_argument()/unrecognized_option() in
img_create().

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 69 +++---
 1 file changed, 61 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index e8234104e5..7ed5e6d1a8 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -132,6 +132,32 @@ void unrecognized_option(const char *option)
 error_exit("qemu-img", "unrecognized option '%s'", option);
 }
 
+/*
+ * 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 cmd_help(const img_cmd_t *ccmd,
+  const char *syntax, const char *arguments)
+{
+printf(
+"Usage:\n"
+"\n"
+"  %s %s %s"
+"\n"
+"Arguments:\n"
+"  -h, --help\n"
+" print this help and exit\n"
+"%s\n",
+   "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)
@@ -530,23 +556,48 @@ static int img_create(const img_cmd_t *ccmd, int argc, 
char **argv)
 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'},
+{"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) {
 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] [-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':
 base_fmt = optarg;
@@ -571,6 +622,8 @@ static int img_create(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_OBJECT:
 user_creatable_process_cmdline(optarg);
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 21/27] qemu-img: bench: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 64 +-
 1 file changed, 54 insertions(+), 10 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 76000c485c..fff537df26 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4849,28 +4849,70 @@ static int img_bench(const img_cmd_t *ccmd, int argc, 
char **argv)
 for (;;) {
 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;
 }
 
 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':
 {
@@ -4987,6 +5029,8 @@ static int img_bench(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 22/27] qemu-img: bitmap: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 40 
 1 file changed, 32 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index fff537df26..7c20a5772d 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -5170,20 +5170,42 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"source-format", required_argument, 0, 'F'},
 {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;
 }
 
 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':
 src_filename = optarg;
@@ -5239,6 +5261,8 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 24/27] qemu-img: measure: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

Also add -s short option for --size (and remove OPTION_SIZE).

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 53 -
 1 file changed, 40 insertions(+), 13 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index b3e521bc09..3721cf070b 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -71,7 +71,6 @@ enum {
 OPTION_FLUSH_INTERVAL = 261,
 OPTION_NO_DRAIN = 262,
 OPTION_TARGET_IMAGE_OPTS = 263,
-OPTION_SIZE = 264,
 OPTION_PREALLOCATION = 265,
 OPTION_SHRINK = 266,
 OPTION_SALVAGE = 267,
@@ -5748,15 +5747,6 @@ static void 
dump_json_block_measure_info(BlockMeasureInfo *info)
 
 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;
 BlockDriver *drv;
@@ -5777,12 +5767,47 @@ static int img_measure(const img_cmd_t *ccmd, int argc, 
char **argv)
 int ret = 1;
 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':
 fmt = optarg;
@@ -5820,12 +5845,14 @@ static int img_measure(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_OUTPUT:
 output_format = parse_output_format(argv[0], optarg);
 break;
-case OPTION_SIZE:
+case 's':
 img_size = cvtnum("image size", optarg);
 if (img_size < 0) {
 goto out;
 }
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 16/27] qemu-img: snapshot: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 45 -
 1 file changed, 36 insertions(+), 9 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 967f6343de..62f9ce4069 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3609,26 +3609,51 @@ static int img_snapshot(const img_cmd_t *ccmd, int 
argc, char **argv)
 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:f:hqU",
+c = getopt_long(argc, argv, "la:c:d:f:hqU",
 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();
-return 0;
+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 'f':
 fmt = optarg;
 break;
@@ -3655,6 +3680,8 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 18/27] qemu-img: resize: do not always eat last argument

2024-04-24 Thread Michael Tokarev
'qemu-img resize --help' does not work, since it wants more
arguments.  Also -size is only recognized as a very last
argument, but it is common for tools to handle other options
after positional arguments too.

Tell getopt_long() to return non-options together with options,
and process filename and size in the loop, and check if there's
an argument right after filename which looks like -N (number),
and treat it as size (decrement).  This way we can handle --help,
and we can also have options after filename and size, and `--'
will be handled fine too.

The only case which is not handled right is when there's an option
between filename and size, and size is given as decrement, - in
this case -size will be treated as option, not as size.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 41 +++--
 1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 47dfa137c1..da10fafffc 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4297,7 +4297,7 @@ 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;
 BlockBackend *blk = NULL;
@@ -4320,17 +4320,7 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 bool image_opts = false;
 bool shrink = false;
 
-/* Remove size from argv manually so that negative numbers are not treated
- * as options by getopt. */
-if (argc < 3) {
-error_exit(argv[0], "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'},
@@ -4340,7 +4330,7 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"shrink", no_argument, 0, OPTION_SHRINK},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, ":f:hq",
+c = getopt_long(argc, argv, "-:f:hq",
 long_options, NULL);
 if (c == -1) {
 break;
@@ -4378,12 +4368,35 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_SHRINK:
 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;
 }
 }
-if (optind != argc - 1) {
+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 */
 switch (size[0]) {
-- 
2.39.2




[PATCH 13/27] qemu-img: map: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

While at it, remove unused option_index variable.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 34 --
 1 file changed, 24 insertions(+), 10 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 34c4cd86de..84e2e53fb7 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3454,7 +3454,6 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 
 fmt = NULL;
 for (;;) {
-int option_index = 0;
 static const struct option long_options[] = {
 {"help", no_argument, 0, 'h'},
 {"format", required_argument, 0, 'f'},
@@ -3466,20 +3465,33 @@ static int img_map(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"max-length", required_argument, 0, 'l'},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, ":f:s:l:hU",
-long_options, _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':
 fmt = optarg;
@@ -3508,6 +3520,8 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 if (optind != argc - 1) {
-- 
2.39.2




[PATCH 10/27] qemu-img: compare: refresh options/--help

2024-04-24 Thread Michael Tokarev
Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 45 +
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 7a111bce72..ea66bfa195 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1488,25 +1488,52 @@ static int img_compare(const img_cmd_t *ccmd, int argc, 
char **argv)
 for (;;) {
 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) {
 break;
 }
 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':
 fmt1 = optarg;
@@ -1547,6 +1574,8 @@ static int img_compare(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 07/27] qemu-img: check: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 38 ++
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 08536553c7..1bd88fcf63 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -805,7 +805,9 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 int option_index = 0;
 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},
 {"object", required_argument, 0, OPTION_OBJECT},
@@ -813,20 +815,38 @@ static int img_check(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"force-share", no_argument, 0, 'U'},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, ":hf:r:T:qU",
+c = getopt_long(argc, argv, "hf:r:T:qU",
 long_options, _index);
 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] [-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':
 fmt = optarg;
@@ -861,6 +881,8 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 if (optind != argc - 1) {
-- 
2.39.2




[PATCH 06/27] qemu-img: factor out parse_output_format() and use it in the code

2024-04-24 Thread Michael Tokarev
Use common code and simplify error message

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 qemu-img.c | 63 --
 1 file changed, 18 insertions(+), 45 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 7ed5e6d1a8..08536553c7 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -158,6 +158,17 @@ void cmd_help(const img_cmd_t *ccmd,
 exit(EXIT_SUCCESS);
 }
 
+static OutputFormat parse_output_format(const char *argv0, const char *arg)
+{
+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);
+}
+}
+
 /* Please keep in synch with docs/tools/qemu-img.rst */
 static G_NORETURN
 void help(void)
@@ -776,7 +787,7 @@ 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;
 int fix = 0;
@@ -788,7 +799,6 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 bool force_share = false;
 
 fmt = NULL;
-output = NULL;
 cache = BDRV_DEFAULT_CACHE;
 
 for(;;) {
@@ -834,7 +844,7 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 }
 break;
 case OPTION_OUTPUT:
-output = optarg;
+output_format = parse_output_format(argv[0], optarg);
 break;
 case 'T':
 cache = optarg;
@@ -858,15 +868,6 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 }
 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, , );
 if (ret < 0) {
 error_report("Invalid source cache option: %s", cache);
@@ -3060,13 +3061,12 @@ 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;
 bool force_share = false;
 
 fmt = NULL;
-output = NULL;
 for(;;) {
 int option_index = 0;
 static const struct option long_options[] = {
@@ -3101,7 +3101,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char 
**argv)
 force_share = true;
 break;
 case OPTION_OUTPUT:
-output = optarg;
+output_format = parse_output_format(argv[0], optarg);
 break;
 case OPTION_BACKING_CHAIN:
 chain = true;
@@ -3119,15 +3119,6 @@ static int img_info(const img_cmd_t *ccmd, int argc, 
char **argv)
 }
 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);
 if (!list) {
@@ -3286,7 +3277,7 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 OutputFormat output_format = OFORMAT_HUMAN;
 BlockBackend *blk;
 BlockDriverState *bs;
-const char *filename, *fmt, *output;
+const char *filename, *fmt;
 int64_t length;
 MapEntry curr = { .length = 0 }, next;
 int ret = 0;
@@ -3296,7 +3287,6 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 int64_t max_length = -1;
 
 fmt = NULL;
-output = NULL;
 for (;;) {
 int option_index = 0;
 static const struct option long_options[] = {
@@ -3332,7 +3322,7 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 force_share = true;
 break;
 case OPTION_OUTPUT:
-output = optarg;
+output_format = parse_output_format(argv[0], optarg);
 break;
 case 's':
 start_offset = cvtnum("start offset", optarg);
@@ -3359,15 +3349,6 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 }
 filename = argv[optind];
 
-if (output && !strcmp(output, "json&qu

[PATCH 02/27] qemu-img: create: convert img_size to signed, simplify handling

2024-04-24 Thread Michael Tokarev
Initializing an unsigned as -1, or using temporary
sval for conversion is awkward.  Since we don't allow
other "negative" values anyway, use signed value and
pass it to bdrv_img_create() (where it is properly
converted to unsigned), simplifying code.

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 qemu-img.c | 9 +++--
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 6e7ac2048f..fe22986931 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -511,7 +511,7 @@ static int64_t cvtnum(const char *name, const char *value)
 static int img_create(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;
 const char *filename;
@@ -582,13 +582,10 @@ 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++]);
+if (img_size < 0) {
 goto fail;
 }
-img_size = (uint64_t)sval;
 }
 if (optind != argc) {
 error_exit("Unexpected argument: %s", argv[optind]);
-- 
2.39.2




[PATCH 11/27] qemu-img: convert: refresh options/--help

2024-04-24 Thread Michael Tokarev
Add missing long options and --help output.

convert uses -B for --backing, - why not -b?

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 90 --
 1 file changed, 81 insertions(+), 9 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index ea66bfa195..0a32d890e3 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -2404,30 +2404,100 @@ static int img_convert(const img_cmd_t *ccmd, int 
argc, char **argv)
 for(;;) {
 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},
 {"salvage", no_argument, 0, OPTION_SALVAGE},
 {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
 {"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"
+" ski

[PATCH 03/27] qemu-img: global option processing and error printing

2024-04-24 Thread Michael Tokarev
In order to correctly print executable name in various
error messages, pass argv[0] to error_exit() function.
This way, error messages will refer to actual executable
name, which may be different from 'qemu-img'.

For subcommands, pass original command name from the
qemu-img argv[0], plus the subcommand name, as its own
argv[0] element, so error messages can be more useful.
Also don't require at least 3 options on the command
line: it makes no sense with options before subcommand.

Introduce tryhelp() function which just prints

 try 'command-name --help' for more info

and exits.  When tryhelp() is called from within a subcommand
handler, the message will look like:

 try 'command-name subcommand --help' for more info

qemu-img uses getopt_long() with ':' as the first char in
optstring parameter, which means it doesn't print error
messages but return ':' or '?' instead, and qemu-img uses
unrecognized_option() or missing_argument() function to
print error messages.  But it doesn't quite work:

 $ ./qemu-img -xx
 qemu-img: unrecognized option './qemu-img'

so the aim is to let getopt_long() to print regular error
messages instead (removing ':' prefix from optstring) and
remove handling of '?' and ':' "options" entirely.  With
concatenated argv[0] and the subcommand, it all finally
does the right thing in all cases.  This will be done in
subsequent changes command by command, with main() done
last.

unrecognized_option() and missing_argument() functions
prototypes aren't changed by this patch, since they're
called from many places and will be removed a few patches
later.  Only artifical "qemu-img" argv0 is provided in
there for now.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 80 +-
 1 file changed, 43 insertions(+), 37 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index fe22986931..130188e287 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -101,8 +101,15 @@ static void format_print(void *opaque, const char *name)
 printf(" %s", name);
 }
 
-static G_NORETURN G_GNUC_PRINTF(1, 2)
-void error_exit(const char *fmt, ...)
+static G_NORETURN
+void tryhelp(const char *argv0)
+{
+error_printf("Try '%s --help' for more info\n", argv0);
+exit(EXIT_FAILURE);
+}
+
+static G_NORETURN G_GNUC_PRINTF(2, 3)
+void error_exit(const char *argv0, const char *fmt, ...)
 {
 va_list ap;
 
@@ -110,20 +117,19 @@ void error_exit(const char *fmt, ...)
 error_vreport(fmt, ap);
 va_end(ap);
 
-error_printf("Try 'qemu-img --help' for more information\n");
-exit(EXIT_FAILURE);
+tryhelp(argv0);
 }
 
 static G_NORETURN
 void missing_argument(const char *option)
 {
-error_exit("missing argument for option '%s'", option);
+error_exit("qemu-img", "missing argument for option '%s'", option);
 }
 
 static G_NORETURN
 void unrecognized_option(const char *option)
 {
-error_exit("unrecognized option '%s'", option);
+error_exit("qemu-img", "unrecognized option '%s'", option);
 }
 
 /* Please keep in synch with docs/tools/qemu-img.rst */
@@ -576,7 +582,7 @@ 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++;
 
@@ -588,7 +594,7 @@ static int img_create(int argc, char **argv)
 }
 }
 if (optind != argc) {
-error_exit("Unexpected argument: %s", argv[optind]);
+error_exit(argv[0], "Unexpected argument: %s", argv[optind]);
 }
 
 bdrv_img_create(filename, fmt, base_filename, base_fmt,
@@ -770,7 +776,7 @@ static int img_check(int argc, char **argv)
 } else if (!strcmp(optarg, "all")) {
 fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
 } else {
-error_exit("Unknown option value for -r "
+error_exit(argv[0], "Unknown option value for -r "
"(expecting 'leaks' or 'all'): %s", optarg);
 }
 break;
@@ -795,7 +801,7 @@ static int img_check(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++];
 
@@ -1025,7 +1031,7 @@ 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++];
 
@@ -1446,7 +1452,7 @@ static int img_compare(int argc, char **argv)
 
 
 if (optind != argc - 2) {
-error_exit("Expecting two image file names");
+error_exit(argv[0]

[PATCH 01/27] qemu-img: measure: convert img_size to signed, simplify handling

2024-04-24 Thread Michael Tokarev
qemu_opt_set_number() expects signed int64_t.

Use int64_t instead of uint64_t for img_size, use -1 as "unset"
value instead of UINT64_MAX, and do not require temporary sval
for conversion from string.

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 qemu-img.c | 19 +++
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 7668f86769..6e7ac2048f 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -5364,7 +5364,7 @@ static int img_measure(int argc, char **argv)
 QemuOpts *sn_opts = NULL;
 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;
 int ret = 1;
@@ -5422,16 +5422,11 @@ static int img_measure(int argc, char **argv)
 }
 break;
 case OPTION_SIZE:
-{
-int64_t sval;
-
-sval = cvtnum("image size", optarg);
-if (sval < 0) {
+img_size = cvtnum("image size", optarg);
+if (img_size < 0) {
 goto out;
 }
-img_size = (uint64_t)sval;
-}
-break;
+break;
 }
 }
 
@@ -5446,11 +5441,11 @@ static int img_measure(int argc, char **argv)
 error_report("--image-opts, -f, and -l require a filename argument.");
 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;
 }
@@ -5498,7 +5493,7 @@ static int img_measure(int argc, char **argv)
 goto out;
 }
 }
-if (img_size != UINT64_MAX) {
+if (img_size != -1) {
 qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, _abort);
 }
 
-- 
2.39.2




[PATCH v3 00/27] qemu-img: refersh options and --help handling, cleanups

2024-04-24 Thread Michael Tokarev
Quite big patchset trying to implement normal, readable qemu-img --help
(and qemu-img COMMAND --help) output with readable descriptions, and
adding many long options in the process.

In the end I stopped using qemu-img-opts.hx in qemu-img.c, perhaps
this can be avoided, with only list of commands and their desrciptions
kept there, but I don't see big advantage here.  The same list should
be included in docs/tools/qemu-img.rst, - this is not done now.

Also each command syntax isn't reflected in the doc for now, because
I want to give good names for options first, - and there, we've quite
some inconsistences and questions.  For example, measure --output=OFMT
-O OFMT, - this is priceless :)  I've no idea why we have this ugly
--output=json thing, why not have --json? ;)  I gave the desired
format long name --target-format to avoid clash with --output.

For rebase, src vs tgt probably should be renamed in local variables
too, and I'm not even sure I've got the caches right. For caches,
the thing is inconsistent across commands.

For compare, I used --a-format/--b-format (for -f/-F), - this can
be made --souce-format and --target-format, to compare source (file1)
with target (file2).

For bitmap, things are scary, I'm not sure what -b SRC_FILENAME
really means, - for now I gave it --source option, but this does
not make it more clear, suggestions welcome.

There are many other inconsistencies, I can't fix them all in one go.

Changes since v2:

 - added Dan's R-Bs
 - refined couple cvtnum conversions
 - dropped "stop printing error twice in a few places"

Michael Tokarev (27):
  qemu-img: measure: convert img_size to signed, simplify handling
  qemu-img: create: convert img_size to signed, simplify handling
  qemu-img: global option processing and error printing
  qemu-img: pass current cmd info into command handlers
  qemu-img: create: refresh options/--help
  qemu-img: factor out parse_output_format() and use it in the code
  qemu-img: check: refresh options/--help
  qemu-img: simplify --repair error message
  qemu-img: commit: refresh options/--help
  qemu-img: compare: refresh options/--help
  qemu-img: convert: refresh options/--help
  qemu-img: info: refresh options/--help
  qemu-img: map: refresh options/--help
  qemu-img: snapshot: allow specifying -f fmt
  qemu-img: snapshot: make -l (list) the default, simplify option
handling
  qemu-img: snapshot: refresh options/--help
  qemu-img: rebase: refresh options/--help
  qemu-img: resize: do not always eat last argument
  qemu-img: resize: refresh options/--help
  qemu-img: amend: refresh options/--help
  qemu-img: bench: refresh options/--help
  qemu-img: bitmap: refresh options/--help
  qemu-img: dd: refresh options/--help
  qemu-img: measure: refresh options/--help
  qemu-img: implement short --help, remove global help() function
  qemu-img: inline list of supported commands, remove qemu-img-cmds.h
include
  qemu-img: extend cvtnum() and use it in more places

 docs/tools/qemu-img.rst|4 +-
 qemu-img-cmds.hx   |4 +-
 qemu-img.c | 1311 ++--
 tests/qemu-iotests/049.out |9 +-
 4 files changed, 821 insertions(+), 507 deletions(-)

-- 
2.39.2




Re: [PATCH] block/virtio-blk: Fix memory leak from virtio_blk_zone_report

2024-04-09 Thread Michael Tokarev

04.04.2024 15:00, Zheyu Ma wrote:

This modification ensures that in scenarios where the buffer size is
insufficient for a zone report, the function will now properly set an
error status and proceed to a cleanup label, instead of merely
returning.

The following ASAN log reveals it:

==1767400==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 312 byte(s) in 1 object(s) allocated from:
 #0 0x64ac7b3280cd in malloc 
llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:129:3
 #1 0x735b02fb9738 in g_malloc 
(/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x5e738)
 #2 0x64ac7d23be96 in virtqueue_split_pop hw/virtio/virtio.c:1612:12
 #3 0x64ac7d23728a in virtqueue_pop hw/virtio/virtio.c:1783:16
 #4 0x64ac7cfcaacd in virtio_blk_get_request hw/block/virtio-blk.c:228:27
 #5 0x64ac7cfca7c7 in virtio_blk_handle_vq hw/block/virtio-blk.c:1123:23
 #6 0x64ac7cfecb95 in virtio_blk_handle_output hw/block/virtio-blk.c:1157:5

Signed-off-by: Zheyu Ma 
---
  hw/block/virtio-blk.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 92de315f17..bb86e65f65 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -768,7 +768,8 @@ static void virtio_blk_handle_zone_report(VirtIOBlockReq 
*req,
  sizeof(struct virtio_blk_zone_report) +
  sizeof(struct virtio_blk_zone_descriptor)) {
  virtio_error(vdev, "in buffer too small for zone report");
-return;
+err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
+goto out;
  }
  
  /* start byte offset of the zone report */


Is this a -stable material, or is it not worth picking up for older release(s)?

Thanks,

/mjt



Re: [PATCH for-9.0 1/2] nbd/server: Fix race in draining the export

2024-03-19 Thread Michael Tokarev

14.03.2024 19:58, Kevin Wolf wrote:

When draining an NBD export, nbd_drained_begin() first sets
client->quiescing so that nbd_client_receive_next_request() won't start
any new request coroutines. Then nbd_drained_poll() tries to makes sure
that we wait for any existing request coroutines by checking that
client->nb_requests has become 0.

However, there is a small window between creating a new request
coroutine and increasing client->nb_requests. If a coroutine is in this
state, it won't be waited for and drain returns too early.

In the context of switching to a different AioContext, this means that
blk_aio_attached() will see client->recv_coroutine != NULL and fail its
assertion.

Fix this by increasing client->nb_requests immediately when starting the
coroutine. Doing this after the checks if we should create a new
coroutine is okay because client->lock is held.

Cc: qemu-sta...@nongnu.org
Fixes: fd6afc501a019682d1b8468b562355a2887087bd
Signed-off-by: Kevin Wolf 


Kevin, Stefan,

This change in master, which is Cc'ed stable, touches (refines) exactly the
same areas as f816310d0c32c "nbd/server: only traverse NBDExport->clients
from main loop thread", which is not (yet?) in stable, neither 7.2 nor 8.2.

Also, 7075d235114b4 "nbd/server: introduce NBDClient->lock to protect fields"
touches one of the places too.

I can try to construct something out of the two, but I think it is better
if either of you can do that, - if this seems a good thing to do anyway.
This way it is definitely much saner than my possible attempts.

Or we can just pick f816310d0c32c and 7075d235114b4 into stable too, - when
I evaluated f816310d0c32c for stable before I thought it isn't needed there
because AioContext lock isn't removed in 8.2 yet.  And I haven't thought
about 7075d235114b4 at all.  All 3 applies cleanly and the result passes
check-block, but it smells a bit too much for stable.

What do you think?

Thanks,

/mjt


diff --git a/nbd/server.c b/nbd/server.c
index 941832f178..c3484cc1eb 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -3007,8 +3007,8 @@ static coroutine_fn int nbd_handle_request(NBDClient 
*client,
  /* Owns a reference to the NBDClient passed as opaque.  */
  static coroutine_fn void nbd_trip(void *opaque)
  {
-NBDClient *client = opaque;
-NBDRequestData *req = NULL;
+NBDRequestData *req = opaque;
+NBDClient *client = req->client;
  NBDRequest request = { 0 };/* GCC thinks it can be used uninitialized 
*/
  int ret;
  Error *local_err = NULL;
@@ -3037,8 +3037,6 @@ static coroutine_fn void nbd_trip(void *opaque)
  goto done;
  }
  
-req = nbd_request_get(client);

-
  /*
   * nbd_co_receive_request() returns -EAGAIN when nbd_drained_begin() has
   * set client->quiescing but by the time we get back nbd_drained_end() may
@@ -3112,9 +3110,7 @@ static coroutine_fn void nbd_trip(void *opaque)
  }
  
  done:

-if (req) {
-nbd_request_put(req);
-}
+nbd_request_put(req);
  
  qemu_mutex_unlock(>lock);
  
@@ -3143,10 +3139,13 @@ disconnect:

   */
  static void nbd_client_receive_next_request(NBDClient *client)
  {
+NBDRequestData *req;
+
  if (!client->recv_coroutine && client->nb_requests < MAX_NBD_REQUESTS &&
  !client->quiescing) {
  nbd_client_get(client);
-client->recv_coroutine = qemu_coroutine_create(nbd_trip, client);
+req = nbd_request_get(client);
+client->recv_coroutine = qemu_coroutine_create(nbd_trip, req);
  aio_co_schedule(client->exp->common.ctx, client->recv_coroutine);
  }
  }





Re: [PATCH 28/28] qemu-img: extend cvtnum() and use it in more places

2024-02-26 Thread Michael Tokarev

22.02.2024 00:16, Michael Tokarev wrote:


-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, );

+err = issize ? qemu_strtosz(value, NULL, ) :
+   qemu_strtou64(value, NULL, 0, );
  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.");
+if (issize) {
+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.");
+} else {
+error_report("Invalid %s specified.", name);
+}


I've added actual value supplied to these error messages now.
And I think the list of possible suffixes makes little sense here.



@@ -5090,7 +5060,7 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, 
char **argv)
  src_fmt = optarg;
  break;
  case 'g':
-granularity = cvtnum("granularity", optarg);
+granularity = cvtnum("granularity", optarg, false);


Here, this is a size, so last arg should be true.  In the tests (190),
we already use -g 2M.  I didn't really knew what a granularity is while
converting it.

/mjt



Re: [PATCH 01/28] qemu-img: stop printing error twice in a few places

2024-02-26 Thread Michael Tokarev

26.02.2024 17:14, Daniel P. Berrangé :

On Thu, Feb 22, 2024 at 12:15:42AM +0300, Michael Tokarev wrote:

Currently we have:

   ./qemu-img resize none +10
   qemu-img: Could not open 'none': Could not open 'none': No such file or 
directory

stop printing the message twice, - local_err already has
all the info, no need to prepend additional text there.

There are a few other places like this, but I'm unsure
about these.

Signed-off-by: Michael Tokarev 
---
  qemu-img.c | 8 +++-
  1 file changed, 3 insertions(+), 5 deletions(-)


Reviewed-by: Daniel P. Berrangé 


Unfortunately I have to drop this one for now, - it requires
much more work.  For example, after this we have:

-qemu-img: TEST_DIR/t.IMGFMT: Extended L2 entries are only supported with 
cluster sizes of at least 16384 bytes
+qemu-img: Extended L2 entries are only supported with cluster sizes of at 
least 16384 bytes

-qemu-img: Could not open 'TEST_DIR/t.IMGFMT': L1 table is too small
+qemu-img: L1 table is too small

-qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'foo': No such 
file or directory
+qemu-img: Could not open 'foo': No such file or directory

and a few other interesting cases.

This whole thing needs a much bigger revisit.

/mjt



[PATCH v2.1 04/28] qemu-img: global option processing and error printing

2024-02-26 Thread Michael Tokarev
In order to correctly print executable name in various
error messages, pass argv[0] to error_exit() function.
This way, error messages will refer to actual executable
name, which may be different from 'qemu-img'.

For subcommands, pass original command name from the
qemu-img argv[0], plus the subcommand name, as its own
argv[0] element, so error messages can be more useful.
Also don't require at least 3 options on the command
line: it makes no sense with options before subcommand.

Introduce tryhelp() function which just prints

 try 'command-name --help' for more info

and exits.  When tryhelp() is called from within a subcommand
handler, the message will look like:

 try 'command-name subcommand --help' for more info

qemu-img uses getopt_long() with ':' as the first char in
optstring parameter, which means it doesn't print error
messages but return ':' or '?' instead, and qemu-img uses
unrecognized_option() or missing_argument() function to
print error messages.  But it doesn't quite work:

 $ ./qemu-img -xx
 qemu-img: unrecognized option './qemu-img'

so the aim is to let getopt_long() to print regular error
messages instead (removing ':' prefix from optstring) and
remove handling of '?' and ':' "options" entirely.  With
concatenated argv[0] and the subcommand, it all finally
does the right thing in all cases.  This will be done in
subsequent changes command by command, with main() done
last.

unrecognized_option() and missing_argument() functions
prototypes aren't changed by this patch, since they're
called from many places and will be removed a few patches
later.  Only artifical "qemu-img" argv0 is provided in
there for now.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 80 +-
 1 file changed, 43 insertions(+), 37 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index df425b2517..d73a5d8fdb 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -101,8 +101,15 @@ static void format_print(void *opaque, const char *name)
 printf(" %s", name);
 }
 
-static G_NORETURN G_GNUC_PRINTF(1, 2)
-void error_exit(const char *fmt, ...)
+static G_NORETURN
+void tryhelp(const char *argv0)
+{
+error_printf("Try '%s --help' for more info\n", argv0);
+exit(EXIT_FAILURE);
+}
+
+static G_NORETURN G_GNUC_PRINTF(2, 3)
+void error_exit(const char *argv0, const char *fmt, ...)
 {
 va_list ap;
 
@@ -110,20 +117,19 @@ void error_exit(const char *fmt, ...)
 error_vreport(fmt, ap);
 va_end(ap);
 
-error_printf("Try 'qemu-img --help' for more information\n");
-exit(EXIT_FAILURE);
+tryhelp(argv0);
 }
 
 static G_NORETURN
 void missing_argument(const char *option)
 {
-error_exit("missing argument for option '%s'", option);
+error_exit("qemu-img", "missing argument for option '%s'", option);
 }
 
 static G_NORETURN
 void unrecognized_option(const char *option)
 {
-error_exit("unrecognized option '%s'", option);
+error_exit("qemu-img", "unrecognized option '%s'", option);
 }
 
 /* Please keep in synch with docs/tools/qemu-img.rst */
@@ -576,7 +582,7 @@ 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++;
 
@@ -588,7 +594,7 @@ static int img_create(int argc, char **argv)
 }
 }
 if (optind != argc) {
-error_exit("Unexpected argument: %s", argv[optind]);
+error_exit(argv[0], "Unexpected argument: %s", argv[optind]);
 }
 
 bdrv_img_create(filename, fmt, base_filename, base_fmt,
@@ -770,7 +776,7 @@ static int img_check(int argc, char **argv)
 } else if (!strcmp(optarg, "all")) {
 fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
 } else {
-error_exit("Unknown option value for -r "
+error_exit(argv[0], "Unknown option value for -r "
"(expecting 'leaks' or 'all'): %s", optarg);
 }
 break;
@@ -795,7 +801,7 @@ static int img_check(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++];
 
@@ -1025,7 +1031,7 @@ 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++];
 
@@ -1446,7 +1452,7 @@ static int img_compare(int argc, char **argv)
 
 
 if (optind != argc - 2) {
-error_exit("Expecting two image file names");
+error_exit(argv[0]

Re: [PATCH 01/28] qemu-img: stop printing error twice in a few places

2024-02-26 Thread Michael Tokarev

22.02.2024 00:15, Michael Tokarev :

Currently we have:

   ./qemu-img resize none +10
   qemu-img: Could not open 'none': Could not open 'none': No such file or 
directory


This one needs expected-output tweaks for tests.

/mjt



Re: [PATCH 04/28] qemu-img: global option processing and error printing

2024-02-26 Thread Michael Tokarev

26.02.2024 18:43, Michael Tokarev wrote:


The reason is most likely the argv/argc handling (lack of optind reset).
In the later change it is fixed but at that stage it's broken.


Nope. GNU getopt_long really needs resetting the state.
Or else it keeps return_in_order/permute/etc setting from
the previous init call.

So this patch needs tweaking, - the reset must be kept, and argv[0] init
should be done a bit differently.

An easy change.

/mjt



Re: [PATCH 04/28] qemu-img: global option processing and error printing

2024-02-26 Thread Michael Tokarev

26.02.2024 18:40, Daniel P. Berrangé :
..

I'm not sure how, but this change seems to have broken the iotests.
Just one example:


Heh.  Thank you for trying that.  I wanted to do that but forgot.

The reason is most likely the argv/argc handling (lack of optind reset).
In the later change it is fixed but at that stage it's broken.

I'll take a look later today.

/mjt



Re: [PATCH 19/28] qemu-img: resize: do not always eat last argument

2024-02-26 Thread Michael Tokarev

26.02.2024 17:52, Daniel P. Berrangé wrote:

On Thu, Feb 22, 2024 at 12:16:00AM +0300, Michael Tokarev wrote:

'qemu-img resize --help' does not work, since it wants more
arguments.  Also it -size is only recognized as a very last
argument, but it is common for tools to handle other options
after positional arguments too.

Tell getopt_long() to return non-options together with options,
and process filename and size in the loop, and check if there's
an argument right after filename which looks like -N (number),
and treat it as size (decrement).  This way we can handle --help,
and we can also have options after filename and size, and `--'
will be handled fine too.

The only case which is not handled right is when there's an option
between filename and size, and size is given as decrement, - in
this case -size will be treated as option, not as size.

Signed-off-by: Michael Tokarev 
---
  qemu-img.c | 41 +++--
  1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 2a4bff2872..c8b0b68d67 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4296,7 +4296,7 @@ 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;
  BlockBackend *blk = NULL;
@@ -4319,17 +4319,7 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
  bool image_opts = false;
  bool shrink = false;
  
-/* Remove size from argv manually so that negative numbers are not treated

- * as options by getopt. */
-if (argc < 3) {
-error_exit(argv[0], "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'},
@@ -4339,7 +4329,7 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
  {"shrink", no_argument, 0, OPTION_SHRINK},
  {0, 0, 0, 0}
  };
-c = getopt_long(argc, argv, ":f:hq",
+c = getopt_long(argc, argv, "-:f:hq",


In other patches you removed the initial ':' from gopt_long arg strings.


Yes, this is done in the next patch, "resize: refresh options/help".


  long_options, NULL);
  if (c == -1) {
  break;
@@ -4377,12 +4367,35 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
  case OPTION_SHRINK:
  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;


Can you say what scenario exercises this code 'case 1' ?  I couldn't
get it to run in any scenarios i tried, and ineed removing this,
and removing the 'getopt_long' change, I could still run  'qemu-img resize 
--help'
OK, and also run 'qemu-img resize foo -43' too.



I was thinking about
  qemu-img resize foo -43 -f qcow2 ..

if not only to make it all consistent with everything else
(options has always been recognized after non-optional args
in gnu/linux world, all utils does that).

But in all scenarios, after changing first char of optstring to include
'-', this code will be called for any non-optional argument.  In this
case, it will be done for argument `foo', and there. -43 will  be
recognized by this piece of code as a size modification since it
starts with minus and follows with a number.

The handling of positional args after the getopt loop is also needed
to handle situations like

  qemu-img resize -- foo 43

-- everything after `--' will be left to that code.

/mjt




Re: [PATCH 06/28] qemu-img: create: refresh options/--help

2024-02-26 Thread Michael Tokarev

26.02.2024 17:34, Daniel P. Berrangé wrote:

On Thu, Feb 22, 2024 at 12:15:47AM +0300, Michael Tokarev wrote:



For the global help there's an extra '\n' after 'Usage'. It would be
good go be consistent in this between global and per-command help.

$ ./build/qemu-img --help
qemu-img version 8.2.50 (v8.2.0-1677-g81b20f4b55)
Copyright (c) 2003-2023 Fabrice Bellard and the QEMU Project developers
QEMU disk image utility.  Usage:

   qemu-img [standard options] COMMAND [--help | command options]
...snip...

vs

$ ./build/qemu-img info --help
Display information about image.  Usage:
   qemu-img info [-f FMT | --image-opts] [-b] [-U] [--object OBJDEF]
 [--output human|json] FILENAME
...snip...


I wonder if we should repeat '[standard options]' for the
per-command help too ?


Yes, this can be done.  I remember you prefer less dense output so
let it be the new line in there.



+"\n"
+"Arguments:\n"


In the global help you called it 'Standard options', so for
consistency lets use 'Options:' here too.


Nope.  Because in global help it's really options (-foo), while
here, it is options and non-optional arguments too, ie, *all*
arguments, not just options.

/mjt



[PATCH 15/28] qemu-img: snapshot: allow specifying -f fmt

2024-02-21 Thread Michael Tokarev
For consistency with other commands, and since it already
accepts --image-opts, allow specifying -f fmt too.

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 docs/tools/qemu-img.rst | 2 +-
 qemu-img-cmds.hx| 4 ++--
 qemu-img.c  | 9 ++---
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 3653adb963..9b628c4da5 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -663,7 +663,7 @@ Command description:
   bitmap support, or 0 if bitmaps are supported but there is nothing
   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
index c9dd70a892..2c5a8a28f9 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -84,9 +84,9 @@ SRST
 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
 
 DEF("rebase", img_rebase,
diff --git a/qemu-img.c b/qemu-img.c
index 3f719bbecf..85c37d491d 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3594,7 +3594,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 BlockBackend *blk;
 BlockDriverState *bs;
 QEMUSnapshotInfo sn;
-char *filename, *snapshot_name = NULL;
+char *filename, *fmt = NULL, *snapshot_name = NULL;
 int c, ret = 0, bdrv_oflags;
 int action = 0;
 bool quiet = false;
@@ -3613,7 +3613,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"force-share", no_argument, 0, 'U'},
 {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) {
 break;
@@ -3628,6 +3628,9 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 case 'h':
 help();
 return 0;
+case 'f':
+fmt = optarg;
+break;
 case 'l':
 if (action) {
 error_exit(argv[0], "Cannot mix '-l', '-a', '-c', '-d'");
@@ -3681,7 +3684,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 filename = argv[optind++];
 
 /* Open the image */
-blk = img_open(image_opts, filename, NULL, bdrv_oflags, false, quiet,
+blk = img_open(image_opts, filename, fmt, bdrv_oflags, false, quiet,
force_share);
 if (!blk) {
 return 1;
-- 
2.39.2




[PATCH 03/28] qemu-img: create: convert img_size to signed, simplify handling

2024-02-21 Thread Michael Tokarev
Initializing an unsigned as -1, or using temporary
sval for conversion is awkward.  Since we don't allow
other "negative" values anyway, use signed value and
pass it to bdrv_img_create() (where it is properly
converted to unsigned), simplifying code.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 9 +++--
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index ae14ed833d..df425b2517 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -511,7 +511,7 @@ static int64_t cvtnum(const char *name, const char *value)
 static int img_create(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;
 const char *filename;
@@ -582,13 +582,10 @@ 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++]);
+if (img_size < 0) {
 goto fail;
 }
-img_size = (uint64_t)sval;
 }
 if (optind != argc) {
 error_exit("Unexpected argument: %s", argv[optind]);
-- 
2.39.2




[PATCH 19/28] qemu-img: resize: do not always eat last argument

2024-02-21 Thread Michael Tokarev
'qemu-img resize --help' does not work, since it wants more
arguments.  Also it -size is only recognized as a very last
argument, but it is common for tools to handle other options
after positional arguments too.

Tell getopt_long() to return non-options together with options,
and process filename and size in the loop, and check if there's
an argument right after filename which looks like -N (number),
and treat it as size (decrement).  This way we can handle --help,
and we can also have options after filename and size, and `--'
will be handled fine too.

The only case which is not handled right is when there's an option
between filename and size, and size is given as decrement, - in
this case -size will be treated as option, not as size.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 41 +++--
 1 file changed, 27 insertions(+), 14 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 2a4bff2872..c8b0b68d67 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4296,7 +4296,7 @@ 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;
 BlockBackend *blk = NULL;
@@ -4319,17 +4319,7 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 bool image_opts = false;
 bool shrink = false;
 
-/* Remove size from argv manually so that negative numbers are not treated
- * as options by getopt. */
-if (argc < 3) {
-error_exit(argv[0], "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'},
@@ -4339,7 +4329,7 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"shrink", no_argument, 0, OPTION_SHRINK},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, ":f:hq",
+c = getopt_long(argc, argv, "-:f:hq",
 long_options, NULL);
 if (c == -1) {
 break;
@@ -4377,12 +4367,35 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_SHRINK:
 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;
 }
 }
-if (optind != argc - 1) {
+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 */
 switch (size[0]) {
-- 
2.39.2




[PATCH 27/28] qemu-img: inline list of supported commands, remove qemu-img-cmds.h include

2024-02-21 Thread Michael Tokarev
also add short description to each command and use it in --help

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 41 ++---
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index ea284dca2d..299e34e470 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -61,6 +61,7 @@
 typedef struct img_cmd_t {
 const char *name;
 int (*handler)(const struct img_cmd_t *ccmd, int argc, char **argv);
+const char *description;
 } img_cmd_t;
 
 enum {
@@ -126,14 +127,14 @@ void cmd_help(const img_cmd_t *ccmd,
   const char *syntax, const char *arguments)
 {
 printf(
-"Usage:\n"
+"%s.  Usage:\n"
 "  %s %s %s"
 "\n"
 "Arguments:\n"
 "  -h, --help\n"
 " print this help and exit\n"
 "%s\n",
-   "qemu-img", ccmd->name,
+   ccmd->description, "qemu-img", ccmd->name,
syntax, arguments);
 exit(EXIT_SUCCESS);
 }
@@ -5824,10 +5825,36 @@ 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, },
 };
 
@@ -5892,7 +5919,7 @@ QEMU_IMG_VERSION
 "\n"
 "Recognized commands (run qemu-img COMMAND --help for command-specific 
help):\n\n");
 for (cmd = img_cmds; cmd->name != NULL; cmd++) {
-printf("  %s\n", cmd->name);
+printf("  %s - %s\n", cmd->name, cmd->description);
 }
 printf("\nSupported image formats:\n");
 c = 99; /* force a newline */
-- 
2.39.2




[PATCH 02/28] qemu-img: measure: convert img_size to signed, simplify handling

2024-02-21 Thread Michael Tokarev
qemu_opt_set_number() expects signed int64_t.

Use int64_t instead of uint64_t for img_size, use -1 as "unset"
value instead of UINT64_MAX, and do not require temporary sval
for conversion from string.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 19 +++
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 5a756be600..ae14ed833d 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -5362,7 +5362,7 @@ static int img_measure(int argc, char **argv)
 QemuOpts *sn_opts = NULL;
 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;
 int ret = 1;
@@ -5420,16 +5420,11 @@ static int img_measure(int argc, char **argv)
 }
 break;
 case OPTION_SIZE:
-{
-int64_t sval;
-
-sval = cvtnum("image size", optarg);
-if (sval < 0) {
+img_size = cvtnum("image size", optarg);
+if (img_size < 0) {
 goto out;
 }
-img_size = (uint64_t)sval;
-}
-break;
+break;
 }
 }
 
@@ -5444,11 +5439,11 @@ static int img_measure(int argc, char **argv)
 error_report("--image-opts, -f, and -l require a filename argument.");
 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;
 }
@@ -5496,7 +5491,7 @@ static int img_measure(int argc, char **argv)
 goto out;
 }
 }
-if (img_size != UINT64_MAX) {
+if (img_size != -1) {
 qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size, _abort);
 }
 
-- 
2.39.2




[PATCH 16/28] qemu-img: snapshot: make -l (list) the default, simplify option handling

2024-02-21 Thread Michael Tokarev
When no -l/-a/-c/-d specified, assume -l (list).

Use the same values for SNAPSHOT_LIST/etc constants as the
option chars (lacd), this makes it possible to simplify
option handling a lot, combining cases for 4 options into
one.

Also remove bdrv_oflags handling (only list can use RO mode).

Signed-off-by: Michael Tokarev 
---
 docs/tools/qemu-img.rst |  2 +-
 qemu-img.c  | 52 ++---
 2 files changed, 19 insertions(+), 35 deletions(-)

diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 9b628c4da5..df184d15b9 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -256,7 +256,7 @@ Parameters to snapshot subcommand:
 
 .. option:: -l
 
-  Lists all snapshots in the given image
+  Lists all snapshots in the given image (default action)
 
 Command description:
 
diff --git a/qemu-img.c b/qemu-img.c
index 85c37d491d..ee35768af8 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3584,10 +3584,11 @@ out:
 return ret < 0;
 }
 
-#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(const img_cmd_t *ccmd, int argc, char **argv)
 {
@@ -3595,7 +3596,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 BlockDriverState *bs;
 QEMUSnapshotInfo sn;
 char *filename, *fmt = NULL, *snapshot_name = NULL;
-int c, ret = 0, bdrv_oflags;
+int c, ret = 0;
 int action = 0;
 bool quiet = false;
 Error *err = NULL;
@@ -3603,7 +3604,6 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 bool force_share = false;
 int64_t rt;
 
-bdrv_oflags = BDRV_O_RDWR;
 /* Parse commandline parameters */
 for(;;) {
 static const struct option long_options[] = {
@@ -3631,36 +3631,15 @@ static int img_snapshot(const img_cmd_t *ccmd, int 
argc, char **argv)
 case 'f':
 fmt = optarg;
 break;
-case 'l':
-if (action) {
-error_exit(argv[0], "Cannot mix '-l', '-a', '-c', '-d'");
-return 0;
-}
-action = SNAPSHOT_LIST;
-bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
-break;
-case 'a':
+case SNAPSHOT_LIST:
+case SNAPSHOT_APPLY:
+case SNAPSHOT_CREATE:
+case SNAPSHOT_DELETE:
 if (action) {
 error_exit(argv[0], "Cannot mix '-l', '-a', '-c', '-d'");
 return 0;
 }
-action = SNAPSHOT_APPLY;
-snapshot_name = optarg;
-break;
-case 'c':
-if (action) {
-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(argv[0], "Cannot mix '-l', '-a', '-c', '-d'");
-return 0;
-}
-action = SNAPSHOT_DELETE;
+action = c;
 snapshot_name = optarg;
 break;
 case 'q':
@@ -3683,9 +3662,14 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 }
 filename = argv[optind++];
 
+if (!action) {
+action = SNAPSHOT_LIST;
+}
+
 /* Open the image */
-blk = img_open(image_opts, filename, fmt, 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;
 }
-- 
2.39.2




[PATCH 13/28] qemu-img: info: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.
Also add -b short option for --backing-chain, and remove
now-unused OPTION_BACKING_CHAIN.

While at it, remove unused option_index variable.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 40 +++-
 1 file changed, 27 insertions(+), 13 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 911cdc159c..cc51da31cf 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -65,7 +65,6 @@ typedef struct img_cmd_t {
 
 enum {
 OPTION_OUTPUT = 256,
-OPTION_BACKING_CHAIN = 257,
 OPTION_OBJECT = 258,
 OPTION_IMAGE_OPTS = 259,
 OPTION_PATTERN = 260,
@@ -3219,31 +3218,44 @@ static int img_info(const img_cmd_t *ccmd, int argc, 
char **argv)
 
 fmt = 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},
 {"force-share", no_argument, 0, 'U'},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, ":f:hU",
-long_options, _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':
 fmt = optarg;
@@ -3254,7 +3266,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_OUTPUT:
 output_format = parse_output_format(argv[0], optarg);
 break;
-case OPTION_BACKING_CHAIN:
+case 'b':
 chain = true;
 break;
 case OPTION_OBJECT:
@@ -3263,6 +3275,8 @@ static int img_info(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 if (optind != argc - 1) {
-- 
2.39.2




[PATCH 28/28] qemu-img: extend cvtnum() and use it in more places

2024-02-21 Thread Michael Tokarev
cvtnum() expects input string to specify some sort of size
(optionally with KMG... suffix).  However, there are a lot
of other number conversions in there (using qemu_strtol ),
also, not all conversions which use cvtnum, actually expects
size, - like dd count=nn.

Add bool issize argument to cvtnum() to specify if it should
treat the argument as a size or something else, - this changes
conversion routine in use and error text.

Use the new cvtnum() in more places (like where strtol were used),
since it never return negative number in successful conversion.
When it makes sense, also specify upper or lower bounds at the
same time.  This simplifies option processing in multiple places,
removing the need of local temporary variables and longer error
reporting code.

While at it, fix errors, like depth in measure must be >= 1,
while the previous code allowed it to be 0.

In a few places, change unsigned variables (like of type size_t)
to be signed instead, - to avoid the need of temporary conversion
variable.  All these variables are okay to be signed, we never
assign <0 value to them except of the cases of conversion error,
where we return immediately.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 118 -
 1 file changed, 44 insertions(+), 74 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 299e34e470..a066c4cfc4 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -397,18 +397,23 @@ static int add_old_style_options(const char *fmt, 
QemuOpts *opts,
 return 0;
 }
 
-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, );
+err = issize ? qemu_strtosz(value, NULL, ) :
+   qemu_strtou64(value, NULL, 0, );
 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.");
+if (issize) {
+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.");
+} else {
+error_report("Invalid %s specified.", name);
+}
 return err;
 }
 if (err == -ERANGE || res > max || res < min) {
@@ -419,9 +424,9 @@ static int64_t cvtnum_full(const char *name, const char 
*value, int64_t min,
 return res;
 }
 
-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(const img_cmd_t *ccmd, int argc, char **argv)
@@ -525,7 +530,7 @@ static int img_create(const img_cmd_t *ccmd, int argc, char 
**argv)
 
 /* Get image size, if specified */
 if (optind < argc) {
-img_size = cvtnum("image size", argv[optind++]);
+img_size = cvtnum("image size", argv[optind++], true);
 if (img_size < 0) {
 goto fail;
 }
@@ -987,7 +992,7 @@ static int img_commit(const img_cmd_t *ccmd, int argc, char 
**argv)
 quiet = true;
 break;
 case 'r':
-rate_limit = cvtnum("rate limit", optarg);
+rate_limit = cvtnum("rate limit", optarg, true);
 if (rate_limit < 0) {
 return 1;
 }
@@ -2412,7 +2417,7 @@ static int img_convert(const img_cmd_t *ccmd, 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;
 } else if (!QEMU_IS_ALIGNED(sval, BDRV_SECTOR_SIZE) ||
@@ -2444,10 +2449,9 @@ static int img_convert(const img_cmd_t *ccmd, int argc, 
char **argv)
 skip_create = true;
 break;
 case 'm':
-if (qemu_strtol(optarg, NULL, 0, _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 corou

[PATCH 20/28] qemu-img: resize: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 37 -
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index c8b0b68d67..45fbef5d37 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4323,27 +4323,44 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 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},
 {"shrink", no_argument, 0, OPTION_SHRINK},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, "-:f:hq",
+c = getopt_long(argc, argv, "-f:hq",
 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();
-break;
+cmd_help(ccmd,
+"[-f FMT | --image-opts] [--preallocation PREALLOC] [--shrink]\n"
+"[--object OBJECTDEF] [-q] FILENAME [+|-]SIZE\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\n"
+" new image size or amount by which to shrink/grow\n"
+);
+return 0;
 case 'f':
 fmt = optarg;
 break;
@@ -4385,6 +4402,8 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 error_exit(argv[0], "Extra argument(s) in command line");
 }
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 if (!filename && optind < argc) {
-- 
2.39.2




[PATCH v2 00/28] qemu-img: refersh options and --help handling, cleanups

2024-02-21 Thread Michael Tokarev
Quite big patchset trying to implement normal, readable qemu-img --help
(and qemu-img COMMAND --help) output with readable descriptions, and
adding many long options in the process.

In the end I stopped using qemu-img-opts.hx in qemu-img.c, perhaps
this can be avoided, with only list of commands and their desrciptions
kept there, but I don't see big advantage here.  The same list should
be included in docs/tools/qemu-img.rst, - this is not done now.

Also each command syntax isn't reflected in the doc for now, because
I want to give good names for options first, - and there, we've quite
some inconsistences and questions.  For example, measure --output=OFMT
-O OFMT, - this is priceless :)  I've no idea why we have this ugly
--output=json thing, why not have --json? ;)  I gave the desired
format long name --target-format to avoid clash with --output.

For rebase, src vs tgt probably should be renamed in local variables
too, and I'm not even sure I've got the caches right. For caches,
the thing is inconsistent across commands.

For compare, I used --a-format/--b-format (for -f/-F), - this can
be made --souce-format and --target-format, to compare source (file1)
with target (file2).

For bitmap, things are scary, I'm not sure what -b SRC_FILENAME
really means, - for now I gave it --source option, but this does
not make it more clear, suggestions welcome.

There are many other inconsistencies, I can't fix them all in one
go.. :)

Changes since v1:

 - reformatted help text to be less condensed
 - added cleanups (first 3 patches and last patch)
 - change argv[0] handling and getopt error reporting to
   fix inherent bug (see patch 4 "global option processing"
   for details)
 - removed missing_argument() & unrecognized_option()
   and handling of '?' and ':' getopt return values
 - more robust handling of resize filename -size vs options
   ("resize: do not always eat last argument")
 - larger cleanup in snapshot mode handling
   ("snapshot: make -l (list) the default...")
 - cvtnum and number conversion and bugfixes
   ("extend cvtnum() and use it in more places")
 - removed unused option_index variable in two places
 - added a few fixmes
 - various other minor changes

I kept Dan's R-b for a few patches he reviewed
despite the changed, - hopefully it's okay, since
the new changes are not related to the initial ones.
Keeping him in Cc for that.

Michael Tokarev (28):
  qemu-img: stop printing error twice in a few places
  qemu-img: measure: convert img_size to signed, simplify handling
  qemu-img: create: convert img_size to signed, simplify handling
  qemu-img: global option processing and error printing
  qemu-img: pass current cmd info into command handlers
  qemu-img: create: refresh options/--help
  qemu-img: factor out parse_output_format() and use it in the code
  qemu-img: check: refresh options/--help
  qemu-img: simplify --repair error message
  qemu-img: commit: refresh options/--help
  qemu-img: compare: refresh options/--help
  qemu-img: convert: refresh options/--help
  qemu-img: info: refresh options/--help
  qemu-img: map: refresh options/--help
  qemu-img: snapshot: allow specifying -f fmt
  qemu-img: snapshot: make -l (list) the default
  qemu-img: snapshot: refresh options/--help
  qemu-img: rebase: refresh options/--help
  qemu-img: resize: do not always eat last argument
  qemu-img: resize: refresh options/--help
  qemu-img: amend: refresh options/--help
  qemu-img: bench: refresh options/--help
  qemu-img: bitmap: refresh options/--help
  qemu-img: dd: refresh options/--help
  qemu-img: measure: refresh options/--help
  qemu-img: implement short --help, remove global help() function
  qemu-img: inline list of supported commands, remove qemu-img-cmds.h
include
  qemu-img: extend cvtnum() and use it in more places

 docs/tools/qemu-img.rst |4 +-
 qemu-img-cmds.hx|4 +-
 qemu-img.c  | 1143 +++
 3 files changed, 670 insertions(+), 481 deletions(-)

-- 
2.39.2




[PATCH 12/28] qemu-img: convert: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

convert uses -B for --backing, - why not -b?

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 90 --
 1 file changed, 81 insertions(+), 9 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index fd61b25ea7..911cdc159c 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -2403,30 +2403,100 @@ static int img_convert(const img_cmd_t *ccmd, int 
argc, char **argv)
 for(;;) {
 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},
 {"salvage", no_argument, 0, OPTION_SALVAGE},
 {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
 {"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"
+" ski

[PATCH 14/28] qemu-img: map: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

While at it, remove unused option_index variable.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 34 --
 1 file changed, 24 insertions(+), 10 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index cc51da31cf..3f719bbecf 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3453,7 +3453,6 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 
 fmt = NULL;
 for (;;) {
-int option_index = 0;
 static const struct option long_options[] = {
 {"help", no_argument, 0, 'h'},
 {"format", required_argument, 0, 'f'},
@@ -3465,20 +3464,33 @@ static int img_map(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"max-length", required_argument, 0, 'l'},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, ":f:s:l:hU",
-long_options, _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':
 fmt = optarg;
@@ -3507,6 +3519,8 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 if (optind != argc - 1) {
-- 
2.39.2




[PATCH 26/28] qemu-img: implement short --help, remove global help() function

2024-02-21 Thread Michael Tokarev
now once all individual subcommands has --help support, remove
the large unreadable help() thing and replace it with small
global --help, which refers to individual command --help for
more info.

While at it, also line-wrap list of formats after 75 chars.

Since missing_argument() and unrecognized_option() are now unused,
remove them.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 172 -
 1 file changed, 39 insertions(+), 133 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index d72e1f565b..ea284dca2d 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -94,11 +94,6 @@ typedef enum OutputFormat {
 /* Default to cache=writeback as data integrity is not important for qemu-img 
*/
 #define BDRV_DEFAULT_CACHE "writeback"
 
-static void format_print(void *opaque, const char *name)
-{
-printf(" %s", name);
-}
-
 static G_NORETURN
 void tryhelp(const char *argv0)
 {
@@ -118,18 +113,6 @@ void error_exit(const char *argv0, const char *fmt, ...)
 tryhelp(argv0);
 }
 
-static G_NORETURN
-void missing_argument(const char *option)
-{
-error_exit("qemu-img", "missing argument for option '%s'", option);
-}
-
-static G_NORETURN
-void unrecognized_option(const char *option)
-{
-error_exit("qemu-img", "unrecognized option '%s'", option);
-}
-
 /*
  * Print --help output for a command and exit.
  * syntax and description are multi-line with trailing EOL
@@ -166,114 +149,6 @@ static OutputFormat parse_output_format(const char 
*argv0, const char *arg)
 }
 }
 
-/* Please keep in synch with docs/tools/qemu-img.rst */
-static G_NORETURN
-void help(void)
-{
-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=]][,events=][,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"

[PATCH 18/28] qemu-img: rebase: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

Options added:
 --format, --cache - for the image in question
 --backing, --backing-format, --backing-cache, --backing-unsafe -
   for the new backing file
(was eg CACHE vs SRC_CACHE, which is unclear).

Probably should rename local variables.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 55 +-
 1 file changed, 46 insertions(+), 9 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index ce939708d4..2a4bff2872 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3792,26 +3792,61 @@ static int img_rebase(const img_cmd_t *ccmd, int argc, 
char **argv)
 for(;;) {
 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':
 fmt = optarg;
@@ -3849,6 +3884,8 @@ static int img_rebase(const img_cmd_t *ccmd, int argc, 
char **argv)
 case 'c':
 compress = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 24/28] qemu-img: dd: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 39 +--
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index e4027ece20..af7841573c 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -5502,31 +5502,48 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char 
**argv)
 const struct option long_options[] = {
 { "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'},
 { 0, 0, 0, 0 }
 };
 
-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;
 break;
 case 'f':
 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;
 break;
@@ -5536,6 +5553,8 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 11/28] qemu-img: compare: refresh options/--help

2024-02-21 Thread Michael Tokarev
Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 45 +
 1 file changed, 37 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 1271217272..fd61b25ea7 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1487,25 +1487,52 @@ static int img_compare(const img_cmd_t *ccmd, int argc, 
char **argv)
 for (;;) {
 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) {
 break;
 }
 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':
 fmt1 = optarg;
@@ -1546,6 +1573,8 @@ static int img_compare(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 23/28] qemu-img: bitmap: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 40 
 1 file changed, 32 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 8455832d34..e4027ece20 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -5168,20 +5168,42 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"source-format", required_argument, 0, 'F'},
 {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;
 }
 
 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 GRANULARITY] [--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 GRANULARITY\n"
+" sets non-default granularity for --add\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':
 src_filename = optarg;
@@ -5237,6 +5259,8 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 08/28] qemu-img: check: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 38 ++
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 01894c097b..69fa9701e9 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -804,7 +804,9 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 int option_index = 0;
 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},
 {"object", required_argument, 0, OPTION_OBJECT},
@@ -812,20 +814,38 @@ static int img_check(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"force-share", no_argument, 0, 'U'},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, ":hf:r:T:qU",
+c = getopt_long(argc, argv, "hf:r:T:qU",
 long_options, _index);
 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] [-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':
 fmt = optarg;
@@ -860,6 +880,8 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 if (optind != argc - 1) {
-- 
2.39.2




[PATCH 25/28] qemu-img: measure: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

Also add -s short option for --size (and remove OPTION_SIZE).

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 53 -
 1 file changed, 40 insertions(+), 13 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index af7841573c..d72e1f565b 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -71,7 +71,6 @@ enum {
 OPTION_FLUSH_INTERVAL = 261,
 OPTION_NO_DRAIN = 262,
 OPTION_TARGET_IMAGE_OPTS = 263,
-OPTION_SIZE = 264,
 OPTION_PREALLOCATION = 265,
 OPTION_SHRINK = 266,
 OPTION_SALVAGE = 267,
@@ -5744,15 +5743,6 @@ static void 
dump_json_block_measure_info(BlockMeasureInfo *info)
 
 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;
 BlockDriver *drv;
@@ -5773,12 +5763,47 @@ static int img_measure(const img_cmd_t *ccmd, int argc, 
char **argv)
 int ret = 1;
 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':
 fmt = optarg;
@@ -5816,12 +5841,14 @@ static int img_measure(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_OUTPUT:
 output_format = parse_output_format(argv[0], optarg);
 break;
-case OPTION_SIZE:
+case 's':
 img_size = cvtnum("image size", optarg);
 if (img_size < 0) {
 goto out;
 }
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 07/28] qemu-img: factor out parse_output_format() and use it in the code

2024-02-21 Thread Michael Tokarev
Use common code and simplify error message

Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 qemu-img.c | 63 --
 1 file changed, 18 insertions(+), 45 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 7e4c993b9c..01894c097b 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -157,6 +157,17 @@ void cmd_help(const img_cmd_t *ccmd,
 exit(EXIT_SUCCESS);
 }
 
+static OutputFormat parse_output_format(const char *argv0, const char *arg)
+{
+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);
+}
+}
+
 /* Please keep in synch with docs/tools/qemu-img.rst */
 static G_NORETURN
 void help(void)
@@ -775,7 +786,7 @@ 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;
 int fix = 0;
@@ -787,7 +798,6 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 bool force_share = false;
 
 fmt = NULL;
-output = NULL;
 cache = BDRV_DEFAULT_CACHE;
 
 for(;;) {
@@ -833,7 +843,7 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 }
 break;
 case OPTION_OUTPUT:
-output = optarg;
+output_format = parse_output_format(argv[0], optarg);
 break;
 case 'T':
 cache = optarg;
@@ -857,15 +867,6 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 }
 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, , );
 if (ret < 0) {
 error_report("Invalid source cache option: %s", cache);
@@ -3059,13 +3060,12 @@ 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;
 bool force_share = false;
 
 fmt = NULL;
-output = NULL;
 for(;;) {
 int option_index = 0;
 static const struct option long_options[] = {
@@ -3100,7 +3100,7 @@ static int img_info(const img_cmd_t *ccmd, int argc, char 
**argv)
 force_share = true;
 break;
 case OPTION_OUTPUT:
-output = optarg;
+output_format = parse_output_format(argv[0], optarg);
 break;
 case OPTION_BACKING_CHAIN:
 chain = true;
@@ -3118,15 +3118,6 @@ static int img_info(const img_cmd_t *ccmd, int argc, 
char **argv)
 }
 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);
 if (!list) {
@@ -3285,7 +3276,7 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 OutputFormat output_format = OFORMAT_HUMAN;
 BlockBackend *blk;
 BlockDriverState *bs;
-const char *filename, *fmt, *output;
+const char *filename, *fmt;
 int64_t length;
 MapEntry curr = { .length = 0 }, next;
 int ret = 0;
@@ -3295,7 +3286,6 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 int64_t max_length = -1;
 
 fmt = NULL;
-output = NULL;
 for (;;) {
 int option_index = 0;
 static const struct option long_options[] = {
@@ -3331,7 +3321,7 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 force_share = true;
 break;
 case OPTION_OUTPUT:
-output = optarg;
+output_format = parse_output_format(argv[0], optarg);
 break;
 case 's':
 start_offset = cvtnum("start offset", optarg);
@@ -3358,15 +3348,6 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 }
 filename = argv[optind];
 
-if (output && !strcmp(output, "json&qu

[PATCH 21/28] qemu-img: amend: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 34 ++
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 45fbef5d37..0d17738fb6 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4557,26 +4557,42 @@ static int img_amend(const img_cmd_t *ccmd, int argc, 
char **argv)
 for (;;) {
 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) {
 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] [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':
 if (accumulate_options(, optarg) < 0) {
@@ -4605,6 +4621,8 @@ static int img_amend(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_FORCE:
 force = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 04/28] qemu-img: global option processing and error printing

2024-02-21 Thread Michael Tokarev
In order to correctly print executable name in various
error messages, pass argv[0] to error_exit() function.
This way, error messages will refer to actual executable
name, which may be different from 'qemu-img'.

For subcommands, pass whole argv[] array, so argv[0] is
the executable name, not subcommand name.  In order to
do that, avoid resetting optind but continue with the
next option.  Also don't require at least 3 options on
the command line: it makes no sense with options before
subcommand.

Before invoking a subcommand, replace argv[0] to include
the subcommand name.

Introduce tryhelp() function which just prints

 try 'command-name --help' for more info

and exits.  When tryhelp() is called from within a subcommand
handler, the message will look like:

 try 'command-name subcommand --help' for more info

qemu-img uses getopt_long() with ':' as the first char in
optstring parameter, which means it doesn't print error
messages but return ':' or '?' instead, and qemu-img uses
unrecognized_option() or missing_argument() function to
print error messages.  But it doesn't quite work:

 $ ./qemu-img -xx
 qemu-img: unrecognized option './qemu-img'

so the aim is to let getopt_long() to print regular error
messages instead (removing ':' prefix from optstring) and
remove handling of '?' and ':' "options" entirely.  With
concatenated argv[0] and the subcommand, it all finally
does the right thing in all cases.  This will be done in
subsequent changes command by command, with main() done
last.

unrecognized_option() and missing_argument() functions
prototypes aren't changed by this patch, since they're
called from many places and will be removed a few patches
later.  Only artifical "qemu-img" argv0 is provided in
there for now.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 75 +++---
 1 file changed, 38 insertions(+), 37 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index df425b2517..44dbf5be4f 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -101,8 +101,15 @@ static void format_print(void *opaque, const char *name)
 printf(" %s", name);
 }
 
-static G_NORETURN G_GNUC_PRINTF(1, 2)
-void error_exit(const char *fmt, ...)
+static G_NORETURN
+void tryhelp(const char *argv0)
+{
+error_printf("Try '%s --help' for more info\n", argv0);
+exit(EXIT_FAILURE);
+}
+
+static G_NORETURN G_GNUC_PRINTF(2, 3)
+void error_exit(const char *argv0, const char *fmt, ...)
 {
 va_list ap;
 
@@ -110,20 +117,19 @@ void error_exit(const char *fmt, ...)
 error_vreport(fmt, ap);
 va_end(ap);
 
-error_printf("Try 'qemu-img --help' for more information\n");
-exit(EXIT_FAILURE);
+tryhelp(argv0);
 }
 
 static G_NORETURN
 void missing_argument(const char *option)
 {
-error_exit("missing argument for option '%s'", option);
+error_exit("qemu-img", "missing argument for option '%s'", option);
 }
 
 static G_NORETURN
 void unrecognized_option(const char *option)
 {
-error_exit("unrecognized option '%s'", option);
+error_exit("qemu-img", "unrecognized option '%s'", option);
 }
 
 /* Please keep in synch with docs/tools/qemu-img.rst */
@@ -576,7 +582,7 @@ 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++;
 
@@ -588,7 +594,7 @@ static int img_create(int argc, char **argv)
 }
 }
 if (optind != argc) {
-error_exit("Unexpected argument: %s", argv[optind]);
+error_exit(argv[0], "Unexpected argument: %s", argv[optind]);
 }
 
 bdrv_img_create(filename, fmt, base_filename, base_fmt,
@@ -770,7 +776,7 @@ static int img_check(int argc, char **argv)
 } else if (!strcmp(optarg, "all")) {
 fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
 } else {
-error_exit("Unknown option value for -r "
+error_exit(argv[0], "Unknown option value for -r "
"(expecting 'leaks' or 'all'): %s", optarg);
 }
 break;
@@ -795,7 +801,7 @@ static int img_check(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++];
 
@@ -1025,7 +1031,7 @@ 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++];
 
@@ -1446,7 +1452,7 @@ static int img_compare(int argc, char **argv)
 
 
 if (optind != arg

[PATCH 17/28] qemu-img: snapshot: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 45 -
 1 file changed, 36 insertions(+), 9 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index ee35768af8..ce939708d4 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3608,26 +3608,51 @@ static int img_snapshot(const img_cmd_t *ccmd, int 
argc, char **argv)
 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:f:hqU",
+c = getopt_long(argc, argv, "la:c:d:f:hqU",
 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();
-return 0;
+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 'f':
 fmt = optarg;
 break;
@@ -3654,6 +3679,8 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 22/28] qemu-img: bench: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 64 +-
 1 file changed, 54 insertions(+), 10 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 0d17738fb6..8455832d34 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4847,28 +4847,70 @@ static int img_bench(const img_cmd_t *ccmd, int argc, 
char **argv)
 for (;;) {
 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;
 }
 
 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':
 {
@@ -4985,6 +5027,8 @@ static int img_bench(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 10/28] qemu-img: commit: refresh options/--help

2024-02-21 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 44 
 1 file changed, 36 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index eba13724b0..1271217272 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1047,24 +1047,50 @@ static int img_commit(const img_cmd_t *ccmd, int argc, 
char **argv)
 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},
+{"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) {
 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] [-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':
 fmt = optarg;
@@ -1098,6 +1124,8 @@ static int img_commit(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_IMAGE_OPTS:
 image_opts = true;
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 05/28] qemu-img: pass current cmd info into command handlers

2024-02-21 Thread Michael Tokarev
This info will be used to generate --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 34 +-
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 44dbf5be4f..38ac0f1845 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -60,7 +60,7 @@
 
 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);
 } img_cmd_t;
 
 enum {
@@ -514,7 +514,7 @@ static int64_t cvtnum(const char *name, const char *value)
 return cvtnum_full(name, value, 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;
 int64_t img_size = -1;
@@ -719,7 +719,7 @@ static int collect_image_check(BlockDriverState *bs,
  *  3 - Check completed, image has leaked clusters, but is good otherwise
  * 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;
@@ -951,7 +951,7 @@ 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;
 const char *filename, *fmt, *cache, *base;
@@ -1358,7 +1358,7 @@ static int check_empty_sectors(BlockBackend *blk, int64_t 
offset,
  * 1 - Images differ
  * >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;
 BlockBackend *blk1, *blk2;
@@ -2234,7 +2234,7 @@ static void set_rate_limit(BlockBackend *blk, int64_t 
rate_limit)
 blk_set_io_limits(blk, );
 }
 
-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;
 const char *fmt = NULL, *out_fmt = NULL, *cache = "unsafe",
@@ -3002,7 +3002,7 @@ err:
 return NULL;
 }
 
-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;
@@ -3227,7 +3227,7 @@ static inline bool entry_mergeable(const MapEntry *curr, 
const MapEntry *next)
 return true;
 }
 
-static int img_map(int argc, char **argv)
+static int img_map(const img_cmd_t *ccmd, int argc, char **argv)
 {
 int c;
 OutputFormat output_format = OFORMAT_HUMAN;
@@ -3376,7 +3376,7 @@ out:
 #define SNAPSHOT_APPLY  3
 #define SNAPSHOT_DELETE 4
 
-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;
@@ -3534,7 +3534,7 @@ static int img_snapshot(int argc, char **argv)
 return 0;
 }
 
-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;
 uint8_t *buf_old = NULL;
@@ -4028,7 +4028,7 @@ out:
 return 0;
 }
 
-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;
@@ -4241,7 +4241,7 @@ static int print_amend_option_help(const char *format)
 return 0;
 }
 
-static int img_amend(int argc, char **argv)
+static int img_amend(const img_cmd_t *ccmd, int argc, char **argv)
 {
 Error *err = NULL;
 int c, ret = 0;
@@ -4505,7 +4505,7 @@ 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;
 const char *fmt = NULL, *filename;
@@ -4775,7 +4775,7 @@ typedef struct ImgBitmapAction {
 QSIMPLEQ_ENTRY(ImgBitmapAction) next;
 } 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;
 int c, ret = 1;
@@ -5075,7 +5075,7 @@ static int img_dd_skip(const char *arg,
 return 0;
 }
 
-static int img_dd(int argc, char **argv)
+static int img_dd(const img_cmd_t *ccmd, int argc, char **argv)
 {
 int ret = 0;
 char *arg = NULL;
@@ -5341,7 +5341,7 @@ static void dump_json_block_measure_info(BlockMeasureInfo 
*info)
 g_string_free(str, true);
 }
 
-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'},
@@ -5603,7 +5603,7 @@ int main(int argc, char **argv)
 for (cmd = img_cmds;

[PATCH 06/28] qemu-img: create: refresh options/--help

2024-02-21 Thread Michael Tokarev
Create helper function cmd_help() to display command-specific
help text, and use it to print --help for 'create' subcommand.

Add missing long options (eg --format) in img_create().

Remove usage of missing_argument()/unrecognized_option() in
img_create().

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 68 +++---
 1 file changed, 60 insertions(+), 8 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 38ac0f1845..7e4c993b9c 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -132,6 +132,31 @@ void unrecognized_option(const char *option)
 error_exit("qemu-img", "unrecognized option '%s'", option);
 }
 
+/*
+ * 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 cmd_help(const img_cmd_t *ccmd,
+  const char *syntax, const char *arguments)
+{
+printf(
+"Usage:\n"
+"  %s %s %s"
+"\n"
+"Arguments:\n"
+"  -h, --help\n"
+" print this help and exit\n"
+"%s\n",
+   "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)
@@ -530,23 +555,48 @@ static int img_create(const img_cmd_t *ccmd, int argc, 
char **argv)
 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'},
+{"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) {
 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] [-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':
 base_fmt = optarg;
@@ -571,6 +621,8 @@ static int img_create(const img_cmd_t *ccmd, int argc, char 
**argv)
 case OPTION_OBJECT:
 user_creatable_process_cmdline(optarg);
 break;
+default:
+tryhelp(argv[0]);
 }
 }
 
-- 
2.39.2




[PATCH 09/28] qemu-img: simplify --repair error message

2024-02-21 Thread Michael Tokarev
Signed-off-by: Michael Tokarev 
Reviewed-by: Daniel P. Berrangé 
---
 qemu-img.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 69fa9701e9..eba13724b0 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -858,8 +858,9 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 } else if (!strcmp(optarg, "all")) {
 fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
 } else {
-error_exit(argv[0], "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:
-- 
2.39.2




[PATCH 01/28] qemu-img: stop printing error twice in a few places

2024-02-21 Thread Michael Tokarev
Currently we have:

  ./qemu-img resize none +10
  qemu-img: Could not open 'none': Could not open 'none': No such file or 
directory

stop printing the message twice, - local_err already has
all the info, no need to prepend additional text there.

There are a few other places like this, but I'm unsure
about these.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 8 +++-
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 7668f86769..5a756be600 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -404,7 +404,7 @@ static BlockBackend *img_open_file(const char *filename,
 }
 blk = blk_new_open(filename, NULL, options, flags, _err);
 if (!blk) {
-error_reportf_err(local_err, "Could not open '%s': ", filename);
+error_report_err(local_err);
 return NULL;
 }
 blk_set_enable_write_cache(blk, !writethrough);
@@ -597,7 +597,7 @@ static int img_create(int argc, char **argv)
 bdrv_img_create(filename, fmt, base_filename, base_fmt,
 options, img_size, flags, quiet, _err);
 if (local_err) {
-error_reportf_err(local_err, "%s: ", filename);
+error_report_err(local_err);
 goto fail;
 }
 
@@ -5253,9 +5253,7 @@ static int img_dd(int argc, char **argv)
 
 ret = bdrv_create(drv, out.filename, opts, _err);
 if (ret < 0) {
-error_reportf_err(local_err,
-  "%s: error while creating output image: ",
-  out.filename);
+error_report_err(local_err);
 ret = -1;
 goto out;
 }
-- 
2.39.2




Re: [PATCH 23/23] qemu-img: inline list of supported commands, remove qemu-img-cmds.h include

2024-02-21 Thread Michael Tokarev

20.02.2024 21:48, Daniel P. Berrangé:


This ends up looking a bit muddled together. I don't think we
need repeat 'qemu-img ' twice, and could add a little
more whitespace

eg instead of:

$ ./build/qemu-img check --help
qemu-img check: Check basic image integrity.  Usage:
qemu-img check [-f FMT | --image-opts] [-T CACHE_MODE] [-r] [-u]
 [--output human|json] [--object OBJDEF] FILENAME
Arguments:
...snip...

have it look like

$ ./build/qemu-img check --help
Check basic image integrity.

Usage:

   qemu-img check [-f FMT | --image-opts] [-T CACHE_MODE] [-r] [-u]
 [--output human|json] [--object OBJDEF] FILENAME

Arguments:
...snip...


Here's the current way how `create' help text looks like:

$ ./qemu-img create --help
Create and format qemu image file.  Usage:
  qemu-img create [-f FMT] [-o FMT_OPTS] [-b BACKING_FILENAME [-F BACKING_FMT]]
[--object OBJDEF] [-u] FILENAME [SIZE[bkKMGTPE]]
Arguments:
  -h, --help
 print this help and exit
  -q, --quiet
 quiet operations
  -f, --format FMT
 specifies format of the new image, default is raw
  -o, --options FMT_OPTS
 format-specific options ('-o list' for list)
  -b, --backing BACKING_FILENAME
 stack new image on top of BACKING_FILENAME
 (for formats which support stacking)
  -F, --backing-format BACKING_FMT
 specify format of BACKING_FILENAME
  -u, --backing-unsafe
 do not fail if BACKING_FMT can not be read
  --object OBJDEF
 QEMU user-creatable object (eg encryption key)
  FILENAME
 image file to create.  It will be overridden if exists
  SIZE
 image size with optional suffix (multiplies in 1024)
 SIZE is required unless BACKING_IMG is specified,
 in which case it will be the same as size of BACKING_IMG

Maybe it's a good idea to add newlines around the "syntax" part,
ie, after "Usage:" and before "Arguments:".  I don't think it needs
extra newlines between each argument description though, - this way
it becomes just too long.

What do you think?

Thanks,

/mjt



Re: [PATCH 12/23] qemu-img: make -l (list) the default for "snapshot" subcommand

2024-02-21 Thread Michael Tokarev

20.02.2024 21:51, Michael Tokarev wrote:

20.02.2024 20:45, Daniel P. Berrangé wrote:

On Sat, Feb 10, 2024 at 12:22:33AM +0300, Michael Tokarev wrote:

also remove bdrv_oflags handling (only list can use RO mode)
---
  qemu-img.c | 13 -
  1 file changed, 8 insertions(+), 5 deletions(-)


I'd suggest docs/tools/qemu-img.rst should also be updated to say


qemu-img.rst needs to be updated, significantly more than this.


Actually, - yes, you're right in this case.  Added.  A good suggestion.

Thanks,

/mjt



Re: [PATCH 15/23] qemu-img: resize: do not always eat last argument

2024-02-21 Thread Michael Tokarev

20.02.2024 20:57, Daniel P. Berrangé пишет:

On Sat, Feb 10, 2024 at 12:22:36AM +0300, Michael Tokarev wrote:

'qemu-img resize --help' does not work, since it wants more arguments.
Only eat last option at the beginning if it starts like -N.., and allow
getopt() to do its work, and eat it up at the end if not already eaten.
This will not allow to mix options and size anyway, but it is better
than now.

Signed-off-by: Michael Tokarev 
---
  qemu-img.c | 15 +--
  1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 69d41e0a92..929a25a021 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4271,13 +4271,13 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
  
  /* Remove size from argv manually so that negative numbers are not treated

   * as options by getopt. */
-if (argc < 3) {
-error_exit(ccmd, "Not enough arguments");
-return 1;
+if (argc > 1 && argv[argc - 1][0] == '-'
+&& argv[argc-1][1] >= '0' && argv[argc-1][1] <= '9') {
+size = argv[--argc];
+} else {
+size = NULL;
  }


We already have a variable 'int relative' that is set to '-1'
or '+1' depending on whether we have a -ve or +ve size.

I think it is clearer to follow if we just set 'relative' much
earlier before parsing by moving this chunk of code to before
the getopt:


Well, we'll also have to repeat the same switch after getopt, since
there, I only test for -[0-9], not +[0-9] or [0-9].   But yes, it
can be done too.

But this is more interesting, - I think we should switch getopt to
use 'return in order' option, and process options together with
getopt, looking at the next option at each iteration, - if it looks
like [+-]size if we already got the filename part.  Lemme try to
do that..

/mjt



Re: [PATCH 23/23] qemu-img: inline list of supported commands, remove qemu-img-cmds.h include

2024-02-20 Thread Michael Tokarev

20.02.2024 21:48, Daniel P. Berrangé:
...

$ ./build/qemu-img check --help
Check basic image integrity.

Usage:

   qemu-img check [-f FMT | --image-opts] [-T CACHE_MODE] [-r] [-u]
 [--output human|json] [--object OBJDEF] FILENAME

Arguments:


$ ./build/qemu-img check --help
Check basic image integrity.  Usage:

   qemu-img check [-f FMT | --image-opts] [-T CACHE_MODE] [-r] [-u]
  [--output human|json] [--object OBJDEF] FILENAME

Arguments:
...

Or just:

Check basic image integrity:

 qemu-img check...


In all cases I tried to make the whole thing as compact as possible,
to (almost) fit on a standard terminal.  The extra empty lines between
different arguments makes it almost impossible.

I think if indentation will be larger, it will be easier to read.
Let me experiment a bit..


 "Arguments:\n"
 " -h|--help - print this help and exit\n"


btw, the common way is to use comma here, not "|", --
  -h,--help - ...

Again, I especially omitted space after "|" to make it
more compact.  Maybe for no good.

We've really big amount of options here, conflicting and illogical
in some cases, which's been added without much thinking.  All this
makes me think it will be difficult to automate generation of all
this text for both code and docs..

Thanks!

/mjt



Re: [PATCH 12/23] qemu-img: make -l (list) the default for "snapshot" subcommand

2024-02-20 Thread Michael Tokarev

20.02.2024 20:45, Daniel P. Berrangé wrote:

On Sat, Feb 10, 2024 at 12:22:33AM +0300, Michael Tokarev wrote:

also remove bdrv_oflags handling (only list can use RO mode)
---
  qemu-img.c | 13 -
  1 file changed, 8 insertions(+), 5 deletions(-)


I'd suggest docs/tools/qemu-img.rst should also be updated to say


qemu-img.rst needs to be updated, significantly more than this.
I especially avoided updating this one for now because I'd love
to agree with the options first, more or less, or else it'd be
large double-work.  Also, there's an open question still, if
we prefer to keep docs and code in sync manually or to use some
automation like qemu-img-cmdx.hx now.  I for one don't see how
this can be done in a reasonable way.

I plan to update it past this series.

Thanks!

/mjt



Re: [PATCH] scsi: megasas: Internal cdbs have 16-byte length

2024-02-17 Thread Michael Tokarev

28.02.2023 20:11, Guenter Roeck wrote:

Host drivers do not necessarily set cdb_len in megasas io commands.
With commits 6d1511cea0 ("scsi: Reject commands if the CDB length
exceeds buf_len") and fe9d8927e2 ("scsi: Add buf_len parameter to
scsi_req_new()"), this results in failures to boot Linux from affected
SCSI drives because cdb_len is set to 0 by the host driver.
Set the cdb length to its actual size to solve the problem.


Has this been lost/forgotten?

/mjt




Re: [PATCH v4 5/9] pcie_sriov: Validate NumVFs

2024-02-14 Thread Michael Tokarev

14.02.2024 17:54, Akihiko Odaki wrote:

On 2024/02/14 17:58, Michael Tokarev wrote:

14.02.2024 08:13, Akihiko Odaki wrote:

The guest may write NumVFs greater than TotalVFs and that can lead
to buffer overflow in VF implementations.


This seems to be stable-worthy (Cc'd), and maybe even CVE-worthy?


Perhaps so. The scope of the bug is limited to emulated SR-IOV devices, and I think nobody use them except for development, but it may be still nice 
to have a CVE.


Can anyone help assign a CVE? I don't know the procedure.


Heh. Usually I ask exactly the opposite question: how to avoid assigning
a CVE# for a non-issue which they most likely think is a serious security
bug?  We've plenty of these in qemu, collecting dust for years...  For
example, for things like some actions by privileged guest process (or kernel)
which leads to qemu dying with assertion failure, which, on a real HW, will
cause hardware lockup.

Nope, I don't remember how to request a CVE ;)

/mjt



Re: [PATCH v4 5/9] pcie_sriov: Validate NumVFs

2024-02-14 Thread Michael Tokarev

14.02.2024 08:13, Akihiko Odaki wrote:

The guest may write NumVFs greater than TotalVFs and that can lead
to buffer overflow in VF implementations.


This seems to be stable-worthy (Cc'd), and maybe even CVE-worthy?

Thanks,

/mjt


Fixes: 7c0fa8dff811 ("pcie: Add support for Single Root I/O Virtualization 
(SR/IOV)")
Signed-off-by: Akihiko Odaki 
---
  hw/pci/pcie_sriov.c | 3 +++
  1 file changed, 3 insertions(+)

diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c
index a1fe65f5d801..da209b7f47fd 100644
--- a/hw/pci/pcie_sriov.c
+++ b/hw/pci/pcie_sriov.c
@@ -176,6 +176,9 @@ static void register_vfs(PCIDevice *dev)
  
  assert(sriov_cap > 0);

  num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF);
+if (num_vfs > pci_get_word(dev->config + sriov_cap + PCI_SRIOV_TOTAL_VF)) {
+return;
+}
  
  dev->exp.sriov_pf.vf = g_new(PCIDevice *, num_vfs);
  






Re: [PATCH 0/2] block: Allow concurrent BB context changes

2024-02-10 Thread Michael Tokarev

09.02.2024 19:51, Hanna Czenczek :

On 09.02.24 15:08, Michael Tokarev wrote:

02.02.2024 17:47, Hanna Czenczek :

Hi,

Without the AioContext lock, a BB's context may kind of change at any
time (unless it has a root node, and I/O requests are pending). That
also means that its own context (BlockBackend.ctx) and that of its root
node can differ sometimes (while the context is being changed).


How relevant this is for -stable (8.2 at least) which does not have
"scsi: eliminate AioContext lock" patchset, and in particular,:
v8.2.0-124-geaad0fe260 "scsi: only access SCSIDevice->requests from
one thread"?

The issue first patch "block-backend: Allow concurrent context changes"
fixes (RHEL-19381) seems to be for 8.1.something, so it exists in 8.2
too, and this particular fix applies to 8.2.

But with other changes around all this, I'm a bit lost as of what should
be done on stable.  Not even thinking about 7.2 here :)


Ah, sorry, yes.  Since we do still have the AioContext lock, this series won’t 
be necessary in -stable.  Sorry for the noise!


Hm. Now I'm confused even more.. :)

ad89367202 "block-backend: Allow concurrent context changes" - the first
one in this series - apparently is needed, as it fixes an issue reported
for qemu 8.1 (https://issues.redhat.com/browse/RHEL-19381).  Or is it not
the case?

FWIW, truth is born in the noise, not in silence ;)

Thanks,

/mjt



Re: [PATCH v2 3/3] virtio-blk: Use ioeventfd_attach in start_ioeventfd

2024-02-10 Thread Michael Tokarev

09.02.2024 20:11, Hanna Czenczek :


The mentioned comit is v8.2.0-812-gd3f6f294ae, - ie, past 8.2.
Is this new change still relevant for stable?


Sorry again. :/ 


There's nothing to be sorry about here - it's regular work, and is quite
good at it, - I just asked to be sure, maybe I misunderstood something.

This patch is a clean-up patch that won’t apply to 8.2.  Now, 8.2 does have basically the same logic as described in the patch 
message (d3f6f294aea restored it after it was broken), so a similar patch could be made for it (removing the event_notifier_set() from 
virtio_blk_data_plane_start()), but whether we kick the virtqueues once or twice on start-up probably won’t make a difference, certainly not in terms 
of correctness.


Ok, excellent, this makes good sense now.
I'm not including this one in stable-8.2 :)

Thank you very much for the excellent work and
the clarification!

/mjt



Re: [PATCH trivial] qemu-img: factor out parse_output_format() and use it in the code

2024-02-09 Thread Michael Tokarev

07.02.2024 20:52, Michael Tokarev :

Use common code and simplify error message


I've sent this as part of qemu-img --help/options refactoring
series, done in that context so this path does not make sense
anymore.

/mjt



Re: [PATCH 00/23] qemu-img: refersh options and --help handling

2024-02-09 Thread Michael Tokarev

10.02.2024 00:22, Michael Tokarev wrote:

Quite big patchset implementing normal, readable qemu-img --help
(and qemu-img COMMAND --help) output with readable descriptions,
and adding many long options in the process.

...

I forgot to run checkpatch.pl - minor edits, the result is at
https://gitlab.com/mjt0k/qemu/-/commits/qemu-img-options

/mjt



Re: [PATCH 11/23] qemu-img: allow specifying -f fmt for snapshot subcommand

2024-02-09 Thread Michael Tokarev

10.02.2024 00:22, Michael Tokarev wrote:

For consistency with other commands, and since it already
accepts --image-opts, allow specifying -f fmt too.


...

-c = getopt_long(argc, argv, ":la:c:d:hqU",
+c = getopt_long(argc, argv, ":la:c:d:fhqU",
  long_options, NULL);


Should be "f:" here, since -f expects an argument.  Fixed locally.

/mjt



[PATCH 14/23] qemu-img: refresh options/--help for "rebase" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.

Options added:
 --format, --cache - for the image in question
 --backing, --backing-format, --backing-cache, --backing-unsafe -
   for the new backing file
(was eg CACHE vs SRC_CACHE, which is unclear).

Probably should rename local variables.
---
 qemu-img.c | 30 +-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/qemu-img.c b/qemu-img.c
index 67e6a7797d..69d41e0a92 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3752,10 +3752,18 @@ static int img_rebase(const img_cmd_t *ccmd, int argc, 
char **argv)
 for(;;) {
 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",
@@ -3771,7 +3779,27 @@ static int img_rebase(const img_cmd_t *ccmd, int argc, 
char **argv)
 unrecognized_option(ccmd, argv[optind - 1]);
 break;
 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 - quiet operation\n"
+" -p|--progress - show progress indicator\n"
+" -f|--format FMT - specify FILENAME format explicitly\n"
+" --image-opts - indicates that FILENAME is a complete image specification\n"
+"  instead of a file name (incompatible with --format)\n"
+" -t|--cache CACHE - cache mode for FILENAME (" BDRV_DEFAULT_CACHE ")\n"
+" -b|--backing BACKING_FILENAME|\"\" - rebase onto this file (or no backing 
file)\n"
+" -F|--backing-format BACKING_FMT - specify format for BACKING_FILENAME\n"
+" -T|--backing-cache CACHE - cache mode for BACKING_FILENAME (" 
BDRV_DEFAULT_CACHE ")\n"
+" -u|--backing-unsafe - do not fail if BACKING_FILENAME can not be read\n"
+" -c|--compress - compress image (when image supports this)\n"
+" -U|--force-share - open image in shared mode for concurrent access\n"
+" --object OBJDEF - QEMU user-creatable object (eg encryption key)\n"
+" FILENAME - image file name (or specification with --image-opts)\n"
+);
 return 0;
 case 'f':
 fmt = optarg;
-- 
2.39.2




[PATCH 07/23] qemu-img: refresh options/--help for "compare" command

2024-02-09 Thread Michael Tokarev
Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/qemu-img.c b/qemu-img.c
index eabf45c423..8f16ee9deb 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1464,9 +1464,17 @@ static int img_compare(const img_cmd_t *ccmd, int argc, 
char **argv)
 for (;;) {
 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",
@@ -1482,7 +1490,22 @@ static int img_compare(const img_cmd_t *ccmd, int argc, 
char **argv)
 unrecognized_option(ccmd, 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 - quiet operation\n"
+" -p|--progress - show operation progress\n"
+" -f|--a-format FMT - specify FILENAME1 image format explicitly\n"
+" -F|--b-format FMT - specify FILENAME2 image format explicitly\n"
+" --image-opts - indicates that FILENAMEs are complete image specifications\n"
+"  instead of file names (incompatible with --a-format and --b-format)\n"
+" -s|--strict - strict mode, also check if sizes are equal\n"
+" -T|--cache - CACHE_MODE cache mode when opening images (" BDRV_DEFAULT_CACHE 
")\n"
+" -U|--force-share - open images in shared mode for concurrent access\n"
+" --object OBJDEF - QEMU user-creatable object (eg encryption key)\n"
+" FILENAME1, FILENAME2 - image files (or specifications) to compare\n"
+);
 break;
 case 'f':
 fmt1 = optarg;
-- 
2.39.2




[PATCH 21/23] qemu-img: refresh options/--help for "measure" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.

Also add -s short option for --size (and remove OPTION_SIZE).
---
 qemu-img.c | 43 +++
 1 file changed, 31 insertions(+), 12 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index db1f80e15d..e2c8855ff5 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -71,7 +71,6 @@ enum {
 OPTION_FLUSH_INTERVAL = 261,
 OPTION_NO_DRAIN = 262,
 OPTION_TARGET_IMAGE_OPTS = 263,
-OPTION_SIZE = 264,
 OPTION_PREALLOCATION = 265,
 OPTION_SHRINK = 266,
 OPTION_SALVAGE = 267,
@@ -5657,15 +5656,6 @@ static void 
dump_json_block_measure_info(BlockMeasureInfo *info)
 
 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;
 BlockDriver *drv;
@@ -5686,12 +5676,41 @@ static int img_measure(const img_cmd_t *ccmd, int argc, 
char **argv)
 int ret = 1;
 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 '?':
+unrecognized_option(ccmd, argv[optind - 1]);
 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 - desired target/output image format (default raw)\n"
+" -s|--size SIZE - measure file size for given image size\n"
+" FILENAME - measure file size required to convert from FILENAME\n"
+" -f|--format - specify format of FILENAME explicitly\n"
+" --image-opts - indicates that FILENAME is a complete image specification\n"
+"  instead of a file name (incompatible with --format)\n"
+" -l|--snapshot SNAPSHOT - use this snapshot in FILENAME as source\n"
+" --output human|json - output format\n"
+" -U|--force-share - open images in shared mode for concurrent access\n"
+);
 break;
 case 'f':
 fmt = optarg;
@@ -5729,7 +5748,7 @@ static int img_measure(const img_cmd_t *ccmd, int argc, 
char **argv)
 case OPTION_OUTPUT:
 output_format = parse_output_format(ccmd, optarg);
 break;
-case OPTION_SIZE:
+case 's':
 {
 int64_t sval;
 
-- 
2.39.2




[PATCH 19/23] qemu-img: refresh options/--help for "bitmap" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.
---
 qemu-img.c | 19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/qemu-img.c b/qemu-img.c
index 3be365cd07..9a0cd05d42 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -5103,7 +5103,24 @@ static int img_bitmap(const img_cmd_t *ccmd, int argc, 
char **argv)
 unrecognized_option(ccmd, 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 GRANULARITY] [--object OBJDEF]\n"
+"  FILENAME BITMAP\n"
+,
+" -f|--format FMT - specify FILENAME format explicitly\n"
+" --image-opts - indicates that FILENAME is a complete image specification\n"
+"  instead of a file name (incompatible with --format)\n"
+" --add - creates BITMAP, enables to record future edits\n"
+"  -g|--granularity GRANULARITY - sets non-default granularity for --add\n"
+" --remove - removes BITMAP\n"
+" --clear - clears BITMAP\n"
+" --enable, --disable - starts and stops recording future edits to BITMAP\n"
+" --merge SRC_FILENAME - merges contents of SRC_FILENAME bitmap into BITMAP\n"
+"  -b|--source-file SRC_FILENAME - select alternative source file for 
--merge\n"
+"  -F|--source-format SRC_FMT - specify format for SRC_FILENAME explicitly\n"
+);
 break;
 case 'b':
 src_filename = optarg;
-- 
2.39.2




[PATCH 23/23] qemu-img: inline list of supported commands, remove qemu-img-cmds.h include

2024-02-09 Thread Michael Tokarev
also add short description to each command and use it in --help

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 42 +++---
 1 file changed, 35 insertions(+), 7 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index d9c5c6078b..e57076738e 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -61,6 +61,7 @@
 typedef struct img_cmd_t {
 const char *name;
 int (*handler)(const struct img_cmd_t *ccmd, int argc, char **argv);
+const char *description;
 } img_cmd_t;
 
 enum {
@@ -130,11 +131,12 @@ static G_NORETURN
 void cmd_help(const img_cmd_t *ccmd,
   const char *syntax, const char *arguments)
 {
-printf("qemu-img %s %s"
+printf("qemu-img %s: %s.  Usage:\n"
+   "qemu-img %s %s"
"Arguments:\n"
" -h|--help - print this help and exit\n"
"%s",
-   ccmd->name, syntax, arguments);
+   ccmd->name, ccmd->description, ccmd->name, syntax, arguments);
 exit(EXIT_SUCCESS);
 }
 
@@ -5746,10 +5748,36 @@ 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, },
 };
 
@@ -5813,7 +5841,7 @@ QEMU_IMG_VERSION
 "   [[enable=]][,events=][,file=]\n"
 "Recognized commands (run qemu-img command --help for command-specific 
help):\n");
 for (cmd = img_cmds; cmd->name != NULL; cmd++) {
-printf("  %s\n", cmd->name);
+printf("  %s - %s\n", cmd->name, cmd->description);
 }
 c = printf("Supported image formats:");
 bdrv_iterate_format(format_print, , false);
-- 
2.39.2




[PATCH 06/23] qemu-img: refresh options/--help for "commit" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/qemu-img.c b/qemu-img.c
index ad7fa033b1..eabf45c423 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1029,8 +1029,15 @@ static int img_commit(const img_cmd_t *ccmd, int argc, 
char **argv)
 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},
+{"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:",
@@ -1046,7 +1053,23 @@ static int img_commit(const img_cmd_t *ccmd, int argc, 
char **argv)
 unrecognized_option(ccmd, 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 - quiet operations\n"
+" -p|--progress - show operation progress\n"
+" -f|--format FMT - specify FILENAME image format explicitly\n"
+" --image-opts - indicates that FILENAME is a complete image specification\n"
+"  instead of a file name (incompatible with --format)\n"
+" -t|--cache CACHE_MODE cache mode when opening image (" BDRV_DEFAULT_CACHE 
")\n"
+" -d|--drop - skip emptying FILENAME on completion\n"
+" -b|--base BASE_IMG - image in the backing chain to which to commit\n"
+"  changes instead of the previous one (implies --drop)\n"
+" -r|--rate RATE - I/O rate limit\n"
+" --object OBJDEF - QEMU user-creatable object (eg encryption key)\n"
+" FILENAME - name of the image file to operate on\n"
+);
 break;
 case 'f':
 fmt = optarg;
-- 
2.39.2




[PATCH 04/23] qemu-img: refresh options/--help for "check" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 19 ++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/qemu-img.c b/qemu-img.c
index 4e962843da..3ae07bfae0 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -792,7 +792,9 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 int option_index = 0;
 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},
 {"object", required_argument, 0, OPTION_OBJECT},
@@ -813,7 +815,22 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 unrecognized_option(ccmd, 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 - quiet operations\n"
+" -f|--format FMT - specifies format of the image explicitly\n"
+" --image-opts - indicates that FILENAME is a complete image specification\n"
+"  instead of a file name (incompatible with --format)\n"
+" -T|--cache CACHE_MODE - cache mode when opening image (" BDRV_DEFAULT_CACHE 
")\n"
+" -U|--force-share - open image in shared mode for concurrent access\n"
+" --output human|json - output format\n"
+" -r|--repair leaks|all - repair particular aspect of the image\n"
+"  (image will be open in read-write mode, incompatible with --force-share)\n"
+" --object OBJDEF - QEMU user-creatable object (eg encryption key)\n"
+" FILENAME - the image file (or image specification) to operate on\n"
+);
 break;
 case 'f':
 fmt = optarg;
-- 
2.39.2




[PATCH 17/23] qemu-img: refresh options/--help for "amend" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.
---
 qemu-img.c | 18 +-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/qemu-img.c b/qemu-img.c
index e552401074..f598eba3a8 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4493,7 +4493,12 @@ static int img_amend(const img_cmd_t *ccmd, int argc, 
char **argv)
 for (;;) {
 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}
@@ -4512,7 +4517,18 @@ static int img_amend(const img_cmd_t *ccmd, int argc, 
char **argv)
 unrecognized_option(ccmd, 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 - quiet operation\n"
+" -p|--progres - show progress\n"
+" -f|--format FMT - specify FILENAME format explicitly\n"
+" --image-opts - indicates that FILENAME is a complete image specification\n"
+"  instead of a file name (incompatible with --format)\n"
+" -t|--cache CACHE - cache mode for FILENAME (" BDRV_DEFAULT_CACHE ")\n"
+" --force - allow certain unsafe operations\n" 
+);
 break;
 case 'o':
 if (accumulate_options(, optarg) < 0) {
-- 
2.39.2




[PATCH 05/23] qemu-img: simplify --repair error message

2024-02-09 Thread Michael Tokarev
Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 3ae07bfae0..ad7fa033b1 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -843,8 +843,8 @@ static int img_check(const img_cmd_t *ccmd, int argc, char 
**argv)
 } else if (!strcmp(optarg, "all")) {
 fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
 } else {
-error_exit(ccmd, "Unknown option value for -r "
-   "(expecting 'leaks' or 'all'): %s", optarg);
+error_exit(ccmd,
+   "--repair expects 'leaks' or 'all' not '%s'", 
optarg);
 }
 break;
 case OPTION_OUTPUT:
-- 
2.39.2




[PATCH 18/23] qemu-img: refresh options/--help for "bench" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.
---
 qemu-img.c | 36 ++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index f598eba3a8..3be365cd07 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4781,9 +4781,19 @@ static int img_bench(const img_cmd_t *ccmd, int argc, 
char **argv)
 for (;;) {
 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}
@@ -4802,7 +4812,29 @@ static int img_bench(const img_cmd_t *ccmd, int argc, 
char **argv)
 unrecognized_option(ccmd, 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 - quiet operations\n"
+" -f|--format FMT - specify FILENAME format explicitly\n"
+" --image-opts - indicates that FILENAME is a complete image specification\n"
+"  instead of a file name (incompatible with --format)\n"
+" -t|--cache CACHE - cache mode for FILENAME (" BDRV_DEFAULT_CACHE ")\n"
+" -c|--count COUNT - number of I/O requests to perform\n"
+" -s|--buffer-size BUFFER_SIZE - size of each I/O request\n"
+" -d|--depth DEPTH - number of requests to perform in parallel\n"
+" -o|--offset OFFSET - start first request at this OFFSET\n"
+" -S|--step-size STEP_SIZE - each next request offset increment\n"
+" -i|--aio AIO - async-io backend (threads, native, io_uring)\n"
+" -n|--native - use native AIO backend if possible\n"
+" -w|--write - perform write test (default is read)\n"
+" --pattern PATTERN - write this pattern instead of zeros\n"
+" --flush-interval FLUSH_INTERVAL - issue flush after this number of 
requests\n"
+" --no-drain - do not wait when flushing pending requests\n"
+" -U|--force-share - open images in shared mode for concurrent access\n"
+);
 break;
 case 'c':
 {
-- 
2.39.2




[PATCH 20/23] qemu-img: refresh options/--help for "dd" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.
---
 qemu-img.c | 29 ++---
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 9a0cd05d42..db1f80e15d 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -5417,6 +5417,8 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char 
**argv)
 const struct option long_options[] = {
 { "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'},
 { 0, 0, 0, 0 }
@@ -5427,12 +5429,6 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char 
**argv)
 break;
 }
 switch (c) {
-case 'O':
-out_fmt = optarg;
-break;
-case 'f':
-fmt = optarg;
-break;
 case ':':
 missing_argument(ccmd, argv[optind - 1]);
 break;
@@ -5440,7 +5436,26 @@ static int img_dd(const img_cmd_t *ccmd, int argc, char 
**argv)
 unrecognized_option(ccmd, argv[optind - 1]);
 break;
 case 'h':
-help();
+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 - specify format for INPUT explicitly\n"
+" --image-opts - indicates that INPUT is a complete image specification\n"
+"  instead of a file name (incompatible with --format)\n"
+" -O|--output-format OUTPUT_FMT - format of the OUTPUT (default raw)\n"
+" -U|--force-share - open images in shared mode for concurrent access\n"
+" bs=BLOCK_SIZE - size of I/O block (default 512)\n"
+" count=COUNT - number of blocks to convert (default whole INPUT)\n"
+" if=INPUT - input file name or image specification (with --image-opts)\n"
+" of=OUTPUT - output file name to create\n"
+);
+break;
+case 'O':
+out_fmt = optarg;
+break;
+case 'f':
+fmt = optarg;
 break;
 case 'U':
 force_share = true;
-- 
2.39.2




[PATCH 22/23] qemu-img: implement short --help, remove global help() function

2024-02-09 Thread Michael Tokarev
now once all individual subcommands has --help support, remove
the large unreadable help() thing and replace it with small
global --help, which refers to individual command --help for
more info.

While at it, also line-wrap list of formats after 74 chars.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 148 +++--
 1 file changed, 30 insertions(+), 118 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index e2c8855ff5..d9c5c6078b 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -94,11 +94,6 @@ typedef enum OutputFormat {
 /* Default to cache=writeback as data integrity is not important for qemu-img 
*/
 #define BDRV_DEFAULT_CACHE "writeback"
 
-static void format_print(void *opaque, const char *name)
-{
-printf(" %s", name);
-}
-
 static G_NORETURN G_GNUC_PRINTF(2, 3)
 void error_exit(const img_cmd_t *ccmd, const char *fmt, ...)
 {
@@ -154,114 +149,6 @@ static OutputFormat parse_output_format(const img_cmd_t 
*ccmd, const char *arg)
 }
 }
 
-/* Please keep in synch with docs/tools/qemu-img.rst */
-static G_NORETURN
-void help(void)
-{
-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=]][,events=][,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"
-   "   conversi

[PATCH 16/23] qemu-img: refresh options/--help for "resize" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.
---
 qemu-img.c | 19 +--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 929a25a021..e552401074 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4283,7 +4283,9 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 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},
 {"shrink", no_argument, 0, OPTION_SHRINK},
@@ -4302,8 +4304,21 @@ static int img_resize(const img_cmd_t *ccmd, int argc, 
char **argv)
 unrecognized_option(ccmd, argv[optind - 1]);
 break;
 case 'h':
-help();
-break;
+cmd_help(ccmd,
+"[-f FMT | --image-opts] [--preallocation PREALLOC] [--shrink]\n"
+"  [--object OBJECTDEF] [-q] FILENAME [+|-]SIZE\n"
+,
+" -q|--quiet - quiet operation\n"
+" -f|--format FMT - specify FILENAME format explicitly\n"
+" --image-opts - indicates that FILENAME is a complete image specification\n"
+"  instead of a file name (incompatible with --format)\n"
+" --shrink - allow operation when new size is smaller than original\n"
+" --preallocation PREALLOC - specify preallocation type for the new areas\n"
+" --object OBJDEF - QEMU user-creatable object (eg encryption key)\n"
+" FILENAME - image file (specification) to resize\n"
+" SIZE - new image size or amount by which to shrink/grow\n"
+);
+return 0;
 case 'f':
 fmt = optarg;
 break;
-- 
2.39.2




[PATCH 02/23] qemu-img: refresh options/--help for "create" subcommand

2024-02-09 Thread Michael Tokarev
Add missing long options (eg --format).

Create helper function cmd_help() to display command-specific
help text, and use it to print --help for 'create' subcommand.

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 45 -
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/qemu-img.c b/qemu-img.c
index 05f80b6e5b..7edfc56572 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -126,6 +126,25 @@ void unrecognized_option(const img_cmd_t *ccmd, const char 
*option)
 error_exit(ccmd, "unrecognized option '%s'", option);
 }
 
+/*
+ * 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 starting with \t
+ * desrciption is indented by one char
+ */
+static G_NORETURN
+void cmd_help(const img_cmd_t *ccmd,
+  const char *syntax, const char *arguments)
+{
+printf("qemu-img %s %s"
+   "Arguments:\n"
+   " -h|--help - print this help and exit\n"
+   "%s",
+   ccmd->name, syntax, arguments);
+exit(EXIT_SUCCESS);
+}
+
 /* Please keep in synch with docs/tools/qemu-img.rst */
 static G_NORETURN
 void help(void)
@@ -524,7 +543,13 @@ static int img_create(const img_cmd_t *ccmd, int argc, 
char **argv)
 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'},
+{"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",
@@ -540,7 +565,25 @@ static int img_create(const img_cmd_t *ccmd, int argc, 
char **argv)
 unrecognized_option(ccmd, 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 - quiet operations\n"
+" -f|--format FMT - specifies format of the new image, default is raw\n"
+" -o|--options FMT_OPTS - format-specific options ('-o list' for list)\n"
+" -b|--backing BACKING_FILENAME - stack new image on top of BACKING_FILENAME\n"
+"  (for formats which support stacking)\n"
+" -F|--backing-format BACKING_FMT - specify format of BACKING_FILENAME\n"
+" -u|--backing-unsafe - do not fail if BACKING_FMT can not be read\n"
+" --object OBJDEF - QEMU user-creatable object (eg encryption key)\n"
+" FILENAME - image file to create.  It will be overriden if exists\n"
+" SIZE - image size with optional suffix: 'b' (byte, default), 'k' or\n"
+"  'K' (kilobyte, 1024b), 'M' (megabyte, 1024K), 'G' (gigabyte, 1024M),\n"
+"  'T' (terabyte, 1024G), 'P' (petabyte, 1024T), or 'E' (exabyte, 1024P)\n"
+"  SIZE is required unless BACKING_IMG is specified, in which case\n"
+"  it will be the same as size of BACKING_IMG\n"
+);
 break;
 case 'F':
 base_fmt = optarg;
-- 
2.39.2




[PATCH 10/23] qemu-img: refresh options/--help for "map" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.
---
 qemu-img.c | 15 ++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/qemu-img.c b/qemu-img.c
index a1a0ba99f0..5af0b8ec18 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3425,7 +3425,20 @@ static int img_map(const img_cmd_t *ccmd, int argc, char 
**argv)
 unrecognized_option(ccmd, 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 - specify FILENAME image format explicitly\n"
+" --image-opts - 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 - specify output format name (default human)\n"
+" -U|--force-share - open image in shared mode for concurrent access\n"
+" --object OBJDEF - QEMU user-creatable object (eg encryption key)\n"
+" FILENAME - image file name (or specification with --image-opts)\n"
+);
 break;
 case 'f':
 fmt = optarg;
-- 
2.39.2




[PATCH 11/23] qemu-img: allow specifying -f fmt for snapshot subcommand

2024-02-09 Thread Michael Tokarev
For consistency with other commands, and since it already
accepts --image-opts, allow specifying -f fmt too.

Signed-off-by: Michael Tokarev 
---
 docs/tools/qemu-img.rst | 2 +-
 qemu-img-cmds.hx| 4 ++--
 qemu-img.c  | 9 ++---
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
index 3653adb963..9b628c4da5 100644
--- a/docs/tools/qemu-img.rst
+++ b/docs/tools/qemu-img.rst
@@ -663,7 +663,7 @@ Command description:
   bitmap support, or 0 if bitmaps are supported but there is nothing
   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
index c9dd70a892..2c5a8a28f9 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -84,9 +84,9 @@ SRST
 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
 
 DEF("rebase", img_rebase,
diff --git a/qemu-img.c b/qemu-img.c
index 5af0b8ec18..1e09b78d00 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3540,7 +3540,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 BlockBackend *blk;
 BlockDriverState *bs;
 QEMUSnapshotInfo sn;
-char *filename, *snapshot_name = NULL;
+char *filename, *fmt = NULL, *snapshot_name = NULL;
 int c, ret = 0, bdrv_oflags;
 int action = 0;
 bool quiet = false;
@@ -3559,7 +3559,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 {"force-share", no_argument, 0, 'U'},
 {0, 0, 0, 0}
 };
-c = getopt_long(argc, argv, ":la:c:d:hqU",
+c = getopt_long(argc, argv, ":la:c:d:fhqU",
 long_options, NULL);
 if (c == -1) {
 break;
@@ -3574,6 +3574,9 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 case 'h':
 help();
 return 0;
+case 'f':
+fmt = optarg;
+break;
 case 'l':
 if (action) {
 error_exit(ccmd, "Cannot mix '-l', '-a', '-c', '-d'");
@@ -3627,7 +3630,7 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 filename = argv[optind++];
 
 /* Open the image */
-blk = img_open(image_opts, filename, NULL, bdrv_oflags, false, quiet,
+blk = img_open(image_opts, filename, fmt, bdrv_oflags, false, quiet,
force_share);
 if (!blk) {
 return 1;
-- 
2.39.2




[PATCH 13/23] qemu-img: refresh options/--help for "snapshot" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.
---
 qemu-img.c | 26 --
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index d9dfff2f07..67e6a7797d 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3553,9 +3553,15 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 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, 'l'},
+{"apply", no_argument, 0, 'a'},
+{"create", no_argument, 0, 'c'},
+{"delete", no_argument, 0, 'd'},
 {0, 0, 0, 0}
 };
 c = getopt_long(argc, argv, ":la:c:d:fhqU",
@@ -3571,8 +3577,24 @@ static int img_snapshot(const img_cmd_t *ccmd, int argc, 
char **argv)
 unrecognized_option(ccmd, argv[optind - 1]);
 break;
 case 'h':
-help();
-return 0;
+cmd_help(ccmd,
+"[-f FMT | --image-opts] [-l | -a|-c|-d SNAPSHOT]\n"
+"  [-U] [--object OBJDEF] FILENAME\n"
+,
+" -q|--quiet - quiet operations\n"
+" -f|--format FMT - specify FILENAME format explicitly\n"
+" --image-opts - indicates that FILENAME is a complete image specification\n"
+"  instead of a file name (incompatible with --format)\n"
+" -U|--force-share - open image in shared mode for concurrent access\n"
+" --object OBJDEF - QEMU user-creatable object (eg encryption key)\n"
+" Operation, one of:\n"
+"  -l|--list - list snapshots in FILENAME (the default)\n"
+"  -c|--create SNAPSHOT - create named snapshot\n"
+"  -a|--apply SNAPSHOT - apply named snapshot to the base\n"
+"  -d|--delete SNAPSHOT - delete named snapshot\n"
+" FILENAME - image file name (or specification with --image-opts)\n"
+);
+break;
 case 'f':
 fmt = optarg;
 break;
-- 
2.39.2




[PATCH 08/23] qemu-img: refresh options/--help for "convert" command

2024-02-09 Thread Michael Tokarev
Add missing long options and --help output.

convert uses -B for --backing, - why not -b?

Signed-off-by: Michael Tokarev 
---
 qemu-img.c | 52 +++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/qemu-img.c b/qemu-img.c
index 8f16ee9deb..d4dafebff9 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -2374,14 +2374,29 @@ static int img_convert(const img_cmd_t *ccmd, int argc, 
char **argv)
 for(;;) {
 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},
 {"salvage", no_argument, 0, OPTION_SALVAGE},
 {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO},
 {"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:",
@@ -2397,7 +2412,42 @@ static int img_convert(const img_cmd_t *ccmd, int argc, 
char **argv)
 unrecognized_option(ccmd, argv[optind - 1]);
 break;
 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 - quiet operations\n"
+" -p|--progress - show operation progress\n"
+" -f|--source-format SRC_FMT - specify SRC_FILENAME source image format 
explicitly\n"
+" --source-image-opts - 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 - specify source snapshot parameters\n"
+" -T|--source-cache SRC_CACHE - cache mode when opening source image (" 
BDRV_DEFAULT_CACHE ")\n"
+" -O|--target-format TGT_FMT - specify TGT_FILENAME image format (default is 
raw)\n"
+" --target-image-opts - 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 - TARGET_FMT-specific options\n"
+" -c|--compress - create compressed output image (qcow and qcow2 format 
only)\n"
+" -t|--target-cache TGT_CACHE - cache mode when opening output image 
(unsafe)\n"
+" -B|--backing BACKING_FILENAME - create output to be a CoW on top of 
BACKING_FILENAME\n"
+" -F|--backing-format BACKING_FMT - specify BACKING_FILENAME image format 
explicitly\n"
+" -n|--no-create - omit target volume creation (eg on rbd)\n"
+" --target-is-zero\n"
+" -S|--sparse-size SPARSE_SIZE\n"
+" --bitmaps - also copy any persistent bitmaps present in source\n"
+" --skip-broken-bitmaps - skip (do not error out) any broken bitmaps\n"
+" -U|--force-share - open images in shared mode for concurrent access\n"
+" -r|--rate RATE - I/O rate limit\n"
+" -m|--parallel NUM_COROUTINES - specify parallelism (default 8)\n"
+" -C|--copy-range-offloading - use copy_range offloading\n"
+" --salvage\n"
+" -W|--oob-writes - enable out-of-order writes to improve performance\n"
+" --object OBJDEF - QEMU user-creatable object (eg encryption key)\n"
+" SRC_FILENAME - source image file name (or specification with --image-opts)\n"
+" TGT_FILENAME - target (output) image file name\n"
+);
 break;
 case 'f':
 fmt = optarg;
-- 
2.39.2




  1   2   3   >