Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

715 rindas
18KB

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