qemu-io.c 11.9 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * Command line utility to exercise the QEMU I/O path.
 *
 * Copyright (C) 2009 Red Hat, Inc.
 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 */
10
#include <sys/time.h>
11 12 13 14
#include <sys/types.h>
#include <stdarg.h>
#include <stdio.h>
#include <getopt.h>
15
#include <libgen.h>
16

K
Kevin Wolf 已提交
17
#include "qemu-io.h"
18
#include "qemu/main-loop.h"
19 20
#include "qemu/option.h"
#include "qemu/config-file.h"
S
Stefan Hajnoczi 已提交
21
#include "qemu/readline.h"
M
Markus Armbruster 已提交
22
#include "sysemu/block-backend.h"
23
#include "block/block_int.h"
24
#include "trace/control.h"
25

D
Devin Nakamura 已提交
26
#define CMD_NOFILE_OK   0x01
27

28
static char *progname;
29

M
Markus Armbruster 已提交
30
static BlockBackend *qemuio_blk;
31
static BlockDriverState *qemuio_bs;
K
Kevin Wolf 已提交
32

33 34 35 36
/* qemu-io commands passed using -c */
static int ncmdline;
static char **cmdline;

S
Stefan Hajnoczi 已提交
37 38
static ReadLineState *readline_state;

39
static int close_f(BlockDriverState *bs, int argc, char **argv)
40
{
M
Markus Armbruster 已提交
41
    blk_unref(qemuio_blk);
42
    qemuio_bs = NULL;
M
Markus Armbruster 已提交
43
    qemuio_blk = NULL;
D
Devin Nakamura 已提交
44
    return 0;
45 46 47
}

static const cmdinfo_t close_cmd = {
D
Devin Nakamura 已提交
48 49 50 51
    .name       = "close",
    .altname    = "c",
    .cfunc      = close_f,
    .oneline    = "close the current open file",
52 53
};

54
static int openfile(char *name, int flags, int growable, QDict *opts)
55
{
56 57
    Error *local_err = NULL;

58
    if (qemuio_bs) {
D
Devin Nakamura 已提交
59
        fprintf(stderr, "file open already, try 'help close'\n");
60
        QDECREF(opts);
D
Devin Nakamura 已提交
61 62 63
        return 1;
    }

64 65
    qemuio_blk = blk_new_with_bs("hda", &error_abort);
    qemuio_bs = blk_bs(qemuio_blk);
66

D
Devin Nakamura 已提交
67
    if (growable) {
68 69 70 71 72 73 74 75
        flags |= BDRV_O_PROTOCOL;
    }

    if (bdrv_open(&qemuio_bs, name, NULL, opts, flags, NULL, &local_err) < 0) {
        fprintf(stderr, "%s: can't open%s%s: %s\n", progname,
                name ? " device " : "", name ?: "",
                error_get_pretty(local_err));
        error_free(local_err);
M
Markus Armbruster 已提交
76
        blk_unref(qemuio_blk);
77
        qemuio_bs = NULL;
M
Markus Armbruster 已提交
78
        qemuio_blk = NULL;
79
        return 1;
D
Devin Nakamura 已提交
80 81 82
    }

    return 0;
83 84
}

D
Devin Nakamura 已提交
85
static void open_help(void)
86
{
D
Devin Nakamura 已提交
87
    printf(
88 89 90 91 92 93 94 95 96 97
"\n"
" opens a new file in the requested mode\n"
"\n"
" Example:\n"
" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
"\n"
" Opens a file for subsequent use by all of the other qemu-io commands.\n"
" -r, -- open file read-only\n"
" -s, -- use snapshot file\n"
" -n, -- disable host cache\n"
98 99
" -g, -- allow file to grow (only applies to protocols)\n"
" -o, -- options to be given to the block driver"
100 101 102
"\n");
}

103
static int open_f(BlockDriverState *bs, int argc, char **argv);
B
Blue Swirl 已提交
104 105

static const cmdinfo_t open_cmd = {
D
Devin Nakamura 已提交
106 107 108 109 110 111
    .name       = "open",
    .altname    = "o",
    .cfunc      = open_f,
    .argmin     = 1,
    .argmax     = -1,
    .flags      = CMD_NOFILE_OK,
112
    .args       = "[-Crsn] [-o options] [path]",
D
Devin Nakamura 已提交
113 114
    .oneline    = "open the file specified by path",
    .help       = open_help,
B
Blue Swirl 已提交
115
};
116

