Prechádzať zdrojové kódy

qemu-img: add support for --object command line arg

Allow creation of user creatable object types with qemu-img
via a new --object command line arg. This will be used to supply
passwords and/or encryption keys to the various block driver
backends via the recently added 'secret' object type.

 # printf letmein > mypasswd.txt
 # qemu-img info --object secret,id=sec0,file=mypasswd.txt \
      ...other info args...

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Daniel P. Berrange 9 rokov pred
rodič
commit
3babeb153c
3 zmenil súbory, kde vykonal 282 pridanie a 30 odobranie
  1. 22 22
      qemu-img-cmds.hx
  2. 252 8
      qemu-img.c
  3. 8 0
      qemu-img.texi

+ 22 - 22
qemu-img-cmds.hx

@@ -10,68 +10,68 @@ STEXI
 ETEXI
 ETEXI
 
 
 DEF("check", img_check,
 DEF("check", img_check,
-    "check [-q] [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] filename")
+    "check [-q] [--object objectdef] [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] filename")
 STEXI
 STEXI
-@item check [-q] [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] [-T @var{src_cache}] @var{filename}
+@item check [--object @var{objectdef}] [-q] [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] [-T @var{src_cache}] @var{filename}
 ETEXI
 ETEXI
 
 
 DEF("create", img_create,
 DEF("create", img_create,
-    "create [-q] [-f fmt] [-o options] filename [size]")
+    "create [-q] [--object objectdef] [-f fmt] [-o options] filename [size]")
 STEXI
 STEXI
