X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qemu-io.c;h=427cbaef57fc70a27088806105ba1088650c53a7;hb=1fde6ee885d3e778acb326cab9f7037939839537;hp=969c8bfdead7e1f36cb99a633c0bbce5e548c33a;hpb=9ba371b6343c58805867a341dc5a1d258e2ab589;p=mirror_qemu.git diff --git a/qemu-io.c b/qemu-io.c index 969c8bfdea..427cbaef57 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -11,17 +11,20 @@ #include #include +#include "qapi/error.h" #include "qemu-io.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/readline.h" +#include "qemu/log.h" #include "qapi/qmp/qstring.h" #include "qom/object_interfaces.h" #include "sysemu/block-backend.h" #include "block/block_int.h" #include "trace/control.h" +#include "crypto/init.h" #define CMD_NOFILE_OK 0x01 @@ -32,6 +35,7 @@ static BlockBackend *qemuio_blk; /* qemu-io commands passed using -c */ static int ncmdline; static char **cmdline; +static bool imageOpts; static ReadLineState *readline_state; @@ -49,7 +53,7 @@ static const cmdinfo_t close_cmd = { .oneline = "close the current open file", }; -static int openfile(char *name, int flags, QDict *opts) +static int openfile(char *name, int flags, bool writethrough, QDict *opts) { Error *local_err = NULL; BlockDriverState *bs; @@ -60,7 +64,7 @@ static int openfile(char *name, int flags, QDict *opts) return 1; } - qemuio_blk = blk_new_open("hda", name, NULL, opts, flags, &local_err); + qemuio_blk = blk_new_open(name, NULL, opts, flags, &local_err); if (!qemuio_blk) { error_reportf_err(local_err, "can't open%s%s: ", name ? " device " : "", name ?: ""); @@ -68,7 +72,7 @@ static int openfile(char *name, int flags, QDict *opts) } bs = blk_bs(qemuio_blk); - if (bdrv_is_encrypted(bs)) { + if (bdrv_is_encrypted(bs) && bdrv_key_required(bs)) { char password[256]; printf("Disk image '%s' is encrypted.\n", name); if (qemu_read_password(password, sizeof(password)) < 0) { @@ -81,6 +85,7 @@ static int openfile(char *name, int flags, QDict *opts) } } + blk_set_enable_write_cache(qemuio_blk, !writethrough); return 0; @@ -97,12 +102,15 @@ static void open_help(void) " opens a new file in the requested mode\n" "\n" " Example:\n" -" 'open -Cn /tmp/data' - creates/opens data file read-write and uncached\n" +" 'open -n -o driver=raw /tmp/data' - opens raw data file read-write, uncached\n" "\n" " Opens a file for subsequent use by all of the other qemu-io commands.\n" " -r, -- open file read-only\n" " -s, -- use snapshot file\n" -" -n, -- disable host cache\n" +" -n, -- disable host cache, short for -t none\n" +" -k, -- use kernel AIO implementation (on Linux only)\n" +" -t, -- use the given cache mode for the image\n" +" -d, -- use the given discard mode for the image\n" " -o, -- options to be given to the block driver" "\n"); } @@ -116,7 +124,7 @@ static const cmdinfo_t open_cmd = { .argmin = 1, .argmax = -1, .flags = CMD_NOFILE_OK, - .args = "[-Crsn] [-o options] [path]", + .args = "[-rsnk] [-t cache] [-d discard] [-o options] [path]", .oneline = "open the file specified by path", .help = open_help, }; @@ -133,24 +141,48 @@ static QemuOptsList empty_opts = { static int open_f(BlockBackend *blk, int argc, char **argv) { - int flags = 0; + int flags = BDRV_O_UNMAP; int readonly = 0; + bool writethrough = true; int c; QemuOpts *qopts; QDict *opts; - while ((c = getopt(argc, argv, "snrgo:")) != -1) { + while ((c = getopt(argc, argv, "snro:kt:d:")) != -1) { switch (c) { case 's': flags |= BDRV_O_SNAPSHOT; break; case 'n': - flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB; + flags |= BDRV_O_NOCACHE; + writethrough = false; break; case 'r': readonly = 1; break; + case 'k': + flags |= BDRV_O_NATIVE_AIO; + break; + case 't': + if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { + error_report("Invalid cache option: %s", optarg); + qemu_opts_reset(&empty_opts); + return 0; + } + break; + case 'd': + if (bdrv_parse_discard_flags(optarg, &flags) < 0) { + error_report("Invalid discard option: %s", optarg); + qemu_opts_reset(&empty_opts); + return 0; + } + break; case 'o': + if (imageOpts) { + printf("--image-opts and 'open -o' are mutually exclusive\n"); + qemu_opts_reset(&empty_opts); + return 0; + } if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) { qemu_opts_reset(&empty_opts); return 0; @@ -166,14 +198,22 @@ static int open_f(BlockBackend *blk, int argc, char **argv) flags |= BDRV_O_RDWR; } + if (imageOpts && (optind == argc - 1)) { + if (!qemu_opts_parse_noisily(&empty_opts, argv[optind], false)) { + qemu_opts_reset(&empty_opts); + return 0; + } + optind++; + } + qopts = qemu_opts_find(&empty_opts, NULL); opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL; qemu_opts_reset(&empty_opts); if (optind == argc - 1) { - return openfile(argv[optind], flags, opts); + return openfile(argv[optind], flags, writethrough, opts); } else if (optind == argc) { - return openfile(NULL, flags, opts); + return openfile(NULL, flags, writethrough, opts); } else { QDECREF(opts); return qemuio_command_usage(&open_cmd); @@ -198,21 +238,25 @@ static const cmdinfo_t quit_cmd = { static void usage(const char *name) { printf( -"Usage: %s [-h] [-V] [-rsnm] [-f FMT] [-c STRING] ... [file]\n" +"Usage: %s [OPTIONS]... [-c STRING]... [file]\n" "QEMU Disk exerciser\n" "\n" " --object OBJECTDEF define an object such as 'secret' for\n" " passwords and/or encryption keys\n" +" --image-opts treat file as option string\n" " -c, --cmd STRING execute command with its arguments\n" " from the given string\n" " -f, --format FMT specifies the block driver to use\n" " -r, --read-only export read-only\n" " -s, --snapshot use snapshot file\n" -" -n, --nocache disable host cache\n" +" -n, --nocache disable host cache, short for -t none\n" " -m, --misalign misalign allocations for O_DIRECT\n" " -k, --native-aio use kernel AIO implementation (on Linux only)\n" " -t, --cache=MODE use the given cache mode for the image\n" -" -T, --trace FILE enable trace events listed in the given file\n" +" -d, --discard=MODE use the given discard mode for the image\n" +" -T, --trace [[enable=]][,events=][,file=]\n" +" specify tracing options\n" +" see qemu-img(1) man page for full description\n" " -h, --help display this help and exit\n" " -V, --version output version information and exit\n" "\n" @@ -366,6 +410,7 @@ static void reenable_tty_echo(void) enum { OPTION_OBJECT = 256, + OPTION_IMAGE_OPTS = 257, }; static QemuOptsList qemu_object_opts = { @@ -378,42 +423,59 @@ static QemuOptsList qemu_object_opts = { }; +static QemuOptsList file_opts = { + .name = "file", + .implied_opt_name = "file", + .head = QTAILQ_HEAD_INITIALIZER(file_opts.head), + .desc = { + /* no elements => accept any params */ + { /* end of list */ } + }, +}; + int main(int argc, char **argv) { int readonly = 0; - const char *sopt = "hVc:d:f:rsnmgkt:T:"; + const char *sopt = "hVc:d:f:rsnmkt:T:"; const struct option lopt[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "offset", 1, NULL, 'o' }, - { "cmd", 1, NULL, 'c' }, - { "format", 1, NULL, 'f' }, - { "read-only", 0, NULL, 'r' }, - { "snapshot", 0, NULL, 's' }, - { "nocache", 0, NULL, 'n' }, - { "misalign", 0, NULL, 'm' }, - { "native-aio", 0, NULL, 'k' }, - { "discard", 1, NULL, 'd' }, - { "cache", 1, NULL, 't' }, - { "trace", 1, NULL, 'T' }, - { "object", 1, NULL, OPTION_OBJECT }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "cmd", required_argument, NULL, 'c' }, + { "format", required_argument, NULL, 'f' }, + { "read-only", no_argument, NULL, 'r' }, + { "snapshot", no_argument, NULL, 's' }, + { "nocache", no_argument, NULL, 'n' }, + { "misalign", no_argument, NULL, 'm' }, + { "native-aio", no_argument, NULL, 'k' }, + { "discard", required_argument, NULL, 'd' }, + { "cache", required_argument, NULL, 't' }, + { "trace", required_argument, NULL, 'T' }, + { "object", required_argument, NULL, OPTION_OBJECT }, + { "image-opts", no_argument, NULL, OPTION_IMAGE_OPTS }, { NULL, 0, NULL, 0 } }; int c; int opt_index = 0; int flags = BDRV_O_UNMAP; + bool writethrough = true; Error *local_error = NULL; QDict *opts = NULL; + const char *format = NULL; + char *trace_file = NULL; #ifdef CONFIG_POSIX signal(SIGPIPE, SIG_IGN); #endif + module_call_init(MODULE_INIT_TRACE); progname = basename(argv[0]); qemu_init_exec_dir(argv[0]); + qcrypto_init(&error_fatal); + module_call_init(MODULE_INIT_QOM); qemu_add_opts(&qemu_object_opts); + qemu_add_opts(&qemu_trace_opts); bdrv_init(); while ((c = getopt_long(argc, argv, sopt, lopt, &opt_index)) != -1) { @@ -422,7 +484,8 @@ int main(int argc, char **argv) flags |= BDRV_O_SNAPSHOT; break; case 'n': - flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB; + flags |= BDRV_O_NOCACHE; + writethrough = false; break; case 'd': if (bdrv_parse_discard_flags(optarg, &flags) < 0) { @@ -431,10 +494,7 @@ int main(int argc, char **argv) } break; case 'f': - if (!opts) { - opts = qdict_new(); - } - qdict_put(opts, "driver", qstring_from_str(optarg)); + format = optarg; break; case 'c': add_user_command(optarg); @@ -449,15 +509,14 @@ int main(int argc, char **argv) flags |= BDRV_O_NATIVE_AIO; break; case 't': - if (bdrv_parse_cache_flags(optarg, &flags) < 0) { + if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) < 0) { error_report("Invalid cache option: %s", optarg); exit(1); } break; case 'T': - if (!trace_init_backends()) { - exit(1); /* error message will have been printed */ - } + g_free(trace_file); + trace_file = trace_opt_parse(optarg); break; case 'V': printf("%s version %s\n", progname, QEMU_VERSION); @@ -466,13 +525,16 @@ int main(int argc, char **argv) usage(progname); exit(0); case OPTION_OBJECT: { - QemuOpts *qopts = NULL; + QemuOpts *qopts; qopts = qemu_opts_parse_noisily(&qemu_object_opts, optarg, true); if (!qopts) { exit(1); } } break; + case OPTION_IMAGE_OPTS: + imageOpts = true; + break; default: usage(progname); exit(1); @@ -484,6 +546,11 @@ int main(int argc, char **argv) exit(1); } + if (format && imageOpts) { + error_report("--image-opts and -f are mutually exclusive"); + exit(1); + } + if (qemu_init_main_loop(&local_error)) { error_report_err(local_error); exit(1); @@ -491,11 +558,16 @@ int main(int argc, char **argv) if (qemu_opts_foreach(&qemu_object_opts, user_creatable_add_opts_foreach, - NULL, &local_error)) { - error_report_err(local_error); + NULL, NULL)) { exit(1); } + if (!trace_init_backends()) { + exit(1); + } + trace_init_file(trace_file); + qemu_set_log(LOG_TRACE); + /* initialize commands */ qemuio_add_command(&quit_cmd); qemuio_add_command(&open_cmd); @@ -516,7 +588,25 @@ int main(int argc, char **argv) } if ((argc - optind) == 1) { - openfile(argv[optind], flags, opts); + if (imageOpts) { + QemuOpts *qopts = NULL; + qopts = qemu_opts_parse_noisily(&file_opts, argv[optind], false); + if (!qopts) { + exit(1); + } + opts = qemu_opts_to_qdict(qopts, NULL); + if (openfile(NULL, flags, writethrough, opts)) { + exit(1); + } + } else { + if (format) { + opts = qdict_new(); + qdict_put(opts, "driver", qstring_from_str(format)); + } + if (openfile(argv[optind], flags, writethrough, opts)) { + exit(1); + } + } } command_loop();