Statistics
| Branch: | Revision:

root / qemu-img.c @ cd5158ea

History | View | Annotate | Download (21.8 kB)

1
/*
2
 * QEMU disk image utility
3
 *
4
 * Copyright (c) 2003-2008 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "qemu-common.h"
25
#include "block_int.h"
26
#include <assert.h>
27

    
28
#ifdef _WIN32
29
#define WIN32_LEAN_AND_MEAN
30
#include <windows.h>
31
#endif
32

    
33
/* Default to cache=writeback as data integrity is not important for qemu-tcg. */
34
#define BRDV_O_FLAGS BDRV_O_CACHE_WB
35

    
36
static void __attribute__((noreturn)) error(const char *fmt, ...)
37
{
38
    va_list ap;
39
    va_start(ap, fmt);
40
    fprintf(stderr, "qemu-img: ");
41
    vfprintf(stderr, fmt, ap);
42
    fprintf(stderr, "\n");
43
    exit(1);
44
    va_end(ap);
45
}
46

    
47
static void format_print(void *opaque, const char *name)
48
{
49
    printf(" %s", name);
50
}
51

    
52
static void help(void)
53
{
54
    printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
55
           "usage: qemu-img command [command options]\n"
56
           "QEMU disk image utility\n"
57
           "\n"
58
           "Command syntax:\n"
59
           "  create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n"
60
           "  commit [-f fmt] filename\n"
61
           "  convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n"
62
           "  info [-f fmt] filename\n"
63
           "\n"
64
           "Command parameters:\n"
65
           "  'filename' is a disk image filename\n"
66
           "  'base_image' is the read-only disk image which is used as base for a copy on\n"
67
           "    write image; the copy on write image only stores the modified data\n"
68
           "  'output_base_image' forces the output image to be created as a copy on write\n"
69
           "    image of the specified base image; 'output_base_image' should have the same\n"
70
           "    content as the input's base image, however the path, image format, etc may\n"
71
           "    differ\n"
72
           "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
73
           "  'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n"
74
           "    and 'G' (gigabyte) are supported\n"
75
           "  'output_filename' is the destination disk image filename\n"
76
           "  'output_fmt' is the destination format\n"
77
           "  '-c' indicates that target image must be compressed (qcow format only)\n"
78
           "  '-e' indicates that the target image must be encrypted (qcow format only)\n"
79
           "  '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"
80
           );
81
    printf("\nSupported format:");
82
    bdrv_iterate_format(format_print, NULL);
83
    printf("\n");
84
    exit(1);
85
}
86

    
87
#if defined(WIN32)
88
/* XXX: put correct support for win32 */
89
static int read_password(char *buf, int buf_size)
90
{
91
    int c, i;
92
    printf("Password: ");
93
    fflush(stdout);
94
    i = 0;
95
    for(;;) {
96
        c = getchar();
97
        if (c == '\n')
98
            break;
99
        if (i < (buf_size - 1))
100
            buf[i++] = c;
101
    }
102
    buf[i] = '\0';
103
    return 0;
104
}
105

    
106
#else
107

    
108
#include <termios.h>
109

    
110
static struct termios oldtty;
111

    
112
static void term_exit(void)
113
{
114
    tcsetattr (0, TCSANOW, &oldtty);
115
}
116

    
117
static void term_init(void)
118
{
119
    struct termios tty;
120

    
121
    tcgetattr (0, &tty);
122
    oldtty = tty;
123

    
124
    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
125
                          |INLCR|IGNCR|ICRNL|IXON);
126
    tty.c_oflag |= OPOST;
127
    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
128
    tty.c_cflag &= ~(CSIZE|PARENB);
129
    tty.c_cflag |= CS8;
130
    tty.c_cc[VMIN] = 1;
131
    tty.c_cc[VTIME] = 0;
132

    
133
    tcsetattr (0, TCSANOW, &tty);
134

    
135
    atexit(term_exit);