-@item create [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
+@item create [--object @var{objectdef}] [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
 ETEXI
 ETEXI
 
 
 DEF("commit", img_commit,
 DEF("commit", img_commit,
-    "commit [-q] [-f fmt] [-t cache] [-b base] [-d] [-p] filename")
+    "commit [-q] [--object objectdef] [-f fmt] [-t cache] [-b base] [-d] [-p] filename")
 STEXI
 STEXI
-@item commit [-q] [-f @var{fmt}] [-t @var{cache}] [-b @var{base}] [-d] [-p] @var{filename}
+@item commit [--object @var{objectdef}] [-q] [-f @var{fmt}] [-t @var{cache}] [-b @var{base}] [-d] [-p] @var{filename}
 ETEXI
 ETEXI
 
 
 DEF("compare", img_compare,
 DEF("compare", img_compare,
-    "compare [-f fmt] [-F fmt] [-T src_cache] [-p] [-q] [-s] filename1 filename2")
+    "compare [--object objectdef] [-f fmt] [-F fmt] [-T src_cache] [-p] [-q] [-s] filename1 filename2")
 STEXI
 STEXI
-@item compare [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-q] [-s] @var{filename1} @var{filename2}
+@item compare [--object @var{objectdef}] [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-q] [-s] @var{filename1} @var{filename2}
 ETEXI
 ETEXI
 
 
 DEF("convert", img_convert,
 DEF("convert", img_convert,
-    "convert [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename [filename2 [...]] output_filename")
+    "convert [--object objectdef] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] filename [filename2 [...]] output_filename")
 STEXI
 STEXI
-@item convert [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
+@item convert [--object @var{objectdef}] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
 ETEXI
 ETEXI
 
 
 DEF("info", img_info,
 DEF("info", img_info,
-    "info [-f fmt] [--output=ofmt] [--backing-chain] filename")
+    "info [--object objectdef] [-f fmt] [--output=ofmt] [--backing-chain] filename")
 STEXI
 STEXI
-@item info [-f @var{fmt}] [--output=@var{ofmt}] [--backing-chain] @var{filename}
+@item info [--object @var{objectdef}] [-f @var{fmt}] [--output=@var{ofmt}] [--backing-chain] @var{filename}
 ETEXI
 ETEXI
 
 
 DEF("map", img_map,
 DEF("map", img_map,
-    "map [-f fmt] [--output=ofmt] filename")
+    "map [--object objectdef] [-f fmt] [--output=ofmt] filename")
 STEXI
 STEXI
-@item map [-f @var{fmt}] [--output=@var{ofmt}] @var{filename}
+@item map [--object @var{objectdef}] [-f @var{fmt}] [--output=@var{ofmt}] @var{filename}
 ETEXI
 ETEXI
 
 
 DEF("snapshot", img_snapshot,
 DEF("snapshot", img_snapshot,
-    "snapshot [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
+    "snapshot [--object objectdef] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
 STEXI
 STEXI
-@item snapshot [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename}
+@item snapshot [--object @var{objectdef}] [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename}
 ETEXI
 ETEXI
 
 
 DEF("rebase", img_rebase,
 DEF("rebase", img_rebase,
-    "rebase [-q] [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
+    "rebase [--object objectdef] [-q] [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
 STEXI
 STEXI
-@item rebase [-q] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
+@item rebase [--object @var{objectdef}] [-q] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
 ETEXI
 ETEXI
 
 
 DEF("resize", img_resize,
 DEF("resize", img_resize,
-    "resize [-q] filename [+ | -]size")
+    "resize [--object objectdef] [-q] filename [+ | -]size")
 STEXI
 STEXI
-@item resize [-q] @var{filename} [+ | -]@var{size}
+@item resize [--object @var{objectdef}] [-q] @var{filename} [+ | -]@var{size}
 ETEXI
 ETEXI
 
 
 DEF("amend", img_amend,
 DEF("amend", img_amend,
-    "amend [-p] [-q] [-f fmt] [-t cache] -o options filename")
+    "amend [--object objectdef] [-p] [-q] [-f fmt] [-t cache] -o options filename")
 STEXI
 STEXI
-@item amend [-p] [-q] [-f @var{fmt}] [-t @var{cache}] -o @var{options} @var{filename}
+@item amend [--object @var{objectdef}] [-p] [-q] [-f @var{fmt}] [-t @var{cache}] -o @var{options} @var{filename}
 @end table
 @end table
 ETEXI
 ETEXI

+ 252 - 8
qemu-img.c

@@ -27,8 +27,10 @@
 #include "qapi/qmp/qerror.h"
 #include "qapi/qmp/qerror.h"
 #include "qapi/qmp/qjson.h"
 #include "qapi/qmp/qjson.h"
 #include "qemu-common.h"
 #include "qemu-common.h"
+#include "qemu/config-file.h"
 #include "qemu/option.h"
 #include "qemu/option.h"
 #include "qemu/error-report.h"
 #include "qemu/error-report.h"
+#include "qom/object_interfaces.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/block-backend.h"
 #include "sysemu/block-backend.h"
 #include "block/block_int.h"
 #include "block/block_int.h"
@@ -47,6 +49,7 @@ typedef struct img_cmd_t {
 enum {
 enum {
     OPTION_OUTPUT = 256,
     OPTION_OUTPUT = 256,
     OPTION_BACKING_CHAIN = 257,
     OPTION_BACKING_CHAIN = 257,
+    OPTION_OBJECT = 258,
 };
 };
 
 
 typedef enum OutputFormat {
 typedef enum OutputFormat {
@@ -94,6 +97,10 @@ static void QEMU_NORETURN help(void)
            "\n"
            "\n"
            "Command parameters:\n"
            "Command parameters:\n"
            "  'filename' is a disk image filename\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"
            "  '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"
            "  '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"
            "    options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
@@ -154,6 +161,15 @@ static void QEMU_NORETURN help(void)
     exit(EXIT_SUCCESS);
     exit(EXIT_SUCCESS);
 }
 }
 
 
+static QemuOptsList qemu_object_opts = {
+    .name = "object",
+    .implied_opt_name = "qom-type",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
+    .desc = {
+        { }
+    },
+};
+
 static int GCC_FMT_ATTR(2, 3) qprintf(bool quiet, const char *fmt, ...)
 static int GCC_FMT_ATTR(2, 3) qprintf(bool quiet, const char *fmt, ...)
 {
 {
     int ret = 0;
     int ret = 0;
@@ -275,7 +291,13 @@ static int img_create(int argc, char **argv)
     bool quiet = false;
     bool quiet = false;
 
 
     for(;;) {
     for(;;) {
-        c = getopt(argc, argv, "F:b:f:he6o:q");
+        static const struct option long_options[] = {
+            {"help", no_argument, 0, 'h'},
+            {"object", required_argument, 0, OPTION_OBJECT},
+            {0, 0, 0, 0}
+        };
+        c = getopt_long(argc, argv, "F:b:f:he6o:q",
+                        long_options, NULL);
         if (c == -1) {
         if (c == -1) {
             break;
             break;
         }
         }
@@ -317,6 +339,14 @@ static int img_create(int argc, char **argv)
         case 'q':
         case 'q':
             quiet = true;
             quiet = true;
             break;
             break;
+        case OPTION_OBJECT: {
+            QemuOpts *opts;
+            opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                           optarg, true);
+            if (!opts) {
+                goto fail;
+            }
+        }   break;
         }
         }
     }
     }
 
 
@@ -332,6 +362,13 @@ static int img_create(int argc, char **argv)
     }
     }
     optind++;
     optind++;
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &local_err)) {
+        error_report_err(local_err);
+        goto fail;
+    }
+
     /* Get image size, if specified */
     /* Get image size, if specified */
     if (optind < argc) {
     if (optind < argc) {
         int64_t sval;
         int64_t sval;
@@ -489,6 +526,7 @@ static int img_check(int argc, char **argv)
     int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
     int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
     ImageCheck *check;
     ImageCheck *check;
     bool quiet = false;
     bool quiet = false;
+    Error *local_err = NULL;
 
 
     fmt = NULL;
     fmt = NULL;
     output = NULL;
     output = NULL;
@@ -500,6 +538,7 @@ static int img_check(int argc, char **argv)
             {"format", required_argument, 0, 'f'},
             {"format", required_argument, 0, 'f'},
             {"repair", required_argument, 0, 'r'},
             {"repair", required_argument, 0, 'r'},
             {"output", required_argument, 0, OPTION_OUTPUT},
             {"output", required_argument, 0, OPTION_OUTPUT},
+            {"object", required_argument, 0, OPTION_OBJECT},
             {0, 0, 0, 0}
             {0, 0, 0, 0}
         };
         };
         c = getopt_long(argc, argv, "hf:r:T:q",
         c = getopt_long(argc, argv, "hf:r:T:q",
@@ -536,6 +575,14 @@ static int img_check(int argc, char **argv)
         case 'q':
         case 'q':
             quiet = true;
             quiet = true;
             break;
             break;
+        case OPTION_OBJECT: {
+            QemuOpts *opts;
+            opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                           optarg, true);
+            if (!opts) {
+                return 1;
+            }
+        }   break;
         }
         }
     }
     }
     if (optind != argc - 1) {
     if (optind != argc - 1) {
@@ -552,6 +599,13 @@ static int img_check(int argc, char **argv)
         return 1;
         return 1;
     }
     }
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &local_err)) {
+        error_report_err(local_err);
+        return 1;
+    }
+
     ret = bdrv_parse_cache_flags(cache, &flags);
     ret = bdrv_parse_cache_flags(cache, &flags);
     if (ret < 0) {
     if (ret < 0) {
         error_report("Invalid source cache option: %s", cache);
         error_report("Invalid source cache option: %s", cache);
@@ -675,7 +729,13 @@ static int img_commit(int argc, char **argv)
     cache = BDRV_DEFAULT_CACHE;
     cache = BDRV_DEFAULT_CACHE;
     base = NULL;
     base = NULL;
     for(;;) {
     for(;;) {
-        c = getopt(argc, argv, "f:ht:b:dpq");
+        static const struct option long_options[] = {
+            {"help", no_argument, 0, 'h'},
+            {"object", required_argument, 0, OPTION_OBJECT},
+            {0, 0, 0, 0}
+        };
+        c = getopt_long(argc, argv, "f:ht:b:dpq",
+                        long_options, NULL);
         if (c == -1) {
         if (c == -1) {
             break;
             break;
         }
         }
@@ -704,6 +764,14 @@ static int img_commit(int argc, char **argv)
         case 'q':
         case 'q':
             quiet = true;
             quiet = true;
             break;
             break;
+        case OPTION_OBJECT: {
+            QemuOpts *opts;
+            opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                           optarg, true);
+            if (!opts) {
+                return 1;
+            }
+        }   break;
         }
         }
     }
     }
 
 
