diff mbox

[v5,07/10] qemu-img: allow specifying image as a set of options args

Message ID 1454417864-18774-8-git-send-email-berrange@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Daniel P. Berrangé Feb. 2, 2016, 12:57 p.m. UTC
Currently qemu-img allows an image filename to be passed on the
command line, but unless using the JSON format, it does not have
a way to set any options except the format eg

   qemu-img info https://127.0.0.1/images/centos7.iso

This adds a --image-opts arg that indicates that the positional
filename should be interpreted as a full option string, not
just a filename.

   qemu-img info --image-opts driver=https,url=https://127.0.0.1/images,sslverify=off

This flag is mutually exclusive with the '-f' / '-F' flags.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 qemu-img-cmds.hx |  44 +++++++--------
 qemu-img.c       | 164 +++++++++++++++++++++++++++++++++++++++++++++++--------
 qemu-img.texi    |   6 ++
 3 files changed, 170 insertions(+), 44 deletions(-)

Comments

Kevin Wolf Feb. 4, 2016, 3:42 p.m. UTC | #1
Am 02.02.2016 um 13:57 hat Daniel P. Berrange geschrieben:
> Currently qemu-img allows an image filename to be passed on the
> command line, but unless using the JSON format, it does not have
> a way to set any options except the format eg
> 
>    qemu-img info https://127.0.0.1/images/centos7.iso
> 
> This adds a --image-opts arg that indicates that the positional
> filename should be interpreted as a full option string, not
> just a filename.
> 
>    qemu-img info --image-opts driver=https,url=https://127.0.0.1/images,sslverify=off
> 
> This flag is mutually exclusive with the '-f' / '-F' flags.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

> @@ -212,9 +222,31 @@ static int print_block_option_help(const char *filename, const char *fmt)
>      return 0;
>  }
>  
> -static BlockBackend *img_open(const char *id, const char *filename,
> -                              const char *fmt, int flags,
> -                              bool require_io, bool quiet)
> +static BlockBackend *img_open_opts(const char *id,
> +                                   QemuOpts *opts, int flags)
> +{
> +    QDict *options;
> +    Error *local_err = NULL;
> +    char *file = NULL;
> +    BlockBackend *blk;
> +    file = g_strdup(qemu_opt_get(opts, "file"));
> +    qemu_opt_unset(opts, "file");

Didn't we decide that we don't want to special-case "file"?

> +    options = qemu_opts_to_qdict(opts, NULL);
> +    blk = blk_new_open(id, file, NULL, options, flags, &local_err);
> +    if (!blk) {
> +        error_report("Could not open '%s': %s", file ? file : "",
> +                     error_get_pretty(local_err));
> +        g_free(file);
> +        error_free(local_err);
> +        return NULL;
> +    }
> +    g_free(file);
> +    return blk;
> +}
> +
> +static BlockBackend *img_open_file(const char *id, const char *filename,
> +                                   const char *fmt, int flags,
> +                                   bool require_io, bool quiet)
>  {
>      BlockBackend *blk;
>      BlockDriverState *bs;
> @@ -251,6 +283,33 @@ fail:
>      return NULL;
>  }
>  
> +
> +static BlockBackend *img_open(const char *id,
> +                              bool image_opts,
> +                              const char *filename,
> +                              const char *fmt, int flags,
> +                              bool require_io, bool quiet)
> +{
> +    BlockBackend *blk;
> +    if (image_opts) {
> +        QemuOpts *opts;
> +        if (fmt) {
> +            error_report("--image-opts and --format are mutually exclusive");
> +            return NULL;
> +        }
> +        opts = qemu_opts_parse_noisily(qemu_find_opts("source"),
> +                                       filename, true);
> +        if (!opts) {
> +            return NULL;
> +        }
> +        blk = img_open_opts("image", opts, flags);
> +    } else {
> +        blk = img_open_file("image", filename, fmt, flags, true, quiet);
> +    }
> +    return blk;
> +}

I think id should be passed on instead of being replaced by "image".

> @@ -1956,7 +2034,13 @@ static int img_convert(int argc, char **argv)
>          goto out;
>      }
>  
> -    out_blk = img_open("target", out_filename, out_fmt, flags, true, quiet);
> +    /* XXX we should allow --image-opts to trigger use of
> +     * img_open() here, but then we have trouble with
> +     * the bdrv_create() call which takes different params.
> +     * Not critical right now, so fix can wait...
> +     */
> +    out_blk = img_open_file("target", out_filename,
> +                            out_fmt, flags, true, quiet);

So is the plan to add another option (like --target-image-opts) when
this call is converted?

