diff mbox series

[v3] qemu-img.c: add help for each command

Message ID 20180925153949.1577-1-programmingkidx@gmail.com (mailing list archive)
State New, archived
Headers show
Series [v3] qemu-img.c: add help for each command | expand

Commit Message

Programmingkid Sept. 25, 2018, 3:39 p.m. UTC
Add the ability for the user to display help for a certain command. 
Example: qemu-img create --help

What is printed is all the options available to this command and an example.

Signed-off-by: John Arbuckle <programmingkidx@gmail.com>
---
v3 changes:
Fixed a bug that caused qemu-img to crash when running a command without
options.

v2 changes:
Removed block of string comparison code for each command.
Added a help_func field to the img_cmd_t struct.
Made strings longer than 80 characters wide.

 qemu-img.c | 660 +++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 559 insertions(+), 101 deletions(-)

Comments

Murilo Opsfelder Araújo Sept. 25, 2018, 4:46 p.m. UTC | #1
Hi, John.

On Tue, Sep 25, 2018 at 11:39:49AM -0400, John Arbuckle wrote:
> Add the ability for the user to display help for a certain command.
> Example: qemu-img create --help
>
> What is printed is all the options available to this command and an example.
>
> Signed-off-by: John Arbuckle <programmingkidx@gmail.com>

Segfault is gone with this patch.

Acked-by: Murilo Opsfelder Araujo <muriloo@linux.ibm.com>