@@ -717,6 +785,13 @@ static int img_commit(int argc, char **argv)
     }
     }
     filename = argv[optind++];
     filename = argv[optind++];
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &local_err)) {
+        error_report_err(local_err);
+        return 1;
+    }
+
     flags = BDRV_O_RDWR | BDRV_O_UNMAP;
     flags = BDRV_O_RDWR | BDRV_O_UNMAP;
     ret = bdrv_parse_cache_flags(cache, &flags);
     ret = bdrv_parse_cache_flags(cache, &flags);
     if (ret < 0) {
     if (ret < 0) {
@@ -973,10 +1048,17 @@ static int img_compare(int argc, char **argv)
     int64_t nb_sectors;
     int64_t nb_sectors;
     int c, pnum;
     int c, pnum;
     uint64_t progress_base;
     uint64_t progress_base;
+    Error *local_err = NULL;
 
 
     cache = BDRV_DEFAULT_CACHE;
     cache = BDRV_DEFAULT_CACHE;
     for (;;) {
     for (;;) {
-        c = getopt(argc, argv, "hf:F:T:pqs");
+        static const struct option long_options[] = {
+            {"help", no_argument, 0, 'h'},
+            {"object", required_argument, 0, OPTION_OBJECT},
+            {0, 0, 0, 0}
+        };
+        c = getopt_long(argc, argv, "hf:F:T:pqs",
+                        long_options, NULL);
         if (c == -1) {
         if (c == -1) {
             break;
             break;
         }
         }
@@ -1003,6 +1085,15 @@ static int img_compare(int argc, char **argv)
         case 's':
         case 's':
             strict = true;
             strict = true;
             break;
             break;
+        case OPTION_OBJECT: {
+            QemuOpts *opts;
+            opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                           optarg, true);
+            if (!opts) {
+                ret = 2;
+                goto out4;
+            }
+        }   break;
         }
         }
     }
     }
 
 
