#include "block/block_int.h"
#include "block/qapi.h"
#include <getopt.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
typedef struct img_cmd_t {
const char *name;
printf(" %s", name);
}
+static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
+{
+ va_list ap;
+
+ error_printf("qemu-img: ");
+
+ va_start(ap, fmt);
+ error_vprintf(fmt, ap);
+ va_end(ap);
+
+ error_printf("\nTry 'qemu-img --help' for more information\n");
+ exit(EXIT_FAILURE);
+}
+
/* Please keep in synch with qemu-img.texi */
-static void help(void)
+static void QEMU_NORETURN help(void)
{
const char *help_msg =
"qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\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"
+ " 'snapshot_id_or_name' is deprecated, use 'snapshot_param'\n"
+ " instead\n"
" '-c' indicates that target image must be compressed (qcow format only)\n"
" '-u' enables unsafe rebasing. It is assumed that old and new backing file\n"
" match exactly. The image doesn't need a working backing file before\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 that must contain only zeros\n"
- " for qemu-img to create a sparse image during conversion\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"
printf("%s\nSupported formats:", help_msg);
bdrv_iterate_format(format_print, NULL);
printf("\n");
- exit(1);
+ exit(EXIT_SUCCESS);
}
static int GCC_FMT_ATTR(2, 3) qprintf(bool quiet, const char *fmt, ...)
return 1;
}
- proto_drv = bdrv_find_protocol(filename, true);
- if (!proto_drv) {
- error_report("Unknown protocol '%s'", filename);
- return 1;
- }
-
create_options = append_option_parameters(create_options,
drv->create_options);
- create_options = append_option_parameters(create_options,
- proto_drv->create_options);
+
+ if (filename) {
+ proto_drv = bdrv_find_protocol(filename, true);
+ if (!proto_drv) {
+ error_report("Unknown protocol '%s'", filename);
+ return 1;
+ }
+ create_options = append_option_parameters(create_options,
+ proto_drv->create_options);
+ }
+
print_option_help(create_options);
free_option_parameters(create_options);
return 0;
}
-static BlockDriverState *bdrv_new_open(const char *filename,
+static BlockDriverState *bdrv_new_open(const char *id,
+ const char *filename,
const char *fmt,
int flags,
bool require_io,
Error *local_err = NULL;
int ret;
- bs = bdrv_new("image");
+ bs = bdrv_new(id, &error_abort);
if (fmt) {
drv = bdrv_find_format(fmt);
drv = NULL;
}
- ret = bdrv_open(bs, filename, NULL, flags, drv, &local_err);
+ ret = bdrv_open(&bs, filename, NULL, NULL, flags, drv, &local_err);
if (ret < 0) {
error_report("Could not open '%s': %s", filename,
error_get_pretty(local_err));
}
return bs;
fail:
- if (bs) {
- bdrv_unref(bs);
- }
+ bdrv_unref(bs);
return NULL;
}
case 'e':
error_report("option -e is deprecated, please use \'-o "
"encryption\' instead!");
- return 1;
+ goto fail;
case '6':
error_report("option -6 is deprecated, please use \'-o "
"compat6\' instead!");
- return 1;
+ goto fail;
case 'o':
- options = optarg;
+ if (!is_valid_option_list(optarg)) {
+ error_report("Invalid option list: %s", optarg);
+ goto fail;
+ }
+ if (!options) {
+ options = g_strdup(optarg);
+ } else {
+ char *old_options = options;
+ options = g_strdup_printf("%s,%s", options, optarg);
+ g_free(old_options);
+ }
break;
case 'q':
quiet = true;
}
/* Get the filename */
+ filename = (optind < argc) ? argv[optind] : NULL;
+ if (options && has_help_option(options)) {
+ g_free(options);
+ return print_block_option_help(filename, fmt);
+ }
+
if (optind >= argc) {
- help();
+ error_exit("Expecting image file name");
}
- filename = argv[optind++];
+ optind++;
/* Get image size, if specified */
if (optind < argc) {
error_report("kilobytes, megabytes, gigabytes, terabytes, "
"petabytes and exabytes.");
}
- return 1;
+ goto fail;
}
img_size = (uint64_t)sval;
}
if (optind != argc) {
- help();
- }
-
- if (options && is_help_option(options)) {
- return print_block_option_help(filename, fmt);
+ error_exit("Unexpected argument: %s", argv[optind]);
}
bdrv_img_create(filename, fmt, base_filename, base_fmt,
options, img_size, BDRV_O_FLAGS, &local_err, quiet);
- if (error_is_set(&local_err)) {
- error_report("%s", error_get_pretty(local_err));
+ if (local_err) {
+ error_report("%s: %s", filename, error_get_pretty(local_err));
error_free(local_err);
- return 1;
+ goto fail;
}
+ g_free(options);
return 0;
+
+fail:
+ g_free(options);
+ return 1;
}
static void dump_json_image_check(ImageCheck *check, bool quiet)
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
{"format", required_argument, 0, 'f'},
- {"repair", no_argument, 0, 'r'},
+ {"repair", required_argument, 0, 'r'},
{"output", required_argument, 0, OPTION_OUTPUT},
{0, 0, 0, 0}
};
} else if (!strcmp(optarg, "all")) {
fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
} else {
- help();
+ error_exit("Unknown option value for -r "
+ "(expecting 'leaks' or 'all'): %s", optarg);
}
break;
case OPTION_OUTPUT:
}
}
if (optind != argc - 1) {
- help();
+ error_exit("Expecting one image file name");
}
filename = argv[optind++];
return 1;
}
- bs = bdrv_new_open(filename, fmt, flags, true, quiet);
+ bs = bdrv_new_open("image", filename, fmt, flags, true, quiet);
if (!bs) {
return 1;
}
if (output_format == OFORMAT_HUMAN) {
error_report("This image format does not support checks");
}
- ret = 1;
+ ret = 63;
goto fail;
}
}
}
if (optind != argc - 1) {
- help();
+ error_exit("Expecting one image file name");
}
filename = argv[optind++];
return -1;
}
- bs = bdrv_new_open(filename, fmt, flags, true, quiet);
+ bs = bdrv_new_open("image", filename, fmt, flags, true, quiet);
if (!bs) {
return 1;
}
if (optind != argc - 2) {
- help();
+ error_exit("Expecting two image file names");
}
filename1 = argv[optind++];
filename2 = argv[optind++];
/* Initialize before goto out */
qemu_progress_init(progress, 2.0);
- bs1 = bdrv_new_open(filename1, fmt1, BDRV_O_FLAGS, true, quiet);
+ bs1 = bdrv_new_open("image 1", filename1, fmt1, BDRV_O_FLAGS, true, quiet);
if (!bs1) {
error_report("Can't open file %s", filename1);
ret = 2;
goto out3;
}
- bs2 = bdrv_new_open(filename2, fmt2, BDRV_O_FLAGS, true, quiet);
+ bs2 = bdrv_new_open("image 2", filename2, fmt2, BDRV_O_FLAGS, true, quiet);
if (!bs2) {
error_report("Can't open file %s", filename2);
ret = 2;
}
ret = compare_sectors(buf1, buf2, nb_sectors, &pnum);
if (ret || pnum != nb_sectors) {
- ret = 1;
qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
sectors_to_bytes(
ret ? sector_num : sector_num + pnum));
+ ret = 1;
goto out;
}
}
}
if (ret) {
if (ret < 0) {
- ret = 4;
error_report("Error while reading offset %" PRId64 ": %s",
sectors_to_bytes(sector_num), strerror(-ret));
+ ret = 4;
}
goto out;
}
filename_over, buf1, quiet);
if (ret) {
if (ret < 0) {
- ret = 4;
error_report("Error while reading offset %" PRId64
" of %s: %s", sectors_to_bytes(sector_num),
filename_over, strerror(-ret));
+ ret = 4;
}
goto out;
}
static int img_convert(int argc, char **argv)
{
- int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size,
- cluster_sectors, skip_create;
+ int c, n, n1, bs_n, bs_i, compress, cluster_sectors, skip_create;
+ int64_t ret = 0;
int progress = 0, flags;
const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
BlockDriver *drv, *proto_drv;
int64_t total_sectors, nb_sectors, sector_num, bs_offset;
uint64_t bs_sectors;
uint8_t * buf = NULL;
+ size_t bufsectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE;
const uint8_t *buf1;
BlockDriverInfo bdi;
QEMUOptionParameter *param = NULL, *create_options = NULL;
QEMUOptionParameter *out_baseimg_param;
char *options = NULL;
const char *snapshot_name = NULL;
- float local_progress = 0;
int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
bool quiet = false;
+ Error *local_err = NULL;
+ QemuOpts *sn_opts = NULL;
fmt = NULL;
out_fmt = "raw";
compress = 0;
skip_create = 0;
for(;;) {
- c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:qn");
+ c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:qnl:");
if (c == -1) {
break;
}
case 'e':
error_report("option -e is deprecated, please use \'-o "
"encryption\' instead!");
- return 1;
+ ret = -1;
+ goto fail_getopt;
case '6':
error_report("option -6 is deprecated, please use \'-o "
"compat6\' instead!");
- return 1;
+ ret = -1;
+ goto fail_getopt;
case 'o':
- options = optarg;
+ if (!is_valid_option_list(optarg)) {
+ error_report("Invalid option list: %s", optarg);
+ ret = -1;
+ goto fail_getopt;
+ }
+ if (!options) {
+ options = g_strdup(optarg);
+ } else {
+ char *old_options = options;
+ options = g_strdup_printf("%s,%s", options, optarg);
+ g_free(old_options);
+ }
break;
case 's':
snapshot_name = optarg;
break;
+ case 'l':
+ if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
+ sn_opts = qemu_opts_parse(&internal_snapshot_opts, optarg, 0);
+ if (!sn_opts) {
+ error_report("Failed in parsing snapshot param '%s'",
+ optarg);
+ ret = -1;
+ goto fail_getopt;
+ }
+ } else {
+ snapshot_name = optarg;
+ }
+ break;
case 'S':
{
int64_t sval;
sval = strtosz_suffix(optarg, &end, STRTOSZ_DEFSUFFIX_B);
if (sval < 0 || *end) {
error_report("Invalid minimum zero buffer size for sparse output specified");
- return 1;
+ ret = -1;
+ goto fail_getopt;
}
min_sparse = sval / BDRV_SECTOR_SIZE;
}
}
+ /* Initialize before goto out */
if (quiet) {
progress = 0;
}
+ qemu_progress_init(progress, 1.0);
- bs_n = argc - optind - 1;
- if (bs_n < 1) {
- help();
- }
-
- out_filename = argv[argc - 1];
- /* Initialize before goto out */
- qemu_progress_init(progress, 2.0);
+ bs_n = argc - optind - 1;
+ out_filename = bs_n >= 1 ? argv[argc - 1] : NULL;
- if (options && is_help_option(options)) {
+ if (options && has_help_option(options)) {
ret = print_block_option_help(out_filename, out_fmt);
goto out;
}
+ if (bs_n < 1) {
+ error_exit("Must specify image file name");
+ }
+
+
if (bs_n > 1 && out_baseimg) {
error_report("-B makes no sense when concatenating multiple input "
"images");
total_sectors = 0;
for (bs_i = 0; bs_i < bs_n; bs_i++) {
- bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true,
- quiet);
+ char *id = bs_n > 1 ? g_strdup_printf("source %d", bs_i)
+ : g_strdup("source");
+ bs[bs_i] = bdrv_new_open(id, argv[optind + bs_i], fmt, BDRV_O_FLAGS,
+ true, quiet);
+ g_free(id);
if (!bs[bs_i]) {
error_report("Could not open '%s'", argv[optind + bs_i]);
ret = -1;
total_sectors += bs_sectors;
}
- if (snapshot_name != NULL) {
+ if (sn_opts) {
+ ret = bdrv_snapshot_load_tmp(bs[0],
+ qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
+ qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
+ &local_err);
+ } else if (snapshot_name != NULL) {
if (bs_n > 1) {
error_report("No support for concatenating multiple snapshot");
ret = -1;
goto out;
}
- if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
- error_report("Failed to load snapshot");
- ret = -1;
- goto out;
- }
+
+ bdrv_snapshot_load_tmp_by_id_or_name(bs[0], snapshot_name, &local_err);
+ }
+ if (local_err) {
+ error_report("Failed to load snapshot: %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ ret = -1;
+ goto out;
}
/* Find driver and parse its options */
if (!skip_create) {
/* Create the new image */
- ret = bdrv_create(drv, out_filename, param);
+ ret = bdrv_create(drv, out_filename, param, &local_err);
if (ret < 0) {
- if (ret == -ENOTSUP) {
- error_report("Formatting not supported for file format '%s'",
- out_fmt);
- } else if (ret == -EFBIG) {
- error_report("The image size is too large for file format '%s'",
- out_fmt);
- } else {
- error_report("%s: error while converting %s: %s",
- out_filename, out_fmt, strerror(-ret));
- }
+ error_report("%s: error while converting %s: %s",
+ out_filename, out_fmt, error_get_pretty(local_err));
+ error_free(local_err);
goto out;
}
}
- flags = BDRV_O_RDWR;
+ flags = min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;
ret = bdrv_parse_cache_flags(cache, &flags);
if (ret < 0) {
error_report("Invalid cache option: %s", cache);
return -1;
}
- out_bs = bdrv_new_open(out_filename, out_fmt, flags, true, quiet);
+ out_bs = bdrv_new_open("target", out_filename, out_fmt, flags, true, quiet);
if (!out_bs) {
ret = -1;
goto out;
bs_i = 0;
bs_offset = 0;
bdrv_get_geometry(bs[0], &bs_sectors);
- buf = qemu_blockalign(out_bs, IO_BUF_SIZE);
+
+ /* increase bufsectors from the default 4096 (2M) if opt_transfer_length
+ * or discard_alignment of the out_bs is greater. Limit to 32768 (16MB)
+ * as maximum. */
+ bufsectors = MIN(32768,
+ MAX(bufsectors, MAX(out_bs->bl.opt_transfer_length,
+ out_bs->bl.discard_alignment))
+ );
+
+ buf = qemu_blockalign(out_bs, bufsectors * BDRV_SECTOR_SIZE);
if (skip_create) {
int64_t output_length = bdrv_getlength(out_bs);
}
}
- if (compress) {
- ret = bdrv_get_info(out_bs, &bdi);
- if (ret < 0) {
+ cluster_sectors = 0;
+ ret = bdrv_get_info(out_bs, &bdi);
+ if (ret < 0) {
+ if (compress) {
error_report("could not get block driver info");
goto out;
}
- cluster_size = bdi.cluster_size;
- if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) {
+ } else {
+ cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
+ }
+
+ if (compress) {
+ if (cluster_sectors <= 0 || cluster_sectors > bufsectors) {
error_report("invalid cluster size");
ret = -1;
goto out;
}
- cluster_sectors = cluster_size >> 9;
sector_num = 0;
nb_sectors = total_sectors;
- if (nb_sectors != 0) {
- local_progress = (float)100 /
- (nb_sectors / MIN(nb_sectors, cluster_sectors));
- }
for(;;) {
int64_t bs_num;
}
}
sector_num += n;
- qemu_progress_print(local_progress, 100);
+ qemu_progress_print(100.0 * sector_num / total_sectors, 0);
}
/* signal EOF to align */
bdrv_write_compressed(out_bs, 0, NULL, 0);
} else {
- int has_zero_init = bdrv_has_zero_init(out_bs);
+ int64_t sectors_to_read, sectors_read, sector_num_next_status;
+ bool count_allocated_sectors;
+ int has_zero_init = min_sparse ? bdrv_has_zero_init(out_bs) : 0;
- sector_num = 0; // total number of sectors converted so far
- nb_sectors = total_sectors - sector_num;
- if (nb_sectors != 0) {
- local_progress = (float)100 /
- (nb_sectors / MIN(nb_sectors, IO_BUF_SIZE / 512));
+ if (!has_zero_init && bdrv_can_write_zeroes_with_unmap(out_bs)) {
+ ret = bdrv_make_zero(out_bs, BDRV_REQ_MAY_UNMAP);
+ if (ret < 0) {
+ goto out;
+ }
+ has_zero_init = 1;
}
+ sectors_to_read = total_sectors;
+ count_allocated_sectors = progress && (out_baseimg || has_zero_init);
+restart:
+ sector_num = 0; // total number of sectors converted so far
+ sectors_read = 0;
+ sector_num_next_status = 0;
+
for(;;) {
nb_sectors = total_sectors - sector_num;
if (nb_sectors <= 0) {
+ if (count_allocated_sectors) {
+ sectors_to_read = sectors_read;
+ count_allocated_sectors = false;
+ goto restart;
+ }
+ ret = 0;
break;
}
- if (nb_sectors >= (IO_BUF_SIZE / 512)) {
- n = (IO_BUF_SIZE / 512);
- } else {
- n = nb_sectors;
- }
while (sector_num - bs_offset >= bs_sectors) {
bs_i ++;
sector_num, bs_i, bs_offset, bs_sectors); */
}
- if (n > bs_offset + bs_sectors - sector_num) {
- n = bs_offset + bs_sectors - sector_num;
- }
-
- /* If the output image is being created as a copy on write image,
- assume that sectors which are unallocated in the input image
- are present in both the output's and input's base images (no
- need to copy them). */
- if (out_baseimg) {
- ret = bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
- n, &n1);
+ if ((out_baseimg || has_zero_init) &&
+ sector_num >= sector_num_next_status) {
+ n = nb_sectors > INT_MAX ? INT_MAX : nb_sectors;
+ ret = bdrv_get_block_status(bs[bs_i], sector_num - bs_offset,
+ n, &n1);
if (ret < 0) {
- error_report("error while reading metadata for sector "
- "%" PRId64 ": %s",
- sector_num - bs_offset, strerror(-ret));
+ error_report("error while reading block status of sector %"
+ PRId64 ": %s", sector_num - bs_offset,
+ strerror(-ret));
goto out;
}
- if (!ret) {
+ /* If the output image is zero initialized, we are not working
+ * on a shared base and the input is zero we can skip the next
+ * n1 sectors */
+ if (has_zero_init && !out_baseimg && (ret & BDRV_BLOCK_ZERO)) {
sector_num += n1;
continue;
}
- /* The next 'n1' sectors are allocated in the input image. Copy
- only those as they may be followed by unallocated sectors. */
- n = n1;
- } else {
- n1 = n;
+ /* If the output image is being created as a copy on write
+ * image, assume that sectors which are unallocated in the
+ * input image are present in both the output's and input's
+ * base images (no need to copy them). */
+ if (out_baseimg) {
+ if (!(ret & BDRV_BLOCK_DATA)) {
+ sector_num += n1;
+ continue;
+ }
+ /* The next 'n1' sectors are allocated in the input image.
+ * Copy only those as they may be followed by unallocated
+ * sectors. */
+ nb_sectors = n1;
+ }
+ /* avoid redundant callouts to get_block_status */
+ sector_num_next_status = sector_num + n1;
+ }
+
+ n = MIN(nb_sectors, bufsectors);
+
+ /* round down request length to an aligned sector, but
+ * do not bother doing this on short requests. They happen
+ * when we found an all-zero area, and the next sector to
+ * write will not be sector_num + n. */
+ if (cluster_sectors > 0 && n >= cluster_sectors) {
+ int64_t next_aligned_sector = (sector_num + n);
+ next_aligned_sector -= next_aligned_sector % cluster_sectors;
+ if (sector_num + n > next_aligned_sector) {
+ n = next_aligned_sector - sector_num;
+ }
+ }
+
+ n = MIN(n, bs_sectors - (sector_num - bs_offset));
+
+ sectors_read += n;
+ if (count_allocated_sectors) {
+ sector_num += n;
+ continue;
}
+ n1 = n;
ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
if (ret < 0) {
error_report("error while reading sector %" PRId64 ": %s",
n -= n1;
buf1 += n1 * 512;
}
- qemu_progress_print(local_progress, 100);
+ qemu_progress_print(100.0 * sectors_read / sectors_to_read, 0);
}
}
out:
+ if (!ret) {
+ qemu_progress_print(100, 0);
+ }
qemu_progress_end();
free_option_parameters(create_options);
free_option_parameters(param);
qemu_vfree(buf);
+ if (sn_opts) {
+ qemu_opts_del(sn_opts);
+ }
if (out_bs) {
bdrv_unref(out_bs);
}
}
g_free(bs);
}
+fail_getopt:
+ g_free(options);
+
if (ret) {
return 1;
}
}
g_hash_table_insert(filenames, (gpointer)filename, NULL);
- bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING,
- false, false);
+ bs = bdrv_new_open("image", filename, fmt,
+ BDRV_O_FLAGS | BDRV_O_NO_BACKING, false, false);
if (!bs) {
goto err;
}
bdrv_query_image_info(bs, &info, &err);
- if (error_is_set(&err)) {
+ if (err) {
error_report("%s", error_get_pretty(err));
error_free(err);
+ bdrv_unref(bs);
goto err;
}
}
}
if (optind != argc - 1) {
- help();
+ error_exit("Expecting one image file name");
}
filename = argv[optind++];
(e->flags & BDRV_BLOCK_ZERO) ? "true" : "false",
(e->flags & BDRV_BLOCK_DATA) ? "true" : "false");
if (e->flags & BDRV_BLOCK_OFFSET_VALID) {
- printf(", 'offset': %"PRId64"", e->offset);
+ printf(", \"offset\": %"PRId64"", e->offset);
}
putchar('}');
break;
}
}
- if (optind >= argc) {
- help();
+ if (optind != argc - 1) {
+ error_exit("Expecting one image file name");
}
- filename = argv[optind++];
+ filename = argv[optind];
if (output && !strcmp(output, "json")) {
output_format = OFORMAT_JSON;
return 1;
}
- bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS, true, false);
+ bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS, true, false);
if (!bs) {
return 1;
}
return 0;
case 'l':
if (action) {
- help();
+ error_exit("Cannot mix '-l', '-a', '-c', '-d'");
return 0;
}
action = SNAPSHOT_LIST;
break;
case 'a':
if (action) {
- help();
+ error_exit("Cannot mix '-l', '-a', '-c', '-d'");
return 0;
}
action = SNAPSHOT_APPLY;
break;
case 'c':
if (action) {
- help();
+ error_exit("Cannot mix '-l', '-a', '-c', '-d'");
return 0;
}
action = SNAPSHOT_CREATE;
break;
case 'd':
if (action) {
- help();
+ error_exit("Cannot mix '-l', '-a', '-c', '-d'");
return 0;
}
action = SNAPSHOT_DELETE;
}
if (optind != argc - 1) {
- help();
+ error_exit("Expecting one image file name");
}
filename = argv[optind++];
/* Open the image */
- bs = bdrv_new_open(filename, NULL, bdrv_oflags, true, quiet);
+ bs = bdrv_new_open("image", filename, NULL, bdrv_oflags, true, quiet);
if (!bs) {
return 1;
}
case SNAPSHOT_DELETE:
bdrv_snapshot_delete_by_id_or_name(bs, snapshot_name, &err);
- if (error_is_set(&err)) {
+ if (err) {
error_report("Could not delete snapshot '%s': (%s)",
snapshot_name, error_get_pretty(err));
error_free(err);
progress = 0;
}
- if ((optind != argc - 1) || (!unsafe && !out_baseimg)) {
- help();
+ 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)");
}
filename = argv[optind++];
* Ignore the old backing file for unsafe rebase in case we want to correct
* the reference to a renamed or moved backing file.
*/
- bs = bdrv_new_open(filename, fmt, flags, true, quiet);
+ bs = bdrv_new_open("image", filename, fmt, flags, true, quiet);
if (!bs) {
return 1;
}
} else {
char backing_name[1024];
- bs_old_backing = bdrv_new("old_backing");
+ bs_old_backing = bdrv_new("old_backing", &error_abort);
bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
- ret = bdrv_open(bs_old_backing, backing_name, NULL, BDRV_O_FLAGS,
+ ret = bdrv_open(&bs_old_backing, backing_name, NULL, NULL, BDRV_O_FLAGS,
old_backing_drv, &local_err);
if (ret) {
error_report("Could not open old backing file '%s': %s",
goto out;
}
if (out_baseimg[0]) {
- bs_new_backing = bdrv_new("new_backing");
- ret = bdrv_open(bs_new_backing, out_baseimg, NULL, BDRV_O_FLAGS,
- new_backing_drv, &local_err);
+ bs_new_backing = bdrv_new("new_backing", &error_abort);
+ ret = bdrv_open(&bs_new_backing, out_baseimg, NULL, NULL,
+ BDRV_O_FLAGS, new_backing_drv, &local_err);
if (ret) {
error_report("Could not open new backing file '%s': %s",
out_baseimg, error_get_pretty(local_err));
/* Remove size from argv manually so that negative numbers are not treated
* as options by getopt. */
if (argc < 3) {
- help();
+ error_exit("Not enough arguments");
return 1;
}
}
}
if (optind != argc - 1) {
- help();
+ error_exit("Expecting one image file name");
}
filename = argv[optind++];
}
/* Parse size */
- param = qemu_opts_create_nofail(&resize_options);
+ param = qemu_opts_create(&resize_options, NULL, 0, &error_abort);
if (qemu_opt_set(param, BLOCK_OPT_SIZE, size)) {
/* Error message already printed when size parsing fails */
ret = -1;
n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0);
qemu_opts_del(param);
- bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet);
+ bs = bdrv_new_open("image", filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR,
+ true, quiet);
if (!bs) {
ret = -1;
goto out;
help();
break;
case 'o':
- options = optarg;
+ if (!is_valid_option_list(optarg)) {
+ error_report("Invalid option list: %s", optarg);
+ ret = -1;
+ goto out;
+ }
+ if (!options) {
+ options = g_strdup(optarg);
+ } else {
+ char *old_options = options;
+ options = g_strdup_printf("%s,%s", options, optarg);
+ g_free(old_options);
+ }
break;
case 'f':
fmt = optarg;
}
}
- if (optind != argc - 1) {
- help();
+ if (!options) {
+ error_exit("Must specify options (-o)");
}
- if (!options) {
- help();
+ filename = (optind == argc - 1) ? argv[argc - 1] : NULL;
+ if (fmt && has_help_option(options)) {
+ /* If a format is explicitly specified (and possibly no filename is
+ * given), print option help here */
+ ret = print_block_option_help(filename, fmt);
+ goto out;
}
- filename = argv[argc - 1];
+ if (optind != argc - 1) {
+ error_exit("Expecting one image file name");
+ }
- bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet);
+ bs = bdrv_new_open("image", filename, fmt,
+ BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet);
if (!bs) {
error_report("Could not open image '%s'", filename);
ret = -1;
fmt = bs->drv->format_name;
- if (is_help_option(options)) {
+ if (has_help_option(options)) {
+ /* If the format was auto-detected, print option help here */
ret = print_block_option_help(filename, fmt);
goto out;
}
}
free_option_parameters(create_options);
free_option_parameters(options_param);
+ g_free(options);
+
if (ret) {
return 1;
}
#endif
error_set_progname(argv[0]);
+ qemu_init_exec_dir(argv[0]);
qemu_init_main_loop();
bdrv_init();
- if (argc < 2)
- help();
+ if (argc < 2) {
+ error_exit("Not enough arguments");
+ }
cmdname = argv[1];
argc--; argv++;
}
/* not found */
- help();
- return 0;
+ error_exit("Command not found: %s", cmdname);
}