Statistics
| Branch: | Revision:

root / qemu-img.c @ 1eec614b

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