136
}
137

    
138
static int read_password(char *buf, int buf_size)
139
{
140
    uint8_t ch;
141
    int i, ret;
142

    
143
    printf("password: ");
144
    fflush(stdout);
145
    term_init();
146
    i = 0;
147
    for(;;) {
148
        ret = read(0, &ch, 1);
149
        if (ret == -1) {
150
            if (errno == EAGAIN || errno == EINTR) {
151
                continue;
152
            } else {
153
                ret = -1;
154
                break;
155
            }
156
        } else if (ret == 0) {
157
            ret = -1;
158
            break;
159
        } else {
160
            if (ch == '\r') {
161
                ret = 0;
162
                break;
163
            }
164
            if (i < (buf_size - 1))
165
                buf[i++] = ch;
166
        }
167
    }
168
    term_exit();
169
    buf[i] = '\0';
170
    printf("\n");
171
    return ret;
172
}
173
#endif
174

    
175
static BlockDriverState *bdrv_new_open(const char *filename,
176
                                       const char *fmt)
177
{
178
    BlockDriverState *bs;
179
    BlockDriver *drv;
180
    char password[256];
181

    
182
    bs = bdrv_new("");
183
    if (!bs)
184
        error("Not enough memory");
185
    if (fmt) {
186
        drv = bdrv_find_format(fmt);
187
        if (!drv)
188
            error("Unknown file format '%s'", fmt);
189
    } else {
190
        drv = NULL;
191
    }
192
    if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
193
        error("Could not open '%s'", filename);
194
    }
195
    if (bdrv_is_encrypted(bs)) {
196
        printf("Disk image '%s' is encrypted.\n", filename);
197
        if (read_password(password, sizeof(password)) < 0)
198
            error("No password given");
199
        if (bdrv_set_key(bs, password) < 0)
200
            error("invalid password");
201
    }
202
    return bs;
203
}
204

    
205
static int img_create(int argc, char **argv)
206
{
207
    int c, ret, flags;
208
    const char *fmt = "raw";
209
    const char *filename;
210
    const char *base_filename = NULL;
211
    uint64_t size;
212
    const char *p;
213
    BlockDriver *drv;
214

    
215
    flags = 0;
216
    for(;;) {
217
        c = getopt(argc, argv, "b:f:he6");
218
        if (c == -1)
219
            break;
220
        switch(c) {
221
        case 'h':
222
            help();
223
            break;
224
        case 'b':
225
            base_filename = optarg;
226
            break;
227
        case 'f':
228
            fmt = optarg;
229
            break;
230
        case 'e':
231
            flags |= BLOCK_FLAG_ENCRYPT;
232
            break;
233
        case '6':
234
            flags |= BLOCK_FLAG_COMPAT6;
235
            break;
236
        }
237
    }
238
    if (optind >= argc)
239
        help();
240
    filename = argv[optind++];
241
    size = 0;
242
    if (base_filename) {
243
        BlockDriverState *bs;
244
        bs = bdrv_new_open(base_filename, NULL);
245
        bdrv_get_geometry(bs, &size);
246
        size *= 512;
247
        bdrv_delete(bs);
248
    } else {
249
        if (optind >= argc)
250
            help();
251
        p = argv[optind];
252
        size = strtoul(p, (char **)&p, 0);
253
        if (*p == 'M') {
254
            size *= 1024 * 1024;
255
        } else if (*p == 'G') {
256
            size *= 1024 * 1024 * 1024;
257
        } else if (*p == 'k' || *p == 'K' || *p == '\0') {
258
            size *= 1024;
259
        } else {
260
            help();
261
        }
262
    }
263
    drv = bdrv_find_format(fmt);
264
    if (!drv)
265
        error("Unknown file format '%s'", fmt);
266
    printf("Formatting '%s', fmt=%s",
267
           filename, fmt);
268
    if (flags & BLOCK_FLAG_ENCRYPT)
269
        printf(", encrypted");
270
    if (flags & BLOCK_FLAG_COMPAT6)
271
        printf(", compatibility level=6");
272
    if (base_filename) {
273
        printf(", backing_file=%s",
274
               base_filename);
275
    }
276
    printf(", size=%" PRIu64 " kB\n", size / 1024);
277
    ret = bdrv_create(drv, filename, size / 512, base_filename, flags);
278
    if (ret < 0) {
279
        if (ret == -ENOTSUP) {
280
            error("Formatting or formatting option not supported for file format '%s'", fmt);
281
        } else {
282
            error("Error while formatting");
283
        }
284
    }
285
    return 0;
286
}
287

    
288
static int img_commit(int argc, char **argv)
289
{
290
    int c, ret;
291
    const char *filename, *fmt;
292
    BlockDriver *drv;
293
    BlockDriverState *bs;
294

    
295
    fmt = NULL;
296
    for(;;) {
297
        c = getopt(argc, argv, "f:h");
298
        if (c == -1)
299
            break;
300
        switch(c) {
301
        case 'h':
302
            help();
303
            break;
304
        case 'f':
305
            fmt = optarg;
306
            break;
307
        }
308
    }
309
    if (optind >= argc)
310
        help();
311
    filename = argv[optind++];
312

    
313
    bs = bdrv_new("");
314
    if (!bs)
315
        error("Not enough memory");
316
    if (fmt) {
317
        drv = bdrv_find_format(fmt);
318
        if (!drv)
319
            error("Unknown file format '%s'", fmt);
320
    } else {
321
        drv = NULL;
322
    }
323
    if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
324
        error("Could not open '%s'", filename);
325
    }