Kevin
Daniel P. Berrangé Feb. 4, 2016, 3:47 p.m. UTC | #2
On Thu, Feb 04, 2016 at 04:42:06PM +0100, Kevin Wolf wrote:
> Am 02.02.2016 um 13:57 hat Daniel P. Berrange geschrieben:
> > Currently qemu-img allows an image filename to be passed on the
> > command line, but unless using the JSON format, it does not have
> > a way to set any options except the format eg
> > 
> >    qemu-img info https://127.0.0.1/images/centos7.iso
> > 
> > This adds a --image-opts arg that indicates that the positional
> > filename should be interpreted as a full option string, not
> > just a filename.
> > 
> >    qemu-img info --image-opts driver=https,url=https://127.0.0.1/images,sslverify=off
> > 
> > This flag is mutually exclusive with the '-f' / '-F' flags.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> 
> > @@ -212,9 +222,31 @@ static int print_block_option_help(const char *filename, const char *fmt)
> >      return 0;
> >  }
> >  
> > -static BlockBackend *img_open(const char *id, const char *filename,
> > -                              const char *fmt, int flags,
> > -                              bool require_io, bool quiet)
> > +static BlockBackend *img_open_opts(const char *id,
> > +                                   QemuOpts *opts, int flags)
> > +{
> > +    QDict *options;
> > +    Error *local_err = NULL;
> > +    char *file = NULL;
> > +    BlockBackend *blk;
> > +    file = g_strdup(qemu_opt_get(opts, "file"));
> > +    qemu_opt_unset(opts, "file");
> 
> Didn't we decide that we don't want to special-case "file"?

Yes, sorry I screwed this up when I refactored it.


> > +static BlockBackend *img_open(const char *id,
> > +                              bool image_opts,
> > +                              const char *filename,
> > +                              const char *fmt, int flags,
> > +                              bool require_io, bool quiet)
> > +{
> > +    BlockBackend *blk;
> > +    if (image_opts) {
> > +        QemuOpts *opts;
> > +        if (fmt) {
> > +            error_report("--image-opts and --format are mutually exclusive");
> > +            return NULL;
> > +        }
> > +        opts = qemu_opts_parse_noisily(qemu_find_opts("source"),
> > +                                       filename, true);
> > +        if (!opts) {
> > +            return NULL;
> > +        }
> > +        blk = img_open_opts("image", opts, flags);
> > +    } else {
> > +        blk = img_open_file("image", filename, fmt, flags, true, quiet);
> > +    }
> > +    return blk;
> > +}
> 
> I think id should be passed on instead of being replaced by "image".

ok
 
> > @@ -1956,7 +2034,13 @@ static int img_convert(int argc, char **argv)
> >          goto out;
> >      }
> >  
> > -    out_blk = img_open("target", out_filename, out_fmt, flags, true, quiet);
> > +    /* XXX we should allow --image-opts to trigger use of
> > +     * img_open() here, but then we have trouble with
> > +     * the bdrv_create() call which takes different params.
> > +     * Not critical right now, so fix can wait...
> > +     */
> > +    out_blk = img_open_file("target", out_filename,
> > +                            out_fmt, flags, true, quiet);
> 
> So is the plan to add another option (like --target-image-opts) when
> this call is converted?

Well I was hoping --image-opts would affect both source and target,
but i guess if we ship it only affecting source, we can't extend
it to also affect target without back compat issues, so that might
force adding a --target-image-opts

Regards,
Daniel
Eric Blake Feb. 4, 2016, 3:59 p.m. UTC | #3
On 02/02/2016 05:57 AM, Daniel P. Berrange wrote:
> Currently qemu-img allows an image filename to be passed on the
> command line, but unless using the JSON format, it does not have
> a way to set any options except the format eg
> 
>    qemu-img info https://127.0.0.1/images/centos7.iso
> 
> This adds a --image-opts arg that indicates that the positional
> filename should be interpreted as a full option string, not
> just a filename.
> 
>    qemu-img info --image-opts driver=https,url=https://127.0.0.1/images,sslverify=off
> 
> This flag is mutually exclusive with the '-f' / '-F' flags.
> 
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  qemu-img-cmds.hx |  44 +++++++--------
>  qemu-img.c       | 164 +++++++++++++++++++++++++++++++++++++++++++++++--------
>  qemu-img.texi    |   6 ++
>  3 files changed, 170 insertions(+), 44 deletions(-)
> 