@@ -1018,6 +1109,14 @@ static int img_compare(int argc, char **argv)
     filename1 = argv[optind++];
     filename1 = argv[optind++];
     filename2 = argv[optind++];
     filename2 = argv[optind++];
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &local_err)) {
+        error_report_err(local_err);
+        ret = 2;
+        goto out4;
+    }
+
     /* Initialize before goto out */
     /* Initialize before goto out */
     qemu_progress_init(progress, 2.0);
     qemu_progress_init(progress, 2.0);
 
 
@@ -1225,6 +1324,7 @@ out2:
     blk_unref(blk1);
     blk_unref(blk1);
 out3:
 out3:
     qemu_progress_end();
     qemu_progress_end();
+out4:
     return ret;
     return ret;
 }
 }
 
 
@@ -1555,7 +1655,13 @@ static int img_convert(int argc, char **argv)
     compress = 0;
     compress = 0;
     skip_create = 0;
     skip_create = 0;
     for(;;) {
     for(;;) {
-        c = getopt(argc, argv, "hf:O:B:ce6o:s:l:S:pt:T:qn");
+        static const struct option long_options[] = {
+            {"help", no_argument, 0, 'h'},
+            {"object", required_argument, 0, OPTION_OBJECT},
+            {0, 0, 0, 0}
+        };
+        c = getopt_long(argc, argv, "hf:O:B:ce6o:s:l:S:pt:T:qn",
+                        long_options, NULL);
         if (c == -1) {
         if (c == -1) {
             break;
             break;
         }
         }
@@ -1646,9 +1752,23 @@ static int img_convert(int argc, char **argv)
         case 'n':
         case 'n':
             skip_create = 1;
             skip_create = 1;
             break;
             break;
+        case OPTION_OBJECT:
+            opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                           optarg, true);
+            if (!opts) {
+                goto fail_getopt;
+            }
+            break;
         }
         }
     }
     }
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &local_err)) {
+        error_report_err(local_err);
+        goto fail_getopt;
+    }
+
     /* Initialize before goto out */
     /* Initialize before goto out */
     if (quiet) {
     if (quiet) {
         progress = 0;
         progress = 0;
@@ -2077,6 +2197,7 @@ static int img_info(int argc, char **argv)
     bool chain = false;
     bool chain = false;
     const char *filename, *fmt, *output;
     const char *filename, *fmt, *output;
     ImageInfoList *list;
     ImageInfoList *list;
+    Error *local_err = NULL;
 
 
     fmt = NULL;
     fmt = NULL;
     output = NULL;
     output = NULL;
@@ -2087,6 +2208,7 @@ static int img_info(int argc, char **argv)
             {"format", required_argument, 0, 'f'},
             {"format", required_argument, 0, 'f'},
             {"output", required_argument, 0, OPTION_OUTPUT},
             {"output", required_argument, 0, OPTION_OUTPUT},
             {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
             {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
+            {"object", required_argument, 0, OPTION_OBJECT},
             {0, 0, 0, 0}
             {0, 0, 0, 0}
         };
         };
         c = getopt_long(argc, argv, "f:h",
         c = getopt_long(argc, argv, "f:h",
@@ -2108,6 +2230,14 @@ static int img_info(int argc, char **argv)
         case OPTION_BACKING_CHAIN:
         case OPTION_BACKING_CHAIN:
             chain = true;
             chain = true;
             break;
             break;
+        case OPTION_OBJECT: {
+            QemuOpts *opts;
+            opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                           optarg, true);
+            if (!opts) {
+                return 1;
+            }
+        }   break;
         }
         }
     }
     }
     if (optind != argc - 1) {
     if (optind != argc - 1) {
@@ -2124,6 +2254,13 @@ static int img_info(int argc, char **argv)
         return 1;
         return 1;
     }
     }
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &local_err)) {
+        error_report_err(local_err);
+        return 1;
+    }
+
     list = collect_image_info_list(filename, fmt, chain);
     list = collect_image_info_list(filename, fmt, chain);
     if (!list) {
     if (!list) {
         return 1;
         return 1;
@@ -2269,6 +2406,7 @@ static int img_map(int argc, char **argv)
     int64_t length;
     int64_t length;
     MapEntry curr = { .length = 0 }, next;
     MapEntry curr = { .length = 0 }, next;
     int ret = 0;
     int ret = 0;
+    Error *local_err = NULL;
 
 
     fmt = NULL;
     fmt = NULL;
     output = NULL;
     output = NULL;
@@ -2278,6 +2416,7 @@ static int img_map(int argc, char **argv)
             {"help", no_argument, 0, 'h'},
             {"help", no_argument, 0, 'h'},
             {"format", required_argument, 0, 'f'},
             {"format", required_argument, 0, 'f'},
             {"output", required_argument, 0, OPTION_OUTPUT},
             {"output", required_argument, 0, OPTION_OUTPUT},
+            {"object", required_argument, 0, OPTION_OBJECT},
             {0, 0, 0, 0}
             {0, 0, 0, 0}
         };
         };
         c = getopt_long(argc, argv, "f:h",
         c = getopt_long(argc, argv, "f:h",
@@ -2296,6 +2435,14 @@ static int img_map(int argc, char **argv)
         case OPTION_OUTPUT:
         case OPTION_OUTPUT:
             output = optarg;
             output = optarg;
             break;
             break;
+        case OPTION_OBJECT: {
+            QemuOpts *opts;
+            opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                           optarg, true);
+            if (!opts) {
+                return 1;
+            }
+        }   break;
         }
         }
     }
     }
     if (optind != argc - 1) {
     if (optind != argc - 1) {
@@ -2312,6 +2459,13 @@ static int img_map(int argc, char **argv)
         return 1;
         return 1;
     }
     }
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &local_err)) {
+        error_report_err(local_err);
+        return 1;
+    }
+
     blk = img_open("image", filename, fmt, BDRV_O_FLAGS, true, false);
     blk = img_open("image", filename, fmt, BDRV_O_FLAGS, true, false);
     if (!blk) {
     if (!blk) {
         return 1;
         return 1;
@@ -2378,7 +2532,13 @@ static int img_snapshot(int argc, char **argv)
     bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
     bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
     /* Parse commandline parameters */
     /* Parse commandline parameters */
     for(;;) {
     for(;;) {
-        c = getopt(argc, argv, "la:c:d:hq");
+        static const struct option long_options[] = {
+            {"help", no_argument, 0, 'h'},
+            {"object", required_argument, 0, OPTION_OBJECT},
+            {0, 0, 0, 0}
+        };
+        c = getopt_long(argc, argv, "la:c:d:hq",
+                        long_options, NULL);
         if (c == -1) {
         if (c == -1) {
             break;
             break;
         }
         }
@@ -2422,6 +2582,14 @@ static int img_snapshot(int argc, char **argv)
         case 'q':
         case 'q':
             quiet = true;
             quiet = true;
             break;
             break;
+        case OPTION_OBJECT: {
+            QemuOpts *opts;
+            opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                           optarg, true);
+            if (!opts) {
+                return 1;
+            }
+        }   break;
         }
         }
     }
     }
 
 
