version 1.1.1.7, 2018/04/24 17:06:52
|
version 1.1.1.8, 2018/04/24 17:20:53
|
Line 22
|
Line 22
|
* THE SOFTWARE. |
* THE SOFTWARE. |
*/ |
*/ |
#include "qemu-common.h" |
#include "qemu-common.h" |
|
#include "qemu-option.h" |
#include "osdep.h" |
#include "osdep.h" |
#include "block_int.h" |
#include "block_int.h" |
#include <assert.h> |
#include <stdio.h> |
|
|
#ifdef _WIN32 |
#ifdef _WIN32 |
#define WIN32_LEAN_AND_MEAN |
|
#include <windows.h> |
#include <windows.h> |
#endif |
#endif |
|
|
|
typedef struct img_cmd_t { |
|
const char *name; |
|
int (*handler)(int argc, char **argv); |
|
} img_cmd_t; |
|
|
/* Default to cache=writeback as data integrity is not important for qemu-tcg. */ |
/* Default to cache=writeback as data integrity is not important for qemu-tcg. */ |
#define BRDV_O_FLAGS BDRV_O_CACHE_WB |
#define BRDV_O_FLAGS BDRV_O_CACHE_WB |
|
|
Line 58 static void help(void)
|
Line 63 static void help(void)
|
"QEMU disk image utility\n" |
"QEMU disk image utility\n" |
"\n" |
"\n" |
"Command syntax:\n" |
"Command syntax:\n" |
" create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n" |
#define DEF(option, callback, arg_string) \ |
" commit [-f fmt] filename\n" |
" " arg_string "\n" |
" convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n" |
#include "qemu-img-cmds.h" |
" info [-f fmt] filename\n" |
#undef DEF |
" snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename\n" |
#undef GEN_DOCS |
"\n" |
"\n" |
"Command parameters:\n" |
"Command parameters:\n" |
" 'filename' is a disk image filename\n" |
" 'filename' is a disk image filename\n" |
Line 78 static void help(void)
|
Line 83 static void help(void)
|
" supported any 'k' or 'K' is ignored\n" |
" supported any 'k' or 'K' is ignored\n" |
" 'output_filename' is the destination disk image filename\n" |
" 'output_filename' is the destination disk image filename\n" |
" 'output_fmt' is the destination format\n" |
" 'output_fmt' is the destination format\n" |
|
" 'options' is a comma separated list of format specific options in a\n" |
|
" name=value format. Use -o ? for an overview of the options supported by the\n" |
|
" used format\n" |
" '-c' indicates that target image must be compressed (qcow format only)\n" |
" '-c' indicates that target image must be compressed (qcow format only)\n" |
" '-e' indicates that the target image must be encrypted (qcow format only)\n" |
|
" '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n" |
|
" '-h' with or without a command shows this help and lists the supported formats\n" |
" '-h' with or without a command shows this help and lists the supported formats\n" |
"\n" |
"\n" |
"Parameters to snapshot subcommand:\n" |
"Parameters to snapshot subcommand:\n" |
Line 214 static BlockDriverState *bdrv_new_open(c
|
Line 220 static BlockDriverState *bdrv_new_open(c
|
return bs; |
return bs; |
} |
} |
|
|
|
static void add_old_style_options(const char *fmt, QEMUOptionParameter *list, |
|
int flags, const char *base_filename, const char *base_fmt) |
|
{ |
|
if (flags & BLOCK_FLAG_ENCRYPT) { |
|
if (set_option_parameter(list, BLOCK_OPT_ENCRYPT, "on")) { |
|
error("Encryption not supported for file format '%s'", fmt); |
|
} |
|
} |
|
if (flags & BLOCK_FLAG_COMPAT6) { |
|
if (set_option_parameter(list, BLOCK_OPT_COMPAT6, "on")) { |
|
error("VMDK version 6 not supported for file format '%s'", fmt); |
|
} |
|
} |
|
|
|
if (base_filename) { |
|
if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) { |
|
error("Backing file not supported for file format '%s'", fmt); |
|
} |
|
} |
|
if (base_fmt) { |
|
if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) { |
|
error("Backing file format not supported for file format '%s'", fmt); |
|
} |
|
} |
|
} |
|
|
static int img_create(int argc, char **argv) |
static int img_create(int argc, char **argv) |
{ |
{ |
int c, ret, flags; |
int c, ret, flags; |
const char *fmt = "raw"; |
const char *fmt = "raw"; |
|
const char *base_fmt = NULL; |
const char *filename; |
const char *filename; |
const char *base_filename = NULL; |
const char *base_filename = NULL; |
uint64_t size; |
|
const char *p; |
|
BlockDriver *drv; |
BlockDriver *drv; |
|
QEMUOptionParameter *param = NULL; |
|
char *options = NULL; |
|
|
flags = 0; |
flags = 0; |
for(;;) { |
for(;;) { |
c = getopt(argc, argv, "b:f:he6"); |
c = getopt(argc, argv, "F:b:f:he6o:"); |
if (c == -1) |
if (c == -1) |
break; |
break; |
switch(c) { |
switch(c) { |
case 'h': |
case 'h': |
help(); |
help(); |
break; |
break; |
|
case 'F': |
|
base_fmt = optarg; |
|
break; |
case 'b': |
case 'b': |
base_filename = optarg; |
base_filename = optarg; |
break; |
break; |
Line 245 static int img_create(int argc, char **a
|
Line 281 static int img_create(int argc, char **a
|
case '6': |
case '6': |
flags |= BLOCK_FLAG_COMPAT6; |
flags |= BLOCK_FLAG_COMPAT6; |
break; |
break; |
|
case 'o': |
|
options = optarg; |
|
break; |
} |
} |
} |
} |
|
|
|
/* Find driver and parse its options */ |
|
drv = bdrv_find_format(fmt); |
|
if (!drv) |
|
error("Unknown file format '%s'", fmt); |
|
|
|
if (options && !strcmp(options, "?")) { |
|
print_option_help(drv->create_options); |
|
return 0; |
|
} |
|
|
|
if (options) { |
|
param = parse_option_parameters(options, drv->create_options, param); |
|
if (param == NULL) { |
|
error("Invalid options for file format '%s'.", fmt); |
|
} |
|
} else { |
|
param = parse_option_parameters("", drv->create_options, param); |
|
} |
|
|
|
/* Get the filename */ |
if (optind >= argc) |
if (optind >= argc) |
help(); |
help(); |
filename = argv[optind++]; |
filename = argv[optind++]; |
size = 0; |
|
if (base_filename) { |
/* Add size to parameters */ |
BlockDriverState *bs; |
if (optind < argc) { |
bs = bdrv_new_open(base_filename, NULL); |
set_option_parameter(param, BLOCK_OPT_SIZE, argv[optind++]); |
bdrv_get_geometry(bs, &size); |
} |
size *= 512; |
|
bdrv_delete(bs); |
/* Add old-style options to parameters */ |
} else { |
add_old_style_options(fmt, param, flags, base_filename, base_fmt); |
if (optind >= argc) |
|
help(); |
// The size for the image must always be specified, with one exception: |
p = argv[optind]; |
// If we are using a backing file, we can obtain the size from there |
size = strtoul(p, (char **)&p, 0); |
if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == 0) { |
if (*p == 'M') { |
|
size *= 1024 * 1024; |
QEMUOptionParameter *backing_file = |
} else if (*p == 'G') { |
get_option_parameter(param, BLOCK_OPT_BACKING_FILE); |
size *= 1024 * 1024 * 1024; |
QEMUOptionParameter *backing_fmt = |
} else if (*p == 'k' || *p == 'K' || *p == '\0') { |
get_option_parameter(param, BLOCK_OPT_BACKING_FMT); |
size *= 1024; |
|
|
if (backing_file && backing_file->value.s) { |
|
BlockDriverState *bs; |
|
uint64_t size; |
|
const char *fmt = NULL; |
|
char buf[32]; |
|
|
|
if (backing_fmt && backing_fmt->value.s) { |
|
if (bdrv_find_format(backing_fmt->value.s)) { |
|
fmt = backing_fmt->value.s; |
|
} else { |
|
error("Unknown backing file format '%s'", |
|
backing_fmt->value.s); |
|
} |
|
} |
|
|
|
bs = bdrv_new_open(backing_file->value.s, fmt); |
|
bdrv_get_geometry(bs, &size); |
|
size *= 512; |
|
bdrv_delete(bs); |
|
|
|
snprintf(buf, sizeof(buf), "%" PRId64, size); |
|
set_option_parameter(param, BLOCK_OPT_SIZE, buf); |
} else { |
} else { |
help(); |
error("Image creation needs a size parameter"); |
} |
} |
} |
} |
drv = bdrv_find_format(fmt); |
|
if (!drv) |
printf("Formatting '%s', fmt=%s ", filename, fmt); |
error("Unknown file format '%s'", fmt); |
print_option_parameters(param); |
printf("Formatting '%s', fmt=%s", |
puts(""); |
filename, fmt); |
|
if (flags & BLOCK_FLAG_ENCRYPT) |
ret = bdrv_create(drv, filename, param); |
printf(", encrypted"); |
free_option_parameters(param); |
if (flags & BLOCK_FLAG_COMPAT6) |
|
printf(", compatibility level=6"); |
|
if (base_filename) { |
|
printf(", backing_file=%s", |
|
base_filename); |
|
} |
|
printf(", size=%" PRIu64 " kB\n", size / 1024); |
|
ret = bdrv_create(drv, filename, size / 512, base_filename, flags); |
|
if (ret < 0) { |
if (ret < 0) { |
if (ret == -ENOTSUP) { |
if (ret == -ENOTSUP) { |
error("Formatting or formatting option not supported for file format '%s'", fmt); |
error("Formatting or formatting option not supported for file format '%s'", fmt); |
Line 299 static int img_create(int argc, char **a
|
Line 374 static int img_create(int argc, char **a
|
return 0; |
return 0; |
} |
} |
|
|
|
static int img_check(int argc, char **argv) |
|
{ |
|
int c, ret; |
|
const char *filename, *fmt; |
|
BlockDriver *drv; |
|
BlockDriverState *bs; |
|
|
|
fmt = NULL; |
|
for(;;) { |
|
c = getopt(argc, argv, "f:h"); |
|
if (c == -1) |
|
break; |
|
switch(c) { |
|
case 'h': |
|
help(); |
|
break; |
|
case 'f': |
|
fmt = optarg; |
|
break; |
|
} |
|
} |
|
if (optind >= argc) |
|
help(); |
|
filename = argv[optind++]; |
|
|
|
bs = bdrv_new(""); |
|
if (!bs) |
|
error("Not enough memory"); |
|
if (fmt) { |
|
drv = bdrv_find_format(fmt); |
|
if (!drv) |
|
error("Unknown file format '%s'", fmt); |
|
} else { |
|
drv = NULL; |
|
} |
|
if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) { |
|
error("Could not open '%s'", filename); |
|
} |
|
ret = bdrv_check(bs); |
|
switch(ret) { |
|
case 0: |
|
printf("No errors were found on the image.\n"); |
|
break; |
|
case -ENOTSUP: |
|
error("This image format does not support checks"); |
|
break; |
|
default: |
|
if (ret < 0) { |
|
error("An error occurred during the check"); |
|
} else { |
|
printf("%d errors were found on the image.\n", ret); |
|
} |
|
break; |
|
} |
|
|
|
bdrv_delete(bs); |
|
return 0; |
|
} |
|
|
static int img_commit(int argc, char **argv) |
static int img_commit(int argc, char **argv) |
{ |
{ |
int c, ret; |
int c, ret; |
Line 409 static int img_convert(int argc, char **
|
Line 543 static int img_convert(int argc, char **
|
uint8_t buf[IO_BUF_SIZE]; |
uint8_t buf[IO_BUF_SIZE]; |
const uint8_t *buf1; |
const uint8_t *buf1; |
BlockDriverInfo bdi; |
BlockDriverInfo bdi; |
|
QEMUOptionParameter *param = NULL; |
|
char *options = NULL; |
|
|
fmt = NULL; |
fmt = NULL; |
out_fmt = "raw"; |
out_fmt = "raw"; |
out_baseimg = NULL; |
out_baseimg = NULL; |
flags = 0; |
flags = 0; |
for(;;) { |
for(;;) { |
c = getopt(argc, argv, "f:O:B:hce6"); |
c = getopt(argc, argv, "f:O:B:hce6o:"); |
if (c == -1) |
if (c == -1) |
break; |
break; |
switch(c) { |
switch(c) { |
Line 440 static int img_convert(int argc, char **
|
Line 576 static int img_convert(int argc, char **
|
case '6': |
case '6': |
flags |= BLOCK_FLAG_COMPAT6; |
flags |= BLOCK_FLAG_COMPAT6; |
break; |
break; |
|
case 'o': |
|
options = optarg; |
|
break; |
} |
} |
} |
} |
|
|
Line 464 static int img_convert(int argc, char **
|
Line 603 static int img_convert(int argc, char **
|
total_sectors += bs_sectors; |
total_sectors += bs_sectors; |
} |
} |
|
|
|
/* Find driver and parse its options */ |
drv = bdrv_find_format(out_fmt); |
drv = bdrv_find_format(out_fmt); |
if (!drv) |
if (!drv) |
error("Unknown file format '%s'", out_fmt); |
error("Unknown file format '%s'", out_fmt); |
if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2) |
|
error("Compression not supported for this file format"); |
|
if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2) |
|
error("Encryption not supported for this file format"); |
|
if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk) |
|
error("Alternative compatibility level not supported for this file format"); |
|
if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS) |
|
error("Compression and encryption not supported at the same time"); |
|
|
|
ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags); |
if (options && !strcmp(options, "?")) { |
|
print_option_help(drv->create_options); |
|
return 0; |
|
} |
|
|
|
if (options) { |
|
param = parse_option_parameters(options, drv->create_options, param); |
|
if (param == NULL) { |
|
error("Invalid options for file format '%s'.", out_fmt); |
|
} |
|
} else { |
|
param = parse_option_parameters("", drv->create_options, param); |
|
} |
|
|
|
set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512); |
|
add_old_style_options(out_fmt, param, flags, out_baseimg, NULL); |
|
|
|
/* Check if compression is supported */ |
|
if (flags & BLOCK_FLAG_COMPRESS) { |
|
QEMUOptionParameter *encryption = |
|
get_option_parameter(param, BLOCK_OPT_ENCRYPT); |
|
|
|
if (!drv->bdrv_write_compressed) { |
|
error("Compression not supported for this file format"); |
|
} |
|
|
|
if (encryption && encryption->value.n) { |
|
error("Compression and encryption not supported at the same time"); |
|
} |
|
} |
|
|
|
/* Create the new image */ |
|
ret = bdrv_create(drv, out_filename, param); |
|
free_option_parameters(param); |
|
|
if (ret < 0) { |
if (ret < 0) { |
if (ret == -ENOTSUP) { |
if (ret == -ENOTSUP) { |
error("Formatting not supported for file format '%s'", out_fmt); |
error("Formatting not supported for file format '%s'", out_fmt); |
Line 580 static int img_convert(int argc, char **
|
Line 746 static int img_convert(int argc, char **
|
if (n > bs_offset + bs_sectors - sector_num) |
if (n > bs_offset + bs_sectors - sector_num) |
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, |
if (strcmp(drv->format_name, "host_device")) { |
assume that sectors which are unallocated in the input image |
/* If the output image is being created as a copy on write image, |
are present in both the output's and input's base images (no |
assume that sectors which are unallocated in the input image |
need to copy them). */ |
are present in both the output's and input's base images (no |
if (out_baseimg) { |
need to copy them). */ |
if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) { |
if (out_baseimg) { |
sector_num += n1; |
if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, |
continue; |
n, &n1)) { |
} |
sector_num += n1; |
/* The next 'n1' sectors are allocated in the input image. Copy |
continue; |
only those as they may be followed by unallocated sectors. */ |
} |
n = n1; |
/* 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 (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) |
if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) |
Line 603 static int img_convert(int argc, char **
|
Line 774 static int img_convert(int argc, char **
|
while (n > 0) { |
while (n > 0) { |
/* If the output image is being created as a copy on write image, |
/* If the output image is being created as a copy on write image, |
copy all sectors even the ones containing only NUL bytes, |
copy all sectors even the ones containing only NUL bytes, |
because they may differ from the sectors in the base image. */ |
because they may differ from the sectors in the base image. |
if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) { |
|
|
If the output is to a host device, we also write out |
|
sectors that are entirely 0, since whatever data was |
|
already there is garbage, not 0s. */ |
|
if (strcmp(drv->format_name, "host_device") == 0 || out_baseimg || |
|
is_allocated_sectors(buf1, n, &n1)) { |
if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) |
if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) |
error("error while writing"); |
error("error while writing"); |
} |
} |
Line 753 static int img_info(int argc, char **arg
|
Line 929 static int img_info(int argc, char **arg
|
#define SNAPSHOT_APPLY 3 |
#define SNAPSHOT_APPLY 3 |
#define SNAPSHOT_DELETE 4 |
#define SNAPSHOT_DELETE 4 |
|
|
static void img_snapshot(int argc, char **argv) |
static int img_snapshot(int argc, char **argv) |
{ |
{ |
BlockDriverState *bs; |
BlockDriverState *bs; |
QEMUSnapshotInfo sn; |
QEMUSnapshotInfo sn; |
Line 770 static void img_snapshot(int argc, char
|
Line 946 static void img_snapshot(int argc, char
|
switch(c) { |
switch(c) { |
case 'h': |
case 'h': |
help(); |
help(); |
return; |
return 0; |
case 'l': |
case 'l': |
if (action) { |
if (action) { |
help(); |
help(); |
return; |
return 0; |
} |
} |
action = SNAPSHOT_LIST; |
action = SNAPSHOT_LIST; |
break; |
break; |
case 'a': |
case 'a': |
if (action) { |
if (action) { |
help(); |
help(); |
return; |
return 0; |
} |
} |
action = SNAPSHOT_APPLY; |
action = SNAPSHOT_APPLY; |
snapshot_name = optarg; |
snapshot_name = optarg; |
Line 789 static void img_snapshot(int argc, char
|
Line 965 static void img_snapshot(int argc, char
|
case 'c': |
case 'c': |
if (action) { |
if (action) { |
help(); |
help(); |
return; |
return 0; |
} |
} |
action = SNAPSHOT_CREATE; |
action = SNAPSHOT_CREATE; |
snapshot_name = optarg; |
snapshot_name = optarg; |
Line 797 static void img_snapshot(int argc, char
|
Line 973 static void img_snapshot(int argc, char
|
case 'd': |
case 'd': |
if (action) { |
if (action) { |
help(); |
help(); |
return; |
return 0; |
} |
} |
action = SNAPSHOT_DELETE; |
action = SNAPSHOT_DELETE; |
snapshot_name = optarg; |
snapshot_name = optarg; |
Line 855 static void img_snapshot(int argc, char
|
Line 1031 static void img_snapshot(int argc, char
|
|
|
/* Cleanup */ |
/* Cleanup */ |
bdrv_delete(bs); |
bdrv_delete(bs); |
|
|
|
return 0; |
} |
} |
|
|
|
static const img_cmd_t img_cmds[] = { |
|
#define DEF(option, callback, arg_string) \ |
|
{ option, callback }, |
|
#include "qemu-img-cmds.h" |
|
#undef DEF |
|
#undef GEN_DOCS |
|
{ NULL, NULL, }, |
|
}; |
|
|
int main(int argc, char **argv) |
int main(int argc, char **argv) |
{ |
{ |
const char *cmd; |
const img_cmd_t *cmd; |
|
const char *cmdname; |
|
|
bdrv_init(); |
bdrv_init(); |
if (argc < 2) |
if (argc < 2) |
help(); |
help(); |
cmd = argv[1]; |
cmdname = argv[1]; |
argc--; argv++; |
argc--; argv++; |
if (!strcmp(cmd, "create")) { |
|
img_create(argc, argv); |
/* find the command */ |
} else if (!strcmp(cmd, "commit")) { |
for(cmd = img_cmds; cmd->name != NULL; cmd++) { |
img_commit(argc, argv); |
if (!strcmp(cmdname, cmd->name)) { |
} else if (!strcmp(cmd, "convert")) { |
return cmd->handler(argc, argv); |
img_convert(argc, argv); |
} |
} else if (!strcmp(cmd, "info")) { |
|
img_info(argc, argv); |
|
} else if (!strcmp(cmd, "snapshot")) { |
|
img_snapshot(argc, argv); |
|
} else { |
|
help(); |
|
} |
} |
|
|
|
/* not found */ |
|
help(); |
return 0; |
return 0; |
} |
} |