Abort on attempts to allocate zero bytes
[qemu-kvm/fedora.git] / qemu-img.c
bloba3d15e716bb556da5a7551c8b40eed1fa4055ad9
1 /*
2 * QEMU disk image utility
4 * Copyright (c) 2003-2008 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
24 #include "qemu-common.h"
25 #include "osdep.h"
26 #include "block_int.h"
27 #include <stdio.h>
29 #ifdef _WIN32
30 #include <windows.h>
31 #endif
33 /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
34 #define BRDV_O_FLAGS BDRV_O_CACHE_WB
36 static void QEMU_NORETURN error(const char *fmt, ...)
38 va_list ap;
39 va_start(ap, fmt);
40 fprintf(stderr, "qemu-img: ");
41 vfprintf(stderr, fmt, ap);
42 fprintf(stderr, "\n");
43 exit(1);
44 va_end(ap);
47 static void format_print(void *opaque, const char *name)
49 printf(" %s", name);
52 /* Please keep in synch with qemu-img.texi */
53 static void help(void)
55 printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
56 "usage: qemu-img command [command options]\n"
57 "QEMU disk image utility\n"
58 "\n"
59 "Command syntax:\n"
60 " check [-f fmt] filename\n"
61 " create [-e] [-6] [-F fmt] [-b base_image] [-f fmt] filename [size]\n"
62 " commit [-f fmt] filename\n"
63 " convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n"
64 " info [-f fmt] filename\n"
65 " snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename\n"
66 "\n"
67 "Command parameters:\n"
68 " 'filename' is a disk image filename\n"
69 " 'base_image' is the read-only disk image which is used as base for a copy on\n"
70 " write image; the copy on write image only stores the modified data\n"
71 " 'output_base_image' forces the output image to be created as a copy on write\n"
72 " image of the specified base image; 'output_base_image' should have the same\n"
73 " content as the input's base image, however the path, image format, etc may\n"
74 " differ\n"
75 " 'fmt' is the disk image format. It is guessed automatically in most cases\n"
76 " 'size' is the disk image size in kilobytes. Optional suffixes\n"
77 " 'M' (megabyte, 1024 * 1024) and 'G' (gigabyte, 1024 * 1024 * 1024) are\n"
78 " supported any 'k' or 'K' is ignored\n"
79 " 'output_filename' is the destination disk image filename\n"
80 " 'output_fmt' is the destination format\n"
81 " '-c' indicates that target image must be compressed (qcow format only)\n"
82 " '-e' indicates that the target image must be encrypted (qcow format only)\n"
83 " '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"
84 " '-h' with or without a command shows this help and lists the supported formats\n"
85 "\n"
86 "Parameters to snapshot subcommand:\n"
87 " 'snapshot' is the name of the snapshot to create, apply or delete\n"
88 " '-a' applies a snapshot (revert disk to saved state)\n"
89 " '-c' creates a snapshot\n"
90 " '-d' deletes a snapshot\n"
91 " '-l' lists all snapshots in the given image\n"
93 printf("\nSupported formats:");
94 bdrv_iterate_format(format_print, NULL);
95 printf("\n");
96 exit(1);
99 #if defined(WIN32)
100 /* XXX: put correct support for win32 */
101 static int read_password(char *buf, int buf_size)
103 int c, i;
104 printf("Password: ");
105 fflush(stdout);
106 i = 0;
107 for(;;) {
108 c = getchar();
109 if (c == '\n')
110 break;
111 if (i < (buf_size - 1))
112 buf[i++] = c;
114 buf[i] = '\0';
115 return 0;
118 #else
120 #include <termios.h>
122 static struct termios oldtty;
124 static void term_exit(void)
126 tcsetattr (0, TCSANOW, &oldtty);
129 static void term_init(void)
131 struct termios tty;
133 tcgetattr (0, &tty);
134 oldtty = tty;
136 tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
137 |INLCR|IGNCR|ICRNL|IXON);
138 tty.c_oflag |= OPOST;
139 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
140 tty.c_cflag &= ~(CSIZE|PARENB);
141 tty.c_cflag |= CS8;
142 tty.c_cc[VMIN] = 1;
143 tty.c_cc[VTIME] = 0;
145 tcsetattr (0, TCSANOW, &tty);
147 atexit(term_exit);
150 static int read_password(char *buf, int buf_size)
152 uint8_t ch;
153 int i, ret;
155 printf("password: ");
156 fflush(stdout);
157 term_init();
158 i = 0;
159 for(;;) {
160 ret = read(0, &ch, 1);
161 if (ret == -1) {
162 if (errno == EAGAIN || errno == EINTR) {
163 continue;
164 } else {
165 ret = -1;
166 break;
168 } else if (ret == 0) {
169 ret = -1;
170 break;
171 } else {
172 if (ch == '\r') {
173 ret = 0;
174 break;
176 if (i < (buf_size - 1))
177 buf[i++] = ch;
180 term_exit();
181 buf[i] = '\0';
182 printf("\n");
183 return ret;
185 #endif
187 static BlockDriverState *bdrv_new_open(const char *filename,
188 const char *fmt)
190 BlockDriverState *bs;
191 BlockDriver *drv;
192 char password[256];
194 bs = bdrv_new("");
195 if (!bs)
196 error("Not enough memory");
197 if (fmt) {
198 drv = bdrv_find_format(fmt);
199 if (!drv)
200 error("Unknown file format '%s'", fmt);
201 } else {
202 drv = NULL;
204 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
205 error("Could not open '%s'", filename);
207 if (bdrv_is_encrypted(bs)) {
208 printf("Disk image '%s' is encrypted.\n", filename);
209 if (read_password(password, sizeof(password)) < 0)
210 error("No password given");
211 if (bdrv_set_key(bs, password) < 0)
212 error("invalid password");
214 return bs;
217 static int img_create(int argc, char **argv)
219 int c, ret, flags;
220 const char *fmt = "raw";
221 const char *base_fmt = NULL;
222 const char *filename;
223 const char *base_filename = NULL;
224 uint64_t size;
225 double sizef;
226 const char *p;
227 BlockDriver *drv;
229 flags = 0;
230 for(;;) {
231 c = getopt(argc, argv, "F:b:f:he6");
232 if (c == -1)
233 break;
234 switch(c) {
235 case 'h':
236 help();
237 break;
238 case 'F':
239 base_fmt = optarg;
240 break;
241 case 'b':
242 base_filename = optarg;
243 break;
244 case 'f':
245 fmt = optarg;
246 break;
247 case 'e':
248 flags |= BLOCK_FLAG_ENCRYPT;
249 break;
250 case '6':
251 flags |= BLOCK_FLAG_COMPAT6;
252 break;
255 if (optind >= argc)
256 help();
257 filename = argv[optind++];
258 size = 0;
259 if (base_filename) {
260 BlockDriverState *bs;
261 BlockDriver *base_drv = NULL;
263 if (base_fmt) {
264 base_drv = bdrv_find_format(base_fmt);
265 if (base_drv == NULL)
266 error("Unknown basefile format '%s'", base_fmt);
269 bs = bdrv_new_open(base_filename, base_fmt);
270 bdrv_get_geometry(bs, &size);
271 size *= 512;
272 bdrv_delete(bs);
273 } else {
274 if (optind >= argc)
275 help();
276 p = argv[optind];
277 sizef = strtod(p, (char **)&p);
278 if (*p == 'M') {
279 size = (uint64_t)(sizef * 1024 * 1024);
280 } else if (*p == 'G') {
281 size = (uint64_t)(sizef * 1024 * 1024 * 1024);
282 } else if (*p == 'k' || *p == 'K' || *p == '\0') {
283 size = (uint64_t)(sizef * 1024);
284 } else {
285 help();
288 drv = bdrv_find_format(fmt);
289 if (!drv)
290 error("Unknown file format '%s'", fmt);
291 printf("Formatting '%s', fmt=%s",
292 filename, fmt);
293 if (flags & BLOCK_FLAG_ENCRYPT)
294 printf(", encrypted");
295 if (flags & BLOCK_FLAG_COMPAT6)
296 printf(", compatibility level=6");
297 if (base_filename) {
298 printf(", backing_file=%s",
299 base_filename);
300 if (base_fmt)
301 printf(", backing_fmt=%s",
302 base_fmt);
304 printf(", size=%" PRIu64 " kB\n", size / 1024);
305 ret = bdrv_create2(drv, filename, size / 512, base_filename, base_fmt, flags);
306 if (ret < 0) {
307 if (ret == -ENOTSUP) {
308 error("Formatting or formatting option not supported for file format '%s'", fmt);
309 } else if (ret == -EFBIG) {
310 error("The image size is too large for file format '%s'", fmt);
311 } else {
312 error("Error while formatting");
315 return 0;
318 static int img_check(int argc, char **argv)
320 int c, ret;
321 const char *filename, *fmt;
322 BlockDriver *drv;
323 BlockDriverState *bs;
325 fmt = NULL;
326 for(;;) {
327 c = getopt(argc, argv, "f:h");
328 if (c == -1)
329 break;
330 switch(c) {
331 case 'h':
332 help();
333 break;
334 case 'f':
335 fmt = optarg;
336 break;
339 if (optind >= argc)
340 help();
341 filename = argv[optind++];
343 bs = bdrv_new("");
344 if (!bs)
345 error("Not enough memory");
346 if (fmt) {
347 drv = bdrv_find_format(fmt);
348 if (!drv)
349 error("Unknown file format '%s'", fmt);
350 } else {
351 drv = NULL;
353 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
354 error("Could not open '%s'", filename);
356 ret = bdrv_check(bs);
357 switch(ret) {
358 case 0:
359 printf("No errors were found on the image.\n");
360 break;
361 case -ENOTSUP:
362 error("This image format does not support checks");
363 break;
364 default:
365 if (ret < 0) {
366 error("An error occurred during the check");
367 } else {
368 printf("%d errors were found on the image.\n", ret);
370 break;
373 bdrv_delete(bs);
374 return 0;
377 static int img_commit(int argc, char **argv)
379 int c, ret;
380 const char *filename, *fmt;
381 BlockDriver *drv;
382 BlockDriverState *bs;
384 fmt = NULL;
385 for(;;) {
386 c = getopt(argc, argv, "f:h");
387 if (c == -1)
388 break;
389 switch(c) {
390 case 'h':
391 help();
392 break;
393 case 'f':
394 fmt = optarg;
395 break;
398 if (optind >= argc)
399 help();
400 filename = argv[optind++];
402 bs = bdrv_new("");
403 if (!bs)
404 error("Not enough memory");
405 if (fmt) {
406 drv = bdrv_find_format(fmt);
407 if (!drv)
408 error("Unknown file format '%s'", fmt);
409 } else {
410 drv = NULL;
412 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
413 error("Could not open '%s'", filename);
415 ret = bdrv_commit(bs);
416 switch(ret) {
417 case 0:
418 printf("Image committed.\n");
419 break;
420 case -ENOENT:
421 error("No disk inserted");
422 break;
423 case -EACCES:
424 error("Image is read-only");
425 break;
426 case -ENOTSUP:
427 error("Image is already committed");
428 break;
429 default:
430 error("Error while committing image");
431 break;
434 bdrv_delete(bs);
435 return 0;
438 static int is_not_zero(const uint8_t *sector, int len)
440 int i;
441 len >>= 2;
442 for(i = 0;i < len; i++) {
443 if (((uint32_t *)sector)[i] != 0)
444 return 1;
446 return 0;
450 * Returns true iff the first sector pointed to by 'buf' contains at least
451 * a non-NUL byte.
453 * 'pnum' is set to the number of sectors (including and immediately following
454 * the first one) that are known to be in the same allocated/unallocated state.
456 static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
458 int v, i;
460 if (n <= 0) {
461 *pnum = 0;
462 return 0;
464 v = is_not_zero(buf, 512);
465 for(i = 1; i < n; i++) {
466 buf += 512;
467 if (v != is_not_zero(buf, 512))
468 break;
470 *pnum = i;
471 return v;
474 #define IO_BUF_SIZE 65536
476 static int img_convert(int argc, char **argv)
478 int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
479 const char *fmt, *out_fmt, *out_baseimg, *out_filename;
480 BlockDriver *drv;
481 BlockDriverState **bs, *out_bs;
482 int64_t total_sectors, nb_sectors, sector_num, bs_offset;
483 uint64_t bs_sectors;
484 uint8_t buf[IO_BUF_SIZE];
485 const uint8_t *buf1;
486 BlockDriverInfo bdi;
488 fmt = NULL;
489 out_fmt = "raw";
490 out_baseimg = NULL;
491 flags = 0;
492 for(;;) {
493 c = getopt(argc, argv, "f:O:B:hce6");
494 if (c == -1)
495 break;
496 switch(c) {
497 case 'h':
498 help();
499 break;
500 case 'f':
501 fmt = optarg;
502 break;
503 case 'O':
504 out_fmt = optarg;
505 break;
506 case 'B':
507 out_baseimg = optarg;
508 break;
509 case 'c':
510 flags |= BLOCK_FLAG_COMPRESS;
511 break;
512 case 'e':
513 flags |= BLOCK_FLAG_ENCRYPT;
514 break;
515 case '6':
516 flags |= BLOCK_FLAG_COMPAT6;
517 break;
521 bs_n = argc - optind - 1;
522 if (bs_n < 1) help();
524 out_filename = argv[argc - 1];
526 if (bs_n > 1 && out_baseimg)
527 error("-B makes no sense when concatenating multiple input images");
529 bs = calloc(bs_n, sizeof(BlockDriverState *));
530 if (!bs)
531 error("Out of memory");
533 total_sectors = 0;
534 for (bs_i = 0; bs_i < bs_n; bs_i++) {
535 bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
536 if (!bs[bs_i])
537 error("Could not open '%s'", argv[optind + bs_i]);
538 bdrv_get_geometry(bs[bs_i], &bs_sectors);
539 total_sectors += bs_sectors;
542 drv = bdrv_find_format(out_fmt);
543 if (!drv)
544 error("Unknown file format '%s'", out_fmt);
545 if (flags & BLOCK_FLAG_COMPRESS && strcmp(drv->format_name, "qcow") && strcmp(drv->format_name, "qcow2"))
546 error("Compression not supported for this file format");
547 if (flags & BLOCK_FLAG_ENCRYPT && strcmp(drv->format_name, "qcow") && strcmp(drv->format_name, "qcow2"))
548 error("Encryption not supported for this file format");
549 if (flags & BLOCK_FLAG_COMPAT6 && strcmp(drv->format_name, "vmdk"))
550 error("Alternative compatibility level not supported for this file format");
551 if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
552 error("Compression and encryption not supported at the same time");
554 ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
555 if (ret < 0) {
556 if (ret == -ENOTSUP) {
557 error("Formatting not supported for file format '%s'", out_fmt);
558 } else if (ret == -EFBIG) {
559 error("The image size is too large for file format '%s'", out_fmt);
560 } else {
561 error("Error while formatting '%s'", out_filename);
565 out_bs = bdrv_new_open(out_filename, out_fmt);
567 bs_i = 0;
568 bs_offset = 0;
569 bdrv_get_geometry(bs[0], &bs_sectors);
571 if (flags & BLOCK_FLAG_COMPRESS) {
572 if (bdrv_get_info(out_bs, &bdi) < 0)
573 error("could not get block driver info");
574 cluster_size = bdi.cluster_size;
575 if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
576 error("invalid cluster size");
577 cluster_sectors = cluster_size >> 9;
578 sector_num = 0;
579 for(;;) {
580 int64_t bs_num;
581 int remainder;
582 uint8_t *buf2;
584 nb_sectors = total_sectors - sector_num;
585 if (nb_sectors <= 0)
586 break;
587 if (nb_sectors >= cluster_sectors)
588 n = cluster_sectors;
589 else
590 n = nb_sectors;
592 bs_num = sector_num - bs_offset;
593 assert (bs_num >= 0);
594 remainder = n;
595 buf2 = buf;
596 while (remainder > 0) {
597 int nlow;
598 while (bs_num == bs_sectors) {
599 bs_i++;
600 assert (bs_i < bs_n);
601 bs_offset += bs_sectors;
602 bdrv_get_geometry(bs[bs_i], &bs_sectors);
603 bs_num = 0;
604 /* printf("changing part: sector_num=%lld, "
605 "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
606 sector_num, bs_i, bs_offset, bs_sectors); */
608 assert (bs_num < bs_sectors);
610 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
612 if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0)
613 error("error while reading");
615 buf2 += nlow * 512;
616 bs_num += nlow;
618 remainder -= nlow;
620 assert (remainder == 0);
622 if (n < cluster_sectors)
623 memset(buf + n * 512, 0, cluster_size - n * 512);
624 if (is_not_zero(buf, cluster_size)) {
625 if (bdrv_write_compressed(out_bs, sector_num, buf,
626 cluster_sectors) != 0)
627 error("error while compressing sector %" PRId64,
628 sector_num);
630 sector_num += n;
632 /* signal EOF to align */
633 bdrv_write_compressed(out_bs, 0, NULL, 0);
634 } else {
635 sector_num = 0; // total number of sectors converted so far
636 for(;;) {
637 nb_sectors = total_sectors - sector_num;
638 if (nb_sectors <= 0)
639 break;
640 if (nb_sectors >= (IO_BUF_SIZE / 512))
641 n = (IO_BUF_SIZE / 512);
642 else
643 n = nb_sectors;
645 while (sector_num - bs_offset >= bs_sectors) {
646 bs_i ++;
647 assert (bs_i < bs_n);
648 bs_offset += bs_sectors;
649 bdrv_get_geometry(bs[bs_i], &bs_sectors);
650 /* printf("changing part: sector_num=%lld, bs_i=%d, "
651 "bs_offset=%lld, bs_sectors=%lld\n",
652 sector_num, bs_i, bs_offset, bs_sectors); */
655 if (n > bs_offset + bs_sectors - sector_num)
656 n = bs_offset + bs_sectors - sector_num;
658 if (strcmp(drv->format_name, "host_device")) {
659 if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
660 n, &n1)) {
661 sector_num += n1;
662 continue;
664 /* The next 'n1' sectors are allocated in the input image. Copy
665 only those as they may be followed by unallocated sectors. */
666 n = n1;
667 } else {
668 n1 = n;
671 if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0)
672 error("error while reading");
673 /* NOTE: at the same time we convert, we do not write zero
674 sectors to have a chance to compress the image. Ideally, we
675 should add a specific call to have the info to go faster */
676 buf1 = buf;
677 while (n > 0) {
678 /* If the output image is being created as a copy on write image,
679 copy all sectors even the ones containing only NUL bytes,
680 because they may differ from the sectors in the base image.
682 If the output is to a host device, we also write out
683 sectors that are entirely 0, since whatever data was
684 already there is garbage, not 0s. */
685 if (strcmp(drv->format_name, "host_device") == 0 || out_baseimg ||
686 is_allocated_sectors(buf1, n, &n1)) {
687 if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
688 error("error while writing");
690 sector_num += n1;
691 n -= n1;
692 buf1 += n1 * 512;
696 bdrv_delete(out_bs);
697 for (bs_i = 0; bs_i < bs_n; bs_i++)
698 bdrv_delete(bs[bs_i]);
699 free(bs);
700 return 0;
703 #ifdef _WIN32
704 static int64_t get_allocated_file_size(const char *filename)
706 typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
707 get_compressed_t get_compressed;
708 struct _stati64 st;
710 /* WinNT support GetCompressedFileSize to determine allocate size */
711 get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
712 if (get_compressed) {
713 DWORD high, low;
714 low = get_compressed(filename, &high);
715 if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
716 return (((int64_t) high) << 32) + low;
719 if (_stati64(filename, &st) < 0)
720 return -1;
721 return st.st_size;
723 #else
724 static int64_t get_allocated_file_size(const char *filename)
726 struct stat st;
727 if (stat(filename, &st) < 0)
728 return -1;
729 return (int64_t)st.st_blocks * 512;
731 #endif
733 static void dump_snapshots(BlockDriverState *bs)
735 QEMUSnapshotInfo *sn_tab, *sn;
736 int nb_sns, i;
737 char buf[256];
739 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
740 if (nb_sns <= 0)
741 return;
742 printf("Snapshot list:\n");
743 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
744 for(i = 0; i < nb_sns; i++) {
745 sn = &sn_tab[i];
746 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
748 qemu_free(sn_tab);
751 static int img_info(int argc, char **argv)
753 int c;
754 const char *filename, *fmt;
755 BlockDriver *drv;
756 BlockDriverState *bs;
757 char fmt_name[128], size_buf[128], dsize_buf[128];
758 uint64_t total_sectors;
759 int64_t allocated_size;
760 char backing_filename[1024];
761 char backing_filename2[1024];
762 BlockDriverInfo bdi;
764 fmt = NULL;
765 for(;;) {
766 c = getopt(argc, argv, "f:h");
767 if (c == -1)
768 break;
769 switch(c) {
770 case 'h':
771 help();
772 break;
773 case 'f':
774 fmt = optarg;
775 break;
778 if (optind >= argc)
779 help();
780 filename = argv[optind++];
782 bs = bdrv_new("");
783 if (!bs)
784 error("Not enough memory");
785 if (fmt) {
786 drv = bdrv_find_format(fmt);
787 if (!drv)
788 error("Unknown file format '%s'", fmt);
789 } else {
790 drv = NULL;
792 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
793 error("Could not open '%s'", filename);
795 bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
796 bdrv_get_geometry(bs, &total_sectors);
797 get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
798 allocated_size = get_allocated_file_size(filename);
799 if (allocated_size < 0)
800 snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
801 else
802 get_human_readable_size(dsize_buf, sizeof(dsize_buf),
803 allocated_size);
804 printf("image: %s\n"
805 "file format: %s\n"
806 "virtual size: %s (%" PRId64 " bytes)\n"
807 "disk size: %s\n",
808 filename, fmt_name, size_buf,
809 (total_sectors * 512),
810 dsize_buf);
811 if (bdrv_is_encrypted(bs))
812 printf("encrypted: yes\n");
813 if (bdrv_get_info(bs, &bdi) >= 0) {
814 if (bdi.cluster_size != 0)
815 printf("cluster_size: %d\n", bdi.cluster_size);
817 bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
818 if (backing_filename[0] != '\0') {
819 path_combine(backing_filename2, sizeof(backing_filename2),
820 filename, backing_filename);
821 printf("backing file: %s (actual path: %s)\n",
822 backing_filename,
823 backing_filename2);
825 dump_snapshots(bs);
826 bdrv_delete(bs);
827 return 0;
830 #define SNAPSHOT_LIST 1
831 #define SNAPSHOT_CREATE 2
832 #define SNAPSHOT_APPLY 3
833 #define SNAPSHOT_DELETE 4
835 static void img_snapshot(int argc, char **argv)
837 BlockDriverState *bs;
838 QEMUSnapshotInfo sn;
839 char *filename, *snapshot_name = NULL;
840 int c, ret;
841 int action = 0;
842 qemu_timeval tv;
844 /* Parse commandline parameters */
845 for(;;) {
846 c = getopt(argc, argv, "la:c:d:h");
847 if (c == -1)
848 break;
849 switch(c) {
850 case 'h':
851 help();
852 return;
853 case 'l':
854 if (action) {
855 help();
856 return;
858 action = SNAPSHOT_LIST;
859 break;
860 case 'a':
861 if (action) {
862 help();
863 return;
865 action = SNAPSHOT_APPLY;
866 snapshot_name = optarg;
867 break;
868 case 'c':
869 if (action) {
870 help();
871 return;
873 action = SNAPSHOT_CREATE;
874 snapshot_name = optarg;
875 break;
876 case 'd':
877 if (action) {
878 help();
879 return;
881 action = SNAPSHOT_DELETE;
882 snapshot_name = optarg;
883 break;
887 if (optind >= argc)
888 help();
889 filename = argv[optind++];
891 /* Open the image */
892 bs = bdrv_new("");
893 if (!bs)
894 error("Not enough memory");
896 if (bdrv_open2(bs, filename, 0, NULL) < 0) {
897 error("Could not open '%s'", filename);
900 /* Perform the requested action */
901 switch(action) {
902 case SNAPSHOT_LIST:
903 dump_snapshots(bs);
904 break;
906 case SNAPSHOT_CREATE:
907 memset(&sn, 0, sizeof(sn));
908 pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
910 qemu_gettimeofday(&tv);
911 sn.date_sec = tv.tv_sec;
912 sn.date_nsec = tv.tv_usec * 1000;
914 ret = bdrv_snapshot_create(bs, &sn);
915 if (ret)
916 error("Could not create snapshot '%s': %d (%s)",
917 snapshot_name, ret, strerror(-ret));
918 break;
920 case SNAPSHOT_APPLY:
921 ret = bdrv_snapshot_goto(bs, snapshot_name);
922 if (ret)
923 error("Could not apply snapshot '%s': %d (%s)",
924 snapshot_name, ret, strerror(-ret));
925 break;
927 case SNAPSHOT_DELETE:
928 ret = bdrv_snapshot_delete(bs, snapshot_name);
929 if (ret)
930 error("Could not delete snapshot '%s': %d (%s)",
931 snapshot_name, ret, strerror(-ret));
932 break;
935 /* Cleanup */
936 bdrv_delete(bs);
939 int main(int argc, char **argv)
941 const char *cmd;
943 bdrv_init();
944 if (argc < 2)
945 help();
946 cmd = argv[1];
947 argc--; argv++;
948 if (!strcmp(cmd, "create")) {
949 img_create(argc, argv);
950 } else if (!strcmp(cmd, "check")) {
951 img_check(argc, argv);
952 } else if (!strcmp(cmd, "commit")) {
953 img_commit(argc, argv);
954 } else if (!strcmp(cmd, "convert")) {
955 img_convert(argc, argv);
956 } else if (!strcmp(cmd, "info")) {
957 img_info(argc, argv);
958 } else if (!strcmp(cmd, "snapshot")) {
959 img_snapshot(argc, argv);
960 } else {
961 help();
963 return 0;