Annotation of qemu/qemu-img.c, revision 1.1.1.14

1.1       root        1: /*
1.1.1.3   root        2:  * QEMU disk image utility
1.1.1.4   root        3:  *
                      4:  * Copyright (c) 2003-2008 Fabrice Bellard
                      5:  *
1.1       root        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:  */
1.1.1.4   root       24: #include "qemu-common.h"
1.1.1.8   root       25: #include "qemu-option.h"
1.1.1.12  root       26: #include "qemu-error.h"
1.1.1.5   root       27: #include "osdep.h"
1.1.1.12  root       28: #include "sysemu.h"
1.1.1.4   root       29: #include "block_int.h"
1.1.1.8   root       30: #include <stdio.h>
1.1       root       31: 
1.1.1.2   root       32: #ifdef _WIN32
                     33: #include <windows.h>
                     34: #endif
                     35: 
1.1.1.8   root       36: typedef struct img_cmd_t {
                     37:     const char *name;
                     38:     int (*handler)(int argc, char **argv);
                     39: } img_cmd_t;
                     40: 
1.1.1.5   root       41: /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
1.1.1.11  root       42: #define BDRV_O_FLAGS BDRV_O_CACHE_WB
1.1.1.13  root       43: #define BDRV_DEFAULT_CACHE "writeback"
1.1       root       44: 
                     45: static void format_print(void *opaque, const char *name)
                     46: {
                     47:     printf(" %s", name);
                     48: }
                     49: 
1.1.1.5   root       50: /* Please keep in synch with qemu-img.texi */
1.1.1.4   root       51: static void help(void)
1.1       root       52: {
1.1.1.11  root       53:     const char *help_msg =
                     54:            "qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
1.1       root       55:            "usage: qemu-img command [command options]\n"
                     56:            "QEMU disk image utility\n"
                     57:            "\n"
                     58:            "Command syntax:\n"
1.1.1.8   root       59: #define DEF(option, callback, arg_string)        \
                     60:            "  " arg_string "\n"
                     61: #include "qemu-img-cmds.h"
                     62: #undef DEF
                     63: #undef GEN_DOCS
1.1       root       64:            "\n"
                     65:            "Command parameters:\n"
                     66:            "  'filename' is a disk image filename\n"
                     67:            "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
1.1.1.13  root       68:            "  'cache' is the cache mode used to write the output disk image, the valid\n"
1.1.1.14! root       69:            "    options are: 'none', 'writeback' (default), 'writethrough', 'directsync'\n"
        !            70:            "    and 'unsafe'\n"
1.1.1.9   root       71:            "  'size' is the disk image size in bytes. Optional suffixes\n"
                     72:            "    'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
                     73:            "    and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
1.1       root       74:            "  'output_filename' is the destination disk image filename\n"
                     75:            "  'output_fmt' is the destination format\n"
1.1.1.8   root       76:            "  'options' is a comma separated list of format specific options in a\n"
                     77:            "    name=value format. Use -o ? for an overview of the options supported by the\n"
                     78:            "    used format\n"
1.1       root       79:            "  '-c' indicates that target image must be compressed (qcow format only)\n"
1.1.1.11  root       80:            "  '-u' enables unsafe rebasing. It is assumed that old and new backing file\n"
                     81:            "       match exactly. The image doesn't need a working backing file before\n"
                     82:            "       rebasing in this case (useful for renaming the backing file)\n"
1.1.1.5   root       83:            "  '-h' with or without a command shows this help and lists the supported formats\n"
1.1.1.13  root       84:            "  '-p' show progress of command (only certain commands)\n"
1.1.1.14! root       85:            "  '-S' indicates the consecutive number of bytes that must contain only zeros\n"
        !            86:            "       for qemu-img to create a sparse image during conversion\n"
1.1.1.5   root       87:            "\n"
                     88:            "Parameters to snapshot subcommand:\n"
                     89:            "  'snapshot' is the name of the snapshot to create, apply or delete\n"
                     90:            "  '-a' applies a snapshot (revert disk to saved state)\n"
                     91:            "  '-c' creates a snapshot\n"
                     92:            "  '-d' deletes a snapshot\n"
1.1.1.11  root       93:            "  '-l' lists all snapshots in the given image\n";
                     94: 
                     95:     printf("%s\nSupported formats:", help_msg);
1.1       root       96:     bdrv_iterate_format(format_print, NULL);
                     97:     printf("\n");
                     98:     exit(1);
                     99: }
                    100: 
                    101: #if defined(WIN32)
                    102: /* XXX: put correct support for win32 */
                    103: static int read_password(char *buf, int buf_size)
                    104: {
                    105:     int c, i;
                    106:     printf("Password: ");
                    107:     fflush(stdout);
                    108:     i = 0;
                    109:     for(;;) {
                    110:         c = getchar();
                    111:         if (c == '\n')
                    112:             break;
                    113:         if (i < (buf_size - 1))
                    114:             buf[i++] = c;
                    115:     }
                    116:     buf[i] = '\0';
                    117:     return 0;
                    118: }
                    119: 
                    120: #else
                    121: 
                    122: #include <termios.h>
                    123: 
                    124: static struct termios oldtty;
                    125: 
                    126: static void term_exit(void)
                    127: {
                    128:     tcsetattr (0, TCSANOW, &oldtty);
                    129: }
                    130: 
                    131: static void term_init(void)
                    132: {
                    133:     struct termios tty;
                    134: 
                    135:     tcgetattr (0, &tty);
                    136:     oldtty = tty;
                    137: 
                    138:     tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
                    139:                           |INLCR|IGNCR|ICRNL|IXON);
                    140:     tty.c_oflag |= OPOST;
                    141:     tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
                    142:     tty.c_cflag &= ~(CSIZE|PARENB);
                    143:     tty.c_cflag |= CS8;
                    144:     tty.c_cc[VMIN] = 1;
                    145:     tty.c_cc[VTIME] = 0;
1.1.1.4   root      146: 
1.1       root      147:     tcsetattr (0, TCSANOW, &tty);
                    148: 
                    149:     atexit(term_exit);
                    150: }
                    151: 
1.1.1.4   root      152: static int read_password(char *buf, int buf_size)
1.1       root      153: {
                    154:     uint8_t ch;
                    155:     int i, ret;
                    156: 
                    157:     printf("password: ");
                    158:     fflush(stdout);
                    159:     term_init();
                    160:     i = 0;
                    161:     for(;;) {
                    162:         ret = read(0, &ch, 1);
                    163:         if (ret == -1) {
                    164:             if (errno == EAGAIN || errno == EINTR) {
                    165:                 continue;
                    166:             } else {
                    167:                 ret = -1;
                    168:                 break;
                    169:             }
                    170:         } else if (ret == 0) {
                    171:             ret = -1;
                    172:             break;
                    173:         } else {
                    174:             if (ch == '\r') {
                    175:                 ret = 0;
                    176:                 break;
                    177:             }
                    178:             if (i < (buf_size - 1))
                    179:                 buf[i++] = ch;
                    180:         }
                    181:     }
                    182:     term_exit();
                    183:     buf[i] = '\0';
                    184:     printf("\n");
                    185:     return ret;
                    186: }
                    187: #endif
                    188: 
1.1.1.12  root      189: static int print_block_option_help(const char *filename, const char *fmt)
                    190: {
                    191:     BlockDriver *drv, *proto_drv;
                    192:     QEMUOptionParameter *create_options = NULL;
                    193: 
                    194:     /* Find driver and parse its options */
                    195:     drv = bdrv_find_format(fmt);
                    196:     if (!drv) {
                    197:         error_report("Unknown file format '%s'", fmt);
                    198:         return 1;
                    199:     }
                    200: 
                    201:     proto_drv = bdrv_find_protocol(filename);
                    202:     if (!proto_drv) {
                    203:         error_report("Unknown protocol '%s'", filename);
                    204:         return 1;
                    205:     }
                    206: 
                    207:     create_options = append_option_parameters(create_options,
                    208:                                               drv->create_options);
                    209:     create_options = append_option_parameters(create_options,
                    210:                                               proto_drv->create_options);
                    211:     print_option_help(create_options);
                    212:     free_option_parameters(create_options);
                    213:     return 0;
                    214: }
                    215: 
1.1       root      216: static BlockDriverState *bdrv_new_open(const char *filename,
1.1.1.11  root      217:                                        const char *fmt,
                    218:                                        int flags)