> +static BlockBackend *img_open_opts(const char *id,
> +                                   QemuOpts *opts, int flags)
> +{
> +    QDict *options;
> +    Error *local_err = NULL;
> +    char *file = NULL;
> +    BlockBackend *blk;
> +    file = g_strdup(qemu_opt_get(opts, "file"));
> +    qemu_opt_unset(opts, "file");
> +    options = qemu_opts_to_qdict(opts, NULL);
> +    blk = blk_new_open(id, file, NULL, options, flags, &local_err);
> +    if (!blk) {
> +        error_report("Could not open '%s': %s", file ? file : "",
> +                     error_get_pretty(local_err));

Markus' code has landed; this would be cleaner with error_reportf_err()
from commit 8277d2aa.

> @@ -2720,6 +2828,7 @@ static int img_rebase(int argc, char **argv)
>      if (optind != argc - 1) {
>          error_exit("Expecting one image file name");
>      }
> +
>      if (!unsafe && !out_baseimg) {
>          error_exit("Must specify backing file (-b) or use unsafe mode (-u)");
>      }

Spurious hunk?
Daniel P. Berrangé Feb. 4, 2016, 4:03 p.m. UTC | #4
On Thu, Feb 04, 2016 at 08:59:56AM -0700, Eric Blake wrote:
> On 02/02/2016 05:57 AM, Daniel P. Berrange wrote:
> > Currently qemu-img allows an image filename to be passed on the
> > command line, but unless using the JSON format, it does not have
> > a way to set any options except the format eg
> > 
> >    qemu-img info https://127.0.0.1/images/centos7.iso
> > 
> > This adds a --image-opts arg that indicates that the positional
> > filename should be interpreted as a full option string, not
> > just a filename.
> > 
> >    qemu-img info --image-opts driver=https,url=https://127.0.0.1/images,sslverify=off
> > 
> > This flag is mutually exclusive with the '-f' / '-F' flags.
> > 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  qemu-img-cmds.hx |  44 +++++++--------
> >  qemu-img.c       | 164 +++++++++++++++++++++++++++++++++++++++++++++++--------
> >  qemu-img.texi    |   6 ++
> >  3 files changed, 170 insertions(+), 44 deletions(-)
> > 
> 
> > +static BlockBackend *img_open_opts(const char *id,
> > +                                   QemuOpts *opts, int flags)
> > +{
> > +    QDict *options;
> > +    Error *local_err = NULL;
> > +    char *file = NULL;
> > +    BlockBackend *blk;
> > +    file = g_strdup(qemu_opt_get(opts, "file"));
> > +    qemu_opt_unset(opts, "file");
> > +    options = qemu_opts_to_qdict(opts, NULL);
> > +    blk = blk_new_open(id, file, NULL, options, flags, &local_err);
> > +    if (!blk) {
> > +        error_report("Could not open '%s': %s", file ? file : "",
> > +                     error_get_pretty(local_err));
> 
> Markus' code has landed; this would be cleaner with error_reportf_err()
> from commit 8277d2aa.

Ok will change.

> 
> > @@ -2720,6 +2828,7 @@ static int img_rebase(int argc, char **argv)
> >      if (optind != argc - 1) {
> >          error_exit("Expecting one image file name");
> >      }
> > +
> >      if (!unsafe && !out_baseimg) {
> >          error_exit("Must specify backing file (-b) or use unsafe mode (-u)");
> >      }
> 
> Spurious hunk?

Yes, left over from earlier versions


Regards,
Daniel
Kevin Wolf Feb. 4, 2016, 4:06 p.m. UTC | #5
Am 04.02.2016 um 16:47 hat Daniel P. Berrange geschrieben:
> On Thu, Feb 04, 2016 at 04:42:06PM +0100, Kevin Wolf wrote:
> > Am 02.02.2016 um 13:57 hat Daniel P. Berrange geschrieben:
> > > @@ -1956,7 +2034,13 @@ static int img_convert(int argc, char **argv)
> > >          goto out;
> > >      }
> > >  
> > > -    out_blk = img_open("target", out_filename, out_fmt, flags, true, quiet);
> > > +    /* XXX we should allow --image-opts to trigger use of
> > > +     * img_open() here, but then we have trouble with
> > > +     * the bdrv_create() call which takes different params.
> > > +     * Not critical right now, so fix can wait...
> > > +     */
> > > +    out_blk = img_open_file("target", out_filename,
> > > +                            out_fmt, flags, true, quiet);
> > 
> > So is the plan to add another option (like --target-image-opts) when
> > this call is converted?
> 
> Well I was hoping --image-opts would affect both source and target,
> but i guess if we ship it only affecting source, we can't extend
> it to also affect target without back compat issues, so that might
> force adding a --target-image-opts

Yes, that's exactly why I'm asking. We need to decide now whether this
would be an acceptable outcome or whether we shouldn't have --image-opts
in this command for now at all.

Kevin
Daniel P. Berrangé Feb. 4, 2016, 4:35 p.m. UTC | #6
On Thu, Feb 04, 2016 at 05:06:06PM +0100, Kevin Wolf wrote:
> Am 04.02.2016 um 16:47 hat Daniel P. Berrange geschrieben:
> > On Thu, Feb 04, 2016 at 04:42:06PM +0100, Kevin Wolf wrote:
> > > Am 02.02.2016 um 13:57 hat Daniel P. Berrange geschrieben:
> > > > @@ -1956,7 +2034,13 @@ static int img_convert(int argc, char **argv)
> > > >          goto out;
> > > >      }
> > > >  
> > > > -    out_blk = img_open("target", out_filename, out_fmt, flags, true, quiet);
> > > > +    /* XXX we should allow --image-opts to trigger use of
> > > > +     * img_open() here, but then we have trouble with
> > > > +     * the bdrv_create() call which takes different params.
> > > > +     * Not critical right now, so fix can wait...
> > > > +     */
> > > > +    out_blk = img_open_file("target", out_filename,
> > > > +                            out_fmt, flags, true, quiet);
> > > 
> > > So is the plan to add another option (like --target-image-opts) when
> > > this call is converted?
> > 
> > Well I was hoping --image-opts would affect both source and target,
> > but i guess if we ship it only affecting source, we can't extend
> > it to also affect target without back compat issues, so that might
> > force adding a --target-image-opts
> 
> Yes, that's exactly why I'm asking. We need to decide now whether this
> would be an acceptable outcome or whether we shouldn't have --image-opts
> in this command for now at all.

I thinking having '--target-image-opts' wouldn't be the end of the world.
I also get the feeling that solving the target problem may well require
new cli args regardless, since there's multiple sets of options we care
about - the image creation options are separate from the image runtime
options in the block layer, and so given the image creation options theres
no obvious way to extrapolate the subset which are also valid runtime
options. Also AFAICT, we can't actually specify options at all for the
layer below - it just assumes a plain file backend, so there's no way
to pass options to express creation of qcow2-on-nbd for example, or
formatting of luks-on-rbd, etc - only qcow2-on-file or luks-on-file.


Regards,
Daniel
Kevin Wolf Feb. 5, 2016, 3:52 p.m. UTC | #7
Am 04.02.2016 um 17:35 hat Daniel P. Berrange geschrieben:
> On Thu, Feb 04, 2016 at 05:06:06PM +0100, Kevin Wolf wrote:
> > Am 04.02.2016 um 16:47 hat Daniel P. Berrange geschrieben:
> > > On Thu, Feb 04, 2016 at 04:42:06PM +0100, Kevin Wolf wrote:
> > > > Am 02.02.2016 um 13:57 hat Daniel P. Berrange geschrieben:
> > > > > @@ -1956,7 +2034,13 @@ static int img_convert(int argc, char **argv)
> > > > >          goto out;
> > > > >      }
> > > > >  
> > > > > -    out_blk = img_open("target", out_filename, out_fmt, flags, true, quiet);
> > > > > +    /* XXX we should allow --image-opts to trigger use of
> > > > > +     * img_open() here, but then we have trouble with
> > > > > +     * the bdrv_create() call which takes different params.
> > > > > +     * Not critical right now, so fix can wait...
> > > > > +     */
> > > > > +    out_blk = img_open_file("target", out_filename,
> > > > > +                            out_fmt, flags, true, quiet);
> > > > 
> > > > So is the plan to add another option (like --target-image-opts) when
> > > > this call is converted?
> > > 
> > > Well I was hoping --image-opts would affect both source and target,
> > > but i guess if we ship it only affecting source, we can't extend
> > > it to also affect target without back compat issues, so that might
> > > force adding a --target-image-opts
> > 
> > Yes, that's exactly why I'm asking. We need to decide now whether this
> > would be an acceptable outcome or whether we shouldn't have --image-opts
> > in this command for now at all.
> 
> I thinking having '--target-image-opts' wouldn't be the end of the world.
> I also get the feeling that solving the target problem may well require
> new cli args regardless, since there's multiple sets of options we care
> about - the image creation options are separate from the image runtime
> options in the block layer, and so given the image creation options theres
> no obvious way to extrapolate the subset which are also valid runtime
> options. Also AFAICT, we can't actually specify options at all for the
> layer below - it just assumes a plain file backend, so there's no way
> to pass options to express creation of qcow2-on-nbd for example, or
> formatting of luks-on-rbd, etc - only qcow2-on-file or luks-on-file.

Eventually I'd like to restructure bdrv_create() option handling similar
to bdrv_open() so that you can pass options explicitly to the protocol
layer, but for the time being, that's right, of course.

If having the options for the source is useful even without having them
for the target, I'm okay with having to add a new option later, if
nobody else objects to it.

Kevin
diff mbox

Patch

diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 0eaf307..e7cded6 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -10,68 +10,68 @@  STEXI
 ETEXI
 
 DEF("check", img_check,
-    "check [-q] [--object objectdef] [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] filename")
+    "check [-q] [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [-r [leaks | all]] [-T src_cache] filename")
 STEXI
