blob: 5ad36f8a09af72b8967d1b47448489665ba412e4 [file] [log] [blame]
Michael Rothab02ab22011-07-19 14:50:37 -05001/*
2 * Core Definitions for QAPI/QMP Dispatch
3 *
4 * Copyright IBM, Corp. 2011
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10 * See the COPYING.LIB file in the top-level directory.
11 *
12 */
13
Peter Maydellcbf21152016-01-29 17:49:57 +000014#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010015#include "qapi/error.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010016#include "qapi/qmp/types.h"
17#include "qapi/qmp/dispatch.h"
18#include "qapi/qmp/json-parser.h"
Eric Blakec7eb39c2016-06-09 10:48:32 -060019#include "qapi/qmp/qjson.h"
Luiz Capitulino93b91c52012-08-01 16:30:13 -030020#include "qapi-types.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010021#include "qapi/qmp/qerror.h"
Michael Rothab02ab22011-07-19 14:50:37 -050022
23static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
24{
25 const QDictEntry *ent;
26 const char *arg_name;
27 const QObject *arg_obj;
28 bool has_exec_key = false;
29 QDict *dict = NULL;
30
Markus Armbrusterca6b6e12017-02-17 21:38:18 +010031 dict = qobject_to_qdict(request);
32 if (!dict) {
Markus Armbruster10e37832017-04-27 10:41:23 +020033 error_setg(errp, "QMP input must be a JSON object");
Michael Rothab02ab22011-07-19 14:50:37 -050034 return NULL;
35 }
36
Michael Rothab02ab22011-07-19 14:50:37 -050037 for (ent = qdict_first(dict); ent;
38 ent = qdict_next(dict, ent)) {
39 arg_name = qdict_entry_key(ent);
40 arg_obj = qdict_entry_value(ent);
41
42 if (!strcmp(arg_name, "execute")) {
43 if (qobject_type(arg_obj) != QTYPE_QSTRING) {
Markus Armbruster10e37832017-04-27 10:41:23 +020044 error_setg(errp,
45 "QMP input member 'execute' must be a string");
Michael Rothab02ab22011-07-19 14:50:37 -050046 return NULL;
47 }
48 has_exec_key = true;
Markus Armbruster74d8c9d2017-03-03 13:32:21 +010049 } else if (!strcmp(arg_name, "arguments")) {
50 if (qobject_type(arg_obj) != QTYPE_QDICT) {
Markus Armbruster10e37832017-04-27 10:41:23 +020051 error_setg(errp,
52 "QMP input member 'arguments' must be an object");
Markus Armbruster74d8c9d2017-03-03 13:32:21 +010053 return NULL;
54 }
55 } else {
Markus Armbruster10e37832017-04-27 10:41:23 +020056 error_setg(errp, "QMP input member '%s' is unexpected",
Markus Armbruster99fb0c52017-03-03 13:32:29 +010057 arg_name);
Michael Rothab02ab22011-07-19 14:50:37 -050058 return NULL;
59 }
60 }
61
62 if (!has_exec_key) {
Markus Armbruster10e37832017-04-27 10:41:23 +020063 error_setg(errp, "QMP input lacks member 'execute'");
Michael Rothab02ab22011-07-19 14:50:37 -050064 return NULL;
65 }
66
67 return dict;
68}
69
Markus Armbruster1527bad2017-03-03 13:32:25 +010070static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
71 Error **errp)
Michael Rothab02ab22011-07-19 14:50:37 -050072{
Markus Armbrusteree16ce92014-05-02 13:26:37 +020073 Error *local_err = NULL;
Michael Rothab02ab22011-07-19 14:50:37 -050074 const char *command;
75 QDict *args, *dict;
76 QmpCommand *cmd;
77 QObject *ret = NULL;
78
Michael Rothab02ab22011-07-19 14:50:37 -050079 dict = qmp_dispatch_check_obj(request, errp);
Markus Armbruster4af8be12014-05-02 13:26:35 +020080 if (!dict) {
Michael Rothab02ab22011-07-19 14:50:37 -050081 return NULL;
82 }
83
84 command = qdict_get_str(dict, "execute");
Markus Armbruster1527bad2017-03-03 13:32:25 +010085 cmd = qmp_find_command(cmds, command);
Michael Rothab02ab22011-07-19 14:50:37 -050086 if (cmd == NULL) {
Markus Armbrustera6c90cb2015-01-13 16:16:35 +010087 error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
88 "The command %s has not been found", command);
Michael Rothab02ab22011-07-19 14:50:37 -050089 return NULL;
90 }
Michael Rothabd6cf62011-12-06 22:03:42 -060091 if (!cmd->enabled) {
Cole Robinsonf231b882014-03-21 19:42:26 -040092 error_setg(errp, "The command %s has been disabled for this instance",
93 command);
Michael Rothabd6cf62011-12-06 22:03:42 -060094 return NULL;
95 }
Michael Rothab02ab22011-07-19 14:50:37 -050096
97 if (!qdict_haskey(dict, "arguments")) {
98 args = qdict_new();
99 } else {
100 args = qdict_get_qdict(dict, "arguments");
101 QINCREF(args);
102 }
103
Eric Blake42a502a2016-04-28 15:45:11 -0600104 cmd->fn(args, &ret, &local_err);
105 if (local_err) {
106 error_propagate(errp, local_err);
107 } else if (cmd->options & QCO_NO_SUCCESS_RESP) {
108 g_assert(!ret);
109 } else if (!ret) {
110 ret = QOBJECT(qdict_new());
Michael Rothab02ab22011-07-19 14:50:37 -0500111 }
112
113 QDECREF(args);
114
115 return ret;
116}
117
Markus Armbrustere940f542014-05-02 13:26:29 +0200118QObject *qmp_build_error_object(Error *err)
Luiz Capitulino93b91c52012-08-01 16:30:13 -0300119{
120 return qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
Eric Blakef22a28b2015-11-18 01:53:00 -0700121 QapiErrorClass_lookup[error_get_class(err)],
Markus Armbrustere940f542014-05-02 13:26:29 +0200122 error_get_pretty(err));
Luiz Capitulino93b91c52012-08-01 16:30:13 -0300123}
124
Markus Armbruster1527bad2017-03-03 13:32:25 +0100125QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request)
Michael Rothab02ab22011-07-19 14:50:37 -0500126{
127 Error *err = NULL;
128 QObject *ret;
129 QDict *rsp;
130
Markus Armbruster1527bad2017-03-03 13:32:25 +0100131 ret = do_qmp_dispatch(cmds, request, &err);
Michael Rothab02ab22011-07-19 14:50:37 -0500132
133 rsp = qdict_new();
134 if (err) {
Luiz Capitulino93b91c52012-08-01 16:30:13 -0300135 qdict_put_obj(rsp, "error", qmp_build_error_object(err));
Michael Rothab02ab22011-07-19 14:50:37 -0500136 error_free(err);
137 } else if (ret) {
138 qdict_put_obj(rsp, "return", ret);
139 } else {
140 QDECREF(rsp);
141 return NULL;
142 }
143
144 return QOBJECT(rsp);
145}