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