Statistics
| Branch: | Revision:

root / qemu-img.c @ 49dc768d

History | View | Annotate | Download (25.3 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
#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 QEMU_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
/* Please keep in synch with qemu-img.texi */
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\n"
76
           "    'M' (megabyte, 1024 * 1024) and 'G' (gigabyte, 1024 * 1024 * 1024) are"
77
           "    supported any @code{k} or @code{K} is ignored\n"
78
           "  'output_filename' is the destination disk image filename\n"
79
           "  'output_fmt' is the destination format\n"
80
           "  '-c' indicates that target image must be compressed (qcow format only)\n"
81
           "  '-e' indicates that the target image must be encrypted (qcow format only)\n"
82
           "  '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"
83
           "  '-h' with or without a command shows this help and lists the supported formats\n"
84
           "\n"
85
           "Parameters to snapshot subcommand:\n"
86
           "  'snapshot' is the name of the snapshot to create, apply or delete\n"
87
           "  '-a' applies a snapshot (revert disk to saved state)\n"
88
           "  '-c' creates a snapshot\n"
89
           "  '-d' deletes a snapshot\n"
90
           "  '-l' lists all snapshots in the given image\n"
91
           );
92
    printf("\nSupported formats:");
93
    bdrv_iterate_format(format_print, NULL);
94
    printf("\n");
95
    exit(1);
96
}
97

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

    
117
#else
118

    
119
#include <termios.h>
120

    
121
static struct termios oldtty;
122

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

    
128
static void term_init(void)
129
{
130
    struct termios tty;
131

    
132
    tcgetattr (0, &tty);
133
    oldtty = tty;
134

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

    
144
    tcsetattr (0, TCSANOW, &tty);
145

    
146
    atexit(term_exit);
147
}
148

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

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

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

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

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

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

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

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

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

    
356
    bdrv_delete(bs);
357
    return 0;
358
}
359

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

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

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

    
396
#define IO_BUF_SIZE 65536
397

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

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

    
443
    bs_n = argc - optind - 1;
444
    if (bs_n < 1) help();
445

    
446
    out_filename = argv[argc - 1];
447

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

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

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

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

    
485
    out_bs = bdrv_new_open(out_filename, out_fmt);
486

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

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

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

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

    
530
                nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
531

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

    
535
                buf2 += nlow * 512;
536
                bs_num += nlow;
537

    
538
                remainder -= nlow;
539
            }
540
            assert (remainder == 0);
541

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

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

    
575
            if (n > bs_offset + bs_sectors - sector_num)
576
                n = bs_offset + bs_sectors - sector_num;
577

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

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

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

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

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

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

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

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

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

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

    
750
#define SNAPSHOT_LIST   1
751
#define SNAPSHOT_CREATE 2
752
#define SNAPSHOT_APPLY  3
753
#define SNAPSHOT_DELETE 4
754

    
755
static void img_snapshot(int argc, char **argv)
756
{
757
    BlockDriverState *bs;
758
    QEMUSnapshotInfo sn;
759
    char *filename, *snapshot_name = NULL;
760
    int c, ret;
761
    int action = 0;
762
    qemu_timeval tv;
763

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

    
807
    if (optind >= argc)
808
        help();
809
    filename = argv[optind++];
810

    
811
    /* Open the image */
812
    bs = bdrv_new("");
813
    if (!bs)
814
        error("Not enough memory");
815

    
816
    if (bdrv_open2(bs, filename, 0, NULL) < 0) {
817
        error("Could not open '%s'", filename);
818
    }
819

    
820
    /* Perform the requested action */
821
    switch(action) {
822
    case SNAPSHOT_LIST:
823
        dump_snapshots(bs);
824
        break;
825

    
826
    case SNAPSHOT_CREATE:
827
        memset(&sn, 0, sizeof(sn));
828
        pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
829

    
830
        qemu_gettimeofday(&tv);
831
        sn.date_sec = tv.tv_sec;
832
        sn.date_nsec = tv.tv_usec * 1000;
833

    
834
        ret = bdrv_snapshot_create(bs, &sn);
835
        if (ret)
836
            error("Could not create snapshot '%s': %d (%s)",
837
                snapshot_name, ret, strerror(-ret));
838
        break;
839

    
840
    case SNAPSHOT_APPLY:
841
        ret = bdrv_snapshot_goto(bs, snapshot_name);
842
        if (ret)
843
            error("Could not apply snapshot '%s': %d (%s)",
844
                snapshot_name, ret, strerror(-ret));
845
        break;
846

    
847
    case SNAPSHOT_DELETE:
848
        ret = bdrv_snapshot_delete(bs, snapshot_name);
849
        if (ret)
850
            error("Could not delete snapshot '%s': %d (%s)",
851
                snapshot_name, ret, strerror(-ret));
852
        break;
853
    }
854

    
855
    /* Cleanup */
856
    bdrv_delete(bs);
857
}
858

    
859
int main(int argc, char **argv)
860
{
861
    const char *cmd;
862

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