-@item check [--object @var{objectdef}] [-q] [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] [-T @var{src_cache}] @var{filename}
+@item check [--object @var{objectdef}] [--image-opts] [-q] [-f @var{fmt}] [--output=@var{ofmt}] [-r [leaks | all]] [-T @var{src_cache}] @var{filename}
 ETEXI
 
 DEF("create", img_create,
-    "create [-q] [--object objectdef] [-f fmt] [-o options] filename [size]")
+    "create [-q] [--object objectdef] [--image-opts] [-f fmt] [-o options] filename [size]")
 STEXI
-@item create [--object @var{objectdef}] [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
+@item create [--object @var{objectdef}] [--image-opts] [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
 ETEXI
 
 DEF("commit", img_commit,
-    "commit [-q] [--object objectdef] [-f fmt] [-t cache] [-b base] [-d] [-p] filename")
+    "commit [-q] [--object objectdef] [--image-opts] [-f fmt] [-t cache] [-b base] [-d] [-p] filename")
 STEXI
-@item commit [--object @var{objectdef}] [-q] [-f @var{fmt}] [-t @var{cache}] [-b @var{base}] [-d] [-p] @var{filename}
+@item commit [--object @var{objectdef}] [--image-opts] [-q] [-f @var{fmt}] [-t @var{cache}] [-b @var{base}] [-d] [-p] @var{filename}
 ETEXI
 
 DEF("compare", img_compare,
-    "compare [--object objectdef] [-f fmt] [-F fmt] [-T src_cache] [-p] [-q] [-s] filename1 filename2")
+    "compare [--object objectdef] [--image-opts] [-f fmt] [-F fmt] [-T src_cache] [-p] [-q] [-s] filename1 filename2")
 STEXI
-@item compare [--object @var{objectdef}] [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-q] [-s] @var{filename1} @var{filename2}
+@item compare [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [-F @var{fmt}] [-T @var{src_cache}] [-p] [-q] [-s] @var{filename1} @var{filename2}
 ETEXI
 
 DEF("convert", img_convert,
-    "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")
+    "convert [--object objectdef] [--image-opts] [-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
-@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}
+@item convert [--object @var{objectdef}] [--image-opts] [-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
 
 DEF("info", img_info,
-    "info [--object objectdef] [-f fmt] [--output=ofmt] [--backing-chain] filename")
+    "info [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] [--backing-chain] filename")
 STEXI
