Safety net for the cases where disassembler/translator disagree over instruction...
[qemu/mini2440.git] / qemu-img.c
blobccf4a6f9fddc0b012307911a900986cd47a34f33
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 <assert.h>
28 #include <stdio.h>
30 #ifdef _WIN32
31 #include <windows.h>
32 #endif
34 /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
35 #define BRDV_O_FLAGS BDRV_O_CACHE_WB
37 static void QEMU_NORETURN error(const char *fmt, ...)
39 va_list ap;
40 va_start(ap, fmt);
41 fprintf(stderr, "qemu-img: ");
42 vfprintf(stderr, fmt, ap);
43 fprintf(stderr, "\n");
44 exit(1);
45 va_end(ap);
48 static void format_print(void *opaque, const char *name)
50 printf(" %s", name);
53 /* Please keep in synch with qemu-img.texi */
54 static void help(void)
56 printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
57 "usage: qemu-img command [command options]\n"
58 "QEMU disk image utility\n"
59 "\n"
60 "Command syntax:\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_commit(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_commit(bs);
357 switch(ret) {
358 case 0:
359 printf("Image committed.\n");
360 break;
361 case -ENOENT:
362 error("No disk inserted");
363 break;
364 case -EACCES:
365 error("Image is read-only");
366 break;
367 case -ENOTSUP:
368 error("Image is already committed");
369 break;
370 default:
371 error("Error while committing image");
372 break;
375 bdrv_delete(bs);
376 return 0;
379 static int is_not_zero(const uint8_t *sector, int len)
381 int i;
382 len >>= 2;
383 for(i = 0;i < len; i++) {
384 if (((uint32_t *)sector)[i] != 0)
385 return 1;
387 return 0;
391 * Returns true iff the first sector pointed to by 'buf' contains at least
392 * a non-NUL byte.
394 * 'pnum' is set to the number of sectors (including and immediately following
395 * the first one) that are known to be in the same allocated/unallocated state.
397 static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
399 int v, i;
401 if (n <= 0) {
402 *pnum = 0;
403 return 0;
405 v = is_not_zero(buf, 512);
406 for(i = 1; i < n; i++) {
407 buf += 512;
408 if (v != is_not_zero(buf, 512))
409 break;
411 *pnum = i;
412 return v;
415 #define IO_BUF_SIZE 65536
417 static int img_convert(int argc, char **argv)
419 int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
420 const char *fmt, *out_fmt, *out_baseimg, *out_filename;
421 BlockDriver *drv;
422 BlockDriverState **bs, *out_bs;
423 int64_t total_sectors, nb_sectors, sector_num, bs_offset;
424 uint64_t bs_sectors;
425 uint8_t buf[IO_BUF_SIZE];
426 const uint8_t *buf1;
427 BlockDriverInfo bdi;
429 fmt = NULL;
430 out_fmt = "raw";
431 out_baseimg = NULL;
432 flags = 0;
433 for(;;) {
434 c = getopt(argc, argv, "f:O:B:hce6");
435 if (c == -1)
436 break;
437 switch(c) {
438 case 'h':
439 help();
440 break;
441 case 'f':
442 fmt = optarg;
443 break;
444 case 'O':
445 out_fmt = optarg;
446 break;
447 case 'B':
448 out_baseimg = optarg;
449 break;
450 case 'c':
451 flags |= BLOCK_FLAG_COMPRESS;
452 break;
453 case 'e':
454 flags |= BLOCK_FLAG_ENCRYPT;
455 break;
456 case '6':
457 flags |= BLOCK_FLAG_COMPAT6;
458 break;
462 bs_n = argc - optind - 1;
463 if (bs_n < 1) help();
465 out_filename = argv[argc - 1];
467 if (bs_n > 1 && out_baseimg)
468 error("-B makes no sense when concatenating multiple input images");
470 bs = calloc(bs_n, sizeof(BlockDriverState *));
471 if (!bs)
472 error("Out of memory");
474 total_sectors = 0;
475 for (bs_i = 0; bs_i < bs_n; bs_i++) {
476 bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
477 if (!bs[bs_i])
478 error("Could not open '%s'", argv[optind + bs_i]);
479 bdrv_get_geometry(bs[bs_i], &bs_sectors);
480 total_sectors += bs_sectors;
483 drv = bdrv_find_format(out_fmt);
484 if (!drv)
485 error("Unknown file format '%s'", out_fmt);
486 if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
487 error("Compression not supported for this file format");
488 if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
489 error("Encryption not supported for this file format");
490 if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk)
491 error("Alternative compatibility level not supported for this file format");
492 if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
493 error("Compression and encryption not supported at the same time");
495 ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
496 if (ret < 0) {
497 if (ret == -ENOTSUP) {
498 error("Formatting not supported for file format '%s'", out_fmt);
499 } else if (ret == -EFBIG) {
500 error("The image size is too large for file format '%s'", out_fmt);
501 } else {
502 error("Error while formatting '%s'", out_filename);
506 out_bs = bdrv_new_open(out_filename, out_fmt);
508 bs_i = 0;
509 bs_offset = 0;
510 bdrv_get_geometry(bs[0], &bs_sectors);
512 if (flags & BLOCK_FLAG_COMPRESS) {
513 if (bdrv_get_info(out_bs, &bdi) < 0)
514 error("could not get block driver info");
515 cluster_size = bdi.cluster_size;
516 if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
517 error("invalid cluster size");
518 cluster_sectors = cluster_size >> 9;
519 sector_num = 0;
520 for(;;) {
521 int64_t bs_num;
522 int remainder;
523 uint8_t *buf2;
525 nb_sectors = total_sectors - sector_num;
526 if (nb_sectors <= 0)
527 break;
528 if (nb_sectors >= cluster_sectors)
529 n = cluster_sectors;
530 else
531 n = nb_sectors;
533 bs_num = sector_num - bs_offset;
534 assert (bs_num >= 0);
535 remainder = n;
536 buf2 = buf;
537 while (remainder > 0) {
538 int nlow;
539 while (bs_num == bs_sectors) {
540 bs_i++;
541 assert (bs_i < bs_n);
542 bs_offset += bs_sectors;
543 bdrv_get_geometry(bs[bs_i], &bs_sectors);
544 bs_num = 0;
545 /* printf("changing part: sector_num=%lld, "
546 "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
547 sector_num, bs_i, bs_offset, bs_sectors); */
549 assert (bs_num < bs_sectors);
551 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
553 if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0)
554 error("error while reading");
556 buf2 += nlow * 512;
557 bs_num += nlow;
559 remainder -= nlow;
561 assert (remainder == 0);
563 if (n < cluster_sectors)
564 memset(buf + n * 512, 0, cluster_size - n * 512);
565 if (is_not_zero(buf, cluster_size)) {
566 if (bdrv_write_compressed(out_bs, sector_num, buf,
567 cluster_sectors) != 0)
568 error("error while compressing sector %" PRId64,
569 sector_num);
571 sector_num += n;
573 /* signal EOF to align */
574 bdrv_write_compressed(out_bs, 0, NULL, 0);
575 } else {
576 sector_num = 0; // total number of sectors converted so far
577 for(;;) {
578 nb_sectors = total_sectors - sector_num;
579 if (nb_sectors <= 0)
580 break;
581 if (nb_sectors >= (IO_BUF_SIZE / 512))
582 n = (IO_BUF_SIZE / 512);
583 else
584 n = nb_sectors;
586 while (sector_num - bs_offset >= bs_sectors) {
587 bs_i ++;
588 assert (bs_i < bs_n);
589 bs_offset += bs_sectors;
590 bdrv_get_geometry(bs[bs_i], &bs_sectors);
591 /* printf("changing part: sector_num=%lld, bs_i=%d, "
592 "bs_offset=%lld, bs_sectors=%lld\n",
593 sector_num, bs_i, bs_offset, bs_sectors); */
596 if (n > bs_offset + bs_sectors - sector_num)
597 n = bs_offset + bs_sectors - sector_num;
599 if (drv != &bdrv_host_device) {
600 if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
601 n, &n1)) {
602 sector_num += n1;
603 continue;
605 /* The next 'n1' sectors are allocated in the input image. Copy
606 only those as they may be followed by unallocated sectors. */
607 n = n1;
608 } else {
609 n1 = n;
612 if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0)
613 error("error while reading");
614 /* NOTE: at the same time we convert, we do not write zero
615 sectors to have a chance to compress the image. Ideally, we
616 should add a specific call to have the info to go faster */
617 buf1 = buf;
618 while (n > 0) {
619 /* If the output image is being created as a copy on write image,
620 copy all sectors even the ones containing only NUL bytes,
621 because they may differ from the sectors in the base image.
623 If the output is to a host device, we also write out
624 sectors that are entirely 0, since whatever data was
625 already there is garbage, not 0s. */
626 if (drv == &bdrv_host_device || out_baseimg ||
627 is_allocated_sectors(buf1, n, &n1)) {
628 if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
629 error("error while writing");
631 sector_num += n1;
632 n -= n1;
633 buf1 += n1 * 512;
637 bdrv_delete(out_bs);
638 for (bs_i = 0; bs_i < bs_n; bs_i++)
639 bdrv_delete(bs[bs_i]);
640 free(bs);
641 return 0;
644 #ifdef _WIN32
645 static int64_t get_allocated_file_size(const char *filename)
647 typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
648 get_compressed_t get_compressed;
649 struct _stati64 st;
651 /* WinNT support GetCompressedFileSize to determine allocate size */
652 get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
653 if (get_compressed) {
654 DWORD high, low;
655 low = get_compressed(filename, &high);
656 if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
657 return (((int64_t) high) << 32) + low;
660 if (_stati64(filename, &st) < 0)
661 return -1;
662 return st.st_size;
664 #else
665 static int64_t get_allocated_file_size(const char *filename)
667 struct stat st;
668 if (stat(filename, &st) < 0)
669 return -1;
670 return (int64_t)st.st_blocks * 512;
672 #endif
674 static void dump_snapshots(BlockDriverState *bs)
676 QEMUSnapshotInfo *sn_tab, *sn;
677 int nb_sns, i;
678 char buf[256];
680 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
681 if (nb_sns <= 0)
682 return;
683 printf("Snapshot list:\n");
684 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
685 for(i = 0; i < nb_sns; i++) {
686 sn = &sn_tab[i];
687 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
689 qemu_free(sn_tab);
692 static int img_info(int argc, char **argv)
694 int c;
695 const char *filename, *fmt;
696 BlockDriver *drv;
697 BlockDriverState *bs;
698 char fmt_name[128], size_buf[128], dsize_buf[128];
699 uint64_t total_sectors;
700 int64_t allocated_size;
701 char backing_filename[1024];
702 char backing_filename2[1024];
703 BlockDriverInfo bdi;
705 fmt = NULL;
706 for(;;) {
707 c = getopt(argc, argv, "f:h");
708 if (c == -1)
709 break;
710 switch(c) {
711 case 'h':
712 help();
713 break;
714 case 'f':
715 fmt = optarg;
716 break;
719 if (optind >= argc)
720 help();
721 filename = argv[optind++];
723 bs = bdrv_new("");
724 if (!bs)
725 error("Not enough memory");
726 if (fmt) {
727 drv = bdrv_find_format(fmt);
728 if (!drv)
729 error("Unknown file format '%s'", fmt);
730 } else {
731 drv = NULL;
733 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
734 error("Could not open '%s'", filename);
736 bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
737 bdrv_get_geometry(bs, &total_sectors);
738 get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
739 allocated_size = get_allocated_file_size(filename);
740 if (allocated_size < 0)
741 snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
742 else
743 get_human_readable_size(dsize_buf, sizeof(dsize_buf),
744 allocated_size);
745 printf("image: %s\n"
746 "file format: %s\n"
747 "virtual size: %s (%" PRId64 " bytes)\n"
748 "disk size: %s\n",
749 filename, fmt_name, size_buf,
750 (total_sectors * 512),
751 dsize_buf);
752 if (bdrv_is_encrypted(bs))
753 printf("encrypted: yes\n");
754 if (bdrv_get_info(bs, &bdi) >= 0) {
755 if (bdi.cluster_size != 0)
756 printf("cluster_size: %d\n", bdi.cluster_size);
758 bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
759 if (backing_filename[0] != '\0') {
760 path_combine(backing_filename2, sizeof(backing_filename2),
761 filename, backing_filename);
762 printf("backing file: %s (actual path: %s)\n",
763 backing_filename,
764 backing_filename2);
766 dump_snapshots(bs);
767 bdrv_delete(bs);
768 return 0;
771 #define SNAPSHOT_LIST 1
772 #define SNAPSHOT_CREATE 2
773 #define SNAPSHOT_APPLY 3
774 #define SNAPSHOT_DELETE 4
776 static void img_snapshot(int argc, char **argv)
778 BlockDriverState *bs;
779 QEMUSnapshotInfo sn;
780 char *filename, *snapshot_name = NULL;
781 int c, ret;
782 int action = 0;
783 qemu_timeval tv;
785 /* Parse commandline parameters */
786 for(;;) {
787 c = getopt(argc, argv, "la:c:d:h");
788 if (c == -1)
789 break;
790 switch(c) {
791 case 'h':
792 help();
793 return;
794 case 'l':
795 if (action) {
796 help();
797 return;
799 action = SNAPSHOT_LIST;
800 break;
801 case 'a':
802 if (action) {
803 help();
804 return;
806 action = SNAPSHOT_APPLY;
807 snapshot_name = optarg;
808 break;
809 case 'c':
810 if (action) {
811 help();
812 return;
814 action = SNAPSHOT_CREATE;
815 snapshot_name = optarg;
816 break;
817 case 'd':
818 if (action) {
819 help();
820 return;
822 action = SNAPSHOT_DELETE;
823 snapshot_name = optarg;
824 break;
828 if (optind >= argc)
829 help();
830 filename = argv[optind++];
832 /* Open the image */
833 bs = bdrv_new("");
834 if (!bs)
835 error("Not enough memory");
837 if (bdrv_open2(bs, filename, 0, NULL) < 0) {
838 error("Could not open '%s'", filename);
841 /* Perform the requested action */
842 switch(action) {
843 case SNAPSHOT_LIST:
844 dump_snapshots(bs);
845 break;
847 case SNAPSHOT_CREATE:
848 memset(&sn, 0, sizeof(sn));
849 pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
851 qemu_gettimeofday(&tv);
852 sn.date_sec = tv.tv_sec;
853 sn.date_nsec = tv.tv_usec * 1000;
855 ret = bdrv_snapshot_create(bs, &sn);
856 if (ret)
857 error("Could not create snapshot '%s': %d (%s)",
858 snapshot_name, ret, strerror(-ret));
859 break;
861 case SNAPSHOT_APPLY:
862 ret = bdrv_snapshot_goto(bs, snapshot_name);
863 if (ret)
864 error("Could not apply snapshot '%s': %d (%s)",
865 snapshot_name, ret, strerror(-ret));
866 break;
868 case SNAPSHOT_DELETE:
869 ret = bdrv_snapshot_delete(bs, snapshot_name);
870 if (ret)
871 error("Could not delete snapshot '%s': %d (%s)",
872 snapshot_name, ret, strerror(-ret));
873 break;
876 /* Cleanup */
877 bdrv_delete(bs);
880 int main(int argc, char **argv)
882 const char *cmd;
884 bdrv_init();
885 if (argc < 2)
886 help();
887 cmd = argv[1];
888 argc--; argv++;
889 if (!strcmp(cmd, "create")) {
890 img_create(argc, argv);
891 } else if (!strcmp(cmd, "commit")) {
892 img_commit(argc, argv);
893 } else if (!strcmp(cmd, "convert")) {
894 img_convert(argc, argv);
895 } else if (!strcmp(cmd, "info")) {
896 img_info(argc, argv);
897 } else if (!strcmp(cmd, "snapshot")) {
898 img_snapshot(argc, argv);
899 } else {
900 help();
902 return 0;