Statistics
| Branch: | Revision:

root / qemu-img.c @ e1c5a2b3

History | View | Annotate | Download (24.9 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 "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

    
37
static void __attribute__((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

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

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

    
96
#if defined(WIN32)
97
/* XXX: put correct support for win32 */
98
static int read_password(char *buf, int buf_size)
99
{
100
    int c, i;
101
    printf("Password: ");
102
    fflush(stdout);
103
    i = 0;
104
    for(;;) {
105
        c = getchar();
106
        if (c == '\n')
107
            break;
108
        if (i < (buf_size - 1))
109
            buf[i++] = c;
110
    }
111
    buf[i] = '\0';
112
    return 0;
113
}
114

    
115
#else
116

    
117
#include <termios.h>
118

    
119
static struct termios oldtty;
120

    
121
static void term_exit(void)
122
{
123
    tcsetattr (0, TCSANOW, &oldtty);
124
}
125

    
126
static void term_init(void)
127
{
128
    struct termios tty;
129

    
130
    tcgetattr (0, &tty);
131
    oldtty = tty;
132

    
133
    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
134
                          |INLCR|IGNCR|ICRNL|IXON);
135
    tty.c_oflag |= OPOST;
136
    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
137
    tty.c_cflag &= ~(CSIZE|PARENB);
138
    tty.c_cflag |= CS8;
139
    tty.c_cc[VMIN] = 1;
140
    tty.c_cc[VTIME] = 0;
141

    
142
    tcsetattr (0, TCSANOW, &tty);
143

    
144
    atexit(term_exit);
145
}
146

    
147
static int read_password(char *buf, int buf_size)
148
{
149
    uint8_t ch;
150
    int i, ret;
151

    
152
    printf("password: ");
153
    fflush(stdout);
154
    term_init();
155
    i = 0;
156
    for(;;) {
157
        ret = read(0, &ch, 1);
158
        if (ret == -1) {
159
            if (errno == EAGAIN || errno == EINTR) {
160
                continue;
161
            } else {
162
                ret = -1;
163
                break;
164
            }
165
        } else if (ret == 0) {
166
            ret = -1;
167
            break;
168
        } else {
169
            if (ch == '\r') {
170
                ret = 0;
171
                break;
172
            }
173
            if (i < (buf_size - 1))
174
                buf[i++] = ch;
175
        }
176
    }
177
    term_exit();
178
    buf[i] = '\0';
179
    printf("\n");
180
    return ret;
181
}
182
#endif
183

    
184
static BlockDriverState *bdrv_new_open(const char *filename,
185
                                       const char *fmt)
186
{
187
    BlockDriverState *bs;
188
    BlockDriver *drv;
189
    char password[256];
190

    
191
    bs = bdrv_new("");
192
    if (!bs)
193
        error("Not enough memory");
194
    if (fmt) {
195
        drv = bdrv_find_format(fmt);
196
        if (!drv)
197
            error("Unknown file format '%s'", fmt);
198
    } else {
199
        drv = NULL;
200
    }
201
    if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
202
        error("Could not open '%s'", filename);
203
    }
204
    if (bdrv_is_encrypted(bs)) {
205
        printf("Disk image '%s' is encrypted.\n", filename);
206
        if (read_password(password, sizeof(password)) < 0)
207
            error("No password given");
208
        if (bdrv_set_key(bs, password) < 0)
209
            error("invalid password");
210
    }
211
    return bs;
212
}
213

    
214
static int img_create(int argc, char **argv)
215
{
216
    int c, ret, flags;
217
    const char *fmt = "raw";
218
    const char *filename;
219
    const char *base_filename = NULL;
220
    uint64_t size;
221
    const char *p;
222
    BlockDriver *drv;
223

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

    
297
static int img_commit(int argc, char **argv)
298
{
299
    int c, ret;
300
    const char *filename, *fmt;
301
    BlockDriver *drv;
302
    BlockDriverState *bs;
303

    
304
    fmt = NULL;
305
    for(;;) {
306
        c = getopt(argc, argv, "f:h");
307
        if (c == -1)
308
            break;
309
        switch(c) {
310
        case 'h':
311
            help();
312
            break;
313
        case 'f':
314
            fmt = optarg;
315
            break;
316
        }
317
    }
318
    if (optind >= argc)
319
        help();
320
    filename = argv[optind++];
321

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

    
354
    bdrv_delete(bs);
355
    return 0;
356
}
357

    
358
static int is_not_zero(const uint8_t *sector, int len)
359
{
360
    int i;
361
    len >>= 2;
362
    for(i = 0;i < len; i++) {
363
        if (((uint32_t *)sector)[i] != 0)
364
            return 1;
365
    }
366
    return 0;
367
}
368

    
369
/*
370
 * Returns true iff the first sector pointed to by 'buf' contains at least
371
 * a non-NUL byte.
372
 *
373
 * 'pnum' is set to the number of sectors (including and immediately following
374
 * the first one) that are known to be in the same allocated/unallocated state.
375
 */
376
static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
377
{
378
    int v, i;
379

    
380
    if (n <= 0) {
381
        *pnum = 0;
382
        return 0;
383
    }
384
    v = is_not_zero(buf, 512);
385
    for(i = 1; i < n; i++) {
386
        buf += 512;
387
        if (v != is_not_zero(buf, 512))
388
            break;
389
    }
390
    *pnum = i;
391
    return v;
392
}
393

    
394
#define IO_BUF_SIZE 65536
395

    
396
static int img_convert(int argc, char **argv)
397
{
398
    int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
399
    const char *fmt, *out_fmt, *out_baseimg, *out_filename;
400
    BlockDriver *drv;
401
    BlockDriverState **bs, *out_bs;
402
    int64_t total_sectors, nb_sectors, sector_num, bs_offset;
403
    uint64_t bs_sectors;
404
    uint8_t buf[IO_BUF_SIZE];
405
    const uint8_t *buf1;
406
    BlockDriverInfo bdi;
407

    
408
    fmt = NULL;
409
    out_fmt = "raw";
410
    out_baseimg = NULL;
411
    flags = 0;
412
    for(;;) {
413
        c = getopt(argc, argv, "f:O:B:hce6");
414
        if (c == -1)
415
            break;
416
        switch(c) {
417
        case 'h':
418
            help();
419
            break;
420
        case 'f':
421
            fmt = optarg;
422
            break;
423
        case 'O':
424
            out_fmt = optarg;
425
            break;
426
        case 'B':
427
            out_baseimg = optarg;
428
            break;
429
        case 'c':
430
            flags |= BLOCK_FLAG_COMPRESS;
431
            break;
432
        case 'e':
433
            flags |= BLOCK_FLAG_ENCRYPT;
434
            break;
435
        case '6':
436
            flags |= BLOCK_FLAG_COMPAT6;
437
            break;
438
        }
439
    }
440

    
441
    bs_n = argc - optind - 1;
442
    if (bs_n < 1) help();
443

    
444
    out_filename = argv[argc - 1];
445

    
446
    if (bs_n > 1 && out_baseimg)
447
        error("-B makes no sense when concatenating multiple input images");
448
        
449
    bs = calloc(bs_n, sizeof(BlockDriverState *));
450
    if (!bs)
451
        error("Out of memory");
452

    
453
    total_sectors = 0;
454
    for (bs_i = 0; bs_i < bs_n; bs_i++) {
455
        bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
456
        if (!bs[bs_i])
457
            error("Could not open '%s'", argv[optind + bs_i]);
458
        bdrv_get_geometry(bs[bs_i], &bs_sectors);
459
        total_sectors += bs_sectors;
460
    }
461

    
462
    drv = bdrv_find_format(out_fmt);
463
    if (!drv)
464
        error("Unknown file format '%s'", out_fmt);
465
    if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
466
        error("Compression not supported for this file format");
467
    if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
468
        error("Encryption not supported for this file format");
469
    if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk)
470
        error("Alternative compatibility level not supported for this file format");
471
    if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
472
        error("Compression and encryption not supported at the same time");
473

    
474
    ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
475
    if (ret < 0) {
476
        if (ret == -ENOTSUP) {
477
            error("Formatting not supported for file format '%s'", fmt);
478
        } else {
479
            error("Error while formatting '%s'", out_filename);
480
        }
481
    }
482

    
483
    out_bs = bdrv_new_open(out_filename, out_fmt);
484

    
485
    bs_i = 0;
486
    bs_offset = 0;
487
    bdrv_get_geometry(bs[0], &bs_sectors);
488

    
489
    if (flags & BLOCK_FLAG_COMPRESS) {
490
        if (bdrv_get_info(out_bs, &bdi) < 0)
491
            error("could not get block driver info");
492
        cluster_size = bdi.cluster_size;
493
        if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
494
            error("invalid cluster size");
495
        cluster_sectors = cluster_size >> 9;
496
        sector_num = 0;
497
        for(;;) {
498
            int64_t bs_num;
499
            int remainder;
500
            uint8_t *buf2;
501

    
502
            nb_sectors = total_sectors - sector_num;
503
            if (nb_sectors <= 0)
504
                break;
505
            if (nb_sectors >= cluster_sectors)
506
                n = cluster_sectors;
507
            else
508
                n = nb_sectors;
509

    
510
            bs_num = sector_num - bs_offset;
511
            assert (bs_num >= 0);
512
            remainder = n;
513
            buf2 = buf;
514
            while (remainder > 0) {
515
                int nlow;
516
                while (bs_num == bs_sectors) {
517
                    bs_i++;
518
                    assert (bs_i < bs_n);
519
                    bs_offset += bs_sectors;
520
                    bdrv_get_geometry(bs[bs_i], &bs_sectors);
521
                    bs_num = 0;
522
                    /* printf("changing part: sector_num=%lld, "
523
                       "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
524
                       sector_num, bs_i, bs_offset, bs_sectors); */
525
                }
526
                assert (bs_num < bs_sectors);
527

    
528
                nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
529

    
530
                if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) 
531
                    error("error while reading");
532

    
533
                buf2 += nlow * 512;
534
                bs_num += nlow;
535

    
536
                remainder -= nlow;
537
            }
538
            assert (remainder == 0);
539

    
540
            if (n < cluster_sectors)
541
                memset(buf + n * 512, 0, cluster_size - n * 512);
542
            if (is_not_zero(buf, cluster_size)) {
543
                if (bdrv_write_compressed(out_bs, sector_num, buf,
544
                                          cluster_sectors) != 0)
545
                    error("error while compressing sector %" PRId64,
546
                          sector_num);
547
            }
548
            sector_num += n;
549
        }
550
        /* signal EOF to align */
551
        bdrv_write_compressed(out_bs, 0, NULL, 0);
552
    } else {
553
        sector_num = 0; // total number of sectors converted so far
554
        for(;;) {
555
            nb_sectors = total_sectors - sector_num;
556
            if (nb_sectors <= 0)
557
                break;
558
            if (nb_sectors >= (IO_BUF_SIZE / 512))
559
                n = (IO_BUF_SIZE / 512);
560
            else
561
                n = nb_sectors;
562

    
563
            while (sector_num - bs_offset >= bs_sectors) {
564
                bs_i ++;
565
                assert (bs_i < bs_n);
566
                bs_offset += bs_sectors;
567
                bdrv_get_geometry(bs[bs_i], &bs_sectors);
568
                /* printf("changing part: sector_num=%lld, bs_i=%d, "
569
                  "bs_offset=%lld, bs_sectors=%lld\n",
570
                   sector_num, bs_i, bs_offset, bs_sectors); */
571
            }
572

    
573
            if (n > bs_offset + bs_sectors - sector_num)
574
                n = bs_offset + bs_sectors - sector_num;
575

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

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

    
617
#ifdef _WIN32
618
static int64_t get_allocated_file_size(const char *filename)
619
{
620
    typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
621
    get_compressed_t get_compressed;
622
    struct _stati64 st;
623

    
624
    /* WinNT support GetCompressedFileSize to determine allocate size */
625
    get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
626
    if (get_compressed) {
627
            DWORD high, low;
628
            low = get_compressed(filename, &high);
629
            if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
630
            return (((int64_t) high) << 32) + low;
631
    }
632

    
633
    if (_stati64(filename, &st) < 0)
634
        return -1;
635
    return st.st_size;
636
}
637
#else
638
static int64_t get_allocated_file_size(const char *filename)
639
{
640
    struct stat st;
641
    if (stat(filename, &st) < 0)
642
        return -1;
643
    return (int64_t)st.st_blocks * 512;
644
}
645
#endif
646

    
647
static void dump_snapshots(BlockDriverState *bs)
648
{
649
    QEMUSnapshotInfo *sn_tab, *sn;
650
    int nb_sns, i;
651
    char buf[256];
652

    
653
    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
654
    if (nb_sns <= 0)
655
        return;
656
    printf("Snapshot list:\n");
657
    printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
658
    for(i = 0; i < nb_sns; i++) {
659
        sn = &sn_tab[i];
660
        printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
661
    }
662
    qemu_free(sn_tab);
663
}
664

    
665
static int img_info(int argc, char **argv)
666
{
667
    int c;
668
    const char *filename, *fmt;
669
    BlockDriver *drv;
670
    BlockDriverState *bs;
671
    char fmt_name[128], size_buf[128], dsize_buf[128];
672
    uint64_t total_sectors;
673
    int64_t allocated_size;
674
    char backing_filename[1024];
675
    char backing_filename2[1024];
676
    BlockDriverInfo bdi;
677

    
678
    fmt = NULL;
679
    for(;;) {
680
        c = getopt(argc, argv, "f:h");
681
        if (c == -1)
682
            break;
683
        switch(c) {
684
        case 'h':
685
            help();
686
            break;
687
        case 'f':
688
            fmt = optarg;
689
            break;
690
        }
691
    }
692
    if (optind >= argc)
693
        help();
694
    filename = argv[optind++];
695

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

    
744
#define SNAPSHOT_LIST   1
745
#define SNAPSHOT_CREATE 2
746
#define SNAPSHOT_APPLY  3
747
#define SNAPSHOT_DELETE 4
748

    
749
static void img_snapshot(int argc, char **argv)
750
{
751
    BlockDriverState *bs;
752
    QEMUSnapshotInfo sn;
753
    char *filename, *snapshot_name = NULL;
754
    char c;
755
    int ret;
756
    int action = 0;
757
    qemu_timeval tv;
758

    
759
    /* Parse commandline parameters */
760
    for(;;) {
761
        c = getopt(argc, argv, "la:c:d:h");
762
        if (c == -1)
763
            break;
764
        switch(c) {
765
        case 'h':
766
            help();
767
            return;
768
        case 'l':
769
            if (action) {
770
                help();
771
                return;
772
            }
773
            action = SNAPSHOT_LIST;
774
            break;
775
        case 'a':
776
            if (action) {
777
                help();
778
                return;
779
            }
780
            action = SNAPSHOT_APPLY;
781
            snapshot_name = optarg;
782
            break;
783
        case 'c':
784
            if (action) {
785
                help();
786
                return;
787
            }
788
            action = SNAPSHOT_CREATE;
789
            snapshot_name = optarg;
790
            break;
791
        case 'd':
792
            if (action) {
793
                help();
794
                return;
795
            }
796
            action = SNAPSHOT_DELETE;
797
            snapshot_name = optarg;
798
            break;
799
        }
800
    }
801

    
802
    if (optind >= argc)
803
        help();
804
    filename = argv[optind++];
805

    
806
    /* Open the image */
807
    bs = bdrv_new("");
808
    if (!bs)
809
        error("Not enough memory");
810

    
811
    if (bdrv_open2(bs, filename, 0, NULL) < 0) {
812
        error("Could not open '%s'", filename);
813
    }
814

    
815
    /* Perform the requested action */
816
    switch(action) {
817
    case SNAPSHOT_LIST:
818
        dump_snapshots(bs);
819
        break;
820

    
821
    case SNAPSHOT_CREATE:
822
        memset(&sn, 0, sizeof(sn));
823
        pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
824

    
825
        qemu_gettimeofday(&tv);
826
        sn.date_sec = tv.tv_sec;
827
        sn.date_nsec = tv.tv_usec * 1000;
828

    
829
        ret = bdrv_snapshot_create(bs, &sn);
830
        if (ret)
831
            error("Could not create snapshot '%s': %d (%s)",
832
                snapshot_name, ret, strerror(-ret));
833
        break;
834

    
835
    case SNAPSHOT_APPLY:
836
        ret = bdrv_snapshot_goto(bs, snapshot_name);
837
        if (ret)
838
            error("Could not apply snapshot '%s': %d (%s)",
839
                snapshot_name, ret, strerror(-ret));
840
        break;
841

    
842
    case SNAPSHOT_DELETE:
843
        ret = bdrv_snapshot_delete(bs, snapshot_name);
844
        if (ret)
845
            error("Could not delete snapshot '%s': %d (%s)",
846
                snapshot_name, ret, strerror(-ret));
847
        break;
848
    }
849

    
850
    /* Cleanup */
851
    bdrv_delete(bs);
852
}
853

    
854
int main(int argc, char **argv)
855
{
856
    const char *cmd;
857

    
858
    bdrv_init();
859
    if (argc < 2)
860
        help();
861
    cmd = argv[1];
862
    optind++;
863
    if (!strcmp(cmd, "create")) {
864
        img_create(argc, argv);
865
    } else if (!strcmp(cmd, "commit")) {
866
        img_commit(argc, argv);
867
    } else if (!strcmp(cmd, "convert")) {
868
        img_convert(argc, argv);
869
    } else if (!strcmp(cmd, "info")) {
870
        img_info(argc, argv);
871
    } else if (!strcmp(cmd, "snapshot")) {
872
        img_snapshot(argc, argv);
873
    } else {
874
        help();
875
    }
876
    return 0;
877
}