1.1       root      219: {
                    220:     BlockDriverState *bs;
                    221:     BlockDriver *drv;
                    222:     char password[256];
1.1.1.12  root      223:     int ret;
                    224: 
                    225:     bs = bdrv_new("image");
1.1       root      226: 
                    227:     if (fmt) {
                    228:         drv = bdrv_find_format(fmt);
1.1.1.11  root      229:         if (!drv) {
1.1.1.12  root      230:             error_report("Unknown file format '%s'", fmt);
1.1.1.11  root      231:             goto fail;
                    232:         }
1.1       root      233:     } else {
                    234:         drv = NULL;
                    235:     }
1.1.1.12  root      236: 
                    237:     ret = bdrv_open(bs, filename, flags, drv);
                    238:     if (ret < 0) {
                    239:         error_report("Could not open '%s': %s", filename, strerror(-ret));
1.1.1.11  root      240:         goto fail;
1.1       root      241:     }
1.1.1.12  root      242: 
1.1       root      243:     if (bdrv_is_encrypted(bs)) {
                    244:         printf("Disk image '%s' is encrypted.\n", filename);
1.1.1.11  root      245:         if (read_password(password, sizeof(password)) < 0) {
1.1.1.12  root      246:             error_report("No password given");
1.1.1.11  root      247:             goto fail;
                    248:         }
                    249:         if (bdrv_set_key(bs, password) < 0) {
1.1.1.12  root      250:             error_report("invalid password");
1.1.1.11  root      251:             goto fail;
                    252:         }
1.1       root      253:     }
                    254:     return bs;
1.1.1.11  root      255: fail:
                    256:     if (bs) {
                    257:         bdrv_delete(bs);
                    258:     }
                    259:     return NULL;
1.1       root      260: }
                    261: 
1.1.1.11  root      262: static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
1.1.1.12  root      263:                                  const char *base_filename,
                    264:                                  const char *base_fmt)
1.1.1.8   root      265: {
                    266:     if (base_filename) {
                    267:         if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
1.1.1.12  root      268:             error_report("Backing file not supported for file format '%s'",
                    269:                          fmt);
1.1.1.11  root      270:             return -1;
1.1.1.8   root      271:         }
                    272:     }
                    273:     if (base_fmt) {
                    274:         if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
1.1.1.12  root      275:             error_report("Backing file format not supported for file "
                    276:                          "format '%s'", fmt);
1.1.1.11  root      277:             return -1;
1.1.1.8   root      278:         }
                    279:     }
1.1.1.11  root      280:     return 0;
1.1.1.8   root      281: }
                    282: 
1.1       root      283: static int img_create(int argc, char **argv)
                    284: {
1.1.1.12  root      285:     int c, ret = 0;
                    286:     uint64_t img_size = -1;
1.1       root      287:     const char *fmt = "raw";
1.1.1.8   root      288:     const char *base_fmt = NULL;
1.1       root      289:     const char *filename;
                    290:     const char *base_filename = NULL;
1.1.1.8   root      291:     char *options = NULL;
1.1.1.4   root      292: 
1.1       root      293:     for(;;) {
1.1.1.8   root      294:         c = getopt(argc, argv, "F:b:f:he6o:");
1.1.1.12  root      295:         if (c == -1) {
1.1       root      296:             break;
1.1.1.12  root      297:         }
1.1       root      298:         switch(c) {
1.1.1.12  root      299:         case '?':
1.1       root      300:         case 'h':
                    301:             help();
                    302:             break;
1.1.1.8   root      303:         case 'F':
                    304:             base_fmt = optarg;
                    305:             break;
1.1       root      306:         case 'b':
                    307:             base_filename = optarg;
                    308:             break;
                    309:         case 'f':
                    310:             fmt = optarg;
                    311:             break;
                    312:         case 'e':
1.1.1.13  root      313:             error_report("option -e is deprecated, please use \'-o "
1.1.1.12  root      314:                   "encryption\' instead!");
                    315:             return 1;
1.1.1.4   root      316:         case '6':
1.1.1.13  root      317:             error_report("option -6 is deprecated, please use \'-o "
1.1.1.12  root      318:                   "compat6\' instead!");
                    319:             return 1;
1.1.1.8   root      320:         case 'o':
                    321:             options = optarg;
                    322:             break;
1.1       root      323:         }
                    324:     }
1.1.1.8   root      325: 
1.1.1.11  root      326:     /* Get the filename */
1.1.1.12  root      327:     if (optind >= argc) {
1.1.1.11  root      328:         help();
                    329:     }
1.1.1.12  root      330:     filename = argv[optind++];
1.1.1.11  root      331: 
1.1.1.12  root      332:     /* Get image size, if specified */
                    333:     if (optind < argc) {
                    334:         int64_t sval;
1.1.1.14! root      335:         char *end;
        !           336:         sval = strtosz_suffix(argv[optind++], &end, STRTOSZ_DEFSUFFIX_B);
        !           337:         if (sval < 0 || *end) {
1.1.1.12  root      338:             error_report("Invalid image size specified! You may use k, M, G or "
                    339:                   "T suffixes for ");
                    340:             error_report("kilobytes, megabytes, gigabytes and terabytes.");
1.1.1.11  root      341:             ret = -1;
                    342:             goto out;
1.1.1.8   root      343:         }
1.1.1.12  root      344:         img_size = (uint64_t)sval;
1.1.1.8   root      345:     }
                    346: 
1.1.1.12  root      347:     if (options && !strcmp(options, "?")) {
                    348:         ret = print_block_option_help(filename, fmt);
1.1.1.11  root      349:         goto out;
                    350:     }
1.1.1.8   root      351: 
1.1.1.12  root      352:     ret = bdrv_img_create(filename, fmt, base_filename, base_fmt,
                    353:                           options, img_size, BDRV_O_FLAGS);
1.1.1.11  root      354: out:
                    355:     if (ret) {
                    356:         return 1;
                    357:     }
1.1       root      358:     return 0;
                    359: }
                    360: 
1.1.1.11  root      361: /*
                    362:  * Checks an image for consistency. Exit codes:
                    363:  *
                    364:  * 0 - Check completed, image is good
                    365:  * 1 - Check not completed because of internal errors
                    366:  * 2 - Check completed, image is corrupted
                    367:  * 3 - Check completed, image has leaked clusters, but is good otherwise
                    368:  */
1.1.1.8   root      369: static int img_check(int argc, char **argv)
                    370: {
                    371:     int c, ret;
                    372:     const char *filename, *fmt;
                    373:     BlockDriverState *bs;
1.1.1.11  root      374:     BdrvCheckResult result;
1.1.1.8   root      375: 
                    376:     fmt = NULL;
                    377:     for(;;) {
                    378:         c = getopt(argc, argv, "f:h");
1.1.1.12  root      379:         if (c == -1) {
1.1.1.8   root      380:             break;
1.1.1.12  root      381:         }
1.1.1.8   root      382:         switch(c) {
1.1.1.12  root      383:         case '?':
1.1.1.8   root      384:         case 'h':
                    385:             help();
                    386:             break;
                    387:         case 'f':
                    388:             fmt = optarg;
                    389:             break;
                    390:         }
                    391:     }
1.1.1.12  root      392:     if (optind >= argc) {
1.1.1.8   root      393:         help();
1.1.1.12  root      394:     }
1.1.1.8   root      395:     filename = argv[optind++];
                    396: 
1.1.1.11  root      397:     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS);
                    398:     if (!bs) {
                    399:         return 1;
1.1.1.8   root      400:     }
1.1.1.11  root      401:     ret = bdrv_check(bs, &result);
                    402: 
                    403:     if (ret == -ENOTSUP) {
1.1.1.12  root      404:         error_report("This image format does not support checks");
1.1.1.11  root      405:         bdrv_delete(bs);
                    406:         return 1;
1.1.1.8   root      407:     }
1.1.1.11  root      408: 
                    409:     if (!(result.corruptions || result.leaks || result.check_errors)) {
1.1.1.8   root      410:         printf("No errors were found on the image.\n");
1.1.1.11  root      411:     } else {
                    412:         if (result.corruptions) {
                    413:             printf("\n%d errors were found on the image.\n"
                    414:                 "Data may be corrupted, or further writes to the image "
                    415:                 "may corrupt it.\n",
                    416:                 result.corruptions);
                    417:         }
                    418: 
                    419:         if (result.leaks) {
                    420:             printf("\n%d leaked clusters were found on the image.\n"
                    421:                 "This means waste of disk space, but no harm to data.\n",
                    422:                 result.leaks);
                    423:         }
                    424: 
                    425:         if (result.check_errors) {
                    426:             printf("\n%d internal errors have occurred during the check.\n",
                    427:                 result.check_errors);
1.1.1.8   root      428:         }
                    429:     }
                    430: 
                    431:     bdrv_delete(bs);
1.1.1.11  root      432: 
                    433:     if (ret < 0 || result.check_errors) {
                    434:         printf("\nAn error has occurred during the check: %s\n"
                    435:             "The check is not complete and may have missed error.\n",
                    436:             strerror(-ret));
                    437:         return 1;
                    438:     }
                    439: 
                    440:     if (result.corruptions) {
                    441:         return 2;
                    442:     } else if (result.leaks) {
                    443:         return 3;
                    444:     } else {
                    445:         return 0;
                    446:     }
1.1.1.8   root      447: }
                    448: 
1.1       root      449: static int img_commit(int argc, char **argv)
                    450: {
1.1.1.13  root      451:     int c, ret, flags;
                    452:     const char *filename, *fmt, *cache;
1.1       root      453:     BlockDriverState *bs;
                    454: 
                    455:     fmt = NULL;
1.1.1.13  root      456:     cache = BDRV_DEFAULT_CACHE;
1.1       root      457:     for(;;) {
1.1.1.13  root      458:         c = getopt(argc, argv, "f:ht:");
1.1.1.12  root      459:         if (c == -1) {
1.1       root      460:             break;
1.1.1.12  root      461:         }
1.1       root      462:         switch(c) {
1.1.1.12  root      463:         case '?':
1.1       root      464:         case 'h':
                    465:             help();
                    466:             break;
                    467:         case 'f':
                    468:             fmt = optarg;
                    469:             break;
1.1.1.13  root      470:         case 't':
                    471:             cache = optarg;
                    472:             break;
1.1       root      473:         }
                    474:     }
1.1.1.12  root      475:     if (optind >= argc) {
1.1       root      476:         help();
1.1.1.12  root      477:     }
1.1       root      478:     filename = argv[optind++];
                    479: 
1.1.1.13  root      480:     flags = BDRV_O_RDWR;
1.1.1.14! root      481:     ret = bdrv_parse_cache_flags(cache, &flags);
1.1.1.13  root      482:     if (ret < 0) {
                    483:         error_report("Invalid cache option: %s", cache);
                    484:         return -1;
                    485:     }
                    486: 
                    487:     bs = bdrv_new_open(filename, fmt, flags);
1.1.1.11  root      488:     if (!bs) {
                    489:         return 1;
1.1       root      490:     }
                    491:     ret = bdrv_commit(bs);
                    492:     switch(ret) {
                    493:     case 0:
                    494:         printf("Image committed.\n");
                    495:         break;
                    496:     case -ENOENT:
1.1.1.12  root      497:         error_report("No disk inserted");
1.1       root      498:         break;
                    499:     case -EACCES:
1.1.1.12  root      500:         error_report("Image is read-only");
1.1       root      501:         break;
                    502:     case -ENOTSUP:
1.1.1.12  root      503:         error_report("Image is already committed");
1.1       root      504:         break;
                    505:     default:
1.1.1.12  root      506:         error_report("Error while committing image");
1.1       root      507:         break;
                    508:     }
                    509: 
                    510:     bdrv_delete(bs);
1.1.1.11  root      511:     if (ret) {
                    512:         return 1;
                    513:     }
1.1       root      514:     return 0;
                    515: }
                    516: 
1.1.1.13  root      517: /*
                    518:  * Checks whether the sector is not a zero sector.
                    519:  *
                    520:  * Attention! The len must be a multiple of 4 * sizeof(long) due to
                    521:  * restriction of optimizations in this function.
                    522:  */
1.1       root      523: static int is_not_zero(const uint8_t *sector, int len)
                    524: {
1.1.1.13  root      525:     /*
                    526:      * Use long as the biggest available internal data type that fits into the
                    527:      * CPU register and unroll the loop to smooth out the effect of memory
                    528:      * latency.
                    529:      */
                    530: 
1.1       root      531:     int i;
1.1.1.13  root      532:     long d0, d1, d2, d3;
                    533:     const long * const data = (const long *) sector;
                    534: 
                    535:     len /= sizeof(long);
                    536: 
                    537:     for(i = 0; i < len; i += 4) {
                    538:         d0 = data[i + 0];
                    539:         d1 = data[i + 1];
                    540:         d2 = data[i + 2];
                    541:         d3 = data[i + 3];
                    542: 
                    543:         if (d0 || d1 || d2 || d3) {
1.1       root      544:             return 1;
1.1.1.13  root      545:         }
1.1       root      546:     }
1.1.1.13  root      547: 
1.1       root      548:     return 0;
                    549: }
                    550: 
1.1.1.5   root      551: /*
                    552:  * Returns true iff the first sector pointed to by 'buf' contains at least
                    553:  * a non-NUL byte.
                    554:  *
                    555:  * 'pnum' is set to the number of sectors (including and immediately following
                    556:  * the first one) that are known to be in the same allocated/unallocated state.
                    557:  */
1.1       root      558: static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
                    559: {
                    560:     int v, i;
                    561: 
                    562:     if (n <= 0) {
                    563:         *pnum = 0;
                    564:         return 0;
                    565:     }
                    566:     v = is_not_zero(buf, 512);
                    567:     for(i = 1; i < n; i++) {
                    568:         buf += 512;
                    569:         if (v != is_not_zero(buf, 512))
                    570:             break;
                    571:     }
                    572:     *pnum = i;
                    573:     return v;
                    574: }
                    575: 
1.1.1.11  root      576: /*
1.1.1.14! root      577:  * Like is_allocated_sectors, but if the buffer starts with a used sector,
        !           578:  * up to 'min' consecutive sectors containing zeros are ignored. This avoids
        !           579:  * breaking up write requests for only small sparse areas.
        !           580:  */
        !           581: static int is_allocated_sectors_min(const uint8_t *buf, int n, int *pnum,
        !           582:     int min)
        !           583: {
        !           584:     int ret;
        !           585:     int num_checked, num_used;
        !           586: 
        !           587:     if (n < min) {
        !           588:         min = n;
        !           589:     }
        !           590: 
        !           591:     ret = is_allocated_sectors(buf, n, pnum);
        !           592:     if (!ret) {
        !           593:         return ret;
        !           594:     }
        !           595: 
        !           596:     num_used = *pnum;
        !           597:     buf += BDRV_SECTOR_SIZE * *pnum;
        !           598:     n -= *pnum;
        !           599:     num_checked = num_used;
        !           600: 
        !           601:     while (n > 0) {
        !           602:         ret = is_allocated_sectors(buf, n, pnum);
        !           603: 
        !           604:         buf += BDRV_SECTOR_SIZE * *pnum;
        !           605:         n -= *pnum;
        !           606:         num_checked += *pnum;
        !           607:         if (ret) {
        !           608:             num_used = num_checked;
        !           609:         } else if (*pnum >= min) {
        !           610:             break;
        !           611:         }
        !           612:     }
        !           613: 
        !           614:     *pnum = num_used;
        !           615:     return 1;
        !           616: }
        !           617: 
        !           618: /*
1.1.1.11  root      619:  * Compares two buffers sector by sector. Returns 0 if the first sector of both
                    620:  * buffers matches, non-zero otherwise.
                    621:  *
                    622:  * pnum is set to the number of sectors (including and immediately following
                    623:  * the first one) that are known to have the same comparison result
                    624:  */
                    625: static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
                    626:     int *pnum)
                    627: {
                    628:     int res, i;
                    629: 
                    630:     if (n <= 0) {
                    631:         *pnum = 0;
                    632:         return 0;
                    633:     }
                    634: 
                    635:     res = !!memcmp(buf1, buf2, 512);
                    636:     for(i = 1; i < n; i++) {
                    637:         buf1 += 512;
                    638:         buf2 += 512;
                    639: 
                    640:         if (!!memcmp(buf1, buf2, 512) != res) {
                    641:             break;
                    642:         }
                    643:     }
                    644: 
                    645:     *pnum = i;
                    646:     return res;
                    647: }
                    648: 
