1e3aff4f6Saliguori /* 2e3aff4f6Saliguori * Command line utility to exercise the QEMU I/O path. 3e3aff4f6Saliguori * 4e3aff4f6Saliguori * Copyright (C) 2009 Red Hat, Inc. 5e3aff4f6Saliguori * Copyright (c) 2003-2005 Silicon Graphics, Inc. 6e3aff4f6Saliguori * 7e3aff4f6Saliguori * This work is licensed under the terms of the GNU GPL, version 2 or later. 8e3aff4f6Saliguori * See the COPYING file in the top-level directory. 9e3aff4f6Saliguori */ 10452fcdbcSMarkus Armbruster 1180c71a24SPeter Maydell #include "qemu/osdep.h" 12e3aff4f6Saliguori #include <getopt.h> 13c32d766aSStefan Weil #include <libgen.h> 140e448a05SDaniel P. Berrange #ifndef _WIN32 150e448a05SDaniel P. Berrange #include <termios.h> 160e448a05SDaniel P. Berrange #endif 17e3aff4f6Saliguori 1849f95221SMarc-André Lureau #include "qemu/help-texts.h" 1906680b15SMarc-André Lureau #include "qemu/cutils.h" 20da34e65cSMarkus Armbruster #include "qapi/error.h" 213d21994fSKevin Wolf #include "qemu-io.h" 22d49b6836SMarkus Armbruster #include "qemu/error-report.h" 231de7afc9SPaolo Bonzini #include "qemu/main-loop.h" 240b8fa32fSMarkus Armbruster #include "qemu/module.h" 25b543c5cdSMax Reitz #include "qemu/option.h" 26b543c5cdSMax Reitz #include "qemu/config-file.h" 270cf17e18SStefan Hajnoczi #include "qemu/readline.h" 28e9a80859SDenis V. Lunev #include "qemu/log.h" 2998c5d2e7SDaniel P. Berrangé #include "qemu/sockets.h" 30*407bc4bfSDaniel P. Berrangé #include "qobject/qstring.h" 31*407bc4bfSDaniel P. Berrangé #include "qobject/qdict.h" 329ba371b6SDaniel P. Berrange #include "qom/object_interfaces.h" 3332cad1ffSPhilippe Mathieu-Daudé #include "system/block-backend.h" 34737e150eSPaolo Bonzini #include "block/block_int.h" 35d7bb72c8SStefan Hajnoczi #include "trace/control.h" 36c2297088SDaniel P. Berrange #include "crypto/init.h" 374face32aSEric Blake #include "qemu-version.h" 38e3aff4f6Saliguori 39e3aff4f6Saliguori #define CMD_NOFILE_OK 0x01 40e3aff4f6Saliguori 4126f54e9aSMarkus Armbruster static BlockBackend *qemuio_blk; 42b444d0e9SMax Reitz static bool quit_qemu_io; 43191c2890SKevin Wolf 44d1174f13SKevin Wolf /* qemu-io commands passed using -c */ 45d1174f13SKevin Wolf static int ncmdline; 46d1174f13SKevin Wolf static char **cmdline; 47499afa25SDaniel P. Berrange static bool imageOpts; 48d1174f13SKevin Wolf 490cf17e18SStefan Hajnoczi static ReadLineState *readline_state; 500cf17e18SStefan Hajnoczi 510e448a05SDaniel P. Berrange static int ttyEOF; 520e448a05SDaniel P. Berrange 530e448a05SDaniel P. Berrange static int get_eof_char(void) 540e448a05SDaniel P. Berrange { 550e448a05SDaniel P. Berrange #ifdef _WIN32 560e448a05SDaniel P. Berrange return 0x4; /* Ctrl-D */ 570e448a05SDaniel P. Berrange #else 580e448a05SDaniel P. Berrange struct termios tty; 590e448a05SDaniel P. Berrange if (tcgetattr(STDIN_FILENO, &tty) != 0) { 600e448a05SDaniel P. Berrange if (errno == ENOTTY) { 610e448a05SDaniel P. Berrange return 0x0; /* just expect read() == 0 */ 620e448a05SDaniel P. Berrange } else { 630e448a05SDaniel P. Berrange return 0x4; /* Ctrl-D */ 640e448a05SDaniel P. Berrange } 650e448a05SDaniel P. Berrange } 660e448a05SDaniel P. Berrange 670e448a05SDaniel P. Berrange return tty.c_cc[VEOF]; 680e448a05SDaniel P. Berrange #endif 690e448a05SDaniel P. Berrange } 700e448a05SDaniel P. Berrange 71b32d7a39SMax Reitz static int close_f(BlockBackend *blk, int argc, char **argv) 72e3aff4f6Saliguori { 7326f54e9aSMarkus Armbruster blk_unref(qemuio_blk); 7426f54e9aSMarkus Armbruster qemuio_blk = NULL; 75b32d7a39SMax Reitz return 0; 76e3aff4f6Saliguori } 77e3aff4f6Saliguori 78e3aff4f6Saliguori static const cmdinfo_t close_cmd = { 79e3aff4f6Saliguori .name = "close", 80e3aff4f6Saliguori .altname = "c", 81e3aff4f6Saliguori .cfunc = close_f, 82e3aff4f6Saliguori .oneline = "close the current open file", 83e3aff4f6Saliguori }; 84e3aff4f6Saliguori 85459571f7SFam Zheng static int openfile(char *name, int flags, bool writethrough, bool force_share, 86459571f7SFam Zheng QDict *opts) 87e3aff4f6Saliguori { 8834b5d2c6SMax Reitz Error *local_err = NULL; 8934b5d2c6SMax Reitz 901b58b438SMax Reitz if (qemuio_blk) { 91b9884681SMarkus Armbruster error_report("file open already, try 'help close'"); 92cb3e7f08SMarc-André Lureau qobject_unref(opts); 93e3aff4f6Saliguori return 1; 94e3aff4f6Saliguori } 95e3aff4f6Saliguori 96459571f7SFam Zheng if (force_share) { 97459571f7SFam Zheng if (!opts) { 98459571f7SFam Zheng opts = qdict_new(); 99459571f7SFam Zheng } 100459571f7SFam Zheng if (qdict_haskey(opts, BDRV_OPT_FORCE_SHARE) 1012a01c01fSMax Reitz && strcmp(qdict_get_str(opts, BDRV_OPT_FORCE_SHARE), "on")) { 102459571f7SFam Zheng error_report("-U conflicts with image options"); 103cb3e7f08SMarc-André Lureau qobject_unref(opts); 104459571f7SFam Zheng return 1; 105459571f7SFam Zheng } 1062a01c01fSMax Reitz qdict_put_str(opts, BDRV_OPT_FORCE_SHARE, "on"); 107459571f7SFam Zheng } 108efaa7c4eSMax Reitz qemuio_blk = blk_new_open(name, NULL, opts, flags, &local_err); 1091b58b438SMax Reitz if (!qemuio_blk) { 110b9884681SMarkus Armbruster error_reportf_err(local_err, "can't open%s%s: ", 111b9884681SMarkus Armbruster name ? " device " : "", name ?: ""); 112e3aff4f6Saliguori return 1; 113e3aff4f6Saliguori } 1146db95603SChristoph Hellwig 115e151fc16SKevin Wolf blk_set_enable_write_cache(qemuio_blk, !writethrough); 1168caf0212SDaniel P. Berrange 117e3aff4f6Saliguori return 0; 118e3aff4f6Saliguori } 119e3aff4f6Saliguori 12043642b38SDevin Nakamura static void open_help(void) 121e3aff4f6Saliguori { 122e3aff4f6Saliguori printf( 123e3aff4f6Saliguori "\n" 124e3aff4f6Saliguori " opens a new file in the requested mode\n" 125e3aff4f6Saliguori "\n" 126e3aff4f6Saliguori " Example:\n" 127e4e12bb2SEric Blake " 'open -n -o driver=raw /tmp/data' - opens raw data file read-write, uncached\n" 128e3aff4f6Saliguori "\n" 129e3aff4f6Saliguori " Opens a file for subsequent use by all of the other qemu-io commands.\n" 130e3aff4f6Saliguori " -r, -- open file read-only\n" 131e3aff4f6Saliguori " -s, -- use snapshot file\n" 1320f40444cSEric Blake " -C, -- use copy-on-read\n" 133b8d970f1SEric Blake " -n, -- disable host cache, short for -t none\n" 134459571f7SFam Zheng " -U, -- force shared permissions\n" 1351c5a2aecSAarushi Mehta " -k, -- use kernel AIO implementation (Linux only, prefer use of -i)\n" 1361c5a2aecSAarushi Mehta " -i, -- use AIO mode (threads, native or io_uring)\n" 137b8d970f1SEric Blake " -t, -- use the given cache mode for the image\n" 138b8d970f1SEric Blake " -d, -- use the given discard mode for the image\n" 139b543c5cdSMax Reitz " -o, -- options to be given to the block driver" 140e3aff4f6Saliguori "\n"); 141e3aff4f6Saliguori } 142e3aff4f6Saliguori 143b32d7a39SMax Reitz static int open_f(BlockBackend *blk, int argc, char **argv); 14422a2bdcbSBlue Swirl 14522a2bdcbSBlue Swirl static const cmdinfo_t open_cmd = { 14622a2bdcbSBlue Swirl .name = "open", 14722a2bdcbSBlue Swirl .altname = "o", 14822a2bdcbSBlue Swirl .cfunc = open_f, 14922a2bdcbSBlue Swirl .argmin = 1, 15022a2bdcbSBlue Swirl .argmax = -1, 15122a2bdcbSBlue Swirl .flags = CMD_NOFILE_OK, 1520f40444cSEric Blake .args = "[-rsCnkU] [-t cache] [-d discard] [-o options] [path]", 15322a2bdcbSBlue Swirl .oneline = "open the file specified by path", 15422a2bdcbSBlue Swirl .help = open_help, 15522a2bdcbSBlue Swirl }; 156e3aff4f6Saliguori 157b543c5cdSMax Reitz static QemuOptsList empty_opts = { 158b543c5cdSMax Reitz .name = "drive", 159443422fdSMarkus Armbruster .merge_lists = true, 160b543c5cdSMax Reitz .head = QTAILQ_HEAD_INITIALIZER(empty_opts.head), 161b543c5cdSMax Reitz .desc = { 162b543c5cdSMax Reitz /* no elements => accept any params */ 163b543c5cdSMax Reitz { /* end of list */ } 164b543c5cdSMax Reitz }, 165b543c5cdSMax Reitz }; 166b543c5cdSMax Reitz 167b32d7a39SMax Reitz static int open_f(BlockBackend *blk, int argc, char **argv) 168e3aff4f6Saliguori { 169b8d970f1SEric Blake int flags = BDRV_O_UNMAP; 170e3aff4f6Saliguori int readonly = 0; 171e151fc16SKevin Wolf bool writethrough = true; 172e3aff4f6Saliguori int c; 173b32d7a39SMax Reitz int ret; 174b543c5cdSMax Reitz QemuOpts *qopts; 175443422fdSMarkus Armbruster QDict *opts; 176459571f7SFam Zheng bool force_share = false; 177e3aff4f6Saliguori 1781c5a2aecSAarushi Mehta while ((c = getopt(argc, argv, "snCro:ki:t:d:U")) != -1) { 179e3aff4f6Saliguori switch (c) { 180e3aff4f6Saliguori case 's': 181e3aff4f6Saliguori flags |= BDRV_O_SNAPSHOT; 182e3aff4f6Saliguori break; 183e3aff4f6Saliguori case 'n': 184e151fc16SKevin Wolf flags |= BDRV_O_NOCACHE; 185e151fc16SKevin Wolf writethrough = false; 186e3aff4f6Saliguori break; 1870f40444cSEric Blake case 'C': 1880f40444cSEric Blake flags |= BDRV_O_COPY_ON_READ; 1890f40444cSEric Blake break; 190e3aff4f6Saliguori case 'r': 191e3aff4f6Saliguori readonly = 1; 192e3aff4f6Saliguori break; 193b8d970f1SEric Blake case 'k': 194b8d970f1SEric Blake flags |= BDRV_O_NATIVE_AIO; 195b8d970f1SEric Blake break; 196b8d970f1SEric Blake case 't': 197b8d970f1SEric Blake if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { 198b8d970f1SEric Blake error_report("Invalid cache option: %s", optarg); 199b8d970f1SEric Blake qemu_opts_reset(&empty_opts); 200b32d7a39SMax Reitz return -EINVAL; 201b8d970f1SEric Blake } 202b8d970f1SEric Blake break; 203b8d970f1SEric Blake case 'd': 204b8d970f1SEric Blake if (bdrv_parse_discard_flags(optarg, &flags) < 0) { 205b8d970f1SEric Blake error_report("Invalid discard option: %s", optarg); 206b8d970f1SEric Blake qemu_opts_reset(&empty_opts); 207b32d7a39SMax Reitz return -EINVAL; 208b8d970f1SEric Blake } 209b8d970f1SEric Blake break; 2101c5a2aecSAarushi Mehta case 'i': 2111c5a2aecSAarushi Mehta if (bdrv_parse_aio(optarg, &flags) < 0) { 2121c5a2aecSAarushi Mehta error_report("Invalid aio option: %s", optarg); 2131c5a2aecSAarushi Mehta qemu_opts_reset(&empty_opts); 2141c5a2aecSAarushi Mehta return -EINVAL; 2151c5a2aecSAarushi Mehta } 2161c5a2aecSAarushi Mehta break; 217b543c5cdSMax Reitz case 'o': 218499afa25SDaniel P. Berrange if (imageOpts) { 219499afa25SDaniel P. Berrange printf("--image-opts and 'open -o' are mutually exclusive\n"); 220b8d970f1SEric Blake qemu_opts_reset(&empty_opts); 221b32d7a39SMax Reitz return -EINVAL; 222499afa25SDaniel P. Berrange } 22370b94331SMarkus Armbruster if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) { 224443422fdSMarkus Armbruster qemu_opts_reset(&empty_opts); 225b32d7a39SMax Reitz return -EINVAL; 226b543c5cdSMax Reitz } 227b543c5cdSMax Reitz break; 228459571f7SFam Zheng case 'U': 229459571f7SFam Zheng force_share = true; 230459571f7SFam Zheng break; 231e3aff4f6Saliguori default: 232443422fdSMarkus Armbruster qemu_opts_reset(&empty_opts); 233b444d0e9SMax Reitz qemuio_command_usage(&open_cmd); 234b32d7a39SMax Reitz return -EINVAL; 235e3aff4f6Saliguori } 236e3aff4f6Saliguori } 237e3aff4f6Saliguori 238f5edb014SNaphtali Sprei if (!readonly) { 239e3aff4f6Saliguori flags |= BDRV_O_RDWR; 240f5edb014SNaphtali Sprei } 241e3aff4f6Saliguori 242499afa25SDaniel P. Berrange if (imageOpts && (optind == argc - 1)) { 243499afa25SDaniel P. Berrange if (!qemu_opts_parse_noisily(&empty_opts, argv[optind], false)) { 244499afa25SDaniel P. Berrange qemu_opts_reset(&empty_opts); 245b32d7a39SMax Reitz return -EINVAL; 246499afa25SDaniel P. Berrange } 247499afa25SDaniel P. Berrange optind++; 248499afa25SDaniel P. Berrange } 249499afa25SDaniel P. Berrange 250443422fdSMarkus Armbruster qopts = qemu_opts_find(&empty_opts, NULL); 251443422fdSMarkus Armbruster opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL; 252443422fdSMarkus Armbruster qemu_opts_reset(&empty_opts); 253443422fdSMarkus Armbruster 254fd0fee34SMax Reitz if (optind == argc - 1) { 255b32d7a39SMax Reitz ret = openfile(argv[optind], flags, writethrough, force_share, opts); 256fd0fee34SMax Reitz } else if (optind == argc) { 257b32d7a39SMax Reitz ret = openfile(NULL, flags, writethrough, force_share, opts); 258fd0fee34SMax Reitz } else { 259cb3e7f08SMarc-André Lureau qobject_unref(opts); 26064ebf556SEric Blake qemuio_command_usage(&open_cmd); 261b32d7a39SMax Reitz return -EINVAL; 262e3aff4f6Saliguori } 263e3aff4f6Saliguori 264b32d7a39SMax Reitz if (ret) { 265b32d7a39SMax Reitz return -EINVAL; 266b32d7a39SMax Reitz } 267b32d7a39SMax Reitz 268b32d7a39SMax Reitz return 0; 269b32d7a39SMax Reitz } 270b32d7a39SMax Reitz 271b32d7a39SMax Reitz static int quit_f(BlockBackend *blk, int argc, char **argv) 272e681be7eSKevin Wolf { 273b444d0e9SMax Reitz quit_qemu_io = true; 274b32d7a39SMax Reitz return 0; 275e681be7eSKevin Wolf } 276e681be7eSKevin Wolf 277e681be7eSKevin Wolf static const cmdinfo_t quit_cmd = { 278e681be7eSKevin Wolf .name = "quit", 279e681be7eSKevin Wolf .altname = "q", 280e681be7eSKevin Wolf .cfunc = quit_f, 281e681be7eSKevin Wolf .argmin = -1, 282e681be7eSKevin Wolf .argmax = -1, 283e681be7eSKevin Wolf .flags = CMD_FLAG_GLOBAL, 284e681be7eSKevin Wolf .oneline = "exit the program", 285e681be7eSKevin Wolf }; 286e681be7eSKevin Wolf 287e3aff4f6Saliguori static void usage(const char *name) 288e3aff4f6Saliguori { 289e3aff4f6Saliguori printf( 290e4e12bb2SEric Blake "Usage: %s [OPTIONS]... [-c STRING]... [file]\n" 29184844a20SStefan Weil "QEMU Disk exerciser\n" 292e3aff4f6Saliguori "\n" 2939ba371b6SDaniel P. Berrange " --object OBJECTDEF define an object such as 'secret' for\n" 2949ba371b6SDaniel P. Berrange " passwords and/or encryption keys\n" 295e4e12bb2SEric Blake " --image-opts treat file as option string\n" 296d208cc35SMaria Kustova " -c, --cmd STRING execute command with its arguments\n" 297d208cc35SMaria Kustova " from the given string\n" 298be6273daSKevin Wolf " -f, --format FMT specifies the block driver to use\n" 299e3aff4f6Saliguori " -r, --read-only export read-only\n" 300e3aff4f6Saliguori " -s, --snapshot use snapshot file\n" 301e4e12bb2SEric Blake " -n, --nocache disable host cache, short for -t none\n" 3020f40444cSEric Blake " -C, --copy-on-read enable copy-on-read\n" 303e3aff4f6Saliguori " -m, --misalign misalign allocations for O_DIRECT\n" 3041c5a2aecSAarushi Mehta " -k, --native-aio use kernel AIO implementation\n" 3051c5a2aecSAarushi Mehta " (Linux only, prefer use of -i)\n" 3061c5a2aecSAarushi Mehta " -i, --aio=MODE use AIO mode (threads, native or io_uring)\n" 307592fa070SKevin Wolf " -t, --cache=MODE use the given cache mode for the image\n" 308e4e12bb2SEric Blake " -d, --discard=MODE use the given discard mode for the image\n" 309e9a80859SDenis V. Lunev " -T, --trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n" 310e9a80859SDenis V. Lunev " specify tracing options\n" 311e9a80859SDenis V. Lunev " see qemu-img(1) man page for full description\n" 312459571f7SFam Zheng " -U, --force-share force shared permissions\n" 313e3aff4f6Saliguori " -h, --help display this help and exit\n" 314e3aff4f6Saliguori " -V, --version output version information and exit\n" 315d208cc35SMaria Kustova "\n" 316f5048cb7SEric Blake "See '%s -c help' for information on available commands.\n" 317f5048cb7SEric Blake "\n" 318f5048cb7SEric Blake QEMU_HELP_BOTTOM "\n", 319d208cc35SMaria Kustova name, name); 320e3aff4f6Saliguori } 321e3aff4f6Saliguori 322d1174f13SKevin Wolf static char *get_prompt(void) 323d1174f13SKevin Wolf { 324d1174f13SKevin Wolf static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ]; 325d1174f13SKevin Wolf 326d1174f13SKevin Wolf if (!prompt[0]) { 327336d354bSMarc-André Lureau snprintf(prompt, sizeof(prompt), "%s> ", g_get_prgname()); 328d1174f13SKevin Wolf } 329d1174f13SKevin Wolf 330d1174f13SKevin Wolf return prompt; 331d1174f13SKevin Wolf } 332d1174f13SKevin Wolf 3339edc6313SMarc-André Lureau static void G_GNUC_PRINTF(2, 3) readline_printf_func(void *opaque, 334d5d1507bSStefan Weil const char *fmt, ...) 335d1174f13SKevin Wolf { 3360cf17e18SStefan Hajnoczi va_list ap; 3370cf17e18SStefan Hajnoczi va_start(ap, fmt); 3380cf17e18SStefan Hajnoczi vprintf(fmt, ap); 3390cf17e18SStefan Hajnoczi va_end(ap); 3400cf17e18SStefan Hajnoczi } 3410cf17e18SStefan Hajnoczi 3420cf17e18SStefan Hajnoczi static void readline_flush_func(void *opaque) 3430cf17e18SStefan Hajnoczi { 3440cf17e18SStefan Hajnoczi fflush(stdout); 3450cf17e18SStefan Hajnoczi } 3460cf17e18SStefan Hajnoczi 3470cf17e18SStefan Hajnoczi static void readline_func(void *opaque, const char *str, void *readline_opaque) 3480cf17e18SStefan Hajnoczi { 3490cf17e18SStefan Hajnoczi char **line = readline_opaque; 3500cf17e18SStefan Hajnoczi *line = g_strdup(str); 3510cf17e18SStefan Hajnoczi } 3520cf17e18SStefan Hajnoczi 3534694020dSStefan Hajnoczi static void completion_match(const char *cmd, void *opaque) 3544694020dSStefan Hajnoczi { 3554694020dSStefan Hajnoczi readline_add_completion(readline_state, cmd); 3564694020dSStefan Hajnoczi } 3574694020dSStefan Hajnoczi 3580cf17e18SStefan Hajnoczi static void readline_completion_func(void *opaque, const char *str) 3590cf17e18SStefan Hajnoczi { 3604694020dSStefan Hajnoczi readline_set_completion_index(readline_state, strlen(str)); 3614694020dSStefan Hajnoczi qemuio_complete_command(str, completion_match, NULL); 3620cf17e18SStefan Hajnoczi } 3630cf17e18SStefan Hajnoczi 3640cf17e18SStefan Hajnoczi static char *fetchline_readline(void) 3650cf17e18SStefan Hajnoczi { 3660cf17e18SStefan Hajnoczi char *line = NULL; 3670cf17e18SStefan Hajnoczi 3680cf17e18SStefan Hajnoczi readline_start(readline_state, get_prompt(), 0, readline_func, &line); 3690cf17e18SStefan Hajnoczi while (!line) { 3700cf17e18SStefan Hajnoczi int ch = getchar(); 3710e448a05SDaniel P. Berrange if (ttyEOF != 0x0 && ch == ttyEOF) { 3720e448a05SDaniel P. Berrange printf("\n"); 3730cf17e18SStefan Hajnoczi break; 3740cf17e18SStefan Hajnoczi } 3750cf17e18SStefan Hajnoczi readline_handle_byte(readline_state, ch); 376d1174f13SKevin Wolf } 377d1174f13SKevin Wolf return line; 378d1174f13SKevin Wolf } 379d1174f13SKevin Wolf 380d1174f13SKevin Wolf #define MAXREADLINESZ 1024 3810cf17e18SStefan Hajnoczi static char *fetchline_fgets(void) 382d1174f13SKevin Wolf { 383d1174f13SKevin Wolf char *p, *line = g_malloc(MAXREADLINESZ); 384d1174f13SKevin Wolf 385d1174f13SKevin Wolf if (!fgets(line, MAXREADLINESZ, stdin)) { 386d1174f13SKevin Wolf g_free(line); 387d1174f13SKevin Wolf return NULL; 388d1174f13SKevin Wolf } 389d1174f13SKevin Wolf 390d1174f13SKevin Wolf p = line + strlen(line); 391d1174f13SKevin Wolf if (p != line && p[-1] == '\n') { 392d1174f13SKevin Wolf p[-1] = '\0'; 393d1174f13SKevin Wolf } 394d1174f13SKevin Wolf 395d1174f13SKevin Wolf return line; 396d1174f13SKevin Wolf } 3970cf17e18SStefan Hajnoczi 3980cf17e18SStefan Hajnoczi static char *fetchline(void) 3990cf17e18SStefan Hajnoczi { 4000cf17e18SStefan Hajnoczi if (readline_state) { 4010cf17e18SStefan Hajnoczi return fetchline_readline(); 4020cf17e18SStefan Hajnoczi } else { 4030cf17e18SStefan Hajnoczi return fetchline_fgets(); 4040cf17e18SStefan Hajnoczi } 4050cf17e18SStefan Hajnoczi } 406d1174f13SKevin Wolf 407d1174f13SKevin Wolf static void prep_fetchline(void *opaque) 408d1174f13SKevin Wolf { 409d1174f13SKevin Wolf int *fetchable = opaque; 410d1174f13SKevin Wolf 411d1174f13SKevin Wolf qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); 412d1174f13SKevin Wolf *fetchable= 1; 413d1174f13SKevin Wolf } 414d1174f13SKevin Wolf 41578632a3dSVladimir Sementsov-Ogievskiy static int do_qemuio_command(const char *cmd) 41678632a3dSVladimir Sementsov-Ogievskiy { 417b49f4755SStefan Hajnoczi return qemuio_command(qemuio_blk, cmd); 41878632a3dSVladimir Sementsov-Ogievskiy } 41978632a3dSVladimir Sementsov-Ogievskiy 4206b3aa848SMax Reitz static int command_loop(void) 421d1174f13SKevin Wolf { 422b444d0e9SMax Reitz int i, fetchable = 0, prompted = 0; 4236b3aa848SMax Reitz int ret, last_error = 0; 424d1174f13SKevin Wolf char *input; 425d1174f13SKevin Wolf 426b444d0e9SMax Reitz for (i = 0; !quit_qemu_io && i < ncmdline; i++) { 42778632a3dSVladimir Sementsov-Ogievskiy ret = do_qemuio_command(cmdline[i]); 4286b3aa848SMax Reitz if (ret < 0) { 4296b3aa848SMax Reitz last_error = ret; 4306b3aa848SMax Reitz } 431d1174f13SKevin Wolf } 432d1174f13SKevin Wolf if (cmdline) { 433d1174f13SKevin Wolf g_free(cmdline); 4346b3aa848SMax Reitz return last_error; 435d1174f13SKevin Wolf } 436d1174f13SKevin Wolf 437b444d0e9SMax Reitz while (!quit_qemu_io) { 438d1174f13SKevin Wolf if (!prompted) { 439d1174f13SKevin Wolf printf("%s", get_prompt()); 440d1174f13SKevin Wolf fflush(stdout); 441d1174f13SKevin Wolf qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable); 442d1174f13SKevin Wolf prompted = 1; 443d1174f13SKevin Wolf } 444d1174f13SKevin Wolf 445d1174f13SKevin Wolf main_loop_wait(false); 446d1174f13SKevin Wolf 447d1174f13SKevin Wolf if (!fetchable) { 448d1174f13SKevin Wolf continue; 449d1174f13SKevin Wolf } 450d1174f13SKevin Wolf 451d1174f13SKevin Wolf input = fetchline(); 452d1174f13SKevin Wolf if (input == NULL) { 453d1174f13SKevin Wolf break; 454d1174f13SKevin Wolf } 45578632a3dSVladimir Sementsov-Ogievskiy ret = do_qemuio_command(input); 456d1174f13SKevin Wolf g_free(input); 457d1174f13SKevin Wolf 4586b3aa848SMax Reitz if (ret < 0) { 4596b3aa848SMax Reitz last_error = ret; 4606b3aa848SMax Reitz } 4616b3aa848SMax Reitz 462d1174f13SKevin Wolf prompted = 0; 463d1174f13SKevin Wolf fetchable = 0; 464d1174f13SKevin Wolf } 465d1174f13SKevin Wolf qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL); 4666b3aa848SMax Reitz 4676b3aa848SMax Reitz return last_error; 468d1174f13SKevin Wolf } 469d1174f13SKevin Wolf 47021c029e6SPhilippe Mathieu-Daudé static void add_user_command(char *user_cmd) 471d1174f13SKevin Wolf { 4725839e53bSMarkus Armbruster cmdline = g_renew(char *, cmdline, ++ncmdline); 47321c029e6SPhilippe Mathieu-Daudé cmdline[ncmdline - 1] = user_cmd; 474d1174f13SKevin Wolf } 475d1174f13SKevin Wolf 4760cf17e18SStefan Hajnoczi static void reenable_tty_echo(void) 4770cf17e18SStefan Hajnoczi { 4780cf17e18SStefan Hajnoczi qemu_set_tty_echo(STDIN_FILENO, true); 4790cf17e18SStefan Hajnoczi } 4800cf17e18SStefan Hajnoczi 4819ba371b6SDaniel P. Berrange enum { 4829ba371b6SDaniel P. Berrange OPTION_OBJECT = 256, 483499afa25SDaniel P. Berrange OPTION_IMAGE_OPTS = 257, 4849ba371b6SDaniel P. Berrange }; 4859ba371b6SDaniel P. Berrange 486499afa25SDaniel P. Berrange static QemuOptsList file_opts = { 487499afa25SDaniel P. Berrange .name = "file", 488499afa25SDaniel P. Berrange .implied_opt_name = "file", 489499afa25SDaniel P. Berrange .head = QTAILQ_HEAD_INITIALIZER(file_opts.head), 490499afa25SDaniel P. Berrange .desc = { 491499afa25SDaniel P. Berrange /* no elements => accept any params */ 492499afa25SDaniel P. Berrange { /* end of list */ } 493499afa25SDaniel P. Berrange }, 494499afa25SDaniel P. Berrange }; 495499afa25SDaniel P. Berrange 496e3aff4f6Saliguori int main(int argc, char **argv) 497e3aff4f6Saliguori { 498e3aff4f6Saliguori int readonly = 0; 4991c5a2aecSAarushi Mehta const char *sopt = "hVc:d:f:rsnCmki:t:T:U"; 500b32bb952SBlue Swirl const struct option lopt[] = { 501a513416eSDaniel P. Berrange { "help", no_argument, NULL, 'h' }, 502a513416eSDaniel P. Berrange { "version", no_argument, NULL, 'V' }, 503a513416eSDaniel P. Berrange { "cmd", required_argument, NULL, 'c' }, 504a513416eSDaniel P. Berrange { "format", required_argument, NULL, 'f' }, 505a513416eSDaniel P. Berrange { "read-only", no_argument, NULL, 'r' }, 506a513416eSDaniel P. Berrange { "snapshot", no_argument, NULL, 's' }, 507a513416eSDaniel P. Berrange { "nocache", no_argument, NULL, 'n' }, 5080f40444cSEric Blake { "copy-on-read", no_argument, NULL, 'C' }, 509a513416eSDaniel P. Berrange { "misalign", no_argument, NULL, 'm' }, 510a513416eSDaniel P. Berrange { "native-aio", no_argument, NULL, 'k' }, 5111c5a2aecSAarushi Mehta { "aio", required_argument, NULL, 'i' }, 512a513416eSDaniel P. Berrange { "discard", required_argument, NULL, 'd' }, 513a513416eSDaniel P. Berrange { "cache", required_argument, NULL, 't' }, 514a513416eSDaniel P. Berrange { "trace", required_argument, NULL, 'T' }, 515a513416eSDaniel P. Berrange { "object", required_argument, NULL, OPTION_OBJECT }, 516a513416eSDaniel P. Berrange { "image-opts", no_argument, NULL, OPTION_IMAGE_OPTS }, 517459571f7SFam Zheng { "force-share", no_argument, 0, 'U'}, 518660f11beSBlue Swirl { NULL, 0, NULL, 0 } 519e3aff4f6Saliguori }; 520e3aff4f6Saliguori int c; 521e3aff4f6Saliguori int opt_index = 0; 5229e8f1835SPaolo Bonzini int flags = BDRV_O_UNMAP; 5236b3aa848SMax Reitz int ret; 524e151fc16SKevin Wolf bool writethrough = true; 5251b58b438SMax Reitz QDict *opts = NULL; 526499afa25SDaniel P. Berrange const char *format = NULL; 527459571f7SFam Zheng bool force_share = false; 528e3aff4f6Saliguori 529526eda14SMORITA Kazutaka #ifdef CONFIG_POSIX 530526eda14SMORITA Kazutaka signal(SIGPIPE, SIG_IGN); 531526eda14SMORITA Kazutaka #endif 532526eda14SMORITA Kazutaka 53398c5d2e7SDaniel P. Berrangé socket_init(); 534f5852efaSChristophe Fergeau error_init(argv[0]); 535fe4db84dSDaniel P. Berrange module_call_init(MODULE_INIT_TRACE); 53610f5bff6SFam Zheng qemu_init_exec_dir(argv[0]); 537e3aff4f6Saliguori 538e8f2d272SEduardo Habkost qcrypto_init(&error_fatal); 539c2297088SDaniel P. Berrange 540064097d9SDaniel P. Berrange module_call_init(MODULE_INIT_QOM); 541e9a80859SDenis V. Lunev qemu_add_opts(&qemu_trace_opts); 542be6273daSKevin Wolf bdrv_init(); 543be6273daSKevin Wolf 544e3aff4f6Saliguori while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) { 545e3aff4f6Saliguori switch (c) { 546e3aff4f6Saliguori case 's': 547e3aff4f6Saliguori flags |= BDRV_O_SNAPSHOT; 548e3aff4f6Saliguori break; 549e3aff4f6Saliguori case 'n': 550e151fc16SKevin Wolf flags |= BDRV_O_NOCACHE; 551e151fc16SKevin Wolf writethrough = false; 552e3aff4f6Saliguori break; 5530f40444cSEric Blake case 'C': 5540f40444cSEric Blake flags |= BDRV_O_COPY_ON_READ; 5550f40444cSEric Blake break; 5569e8f1835SPaolo Bonzini case 'd': 5579e8f1835SPaolo Bonzini if (bdrv_parse_discard_flags(optarg, &flags) < 0) { 5589e8f1835SPaolo Bonzini error_report("Invalid discard option: %s", optarg); 5599e8f1835SPaolo Bonzini exit(1); 5609e8f1835SPaolo Bonzini } 5619e8f1835SPaolo Bonzini break; 562be6273daSKevin Wolf case 'f': 563499afa25SDaniel P. Berrange format = optarg; 564be6273daSKevin Wolf break; 565e3aff4f6Saliguori case 'c': 566e3aff4f6Saliguori add_user_command(optarg); 567e3aff4f6Saliguori break; 568e3aff4f6Saliguori case 'r': 569e3aff4f6Saliguori readonly = 1; 570e3aff4f6Saliguori break; 571e3aff4f6Saliguori case 'm': 572f9883880SStefan Weil qemuio_misalign = true; 573e3aff4f6Saliguori break; 5745c6c3a6cSChristoph Hellwig case 'k': 5755c6c3a6cSChristoph Hellwig flags |= BDRV_O_NATIVE_AIO; 5765c6c3a6cSChristoph Hellwig break; 5771c5a2aecSAarushi Mehta case 'i': 5781c5a2aecSAarushi Mehta if (bdrv_parse_aio(optarg, &flags) < 0) { 5791c5a2aecSAarushi Mehta error_report("Invalid aio option: %s", optarg); 5801c5a2aecSAarushi Mehta exit(1); 5811c5a2aecSAarushi Mehta } 5821c5a2aecSAarushi Mehta break; 583592fa070SKevin Wolf case 't': 584e151fc16SKevin Wolf if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { 585592fa070SKevin Wolf error_report("Invalid cache option: %s", optarg); 586592fa070SKevin Wolf exit(1); 587592fa070SKevin Wolf } 588592fa070SKevin Wolf break; 589d7bb72c8SStefan Hajnoczi case 'T': 59092eecfffSPaolo Bonzini trace_opt_parse(optarg); 591d7bb72c8SStefan Hajnoczi break; 592e3aff4f6Saliguori case 'V': 5937e563bfbSThomas Huth printf("%s version " QEMU_FULL_VERSION "\n" 594336d354bSMarc-André Lureau QEMU_COPYRIGHT "\n", g_get_prgname()); 595e3aff4f6Saliguori exit(0); 596e3aff4f6Saliguori case 'h': 597336d354bSMarc-André Lureau usage(g_get_prgname()); 598e3aff4f6Saliguori exit(0); 599459571f7SFam Zheng case 'U': 600459571f7SFam Zheng force_share = true; 601459571f7SFam Zheng break; 602b3e79bc6SKevin Wolf case OPTION_OBJECT: 603b3e79bc6SKevin Wolf user_creatable_process_cmdline(optarg); 604b3e79bc6SKevin Wolf break; 605499afa25SDaniel P. Berrange case OPTION_IMAGE_OPTS: 606499afa25SDaniel P. Berrange imageOpts = true; 607499afa25SDaniel P. Berrange break; 608e3aff4f6Saliguori default: 609336d354bSMarc-André Lureau usage(g_get_prgname()); 610e3aff4f6Saliguori exit(1); 611e3aff4f6Saliguori } 612e3aff4f6Saliguori } 613e3aff4f6Saliguori 614e3aff4f6Saliguori if ((argc - optind) > 1) { 615336d354bSMarc-André Lureau usage(g_get_prgname()); 616e3aff4f6Saliguori exit(1); 617e3aff4f6Saliguori } 618e3aff4f6Saliguori 619499afa25SDaniel P. Berrange if (format && imageOpts) { 620499afa25SDaniel P. Berrange error_report("--image-opts and -f are mutually exclusive"); 621499afa25SDaniel P. Berrange exit(1); 622499afa25SDaniel P. Berrange } 623499afa25SDaniel P. Berrange 624f9734d5dSMarkus Armbruster qemu_init_main_loop(&error_fatal); 625a57d1143SZhi Yong Wu 626e9a80859SDenis V. Lunev if (!trace_init_backends()) { 627e9a80859SDenis V. Lunev exit(1); 628e9a80859SDenis V. Lunev } 62992eecfffSPaolo Bonzini trace_init_file(); 630c5955f4fSRichard Henderson qemu_set_log(LOG_TRACE, &error_fatal); 631e9a80859SDenis V. Lunev 632e3aff4f6Saliguori /* initialize commands */ 633c2cdf5c5SKevin Wolf qemuio_add_command(&quit_cmd); 634c2cdf5c5SKevin Wolf qemuio_add_command(&open_cmd); 635c2cdf5c5SKevin Wolf qemuio_add_command(&close_cmd); 636e3aff4f6Saliguori 6370cf17e18SStefan Hajnoczi if (isatty(STDIN_FILENO)) { 6380e448a05SDaniel P. Berrange ttyEOF = get_eof_char(); 6390cf17e18SStefan Hajnoczi readline_state = readline_init(readline_printf_func, 6400cf17e18SStefan Hajnoczi readline_flush_func, 6410cf17e18SStefan Hajnoczi NULL, 6420cf17e18SStefan Hajnoczi readline_completion_func); 6430cf17e18SStefan Hajnoczi qemu_set_tty_echo(STDIN_FILENO, false); 6440cf17e18SStefan Hajnoczi atexit(reenable_tty_echo); 6450cf17e18SStefan Hajnoczi } 6460cf17e18SStefan Hajnoczi 647e3aff4f6Saliguori /* open the device */ 648f5edb014SNaphtali Sprei if (!readonly) { 649e3aff4f6Saliguori flags |= BDRV_O_RDWR; 650f5edb014SNaphtali Sprei } 651e3aff4f6Saliguori 65243642b38SDevin Nakamura if ((argc - optind) == 1) { 653499afa25SDaniel P. Berrange if (imageOpts) { 654499afa25SDaniel P. Berrange QemuOpts *qopts = NULL; 655499afa25SDaniel P. Berrange qopts = qemu_opts_parse_noisily(&file_opts, argv[optind], false); 656499afa25SDaniel P. Berrange if (!qopts) { 657499afa25SDaniel P. Berrange exit(1); 658499afa25SDaniel P. Berrange } 659499afa25SDaniel P. Berrange opts = qemu_opts_to_qdict(qopts, NULL); 660459571f7SFam Zheng if (openfile(NULL, flags, writethrough, force_share, opts)) { 661b7aa1315SNir Soffer exit(1); 662b7aa1315SNir Soffer } 663499afa25SDaniel P. Berrange } else { 664499afa25SDaniel P. Berrange if (format) { 665499afa25SDaniel P. Berrange opts = qdict_new(); 66646f5ac20SEric Blake qdict_put_str(opts, "driver", format); 667499afa25SDaniel P. Berrange } 668459571f7SFam Zheng if (openfile(argv[optind], flags, writethrough, 669459571f7SFam Zheng force_share, opts)) { 670b7aa1315SNir Soffer exit(1); 671b7aa1315SNir Soffer } 67243642b38SDevin Nakamura } 673499afa25SDaniel P. Berrange } 6746b3aa848SMax Reitz ret = command_loop(); 675e3aff4f6Saliguori 67695533d5fSChristoph Hellwig /* 677922453bcSStefan Hajnoczi * Make sure all outstanding requests complete before the program exits. 67895533d5fSChristoph Hellwig */ 679922453bcSStefan Hajnoczi bdrv_drain_all(); 68095533d5fSChristoph Hellwig 68126f54e9aSMarkus Armbruster blk_unref(qemuio_blk); 6820cf17e18SStefan Hajnoczi g_free(readline_state); 6836b3aa848SMax Reitz 6846b3aa848SMax Reitz if (ret < 0) { 6856b3aa848SMax Reitz return 1; 6866b3aa848SMax Reitz } else { 687e3aff4f6Saliguori return 0; 688e3aff4f6Saliguori } 6896b3aa848SMax Reitz } 690