blob: e300f911cb5b05b7e68323ad47d80129f4caf8cc [file] [log] [blame]
bellardea2384d2004-08-01 21:59:26 +00001/*
bellardfb43f4d2006-08-07 21:34:46 +00002 * QEMU disk image utility
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard68d0f702008-01-06 17:21:48 +00004 * Copyright (c) 2003-2008 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellardea2384d2004-08-01 21:59:26 +00006 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
pbrookfaf07962007-11-11 02:51:17 +000024#include "qemu-common.h"
Kevin Wolf9ea2ea72009-05-18 16:42:11 +020025#include "qemu-option.h"
aliguorif7b4a942009-01-07 17:40:15 +000026#include "osdep.h"
thsec36ba12007-09-16 21:59:02 +000027#include "block_int.h"
aliguori9230eaf2009-03-28 17:55:19 +000028#include <stdio.h>
bellardea2384d2004-08-01 21:59:26 +000029
bellarde8445332006-06-14 15:32:10 +000030#ifdef _WIN32
31#include <windows.h>
32#endif
33
Anthony Liguoric227f092009-10-01 16:12:16 -050034typedef struct img_cmd_t {
Stuart Brady153859b2009-06-07 00:42:17 +010035 const char *name;
36 int (*handler)(int argc, char **argv);
Anthony Liguoric227f092009-10-01 16:12:16 -050037} img_cmd_t;
Stuart Brady153859b2009-06-07 00:42:17 +010038
aurel32137519c2008-11-30 19:12:49 +000039/* Default to cache=writeback as data integrity is not important for qemu-tcg. */
Stefan Hajnocziadfe0782010-04-13 10:29:35 +010040#define BDRV_O_FLAGS BDRV_O_CACHE_WB
aurel32137519c2008-11-30 19:12:49 +000041
MORITA Kazutakac2abcce2010-06-21 04:26:35 +090042static void error(const char *fmt, ...)
bellardea2384d2004-08-01 21:59:26 +000043{
44 va_list ap;
45 va_start(ap, fmt);
bellard57d1a2b2004-08-03 21:15:11 +000046 fprintf(stderr, "qemu-img: ");
bellardea2384d2004-08-01 21:59:26 +000047 vfprintf(stderr, fmt, ap);
48 fprintf(stderr, "\n");
bellardea2384d2004-08-01 21:59:26 +000049 va_end(ap);
50}
51
52static void format_print(void *opaque, const char *name)
53{
54 printf(" %s", name);
55}
56
blueswir1d2c639d2009-01-24 18:19:25 +000057/* Please keep in synch with qemu-img.texi */
pbrook3f379ab2007-11-11 03:33:13 +000058static void help(void)
bellardea2384d2004-08-01 21:59:26 +000059{
Paolo Bonzinie00291c2010-02-04 16:49:56 +010060 const char *help_msg =
61 "qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
malc3f020d72010-02-08 12:04:56 +030062 "usage: qemu-img command [command options]\n"
63 "QEMU disk image utility\n"
64 "\n"
65 "Command syntax:\n"
Stuart Brady153859b2009-06-07 00:42:17 +010066#define DEF(option, callback, arg_string) \
67 " " arg_string "\n"
68#include "qemu-img-cmds.h"
69#undef DEF
70#undef GEN_DOCS
malc3f020d72010-02-08 12:04:56 +030071 "\n"
72 "Command parameters:\n"
73 " 'filename' is a disk image filename\n"
74 " 'fmt' is the disk image format. It is guessed automatically in most cases\n"
75 " 'size' is the disk image size in bytes. Optional suffixes\n"
76 " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
77 " and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
78 " 'output_filename' is the destination disk image filename\n"
79 " 'output_fmt' is the destination format\n"
80 " 'options' is a comma separated list of format specific options in a\n"
81 " name=value format. Use -o ? for an overview of the options supported by the\n"
82 " used format\n"
83 " '-c' indicates that target image must be compressed (qcow format only)\n"
84 " '-u' enables unsafe rebasing. It is assumed that old and new backing file\n"
85 " match exactly. The image doesn't need a working backing file before\n"
86 " rebasing in this case (useful for renaming the backing file)\n"
87 " '-h' with or without a command shows this help and lists the supported formats\n"
88 "\n"
89 "Parameters to snapshot subcommand:\n"
90 " 'snapshot' is the name of the snapshot to create, apply or delete\n"
91 " '-a' applies a snapshot (revert disk to saved state)\n"
92 " '-c' creates a snapshot\n"
93 " '-d' deletes a snapshot\n"
Paolo Bonzinie00291c2010-02-04 16:49:56 +010094 " '-l' lists all snapshots in the given image\n";
95
96 printf("%s\nSupported formats:", help_msg);
bellardea2384d2004-08-01 21:59:26 +000097 bdrv_iterate_format(format_print, NULL);
98 printf("\n");
99 exit(1);
100}
101
bellardea2384d2004-08-01 21:59:26 +0000102#if defined(WIN32)
103/* XXX: put correct support for win32 */
104static int read_password(char *buf, int buf_size)
105{
106 int c, i;
107 printf("Password: ");
108 fflush(stdout);
109 i = 0;
110 for(;;) {
111 c = getchar();
112 if (c == '\n')
113 break;
114 if (i < (buf_size - 1))
115 buf[i++] = c;
116 }
117 buf[i] = '\0';
118 return 0;
119}
120
121#else
122
123#include <termios.h>
124
125static struct termios oldtty;
126
127static void term_exit(void)
128{
129 tcsetattr (0, TCSANOW, &oldtty);
130}
131
132static void term_init(void)
133{
134 struct termios tty;
135
136 tcgetattr (0, &tty);
137 oldtty = tty;
138
139 tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
140 |INLCR|IGNCR|ICRNL|IXON);
141 tty.c_oflag |= OPOST;
142 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
143 tty.c_cflag &= ~(CSIZE|PARENB);
144 tty.c_cflag |= CS8;
145 tty.c_cc[VMIN] = 1;
146 tty.c_cc[VTIME] = 0;
ths3b46e622007-09-17 08:09:54 +0000147
bellardea2384d2004-08-01 21:59:26 +0000148 tcsetattr (0, TCSANOW, &tty);
149
150 atexit(term_exit);
151}
152
pbrook3f379ab2007-11-11 03:33:13 +0000153static int read_password(char *buf, int buf_size)
bellardea2384d2004-08-01 21:59:26 +0000154{
155 uint8_t ch;
156 int i, ret;
157
158 printf("password: ");
159 fflush(stdout);
160 term_init();
161 i = 0;
162 for(;;) {
163 ret = read(0, &ch, 1);
164 if (ret == -1) {
165 if (errno == EAGAIN || errno == EINTR) {
166 continue;
167 } else {
168 ret = -1;
169 break;
170 }
171 } else if (ret == 0) {
172 ret = -1;
173 break;
174 } else {
175 if (ch == '\r') {
176 ret = 0;
177 break;
178 }
179 if (i < (buf_size - 1))
180 buf[i++] = ch;
181 }
182 }
183 term_exit();
184 buf[i] = '\0';
185 printf("\n");
186 return ret;
187}
188#endif
189
bellard75c23802004-08-27 21:28:58 +0000190static BlockDriverState *bdrv_new_open(const char *filename,
Sheng Yang9bc378c2010-01-29 10:15:06 +0800191 const char *fmt,
Stefan Hajnoczif163d072010-04-13 10:29:34 +0100192 int flags)
bellard75c23802004-08-27 21:28:58 +0000193{
194 BlockDriverState *bs;
195 BlockDriver *drv;
196 char password[256];
197
198 bs = bdrv_new("");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900199 if (!bs) {
bellard75c23802004-08-27 21:28:58 +0000200 error("Not enough memory");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900201 goto fail;
202 }
bellard75c23802004-08-27 21:28:58 +0000203 if (fmt) {
204 drv = bdrv_find_format(fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900205 if (!drv) {
bellard75c23802004-08-27 21:28:58 +0000206 error("Unknown file format '%s'", fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900207 goto fail;
208 }
bellard75c23802004-08-27 21:28:58 +0000209 } else {
210 drv = NULL;
211 }
Kevin Wolfd6e90982010-03-31 14:40:27 +0200212 if (bdrv_open(bs, filename, flags, drv) < 0) {
bellard75c23802004-08-27 21:28:58 +0000213 error("Could not open '%s'", filename);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900214 goto fail;
bellard75c23802004-08-27 21:28:58 +0000215 }
216 if (bdrv_is_encrypted(bs)) {
217 printf("Disk image '%s' is encrypted.\n", filename);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900218 if (read_password(password, sizeof(password)) < 0) {
bellard75c23802004-08-27 21:28:58 +0000219 error("No password given");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900220 goto fail;
221 }
222 if (bdrv_set_key(bs, password) < 0) {
bellard75c23802004-08-27 21:28:58 +0000223 error("invalid password");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900224 goto fail;
225 }
bellard75c23802004-08-27 21:28:58 +0000226 }
227 return bs;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900228fail:
229 if (bs) {
230 bdrv_delete(bs);
231 }
232 return NULL;
bellard75c23802004-08-27 21:28:58 +0000233}
234
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900235static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
Kevin Wolfefa84d42009-05-18 16:42:12 +0200236 int flags, const char *base_filename, const char *base_fmt)
237{
238 if (flags & BLOCK_FLAG_ENCRYPT) {
239 if (set_option_parameter(list, BLOCK_OPT_ENCRYPT, "on")) {
240 error("Encryption not supported for file format '%s'", fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900241 return -1;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200242 }
243 }
244 if (flags & BLOCK_FLAG_COMPAT6) {
245 if (set_option_parameter(list, BLOCK_OPT_COMPAT6, "on")) {
246 error("VMDK version 6 not supported for file format '%s'", fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900247 return -1;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200248 }
249 }
250
251 if (base_filename) {
252 if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
253 error("Backing file not supported for file format '%s'", fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900254 return -1;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200255 }
256 }
257 if (base_fmt) {
258 if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
259 error("Backing file format not supported for file format '%s'", fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900260 return -1;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200261 }
262 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900263 return 0;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200264}
265
bellardea2384d2004-08-01 21:59:26 +0000266static int img_create(int argc, char **argv)
267{
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900268 int c, ret = 0, flags;
bellardea2384d2004-08-01 21:59:26 +0000269 const char *fmt = "raw";
aliguori9230eaf2009-03-28 17:55:19 +0000270 const char *base_fmt = NULL;
bellardea2384d2004-08-01 21:59:26 +0000271 const char *filename;
272 const char *base_filename = NULL;
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900273 BlockDriver *drv, *proto_drv;
274 QEMUOptionParameter *param = NULL, *create_options = NULL;
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200275 char *options = NULL;
ths3b46e622007-09-17 08:09:54 +0000276
thsec36ba12007-09-16 21:59:02 +0000277 flags = 0;
bellardea2384d2004-08-01 21:59:26 +0000278 for(;;) {
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200279 c = getopt(argc, argv, "F:b:f:he6o:");
bellardea2384d2004-08-01 21:59:26 +0000280 if (c == -1)
281 break;
282 switch(c) {
283 case 'h':
284 help();
285 break;
aliguori9230eaf2009-03-28 17:55:19 +0000286 case 'F':
287 base_fmt = optarg;
288 break;
bellardea2384d2004-08-01 21:59:26 +0000289 case 'b':
290 base_filename = optarg;
291 break;
292 case 'f':
293 fmt = optarg;
294 break;
295 case 'e':
thsec36ba12007-09-16 21:59:02 +0000296 flags |= BLOCK_FLAG_ENCRYPT;
bellardea2384d2004-08-01 21:59:26 +0000297 break;
thsd8871c52007-10-24 16:11:42 +0000298 case '6':
thsec36ba12007-09-16 21:59:02 +0000299 flags |= BLOCK_FLAG_COMPAT6;
thsd8871c52007-10-24 16:11:42 +0000300 break;
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200301 case 'o':
302 options = optarg;
303 break;
bellardea2384d2004-08-01 21:59:26 +0000304 }
305 }
aliguori9230eaf2009-03-28 17:55:19 +0000306
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900307 /* Get the filename */
308 if (optind >= argc)
309 help();
310 filename = argv[optind++];
311
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200312 /* Find driver and parse its options */
bellardea2384d2004-08-01 21:59:26 +0000313 drv = bdrv_find_format(fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900314 if (!drv) {
bellardea2384d2004-08-01 21:59:26 +0000315 error("Unknown file format '%s'", fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900316 return 1;
317 }
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200318
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900319 proto_drv = bdrv_find_protocol(filename);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900320 if (!proto_drv) {
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900321 error("Unknown protocol '%s'", filename);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900322 return 1;
323 }
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900324
325 create_options = append_option_parameters(create_options,
326 drv->create_options);
327 create_options = append_option_parameters(create_options,
328 proto_drv->create_options);
329
Kevin Wolfdb08adf2009-06-04 15:39:38 +0200330 if (options && !strcmp(options, "?")) {
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900331 print_option_help(create_options);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900332 goto out;
Kevin Wolfdb08adf2009-06-04 15:39:38 +0200333 }
334
Kevin Wolf9f566402009-10-28 11:36:07 +0100335 /* Create parameter list with default values */
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900336 param = parse_option_parameters("", create_options, param);
Kevin Wolf9f566402009-10-28 11:36:07 +0100337 set_option_parameter_int(param, BLOCK_OPT_SIZE, -1);
338
339 /* Parse -o options */
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200340 if (options) {
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900341 param = parse_option_parameters(options, create_options, param);
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200342 if (param == NULL) {
343 error("Invalid options for file format '%s'.", fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900344 ret = -1;
345 goto out;
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200346 }
bellard75c23802004-08-27 21:28:58 +0000347 }
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200348
349 /* Add size to parameters */
350 if (optind < argc) {
351 set_option_parameter(param, BLOCK_OPT_SIZE, argv[optind++]);
352 }
353
354 /* Add old-style options to parameters */
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900355 ret = add_old_style_options(fmt, param, flags, base_filename, base_fmt);
356 if (ret < 0) {
357 goto out;
358 }
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200359
360 // The size for the image must always be specified, with one exception:
361 // If we are using a backing file, we can obtain the size from there
Kevin Wolf9f566402009-10-28 11:36:07 +0100362 if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200363
364 QEMUOptionParameter *backing_file =
365 get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
366 QEMUOptionParameter *backing_fmt =
367 get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
368
369 if (backing_file && backing_file->value.s) {
370 BlockDriverState *bs;
371 uint64_t size;
372 const char *fmt = NULL;
373 char buf[32];
374
375 if (backing_fmt && backing_fmt->value.s) {
376 if (bdrv_find_format(backing_fmt->value.s)) {
377 fmt = backing_fmt->value.s;
378 } else {
379 error("Unknown backing file format '%s'",
380 backing_fmt->value.s);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900381 ret = -1;
382 goto out;
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200383 }
384 }
385
Stefan Hajnocziadfe0782010-04-13 10:29:35 +0100386 bs = bdrv_new_open(backing_file->value.s, fmt, BDRV_O_FLAGS);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900387 if (!bs) {
388 ret = -1;
389 goto out;
390 }
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200391 bdrv_get_geometry(bs, &size);
392 size *= 512;
393 bdrv_delete(bs);
394
395 snprintf(buf, sizeof(buf), "%" PRId64, size);
396 set_option_parameter(param, BLOCK_OPT_SIZE, buf);
397 } else {
398 error("Image creation needs a size parameter");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900399 ret = -1;
400 goto out;
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200401 }
402 }
403
404 printf("Formatting '%s', fmt=%s ", filename, fmt);
405 print_option_parameters(param);
406 puts("");
407
408 ret = bdrv_create(drv, filename, param);
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900409 free_option_parameters(create_options);
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200410 free_option_parameters(param);
411
bellardea2384d2004-08-01 21:59:26 +0000412 if (ret < 0) {
413 if (ret == -ENOTSUP) {
bellard3c565212004-09-29 21:29:14 +0000414 error("Formatting or formatting option not supported for file format '%s'", fmt);
aurel326e9ea0c2009-04-15 14:42:46 +0000415 } else if (ret == -EFBIG) {
416 error("The image size is too large for file format '%s'", fmt);
bellardea2384d2004-08-01 21:59:26 +0000417 } else {
Juan Quintela3e7896d2010-03-04 10:00:38 +0100418 error("%s: error while creating %s: %s", filename, fmt, strerror(-ret));
bellardea2384d2004-08-01 21:59:26 +0000419 }
420 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900421out:
422 if (ret) {
423 return 1;
424 }
bellardea2384d2004-08-01 21:59:26 +0000425 return 0;
426}
427
Kevin Wolfe076f332010-06-29 11:43:13 +0200428/*
429 * Checks an image for consistency. Exit codes:
430 *
431 * 0 - Check completed, image is good
432 * 1 - Check not completed because of internal errors
433 * 2 - Check completed, image is corrupted
434 * 3 - Check completed, image has leaked clusters, but is good otherwise
435 */
aliguori15859692009-04-21 23:11:53 +0000436static int img_check(int argc, char **argv)
437{
438 int c, ret;
439 const char *filename, *fmt;
aliguori15859692009-04-21 23:11:53 +0000440 BlockDriverState *bs;
Kevin Wolfe076f332010-06-29 11:43:13 +0200441 BdrvCheckResult result;
aliguori15859692009-04-21 23:11:53 +0000442
443 fmt = NULL;
444 for(;;) {
445 c = getopt(argc, argv, "f:h");
446 if (c == -1)
447 break;
448 switch(c) {
449 case 'h':
450 help();
451 break;
452 case 'f':
453 fmt = optarg;
454 break;
455 }
456 }
457 if (optind >= argc)
458 help();
459 filename = argv[optind++];
460
Stefan Hajnocziadfe0782010-04-13 10:29:35 +0100461 bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900462 if (!bs) {
463 return 1;
464 }
Kevin Wolfe076f332010-06-29 11:43:13 +0200465 ret = bdrv_check(bs, &result);
466
467 if (ret == -ENOTSUP) {
aliguori15859692009-04-21 23:11:53 +0000468 error("This image format does not support checks");
Kevin Wolfe076f332010-06-29 11:43:13 +0200469 bdrv_delete(bs);
470 return 1;
471 }
472
473 if (!(result.corruptions || result.leaks || result.check_errors)) {
474 printf("No errors were found on the image.\n");
475 } else {
476 if (result.corruptions) {
477 printf("\n%d errors were found on the image.\n"
478 "Data may be corrupted, or further writes to the image "
479 "may corrupt it.\n",
480 result.corruptions);
aliguori15859692009-04-21 23:11:53 +0000481 }
Kevin Wolfe076f332010-06-29 11:43:13 +0200482
483 if (result.leaks) {
484 printf("\n%d leaked clusters were found on the image.\n"
485 "This means waste of disk space, but no harm to data.\n",
486 result.leaks);
487 }
488
489 if (result.check_errors) {
490 printf("\n%d internal errors have occurred during the check.\n",
491 result.check_errors);
492 }
aliguori15859692009-04-21 23:11:53 +0000493 }
494
495 bdrv_delete(bs);
Kevin Wolfe076f332010-06-29 11:43:13 +0200496
497 if (ret < 0 || result.check_errors) {
498 printf("\nAn error has occurred during the check: %s\n"
499 "The check is not complete and may have missed error.\n",
500 strerror(-ret));
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900501 return 1;
502 }
Kevin Wolfe076f332010-06-29 11:43:13 +0200503
504 if (result.corruptions) {
505 return 2;
506 } else if (result.leaks) {
507 return 3;
508 } else {
509 return 0;
510 }
aliguori15859692009-04-21 23:11:53 +0000511}
512
bellardea2384d2004-08-01 21:59:26 +0000513static int img_commit(int argc, char **argv)
514{
515 int c, ret;
516 const char *filename, *fmt;
bellardea2384d2004-08-01 21:59:26 +0000517 BlockDriverState *bs;
518
519 fmt = NULL;
520 for(;;) {
521 c = getopt(argc, argv, "f:h");
522 if (c == -1)
523 break;
524 switch(c) {
525 case 'h':
526 help();
527 break;
528 case 'f':
529 fmt = optarg;
530 break;
531 }
532 }
ths5fafdf22007-09-16 21:08:06 +0000533 if (optind >= argc)
bellardea2384d2004-08-01 21:59:26 +0000534 help();
535 filename = argv[optind++];
536
Stefan Hajnocziadfe0782010-04-13 10:29:35 +0100537 bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900538 if (!bs) {
539 return 1;
540 }
bellardea2384d2004-08-01 21:59:26 +0000541 ret = bdrv_commit(bs);
542 switch(ret) {
543 case 0:
544 printf("Image committed.\n");
545 break;
546 case -ENOENT:
547 error("No disk inserted");
548 break;
549 case -EACCES:
550 error("Image is read-only");
551 break;
552 case -ENOTSUP:
553 error("Image is already committed");
554 break;
555 default:
556 error("Error while committing image");
557 break;
558 }
559
560 bdrv_delete(bs);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900561 if (ret) {
562 return 1;
563 }
bellardea2384d2004-08-01 21:59:26 +0000564 return 0;
565}
566
567static int is_not_zero(const uint8_t *sector, int len)
568{
569 int i;
570 len >>= 2;
571 for(i = 0;i < len; i++) {
572 if (((uint32_t *)sector)[i] != 0)
573 return 1;
574 }
575 return 0;
576}
577
thsf58c7b32008-06-05 21:53:49 +0000578/*
579 * Returns true iff the first sector pointed to by 'buf' contains at least
580 * a non-NUL byte.
581 *
582 * 'pnum' is set to the number of sectors (including and immediately following
583 * the first one) that are known to be in the same allocated/unallocated state.
584 */
bellardea2384d2004-08-01 21:59:26 +0000585static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
586{
587 int v, i;
588
589 if (n <= 0) {
590 *pnum = 0;
591 return 0;
592 }
593 v = is_not_zero(buf, 512);
594 for(i = 1; i < n; i++) {
595 buf += 512;
596 if (v != is_not_zero(buf, 512))
597 break;
598 }
599 *pnum = i;
600 return v;
601}
602
Kevin Wolf3e85c6f2010-01-12 12:55:18 +0100603/*
604 * Compares two buffers sector by sector. Returns 0 if the first sector of both
605 * buffers matches, non-zero otherwise.
606 *
607 * pnum is set to the number of sectors (including and immediately following
608 * the first one) that are known to have the same comparison result
609 */
610static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
611 int *pnum)
612{
613 int res, i;
614
615 if (n <= 0) {
616 *pnum = 0;
617 return 0;
618 }
619
620 res = !!memcmp(buf1, buf2, 512);
621 for(i = 1; i < n; i++) {
622 buf1 += 512;
623 buf2 += 512;
624
625 if (!!memcmp(buf1, buf2, 512) != res) {
626 break;
627 }
628 }
629
630 *pnum = i;
631 return res;
632}
633
Kevin Wolf80ee15a2009-09-15 12:30:43 +0200634#define IO_BUF_SIZE (2 * 1024 * 1024)
bellardea2384d2004-08-01 21:59:26 +0000635
636static int img_convert(int argc, char **argv)
637{
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900638 int c, ret = 0, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
thsf58c7b32008-06-05 21:53:49 +0000639 const char *fmt, *out_fmt, *out_baseimg, *out_filename;
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900640 BlockDriver *drv, *proto_drv;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900641 BlockDriverState **bs = NULL, *out_bs = NULL;
ths96b8f132007-12-17 01:35:20 +0000642 int64_t total_sectors, nb_sectors, sector_num, bs_offset;
643 uint64_t bs_sectors;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900644 uint8_t * buf = NULL;
bellardea2384d2004-08-01 21:59:26 +0000645 const uint8_t *buf1;
bellardfaea38e2006-08-05 21:31:00 +0000646 BlockDriverInfo bdi;
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900647 QEMUOptionParameter *param = NULL, *create_options = NULL;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200648 char *options = NULL;
bellardea2384d2004-08-01 21:59:26 +0000649
650 fmt = NULL;
651 out_fmt = "raw";
thsf58c7b32008-06-05 21:53:49 +0000652 out_baseimg = NULL;
thsec36ba12007-09-16 21:59:02 +0000653 flags = 0;
bellardea2384d2004-08-01 21:59:26 +0000654 for(;;) {
Kevin Wolfefa84d42009-05-18 16:42:12 +0200655 c = getopt(argc, argv, "f:O:B:hce6o:");
bellardea2384d2004-08-01 21:59:26 +0000656 if (c == -1)
657 break;
658 switch(c) {
659 case 'h':
660 help();
661 break;
662 case 'f':
663 fmt = optarg;
664 break;
665 case 'O':
666 out_fmt = optarg;
667 break;
thsf58c7b32008-06-05 21:53:49 +0000668 case 'B':
669 out_baseimg = optarg;
670 break;
bellardea2384d2004-08-01 21:59:26 +0000671 case 'c':
thsec36ba12007-09-16 21:59:02 +0000672 flags |= BLOCK_FLAG_COMPRESS;
bellardea2384d2004-08-01 21:59:26 +0000673 break;
674 case 'e':
thsec36ba12007-09-16 21:59:02 +0000675 flags |= BLOCK_FLAG_ENCRYPT;
676 break;
677 case '6':
678 flags |= BLOCK_FLAG_COMPAT6;
bellardea2384d2004-08-01 21:59:26 +0000679 break;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200680 case 'o':
681 options = optarg;
682 break;
bellardea2384d2004-08-01 21:59:26 +0000683 }
684 }
ths3b46e622007-09-17 08:09:54 +0000685
balrog926c2d22007-10-31 01:11:44 +0000686 bs_n = argc - optind - 1;
687 if (bs_n < 1) help();
688
689 out_filename = argv[argc - 1];
thsf58c7b32008-06-05 21:53:49 +0000690
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900691 if (bs_n > 1 && out_baseimg) {
thsf58c7b32008-06-05 21:53:49 +0000692 error("-B makes no sense when concatenating multiple input images");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900693 return 1;
694 }
balrog926c2d22007-10-31 01:11:44 +0000695
696 bs = calloc(bs_n, sizeof(BlockDriverState *));
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900697 if (!bs) {
balrog926c2d22007-10-31 01:11:44 +0000698 error("Out of memory");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900699 return 1;
700 }
balrog926c2d22007-10-31 01:11:44 +0000701
702 total_sectors = 0;
703 for (bs_i = 0; bs_i < bs_n; bs_i++) {
Stefan Hajnocziadfe0782010-04-13 10:29:35 +0100704 bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900705 if (!bs[bs_i]) {
balrog926c2d22007-10-31 01:11:44 +0000706 error("Could not open '%s'", argv[optind + bs_i]);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900707 ret = -1;
708 goto out;
709 }
balrog926c2d22007-10-31 01:11:44 +0000710 bdrv_get_geometry(bs[bs_i], &bs_sectors);
711 total_sectors += bs_sectors;
712 }
bellardea2384d2004-08-01 21:59:26 +0000713
Kevin Wolfefa84d42009-05-18 16:42:12 +0200714 /* Find driver and parse its options */
bellardea2384d2004-08-01 21:59:26 +0000715 drv = bdrv_find_format(out_fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900716 if (!drv) {
thsd34dda52007-02-10 22:59:40 +0000717 error("Unknown file format '%s'", out_fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900718 ret = -1;
719 goto out;
720 }
balrog926c2d22007-10-31 01:11:44 +0000721
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900722 proto_drv = bdrv_find_protocol(out_filename);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900723 if (!proto_drv) {
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900724 error("Unknown protocol '%s'", out_filename);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900725 ret = -1;
726 goto out;
727 }
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900728
729 create_options = append_option_parameters(create_options,
730 drv->create_options);
731 create_options = append_option_parameters(create_options,
732 proto_drv->create_options);
Kevin Wolfdb08adf2009-06-04 15:39:38 +0200733 if (options && !strcmp(options, "?")) {
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900734 print_option_help(create_options);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900735 goto out;
Kevin Wolfdb08adf2009-06-04 15:39:38 +0200736 }
737
Kevin Wolfefa84d42009-05-18 16:42:12 +0200738 if (options) {
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900739 param = parse_option_parameters(options, create_options, param);
Kevin Wolfefa84d42009-05-18 16:42:12 +0200740 if (param == NULL) {
741 error("Invalid options for file format '%s'.", out_fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900742 ret = -1;
743 goto out;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200744 }
745 } else {
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900746 param = parse_option_parameters("", create_options, param);
Kevin Wolfefa84d42009-05-18 16:42:12 +0200747 }
748
749 set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900750 ret = add_old_style_options(out_fmt, param, flags, out_baseimg, NULL);
751 if (ret < 0) {
752 goto out;
753 }
Kevin Wolfefa84d42009-05-18 16:42:12 +0200754
755 /* Check if compression is supported */
756 if (flags & BLOCK_FLAG_COMPRESS) {
757 QEMUOptionParameter *encryption =
758 get_option_parameter(param, BLOCK_OPT_ENCRYPT);
759
760 if (!drv->bdrv_write_compressed) {
761 error("Compression not supported for this file format");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900762 ret = -1;
763 goto out;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200764 }
765
766 if (encryption && encryption->value.n) {
767 error("Compression and encryption not supported at the same time");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900768 ret = -1;
769 goto out;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200770 }
771 }
772
773 /* Create the new image */
774 ret = bdrv_create(drv, out_filename, param);
bellardea2384d2004-08-01 21:59:26 +0000775 if (ret < 0) {
776 if (ret == -ENOTSUP) {
aliguori93c65b42009-04-05 17:40:43 +0000777 error("Formatting not supported for file format '%s'", out_fmt);
aurel326e9ea0c2009-04-15 14:42:46 +0000778 } else if (ret == -EFBIG) {
779 error("The image size is too large for file format '%s'", out_fmt);
bellardea2384d2004-08-01 21:59:26 +0000780 } else {
Juan Quintela3e7896d2010-03-04 10:00:38 +0100781 error("%s: error while converting %s: %s", out_filename, out_fmt, strerror(-ret));
bellardea2384d2004-08-01 21:59:26 +0000782 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900783 goto out;
bellardea2384d2004-08-01 21:59:26 +0000784 }
ths3b46e622007-09-17 08:09:54 +0000785
Stefan Hajnocziadfe0782010-04-13 10:29:35 +0100786 out_bs = bdrv_new_open(out_filename, out_fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900787 if (!out_bs) {
788 ret = -1;
789 goto out;
790 }
bellardea2384d2004-08-01 21:59:26 +0000791
balrog926c2d22007-10-31 01:11:44 +0000792 bs_i = 0;
793 bs_offset = 0;
794 bdrv_get_geometry(bs[0], &bs_sectors);
TeLeMand6771bf2010-02-08 16:20:00 +0800795 buf = qemu_malloc(IO_BUF_SIZE);
balrog926c2d22007-10-31 01:11:44 +0000796
797 if (flags & BLOCK_FLAG_COMPRESS) {
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900798 ret = bdrv_get_info(out_bs, &bdi);
799 if (ret < 0) {
bellardfaea38e2006-08-05 21:31:00 +0000800 error("could not get block driver info");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900801 goto out;
802 }
bellardfaea38e2006-08-05 21:31:00 +0000803 cluster_size = bdi.cluster_size;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900804 if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) {
bellardea2384d2004-08-01 21:59:26 +0000805 error("invalid cluster size");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900806 ret = -1;
807 goto out;
808 }
bellardea2384d2004-08-01 21:59:26 +0000809 cluster_sectors = cluster_size >> 9;
810 sector_num = 0;
811 for(;;) {
balrog926c2d22007-10-31 01:11:44 +0000812 int64_t bs_num;
813 int remainder;
814 uint8_t *buf2;
815
bellardea2384d2004-08-01 21:59:26 +0000816 nb_sectors = total_sectors - sector_num;
817 if (nb_sectors <= 0)
818 break;
819 if (nb_sectors >= cluster_sectors)
820 n = cluster_sectors;
821 else
822 n = nb_sectors;
balrog926c2d22007-10-31 01:11:44 +0000823
824 bs_num = sector_num - bs_offset;
825 assert (bs_num >= 0);
826 remainder = n;
827 buf2 = buf;
828 while (remainder > 0) {
829 int nlow;
830 while (bs_num == bs_sectors) {
831 bs_i++;
832 assert (bs_i < bs_n);
833 bs_offset += bs_sectors;
834 bdrv_get_geometry(bs[bs_i], &bs_sectors);
835 bs_num = 0;
Blue Swirl0bfcd592010-05-22 08:02:12 +0000836 /* printf("changing part: sector_num=%" PRId64 ", "
837 "bs_i=%d, bs_offset=%" PRId64 ", bs_sectors=%" PRId64
838 "\n", sector_num, bs_i, bs_offset, bs_sectors); */
balrog926c2d22007-10-31 01:11:44 +0000839 }
840 assert (bs_num < bs_sectors);
841
842 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
843
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900844 ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);
845 if (ret < 0) {
balrog926c2d22007-10-31 01:11:44 +0000846 error("error while reading");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900847 goto out;
848 }
balrog926c2d22007-10-31 01:11:44 +0000849
850 buf2 += nlow * 512;
851 bs_num += nlow;
852
853 remainder -= nlow;
854 }
855 assert (remainder == 0);
856
bellardea2384d2004-08-01 21:59:26 +0000857 if (n < cluster_sectors)
858 memset(buf + n * 512, 0, cluster_size - n * 512);
859 if (is_not_zero(buf, cluster_size)) {
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900860 ret = bdrv_write_compressed(out_bs, sector_num, buf,
861 cluster_sectors);
862 if (ret != 0) {
bellardec3757d2006-06-14 15:50:07 +0000863 error("error while compressing sector %" PRId64,
864 sector_num);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900865 goto out;
866 }
bellardea2384d2004-08-01 21:59:26 +0000867 }
868 sector_num += n;
869 }
bellardfaea38e2006-08-05 21:31:00 +0000870 /* signal EOF to align */
871 bdrv_write_compressed(out_bs, 0, NULL, 0);
bellardea2384d2004-08-01 21:59:26 +0000872 } else {
Kevin Wolff2feebb2010-04-14 17:30:35 +0200873 int has_zero_init = bdrv_has_zero_init(out_bs);
874
thsf58c7b32008-06-05 21:53:49 +0000875 sector_num = 0; // total number of sectors converted so far
bellardea2384d2004-08-01 21:59:26 +0000876 for(;;) {
877 nb_sectors = total_sectors - sector_num;
878 if (nb_sectors <= 0)
879 break;
880 if (nb_sectors >= (IO_BUF_SIZE / 512))
881 n = (IO_BUF_SIZE / 512);
882 else
883 n = nb_sectors;
balrog926c2d22007-10-31 01:11:44 +0000884
885 while (sector_num - bs_offset >= bs_sectors) {
886 bs_i ++;
887 assert (bs_i < bs_n);
888 bs_offset += bs_sectors;
889 bdrv_get_geometry(bs[bs_i], &bs_sectors);
Blue Swirl0bfcd592010-05-22 08:02:12 +0000890 /* printf("changing part: sector_num=%" PRId64 ", bs_i=%d, "
891 "bs_offset=%" PRId64 ", bs_sectors=%" PRId64 "\n",
balrog926c2d22007-10-31 01:11:44 +0000892 sector_num, bs_i, bs_offset, bs_sectors); */
893 }
894
895 if (n > bs_offset + bs_sectors - sector_num)
896 n = bs_offset + bs_sectors - sector_num;
897
Kevin Wolff2feebb2010-04-14 17:30:35 +0200898 if (has_zero_init) {
Akkarit Sangpetchd0320442009-07-17 10:02:15 +0200899 /* If the output image is being created as a copy on write image,
900 assume that sectors which are unallocated in the input image
901 are present in both the output's and input's base images (no
902 need to copy them). */
903 if (out_baseimg) {
904 if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
905 n, &n1)) {
906 sector_num += n1;
907 continue;
908 }
909 /* The next 'n1' sectors are allocated in the input image. Copy
910 only those as they may be followed by unallocated sectors. */
911 n = n1;
aliguori93c65b42009-04-05 17:40:43 +0000912 }
aliguori93c65b42009-04-05 17:40:43 +0000913 } else {
914 n1 = n;
thsf58c7b32008-06-05 21:53:49 +0000915 }
916
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900917 ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
918 if (ret < 0) {
bellardea2384d2004-08-01 21:59:26 +0000919 error("error while reading");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900920 goto out;
921 }
bellardea2384d2004-08-01 21:59:26 +0000922 /* NOTE: at the same time we convert, we do not write zero
923 sectors to have a chance to compress the image. Ideally, we
924 should add a specific call to have the info to go faster */
925 buf1 = buf;
926 while (n > 0) {
thsf58c7b32008-06-05 21:53:49 +0000927 /* If the output image is being created as a copy on write image,
928 copy all sectors even the ones containing only NUL bytes,
aliguori93c65b42009-04-05 17:40:43 +0000929 because they may differ from the sectors in the base image.
930
931 If the output is to a host device, we also write out
932 sectors that are entirely 0, since whatever data was
933 already there is garbage, not 0s. */
Kevin Wolff2feebb2010-04-14 17:30:35 +0200934 if (!has_zero_init || out_baseimg ||
aliguori93c65b42009-04-05 17:40:43 +0000935 is_allocated_sectors(buf1, n, &n1)) {
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900936 ret = bdrv_write(out_bs, sector_num, buf1, n1);
937 if (ret < 0) {
bellardea2384d2004-08-01 21:59:26 +0000938 error("error while writing");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900939 goto out;
940 }
bellardea2384d2004-08-01 21:59:26 +0000941 }
942 sector_num += n1;
943 n -= n1;
944 buf1 += n1 * 512;
945 }
946 }
947 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900948out:
949 free_option_parameters(create_options);
950 free_option_parameters(param);
TeLeMand6771bf2010-02-08 16:20:00 +0800951 qemu_free(buf);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900952 if (out_bs) {
953 bdrv_delete(out_bs);
954 }
955 for (bs_i = 0; bs_i < bs_n; bs_i++) {
956 if (bs[bs_i]) {
957 bdrv_delete(bs[bs_i]);
958 }
959 }
balrog926c2d22007-10-31 01:11:44 +0000960 free(bs);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900961 if (ret) {
962 return 1;
963 }
bellardea2384d2004-08-01 21:59:26 +0000964 return 0;
965}
966
bellard57d1a2b2004-08-03 21:15:11 +0000967#ifdef _WIN32
968static int64_t get_allocated_file_size(const char *filename)
969{
bellarde8445332006-06-14 15:32:10 +0000970 typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
971 get_compressed_t get_compressed;
bellard57d1a2b2004-08-03 21:15:11 +0000972 struct _stati64 st;
bellarde8445332006-06-14 15:32:10 +0000973
974 /* WinNT support GetCompressedFileSize to determine allocate size */
975 get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
976 if (get_compressed) {
977 DWORD high, low;
978 low = get_compressed(filename, &high);
979 if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
980 return (((int64_t) high) << 32) + low;
981 }
982
ths5fafdf22007-09-16 21:08:06 +0000983 if (_stati64(filename, &st) < 0)
bellard57d1a2b2004-08-03 21:15:11 +0000984 return -1;
985 return st.st_size;
986}
987#else
988static int64_t get_allocated_file_size(const char *filename)
989{
990 struct stat st;
ths5fafdf22007-09-16 21:08:06 +0000991 if (stat(filename, &st) < 0)
bellard57d1a2b2004-08-03 21:15:11 +0000992 return -1;
993 return (int64_t)st.st_blocks * 512;
994}
995#endif
996
bellardfaea38e2006-08-05 21:31:00 +0000997static void dump_snapshots(BlockDriverState *bs)
998{
999 QEMUSnapshotInfo *sn_tab, *sn;
1000 int nb_sns, i;
1001 char buf[256];
1002
1003 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
1004 if (nb_sns <= 0)
1005 return;
1006 printf("Snapshot list:\n");
1007 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
1008 for(i = 0; i < nb_sns; i++) {
1009 sn = &sn_tab[i];
1010 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
1011 }
1012 qemu_free(sn_tab);
1013}
1014
bellardea2384d2004-08-01 21:59:26 +00001015static int img_info(int argc, char **argv)
1016{
1017 int c;
1018 const char *filename, *fmt;
bellardea2384d2004-08-01 21:59:26 +00001019 BlockDriverState *bs;
1020 char fmt_name[128], size_buf[128], dsize_buf[128];
ths96b8f132007-12-17 01:35:20 +00001021 uint64_t total_sectors;
1022 int64_t allocated_size;
bellard93b6b2a2006-08-01 15:51:11 +00001023 char backing_filename[1024];
1024 char backing_filename2[1024];
bellardfaea38e2006-08-05 21:31:00 +00001025 BlockDriverInfo bdi;
bellardea2384d2004-08-01 21:59:26 +00001026
1027 fmt = NULL;
1028 for(;;) {
1029 c = getopt(argc, argv, "f:h");
1030 if (c == -1)
1031 break;
1032 switch(c) {
1033 case 'h':
1034 help();
1035 break;
1036 case 'f':
1037 fmt = optarg;
1038 break;
1039 }
1040 }
ths5fafdf22007-09-16 21:08:06 +00001041 if (optind >= argc)
bellardea2384d2004-08-01 21:59:26 +00001042 help();
1043 filename = argv[optind++];
1044
Stefan Hajnocziadfe0782010-04-13 10:29:35 +01001045 bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001046 if (!bs) {
1047 return 1;
1048 }
bellardea2384d2004-08-01 21:59:26 +00001049 bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
1050 bdrv_get_geometry(bs, &total_sectors);
1051 get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
bellard57d1a2b2004-08-03 21:15:11 +00001052 allocated_size = get_allocated_file_size(filename);
1053 if (allocated_size < 0)
blueswir1a10ea302008-08-24 10:30:33 +00001054 snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
bellardde167e42005-04-28 21:15:08 +00001055 else
ths5fafdf22007-09-16 21:08:06 +00001056 get_human_readable_size(dsize_buf, sizeof(dsize_buf),
bellardde167e42005-04-28 21:15:08 +00001057 allocated_size);
bellardea2384d2004-08-01 21:59:26 +00001058 printf("image: %s\n"
1059 "file format: %s\n"
bellardec3757d2006-06-14 15:50:07 +00001060 "virtual size: %s (%" PRId64 " bytes)\n"
bellardea2384d2004-08-01 21:59:26 +00001061 "disk size: %s\n",
ths5fafdf22007-09-16 21:08:06 +00001062 filename, fmt_name, size_buf,
bellardec3757d2006-06-14 15:50:07 +00001063 (total_sectors * 512),
bellardea2384d2004-08-01 21:59:26 +00001064 dsize_buf);
1065 if (bdrv_is_encrypted(bs))
1066 printf("encrypted: yes\n");
bellardfaea38e2006-08-05 21:31:00 +00001067 if (bdrv_get_info(bs, &bdi) >= 0) {
ths5fafdf22007-09-16 21:08:06 +00001068 if (bdi.cluster_size != 0)
bellardfaea38e2006-08-05 21:31:00 +00001069 printf("cluster_size: %d\n", bdi.cluster_size);
1070 }
bellard93b6b2a2006-08-01 15:51:11 +00001071 bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
bellardfaea38e2006-08-05 21:31:00 +00001072 if (backing_filename[0] != '\0') {
bellard93b6b2a2006-08-01 15:51:11 +00001073 path_combine(backing_filename2, sizeof(backing_filename2),
1074 filename, backing_filename);
ths5fafdf22007-09-16 21:08:06 +00001075 printf("backing file: %s (actual path: %s)\n",
bellard93b6b2a2006-08-01 15:51:11 +00001076 backing_filename,
1077 backing_filename2);
bellardfaea38e2006-08-05 21:31:00 +00001078 }
1079 dump_snapshots(bs);
bellardea2384d2004-08-01 21:59:26 +00001080 bdrv_delete(bs);
1081 return 0;
1082}
1083
aliguorif7b4a942009-01-07 17:40:15 +00001084#define SNAPSHOT_LIST 1
1085#define SNAPSHOT_CREATE 2
1086#define SNAPSHOT_APPLY 3
1087#define SNAPSHOT_DELETE 4
1088
Stuart Brady153859b2009-06-07 00:42:17 +01001089static int img_snapshot(int argc, char **argv)
aliguorif7b4a942009-01-07 17:40:15 +00001090{
1091 BlockDriverState *bs;
1092 QEMUSnapshotInfo sn;
1093 char *filename, *snapshot_name = NULL;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001094 int c, ret = 0, bdrv_oflags;
aliguorif7b4a942009-01-07 17:40:15 +00001095 int action = 0;
1096 qemu_timeval tv;
1097
Naphtali Spreif5edb012010-01-17 16:48:13 +02001098 bdrv_oflags = BDRV_O_RDWR;
aliguorif7b4a942009-01-07 17:40:15 +00001099 /* Parse commandline parameters */
1100 for(;;) {
1101 c = getopt(argc, argv, "la:c:d:h");
1102 if (c == -1)
1103 break;
1104 switch(c) {
1105 case 'h':
1106 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001107 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001108 case 'l':
1109 if (action) {
1110 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001111 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001112 }
1113 action = SNAPSHOT_LIST;
Naphtali Spreif5edb012010-01-17 16:48:13 +02001114 bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
aliguorif7b4a942009-01-07 17:40:15 +00001115 break;
1116 case 'a':
1117 if (action) {
1118 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001119 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001120 }
1121 action = SNAPSHOT_APPLY;
1122 snapshot_name = optarg;
1123 break;
1124 case 'c':
1125 if (action) {
1126 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001127 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001128 }
1129 action = SNAPSHOT_CREATE;
1130 snapshot_name = optarg;
1131 break;
1132 case 'd':
1133 if (action) {
1134 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001135 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001136 }
1137 action = SNAPSHOT_DELETE;
1138 snapshot_name = optarg;
1139 break;
1140 }
1141 }
1142
1143 if (optind >= argc)
1144 help();
1145 filename = argv[optind++];
1146
1147 /* Open the image */
Stefan Hajnoczif163d072010-04-13 10:29:34 +01001148 bs = bdrv_new_open(filename, NULL, bdrv_oflags);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001149 if (!bs) {
1150 return 1;
1151 }
aliguorif7b4a942009-01-07 17:40:15 +00001152
1153 /* Perform the requested action */
1154 switch(action) {
1155 case SNAPSHOT_LIST:
1156 dump_snapshots(bs);
1157 break;
1158
1159 case SNAPSHOT_CREATE:
1160 memset(&sn, 0, sizeof(sn));
1161 pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
1162
1163 qemu_gettimeofday(&tv);
1164 sn.date_sec = tv.tv_sec;
1165 sn.date_nsec = tv.tv_usec * 1000;
1166
1167 ret = bdrv_snapshot_create(bs, &sn);
1168 if (ret)
1169 error("Could not create snapshot '%s': %d (%s)",
1170 snapshot_name, ret, strerror(-ret));
1171 break;
1172
1173 case SNAPSHOT_APPLY:
1174 ret = bdrv_snapshot_goto(bs, snapshot_name);
1175 if (ret)
1176 error("Could not apply snapshot '%s': %d (%s)",
1177 snapshot_name, ret, strerror(-ret));
1178 break;
1179
1180 case SNAPSHOT_DELETE:
1181 ret = bdrv_snapshot_delete(bs, snapshot_name);
1182 if (ret)
1183 error("Could not delete snapshot '%s': %d (%s)",
1184 snapshot_name, ret, strerror(-ret));
1185 break;
1186 }
1187
1188 /* Cleanup */
1189 bdrv_delete(bs);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001190 if (ret) {
1191 return 1;
1192 }
Stuart Brady153859b2009-06-07 00:42:17 +01001193 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001194}
1195
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001196static int img_rebase(int argc, char **argv)
1197{
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001198 BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL;
Stefan Hajnoczif163d072010-04-13 10:29:34 +01001199 BlockDriver *old_backing_drv, *new_backing_drv;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001200 char *filename;
Kevin Wolfe53dbee2010-03-02 12:14:31 +01001201 const char *fmt, *out_basefmt, *out_baseimg;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001202 int c, flags, ret;
1203 int unsafe = 0;
1204
1205 /* Parse commandline parameters */
Kevin Wolfe53dbee2010-03-02 12:14:31 +01001206 fmt = NULL;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001207 out_baseimg = NULL;
1208 out_basefmt = NULL;
1209
1210 for(;;) {
Kevin Wolfe53dbee2010-03-02 12:14:31 +01001211 c = getopt(argc, argv, "uhf:F:b:");
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001212 if (c == -1)
1213 break;
1214 switch(c) {
1215 case 'h':
1216 help();
1217 return 0;
Kevin Wolfe53dbee2010-03-02 12:14:31 +01001218 case 'f':
1219 fmt = optarg;
1220 break;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001221 case 'F':
1222 out_basefmt = optarg;
1223 break;
1224 case 'b':
1225 out_baseimg = optarg;
1226 break;
1227 case 'u':
1228 unsafe = 1;
1229 break;
1230 }
1231 }
1232
1233 if ((optind >= argc) || !out_baseimg)
1234 help();
1235 filename = argv[optind++];
1236
1237 /*
1238 * Open the images.
1239 *
1240 * Ignore the old backing file for unsafe rebase in case we want to correct
1241 * the reference to a renamed or moved backing file.
1242 */
Stefan Hajnocziadfe0782010-04-13 10:29:35 +01001243 flags = BDRV_O_FLAGS | BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
Stefan Hajnoczif163d072010-04-13 10:29:34 +01001244 bs = bdrv_new_open(filename, fmt, flags);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001245 if (!bs) {
1246 return 1;
1247 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001248
1249 /* Find the right drivers for the backing files */
1250 old_backing_drv = NULL;
1251 new_backing_drv = NULL;
1252
1253 if (!unsafe && bs->backing_format[0] != '\0') {
1254 old_backing_drv = bdrv_find_format(bs->backing_format);
1255 if (old_backing_drv == NULL) {
1256 error("Invalid format name: '%s'", bs->backing_format);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001257 ret = -1;
1258 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001259 }
1260 }
1261
1262 if (out_basefmt != NULL) {
1263 new_backing_drv = bdrv_find_format(out_basefmt);
1264 if (new_backing_drv == NULL) {
1265 error("Invalid format name: '%s'", out_basefmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001266 ret = -1;
1267 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001268 }
1269 }
1270
1271 /* For safe rebasing we need to compare old and new backing file */
1272 if (unsafe) {
1273 /* Make the compiler happy */
1274 bs_old_backing = NULL;
1275 bs_new_backing = NULL;
1276 } else {
1277 char backing_name[1024];
1278
1279 bs_old_backing = bdrv_new("old_backing");
1280 bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001281 ret = bdrv_open(bs_old_backing, backing_name, BDRV_O_FLAGS,
1282 old_backing_drv);
1283 if (ret) {
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001284 error("Could not open old backing file '%s'", backing_name);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001285 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001286 }
1287
1288 bs_new_backing = bdrv_new("new_backing");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001289 ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS | BDRV_O_RDWR,
1290 new_backing_drv);
1291 if (ret) {
Kevin Wolf584771e2010-02-17 12:33:17 +01001292 error("Could not open new backing file '%s'", out_baseimg);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001293 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001294 }
1295 }
1296
1297 /*
1298 * Check each unallocated cluster in the COW file. If it is unallocated,
1299 * accesses go to the backing file. We must therefore compare this cluster
1300 * in the old and new backing file, and if they differ we need to copy it
1301 * from the old backing file into the COW file.
1302 *
1303 * If qemu-img crashes during this step, no harm is done. The content of
1304 * the image is the same as the original one at any time.
1305 */
1306 if (!unsafe) {
1307 uint64_t num_sectors;
1308 uint64_t sector;
Kevin Wolfcc60e322010-04-29 14:47:48 +02001309 int n;
TeLeMand6771bf2010-02-08 16:20:00 +08001310 uint8_t * buf_old;
1311 uint8_t * buf_new;
1312
1313 buf_old = qemu_malloc(IO_BUF_SIZE);
1314 buf_new = qemu_malloc(IO_BUF_SIZE);
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001315
1316 bdrv_get_geometry(bs, &num_sectors);
1317
1318 for (sector = 0; sector < num_sectors; sector += n) {
1319
1320 /* How many sectors can we handle with the next read? */
1321 if (sector + (IO_BUF_SIZE / 512) <= num_sectors) {
1322 n = (IO_BUF_SIZE / 512);
1323 } else {
1324 n = num_sectors - sector;
1325 }
1326
1327 /* If the cluster is allocated, we don't need to take action */
Kevin Wolfcc60e322010-04-29 14:47:48 +02001328 ret = bdrv_is_allocated(bs, sector, n, &n);
1329 if (ret) {
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001330 continue;
1331 }
1332
1333 /* Read old and new backing file */
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001334 ret = bdrv_read(bs_old_backing, sector, buf_old, n);
1335 if (ret < 0) {
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001336 error("error while reading from old backing file");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001337 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001338 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001339 ret = bdrv_read(bs_new_backing, sector, buf_new, n);
1340 if (ret < 0) {
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001341 error("error while reading from new backing file");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001342 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001343 }
1344
1345 /* If they differ, we need to write to the COW file */
1346 uint64_t written = 0;
1347
1348 while (written < n) {
1349 int pnum;
1350
1351 if (compare_sectors(buf_old + written * 512,
Kevin Wolf60b1bd42010-02-17 12:32:59 +01001352 buf_new + written * 512, n - written, &pnum))
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001353 {
1354 ret = bdrv_write(bs, sector + written,
1355 buf_old + written * 512, pnum);
1356 if (ret < 0) {
1357 error("Error while writing to COW image: %s",
1358 strerror(-ret));
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001359 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001360 }
1361 }
1362
1363 written += pnum;
1364 }
1365 }
TeLeMand6771bf2010-02-08 16:20:00 +08001366
1367 qemu_free(buf_old);
1368 qemu_free(buf_new);
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001369 }
1370
1371 /*
1372 * Change the backing file. All clusters that are different from the old
1373 * backing file are overwritten in the COW file now, so the visible content
1374 * doesn't change when we switch the backing file.
1375 */
1376 ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt);
1377 if (ret == -ENOSPC) {
1378 error("Could not change the backing file to '%s': No space left in "
1379 "the file header", out_baseimg);
1380 } else if (ret < 0) {
1381 error("Could not change the backing file to '%s': %s",
1382 out_baseimg, strerror(-ret));
1383 }
1384
1385 /*
1386 * TODO At this point it is possible to check if any clusters that are
1387 * allocated in the COW file are the same in the backing file. If so, they
1388 * could be dropped from the COW file. Don't do this before switching the
1389 * backing file, in case of a crash this would lead to corruption.
1390 */
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001391out:
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001392 /* Cleanup */
1393 if (!unsafe) {
1394 bdrv_delete(bs_old_backing);
1395 bdrv_delete(bs_new_backing);
1396 }
1397
1398 bdrv_delete(bs);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001399 if (ret) {
1400 return 1;
1401 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001402 return 0;
1403}
1404
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01001405static int img_resize(int argc, char **argv)
1406{
1407 int c, ret, relative;
1408 const char *filename, *fmt, *size;
1409 int64_t n, total_size;
1410 BlockDriverState *bs;
1411 QEMUOptionParameter *param;
1412 QEMUOptionParameter resize_options[] = {
1413 {
1414 .name = BLOCK_OPT_SIZE,
1415 .type = OPT_SIZE,
1416 .help = "Virtual disk size"
1417 },
1418 { NULL }
1419 };
1420
1421 fmt = NULL;
1422 for(;;) {
1423 c = getopt(argc, argv, "f:h");
1424 if (c == -1) {
1425 break;
1426 }
1427 switch(c) {
1428 case 'h':
1429 help();
1430 break;
1431 case 'f':
1432 fmt = optarg;
1433 break;
1434 }
1435 }
1436 if (optind + 1 >= argc) {
1437 help();
1438 }
1439 filename = argv[optind++];
1440 size = argv[optind++];
1441
1442 /* Choose grow, shrink, or absolute resize mode */
1443 switch (size[0]) {
1444 case '+':
1445 relative = 1;
1446 size++;
1447 break;
1448 case '-':
1449 relative = -1;
1450 size++;
1451 break;
1452 default:
1453 relative = 0;
1454 break;
1455 }
1456
1457 /* Parse size */
1458 param = parse_option_parameters("", resize_options, NULL);
1459 if (set_option_parameter(param, BLOCK_OPT_SIZE, size)) {
1460 /* Error message already printed when size parsing fails */
1461 exit(1);
1462 }
1463 n = get_option_parameter(param, BLOCK_OPT_SIZE)->value.n;
1464 free_option_parameters(param);
1465
1466 bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001467 if (!bs) {
1468 return 1;
1469 }
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01001470
1471 if (relative) {
1472 total_size = bdrv_getlength(bs) + n * relative;
1473 } else {
1474 total_size = n;
1475 }
1476 if (total_size <= 0) {
1477 error("New image size must be positive");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001478 ret = -1;
1479 goto out;
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01001480 }
1481
1482 ret = bdrv_truncate(bs, total_size);
1483 switch (ret) {
1484 case 0:
1485 printf("Image resized.\n");
1486 break;
1487 case -ENOTSUP:
1488 error("This image format does not support resize");
1489 break;
1490 case -EACCES:
1491 error("Image is read-only");
1492 break;
1493 default:
1494 error("Error resizing image (%d)", -ret);
1495 break;
1496 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001497out:
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01001498 bdrv_delete(bs);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001499 if (ret) {
1500 return 1;
1501 }
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01001502 return 0;
1503}
1504
Anthony Liguoric227f092009-10-01 16:12:16 -05001505static const img_cmd_t img_cmds[] = {
Stuart Brady153859b2009-06-07 00:42:17 +01001506#define DEF(option, callback, arg_string) \
1507 { option, callback },
1508#include "qemu-img-cmds.h"
1509#undef DEF
1510#undef GEN_DOCS
1511 { NULL, NULL, },
1512};
1513
bellardea2384d2004-08-01 21:59:26 +00001514int main(int argc, char **argv)
1515{
Anthony Liguoric227f092009-10-01 16:12:16 -05001516 const img_cmd_t *cmd;
Stuart Brady153859b2009-06-07 00:42:17 +01001517 const char *cmdname;
bellardea2384d2004-08-01 21:59:26 +00001518
1519 bdrv_init();
1520 if (argc < 2)
1521 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001522 cmdname = argv[1];
aurel328f9b1572009-02-09 18:14:31 +00001523 argc--; argv++;
Stuart Brady153859b2009-06-07 00:42:17 +01001524
1525 /* find the command */
1526 for(cmd = img_cmds; cmd->name != NULL; cmd++) {
1527 if (!strcmp(cmdname, cmd->name)) {
1528 return cmd->handler(argc, argv);
1529 }
bellardea2384d2004-08-01 21:59:26 +00001530 }
Stuart Brady153859b2009-06-07 00:42:17 +01001531
1532 /* not found */
1533 help();
bellardea2384d2004-08-01 21:59:26 +00001534 return 0;
1535}