@@ -2430,6 +2598,13 @@ static int img_snapshot(int argc, char **argv)
     }
     }
     filename = argv[optind++];
     filename = argv[optind++];
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &err)) {
+        error_report_err(err);
+        return 1;
+    }
+
     /* Open the image */
     /* Open the image */
     blk = img_open("image", filename, NULL, bdrv_oflags, true, quiet);
     blk = img_open("image", filename, NULL, bdrv_oflags, true, quiet);
     if (!blk) {
     if (!blk) {
@@ -2503,7 +2678,13 @@ static int img_rebase(int argc, char **argv)
     out_baseimg = NULL;
     out_baseimg = NULL;
     out_basefmt = NULL;
     out_basefmt = NULL;
     for(;;) {
     for(;;) {
-        c = getopt(argc, argv, "hf:F:b:upt:T:q");
+        static const struct option long_options[] = {
+            {"help", no_argument, 0, 'h'},
+            {"object", required_argument, 0, OPTION_OBJECT},
+            {0, 0, 0, 0}
+        };
+        c = getopt_long(argc, argv, "hf:F:b:upt:T:q",
+                        long_options, NULL);
         if (c == -1) {
         if (c == -1) {
             break;
             break;
         }
         }
@@ -2536,6 +2717,14 @@ static int img_rebase(int argc, char **argv)
         case 'q':
         case 'q':
             quiet = true;
             quiet = true;
             break;
             break;
+        case OPTION_OBJECT: {
+            QemuOpts *opts;
+            opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                           optarg, true);
+            if (!opts) {
+                return 1;
+            }
+        }   break;
         }
         }
     }
     }
 
 
