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