This patch adds the CommandArgumentInfo type that lists the details of an argument that a QMP command can take. It currently includes its name and whether it's optional or not, but it can be extended in the future to include other information.
A new 'query-command-args' command returns a list of all supported arguments from a particular command. Additionally, 'query-commands' has a new, optional, 'query-args' argument that makes the return value include the arguments for all commands. Signed-off-by: Alberto Garcia <be...@igalia.com> --- monitor.c | 53 +++++++++++++++++++++++++++++++- qapi/common.json | 41 +++++++++++++++++++++++-- qmp-commands.hx | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 178 insertions(+), 9 deletions(-) diff --git a/monitor.c b/monitor.c index c3cc060..867a1cc 100644 --- a/monitor.c +++ b/monitor.c @@ -231,6 +231,8 @@ static const mon_cmd_t qmp_cmds[]; Monitor *cur_mon; Monitor *default_mon; +static const mon_cmd_t *qmp_find_cmd(const char *cmdname); + static void monitor_command_cb(void *opaque, const char *cmdline, void *readline_opaque); @@ -963,7 +965,52 @@ static void do_info_help(Monitor *mon, const QDict *qdict) help_cmd(mon, "info"); } -CommandInfoList *qmp_query_commands(Error **errp) +CommandArgumentInfoList *qmp_query_command_args(const char *command, + Error **errp) +{ + CommandArgumentInfoList *cmd_list = NULL; + const mon_cmd_t *cmd = qmp_find_cmd(command); + const char *arg; + + if (cmd == NULL) { + error_setg(errp, "Command '%s' not found", command); + return NULL; + } + + for (arg = cmd->args_type; arg && *arg; arg = index(arg, ',')) { + CommandArgumentInfoList *info; + const char *type = index(arg, ':'); + + /* Skip the comma before the argument name */ + if (*arg == ',') { + arg++; + } + + /* Skip the semicolon before the argument type */ + if (type) { + type++; + } + + /* Check if the string is malformed */ + if (!type || !*type) { + g_assert_not_reached(); + return cmd_list; + } + + info = g_malloc0(sizeof(*info)); + info->value = g_malloc0(sizeof(*info->value)); + info->value->name = g_strndup(arg, type - arg - 1); + info->value->optional = (type[0] == '-' || type[1] == '?'); + + info->next = cmd_list; + cmd_list = info; + } + + return cmd_list; +} + +CommandInfoList *qmp_query_commands(bool has_query_args, bool query_args, + Error **errp) { CommandInfoList *info, *cmd_list = NULL; const mon_cmd_t *cmd; @@ -973,6 +1020,10 @@ CommandInfoList *qmp_query_commands(Error **errp) info->value = g_malloc0(sizeof(*info->value)); info->value->name = g_strdup(cmd->name); + if (has_query_args && query_args) { + info->value->args = qmp_query_command_args(cmd->name, errp); + } + info->next = cmd_list; cmd_list = info; } diff --git a/qapi/common.json b/qapi/common.json index 63ef3b4..d812557 100644 --- a/qapi/common.json +++ b/qapi/common.json @@ -66,26 +66,63 @@ { 'command': 'query-version', 'returns': 'VersionInfo' } ## +# @CommandArgumentInfo: +# +# Information about an argument that a QMP command can take. +# +# @name: The argument name. +# +# @optional: Whether the argument is optional or not +# +# Since: 2.3 +## +{ 'type': 'CommandArgumentInfo', + 'data': {'name': 'str', 'optional': 'bool'} } + +## # @CommandInfo: # # Information about a QMP command # # @name: The command name # +# @args: A list of @CommandArgumentInfo that the command can take (Since 2.3) +# # Since: 0.14.0 ## -{ 'type': 'CommandInfo', 'data': {'name': 'str'} } +{ 'type': 'CommandInfo', + 'data': {'name': 'str', 'args': ['CommandArgumentInfo'] } } ## # @query-commands: # # Return a list of supported QMP commands by this server # +# @query-args: #optional Whether to return the list of arguments +# for that command. Defaults to false (Since 2.3) +# # Returns: A list of @CommandInfo for all supported commands # # Since: 0.14.0 ## -{ 'command': 'query-commands', 'returns': ['CommandInfo'] } +{ 'command': 'query-commands', + 'data': {'*query-args': 'bool' }, + 'returns': ['CommandInfo'] } + +## +# @query-command-args: +# +# Return the list of arguments that a QMP command can take +# +# @command: Name of the command to query +# +# Returns: A list of @CommandArgumentInfo for all supported arguments +# +# Since: 2.3 +## +{ 'command': 'query-command-args', + 'data': {'command': 'str' }, + 'returns': ['CommandArgumentInfo'] } ## # @OnOffAuto diff --git a/qmp-commands.hx b/qmp-commands.hx index a85d847..cab69f9 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1946,25 +1946,52 @@ query-commands List QMP available commands. Each command is represented by a json-object, the returned value is a json-array -of all commands. +of all commands, optionally including their arguments. + +Arguments: + +- "query-args": whether to return the arguments for each command. + Defaults to false (json-bool, optional) Each json-object contain: - "name": command's name (json-string) +- "args": a json-array of all arguments for that command. It will be empty if + the list of arguments was not requested using "query-args". + Each argument contains: + - "name": name of the argument (json-string) + - "optional": whether the argument is optional or not (json-bool) Example: --> { "execute": "query-commands" } +-> { "execute": "query-commands", "arguments": { "query-args": true } } <- { "return":[ { - "name":"query-balloon" + "name": "drive-backup", + "args": [ + { "name": "sync", "optional": false } + { "name": "device", "optional": false }, + { "name": "target", "optional": false }, + { "name": "speed", "optional": true }, + { "name": "mode", "optional": true }, + { "name": "format", "optional": true }, + { "name": "on-source-error", "optional": true }, + { "name": "on-target-error", "optional": true }, + ] }, { - "name":"system_powerdown" + "name": "block-commit", + "args": [ + { "name": "device", "optional": false } + { "name": "base", "optional": true }, + { "name": "top", "optional": true }, + { "name": "backing-file", "optional": true }, + { "name": "speed", "optional": true }, + ] } ] - } +} Note: This example has been shortened as the real response is too long. @@ -1972,11 +1999,65 @@ EQMP { .name = "query-commands", - .args_type = "", + .args_type = "query-args:b?", .mhandler.cmd_new = qmp_marshal_input_query_commands, }, SQMP +query-command-args +------------------ + +List all arguments from a QMP command. + +Each argument is represented by a json-object, the returned value is a +json-array of all arguments from a particular command. + +Arguments: + +- "command": the command name (json-string) + +Each json-object contain: + +- "name": the name of the argument (json-string) +- "optional": whether that argument is optional or not (json-bool) + +Example: + +-> { "execute": "query-command-args", "arguments": { "command": "block-commit" } } +<- { + "return":[ + { + "name": "device", + "optional": false + }, + { + "name": "base", + "optional": true + }, + { + "name": "top", + "optional": true + }, + { + "name": "backing-file", + "optional": true + }, + { + "name": "speed", + "optional": true + } + ] +} + +EQMP + + { + .name = "query-command-args", + .args_type = "command:s", + .mhandler.cmd_new = qmp_marshal_input_query_command_args, + }, + +SQMP query-events -------------- -- 2.1.4