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

1.1     ! root        1: /*
        !             2:  * create a COW disk image
        !             3:  * 
        !             4:  * Copyright (c) 2003 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 "vl.h"
        !            25: 
        !            26: void *get_mmap_addr(unsigned long size)
        !            27: {
        !            28:     return NULL;
        !            29: }
        !            30: 
        !            31: void qemu_free(void *ptr)
        !            32: {
        !            33:     free(ptr);
        !            34: }
        !            35: 
        !            36: void *qemu_malloc(size_t size)
        !            37: {
        !            38:     return malloc(size);
        !            39: }
        !            40: 
        !            41: void *qemu_mallocz(size_t size)
        !            42: {
        !            43:     void *ptr;
        !            44:     ptr = qemu_malloc(size);
        !            45:     if (!ptr)
        !            46:         return NULL;
        !            47:     memset(ptr, 0, size);
        !            48:     return ptr;
        !            49: }
        !            50: 
        !            51: char *qemu_strdup(const char *str)
        !            52: {
        !            53:     char *ptr;
        !            54:     ptr = qemu_malloc(strlen(str) + 1);
        !            55:     if (!ptr)
        !            56:         return NULL;
        !            57:     strcpy(ptr, str);
        !            58:     return ptr;
        !            59: }
        !            60: 
        !            61: void pstrcpy(char *buf, int buf_size, const char *str)
        !            62: {
        !            63:     int c;
        !            64:     char *q = buf;
        !            65: 
        !            66:     if (buf_size <= 0)
        !            67:         return;
        !            68: 
        !            69:     for(;;) {
        !            70:         c = *str++;
        !            71:         if (c == 0 || q >= buf + buf_size - 1)
        !            72:             break;
        !            73:         *q++ = c;
        !            74:     }
        !            75:     *q = '\0';
        !            76: }
        !            77: 
        !            78: /* strcat and truncate. */
        !            79: char *pstrcat(char *buf, int buf_size, const char *s)
        !            80: {
        !            81:     int len;
        !            82:     len = strlen(buf);
        !            83:     if (len < buf_size) 
        !            84:         pstrcpy(buf + len, buf_size - len, s);
        !            85:     return buf;
        !            86: }
        !            87: 
        !            88: int strstart(const char *str, const char *val, const char **ptr)
        !            89: {
        !            90:     const char *p, *q;
        !            91:     p = str;
        !            92:     q = val;
        !            93:     while (*q != '\0') {
        !            94:         if (*p != *q)
        !            95:             return 0;
        !            96:         p++;
        !            97:         q++;
        !            98:     }
        !            99:     if (ptr)
        !           100:         *ptr = p;
        !           101:     return 1;
        !           102: }
        !           103: 
        !           104: void term_printf(const char *fmt, ...)
        !           105: {
        !           106:     va_list ap;
        !           107:     va_start(ap, fmt);
        !           108:     vprintf(fmt, ap);
        !           109:     va_end(ap);
        !           110: }
        !           111: 
        !           112: void __attribute__((noreturn)) error(const char *fmt, ...) 
        !           113: {
        !           114:     va_list ap;
        !           115:     va_start(ap, fmt);
        !           116:     fprintf(stderr, "qemu-img: ");
        !           117:     vfprintf(stderr, fmt, ap);
        !           118:     fprintf(stderr, "\n");
        !           119:     exit(1);
        !           120:     va_end(ap);
        !           121: }
        !           122: 
        !           123: static void format_print(void *opaque, const char *name)
        !           124: {
        !           125:     printf(" %s", name);
        !           126: }
        !           127: 
        !           128: void help(void)
        !           129: {
        !           130:     printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2005 Fabrice Bellard\n"
        !           131:            "usage: qemu-img command [command options]\n"
        !           132:            "QEMU disk image utility\n"
        !           133:            "\n"
        !           134:            "Command syntax:\n"
        !           135:            "  create [-e] [-b base_image] [-f fmt] filename [size]\n"
        !           136:            "  commit [-f fmt] filename\n"
        !           137:            "  convert [-c] [-e] [-f fmt] filename [-O output_fmt] output_filename\n"
        !           138:            "  info [-f fmt] filename\n"
        !           139:            "\n"
        !           140:            "Command parameters:\n"
        !           141:            "  'filename' is a disk image filename\n"
        !           142:            "  'base_image' is the read-only disk image which is used as base for a copy on\n"
        !           143:            "    write image; the copy on write image only stores the modified data\n"
        !           144:            "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
        !           145:            "  'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n"
        !           146:            "    and 'G' (gigabyte) are supported\n"
        !           147:            "  'output_filename' is the destination disk image filename\n"
        !           148:            "  'output_fmt' is the destination format\n"
        !           149:            "  '-c' indicates that target image must be compressed (qcow format only)\n"
        !           150:            "  '-e' indicates that the target image must be encrypted (qcow format only)\n"
        !           151:            );
        !           152:     printf("\nSupported format:");
        !           153:     bdrv_iterate_format(format_print, NULL);
        !           154:     printf("\n");
        !           155:     exit(1);
        !           156: }
        !           157: 
        !           158: 
        !           159: #define NB_SUFFIXES 4
        !           160: 
        !           161: static void get_human_readable_size(char *buf, int buf_size, int64_t size)
        !           162: {
        !           163:     char suffixes[NB_SUFFIXES] = "KMGT";
        !           164:     int64_t base;
        !           165:     int i;
        !           166: 
        !           167:     if (size <= 999) {
        !           168:         snprintf(buf, buf_size, "%lld", (long long) size);
        !           169:     } else {
        !           170:         base = 1024;
        !           171:         for(i = 0; i < NB_SUFFIXES; i++) {
        !           172:             if (size < (10 * base)) {
        !           173:                 snprintf(buf, buf_size, "%0.1f%c", 
        !           174:                          (double)size / base,
        !           175:                          suffixes[i]);
        !           176:                 break;
        !           177:             } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) {
        !           178:                 snprintf(buf, buf_size, "%lld%c", 
        !           179:                          (long long) ((size + (base >> 1)) / base),
        !           180:                          suffixes[i]);
        !           181:                 break;
        !           182:             }
        !           183:             base = base * 1024;
        !           184:         }
        !           185:     }
        !           186: }
        !           187: 
        !           188: #if defined(WIN32)
        !           189: /* XXX: put correct support for win32 */
        !           190: static int read_password(char *buf, int buf_size)
        !           191: {
        !           192:     int c, i;
        !           193:     printf("Password: ");
        !           194:     fflush(stdout);
        !           195:     i = 0;
        !           196:     for(;;) {
        !           197:         c = getchar();
        !           198:         if (c == '\n')
        !           199:             break;
        !           200:         if (i < (buf_size - 1))
        !           201:             buf[i++] = c;
        !           202:     }
        !           203:     buf[i] = '\0';
        !           204:     return 0;
        !           205: }
        !           206: 
        !           207: #else
        !           208: 
        !           209: #include <termios.h>
        !           210: 
        !           211: static struct termios oldtty;
        !           212: 
        !           213: static void term_exit(void)
        !           214: {
        !           215:     tcsetattr (0, TCSANOW, &oldtty);
        !           216: }
        !           217: 
        !           218: static void term_init(void)
        !           219: {
        !           220:     struct termios tty;
        !           221: 
        !           222:     tcgetattr (0, &tty);
        !           223:     oldtty = tty;
        !           224: 
        !           225:     tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
        !           226:                           |INLCR|IGNCR|ICRNL|IXON);
        !           227:     tty.c_oflag |= OPOST;
        !           228:     tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
        !           229:     tty.c_cflag &= ~(CSIZE|PARENB);
        !           230:     tty.c_cflag |= CS8;
        !           231:     tty.c_cc[VMIN] = 1;
        !           232:     tty.c_cc[VTIME] = 0;
        !           233:     
        !           234:     tcsetattr (0, TCSANOW, &tty);
        !           235: 
        !           236:     atexit(term_exit);
        !           237: }
        !           238: 
        !           239: int read_password(char *buf, int buf_size)
        !           240: {
        !           241:     uint8_t ch;
        !           242:     int i, ret;
        !           243: 
        !           244:     printf("password: ");
        !           245:     fflush(stdout);
        !           246:     term_init();
        !           247:     i = 0;
        !           248:     for(;;) {
        !           249:         ret = read(0, &ch, 1);
        !           250:         if (ret == -1) {
        !           251:             if (errno == EAGAIN || errno == EINTR) {
        !           252:                 continue;
        !           253:             } else {
        !           254:                 ret = -1;
        !           255:                 break;
        !           256:             }
        !           257:         } else if (ret == 0) {
        !           258:             ret = -1;
        !           259:             break;
        !           260:         } else {
        !           261:             if (ch == '\r') {
        !           262:                 ret = 0;
        !           263:                 break;
        !           264:             }
        !           265:             if (i < (buf_size - 1))
        !           266:                 buf[i++] = ch;
        !           267:         }
        !           268:     }
        !           269:     term_exit();
        !           270:     buf[i] = '\0';
        !           271:     printf("\n");
        !           272:     return ret;
        !           273: }
        !           274: #endif
        !           275: 
        !           276: static BlockDriverState *bdrv_new_open(const char *filename,
        !           277:                                        const char *fmt)
        !           278: {
        !           279:     BlockDriverState *bs;
        !           280:     BlockDriver *drv;
        !           281:     char password[256];
        !           282: 
        !           283:     bs = bdrv_new("");
        !           284:     if (!bs)
        !           285:         error("Not enough memory");
        !           286:     if (fmt) {
        !           287:         drv = bdrv_find_format(fmt);
        !           288:         if (!drv)
        !           289:             error("Unknown file format '%s'", fmt);
        !           290:     } else {
        !           291:         drv = NULL;
        !           292:     }
        !           293:     if (bdrv_open2(bs, filename, 0, drv) < 0) {
        !           294:         error("Could not open '%s'", filename);
        !           295:     }
        !           296:     if (bdrv_is_encrypted(bs)) {
        !           297:         printf("Disk image '%s' is encrypted.\n", filename);
        !           298:         if (read_password(password, sizeof(password)) < 0)
        !           299:             error("No password given");
        !           300:         if (bdrv_set_key(bs, password) < 0)
        !           301:             error("invalid password");
        !           302:     }
        !           303:     return bs;
        !           304: }
        !           305: 
        !           306: static int img_create(int argc, char **argv)
        !           307: {
        !           308:     int c, ret, encrypted;
        !           309:     const char *fmt = "raw";
        !           310:     const char *filename;
        !           311:     const char *base_filename = NULL;
        !           312:     int64_t size;
        !           313:     const char *p;
        !           314:     BlockDriver *drv;
        !           315:     
        !           316:     encrypted = 0;
        !           317:     for(;;) {
        !           318:         c = getopt(argc, argv, "b:f:he");
        !           319:         if (c == -1)
        !           320:             break;
        !           321:         switch(c) {
        !           322:         case 'h':
        !           323:             help();
        !           324:             break;
        !           325:         case 'b':
        !           326:             base_filename = optarg;
        !           327:             break;
        !           328:         case 'f':
        !           329:             fmt = optarg;
        !           330:             break;
        !           331:         case 'e':
        !           332:             encrypted = 1;
        !           333:             break;
        !           334:         }
        !           335:     }
        !           336:     if (optind >= argc) 
        !           337:         help();
        !           338:     filename = argv[optind++];
        !           339:     size = 0;
        !           340:     if (base_filename) {
        !           341:         BlockDriverState *bs;
        !           342:         bs = bdrv_new_open(base_filename, NULL);
        !           343:         bdrv_get_geometry(bs, &size);
        !           344:         size *= 512;
        !           345:         bdrv_delete(bs);
        !           346:     } else {
        !           347:         if (optind >= argc)
        !           348:             help();
        !           349:         p = argv[optind];
        !           350:         size = strtoul(p, (char **)&p, 0);
        !           351:         if (*p == 'M') {
        !           352:             size *= 1024 * 1024;
        !           353:         } else if (*p == 'G') {
        !           354:             size *= 1024 * 1024 * 1024;
        !           355:         } else if (*p == 'k' || *p == 'K' || *p == '\0') {
        !           356:             size *= 1024;
        !           357:         } else {
        !           358:             help();
        !           359:         }
        !           360:     }
        !           361:     drv = bdrv_find_format(fmt);
        !           362:     if (!drv)
        !           363:         error("Unknown file format '%s'", fmt);
        !           364:     printf("Formating '%s', fmt=%s",
        !           365:            filename, fmt);
        !           366:     if (encrypted)
        !           367:         printf(", encrypted");
        !           368:     if (base_filename) {
        !           369:         printf(", backing_file=%s",
        !           370:                base_filename);
        !           371:     }
        !           372:     printf(", size=%lld kB\n", (long long) (size / 1024));
        !           373:     ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted);
        !           374:     if (ret < 0) {
        !           375:         if (ret == -ENOTSUP) {
        !           376:             error("Formatting or formatting option not supported for file format '%s'", fmt);
        !           377:         } else {
        !           378:             error("Error while formatting");
        !           379:         }
        !           380:     }
        !           381:     return 0;
        !           382: }
        !           383: 
        !           384: static int img_commit(int argc, char **argv)
        !           385: {
        !           386:     int c, ret;
        !           387:     const char *filename, *fmt;
        !           388:     BlockDriver *drv;
        !           389:     BlockDriverState *bs;
        !           390: 
        !           391:     fmt = NULL;
        !           392:     for(;;) {
        !           393:         c = getopt(argc, argv, "f:h");
        !           394:         if (c == -1)
        !           395:             break;
        !           396:         switch(c) {
        !           397:         case 'h':
        !           398:             help();
        !           399:             break;
        !           400:         case 'f':
        !           401:             fmt = optarg;
        !           402:             break;
        !           403:         }
        !           404:     }
        !           405:     if (optind >= argc) 
        !           406:         help();
        !           407:     filename = argv[optind++];
        !           408: 
        !           409:     bs = bdrv_new("");
        !           410:     if (!bs)
        !           411:         error("Not enough memory");
        !           412:     if (fmt) {
        !           413:         drv = bdrv_find_format(fmt);
        !           414:         if (!drv)
        !           415:             error("Unknown file format '%s'", fmt);
        !           416:     } else {
        !           417:         drv = NULL;
        !           418:     }
        !           419:     if (bdrv_open2(bs, filename, 0, drv) < 0) {
        !           420:         error("Could not open '%s'", filename);
        !           421:     }
        !           422:     ret = bdrv_commit(bs);
        !           423:     switch(ret) {
        !           424:     case 0:
        !           425:         printf("Image committed.\n");
        !           426:         break;
        !           427:     case -ENOENT:
        !           428:         error("No disk inserted");
        !           429:         break;
        !           430:     case -EACCES:
        !           431:         error("Image is read-only");
        !           432:         break;
        !           433:     case -ENOTSUP:
        !           434:         error("Image is already committed");
        !           435:         break;
        !           436:     default:
        !           437:         error("Error while committing image");
        !           438:         break;
        !           439:     }
        !           440: 
        !           441:     bdrv_delete(bs);
        !           442:     return 0;
        !           443: }
        !           444: 
        !           445: static int is_not_zero(const uint8_t *sector, int len)
        !           446: {
        !           447:     int i;
        !           448:     len >>= 2;
        !           449:     for(i = 0;i < len; i++) {
        !           450:         if (((uint32_t *)sector)[i] != 0)
        !           451:             return 1;
        !           452:     }
        !           453:     return 0;
        !           454: }
        !           455: 
        !           456: static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
        !           457: {
        !           458:     int v, i;
        !           459: 
        !           460:     if (n <= 0) {
        !           461:         *pnum = 0;
        !           462:         return 0;
        !           463:     }
        !           464:     v = is_not_zero(buf, 512);
        !           465:     for(i = 1; i < n; i++) {
        !           466:         buf += 512;
        !           467:         if (v != is_not_zero(buf, 512))
        !           468:             break;
        !           469:     }
        !           470:     *pnum = i;
        !           471:     return v;
        !           472: }
        !           473: 
        !           474: #define IO_BUF_SIZE 65536
        !           475: 
        !           476: static int img_convert(int argc, char **argv)
        !           477: {
        !           478:     int c, ret, n, n1, compress, cluster_size, cluster_sectors, encrypt;
        !           479:     const char *filename, *fmt, *out_fmt, *out_filename;
        !           480:     BlockDriver *drv;
        !           481:     BlockDriverState *bs, *out_bs;
        !           482:     int64_t total_sectors, nb_sectors, sector_num;
        !           483:     uint8_t buf[IO_BUF_SIZE];
        !           484:     const uint8_t *buf1;
        !           485: 
        !           486:     fmt = NULL;
        !           487:     out_fmt = "raw";
        !           488:     compress = 0;
        !           489:     encrypt = 0;
        !           490:     for(;;) {
        !           491:         c = getopt(argc, argv, "f:O:hce");
        !           492:         if (c == -1)
        !           493:             break;
        !           494:         switch(c) {
        !           495:         case 'h':
        !           496:             help();
        !           497:             break;
        !           498:         case 'f':
        !           499:             fmt = optarg;
        !           500:             break;
        !           501:         case 'O':
        !           502:             out_fmt = optarg;
        !           503:             break;
        !           504:         case 'c':
        !           505:             compress = 1;
        !           506:             break;
        !           507:         case 'e':
        !           508:             encrypt = 1;
        !           509:             break;
        !           510:         }
        !           511:     }
        !           512:     if (optind >= argc) 
        !           513:         help();
        !           514:     filename = argv[optind++];
        !           515:     if (optind >= argc) 
        !           516:         help();
        !           517:     out_filename = argv[optind++];
        !           518:     
        !           519:     bs = bdrv_new_open(filename, fmt);
        !           520: 
        !           521:     drv = bdrv_find_format(out_fmt);
        !           522:     if (!drv)
        !           523:         error("Unknown file format '%s'", fmt);
        !           524:     if (compress && drv != &bdrv_qcow)
        !           525:         error("Compression not supported for this file format");
        !           526:     if (encrypt && drv != &bdrv_qcow)
        !           527:         error("Encryption not supported for this file format");
        !           528:     if (compress && encrypt)
        !           529:         error("Compression and encryption not supported at the same time");
        !           530:     bdrv_get_geometry(bs, &total_sectors);
        !           531:     ret = bdrv_create(drv, out_filename, total_sectors, NULL, encrypt);
        !           532:     if (ret < 0) {
        !           533:         if (ret == -ENOTSUP) {
        !           534:             error("Formatting not supported for file format '%s'", fmt);
        !           535:         } else {
        !           536:             error("Error while formatting '%s'", out_filename);
        !           537:         }
        !           538:     }
        !           539:     
        !           540:     out_bs = bdrv_new_open(out_filename, out_fmt);
        !           541: 
        !           542:     if (compress) {
        !           543:         cluster_size = qcow_get_cluster_size(out_bs);
        !           544:         if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
        !           545:             error("invalid cluster size");
        !           546:         cluster_sectors = cluster_size >> 9;
        !           547:         sector_num = 0;
        !           548:         for(;;) {
        !           549:             nb_sectors = total_sectors - sector_num;
        !           550:             if (nb_sectors <= 0)
        !           551:                 break;
        !           552:             if (nb_sectors >= cluster_sectors)
        !           553:                 n = cluster_sectors;
        !           554:             else
        !           555:                 n = nb_sectors;
        !           556:             if (bdrv_read(bs, sector_num, buf, n) < 0) 
        !           557:                 error("error while reading");
        !           558:             if (n < cluster_sectors)
        !           559:                 memset(buf + n * 512, 0, cluster_size - n * 512);
        !           560:             if (is_not_zero(buf, cluster_size)) {
        !           561:                 if (qcow_compress_cluster(out_bs, sector_num, buf) != 0)
        !           562:                     error("error while compressing sector %lld", sector_num);
        !           563:             }
        !           564:             sector_num += n;
        !           565:         }
        !           566:     } else {
        !           567:         sector_num = 0;
        !           568:         for(;;) {
        !           569:             nb_sectors = total_sectors - sector_num;
        !           570:             if (nb_sectors <= 0)
        !           571:                 break;
        !           572:             if (nb_sectors >= (IO_BUF_SIZE / 512))
        !           573:                 n = (IO_BUF_SIZE / 512);
        !           574:             else
        !           575:                 n = nb_sectors;
        !           576:             if (bdrv_read(bs, sector_num, buf, n) < 0) 
        !           577:                 error("error while reading");
        !           578:             /* NOTE: at the same time we convert, we do not write zero
        !           579:                sectors to have a chance to compress the image. Ideally, we
        !           580:                should add a specific call to have the info to go faster */
        !           581:             buf1 = buf;
        !           582:             while (n > 0) {
        !           583:                 if (is_allocated_sectors(buf1, n, &n1)) {
        !           584:                     if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) 
        !           585:                         error("error while writing");
        !           586:                 }
        !           587:                 sector_num += n1;
        !           588:                 n -= n1;
        !           589:                 buf1 += n1 * 512;
        !           590:             }
        !           591:         }
        !           592:     }
        !           593:     bdrv_delete(out_bs);
        !           594:     bdrv_delete(bs);
        !           595:     return 0;
        !           596: }
        !           597: 
        !           598: #ifdef _WIN32
        !           599: static int64_t get_allocated_file_size(const char *filename)
        !           600: {
        !           601:     struct _stati64 st;
        !           602:     if (_stati64(filename, &st) < 0) 
        !           603:         return -1;
        !           604:     return st.st_size;
        !           605: }
        !           606: #else
        !           607: static int64_t get_allocated_file_size(const char *filename)
        !           608: {
        !           609:     struct stat st;
        !           610:     if (stat(filename, &st) < 0) 
        !           611:         return -1;
        !           612:     return (int64_t)st.st_blocks * 512;
        !           613: }
        !           614: #endif
        !           615: 
        !           616: static int img_info(int argc, char **argv)
        !           617: {
        !           618:     int c;
        !           619:     const char *filename, *fmt;
        !           620:     BlockDriver *drv;
        !           621:     BlockDriverState *bs;
        !           622:     char fmt_name[128], size_buf[128], dsize_buf[128];
        !           623:     int64_t total_sectors, allocated_size;
        !           624: 
        !           625:     fmt = NULL;
        !           626:     for(;;) {
        !           627:         c = getopt(argc, argv, "f:h");
        !           628:         if (c == -1)
        !           629:             break;
        !           630:         switch(c) {
        !           631:         case 'h':
        !           632:             help();
        !           633:             break;
        !           634:         case 'f':
        !           635:             fmt = optarg;
        !           636:             break;
        !           637:         }
        !           638:     }
        !           639:     if (optind >= argc) 
        !           640:         help();
        !           641:     filename = argv[optind++];
        !           642: 
        !           643:     bs = bdrv_new("");
        !           644:     if (!bs)
        !           645:         error("Not enough memory");
        !           646:     if (fmt) {
        !           647:         drv = bdrv_find_format(fmt);
        !           648:         if (!drv)
        !           649:             error("Unknown file format '%s'", fmt);
        !           650:     } else {
        !           651:         drv = NULL;
        !           652:     }
        !           653:     if (bdrv_open2(bs, filename, 0, drv) < 0) {
        !           654:         error("Could not open '%s'", filename);
        !           655:     }
        !           656:     bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
        !           657:     bdrv_get_geometry(bs, &total_sectors);
        !           658:     get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
        !           659:     allocated_size = get_allocated_file_size(filename);
        !           660:     if (allocated_size < 0)
        !           661:        sprintf(dsize_buf, "unavailable");
        !           662:     else
        !           663:         get_human_readable_size(dsize_buf, sizeof(dsize_buf), 
        !           664:                                 allocated_size);
        !           665:     printf("image: %s\n"
        !           666:            "file format: %s\n"
        !           667:            "virtual size: %s (%lld bytes)\n"
        !           668:            "disk size: %s\n",
        !           669:            filename, fmt_name, size_buf, 
        !           670:            (long long) (total_sectors * 512),
        !           671:            dsize_buf);
        !           672:     if (bdrv_is_encrypted(bs))
        !           673:         printf("encrypted: yes\n");
        !           674:     bdrv_delete(bs);
        !           675:     return 0;
        !           676: }
        !           677: 
        !           678: int main(int argc, char **argv)
        !           679: {
        !           680:     const char *cmd;
        !           681: 
        !           682:     bdrv_init();
        !           683:     if (argc < 2)
        !           684:         help();
        !           685:     cmd = argv[1];
        !           686:     optind++;
        !           687:     if (!strcmp(cmd, "create")) {
        !           688:         img_create(argc, argv);
        !           689:     } else if (!strcmp(cmd, "commit")) {
        !           690:         img_commit(argc, argv);
        !           691:     } else if (!strcmp(cmd, "convert")) {
        !           692:         img_convert(argc, argv);
        !           693:     } else if (!strcmp(cmd, "info")) {
        !           694:         img_info(argc, argv);
        !           695:     } else {
        !           696:         help();
        !           697:     }
        !           698:     return 0;
        !           699: }

unix.superglobalmegacorp.com