1.1.1.9   root      649: #define IO_BUF_SIZE (2 * 1024 * 1024)
1.1       root      650: 
                    651: static int img_convert(int argc, char **argv)
                    652: {
1.1.1.12  root      653:     int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
1.1.1.13  root      654:     int progress = 0, flags;
                    655:     const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
1.1.1.11  root      656:     BlockDriver *drv, *proto_drv;
                    657:     BlockDriverState **bs = NULL, *out_bs = NULL;
1.1.1.4   root      658:     int64_t total_sectors, nb_sectors, sector_num, bs_offset;
                    659:     uint64_t bs_sectors;
1.1.1.11  root      660:     uint8_t * buf = NULL;
1.1       root      661:     const uint8_t *buf1;
1.1.1.3   root      662:     BlockDriverInfo bdi;
1.1.1.11  root      663:     QEMUOptionParameter *param = NULL, *create_options = NULL;
1.1.1.12  root      664:     QEMUOptionParameter *out_baseimg_param;
1.1.1.8   root      665:     char *options = NULL;
1.1.1.12  root      666:     const char *snapshot_name = NULL;
1.1.1.13  root      667:     float local_progress;
1.1.1.14! root      668:     int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
1.1       root      669: 
                    670:     fmt = NULL;
                    671:     out_fmt = "raw";
1.1.1.13  root      672:     cache = "unsafe";
1.1.1.5   root      673:     out_baseimg = NULL;
1.1.1.12  root      674:     compress = 0;
1.1       root      675:     for(;;) {
1.1.1.14! root      676:         c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:");
1.1.1.12  root      677:         if (c == -1) {
1.1       root      678:             break;
1.1.1.12  root      679:         }
1.1       root      680:         switch(c) {
1.1.1.12  root      681:         case '?':
1.1       root      682:         case 'h':
                    683:             help();
                    684:             break;
                    685:         case 'f':
                    686:             fmt = optarg;
                    687:             break;
                    688:         case 'O':
                    689:             out_fmt = optarg;
                    690:             break;
1.1.1.5   root      691:         case 'B':
                    692:             out_baseimg = optarg;
                    693:             break;
1.1       root      694:         case 'c':
1.1.1.12  root      695:             compress = 1;
1.1       root      696:             break;
                    697:         case 'e':
1.1.1.13  root      698:             error_report("option -e is deprecated, please use \'-o "
1.1.1.12  root      699:                   "encryption\' instead!");
                    700:             return 1;
1.1.1.4   root      701:         case '6':
1.1.1.13  root      702:             error_report("option -6 is deprecated, please use \'-o "
1.1.1.12  root      703:                   "compat6\' instead!");
                    704:             return 1;
1.1.1.8   root      705:         case 'o':
                    706:             options = optarg;
                    707:             break;
1.1.1.12  root      708:         case 's':
                    709:             snapshot_name = optarg;
                    710:             break;
1.1.1.14! root      711:         case 'S':
        !           712:         {
        !           713:             int64_t sval;
        !           714:             char *end;
        !           715:             sval = strtosz_suffix(optarg, &end, STRTOSZ_DEFSUFFIX_B);
        !           716:             if (sval < 0 || *end) {
        !           717:                 error_report("Invalid minimum zero buffer size for sparse output specified");
        !           718:                 return 1;
        !           719:             }
        !           720: 
        !           721:             min_sparse = sval / BDRV_SECTOR_SIZE;
        !           722:             break;
        !           723:         }
1.1.1.13  root      724:         case 'p':
                    725:             progress = 1;
                    726:             break;
                    727:         case 't':
                    728:             cache = optarg;
                    729:             break;
1.1       root      730:         }
                    731:     }
1.1.1.4   root      732: 
                    733:     bs_n = argc - optind - 1;
1.1.1.12  root      734:     if (bs_n < 1) {
                    735:         help();
                    736:     }
1.1.1.4   root      737: 
                    738:     out_filename = argv[argc - 1];
1.1.1.5   root      739: 
1.1.1.12  root      740:     if (options && !strcmp(options, "?")) {
                    741:         ret = print_block_option_help(out_filename, out_fmt);
                    742:         goto out;
                    743:     }
                    744: 
1.1.1.11  root      745:     if (bs_n > 1 && out_baseimg) {
1.1.1.12  root      746:         error_report("-B makes no sense when concatenating multiple input "
                    747:                      "images");
                    748:         ret = -1;
                    749:         goto out;
1.1.1.11  root      750:     }
1.1.1.4   root      751:         
1.1.1.13  root      752:     qemu_progress_init(progress, 2.0);
                    753:     qemu_progress_print(0, 100);
                    754: 
1.1.1.14! root      755:     bs = g_malloc0(bs_n * sizeof(BlockDriverState *));
1.1.1.4   root      756: 
                    757:     total_sectors = 0;
                    758:     for (bs_i = 0; bs_i < bs_n; bs_i++) {
1.1.1.11  root      759:         bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS);
                    760:         if (!bs[bs_i]) {
1.1.1.12  root      761:             error_report("Could not open '%s'", argv[optind + bs_i]);
1.1.1.11  root      762:             ret = -1;
                    763:             goto out;
                    764:         }
1.1.1.4   root      765:         bdrv_get_geometry(bs[bs_i], &bs_sectors);
                    766:         total_sectors += bs_sectors;
                    767:     }
1.1       root      768: 
1.1.1.12  root      769:     if (snapshot_name != NULL) {
                    770:         if (bs_n > 1) {
1.1.1.13  root      771:             error_report("No support for concatenating multiple snapshot");
1.1.1.12  root      772:             ret = -1;
                    773:             goto out;
                    774:         }
                    775:         if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
1.1.1.13  root      776:             error_report("Failed to load snapshot");
1.1.1.12  root      777:             ret = -1;
                    778:             goto out;
                    779:         }
                    780:     }
                    781: 
1.1.1.8   root      782:     /* Find driver and parse its options */
1.1       root      783:     drv = bdrv_find_format(out_fmt);
1.1.1.11  root      784:     if (!drv) {
1.1.1.12  root      785:         error_report("Unknown file format '%s'", out_fmt);
1.1.1.11  root      786:         ret = -1;
                    787:         goto out;
                    788:     }
                    789: 
                    790:     proto_drv = bdrv_find_protocol(out_filename);
                    791:     if (!proto_drv) {
1.1.1.12  root      792:         error_report("Unknown protocol '%s'", out_filename);
1.1.1.11  root      793:         ret = -1;
                    794:         goto out;
                    795:     }
1.1.1.4   root      796: 
1.1.1.11  root      797:     create_options = append_option_parameters(create_options,
                    798:                                               drv->create_options);
                    799:     create_options = append_option_parameters(create_options,
                    800:                                               proto_drv->create_options);
1.1.1.8   root      801: 
                    802:     if (options) {
1.1.1.11  root      803:         param = parse_option_parameters(options, create_options, param);
1.1.1.8   root      804:         if (param == NULL) {
1.1.1.12  root      805:             error_report("Invalid options for file format '%s'.", out_fmt);
1.1.1.11  root      806:             ret = -1;
                    807:             goto out;
1.1.1.8   root      808:         }
                    809:     } else {
1.1.1.11  root      810:         param = parse_option_parameters("", create_options, param);
1.1.1.8   root      811:     }
                    812: 
                    813:     set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
1.1.1.12  root      814:     ret = add_old_style_options(out_fmt, param, out_baseimg, NULL);
1.1.1.11  root      815:     if (ret < 0) {
                    816:         goto out;
                    817:     }
1.1.1.8   root      818: 
1.1.1.12  root      819:     /* Get backing file name if -o backing_file was used */
                    820:     out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
                    821:     if (out_baseimg_param) {
                    822:         out_baseimg = out_baseimg_param->value.s;
                    823:     }
                    824: 
1.1.1.8   root      825:     /* Check if compression is supported */
1.1.1.12  root      826:     if (compress) {
1.1.1.8   root      827:         QEMUOptionParameter *encryption =
                    828:             get_option_parameter(param, BLOCK_OPT_ENCRYPT);
1.1.1.14! root      829:         QEMUOptionParameter *preallocation =
        !           830:             get_option_parameter(param, BLOCK_OPT_PREALLOC);
1.1.1.8   root      831: 
                    832:         if (!drv->bdrv_write_compressed) {
1.1.1.12  root      833:             error_report("Compression not supported for this file format");
1.1.1.11  root      834:             ret = -1;
                    835:             goto out;
1.1.1.8   root      836:         }
                    837: 
                    838:         if (encryption && encryption->value.n) {
1.1.1.12  root      839:             error_report("Compression and encryption not supported at "
                    840:                          "the same time");
1.1.1.11  root      841:             ret = -1;
                    842:             goto out;
1.1.1.8   root      843:         }
1.1.1.14! root      844: 
        !           845:         if (preallocation && preallocation->value.s
        !           846:             && strcmp(preallocation->value.s, "off"))
        !           847:         {
        !           848:             error_report("Compression and preallocation not supported at "
        !           849:                          "the same time");
        !           850:             ret = -1;
        !           851:             goto out;
        !           852:         }
1.1.1.8   root      853:     }
                    854: 
                    855:     /* Create the new image */
                    856:     ret = bdrv_create(drv, out_filename, param);
1.1       root      857:     if (ret < 0) {
                    858:         if (ret == -ENOTSUP) {
1.1.1.12  root      859:             error_report("Formatting not supported for file format '%s'",
                    860:                          out_fmt);
1.1.1.7   root      861:         } else if (ret == -EFBIG) {
1.1.1.12  root      862:             error_report("The image size is too large for file format '%s'",
                    863:                          out_fmt);
1.1       root      864:         } else {
1.1.1.12  root      865:             error_report("%s: error while converting %s: %s",
                    866:                          out_filename, out_fmt, strerror(-ret));
1.1       root      867:         }
1.1.1.11  root      868:         goto out;
1.1       root      869:     }
1.1.1.4   root      870: 
1.1.1.13  root      871:     flags = BDRV_O_RDWR;
1.1.1.14! root      872:     ret = bdrv_parse_cache_flags(cache, &flags);
1.1.1.13  root      873:     if (ret < 0) {
                    874:         error_report("Invalid cache option: %s", cache);
                    875:         return -1;
                    876:     }
                    877: 
                    878:     out_bs = bdrv_new_open(out_filename, out_fmt, flags);
1.1.1.11  root      879:     if (!out_bs) {
                    880:         ret = -1;
                    881:         goto out;
                    882:     }
1.1       root      883: 
1.1.1.4   root      884:     bs_i = 0;
                    885:     bs_offset = 0;
                    886:     bdrv_get_geometry(bs[0], &bs_sectors);
1.1.1.14! root      887:     buf = qemu_blockalign(out_bs, IO_BUF_SIZE);
1.1.1.4   root      888: 
1.1.1.12  root      889:     if (compress) {
1.1.1.11  root      890:         ret = bdrv_get_info(out_bs, &bdi);
                    891:         if (ret < 0) {
1.1.1.12  root      892:             error_report("could not get block driver info");
1.1.1.11  root      893:             goto out;
                    894:         }
1.1.1.3   root      895:         cluster_size = bdi.cluster_size;
1.1.1.11  root      896:         if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) {
1.1.1.12  root      897:             error_report("invalid cluster size");
1.1.1.11  root      898:             ret = -1;
                    899:             goto out;
                    900:         }