-@item info [--object @var{objectdef}] [-f @var{fmt}] [--output=@var{ofmt}] [--backing-chain] @var{filename}
+@item info [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] [--backing-chain] @var{filename}
 ETEXI
 
 DEF("map", img_map,
-    "map [--object objectdef] [-f fmt] [--output=ofmt] filename")
+    "map [--object objectdef] [--image-opts] [-f fmt] [--output=ofmt] filename")
 STEXI
-@item map [--object @var{objectdef}] [-f @var{fmt}] [--output=@var{ofmt}] @var{filename}
+@item map [--object @var{objectdef}] [--image-opts] [-f @var{fmt}] [--output=@var{ofmt}] @var{filename}
 ETEXI
 
 DEF("snapshot", img_snapshot,
-    "snapshot [--object objectdef] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
+    "snapshot [--object objectdef] [--image-opts] [-q] [-l | -a snapshot | -c snapshot | -d snapshot] filename")
 STEXI
-@item snapshot [--object @var{objectdef}] [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename}
+@item snapshot [--object @var{objectdef}] [--image-opts] [-q] [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot}] @var{filename}
 ETEXI
 
 DEF("rebase", img_rebase,
-    "rebase [--object objectdef] [-q] [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
+    "rebase [--object objectdef] [--image-opts] [-q] [-f fmt] [-t cache] [-T src_cache] [-p] [-u] -b backing_file [-F backing_fmt] filename")
 STEXI
-@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}
+@item rebase [--object @var{objectdef}] [--image-opts] [-q] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-p] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
 ETEXI
 
 DEF("resize", img_resize,
-    "resize [--object objectdef] [-q] filename [+ | -]size")
+    "resize [--object objectdef] [--image-opts] [-q] filename [+ | -]size")
 STEXI
-@item resize [--object @var{objectdef}] [-q] @var{filename} [+ | -]@var{size}
+@item resize [--object @var{objectdef}] [--image-opts] [-q] @var{filename} [+ | -]@var{size}
 ETEXI
 
 DEF("amend", img_amend,
-    "amend [--object objectdef] [-p] [-q] [-f fmt] [-t cache] -o options filename")
+    "amend [--object objectdef] [--image-opts] [-p] [-q] [-f fmt] [-t cache] -o options filename")
 STEXI
-@item amend [--object @var{objectdef}] [-p] [-q] [-f @var{fmt}] [-t @var{cache}] -o @var{options} @var{filename}
+@item amend [--object @var{objectdef}] [--image-opts] [-p] [-q] [-f @var{fmt}] [-t @var{cache}] -o @var{options} @var{filename}
 @end table
 ETEXI
diff --git a/qemu-img.c b/qemu-img.c
index 524b64f..0c54fe6 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -50,6 +50,7 @@  enum {
     OPTION_OUTPUT = 256,
     OPTION_BACKING_CHAIN = 257,
     OPTION_OBJECT = 258,
+    OPTION_IMAGE_OPTS = 259,
 };
 
 typedef enum OutputFormat {
@@ -170,6 +171,15 @@  static QemuOptsList qemu_object_opts = {
     },
 };
 
+static QemuOptsList qemu_source_opts = {
+    .name = "source",
+    .implied_opt_name = "file",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_source_opts.head),
+    .desc = {
+        { }
+    },
+};
+
 static int GCC_FMT_ATTR(2, 3) qprintf(bool quiet, const char *fmt, ...)
 {
     int ret = 0;
@@ -212,9 +222,31 @@  static int print_block_option_help(const char *filename, const char *fmt)
     return 0;
 }
 
-static BlockBackend *img_open(const char *id, const char *filename,
-                              const char *fmt, int flags,
-                              bool require_io, bool quiet)
+static BlockBackend *img_open_opts(const char *id,
+                                   QemuOpts *opts, int flags)
+{
+    QDict *options;
+    Error *local_err = NULL;
+    char *file = NULL;
+    BlockBackend *blk;
+    file = g_strdup(qemu_opt_get(opts, "file"));
+    qemu_opt_unset(opts, "file");
+    options = qemu_opts_to_qdict(opts, NULL);
+    blk = blk_new_open(id, file, NULL, options, flags, &local_err);
+    if (!blk) {
+        error_report("Could not open '%s': %s", file ? file : "",
+                     error_get_pretty(local_err));
+        g_free(file);
+        error_free(local_err);
+        return NULL;
+    }
+    g_free(file);
+    return blk;
+}
+
+static BlockBackend *img_open_file(const char *id, const char *filename,
+                                   const char *fmt, int flags,
+                                   bool require_io, bool quiet)
 {
     BlockBackend *blk;
     BlockDriverState *bs;
@@ -251,6 +283,33 @@  fail:
     return NULL;
 }
 