@@ -2551,6 +2740,13 @@ static int img_rebase(int argc, char **argv)
     }
     }
     filename = argv[optind++];
     filename = argv[optind++];
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &local_err)) {
+        error_report_err(local_err);
+        return 1;
+    }
+
     qemu_progress_init(progress, 2.0);
     qemu_progress_init(progress, 2.0);
     qemu_progress_print(0, 100);
     qemu_progress_print(0, 100);
 
 
@@ -2811,6 +3007,8 @@ static int img_resize(int argc, char **argv)
     bool quiet = false;
     bool quiet = false;
     BlockBackend *blk = NULL;
     BlockBackend *blk = NULL;
     QemuOpts *param;
     QemuOpts *param;
+    Error *local_err = NULL;
+
     static QemuOptsList resize_options = {
     static QemuOptsList resize_options = {
         .name = "resize_options",
         .name = "resize_options",
         .head = QTAILQ_HEAD_INITIALIZER(resize_options.head),
         .head = QTAILQ_HEAD_INITIALIZER(resize_options.head),
@@ -2837,7 +3035,13 @@ static int img_resize(int argc, char **argv)
     /* Parse getopt arguments */
     /* Parse getopt arguments */
     fmt = NULL;
     fmt = NULL;
     for(;;) {
     for(;;) {
-        c = getopt(argc, argv, "f:hq");
+        static const struct option long_options[] = {
+            {"help", no_argument, 0, 'h'},
+            {"object", required_argument, 0, OPTION_OBJECT},
+            {0, 0, 0, 0}
+        };
+        c = getopt_long(argc, argv, "f:hq",
+                        long_options, NULL);
         if (c == -1) {
         if (c == -1) {
             break;
             break;
         }
         }
@@ -2852,6 +3056,14 @@ static int img_resize(int argc, char **argv)
         case 'q':
         case 'q':
             quiet = true;
             quiet = true;
             break;
             break;
+        case OPTION_OBJECT: {
+            QemuOpts *opts;
+            opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                           optarg, true);
+            if (!opts) {
+                return 1;
+            }
+        }   break;
         }
         }
     }
     }
     if (optind != argc - 1) {
     if (optind != argc - 1) {
@@ -2859,6 +3071,13 @@ static int img_resize(int argc, char **argv)
     }
     }
     filename = argv[optind++];
     filename = argv[optind++];
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &local_err)) {
+        error_report_err(local_err);
+        return 1;
+    }
+
     /* Choose grow, shrink, or absolute resize mode */
     /* Choose grow, shrink, or absolute resize mode */
     switch (size[0]) {
     switch (size[0]) {
     case '+':
     case '+':
@@ -2946,10 +3165,17 @@ static int img_amend(int argc, char **argv)
     bool quiet = false, progress = false;
     bool quiet = false, progress = false;
     BlockBackend *blk = NULL;
     BlockBackend *blk = NULL;
     BlockDriverState *bs = NULL;
     BlockDriverState *bs = NULL;
+    Error *local_err = NULL;
 
 
     cache = BDRV_DEFAULT_CACHE;
     cache = BDRV_DEFAULT_CACHE;
     for (;;) {
     for (;;) {
-        c = getopt(argc, argv, "ho:f:t:pq");
+        static const struct option long_options[] = {
+            {"help", no_argument, 0, 'h'},
+            {"object", required_argument, 0, OPTION_OBJECT},
+            {0, 0, 0, 0}
+        };
+        c = getopt_long(argc, argv, "ho:f:t:pq",
+                        long_options, NULL);
         if (c == -1) {
         if (c == -1) {
             break;
             break;
         }
         }
@@ -2985,6 +3211,14 @@ static int img_amend(int argc, char **argv)
             case 'q':
             case 'q':
                 quiet = true;
                 quiet = true;
                 break;
                 break;
+            case OPTION_OBJECT:
+                opts = qemu_opts_parse_noisily(&qemu_object_opts,
+                                               optarg, true);
+                if (!opts) {
+                    ret = -1;
+                    goto out_no_progress;
+                }
+                break;
         }
         }
     }
     }
 
 