326
    ret = bdrv_commit(bs);
327
    switch(ret) {
328
    case 0:
329
        printf("Image committed.\n");
330
        break;
331
    case -ENOENT:
332
        error("No disk inserted");
333
        break;
334
    case -EACCES:
335
        error("Image is read-only");
336
        break;
337
    case -ENOTSUP:
338
        error("Image is already committed");
339
        break;
340
    default:
341
        error("Error while committing image");
342
        break;
343
    }
344

    
345
    bdrv_delete(bs);
346
    return 0;
347
}
348

    
349
static int is_not_zero(const uint8_t *sector, int len)
350
{
351
    int i;
352
    len >>= 2;
353
    for(i = 0;i < len; i++) {
354
        if (((uint32_t *)sector)[i] != 0)
355
            return 1;
356
    }
357
    return 0;
358
}
359

    
360
/*
361
 * Returns true iff the first sector pointed to by 'buf' contains at least
362
 * a non-NUL byte.
363
 *
364
 * 'pnum' is set to the number of sectors (including and immediately following
365
 * the first one) that are known to be in the same allocated/unallocated state.
366
 */
367
static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
368
{
369
    int v, i;
370

    
371
    if (n <= 0) {
372
        *pnum = 0;
373
        return 0;
374
    }
375
    v = is_not_zero(buf, 512);
376
    for(i = 1; i < n; i++) {
377
        buf += 512;
378
        if (v != is_not_zero(buf, 512))
379
            break;
380
    }
381
    *pnum = i;
382
    return v;
383
}
384

    
385
#define IO_BUF_SIZE 65536
386

    
387
static int img_convert(int argc, char **argv)
388
{
389
    int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
390
    const char *fmt, *out_fmt, *out_baseimg, *out_filename;
391
    BlockDriver *drv;
392
    BlockDriverState **bs, *out_bs;
393
    int64_t total_sectors, nb_sectors, sector_num, bs_offset;
394
    uint64_t bs_sectors;
395
    uint8_t buf[IO_BUF_SIZE];
396
    const uint8_t *buf1;
397
    BlockDriverInfo bdi;
398

    
399
    fmt = NULL;
400
    out_fmt = "raw";
401
    out_baseimg = NULL;
402
    flags = 0;
403
    for(;;) {
404
        c = getopt(argc, argv, "f:O:B:hce6");
405
        if (c == -1)
406
            break;
407
        switch(c) {
408
        case 'h':
409
            help();
410
            break;
411
        case 'f':
412
            fmt = optarg;
413
            break;
414
        case 'O':
415
            out_fmt = optarg;
416
            break;
417
        case 'B':
418
            out_baseimg = optarg;
419
            break;
420
        case 'c':
421
            flags |= BLOCK_FLAG_COMPRESS;
422
            break;
423
        case 'e':
424
            flags |= BLOCK_FLAG_ENCRYPT;
425
            break;
426
        case '6':
427
            flags |= BLOCK_FLAG_COMPAT6;
428
            break;
429
        }
430
    }
431

    
432
    bs_n = argc - optind - 1;
433
    if (bs_n < 1) help();
434

    
435
    out_filename = argv[argc - 1];
436

    
437
    if (bs_n > 1 && out_baseimg)
438
        error("-B makes no sense when concatenating multiple input images");
439
        
440
    bs = calloc(bs_n, sizeof(BlockDriverState *));
441
    if (!bs)
442
        error("Out of memory");
443

    
444
    total_sectors = 0;
445
    for (bs_i = 0; bs_i < bs_n; bs_i++) {
446
        bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
447
        if (!bs[bs_i])
448
            error("Could not open '%s'", argv[optind + bs_i]);
449
        bdrv_get_geometry(bs[bs_i], &bs_sectors);
450
        total_sectors += bs_sectors;
451
    }
452

    
453
    drv = bdrv_find_format(out_fmt);
454
    if (!drv)
455
        error("Unknown file format '%s'", out_fmt);
456
    if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
457
        error("Compression not supported for this file format");
458
    if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
459
        error("Encryption not supported for this file format");
460
    if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk)