+
+static BlockBackend *img_open(const char *id,
+                              bool image_opts,
+                              const char *filename,
+                              const char *fmt, int flags,
+                              bool require_io, bool quiet)
+{
+    BlockBackend *blk;
+    if (image_opts) {
+        QemuOpts *opts;
+        if (fmt) {
+            error_report("--image-opts and --format are mutually exclusive");
+            return NULL;
+        }
+        opts = qemu_opts_parse_noisily(qemu_find_opts("source"),
+                                       filename, true);
+        if (!opts) {
+            return NULL;
+        }
+        blk = img_open_opts("image", opts, flags);
+    } else {
+        blk = img_open_file("image", filename, fmt, flags, true, quiet);
+    }
+    return blk;
+}
+
+
 static int add_old_style_options(const char *fmt, QemuOpts *opts,
                                  const char *base_filename,
                                  const char *base_fmt)
@@ -528,6 +587,7 @@  static int img_check(int argc, char **argv)
     ImageCheck *check;
     bool quiet = false;
     Error *local_err = NULL;
+    bool image_opts = false;
 
     fmt = NULL;
     output = NULL;
@@ -540,6 +600,7 @@  static int img_check(int argc, char **argv)
             {"repair", required_argument, 0, 'r'},
             {"output", required_argument, 0, OPTION_OUTPUT},
             {"object", required_argument, 0, OPTION_OBJECT},
+            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "hf:r:T:q",
@@ -584,6 +645,9 @@  static int img_check(int argc, char **argv)
                 return 1;
             }
         }   break;
+        case OPTION_IMAGE_OPTS:
+            image_opts = true;
+            break;
         }
     }
     if (optind != argc - 1) {
@@ -613,7 +677,7 @@  static int img_check(int argc, char **argv)
         return 1;
     }
 
-    blk = img_open("image", filename, fmt, flags, true, quiet);
+    blk = img_open("image", image_opts, filename, fmt, flags, true, quiet);
     if (!blk) {
         return 1;
     }
@@ -725,6 +789,7 @@  static int img_commit(int argc, char **argv)
     bool progress = false, quiet = false, drop = false;
     Error *local_err = NULL;
     CommonBlockJobCBInfo cbi;
+    bool image_opts = false;
 
     fmt = NULL;
     cache = BDRV_DEFAULT_CACHE;
@@ -734,6 +799,7 @@  static int img_commit(int argc, char **argv)
         static const struct option long_options[] = {
             {"help", no_argument, 0, 'h'},
             {"object", required_argument, 0, OPTION_OBJECT},
+            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "f:ht:b:dpq",
@@ -774,6 +840,9 @@  static int img_commit(int argc, char **argv)
                 return 1;
             }
         }   break;
+        case OPTION_IMAGE_OPTS:
+            image_opts = true;
+            break;
         }
     }
 
@@ -801,7 +870,7 @@  static int img_commit(int argc, char **argv)
         return 1;
     }
 
-    blk = img_open("image", filename, fmt, flags, true, quiet);
+    blk = img_open("image", image_opts, filename, fmt, flags, true, quiet);
     if (!blk) {
         return 1;
     }
@@ -1051,6 +1120,7 @@  static int img_compare(int argc, char **argv)
     int c, pnum;
     uint64_t progress_base;
     Error *local_err = NULL;
+    bool image_opts = false;
 
     cache = BDRV_DEFAULT_CACHE;
     for (;;) {
@@ -1058,6 +1128,7 @@  static int img_compare(int argc, char **argv)
         static const struct option long_options[] = {
             {"help", no_argument, 0, 'h'},
             {"object", required_argument, 0, OPTION_OBJECT},
+            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "hf:F:T:pqs",
@@ -1097,6 +1168,9 @@  static int img_compare(int argc, char **argv)
                 goto out4;
             }
         }   break;
+        case OPTION_IMAGE_OPTS:
+            image_opts = true;
+            break;
         }
     }
 
@@ -1131,18 +1205,18 @@  static int img_compare(int argc, char **argv)
         goto out3;
     }
 
-    blk1 = img_open("image_1", filename1, fmt1, flags, true, quiet);
+    blk1 = img_open("image_1", image_opts, filename1, fmt1, flags, true, quiet);
     if (!blk1) {
         ret = 2;
         goto out3;
     }
-    bs1 = blk_bs(blk1);
 
-    blk2 = img_open("image_2", filename2, fmt2, flags, true, quiet);
+    blk2 = img_open("image_2", image_opts, filename2, fmt2, flags, true, quiet);
     if (!blk2) {
         ret = 2;
         goto out2;
     }
+    bs1 = blk_bs(blk1);
     bs2 = blk_bs(blk2);
 
     buf1 = blk_blockalign(blk1, IO_BUF_SIZE);
@@ -1646,6 +1720,7 @@  static int img_convert(int argc, char **argv)
     Error *local_err = NULL;
     QemuOpts *sn_opts = NULL;
     ImgConvertState state;
+    bool image_opts = false;
 
     fmt = NULL;
     out_fmt = "raw";
@@ -1659,6 +1734,7 @@  static int img_convert(int argc, char **argv)
         static const struct option long_options[] = {
             {"help", no_argument, 0, 'h'},
             {"object", required_argument, 0, OPTION_OBJECT},
+            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "hf:O:B:ce6o:s:l:S:pt:T:qn",
@@ -1760,6 +1836,9 @@  static int img_convert(int argc, char **argv)
                 goto fail_getopt;
             }
             break;