117 118
static QemuOptsList empty_opts = {
    .name = "drive",
119
    .merge_lists = true,
120 121 122 123 124 125 126
    .head = QTAILQ_HEAD_INITIALIZER(empty_opts.head),
    .desc = {
        /* no elements => accept any params */
        { /* end of list */ }
    },
};

127
static int open_f(BlockDriverState *bs, int argc, char **argv)
128
{
D
Devin Nakamura 已提交
129 130 131 132
    int flags = 0;
    int readonly = 0;
    int growable = 0;
    int c;
133
    QemuOpts *qopts;
134
    QDict *opts;
D
Devin Nakamura 已提交
135

136
    while ((c = getopt(argc, argv, "snrgo:")) != EOF) {
D
Devin Nakamura 已提交
137 138 139 140 141 142 143 144 145 146 147 148 149
        switch (c) {
        case 's':
            flags |= BDRV_O_SNAPSHOT;
            break;
        case 'n':
            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
            break;
        case 'r':
            readonly = 1;
            break;
        case 'g':
            growable = 1;
            break;
150
        case 'o':
151
            if (!qemu_opts_parse(&empty_opts, optarg, 0)) {
152
                printf("could not parse option list -- %s\n", optarg);
153
                qemu_opts_reset(&empty_opts);
154 155 156
                return 0;
            }
            break;
D
Devin Nakamura 已提交
157
        default:
158
            qemu_opts_reset(&empty_opts);
159
            return qemuio_command_usage(&open_cmd);
160
        }
D
Devin Nakamura 已提交
161 162 163 164 165
    }

    if (!readonly) {
        flags |= BDRV_O_RDWR;
    }
166

167 168 169 170
    qopts = qemu_opts_find(&empty_opts, NULL);
    opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
    qemu_opts_reset(&empty_opts);

M
Max Reitz 已提交
171 172 173 174 175
    if (optind == argc - 1) {
        return openfile(argv[optind], flags, growable, opts);
    } else if (optind == argc) {
        return openfile(NULL, flags, growable, opts);
    } else {
176
        QDECREF(opts);
177
        return qemuio_command_usage(&open_cmd);
D
Devin Nakamura 已提交
178
    }
179 180
}

K
Kevin Wolf 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
static int quit_f(BlockDriverState *bs, int argc, char **argv)
{
    return 1;
}

static const cmdinfo_t quit_cmd = {
    .name       = "quit",
    .altname    = "q",
    .cfunc      = quit_f,
    .argmin     = -1,
    .argmax     = -1,
    .flags      = CMD_FLAG_GLOBAL,
    .oneline    = "exit the program",
};

196 197
static void usage(const char *name)
{
D
Devin Nakamura 已提交
198
    printf(
199
"Usage: %s [-h] [-V] [-rsnm] [-c STRING] ... [file]\n"
200
"QEMU Disk exerciser\n"
201
"\n"
202 203
"  -c, --cmd STRING     execute command with its arguments\n"
"                       from the given string\n"
204 205 206
"  -r, --read-only      export read-only\n"
"  -s, --snapshot       use snapshot file\n"
"  -n, --nocache        disable host cache\n"
207
"  -g, --growable       allow file to grow (only applies to protocols)\n"
208
"  -m, --misalign       misalign allocations for O_DIRECT\n"
209
"  -k, --native-aio     use kernel AIO implementation (on Linux only)\n"
210
"  -t, --cache=MODE     use the given cache mode for the image\n"
211
"  -T, --trace FILE     enable trace events listed in the given file\n"
212 213
"  -h, --help           display this help and exit\n"
"  -V, --version        output version information and exit\n"
214 215
"\n"
"See '%s -c help' for information on available commands."
216
"\n",
217
    name, name);
218 219
}

220 221 222 223 224 225 226 227 228 229 230
static char *get_prompt(void)
{
    static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];

    if (!prompt[0]) {
        snprintf(prompt, sizeof(prompt), "%s> ", progname);
    }

    return prompt;
}

S
Stefan Weil 已提交
231 232
static void GCC_FMT_ATTR(2, 3) readline_printf_func(void *opaque,
                                                    const char *fmt, ...)
