1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include "qemu-common.h"
25#include "qemu-option.h"
26#include "osdep.h"
27#include "block_int.h"
28#include <stdio.h>
29
30#ifdef _WIN32
31#include <windows.h>
32#endif
33
34typedef struct img_cmd_t {
35 const char *name;
36 int (*handler)(int argc, char **argv);
37} img_cmd_t;
38
39
40#define BRDV_O_FLAGS BDRV_O_CACHE_WB
41
42static void QEMU_NORETURN error(const char *fmt, ...)
43{
44 va_list ap;
45 va_start(ap, fmt);
46 fprintf(stderr, "qemu-img: ");
47 vfprintf(stderr, fmt, ap);
48 fprintf(stderr, "\n");
49 exit(1);
50 va_end(ap);
51}
52
53static void format_print(void *opaque, const char *name)
54{
55 printf(" %s", name);
56}
57
58
59static void help(void)
60{
61 printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
62 "usage: qemu-img command [command options]\n"
63 "QEMU disk image utility\n"
64 "\n"
65 "Command syntax:\n"
66#define DEF(option, callback, arg_string) \
67 " " arg_string "\n"
68#include "qemu-img-cmds.h"
69#undef DEF
70#undef GEN_DOCS
71 "\n"
72 "Command parameters:\n"
73 " 'filename' is a disk image filename\n"
74 " 'fmt' is the disk image format. It is guessed automatically in most cases\n"
75 " 'size' is the disk image size in bytes. Optional suffixes\n"
76 " 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
77 " and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
78 " 'output_filename' is the destination disk image filename\n"
79 " 'output_fmt' is the destination format\n"
80 " 'options' is a comma separated list of format specific options in a\n"
81 " name=value format. Use -o ? for an overview of the options supported by the\n"
82 " used format\n"
83 " '-c' indicates that target image must be compressed (qcow format only)\n"
84 " '-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"
92 );
93 printf("\nSupported formats:");
94 bdrv_iterate_format(format_print, NULL);
95 printf("\n");
96 exit(1);
97}
98
99#if defined(WIN32)
100
101static int read_password(char *buf, int buf_size)
102{
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;
113 }
114 buf[i] = '\0';
115 return 0;
116}
117
118#else
119
120#include <termios.h>
121
122static struct termios oldtty;
123
124static void term_exit(void)
125{
126 tcsetattr (0, TCSANOW, &oldtty);
127}
128
129static void term_init(void)
130{
131 struct termios tty;
132
133 tcgetattr (0, &tty);
134 oldtty = tty;
135
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;
144
145 tcsetattr (0, TCSANOW, &tty);
146
147 atexit(term_exit);
148}
149
150static int read_password(char *buf, int buf_size)
151{
152 uint8_t ch;
153 int i, ret;
154
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;
167 }
168 } else if (ret == 0) {
169 ret = -1;
170 break;
171 } else {
172 if (ch == '\r') {
173 ret = 0;
174 break;
175 }
176 if (i < (buf_size - 1))
177 buf[i++] = ch;
178 }
179 }
180 term_exit();
181 buf[i] = '\0';
182 printf("\n");
183 return ret;
184}
185#endif
186
187static BlockDriverState *bdrv_new_open(const char *filename,
188 const char *fmt)
189{
190 BlockDriverState *bs;
191 BlockDriver *drv;
192 char password[256];
193
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;
203 }
204 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
205 error("Could not open '%s'", filename);
206 }
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");
213 }
214 return bs;
215}
216
217static void add_old_style_options(const char *fmt, QEMUOptionParameter *list,
218 int flags, const char *base_filename, const char *base_fmt)
219{
220 if (flags & BLOCK_FLAG_ENCRYPT) {
221 if (set_option_parameter(list, BLOCK_OPT_ENCRYPT, "on")) {
222 error("Encryption not supported for file format '%s'", fmt);
223 }
224 }
225 if (flags & BLOCK_FLAG_COMPAT6) {
226 if (set_option_parameter(list, BLOCK_OPT_COMPAT6, "on")) {
227 error("VMDK version 6 not supported for file format '%s'", fmt);
228 }
229 }
230
231 if (base_filename) {
232 if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
233 error("Backing file not supported for file format '%s'", fmt);
234 }
235 }
236 if (base_fmt) {
237 if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
238 error("Backing file format not supported for file format '%s'", fmt);
239 }
240 }
241}
242
243static int img_create(int argc, char **argv)
244{
245 int c, ret, flags;
246 const char *fmt = "raw";
247 const char *base_fmt = NULL;
248 const char *filename;
249 const char *base_filename = NULL;
250 BlockDriver *drv;
251 QEMUOptionParameter *param = NULL;
252 char *options = NULL;
253
254 flags = 0;
255 for(;;) {
256 c = getopt(argc, argv, "F:b:f:he6o:");
257 if (c == -1)
258 break;
259 switch(c) {
260 case 'h':
261 help();
262 break;
263 case 'F':
264 base_fmt = optarg;
265 break;
266 case 'b':
267 base_filename = optarg;
268 break;
269 case 'f':
270 fmt = optarg;
271 break;
272 case 'e':
273 flags |= BLOCK_FLAG_ENCRYPT;
274 break;
275 case '6':
276 flags |= BLOCK_FLAG_COMPAT6;
277 break;
278 case 'o':
279 options = optarg;
280 break;
281 }
282 }
283
284
285 drv = bdrv_find_format(fmt);
286 if (!drv)
287 error("Unknown file format '%s'", fmt);
288
289 if (options && !strcmp(options, "?")) {
290 print_option_help(drv->create_options);
291 return 0;
292 }
293
294
295 param = parse_option_parameters("", drv->create_options, param);
296 set_option_parameter_int(param, BLOCK_OPT_SIZE, -1);
297
298
299 if (options) {
300 param = parse_option_parameters(options, drv->create_options, param);
301 if (param == NULL) {
302 error("Invalid options for file format '%s'.", fmt);
303 }
304 }
305
306
307 if (optind >= argc)
308 help();
309 filename = argv[optind++];
310
311
312 if (optind < argc) {
313 set_option_parameter(param, BLOCK_OPT_SIZE, argv[optind++]);
314 }
315
316
317 add_old_style_options(fmt, param, flags, base_filename, base_fmt);
318
319
320
321 if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
322
323 QEMUOptionParameter *backing_file =
324 get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
325 QEMUOptionParameter *backing_fmt =
326 get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
327
328 if (backing_file && backing_file->value.s) {
329 BlockDriverState *bs;
330 uint64_t size;
331 const char *fmt = NULL;
332 char buf[32];
333
334 if (backing_fmt && backing_fmt->value.s) {
335 if (bdrv_find_format(backing_fmt->value.s)) {
336 fmt = backing_fmt->value.s;
337 } else {
338 error("Unknown backing file format '%s'",
339 backing_fmt->value.s);
340 }
341 }
342
343 bs = bdrv_new_open(backing_file->value.s, fmt);
344 bdrv_get_geometry(bs, &size);
345 size *= 512;
346 bdrv_delete(bs);
347
348 snprintf(buf, sizeof(buf), "%" PRId64, size);
349 set_option_parameter(param, BLOCK_OPT_SIZE, buf);
350 } else {
351 error("Image creation needs a size parameter");
352 }
353 }
354
355 printf("Formatting '%s', fmt=%s ", filename, fmt);
356 print_option_parameters(param);
357 puts("");
358
359 ret = bdrv_create(drv, filename, param);
360 free_option_parameters(param);
361
362 if (ret < 0) {
363 if (ret == -ENOTSUP) {
364 error("Formatting or formatting option not supported for file format '%s'", fmt);
365 } else if (ret == -EFBIG) {
366 error("The image size is too large for file format '%s'", fmt);
367 } else {
368 error("Error while formatting");
369 }
370 }
371 return 0;
372}
373
374static int img_check(int argc, char **argv)
375{
376 int c, ret;
377 const char *filename, *fmt;
378 BlockDriver *drv;
379 BlockDriverState *bs;
380
381 fmt = NULL;
382 for(;;) {
383 c = getopt(argc, argv, "f:h");
384 if (c == -1)
385 break;
386 switch(c) {
387 case 'h':
388 help();
389 break;
390 case 'f':
391 fmt = optarg;
392 break;
393 }
394 }
395 if (optind >= argc)
396 help();
397 filename = argv[optind++];
398
399 bs = bdrv_new("");
400 if (!bs)
401 error("Not enough memory");
402 if (fmt) {
403 drv = bdrv_find_format(fmt);
404 if (!drv)
405 error("Unknown file format '%s'", fmt);
406 } else {
407 drv = NULL;
408 }
409 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
410 error("Could not open '%s'", filename);
411 }
412 ret = bdrv_check(bs);
413 switch(ret) {
414 case 0:
415 printf("No errors were found on the image.\n");
416 break;
417 case -ENOTSUP:
418 error("This image format does not support checks");
419 break;
420 default:
421 if (ret < 0) {
422 error("An error occurred during the check");
423 } else {
424 printf("%d errors were found on the image.\n", ret);
425 }
426 break;
427 }
428
429 bdrv_delete(bs);
430 return 0;
431}
432
433static int img_commit(int argc, char **argv)
434{
435 int c, ret;
436 const char *filename, *fmt;
437 BlockDriver *drv;
438 BlockDriverState *bs;
439
440 fmt = NULL;
441 for(;;) {
442 c = getopt(argc, argv, "f:h");
443 if (c == -1)
444 break;
445 switch(c) {
446 case 'h':
447 help();
448 break;
449 case 'f':
450 fmt = optarg;
451 break;
452 }
453 }
454 if (optind >= argc)
455 help();
456 filename = argv[optind++];
457
458 bs = bdrv_new("");
459 if (!bs)
460 error("Not enough memory");
461 if (fmt) {
462 drv = bdrv_find_format(fmt);
463 if (!drv)
464 error("Unknown file format '%s'", fmt);
465 } else {
466 drv = NULL;
467 }
468 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
469 error("Could not open '%s'", filename);
470 }
471 ret = bdrv_commit(bs);
472 switch(ret) {
473 case 0:
474 printf("Image committed.\n");
475 break;
476 case -ENOENT:
477 error("No disk inserted");
478 break;
479 case -EACCES:
480 error("Image is read-only");
481 break;
482 case -ENOTSUP:
483 error("Image is already committed");
484 break;
485 default:
486 error("Error while committing image");
487 break;
488 }
489
490 bdrv_delete(bs);
491 return 0;
492}
493
494static int is_not_zero(const uint8_t *sector, int len)
495{
496 int i;
497 len >>= 2;
498 for(i = 0;i < len; i++) {
499 if (((uint32_t *)sector)[i] != 0)
500 return 1;
501 }
502 return 0;
503}
504
505
506
507
508
509
510
511
512static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
513{
514 int v, i;
515
516 if (n <= 0) {
517 *pnum = 0;
518 return 0;
519 }
520 v = is_not_zero(buf, 512);
521 for(i = 1; i < n; i++) {
522 buf += 512;
523 if (v != is_not_zero(buf, 512))
524 break;
525 }
526 *pnum = i;
527 return v;
528}
529
530#define IO_BUF_SIZE (2 * 1024 * 1024)
531
532static int img_convert(int argc, char **argv)
533{
534 int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
535 const char *fmt, *out_fmt, *out_baseimg, *out_filename;
536 BlockDriver *drv;
537 BlockDriverState **bs, *out_bs;
538 int64_t total_sectors, nb_sectors, sector_num, bs_offset;
539 uint64_t bs_sectors;
540 uint8_t buf[IO_BUF_SIZE];
541 const uint8_t *buf1;
542 BlockDriverInfo bdi;
543 QEMUOptionParameter *param = NULL;
544 char *options = NULL;
545
546 fmt = NULL;
547 out_fmt = "raw";
548 out_baseimg = NULL;
549 flags = 0;
550 for(;;) {
551 c = getopt(argc, argv, "f:O:B:hce6o:");
552 if (c == -1)
553 break;
554 switch(c) {
555 case 'h':
556 help();
557 break;
558 case 'f':
559 fmt = optarg;
560 break;
561 case 'O':
562 out_fmt = optarg;
563 break;
564 case 'B':
565 out_baseimg = optarg;
566 break;
567 case 'c':
568 flags |= BLOCK_FLAG_COMPRESS;
569 break;
570 case 'e':
571 flags |= BLOCK_FLAG_ENCRYPT;
572 break;
573 case '6':
574 flags |= BLOCK_FLAG_COMPAT6;
575 break;
576 case 'o':
577 options = optarg;
578 break;
579 }
580 }
581
582 bs_n = argc - optind - 1;
583 if (bs_n < 1) help();
584
585 out_filename = argv[argc - 1];
586
587 if (bs_n > 1 && out_baseimg)
588 error("-B makes no sense when concatenating multiple input images");
589
590 bs = calloc(bs_n, sizeof(BlockDriverState *));
591 if (!bs)
592 error("Out of memory");
593
594 total_sectors = 0;
595 for (bs_i = 0; bs_i < bs_n; bs_i++) {
596 bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
597 if (!bs[bs_i])
598 error("Could not open '%s'", argv[optind + bs_i]);
599 bdrv_get_geometry(bs[bs_i], &bs_sectors);
600 total_sectors += bs_sectors;
601 }
602
603
604 drv = bdrv_find_format(out_fmt);
605 if (!drv)
606 error("Unknown file format '%s'", out_fmt);
607
608 if (options && !strcmp(options, "?")) {
609 print_option_help(drv->create_options);
610 free(bs);
611 return 0;
612 }
613
614 if (options) {
615 param = parse_option_parameters(options, drv->create_options, param);
616 if (param == NULL) {
617 error("Invalid options for file format '%s'.", out_fmt);
618 }
619 } else {
620 param = parse_option_parameters("", drv->create_options, param);
621 }
622
623 set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
624 add_old_style_options(out_fmt, param, flags, out_baseimg, NULL);
625
626
627 if (flags & BLOCK_FLAG_COMPRESS) {
628 QEMUOptionParameter *encryption =
629 get_option_parameter(param, BLOCK_OPT_ENCRYPT);
630
631 if (!drv->bdrv_write_compressed) {
632 error("Compression not supported for this file format");
633 }
634
635 if (encryption && encryption->value.n) {
636 error("Compression and encryption not supported at the same time");
637 }
638 }
639
640
641 ret = bdrv_create(drv, out_filename, param);
642 free_option_parameters(param);
643
644 if (ret < 0) {
645 if (ret == -ENOTSUP) {
646 error("Formatting not supported for file format '%s'", out_fmt);
647 } else if (ret == -EFBIG) {
648 error("The image size is too large for file format '%s'", out_fmt);
649 } else {
650 error("Error while formatting '%s'", out_filename);
651 }
652 }
653
654 out_bs = bdrv_new_open(out_filename, out_fmt);
655
656 bs_i = 0;
657 bs_offset = 0;
658 bdrv_get_geometry(bs[0], &bs_sectors);
659
660 if (flags & BLOCK_FLAG_COMPRESS) {
661 if (bdrv_get_info(out_bs, &bdi) < 0)
662 error("could not get block driver info");
663 cluster_size = bdi.cluster_size;
664 if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
665 error("invalid cluster size");
666 cluster_sectors = cluster_size >> 9;
667 sector_num = 0;
668 for(;;) {
669 int64_t bs_num;
670 int remainder;
671 uint8_t *buf2;
672
673 nb_sectors = total_sectors - sector_num;
674 if (nb_sectors <= 0)
675 break;
676 if (nb_sectors >= cluster_sectors)
677 n = cluster_sectors;
678 else
679 n = nb_sectors;
680
681 bs_num = sector_num - bs_offset;
682 assert (bs_num >= 0);
683 remainder = n;
684 buf2 = buf;
685 while (remainder > 0) {
686 int nlow;
687 while (bs_num == bs_sectors) {
688 bs_i++;
689 assert (bs_i < bs_n);
690 bs_offset += bs_sectors;
691 bdrv_get_geometry(bs[bs_i], &bs_sectors);
692 bs_num = 0;
693
694
695
696 }
697 assert (bs_num < bs_sectors);
698
699 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
700
701 if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0)
702 error("error while reading");
703
704 buf2 += nlow * 512;
705 bs_num += nlow;
706
707 remainder -= nlow;
708 }
709 assert (remainder == 0);
710
711 if (n < cluster_sectors)
712 memset(buf + n * 512, 0, cluster_size - n * 512);
713 if (is_not_zero(buf, cluster_size)) {
714 if (bdrv_write_compressed(out_bs, sector_num, buf,
715 cluster_sectors) != 0)
716 error("error while compressing sector %" PRId64,
717 sector_num);
718 }
719 sector_num += n;
720 }
721
722 bdrv_write_compressed(out_bs, 0, NULL, 0);
723 } else {
724 sector_num = 0;
725 for(;;) {
726 nb_sectors = total_sectors - sector_num;
727 if (nb_sectors <= 0)
728 break;
729 if (nb_sectors >= (IO_BUF_SIZE / 512))
730 n = (IO_BUF_SIZE / 512);
731 else
732 n = nb_sectors;
733
734 while (sector_num - bs_offset >= bs_sectors) {
735 bs_i ++;
736 assert (bs_i < bs_n);
737 bs_offset += bs_sectors;
738 bdrv_get_geometry(bs[bs_i], &bs_sectors);
739
740
741
742 }
743
744 if (n > bs_offset + bs_sectors - sector_num)
745 n = bs_offset + bs_sectors - sector_num;
746
747 if (!drv->no_zero_init) {
748
749
750
751
752 if (out_baseimg) {
753 if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
754 n, &n1)) {
755 sector_num += n1;
756 continue;
757 }
758
759
760 n = n1;
761 }
762 } else {
763 n1 = n;
764 }
765
766 if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0)
767 error("error while reading");
768
769
770
771 buf1 = buf;
772 while (n > 0) {
773
774
775
776
777
778
779
780 if (drv->no_zero_init || out_baseimg ||
781 is_allocated_sectors(buf1, n, &n1)) {
782 if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
783 error("error while writing");
784 }
785 sector_num += n1;
786 n -= n1;
787 buf1 += n1 * 512;
788 }
789 }
790 }
791 bdrv_delete(out_bs);
792 for (bs_i = 0; bs_i < bs_n; bs_i++)
793 bdrv_delete(bs[bs_i]);
794 free(bs);
795 return 0;
796}
797
798#ifdef _WIN32
799static int64_t get_allocated_file_size(const char *filename)
800{
801 typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
802 get_compressed_t get_compressed;
803 struct _stati64 st;
804
805
806 get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
807 if (get_compressed) {
808 DWORD high, low;
809 low = get_compressed(filename, &high);
810 if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
811 return (((int64_t) high) << 32) + low;
812 }
813
814 if (_stati64(filename, &st) < 0)
815 return -1;
816 return st.st_size;
817}
818#else
819static int64_t get_allocated_file_size(const char *filename)
820{
821 struct stat st;
822 if (stat(filename, &st) < 0)
823 return -1;
824 return (int64_t)st.st_blocks * 512;
825}
826#endif
827
828static void dump_snapshots(BlockDriverState *bs)
829{
830 QEMUSnapshotInfo *sn_tab, *sn;
831 int nb_sns, i;
832 char buf[256];
833
834 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
835 if (nb_sns <= 0)
836 return;
837 printf("Snapshot list:\n");
838 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
839 for(i = 0; i < nb_sns; i++) {
840 sn = &sn_tab[i];
841 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
842 }
843 qemu_free(sn_tab);
844}
845
846static int img_info(int argc, char **argv)
847{
848 int c;
849 const char *filename, *fmt;
850 BlockDriver *drv;
851 BlockDriverState *bs;
852 char fmt_name[128], size_buf[128], dsize_buf[128];
853 uint64_t total_sectors;
854 int64_t allocated_size;
855 char backing_filename[1024];
856 char backing_filename2[1024];
857 BlockDriverInfo bdi;
858
859 fmt = NULL;
860 for(;;) {
861 c = getopt(argc, argv, "f:h");
862 if (c == -1)
863 break;
864 switch(c) {
865 case 'h':
866 help();
867 break;
868 case 'f':
869 fmt = optarg;
870 break;
871 }
872 }
873 if (optind >= argc)
874 help();
875 filename = argv[optind++];
876
877 bs = bdrv_new("");
878 if (!bs)
879 error("Not enough memory");
880 if (fmt) {
881 drv = bdrv_find_format(fmt);
882 if (!drv)
883 error("Unknown file format '%s'", fmt);
884 } else {
885 drv = NULL;
886 }
887 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
888 error("Could not open '%s'", filename);
889 }
890 bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
891 bdrv_get_geometry(bs, &total_sectors);
892 get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
893 allocated_size = get_allocated_file_size(filename);
894 if (allocated_size < 0)
895 snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
896 else
897 get_human_readable_size(dsize_buf, sizeof(dsize_buf),
898 allocated_size);
899 printf("image: %s\n"
900 "file format: %s\n"
901 "virtual size: %s (%" PRId64 " bytes)\n"
902 "disk size: %s\n",
903 filename, fmt_name, size_buf,
904 (total_sectors * 512),
905 dsize_buf);
906 if (bdrv_is_encrypted(bs))
907 printf("encrypted: yes\n");
908 if (bdrv_get_info(bs, &bdi) >= 0) {
909 if (bdi.cluster_size != 0)
910 printf("cluster_size: %d\n", bdi.cluster_size);
911 }
912 bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
913 if (backing_filename[0] != '\0') {
914 path_combine(backing_filename2, sizeof(backing_filename2),
915 filename, backing_filename);
916 printf("backing file: %s (actual path: %s)\n",
917 backing_filename,
918 backing_filename2);
919 }
920 dump_snapshots(bs);
921 bdrv_delete(bs);
922 return 0;
923}
924
925#define SNAPSHOT_LIST 1
926#define SNAPSHOT_CREATE 2
927#define SNAPSHOT_APPLY 3
928#define SNAPSHOT_DELETE 4
929
930static int img_snapshot(int argc, char **argv)
931{
932 BlockDriverState *bs;
933 QEMUSnapshotInfo sn;
934 char *filename, *snapshot_name = NULL;
935 int c, ret;
936 int action = 0;
937 qemu_timeval tv;
938
939
940 for(;;) {
941 c = getopt(argc, argv, "la:c:d:h");
942 if (c == -1)
943 break;
944 switch(c) {
945 case 'h':
946 help();
947 return 0;
948 case 'l':
949 if (action) {
950 help();
951 return 0;
952 }
953 action = SNAPSHOT_LIST;
954 break;
955 case 'a':
956 if (action) {
957 help();
958 return 0;
959 }
960 action = SNAPSHOT_APPLY;
961 snapshot_name = optarg;
962 break;
963 case 'c':
964 if (action) {
965 help();
966 return 0;
967 }
968 action = SNAPSHOT_CREATE;
969 snapshot_name = optarg;
970 break;
971 case 'd':
972 if (action) {
973 help();
974 return 0;
975 }
976 action = SNAPSHOT_DELETE;
977 snapshot_name = optarg;
978 break;
979 }
980 }
981
982 if (optind >= argc)
983 help();
984 filename = argv[optind++];
985
986
987 bs = bdrv_new("");
988 if (!bs)
989 error("Not enough memory");
990
991 if (bdrv_open2(bs, filename, 0, NULL) < 0) {
992 error("Could not open '%s'", filename);
993 }
994
995
996 switch(action) {
997 case SNAPSHOT_LIST:
998 dump_snapshots(bs);
999 break;
1000
1001 case SNAPSHOT_CREATE:
1002 memset(&sn, 0, sizeof(sn));
1003 pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
1004
1005 qemu_gettimeofday(&tv);
1006 sn.date_sec = tv.tv_sec;
1007 sn.date_nsec = tv.tv_usec * 1000;
1008
1009 ret = bdrv_snapshot_create(bs, &sn);
1010 if (ret)
1011 error("Could not create snapshot '%s': %d (%s)",
1012 snapshot_name, ret, strerror(-ret));
1013 break;
1014
1015 case SNAPSHOT_APPLY:
1016 ret = bdrv_snapshot_goto(bs, snapshot_name);
1017 if (ret)
1018 error("Could not apply snapshot '%s': %d (%s)",
1019 snapshot_name, ret, strerror(-ret));
1020 break;
1021
1022 case SNAPSHOT_DELETE:
1023 ret = bdrv_snapshot_delete(bs, snapshot_name);
1024 if (ret)
1025 error("Could not delete snapshot '%s': %d (%s)",
1026 snapshot_name, ret, strerror(-ret));
1027 break;
1028 }
1029
1030
1031 bdrv_delete(bs);
1032
1033 return 0;
1034}
1035
1036static const img_cmd_t img_cmds[] = {
1037#define DEF(option, callback, arg_string) \
1038 { option, callback },
1039#include "qemu-img-cmds.h"
1040#undef DEF
1041#undef GEN_DOCS
1042 { NULL, NULL, },
1043};
1044
1045int main(int argc, char **argv)
1046{
1047 const img_cmd_t *cmd;
1048 const char *cmdname;
1049
1050 bdrv_init();
1051 if (argc < 2)
1052 help();
1053 cmdname = argv[1];
1054 argc--; argv++;
1055
1056
1057 for(cmd = img_cmds; cmd->name != NULL; cmd++) {
1058 if (!strcmp(cmdname, cmd->name)) {
1059 return cmd->handler(argc, argv);
1060 }
1061 }
1062
1063
1064 help();
1065 return 0;
1066}
1067