[S3C] Added placeholder for 2440 nand
[qemu/mini2440.git] / qemu-img.c
blob2af695fbe64a7a03fe7d3eb4418226469ef3c859
1 /*
2 * QEMU disk image utility
4 * Copyright (c) 2003-2008 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include "qemu-common.h"
25 #include "osdep.h"
26 #include "block_int.h"
27 #include <assert.h>
29 #ifdef _WIN32
30 #include <windows.h>
31 #endif
33 /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
34 #define BRDV_O_FLAGS BDRV_O_CACHE_WB
36 static void QEMU_NORETURN error(const char *fmt, ...)
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);
47 static void format_print(void *opaque, const char *name)
49 printf(" %s", name);
52 /* Please keep in synch with qemu-img.texi */
53 static void help(void)
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"
92 printf("\nSupported formats:");
93 bdrv_iterate_format(format_print, NULL);
94 printf("\n");
95 exit(1);
98 #if defined(WIN32)
99 /* XXX: put correct support for win32 */
100 static int read_password(char *buf, int buf_size)
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;
113 buf[i] = '\0';
114 return 0;
117 #else
119 #include <termios.h>
121 static struct termios oldtty;
123 static void term_exit(void)
125 tcsetattr (0, TCSANOW, &oldtty);
128 static void term_init(void)
130 struct termios tty;
132 tcgetattr (0, &tty);
133 oldtty = tty;
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;
144 tcsetattr (0, TCSANOW, &tty);
146 atexit(term_exit);
149 static int read_password(char *buf, int buf_size)
151 uint8_t ch;
152 int i, ret;
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;
167 } else if (ret == 0) {
168 ret = -1;
169 break;
170 } else {
171 if (ch == '\r') {
172 ret = 0;
173 break;
175 if (i < (buf_size - 1))
176 buf[i++] = ch;
179 term_exit();
180 buf[i] = '\0';
181 printf("\n");
182 return ret;
184 #endif
186 static BlockDriverState *bdrv_new_open(const char *filename,
187 const char *fmt)
189 BlockDriverState *bs;
190 BlockDriver *drv;
191 char password[256];
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;
203 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
204 error("Could not open '%s'", filename);
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");
213 return bs;
216 static int img_create(int argc, char **argv)
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;
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;
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();
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);
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");
296 return 0;
299 static int img_commit(int argc, char **argv)
301 int c, ret;
302 const char *filename, *fmt;
303 BlockDriver *drv;
304 BlockDriverState *bs;
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;
320 if (optind >= argc)
321 help();
322 filename = argv[optind++];
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;
334 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
335 error("Could not open '%s'", filename);
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;
356 bdrv_delete(bs);
357 return 0;
360 static int is_not_zero(const uint8_t *sector, int len)
362 int i;
363 len >>= 2;
364 for(i = 0;i < len; i++) {
365 if (((uint32_t *)sector)[i] != 0)
366 return 1;
368 return 0;
372 * Returns true iff the first sector pointed to by 'buf' contains at least
373 * a non-NUL byte.
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.
378 static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
380 int v, i;
382 if (n <= 0) {
383 *pnum = 0;
384 return 0;
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;
392 *pnum = i;
393 return v;
396 #define IO_BUF_SIZE 65536
398 static int img_convert(int argc, char **argv)
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;
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;
443 bs_n = argc - optind - 1;
444 if (bs_n < 1) help();
446 out_filename = argv[argc - 1];
448 if (bs_n > 1 && out_baseimg)
449 error("-B makes no sense when concatenating multiple input images");
451 bs = calloc(bs_n, sizeof(BlockDriverState *));
452 if (!bs)
453 error("Out of memory");
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;
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");
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);
485 out_bs = bdrv_new_open(out_filename, out_fmt);
487 bs_i = 0;
488 bs_offset = 0;
489 bdrv_get_geometry(bs[0], &bs_sectors);
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;
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;
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); */
528 assert (bs_num < bs_sectors);
530 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
532 if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0)
533 error("error while reading");
535 buf2 += nlow * 512;
536 bs_num += nlow;
538 remainder -= nlow;
540 assert (remainder == 0);
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);
550 sector_num += n;
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;
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); */
575 if (n > bs_offset + bs_sectors - sector_num)
576 n = bs_offset + bs_sectors - sector_num;
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;
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;
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");
606 sector_num += n1;
607 n -= n1;
608 buf1 += n1 * 512;
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;
619 #ifdef _WIN32
620 static int64_t get_allocated_file_size(const char *filename)
622 typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
623 get_compressed_t get_compressed;
624 struct _stati64 st;
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;
635 if (_stati64(filename, &st) < 0)
636 return -1;
637 return st.st_size;
639 #else
640 static int64_t get_allocated_file_size(const char *filename)
642 struct stat st;
643 if (stat(filename, &st) < 0)
644 return -1;
645 return (int64_t)st.st_blocks * 512;
647 #endif
649 static void dump_snapshots(BlockDriverState *bs)
651 QEMUSnapshotInfo *sn_tab, *sn;
652 int nb_sns, i;
653 char buf[256];
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));
664 qemu_free(sn_tab);
667 static int img_info(int argc, char **argv)
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;
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;
694 if (optind >= argc)
695 help();
696 filename = argv[optind++];
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;
708 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
709 error("Could not open '%s'", filename);
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);
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);
745 dump_snapshots(bs);
746 bdrv_delete(bs);
747 return 0;
750 #define SNAPSHOT_LIST 1
751 #define SNAPSHOT_CREATE 2
752 #define SNAPSHOT_APPLY 3
753 #define SNAPSHOT_DELETE 4
755 static void img_snapshot(int argc, char **argv)
757 BlockDriverState *bs;
758 QEMUSnapshotInfo sn;
759 char *filename, *snapshot_name = NULL;
760 int c, ret;
761 int action = 0;
762 qemu_timeval tv;
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;
778 action = SNAPSHOT_LIST;
779 break;
780 case 'a':
781 if (action) {
782 help();
783 return;
785 action = SNAPSHOT_APPLY;
786 snapshot_name = optarg;
787 break;
788 case 'c':
789 if (action) {
790 help();
791 return;
793 action = SNAPSHOT_CREATE;
794 snapshot_name = optarg;
795 break;
796 case 'd':
797 if (action) {
798 help();
799 return;
801 action = SNAPSHOT_DELETE;
802 snapshot_name = optarg;
803 break;
807 if (optind >= argc)
808 help();
809 filename = argv[optind++];
811 /* Open the image */
812 bs = bdrv_new("");
813 if (!bs)
814 error("Not enough memory");
816 if (bdrv_open2(bs, filename, 0, NULL) < 0) {
817 error("Could not open '%s'", filename);
820 /* Perform the requested action */
821 switch(action) {
822 case SNAPSHOT_LIST:
823 dump_snapshots(bs);
824 break;
826 case SNAPSHOT_CREATE:
827 memset(&sn, 0, sizeof(sn));
828 pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
830 qemu_gettimeofday(&tv);
831 sn.date_sec = tv.tv_sec;
832 sn.date_nsec = tv.tv_usec * 1000;
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;
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;
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;
855 /* Cleanup */
856 bdrv_delete(bs);
859 int main(int argc, char **argv)
861 const char *cmd;
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();
881 return 0;