1.1       root      901:         cluster_sectors = cluster_size >> 9;
                    902:         sector_num = 0;
1.1.1.13  root      903: 
                    904:         nb_sectors = total_sectors;
                    905:         local_progress = (float)100 /
                    906:             (nb_sectors / MIN(nb_sectors, cluster_sectors));
                    907: 
1.1       root      908:         for(;;) {
1.1.1.4   root      909:             int64_t bs_num;
                    910:             int remainder;
                    911:             uint8_t *buf2;
                    912: 
1.1       root      913:             nb_sectors = total_sectors - sector_num;
                    914:             if (nb_sectors <= 0)
                    915:                 break;
                    916:             if (nb_sectors >= cluster_sectors)
                    917:                 n = cluster_sectors;
                    918:             else
                    919:                 n = nb_sectors;
1.1.1.4   root      920: 
                    921:             bs_num = sector_num - bs_offset;
                    922:             assert (bs_num >= 0);
                    923:             remainder = n;
                    924:             buf2 = buf;
                    925:             while (remainder > 0) {
                    926:                 int nlow;
                    927:                 while (bs_num == bs_sectors) {
                    928:                     bs_i++;
                    929:                     assert (bs_i < bs_n);
                    930:                     bs_offset += bs_sectors;
                    931:                     bdrv_get_geometry(bs[bs_i], &bs_sectors);
                    932:                     bs_num = 0;
1.1.1.11  root      933:                     /* printf("changing part: sector_num=%" PRId64 ", "
                    934:                        "bs_i=%d, bs_offset=%" PRId64 ", bs_sectors=%" PRId64
                    935:                        "\n", sector_num, bs_i, bs_offset, bs_sectors); */
1.1.1.4   root      936:                 }
                    937:                 assert (bs_num < bs_sectors);
                    938: 
                    939:                 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
                    940: 
1.1.1.11  root      941:                 ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);
                    942:                 if (ret < 0) {
1.1.1.14! root      943:                     error_report("error while reading sector %" PRId64 ": %s",
        !           944:                                  bs_num, strerror(-ret));
1.1.1.11  root      945:                     goto out;
                    946:                 }
1.1.1.4   root      947: 
                    948:                 buf2 += nlow * 512;
                    949:                 bs_num += nlow;
                    950: 
                    951:                 remainder -= nlow;
                    952:             }
                    953:             assert (remainder == 0);
                    954: 
1.1.1.12  root      955:             if (n < cluster_sectors) {
1.1       root      956:                 memset(buf + n * 512, 0, cluster_size - n * 512);
1.1.1.12  root      957:             }
1.1       root      958:             if (is_not_zero(buf, cluster_size)) {
1.1.1.11  root      959:                 ret = bdrv_write_compressed(out_bs, sector_num, buf,
                    960:                                             cluster_sectors);
                    961:                 if (ret != 0) {
1.1.1.14! root      962:                     error_report("error while compressing sector %" PRId64
        !           963:                                  ": %s", sector_num, strerror(-ret));
1.1.1.11  root      964:                     goto out;
                    965:                 }
1.1       root      966:             }
                    967:             sector_num += n;
1.1.1.13  root      968:             qemu_progress_print(local_progress, 100);
1.1       root      969:         }
1.1.1.3   root      970:         /* signal EOF to align */
                    971:         bdrv_write_compressed(out_bs, 0, NULL, 0);
1.1       root      972:     } else {
1.1.1.11  root      973:         int has_zero_init = bdrv_has_zero_init(out_bs);
                    974: 
1.1.1.5   root      975:         sector_num = 0; // total number of sectors converted so far
1.1.1.13  root      976:         nb_sectors = total_sectors - sector_num;
                    977:         local_progress = (float)100 /
                    978:             (nb_sectors / MIN(nb_sectors, IO_BUF_SIZE / 512));
                    979: 
1.1       root      980:         for(;;) {
                    981:             nb_sectors = total_sectors - sector_num;
1.1.1.12  root      982:             if (nb_sectors <= 0) {
1.1       root      983:                 break;
1.1.1.12  root      984:             }
                    985:             if (nb_sectors >= (IO_BUF_SIZE / 512)) {
1.1       root      986:                 n = (IO_BUF_SIZE / 512);
1.1.1.12  root      987:             } else {
1.1       root      988:                 n = nb_sectors;
1.1.1.12  root      989:             }
1.1.1.4   root      990: 
                    991:             while (sector_num - bs_offset >= bs_sectors) {
                    992:                 bs_i ++;
                    993:                 assert (bs_i < bs_n);
                    994:                 bs_offset += bs_sectors;
                    995:                 bdrv_get_geometry(bs[bs_i], &bs_sectors);
1.1.1.11  root      996:                 /* printf("changing part: sector_num=%" PRId64 ", bs_i=%d, "
                    997:                   "bs_offset=%" PRId64 ", bs_sectors=%" PRId64 "\n",
1.1.1.4   root      998:                    sector_num, bs_i, bs_offset, bs_sectors); */
                    999:             }
                   1000: 
1.1.1.12  root     1001:             if (n > bs_offset + bs_sectors - sector_num) {
1.1.1.4   root     1002:                 n = bs_offset + bs_sectors - sector_num;
1.1.1.12  root     1003:             }
1.1.1.4   root     1004: 
1.1.1.11  root     1005:             if (has_zero_init) {
1.1.1.8   root     1006:                 /* If the output image is being created as a copy on write image,
                   1007:                    assume that sectors which are unallocated in the input image
                   1008:                    are present in both the output's and input's base images (no
                   1009:                    need to copy them). */
                   1010:                 if (out_baseimg) {
                   1011:                     if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
                   1012:                                            n, &n1)) {
                   1013:                         sector_num += n1;
                   1014:                         continue;
                   1015:                     }
                   1016:                     /* The next 'n1' sectors are allocated in the input image. Copy
                   1017:                        only those as they may be followed by unallocated sectors. */
                   1018:                     n = n1;
                   1019:                 }
                   1020:             } else {
                   1021:                 n1 = n;
1.1.1.5   root     1022:             }
                   1023: 
1.1.1.11  root     1024:             ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
                   1025:             if (ret < 0) {
1.1.1.14! root     1026:                 error_report("error while reading sector %" PRId64 ": %s",
        !          1027:                              sector_num - bs_offset, strerror(-ret));
1.1.1.11  root     1028:                 goto out;
                   1029:             }
1.1       root     1030:             /* NOTE: at the same time we convert, we do not write zero
                   1031:                sectors to have a chance to compress the image. Ideally, we
                   1032:                should add a specific call to have the info to go faster */
                   1033:             buf1 = buf;
                   1034:             while (n > 0) {
1.1.1.5   root     1035:                 /* If the output image is being created as a copy on write image,
                   1036:                    copy all sectors even the ones containing only NUL bytes,
1.1.1.8   root     1037:                    because they may differ from the sectors in the base image.
                   1038: 
                   1039:                    If the output is to a host device, we also write out
                   1040:                    sectors that are entirely 0, since whatever data was
                   1041:                    already there is garbage, not 0s. */
1.1.1.11  root     1042:                 if (!has_zero_init || out_baseimg ||
1.1.1.14! root     1043:                     is_allocated_sectors_min(buf1, n, &n1, min_sparse)) {
1.1.1.11  root     1044:                     ret = bdrv_write(out_bs, sector_num, buf1, n1);
                   1045:                     if (ret < 0) {
1.1.1.14! root     1046:                         error_report("error while writing sector %" PRId64
        !          1047:                                      ": %s", sector_num, strerror(-ret));
1.1.1.11  root     1048:                         goto out;
                   1049:                     }
1.1       root     1050:                 }
                   1051:                 sector_num += n1;
                   1052:                 n -= n1;
                   1053:                 buf1 += n1 * 512;
                   1054:             }
1.1.1.13  root     1055:             qemu_progress_print(local_progress, 100);
1.1       root     1056:         }
                   1057:     }
1.1.1.11  root     1058: out:
1.1.1.13  root     1059:     qemu_progress_end();
1.1.1.11  root     1060:     free_option_parameters(create_options);
                   1061:     free_option_parameters(param);
1.1.1.14! root     1062:     qemu_vfree(buf);
1.1.1.11  root     1063:     if (out_bs) {
                   1064:         bdrv_delete(out_bs);
                   1065:     }
1.1.1.12  root     1066:     if (bs) {
                   1067:         for (bs_i = 0; bs_i < bs_n; bs_i++) {
                   1068:             if (bs[bs_i]) {
                   1069:                 bdrv_delete(bs[bs_i]);
                   1070:             }
1.1.1.11  root     1071:         }
1.1.1.14! root     1072:         g_free(bs);
1.1.1.11  root     1073:     }
                   1074:     if (ret) {
                   1075:         return 1;
                   1076:     }
1.1       root     1077:     return 0;
                   1078: }
                   1079: 
                   1080: 