@@ -2992,6 +3226,14 @@ static int img_amend(int argc, char **argv)
         error_exit("Must specify options (-o)");
         error_exit("Must specify options (-o)");
     }
     }
 
 
+    if (qemu_opts_foreach(&qemu_object_opts,
+                          user_creatable_add_opts_foreach,
+                          NULL, &local_err)) {
+        error_report_err(local_err);
+        ret = -1;
+        goto out_no_progress;
+    }
+
     if (quiet) {
     if (quiet) {
         progress = false;
         progress = false;
     }
     }
@@ -3115,6 +3357,8 @@ int main(int argc, char **argv)
     }
     }
     cmdname = argv[1];
     cmdname = argv[1];
 
 
+    qemu_add_opts(&qemu_object_opts);
+
     /* find the command */
     /* find the command */
     for (cmd = img_cmds; cmd->name != NULL; cmd++) {
     for (cmd = img_cmds; cmd->name != NULL; cmd++) {
         if (!strcmp(cmdname, cmd->name)) {
         if (!strcmp(cmdname, cmd->name)) {

+ 8 - 0
qemu-img.texi

@@ -24,6 +24,14 @@ Command parameters:
 @table @var
 @table @var
 @item filename
 @item filename
  is a disk image filename
  is a disk image filename
+
+@item --object @var{objectdef}
+
+is a QEMU user creatable object definition. See the @code{qemu(1)} manual
+page for a description of the object properties. The most common object
+type is a @code{secret}, which is used to supply passwords and/or encryption
+keys.
+
 @item fmt
 @item fmt
 is the disk image format. It is guessed automatically in most cases. See below
 is the disk image format. It is guessed automatically in most cases. See below
 for a description of the supported disk formats.
 for a description of the supported disk formats.