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