qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

qemu-io.c (18312B)


      1 /*
      2  * Command line utility to exercise the QEMU I/O path.
      3  *
      4  * Copyright (C) 2009 Red Hat, Inc.
      5  * Copyright (c) 2003-2005 Silicon Graphics, Inc.
      6  *
      7  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      8  * See the COPYING file in the top-level directory.
      9  */
     10 
     11 #include "qemu/osdep.h"
     12 #include <getopt.h>
     13 #include <libgen.h>
     14 #ifndef _WIN32
     15 #include <termios.h>
     16 #endif
     17 
     18 #include "qemu/help-texts.h"
     19 #include "qemu/cutils.h"
     20 #include "qapi/error.h"
     21 #include "qemu-io.h"
     22 #include "qemu/error-report.h"
     23 #include "qemu/main-loop.h"
     24 #include "qemu/module.h"
     25 #include "qemu/option.h"
     26 #include "qemu/config-file.h"
     27 #include "qemu/readline.h"
     28 #include "qemu/log.h"
     29 #include "qemu/sockets.h"
     30 #include "qapi/qmp/qstring.h"
     31 #include "qapi/qmp/qdict.h"
     32 #include "qom/object_interfaces.h"
     33 #include "sysemu/block-backend.h"
     34 #include "block/block_int.h"
     35 #include "trace/control.h"
     36 #include "crypto/init.h"
     37 #include "qemu-version.h"
     38 
     39 #define CMD_NOFILE_OK   0x01
     40 
     41 static BlockBackend *qemuio_blk;
     42 static bool quit_qemu_io;
     43 
     44 /* qemu-io commands passed using -c */
     45 static int ncmdline;
     46 static char **cmdline;
     47 static bool imageOpts;
     48 
     49 static ReadLineState *readline_state;
     50 
     51 static int ttyEOF;
     52 
     53 static int get_eof_char(void)
     54 {
     55 #ifdef _WIN32
     56     return 0x4; /* Ctrl-D */
     57 #else
     58     struct termios tty;
     59     if (tcgetattr(STDIN_FILENO, &tty) != 0) {
     60         if (errno == ENOTTY) {
     61             return 0x0; /* just expect read() == 0 */
     62         } else {
     63             return 0x4; /* Ctrl-D */
     64         }
     65     }
     66 
     67     return tty.c_cc[VEOF];
     68 #endif
     69 }
     70 
     71 static int close_f(BlockBackend *blk, int argc, char **argv)
     72 {
     73     blk_unref(qemuio_blk);
     74     qemuio_blk = NULL;
     75     return 0;
     76 }
     77 
     78 static const cmdinfo_t close_cmd = {
     79     .name       = "close",
     80     .altname    = "c",
     81     .cfunc      = close_f,
     82     .oneline    = "close the current open file",
     83 };
     84 
     85 static int openfile(char *name, int flags, bool writethrough, bool force_share,
     86                     QDict *opts)
     87 {
     88     Error *local_err = NULL;
     89 
     90     if (qemuio_blk) {
     91         error_report("file open already, try 'help close'");
     92         qobject_unref(opts);
     93         return 1;
     94     }
     95 
     96     if (force_share) {
     97         if (!opts) {
     98             opts = qdict_new();
     99         }
    100         if (qdict_haskey(opts, BDRV_OPT_FORCE_SHARE)
    101             && strcmp(qdict_get_str(opts, BDRV_OPT_FORCE_SHARE), "on")) {
    102             error_report("-U conflicts with image options");
    103             qobject_unref(opts);
    104             return 1;
    105         }
    106         qdict_put_str(opts, BDRV_OPT_FORCE_SHARE, "on");
    107     }
    108     qemuio_blk = blk_new_open(name, NULL, opts, flags, &local_err);
    109     if (!qemuio_blk) {
    110         error_reportf_err(local_err, "can't open%s%s: ",
    111                           name ? " device " : "", name ?: "");
    112         return 1;
    113     }
    114 
    115     blk_set_enable_write_cache(qemuio_blk, !writethrough);
    116 
    117     return 0;
    118 }
    119 
    120 static void open_help(void)
    121 {
    122     printf(
    123 "\n"
    124 " opens a new file in the requested mode\n"
    125 "\n"
    126 " Example:\n"
    127 " 'open -n -o driver=raw /tmp/data' - opens raw data file read-write, uncached\n"
    128 "\n"
    129 " Opens a file for subsequent use by all of the other qemu-io commands.\n"
    130 " -r, -- open file read-only\n"
    131 " -s, -- use snapshot file\n"
    132 " -C, -- use copy-on-read\n"
    133 " -n, -- disable host cache, short for -t none\n"
    134 " -U, -- force shared permissions\n"
    135 " -k, -- use kernel AIO implementation (Linux only, prefer use of -i)\n"
    136 " -i, -- use AIO mode (threads, native or io_uring)\n"
    137 " -t, -- use the given cache mode for the image\n"
    138 " -d, -- use the given discard mode for the image\n"
    139 " -o, -- options to be given to the block driver"
    140 "\n");
    141 }
    142 
    143 static int open_f(BlockBackend *blk, int argc, char **argv);
    144 
    145 static const cmdinfo_t open_cmd = {
    146     .name       = "open",
    147     .altname    = "o",
    148     .cfunc      = open_f,
    149     .argmin     = 1,
    150     .argmax     = -1,
    151     .flags      = CMD_NOFILE_OK,
    152     .args       = "[-rsCnkU] [-t cache] [-d discard] [-o options] [path]",
    153     .oneline    = "open the file specified by path",
    154     .help       = open_help,
    155 };
    156 
    157 static QemuOptsList empty_opts = {
    158     .name = "drive",
    159     .merge_lists = true,
    160     .head = QTAILQ_HEAD_INITIALIZER(empty_opts.head),
    161     .desc = {
    162         /* no elements => accept any params */
    163         { /* end of list */ }
    164     },
    165 };
    166 
    167 static int open_f(BlockBackend *blk, int argc, char **argv)
    168 {
    169     int flags = BDRV_O_UNMAP;
    170     int readonly = 0;
    171     bool writethrough = true;
    172     int c;
    173     int ret;
    174     QemuOpts *qopts;
    175     QDict *opts;
    176     bool force_share = false;
    177 
    178     while ((c = getopt(argc, argv, "snCro:ki:t:d:U")) != -1) {
    179         switch (c) {
    180         case 's':
    181             flags |= BDRV_O_SNAPSHOT;
    182             break;
    183         case 'n':
    184             flags |= BDRV_O_NOCACHE;
    185             writethrough = false;
    186             break;
    187         case 'C':
    188             flags |= BDRV_O_COPY_ON_READ;
    189             break;
    190         case 'r':
    191             readonly = 1;
    192             break;
    193         case 'k':
    194             flags |= BDRV_O_NATIVE_AIO;
    195             break;
    196         case 't':
    197             if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
    198                 error_report("Invalid cache option: %s", optarg);
    199                 qemu_opts_reset(&empty_opts);
    200                 return -EINVAL;
    201             }
    202             break;
    203         case 'd':
    204             if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
    205                 error_report("Invalid discard option: %s", optarg);
    206                 qemu_opts_reset(&empty_opts);
    207                 return -EINVAL;
    208             }
    209             break;
    210         case 'i':
    211             if (bdrv_parse_aio(optarg, &flags) < 0) {
    212                 error_report("Invalid aio option: %s", optarg);
    213                 qemu_opts_reset(&empty_opts);
    214                 return -EINVAL;
    215             }
    216             break;
    217         case 'o':
    218             if (imageOpts) {
    219                 printf("--image-opts and 'open -o' are mutually exclusive\n");
    220                 qemu_opts_reset(&empty_opts);
    221                 return -EINVAL;
    222             }
    223             if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) {
    224                 qemu_opts_reset(&empty_opts);
    225                 return -EINVAL;
    226             }
    227             break;
    228         case 'U':
    229             force_share = true;
    230             break;
    231         default:
    232             qemu_opts_reset(&empty_opts);
    233             qemuio_command_usage(&open_cmd);
    234             return -EINVAL;
    235         }
    236     }
    237 
    238     if (!readonly) {
    239         flags |= BDRV_O_RDWR;
    240     }
    241 
    242     if (imageOpts && (optind == argc - 1)) {
    243         if (!qemu_opts_parse_noisily(&empty_opts, argv[optind], false)) {
    244             qemu_opts_reset(&empty_opts);
    245             return -EINVAL;
    246         }
    247         optind++;
    248     }
    249 
    250     qopts = qemu_opts_find(&empty_opts, NULL);
    251     opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
    252     qemu_opts_reset(&empty_opts);
    253 
    254     if (optind == argc - 1) {
    255         ret = openfile(argv[optind], flags, writethrough, force_share, opts);
    256     } else if (optind == argc) {
    257         ret = openfile(NULL, flags, writethrough, force_share, opts);
    258     } else {
    259         qobject_unref(opts);
    260         qemuio_command_usage(&open_cmd);
    261         return -EINVAL;
    262     }
    263 
    264     if (ret) {
    265         return -EINVAL;
    266     }
    267 
    268     return 0;
    269 }
    270 
    271 static int quit_f(BlockBackend *blk, int argc, char **argv)
    272 {
    273     quit_qemu_io = true;
    274     return 0;
    275 }
    276 
    277 static const cmdinfo_t quit_cmd = {
    278     .name       = "quit",
    279     .altname    = "q",
    280     .cfunc      = quit_f,
    281     .argmin     = -1,
    282     .argmax     = -1,
    283     .flags      = CMD_FLAG_GLOBAL,
    284     .oneline    = "exit the program",
    285 };
    286 
    287 static void usage(const char *name)
    288 {
    289     printf(
    290 "Usage: %s [OPTIONS]... [-c STRING]... [file]\n"
    291 "QEMU Disk exerciser\n"
    292 "\n"
    293 "  --object OBJECTDEF   define an object such as 'secret' for\n"
    294 "                       passwords and/or encryption keys\n"
    295 "  --image-opts         treat file as option string\n"
    296 "  -c, --cmd STRING     execute command with its arguments\n"
    297 "                       from the given string\n"
    298 "  -f, --format FMT     specifies the block driver to use\n"
    299 "  -r, --read-only      export read-only\n"
    300 "  -s, --snapshot       use snapshot file\n"
    301 "  -n, --nocache        disable host cache, short for -t none\n"
    302 "  -C, --copy-on-read   enable copy-on-read\n"
    303 "  -m, --misalign       misalign allocations for O_DIRECT\n"
    304 "  -k, --native-aio     use kernel AIO implementation\n"
    305 "                       (Linux only, prefer use of -i)\n"
    306 "  -i, --aio=MODE       use AIO mode (threads, native or io_uring)\n"
    307 "  -t, --cache=MODE     use the given cache mode for the image\n"
    308 "  -d, --discard=MODE   use the given discard mode for the image\n"
    309 "  -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
    310 "                       specify tracing options\n"
    311 "                       see qemu-img(1) man page for full description\n"
    312 "  -U, --force-share    force shared permissions\n"
    313 "  -h, --help           display this help and exit\n"
    314 "  -V, --version        output version information and exit\n"
    315 "\n"
    316 "See '%s -c help' for information on available commands.\n"
    317 "\n"
    318 QEMU_HELP_BOTTOM "\n",
    319     name, name);
    320 }
    321 
    322 static char *get_prompt(void)
    323 {
    324     static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
    325 
    326     if (!prompt[0]) {
    327         snprintf(prompt, sizeof(prompt), "%s> ", g_get_prgname());
    328     }
    329 
    330     return prompt;
    331 }
    332 
    333 static void G_GNUC_PRINTF(2, 3) readline_printf_func(void *opaque,
    334                                                     const char *fmt, ...)
    335 {
    336     va_list ap;
    337     va_start(ap, fmt);
    338     vprintf(fmt, ap);
    339     va_end(ap);
    340 }
    341 
    342 static void readline_flush_func(void *opaque)
    343 {
    344     fflush(stdout);
    345 }
    346 
    347 static void readline_func(void *opaque, const char *str, void *readline_opaque)
    348 {
    349     char **line = readline_opaque;
    350     *line = g_strdup(str);
    351 }
    352 
    353 static void completion_match(const char *cmd, void *opaque)
    354 {
    355     readline_add_completion(readline_state, cmd);
    356 }
    357 
    358 static void readline_completion_func(void *opaque, const char *str)
    359 {
    360     readline_set_completion_index(readline_state, strlen(str));
    361     qemuio_complete_command(str, completion_match, NULL);
    362 }
    363 
    364 static char *fetchline_readline(void)
    365 {
    366     char *line = NULL;
    367 
    368     readline_start(readline_state, get_prompt(), 0, readline_func, &line);
    369     while (!line) {
    370         int ch = getchar();
    371         if (ttyEOF != 0x0 && ch == ttyEOF) {
    372             printf("\n");
    373             break;
    374         }
    375         readline_handle_byte(readline_state, ch);
    376     }
    377     return line;
    378 }
    379 
    380 #define MAXREADLINESZ 1024
    381 static char *fetchline_fgets(void)
    382 {
    383     char *p, *line = g_malloc(MAXREADLINESZ);
    384 
    385     if (!fgets(line, MAXREADLINESZ, stdin)) {
    386         g_free(line);
    387         return NULL;
    388     }
    389 
    390     p = line + strlen(line);
    391     if (p != line && p[-1] == '\n') {
    392         p[-1] = '\0';
    393     }
    394 
    395     return line;
    396 }
    397 
    398 static char *fetchline(void)
    399 {
    400     if (readline_state) {
    401         return fetchline_readline();
    402     } else {
    403         return fetchline_fgets();
    404     }
    405 }
    406 
    407 static void prep_fetchline(void *opaque)
    408 {
    409     int *fetchable = opaque;
    410 
    411     qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
    412     *fetchable= 1;
    413 }
    414 
    415 static int do_qemuio_command(const char *cmd)
    416 {
    417     int ret;
    418     AioContext *ctx =
    419         qemuio_blk ? blk_get_aio_context(qemuio_blk) : qemu_get_aio_context();
    420 
    421     aio_context_acquire(ctx);
    422     ret = qemuio_command(qemuio_blk, cmd);
    423     aio_context_release(ctx);
    424 
    425     return ret;
    426 }
    427 
    428 static int command_loop(void)
    429 {
    430     int i, fetchable = 0, prompted = 0;
    431     int ret, last_error = 0;
    432     char *input;
    433 
    434     for (i = 0; !quit_qemu_io && i < ncmdline; i++) {
    435         ret = do_qemuio_command(cmdline[i]);
    436         if (ret < 0) {
    437             last_error = ret;
    438         }
    439     }
    440     if (cmdline) {
    441         g_free(cmdline);
    442         return last_error;
    443     }
    444 
    445     while (!quit_qemu_io) {
    446         if (!prompted) {
    447             printf("%s", get_prompt());
    448             fflush(stdout);
    449             qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable);
    450             prompted = 1;
    451         }
    452 
    453         main_loop_wait(false);
    454 
    455         if (!fetchable) {
    456             continue;
    457         }
    458 
    459         input = fetchline();
    460         if (input == NULL) {
    461             break;
    462         }
    463         ret = do_qemuio_command(input);
    464         g_free(input);
    465 
    466         if (ret < 0) {
    467             last_error = ret;
    468         }
    469 
    470         prompted = 0;
    471         fetchable = 0;
    472     }
    473     qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
    474 
    475     return last_error;
    476 }
    477 
    478 static void add_user_command(char *optarg)
    479 {
    480     cmdline = g_renew(char *, cmdline, ++ncmdline);
    481     cmdline[ncmdline-1] = optarg;
    482 }
    483 
    484 static void reenable_tty_echo(void)
    485 {
    486     qemu_set_tty_echo(STDIN_FILENO, true);
    487 }
    488 
    489 enum {
    490     OPTION_OBJECT = 256,
    491     OPTION_IMAGE_OPTS = 257,
    492 };
    493 
    494 static QemuOptsList file_opts = {
    495     .name = "file",
    496     .implied_opt_name = "file",
    497     .head = QTAILQ_HEAD_INITIALIZER(file_opts.head),
    498     .desc = {
    499         /* no elements => accept any params */
    500         { /* end of list */ }
    501     },
    502 };
    503 
    504 int main(int argc, char **argv)
    505 {
    506     int readonly = 0;
    507     const char *sopt = "hVc:d:f:rsnCmki:t:T:U";
    508     const struct option lopt[] = {
    509         { "help", no_argument, NULL, 'h' },
    510         { "version", no_argument, NULL, 'V' },
    511         { "cmd", required_argument, NULL, 'c' },
    512         { "format", required_argument, NULL, 'f' },
    513         { "read-only", no_argument, NULL, 'r' },
    514         { "snapshot", no_argument, NULL, 's' },
    515         { "nocache", no_argument, NULL, 'n' },
    516         { "copy-on-read", no_argument, NULL, 'C' },
    517         { "misalign", no_argument, NULL, 'm' },
    518         { "native-aio", no_argument, NULL, 'k' },
    519         { "aio", required_argument, NULL, 'i' },
    520         { "discard", required_argument, NULL, 'd' },
    521         { "cache", required_argument, NULL, 't' },
    522         { "trace", required_argument, NULL, 'T' },
    523         { "object", required_argument, NULL, OPTION_OBJECT },
    524         { "image-opts", no_argument, NULL, OPTION_IMAGE_OPTS },
    525         { "force-share", no_argument, 0, 'U'},
    526         { NULL, 0, NULL, 0 }
    527     };
    528     int c;
    529     int opt_index = 0;
    530     int flags = BDRV_O_UNMAP;
    531     int ret;
    532     bool writethrough = true;
    533     QDict *opts = NULL;
    534     const char *format = NULL;
    535     bool force_share = false;
    536 
    537 #ifdef CONFIG_POSIX
    538     signal(SIGPIPE, SIG_IGN);
    539 #endif
    540 
    541     socket_init();
    542     error_init(argv[0]);
    543     module_call_init(MODULE_INIT_TRACE);
    544     qemu_init_exec_dir(argv[0]);
    545 
    546     qcrypto_init(&error_fatal);
    547 
    548     module_call_init(MODULE_INIT_QOM);
    549     qemu_add_opts(&qemu_trace_opts);
    550     bdrv_init();
    551 
    552     while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
    553         switch (c) {
    554         case 's':
    555             flags |= BDRV_O_SNAPSHOT;
    556             break;
    557         case 'n':
    558             flags |= BDRV_O_NOCACHE;
    559             writethrough = false;
    560             break;
    561         case 'C':
    562             flags |= BDRV_O_COPY_ON_READ;
    563             break;
    564         case 'd':
    565             if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
    566                 error_report("Invalid discard option: %s", optarg);
    567                 exit(1);
    568             }
    569             break;
    570         case 'f':
    571             format = optarg;
    572             break;
    573         case 'c':
    574             add_user_command(optarg);
    575             break;
    576         case 'r':
    577             readonly = 1;
    578             break;
    579         case 'm':
    580             qemuio_misalign = true;
    581             break;
    582         case 'k':
    583             flags |= BDRV_O_NATIVE_AIO;
    584             break;
    585         case 'i':
    586             if (bdrv_parse_aio(optarg, &flags) < 0) {
    587                 error_report("Invalid aio option: %s", optarg);
    588                 exit(1);
    589             }
    590             break;
    591         case 't':
    592             if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) {
    593                 error_report("Invalid cache option: %s", optarg);
    594                 exit(1);
    595             }
    596             break;
    597         case 'T':
    598             trace_opt_parse(optarg);
    599             break;
    600         case 'V':
    601             printf("%s version " QEMU_FULL_VERSION "\n"
    602                    QEMU_COPYRIGHT "\n", g_get_prgname());
    603             exit(0);
    604         case 'h':
    605             usage(g_get_prgname());
    606             exit(0);
    607         case 'U':
    608             force_share = true;
    609             break;
    610         case OPTION_OBJECT:
    611             user_creatable_process_cmdline(optarg);
    612             break;
    613         case OPTION_IMAGE_OPTS:
    614             imageOpts = true;
    615             break;
    616         default:
    617             usage(g_get_prgname());
    618             exit(1);
    619         }
    620     }
    621 
    622     if ((argc - optind) > 1) {
    623         usage(g_get_prgname());
    624         exit(1);
    625     }
    626 
    627     if (format && imageOpts) {
    628         error_report("--image-opts and -f are mutually exclusive");
    629         exit(1);
    630     }
    631 
    632     qemu_init_main_loop(&error_fatal);
    633 
    634     if (!trace_init_backends()) {
    635         exit(1);
    636     }
    637     trace_init_file();
    638     qemu_set_log(LOG_TRACE, &error_fatal);
    639 
    640     /* initialize commands */
    641     qemuio_add_command(&quit_cmd);
    642     qemuio_add_command(&open_cmd);
    643     qemuio_add_command(&close_cmd);
    644 
    645     if (isatty(STDIN_FILENO)) {
    646         ttyEOF = get_eof_char();
    647         readline_state = readline_init(readline_printf_func,
    648                                        readline_flush_func,
    649                                        NULL,
    650                                        readline_completion_func);
    651         qemu_set_tty_echo(STDIN_FILENO, false);
    652         atexit(reenable_tty_echo);
    653     }
    654 
    655     /* open the device */
    656     if (!readonly) {
    657         flags |= BDRV_O_RDWR;
    658     }
    659 
    660     if ((argc - optind) == 1) {
    661         if (imageOpts) {
    662             QemuOpts *qopts = NULL;
    663             qopts = qemu_opts_parse_noisily(&file_opts, argv[optind], false);
    664             if (!qopts) {
    665                 exit(1);
    666             }
    667             opts = qemu_opts_to_qdict(qopts, NULL);
    668             if (openfile(NULL, flags, writethrough, force_share, opts)) {
    669                 exit(1);
    670             }
    671         } else {
    672             if (format) {
    673                 opts = qdict_new();
    674                 qdict_put_str(opts, "driver", format);
    675             }
    676             if (openfile(argv[optind], flags, writethrough,
    677                          force_share, opts)) {
    678                 exit(1);
    679             }
    680         }
    681     }
    682     ret = command_loop();
    683 
    684     /*
    685      * Make sure all outstanding requests complete before the program exits.
    686      */
    687     bdrv_drain_all();
    688 
    689     blk_unref(qemuio_blk);
    690     g_free(readline_state);
    691 
    692     if (ret < 0) {
    693         return 1;
    694     } else {
    695         return 0;
    696     }
    697 }