1.1.1.3   root     1081: static void dump_snapshots(BlockDriverState *bs)
                   1082: {
                   1083:     QEMUSnapshotInfo *sn_tab, *sn;
                   1084:     int nb_sns, i;
                   1085:     char buf[256];
                   1086: 
                   1087:     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
                   1088:     if (nb_sns <= 0)
                   1089:         return;
                   1090:     printf("Snapshot list:\n");
                   1091:     printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
                   1092:     for(i = 0; i < nb_sns; i++) {
                   1093:         sn = &sn_tab[i];
                   1094:         printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
                   1095:     }
1.1.1.14! root     1096:     g_free(sn_tab);
1.1.1.3   root     1097: }
                   1098: 
1.1       root     1099: static int img_info(int argc, char **argv)
                   1100: {
                   1101:     int c;
                   1102:     const char *filename, *fmt;
                   1103:     BlockDriverState *bs;
                   1104:     char fmt_name[128], size_buf[128], dsize_buf[128];
1.1.1.4   root     1105:     uint64_t total_sectors;
                   1106:     int64_t allocated_size;
1.1.1.3   root     1107:     char backing_filename[1024];
                   1108:     char backing_filename2[1024];
                   1109:     BlockDriverInfo bdi;
1.1       root     1110: 
                   1111:     fmt = NULL;
                   1112:     for(;;) {
                   1113:         c = getopt(argc, argv, "f:h");
1.1.1.12  root     1114:         if (c == -1) {
1.1       root     1115:             break;
1.1.1.12  root     1116:         }
1.1       root     1117:         switch(c) {
1.1.1.12  root     1118:         case '?':
1.1       root     1119:         case 'h':
                   1120:             help();
                   1121:             break;
                   1122:         case 'f':
                   1123:             fmt = optarg;
                   1124:             break;
                   1125:         }
                   1126:     }
1.1.1.12  root     1127:     if (optind >= argc) {
1.1       root     1128:         help();
1.1.1.12  root     1129:     }
1.1       root     1130:     filename = argv[optind++];
                   1131: 
1.1.1.11  root     1132:     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING);
                   1133:     if (!bs) {
                   1134:         return 1;
1.1       root     1135:     }
                   1136:     bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
                   1137:     bdrv_get_geometry(bs, &total_sectors);
                   1138:     get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
1.1.1.13  root     1139:     allocated_size = bdrv_get_allocated_file_size(bs);
1.1.1.12  root     1140:     if (allocated_size < 0) {
1.1.1.5   root     1141:         snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
1.1.1.12  root     1142:     } else {
1.1.1.4   root     1143:         get_human_readable_size(dsize_buf, sizeof(dsize_buf),
1.1       root     1144:                                 allocated_size);
1.1.1.12  root     1145:     }
1.1       root     1146:     printf("image: %s\n"
                   1147:            "file format: %s\n"
1.1.1.2   root     1148:            "virtual size: %s (%" PRId64 " bytes)\n"
1.1       root     1149:            "disk size: %s\n",
1.1.1.4   root     1150:            filename, fmt_name, size_buf,
1.1.1.2   root     1151:            (total_sectors * 512),
1.1       root     1152:            dsize_buf);
1.1.1.12  root     1153:     if (bdrv_is_encrypted(bs)) {
1.1       root     1154:         printf("encrypted: yes\n");
1.1.1.12  root     1155:     }
1.1.1.3   root     1156:     if (bdrv_get_info(bs, &bdi) >= 0) {
1.1.1.12  root     1157:         if (bdi.cluster_size != 0) {
1.1.1.3   root     1158:             printf("cluster_size: %d\n", bdi.cluster_size);
1.1.1.12  root     1159:         }
1.1.1.3   root     1160:     }
                   1161:     bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
                   1162:     if (backing_filename[0] != '\0') {
                   1163:         path_combine(backing_filename2, sizeof(backing_filename2),
                   1164:                      filename, backing_filename);
1.1.1.4   root     1165:         printf("backing file: %s (actual path: %s)\n",
1.1.1.3   root     1166:                backing_filename,
                   1167:                backing_filename2);
                   1168:     }
                   1169:     dump_snapshots(bs);
1.1       root     1170:     bdrv_delete(bs);
                   1171:     return 0;
                   1172: }
                   1173: 
1.1.1.5   root     1174: #define SNAPSHOT_LIST   1
                   1175: #define SNAPSHOT_CREATE 2
                   1176: #define SNAPSHOT_APPLY  3
                   1177: #define SNAPSHOT_DELETE 4
                   1178: 