233
{
S
Stefan Hajnoczi 已提交
234 235 236 237
    va_list ap;
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
238
}
S
Stefan Hajnoczi 已提交
239 240

static void readline_flush_func(void *opaque)
241
{
S
Stefan Hajnoczi 已提交
242
    fflush(stdout);
243 244
}

S
Stefan Hajnoczi 已提交
245
static void readline_func(void *opaque, const char *str, void *readline_opaque)
246
{
S
Stefan Hajnoczi 已提交
247 248 249 250
    char **line = readline_opaque;
    *line = g_strdup(str);
}

251 252 253 254 255
static void completion_match(const char *cmd, void *opaque)
{
    readline_add_completion(readline_state, cmd);
}

S
Stefan Hajnoczi 已提交
256 257
static void readline_completion_func(void *opaque, const char *str)
{
258 259
    readline_set_completion_index(readline_state, strlen(str));
    qemuio_complete_command(str, completion_match, NULL);
S
Stefan Hajnoczi 已提交
260 261 262 263 264 265 266 267 268 269 270
}

static char *fetchline_readline(void)
{
    char *line = NULL;

    readline_start(readline_state, get_prompt(), 0, readline_func, &line);
    while (!line) {
        int ch = getchar();
        if (ch == EOF) {
            break;
271
        }
S
Stefan Hajnoczi 已提交
272
        readline_handle_byte(readline_state, ch);
273 274 275
    }
    return line;
}
S
Stefan Hajnoczi 已提交
276 277 278

#define MAXREADLINESZ 1024
static char *fetchline_fgets(void)
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
{
    char *p, *line = g_malloc(MAXREADLINESZ);

    if (!fgets(line, MAXREADLINESZ, stdin)) {
        g_free(line);
        return NULL;
    }

    p = line + strlen(line);
    if (p != line && p[-1] == '\n') {
        p[-1] = '\0';
    }

    return line;
}
S
Stefan Hajnoczi 已提交
294 295 296 297 298 299 300 301 302

static char *fetchline(void)
{
    if (readline_state) {
        return fetchline_readline();
    } else {
        return fetchline_fgets();
    }
}
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317

static void prep_fetchline(void *opaque)
{
    int *fetchable = opaque;

    qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
    *fetchable= 1;
}

static void command_loop(void)
{
    int i, done = 0, fetchable = 0, prompted = 0;
    char *input;

    for (i = 0; !done && i < ncmdline; i++) {
K
Kevin Wolf 已提交
318
        done = qemuio_command(qemuio_bs, cmdline[i]);
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
    }
    if (cmdline) {
        g_free(cmdline);
        return;
    }

    while (!done) {
        if (!prompted) {
            printf("%s", get_prompt());
            fflush(stdout);
            qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable);
            prompted = 1;
        }

        main_loop_wait(false);

        if (!fetchable) {
            continue;
        }

        input = fetchline();
        if (input == NULL) {
            break;
        }
K
Kevin Wolf 已提交
343
        done = qemuio_command(qemuio_bs, input);
344 345 346 347 348 349 350 351 352 353
        g_free(input);

        prompted = 0;
        fetchable = 0;
    }
    qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
}

static void add_user_command(char *optarg)
{
354
    cmdline = g_renew(char *, cmdline, ++ncmdline);
355 356 357
    cmdline[ncmdline-1] = optarg;
}

S
Stefan Hajnoczi 已提交
358 359 360 361 362
static void reenable_tty_echo(void)
{
    qemu_set_tty_echo(STDIN_FILENO, true);
}

