]> git.proxmox.com Git - qemu.git/blame - qemu-img.c
qemu-img: set encrypted disk image password (Laurent Vivier)
[qemu.git] / qemu-img.c
CommitLineData
ea2384d3 1/*
fb43f4dd 2 * QEMU disk image utility
5fafdf24 3 *
68d0f70e 4 * Copyright (c) 2003-2008 Fabrice Bellard
5fafdf24 5 *
ea2384d3
FB
6 * 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 */
faf07963 24#include "qemu-common.h"
ec36ba14 25#include "block_int.h"
926c2d23 26#include <assert.h>
ea2384d3 27
e8445331 28#ifdef _WIN32
4fddf62a 29#define WIN32_LEAN_AND_MEAN
e8445331
FB
30#include <windows.h>
31#endif
32
3f379ab1 33static void __attribute__((noreturn)) error(const char *fmt, ...)
ea2384d3
FB
34{
35 va_list ap;
36 va_start(ap, fmt);
57d1a2b6 37 fprintf(stderr, "qemu-img: ");
ea2384d3
FB
38 vfprintf(stderr, fmt, ap);
39 fprintf(stderr, "\n");
40 exit(1);
41 va_end(ap);
42}
43
44static void format_print(void *opaque, const char *name)
45{
46 printf(" %s", name);
47}
48
3f379ab1 49static void help(void)
ea2384d3 50{
68d0f70e 51 printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
57d1a2b6 52 "usage: qemu-img command [command options]\n"
ea2384d3
FB
53 "QEMU disk image utility\n"
54 "\n"
55 "Command syntax:\n"
ec36ba14 56 " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n"
ea2384d3 57 " commit [-f fmt] filename\n"
f58c7b35 58 " convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n"
ea2384d3
FB
59 " info [-f fmt] filename\n"
60 "\n"
61 "Command parameters:\n"
62 " 'filename' is a disk image filename\n"
63 " 'base_image' is the read-only disk image which is used as base for a copy on\n"
64 " write image; the copy on write image only stores the modified data\n"
f58c7b35
TS
65 " 'output_base_image' forces the output image to be created as a copy on write\n"
66 " image of the specified base image; 'output_base_image' should have the same\n"
67 " content as the input's base image, however the path, image format, etc may\n"
68 " differ\n"
ea2384d3
FB
69 " 'fmt' is the disk image format. It is guessed automatically in most cases\n"
70 " 'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n"
71 " and 'G' (gigabyte) are supported\n"
72 " 'output_filename' is the destination disk image filename\n"
73 " 'output_fmt' is the destination format\n"
74 " '-c' indicates that target image must be compressed (qcow format only)\n"
75 " '-e' indicates that the target image must be encrypted (qcow format only)\n"
ec36ba14 76 " '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"
ea2384d3
FB
77 );
78 printf("\nSupported format:");
79 bdrv_iterate_format(format_print, NULL);
80 printf("\n");
81 exit(1);
82}
83
ea2384d3
FB
84#if defined(WIN32)
85/* XXX: put correct support for win32 */
86static int read_password(char *buf, int buf_size)
87{
88 int c, i;
89 printf("Password: ");
90 fflush(stdout);
91 i = 0;
92 for(;;) {
93 c = getchar();
94 if (c == '\n')
95 break;
96 if (i < (buf_size - 1))
97 buf[i++] = c;
98 }
99 buf[i] = '\0';
100 return 0;
101}
102
103#else
104
105#include <termios.h>
106
107static struct termios oldtty;
108
109static void term_exit(void)
110{
111 tcsetattr (0, TCSANOW, &oldtty);
112}
113
114static void term_init(void)
115{
116 struct termios tty;
117
118 tcgetattr (0, &tty);
119 oldtty = tty;
120
121 tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
122 |INLCR|IGNCR|ICRNL|IXON);
123 tty.c_oflag |= OPOST;
124 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
125 tty.c_cflag &= ~(CSIZE|PARENB);
126 tty.c_cflag |= CS8;
127 tty.c_cc[VMIN] = 1;
128 tty.c_cc[VTIME] = 0;
3b46e624 129
ea2384d3
FB
130 tcsetattr (0, TCSANOW, &tty);
131
132 atexit(term_exit);
133}
134
3f379ab1 135static int read_password(char *buf, int buf_size)
ea2384d3
FB
136{
137 uint8_t ch;
138 int i, ret;
139
140 printf("password: ");
141 fflush(stdout);
142 term_init();
143 i = 0;
144 for(;;) {
145 ret = read(0, &ch, 1);
146 if (ret == -1) {
147 if (errno == EAGAIN || errno == EINTR) {
148 continue;
149 } else {
150 ret = -1;
151 break;
152 }
153 } else if (ret == 0) {
154 ret = -1;
155 break;
156 } else {
157 if (ch == '\r') {
158 ret = 0;
159 break;
160 }
161 if (i < (buf_size - 1))
162 buf[i++] = ch;
163 }
164 }
165 term_exit();
166 buf[i] = '\0';
167 printf("\n");
168 return ret;
169}
170#endif
171
75c23805
FB
172static BlockDriverState *bdrv_new_open(const char *filename,
173 const char *fmt)
174{
175 BlockDriverState *bs;
176 BlockDriver *drv;
177 char password[256];
178
179 bs = bdrv_new("");
180 if (!bs)
181 error("Not enough memory");
182 if (fmt) {
183 drv = bdrv_find_format(fmt);
184 if (!drv)
185 error("Unknown file format '%s'", fmt);
186 } else {
187 drv = NULL;
188 }
189 if (bdrv_open2(bs, filename, 0, drv) < 0) {
190 error("Could not open '%s'", filename);
191 }
192 if (bdrv_is_encrypted(bs)) {
193 printf("Disk image '%s' is encrypted.\n", filename);
194 if (read_password(password, sizeof(password)) < 0)
195 error("No password given");
196 if (bdrv_set_key(bs, password) < 0)
197 error("invalid password");
198 }
199 return bs;
200}
201
ea2384d3
FB
202static int img_create(int argc, char **argv)
203{
ec36ba14 204 int c, ret, flags;
ea2384d3
FB
205 const char *fmt = "raw";
206 const char *filename;
207 const char *base_filename = NULL;
96b8f136 208 uint64_t size;
ea2384d3
FB
209 const char *p;
210 BlockDriver *drv;
61fce45f 211 BlockDriverState *bs;
3b46e624 212
ec36ba14 213 flags = 0;
ea2384d3 214 for(;;) {
ec36ba14 215 c = getopt(argc, argv, "b:f:he6");
ea2384d3
FB
216 if (c == -1)
217 break;
218 switch(c) {
219 case 'h':
220 help();
221 break;
222 case 'b':
223 base_filename = optarg;
224 break;
225 case 'f':
226 fmt = optarg;
227 break;
228 case 'e':
ec36ba14 229 flags |= BLOCK_FLAG_ENCRYPT;
ea2384d3 230 break;
d8871c5a 231 case '6':
ec36ba14 232 flags |= BLOCK_FLAG_COMPAT6;
d8871c5a 233 break;
ea2384d3
FB
234 }
235 }
5fafdf24 236 if (optind >= argc)
ea2384d3
FB
237 help();
238 filename = argv[optind++];
239 size = 0;
75c23805 240 if (base_filename) {
75c23805
FB
241 bs = bdrv_new_open(base_filename, NULL);
242 bdrv_get_geometry(bs, &size);
243 size *= 512;
244 bdrv_delete(bs);
245 } else {
ea2384d3
FB
246 if (optind >= argc)
247 help();
248 p = argv[optind];
249 size = strtoul(p, (char **)&p, 0);
250 if (*p == 'M') {
251 size *= 1024 * 1024;
252 } else if (*p == 'G') {
253 size *= 1024 * 1024 * 1024;
254 } else if (*p == 'k' || *p == 'K' || *p == '\0') {
255 size *= 1024;
256 } else {
257 help();
258 }
259 }
260 drv = bdrv_find_format(fmt);
261 if (!drv)
262 error("Unknown file format '%s'", fmt);
0cfec834 263 printf("Formatting '%s', fmt=%s",
ea2384d3 264 filename, fmt);
ec36ba14 265 if (flags & BLOCK_FLAG_ENCRYPT)
ea2384d3 266 printf(", encrypted");
ec36ba14
TS
267 if (flags & BLOCK_FLAG_COMPAT6)
268 printf(", compatibility level=6");
75c23805
FB
269 if (base_filename) {
270 printf(", backing_file=%s",
ea2384d3 271 base_filename);
75c23805 272 }
96b8f136 273 printf(", size=%" PRIu64 " kB\n", size / 1024);
ec36ba14 274 ret = bdrv_create(drv, filename, size / 512, base_filename, flags);
ea2384d3
FB
275 if (ret < 0) {
276 if (ret == -ENOTSUP) {
3c56521b 277 error("Formatting or formatting option not supported for file format '%s'", fmt);
ea2384d3
FB
278 } else {
279 error("Error while formatting");
280 }
281 }
61fce45f
AL
282 /* to set password */
283 bs = bdrv_new_open(filename, NULL);
284 bdrv_delete(bs);
ea2384d3
FB
285 return 0;
286}
287
288static int img_commit(int argc, char **argv)
289{
290 int c, ret;
291 const char *filename, *fmt;
292 BlockDriver *drv;
293 BlockDriverState *bs;
294
295 fmt = NULL;
296 for(;;) {
297 c = getopt(argc, argv, "f:h");
298 if (c == -1)
299 break;
300 switch(c) {
301 case 'h':
302 help();
303 break;
304 case 'f':
305 fmt = optarg;
306 break;
307 }
308 }
5fafdf24 309 if (optind >= argc)
ea2384d3
FB
310 help();
311 filename = argv[optind++];
312
313 bs = bdrv_new("");
314 if (!bs)
315 error("Not enough memory");
316 if (fmt) {
317 drv = bdrv_find_format(fmt);
318 if (!drv)
319 error("Unknown file format '%s'", fmt);
320 } else {
321 drv = NULL;
322 }
323 if (bdrv_open2(bs, filename, 0, drv) < 0) {
324 error("Could not open '%s'", filename);
325 }
326 ret = bdrv_commit(bs);
327 switch(ret) {
328 case 0:
329 printf("Image committed.\n");
330 break;
331 case -ENOENT:
332 error("No disk inserted");
333 break;
334 case -EACCES:
335 error("Image is read-only");
336 break;
337 case -ENOTSUP:
338 error("Image is already committed");
339 break;
340 default:
341 error("Error while committing image");
342 break;
343 }
344
345 bdrv_delete(bs);
346 return 0;
347}
348
349static int is_not_zero(const uint8_t *sector, int len)
350{
351 int i;
352 len >>= 2;
353 for(i = 0;i < len; i++) {
354 if (((uint32_t *)sector)[i] != 0)
355 return 1;
356 }
357 return 0;
358}
359
f58c7b35
TS
360/*
361 * Returns true iff the first sector pointed to by 'buf' contains at least
362 * a non-NUL byte.
363 *
364 * 'pnum' is set to the number of sectors (including and immediately following
365 * the first one) that are known to be in the same allocated/unallocated state.
366 */
ea2384d3
FB
367static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
368{
369 int v, i;
370
371 if (n <= 0) {
372 *pnum = 0;
373 return 0;
374 }
375 v = is_not_zero(buf, 512);
376 for(i = 1; i < n; i++) {
377 buf += 512;
378 if (v != is_not_zero(buf, 512))
379 break;
380 }
381 *pnum = i;
382 return v;
383}
384
ea2384d3
FB
385#define IO_BUF_SIZE 65536
386
387static int img_convert(int argc, char **argv)
388{
926c2d23 389 int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
f58c7b35 390 const char *fmt, *out_fmt, *out_baseimg, *out_filename;
ea2384d3 391 BlockDriver *drv;
926c2d23 392 BlockDriverState **bs, *out_bs;
96b8f136
TS
393 int64_t total_sectors, nb_sectors, sector_num, bs_offset;
394 uint64_t bs_sectors;
ea2384d3
FB
395 uint8_t buf[IO_BUF_SIZE];
396 const uint8_t *buf1;
faea38e7 397 BlockDriverInfo bdi;
ea2384d3
FB
398
399 fmt = NULL;
400 out_fmt = "raw";
f58c7b35 401 out_baseimg = NULL;
ec36ba14 402 flags = 0;
ea2384d3 403 for(;;) {
f58c7b35 404 c = getopt(argc, argv, "f:O:B:hce6");
ea2384d3
FB
405 if (c == -1)
406 break;
407 switch(c) {
408 case 'h':
409 help();
410 break;
411 case 'f':
412 fmt = optarg;
413 break;
414 case 'O':
415 out_fmt = optarg;
416 break;
f58c7b35
TS
417 case 'B':
418 out_baseimg = optarg;
419 break;
ea2384d3 420 case 'c':
ec36ba14 421 flags |= BLOCK_FLAG_COMPRESS;
ea2384d3
FB
422 break;
423 case 'e':
ec36ba14
TS
424 flags |= BLOCK_FLAG_ENCRYPT;
425 break;
426 case '6':
427 flags |= BLOCK_FLAG_COMPAT6;
ea2384d3
FB
428 break;
429 }
430 }
3b46e624 431
926c2d23
AZ
432 bs_n = argc - optind - 1;
433 if (bs_n < 1) help();
434
435 out_filename = argv[argc - 1];
f58c7b35
TS
436
437 if (bs_n > 1 && out_baseimg)
438 error("-B makes no sense when concatenating multiple input images");
926c2d23
AZ
439
440 bs = calloc(bs_n, sizeof(BlockDriverState *));
441 if (!bs)
442 error("Out of memory");
443
444 total_sectors = 0;
445 for (bs_i = 0; bs_i < bs_n; bs_i++) {
446 bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
447 if (!bs[bs_i])
448 error("Could not open '%s'", argv[optind + bs_i]);
449 bdrv_get_geometry(bs[bs_i], &bs_sectors);
450 total_sectors += bs_sectors;
451 }
ea2384d3
FB
452
453 drv = bdrv_find_format(out_fmt);
454 if (!drv)
d34dda5e 455 error("Unknown file format '%s'", out_fmt);
ec36ba14 456 if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
ea2384d3 457 error("Compression not supported for this file format");
ec36ba14 458 if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
ea2384d3 459 error("Encryption not supported for this file format");
d8871c5a 460 if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk)
ec36ba14
TS
461 error("Alternative compatibility level not supported for this file format");
462 if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
ea2384d3 463 error("Compression and encryption not supported at the same time");
926c2d23 464
f58c7b35 465 ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
ea2384d3
FB
466 if (ret < 0) {
467 if (ret == -ENOTSUP) {
3c56521b 468 error("Formatting not supported for file format '%s'", fmt);
ea2384d3
FB
469 } else {
470 error("Error while formatting '%s'", out_filename);
471 }
472 }
3b46e624 473
ea2384d3
FB
474 out_bs = bdrv_new_open(out_filename, out_fmt);
475
926c2d23
AZ
476 bs_i = 0;
477 bs_offset = 0;
478 bdrv_get_geometry(bs[0], &bs_sectors);
479
480 if (flags & BLOCK_FLAG_COMPRESS) {
faea38e7
FB
481 if (bdrv_get_info(out_bs, &bdi) < 0)
482 error("could not get block driver info");
483 cluster_size = bdi.cluster_size;
ea2384d3
FB
484 if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
485 error("invalid cluster size");
486 cluster_sectors = cluster_size >> 9;
487 sector_num = 0;
488 for(;;) {
926c2d23
AZ
489 int64_t bs_num;
490 int remainder;
491 uint8_t *buf2;
492
ea2384d3
FB
493 nb_sectors = total_sectors - sector_num;
494 if (nb_sectors <= 0)
495 break;
496 if (nb_sectors >= cluster_sectors)
497 n = cluster_sectors;
498 else
499 n = nb_sectors;
926c2d23
AZ
500
501 bs_num = sector_num - bs_offset;
502 assert (bs_num >= 0);
503 remainder = n;
504 buf2 = buf;
505 while (remainder > 0) {
506 int nlow;
507 while (bs_num == bs_sectors) {
508 bs_i++;
509 assert (bs_i < bs_n);
510 bs_offset += bs_sectors;
511 bdrv_get_geometry(bs[bs_i], &bs_sectors);
512 bs_num = 0;
513 /* printf("changing part: sector_num=%lld, "
514 "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
515 sector_num, bs_i, bs_offset, bs_sectors); */
516 }
517 assert (bs_num < bs_sectors);
518
519 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
520
521 if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0)
522 error("error while reading");
523
524 buf2 += nlow * 512;
525 bs_num += nlow;
526
527 remainder -= nlow;
528 }
529 assert (remainder == 0);
530
ea2384d3
FB
531 if (n < cluster_sectors)
532 memset(buf + n * 512, 0, cluster_size - n * 512);
533 if (is_not_zero(buf, cluster_size)) {
5fafdf24 534 if (bdrv_write_compressed(out_bs, sector_num, buf,
faea38e7 535 cluster_sectors) != 0)
ec3757de
FB
536 error("error while compressing sector %" PRId64,
537 sector_num);
ea2384d3
FB
538 }
539 sector_num += n;
540 }
faea38e7
FB
541 /* signal EOF to align */
542 bdrv_write_compressed(out_bs, 0, NULL, 0);
ea2384d3 543 } else {
f58c7b35 544 sector_num = 0; // total number of sectors converted so far
ea2384d3
FB
545 for(;;) {
546 nb_sectors = total_sectors - sector_num;
547 if (nb_sectors <= 0)
548 break;
549 if (nb_sectors >= (IO_BUF_SIZE / 512))
550 n = (IO_BUF_SIZE / 512);
551 else
552 n = nb_sectors;
926c2d23
AZ
553
554 while (sector_num - bs_offset >= bs_sectors) {
555 bs_i ++;
556 assert (bs_i < bs_n);
557 bs_offset += bs_sectors;
558 bdrv_get_geometry(bs[bs_i], &bs_sectors);
559 /* printf("changing part: sector_num=%lld, bs_i=%d, "
560 "bs_offset=%lld, bs_sectors=%lld\n",
561 sector_num, bs_i, bs_offset, bs_sectors); */
562 }
563
564 if (n > bs_offset + bs_sectors - sector_num)
565 n = bs_offset + bs_sectors - sector_num;
566
f58c7b35
TS
567 /* If the output image is being created as a copy on write image,
568 assume that sectors which are unallocated in the input image
569 are present in both the output's and input's base images (no
570 need to copy them). */
571 if (out_baseimg) {
572 if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) {
573 sector_num += n1;
574 continue;
575 }
576 /* The next 'n1' sectors are allocated in the input image. Copy
577 only those as they may be followed by unallocated sectors. */
578 n = n1;
579 }
580
926c2d23 581 if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0)
ea2384d3
FB
582 error("error while reading");
583 /* NOTE: at the same time we convert, we do not write zero
584 sectors to have a chance to compress the image. Ideally, we
585 should add a specific call to have the info to go faster */
586 buf1 = buf;
587 while (n > 0) {
f58c7b35
TS
588 /* If the output image is being created as a copy on write image,
589 copy all sectors even the ones containing only NUL bytes,
590 because they may differ from the sectors in the base image. */
591 if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) {
5fafdf24 592 if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
ea2384d3
FB
593 error("error while writing");
594 }
595 sector_num += n1;
596 n -= n1;
597 buf1 += n1 * 512;
598 }
599 }
600 }
601 bdrv_delete(out_bs);
926c2d23
AZ
602 for (bs_i = 0; bs_i < bs_n; bs_i++)
603 bdrv_delete(bs[bs_i]);
604 free(bs);
ea2384d3
FB
605 return 0;
606}
607
57d1a2b6
FB
608#ifdef _WIN32
609static int64_t get_allocated_file_size(const char *filename)
610{
e8445331
FB
611 typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
612 get_compressed_t get_compressed;
57d1a2b6 613 struct _stati64 st;
e8445331
FB
614
615 /* WinNT support GetCompressedFileSize to determine allocate size */
616 get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
617 if (get_compressed) {
618 DWORD high, low;
619 low = get_compressed(filename, &high);
620 if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
621 return (((int64_t) high) << 32) + low;
622 }
623
5fafdf24 624 if (_stati64(filename, &st) < 0)
57d1a2b6
FB
625 return -1;
626 return st.st_size;
627}
628#else
629static int64_t get_allocated_file_size(const char *filename)
630{
631 struct stat st;
5fafdf24 632 if (stat(filename, &st) < 0)
57d1a2b6
FB
633 return -1;
634 return (int64_t)st.st_blocks * 512;
635}
636#endif
637
faea38e7
FB
638static void dump_snapshots(BlockDriverState *bs)
639{
640 QEMUSnapshotInfo *sn_tab, *sn;
641 int nb_sns, i;
642 char buf[256];
643
644 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
645 if (nb_sns <= 0)
646 return;
647 printf("Snapshot list:\n");
648 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
649 for(i = 0; i < nb_sns; i++) {
650 sn = &sn_tab[i];
651 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
652 }
653 qemu_free(sn_tab);
654}
655
ea2384d3
FB
656static int img_info(int argc, char **argv)
657{
658 int c;
659 const char *filename, *fmt;
660 BlockDriver *drv;
661 BlockDriverState *bs;
662 char fmt_name[128], size_buf[128], dsize_buf[128];
96b8f136
TS
663 uint64_t total_sectors;
664 int64_t allocated_size;
93b6b2a3
FB
665 char backing_filename[1024];
666 char backing_filename2[1024];
faea38e7 667 BlockDriverInfo bdi;
ea2384d3
FB
668
669 fmt = NULL;
670 for(;;) {
671 c = getopt(argc, argv, "f:h");
672 if (c == -1)
673 break;
674 switch(c) {
675 case 'h':
676 help();
677 break;
678 case 'f':
679 fmt = optarg;
680 break;
681 }
682 }
5fafdf24 683 if (optind >= argc)
ea2384d3
FB
684 help();
685 filename = argv[optind++];
686
687 bs = bdrv_new("");
688 if (!bs)
689 error("Not enough memory");
690 if (fmt) {
691 drv = bdrv_find_format(fmt);
692 if (!drv)
693 error("Unknown file format '%s'", fmt);
694 } else {
695 drv = NULL;
696 }
697 if (bdrv_open2(bs, filename, 0, drv) < 0) {
698 error("Could not open '%s'", filename);
699 }
700 bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
701 bdrv_get_geometry(bs, &total_sectors);
702 get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
57d1a2b6
FB
703 allocated_size = get_allocated_file_size(filename);
704 if (allocated_size < 0)
de167e41
FB
705 sprintf(dsize_buf, "unavailable");
706 else
5fafdf24 707 get_human_readable_size(dsize_buf, sizeof(dsize_buf),
de167e41 708 allocated_size);
ea2384d3
FB
709 printf("image: %s\n"
710 "file format: %s\n"
ec3757de 711 "virtual size: %s (%" PRId64 " bytes)\n"
ea2384d3 712 "disk size: %s\n",
5fafdf24 713 filename, fmt_name, size_buf,
ec3757de 714 (total_sectors * 512),
ea2384d3
FB
715 dsize_buf);
716 if (bdrv_is_encrypted(bs))
717 printf("encrypted: yes\n");
faea38e7 718 if (bdrv_get_info(bs, &bdi) >= 0) {
5fafdf24 719 if (bdi.cluster_size != 0)
faea38e7
FB
720 printf("cluster_size: %d\n", bdi.cluster_size);
721 }
93b6b2a3 722 bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
faea38e7 723 if (backing_filename[0] != '\0') {
93b6b2a3
FB
724 path_combine(backing_filename2, sizeof(backing_filename2),
725 filename, backing_filename);
5fafdf24 726 printf("backing file: %s (actual path: %s)\n",
93b6b2a3
FB
727 backing_filename,
728 backing_filename2);
faea38e7
FB
729 }
730 dump_snapshots(bs);
ea2384d3
FB
731 bdrv_delete(bs);
732 return 0;
733}
734
735int main(int argc, char **argv)
736{
737 const char *cmd;
738
739 bdrv_init();
740 if (argc < 2)
741 help();
742 cmd = argv[1];
e3888186 743 optind++;
ea2384d3
FB
744 if (!strcmp(cmd, "create")) {
745 img_create(argc, argv);
746 } else if (!strcmp(cmd, "commit")) {
747 img_commit(argc, argv);
748 } else if (!strcmp(cmd, "convert")) {
749 img_convert(argc, argv);
750 } else if (!strcmp(cmd, "info")) {
751 img_info(argc, argv);
752 } else {
753 help();
754 }
755 return 0;
756}