blob: 809b4f1c00ae05dc1248c15848b2a2b0050b48da [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 */
Benoît Canetc054b3f2012-09-05 13:09:02 +020024#include "qapi-visit.h"
25#include "qapi/qmp-output-visitor.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010026#include "qapi/qmp/qjson.h"
pbrookfaf07962007-11-11 02:51:17 +000027#include "qemu-common.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010028#include "qemu/option.h"
29#include "qemu/error-report.h"
30#include "qemu/osdep.h"
Paolo Bonzini9c17d612012-12-17 18:20:04 +010031#include "sysemu/sysemu.h"
Paolo Bonzini737e1502012-12-17 18:19:44 +010032#include "block/block_int.h"
Wenchao Xiaf364ec62013-05-25 11:09:44 +080033#include "block/qapi.h"
Benoît Canetc054b3f2012-09-05 13:09:02 +020034#include <getopt.h>
aliguori9230eaf2009-03-28 17:55:19 +000035#include <stdio.h>
Miroslav Rezaninaf382d432013-02-13 09:09:40 +010036#include <stdarg.h>
bellardea2384d2004-08-01 21:59:26 +000037
bellarde8445332006-06-14 15:32:10 +000038#ifdef _WIN32
39#include <windows.h>
40#endif
41
Anthony Liguoric227f092009-10-01 16:12:16 -050042typedef struct img_cmd_t {
Stuart Brady153859b2009-06-07 00:42:17 +010043 const char *name;
44 int (*handler)(int argc, char **argv);
Anthony Liguoric227f092009-10-01 16:12:16 -050045} img_cmd_t;
Stuart Brady153859b2009-06-07 00:42:17 +010046
Federico Simoncelli8599ea42013-01-28 06:59:47 -050047enum {
48 OPTION_OUTPUT = 256,
49 OPTION_BACKING_CHAIN = 257,
50};
51
52typedef enum OutputFormat {
53 OFORMAT_JSON,
54 OFORMAT_HUMAN,
55} OutputFormat;
56
aurel32137519c2008-11-30 19:12:49 +000057/* Default to cache=writeback as data integrity is not important for qemu-tcg. */
Stefan Hajnocziadfe0782010-04-13 10:29:35 +010058#define BDRV_O_FLAGS BDRV_O_CACHE_WB
Federico Simoncelli661a0f72011-06-20 12:48:19 -040059#define BDRV_DEFAULT_CACHE "writeback"
aurel32137519c2008-11-30 19:12:49 +000060
bellardea2384d2004-08-01 21:59:26 +000061static void format_print(void *opaque, const char *name)
62{
63 printf(" %s", name);
64}
65
blueswir1d2c639d2009-01-24 18:19:25 +000066/* Please keep in synch with qemu-img.texi */
pbrook3f379ab2007-11-11 03:33:13 +000067static void help(void)
bellardea2384d2004-08-01 21:59:26 +000068{
Paolo Bonzinie00291c2010-02-04 16:49:56 +010069 const char *help_msg =
70 "qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
malc3f020d72010-02-08 12:04:56 +030071 "usage: qemu-img command [command options]\n"
72 "QEMU disk image utility\n"
73 "\n"
74 "Command syntax:\n"
Stuart Brady153859b2009-06-07 00:42:17 +010075#define DEF(option, callback, arg_string) \
76 " " arg_string "\n"
77#include "qemu-img-cmds.h"
78#undef DEF
79#undef GEN_DOCS
malc3f020d72010-02-08 12:04:56 +030080 "\n"
81 "Command parameters:\n"
82 " 'filename' is a disk image filename\n"
83 " 'fmt' is the disk image format. It is guessed automatically in most cases\n"
Federico Simoncelli661a0f72011-06-20 12:48:19 -040084 " 'cache' is the cache mode used to write the output disk image, the valid\n"
Liu Yuan80ccf932012-04-20 17:10:56 +080085 " options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
86 " 'directsync' and 'unsafe' (default for convert)\n"
malc3f020d72010-02-08 12:04:56 +030087 " 'size' is the disk image size in bytes. Optional suffixes\n"
Kevin Wolf5e009842013-06-05 14:19:27 +020088 " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M),\n"
89 " 'T' (terabyte, 1024G), 'P' (petabyte, 1024T) and 'E' (exabyte, 1024P) are\n"
90 " supported. 'b' is ignored.\n"
malc3f020d72010-02-08 12:04:56 +030091 " 'output_filename' is the destination disk image filename\n"
92 " 'output_fmt' is the destination format\n"
93 " 'options' is a comma separated list of format specific options in a\n"
94 " name=value format. Use -o ? for an overview of the options supported by the\n"
95 " used format\n"
96 " '-c' indicates that target image must be compressed (qcow format only)\n"
97 " '-u' enables unsafe rebasing. It is assumed that old and new backing file\n"
98 " match exactly. The image doesn't need a working backing file before\n"
99 " rebasing in this case (useful for renaming the backing file)\n"
100 " '-h' with or without a command shows this help and lists the supported formats\n"
Jes Sorensen6b837bc2011-03-30 14:16:25 +0200101 " '-p' show progress of command (only certain commands)\n"
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100102 " '-q' use Quiet mode - do not print any output (except errors)\n"
Kevin Wolfa22f1232011-08-26 15:27:13 +0200103 " '-S' indicates the consecutive number of bytes that must contain only zeros\n"
104 " for qemu-img to create a sparse image during conversion\n"
Benoît Canetc054b3f2012-09-05 13:09:02 +0200105 " '--output' takes the format in which the output must be done (human or json)\n"
malc3f020d72010-02-08 12:04:56 +0300106 "\n"
Kevin Wolf4534ff52012-05-11 16:07:02 +0200107 "Parameters to check subcommand:\n"
108 " '-r' tries to repair any inconsistencies that are found during the check.\n"
109 " '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all\n"
110 " kinds of errors, with a higher risk of choosing the wrong fix or\n"
Stefan Weil0546b8c2012-08-10 22:03:25 +0200111 " hiding corruption that has already occurred.\n"
Kevin Wolf4534ff52012-05-11 16:07:02 +0200112 "\n"
malc3f020d72010-02-08 12:04:56 +0300113 "Parameters to snapshot subcommand:\n"
114 " 'snapshot' is the name of the snapshot to create, apply or delete\n"
115 " '-a' applies a snapshot (revert disk to saved state)\n"
116 " '-c' creates a snapshot\n"
117 " '-d' deletes a snapshot\n"
Miroslav Rezaninad14ed182013-02-13 09:09:41 +0100118 " '-l' lists all snapshots in the given image\n"
119 "\n"
120 "Parameters to compare subcommand:\n"
121 " '-f' first image format\n"
122 " '-F' second image format\n"
123 " '-s' run in Strict mode - fail on different image size or sector allocation\n";
Paolo Bonzinie00291c2010-02-04 16:49:56 +0100124
125 printf("%s\nSupported formats:", help_msg);
bellardea2384d2004-08-01 21:59:26 +0000126 bdrv_iterate_format(format_print, NULL);
127 printf("\n");
128 exit(1);
129}
130
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100131static int qprintf(bool quiet, const char *fmt, ...)
132{
133 int ret = 0;
134 if (!quiet) {
135 va_list args;
136 va_start(args, fmt);
137 ret = vprintf(fmt, args);
138 va_end(args);
139 }
140 return ret;
141}
142
bellardea2384d2004-08-01 21:59:26 +0000143#if defined(WIN32)
144/* XXX: put correct support for win32 */
145static int read_password(char *buf, int buf_size)
146{
147 int c, i;
148 printf("Password: ");
149 fflush(stdout);
150 i = 0;
151 for(;;) {
152 c = getchar();
153 if (c == '\n')
154 break;
155 if (i < (buf_size - 1))
156 buf[i++] = c;
157 }
158 buf[i] = '\0';
159 return 0;
160}
161
162#else
163
164#include <termios.h>
165
166static struct termios oldtty;
167
168static void term_exit(void)
169{
170 tcsetattr (0, TCSANOW, &oldtty);
171}
172
173static void term_init(void)
174{
175 struct termios tty;
176
177 tcgetattr (0, &tty);
178 oldtty = tty;
179
180 tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
181 |INLCR|IGNCR|ICRNL|IXON);
182 tty.c_oflag |= OPOST;
183 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
184 tty.c_cflag &= ~(CSIZE|PARENB);
185 tty.c_cflag |= CS8;
186 tty.c_cc[VMIN] = 1;
187 tty.c_cc[VTIME] = 0;
ths3b46e622007-09-17 08:09:54 +0000188
bellardea2384d2004-08-01 21:59:26 +0000189 tcsetattr (0, TCSANOW, &tty);
190
191 atexit(term_exit);
192}
193
pbrook3f379ab2007-11-11 03:33:13 +0000194static int read_password(char *buf, int buf_size)
bellardea2384d2004-08-01 21:59:26 +0000195{
196 uint8_t ch;
197 int i, ret;
198
199 printf("password: ");
200 fflush(stdout);
201 term_init();
202 i = 0;
203 for(;;) {
204 ret = read(0, &ch, 1);
205 if (ret == -1) {
206 if (errno == EAGAIN || errno == EINTR) {
207 continue;
208 } else {
209 ret = -1;
210 break;
211 }
212 } else if (ret == 0) {
213 ret = -1;
214 break;
215 } else {
216 if (ch == '\r') {
217 ret = 0;
218 break;
219 }
220 if (i < (buf_size - 1))
221 buf[i++] = ch;
222 }
223 }
224 term_exit();
225 buf[i] = '\0';
226 printf("\n");
227 return ret;
228}
229#endif
230
Jes Sorensen4ac8aac2010-12-06 15:25:38 +0100231static int print_block_option_help(const char *filename, const char *fmt)
232{
233 BlockDriver *drv, *proto_drv;
234 QEMUOptionParameter *create_options = NULL;
235
236 /* Find driver and parse its options */
237 drv = bdrv_find_format(fmt);
238 if (!drv) {
Jes Sorensen15654a62010-12-16 14:31:53 +0100239 error_report("Unknown file format '%s'", fmt);
Jes Sorensen4ac8aac2010-12-06 15:25:38 +0100240 return 1;
241 }
242
243 proto_drv = bdrv_find_protocol(filename);
244 if (!proto_drv) {
Jes Sorensen15654a62010-12-16 14:31:53 +0100245 error_report("Unknown protocol '%s'", filename);
Jes Sorensen4ac8aac2010-12-06 15:25:38 +0100246 return 1;
247 }
248
249 create_options = append_option_parameters(create_options,
250 drv->create_options);
251 create_options = append_option_parameters(create_options,
252 proto_drv->create_options);
253 print_option_help(create_options);
254 free_option_parameters(create_options);
255 return 0;
256}
257
bellard75c23802004-08-27 21:28:58 +0000258static BlockDriverState *bdrv_new_open(const char *filename,
Sheng Yang9bc378c2010-01-29 10:15:06 +0800259 const char *fmt,
Daniel P. Berrangef0536bb2012-09-10 12:11:31 +0100260 int flags,
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100261 bool require_io,
262 bool quiet)
bellard75c23802004-08-27 21:28:58 +0000263{
264 BlockDriverState *bs;
265 BlockDriver *drv;
266 char password[256];
Kevin Wolfb9eaf9e2011-02-09 11:25:53 +0100267 int ret;
bellard75c23802004-08-27 21:28:58 +0000268
Kevin Wolfb9eaf9e2011-02-09 11:25:53 +0100269 bs = bdrv_new("image");
Kevin Wolfad717132010-12-16 15:37:41 +0100270
bellard75c23802004-08-27 21:28:58 +0000271 if (fmt) {
272 drv = bdrv_find_format(fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900273 if (!drv) {
Jes Sorensen15654a62010-12-16 14:31:53 +0100274 error_report("Unknown file format '%s'", fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900275 goto fail;
276 }
bellard75c23802004-08-27 21:28:58 +0000277 } else {
278 drv = NULL;
279 }
Kevin Wolfb9eaf9e2011-02-09 11:25:53 +0100280
Kevin Wolfde9c0ce2013-03-15 10:35:02 +0100281 ret = bdrv_open(bs, filename, NULL, flags, drv);
Kevin Wolfb9eaf9e2011-02-09 11:25:53 +0100282 if (ret < 0) {
283 error_report("Could not open '%s': %s", filename, strerror(-ret));
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900284 goto fail;
bellard75c23802004-08-27 21:28:58 +0000285 }
Kevin Wolfb9eaf9e2011-02-09 11:25:53 +0100286
Daniel P. Berrangef0536bb2012-09-10 12:11:31 +0100287 if (bdrv_is_encrypted(bs) && require_io) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100288 qprintf(quiet, "Disk image '%s' is encrypted.\n", filename);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900289 if (read_password(password, sizeof(password)) < 0) {
Jes Sorensen15654a62010-12-16 14:31:53 +0100290 error_report("No password given");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900291 goto fail;
292 }
293 if (bdrv_set_key(bs, password) < 0) {
Jes Sorensen15654a62010-12-16 14:31:53 +0100294 error_report("invalid password");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900295 goto fail;
296 }
bellard75c23802004-08-27 21:28:58 +0000297 }
298 return bs;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900299fail:
300 if (bs) {
301 bdrv_delete(bs);
302 }
303 return NULL;
bellard75c23802004-08-27 21:28:58 +0000304}
305
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900306static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
Jes Sorenseneec77d92010-12-07 17:44:34 +0100307 const char *base_filename,
308 const char *base_fmt)
Kevin Wolfefa84d42009-05-18 16:42:12 +0200309{
Kevin Wolfefa84d42009-05-18 16:42:12 +0200310 if (base_filename) {
311 if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
Jes Sorensen15654a62010-12-16 14:31:53 +0100312 error_report("Backing file not supported for file format '%s'",
313 fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900314 return -1;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200315 }
316 }
317 if (base_fmt) {
318 if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
Jes Sorensen15654a62010-12-16 14:31:53 +0100319 error_report("Backing file format not supported for file "
320 "format '%s'", fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900321 return -1;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200322 }
323 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900324 return 0;
Kevin Wolfefa84d42009-05-18 16:42:12 +0200325}
326
bellardea2384d2004-08-01 21:59:26 +0000327static int img_create(int argc, char **argv)
328{
Luiz Capitulinoa9300912012-11-30 10:52:06 -0200329 int c;
Jes Sorensen1da7cfb2010-12-09 14:17:25 +0100330 uint64_t img_size = -1;
bellardea2384d2004-08-01 21:59:26 +0000331 const char *fmt = "raw";
aliguori9230eaf2009-03-28 17:55:19 +0000332 const char *base_fmt = NULL;
bellardea2384d2004-08-01 21:59:26 +0000333 const char *filename;
334 const char *base_filename = NULL;
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200335 char *options = NULL;
Luiz Capitulino9b375252012-11-30 10:52:05 -0200336 Error *local_err = NULL;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100337 bool quiet = false;
ths3b46e622007-09-17 08:09:54 +0000338
bellardea2384d2004-08-01 21:59:26 +0000339 for(;;) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100340 c = getopt(argc, argv, "F:b:f:he6o:q");
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100341 if (c == -1) {
bellardea2384d2004-08-01 21:59:26 +0000342 break;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100343 }
bellardea2384d2004-08-01 21:59:26 +0000344 switch(c) {
Jes Sorensenef873942010-12-06 15:25:40 +0100345 case '?':
bellardea2384d2004-08-01 21:59:26 +0000346 case 'h':
347 help();
348 break;
aliguori9230eaf2009-03-28 17:55:19 +0000349 case 'F':
350 base_fmt = optarg;
351 break;
bellardea2384d2004-08-01 21:59:26 +0000352 case 'b':
353 base_filename = optarg;
354 break;
355 case 'f':
356 fmt = optarg;
357 break;
358 case 'e':
Markus Armbruster9d42e152011-06-22 14:03:55 +0200359 error_report("option -e is deprecated, please use \'-o "
Jes Sorenseneec77d92010-12-07 17:44:34 +0100360 "encryption\' instead!");
361 return 1;
thsd8871c52007-10-24 16:11:42 +0000362 case '6':
Markus Armbruster9d42e152011-06-22 14:03:55 +0200363 error_report("option -6 is deprecated, please use \'-o "
Jes Sorenseneec77d92010-12-07 17:44:34 +0100364 "compat6\' instead!");
365 return 1;
Kevin Wolf9ea2ea72009-05-18 16:42:11 +0200366 case 'o':
367 options = optarg;
368 break;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100369 case 'q':
370 quiet = true;
371 break;
bellardea2384d2004-08-01 21:59:26 +0000372 }
373 }
aliguori9230eaf2009-03-28 17:55:19 +0000374
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900375 /* Get the filename */
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100376 if (optind >= argc) {
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900377 help();
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100378 }
MORITA Kazutakab50cbab2010-05-26 11:35:36 +0900379 filename = argv[optind++];
380
Jes Sorensen1da7cfb2010-12-09 14:17:25 +0100381 /* Get image size, if specified */
382 if (optind < argc) {
Jes Sorensen70b4f4b2011-01-05 11:41:02 +0100383 int64_t sval;
Markus Armbrustere36b3692011-11-22 09:46:05 +0100384 char *end;
385 sval = strtosz_suffix(argv[optind++], &end, STRTOSZ_DEFSUFFIX_B);
386 if (sval < 0 || *end) {
liguang79443392012-12-17 09:49:23 +0800387 if (sval == -ERANGE) {
388 error_report("Image size must be less than 8 EiB!");
389 } else {
390 error_report("Invalid image size specified! You may use k, M, "
Kevin Wolf5e009842013-06-05 14:19:27 +0200391 "G, T, P or E suffixes for ");
392 error_report("kilobytes, megabytes, gigabytes, terabytes, "
393 "petabytes and exabytes.");
liguang79443392012-12-17 09:49:23 +0800394 }
Luiz Capitulinoa9300912012-11-30 10:52:06 -0200395 return 1;
Jes Sorensen1da7cfb2010-12-09 14:17:25 +0100396 }
397 img_size = (uint64_t)sval;
398 }
399
Peter Maydellc8057f92012-08-02 13:45:54 +0100400 if (options && is_help_option(options)) {
Luiz Capitulinoa9300912012-11-30 10:52:06 -0200401 return print_block_option_help(filename, fmt);
Jes Sorensen4ac8aac2010-12-06 15:25:38 +0100402 }
403
Luiz Capitulino9b375252012-11-30 10:52:05 -0200404 bdrv_img_create(filename, fmt, base_filename, base_fmt,
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100405 options, img_size, BDRV_O_FLAGS, &local_err, quiet);
Luiz Capitulino9b375252012-11-30 10:52:05 -0200406 if (error_is_set(&local_err)) {
407 error_report("%s", error_get_pretty(local_err));
408 error_free(local_err);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900409 return 1;
410 }
Luiz Capitulinoa9300912012-11-30 10:52:06 -0200411
bellardea2384d2004-08-01 21:59:26 +0000412 return 0;
413}
414
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100415static void dump_json_image_check(ImageCheck *check, bool quiet)
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500416{
417 Error *errp = NULL;
418 QString *str;
419 QmpOutputVisitor *ov = qmp_output_visitor_new();
420 QObject *obj;
421 visit_type_ImageCheck(qmp_output_get_visitor(ov),
422 &check, NULL, &errp);
423 obj = qmp_output_get_qobject(ov);
424 str = qobject_to_json_pretty(obj);
425 assert(str != NULL);
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100426 qprintf(quiet, "%s\n", qstring_get_str(str));
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500427 qobject_decref(obj);
428 qmp_output_visitor_cleanup(ov);
429 QDECREF(str);
430}
431
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100432static void dump_human_image_check(ImageCheck *check, bool quiet)
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500433{
434 if (!(check->corruptions || check->leaks || check->check_errors)) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100435 qprintf(quiet, "No errors were found on the image.\n");
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500436 } else {
437 if (check->corruptions) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100438 qprintf(quiet, "\n%" PRId64 " errors were found on the image.\n"
439 "Data may be corrupted, or further writes to the image "
440 "may corrupt it.\n",
441 check->corruptions);
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500442 }
443
444 if (check->leaks) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100445 qprintf(quiet,
446 "\n%" PRId64 " leaked clusters were found on the image.\n"
447 "This means waste of disk space, but no harm to data.\n",
448 check->leaks);
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500449 }
450
451 if (check->check_errors) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100452 qprintf(quiet,
453 "\n%" PRId64
454 " internal errors have occurred during the check.\n",
455 check->check_errors);
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500456 }
457 }
458
459 if (check->total_clusters != 0 && check->allocated_clusters != 0) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100460 qprintf(quiet, "%" PRId64 "/%" PRId64 " = %0.2f%% allocated, "
461 "%0.2f%% fragmented, %0.2f%% compressed clusters\n",
462 check->allocated_clusters, check->total_clusters,
463 check->allocated_clusters * 100.0 / check->total_clusters,
464 check->fragmented_clusters * 100.0 / check->allocated_clusters,
465 check->compressed_clusters * 100.0 /
466 check->allocated_clusters);
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500467 }
468
469 if (check->image_end_offset) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100470 qprintf(quiet,
471 "Image end offset: %" PRId64 "\n", check->image_end_offset);
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500472 }
473}
474
475static int collect_image_check(BlockDriverState *bs,
476 ImageCheck *check,
477 const char *filename,
478 const char *fmt,
479 int fix)
480{
481 int ret;
482 BdrvCheckResult result;
483
484 ret = bdrv_check(bs, &result, fix);
485 if (ret < 0) {
486 return ret;
487 }
488
489 check->filename = g_strdup(filename);
490 check->format = g_strdup(bdrv_get_format_name(bs));
491 check->check_errors = result.check_errors;
492 check->corruptions = result.corruptions;
493 check->has_corruptions = result.corruptions != 0;
494 check->leaks = result.leaks;
495 check->has_leaks = result.leaks != 0;
496 check->corruptions_fixed = result.corruptions_fixed;
497 check->has_corruptions_fixed = result.corruptions != 0;
498 check->leaks_fixed = result.leaks_fixed;
499 check->has_leaks_fixed = result.leaks != 0;
500 check->image_end_offset = result.image_end_offset;
501 check->has_image_end_offset = result.image_end_offset != 0;
502 check->total_clusters = result.bfi.total_clusters;
503 check->has_total_clusters = result.bfi.total_clusters != 0;
504 check->allocated_clusters = result.bfi.allocated_clusters;
505 check->has_allocated_clusters = result.bfi.allocated_clusters != 0;
506 check->fragmented_clusters = result.bfi.fragmented_clusters;
507 check->has_fragmented_clusters = result.bfi.fragmented_clusters != 0;
Stefan Hajnoczie6439d72013-02-07 17:15:04 +0100508 check->compressed_clusters = result.bfi.compressed_clusters;
509 check->has_compressed_clusters = result.bfi.compressed_clusters != 0;
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500510
511 return 0;
512}
513
Kevin Wolfe076f332010-06-29 11:43:13 +0200514/*
515 * Checks an image for consistency. Exit codes:
516 *
517 * 0 - Check completed, image is good
518 * 1 - Check not completed because of internal errors
519 * 2 - Check completed, image is corrupted
520 * 3 - Check completed, image has leaked clusters, but is good otherwise
521 */
aliguori15859692009-04-21 23:11:53 +0000522static int img_check(int argc, char **argv)
523{
524 int c, ret;
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500525 OutputFormat output_format = OFORMAT_HUMAN;
526 const char *filename, *fmt, *output;
aliguori15859692009-04-21 23:11:53 +0000527 BlockDriverState *bs;
Kevin Wolf4534ff52012-05-11 16:07:02 +0200528 int fix = 0;
Stefan Hajnoczi058f8f12012-08-09 13:05:56 +0100529 int flags = BDRV_O_FLAGS | BDRV_O_CHECK;
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500530 ImageCheck *check;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100531 bool quiet = false;
aliguori15859692009-04-21 23:11:53 +0000532
533 fmt = NULL;
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500534 output = NULL;
aliguori15859692009-04-21 23:11:53 +0000535 for(;;) {
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500536 int option_index = 0;
537 static const struct option long_options[] = {
538 {"help", no_argument, 0, 'h'},
539 {"format", required_argument, 0, 'f'},
540 {"repair", no_argument, 0, 'r'},
541 {"output", required_argument, 0, OPTION_OUTPUT},
542 {0, 0, 0, 0}
543 };
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100544 c = getopt_long(argc, argv, "f:hr:q",
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500545 long_options, &option_index);
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100546 if (c == -1) {
aliguori15859692009-04-21 23:11:53 +0000547 break;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100548 }
aliguori15859692009-04-21 23:11:53 +0000549 switch(c) {
Jes Sorensenef873942010-12-06 15:25:40 +0100550 case '?':
aliguori15859692009-04-21 23:11:53 +0000551 case 'h':
552 help();
553 break;
554 case 'f':
555 fmt = optarg;
556 break;
Kevin Wolf4534ff52012-05-11 16:07:02 +0200557 case 'r':
558 flags |= BDRV_O_RDWR;
559
560 if (!strcmp(optarg, "leaks")) {
561 fix = BDRV_FIX_LEAKS;
562 } else if (!strcmp(optarg, "all")) {
563 fix = BDRV_FIX_LEAKS | BDRV_FIX_ERRORS;
564 } else {
565 help();
566 }
567 break;
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500568 case OPTION_OUTPUT:
569 output = optarg;
570 break;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100571 case 'q':
572 quiet = true;
573 break;
aliguori15859692009-04-21 23:11:53 +0000574 }
575 }
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100576 if (optind >= argc) {
aliguori15859692009-04-21 23:11:53 +0000577 help();
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100578 }
aliguori15859692009-04-21 23:11:53 +0000579 filename = argv[optind++];
580
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500581 if (output && !strcmp(output, "json")) {
582 output_format = OFORMAT_JSON;
583 } else if (output && !strcmp(output, "human")) {
584 output_format = OFORMAT_HUMAN;
585 } else if (output) {
586 error_report("--output must be used with human or json as argument.");
587 return 1;
588 }
589
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100590 bs = bdrv_new_open(filename, fmt, flags, true, quiet);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900591 if (!bs) {
592 return 1;
593 }
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500594
595 check = g_new0(ImageCheck, 1);
596 ret = collect_image_check(bs, check, filename, fmt, fix);
Kevin Wolfe076f332010-06-29 11:43:13 +0200597
598 if (ret == -ENOTSUP) {
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500599 if (output_format == OFORMAT_HUMAN) {
600 error_report("This image format does not support checks");
601 }
602 ret = 1;
603 goto fail;
Kevin Wolfe076f332010-06-29 11:43:13 +0200604 }
605
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500606 if (check->corruptions_fixed || check->leaks_fixed) {
607 int corruptions_fixed, leaks_fixed;
608
609 leaks_fixed = check->leaks_fixed;
610 corruptions_fixed = check->corruptions_fixed;
611
612 if (output_format == OFORMAT_HUMAN) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100613 qprintf(quiet,
614 "The following inconsistencies were found and repaired:\n\n"
615 " %" PRId64 " leaked clusters\n"
616 " %" PRId64 " corruptions\n\n"
617 "Double checking the fixed image now...\n",
618 check->leaks_fixed,
619 check->corruptions_fixed);
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500620 }
621
622 ret = collect_image_check(bs, check, filename, fmt, 0);
623
624 check->leaks_fixed = leaks_fixed;
625 check->corruptions_fixed = corruptions_fixed;
Kevin Wolfccf34712012-05-11 18:16:54 +0200626 }
627
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500628 switch (output_format) {
629 case OFORMAT_HUMAN:
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100630 dump_human_image_check(check, quiet);
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500631 break;
632 case OFORMAT_JSON:
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100633 dump_json_image_check(check, quiet);
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500634 break;
635 }
636
637 if (ret || check->check_errors) {
638 ret = 1;
639 goto fail;
640 }
641
642 if (check->corruptions) {
643 ret = 2;
644 } else if (check->leaks) {
645 ret = 3;
Kevin Wolfe076f332010-06-29 11:43:13 +0200646 } else {
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500647 ret = 0;
aliguori15859692009-04-21 23:11:53 +0000648 }
649
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500650fail:
651 qapi_free_ImageCheck(check);
aliguori15859692009-04-21 23:11:53 +0000652 bdrv_delete(bs);
Kevin Wolfe076f332010-06-29 11:43:13 +0200653
Federico Simoncelli8599ea42013-01-28 06:59:47 -0500654 return ret;
aliguori15859692009-04-21 23:11:53 +0000655}
656
bellardea2384d2004-08-01 21:59:26 +0000657static int img_commit(int argc, char **argv)
658{
Federico Simoncelli661a0f72011-06-20 12:48:19 -0400659 int c, ret, flags;
660 const char *filename, *fmt, *cache;
bellardea2384d2004-08-01 21:59:26 +0000661 BlockDriverState *bs;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100662 bool quiet = false;
bellardea2384d2004-08-01 21:59:26 +0000663
664 fmt = NULL;
Federico Simoncelli661a0f72011-06-20 12:48:19 -0400665 cache = BDRV_DEFAULT_CACHE;
bellardea2384d2004-08-01 21:59:26 +0000666 for(;;) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100667 c = getopt(argc, argv, "f:ht:q");
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100668 if (c == -1) {
bellardea2384d2004-08-01 21:59:26 +0000669 break;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100670 }
bellardea2384d2004-08-01 21:59:26 +0000671 switch(c) {
Jes Sorensenef873942010-12-06 15:25:40 +0100672 case '?':
bellardea2384d2004-08-01 21:59:26 +0000673 case 'h':
674 help();
675 break;
676 case 'f':
677 fmt = optarg;
678 break;
Federico Simoncelli661a0f72011-06-20 12:48:19 -0400679 case 't':
680 cache = optarg;
681 break;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100682 case 'q':
683 quiet = true;
684 break;
bellardea2384d2004-08-01 21:59:26 +0000685 }
686 }
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100687 if (optind >= argc) {
bellardea2384d2004-08-01 21:59:26 +0000688 help();
Jes Sorensenb8fb60d2010-12-06 15:25:39 +0100689 }
bellardea2384d2004-08-01 21:59:26 +0000690 filename = argv[optind++];
691
Federico Simoncelli661a0f72011-06-20 12:48:19 -0400692 flags = BDRV_O_RDWR;
Stefan Hajnoczic3993cd2011-08-04 12:26:51 +0100693 ret = bdrv_parse_cache_flags(cache, &flags);
Federico Simoncelli661a0f72011-06-20 12:48:19 -0400694 if (ret < 0) {
695 error_report("Invalid cache option: %s", cache);
696 return -1;
697 }
698
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100699 bs = bdrv_new_open(filename, fmt, flags, true, quiet);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900700 if (!bs) {
701 return 1;
702 }
bellardea2384d2004-08-01 21:59:26 +0000703 ret = bdrv_commit(bs);
704 switch(ret) {
705 case 0:
Miroslav Rezaninaf382d432013-02-13 09:09:40 +0100706 qprintf(quiet, "Image committed.\n");
bellardea2384d2004-08-01 21:59:26 +0000707 break;
708 case -ENOENT:
Jes Sorensen15654a62010-12-16 14:31:53 +0100709 error_report("No disk inserted");
bellardea2384d2004-08-01 21:59:26 +0000710 break;
711 case -EACCES:
Jes Sorensen15654a62010-12-16 14:31:53 +0100712 error_report("Image is read-only");
bellardea2384d2004-08-01 21:59:26 +0000713 break;
714 case -ENOTSUP:
Jes Sorensen15654a62010-12-16 14:31:53 +0100715 error_report("Image is already committed");
bellardea2384d2004-08-01 21:59:26 +0000716 break;
717 default:
Jes Sorensen15654a62010-12-16 14:31:53 +0100718 error_report("Error while committing image");
bellardea2384d2004-08-01 21:59:26 +0000719 break;
720 }
721
722 bdrv_delete(bs);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +0900723 if (ret) {
724 return 1;
725 }
bellardea2384d2004-08-01 21:59:26 +0000726 return 0;
727}
728
Dmitry Konishchevf6a00aa2011-05-18 15:03:59 +0400729/*
thsf58c7b32008-06-05 21:53:49 +0000730 * Returns true iff the first sector pointed to by 'buf' contains at least
731 * a non-NUL byte.
732 *
733 * 'pnum' is set to the number of sectors (including and immediately following
734 * the first one) that are known to be in the same allocated/unallocated state.
735 */
bellardea2384d2004-08-01 21:59:26 +0000736static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
737{
Stefan Hajnoczi1a6d39f2012-02-07 13:27:24 +0000738 bool is_zero;
739 int i;
bellardea2384d2004-08-01 21:59:26 +0000740
741 if (n <= 0) {
742 *pnum = 0;
743 return 0;
744 }
Stefan Hajnoczi1a6d39f2012-02-07 13:27:24 +0000745 is_zero = buffer_is_zero(buf, 512);
bellardea2384d2004-08-01 21:59:26 +0000746 for(i = 1; i < n; i++) {
747 buf += 512;
Stefan Hajnoczi1a6d39f2012-02-07 13:27:24 +0000748 if (is_zero != buffer_is_zero(buf, 512)) {
bellardea2384d2004-08-01 21:59:26 +0000749 break;
Stefan Hajnoczi1a6d39f2012-02-07 13:27:24 +0000750 }
bellardea2384d2004-08-01 21:59:26 +0000751 }
752 *pnum = i;
Stefan Hajnoczi1a6d39f2012-02-07 13:27:24 +0000753 return !is_zero;
bellardea2384d2004-08-01 21:59:26 +0000754}
755
Kevin Wolf3e85c6f2010-01-12 12:55:18 +0100756/*
Kevin Wolfa22f1232011-08-26 15:27:13 +0200757 * Like is_allocated_sectors, but if the buffer starts with a used sector,
758 * up to 'min' consecutive sectors containing zeros are ignored. This avoids
759 * breaking up write requests for only small sparse areas.
760 */
761static int is_allocated_sectors_min(const uint8_t *buf, int n, int *pnum,
762 int min)
763{
764 int ret;
765 int num_checked, num_used;
766
767 if (n < min) {
768 min = n;
769 }
770
771 ret = is_allocated_sectors(buf, n, pnum);
772 if (!ret) {
773 return ret;
774 }
775
776 num_used = *pnum;
777 buf += BDRV_SECTOR_SIZE * *pnum;
778 n -= *pnum;
779 num_checked = num_used;
780
781 while (n > 0) {
782 ret = is_allocated_sectors(buf, n, pnum);
783
784 buf += BDRV_SECTOR_SIZE * *pnum;
785 n -= *pnum;
786 num_checked += *pnum;
787 if (ret) {
788 num_used = num_checked;
789 } else if (*pnum >= min) {
790 break;
791 }
792 }
793
794 *pnum = num_used;
795 return 1;
796}
797
798/*
Kevin Wolf3e85c6f2010-01-12 12:55:18 +0100799 * Compares two buffers sector by sector. Returns 0 if the first sector of both
800 * buffers matches, non-zero otherwise.
801 *
802 * pnum is set to the number of sectors (including and immediately following
803 * the first one) that are known to have the same comparison result
804 */
805static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
806 int *pnum)
807{
808 int res, i;
809
810 if (n <= 0) {
811 *pnum = 0;
812 return 0;
813 }
814
815 res = !!memcmp(buf1, buf2, 512);
816 for(i = 1; i < n; i++) {
817 buf1 += 512;
818 buf2 += 512;
819
820 if (!!memcmp(buf1, buf2, 512) != res) {
821 break;
822 }
823 }
824
825 *pnum = i;
826 return res;
827}
828
Kevin Wolf80ee15a2009-09-15 12:30:43 +0200829#define IO_BUF_SIZE (2 * 1024 * 1024)
bellardea2384d2004-08-01 21:59:26 +0000830
Miroslav Rezaninad14ed182013-02-13 09:09:41 +0100831static int64_t sectors_to_bytes(int64_t sectors)
832{
833 return sectors << BDRV_SECTOR_BITS;
834}
835
836static int64_t sectors_to_process(int64_t total, int64_t from)
837{
838 return MIN(total - from, IO_BUF_SIZE >> BDRV_SECTOR_BITS);
839}
840
841/*
842 * Check if passed sectors are empty (not allocated or contain only 0 bytes)
843 *
844 * Returns 0 in case sectors are filled with 0, 1 if sectors contain non-zero
845 * data and negative value on error.
846 *
847 * @param bs: Driver used for accessing file
848 * @param sect_num: Number of first sector to check
849 * @param sect_count: Number of sectors to check
850 * @param filename: Name of disk file we are checking (logging purpose)
851 * @param buffer: Allocated buffer for storing read data
852 * @param quiet: Flag for quiet mode
853 */
854static int check_empty_sectors(BlockDriverState *bs, int64_t sect_num,
855 int sect_count, const char *filename,
856 uint8_t *buffer, bool quiet)
857{
858 int pnum, ret = 0;
859 ret = bdrv_read(bs, sect_num, buffer, sect_count);
860 if (ret < 0) {
861 error_report("Error while reading offset %" PRId64 " of %s: %s",
862 sectors_to_bytes(sect_num), filename, strerror(-ret));
863 return ret;
864 }
865 ret = is_allocated_sectors(buffer, sect_count, &pnum);
866 if (ret || pnum != sect_count) {
867 qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
868 sectors_to_bytes(ret ? sect_num : sect_num + pnum));
869 return 1;
870 }
871
872 return 0;
873}
874
875/*
876 * Compares two images. Exit codes:
877 *
878 * 0 - Images are identical
879 * 1 - Images differ
880 * >1 - Error occurred
881 */
882static int img_compare(int argc, char **argv)
883{
884 const char *fmt1 = NULL, *fmt2 = NULL, *filename1, *filename2;
885 BlockDriverState *bs1, *bs2;
886 int64_t total_sectors1, total_sectors2;
887 uint8_t *buf1 = NULL, *buf2 = NULL;
888 int pnum1, pnum2;
889 int allocated1, allocated2;
890 int ret = 0; /* return value - 0 Ident, 1 Different, >1 Error */
891 bool progress = false, quiet = false, strict = false;
892 int64_t total_sectors;
893 int64_t sector_num = 0;
894 int64_t nb_sectors;
895 int c, pnum;
896 uint64_t bs_sectors;
897 uint64_t progress_base;
898
899 for (;;) {
900 c = getopt(argc, argv, "hpf:F:sq");
901 if (c == -1) {
902 break;
903 }
904 switch (c) {
905 case '?':
906 case 'h':
907 help();
908 break;
909 case 'f':
910 fmt1 = optarg;
911 break;
912 case 'F':
913 fmt2 = optarg;
914 break;
915 case 'p':
916 progress = true;
917 break;
918 case 'q':
919 quiet = true;
920 break;
921 case 's':
922 strict = true;
923 break;
924 }
925 }
926
927 /* Progress is not shown in Quiet mode */
928 if (quiet) {
929 progress = false;
930 }
931
932
933 if (optind > argc - 2) {
934 help();
935 }
936 filename1 = argv[optind++];
937 filename2 = argv[optind++];
938
939 /* Initialize before goto out */
940 qemu_progress_init(progress, 2.0);
941
942 bs1 = bdrv_new_open(filename1, fmt1, BDRV_O_FLAGS, true, quiet);
943 if (!bs1) {
944 error_report("Can't open file %s", filename1);
945 ret = 2;
946 goto out3;
947 }
948
949 bs2 = bdrv_new_open(filename2, fmt2, BDRV_O_FLAGS, true, quiet);
950 if (!bs2) {
951 error_report("Can't open file %s", filename2);
952 ret = 2;
953 goto out2;
954 }
955
956 buf1 = qemu_blockalign(bs1, IO_BUF_SIZE);
957 buf2 = qemu_blockalign(bs2, IO_BUF_SIZE);
958 bdrv_get_geometry(bs1, &bs_sectors);
959 total_sectors1 = bs_sectors;
960 bdrv_get_geometry(bs2, &bs_sectors);
961 total_sectors2 = bs_sectors;
962 total_sectors = MIN(total_sectors1, total_sectors2);
963 progress_base = MAX(total_sectors1, total_sectors2);
964
965 qemu_progress_print(0, 100);
966
967 if (strict && total_sectors1 != total_sectors2) {
968 ret = 1;
969 qprintf(quiet, "Strict mode: Image size mismatch!\n");
970 goto out;
971 }
972
973 for (;;) {
974 nb_sectors = sectors_to_process(total_sectors, sector_num);
975 if (nb_sectors <= 0) {
976 break;
977 }
978 allocated1 = bdrv_is_allocated_above(bs1, NULL, sector_num, nb_sectors,
979 &pnum1);
980 if (allocated1 < 0) {
981 ret = 3;
982 error_report("Sector allocation test failed for %s", filename1);
983 goto out;
984 }
985
986 allocated2 = bdrv_is_allocated_above(bs2, NULL, sector_num, nb_sectors,
987 &pnum2);
988 if (allocated2 < 0) {
989 ret = 3;
990 error_report("Sector allocation test failed for %s", filename2);
991 goto out;
992 }
993 nb_sectors = MIN(pnum1, pnum2);
994
995 if (allocated1 == allocated2) {
996 if (allocated1) {
997 ret = bdrv_read(bs1, sector_num, buf1, nb_sectors);
998 if (ret < 0) {
999 error_report("Error while reading offset %" PRId64 " of %s:"
1000 " %s", sectors_to_bytes(sector_num), filename1,
1001 strerror(-ret));
1002 ret = 4;
1003 goto out;
1004 }
1005 ret = bdrv_read(bs2, sector_num, buf2, nb_sectors);
1006 if (ret < 0) {
1007 error_report("Error while reading offset %" PRId64
1008 " of %s: %s", sectors_to_bytes(sector_num),
1009 filename2, strerror(-ret));
1010 ret = 4;
1011 goto out;
1012 }
1013 ret = compare_sectors(buf1, buf2, nb_sectors, &pnum);
1014 if (ret || pnum != nb_sectors) {
1015 ret = 1;
1016 qprintf(quiet, "Content mismatch at offset %" PRId64 "!\n",
1017 sectors_to_bytes(
1018 ret ? sector_num : sector_num + pnum));
1019 goto out;
1020 }
1021 }
1022 } else {
1023 if (strict) {
1024 ret = 1;
1025 qprintf(quiet, "Strict mode: Offset %" PRId64
1026 " allocation mismatch!\n",
1027 sectors_to_bytes(sector_num));
1028 goto out;
1029 }
1030
1031 if (allocated1) {
1032 ret = check_empty_sectors(bs1, sector_num, nb_sectors,
1033 filename1, buf1, quiet);
1034 } else {
1035 ret = check_empty_sectors(bs2, sector_num, nb_sectors,
1036 filename2, buf1, quiet);
1037 }
1038 if (ret) {
1039 if (ret < 0) {
1040 ret = 4;
1041 error_report("Error while reading offset %" PRId64 ": %s",
1042 sectors_to_bytes(sector_num), strerror(-ret));
1043 }
1044 goto out;
1045 }
1046 }
1047 sector_num += nb_sectors;
1048 qemu_progress_print(((float) nb_sectors / progress_base)*100, 100);
1049 }
1050
1051 if (total_sectors1 != total_sectors2) {
1052 BlockDriverState *bs_over;
1053 int64_t total_sectors_over;
1054 const char *filename_over;
1055
1056 qprintf(quiet, "Warning: Image size mismatch!\n");
1057 if (total_sectors1 > total_sectors2) {
1058 total_sectors_over = total_sectors1;
1059 bs_over = bs1;
1060 filename_over = filename1;
1061 } else {
1062 total_sectors_over = total_sectors2;
1063 bs_over = bs2;
1064 filename_over = filename2;
1065 }
1066
1067 for (;;) {
1068 nb_sectors = sectors_to_process(total_sectors_over, sector_num);
1069 if (nb_sectors <= 0) {
1070 break;
1071 }
1072 ret = bdrv_is_allocated_above(bs_over, NULL, sector_num,
1073 nb_sectors, &pnum);
1074 if (ret < 0) {
1075 ret = 3;
1076 error_report("Sector allocation test failed for %s",
1077 filename_over);
1078 goto out;
1079
1080 }
1081 nb_sectors = pnum;
1082 if (ret) {
1083 ret = check_empty_sectors(bs_over, sector_num, nb_sectors,
1084 filename_over, buf1, quiet);
1085 if (ret) {
1086 if (ret < 0) {
1087 ret = 4;
1088 error_report("Error while reading offset %" PRId64
1089 " of %s: %s", sectors_to_bytes(sector_num),
1090 filename_over, strerror(-ret));
1091 }
1092 goto out;
1093 }
1094 }
1095 sector_num += nb_sectors;
1096 qemu_progress_print(((float) nb_sectors / progress_base)*100, 100);
1097 }
1098 }
1099
1100 qprintf(quiet, "Images are identical.\n");
1101 ret = 0;
1102
1103out:
1104 bdrv_delete(bs2);
1105 qemu_vfree(buf1);
1106 qemu_vfree(buf2);
1107out2:
1108 bdrv_delete(bs1);
1109out3:
1110 qemu_progress_end();
1111 return ret;
1112}
1113
bellardea2384d2004-08-01 21:59:26 +00001114static int img_convert(int argc, char **argv)
1115{
Jes Sorenseneec77d92010-12-07 17:44:34 +01001116 int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
Federico Simoncelli661a0f72011-06-20 12:48:19 -04001117 int progress = 0, flags;
1118 const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
MORITA Kazutakab50cbab2010-05-26 11:35:36 +09001119 BlockDriver *drv, *proto_drv;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001120 BlockDriverState **bs = NULL, *out_bs = NULL;
ths96b8f132007-12-17 01:35:20 +00001121 int64_t total_sectors, nb_sectors, sector_num, bs_offset;
1122 uint64_t bs_sectors;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001123 uint8_t * buf = NULL;
bellardea2384d2004-08-01 21:59:26 +00001124 const uint8_t *buf1;
bellardfaea38e2006-08-05 21:31:00 +00001125 BlockDriverInfo bdi;
MORITA Kazutakab50cbab2010-05-26 11:35:36 +09001126 QEMUOptionParameter *param = NULL, *create_options = NULL;
Kevin Wolfa18953f2010-10-14 15:46:04 +02001127 QEMUOptionParameter *out_baseimg_param;
Kevin Wolfefa84d42009-05-18 16:42:12 +02001128 char *options = NULL;
edison51ef6722010-09-21 19:58:41 -07001129 const char *snapshot_name = NULL;
Kevin Wolf1f710492012-10-12 14:29:18 +02001130 float local_progress = 0;
Kevin Wolfa22f1232011-08-26 15:27:13 +02001131 int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001132 bool quiet = false;
bellardea2384d2004-08-01 21:59:26 +00001133
1134 fmt = NULL;
1135 out_fmt = "raw";
Federico Simoncelli661a0f72011-06-20 12:48:19 -04001136 cache = "unsafe";
thsf58c7b32008-06-05 21:53:49 +00001137 out_baseimg = NULL;
Jes Sorenseneec77d92010-12-07 17:44:34 +01001138 compress = 0;
bellardea2384d2004-08-01 21:59:26 +00001139 for(;;) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001140 c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:q");
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001141 if (c == -1) {
bellardea2384d2004-08-01 21:59:26 +00001142 break;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001143 }
bellardea2384d2004-08-01 21:59:26 +00001144 switch(c) {
Jes Sorensenef873942010-12-06 15:25:40 +01001145 case '?':
bellardea2384d2004-08-01 21:59:26 +00001146 case 'h':
1147 help();
1148 break;
1149 case 'f':
1150 fmt = optarg;
1151 break;
1152 case 'O':
1153 out_fmt = optarg;
1154 break;
thsf58c7b32008-06-05 21:53:49 +00001155 case 'B':
1156 out_baseimg = optarg;
1157 break;
bellardea2384d2004-08-01 21:59:26 +00001158 case 'c':
Jes Sorenseneec77d92010-12-07 17:44:34 +01001159 compress = 1;
bellardea2384d2004-08-01 21:59:26 +00001160 break;
1161 case 'e':
Markus Armbruster9d42e152011-06-22 14:03:55 +02001162 error_report("option -e is deprecated, please use \'-o "
Jes Sorenseneec77d92010-12-07 17:44:34 +01001163 "encryption\' instead!");
1164 return 1;
thsec36ba12007-09-16 21:59:02 +00001165 case '6':
Markus Armbruster9d42e152011-06-22 14:03:55 +02001166 error_report("option -6 is deprecated, please use \'-o "
Jes Sorenseneec77d92010-12-07 17:44:34 +01001167 "compat6\' instead!");
1168 return 1;
Kevin Wolfefa84d42009-05-18 16:42:12 +02001169 case 'o':
1170 options = optarg;
1171 break;
edison51ef6722010-09-21 19:58:41 -07001172 case 's':
1173 snapshot_name = optarg;
1174 break;
Kevin Wolfa22f1232011-08-26 15:27:13 +02001175 case 'S':
1176 {
1177 int64_t sval;
Markus Armbrustere36b3692011-11-22 09:46:05 +01001178 char *end;
1179 sval = strtosz_suffix(optarg, &end, STRTOSZ_DEFSUFFIX_B);
1180 if (sval < 0 || *end) {
Kevin Wolfa22f1232011-08-26 15:27:13 +02001181 error_report("Invalid minimum zero buffer size for sparse output specified");
1182 return 1;
1183 }
1184
1185 min_sparse = sval / BDRV_SECTOR_SIZE;
1186 break;
1187 }
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001188 case 'p':
1189 progress = 1;
1190 break;
Federico Simoncelli661a0f72011-06-20 12:48:19 -04001191 case 't':
1192 cache = optarg;
1193 break;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001194 case 'q':
1195 quiet = true;
1196 break;
bellardea2384d2004-08-01 21:59:26 +00001197 }
1198 }
ths3b46e622007-09-17 08:09:54 +00001199
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001200 if (quiet) {
1201 progress = 0;
1202 }
1203
balrog926c2d22007-10-31 01:11:44 +00001204 bs_n = argc - optind - 1;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001205 if (bs_n < 1) {
1206 help();
1207 }
balrog926c2d22007-10-31 01:11:44 +00001208
1209 out_filename = argv[argc - 1];
thsf58c7b32008-06-05 21:53:49 +00001210
Charles Arnoldfa170c12012-05-11 10:57:54 -06001211 /* Initialize before goto out */
1212 qemu_progress_init(progress, 2.0);
1213
Peter Maydellc8057f92012-08-02 13:45:54 +01001214 if (options && is_help_option(options)) {
Jes Sorensen4ac8aac2010-12-06 15:25:38 +01001215 ret = print_block_option_help(out_filename, out_fmt);
1216 goto out;
1217 }
1218
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001219 if (bs_n > 1 && out_baseimg) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001220 error_report("-B makes no sense when concatenating multiple input "
1221 "images");
Jes Sorensen31ca34b2010-12-06 15:25:36 +01001222 ret = -1;
1223 goto out;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001224 }
Dong Xu Wangf8111c22012-03-15 20:13:31 +08001225
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001226 qemu_progress_print(0, 100);
1227
Anthony Liguori7267c092011-08-20 22:09:37 -05001228 bs = g_malloc0(bs_n * sizeof(BlockDriverState *));
balrog926c2d22007-10-31 01:11:44 +00001229
1230 total_sectors = 0;
1231 for (bs_i = 0; bs_i < bs_n; bs_i++) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001232 bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true,
1233 quiet);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001234 if (!bs[bs_i]) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001235 error_report("Could not open '%s'", argv[optind + bs_i]);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001236 ret = -1;
1237 goto out;
1238 }
balrog926c2d22007-10-31 01:11:44 +00001239 bdrv_get_geometry(bs[bs_i], &bs_sectors);
1240 total_sectors += bs_sectors;
1241 }
bellardea2384d2004-08-01 21:59:26 +00001242
edison51ef6722010-09-21 19:58:41 -07001243 if (snapshot_name != NULL) {
1244 if (bs_n > 1) {
Markus Armbruster6daf1942011-06-22 14:03:54 +02001245 error_report("No support for concatenating multiple snapshot");
edison51ef6722010-09-21 19:58:41 -07001246 ret = -1;
1247 goto out;
1248 }
1249 if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
Markus Armbruster6daf1942011-06-22 14:03:54 +02001250 error_report("Failed to load snapshot");
edison51ef6722010-09-21 19:58:41 -07001251 ret = -1;
1252 goto out;
1253 }
1254 }
1255
Kevin Wolfefa84d42009-05-18 16:42:12 +02001256 /* Find driver and parse its options */
bellardea2384d2004-08-01 21:59:26 +00001257 drv = bdrv_find_format(out_fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001258 if (!drv) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001259 error_report("Unknown file format '%s'", out_fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001260 ret = -1;
1261 goto out;
1262 }
balrog926c2d22007-10-31 01:11:44 +00001263
MORITA Kazutakab50cbab2010-05-26 11:35:36 +09001264 proto_drv = bdrv_find_protocol(out_filename);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001265 if (!proto_drv) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001266 error_report("Unknown protocol '%s'", out_filename);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001267 ret = -1;
1268 goto out;
1269 }
MORITA Kazutakab50cbab2010-05-26 11:35:36 +09001270
1271 create_options = append_option_parameters(create_options,
1272 drv->create_options);
1273 create_options = append_option_parameters(create_options,
1274 proto_drv->create_options);
Kevin Wolfdb08adf2009-06-04 15:39:38 +02001275
Kevin Wolfefa84d42009-05-18 16:42:12 +02001276 if (options) {
MORITA Kazutakab50cbab2010-05-26 11:35:36 +09001277 param = parse_option_parameters(options, create_options, param);
Kevin Wolfefa84d42009-05-18 16:42:12 +02001278 if (param == NULL) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001279 error_report("Invalid options for file format '%s'.", out_fmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001280 ret = -1;
1281 goto out;
Kevin Wolfefa84d42009-05-18 16:42:12 +02001282 }
1283 } else {
MORITA Kazutakab50cbab2010-05-26 11:35:36 +09001284 param = parse_option_parameters("", create_options, param);
Kevin Wolfefa84d42009-05-18 16:42:12 +02001285 }
1286
1287 set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
Jes Sorenseneec77d92010-12-07 17:44:34 +01001288 ret = add_old_style_options(out_fmt, param, out_baseimg, NULL);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001289 if (ret < 0) {
1290 goto out;
1291 }
Kevin Wolfefa84d42009-05-18 16:42:12 +02001292
Kevin Wolfa18953f2010-10-14 15:46:04 +02001293 /* Get backing file name if -o backing_file was used */
1294 out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
1295 if (out_baseimg_param) {
1296 out_baseimg = out_baseimg_param->value.s;
1297 }
1298
Kevin Wolfefa84d42009-05-18 16:42:12 +02001299 /* Check if compression is supported */
Jes Sorenseneec77d92010-12-07 17:44:34 +01001300 if (compress) {
Kevin Wolfefa84d42009-05-18 16:42:12 +02001301 QEMUOptionParameter *encryption =
1302 get_option_parameter(param, BLOCK_OPT_ENCRYPT);
Kevin Wolf41521fa2011-10-18 16:19:42 +02001303 QEMUOptionParameter *preallocation =
1304 get_option_parameter(param, BLOCK_OPT_PREALLOC);
Kevin Wolfefa84d42009-05-18 16:42:12 +02001305
1306 if (!drv->bdrv_write_compressed) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001307 error_report("Compression not supported for this file format");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001308 ret = -1;
1309 goto out;
Kevin Wolfefa84d42009-05-18 16:42:12 +02001310 }
1311
1312 if (encryption && encryption->value.n) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001313 error_report("Compression and encryption not supported at "
1314 "the same time");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001315 ret = -1;
1316 goto out;
Kevin Wolfefa84d42009-05-18 16:42:12 +02001317 }
Kevin Wolf41521fa2011-10-18 16:19:42 +02001318
1319 if (preallocation && preallocation->value.s
1320 && strcmp(preallocation->value.s, "off"))
1321 {
1322 error_report("Compression and preallocation not supported at "
1323 "the same time");
1324 ret = -1;
1325 goto out;
1326 }
Kevin Wolfefa84d42009-05-18 16:42:12 +02001327 }
1328
1329 /* Create the new image */
1330 ret = bdrv_create(drv, out_filename, param);
bellardea2384d2004-08-01 21:59:26 +00001331 if (ret < 0) {
1332 if (ret == -ENOTSUP) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001333 error_report("Formatting not supported for file format '%s'",
1334 out_fmt);
aurel326e9ea0c2009-04-15 14:42:46 +00001335 } else if (ret == -EFBIG) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001336 error_report("The image size is too large for file format '%s'",
1337 out_fmt);
bellardea2384d2004-08-01 21:59:26 +00001338 } else {
Jes Sorensen15654a62010-12-16 14:31:53 +01001339 error_report("%s: error while converting %s: %s",
1340 out_filename, out_fmt, strerror(-ret));
bellardea2384d2004-08-01 21:59:26 +00001341 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001342 goto out;
bellardea2384d2004-08-01 21:59:26 +00001343 }
ths3b46e622007-09-17 08:09:54 +00001344
Federico Simoncelli661a0f72011-06-20 12:48:19 -04001345 flags = BDRV_O_RDWR;
Stefan Hajnoczic3993cd2011-08-04 12:26:51 +01001346 ret = bdrv_parse_cache_flags(cache, &flags);
Federico Simoncelli661a0f72011-06-20 12:48:19 -04001347 if (ret < 0) {
1348 error_report("Invalid cache option: %s", cache);
1349 return -1;
1350 }
1351
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001352 out_bs = bdrv_new_open(out_filename, out_fmt, flags, true, quiet);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001353 if (!out_bs) {
1354 ret = -1;
1355 goto out;
1356 }
bellardea2384d2004-08-01 21:59:26 +00001357
balrog926c2d22007-10-31 01:11:44 +00001358 bs_i = 0;
1359 bs_offset = 0;
1360 bdrv_get_geometry(bs[0], &bs_sectors);
Kevin Wolfbb1c0592011-08-08 14:09:12 +02001361 buf = qemu_blockalign(out_bs, IO_BUF_SIZE);
balrog926c2d22007-10-31 01:11:44 +00001362
Jes Sorenseneec77d92010-12-07 17:44:34 +01001363 if (compress) {
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001364 ret = bdrv_get_info(out_bs, &bdi);
1365 if (ret < 0) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001366 error_report("could not get block driver info");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001367 goto out;
1368 }
bellardfaea38e2006-08-05 21:31:00 +00001369 cluster_size = bdi.cluster_size;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001370 if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001371 error_report("invalid cluster size");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001372 ret = -1;
1373 goto out;
1374 }
bellardea2384d2004-08-01 21:59:26 +00001375 cluster_sectors = cluster_size >> 9;
1376 sector_num = 0;
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001377
1378 nb_sectors = total_sectors;
Kevin Wolf1f710492012-10-12 14:29:18 +02001379 if (nb_sectors != 0) {
1380 local_progress = (float)100 /
1381 (nb_sectors / MIN(nb_sectors, cluster_sectors));
1382 }
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001383
bellardea2384d2004-08-01 21:59:26 +00001384 for(;;) {
balrog926c2d22007-10-31 01:11:44 +00001385 int64_t bs_num;
1386 int remainder;
1387 uint8_t *buf2;
1388
bellardea2384d2004-08-01 21:59:26 +00001389 nb_sectors = total_sectors - sector_num;
1390 if (nb_sectors <= 0)
1391 break;
1392 if (nb_sectors >= cluster_sectors)
1393 n = cluster_sectors;
1394 else
1395 n = nb_sectors;
balrog926c2d22007-10-31 01:11:44 +00001396
1397 bs_num = sector_num - bs_offset;
1398 assert (bs_num >= 0);
1399 remainder = n;
1400 buf2 = buf;
1401 while (remainder > 0) {
1402 int nlow;
1403 while (bs_num == bs_sectors) {
1404 bs_i++;
1405 assert (bs_i < bs_n);
1406 bs_offset += bs_sectors;
1407 bdrv_get_geometry(bs[bs_i], &bs_sectors);
1408 bs_num = 0;
Blue Swirl0bfcd592010-05-22 08:02:12 +00001409 /* printf("changing part: sector_num=%" PRId64 ", "
1410 "bs_i=%d, bs_offset=%" PRId64 ", bs_sectors=%" PRId64
1411 "\n", sector_num, bs_i, bs_offset, bs_sectors); */
balrog926c2d22007-10-31 01:11:44 +00001412 }
1413 assert (bs_num < bs_sectors);
1414
1415 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
1416
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001417 ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);
1418 if (ret < 0) {
Stefan Hajnoczi3fba9d82011-08-17 17:41:09 +01001419 error_report("error while reading sector %" PRId64 ": %s",
1420 bs_num, strerror(-ret));
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001421 goto out;
1422 }
balrog926c2d22007-10-31 01:11:44 +00001423
1424 buf2 += nlow * 512;
1425 bs_num += nlow;
1426
1427 remainder -= nlow;
1428 }
1429 assert (remainder == 0);
1430
Stefan Hajnoczi54f106d2013-04-15 17:17:33 +02001431 if (!buffer_is_zero(buf, n * BDRV_SECTOR_SIZE)) {
1432 ret = bdrv_write_compressed(out_bs, sector_num, buf, n);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001433 if (ret != 0) {
Stefan Hajnoczi3fba9d82011-08-17 17:41:09 +01001434 error_report("error while compressing sector %" PRId64
1435 ": %s", sector_num, strerror(-ret));
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001436 goto out;
1437 }
bellardea2384d2004-08-01 21:59:26 +00001438 }
1439 sector_num += n;
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001440 qemu_progress_print(local_progress, 100);
bellardea2384d2004-08-01 21:59:26 +00001441 }
bellardfaea38e2006-08-05 21:31:00 +00001442 /* signal EOF to align */
1443 bdrv_write_compressed(out_bs, 0, NULL, 0);
bellardea2384d2004-08-01 21:59:26 +00001444 } else {
Kevin Wolff2feebb2010-04-14 17:30:35 +02001445 int has_zero_init = bdrv_has_zero_init(out_bs);
1446
thsf58c7b32008-06-05 21:53:49 +00001447 sector_num = 0; // total number of sectors converted so far
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001448 nb_sectors = total_sectors - sector_num;
Kevin Wolf1f710492012-10-12 14:29:18 +02001449 if (nb_sectors != 0) {
1450 local_progress = (float)100 /
1451 (nb_sectors / MIN(nb_sectors, IO_BUF_SIZE / 512));
1452 }
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001453
bellardea2384d2004-08-01 21:59:26 +00001454 for(;;) {
1455 nb_sectors = total_sectors - sector_num;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001456 if (nb_sectors <= 0) {
bellardea2384d2004-08-01 21:59:26 +00001457 break;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001458 }
1459 if (nb_sectors >= (IO_BUF_SIZE / 512)) {
bellardea2384d2004-08-01 21:59:26 +00001460 n = (IO_BUF_SIZE / 512);
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001461 } else {
bellardea2384d2004-08-01 21:59:26 +00001462 n = nb_sectors;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001463 }
balrog926c2d22007-10-31 01:11:44 +00001464
1465 while (sector_num - bs_offset >= bs_sectors) {
1466 bs_i ++;
1467 assert (bs_i < bs_n);
1468 bs_offset += bs_sectors;
1469 bdrv_get_geometry(bs[bs_i], &bs_sectors);
Blue Swirl0bfcd592010-05-22 08:02:12 +00001470 /* printf("changing part: sector_num=%" PRId64 ", bs_i=%d, "
1471 "bs_offset=%" PRId64 ", bs_sectors=%" PRId64 "\n",
balrog926c2d22007-10-31 01:11:44 +00001472 sector_num, bs_i, bs_offset, bs_sectors); */
1473 }
1474
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001475 if (n > bs_offset + bs_sectors - sector_num) {
balrog926c2d22007-10-31 01:11:44 +00001476 n = bs_offset + bs_sectors - sector_num;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001477 }
balrog926c2d22007-10-31 01:11:44 +00001478
Kevin Wolff2feebb2010-04-14 17:30:35 +02001479 if (has_zero_init) {
Akkarit Sangpetchd0320442009-07-17 10:02:15 +02001480 /* If the output image is being created as a copy on write image,
1481 assume that sectors which are unallocated in the input image
1482 are present in both the output's and input's base images (no
1483 need to copy them). */
1484 if (out_baseimg) {
1485 if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
1486 n, &n1)) {
1487 sector_num += n1;
1488 continue;
1489 }
1490 /* The next 'n1' sectors are allocated in the input image. Copy
1491 only those as they may be followed by unallocated sectors. */
1492 n = n1;
aliguori93c65b42009-04-05 17:40:43 +00001493 }
aliguori93c65b42009-04-05 17:40:43 +00001494 } else {
1495 n1 = n;
thsf58c7b32008-06-05 21:53:49 +00001496 }
1497
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001498 ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
1499 if (ret < 0) {
Stefan Hajnoczi3fba9d82011-08-17 17:41:09 +01001500 error_report("error while reading sector %" PRId64 ": %s",
1501 sector_num - bs_offset, strerror(-ret));
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001502 goto out;
1503 }
bellardea2384d2004-08-01 21:59:26 +00001504 /* NOTE: at the same time we convert, we do not write zero
1505 sectors to have a chance to compress the image. Ideally, we
1506 should add a specific call to have the info to go faster */
1507 buf1 = buf;
1508 while (n > 0) {
thsf58c7b32008-06-05 21:53:49 +00001509 /* If the output image is being created as a copy on write image,
1510 copy all sectors even the ones containing only NUL bytes,
aliguori93c65b42009-04-05 17:40:43 +00001511 because they may differ from the sectors in the base image.
1512
1513 If the output is to a host device, we also write out
1514 sectors that are entirely 0, since whatever data was
1515 already there is garbage, not 0s. */
Kevin Wolff2feebb2010-04-14 17:30:35 +02001516 if (!has_zero_init || out_baseimg ||
Kevin Wolfa22f1232011-08-26 15:27:13 +02001517 is_allocated_sectors_min(buf1, n, &n1, min_sparse)) {
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001518 ret = bdrv_write(out_bs, sector_num, buf1, n1);
1519 if (ret < 0) {
Stefan Hajnoczi3fba9d82011-08-17 17:41:09 +01001520 error_report("error while writing sector %" PRId64
1521 ": %s", sector_num, strerror(-ret));
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001522 goto out;
1523 }
bellardea2384d2004-08-01 21:59:26 +00001524 }
1525 sector_num += n1;
1526 n -= n1;
1527 buf1 += n1 * 512;
1528 }
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001529 qemu_progress_print(local_progress, 100);
bellardea2384d2004-08-01 21:59:26 +00001530 }
1531 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001532out:
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001533 qemu_progress_end();
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001534 free_option_parameters(create_options);
1535 free_option_parameters(param);
Kevin Wolfbb1c0592011-08-08 14:09:12 +02001536 qemu_vfree(buf);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001537 if (out_bs) {
1538 bdrv_delete(out_bs);
1539 }
Jes Sorensen31ca34b2010-12-06 15:25:36 +01001540 if (bs) {
1541 for (bs_i = 0; bs_i < bs_n; bs_i++) {
1542 if (bs[bs_i]) {
1543 bdrv_delete(bs[bs_i]);
1544 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001545 }
Anthony Liguori7267c092011-08-20 22:09:37 -05001546 g_free(bs);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001547 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001548 if (ret) {
1549 return 1;
1550 }
bellardea2384d2004-08-01 21:59:26 +00001551 return 0;
1552}
1553
bellard57d1a2b2004-08-03 21:15:11 +00001554
bellardfaea38e2006-08-05 21:31:00 +00001555static void dump_snapshots(BlockDriverState *bs)
1556{
1557 QEMUSnapshotInfo *sn_tab, *sn;
1558 int nb_sns, i;
bellardfaea38e2006-08-05 21:31:00 +00001559
1560 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
1561 if (nb_sns <= 0)
1562 return;
1563 printf("Snapshot list:\n");
Wenchao Xia5b917042013-05-25 11:09:45 +08001564 bdrv_snapshot_dump(fprintf, stdout, NULL);
1565 printf("\n");
bellardfaea38e2006-08-05 21:31:00 +00001566 for(i = 0; i < nb_sns; i++) {
1567 sn = &sn_tab[i];
Wenchao Xia5b917042013-05-25 11:09:45 +08001568 bdrv_snapshot_dump(fprintf, stdout, sn);
1569 printf("\n");
bellardfaea38e2006-08-05 21:31:00 +00001570 }
Anthony Liguori7267c092011-08-20 22:09:37 -05001571 g_free(sn_tab);
bellardfaea38e2006-08-05 21:31:00 +00001572}
1573
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001574static void dump_json_image_info_list(ImageInfoList *list)
1575{
1576 Error *errp = NULL;
1577 QString *str;
1578 QmpOutputVisitor *ov = qmp_output_visitor_new();
1579 QObject *obj;
1580 visit_type_ImageInfoList(qmp_output_get_visitor(ov),
1581 &list, NULL, &errp);
1582 obj = qmp_output_get_qobject(ov);
1583 str = qobject_to_json_pretty(obj);
1584 assert(str != NULL);
1585 printf("%s\n", qstring_get_str(str));
1586 qobject_decref(obj);
1587 qmp_output_visitor_cleanup(ov);
1588 QDECREF(str);
1589}
1590
Benoît Canetc054b3f2012-09-05 13:09:02 +02001591static void dump_json_image_info(ImageInfo *info)
1592{
1593 Error *errp = NULL;
1594 QString *str;
1595 QmpOutputVisitor *ov = qmp_output_visitor_new();
1596 QObject *obj;
1597 visit_type_ImageInfo(qmp_output_get_visitor(ov),
1598 &info, NULL, &errp);
1599 obj = qmp_output_get_qobject(ov);
1600 str = qobject_to_json_pretty(obj);
1601 assert(str != NULL);
1602 printf("%s\n", qstring_get_str(str));
1603 qobject_decref(obj);
1604 qmp_output_visitor_cleanup(ov);
1605 QDECREF(str);
1606}
1607
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001608static void dump_human_image_info_list(ImageInfoList *list)
1609{
1610 ImageInfoList *elem;
1611 bool delim = false;
1612
1613 for (elem = list; elem; elem = elem->next) {
1614 if (delim) {
1615 printf("\n");
1616 }
1617 delim = true;
1618
Wenchao Xia5b917042013-05-25 11:09:45 +08001619 bdrv_image_info_dump(fprintf, stdout, elem->value);
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001620 }
1621}
1622
1623static gboolean str_equal_func(gconstpointer a, gconstpointer b)
1624{
1625 return strcmp(a, b) == 0;
1626}
1627
1628/**
1629 * Open an image file chain and return an ImageInfoList
1630 *
1631 * @filename: topmost image filename
1632 * @fmt: topmost image format (may be NULL to autodetect)
1633 * @chain: true - enumerate entire backing file chain
1634 * false - only topmost image file
1635 *
1636 * Returns a list of ImageInfo objects or NULL if there was an error opening an
1637 * image file. If there was an error a message will have been printed to
1638 * stderr.
1639 */
1640static ImageInfoList *collect_image_info_list(const char *filename,
1641 const char *fmt,
1642 bool chain)
1643{
1644 ImageInfoList *head = NULL;
1645 ImageInfoList **last = &head;
1646 GHashTable *filenames;
Wenchao Xia43526ec2013-06-06 12:27:58 +08001647 Error *err = NULL;
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001648
1649 filenames = g_hash_table_new_full(g_str_hash, str_equal_func, NULL, NULL);
1650
1651 while (filename) {
1652 BlockDriverState *bs;
1653 ImageInfo *info;
1654 ImageInfoList *elem;
1655
1656 if (g_hash_table_lookup_extended(filenames, filename, NULL, NULL)) {
1657 error_report("Backing file '%s' creates an infinite loop.",
1658 filename);
1659 goto err;
1660 }
1661 g_hash_table_insert(filenames, (gpointer)filename, NULL);
1662
1663 bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING,
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001664 false, false);
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001665 if (!bs) {
1666 goto err;
1667 }
1668
Wenchao Xia43526ec2013-06-06 12:27:58 +08001669 bdrv_query_image_info(bs, &info, &err);
1670 if (error_is_set(&err)) {
1671 error_report("%s", error_get_pretty(err));
1672 error_free(err);
1673 goto err;
Wenchao Xiafb0ed452013-06-06 12:27:57 +08001674 }
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001675
1676 elem = g_new0(ImageInfoList, 1);
1677 elem->value = info;
1678 *last = elem;
1679 last = &elem->next;
1680
1681 bdrv_delete(bs);
1682
1683 filename = fmt = NULL;
1684 if (chain) {
1685 if (info->has_full_backing_filename) {
1686 filename = info->full_backing_filename;
1687 } else if (info->has_backing_filename) {
1688 filename = info->backing_filename;
1689 }
1690 if (info->has_backing_filename_format) {
1691 fmt = info->backing_filename_format;
1692 }
1693 }
1694 }
1695 g_hash_table_destroy(filenames);
1696 return head;
1697
1698err:
1699 qapi_free_ImageInfoList(head);
1700 g_hash_table_destroy(filenames);
1701 return NULL;
1702}
1703
Benoît Canetc054b3f2012-09-05 13:09:02 +02001704static int img_info(int argc, char **argv)
1705{
1706 int c;
1707 OutputFormat output_format = OFORMAT_HUMAN;
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001708 bool chain = false;
Benoît Canetc054b3f2012-09-05 13:09:02 +02001709 const char *filename, *fmt, *output;
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001710 ImageInfoList *list;
Benoît Canetc054b3f2012-09-05 13:09:02 +02001711
bellardea2384d2004-08-01 21:59:26 +00001712 fmt = NULL;
Benoît Canetc054b3f2012-09-05 13:09:02 +02001713 output = NULL;
bellardea2384d2004-08-01 21:59:26 +00001714 for(;;) {
Benoît Canetc054b3f2012-09-05 13:09:02 +02001715 int option_index = 0;
1716 static const struct option long_options[] = {
1717 {"help", no_argument, 0, 'h'},
1718 {"format", required_argument, 0, 'f'},
1719 {"output", required_argument, 0, OPTION_OUTPUT},
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001720 {"backing-chain", no_argument, 0, OPTION_BACKING_CHAIN},
Benoît Canetc054b3f2012-09-05 13:09:02 +02001721 {0, 0, 0, 0}
1722 };
1723 c = getopt_long(argc, argv, "f:h",
1724 long_options, &option_index);
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001725 if (c == -1) {
bellardea2384d2004-08-01 21:59:26 +00001726 break;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001727 }
bellardea2384d2004-08-01 21:59:26 +00001728 switch(c) {
Jes Sorensenef873942010-12-06 15:25:40 +01001729 case '?':
bellardea2384d2004-08-01 21:59:26 +00001730 case 'h':
1731 help();
1732 break;
1733 case 'f':
1734 fmt = optarg;
1735 break;
Benoît Canetc054b3f2012-09-05 13:09:02 +02001736 case OPTION_OUTPUT:
1737 output = optarg;
1738 break;
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001739 case OPTION_BACKING_CHAIN:
1740 chain = true;
1741 break;
bellardea2384d2004-08-01 21:59:26 +00001742 }
1743 }
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001744 if (optind >= argc) {
bellardea2384d2004-08-01 21:59:26 +00001745 help();
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001746 }
bellardea2384d2004-08-01 21:59:26 +00001747 filename = argv[optind++];
1748
Benoît Canetc054b3f2012-09-05 13:09:02 +02001749 if (output && !strcmp(output, "json")) {
1750 output_format = OFORMAT_JSON;
1751 } else if (output && !strcmp(output, "human")) {
1752 output_format = OFORMAT_HUMAN;
1753 } else if (output) {
1754 error_report("--output must be used with human or json as argument.");
1755 return 1;
1756 }
1757
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001758 list = collect_image_info_list(filename, fmt, chain);
1759 if (!list) {
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001760 return 1;
1761 }
Benoît Canetc054b3f2012-09-05 13:09:02 +02001762
Benoît Canetc054b3f2012-09-05 13:09:02 +02001763 switch (output_format) {
1764 case OFORMAT_HUMAN:
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001765 dump_human_image_info_list(list);
Benoît Canetc054b3f2012-09-05 13:09:02 +02001766 break;
1767 case OFORMAT_JSON:
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001768 if (chain) {
1769 dump_json_image_info_list(list);
1770 } else {
1771 dump_json_image_info(list->value);
1772 }
Benoît Canetc054b3f2012-09-05 13:09:02 +02001773 break;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001774 }
Benoît Canetc054b3f2012-09-05 13:09:02 +02001775
Stefan Hajnoczi9699bf02012-10-17 14:02:31 +02001776 qapi_free_ImageInfoList(list);
bellardea2384d2004-08-01 21:59:26 +00001777 return 0;
1778}
1779
aliguorif7b4a942009-01-07 17:40:15 +00001780#define SNAPSHOT_LIST 1
1781#define SNAPSHOT_CREATE 2
1782#define SNAPSHOT_APPLY 3
1783#define SNAPSHOT_DELETE 4
1784
Stuart Brady153859b2009-06-07 00:42:17 +01001785static int img_snapshot(int argc, char **argv)
aliguorif7b4a942009-01-07 17:40:15 +00001786{
1787 BlockDriverState *bs;
1788 QEMUSnapshotInfo sn;
1789 char *filename, *snapshot_name = NULL;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001790 int c, ret = 0, bdrv_oflags;
aliguorif7b4a942009-01-07 17:40:15 +00001791 int action = 0;
1792 qemu_timeval tv;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001793 bool quiet = false;
aliguorif7b4a942009-01-07 17:40:15 +00001794
Kevin Wolf710da702011-01-10 12:33:02 +01001795 bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
aliguorif7b4a942009-01-07 17:40:15 +00001796 /* Parse commandline parameters */
1797 for(;;) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001798 c = getopt(argc, argv, "la:c:d:hq");
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001799 if (c == -1) {
aliguorif7b4a942009-01-07 17:40:15 +00001800 break;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001801 }
aliguorif7b4a942009-01-07 17:40:15 +00001802 switch(c) {
Jes Sorensenef873942010-12-06 15:25:40 +01001803 case '?':
aliguorif7b4a942009-01-07 17:40:15 +00001804 case 'h':
1805 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001806 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001807 case 'l':
1808 if (action) {
1809 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001810 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001811 }
1812 action = SNAPSHOT_LIST;
Naphtali Spreif5edb012010-01-17 16:48:13 +02001813 bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
aliguorif7b4a942009-01-07 17:40:15 +00001814 break;
1815 case 'a':
1816 if (action) {
1817 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001818 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001819 }
1820 action = SNAPSHOT_APPLY;
1821 snapshot_name = optarg;
1822 break;
1823 case 'c':
1824 if (action) {
1825 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001826 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001827 }
1828 action = SNAPSHOT_CREATE;
1829 snapshot_name = optarg;
1830 break;
1831 case 'd':
1832 if (action) {
1833 help();
Stuart Brady153859b2009-06-07 00:42:17 +01001834 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001835 }
1836 action = SNAPSHOT_DELETE;
1837 snapshot_name = optarg;
1838 break;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001839 case 'q':
1840 quiet = true;
1841 break;
aliguorif7b4a942009-01-07 17:40:15 +00001842 }
1843 }
1844
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001845 if (optind >= argc) {
aliguorif7b4a942009-01-07 17:40:15 +00001846 help();
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001847 }
aliguorif7b4a942009-01-07 17:40:15 +00001848 filename = argv[optind++];
1849
1850 /* Open the image */
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001851 bs = bdrv_new_open(filename, NULL, bdrv_oflags, true, quiet);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001852 if (!bs) {
1853 return 1;
1854 }
aliguorif7b4a942009-01-07 17:40:15 +00001855
1856 /* Perform the requested action */
1857 switch(action) {
1858 case SNAPSHOT_LIST:
1859 dump_snapshots(bs);
1860 break;
1861
1862 case SNAPSHOT_CREATE:
1863 memset(&sn, 0, sizeof(sn));
1864 pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
1865
1866 qemu_gettimeofday(&tv);
1867 sn.date_sec = tv.tv_sec;
1868 sn.date_nsec = tv.tv_usec * 1000;
1869
1870 ret = bdrv_snapshot_create(bs, &sn);
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001871 if (ret) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001872 error_report("Could not create snapshot '%s': %d (%s)",
aliguorif7b4a942009-01-07 17:40:15 +00001873 snapshot_name, ret, strerror(-ret));
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001874 }
aliguorif7b4a942009-01-07 17:40:15 +00001875 break;
1876
1877 case SNAPSHOT_APPLY:
1878 ret = bdrv_snapshot_goto(bs, snapshot_name);
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001879 if (ret) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001880 error_report("Could not apply snapshot '%s': %d (%s)",
aliguorif7b4a942009-01-07 17:40:15 +00001881 snapshot_name, ret, strerror(-ret));
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001882 }
aliguorif7b4a942009-01-07 17:40:15 +00001883 break;
1884
1885 case SNAPSHOT_DELETE:
1886 ret = bdrv_snapshot_delete(bs, snapshot_name);
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001887 if (ret) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001888 error_report("Could not delete snapshot '%s': %d (%s)",
aliguorif7b4a942009-01-07 17:40:15 +00001889 snapshot_name, ret, strerror(-ret));
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001890 }
aliguorif7b4a942009-01-07 17:40:15 +00001891 break;
1892 }
1893
1894 /* Cleanup */
1895 bdrv_delete(bs);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001896 if (ret) {
1897 return 1;
1898 }
Stuart Brady153859b2009-06-07 00:42:17 +01001899 return 0;
aliguorif7b4a942009-01-07 17:40:15 +00001900}
1901
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001902static int img_rebase(int argc, char **argv)
1903{
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001904 BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL;
Stefan Hajnoczif163d072010-04-13 10:29:34 +01001905 BlockDriver *old_backing_drv, *new_backing_drv;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001906 char *filename;
Federico Simoncelli661a0f72011-06-20 12:48:19 -04001907 const char *fmt, *cache, *out_basefmt, *out_baseimg;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001908 int c, flags, ret;
1909 int unsafe = 0;
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001910 int progress = 0;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001911 bool quiet = false;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001912
1913 /* Parse commandline parameters */
Kevin Wolfe53dbee2010-03-02 12:14:31 +01001914 fmt = NULL;
Federico Simoncelli661a0f72011-06-20 12:48:19 -04001915 cache = BDRV_DEFAULT_CACHE;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001916 out_baseimg = NULL;
1917 out_basefmt = NULL;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001918 for(;;) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001919 c = getopt(argc, argv, "uhf:F:b:pt:q");
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001920 if (c == -1) {
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001921 break;
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001922 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001923 switch(c) {
Jes Sorensenef873942010-12-06 15:25:40 +01001924 case '?':
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001925 case 'h':
1926 help();
1927 return 0;
Kevin Wolfe53dbee2010-03-02 12:14:31 +01001928 case 'f':
1929 fmt = optarg;
1930 break;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001931 case 'F':
1932 out_basefmt = optarg;
1933 break;
1934 case 'b':
1935 out_baseimg = optarg;
1936 break;
1937 case 'u':
1938 unsafe = 1;
1939 break;
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001940 case 'p':
1941 progress = 1;
1942 break;
Federico Simoncelli661a0f72011-06-20 12:48:19 -04001943 case 't':
1944 cache = optarg;
1945 break;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001946 case 'q':
1947 quiet = true;
1948 break;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001949 }
1950 }
1951
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001952 if (quiet) {
1953 progress = 0;
1954 }
1955
Anthony Liguori9a9d9db2011-04-13 15:51:47 +01001956 if ((optind >= argc) || (!unsafe && !out_baseimg)) {
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001957 help();
Jes Sorensenb8fb60d2010-12-06 15:25:39 +01001958 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001959 filename = argv[optind++];
1960
Jes Sorensen6b837bc2011-03-30 14:16:25 +02001961 qemu_progress_init(progress, 2.0);
1962 qemu_progress_print(0, 100);
1963
Federico Simoncelli661a0f72011-06-20 12:48:19 -04001964 flags = BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
Stefan Hajnoczic3993cd2011-08-04 12:26:51 +01001965 ret = bdrv_parse_cache_flags(cache, &flags);
Federico Simoncelli661a0f72011-06-20 12:48:19 -04001966 if (ret < 0) {
1967 error_report("Invalid cache option: %s", cache);
1968 return -1;
1969 }
1970
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001971 /*
1972 * Open the images.
1973 *
1974 * Ignore the old backing file for unsafe rebase in case we want to correct
1975 * the reference to a renamed or moved backing file.
1976 */
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01001977 bs = bdrv_new_open(filename, fmt, flags, true, quiet);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001978 if (!bs) {
1979 return 1;
1980 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001981
1982 /* Find the right drivers for the backing files */
1983 old_backing_drv = NULL;
1984 new_backing_drv = NULL;
1985
1986 if (!unsafe && bs->backing_format[0] != '\0') {
1987 old_backing_drv = bdrv_find_format(bs->backing_format);
1988 if (old_backing_drv == NULL) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001989 error_report("Invalid format name: '%s'", bs->backing_format);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001990 ret = -1;
1991 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01001992 }
1993 }
1994
1995 if (out_basefmt != NULL) {
1996 new_backing_drv = bdrv_find_format(out_basefmt);
1997 if (new_backing_drv == NULL) {
Jes Sorensen15654a62010-12-16 14:31:53 +01001998 error_report("Invalid format name: '%s'", out_basefmt);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09001999 ret = -1;
2000 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002001 }
2002 }
2003
2004 /* For safe rebasing we need to compare old and new backing file */
2005 if (unsafe) {
2006 /* Make the compiler happy */
2007 bs_old_backing = NULL;
2008 bs_new_backing = NULL;
2009 } else {
2010 char backing_name[1024];
2011
2012 bs_old_backing = bdrv_new("old_backing");
2013 bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
Kevin Wolfde9c0ce2013-03-15 10:35:02 +01002014 ret = bdrv_open(bs_old_backing, backing_name, NULL, BDRV_O_FLAGS,
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002015 old_backing_drv);
2016 if (ret) {
Jes Sorensen15654a62010-12-16 14:31:53 +01002017 error_report("Could not open old backing file '%s'", backing_name);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002018 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002019 }
Alex Bligha6166732012-10-16 13:46:18 +01002020 if (out_baseimg[0]) {
2021 bs_new_backing = bdrv_new("new_backing");
Kevin Wolfde9c0ce2013-03-15 10:35:02 +01002022 ret = bdrv_open(bs_new_backing, out_baseimg, NULL, BDRV_O_FLAGS,
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002023 new_backing_drv);
Alex Bligha6166732012-10-16 13:46:18 +01002024 if (ret) {
2025 error_report("Could not open new backing file '%s'",
2026 out_baseimg);
2027 goto out;
2028 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002029 }
2030 }
2031
2032 /*
2033 * Check each unallocated cluster in the COW file. If it is unallocated,
2034 * accesses go to the backing file. We must therefore compare this cluster
2035 * in the old and new backing file, and if they differ we need to copy it
2036 * from the old backing file into the COW file.
2037 *
2038 * If qemu-img crashes during this step, no harm is done. The content of
2039 * the image is the same as the original one at any time.
2040 */
2041 if (!unsafe) {
2042 uint64_t num_sectors;
Kevin Wolf87a1b3e2011-12-07 12:42:10 +01002043 uint64_t old_backing_num_sectors;
Alex Bligha6166732012-10-16 13:46:18 +01002044 uint64_t new_backing_num_sectors = 0;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002045 uint64_t sector;
Kevin Wolfcc60e322010-04-29 14:47:48 +02002046 int n;
TeLeMand6771bf2010-02-08 16:20:00 +08002047 uint8_t * buf_old;
2048 uint8_t * buf_new;
Kevin Wolf1f710492012-10-12 14:29:18 +02002049 float local_progress = 0;
TeLeMand6771bf2010-02-08 16:20:00 +08002050
Kevin Wolfbb1c0592011-08-08 14:09:12 +02002051 buf_old = qemu_blockalign(bs, IO_BUF_SIZE);
2052 buf_new = qemu_blockalign(bs, IO_BUF_SIZE);
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002053
2054 bdrv_get_geometry(bs, &num_sectors);
Kevin Wolf87a1b3e2011-12-07 12:42:10 +01002055 bdrv_get_geometry(bs_old_backing, &old_backing_num_sectors);
Alex Bligha6166732012-10-16 13:46:18 +01002056 if (bs_new_backing) {
2057 bdrv_get_geometry(bs_new_backing, &new_backing_num_sectors);
2058 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002059
Kevin Wolf1f710492012-10-12 14:29:18 +02002060 if (num_sectors != 0) {
2061 local_progress = (float)100 /
2062 (num_sectors / MIN(num_sectors, IO_BUF_SIZE / 512));
2063 }
2064
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002065 for (sector = 0; sector < num_sectors; sector += n) {
2066
2067 /* How many sectors can we handle with the next read? */
2068 if (sector + (IO_BUF_SIZE / 512) <= num_sectors) {
2069 n = (IO_BUF_SIZE / 512);
2070 } else {
2071 n = num_sectors - sector;
2072 }
2073
2074 /* If the cluster is allocated, we don't need to take action */
Kevin Wolfcc60e322010-04-29 14:47:48 +02002075 ret = bdrv_is_allocated(bs, sector, n, &n);
2076 if (ret) {
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002077 continue;
2078 }
2079
Kevin Wolf87a1b3e2011-12-07 12:42:10 +01002080 /*
2081 * Read old and new backing file and take into consideration that
2082 * backing files may be smaller than the COW image.
2083 */
2084 if (sector >= old_backing_num_sectors) {
2085 memset(buf_old, 0, n * BDRV_SECTOR_SIZE);
2086 } else {
2087 if (sector + n > old_backing_num_sectors) {
2088 n = old_backing_num_sectors - sector;
2089 }
2090
2091 ret = bdrv_read(bs_old_backing, sector, buf_old, n);
2092 if (ret < 0) {
2093 error_report("error while reading from old backing file");
2094 goto out;
2095 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002096 }
Kevin Wolf87a1b3e2011-12-07 12:42:10 +01002097
Alex Bligha6166732012-10-16 13:46:18 +01002098 if (sector >= new_backing_num_sectors || !bs_new_backing) {
Kevin Wolf87a1b3e2011-12-07 12:42:10 +01002099 memset(buf_new, 0, n * BDRV_SECTOR_SIZE);
2100 } else {
2101 if (sector + n > new_backing_num_sectors) {
2102 n = new_backing_num_sectors - sector;
2103 }
2104
2105 ret = bdrv_read(bs_new_backing, sector, buf_new, n);
2106 if (ret < 0) {
2107 error_report("error while reading from new backing file");
2108 goto out;
2109 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002110 }
2111
2112 /* If they differ, we need to write to the COW file */
2113 uint64_t written = 0;
2114
2115 while (written < n) {
2116 int pnum;
2117
2118 if (compare_sectors(buf_old + written * 512,
Kevin Wolf60b1bd42010-02-17 12:32:59 +01002119 buf_new + written * 512, n - written, &pnum))
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002120 {
2121 ret = bdrv_write(bs, sector + written,
2122 buf_old + written * 512, pnum);
2123 if (ret < 0) {
Jes Sorensen15654a62010-12-16 14:31:53 +01002124 error_report("Error while writing to COW image: %s",
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002125 strerror(-ret));
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002126 goto out;
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002127 }
2128 }
2129
2130 written += pnum;
2131 }
Jes Sorensen6b837bc2011-03-30 14:16:25 +02002132 qemu_progress_print(local_progress, 100);
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002133 }
TeLeMand6771bf2010-02-08 16:20:00 +08002134
Kevin Wolfbb1c0592011-08-08 14:09:12 +02002135 qemu_vfree(buf_old);
2136 qemu_vfree(buf_new);
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002137 }
2138
2139 /*
2140 * Change the backing file. All clusters that are different from the old
2141 * backing file are overwritten in the COW file now, so the visible content
2142 * doesn't change when we switch the backing file.
2143 */
Alex Bligha6166732012-10-16 13:46:18 +01002144 if (out_baseimg && *out_baseimg) {
2145 ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt);
2146 } else {
2147 ret = bdrv_change_backing_file(bs, NULL, NULL);
2148 }
2149
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002150 if (ret == -ENOSPC) {
Jes Sorensen15654a62010-12-16 14:31:53 +01002151 error_report("Could not change the backing file to '%s': No "
2152 "space left in the file header", out_baseimg);
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002153 } else if (ret < 0) {
Jes Sorensen15654a62010-12-16 14:31:53 +01002154 error_report("Could not change the backing file to '%s': %s",
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002155 out_baseimg, strerror(-ret));
2156 }
2157
Jes Sorensen6b837bc2011-03-30 14:16:25 +02002158 qemu_progress_print(100, 0);
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002159 /*
2160 * TODO At this point it is possible to check if any clusters that are
2161 * allocated in the COW file are the same in the backing file. If so, they
2162 * could be dropped from the COW file. Don't do this before switching the
2163 * backing file, in case of a crash this would lead to corruption.
2164 */
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002165out:
Jes Sorensen6b837bc2011-03-30 14:16:25 +02002166 qemu_progress_end();
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002167 /* Cleanup */
2168 if (!unsafe) {
Kevin Wolfeb863ad2011-03-31 12:39:51 +02002169 if (bs_old_backing != NULL) {
2170 bdrv_delete(bs_old_backing);
2171 }
2172 if (bs_new_backing != NULL) {
2173 bdrv_delete(bs_new_backing);
2174 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002175 }
2176
2177 bdrv_delete(bs);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002178 if (ret) {
2179 return 1;
2180 }
Kevin Wolf3e85c6f2010-01-12 12:55:18 +01002181 return 0;
2182}
2183
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002184static int img_resize(int argc, char **argv)
2185{
2186 int c, ret, relative;
2187 const char *filename, *fmt, *size;
2188 int64_t n, total_size;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01002189 bool quiet = false;
Jes Sorensen2a819982010-12-06 17:08:31 +01002190 BlockDriverState *bs = NULL;
Dong Xu Wang20caf0f2012-08-06 10:18:42 +08002191 QemuOpts *param;
2192 static QemuOptsList resize_options = {
2193 .name = "resize_options",
2194 .head = QTAILQ_HEAD_INITIALIZER(resize_options.head),
2195 .desc = {
2196 {
2197 .name = BLOCK_OPT_SIZE,
2198 .type = QEMU_OPT_SIZE,
2199 .help = "Virtual disk size"
2200 }, {
2201 /* end of list */
2202 }
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002203 },
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002204 };
2205
Kevin Wolfe80fec72011-04-29 10:58:12 +02002206 /* Remove size from argv manually so that negative numbers are not treated
2207 * as options by getopt. */
2208 if (argc < 3) {
2209 help();
2210 return 1;
2211 }
2212
2213 size = argv[--argc];
2214
2215 /* Parse getopt arguments */
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002216 fmt = NULL;
2217 for(;;) {
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01002218 c = getopt(argc, argv, "f:hq");
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002219 if (c == -1) {
2220 break;
2221 }
2222 switch(c) {
Jes Sorensenef873942010-12-06 15:25:40 +01002223 case '?':
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002224 case 'h':
2225 help();
2226 break;
2227 case 'f':
2228 fmt = optarg;
2229 break;
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01002230 case 'q':
2231 quiet = true;
2232 break;
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002233 }
2234 }
Kevin Wolfe80fec72011-04-29 10:58:12 +02002235 if (optind >= argc) {
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002236 help();
2237 }
2238 filename = argv[optind++];
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002239
2240 /* Choose grow, shrink, or absolute resize mode */
2241 switch (size[0]) {
2242 case '+':
2243 relative = 1;
2244 size++;
2245 break;
2246 case '-':
2247 relative = -1;
2248 size++;
2249 break;
2250 default:
2251 relative = 0;
2252 break;
2253 }
2254
2255 /* Parse size */
Dong Xu Wange478b442012-12-06 14:47:22 +08002256 param = qemu_opts_create_nofail(&resize_options);
Dong Xu Wang20caf0f2012-08-06 10:18:42 +08002257 if (qemu_opt_set(param, BLOCK_OPT_SIZE, size)) {
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002258 /* Error message already printed when size parsing fails */
Jes Sorensen2a819982010-12-06 17:08:31 +01002259 ret = -1;
Dong Xu Wang20caf0f2012-08-06 10:18:42 +08002260 qemu_opts_del(param);
Jes Sorensen2a819982010-12-06 17:08:31 +01002261 goto out;
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002262 }
Dong Xu Wang20caf0f2012-08-06 10:18:42 +08002263 n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0);
2264 qemu_opts_del(param);
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002265
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01002266 bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true, quiet);
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002267 if (!bs) {
Jes Sorensen2a819982010-12-06 17:08:31 +01002268 ret = -1;
2269 goto out;
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002270 }
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002271
2272 if (relative) {
2273 total_size = bdrv_getlength(bs) + n * relative;
2274 } else {
2275 total_size = n;
2276 }
2277 if (total_size <= 0) {
Jes Sorensen15654a62010-12-16 14:31:53 +01002278 error_report("New image size must be positive");
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002279 ret = -1;
2280 goto out;
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002281 }
2282
2283 ret = bdrv_truncate(bs, total_size);
2284 switch (ret) {
2285 case 0:
Miroslav Rezaninaf382d432013-02-13 09:09:40 +01002286 qprintf(quiet, "Image resized.\n");
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002287 break;
2288 case -ENOTSUP:
Kevin Wolf259b2172012-03-06 12:44:45 +01002289 error_report("This image does not support resize");
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002290 break;
2291 case -EACCES:
Jes Sorensen15654a62010-12-16 14:31:53 +01002292 error_report("Image is read-only");
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002293 break;
2294 default:
Jes Sorensen15654a62010-12-16 14:31:53 +01002295 error_report("Error resizing image (%d)", -ret);
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002296 break;
2297 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002298out:
Jes Sorensen2a819982010-12-06 17:08:31 +01002299 if (bs) {
2300 bdrv_delete(bs);
2301 }
MORITA Kazutakac2abcce2010-06-21 04:26:35 +09002302 if (ret) {
2303 return 1;
2304 }
Stefan Hajnocziae6b0ed2010-04-24 09:12:12 +01002305 return 0;
2306}
2307
Anthony Liguoric227f092009-10-01 16:12:16 -05002308static const img_cmd_t img_cmds[] = {
Stuart Brady153859b2009-06-07 00:42:17 +01002309#define DEF(option, callback, arg_string) \
2310 { option, callback },
2311#include "qemu-img-cmds.h"
2312#undef DEF
2313#undef GEN_DOCS
2314 { NULL, NULL, },
2315};
2316
bellardea2384d2004-08-01 21:59:26 +00002317int main(int argc, char **argv)
2318{
Anthony Liguoric227f092009-10-01 16:12:16 -05002319 const img_cmd_t *cmd;
Stuart Brady153859b2009-06-07 00:42:17 +01002320 const char *cmdname;
bellardea2384d2004-08-01 21:59:26 +00002321
Kevin Wolf53f76e52010-12-16 15:10:32 +01002322 error_set_progname(argv[0]);
2323
Paolo Bonzini2592c592012-11-03 18:10:17 +01002324 qemu_init_main_loop();
bellardea2384d2004-08-01 21:59:26 +00002325 bdrv_init();
2326 if (argc < 2)
2327 help();
Stuart Brady153859b2009-06-07 00:42:17 +01002328 cmdname = argv[1];
aurel328f9b1572009-02-09 18:14:31 +00002329 argc--; argv++;
Stuart Brady153859b2009-06-07 00:42:17 +01002330
2331 /* find the command */
2332 for(cmd = img_cmds; cmd->name != NULL; cmd++) {
2333 if (!strcmp(cmdname, cmd->name)) {
2334 return cmd->handler(argc, argv);
2335 }
bellardea2384d2004-08-01 21:59:26 +00002336 }
Stuart Brady153859b2009-06-07 00:42:17 +01002337
2338 /* not found */
2339 help();
bellardea2384d2004-08-01 21:59:26 +00002340 return 0;
2341}