mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 16:23:55 -06:00
Merge remote branch 'qmp/for-anthony' into staging
This commit is contained in:
commit
02d0ba1420
14 changed files with 469 additions and 263 deletions
537
monitor.c
537
monitor.c
|
@ -113,7 +113,7 @@ typedef struct mon_cmd_t {
|
|||
int (*cmd_async)(Monitor *mon, const QDict *params,
|
||||
MonitorCompletion *cb, void *opaque);
|
||||
} mhandler;
|
||||
int async;
|
||||
int flags;
|
||||
} mon_cmd_t;
|
||||
|
||||
/* file descriptors passed via SCM_RIGHTS */
|
||||
|
@ -178,6 +178,9 @@ static inline void mon_print_count_init(Monitor *mon) { }
|
|||
static inline int mon_print_count_get(const Monitor *mon) { return 0; }
|
||||
#endif /* CONFIG_DEBUG_MONITOR */
|
||||
|
||||
/* QMP checker flags */
|
||||
#define QMP_ACCEPT_UNKNOWNS 1
|
||||
|
||||
static QLIST_HEAD(mon_list, Monitor) mon_list;
|
||||
|
||||
static const mon_cmd_t mon_cmds[];
|
||||
|
@ -328,7 +331,12 @@ static inline int monitor_handler_ported(const mon_cmd_t *cmd)
|
|||
|
||||
static inline bool monitor_handler_is_async(const mon_cmd_t *cmd)
|
||||
{
|
||||
return cmd->async != 0;
|
||||
return cmd->flags & MONITOR_CMD_ASYNC;
|
||||
}
|
||||
|
||||
static inline bool monitor_cmd_user_only(const mon_cmd_t *cmd)
|
||||
{
|
||||
return (cmd->flags & MONITOR_CMD_USER_ONLY);
|
||||
}
|
||||
|
||||
static inline int monitor_has_error(const Monitor *mon)
|
||||
|
@ -547,10 +555,10 @@ static void qmp_monitor_complete(void *opaque, QObject *ret_data)
|
|||
monitor_protocol_emitter(opaque, ret_data);
|
||||
}
|
||||
|
||||
static void qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
|
||||
const QDict *params)
|
||||
static int qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
|
||||
const QDict *params)
|
||||
{
|
||||
cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
|
||||
return cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
|
||||
}
|
||||
|
||||
static void qmp_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
|
||||
|
@ -613,6 +621,11 @@ static int do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
|||
goto help;
|
||||
}
|
||||
|
||||
if (monitor_ctrl_mode(mon) && monitor_cmd_user_only(cmd)) {
|
||||
qerror_report(QERR_COMMAND_NOT_FOUND, item);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (monitor_handler_is_async(cmd)) {
|
||||
if (monitor_ctrl_mode(mon)) {
|
||||
qmp_async_info_handler(mon, cmd);
|
||||
|
@ -710,13 +723,14 @@ static void do_info_commands(Monitor *mon, QObject **ret_data)
|
|||
cmd_list = qlist_new();
|
||||
|
||||
for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
|
||||
if (monitor_handler_ported(cmd) && !compare_cmd(cmd->name, "info")) {
|
||||
if (monitor_handler_ported(cmd) && !monitor_cmd_user_only(cmd) &&
|
||||
!compare_cmd(cmd->name, "info")) {
|
||||
qlist_append_obj(cmd_list, get_cmd_dict(cmd->name));
|
||||
}
|
||||
}
|
||||
|
||||
for (cmd = info_cmds; cmd->name != NULL; cmd++) {
|
||||
if (monitor_handler_ported(cmd)) {
|
||||
if (monitor_handler_ported(cmd) && !monitor_cmd_user_only(cmd)) {
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof(buf), "query-%s", cmd->name);
|
||||
qlist_append_obj(cmd_list, get_cmd_dict(buf));
|
||||
|
@ -2537,7 +2551,7 @@ static const mon_cmd_t info_cmds[] = {
|
|||
.help = "show balloon information",
|
||||
.user_print = monitor_print_balloon,
|
||||
.mhandler.info_async = do_info_balloon,
|
||||
.async = 1,
|
||||
.flags = MONITOR_CMD_ASYNC,
|
||||
},
|
||||
{
|
||||
.name = "qtree",
|
||||
|
@ -3566,7 +3580,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
|
|||
case '-':
|
||||
{
|
||||
const char *tmp = p;
|
||||
int has_option, skip_key = 0;
|
||||
int skip_key = 0;
|
||||
/* option */
|
||||
|
||||
c = *typestr++;
|
||||
|
@ -3574,7 +3588,6 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
|
|||
goto bad_type;
|
||||
while (qemu_isspace(*p))
|
||||
p++;
|
||||
has_option = 0;
|
||||
if (*p == '-') {
|
||||
p++;
|
||||
if(c != *p) {
|
||||
|
@ -3590,11 +3603,11 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
|
|||
if(skip_key) {
|
||||
p = tmp;
|
||||
} else {
|
||||
/* has option */
|
||||
p++;
|
||||
has_option = 1;
|
||||
qdict_put(qdict, key, qbool_from_int(1));
|
||||
}
|
||||
}
|
||||
qdict_put(qdict, key, qint_from_int(has_option));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -3883,8 +3896,9 @@ static void monitor_find_completion(const char *cmdline)
|
|||
next arg */
|
||||
len = strlen(cmdline);
|
||||
if (len > 0 && qemu_isspace(cmdline[len - 1])) {
|
||||
if (nb_args >= MAX_ARGS)
|
||||
return;
|
||||
if (nb_args >= MAX_ARGS) {
|
||||
goto cleanup;
|
||||
}
|
||||
args[nb_args++] = qemu_strdup("");
|
||||
}
|
||||
if (nb_args <= 1) {
|
||||
|
@ -3899,12 +3913,15 @@ static void monitor_find_completion(const char *cmdline)
|
|||
}
|
||||
} else {
|
||||
/* find the command */
|
||||
for(cmd = mon_cmds; cmd->name != NULL; cmd++) {
|
||||
if (compare_cmd(args[0], cmd->name))
|
||||
goto found;
|
||||
for (cmd = mon_cmds; cmd->name != NULL; cmd++) {
|
||||
if (compare_cmd(args[0], cmd->name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
found:
|
||||
if (!cmd->name) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ptype = next_arg_type(cmd->args_type);
|
||||
for(i = 0; i < nb_args - 2; i++) {
|
||||
if (*ptype != '\0') {
|
||||
|
@ -3915,7 +3932,7 @@ static void monitor_find_completion(const char *cmdline)
|
|||
}
|
||||
str = args[nb_args - 1];
|
||||
if (*ptype == '-' && ptype[1] != '\0') {
|
||||
ptype += 2;
|
||||
ptype = next_arg_type(ptype);
|
||||
}
|
||||
switch(*ptype) {
|
||||
case 'F':
|
||||
|
@ -3954,8 +3971,11 @@ static void monitor_find_completion(const char *cmdline)
|
|||
break;
|
||||
}
|
||||
}
|
||||
for(i = 0; i < nb_args; i++)
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < nb_args; i++) {
|
||||
qemu_free(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int monitor_can_read(void *opaque)
|
||||
|
@ -3965,193 +3985,258 @@ static int monitor_can_read(void *opaque)
|
|||
return (mon->suspend_cnt == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
typedef struct CmdArgs {
|
||||
QString *name;
|
||||
int type;
|
||||
int flag;
|
||||
int optional;
|
||||
} CmdArgs;
|
||||
|
||||
static int check_opt(const CmdArgs *cmd_args, const char *name, QDict *args)
|
||||
{
|
||||
if (!cmd_args->optional) {
|
||||
qerror_report(QERR_MISSING_PARAMETER, name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cmd_args->type == '-') {
|
||||
/* handlers expect a value, they need to be changed */
|
||||
qdict_put(args, name, qint_from_int(0));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_arg(const CmdArgs *cmd_args, QDict *args)
|
||||
{
|
||||
QObject *value;
|
||||
const char *name;
|
||||
|
||||
name = qstring_get_str(cmd_args->name);
|
||||
|
||||
if (!args) {
|
||||
return check_opt(cmd_args, name, args);
|
||||
}
|
||||
|
||||
value = qdict_get(args, name);
|
||||
if (!value) {
|
||||
return check_opt(cmd_args, name, args);
|
||||
}
|
||||
|
||||
switch (cmd_args->type) {
|
||||
case 'F':
|
||||
case 'B':
|
||||
case 's':
|
||||
if (qobject_type(value) != QTYPE_QSTRING) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "string");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case '/': {
|
||||
int i;
|
||||
const char *keys[] = { "count", "format", "size", NULL };
|
||||
|
||||
for (i = 0; keys[i]; i++) {
|
||||
QObject *obj = qdict_get(args, keys[i]);
|
||||
if (!obj) {
|
||||
qerror_report(QERR_MISSING_PARAMETER, name);
|
||||
return -1;
|
||||
}
|
||||
if (qobject_type(obj) != QTYPE_QINT) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "int");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'i':
|
||||
case 'l':
|
||||
case 'M':
|
||||
if (qobject_type(value) != QTYPE_QINT) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "int");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
case 'T':
|
||||
if (qobject_type(value) != QTYPE_QINT && qobject_type(value) != QTYPE_QFLOAT) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "number");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
if (qobject_type(value) != QTYPE_QBOOL) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "bool");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (qobject_type(value) != QTYPE_QINT &&
|
||||
qobject_type(value) != QTYPE_QBOOL) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_TYPE, name, "bool");
|
||||
return -1;
|
||||
}
|
||||
if (qobject_type(value) == QTYPE_QBOOL) {
|
||||
/* handlers expect a QInt, they need to be changed */
|
||||
qdict_put(args, name,
|
||||
qint_from_int(qbool_get_int(qobject_to_qbool(value))));
|
||||
}
|
||||
break;
|
||||
case 'O':
|
||||
default:
|
||||
/* impossible */
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cmd_args_init(CmdArgs *cmd_args)
|
||||
{
|
||||
cmd_args->name = qstring_new();
|
||||
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.
|
||||
*
|
||||
* In the near future we will be using an array for that and will be
|
||||
* able to drop all this parsing...
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
err = 0;
|
||||
cmd_args_init(&cmd_args);
|
||||
opts_list = NULL;
|
||||
|
||||
for (p = cmd->args_type;; p++) {
|
||||
if (*p == ':') {
|
||||
cmd_args.type = *++p;
|
||||
p++;
|
||||
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');
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
qstring_append_chr(cmd_args.name, *p);
|
||||
}
|
||||
|
||||
if (*p == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QDECREF(cmd_args.name);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int invalid_qmp_mode(const Monitor *mon, const char *cmd_name)
|
||||
{
|
||||
int is_cap = compare_cmd(cmd_name, "qmp_capabilities");
|
||||
return (qmp_cmd_mode(mon) ? is_cap : !is_cap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Argument validation rules:
|
||||
*
|
||||
* 1. The argument must exist in cmd_args qdict
|
||||
* 2. The argument type must be the expected one
|
||||
*
|
||||
* Special case: If the argument doesn't exist in cmd_args and
|
||||
* the QMP_ACCEPT_UNKNOWNS flag is set, then the
|
||||
* checking is skipped for it.
|
||||
*/
|
||||
static int check_client_args_type(const QDict *client_args,
|
||||
const QDict *cmd_args, int flags)
|
||||
{
|
||||
const QDictEntry *ent;
|
||||
|
||||
for (ent = qdict_first(client_args); ent;ent = qdict_next(client_args,ent)){
|
||||
QObject *obj;
|
||||
QString *arg_type;
|
||||
const QObject *client_arg = qdict_entry_value(ent);
|
||||
const char *client_arg_name = qdict_entry_key(ent);
|
||||
|
||||
obj = qdict_get(cmd_args, client_arg_name);
|
||||
if (!obj) {
|
||||
if (flags & QMP_ACCEPT_UNKNOWNS) {
|
||||
/* handler accepts unknowns */
|
||||
continue;
|
||||
}
|
||||
/* client arg doesn't exist */
|
||||
qerror_report(QERR_INVALID_PARAMETER, client_arg_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
arg_type = qobject_to_qstring(obj);
|
||||
assert(arg_type != NULL);
|
||||
|
||||
/* check if argument's type is correct */
|
||||
switch (qstring_get_str(arg_type)[0]) {
|
||||
case 'F':
|
||||
case 'B':
|
||||
case 's':
|
||||
if (qobject_type(client_arg) != QTYPE_QSTRING) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
|
||||
"string");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
case 'l':
|
||||
case 'M':
|
||||
if (qobject_type(client_arg) != QTYPE_QINT) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
|
||||
"int");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
case 'T':
|
||||
if (qobject_type(client_arg) != QTYPE_QINT &&
|
||||
qobject_type(client_arg) != QTYPE_QFLOAT) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
|
||||
"number");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
case '-':
|
||||
if (qobject_type(client_arg) != QTYPE_QBOOL) {
|
||||
qerror_report(QERR_INVALID_PARAMETER_TYPE, client_arg_name,
|
||||
"bool");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'O':
|
||||
assert(flags & QMP_ACCEPT_UNKNOWNS);
|
||||
break;
|
||||
case '/':
|
||||
case '.':
|
||||
/*
|
||||
* These types are not supported by QMP and thus are not
|
||||
* handled here. Fall through.
|
||||
*/
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* - Check if the client has passed all mandatory args
|
||||
* - Set special flags for argument validation
|
||||
*/
|
||||
static int check_mandatory_args(const QDict *cmd_args,
|
||||
const QDict *client_args, int *flags)
|
||||
{
|
||||
const QDictEntry *ent;
|
||||
|
||||
for (ent = qdict_first(cmd_args); ent; ent = qdict_next(cmd_args, ent)) {
|
||||
const char *cmd_arg_name = qdict_entry_key(ent);
|
||||
QString *type = qobject_to_qstring(qdict_entry_value(ent));
|
||||
assert(type != NULL);
|
||||
|
||||
if (qstring_get_str(type)[0] == 'O') {
|
||||
assert((*flags & QMP_ACCEPT_UNKNOWNS) == 0);
|
||||
*flags |= QMP_ACCEPT_UNKNOWNS;
|
||||
} else if (qstring_get_str(type)[0] != '-' &&
|
||||
qstring_get_str(type)[1] != '?' &&
|
||||
!qdict_haskey(client_args, cmd_arg_name)) {
|
||||
qerror_report(QERR_MISSING_PARAMETER, cmd_arg_name);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static QDict *qdict_from_args_type(const char *args_type)
|
||||
{
|
||||
int i;
|
||||
QDict *qdict;
|
||||
QString *key, *type, *cur_qs;
|
||||
|
||||
assert(args_type != NULL);
|
||||
|
||||
qdict = qdict_new();
|
||||
|
||||
if (args_type == NULL || args_type[0] == '\0') {
|
||||
/* no args, empty qdict */
|
||||
goto out;
|
||||
}
|
||||
|
||||
key = qstring_new();
|
||||
type = qstring_new();
|
||||
|
||||
cur_qs = key;
|
||||
|
||||
for (i = 0;; i++) {
|
||||
switch (args_type[i]) {
|
||||
case ',':
|
||||
case '\0':
|
||||
qdict_put(qdict, qstring_get_str(key), type);
|
||||
QDECREF(key);
|
||||
if (args_type[i] == '\0') {
|
||||
goto out;
|
||||
}
|
||||
type = qstring_new(); /* qdict has ref */
|
||||
cur_qs = key = qstring_new();
|
||||
break;
|
||||
case ':':
|
||||
cur_qs = type;
|
||||
break;
|
||||
default:
|
||||
qstring_append_chr(cur_qs, args_type[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return qdict;
|
||||
}
|
||||
|
||||
/*
|
||||
* Client argument checking rules:
|
||||
*
|
||||
* 1. Client must provide all mandatory arguments
|
||||
* 2. Each argument provided by the client must be expected
|
||||
* 3. Each argument provided by the client must have the type expected
|
||||
* by the command
|
||||
*/
|
||||
static int qmp_check_client_args(const mon_cmd_t *cmd, QDict *client_args)
|
||||
{
|
||||
int flags, err;
|
||||
QDict *cmd_args;
|
||||
|
||||
cmd_args = qdict_from_args_type(cmd->args_type);
|
||||
|
||||
flags = 0;
|
||||
err = check_mandatory_args(cmd_args, client_args, &flags);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = check_client_args_type(client_args, cmd_args, flags);
|
||||
|
||||
out:
|
||||
QDECREF(cmd_args);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input object checking rules
|
||||
*
|
||||
* 1. Input object must be a dict
|
||||
* 2. The "execute" key must exist
|
||||
* 3. The "execute" key must be a string
|
||||
* 4. If the "arguments" key exists, it must be a dict
|
||||
* 5. If the "id" key exists, it can be anything (ie. json-value)
|
||||
* 6. Any argument not listed above is considered invalid
|
||||
*/
|
||||
static QDict *qmp_check_input_obj(QObject *input_obj)
|
||||
{
|
||||
const QDictEntry *ent;
|
||||
int has_exec_key = 0;
|
||||
QDict *input_dict;
|
||||
|
||||
if (qobject_type(input_obj) != QTYPE_QDICT) {
|
||||
qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
input_dict = qobject_to_qdict(input_obj);
|
||||
|
||||
for (ent = qdict_first(input_dict); ent; ent = qdict_next(input_dict, ent)){
|
||||
const char *arg_name = qdict_entry_key(ent);
|
||||
const QObject *arg_obj = qdict_entry_value(ent);
|
||||
|
||||
if (!strcmp(arg_name, "execute")) {
|
||||
if (qobject_type(arg_obj) != QTYPE_QSTRING) {
|
||||
qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute",
|
||||
"string");
|
||||
return NULL;
|
||||
}
|
||||
has_exec_key = 1;
|
||||
} else if (!strcmp(arg_name, "arguments")) {
|
||||
if (qobject_type(arg_obj) != QTYPE_QDICT) {
|
||||
qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "arguments",
|
||||
"object");
|
||||
return NULL;
|
||||
}
|
||||
} else if (!strcmp(arg_name, "id")) {
|
||||
/* FIXME: check duplicated IDs for async commands */
|
||||
} else {
|
||||
qerror_report(QERR_QMP_EXTRA_MEMBER, arg_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_exec_key) {
|
||||
qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "execute");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return input_dict;
|
||||
}
|
||||
|
||||
static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
||||
{
|
||||
int err;
|
||||
|
@ -4161,38 +4246,28 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
|||
Monitor *mon = cur_mon;
|
||||
const char *cmd_name, *info_item;
|
||||
|
||||
args = NULL;
|
||||
args = input = NULL;
|
||||
|
||||
obj = json_parser_parse(tokens, NULL);
|
||||
if (!obj) {
|
||||
// FIXME: should be triggered in json_parser_parse()
|
||||
qerror_report(QERR_JSON_PARSING);
|
||||
goto err_out;
|
||||
} else if (qobject_type(obj) != QTYPE_QDICT) {
|
||||
qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "object");
|
||||
}
|
||||
|
||||
input = qmp_check_input_obj(obj);
|
||||
if (!input) {
|
||||
qobject_decref(obj);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
input = qobject_to_qdict(obj);
|
||||
|
||||
mon->mc->id = qdict_get(input, "id");
|
||||
qobject_incref(mon->mc->id);
|
||||
|
||||
obj = qdict_get(input, "execute");
|
||||
if (!obj) {
|
||||
qerror_report(QERR_QMP_BAD_INPUT_OBJECT, "execute");
|
||||
goto err_input;
|
||||
} else if (qobject_type(obj) != QTYPE_QSTRING) {
|
||||
qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute", "string");
|
||||
goto err_input;
|
||||
}
|
||||
|
||||
cmd_name = qstring_get_str(qobject_to_qstring(obj));
|
||||
|
||||
cmd_name = qdict_get_str(input, "execute");
|
||||
if (invalid_qmp_mode(mon, cmd_name)) {
|
||||
qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
|
||||
goto err_input;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4201,49 +4276,49 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
|
|||
*/
|
||||
if (compare_cmd(cmd_name, "info")) {
|
||||
qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
|
||||
goto err_input;
|
||||
goto err_out;
|
||||
} else if (strstart(cmd_name, "query-", &info_item)) {
|
||||
cmd = monitor_find_command("info");
|
||||
qdict_put_obj(input, "arguments",
|
||||
qobject_from_jsonf("{ 'item': %s }", info_item));
|
||||
} else {
|
||||
cmd = monitor_find_command(cmd_name);
|
||||
if (!cmd || !monitor_handler_ported(cmd)) {
|
||||
if (!cmd || !monitor_handler_ported(cmd)
|
||||
|| monitor_cmd_user_only(cmd)) {
|
||||
qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
|
||||
goto err_input;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
obj = qdict_get(input, "arguments");
|
||||
if (!obj) {
|
||||
args = qdict_new();
|
||||
} else if (qobject_type(obj) != QTYPE_QDICT) {
|
||||
qerror_report(QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "arguments", "object");
|
||||
goto err_input;
|
||||
} else {
|
||||
args = qobject_to_qdict(obj);
|
||||
QINCREF(args);
|
||||
}
|
||||
|
||||
QDECREF(input);
|
||||
|
||||
err = monitor_check_qmp_args(cmd, args);
|
||||
err = qmp_check_client_args(cmd, args);
|
||||
if (err < 0) {
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (monitor_handler_is_async(cmd)) {
|
||||
qmp_async_cmd_handler(mon, cmd, args);
|
||||
err = qmp_async_cmd_handler(mon, cmd, args);
|
||||
if (err) {
|
||||
/* emit the error response */
|
||||
goto err_out;
|
||||
}
|
||||
} else {
|
||||
monitor_call_handler(mon, cmd, args);
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
err_input:
|
||||
QDECREF(input);
|
||||
err_out:
|
||||
monitor_protocol_emitter(mon, NULL);
|
||||
out:
|
||||
QDECREF(input);
|
||||
QDECREF(args);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue