qemu-io.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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. #include "qemu-io.h"
  14. #include "qemu/error-report.h"
  15. #include "qemu/main-loop.h"
  16. #include "qemu/option.h"
  17. #include "qemu/config-file.h"
  18. #include "qemu/readline.h"
  19. #include "qapi/qmp/qstring.h"
  20. #include "qom/object_interfaces.h"
  21. #include "sysemu/block-backend.h"
  22. #include "block/block_int.h"
  23. #include "trace/control.h"
  24. #define CMD_NOFILE_OK 0x01
  25. static char *progname;
  26. static BlockBackend *qemuio_blk;
  27. /* qemu-io commands passed using -c */
  28. static int ncmdline;
  29. static char **cmdline;
  30. static bool imageOpts;
  31. static ReadLineState *readline_state;
  32. static int close_f(BlockBackend *blk, int argc, char **argv)
  33. {
  34. blk_unref(qemuio_blk);
  35. qemuio_blk = NULL;
  36. return 0;
  37. }
  38. static const cmdinfo_t close_cmd = {
  39. .name = "close",
  40. .altname = "c",
  41. .cfunc = close_f,
  42. .oneline = "close the current open file",
  43. };
  44. static int openfile(char *name, int flags, QDict *opts)
  45. {
  46. Error *local_err = NULL;
  47. BlockDriverState *bs;
  48. if (qemuio_blk) {
  49. error_report("file open already, try 'help close'");
  50. QDECREF(opts);
  51. return 1;
  52. }
  53. qemuio_blk = blk_new_open(name, NULL, opts, flags, &local_err);
  54. if (!qemuio_blk) {
  55. error_reportf_err(local_err, "can't open%s%s: ",
  56. name ? " device " : "", name ?: "");
  57. return 1;
  58. }
  59. bs = blk_bs(qemuio_blk);
  60. if (bdrv_is_encrypted(bs)) {
  61. char password[256];
  62. printf("Disk image '%s' is encrypted.\n", name);
  63. if (qemu_read_password(password, sizeof(password)) < 0) {
  64. error_report("No password given");
  65. goto error;
  66. }
  67. if (bdrv_set_key(bs, password) < 0) {
  68. error_report("invalid password");
  69. goto error;
  70. }
  71. }
  72. return 0;
  73. error:
  74. blk_unref(qemuio_blk);
  75. qemuio_blk = NULL;
  76. return 1;
  77. }
  78. static void open_help(void)
  79. {
  80. printf(
  81. "\n"
  82. " opens a new file in the requested mode\n"
  83. "\n"
  84. " Example:\n"
  85. " 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n"
  86. "\n"
  87. " Opens a file for subsequent use by all of the other qemu-io commands.\n"
  88. " -r, -- open file read-only\n"
  89. " -s, -- use snapshot file\n"
  90. " -n, -- disable host cache\n"
  91. " -o, -- options to be given to the block driver"
  92. "\n");
  93. }
  94. static int open_f(BlockBackend *blk, int argc, char **argv);
  95. static const cmdinfo_t open_cmd = {
  96. .name = "open",
  97. .altname = "o",
  98. .cfunc = open_f,
  99. .argmin = 1,
  100. .argmax = -1,
  101. .flags = CMD_NOFILE_OK,
  102. .args = "[-Crsn] [-o options] [path]",
  103. .oneline = "open the file specified by path",
  104. .help = open_help,
  105. };
  106. static QemuOptsList empty_opts = {
  107. .name = "drive",
  108. .merge_lists = true,
  109. .head = QTAILQ_HEAD_INITIALIZER(empty_opts.head),
  110. .desc = {
  111. /* no elements => accept any params */
  112. { /* end of list */ }
  113. },
  114. };
  115. static int open_f(BlockBackend *blk, int argc, char **argv)
  116. {
  117. int flags = 0;
  118. int readonly = 0;
  119. int c;
  120. QemuOpts *qopts;
  121. QDict *opts;
  122. while ((c = getopt(argc, argv, "snrgo:")) != -1) {
  123. switch (c) {
  124. case 's':
  125. flags |= BDRV_O_SNAPSHOT;
  126. break;
  127. case 'n':
  128. flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
  129. break;
  130. case 'r':
  131. readonly = 1;
  132. break;
  133. case 'o':
  134. if (imageOpts) {
  135. printf("--image-opts and 'open -o' are mutually exclusive\n");
  136. return 0;
  137. }
  138. if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) {
  139. qemu_opts_reset(&empty_opts);
  140. return 0;
  141. }
  142. break;
  143. default:
  144. qemu_opts_reset(&empty_opts);
  145. return qemuio_command_usage(&open_cmd);
  146. }
  147. }
  148. if (!readonly) {
  149. flags |= BDRV_O_RDWR;
  150. }
  151. if (imageOpts && (optind == argc - 1)) {
  152. if (!qemu_opts_parse_noisily(&empty_opts, argv[optind], false)) {
  153. qemu_opts_reset(&empty_opts);
  154. return 0;
  155. }
  156. optind++;
  157. }
  158. qopts = qemu_opts_find(&empty_opts, NULL);
  159. opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
  160. qemu_opts_reset(&empty_opts);
  161. if (optind == argc - 1) {
  162. return openfile(argv[optind], flags, opts);
  163. } else if (optind == argc) {
  164. return openfile(NULL, flags, opts);
  165. } else {
  166. QDECREF(opts);
  167. return qemuio_command_usage(&open_cmd);
  168. }
  169. }
  170. static int quit_f(BlockBackend *blk, int argc, char **argv)
  171. {
  172. return 1;
  173. }
  174. static const cmdinfo_t quit_cmd = {
  175. .name = "quit",
  176. .altname = "q",
  177. .cfunc = quit_f,
  178. .argmin = -1,
  179. .argmax = -1,
  180. .flags = CMD_FLAG_GLOBAL,
  181. .oneline = "exit the program",
  182. };
  183. static void usage(const char *name)
  184. {
  185. printf(
  186. "Usage: %s [-h] [-V] [-rsnm] [-f FMT] [-c STRING] ... [file]\n"
  187. "QEMU Disk exerciser\n"
  188. "\n"
  189. " --object OBJECTDEF define an object such as 'secret' for\n"
  190. " passwords and/or encryption keys\n"
  191. " -c, --cmd STRING execute command with its arguments\n"
  192. " from the given string\n"
  193. " -f, --format FMT specifies the block driver to use\n"
  194. " -r, --read-only export read-only\n"
  195. " -s, --snapshot use snapshot file\n"
  196. " -n, --nocache disable host cache\n"
  197. " -m, --misalign misalign allocations for O_DIRECT\n"
  198. " -k, --native-aio use kernel AIO implementation (on Linux only)\n"
  199. " -t, --cache=MODE use the given cache mode for the image\n"
  200. " -T, --trace FILE enable trace events listed in the given file\n"
  201. " -h, --help display this help and exit\n"
  202. " -V, --version output version information and exit\n"
  203. "\n"
  204. "See '%s -c help' for information on available commands."
  205. "\n",
  206. name, name);
  207. }
  208. static char *get_prompt(void)
  209. {
  210. static char prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
  211. if (!prompt[0]) {
  212. snprintf(prompt, sizeof(prompt), "%s> ", progname);
  213. }
  214. return prompt;
  215. }
  216. static void GCC_FMT_ATTR(2, 3) readline_printf_func(void *opaque,
  217. const char *fmt, ...)
  218. {
  219. va_list ap;
  220. va_start(ap, fmt);
  221. vprintf(fmt, ap);
  222. va_end(ap);
  223. }
  224. static void readline_flush_func(void *opaque)
  225. {
  226. fflush(stdout);
  227. }
  228. static void readline_func(void *opaque, const char *str, void *readline_opaque)
  229. {
  230. char **line = readline_opaque;
  231. *line = g_strdup(str);
  232. }
  233. static void completion_match(const char *cmd, void *opaque)
  234. {
  235. readline_add_completion(readline_state, cmd);
  236. }
  237. static void readline_completion_func(void *opaque, const char *str)
  238. {
  239. readline_set_completion_index(readline_state, strlen(str));
  240. qemuio_complete_command(str, completion_match, NULL);
  241. }
  242. static char *fetchline_readline(void)
  243. {
  244. char *line = NULL;
  245. readline_start(readline_state, get_prompt(), 0, readline_func, &line);
  246. while (!line) {
  247. int ch = getchar();
  248. if (ch == EOF) {
  249. break;
  250. }
  251. readline_handle_byte(readline_state, ch);
  252. }
  253. return line;
  254. }
  255. #define MAXREADLINESZ 1024
  256. static char *fetchline_fgets(void)
  257. {
  258. char *p, *line = g_malloc(MAXREADLINESZ);
  259. if (!fgets(line, MAXREADLINESZ, stdin)) {
  260. g_free(line);
  261. return NULL;
  262. }
  263. p = line + strlen(line);
  264. if (p != line && p[-1] == '\n') {
  265. p[-1] = '\0';
  266. }
  267. return line;
  268. }
  269. static char *fetchline(void)
  270. {
  271. if (readline_state) {
  272. return fetchline_readline();
  273. } else {
  274. return fetchline_fgets();
  275. }
  276. }
  277. static void prep_fetchline(void *opaque)
  278. {
  279. int *fetchable = opaque;
  280. qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
  281. *fetchable= 1;
  282. }
  283. static void command_loop(void)
  284. {
  285. int i, done = 0, fetchable = 0, prompted = 0;
  286. char *input;
  287. for (i = 0; !done && i < ncmdline; i++) {
  288. done = qemuio_command(qemuio_blk, cmdline[i]);
  289. }
  290. if (cmdline) {
  291. g_free(cmdline);
  292. return;
  293. }
  294. while (!done) {
  295. if (!prompted) {
  296. printf("%s", get_prompt());
  297. fflush(stdout);
  298. qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable);
  299. prompted = 1;
  300. }
  301. main_loop_wait(false);
  302. if (!fetchable) {
  303. continue;
  304. }
  305. input = fetchline();
  306. if (input == NULL) {
  307. break;
  308. }
  309. done = qemuio_command(qemuio_blk, input);
  310. g_free(input);
  311. prompted = 0;
  312. fetchable = 0;
  313. }
  314. qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
  315. }
  316. static void add_user_command(char *optarg)
  317. {
  318. cmdline = g_renew(char *, cmdline, ++ncmdline);
  319. cmdline[ncmdline-1] = optarg;
  320. }
  321. static void reenable_tty_echo(void)
  322. {
  323. qemu_set_tty_echo(STDIN_FILENO, true);
  324. }
  325. enum {
  326. OPTION_OBJECT = 256,
  327. OPTION_IMAGE_OPTS = 257,
  328. };
  329. static QemuOptsList qemu_object_opts = {
  330. .name = "object",
  331. .implied_opt_name = "qom-type",
  332. .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
  333. .desc = {
  334. { }
  335. },
  336. };
  337. static QemuOptsList file_opts = {
  338. .name = "file",
  339. .implied_opt_name = "file",
  340. .head = QTAILQ_HEAD_INITIALIZER(file_opts.head),
  341. .desc = {
  342. /* no elements => accept any params */
  343. { /* end of list */ }
  344. },
  345. };
  346. int main(int argc, char **argv)
  347. {
  348. int readonly = 0;
  349. const char *sopt = "hVc:d:f:rsnmgkt:T:";
  350. const struct option lopt[] = {
  351. { "help", no_argument, NULL, 'h' },
  352. { "version", no_argument, NULL, 'V' },
  353. { "offset", required_argument, NULL, 'o' },
  354. { "cmd", required_argument, NULL, 'c' },
  355. { "format", required_argument, NULL, 'f' },
  356. { "read-only", no_argument, NULL, 'r' },
  357. { "snapshot", no_argument, NULL, 's' },
  358. { "nocache", no_argument, NULL, 'n' },
  359. { "misalign", no_argument, NULL, 'm' },
  360. { "native-aio", no_argument, NULL, 'k' },
  361. { "discard", required_argument, NULL, 'd' },
  362. { "cache", required_argument, NULL, 't' },
  363. { "trace", required_argument, NULL, 'T' },
  364. { "object", required_argument, NULL, OPTION_OBJECT },
  365. { "image-opts", no_argument, NULL, OPTION_IMAGE_OPTS },
  366. { NULL, 0, NULL, 0 }
  367. };
  368. int c;
  369. int opt_index = 0;
  370. int flags = BDRV_O_UNMAP;
  371. Error *local_error = NULL;
  372. QDict *opts = NULL;
  373. const char *format = NULL;
  374. #ifdef CONFIG_POSIX
  375. signal(SIGPIPE, SIG_IGN);
  376. #endif
  377. progname = basename(argv[0]);
  378. qemu_init_exec_dir(argv[0]);
  379. module_call_init(MODULE_INIT_QOM);
  380. qemu_add_opts(&qemu_object_opts);
  381. bdrv_init();
  382. while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) {
  383. switch (c) {
  384. case 's':
  385. flags |= BDRV_O_SNAPSHOT;
  386. break;
  387. case 'n':
  388. flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
  389. break;
  390. case 'd':
  391. if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
  392. error_report("Invalid discard option: %s", optarg);
  393. exit(1);
  394. }
  395. break;
  396. case 'f':
  397. format = optarg;
  398. break;
  399. case 'c':
  400. add_user_command(optarg);
  401. break;
  402. case 'r':
  403. readonly = 1;
  404. break;
  405. case 'm':
  406. qemuio_misalign = true;
  407. break;
  408. case 'k':
  409. flags |= BDRV_O_NATIVE_AIO;
  410. break;
  411. case 't':
  412. if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
  413. error_report("Invalid cache option: %s", optarg);
  414. exit(1);
  415. }
  416. break;
  417. case 'T':
  418. if (!trace_init_backends()) {
  419. exit(1); /* error message will have been printed */
  420. }
  421. break;
  422. case 'V':
  423. printf("%s version %s\n", progname, QEMU_VERSION);
  424. exit(0);
  425. case 'h':
  426. usage(progname);
  427. exit(0);
  428. case OPTION_OBJECT: {
  429. QemuOpts *qopts;
  430. qopts = qemu_opts_parse_noisily(&qemu_object_opts,
  431. optarg, true);
  432. if (!qopts) {
  433. exit(1);
  434. }
  435. } break;
  436. case OPTION_IMAGE_OPTS:
  437. imageOpts = true;
  438. break;
  439. default:
  440. usage(progname);
  441. exit(1);
  442. }
  443. }
  444. if ((argc - optind) > 1) {
  445. usage(progname);
  446. exit(1);
  447. }
  448. if (format && imageOpts) {
  449. error_report("--image-opts and -f are mutually exclusive");
  450. exit(1);
  451. }
  452. if (qemu_init_main_loop(&local_error)) {
  453. error_report_err(local_error);
  454. exit(1);
  455. }
  456. if (qemu_opts_foreach(&qemu_object_opts,
  457. user_creatable_add_opts_foreach,
  458. NULL, &local_error)) {
  459. error_report_err(local_error);
  460. exit(1);
  461. }
  462. /* initialize commands */
  463. qemuio_add_command(&quit_cmd);
  464. qemuio_add_command(&open_cmd);
  465. qemuio_add_command(&close_cmd);
  466. if (isatty(STDIN_FILENO)) {
  467. readline_state = readline_init(readline_printf_func,
  468. readline_flush_func,
  469. NULL,
  470. readline_completion_func);
  471. qemu_set_tty_echo(STDIN_FILENO, false);
  472. atexit(reenable_tty_echo);
  473. }
  474. /* open the device */
  475. if (!readonly) {
  476. flags |= BDRV_O_RDWR;
  477. }
  478. if ((argc - optind) == 1) {
  479. if (imageOpts) {
  480. QemuOpts *qopts = NULL;
  481. qopts = qemu_opts_parse_noisily(&file_opts, argv[optind], false);
  482. if (!qopts) {
  483. exit(1);
  484. }
  485. opts = qemu_opts_to_qdict(qopts, NULL);
  486. openfile(NULL, flags, opts);
  487. } else {
  488. if (format) {
  489. opts = qdict_new();
  490. qdict_put(opts, "driver", qstring_from_str(format));
  491. }
  492. openfile(argv[optind], flags, opts);
  493. }
  494. }
  495. command_loop();
  496. /*
  497. * Make sure all outstanding requests complete before the program exits.
  498. */
  499. bdrv_drain_all();
  500. blk_unref(qemuio_blk);
  501. g_free(readline_state);
  502. return 0;
  503. }