+        case OPTION_IMAGE_OPTS:
+            image_opts = true;
+            break;
         }
     }
 
@@ -1776,7 +1855,6 @@  static int img_convert(int argc, char **argv)
     }
     qemu_progress_init(progress, 1.0);
 
-
     bs_n = argc - optind - 1;
     out_filename = bs_n >= 1 ? argv[argc - 1] : NULL;
 
@@ -1814,8 +1892,8 @@  static int img_convert(int argc, char **argv)
     for (bs_i = 0; bs_i < bs_n; bs_i++) {
         char *id = bs_n > 1 ? g_strdup_printf("source_%d", bs_i)
                             : g_strdup("source");
-        blk[bs_i] = img_open(id, argv[optind + bs_i], fmt, src_flags,
-                             true, quiet);
+        blk[bs_i] = img_open(id, image_opts, argv[optind + bs_i],
+                             fmt, src_flags, true, quiet);
         g_free(id);
         if (!blk[bs_i]) {
             ret = -1;
@@ -1956,7 +2034,13 @@  static int img_convert(int argc, char **argv)
         goto out;
     }
 
-    out_blk = img_open("target", out_filename, out_fmt, flags, true, quiet);
+    /* XXX we should allow --image-opts to trigger use of
+     * img_open() here, but then we have trouble with
+     * the bdrv_create() call which takes different params.
+     * Not critical right now, so fix can wait...
+     */
+    out_blk = img_open_file("target", out_filename,
+                            out_fmt, flags, true, quiet);
     if (!out_blk) {
         ret = -1;
         goto out;
@@ -2123,7 +2207,8 @@  static gboolean str_equal_func(gconstpointer a, gconstpointer b)
  * image file.  If there was an error a message will have been printed to
  * stderr.
  */
-static ImageInfoList *collect_image_info_list(const char *filename,
+static ImageInfoList *collect_image_info_list(bool image_opts,
+                                              const char *filename,
                                               const char *fmt,
                                               bool chain)
 {
@@ -2147,8 +2232,9 @@  static ImageInfoList *collect_image_info_list(const char *filename,
         }
         g_hash_table_insert(filenames, (gpointer)filename, NULL);
 
-        blk = img_open("image", filename, fmt,
-                       BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false);
+        blk = img_open("image", image_opts, filename, fmt,
+                       BDRV_O_FLAGS | BDRV_O_NO_BACKING,
+                       false, false);
         if (!blk) {
             goto err;
         }
@@ -2200,6 +2286,7 @@  static int img_info(int argc, char **argv)
     const char *filename, *fmt, *output;
     ImageInfoList *list;
     Error *local_err = NULL;
+    bool image_opts = false;
 
     fmt = NULL;
     output = NULL;
@@ -2211,6 +2298,7 @@  static int img_info(int argc, char **argv)
             {"output", required_argument, 0, OPTION_OUTPUT},
             {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
             {"object", required_argument, 0, OPTION_OBJECT},
+            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "f:h",
@@ -2240,6 +2328,9 @@  static int img_info(int argc, char **argv)
                 return 1;
             }
         }   break;
+        case OPTION_IMAGE_OPTS:
+            image_opts = true;
+            break;
         }
     }
     if (optind != argc - 1) {
@@ -2263,7 +2354,7 @@  static int img_info(int argc, char **argv)
         return 1;
     }
 
-    list = collect_image_info_list(filename, fmt, chain);
+    list = collect_image_info_list(image_opts, filename, fmt, chain);
     if (!list) {
         return 1;
     }
@@ -2387,6 +2478,7 @@  static int img_map(int argc, char **argv)
     MapEntry curr = { .length = 0 }, next;
     int ret = 0;
     Error *local_err = NULL;
+    bool image_opts = false;
 
     fmt = NULL;
     output = NULL;
@@ -2397,6 +2489,7 @@  static int img_map(int argc, char **argv)
             {"format", required_argument, 0, 'f'},
             {"output", required_argument, 0, OPTION_OUTPUT},
             {"object", required_argument, 0, OPTION_OBJECT},
+            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "f:h",
@@ -2423,6 +2516,9 @@  static int img_map(int argc, char **argv)
                 return 1;
             }
         }   break;
+        case OPTION_IMAGE_OPTS:
+            image_opts = true;
+            break;
         }
     }
     if (optind != argc - 1) {
@@ -2446,7 +2542,8 @@  static int img_map(int argc, char **argv)
         return 1;
     }
 
-    blk = img_open("image", filename, fmt, BDRV_O_FLAGS, true, false);
+    blk = img_open("image", image_opts, filename, fmt,
+                   BDRV_O_FLAGS, true, false);
     if (!blk) {
         return 1;
     }
@@ -2511,6 +2608,7 @@  static int img_snapshot(int argc, char **argv)
     qemu_timeval tv;
     bool quiet = false;
     Error *err = NULL;
+    bool image_opts = false;
 
     bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
     /* Parse commandline parameters */
@@ -2519,6 +2617,7 @@  static int img_snapshot(int argc, char **argv)
         static const struct option long_options[] = {
             {"help", no_argument, 0, 'h'},
             {"object", required_argument, 0, OPTION_OBJECT},
+            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "la:c:d:hq",
@@ -2574,6 +2673,9 @@  static int img_snapshot(int argc, char **argv)
                 return 1;
             }
         }   break;