1.1.1.8   root     1179: static int img_snapshot(int argc, char **argv)
1.1.1.5   root     1180: {
                   1181:     BlockDriverState *bs;
                   1182:     QEMUSnapshotInfo sn;
                   1183:     char *filename, *snapshot_name = NULL;
1.1.1.11  root     1184:     int c, ret = 0, bdrv_oflags;
1.1.1.5   root     1185:     int action = 0;
                   1186:     qemu_timeval tv;
                   1187: 
1.1.1.12  root     1188:     bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
1.1.1.5   root     1189:     /* Parse commandline parameters */
                   1190:     for(;;) {
                   1191:         c = getopt(argc, argv, "la:c:d:h");
1.1.1.12  root     1192:         if (c == -1) {
1.1.1.5   root     1193:             break;
1.1.1.12  root     1194:         }
1.1.1.5   root     1195:         switch(c) {
1.1.1.12  root     1196:         case '?':
1.1.1.5   root     1197:         case 'h':
                   1198:             help();
1.1.1.8   root     1199:             return 0;
1.1.1.5   root     1200:         case 'l':
                   1201:             if (action) {
                   1202:                 help();
1.1.1.8   root     1203:                 return 0;
1.1.1.5   root     1204:             }
                   1205:             action = SNAPSHOT_LIST;
1.1.1.11  root     1206:             bdrv_oflags &= ~BDRV_O_RDWR; /* no need for RW */
1.1.1.5   root     1207:             break;
                   1208:         case 'a':
                   1209:             if (action) {
                   1210:                 help();
1.1.1.8   root     1211:                 return 0;
1.1.1.5   root     1212:             }
                   1213:             action = SNAPSHOT_APPLY;
                   1214:             snapshot_name = optarg;
                   1215:             break;
                   1216:         case 'c':
                   1217:             if (action) {
                   1218:                 help();
1.1.1.8   root     1219:                 return 0;
1.1.1.5   root     1220:             }
                   1221:             action = SNAPSHOT_CREATE;
                   1222:             snapshot_name = optarg;
                   1223:             break;
                   1224:         case 'd':
                   1225:             if (action) {
                   1226:                 help();
1.1.1.8   root     1227:                 return 0;
1.1.1.5   root     1228:             }
                   1229:             action = SNAPSHOT_DELETE;
                   1230:             snapshot_name = optarg;
                   1231:             break;
                   1232:         }
                   1233:     }
                   1234: 
1.1.1.12  root     1235:     if (optind >= argc) {
1.1.1.5   root     1236:         help();
1.1.1.12  root     1237:     }
1.1.1.5   root     1238:     filename = argv[optind++];
                   1239: 
                   1240:     /* Open the image */
1.1.1.11  root     1241:     bs = bdrv_new_open(filename, NULL, bdrv_oflags);
                   1242:     if (!bs) {
                   1243:         return 1;
1.1.1.5   root     1244:     }
                   1245: 
                   1246:     /* Perform the requested action */
                   1247:     switch(action) {
                   1248:     case SNAPSHOT_LIST:
                   1249:         dump_snapshots(bs);
                   1250:         break;
                   1251: 
                   1252:     case SNAPSHOT_CREATE:
                   1253:         memset(&sn, 0, sizeof(sn));
                   1254:         pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
                   1255: 
                   1256:         qemu_gettimeofday(&tv);
                   1257:         sn.date_sec = tv.tv_sec;
                   1258:         sn.date_nsec = tv.tv_usec * 1000;
                   1259: 
                   1260:         ret = bdrv_snapshot_create(bs, &sn);
1.1.1.12  root     1261:         if (ret) {
                   1262:             error_report("Could not create snapshot '%s': %d (%s)",
1.1.1.5   root     1263:                 snapshot_name, ret, strerror(-ret));
1.1.1.12  root     1264:         }
1.1.1.5   root     1265:         break;
                   1266: 
                   1267:     case SNAPSHOT_APPLY:
                   1268:         ret = bdrv_snapshot_goto(bs, snapshot_name);
1.1.1.12  root     1269:         if (ret) {
                   1270:             error_report("Could not apply snapshot '%s': %d (%s)",
1.1.1.5   root     1271:                 snapshot_name, ret, strerror(-ret));
1.1.1.12  root     1272:         }
1.1.1.5   root     1273:         break;
                   1274: 
                   1275:     case SNAPSHOT_DELETE:
                   1276:         ret = bdrv_snapshot_delete(bs, snapshot_name);
1.1.1.12  root     1277:         if (ret) {
                   1278:             error_report("Could not delete snapshot '%s': %d (%s)",
1.1.1.5   root     1279:                 snapshot_name, ret, strerror(-ret));
1.1.1.12  root     1280:         }
1.1.1.5   root     1281:         break;
                   1282:     }
                   1283: 
                   1284:     /* Cleanup */
                   1285:     bdrv_delete(bs);
1.1.1.11  root     1286:     if (ret) {
                   1287:         return 1;
                   1288:     }
                   1289:     return 0;
                   1290: }
                   1291: 
                   1292: static int img_rebase(int argc, char **argv)
                   1293: {
                   1294:     BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL;
                   1295:     BlockDriver *old_backing_drv, *new_backing_drv;
                   1296:     char *filename;
1.1.1.13  root     1297:     const char *fmt, *cache, *out_basefmt, *out_baseimg;
1.1.1.11  root     1298:     int c, flags, ret;
                   1299:     int unsafe = 0;
1.1.1.13  root     1300:     int progress = 0;
1.1.1.11  root     1301: 
                   1302:     /* Parse commandline parameters */
                   1303:     fmt = NULL;
1.1.1.13  root     1304:     cache = BDRV_DEFAULT_CACHE;
1.1.1.11  root     1305:     out_baseimg = NULL;
                   1306:     out_basefmt = NULL;
                   1307:     for(;;) {
1.1.1.13  root     1308:         c = getopt(argc, argv, "uhf:F:b:pt:");
1.1.1.12  root     1309:         if (c == -1) {
1.1.1.11  root     1310:             break;
1.1.1.12  root     1311:         }
1.1.1.11  root     1312:         switch(c) {
1.1.1.12  root     1313:         case '?':
1.1.1.11  root     1314:         case 'h':
                   1315:             help();
                   1316:             return 0;
                   1317:         case 'f':
                   1318:             fmt = optarg;
                   1319:             break;
                   1320:         case 'F':
                   1321:             out_basefmt = optarg;
                   1322:             break;
                   1323:         case 'b':
                   1324:             out_baseimg = optarg;
                   1325:             break;
                   1326:         case 'u':
                   1327:             unsafe = 1;
                   1328:             break;
1.1.1.13  root     1329:         case 'p':
                   1330:             progress = 1;
                   1331:             break;
                   1332:         case 't':
                   1333:             cache = optarg;
                   1334:             break;
1.1.1.11  root     1335:         }
                   1336:     }
                   1337: 
1.1.1.13  root     1338:     if ((optind >= argc) || (!unsafe && !out_baseimg)) {
1.1.1.11  root     1339:         help();
1.1.1.12  root     1340:     }
1.1.1.11  root     1341:     filename = argv[optind++];
                   1342: 
1.1.1.13  root     1343:     qemu_progress_init(progress, 2.0);
                   1344:     qemu_progress_print(0, 100);
                   1345: 
                   1346:     flags = BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
1.1.1.14! root     1347:     ret = bdrv_parse_cache_flags(cache, &flags);
1.1.1.13  root     1348:     if (ret < 0) {
                   1349:         error_report("Invalid cache option: %s", cache);
                   1350:         return -1;
                   1351:     }
                   1352: 
1.1.1.11  root     1353:     /*
                   1354:      * Open the images.
                   1355:      *
                   1356:      * Ignore the old backing file for unsafe rebase in case we want to correct
                   1357:      * the reference to a renamed or moved backing file.
                   1358:      */
                   1359:     bs = bdrv_new_open(filename, fmt, flags);
                   1360:     if (!bs) {
                   1361:         return 1;
                   1362:     }
                   1363: 
                   1364:     /* Find the right drivers for the backing files */
                   1365:     old_backing_drv = NULL;
                   1366:     new_backing_drv = NULL;
                   1367: 
                   1368:     if (!unsafe && bs->backing_format[0] != '\0') {
                   1369:         old_backing_drv = bdrv_find_format(bs->backing_format);
                   1370:         if (old_backing_drv == NULL) {
1.1.1.12  root     1371:             error_report("Invalid format name: '%s'", bs->backing_format);
1.1.1.11  root     1372:             ret = -1;
                   1373:             goto out;
                   1374:         }
                   1375:     }
                   1376: 
                   1377:     if (out_basefmt != NULL) {
                   1378:         new_backing_drv = bdrv_find_format(out_basefmt);
                   1379:         if (new_backing_drv == NULL) {
1.1.1.12  root     1380:             error_report("Invalid format name: '%s'", out_basefmt);
1.1.1.11  root     1381:             ret = -1;
                   1382:             goto out;
                   1383:         }
                   1384:     }
                   1385: 
                   1386:     /* For safe rebasing we need to compare old and new backing file */
                   1387:     if (unsafe) {
                   1388:         /* Make the compiler happy */
                   1389:         bs_old_backing = NULL;
                   1390:         bs_new_backing = NULL;
                   1391:     } else {
                   1392:         char backing_name[1024];
                   1393: 
                   1394:         bs_old_backing = bdrv_new("old_backing");
                   1395:         bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
                   1396:         ret = bdrv_open(bs_old_backing, backing_name, BDRV_O_FLAGS,
                   1397:                         old_backing_drv);
                   1398:         if (ret) {
1.1.1.12  root     1399:             error_report("Could not open old backing file '%s'", backing_name);
1.1.1.11  root     1400:             goto out;
                   1401:         }
                   1402: 
                   1403:         bs_new_backing = bdrv_new("new_backing");
                   1404:         ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS,
                   1405:                         new_backing_drv);
                   1406:         if (ret) {
1.1.1.12  root     1407:             error_report("Could not open new backing file '%s'", out_baseimg);
1.1.1.11  root     1408:             goto out;
                   1409:         }
                   1410:     }
                   1411: 
                   1412:     /*
                   1413:      * Check each unallocated cluster in the COW file. If it is unallocated,
                   1414:      * accesses go to the backing file. We must therefore compare this cluster
                   1415:      * in the old and new backing file, and if they differ we need to copy it
                   1416:      * from the old backing file into the COW file.
                   1417:      *
                   1418:      * If qemu-img crashes during this step, no harm is done. The content of
                   1419:      * the image is the same as the original one at any time.
                   1420:      */
                   1421:     if (!unsafe) {
                   1422:         uint64_t num_sectors;
1.1.1.14! root     1423:         uint64_t old_backing_num_sectors;
        !          1424:         uint64_t new_backing_num_sectors;
1.1.1.11  root     1425:         uint64_t sector;
                   1426:         int n;
                   1427:         uint8_t * buf_old;
                   1428:         uint8_t * buf_new;
1.1.1.13  root     1429:         float local_progress;
1.1.1.11  root     1430: 
1.1.1.14! root     1431:         buf_old = qemu_blockalign(bs, IO_BUF_SIZE);
        !          1432:         buf_new = qemu_blockalign(bs, IO_BUF_SIZE);
1.1.1.11  root     1433: 
                   1434:         bdrv_get_geometry(bs, &num_sectors);
1.1.1.14! root     1435:         bdrv_get_geometry(bs_old_backing, &old_backing_num_sectors);
        !          1436:         bdrv_get_geometry(bs_new_backing, &new_backing_num_sectors);
1.1.1.11  root     1437: 
1.1.1.13  root     1438:         local_progress = (float)100 /
                   1439:             (num_sectors / MIN(num_sectors, IO_BUF_SIZE / 512));
1.1.1.11  root     1440:         for (sector = 0; sector < num_sectors; sector += n) {
                   1441: 
                   1442:             /* How many sectors can we handle with the next read? */
                   1443:             if (sector + (IO_BUF_SIZE / 512) <= num_sectors) {
                   1444:                 n = (IO_BUF_SIZE / 512);
                   1445:             } else {
                   1446:                 n = num_sectors - sector;
                   1447:             }
                   1448: 
                   1449:             /* If the cluster is allocated, we don't need to take action */
                   1450:             ret = bdrv_is_allocated(bs, sector, n, &n);
                   1451:             if (ret) {
                   1452:                 continue;
                   1453:             }
                   1454: 
1.1.1.14! root     1455:             /*
        !          1456:              * Read old and new backing file and take into consideration that
        !          1457:              * backing files may be smaller than the COW image.
        !          1458:              */
        !          1459:             if (sector >= old_backing_num_sectors) {
        !          1460:                 memset(buf_old, 0, n * BDRV_SECTOR_SIZE);
        !          1461:             } else {
        !          1462:                 if (sector + n > old_backing_num_sectors) {
        !          1463:                     n = old_backing_num_sectors - sector;
        !          1464:                 }
        !          1465: 
        !          1466:                 ret = bdrv_read(bs_old_backing, sector, buf_old, n);
        !          1467:                 if (ret < 0) {
        !          1468:                     error_report("error while reading from old backing file");
        !          1469:                     goto out;
        !          1470:                 }
1.1.1.11  root     1471:             }
1.1.1.14! root     1472: 
        !          1473:             if (sector >= new_backing_num_sectors) {
        !          1474:                 memset(buf_new, 0, n * BDRV_SECTOR_SIZE);
        !          1475:             } else {
        !          1476:                 if (sector + n > new_backing_num_sectors) {
        !          1477:                     n = new_backing_num_sectors - sector;
        !          1478:                 }
        !          1479: 
        !          1480:                 ret = bdrv_read(bs_new_backing, sector, buf_new, n);
        !          1481:                 if (ret < 0) {
        !          1482:                     error_report("error while reading from new backing file");
        !          1483:                     goto out;
        !          1484:                 }
1.1.1.11  root     1485:             }
                   1486: 
                   1487:             /* If they differ, we need to write to the COW file */
                   1488:             uint64_t written = 0;
                   1489: 
                   1490:             while (written < n) {
                   1491:                 int pnum;
                   1492: 
                   1493:                 if (compare_sectors(buf_old + written * 512,
                   1494:                     buf_new + written * 512, n - written, &pnum))
                   1495:                 {
                   1496:                     ret = bdrv_write(bs, sector + written,
                   1497:                         buf_old + written * 512, pnum);
                   1498:                     if (ret < 0) {
1.1.1.12  root     1499:                         error_report("Error while writing to COW image: %s",
1.1.1.11  root     1500:                             strerror(-ret));
                   1501:                         goto out;
                   1502:                     }
                   1503:                 }
                   1504: 
                   1505:                 written += pnum;
                   1506:             }
1.1.1.13  root     1507:             qemu_progress_print(local_progress, 100);
1.1.1.11  root     1508:         }
                   1509: 
1.1.1.14! root     1510:         qemu_vfree(buf_old);
        !          1511:         qemu_vfree(buf_new);
1.1.1.11  root     1512:     }
                   1513: 
                   1514:     /*
                   1515:      * Change the backing file. All clusters that are different from the old
                   1516:      * backing file are overwritten in the COW file now, so the visible content
                   1517:      * doesn't change when we switch the backing file.
                   1518:      */
                   1519:     ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt);
                   1520:     if (ret == -ENOSPC) {
1.1.1.12  root     1521:         error_report("Could not change the backing file to '%s': No "
                   1522:                      "space left in the file header", out_baseimg);
1.1.1.11  root     1523:     } else if (ret < 0) {
1.1.1.12  root     1524:         error_report("Could not change the backing file to '%s': %s",
1.1.1.11  root     1525:             out_baseimg, strerror(-ret));
                   1526:     }
                   1527: 
