Fix windows build and clean up use of <windows.h>
[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"
77            "    supported any @code{k} or @code{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     const char *p;
224     BlockDriver *drv;
225
226     flags = 0;
227     for(;;) {
228         c = getopt(argc, argv, "b:f:he6");
229         if (c == -1)
230             break;
231         switch(c) {
232         case 'h':
233             help();
234             break;
235         case 'b':
236             base_filename = optarg;
237             break;
238         case 'f':
239             fmt = optarg;
240             break;
241         case 'e':
242             flags |= BLOCK_FLAG_ENCRYPT;
243             break;
244         case '6':
245             flags |= BLOCK_FLAG_COMPAT6;
246             break;
247         }
248     }
249     if (optind >= argc)
250         help();
251     filename = argv[optind++];
252     size = 0;
253     if (base_filename) {
254         BlockDriverState *bs;
255         bs = bdrv_new_open(base_filename, NULL);
256         bdrv_get_geometry(bs, &size);
257         size *= 512;
258         bdrv_delete(bs);
259     } else {
260         if (optind >= argc)
261             help();
262         p = argv[optind];
263         size = strtoul(p, (char **)&p, 0);
264         if (*p == 'M') {
265             size *= 1024 * 1024;
266         } else if (*p == 'G') {
267             size *= 1024 * 1024 * 1024;
268         } else if (*p == 'k' || *p == 'K' || *p == '\0') {
269             size *= 1024;
270         } else {
271             help();
272         }
273     }
274     drv = bdrv_find_format(fmt);
275     if (!drv)
276         error("Unknown file format '%s'", fmt);
277     printf("Formatting '%s', fmt=%s",
278            filename, fmt);
279     if (flags & BLOCK_FLAG_ENCRYPT)
280         printf(", encrypted");
281     if (flags & BLOCK_FLAG_COMPAT6)
282         printf(", compatibility level=6");
283     if (base_filename) {
284         printf(", backing_file=%s",
285                base_filename);
286     }
287     printf(", size=%" PRIu64 " kB\n", size / 1024);
288     ret = bdrv_create(drv, filename, size / 512, base_filename, flags);
289     if (ret < 0) {
290         if (ret == -ENOTSUP) {
291             error("Formatting or formatting option not supported for file format '%s'", fmt);
292         } else {
293             error("Error while formatting");
294         }
295     }
296     return 0;
297 }
298
299 static int img_commit(int argc, char **argv)
300 {
301     int c, ret;
302     const char *filename, *fmt;
303     BlockDriver *drv;
304     BlockDriverState *bs;
305
306     fmt = NULL;
307     for(;;) {
308         c = getopt(argc, argv, "f:h");
309         if (c == -1)
310             break;
311         switch(c) {
312         case 'h':
313             help();
314             break;
315         case 'f':
316             fmt = optarg;
317             break;
318         }
319     }
320     if (optind >= argc)
321         help();
322     filename = argv[optind++];
323
324     bs = bdrv_new("");
325     if (!bs)
326         error("Not enough memory");
327     if (fmt) {
328         drv = bdrv_find_format(fmt);
329         if (!drv)
330             error("Unknown file format '%s'", fmt);
331     } else {
332         drv = NULL;
333     }
334     if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
335         error("Could not open '%s'", filename);
336     }
337     ret = bdrv_commit(bs);
338     switch(ret) {
339     case 0:
340         printf("Image committed.\n");
341         break;
342     case -ENOENT:
343         error("No disk inserted");
344         break;
345     case -EACCES:
346         error("Image is read-only");
347         break;
348     case -ENOTSUP:
349         error("Image is already committed");
350         break;
351     default:
352         error("Error while committing image");
353         break;
354     }
355
356     bdrv_delete(bs);
357     return 0;
358 }
359
360 static int is_not_zero(const uint8_t *sector, int len)
361 {
362     int i;
363     len >>= 2;
364     for(i = 0;i < len; i++) {
365         if (((uint32_t *)sector)[i] != 0)
366             return 1;
367     }
368     return 0;
369 }
370
371 /*
372  * Returns true iff the first sector pointed to by 'buf' contains at least
373  * a non-NUL byte.
374  *
375  * 'pnum' is set to the number of sectors (including and immediately following
376  * the first one) that are known to be in the same allocated/unallocated state.
377  */
378 static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
379 {
380     int v, i;
381
382     if (n <= 0) {
383         *pnum = 0;
384         return 0;
385     }
386     v = is_not_zero(buf, 512);
387     for(i = 1; i < n; i++) {
388         buf += 512;
389         if (v != is_not_zero(buf, 512))
390             break;
391     }
392     *pnum = i;
393     return v;
394 }
395
396 #define IO_BUF_SIZE 65536
397
398 static int img_convert(int argc, char **argv)
399 {
400     int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
401     const char *fmt, *out_fmt, *out_baseimg, *out_filename;
402     BlockDriver *drv;
403     BlockDriverState **bs, *out_bs;
404     int64_t total_sectors, nb_sectors, sector_num, bs_offset;
405     uint64_t bs_sectors;
406     uint8_t buf[IO_BUF_SIZE];
407     const uint8_t *buf1;
408     BlockDriverInfo bdi;
409
410     fmt = NULL;
411     out_fmt = "raw";
412     out_baseimg = NULL;
413     flags = 0;
414     for(;;) {
415         c = getopt(argc, argv, "f:O:B:hce6");
416         if (c == -1)
417             break;
418         switch(c) {
419         case 'h':
420             help();
421             break;
422         case 'f':
423             fmt = optarg;
424             break;
425         case 'O':
426             out_fmt = optarg;
427             break;
428         case 'B':
429             out_baseimg = optarg;
430             break;
431         case 'c':
432             flags |= BLOCK_FLAG_COMPRESS;
433             break;
434         case 'e':
435             flags |= BLOCK_FLAG_ENCRYPT;
436             break;
437         case '6':
438             flags |= BLOCK_FLAG_COMPAT6;
439             break;
440         }
441     }
442
443     bs_n = argc - optind - 1;
444     if (bs_n < 1) help();
445
446     out_filename = argv[argc - 1];
447
448     if (bs_n > 1 && out_baseimg)
449         error("-B makes no sense when concatenating multiple input images");
450         
451     bs = calloc(bs_n, sizeof(BlockDriverState *));
452     if (!bs)
453         error("Out of memory");
454
455     total_sectors = 0;
456     for (bs_i = 0; bs_i < bs_n; bs_i++) {
457         bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
458         if (!bs[bs_i])
459             error("Could not open '%s'", argv[optind + bs_i]);
460         bdrv_get_geometry(bs[bs_i], &bs_sectors);
461         total_sectors += bs_sectors;
462     }
463
464     drv = bdrv_find_format(out_fmt);
465     if (!drv)
466         error("Unknown file format '%s'", out_fmt);
467     if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
468         error("Compression not supported for this file format");
469     if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
470         error("Encryption not supported for this file format");
471     if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk)
472         error("Alternative compatibility level not supported for this file format");
473     if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
474         error("Compression and encryption not supported at the same time");
475
476     ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
477     if (ret < 0) {
478         if (ret == -ENOTSUP) {
479             error("Formatting not supported for file format '%s'", fmt);
480         } else {
481             error("Error while formatting '%s'", out_filename);
482         }
483     }
484
485     out_bs = bdrv_new_open(out_filename, out_fmt);
486
487     bs_i = 0;
488     bs_offset = 0;
489     bdrv_get_geometry(bs[0], &bs_sectors);
490
491     if (flags & BLOCK_FLAG_COMPRESS) {
492         if (bdrv_get_info(out_bs, &bdi) < 0)
493             error("could not get block driver info");
494         cluster_size = bdi.cluster_size;
495         if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
496             error("invalid cluster size");
497         cluster_sectors = cluster_size >> 9;
498         sector_num = 0;
499         for(;;) {
500             int64_t bs_num;
501             int remainder;
502             uint8_t *buf2;
503
504             nb_sectors = total_sectors - sector_num;
505             if (nb_sectors <= 0)
506                 break;
507             if (nb_sectors >= cluster_sectors)
508                 n = cluster_sectors;
509             else
510                 n = nb_sectors;
511
512             bs_num = sector_num - bs_offset;
513             assert (bs_num >= 0);
514             remainder = n;
515             buf2 = buf;
516             while (remainder > 0) {
517                 int nlow;
518                 while (bs_num == bs_sectors) {
519                     bs_i++;
520                     assert (bs_i < bs_n);
521                     bs_offset += bs_sectors;
522                     bdrv_get_geometry(bs[bs_i], &bs_sectors);
523                     bs_num = 0;
524                     /* printf("changing part: sector_num=%lld, "
525                        "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
526                        sector_num, bs_i, bs_offset, bs_sectors); */
527                 }
528                 assert (bs_num < bs_sectors);
529
530                 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
531
532                 if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) 
533                     error("error while reading");
534
535                 buf2 += nlow * 512;
536                 bs_num += nlow;
537
538                 remainder -= nlow;
539             }
540             assert (remainder == 0);
541
542             if (n < cluster_sectors)
543                 memset(buf + n * 512, 0, cluster_size - n * 512);
544             if (is_not_zero(buf, cluster_size)) {
545                 if (bdrv_write_compressed(out_bs, sector_num, buf,
546                                           cluster_sectors) != 0)
547                     error("error while compressing sector %" PRId64,
548                           sector_num);
549             }
550             sector_num += n;
551         }
552         /* signal EOF to align */
553         bdrv_write_compressed(out_bs, 0, NULL, 0);
554     } else {
555         sector_num = 0; // total number of sectors converted so far
556         for(;;) {
557             nb_sectors = total_sectors - sector_num;
558             if (nb_sectors <= 0)
559                 break;
560             if (nb_sectors >= (IO_BUF_SIZE / 512))
561                 n = (IO_BUF_SIZE / 512);
562             else
563                 n = nb_sectors;
564
565             while (sector_num - bs_offset >= bs_sectors) {
566                 bs_i ++;
567                 assert (bs_i < bs_n);
568                 bs_offset += bs_sectors;
569                 bdrv_get_geometry(bs[bs_i], &bs_sectors);
570                 /* printf("changing part: sector_num=%lld, bs_i=%d, "
571                   "bs_offset=%lld, bs_sectors=%lld\n",
572                    sector_num, bs_i, bs_offset, bs_sectors); */
573             }
574
575             if (n > bs_offset + bs_sectors - sector_num)
576                 n = bs_offset + bs_sectors - sector_num;
577
578             /* If the output image is being created as a copy on write image,
579                assume that sectors which are unallocated in the input image
580                are present in both the output's and input's base images (no
581                need to copy them). */
582             if (out_baseimg) {
583                if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) {
584                   sector_num += n1;
585                   continue;
586                }
587                /* The next 'n1' sectors are allocated in the input image. Copy
588                   only those as they may be followed by unallocated sectors. */
589                n = n1;
590             }
591
592             if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) 
593                 error("error while reading");
594             /* NOTE: at the same time we convert, we do not write zero
595                sectors to have a chance to compress the image. Ideally, we
596                should add a specific call to have the info to go faster */
597             buf1 = buf;
598             while (n > 0) {
599                 /* If the output image is being created as a copy on write image,
600                    copy all sectors even the ones containing only NUL bytes,
601                    because they may differ from the sectors in the base image. */
602                 if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) {
603                     if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
604                         error("error while writing");
605                 }
606                 sector_num += n1;
607                 n -= n1;
608                 buf1 += n1 * 512;
609             }
610         }
611     }
612     bdrv_delete(out_bs);
613     for (bs_i = 0; bs_i < bs_n; bs_i++)
614         bdrv_delete(bs[bs_i]);
615     free(bs);
616     return 0;
617 }
618
619 #ifdef _WIN32
620 static int64_t get_allocated_file_size(const char *filename)
621 {
622     typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
623     get_compressed_t get_compressed;
624     struct _stati64 st;
625
626     /* WinNT support GetCompressedFileSize to determine allocate size */
627     get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
628     if (get_compressed) {
629         DWORD high, low;
630         low = get_compressed(filename, &high);
631         if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
632             return (((int64_t) high) << 32) + low;
633     }
634
635     if (_stati64(filename, &st) < 0)
636         return -1;
637     return st.st_size;
638 }
639 #else
640 static int64_t get_allocated_file_size(const char *filename)
641 {
642     struct stat st;
643     if (stat(filename, &st) < 0)
644         return -1;
645     return (int64_t)st.st_blocks * 512;
646 }
647 #endif
648
649 static void dump_snapshots(BlockDriverState *bs)
650 {
651     QEMUSnapshotInfo *sn_tab, *sn;
652     int nb_sns, i;
653     char buf[256];
654
655     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
656     if (nb_sns <= 0)
657         return;
658     printf("Snapshot list:\n");
659     printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
660     for(i = 0; i < nb_sns; i++) {
661         sn = &sn_tab[i];
662         printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
663     }
664     qemu_free(sn_tab);
665 }
666
667 static int img_info(int argc, char **argv)
668 {
669     int c;
670     const char *filename, *fmt;
671     BlockDriver *drv;
672     BlockDriverState *bs;
673     char fmt_name[128], size_buf[128], dsize_buf[128];
674     uint64_t total_sectors;
675     int64_t allocated_size;
676     char backing_filename[1024];
677     char backing_filename2[1024];
678     BlockDriverInfo bdi;
679
680     fmt = NULL;
681     for(;;) {
682         c = getopt(argc, argv, "f:h");
683         if (c == -1)
684             break;
685         switch(c) {
686         case 'h':
687             help();
688             break;
689         case 'f':
690             fmt = optarg;
691             break;
692         }
693     }
694     if (optind >= argc)
695         help();
696     filename = argv[optind++];
697
698     bs = bdrv_new("");
699     if (!bs)
700         error("Not enough memory");
701     if (fmt) {
702         drv = bdrv_find_format(fmt);
703         if (!drv)
704             error("Unknown file format '%s'", fmt);
705     } else {
706         drv = NULL;
707     }
708     if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
709         error("Could not open '%s'", filename);
710     }
711     bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
712     bdrv_get_geometry(bs, &total_sectors);
713     get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
714     allocated_size = get_allocated_file_size(filename);
715     if (allocated_size < 0)
716         snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
717     else
718         get_human_readable_size(dsize_buf, sizeof(dsize_buf),
719                                 allocated_size);
720     printf("image: %s\n"
721            "file format: %s\n"
722            "virtual size: %s (%" PRId64 " bytes)\n"
723            "disk size: %s\n",
724            filename, fmt_name, size_buf,
725            (total_sectors * 512),
726            dsize_buf);
727     if (bdrv_is_encrypted(bs))
728         printf("encrypted: yes\n");
729     if (bdrv_get_info(bs, &bdi) >= 0) {
730         if (bdi.cluster_size != 0)
731             printf("cluster_size: %d\n", bdi.cluster_size);
732         if (bdi.highest_alloc)
733             printf("highest_alloc: %" PRId64 "\n", bdi.highest_alloc);
734         if (bdi.num_free_bytes)
735             printf("num_free_bytes: %" PRId64 "\n", bdi.num_free_bytes);
736     }
737     bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
738     if (backing_filename[0] != '\0') {
739         path_combine(backing_filename2, sizeof(backing_filename2),
740                      filename, backing_filename);
741         printf("backing file: %s (actual path: %s)\n",
742                backing_filename,
743                backing_filename2);
744     }
745     dump_snapshots(bs);
746     bdrv_delete(bs);
747     return 0;
748 }
749
750 #define SNAPSHOT_LIST   1
751 #define SNAPSHOT_CREATE 2
752 #define SNAPSHOT_APPLY  3
753 #define SNAPSHOT_DELETE 4
754
755 static void img_snapshot(int argc, char **argv)
756 {
757     BlockDriverState *bs;
758     QEMUSnapshotInfo sn;
759     char *filename, *snapshot_name = NULL;
760     int c, ret;
761     int action = 0;
762     qemu_timeval tv;
763
764     /* Parse commandline parameters */
765     for(;;) {
766         c = getopt(argc, argv, "la:c:d:h");
767         if (c == -1)
768             break;
769         switch(c) {
770         case 'h':
771             help();
772             return;
773         case 'l':
774             if (action) {
775                 help();
776                 return;
777             }
778             action = SNAPSHOT_LIST;
779             break;
780         case 'a':
781             if (action) {
782                 help();
783                 return;
784             }
785             action = SNAPSHOT_APPLY;
786             snapshot_name = optarg;
787             break;
788         case 'c':
789             if (action) {
790                 help();
791                 return;
792             }
793             action = SNAPSHOT_CREATE;
794             snapshot_name = optarg;
795             break;
796         case 'd':
797             if (action) {
798                 help();
799                 return;
800             }
801             action = SNAPSHOT_DELETE;
802             snapshot_name = optarg;
803             break;
804         }
805     }
806
807     if (optind >= argc)
808         help();
809     filename = argv[optind++];
810
811     /* Open the image */
812     bs = bdrv_new("");
813     if (!bs)
814         error("Not enough memory");
815
816     if (bdrv_open2(bs, filename, 0, NULL) < 0) {
817         error("Could not open '%s'", filename);
818     }
819
820     /* Perform the requested action */
821     switch(action) {
822     case SNAPSHOT_LIST:
823         dump_snapshots(bs);
824         break;
825
826     case SNAPSHOT_CREATE:
827         memset(&sn, 0, sizeof(sn));
828         pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
829
830         qemu_gettimeofday(&tv);
831         sn.date_sec = tv.tv_sec;
832         sn.date_nsec = tv.tv_usec * 1000;
833
834         ret = bdrv_snapshot_create(bs, &sn);
835         if (ret)
836             error("Could not create snapshot '%s': %d (%s)",
837                 snapshot_name, ret, strerror(-ret));
838         break;
839
840     case SNAPSHOT_APPLY:
841         ret = bdrv_snapshot_goto(bs, snapshot_name);
842         if (ret)
843             error("Could not apply snapshot '%s': %d (%s)",
844                 snapshot_name, ret, strerror(-ret));
845         break;
846
847     case SNAPSHOT_DELETE:
848         ret = bdrv_snapshot_delete(bs, snapshot_name);
849         if (ret)
850             error("Could not delete snapshot '%s': %d (%s)",
851                 snapshot_name, ret, strerror(-ret));
852         break;
853     }
854
855     /* Cleanup */
856     bdrv_delete(bs);
857 }
858
859 int main(int argc, char **argv)
860 {
861     const char *cmd;
862
863     bdrv_init();
864     if (argc < 2)
865         help();
866     cmd = argv[1];
867     argc--; argv++;
868     if (!strcmp(cmd, "create")) {
869         img_create(argc, argv);
870     } else if (!strcmp(cmd, "commit")) {
871         img_commit(argc, argv);
872     } else if (!strcmp(cmd, "convert")) {
873         img_convert(argc, argv);
874     } else if (!strcmp(cmd, "info")) {
875         img_info(argc, argv);
876     } else if (!strcmp(cmd, "snapshot")) {
877         img_snapshot(argc, argv);
878     } else {
879         help();
880     }
881     return 0;
882 }