diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2010-03-17 09:44:37 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2010-03-17 09:44:37 -0500 |
commit | 4a39943bd1fd2ac7e3163f9d9b056394519661f3 (patch) | |
tree | eab01e0258d2344117873952b589bac333bb0ea3 /monitor.c | |
parent | 7d834c7450245335db0a7055ccdc783ccab21935 (diff) | |
parent | 8bc27249f0f62524887ea355a6604722edd276a9 (diff) |
Merge remote branch 'markus/qerror' into staging
Diffstat (limited to 'monitor.c')
-rw-r--r-- | monitor.c | 337 |
1 files changed, 147 insertions, 190 deletions
@@ -67,6 +67,11 @@ * 'F' filename * 'B' block device name * 's' string (accept optional quote) + * 'O' option string of the form NAME=VALUE,... + * parsed according to QemuOptsList given by its name + * Example: 'device:O' uses qemu_device_opts. + * Restriction: only lists with empty desc are supported + * TODO lift the restriction * 'i' 32 bit integer * 'l' target long (32 or 64 bit) * 'M' just like 'l', except in user mode the value is @@ -177,7 +182,8 @@ static QLIST_HEAD(mon_list, Monitor) mon_list; static const mon_cmd_t mon_cmds[]; static const mon_cmd_t info_cmds[]; -Monitor *cur_mon = NULL; +Monitor *cur_mon; +Monitor *default_mon; static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque); @@ -193,6 +199,12 @@ static inline int monitor_ctrl_mode(const Monitor *mon) return (mon->flags & MONITOR_USE_CONTROL); } +/* Return non-zero iff we have a current monitor, and it is in QMP mode. */ +int monitor_cur_is_qmp(void) +{ + return cur_mon && monitor_ctrl_mode(cur_mon); +} + static void monitor_read_command(Monitor *mon, int show_prompt) { if (!mon->rs) @@ -207,7 +219,7 @@ static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func, void *opaque) { if (monitor_ctrl_mode(mon)) { - qemu_error_new(QERR_MISSING_PARAMETER, "password"); + qerror_report(QERR_MISSING_PARAMETER, "password"); return -EINVAL; } else if (mon->rs) { readline_start(mon->rs, "Password: ", 1, readline_func, opaque); @@ -606,7 +618,7 @@ static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data) if (cmd->name == NULL) { if (monitor_ctrl_mode(mon)) { - qemu_error_new(QERR_COMMAND_NOT_FOUND, item); + qerror_report(QERR_COMMAND_NOT_FOUND, item); return -1; } goto help; @@ -638,7 +650,7 @@ static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data) } else { if (monitor_ctrl_mode(mon)) { /* handler not converted yet */ - qemu_error_new(QERR_COMMAND_NOT_FOUND, item); + qerror_report(QERR_COMMAND_NOT_FOUND, item); return -1; } else { cmd->mhandler.info(mon); @@ -960,7 +972,7 @@ static int do_cpu_set(Monitor *mon, const QDict *qdict, QObject **ret_data) { int index = qdict_get_int(qdict, "index"); if (mon_set_cpu(index) < 0) { - qemu_error_new(QERR_INVALID_PARAMETER, "index"); + qerror_report(QERR_INVALID_PARAMETER, "index"); return -1; } return 0; @@ -1013,12 +1025,12 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force) if (bdrv_is_inserted(bs)) { if (!force) { if (!bdrv_is_removable(bs)) { - qemu_error_new(QERR_DEVICE_NOT_REMOVABLE, + qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs)); return -1; } if (bdrv_is_locked(bs)) { - qemu_error_new(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); + qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs)); return -1; } } @@ -1035,7 +1047,7 @@ static int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data) bs = bdrv_find(filename); if (!bs) { - qemu_error_new(QERR_DEVICE_NOT_FOUND, filename); + qerror_report(QERR_DEVICE_NOT_FOUND, filename); return -1; } return eject_device(mon, bs, force); @@ -1048,12 +1060,12 @@ static int do_block_set_passwd(Monitor *mon, const QDict *qdict, bs = bdrv_find(qdict_get_str(qdict, "device")); if (!bs) { - qemu_error_new(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device")); + qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device")); return -1; } if (bdrv_set_key(bs, qdict_get_str(qdict, "password")) < 0) { - qemu_error_new(QERR_INVALID_PASSWORD); + qerror_report(QERR_INVALID_PASSWORD); return -1; } @@ -1068,13 +1080,13 @@ static int do_change_block(Monitor *mon, const char *device, bs = bdrv_find(device); if (!bs) { - qemu_error_new(QERR_DEVICE_NOT_FOUND, device); + qerror_report(QERR_DEVICE_NOT_FOUND, device); return -1; } if (fmt) { drv = bdrv_find_whitelisted_format(fmt); if (!drv) { - qemu_error_new(QERR_INVALID_BLOCK_FORMAT, fmt); + qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt); return -1; } } @@ -1090,7 +1102,7 @@ static int do_change_block(Monitor *mon, const char *device, static int change_vnc_password(const char *password) { if (vnc_display_password(NULL, password) < 0) { - qemu_error_new(QERR_SET_PASSWD_FAILED); + qerror_report(QERR_SET_PASSWD_FAILED); return -1; } @@ -1118,7 +1130,7 @@ static int do_change_vnc(Monitor *mon, const char *target, const char *arg) } } else { if (vnc_display_open(NULL, target) < 0) { - qemu_error_new(QERR_VNC_SERVER_FAILED, target); + qerror_report(QERR_VNC_SERVER_FAILED, target); return -1; } } @@ -1490,7 +1502,7 @@ static int do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data) f = fopen(filename, "wb"); if (!f) { - qemu_error_new(QERR_OPEN_FILE_FAILED, filename); + qerror_report(QERR_OPEN_FILE_FAILED, filename); return -1; } while (size != 0) { @@ -1526,7 +1538,7 @@ static int do_physical_memory_save(Monitor *mon, const QDict *qdict, f = fopen(filename, "wb"); if (!f) { - qemu_error_new(QERR_OPEN_FILE_FAILED, filename); + qerror_report(QERR_OPEN_FILE_FAILED, filename); return -1; } while (size != 0) { @@ -2300,13 +2312,13 @@ static int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque) int ret; if (kvm_enabled() && !kvm_has_sync_mmu()) { - qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); + qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); return -1; } ret = qemu_balloon_status(cb, opaque); if (!ret) { - qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon"); + qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); return -1; } @@ -2322,13 +2334,13 @@ static int do_balloon(Monitor *mon, const QDict *params, int ret; if (kvm_enabled() && !kvm_has_sync_mmu()) { - qemu_error_new(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); + qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon"); return -1; } ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque); if (ret == 0) { - qemu_error_new(QERR_DEVICE_NOT_ACTIVE, "balloon"); + qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); return -1; } @@ -2469,21 +2481,21 @@ static int do_getfd(Monitor *mon, const QDict *qdict, QObject **ret_data) fd = qemu_chr_get_msgfd(mon->chr); if (fd == -1) { - qemu_error_new(QERR_FD_NOT_SUPPLIED); + qerror_report(QERR_FD_NOT_SUPPLIED); return -1; } if (qemu_isdigit(fdname[0])) { - qemu_error_new(QERR_INVALID_PARAMETER, "fdname"); + qerror_report(QERR_INVALID_PARAMETER, "fdname"); return -1; } fd = dup(fd); if (fd == -1) { if (errno == EMFILE) - qemu_error_new(QERR_TOO_MANY_FILES); + qerror_report(QERR_TOO_MANY_FILES); else - qemu_error_new(QERR_UNDEFINED_ERROR); + qerror_report(QERR_UNDEFINED_ERROR); return -1; } @@ -2522,7 +2534,7 @@ static int do_closefd(Monitor *mon, const QDict *qdict, QObject **ret_data) return 0; } - qemu_error_new(QERR_FD_NOT_FOUND, fdname); + qerror_report(QERR_FD_NOT_FOUND, fdname); return -1; } @@ -2533,7 +2545,7 @@ static void do_loadvm(Monitor *mon, const QDict *qdict) vm_stop(0); - if (load_vmstate(mon, name) >= 0 && saved_vm_running) + if (load_vmstate(name) >= 0 && saved_vm_running) vm_start(); } @@ -3638,6 +3650,31 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, qdict_put(qdict, key, qstring_from_str(buf)); } break; + case 'O': + { + QemuOptsList *opts_list; + QemuOpts *opts; + + opts_list = qemu_find_opts(key); + if (!opts_list || opts_list->desc->name) { + goto bad_type; + } + while (qemu_isspace(*p)) { + p++; + } + if (!*p) + break; + if (get_str(buf, sizeof(buf), &p) < 0) { + goto fail; + } + opts = qemu_opts_parse(opts_list, buf, 1); + if (!opts) { + goto fail; + } + qemu_opts_to_qdict(opts, qdict); + qemu_opts_del(opts); + } + break; case '/': { int count, format, size; @@ -3857,11 +3894,16 @@ fail: return NULL; } -static void monitor_print_error(Monitor *mon) +void monitor_set_error(Monitor *mon, QError *qerror) { - qerror_print(mon->error); - QDECREF(mon->error); - mon->error = NULL; + /* report only the first error */ + if (!mon->error) { + mon->error = qerror; + } else { + MON_DEBUG("Additional error report at %s:%d\n", + qerror->file, qerror->linenr); + QDECREF(qerror); + } } static int is_async_return(const QObject *data) @@ -3875,45 +3917,49 @@ static int is_async_return(const QObject *data) static void handler_audit(Monitor *mon, const mon_cmd_t *cmd, int ret) { - if (ret && !monitor_has_error(mon)) { - /* - * If it returns failure, it must have passed on error. - * - * Action: Report an internal error to the client if in QMP. - */ - if (monitor_ctrl_mode(mon)) { - qemu_error_new(QERR_UNDEFINED_ERROR); + if (monitor_ctrl_mode(mon)) { + if (ret && !monitor_has_error(mon)) { + /* + * If it returns failure, it must have passed on error. + * + * Action: Report an internal error to the client if in QMP. + */ + qerror_report(QERR_UNDEFINED_ERROR); + MON_DEBUG("command '%s' returned failure but did not pass an error\n", + cmd->name); } - MON_DEBUG("command '%s' returned failure but did not pass an error\n", - cmd->name); - } #ifdef CONFIG_DEBUG_MONITOR - if (!ret && monitor_has_error(mon)) { - /* - * If it returns success, it must not have passed an error. - * - * Action: Report the passed error to the client. - */ - MON_DEBUG("command '%s' returned success but passed an error\n", - cmd->name); - } + if (!ret && monitor_has_error(mon)) { + /* + * If it returns success, it must not have passed an error. + * + * Action: Report the passed error to the client. + */ + MON_DEBUG("command '%s' returned success but passed an error\n", + cmd->name); + } - if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) { - /* - * Handlers should not call Monitor print functions. - * - * Action: Ignore them in QMP. - * - * (XXX: we don't check any 'info' or 'query' command here - * because the user print function _is_ called by do_info(), hence - * we will trigger this check. This problem will go away when we - * make 'query' commands real and kill do_info()) - */ - MON_DEBUG("command '%s' called print functions %d time(s)\n", - cmd->name, mon_print_count_get(mon)); - } + if (mon_print_count_get(mon) > 0 && strcmp(cmd->name, "info") != 0) { + /* + * Handlers should not call Monitor print functions. + * + * Action: Ignore them in QMP. + * + * (XXX: we don't check any 'info' or 'query' command here + * because the user print function _is_ called by do_info(), hence + * we will trigger this check. This problem will go away when we + * make 'query' commands real and kill do_info()) + */ + MON_DEBUG("command '%s' called print functions %d time(s)\n", + cmd->name, mon_print_count_get(mon)); + } #endif + } else { + assert(!monitor_has_error(mon)); + QDECREF(mon->error); + mon->error = NULL; + } } static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd, @@ -3958,8 +4004,6 @@ static void handle_user_command(Monitor *mon, const char *cmdline) if (!cmd) goto out; - qemu_errors_to_mon(mon); - if (monitor_handler_is_async(cmd)) { user_async_cmd_handler(mon, cmd, qdict); } else if (monitor_handler_ported(cmd)) { @@ -3968,11 +4012,6 @@ static void handle_user_command(Monitor *mon, const char *cmdline) cmd->mhandler.cmd(mon, qdict); } - if (monitor_has_error(mon)) - monitor_print_error(mon); - - qemu_errors_to_previous(); - out: QDECREF(qdict); } @@ -4209,7 +4248,7 @@ typedef struct CmdArgs { static int check_opt(const CmdArgs *cmd_args, const char *name, QDict *args) { if (!cmd_args->optional) { - qemu_error_new(QERR_MISSING_PARAMETER, name); + qerror_report(QERR_MISSING_PARAMETER, name); return -1; } @@ -4242,7 +4281,7 @@ static int check_arg(const CmdArgs *cmd_args, QDict *args) case 'B': case 's': if (qobject_type(value) != QTYPE_QSTRING) { - qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "string"); + qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "string"); return -1; } break; @@ -4253,11 +4292,11 @@ static int check_arg(const CmdArgs *cmd_args, QDict *args) for (i = 0; keys[i]; i++) { QObject *obj = qdict_get(args, keys[i]); if (!obj) { - qemu_error_new(QERR_MISSING_PARAMETER, name); + qerror_report(QERR_MISSING_PARAMETER, name); return -1; } if (qobject_type(obj) != QTYPE_QINT) { - qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "int"); + qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "int"); return -1; } } @@ -4267,21 +4306,21 @@ static int check_arg(const CmdArgs *cmd_args, QDict *args) case 'l': case 'M': if (qobject_type(value) != QTYPE_QINT) { - qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "int"); + qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "int"); return -1; } break; case 'b': case 'T': if (qobject_type(value) != QTYPE_QINT && qobject_type(value) != QTYPE_QFLOAT) { - qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "number"); + qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "number"); return -1; } break; case '-': if (qobject_type(value) != QTYPE_QINT && qobject_type(value) != QTYPE_QBOOL) { - qemu_error_new(QERR_INVALID_PARAMETER_TYPE, name, "bool"); + qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "bool"); return -1; } if (qobject_type(value) == QTYPE_QBOOL) { @@ -4290,6 +4329,7 @@ static int check_arg(const CmdArgs *cmd_args, QDict *args) qint_from_int(qbool_get_int(qobject_to_qbool(value)))); } break; + case 'O': default: /* impossible */ abort(); @@ -4304,6 +4344,12 @@ static void cmd_args_init(CmdArgs *cmd_args) cmd_args->type = cmd_args->flag = cmd_args->optional = 0; } +static int check_opts(QemuOptsList *opts_list, QDict *args) +{ + assert(!opts_list->desc->name); + return 0; +} + /* * This is not trivial, we have to parse Monitor command's argument * type syntax to be able to check the arguments provided by clients. @@ -4316,6 +4362,7 @@ static int monitor_check_qmp_args(const mon_cmd_t *cmd, QDict *args) int err; const char *p; CmdArgs cmd_args; + QemuOptsList *opts_list; if (cmd->args_type == NULL) { return (qdict_size(args) == 0 ? 0 : -1); @@ -4323,6 +4370,7 @@ static int monitor_check_qmp_args(const mon_cmd_t *cmd, QDict *args) err = 0; cmd_args_init(&cmd_args); + opts_list = NULL; for (p = cmd->args_type;; p++) { if (*p == ':') { @@ -4331,16 +4379,23 @@ static int monitor_check_qmp_args(const mon_cmd_t *cmd, QDict *args) if (cmd_args.type == '-') { cmd_args.flag = *p++; cmd_args.optional = 1; + } else if (cmd_args.type == 'O') { + opts_list = qemu_find_opts(qstring_get_str(cmd_args.name)); + assert(opts_list); } else if (*p == '?') { cmd_args.optional = 1; p++; } assert(*p == ',' || *p == '\0'); - err = check_arg(&cmd_args, args); - - QDECREF(cmd_args.name); - cmd_args_init(&cmd_args); + if (opts_list) { + err = check_opts(opts_list, args); + opts_list = NULL; + } else { + err = check_arg(&cmd_args, args); + QDECREF(cmd_args.name); + cmd_args_init(&cmd_args); + } if (err < 0) { break; @@ -4374,15 +4429,14 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) const char *cmd_name, *info_item; args = NULL; - qemu_errors_to_mon(mon); obj = json_parser_parse(tokens, NULL); if (!obj) { // FIXME: should be triggered in json_parser_parse() - qemu_error_new(QERR_JSON_PARSING); + qerror_report(QERR_JSON_PARSING); goto err_out; } else if (qobject_type(obj) != QTYPE_QDICT) { - qemu_error_new(QERR_QMP_BAD_INPUT_OBJECT, "object"); + qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object"); qobject_decref(obj); goto err_out; } @@ -4394,17 +4448,17 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) obj = qdict_get(input, "execute"); if (!obj) { - qemu_error_new(QERR_QMP_BAD_INPUT_OBJECT, "execute"); + qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "execute"); goto err_input; } else if (qobject_type(obj) != QTYPE_QSTRING) { - qemu_error_new(QERR_QMP_BAD_INPUT_OBJECT, "string"); + qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "string"); goto err_input; } cmd_name = qstring_get_str(qobject_to_qstring(obj)); if (invalid_qmp_mode(mon, cmd_name)) { - qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name); + qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); goto err_input; } @@ -4413,7 +4467,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) * converted into 'query-' commands */ if (compare_cmd(cmd_name, "info")) { - qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name); + qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); goto err_input; } else if (strstart(cmd_name, "query-", &info_item)) { cmd = monitor_find_command("info"); @@ -4422,7 +4476,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) } else { cmd = monitor_find_command(cmd_name); if (!cmd || !monitor_handler_ported(cmd)) { - qemu_error_new(QERR_COMMAND_NOT_FOUND, cmd_name); + qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name); goto err_input; } } @@ -4455,7 +4509,6 @@ err_out: monitor_protocol_emitter(mon, NULL); out: QDECREF(args); - qemu_errors_to_previous(); } /** @@ -4624,8 +4677,8 @@ void monitor_init(CharDriverState *chr, int flags) } QLIST_INSERT_HEAD(&mon_list, mon, entry); - if (!cur_mon || (flags & MONITOR_IS_DEFAULT)) - cur_mon = mon; + if (!default_mon || (flags & MONITOR_IS_DEFAULT)) + default_mon = mon; } static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque) @@ -4656,7 +4709,7 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, } if (monitor_ctrl_mode(mon)) { - qemu_error_new(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs)); + qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs)); return -1; } @@ -4673,99 +4726,3 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs, return err; } - -typedef struct QemuErrorSink QemuErrorSink; -struct QemuErrorSink { - enum { - ERR_SINK_FILE, - ERR_SINK_MONITOR, - } dest; - union { - FILE *fp; - Monitor *mon; - }; - QemuErrorSink *previous; -}; - -static QemuErrorSink *qemu_error_sink; - -void qemu_errors_to_file(FILE *fp) -{ - QemuErrorSink *sink; - - sink = qemu_mallocz(sizeof(*sink)); - sink->dest = ERR_SINK_FILE; - sink->fp = fp; - sink->previous = qemu_error_sink; - qemu_error_sink = sink; -} - -void qemu_errors_to_mon(Monitor *mon) -{ - QemuErrorSink *sink; - - sink = qemu_mallocz(sizeof(*sink)); - sink->dest = ERR_SINK_MONITOR; - sink->mon = mon; - sink->previous = qemu_error_sink; - qemu_error_sink = sink; -} - -void qemu_errors_to_previous(void) -{ - QemuErrorSink *sink; - - assert(qemu_error_sink != NULL); - sink = qemu_error_sink; - qemu_error_sink = sink->previous; - qemu_free(sink); -} - -void qemu_error(const char *fmt, ...) -{ - va_list args; - - assert(qemu_error_sink != NULL); - switch (qemu_error_sink->dest) { - case ERR_SINK_FILE: - va_start(args, fmt); - vfprintf(qemu_error_sink->fp, fmt, args); - va_end(args); - break; - case ERR_SINK_MONITOR: - va_start(args, fmt); - monitor_vprintf(qemu_error_sink->mon, fmt, args); - va_end(args); - break; - } -} - -void qemu_error_internal(const char *file, int linenr, const char *func, - const char *fmt, ...) -{ - va_list va; - QError *qerror; - - assert(qemu_error_sink != NULL); - - va_start(va, fmt); - qerror = qerror_from_info(file, linenr, func, fmt, &va); - va_end(va); - - switch (qemu_error_sink->dest) { - case ERR_SINK_FILE: - qerror_print(qerror); - QDECREF(qerror); - break; - case ERR_SINK_MONITOR: - /* report only the first error */ - if (!qemu_error_sink->mon->error) { - qemu_error_sink->mon->error = qerror; - } else { - MON_DEBUG("Additional error report at %s:%d\n", qerror->file, - qerror->linenr); - QDECREF(qerror); - } - break; - } -} |