461
        error("Alternative compatibility level not supported for this file format");
462
    if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
463
        error("Compression and encryption not supported at the same time");
464

    
465
    ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
466
    if (ret < 0) {
467
        if (ret == -ENOTSUP) {
468
            error("Formatting not supported for file format '%s'", fmt);
469
        } else {
470
            error("Error while formatting '%s'", out_filename);
471
        }
472
    }
473

    
474
    out_bs = bdrv_new_open(out_filename, out_fmt);
475

    
476
    bs_i = 0;
477
    bs_offset = 0;
478
    bdrv_get_geometry(bs[0], &bs_sectors);
479

    
480
    if (flags & BLOCK_FLAG_COMPRESS) {
481
        if (bdrv_get_info(out_bs, &bdi) < 0)
482
            error("could not get block driver info");
483
        cluster_size = bdi.cluster_size;
484
        if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
485
            error("invalid cluster size");
486
        cluster_sectors = cluster_size >> 9;
487
        sector_num = 0;
488
        for(;;) {
489
            int64_t bs_num;
490
            int remainder;
491
            uint8_t *buf2;
492

    
493
            nb_sectors = total_sectors - sector_num;
494
            if (nb_sectors <= 0)
495
                break;
496
            if (nb_sectors >= cluster_sectors)
497
                n = cluster_sectors;
498
            else
499
                n = nb_sectors;
500

    
501
            bs_num = sector_num - bs_offset;
502
            assert (bs_num >= 0);
503
            remainder = n;
504
            buf2 = buf;
505
            while (remainder > 0) {
506
                int nlow;
507
                while (bs_num == bs_sectors) {
508
                    bs_i++;
509
                    assert (bs_i < bs_n);
510
                    bs_offset += bs_sectors;
511
                    bdrv_get_geometry(bs[bs_i], &bs_sectors);
512
                    bs_num = 0;
513
                    /* printf("changing part: sector_num=%lld, "
514
                       "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
515
                       sector_num, bs_i, bs_offset, bs_sectors); */
516
                }
517
                assert (bs_num < bs_sectors);
518

    
519
                nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
520

    
521
                if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) 
522
                    error("error while reading");
523

    
524
                buf2 += nlow * 512;
525
                bs_num += nlow;
526

    
527
                remainder -= nlow;
528
            }
529
            assert (remainder == 0);
530

    
531
            if (n < cluster_sectors)
532
                memset(buf + n * 512, 0, cluster_size - n * 512);
533
            if (is_not_zero(buf, cluster_size)) {
534
                if (bdrv_write_compressed(out_bs, sector_num, buf,
535
                                          cluster_sectors) != 0)
536
                    error("error while compressing sector %" PRId64,
537
                          sector_num);
538
            }
539
            sector_num += n;
540
        }