363 364
int main(int argc, char **argv)
{
D
Devin Nakamura 已提交
365 366
    int readonly = 0;
    int growable = 0;
P
Paolo Bonzini 已提交
367
    const char *sopt = "hVc:d:rsnmgkt:T:";
D
Devin Nakamura 已提交
368 369 370 371 372 373 374 375 376 377 378
    const struct option lopt[] = {
        { "help", 0, NULL, 'h' },
        { "version", 0, NULL, 'V' },
        { "offset", 1, NULL, 'o' },
        { "cmd", 1, NULL, 'c' },
        { "read-only", 0, NULL, 'r' },
        { "snapshot", 0, NULL, 's' },
        { "nocache", 0, NULL, 'n' },
        { "misalign", 0, NULL, 'm' },
        { "growable", 0, NULL, 'g' },
        { "native-aio", 0, NULL, 'k' },
P
Paolo Bonzini 已提交
379
        { "discard", 1, NULL, 'd' },
380
        { "cache", 1, NULL, 't' },
381
        { "trace", 1, NULL, 'T' },
D
Devin Nakamura 已提交
382 383 384 385
        { NULL, 0, NULL, 0 }
    };
    int c;
    int opt_index = 0;
P
Paolo Bonzini 已提交
386
    int flags = BDRV_O_UNMAP;
387
    Error *local_error = NULL;
D
Devin Nakamura 已提交
388

389 390 391 392
#ifdef CONFIG_POSIX
    signal(SIGPIPE, SIG_IGN);
#endif

D
Devin Nakamura 已提交
393
    progname = basename(argv[0]);
394
    qemu_init_exec_dir(argv[0]);
D
Devin Nakamura 已提交
395 396 397 398 399 400 401 402 403

    while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
        switch (c) {
        case 's':
            flags |= BDRV_O_SNAPSHOT;
            break;
        case 'n':
            flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
            break;
P
Paolo Bonzini 已提交
404 405 406 407 408 409
        case 'd':
            if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
                error_report("Invalid discard option: %s", optarg);
                exit(1);
            }
            break;
D
Devin Nakamura 已提交
410 411 412 413 414 415 416
        case 'c':
            add_user_command(optarg);
            break;
        case 'r':
            readonly = 1;
            break;
        case 'm':
417
            qemuio_misalign = true;
D
Devin Nakamura 已提交
418 419 420 421 422 423 424
            break;
        case 'g':
            growable = 1;
            break;
        case 'k':
            flags |= BDRV_O_NATIVE_AIO;
            break;
425 426 427 428 429 430
        case 't':
            if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
                error_report("Invalid cache option: %s", optarg);
                exit(1);
            }
            break;
431
        case 'T':
L
Lluís Vilanova 已提交
432
            if (!trace_init_backends(optarg, NULL)) {
433 434 435
                exit(1); /* error message will have been printed */
            }
            break;
D
Devin Nakamura 已提交
436
        case 'V':
437
            printf("%s version %s\n", progname, QEMU_VERSION);
D
Devin Nakamura 已提交
438 439 440 441 442 443 444
            exit(0);
        case 'h':
            usage(progname);
            exit(0);
        default:
            usage(progname);
            exit(1);
445
        }
D
Devin Nakamura 已提交
446 447 448 449 450 451
    }

    if ((argc - optind) > 1) {
        usage(progname);
        exit(1);
    }
452

453 454 455 456 457
    if (qemu_init_main_loop(&local_error)) {
        error_report("%s", error_get_pretty(local_error));
        error_free(local_error);
        exit(1);
    }
458
    bdrv_init();
459

D
Devin Nakamura 已提交
460
    /* initialize commands */
461 462 463
    qemuio_add_command(&quit_cmd);
    qemuio_add_command(&open_cmd);
    qemuio_add_command(&close_cmd);
D
Devin Nakamura 已提交
464

S
Stefan Hajnoczi 已提交
465 466 467 468 469 470 471 472 473
    if (isatty(STDIN_FILENO)) {
        readline_state = readline_init(readline_printf_func,
                                       readline_flush_func,
                                       NULL,
                                       readline_completion_func);
        qemu_set_tty_echo(STDIN_FILENO, false);
        atexit(reenable_tty_echo);
    }

D
Devin Nakamura 已提交
474 475 476 477 478 479
    /* open the device */
    if (!readonly) {
        flags |= BDRV_O_RDWR;
    }

    if ((argc - optind) == 1) {
480
        openfile(argv[optind], flags, growable, NULL);
D
Devin Nakamura 已提交
481 482
    }
    command_loop();
483

D
Devin Nakamura 已提交
484
    /*
485
     * Make sure all outstanding requests complete before the program exits.
D
Devin Nakamura 已提交
486
     */
487
    bdrv_drain_all();
488

M
Markus Armbruster 已提交
489
    blk_unref(qemuio_blk);
S
Stefan Hajnoczi 已提交
490
    g_free(readline_state);
D
Devin Nakamura 已提交
491
    return 0;
492
}