+        case OPTION_IMAGE_OPTS:
+            image_opts = true;
+            break;
         }
     }
 
@@ -2590,7 +2692,8 @@  static int img_snapshot(int argc, char **argv)
     }
 
     /* Open the image */
-    blk = img_open("image", filename, NULL, bdrv_oflags, true, quiet);
+    blk = img_open("image", image_opts, filename, NULL,
+                   bdrv_oflags, true, quiet);
     if (!blk) {
         return 1;
     }
@@ -2654,6 +2757,7 @@  static int img_rebase(int argc, char **argv)
     int progress = 0;
     bool quiet = false;
     Error *local_err = NULL;
+    bool image_opts = false;
 
     /* Parse commandline parameters */
     fmt = NULL;
@@ -2666,6 +2770,7 @@  static int img_rebase(int argc, char **argv)
         static const struct option long_options[] = {
             {"help", no_argument, 0, 'h'},
             {"object", required_argument, 0, OPTION_OBJECT},
+            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "hf:F:b:upt:T:q",
@@ -2710,6 +2815,9 @@  static int img_rebase(int argc, char **argv)
                 return 1;
             }
         }   break;
+        case OPTION_IMAGE_OPTS:
+            image_opts = true;
+            break;
         }
     }
 
@@ -2720,6 +2828,7 @@  static int img_rebase(int argc, char **argv)
     if (optind != argc - 1) {
         error_exit("Expecting one image file name");
     }
+
     if (!unsafe && !out_baseimg) {
         error_exit("Must specify backing file (-b) or use unsafe mode (-u)");
     }
@@ -2755,7 +2864,7 @@  static int img_rebase(int argc, char **argv)
      * Ignore the old backing file for unsafe rebase in case we want to correct
      * the reference to a renamed or moved backing file.
      */
-    blk = img_open("image", filename, fmt, flags, true, quiet);
+    blk = img_open("image", image_opts, filename, fmt, flags, true, quiet);
     if (!blk) {
         ret = -1;
         goto out;
@@ -3007,6 +3116,7 @@  static int img_resize(int argc, char **argv)
             }
         },
     };
+    bool image_opts = false;
 
     /* Remove size from argv manually so that negative numbers are not treated
      * as options by getopt. */
@@ -3024,6 +3134,7 @@  static int img_resize(int argc, char **argv)
         static const struct option long_options[] = {
             {"help", no_argument, 0, 'h'},
             {"object", required_argument, 0, OPTION_OBJECT},
+            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "f:hq",
@@ -3050,6 +3161,9 @@  static int img_resize(int argc, char **argv)
                 return 1;
             }
         }   break;
+        case OPTION_IMAGE_OPTS:
+            image_opts = true;
+            break;
         }
     }
     if (optind != argc - 1) {
@@ -3091,8 +3205,8 @@  static int img_resize(int argc, char **argv)
     n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0);
     qemu_opts_del(param);
 
-    blk = img_open("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR,
-                   true, quiet);
+    blk = img_open("image", image_opts, filename, fmt,
+                   BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet);
     if (!blk) {
         ret = -1;
         goto out;
@@ -3152,6 +3266,7 @@  static int img_amend(int argc, char **argv)
     BlockBackend *blk = NULL;
     BlockDriverState *bs = NULL;
     Error *local_err = NULL;
+    bool image_opts = false;
 
     cache = BDRV_DEFAULT_CACHE;
     for (;;) {
@@ -3159,6 +3274,7 @@  static int img_amend(int argc, char **argv)
         static const struct option long_options[] = {
             {"help", no_argument, 0, 'h'},
             {"object", required_argument, 0, OPTION_OBJECT},
+            {"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
             {0, 0, 0, 0}
         };
         c = getopt_long(argc, argv, "ho:f:t:pq",
@@ -3206,6 +3322,9 @@  static int img_amend(int argc, char **argv)
                     goto out_no_progress;
                 }
                 break;
+            case OPTION_IMAGE_OPTS:
+                image_opts = true;
+                break;
         }
     }
 
@@ -3247,7 +3366,7 @@  static int img_amend(int argc, char **argv)
         goto out;
     }
 
-    blk = img_open("image", filename, fmt, flags, true, quiet);
+    blk = img_open("image", image_opts, filename, fmt, flags, true, quiet);
     if (!blk) {
         ret = -1;
         goto out;
@@ -3345,6 +3464,7 @@  int main(int argc, char **argv)
 
     module_call_init(MODULE_INIT_QOM);
     qemu_add_opts(&qemu_object_opts);
+    qemu_add_opts(&qemu_source_opts);
 
     /* find the command */
     for (cmd = img_cmds; cmd->name != NULL; cmd++) {
diff --git a/qemu-img.texi b/qemu-img.texi
index 612f15a..da599c8 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -32,6 +32,12 @@  page for a description of the object properties. The only object type that
 it makes sense to define is the @code{secret} object, which is used to
 supply passwords and/or encryption keys.
 
+@item --image-opts
+
+Indicates that the @var{filename} parameter is to be interpreted as a
+full option string, not a plain filename. This parameter is mutually
+exclusive with the @var{-f} and @var{-F} parameters.
+
 @item fmt
 is the disk image format. It is guessed automatically in most cases. See below
 for a description of the supported disk formats.