964b28bcd42e9ba2113481e8044764ffdede3ad0
[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 __attribute__((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     }
731     bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
732     if (backing_filename[0] != '\0') {
733         path_combine(backing_filename2, sizeof(backing_filename2),
734                      filename, backing_filename);
735         printf("backing file: %s (actual path: %s)\n",
736                backing_filename,
737                backing_filename2);
738     }
739     dump_snapshots(bs);
740     bdrv_delete(bs);
741     return 0;
742 }
743
744 #define SNAPSHOT_LIST   1
745 #define SNAPSHOT_CREATE 2
746 #define SNAPSHOT_APPLY  3
747 #define SNAPSHOT_DELETE 4
748
749 static void img_snapshot(int argc, char **argv)
750 {
751     BlockDriverState *bs;
752     QEMUSnapshotInfo sn;
753     char *filename, *snapshot_name = NULL;
754     char c;
755     int ret;
756     int action = 0;
757     qemu_timeval tv;
758
759     /* Parse commandline parameters */
760     for(;;) {
761         c = getopt(argc, argv, "la:c:d:h");
762         if (c == -1)
763             break;
764         switch(c) {
765         case 'h':
766             help();
767             return;
768         case 'l':
769             if (action) {
770                 help();
771                 return;
772             }
773             action = SNAPSHOT_LIST;
774             break;
775         case 'a':
776             if (action) {
777                 help();
778                 return;
779             }
780             action = SNAPSHOT_APPLY;
781             snapshot_name = optarg;
782             break;
783         case 'c':
784             if (action) {
785                 help();
786                 return;
787             }
788             action = SNAPSHOT_CREATE;
789             snapshot_name = optarg;
790             break;
791         case 'd':
792             if (action) {
793                 help();
794                 return;
795             }
796             action = SNAPSHOT_DELETE;
797             snapshot_name = optarg;
798             break;
799         }
800     }
801
802     if (optind >= argc)
803         help();
804     filename = argv[optind++];
805
806     /* Open the image */
807     bs = bdrv_new("");
808     if (!bs)
809         error("Not enough memory");
810
811     if (bdrv_open2(bs, filename, 0, NULL) < 0) {
812         error("Could not open '%s'", filename);
813     }
814
815     /* Perform the requested action */
816     switch(action) {
817     case SNAPSHOT_LIST:
818         dump_snapshots(bs);
819         break;
820
821     case SNAPSHOT_CREATE:
822         memset(&sn, 0, sizeof(sn));
823         pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
824
825         qemu_gettimeofday(&tv);
826         sn.date_sec = tv.tv_sec;
827         sn.date_nsec = tv.tv_usec * 1000;
828
829         ret = bdrv_snapshot_create(bs, &sn);
830         if (ret)
831             error("Could not create snapshot '%s': %d (%s)",
832                 snapshot_name, ret, strerror(-ret));
833         break;
834
835     case SNAPSHOT_APPLY:
836         ret = bdrv_snapshot_goto(bs, snapshot_name);
837         if (ret)
838             error("Could not apply snapshot '%s': %d (%s)",
839                 snapshot_name, ret, strerror(-ret));
840         break;
841
842     case SNAPSHOT_DELETE:
843         ret = bdrv_snapshot_delete(bs, snapshot_name);
844         if (ret)
845             error("Could not delete snapshot '%s': %d (%s)",
846                 snapshot_name, ret, strerror(-ret));
847         break;
848     }
849
850     /* Cleanup */
851     bdrv_delete(bs);
852 }
853
854 int main(int argc, char **argv)
855 {
856     const char *cmd;
857
858     bdrv_init();
859     if (argc < 2)
860         help();
861     cmd = argv[1];
862     optind++;
863     if (!strcmp(cmd, "create")) {
864         img_create(argc, argv);
865     } else if (!strcmp(cmd, "commit")) {
866         img_commit(argc, argv);
867     } else if (!strcmp(cmd, "convert")) {
868         img_convert(argc, argv);
869     } else if (!strcmp(cmd, "info")) {
870         img_info(argc, argv);
871     } else if (!strcmp(cmd, "snapshot")) {
872         img_snapshot(argc, argv);
873     } else {
874         help();
875     }
876     return 0;
877 }