#include "qapi-event.h"
#include "qmp-introspect.h"
#include "sysemu/qtest.h"
+#include "sysemu/cpus.h"
#include "qemu/cutils.h"
#include "qapi/qmp/dispatch.h"
* When command qmp_capabilities succeeds, we go into command
* mode.
*/
- bool in_command_mode; /* are we in command mode? */
+ QmpCommandList *commands;
} MonitorQMP;
/*
static mon_cmd_t mon_cmds[];
static mon_cmd_t info_cmds[];
-QmpCommandList qmp_commands;
+QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
Monitor *cur_mon;
trace_monitor_protocol_event_emit(event, qdict);
QLIST_FOREACH(mon, &mon_list, entry) {
- if (monitor_is_qmp(mon) && mon->qmp.in_command_mode) {
+ if (monitor_is_qmp(mon)
+ && mon->qmp.commands != &qmp_cap_negotiation_commands) {
monitor_json_emitter(mon, QOBJECT(qdict));
}
}
qmp_event_set_func_emit(monitor_qapi_event_queue);
}
-void qmp_qmp_capabilities(Error **errp)
-{
- cur_mon->qmp.in_command_mode = true;
-}
-
static void handle_hmp_command(Monitor *mon, const char *cmdline);
static void monitor_data_init(Monitor *mon)
{
CommandInfoList *list = NULL;
- qmp_for_each_command(&qmp_commands, query_commands_cb, &list);
+ qmp_for_each_command(cur_mon->qmp.commands, query_commands_cb, &list);
return list;
}
static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
Error **errp)
{
- *ret_data = qobject_from_json(qmp_schema_json);
+ *ret_data = qobject_from_json(qmp_schema_json, &error_abort);
}
/*
void monitor_init_qmp_commands(void)
{
+ /*
+ * Two command lists:
+ * - qmp_commands contains all QMP commands
+ * - qmp_cap_negotiation_commands contains just
+ * "qmp_capabilities", to enforce capability negotiation
+ */
+
qmp_init_marshal(&qmp_commands);
qmp_register_command(&qmp_commands, "query-qmp-schema",
QCO_NO_OPTIONS);
qmp_unregister_commands_hack();
+
+ QTAILQ_INIT(&qmp_cap_negotiation_commands);
+ qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
+ qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS);
+}
+
+void qmp_qmp_capabilities(Error **errp)
+{
+ if (cur_mon->qmp.commands == &qmp_commands) {
+ error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
+ "Capabilities negotiation is already complete, command "
+ "ignored");
+ return;
+ }
+
+ cur_mon->qmp.commands = &qmp_commands;
}
/* set the current CPU defined by the user */
return (mon->suspend_cnt == 0) ? 1 : 0;
}
-static bool invalid_qmp_mode(const Monitor *mon, const char *cmd,
- Error **errp)
-{
- bool is_cap = g_str_equal(cmd, "qmp_capabilities");
-
- if (is_cap && mon->qmp.in_command_mode) {
- error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
- "Capabilities negotiation is already complete, command "
- "'%s' ignored", cmd);
- return true;
- }
- if (!is_cap && !mon->qmp.in_command_mode) {
- error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
- "Expecting capabilities negotiation with "
- "'qmp_capabilities' before command '%s'", cmd);
- return true;
- }
- return false;
-}
-
-/*
- * 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, Error **errp)
-{
- const QDictEntry *ent;
- int has_exec_key = 0;
- QDict *input_dict;
-
- input_dict = qobject_to_qdict(input_obj);
- if (!input_dict) {
- error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT, "object");
- return NULL;
- }
-
-
- 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) {
- error_setg(errp, 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) {
- error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER,
- "arguments", "object");
- return NULL;
- }
- } else if (!strcmp(arg_name, "id")) {
- /* Any string is acceptable as "id", so nothing to check */
- } else {
- error_setg(errp, QERR_QMP_EXTRA_MEMBER, arg_name);
- return NULL;
- }
- }
-
- if (!has_exec_key) {
- error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT, "execute");
- return NULL;
- }
-
- return input_dict;
-}
-
static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
{
QObject *req, *rsp = NULL, *id = NULL;
QDict *qdict = NULL;
- const char *cmd_name;
Monitor *mon = cur_mon;
Error *err = NULL;
goto err_out;
}
- qdict = qmp_check_input_obj(req, &err);
- if (!qdict) {
- goto err_out;
- }
-
- id = qdict_get(qdict, "id");
- qobject_incref(id);
- qdict_del(qdict, "id");
-
- cmd_name = qdict_get_str(qdict, "execute");
- trace_handle_qmp_command(mon, cmd_name);
-
- if (invalid_qmp_mode(mon, cmd_name, &err)) {
- goto err_out;
+ qdict = qobject_to_qdict(req);
+ if (qdict) {
+ id = qdict_get(qdict, "id");
+ qobject_incref(id);
+ qdict_del(qdict, "id");
+ } /* else will fail qmp_dispatch() */
+
+ rsp = qmp_dispatch(cur_mon->qmp.commands, req);
+
+ if (mon->qmp.commands == &qmp_cap_negotiation_commands) {
+ qdict = qdict_get_qdict(qobject_to_qdict(rsp), "error");
+ if (qdict
+ && !g_strcmp0(qdict_get_try_str(qdict, "class"),
+ QapiErrorClass_lookup[ERROR_CLASS_COMMAND_NOT_FOUND])) {
+ /* Provide a more useful error message */
+ qdict_del(qdict, "desc");
+ qdict_put(qdict, "desc",
+ qstring_from_str("Expecting capabilities negotiation"
+ " with 'qmp_capabilities'"));
+ }
}
- rsp = qmp_dispatch(&qmp_commands, req);
-
err_out:
if (err) {
qdict = qdict_new();
switch (event) {
case CHR_EVENT_OPENED:
- mon->qmp.in_command_mode = false;
+ mon->qmp.commands = &qmp_cap_negotiation_commands;
data = get_qmp_greeting();
monitor_json_emitter(mon, data);
qobject_decref(data);