qemu/qemu-img.c
<<
>>
Prefs
   1/*
   2 * QEMU disk image utility
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24#include "qemu-common.h"
  25#include "osdep.h"
  26#include "block_int.h"
  27#include <assert.h>
  28
  29#ifdef _WIN32
  30#define WIN32_LEAN_AND_MEAN
  31#include <windows.h>
  32#endif
  33
  34/* Default to cache=writeback as data integrity is not important for qemu-tcg. */
  35#define BRDV_O_FLAGS BDRV_O_CACHE_WB
  36
  37static void QEMU_NORETURN error(const char *fmt, ...)
  38{
  39    va_list ap;
  40    va_start(ap, fmt);
  41    fprintf(stderr, "qemu-img: ");
  42    vfprintf(stderr, fmt, ap);
  43    fprintf(stderr, "\n");
  44    exit(1);
  45    va_end(ap);
  46}
  47
  48static void format_print(void *opaque, const char *name)
  49{
  50    printf(" %s", name);
  51}
  52
  53/* Please keep in synch with qemu-img.texi */
  54static void help(void)
  55{
  56    printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
  57           "usage: qemu-img command [command options]\n"
  58           "QEMU disk image utility\n"
  59           "\n"
  60           "Command syntax:\n"
  61           "  create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n"
  62           "  commit [-f fmt] filename\n"
  63           "  convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n"
  64           "  info [-f fmt] filename\n"
  65           "  snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename\n"
  66           "\n"
  67           "Command parameters:\n"
  68           "  'filename' is a disk image filename\n"
  69           "  'base_image' is the read-only disk image which is used as base for a copy on\n"
  70           "    write image; the copy on write image only stores the modified data\n"
  71           "  'output_base_image' forces the output image to be created as a copy on write\n"
  72           "    image of the specified base image; 'output_base_image' should have the same\n"
  73           "    content as the input's base image, however the path, image format, etc may\n"
  74           "    differ\n"
  75           "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
  76           "  'size' is the disk image size in kilobytes. Optional suffixes\n"
  77           "    'M' (megabyte, 1024 * 1024) and 'G' (gigabyte, 1024 * 1024 * 1024) are"
  78           "    supported any @code{k} or @code{K} is ignored\n"
  79           "  'output_filename' is the destination disk image filename\n"
  80           "  'output_fmt' is the destination format\n"
  81           "  '-c' indicates that target image must be compressed (qcow format only)\n"
  82           "  '-e' indicates that the target image must be encrypted (qcow format only)\n"
  83           "  '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"
  84           "  '-h' with or without a command shows this help and lists the supported formats\n"
  85           "\n"
  86           "Parameters to snapshot subcommand:\n"
  87           "  'snapshot' is the name of the snapshot to create, apply or delete\n"
  88           "  '-a' applies a snapshot (revert disk to saved state)\n"
  89           "  '-c' creates a snapshot\n"
  90           "  '-d' deletes a snapshot\n"
  91           "  '-l' lists all snapshots in the given image\n"
  92           );
  93    printf("\nSupported formats:");
  94    bdrv_iterate_format(format_print, NULL);
  95    printf("\n");
  96    exit(1);
  97}
  98
  99#if defined(WIN32)
 100/* XXX: put correct support for win32 */
 101static int read_password(char *buf, int buf_size)
 102{
 103    int c, i;
 104    printf("Password: ");
 105    fflush(stdout);
 106    i = 0;
 107    for(;;) {
 108        c = getchar();
 109        if (c == '\n')
 110            break;
 111        if (i < (buf_size - 1))
 112            buf[i++] = c;
 113    }
 114    buf[i] = '\0';
 115    return 0;
 116}
 117
 118#else
 119
 120#include <termios.h>
 121
 122static struct termios oldtty;
 123
 124static void term_exit(void)
 125{
 126    tcsetattr (0, TCSANOW, &oldtty);
 127}
 128
 129static void term_init(void)
 130{
 131    struct termios tty;
 132
 133    tcgetattr (0, &tty);
 134    oldtty = tty;
 135
 136    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
 137                          |INLCR|IGNCR|ICRNL|IXON);
 138    tty.c_oflag |= OPOST;
 139    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
 140    tty.c_cflag &= ~(CSIZE|PARENB);
 141    tty.c_cflag |= CS8;
 142    tty.c_cc[VMIN] = 1;
 143    tty.c_cc[VTIME] = 0;
 144
 145    tcsetattr (0, TCSANOW, &tty);
 146
 147    atexit(term_exit);
 148}
 149
 150static int read_password(char *buf, int buf_size)
 151{
 152    uint8_t ch;
 153    int i, ret;
 154
 155    printf("password: ");
 156    fflush(stdout);
 157    term_init();
 158    i = 0;
 159    for(;;) {
 160        ret = read(0, &ch, 1);
 161        if (ret == -1) {
 162            if (errno == EAGAIN || errno == EINTR) {
 163                continue;
 164            } else {
 165                ret = -1;
 166                break;
 167            }
 168        } else if (ret == 0) {
 169            ret = -1;
 170            break;
 171        } else {
 172            if (ch == '\r') {
 173                ret = 0;
 174                break;
 175            }
 176            if (i < (buf_size - 1))
 177                buf[i++] = ch;
 178        }
 179    }
 180    term_exit();
 181    buf[i] = '\0';
 182    printf("\n");
 183    return ret;
 184}
 185#endif
 186
 187static BlockDriverState *bdrv_new_open(const char *filename,
 188                                       const char *fmt)
 189{
 190    BlockDriverState *bs;
 191    BlockDriver *drv;
 192    char password[256];
 193
 194    bs = bdrv_new("");
 195    if (!bs)
 196        error("Not enough memory");
 197    if (fmt) {
 198        drv = bdrv_find_format(fmt);
 199        if (!drv)
 200            error("Unknown file format '%s'", fmt);
 201    } else {
 202        drv = NULL;
 203    }
 204    if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
 205        error("Could not open '%s'", filename);
 206    }
 207    if (bdrv_is_encrypted(bs)) {
 208        printf("Disk image '%s' is encrypted.\n", filename);
 209        if (read_password(password, sizeof(password)) < 0)
 210            error("No password given");
 211        if (bdrv_set_key(bs, password) < 0)
 212            error("invalid password");
 213    }
 214    return bs;
 215}
 216
 217static int img_create(int argc, char **argv)
 218{
 219    int c, ret, flags;
 220    const char *fmt = "raw";
 221    const char *filename;
 222    const char *base_filename = NULL;
 223    uint64_t size;
 224    const char *p;
 225    BlockDriver *drv;
 226
 227    flags = 0;
 228    for(;;) {
 229        c = getopt(argc, argv, "b:f:he6");
 230        if (c == -1)
 231            break;
 232        switch(c) {
 233        case 'h':
 234            help();
 235            break;
 236        case 'b':
 237            base_filename = optarg;
 238            break;
 239        case 'f':
 240            fmt = optarg;
 241            break;
 242        case 'e':
 243            flags |= BLOCK_FLAG_ENCRYPT;
 244            break;
 245        case '6':
 246            flags |= BLOCK_FLAG_COMPAT6;
 247            break;
 248        }
 249    }
 250    if (optind >= argc)
 251        help();
 252    filename = argv[optind++];
 253    size = 0;
 254    if (base_filename) {
 255        BlockDriverState *bs;
 256        bs = bdrv_new_open(base_filename, NULL);
 257        bdrv_get_geometry(bs, &size);
 258        size *= 512;
 259        bdrv_delete(bs);
 260    } else {
 261        if (optind >= argc)
 262            help();
 263        p = argv[optind];
 264        size = strtoul(p, (char **)&p, 0);
 265        if (*p == 'M') {
 266            size *= 1024 * 1024;
 267        } else if (*p == 'G') {
 268            size *= 1024 * 1024 * 1024;
 269        } else if (*p == 'k' || *p == 'K' || *p == '\0') {
 270            size *= 1024;
 271        } else {
 272            help();
 273        }
 274    }
 275    drv = bdrv_find_format(fmt);
 276    if (!drv)
 277        error("Unknown file format '%s'", fmt);
 278    printf("Formatting '%s', fmt=%s",
 279           filename, fmt);
 280    if (flags & BLOCK_FLAG_ENCRYPT)
 281        printf(", encrypted");
 282    if (flags & BLOCK_FLAG_COMPAT6)
 283        printf(", compatibility level=6");
 284    if (base_filename) {
 285        printf(", backing_file=%s",
 286               base_filename);
 287    }
 288    printf(", size=%" PRIu64 " kB\n", size / 1024);
 289    ret = bdrv_create(drv, filename, size / 512, base_filename, flags);
 290    if (ret < 0) {
 291        if (ret == -ENOTSUP) {
 292            error("Formatting or formatting option not supported for file format '%s'", fmt);
 293        } else {
 294            error("Error while formatting");
 295        }
 296    }
 297    return 0;
 298}
 299
 300static int img_commit(int argc, char **argv)
 301{
 302    int c, ret;
 303    const char *filename, *fmt;
 304    BlockDriver *drv;
 305    BlockDriverState *bs;
 306
 307    fmt = NULL;
 308    for(;;) {
 309        c = getopt(argc, argv, "f:h");
 310        if (c == -1)
 311            break;
 312        switch(c) {
 313        case 'h':
 314            help();
 315            break;
 316        case 'f':
 317            fmt = optarg;
 318            break;
 319        }
 320    }
 321    if (optind >= argc)
 322        help();
 323    filename = argv[optind++];
 324
 325    bs = bdrv_new("");
 326    if (!bs)
 327        error("Not enough memory");
 328    if (fmt) {
 329        drv = bdrv_find_format(fmt);
 330        if (!drv)
 331            error("Unknown file format '%s'", fmt);
 332    } else {
 333        drv = NULL;
 334    }
 335    if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
 336        error("Could not open '%s'", filename);
 337    }
 338    ret = bdrv_commit(bs);
 339    switch(ret) {
 340    case 0:
 341        printf("Image committed.\n");
 342        break;
 343    case -ENOENT:
 344        error("No disk inserted");
 345        break;
 346    case -EACCES:
 347        error("Image is read-only");
 348        break;
 349    case -ENOTSUP:
 350        error("Image is already committed");
 351        break;
 352    default:
 353        error("Error while committing image");
 354        break;
 355    }
 356
 357    bdrv_delete(bs);
 358    return 0;
 359}
 360
 361static int is_not_zero(const uint8_t *sector, int len)
 362{
 363    int i;
 364    len >>= 2;
 365    for(i = 0;i < len; i++) {
 366        if (((uint32_t *)sector)[i] != 0)
 367            return 1;
 368    }
 369    return 0;
 370}
 371
 372/*
 373 * Returns true iff the first sector pointed to by 'buf' contains at least
 374 * a non-NUL byte.
 375 *
 376 * 'pnum' is set to the number of sectors (including and immediately following
 377 * the first one) that are known to be in the same allocated/unallocated state.
 378 */
 379static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
 380{
 381    int v, i;
 382
 383    if (n <= 0) {
 384        *pnum = 0;
 385        return 0;
 386    }
 387    v = is_not_zero(buf, 512);
 388    for(i = 1; i < n; i++) {
 389        buf += 512;
 390        if (v != is_not_zero(buf, 512))
 391            break;
 392    }
 393    *pnum = i;
 394    return v;
 395}
 396
 397#define IO_BUF_SIZE 65536
 398
 399static int img_convert(int argc, char **argv)
 400{
 401    int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
 402    const char *fmt, *out_fmt, *out_baseimg, *out_filename;
 403    BlockDriver *drv;
 404    BlockDriverState **bs, *out_bs;
 405    int64_t total_sectors, nb_sectors, sector_num, bs_offset;
 406    uint64_t bs_sectors;
 407    uint8_t buf[IO_BUF_SIZE];
 408    const uint8_t *buf1;
 409    BlockDriverInfo bdi;
 410
 411    fmt = NULL;
 412    out_fmt = "raw";
 413    out_baseimg = NULL;
 414    flags = 0;
 415    for(;;) {
 416        c = getopt(argc, argv, "f:O:B:hce6");
 417        if (c == -1)
 418            break;
 419        switch(c) {
 420        case 'h':
 421            help();
 422            break;
 423        case 'f':
 424            fmt = optarg;
 425            break;
 426        case 'O':
 427            out_fmt = optarg;
 428            break;
 429        case 'B':
 430            out_baseimg = optarg;
 431            break;
 432        case 'c':
 433            flags |= BLOCK_FLAG_COMPRESS;
 434            break;
 435        case 'e':
 436            flags |= BLOCK_FLAG_ENCRYPT;
 437            break;
 438        case '6':
 439            flags |= BLOCK_FLAG_COMPAT6;
 440            break;
 441        }
 442    }
 443
 444    bs_n = argc - optind - 1;
 445    if (bs_n < 1) help();
 446
 447    out_filename = argv[argc - 1];
 448
 449    if (bs_n > 1 && out_baseimg)
 450        error("-B makes no sense when concatenating multiple input images");
 451        
 452    bs = calloc(bs_n, sizeof(BlockDriverState *));
 453    if (!bs)
 454        error("Out of memory");
 455
 456    total_sectors = 0;
 457    for (bs_i = 0; bs_i < bs_n; bs_i++) {
 458        bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
 459        if (!bs[bs_i])
 460            error("Could not open '%s'", argv[optind + bs_i]);
 461        bdrv_get_geometry(bs[bs_i], &bs_sectors);
 462        total_sectors += bs_sectors;
 463    }
 464
 465    drv = bdrv_find_format(out_fmt);
 466    if (!drv)
 467        error("Unknown file format '%s'", out_fmt);
 468    if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
 469        error("Compression not supported for this file format");
 470    if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
 471        error("Encryption not supported for this file format");
 472    if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk)
 473        error("Alternative compatibility level not supported for this file format");
 474    if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
 475        error("Compression and encryption not supported at the same time");
 476
 477    ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
 478    if (ret < 0) {
 479        if (ret == -ENOTSUP) {
 480            error("Formatting not supported for file format '%s'", fmt);
 481        } else {
 482            error("Error while formatting '%s'", out_filename);
 483        }
 484    }
 485
 486    out_bs = bdrv_new_open(out_filename, out_fmt);
 487
 488    bs_i = 0;
 489    bs_offset = 0;
 490    bdrv_get_geometry(bs[0], &bs_sectors);
 491
 492    if (flags & BLOCK_FLAG_COMPRESS) {
 493        if (bdrv_get_info(out_bs, &bdi) < 0)
 494            error("could not get block driver info");
 495        cluster_size = bdi.cluster_size;
 496        if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
 497            error("invalid cluster size");
 498        cluster_sectors = cluster_size >> 9;
 499        sector_num = 0;
 500        for(;;) {
 501            int64_t bs_num;
 502            int remainder;
 503            uint8_t *buf2;
 504
 505            nb_sectors = total_sectors - sector_num;
 506            if (nb_sectors <= 0)
 507                break;
 508            if (nb_sectors >= cluster_sectors)
 509                n = cluster_sectors;
 510            else
 511                n = nb_sectors;
 512
 513            bs_num = sector_num - bs_offset;
 514            assert (bs_num >= 0);
 515            remainder = n;
 516            buf2 = buf;
 517            while (remainder > 0) {
 518                int nlow;
 519                while (bs_num == bs_sectors) {
 520                    bs_i++;
 521                    assert (bs_i < bs_n);
 522                    bs_offset += bs_sectors;
 523                    bdrv_get_geometry(bs[bs_i], &bs_sectors);
 524                    bs_num = 0;
 525                    /* printf("changing part: sector_num=%lld, "
 526                       "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
 527                       sector_num, bs_i, bs_offset, bs_sectors); */
 528                }
 529                assert (bs_num < bs_sectors);
 530
 531                nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
 532
 533                if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) 
 534                    error("error while reading");
 535
 536                buf2 += nlow * 512;
 537                bs_num += nlow;
 538
 539                remainder -= nlow;
 540            }
 541            assert (remainder == 0);
 542
 543            if (n < cluster_sectors)
 544                memset(buf + n * 512, 0, cluster_size - n * 512);
 545            if (is_not_zero(buf, cluster_size)) {
 546                if (bdrv_write_compressed(out_bs, sector_num, buf,
 547                                          cluster_sectors) != 0)
 548                    error("error while compressing sector %" PRId64,
 549                          sector_num);
 550            }
 551            sector_num += n;
 552        }
 553        /* signal EOF to align */
 554        bdrv_write_compressed(out_bs, 0, NULL, 0);
 555    } else {
 556        sector_num = 0; // total number of sectors converted so far
 557        for(;;) {
 558            nb_sectors = total_sectors - sector_num;
 559            if (nb_sectors <= 0)
 560                break;
 561            if (nb_sectors >= (IO_BUF_SIZE / 512))
 562                n = (IO_BUF_SIZE / 512);
 563            else
 564                n = nb_sectors;
 565
 566            while (sector_num - bs_offset >= bs_sectors) {
 567                bs_i ++;
 568                assert (bs_i < bs_n);
 569                bs_offset += bs_sectors;
 570                bdrv_get_geometry(bs[bs_i], &bs_sectors);
 571                /* printf("changing part: sector_num=%lld, bs_i=%d, "
 572                  "bs_offset=%lld, bs_sectors=%lld\n",
 573                   sector_num, bs_i, bs_offset, bs_sectors); */
 574            }
 575
 576            if (n > bs_offset + bs_sectors - sector_num)
 577                n = bs_offset + bs_sectors - sector_num;
 578
 579            /* If the output image is being created as a copy on write image,
 580               assume that sectors which are unallocated in the input image
 581               are present in both the output's and input's base images (no
 582               need to copy them). */
 583            if (out_baseimg) {
 584               if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) {
 585                  sector_num += n1;
 586                  continue;
 587               }
 588               /* The next 'n1' sectors are allocated in the input image. Copy
 589                  only those as they may be followed by unallocated sectors. */
 590               n = n1;
 591            }
 592
 593            if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) 
 594                error("error while reading");
 595            /* NOTE: at the same time we convert, we do not write zero
 596               sectors to have a chance to compress the image. Ideally, we
 597               should add a specific call to have the info to go faster */
 598            buf1 = buf;
 599            while (n > 0) {
 600                /* If the output image is being created as a copy on write image,
 601                   copy all sectors even the ones containing only NUL bytes,
 602                   because they may differ from the sectors in the base image. */
 603                if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) {
 604                    if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
 605                        error("error while writing");
 606                }
 607                sector_num += n1;
 608                n -= n1;
 609                buf1 += n1 * 512;
 610            }
 611        }
 612    }
 613    bdrv_delete(out_bs);
 614    for (bs_i = 0; bs_i < bs_n; bs_i++)
 615        bdrv_delete(bs[bs_i]);
 616    free(bs);
 617    return 0;
 618}
 619
 620#ifdef _WIN32
 621static int64_t get_allocated_file_size(const char *filename)
 622{
 623    typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
 624    get_compressed_t get_compressed;
 625    struct _stati64 st;
 626
 627    /* WinNT support GetCompressedFileSize to determine allocate size */
 628    get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
 629    if (get_compressed) {
 630        DWORD high, low;
 631        low = get_compressed(filename, &high);
 632        if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
 633            return (((int64_t) high) << 32) + low;
 634    }
 635
 636    if (_stati64(filename, &st) < 0)
 637        return -1;
 638    return st.st_size;
 639}
 640#else
 641static int64_t get_allocated_file_size(const char *filename)
 642{
 643    struct stat st;
 644    if (stat(filename, &st) < 0)
 645        return -1;
 646    return (int64_t)st.st_blocks * 512;
 647}
 648#endif
 649
 650static void dump_snapshots(BlockDriverState *bs)
 651{
 652    QEMUSnapshotInfo *sn_tab, *sn;
 653    int nb_sns, i;
 654    char buf[256];
 655
 656    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
 657    if (nb_sns <= 0)
 658        return;
 659    printf("Snapshot list:\n");
 660    printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
 661    for(i = 0; i < nb_sns; i++) {
 662        sn = &sn_tab[i];
 663        printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
 664    }
 665    qemu_free(sn_tab);
 666}
 667
 668static int img_info(int argc, char **argv)
 669{
 670    int c;
 671    const char *filename, *fmt;
 672    BlockDriver *drv;
 673    BlockDriverState *bs;
 674    char fmt_name[128], size_buf[128], dsize_buf[128];
 675    uint64_t total_sectors;
 676    int64_t allocated_size;
 677    char backing_filename[1024];
 678    char backing_filename2[1024];
 679    BlockDriverInfo bdi;
 680
 681    fmt = NULL;
 682    for(;;) {
 683        c = getopt(argc, argv, "f:h");
 684        if (c == -1)
 685            break;
 686        switch(c) {
 687        case 'h':
 688            help();
 689            break;
 690        case 'f':
 691            fmt = optarg;
 692            break;
 693        }
 694    }
 695    if (optind >= argc)
 696        help();
 697    filename = argv[optind++];
 698
 699    bs = bdrv_new("");
 700    if (!bs)
 701        error("Not enough memory");
 702    if (fmt) {
 703        drv = bdrv_find_format(fmt);
 704        if (!drv)
 705            error("Unknown file format '%s'", fmt);
 706    } else {
 707        drv = NULL;
 708    }
 709    if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
 710        error("Could not open '%s'", filename);
 711    }
 712    bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
 713    bdrv_get_geometry(bs, &total_sectors);
 714    get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
 715    allocated_size = get_allocated_file_size(filename);
 716    if (allocated_size < 0)
 717        snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
 718    else
 719        get_human_readable_size(dsize_buf, sizeof(dsize_buf),
 720                                allocated_size);
 721    printf("image: %s\n"
 722           "file format: %s\n"
 723           "virtual size: %s (%" PRId64 " bytes)\n"
 724           "disk size: %s\n",
 725           filename, fmt_name, size_buf,
 726           (total_sectors * 512),
 727           dsize_buf);
 728    if (bdrv_is_encrypted(bs))
 729        printf("encrypted: yes\n");
 730    if (bdrv_get_info(bs, &bdi) >= 0) {
 731        if (bdi.cluster_size != 0)
 732            printf("cluster_size: %d\n", bdi.cluster_size);
 733        if (bdi.highest_alloc)
 734            printf("highest_alloc: %" PRId64 "\n", bdi.highest_alloc);
 735        if (bdi.num_free_bytes)
 736            printf("num_free_bytes: %" PRId64 "\n", bdi.num_free_bytes);
 737    }
 738    bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
 739    if (backing_filename[0] != '\0') {
 740        path_combine(backing_filename2, sizeof(backing_filename2),
 741                     filename, backing_filename);
 742        printf("backing file: %s (actual path: %s)\n",
 743               backing_filename,
 744               backing_filename2);
 745    }
 746    dump_snapshots(bs);
 747    bdrv_delete(bs);
 748    return 0;
 749}
 750
 751#define SNAPSHOT_LIST   1
 752#define SNAPSHOT_CREATE 2
 753#define SNAPSHOT_APPLY  3
 754#define SNAPSHOT_DELETE 4
 755
 756static void img_snapshot(int argc, char **argv)
 757{
 758    BlockDriverState *bs;
 759    QEMUSnapshotInfo sn;
 760    char *filename, *snapshot_name = NULL;
 761    int c, ret;
 762    int action = 0;
 763    qemu_timeval tv;
 764
 765    /* Parse commandline parameters */
 766    for(;;) {
 767        c = getopt(argc, argv, "la:c:d:h");
 768        if (c == -1)
 769            break;
 770        switch(c) {
 771        case 'h':
 772            help();
 773            return;
 774        case 'l':
 775            if (action) {
 776                help();
 777                return;
 778            }
 779            action = SNAPSHOT_LIST;
 780            break;
 781        case 'a':
 782            if (action) {
 783                help();
 784                return;
 785            }
 786            action = SNAPSHOT_APPLY;
 787            snapshot_name = optarg;
 788            break;
 789        case 'c':
 790            if (action) {
 791                help();
 792                return;
 793            }
 794            action = SNAPSHOT_CREATE;
 795            snapshot_name = optarg;
 796            break;
 797        case 'd':
 798            if (action) {
 799                help();
 800                return;
 801            }
 802            action = SNAPSHOT_DELETE;
 803            snapshot_name = optarg;
 804            break;
 805        }
 806    }
 807
 808    if (optind >= argc)
 809        help();
 810    filename = argv[optind++];
 811
 812    /* Open the image */
 813    bs = bdrv_new("");
 814    if (!bs)
 815        error("Not enough memory");
 816
 817    if (bdrv_open2(bs, filename, 0, NULL) < 0) {
 818        error("Could not open '%s'", filename);
 819    }
 820
 821    /* Perform the requested action */
 822    switch(action) {
 823    case SNAPSHOT_LIST:
 824        dump_snapshots(bs);
 825        break;
 826
 827    case SNAPSHOT_CREATE:
 828        memset(&sn, 0, sizeof(sn));
 829        pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
 830
 831        qemu_gettimeofday(&tv);
 832        sn.date_sec = tv.tv_sec;
 833        sn.date_nsec = tv.tv_usec * 1000;
 834
 835        ret = bdrv_snapshot_create(bs, &sn);
 836        if (ret)
 837            error("Could not create snapshot '%s': %d (%s)",
 838                snapshot_name, ret, strerror(-ret));
 839        break;
 840
 841    case SNAPSHOT_APPLY:
 842        ret = bdrv_snapshot_goto(bs, snapshot_name);
 843        if (ret)
 844            error("Could not apply snapshot '%s': %d (%s)",
 845                snapshot_name, ret, strerror(-ret));
 846        break;
 847
 848    case SNAPSHOT_DELETE:
 849        ret = bdrv_snapshot_delete(bs, snapshot_name);
 850        if (ret)
 851            error("Could not delete snapshot '%s': %d (%s)",
 852                snapshot_name, ret, strerror(-ret));
 853        break;
 854    }
 855
 856    /* Cleanup */
 857    bdrv_delete(bs);
 858}
 859
 860int main(int argc, char **argv)
 861{
 862    const char *cmd;
 863
 864    bdrv_init();
 865    if (argc < 2)
 866        help();
 867    cmd = argv[1];
 868    argc--; argv++;
 869    if (!strcmp(cmd, "create")) {
 870        img_create(argc, argv);
 871    } else if (!strcmp(cmd, "commit")) {
 872        img_commit(argc, argv);
 873    } else if (!strcmp(cmd, "convert")) {
 874        img_convert(argc, argv);
 875    } else if (!strcmp(cmd, "info")) {
 876        img_info(argc, argv);
 877    } else if (!strcmp(cmd, "snapshot")) {
 878        img_snapshot(argc, argv);
 879    } else {
 880        help();
 881    }
 882    return 0;
 883}
 884