541
        /* signal EOF to align */
542
        bdrv_write_compressed(out_bs, 0, NULL, 0);
543
    } else {
544
        sector_num = 0; // total number of sectors converted so far
545
        for(;;) {
546
            nb_sectors = total_sectors - sector_num;
547
            if (nb_sectors <= 0)
548
                break;
549
            if (nb_sectors >= (IO_BUF_SIZE / 512))
550
                n = (IO_BUF_SIZE / 512);
551
            else
552
                n = nb_sectors;
553

    
554
            while (sector_num - bs_offset >= bs_sectors) {
555
                bs_i ++;
556
                assert (bs_i < bs_n);
557
                bs_offset += bs_sectors;
558
                bdrv_get_geometry(bs[bs_i], &bs_sectors);
559
                /* printf("changing part: sector_num=%lld, bs_i=%d, "
560
                  "bs_offset=%lld, bs_sectors=%lld\n",
561
                   sector_num, bs_i, bs_offset, bs_sectors); */
562
            }
563

    
564
            if (n > bs_offset + bs_sectors - sector_num)
565
                n = bs_offset + bs_sectors - sector_num;
566

    
567
            /* If the output image is being created as a copy on write image,
568
               assume that sectors which are unallocated in the input image
569
               are present in both the output's and input's base images (no
570
               need to copy them). */
571
            if (out_baseimg) {
572
               if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) {
573
                  sector_num += n1;
574
                  continue;
575
               }
576
               /* The next 'n1' sectors are allocated in the input image. Copy
577
                  only those as they may be followed by unallocated sectors. */
578
               n = n1;
579
            }
580

    
581
            if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) 
582
                error("error while reading");
583
            /* NOTE: at the same time we convert, we do not write zero
584
               sectors to have a chance to compress the image. Ideally, we
585
               should add a specific call to have the info to go faster */
586
            buf1 = buf;
587
            while (n > 0) {
588
                /* If the output image is being created as a copy on write image,
589
                   copy all sectors even the ones containing only NUL bytes,
590
                   because they may differ from the sectors in the base image. */
591
                if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) {
592
                    if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
593
                        error("error while writing");
594
                }
595
                sector_num += n1;
596
                n -= n1;
597
                buf1 += n1 * 512;
598
            }
599
        }
600
    }
601
    bdrv_delete(out_bs);
602
    for (bs_i = 0; bs_i < bs_n; bs_i++)
603
        bdrv_delete(bs[bs_i]);
604
    free(bs);
605
    return 0;