> ---
> v3 changes:
> Fixed a bug that caused qemu-img to crash when running a command without
> options.
>
> v2 changes:
> Removed block of string comparison code for each command.
> Added a help_func field to the img_cmd_t struct.
> Made strings longer than 80 characters wide.
>
>  qemu-img.c | 660 +++++++++++++++++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 559 insertions(+), 101 deletions(-)
>
> diff --git a/qemu-img.c b/qemu-img.c
> index 1acddf693c..e4d9baa550 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -52,6 +52,7 @@
>  typedef struct img_cmd_t {
>      const char *name;
>      int (*handler)(int argc, char **argv);
> +    void (*help_func)(void);
>  } img_cmd_t;
>
>  enum {
> @@ -76,11 +77,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 void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
>  {
>      va_list ap;
> @@ -105,102 +101,546 @@ static void QEMU_NORETURN unrecognized_option(const char *option)
>      error_exit("unrecognized option '%s'", option);
>  }
>
> -/* Please keep in synch with qemu-img.texi */
> -static void QEMU_NORETURN help(void)
> +/* Prints an overview of available help options */
> +static 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=]<pattern>][,events=<file>][,file=<file>]\n"
> -           "                         specify tracing options\n"
> -           "\n"
> -           "Command syntax:\n"
> -#define DEF(option, callback, arg_string)        \
> -           "  " arg_string "\n"
> -#include "qemu-img-cmds.h"
> -#undef DEF
> -           "\n"
> -           "Command parameters:\n"
> -           "  'filename' is a disk image filename\n"
> -           "  'objectdef' is a QEMU user creatable object definition. See the qemu(1)\n"
> -           "    manual page for a description of the object properties. The most common\n"
> -           "    object type is a 'secret', which is used to supply passwords and/or\n"
> -           "    encryption keys.\n"
> -           "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
> -           "  'cache' is the cache mode used to write the output disk image, the valid\n"
> -           "    options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
> -           "    'directsync' and 'unsafe' (default for convert)\n"
> -           "  'src_cache' is the cache mode used to read input disk images, the valid\n"
> -           "    options are the same as for the 'cache' option\n"
> -           "  'size' is the disk image size in bytes. Optional suffixes\n"
> -           "    'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M),\n"
> -           "    'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E' (exabyte, 1024P)  are\n"
> -           "    supported. 'b' is ignored.\n"
> -           "  'output_filename' is the destination disk image filename\n"
> -           "  'output_fmt' is the destination format\n"
> -           "  'options' is a comma separated list of format specific options in a\n"
> -           "    name=value format. Use -o ? for an overview of the options supported by the\n"
> -           "    used format\n"
> -           "  'snapshot_param' is param used for internal snapshot, format\n"
> -           "    is 'snapshot.id=[ID],snapshot.name=[NAME]', or\n"
> -           "    '[ID_OR_NAME]'\n"
> -           "  '-c' indicates that target image must be compressed (qcow format only)\n"
> -           "  '-u' allows unsafe backing chains. For rebasing, it is assumed that old and\n"
> -           "       new backing file match exactly. The image doesn't need a working\n"
> -           "       backing file before rebasing in this case (useful for renaming the\n"
> -           "       backing file). For image creation, allow creating without attempting\n"
> -           "       to open the backing file.\n"
> -           "  '-h' with or without a command shows this help and lists the supported formats\n"
> -           "  '-p' show progress of command (only certain commands)\n"
> -           "  '-q' use Quiet mode - do not print any output (except errors)\n"
> -           "  '-S' indicates the consecutive number of bytes (defaults to 4k) that must\n"
> -           "       contain only zeros for qemu-img to create a sparse image during\n"
> -           "       conversion. If the number of bytes is 0, the source will not be scanned for\n"
> -           "       unallocated or zero sectors, and the destination image will always be\n"
> -           "       fully allocated\n"
> -           "  '--output' takes the format in which the output must be done (human or json)\n"
> -           "  '-n' skips the target volume creation (useful if the volume is created\n"
> -           "       prior to running qemu-img)\n"
> -           "\n"
> -           "Parameters to check subcommand:\n"
> -           "  '-r' tries to repair any inconsistencies that are found during the check.\n"
> -           "       '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all\n"
> -           "       kinds of errors, with a higher risk of choosing the wrong fix or\n"
> -           "       hiding corruption that has already occurred.\n"
> -           "\n"
> -           "Parameters to convert subcommand:\n"
> -           "  '-m' specifies how many coroutines work in parallel during the convert\n"
> -           "       process (defaults to 8)\n"
> -           "  '-W' allow to write to the target out of order rather than sequential\n"
> -           "\n"
> -           "Parameters to snapshot subcommand:\n"
> -           "  'snapshot' is the name of the snapshot to create, apply or delete\n"
> -           "  '-a' applies a snapshot (revert disk to saved state)\n"
> -           "  '-c' creates a snapshot\n"
> -           "  '-d' deletes a snapshot\n"
> -           "  '-l' lists all snapshots in the given image\n"
> -           "\n"
> -           "Parameters to compare subcommand:\n"
> -           "  '-f' first image format\n"
> -           "  '-F' second image format\n"
> -           "  '-s' run in Strict mode - fail on different image size or sector allocation\n"
> -           "\n"
> -           "Parameters to dd subcommand:\n"
> -           "  'bs=BYTES' read and write up to BYTES bytes at a time "
> -           "(default: 512)\n"
> -           "  'count=N' copy only N input blocks\n"
> -           "  'if=FILE' read from FILE\n"
> -           "  'of=FILE' write to FILE\n"
> -           "  'skip=N' skip N bs-sized blocks at the start of input\n";
> -
> -    printf("%s\nSupported formats:", help_msg);
> -    bdrv_iterate_format(format_print, NULL);
> -    printf("\n\n" QEMU_HELP_BOTTOM "\n");
> -    exit(EXIT_SUCCESS);
> +    QEMU_IMG_VERSION
> +    "usage: qemu-img [standard options] command [command options]\n"
> +    "QEMU disk image utility\n"
> +    "\n"
> +    "    '-h', '--help'       display this help and exit\n"
> +    "    '-V', '--version'    output version information and exit\n"
> +    "    '-T', '--trace'      [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
> +    "                         specify tracing options\n"
> +    "\n"
> +    "Command:\n"
> +    "\tamend              Change options of an existing disk image\n"
> +    "\tbench              Run benchmarks on a given disk image\n"
> +    "\tcheck              Check the disk image for consistency or repair it\n"
> +    "\tcommit             Merge the disk image into its backing file\n"
> +    "\tcompare            Check if two images have the same content\n"
> +    "\tconvert            Convert an image file or snapshot into another file\n"
> +    "\tcreate             Create a new disk image\n"
> +    "\tdd                 Copies and converts an input file into another file\n"
> +    "\tinfo               Gives information about the specified image file\n"
> +    "\tmap                Dump the metadata of image filename\n"
> +    "\tmeasure            Calculate the file size required for a new image\n"
> +    "\tsnapshot           List, apply, create or delete snapshots in a file\n"
> +    "\trebase             Changes the backing file of an image file\n"
> +    "\tresize             Resize an image file\n"
> +    "\n\nRun 'qemu-img <command> --help' for details.\n"
> +    "See <https://qemu.org/contribute/report-a-bug> for how to report bugs.\n"
> +    "More information on the QEMU project at <https://qemu.org>.\n";
> +    printf("%s\n", help_msg);
> +}
> +
> +static void help_amend(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt]\n"
> +    "[-t cache] -o options filename\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -f             The format of the image file.\n"
> +    "\n"
> +    "--image-opts    Treat filename as a set of image options, instead of a plain\n"
> +    "                filename.\n"
> +    "\n"
> +    " -o             Used with a comma separated list of format specific options in a\n"
> +    "                name=value format. Use \"-o help\" for an overview of the options\n"
> +    "                supported by the used format.\n"
> +    "\n"
> +    "--object        \'objectdef\' is a QEMU user creatable object definition. See the\n"
> +    "                qemu(1) manual page for a description of the object properties.\n"
> +    "                The most common object type is a \'secret\', which is used to\n"
> +    "                supply passwords and/or encryption keys.\n"
> +    "\n"
> +    " -p             Display progress bar. If the -p option is not used for a command\n"
> +    "                that supports it, the progress is reported when the process\n"
> +    "                receives a \"SIGUSR1\" signal. Avoid using with the -q option.\n"
> +    "\n"
> +    " -q             Quiet mode - do not print any output (except errors). Avoid\n"
> +    "                using with the -p option.\n"
> +    "\n"
> +    " -t             Specifies the cache mode that should be used with the\n"
> +    "                destination file. Options are: none, writeback, writethrough,\n"
> +    "                directsync, and unsafe.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img amend -o compat=v3 -f qcow2 image.qcow2\n"
> +    "    qemu-img amend --object secret,id=sec0,data=test --image-opts \\\n"
> +    "    driver=luks,key-secret=sec0,file.filename=test.luks -o size=2G\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_bench(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img bench [-c count] [-d depth] [-f fmt]\n"
> +    "[--flush-interval=flush_interval] [-n] [--no-drain] [-o offset]\n"
> +    "[--pattern=pattern] [-q] [-s buffer_size] [-S step_size] [-t cache] [-w] [-U]\n"
> +    "filename\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -c                  Number of I/O requests to perform.\n"
> +    "\n"
> +    " -d                  Number of I/O requests done in parallel.\n"
> +    "\n"
> +    " -f                  The format of the image file.\n"
> +    "\n"
> +    " --flush-interval    How often a flush should take place.\n"
> +    "\n"
> +    " -n                  Use native AIO backend if possible.\n"
> +    "\n"
> +    " --no-drain          Issue a flush without draining the request queue first.\n"
> +    "\n"
> +    " -o                  The starting position.\n"
> +    "\n"
> +    " --pattern           The byte pattern used to in write tests.\n"
> +    "\n"
> +    " -q                  Quiet mode - do not print any output (except errors).\n"
> +    "                     There\'s no progress bar in case both -q and -p options are\n"
> +    "                     used.\n"
> +    "\n"
> +    " -s                  buffer_size in bytes.\n"
> +    "\n"
> +    " -S                  Increases current position by step_size.\n"
> +    "\n"
> +    " -t                  Specifies the cache mode that should be used with the\n"
> +    "                     destination file.  Options are: none, writeback,\n"
> +    "                     writethrough, directsync, and unsafe.\n"
> +    "\n"
> +    " -w                  Perform write test.\n"
> +    "\n"
> +    " -U                  Open the image in shared mode, allowing other QEMU\n"
> +    "                     processes to open it in write mode. This option is only\n"
> +    "                     allowed when opening images in read-only mode.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img bench -c 20000 -d 50000 -f qcow2 image.qcow2\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_check(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img check [--object objectdef] [--image-opts] [-q] [-f fmt]\n"
> +    "[--output=ofmt] [-r [leaks | all]] [-T src_cache] [-U] filename\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -f         The format of the image file.\n"
> +    "\n"
> +    " -q         Use Quiet mode - do not print any output (except errors).\n"
> +    "\n"
> +    " -r         Tries to repair any inconsistencies that are found during the check.\n"
> +    "            \'-r leaks\' repairs only cluster leaks, whereas \'-r all\' fixes all\n"
> +    "            kinds of errors, with a higher risk of choosing the wrong fix or\n"
> +    "            hiding corruption that has already occurred.\n"
> +    "\n"
> +    " -T         \'src_cache\' is the cache mode used to read input disk images, the\n"
> +    "            valid options are the same as for the \'cache\' option. Options are:\n"
> +    "            none, writeback, writethrough, directsync, and unsafe.\n"
> +    "\n"
> +    " --object   \'objectdef\' is a QEMU user creatable object definition. See the\n"
> +    "            qemu(1) manual page for a description of the object properties. The\n"
> +    "            most common object type is a \'secret\', which is used to supply\n"
> +    "            passwords and/or encryption keys.\n"
> +    "\n"
> +    " --output   \'ofmt\' is \'human\' for human-readable output (default) or \'json\' for\n"
> +    "            JSON output.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img check image.qcow2\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_commit(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img commit [--object objectdef] [--image-opts] [-q] [-f fmt]\n"
> +    "[-t cache] [-b base] [-d] [-p] filename\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -b            The base image or backing file.\n"
> +    "\n"
> +    " -d            Skip emptying filename.\n"
> +    "\n"
> +    " -f            The format of the image file.\n"
> +    "\n"
> +    " --image-opts  Treat filename as a set of image options, instead of a plain\n"
> +    "               filename.\n"
> +    "\n"
> +    " --object      \'objectdef\' is a QEMU user creatable object definition. See the\n"
> +    "               qemu(1) manual page for a description of the object properties.\n"
> +    "               The most common object type is a \'secret\', which is used to\n"
> +    "               supply passwords and/or encryption keys.\n"
> +    "\n"
> +    " -p            Display progress bar. If the -p option is not used for a command\n"
> +    "               that supports it, the progress is reported when the process\n"
> +    "               receives a \"SIGUSR1\" signal.\n"
> +    "\n"
> +    " -q            Quiet mode - do not print any output (except errors). There\'s no\n"
> +    "               progress bar in case both -q and -p options are used.\n"
> +    "\n"
> +    " -t            Specifies the cache mode that should be used with the\n"
> +    "               destination file.  Options are: none, writeback, writethrough,\n"
> +    "               directsync, and unsafe.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img commit image.qcow2\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_compare(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img compare [--object objectdef] [--image-opts] [-f fmt] [-F fmt]\n"
> +    "[-T src_cache] [-p] [-q] [-s] [-U] filename1 filename2\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -f                 First image\'s format.\n"
> +    "\n"
> +    " -F                 Second image\'s format.\n"
> +    "\n"
> +    " --image-opts       Treat filename as a set of image options, instead of a plain\n"
> +    "                    filename.\n"
> +    "\n"
> +    " -T                 Specifies the cache mode that should be used with the source\n"
> +    "                    file. Options are: none, writeback, writethrough,\n"
> +    "                    directsync, and unsafe.\n"
> +    "\n"
> +    " --object           \'objectdef\' is a QEMU user creatable object definition. See\n"
> +    "                    the qemu(1) manual page for a description of the object\n"
> +    "                    properties. The most common object type is a \'secret\', which\n"
> +    "                    is used to supply passwords and/or encryption keys.\n"
> +    "\n"
> +    " -p                 Display progress bar. If the -p option is not used for a\n"
> +    "                    command that supports it, the progress is reported when the\n"
> +    "                    process receives a \"SIGUSR1\" signal.\n"
> +    "\n"
> +    " -q                 Quiet mode - do not print any output (except errors).\n"
> +    "                    There\'s no progress bar in case both -q and -p options are\n"
> +    "                    used.\n"
> +    "\n"
> +    " -s                 Enable strict mode. Comparisons differ when image sizes\n"
> +    "                    differ or if a sector is allocated in one image and not\n"
> +    "                    allocated in the other image.\n"
> +    "\n"
> +    " -U                 Open the image in shared mode, allowing other QEMU\n"
> +    "                    processes to open it in write mode. This option is only\n"
> +    "                    allowed when opening images in read-only mode.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img compare image1.qcow image2.qcow2\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_convert(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img convert [--object objectdef] [--image-opts]\n"
> +    "[--target-image-opts] [-U] [-c] [-p] [-q] [-n] [-f fmt] [-t cache]\n"
> +    "[-T src_cache] [-O output_fmt] [-B backing_file] [-o options]\n"
> +    "[-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size]\n"
> +    "[-m num_coroutines] [-W] filename [filename2 [...]] output_filename\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -B                      Force the output image to be created as a copy on write\n"
> +    "                         image of the specified base image.\n"
> +    "\n"
> +    " -c                      Compress the output image file.\n"
> +    "\n"
> +    " -f                      The format of the image file.\n"
> +    "\n"
> +    " --image-opts            Indicates that the source filename parameter is to be\n"
> +    "                         interpreted as a full option string, not a plain\n"
> +    "                         filename.\n"
> +    "\n"
> +    " -l                      Specifies a snapshot parameter.\n"
> +    "\n"
> +    " -m                      Number of parallel coroutines for the convert process\n"
> +    "\n"
> +    " -n                      Skip the creation of the target volume.\n"
> +    "\n"
> +    " -O                      Format of the output file.\n"
> +    "\n"
> +    " -o                      Allows for specifying options like virtual disk size.\n"
> +    "\n"
> +    " --object                \'objectdef\' is a QEMU user creatable object definition.\n"
> +    "                         See the qemu(1) manual page for a description of the\n"
> +    "                         object properties. The most common object type is a\n"
> +    "                         \'secret\', which is used to supply passwords and/or\n"
> +    "                         encryption keys.\n"
> +    "\n"
> +    " -p                      Display progress bar. If the -p option is not used for\n"
> +    "                         a command that supports it, the progress is reported\n"
> +    "                         when the process receives a \"SIGUSR1\" signal.\n"
> +    "\n"
> +    " -q                      Quiet mode - do not print any output (except errors).\n"
> +    "                         There\'s no progress bar in case both -q and -p options\n"
> +    "                         are used.\n"
> +    "\n"
> +    " -S                      The consecutive number of bytes (defaults to 4k) that\n"
> +    "                         must contain only zeros for qemu-img to create a sparse\n"
> +    "                         image during conversion.\n"
> +    "\n"
> +    " -s                      The name or ID of the snapshot to use.\n"
> +    "\n"
> +    " -T                      Specifies the cache mode that should be used with the\n"
> +    "                         source file.\n"
> +    "\n"
> +    " -t                      Specifies the cache mode that should be used with the\n"
> +    "                         destination file. Options are: none, writeback,\n"
> +    "                         writethrough, directsync, and unsafe.\n"
> +    "\n"
> +    "--target-image-opts      Indicates whether the source filename includes options.\n"
> +    "\n"
> +    " -U                      Open the image in shared mode, allowing other QEMU\n"
> +    "                         processes to open it in write mode. This option is only\n"
> +    "                         allowed when opening images in read-only mode.\n"
> +    "\n"
> +    " -W                      Allow out-of-order writes to the destination. This\n"
> +    "                         option improves performance, but is only recommended\n"
> +    "                         for preallocated devices like host devices or other raw\n"
> +    "                         block devices.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img convert -f raw -O qcow2 image.img image.qcow2\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_create(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img create [--object objectdef] [-q] [-f fmt] [-b backing_file]\n"
> +    "[-F backing_fmt] [-u] [-o options] filename [size]\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -b             The backing file used to base the output file on.\n"
> +    "\n"
> +    " -f             The format of the image file.\n"
> +    "\n"
> +    " -F             The format of the backing file.\n"
> +    "\n"
> +    " -u             Create the image file even if the backing file cannot be opened.\n"
> +    "\n"
> +    " -o             Allows for specifying options like virtual disk size.\n"
> +    "\n"
> +    "--object        \'objectdef\' is a QEMU user creatable object definition.\n"
> +    "                See the qemu(1) manual page for a description of the\n"
> +    "                object properties. The most common object type is a\n"
> +    "                \'secret\', which is used to supply passwords and/or\n"
> +    "                encryption keys.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img create -f qcow2 image.qcow2 10G\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_dd(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img dd [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks]\n"
> +    "[skip=blocks] if=input of=output\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " bs                 Size of the blocks used in reading and writing (512 bytes is\n"
> +    "                    the default).\n"
> +    "\n"
> +    " count              The limit to how many blocks to read.\n"
> +    "\n"
> +    " -f                 The format of the image file.\n"
> +    "\n"
> +    " if                 The input file.\n"
> +    "\n"
> +    " -O                 Format of the output file.\n"
> +    "\n"
> +    " of                 The output file.\n"
> +    "\n"
> +    " skip               Number of blocks to skip.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img dd if=/dev/cdrom -O raw of=cd.iso\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_info(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img info [-f fmt] [--output=ofmt] [--backing-chain] filename\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " --backing-chain            Recursively enumerate thru each disk image in the\n"
> +    "                            chain for information.\n"
> +    "\n"
> +    " -f                         The format of the image file.\n"
> +    "\n"
> +    "--output                    The output format of this command. Can be \"human\" or\n"
> +    "                            \"json\".\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img info image.qcow2\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_map(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img map [-f fmt] [--output=ofmt] filename\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -f                 The format of the image file.\n"
> +    "\n"
> +    "--output            The output format of this command. Can be \"human\" or \"json\".\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img map image.qcow2\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_measure(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img measure [--output=ofmt] [-O output_fmt] [-o options] [--size N ]\n"
> +    "[--object objectdef] [--image-opts] [-f fmt] [-l snapshot_param]\n"
> +    "filename\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -f                 The format of the image file.\n"
> +    "\n"
> +    " --image-opts       Indicates that the source filename parameter is to be\n"
> +    "                    interpreted as a full option string, not a plain\n"
> +    "                    filename.\n"
> +    "\n"
> +    " -l                 Specifies a snapshot parameter.\n"
> +    "\n"
> +    " -O                 Format of the output file.\n"
> +    "\n"
> +    " -o                 Allows for specifying options.\n"
> +    "\n"
> +    " --object           \'objectdef\' is a QEMU user creatable object definition. See\n"
> +    "                    the qemu(1) manual page for a description of the object\n"
> +    "                    properties. The most common object type is a \'secret\',\n"
> +    "                    which is used to supply passwords and/or encryption keys.\n"
> +    "\n"
> +    " --output           \'ofmt\' is \'human\' for human-readable output (default) or\n"
> +    "                    \'json\' for JSON output.\n"
> +    "\n"
> +    " --size             If given act as if creating a new empty image file using\n"
> +    "                    qemu-img create.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img measure -O qcow2 --size 5G\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_snapshot(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img snapshot [-l | -a snapshot | -c snapshot | -d snapshot ]\n"
> +    "filename\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -a                 Applies the snapshot.\n"
> +    "\n"
> +    " -c                 Create a snapshot.\n"
> +    "\n"
> +    " -d                 Deletes a snapshot.\n"
> +    "\n"
> +    " -l                 Lists all snapshots\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img snapshot -l image.qcow2\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_rebase(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img rebase [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b\n"
> +    "backing_file [-F backing_fmt] filename\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " -b         The new backing file.\n"
> +    "\n"
> +    " -F         The format for the new backing file.\n"
> +    "\n"
> +    " -f         The format of the image file being rebased.\n"
> +    "\n"
> +    " -T         Specifies the cache mode that should be used with the source file.\n"
> +    "\n"
> +    " -t         Specifies the cache mode that should be used with the destination\n"
> +    "            file. Options are: none, writeback, writethrough, directsync, and\n"
> +    "            unsafe.\n"
> +    "\n"
> +    " -p         Display progress bar. If the -p option is not used for a command\n"
> +    "            that supports it, the progress is reported when the process\n"
> +    "            receives a \"SIGUSR1\" signal.\n"
> +    "\n"
> +    " -u         Operate in unsafe mode.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img rebase -b backing.img diff.qcow2\n"
> +    "\n"
> +    "\n";
> +    printf("%s", msg);
> +}
> +
> +static void help_resize(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img resize [--shrink] [--preallocation=prealloc] filename\n"
> +    "[+ | -] size\n"
> +    "\n"
> +    "Command parameters:\n"
> +    " --preallocation    When growing an image, specify how the additional image\n"
> +    "                    area should be allocated on the host.\n"
> +    "\n"
> +    " --shrink           Informs qemu-img that the user acknowledges all loss of\n"
> +    "                    data beyond the truncated image\'s end.\n"
> +    "\n"
> +    "Example:\n"
> +    "    qemu-img resize image.qcow2 20G\n";
> +    printf("%s", msg);
>  }
>
>  static QemuOptsList qemu_object_opts = {
> @@ -4886,7 +5326,7 @@ out:
>      return ret;
>  }
>
> -static const img_cmd_t img_cmds[] = {
> +static img_cmd_t img_cmds[] = {
>  #define DEF(option, callback, arg_string)        \
>      { option, callback },
>  #include "qemu-img-cmds.h"
> @@ -4894,6 +5334,12 @@ static const img_cmd_t img_cmds[] = {
>      { NULL, NULL, },
>  };
>
> +/* These functions will be added to the img_cmds array */
> +void (*help_functions[])(void) = {help_amend, help_bench, help_check,\
> +    help_commit, help_compare, help_convert, help_create, help_dd, help_info,\
> +    help_map, help_measure, help_snapshot, help_rebase, help_resize};
> +
> +
>  int main(int argc, char **argv)
>  {
>      const img_cmd_t *cmd;
> @@ -4970,10 +5416,22 @@ int main(int argc, char **argv)
>      trace_init_file(trace_file);
>      qemu_set_log(LOG_TRACE);
>
> +    /* Add all the help functions to the array */
> +    int i;
> +    for (i = 0; i < ARRAY_SIZE(help_functions); i++) {
> +        img_cmds[i].help_func = help_functions[i];
> +    }
> +
>      /* find the command */
>      for (cmd = img_cmds; cmd->name != NULL; cmd++) {
>          if (!strcmp(cmdname, cmd->name)) {
> -            return cmd->handler(argc, argv);
> +            if ((argc > (optind + 1)) &&
> +                strcmp("--help", argv[optind + 1]) == 0) {
> +                cmd->help_func();
> +                return 0;
> +            } else {
> +                return cmd->handler(argc, argv);
> +            }
>          }
>      }
>
> --
> 2.14.3 (Apple Git-98)
>

--
Murilo
Programmingkid Sept. 25, 2018, 5:28 p.m. UTC | #2
> On Sep 25, 2018, at 12:46 PM, Murilo Opsfelder Araujo <muriloo@linux.ibm.com> wrote:
> 
> Hi, John.
> 
> On Tue, Sep 25, 2018 at 11:39:49AM -0400, John Arbuckle wrote:
>> Add the ability for the user to display help for a certain command.
>> Example: qemu-img create --help
>> 
>> What is printed is all the options available to this command and an example.
>> 
>> Signed-off-by: John Arbuckle <programmingkidx@gmail.com>
> 
> Segfault is gone with this patch.
> 
> Acked-by: Murilo Opsfelder Araujo <muriloo@linux.ibm.com>

Thank you very much for your help.
Eric Blake Oct. 2, 2018, 9:09 p.m. UTC | #3
On 9/25/18 10:39 AM, John Arbuckle wrote:
> Add the ability for the user to display help for a certain command.
> Example: qemu-img create --help
> 
> What is printed is all the options available to this command and an example.
> 
> Signed-off-by: John Arbuckle <programmingkidx@gmail.com>
> ---
> v3 changes:
> Fixed a bug that caused qemu-img to crash when running a command without
> options.

Hmm, I just reviewed v2 without noticing that you had posted v3.

> 
> v2 changes:
> Removed block of string comparison code for each command.
> Added a help_func field to the img_cmd_t struct.
> Made strings longer than 80 characters wide.
> 
>   qemu-img.c | 660 +++++++++++++++++++++++++++++++++++++++++++++++++++----------
>   1 file changed, 559 insertions(+), 101 deletions(-)

My v2 comment about splitting this into more reviewable portions still 
applies.

> +++ b/qemu-img.c
> @@ -52,6 +52,7 @@
>   typedef struct img_cmd_t {
>       const char *name;
>       int (*handler)(int argc, char **argv);
> +    void (*help_func)(void);
>   } img_cmd_t;

As does my complaint that you want to track the command synopses here in 
this struct for reuse in multiple contexts later, rather than...

> +static void help_amend(void)
> +{
> +    const char *msg =
> +    "\n"
> +    "usage: qemu-img amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt]\n"
> +    "[-t cache] -o options filename\n"

repeating things that are in qemu-img-cmds.h and risking them getting 
out of sync.

>   
> -static const img_cmd_t img_cmds[] = {
> +static img_cmd_t img_cmds[] = {
>   #define DEF(option, callback, arg_string)        \
>       { option, callback },
>   #include "qemu-img-cmds.h"
> @@ -4894,6 +5334,12 @@ static const img_cmd_t img_cmds[] = {
>       { NULL, NULL, },
>   };
>   
> +/* These functions will be added to the img_cmds array */
> +void (*help_functions[])(void) = {help_amend, help_bench, help_check,\
> +    help_commit, help_compare, help_convert, help_create, help_dd, help_info,\
> +    help_map, help_measure, help_snapshot, help_rebase, help_resize};

And my biggest gripe, that this approach to initialization is dead 
wrong, is still applicable.

Overall, I like the end result that you are trying to reach. (I'm not 
always a fan of having to run 'command --help' followed by 'command 
subcommand --help' to learn everything, but it sure beats a wall of 
text, and we have at least 'git' and 'cvs' as examples of programs that 
have used that approach, so we are not inventing something new).  But 
you'll need a v4, and preferably broken up into something easier to 
review (one patch per command, rather than a wholesale rewrite in go), 
if you want to get it in.
diff mbox series

Patch

diff --git a/qemu-img.c b/qemu-img.c
index 1acddf693c..e4d9baa550 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -52,6 +52,7 @@ 
 typedef struct img_cmd_t {
     const char *name;
     int (*handler)(int argc, char **argv);
+    void (*help_func)(void);
 } img_cmd_t;
 
 enum {
@@ -76,11 +77,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 void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
 {
     va_list ap;
@@ -105,102 +101,546 @@  static void QEMU_NORETURN unrecognized_option(const char *option)
     error_exit("unrecognized option '%s'", option);
 }
 
-/* Please keep in synch with qemu-img.texi */
-static void QEMU_NORETURN help(void)
+/* Prints an overview of available help options */
+static 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=]<pattern>][,events=<file>][,file=<file>]\n"
-           "                         specify tracing options\n"
-           "\n"
-           "Command syntax:\n"
-#define DEF(option, callback, arg_string)        \
-           "  " arg_string "\n"
-#include "qemu-img-cmds.h"
-#undef DEF
-           "\n"
-           "Command parameters:\n"
-           "  'filename' is a disk image filename\n"
-           "  'objectdef' is a QEMU user creatable object definition. See the qemu(1)\n"
-           "    manual page for a description of the object properties. The most common\n"
-           "    object type is a 'secret', which is used to supply passwords and/or\n"
-           "    encryption keys.\n"
-           "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
-           "  'cache' is the cache mode used to write the output disk image, the valid\n"
-           "    options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
-           "    'directsync' and 'unsafe' (default for convert)\n"
-           "  'src_cache' is the cache mode used to read input disk images, the valid\n"
-           "    options are the same as for the 'cache' option\n"
-           "  'size' is the disk image size in bytes. Optional suffixes\n"
-           "    'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M),\n"
-           "    'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E' (exabyte, 1024P)  are\n"
-           "    supported. 'b' is ignored.\n"
-           "  'output_filename' is the destination disk image filename\n"
-           "  'output_fmt' is the destination format\n"
-           "  'options' is a comma separated list of format specific options in a\n"
-           "    name=value format. Use -o ? for an overview of the options supported by the\n"
-           "    used format\n"
-           "  'snapshot_param' is param used for internal snapshot, format\n"
-           "    is 'snapshot.id=[ID],snapshot.name=[NAME]', or\n"
-           "    '[ID_OR_NAME]'\n"
-           "  '-c' indicates that target image must be compressed (qcow format only)\n"
-           "  '-u' allows unsafe backing chains. For rebasing, it is assumed that old and\n"
-           "       new backing file match exactly. The image doesn't need a working\n"
-           "       backing file before rebasing in this case (useful for renaming the\n"
-           "       backing file). For image creation, allow creating without attempting\n"
-           "       to open the backing file.\n"
-           "  '-h' with or without a command shows this help and lists the supported formats\n"
-           "  '-p' show progress of command (only certain commands)\n"
-           "  '-q' use Quiet mode - do not print any output (except errors)\n"
-           "  '-S' indicates the consecutive number of bytes (defaults to 4k) that must\n"
-           "       contain only zeros for qemu-img to create a sparse image during\n"
-           "       conversion. If the number of bytes is 0, the source will not be scanned for\n"
-           "       unallocated or zero sectors, and the destination image will always be\n"
-           "       fully allocated\n"
-           "  '--output' takes the format in which the output must be done (human or json)\n"
-           "  '-n' skips the target volume creation (useful if the volume is created\n"
-           "       prior to running qemu-img)\n"
-           "\n"
-           "Parameters to check subcommand:\n"
-           "  '-r' tries to repair any inconsistencies that are found during the check.\n"
-           "       '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all\n"
-           "       kinds of errors, with a higher risk of choosing the wrong fix or\n"
-           "       hiding corruption that has already occurred.\n"
-           "\n"
-           "Parameters to convert subcommand:\n"
-           "  '-m' specifies how many coroutines work in parallel during the convert\n"
-           "       process (defaults to 8)\n"
-           "  '-W' allow to write to the target out of order rather than sequential\n"
-           "\n"
-           "Parameters to snapshot subcommand:\n"
-           "  'snapshot' is the name of the snapshot to create, apply or delete\n"
-           "  '-a' applies a snapshot (revert disk to saved state)\n"
-           "  '-c' creates a snapshot\n"
-           "  '-d' deletes a snapshot\n"
-           "  '-l' lists all snapshots in the given image\n"
-           "\n"
-           "Parameters to compare subcommand:\n"
-           "  '-f' first image format\n"
-           "  '-F' second image format\n"
-           "  '-s' run in Strict mode - fail on different image size or sector allocation\n"
-           "\n"
-           "Parameters to dd subcommand:\n"
-           "  'bs=BYTES' read and write up to BYTES bytes at a time "
-           "(default: 512)\n"
-           "  'count=N' copy only N input blocks\n"
-           "  'if=FILE' read from FILE\n"
-           "  'of=FILE' write to FILE\n"
-           "  'skip=N' skip N bs-sized blocks at the start of input\n";
-
-    printf("%s\nSupported formats:", help_msg);
-    bdrv_iterate_format(format_print, NULL);
-    printf("\n\n" QEMU_HELP_BOTTOM "\n");
-    exit(EXIT_SUCCESS);
+    QEMU_IMG_VERSION
+    "usage: qemu-img [standard options] command [command options]\n"
+    "QEMU disk image utility\n"
+    "\n"
+    "    '-h', '--help'       display this help and exit\n"
+    "    '-V', '--version'    output version information and exit\n"
+    "    '-T', '--trace'      [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
+    "                         specify tracing options\n"
+    "\n"
+    "Command:\n"
+    "\tamend              Change options of an existing disk image\n"
+    "\tbench              Run benchmarks on a given disk image\n"
+    "\tcheck              Check the disk image for consistency or repair it\n"
+    "\tcommit             Merge the disk image into its backing file\n"
+    "\tcompare            Check if two images have the same content\n"
+    "\tconvert            Convert an image file or snapshot into another file\n"
+    "\tcreate             Create a new disk image\n"
+    "\tdd                 Copies and converts an input file into another file\n"
+    "\tinfo               Gives information about the specified image file\n"
+    "\tmap                Dump the metadata of image filename\n"
+    "\tmeasure            Calculate the file size required for a new image\n"
+    "\tsnapshot           List, apply, create or delete snapshots in a file\n"
+    "\trebase             Changes the backing file of an image file\n"
+    "\tresize             Resize an image file\n"
+    "\n\nRun 'qemu-img <command> --help' for details.\n"
+    "See <https://qemu.org/contribute/report-a-bug> for how to report bugs.\n"
+    "More information on the QEMU project at <https://qemu.org>.\n";
+    printf("%s\n", help_msg);
+}
+
+static void help_amend(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt]\n"
+    "[-t cache] -o options filename\n"
+    "\n"
+    "Command parameters:\n"
+    " -f             The format of the image file.\n"
+    "\n"
+    "--image-opts    Treat filename as a set of image options, instead of a plain\n"
+    "                filename.\n"
+    "\n"
+    " -o             Used with a comma separated list of format specific options in a\n"
+    "                name=value format. Use \"-o help\" for an overview of the options\n"
+    "                supported by the used format.\n"
+    "\n"
+    "--object        \'objectdef\' is a QEMU user creatable object definition. See the\n"
+    "                qemu(1) manual page for a description of the object properties.\n"
+    "                The most common object type is a \'secret\', which is used to\n"
+    "                supply passwords and/or encryption keys.\n"
+    "\n"
+    " -p             Display progress bar. If the -p option is not used for a command\n"
+    "                that supports it, the progress is reported when the process\n"
+    "                receives a \"SIGUSR1\" signal. Avoid using with the -q option.\n"
+    "\n"
+    " -q             Quiet mode - do not print any output (except errors). Avoid\n"
+    "                using with the -p option.\n"
+    "\n"
+    " -t             Specifies the cache mode that should be used with the\n"
+    "                destination file. Options are: none, writeback, writethrough,\n"
+    "                directsync, and unsafe.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img amend -o compat=v3 -f qcow2 image.qcow2\n"
+    "    qemu-img amend --object secret,id=sec0,data=test --image-opts \\\n"
+    "    driver=luks,key-secret=sec0,file.filename=test.luks -o size=2G\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_bench(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img bench [-c count] [-d depth] [-f fmt]\n"
+    "[--flush-interval=flush_interval] [-n] [--no-drain] [-o offset]\n"
+    "[--pattern=pattern] [-q] [-s buffer_size] [-S step_size] [-t cache] [-w] [-U]\n"
+    "filename\n"
+    "\n"
+    "Command parameters:\n"
+    " -c                  Number of I/O requests to perform.\n"
+    "\n"
+    " -d                  Number of I/O requests done in parallel.\n"
+    "\n"
+    " -f                  The format of the image file.\n"
+    "\n"
+    " --flush-interval    How often a flush should take place.\n"
+    "\n"
+    " -n                  Use native AIO backend if possible.\n"
+    "\n"
+    " --no-drain          Issue a flush without draining the request queue first.\n"
+    "\n"
+    " -o                  The starting position.\n"
+    "\n"
+    " --pattern           The byte pattern used to in write tests.\n"
+    "\n"
+    " -q                  Quiet mode - do not print any output (except errors).\n"
+    "                     There\'s no progress bar in case both -q and -p options are\n"
+    "                     used.\n"
+    "\n"
+    " -s                  buffer_size in bytes.\n"
+    "\n"
+    " -S                  Increases current position by step_size.\n"
+    "\n"
+    " -t                  Specifies the cache mode that should be used with the\n"
+    "                     destination file.  Options are: none, writeback,\n"
+    "                     writethrough, directsync, and unsafe.\n"
+    "\n"
+    " -w                  Perform write test.\n"
+    "\n"
+    " -U                  Open the image in shared mode, allowing other QEMU\n"
+    "                     processes to open it in write mode. This option is only\n"
+    "                     allowed when opening images in read-only mode.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img bench -c 20000 -d 50000 -f qcow2 image.qcow2\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_check(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img check [--object objectdef] [--image-opts] [-q] [-f fmt]\n"
+    "[--output=ofmt] [-r [leaks | all]] [-T src_cache] [-U] filename\n"
+    "\n"
+    "Command parameters:\n"
+    " -f         The format of the image file.\n"
+    "\n"
+    " -q         Use Quiet mode - do not print any output (except errors).\n"
+    "\n"
+    " -r         Tries to repair any inconsistencies that are found during the check.\n"
+    "            \'-r leaks\' repairs only cluster leaks, whereas \'-r all\' fixes all\n"
+    "            kinds of errors, with a higher risk of choosing the wrong fix or\n"
+    "            hiding corruption that has already occurred.\n"
+    "\n"
+    " -T         \'src_cache\' is the cache mode used to read input disk images, the\n"
+    "            valid options are the same as for the \'cache\' option. Options are:\n"
+    "            none, writeback, writethrough, directsync, and unsafe.\n"
+    "\n"
+    " --object   \'objectdef\' is a QEMU user creatable object definition. See the\n"
+    "            qemu(1) manual page for a description of the object properties. The\n"
+    "            most common object type is a \'secret\', which is used to supply\n"
+    "            passwords and/or encryption keys.\n"
+    "\n"
+    " --output   \'ofmt\' is \'human\' for human-readable output (default) or \'json\' for\n"
+    "            JSON output.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img check image.qcow2\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_commit(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img commit [--object objectdef] [--image-opts] [-q] [-f fmt]\n"
+    "[-t cache] [-b base] [-d] [-p] filename\n"
+    "\n"
+    "Command parameters:\n"
+    " -b            The base image or backing file.\n"
+    "\n"
+    " -d            Skip emptying filename.\n"
+    "\n"
+    " -f            The format of the image file.\n"
+    "\n"
+    " --image-opts  Treat filename as a set of image options, instead of a plain\n"
+    "               filename.\n"
+    "\n"
+    " --object      \'objectdef\' is a QEMU user creatable object definition. See the\n"
+    "               qemu(1) manual page for a description of the object properties.\n"
+    "               The most common object type is a \'secret\', which is used to\n"
+    "               supply passwords and/or encryption keys.\n"
+    "\n"
+    " -p            Display progress bar. If the -p option is not used for a command\n"
+    "               that supports it, the progress is reported when the process\n"
+    "               receives a \"SIGUSR1\" signal.\n"
+    "\n"
+    " -q            Quiet mode - do not print any output (except errors). There\'s no\n"
+    "               progress bar in case both -q and -p options are used.\n"
+    "\n"
+    " -t            Specifies the cache mode that should be used with the\n"
+    "               destination file.  Options are: none, writeback, writethrough,\n"
+    "               directsync, and unsafe.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img commit image.qcow2\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_compare(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img compare [--object objectdef] [--image-opts] [-f fmt] [-F fmt]\n"
+    "[-T src_cache] [-p] [-q] [-s] [-U] filename1 filename2\n"
+    "\n"
+    "Command parameters:\n"
+    " -f                 First image\'s format.\n"
+    "\n"
+    " -F                 Second image\'s format.\n"
+    "\n"
+    " --image-opts       Treat filename as a set of image options, instead of a plain\n"
+    "                    filename.\n"
+    "\n"
+    " -T                 Specifies the cache mode that should be used with the source\n"
+    "                    file. Options are: none, writeback, writethrough,\n"
+    "                    directsync, and unsafe.\n"
+    "\n"
+    " --object           \'objectdef\' is a QEMU user creatable object definition. See\n"
+    "                    the qemu(1) manual page for a description of the object\n"
+    "                    properties. The most common object type is a \'secret\', which\n"
+    "                    is used to supply passwords and/or encryption keys.\n"
+    "\n"
+    " -p                 Display progress bar. If the -p option is not used for a\n"
+    "                    command that supports it, the progress is reported when the\n"
+    "                    process receives a \"SIGUSR1\" signal.\n"
+    "\n"
+    " -q                 Quiet mode - do not print any output (except errors).\n"
+    "                    There\'s no progress bar in case both -q and -p options are\n"
+    "                    used.\n"
+    "\n"
+    " -s                 Enable strict mode. Comparisons differ when image sizes\n"
+    "                    differ or if a sector is allocated in one image and not\n"
+    "                    allocated in the other image.\n"
+    "\n"
+    " -U                 Open the image in shared mode, allowing other QEMU\n"
+    "                    processes to open it in write mode. This option is only\n"
+    "                    allowed when opening images in read-only mode.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img compare image1.qcow image2.qcow2\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_convert(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img convert [--object objectdef] [--image-opts]\n"
+    "[--target-image-opts] [-U] [-c] [-p] [-q] [-n] [-f fmt] [-t cache]\n"
+    "[-T src_cache] [-O output_fmt] [-B backing_file] [-o options]\n"
+    "[-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size]\n"
+    "[-m num_coroutines] [-W] filename [filename2 [...]] output_filename\n"
+    "\n"
+    "Command parameters:\n"
+    " -B                      Force the output image to be created as a copy on write\n"
+    "                         image of the specified base image.\n"
+    "\n"
+    " -c                      Compress the output image file.\n"
+    "\n"
+    " -f                      The format of the image file.\n"
+    "\n"
+    " --image-opts            Indicates that the source filename parameter is to be\n"
+    "                         interpreted as a full option string, not a plain\n"
+    "                         filename.\n"
+    "\n"
+    " -l                      Specifies a snapshot parameter.\n"
+    "\n"
+    " -m                      Number of parallel coroutines for the convert process\n"
+    "\n"
+    " -n                      Skip the creation of the target volume.\n"
+    "\n"
+    " -O                      Format of the output file.\n"
+    "\n"
+    " -o                      Allows for specifying options like virtual disk size.\n"
+    "\n"
+    " --object                \'objectdef\' is a QEMU user creatable object definition.\n"
+    "                         See the qemu(1) manual page for a description of the\n"
+    "                         object properties. The most common object type is a\n"
+    "                         \'secret\', which is used to supply passwords and/or\n"
+    "                         encryption keys.\n"
+    "\n"
+    " -p                      Display progress bar. If the -p option is not used for\n"
+    "                         a command that supports it, the progress is reported\n"
+    "                         when the process receives a \"SIGUSR1\" signal.\n"
+    "\n"
+    " -q                      Quiet mode - do not print any output (except errors).\n"
+    "                         There\'s no progress bar in case both -q and -p options\n"
+    "                         are used.\n"
+    "\n"
+    " -S                      The consecutive number of bytes (defaults to 4k) that\n"
+    "                         must contain only zeros for qemu-img to create a sparse\n"
+    "                         image during conversion.\n"
+    "\n"
+    " -s                      The name or ID of the snapshot to use.\n"
+    "\n"
+    " -T                      Specifies the cache mode that should be used with the\n"
+    "                         source file.\n"
+    "\n"
+    " -t                      Specifies the cache mode that should be used with the\n"
+    "                         destination file. Options are: none, writeback,\n"
+    "                         writethrough, directsync, and unsafe.\n"
+    "\n"
+    "--target-image-opts      Indicates whether the source filename includes options.\n"
+    "\n"
+    " -U                      Open the image in shared mode, allowing other QEMU\n"
+    "                         processes to open it in write mode. This option is only\n"
+    "                         allowed when opening images in read-only mode.\n"
+    "\n"
+    " -W                      Allow out-of-order writes to the destination. This\n"
+    "                         option improves performance, but is only recommended\n"
+    "                         for preallocated devices like host devices or other raw\n"
+    "                         block devices.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img convert -f raw -O qcow2 image.img image.qcow2\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_create(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img create [--object objectdef] [-q] [-f fmt] [-b backing_file]\n"
+    "[-F backing_fmt] [-u] [-o options] filename [size]\n"
+    "\n"
+    "Command parameters:\n"
+    " -b             The backing file used to base the output file on.\n"
+    "\n"
+    " -f             The format of the image file.\n"
+    "\n"
+    " -F             The format of the backing file.\n"
+    "\n"
+    " -u             Create the image file even if the backing file cannot be opened.\n"
+    "\n"
+    " -o             Allows for specifying options like virtual disk size.\n"
+    "\n"
+    "--object        \'objectdef\' is a QEMU user creatable object definition.\n"
+    "                See the qemu(1) manual page for a description of the\n"
+    "                object properties. The most common object type is a\n"
+    "                \'secret\', which is used to supply passwords and/or\n"
+    "                encryption keys.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img create -f qcow2 image.qcow2 10G\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_dd(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img dd [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks]\n"
+    "[skip=blocks] if=input of=output\n"
+    "\n"
+    "Command parameters:\n"
+    " bs                 Size of the blocks used in reading and writing (512 bytes is\n"
+    "                    the default).\n"
+    "\n"
+    " count              The limit to how many blocks to read.\n"
+    "\n"
+    " -f                 The format of the image file.\n"
+    "\n"
+    " if                 The input file.\n"
+    "\n"
+    " -O                 Format of the output file.\n"
+    "\n"
+    " of                 The output file.\n"
+    "\n"
+    " skip               Number of blocks to skip.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img dd if=/dev/cdrom -O raw of=cd.iso\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_info(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img info [-f fmt] [--output=ofmt] [--backing-chain] filename\n"
+    "\n"
+    "Command parameters:\n"
+    " --backing-chain            Recursively enumerate thru each disk image in the\n"
+    "                            chain for information.\n"
+    "\n"
+    " -f                         The format of the image file.\n"
+    "\n"
+    "--output                    The output format of this command. Can be \"human\" or\n"
+    "                            \"json\".\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img info image.qcow2\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_map(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img map [-f fmt] [--output=ofmt] filename\n"
+    "\n"
+    "Command parameters:\n"
+    " -f                 The format of the image file.\n"
+    "\n"
+    "--output            The output format of this command. Can be \"human\" or \"json\".\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img map image.qcow2\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_measure(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img measure [--output=ofmt] [-O output_fmt] [-o options] [--size N ]\n"
+    "[--object objectdef] [--image-opts] [-f fmt] [-l snapshot_param]\n"
+    "filename\n"
+    "\n"
+    "Command parameters:\n"
+    " -f                 The format of the image file.\n"
+    "\n"
+    " --image-opts       Indicates that the source filename parameter is to be\n"
+    "                    interpreted as a full option string, not a plain\n"
+    "                    filename.\n"
+    "\n"
+    " -l                 Specifies a snapshot parameter.\n"
+    "\n"
+    " -O                 Format of the output file.\n"
+    "\n"
+    " -o                 Allows for specifying options.\n"
+    "\n"
+    " --object           \'objectdef\' is a QEMU user creatable object definition. See\n"
+    "                    the qemu(1) manual page for a description of the object\n"
+    "                    properties. The most common object type is a \'secret\',\n"
+    "                    which is used to supply passwords and/or encryption keys.\n"
+    "\n"
+    " --output           \'ofmt\' is \'human\' for human-readable output (default) or\n"
+    "                    \'json\' for JSON output.\n"
+    "\n"
+    " --size             If given act as if creating a new empty image file using\n"
+    "                    qemu-img create.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img measure -O qcow2 --size 5G\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_snapshot(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img snapshot [-l | -a snapshot | -c snapshot | -d snapshot ]\n"
+    "filename\n"
+    "\n"
+    "Command parameters:\n"
+    " -a                 Applies the snapshot.\n"
+    "\n"
+    " -c                 Create a snapshot.\n"
+    "\n"
+    " -d                 Deletes a snapshot.\n"
+    "\n"
+    " -l                 Lists all snapshots\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img snapshot -l image.qcow2\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_rebase(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img rebase [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b\n"
+    "backing_file [-F backing_fmt] filename\n"
+    "\n"
+    "Command parameters:\n"
+    " -b         The new backing file.\n"
+    "\n"
+    " -F         The format for the new backing file.\n"
+    "\n"
+    " -f         The format of the image file being rebased.\n"
+    "\n"
+    " -T         Specifies the cache mode that should be used with the source file.\n"
+    "\n"
+    " -t         Specifies the cache mode that should be used with the destination\n"
+    "            file. Options are: none, writeback, writethrough, directsync, and\n"
+    "            unsafe.\n"
+    "\n"
+    " -p         Display progress bar. If the -p option is not used for a command\n"
+    "            that supports it, the progress is reported when the process\n"
+    "            receives a \"SIGUSR1\" signal.\n"
+    "\n"
+    " -u         Operate in unsafe mode.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img rebase -b backing.img diff.qcow2\n"
+    "\n"
+    "\n";
+    printf("%s", msg);
+}
+
+static void help_resize(void)
+{
+    const char *msg =
+    "\n"
+    "usage: qemu-img resize [--shrink] [--preallocation=prealloc] filename\n"
+    "[+ | -] size\n"
+    "\n"
+    "Command parameters:\n"
+    " --preallocation    When growing an image, specify how the additional image\n"
+    "                    area should be allocated on the host.\n"
+    "\n"
+    " --shrink           Informs qemu-img that the user acknowledges all loss of\n"
+    "                    data beyond the truncated image\'s end.\n"
+    "\n"
+    "Example:\n"
+    "    qemu-img resize image.qcow2 20G\n";
+    printf("%s", msg);
 }
 
 static QemuOptsList qemu_object_opts = {
@@ -4886,7 +5326,7 @@  out:
     return ret;
 }
 
-static const img_cmd_t img_cmds[] = {
+static img_cmd_t img_cmds[] = {
 #define DEF(option, callback, arg_string)        \
     { option, callback },
 #include "qemu-img-cmds.h"
@@ -4894,6 +5334,12 @@  static const img_cmd_t img_cmds[] = {
     { NULL, NULL, },
 };
 
+/* These functions will be added to the img_cmds array */
+void (*help_functions[])(void) = {help_amend, help_bench, help_check,\
+    help_commit, help_compare, help_convert, help_create, help_dd, help_info,\
+    help_map, help_measure, help_snapshot, help_rebase, help_resize};
+
+
 int main(int argc, char **argv)
 {
     const img_cmd_t *cmd;
@@ -4970,10 +5416,22 @@  int main(int argc, char **argv)
     trace_init_file(trace_file);
     qemu_set_log(LOG_TRACE);
 
+    /* Add all the help functions to the array */
+    int i;
+    for (i = 0; i < ARRAY_SIZE(help_functions); i++) {
+        img_cmds[i].help_func = help_functions[i];
+    }
+
     /* find the command */
     for (cmd = img_cmds; cmd->name != NULL; cmd++) {
         if (!strcmp(cmdname, cmd->name)) {
-            return cmd->handler(argc, argv);
+            if ((argc > (optind + 1)) &&
+                strcmp("--help", argv[optind + 1]) == 0) {
+                cmd->help_func();
+                return 0;
+            } else {
+                return cmd->handler(argc, argv);
+            }
         }
     }