|
@@ -60,6 +60,7 @@ enum {
|
|
OPTION_PATTERN = 260,
|
|
OPTION_PATTERN = 260,
|
|
OPTION_FLUSH_INTERVAL = 261,
|
|
OPTION_FLUSH_INTERVAL = 261,
|
|
OPTION_NO_DRAIN = 262,
|
|
OPTION_NO_DRAIN = 262,
|
|
|
|
+ OPTION_TARGET_IMAGE_OPTS = 263,
|
|
};
|
|
};
|
|
|
|
|
|
typedef enum OutputFormat {
|
|
typedef enum OutputFormat {
|
|
@@ -294,6 +295,7 @@ static BlockBackend *img_open_opts(const char *optstr,
|
|
if (qdict_haskey(options, BDRV_OPT_FORCE_SHARE)
|
|
if (qdict_haskey(options, BDRV_OPT_FORCE_SHARE)
|
|
&& !qdict_get_bool(options, BDRV_OPT_FORCE_SHARE)) {
|
|
&& !qdict_get_bool(options, BDRV_OPT_FORCE_SHARE)) {
|
|
error_report("--force-share/-U conflicts with image options");
|
|
error_report("--force-share/-U conflicts with image options");
|
|
|
|
+ QDECREF(options);
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
|
|
qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
|
|
@@ -313,14 +315,17 @@ static BlockBackend *img_open_opts(const char *optstr,
|
|
}
|
|
}
|
|
|
|
|
|
static BlockBackend *img_open_file(const char *filename,
|
|
static BlockBackend *img_open_file(const char *filename,
|
|
|
|
+ QDict *options,
|
|
const char *fmt, int flags,
|
|
const char *fmt, int flags,
|
|
bool writethrough, bool quiet,
|
|
bool writethrough, bool quiet,
|
|
bool force_share)
|
|
bool force_share)
|
|
{
|
|
{
|
|
BlockBackend *blk;
|
|
BlockBackend *blk;
|
|
Error *local_err = NULL;
|
|
Error *local_err = NULL;
|
|
- QDict *options = qdict_new();
|
|
|
|
|
|
|
|
|
|
+ if (!options) {
|
|
|
|
+ options = qdict_new();
|
|
|
|
+ }
|
|
if (fmt) {
|
|
if (fmt) {
|
|
qdict_put_str(options, "driver", fmt);
|
|
qdict_put_str(options, "driver", fmt);
|
|
}
|
|
}
|
|
@@ -343,6 +348,35 @@ static BlockBackend *img_open_file(const char *filename,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+static int img_add_key_secrets(void *opaque,
|
|
|
|
+ const char *name, const char *value,
|
|
|
|
+ Error **errp)
|
|
|
|
+{
|
|
|
|
+ QDict *options = opaque;
|
|
|
|
+
|
|
|
|
+ if (g_str_has_suffix(name, "key-secret")) {
|
|
|
|
+ qdict_put(options, name, qstring_from_str(value));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static BlockBackend *img_open_new_file(const char *filename,
|
|
|
|
+ QemuOpts *create_opts,
|
|
|
|
+ const char *fmt, int flags,
|
|
|
|
+ bool writethrough, bool quiet,
|
|
|
|
+ bool force_share)
|
|
|
|
+{
|
|
|
|
+ QDict *options = NULL;
|
|
|
|
+
|
|
|
|
+ options = qdict_new();
|
|
|
|
+ qemu_opt_foreach(create_opts, img_add_key_secrets, options, &error_abort);
|
|
|
|
+
|
|
|
|
+ return img_open_file(filename, options, fmt, flags, writethrough, quiet,
|
|
|
|
+ force_share);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
static BlockBackend *img_open(bool image_opts,
|
|
static BlockBackend *img_open(bool image_opts,
|
|
const char *filename,
|
|
const char *filename,
|
|
const char *fmt, int flags, bool writethrough,
|
|
const char *fmt, int flags, bool writethrough,
|
|
@@ -363,7 +397,7 @@ static BlockBackend *img_open(bool image_opts,
|
|
blk = img_open_opts(filename, opts, flags, writethrough, quiet,
|
|
blk = img_open_opts(filename, opts, flags, writethrough, quiet,
|
|
force_share);
|
|
force_share);
|
|
} else {
|
|
} else {
|
|
- blk = img_open_file(filename, fmt, flags, writethrough, quiet,
|
|
|
|
|
|
+ blk = img_open_file(filename, NULL, fmt, flags, writethrough, quiet,
|
|
force_share);
|
|
force_share);
|
|
}
|
|
}
|
|
return blk;
|
|
return blk;
|
|
@@ -1913,10 +1947,10 @@ static int convert_do_copy(ImgConvertState *s)
|
|
static int img_convert(int argc, char **argv)
|
|
static int img_convert(int argc, char **argv)
|
|
{
|
|
{
|
|
int c, bs_i, flags, src_flags = 0;
|
|
int c, bs_i, flags, src_flags = 0;
|
|
- const char *fmt = NULL, *out_fmt = "raw", *cache = "unsafe",
|
|
|
|
|
|
+ const char *fmt = NULL, *out_fmt = NULL, *cache = "unsafe",
|
|
*src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL,
|
|
*src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL,
|
|
*out_filename, *out_baseimg_param, *snapshot_name = NULL;
|
|
*out_filename, *out_baseimg_param, *snapshot_name = NULL;
|
|
- BlockDriver *drv, *proto_drv;
|
|
|
|
|
|
+ BlockDriver *drv = NULL, *proto_drv = NULL;
|
|
BlockDriverInfo bdi;
|
|
BlockDriverInfo bdi;
|
|
BlockDriverState *out_bs;
|
|
BlockDriverState *out_bs;
|
|
QemuOpts *opts = NULL, *sn_opts = NULL;
|
|
QemuOpts *opts = NULL, *sn_opts = NULL;
|
|
@@ -1924,7 +1958,7 @@ static int img_convert(int argc, char **argv)
|
|
char *options = NULL;
|
|
char *options = NULL;
|
|
Error *local_err = NULL;
|
|
Error *local_err = NULL;
|
|
bool writethrough, src_writethrough, quiet = false, image_opts = false,
|
|
bool writethrough, src_writethrough, quiet = false, image_opts = false,
|
|
- skip_create = false, progress = false;
|
|
|
|
|
|
+ skip_create = false, progress = false, tgt_image_opts = false;
|
|
int64_t ret = -EINVAL;
|
|
int64_t ret = -EINVAL;
|
|
bool force_share = false;
|
|
bool force_share = false;
|
|
|
|
|
|
@@ -1942,6 +1976,7 @@ static int img_convert(int argc, char **argv)
|
|
{"object", required_argument, 0, OPTION_OBJECT},
|
|
{"object", required_argument, 0, OPTION_OBJECT},
|
|
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
|
|
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
|
|
{"force-share", no_argument, 0, 'U'},
|
|
{"force-share", no_argument, 0, 'U'},
|
|
|
|
+ {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
|
|
{0, 0, 0, 0}
|
|
{0, 0, 0, 0}
|
|
};
|
|
};
|
|
c = getopt_long(argc, argv, ":hf:O:B:ce6o:s:l:S:pt:T:qnm:WU",
|
|
c = getopt_long(argc, argv, ":hf:O:B:ce6o:s:l:S:pt:T:qnm:WU",
|
|
@@ -2062,9 +2097,16 @@ static int img_convert(int argc, char **argv)
|
|
case OPTION_IMAGE_OPTS:
|
|
case OPTION_IMAGE_OPTS:
|
|
image_opts = true;
|
|
image_opts = true;
|
|
break;
|
|
break;
|
|
|
|
+ case OPTION_TARGET_IMAGE_OPTS:
|
|
|
|
+ tgt_image_opts = true;
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!out_fmt && !tgt_image_opts) {
|
|
|
|
+ out_fmt = "raw";
|
|
|
|
+ }
|
|
|
|
+
|
|
if (qemu_opts_foreach(&qemu_object_opts,
|
|
if (qemu_opts_foreach(&qemu_object_opts,
|
|
user_creatable_add_opts_foreach,
|
|
user_creatable_add_opts_foreach,
|
|
NULL, NULL)) {
|
|
NULL, NULL)) {
|
|
@@ -2076,12 +2118,22 @@ static int img_convert(int argc, char **argv)
|
|
goto fail_getopt;
|
|
goto fail_getopt;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (tgt_image_opts && !skip_create) {
|
|
|
|
+ error_report("--target-image-opts requires use of -n flag");
|
|
|
|
+ goto fail_getopt;
|
|
|
|
+ }
|
|
|
|
+
|
|
s.src_num = argc - optind - 1;
|
|
s.src_num = argc - optind - 1;
|
|
out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL;
|
|
out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL;
|
|
|
|
|
|
if (options && has_help_option(options)) {
|
|
if (options && has_help_option(options)) {
|
|
- ret = print_block_option_help(out_filename, out_fmt);
|
|
|
|
- goto fail_getopt;
|
|
|
|
|
|
+ if (out_fmt) {
|
|
|
|
+ ret = print_block_option_help(out_filename, out_fmt);
|
|
|
|
+ goto fail_getopt;
|
|
|
|
+ } else {
|
|
|
|
+ error_report("Option help requires a format be specified");
|
|
|
|
+ goto fail_getopt;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if (s.src_num < 1) {
|
|
if (s.src_num < 1) {
|
|
@@ -2146,22 +2198,22 @@ static int img_convert(int argc, char **argv)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Find driver and parse its options */
|
|
|
|
- drv = bdrv_find_format(out_fmt);
|
|
|
|
- if (!drv) {
|
|
|
|
- error_report("Unknown file format '%s'", out_fmt);
|
|
|
|
- ret = -1;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!skip_create) {
|
|
|
|
+ /* Find driver and parse its options */
|
|
|
|
+ drv = bdrv_find_format(out_fmt);
|
|
|
|
+ if (!drv) {
|
|
|
|
+ error_report("Unknown file format '%s'", out_fmt);
|
|
|
|
+ ret = -1;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
|
|
- proto_drv = bdrv_find_protocol(out_filename, true, &local_err);
|
|
|
|
- if (!proto_drv) {
|
|
|
|
- error_report_err(local_err);
|
|
|
|
- ret = -1;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
|
|
+ proto_drv = bdrv_find_protocol(out_filename, true, &local_err);
|
|
|
|
+ if (!proto_drv) {
|
|
|
|
+ error_report_err(local_err);
|
|
|
|
+ ret = -1;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
|
|
- if (!skip_create) {
|
|
|
|
if (!drv->create_opts) {
|
|
if (!drv->create_opts) {
|
|
error_report("Format driver '%s' does not support image creation",
|
|
error_report("Format driver '%s' does not support image creation",
|
|
drv->format_name);
|
|
drv->format_name);
|
|
@@ -2218,7 +2270,7 @@ static int img_convert(int argc, char **argv)
|
|
const char *preallocation =
|
|
const char *preallocation =
|
|
qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
|
|
qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
|
|
|
|
|
|
- if (!drv->bdrv_co_pwritev_compressed) {
|
|
|
|
|
|
+ if (drv && !drv->bdrv_co_pwritev_compressed) {
|
|
error_report("Compression not supported for this file format");
|
|
error_report("Compression not supported for this file format");
|
|
ret = -1;
|
|
ret = -1;
|
|
goto out;
|
|
goto out;
|
|
@@ -2258,19 +2310,30 @@ static int img_convert(int argc, char **argv)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- /* 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...
|
|
|
|
- */
|
|
|
|
- s.target = img_open_file(out_filename, out_fmt, flags, writethrough, quiet,
|
|
|
|
- false);
|
|
|
|
|
|
+ if (skip_create) {
|
|
|
|
+ s.target = img_open(tgt_image_opts, out_filename, out_fmt,
|
|
|
|
+ flags, writethrough, quiet, false);
|
|
|
|
+ } else {
|
|
|
|
+ /* TODO ultimately we should allow --target-image-opts
|
|
|
|
+ * to be used even when -n is not given.
|
|
|
|
+ * That has to wait for bdrv_create to be improved
|
|
|
|
+ * to allow filenames in option syntax
|
|
|
|
+ */
|
|
|
|
+ s.target = img_open_new_file(out_filename, opts, out_fmt,
|
|
|
|
+ flags, writethrough, quiet, false);
|
|
|
|
+ }
|
|
if (!s.target) {
|
|
if (!s.target) {
|
|
ret = -1;
|
|
ret = -1;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
out_bs = blk_bs(s.target);
|
|
out_bs = blk_bs(s.target);
|
|
|
|
|
|
|
|
+ if (s.compressed && !out_bs->drv->bdrv_co_pwritev_compressed) {
|
|
|
|
+ error_report("Compression not supported for this file format");
|
|
|
|
+ ret = -1;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
/* increase bufsectors from the default 4096 (2M) if opt_transfer
|
|
/* increase bufsectors from the default 4096 (2M) if opt_transfer
|
|
* or discard_alignment of the out_bs is greater. Limit to 32768 (16MB)
|
|
* or discard_alignment of the out_bs is greater. Limit to 32768 (16MB)
|
|
* as maximum. */
|
|
* as maximum. */
|
|
@@ -4157,6 +4220,7 @@ static int img_dd(int argc, char **argv)
|
|
};
|
|
};
|
|
const struct option long_options[] = {
|
|
const struct option long_options[] = {
|
|
{ "help", no_argument, 0, 'h'},
|
|
{ "help", no_argument, 0, 'h'},
|
|
|
|
+ { "object", required_argument, 0, OPTION_OBJECT},
|
|
{ "image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
|
|
{ "image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
|
|
{ "force-share", no_argument, 0, 'U'},
|
|
{ "force-share", no_argument, 0, 'U'},
|
|
{ 0, 0, 0, 0 }
|
|
{ 0, 0, 0, 0 }
|
|
@@ -4185,6 +4249,15 @@ static int img_dd(int argc, char **argv)
|
|
case 'U':
|
|
case 'U':
|
|
force_share = true;
|
|
force_share = true;
|
|
break;
|
|
break;
|
|
|
|
+ case OPTION_OBJECT: {
|
|
|
|
+ QemuOpts *opts;
|
|
|
|
+ opts = qemu_opts_parse_noisily(&qemu_object_opts,
|
|
|
|
+ optarg, true);
|
|
|
|
+ if (!opts) {
|
|
|
|
+ ret = -1;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ } break;
|
|
case OPTION_IMAGE_OPTS:
|
|
case OPTION_IMAGE_OPTS:
|
|
image_opts = true;
|
|
image_opts = true;
|
|
break;
|
|
break;
|
|
@@ -4229,6 +4302,14 @@ static int img_dd(int argc, char **argv)
|
|
ret = -1;
|
|
ret = -1;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (qemu_opts_foreach(&qemu_object_opts,
|
|
|
|
+ user_creatable_add_opts_foreach,
|
|
|
|
+ NULL, NULL)) {
|
|
|
|
+ ret = -1;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
|
|
blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
|
|
force_share);
|
|
force_share);
|
|
|
|
|
|
@@ -4297,8 +4378,13 @@ static int img_dd(int argc, char **argv)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR,
|
|
|
|
- false, false, false);
|
|
|
|
|
|
+ /* TODO, we can't honour --image-opts for the target,
|
|
|
|
+ * since it needs to be given in a format compatible
|
|
|
|
+ * with the bdrv_create() call above which does not
|
|
|
|
+ * support image-opts style.
|
|
|
|
+ */
|
|
|
|
+ blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
|
|
|
|
+ false, false, false);
|
|
|
|
|
|
if (!blk2) {
|
|
if (!blk2) {
|
|
ret = -1;
|
|
ret = -1;
|