Statistics
| Branch: | Revision:

root / qemu-img.c @ 9f8df9c1

History | View | Annotate | Download (24.9 kB)

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