Statistics
| Branch: | Revision:

root / qemu-img.c @ 8f9b157e

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
#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 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

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

    
53
/* Please keep in synch with qemu-img.texi */
54
static 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 */
101
static 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

    
122
static struct termios oldtty;
123

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

    
129
static 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

    
150
static 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

    
187
static 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

    
217
static 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

    
300
static 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

    
361
static 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
 */
379
static 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

    
399
static 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
621
static 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
641
static 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

    
650
static 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

    
668
static 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

    
756
static 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

    
860
int 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
}