You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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