From e7711b784f9fe5d5039b24b464b7cf88aff9d4da Mon Sep 17 00:00:00 2001 From: Jeffrey Cody Date: Tue, 20 Mar 2012 14:07:23 -0300 Subject: [RHEL6 qemu-kvm PATCH 03/21] QMP: New argument checker (first part) RH-Author: Jeffrey Cody Message-id: <5f015d41f4c7bf098a59872240cbc37a2fbec35b.1332249823.git.jcody@redhat.com> Patchwork-id: 38628 O-Subject: [RHEL6.3 qemu-kvm PATCH v3 03/21] QMP: New argument checker (first part) Bugzilla: 784153 RH-Acked-by: Kevin Wolf RH-Acked-by: Paolo Bonzini RH-Acked-by: Markus Armbruster From: Luiz Capitulino Current QMP's argument checker is more complex than it should be and has (at least) one serious bug: it ignores unknown arguments. To solve both problems we introduce a new argument checker. It's added on top of the existing one, so that there are no regressions during the transition. This commit introduces the first part of the new checker, which is run by qmp_check_client_args() and does the following: 1. Check if all mandatory arguments were provided 2. Set flags for argument validation In order to do that, we transform the args_type string (from qemu-montor.hx) into a qdict and iterate over it. Next commit adds the new checker's second part: type checking and invalid argument detection. Signed-off-by: Luiz Capitulino (cherry picked from commit 2dbc8db0ba9e34b168c3b79a6c5435f770d3796e) Signed-off-by: Jeff Cody --- monitor.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 106 insertions(+), 0 deletions(-) Signed-off-by: Eduardo Habkost --- monitor.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 106 insertions(+), 0 deletions(-) diff --git a/monitor.c b/monitor.c index 5b9deb8..4ae260f 100644 --- a/monitor.c +++ b/monitor.c @@ -189,6 +189,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[]; @@ -4585,6 +4588,104 @@ static int invalid_qmp_mode(const Monitor *mon, const char *cmd_name) return (qmp_cmd_mode(mon) ? is_cap : !is_cap); } +/* + * - 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 + */ +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; + } + + /* TODO: Check client args type */ + +out: + QDECREF(cmd_args); + return err; +} + static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) { int err; @@ -4660,6 +4761,11 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens) QDECREF(input); + err = qmp_check_client_args(cmd, args); + if (err < 0) { + goto err_out; + } + err = monitor_check_qmp_args(cmd, args); if (err < 0) { goto err_out; -- 1.7.3.2