606
}
607

    
608
#ifdef _WIN32
609
static int64_t get_allocated_file_size(const char *filename)
610
{
611
    typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
612
    get_compressed_t get_compressed;
613
    struct _stati64 st;
614

    
615
    /* WinNT support GetCompressedFileSize to determine allocate size */
616
    get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
617
    if (get_compressed) {
618
            DWORD high, low;
619
            low = get_compressed(filename, &high);
620
            if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
621
            return (((int64_t) high) << 32) + low;
622
    }
623

    
624
    if (_stati64(filename, &st) < 0)
625
        return -1;
626
    return st.st_size;
627
}
628
#else
629
static int64_t get_allocated_file_size(const char *filename)
630
{
631
    struct stat st;
632
    if (stat(filename, &st) < 0)
633
        return -1;
634
    return (int64_t)st.st_blocks * 512;
635
}
636
#endif
637

    
638
static void dump_snapshots(BlockDriverState *bs)
639
{
640
    QEMUSnapshotInfo *sn_tab, *sn;
641
    int nb_sns, i;
642
    char buf[256];
643

    
644
    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
645
    if (nb_sns <= 0)
646
        return;
647
    printf("Snapshot list:\n");
648
    printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
649
    for(i = 0; i < nb_sns; i++) {
650
        sn = &sn_tab[i];
651
        printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
652
    }
653
    qemu_free(sn_tab);
654
}
655

    
656
static int img_info(int argc, char **argv)
657
{
658
    int c;
659
    const char *filename, *fmt;
660
    BlockDriver *drv;
661
    BlockDriverState *bs;
662
    char fmt_name[128], size_buf[128], dsize_buf[128];
663
    uint64_t total_sectors;
664
    int64_t allocated_size;
665
    char backing_filename[1024];
666
    char backing_filename2[1024];
667
    BlockDriverInfo bdi;
668

    
669
    fmt = NULL;
670
    for(;;) {
671
        c = getopt(argc, argv, "f:h");
672
        if (c == -1)
673
            break;
674
        switch(c) {
675
        case 'h':
676
            help();
677
            break;
678
        case 'f':
679
            fmt = optarg;
680
            break;
681
        }
682
    }
683
    if (optind >= argc)
684
        help();
685
    filename = argv[optind++];
686

    
687
    bs = bdrv_new("");
688
    if (!bs)
689
        error("Not enough memory");
690
    if (fmt) {
691
        drv = bdrv_find_format(fmt);
692
        if (!drv)
693
            error("Unknown file format '%s'", fmt);
694
    } else {
695
        drv = NULL;
696
    }
697
    if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
698
        error("Could not open '%s'", filename);
699
    }
700
    bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
701
    bdrv_get_geometry(bs, &total_sectors);
702
    get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
703
    allocated_size = get_allocated_file_size(filename);
704
    if (allocated_size < 0)
705
        snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
706
    else
707
        get_human_readable_size(dsize_buf, sizeof(dsize_buf),
708
                                allocated_size);
709
    printf("image: %s\n"
710
           "file format: %s\n"
711
           "virtual size: %s (%" PRId64 " bytes)\n"
712
           "disk size: %s\n",
713
           filename, fmt_name, size_buf,
714
           (total_sectors * 512),
715
           dsize_buf);
716
    if (bdrv_is_encrypted(bs))
717
        printf("encrypted: yes\n");
718
    if (bdrv_get_info(bs, &bdi) >= 0) {
719
        if (bdi.cluster_size != 0)
720
            printf("cluster_size: %d\n", bdi.cluster_size);
721
    }
722
    bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
723
    if (backing_filename[0] != '\0') {
724
        path_combine(backing_filename2, sizeof(backing_filename2),
725
                     filename, backing_filename);
726
        printf("backing file: %s (actual path: %s)\n",
727
               backing_filename,
728
               backing_filename2);
729
    }
730
    dump_snapshots(bs);
731
    bdrv_delete(bs);
732
    return 0;
733
}
734

    
735
int main(int argc, char **argv)
736
{
737
    const char *cmd;
738

    
739
    bdrv_init();
740
    if (argc < 2)
741
        help();
742
    cmd = argv[1];
743
    optind++;
744
    if (!strcmp(cmd, "create")) {
745
        img_create(argc, argv);
746
    } else if (!strcmp(cmd, "commit")) {
747
        img_commit(argc, argv);
748
    } else if (!strcmp(cmd, "convert")) {
749
        img_convert(argc, argv);
750
    } else if (!strcmp(cmd, "info")) {
751
        img_info(argc, argv);
752
    } else {
753
        help();
754
    }
755
    return 0;
756
}