1.1.1.13  root     1528:     qemu_progress_print(100, 0);
1.1.1.11  root     1529:     /*
                   1530:      * TODO At this point it is possible to check if any clusters that are
                   1531:      * allocated in the COW file are the same in the backing file. If so, they
                   1532:      * could be dropped from the COW file. Don't do this before switching the
                   1533:      * backing file, in case of a crash this would lead to corruption.
                   1534:      */
                   1535: out:
1.1.1.13  root     1536:     qemu_progress_end();
1.1.1.11  root     1537:     /* Cleanup */
                   1538:     if (!unsafe) {
1.1.1.13  root     1539:         if (bs_old_backing != NULL) {
                   1540:             bdrv_delete(bs_old_backing);
                   1541:         }
                   1542:         if (bs_new_backing != NULL) {
                   1543:             bdrv_delete(bs_new_backing);
                   1544:         }
1.1.1.11  root     1545:     }
                   1546: 
                   1547:     bdrv_delete(bs);
                   1548:     if (ret) {
                   1549:         return 1;
                   1550:     }
                   1551:     return 0;
                   1552: }
                   1553: 
                   1554: static int img_resize(int argc, char **argv)
                   1555: {
                   1556:     int c, ret, relative;
                   1557:     const char *filename, *fmt, *size;
                   1558:     int64_t n, total_size;
1.1.1.12  root     1559:     BlockDriverState *bs = NULL;
1.1.1.11  root     1560:     QEMUOptionParameter *param;
                   1561:     QEMUOptionParameter resize_options[] = {
                   1562:         {
                   1563:             .name = BLOCK_OPT_SIZE,
                   1564:             .type = OPT_SIZE,
                   1565:             .help = "Virtual disk size"
                   1566:         },
                   1567:         { NULL }
                   1568:     };
                   1569: 
1.1.1.13  root     1570:     /* Remove size from argv manually so that negative numbers are not treated
                   1571:      * as options by getopt. */
                   1572:     if (argc < 3) {
                   1573:         help();
                   1574:         return 1;
                   1575:     }
                   1576: 
                   1577:     size = argv[--argc];
                   1578: 
                   1579:     /* Parse getopt arguments */
1.1.1.11  root     1580:     fmt = NULL;
                   1581:     for(;;) {
                   1582:         c = getopt(argc, argv, "f:h");
                   1583:         if (c == -1) {
                   1584:             break;
                   1585:         }
                   1586:         switch(c) {
1.1.1.12  root     1587:         case '?':
1.1.1.11  root     1588:         case 'h':
                   1589:             help();
                   1590:             break;
                   1591:         case 'f':
                   1592:             fmt = optarg;
                   1593:             break;
                   1594:         }
                   1595:     }
1.1.1.13  root     1596:     if (optind >= argc) {
1.1.1.11  root     1597:         help();
                   1598:     }
                   1599:     filename = argv[optind++];
                   1600: 
                   1601:     /* Choose grow, shrink, or absolute resize mode */
                   1602:     switch (size[0]) {
                   1603:     case '+':
                   1604:         relative = 1;
                   1605:         size++;
                   1606:         break;
                   1607:     case '-':
                   1608:         relative = -1;
                   1609:         size++;
                   1610:         break;
                   1611:     default:
                   1612:         relative = 0;
                   1613:         break;
                   1614:     }
                   1615: 
                   1616:     /* Parse size */
                   1617:     param = parse_option_parameters("", resize_options, NULL);
                   1618:     if (set_option_parameter(param, BLOCK_OPT_SIZE, size)) {
                   1619:         /* Error message already printed when size parsing fails */
1.1.1.12  root     1620:         ret = -1;
                   1621:         goto out;
1.1.1.11  root     1622:     }
                   1623:     n = get_option_parameter(param, BLOCK_OPT_SIZE)->value.n;
                   1624:     free_option_parameters(param);
                   1625: 
                   1626:     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
                   1627:     if (!bs) {
1.1.1.12  root     1628:         ret = -1;
                   1629:         goto out;
1.1.1.11  root     1630:     }
1.1.1.8   root     1631: 
1.1.1.11  root     1632:     if (relative) {
                   1633:         total_size = bdrv_getlength(bs) + n * relative;
                   1634:     } else {
                   1635:         total_size = n;
                   1636:     }
                   1637:     if (total_size <= 0) {
1.1.1.12  root     1638:         error_report("New image size must be positive");
1.1.1.11  root     1639:         ret = -1;
                   1640:         goto out;
                   1641:     }
                   1642: 
                   1643:     ret = bdrv_truncate(bs, total_size);
                   1644:     switch (ret) {
                   1645:     case 0:
                   1646:         printf("Image resized.\n");
                   1647:         break;
                   1648:     case -ENOTSUP:
1.1.1.12  root     1649:         error_report("This image format does not support resize");
1.1.1.11  root     1650:         break;
                   1651:     case -EACCES:
1.1.1.12  root     1652:         error_report("Image is read-only");
1.1.1.11  root     1653:         break;
                   1654:     default:
1.1.1.12  root     1655:         error_report("Error resizing image (%d)", -ret);
1.1.1.11  root     1656:         break;
                   1657:     }
                   1658: out:
1.1.1.12  root     1659:     if (bs) {
                   1660:         bdrv_delete(bs);
                   1661:     }
1.1.1.11  root     1662:     if (ret) {
                   1663:         return 1;
                   1664:     }
1.1.1.8   root     1665:     return 0;
1.1.1.5   root     1666: }
                   1667: 
1.1.1.8   root     1668: static const img_cmd_t img_cmds[] = {
                   1669: #define DEF(option, callback, arg_string)        \
                   1670:     { option, callback },
                   1671: #include "qemu-img-cmds.h"
                   1672: #undef DEF
                   1673: #undef GEN_DOCS
                   1674:     { NULL, NULL, },
                   1675: };
                   1676: 
1.1       root     1677: int main(int argc, char **argv)
                   1678: {
1.1.1.8   root     1679:     const img_cmd_t *cmd;
                   1680:     const char *cmdname;
1.1       root     1681: 
1.1.1.12  root     1682:     error_set_progname(argv[0]);
                   1683: 
1.1       root     1684:     bdrv_init();
                   1685:     if (argc < 2)
                   1686:         help();
1.1.1.8   root     1687:     cmdname = argv[1];
1.1.1.5   root     1688:     argc--; argv++;
1.1.1.8   root     1689: 
                   1690:     /* find the command */
                   1691:     for(cmd = img_cmds; cmd->name != NULL; cmd++) {
                   1692:         if (!strcmp(cmdname, cmd->name)) {
                   1693:             return cmd->handler(argc, argv);
                   1694:         }
1.1       root     1695:     }
1.1.1.8   root     1696: 
                   1697:     /* not found */
                   1698:     help();
1.1       root     1699:     return 0;
                   1700: }

unix.superglobalmegacorp.com