blob: 59600210cec19dedf1aa61dc2f73430705f9f3f8 [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"
Kevin Wolf9ce44e22020-10-05 17:58:50 +020015
16#include "block/aio.h"
Markus Armbruster6dd75472021-03-18 16:55:10 +010017#include "qapi/compat-policy.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010018#include "qapi/error.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010019#include "qapi/qmp/dispatch.h"
Markus Armbruster452fcdb2018-02-01 12:18:39 +010020#include "qapi/qmp/qdict.h"
Eric Blakec7eb39c2016-06-09 10:48:32 -060021#include "qapi/qmp/qjson.h"
Markus Armbrusterdb291642021-03-18 16:55:18 +010022#include "qapi/qobject-input-visitor.h"
Markus Armbruster91fa93e2021-03-18 16:55:11 +010023#include "qapi/qobject-output-visitor.h"
Markus Armbruster54d31232019-08-12 07:23:59 +020024#include "sysemu/runstate.h"
Peter Xucf869d52018-03-10 20:38:05 -060025#include "qapi/qmp/qbool.h"
Kevin Wolf9ce44e22020-10-05 17:58:50 +020026#include "qemu/coroutine.h"
27#include "qemu/main-loop.h"
Michael Rothab02ab22011-07-19 14:50:37 -050028
Markus Armbruster6dd75472021-03-18 16:55:10 +010029CompatPolicy compat_policy;
30
Markus Armbrusterdb291642021-03-18 16:55:18 +010031Visitor *qobject_input_visitor_new_qmp(QObject *obj)
32{
33 Visitor *v = qobject_input_visitor_new(obj);
34
35 qobject_input_visitor_set_policy(v, compat_policy.deprecated_input);
36 return v;
37}
38
Markus Armbruster91fa93e2021-03-18 16:55:11 +010039Visitor *qobject_output_visitor_new_qmp(QObject **result)
40{
41 Visitor *v = qobject_output_visitor_new(result);
42
43 qobject_output_visitor_set_policy(v, compat_policy.deprecated_output);
44 return v;
45}
46
Markus Armbrustera62c6172020-03-17 12:54:48 +010047static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob,
Markus Armbruster69240fe2018-07-03 10:53:43 +020048 Error **errp)
Michael Rothab02ab22011-07-19 14:50:37 -050049{
Markus Armbruster00ecec12018-07-03 10:53:38 +020050 const char *exec_key = NULL;
Michael Rothab02ab22011-07-19 14:50:37 -050051 const QDictEntry *ent;
52 const char *arg_name;
53 const QObject *arg_obj;
Michael Rothab02ab22011-07-19 14:50:37 -050054
Michael Rothab02ab22011-07-19 14:50:37 -050055 for (ent = qdict_first(dict); ent;
56 ent = qdict_next(dict, ent)) {
57 arg_name = qdict_entry_key(ent);
58 arg_obj = qdict_entry_value(ent);
59
Markus Armbruster00ecec12018-07-03 10:53:38 +020060 if (!strcmp(arg_name, "execute")
61 || (!strcmp(arg_name, "exec-oob") && allow_oob)) {
Michael Rothab02ab22011-07-19 14:50:37 -050062 if (qobject_type(arg_obj) != QTYPE_QSTRING) {
Markus Armbruster00ecec12018-07-03 10:53:38 +020063 error_setg(errp, "QMP input member '%s' must be a string",
64 arg_name);
Michael Rothab02ab22011-07-19 14:50:37 -050065 return NULL;
66 }
Markus Armbruster00ecec12018-07-03 10:53:38 +020067 if (exec_key) {
68 error_setg(errp, "QMP input member '%s' clashes with '%s'",
69 arg_name, exec_key);
70 return NULL;
71 }
72 exec_key = arg_name;
Markus Armbruster74d8c9d2017-03-03 13:32:21 +010073 } else if (!strcmp(arg_name, "arguments")) {
74 if (qobject_type(arg_obj) != QTYPE_QDICT) {
Markus Armbruster10e37832017-04-27 10:41:23 +020075 error_setg(errp,
76 "QMP input member 'arguments' must be an object");
Markus Armbruster74d8c9d2017-03-03 13:32:21 +010077 return NULL;
78 }
Marc-André Lureau4eaca8d2019-02-20 16:42:53 +010079 } else if (!strcmp(arg_name, "id")) {
80 continue;
Markus Armbruster74d8c9d2017-03-03 13:32:21 +010081 } else {
Markus Armbruster10e37832017-04-27 10:41:23 +020082 error_setg(errp, "QMP input member '%s' is unexpected",
Markus Armbruster99fb0c52017-03-03 13:32:29 +010083 arg_name);
Michael Rothab02ab22011-07-19 14:50:37 -050084 return NULL;
85 }
86 }
87
Markus Armbruster00ecec12018-07-03 10:53:38 +020088 if (!exec_key) {
Markus Armbruster10e37832017-04-27 10:41:23 +020089 error_setg(errp, "QMP input lacks member 'execute'");
Michael Rothab02ab22011-07-19 14:50:37 -050090 return NULL;
91 }
92
93 return dict;
94}
95
Markus Armbrustercee32792018-07-03 10:53:48 +020096QDict *qmp_error_response(Error *err)
Luiz Capitulino93b91c52012-08-01 16:30:13 -030097{
Markus Armbrustercee32792018-07-03 10:53:48 +020098 QDict *rsp;
99
100 rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }",
101 QapiErrorClass_str(error_get_class(err)),
102 error_get_pretty(err));
103 error_free(err);
104 return rsp;
Luiz Capitulino93b91c52012-08-01 16:30:13 -0300105}
106
Peter Xucf869d52018-03-10 20:38:05 -0600107/*
Markus Armbruster00ecec12018-07-03 10:53:38 +0200108 * Does @qdict look like a command to be run out-of-band?
Peter Xucf869d52018-03-10 20:38:05 -0600109 */
Marc-André Lureau2aa788f2018-08-29 15:40:35 +0200110bool qmp_is_oob(const QDict *dict)
Peter Xucf869d52018-03-10 20:38:05 -0600111{
Markus Armbruster00ecec12018-07-03 10:53:38 +0200112 return qdict_haskey(dict, "exec-oob")
113 && !qdict_haskey(dict, "execute");
Peter Xucf869d52018-03-10 20:38:05 -0600114}
115
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200116typedef struct QmpDispatchBH {
117 const QmpCommand *cmd;
118 Monitor *cur_mon;
119 QDict *args;
120 QObject **ret;
121 Error **errp;
122 Coroutine *co;
123} QmpDispatchBH;
124
125static void do_qmp_dispatch_bh(void *opaque)
126{
127 QmpDispatchBH *data = opaque;
128
129 assert(monitor_cur() == NULL);
130 monitor_set_cur(qemu_coroutine_self(), data->cur_mon);
131 data->cmd->fn(data->args, data->ret, data->errp);
132 monitor_set_cur(qemu_coroutine_self(), NULL);
133 aio_co_wake(data->co);
134}
135
136/*
137 * Runs outside of coroutine context for OOB commands, but in coroutine
138 * context for everything else.
139 */
Marc-André Lureauf0ccc002020-03-16 18:18:24 +0100140QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
Kevin Wolf41725fa2020-10-05 17:58:47 +0200141 bool allow_oob, Monitor *cur_mon)
Michael Rothab02ab22011-07-19 14:50:37 -0500142{
143 Error *err = NULL;
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100144 bool oob;
145 const char *command;
146 QDict *args;
Marc-André Lureauf0ccc002020-03-16 18:18:24 +0100147 const QmpCommand *cmd;
Markus Armbrustera62c6172020-03-17 12:54:48 +0100148 QDict *dict;
149 QObject *id;
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100150 QObject *ret = NULL;
Markus Armbrusterd3226032020-03-17 12:54:47 +0100151 QDict *rsp = NULL;
Michael Rothab02ab22011-07-19 14:50:37 -0500152
Markus Armbrustera62c6172020-03-17 12:54:48 +0100153 dict = qobject_to(QDict, request);
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100154 if (!dict) {
Markus Armbrustera62c6172020-03-17 12:54:48 +0100155 id = NULL;
156 error_setg(&err, "QMP input must be a JSON object");
157 goto out;
158 }
159
160 id = qdict_get(dict, "id");
161
162 if (!qmp_dispatch_check_obj(dict, allow_oob, &err)) {
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100163 goto out;
164 }
165
166 command = qdict_get_try_str(dict, "execute");
167 oob = false;
168 if (!command) {
169 assert(allow_oob);
170 command = qdict_get_str(dict, "exec-oob");
171 oob = true;
172 }
173 cmd = qmp_find_command(cmds, command);
174 if (cmd == NULL) {
175 error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
176 "The command %s has not been found", command);
177 goto out;
178 }
Markus Armbrusterd2032592021-03-18 16:55:17 +0100179 if (cmd->options & QCO_DEPRECATED) {
180 switch (compat_policy.deprecated_input) {
181 case COMPAT_POLICY_INPUT_ACCEPT:
182 break;
183 case COMPAT_POLICY_INPUT_REJECT:
184 error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
185 "Deprecated command %s disabled by policy",
186 command);
187 goto out;
Markus Armbrusterdbb675c2021-03-18 16:55:19 +0100188 case COMPAT_POLICY_INPUT_CRASH:
Markus Armbrusterd2032592021-03-18 16:55:17 +0100189 default:
190 abort();
191 }
192 }
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100193 if (!cmd->enabled) {
194 error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
Marc-André Lureauc98939d2021-02-19 12:28:14 +0400195 "Command %s has been disabled%s%s",
196 command,
197 cmd->disable_reason ? ": " : "",
198 cmd->disable_reason ?: "");
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100199 goto out;
200 }
201 if (oob && !(cmd->options & QCO_ALLOW_OOB)) {
202 error_setg(&err, "The command %s does not support OOB",
203 command);
204 goto out;
205 }
206
Paolo Bonzini164dafd2020-10-27 04:44:18 -0400207 if (!qmp_command_available(cmd, &err)) {
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100208 goto out;
209 }
210
211 if (!qdict_haskey(dict, "arguments")) {
212 args = qdict_new();
213 } else {
214 args = qdict_get_qdict(dict, "arguments");
215 qobject_ref(args);
216 }
Kevin Wolf41725fa2020-10-05 17:58:47 +0200217
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200218 assert(!(oob && qemu_in_coroutine()));
Kevin Wolf41725fa2020-10-05 17:58:47 +0200219 assert(monitor_cur() == NULL);
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200220 if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) {
221 monitor_set_cur(qemu_coroutine_self(), cur_mon);
222 cmd->fn(args, &ret, &err);
223 monitor_set_cur(qemu_coroutine_self(), NULL);
224 } else {
225 /*
226 * Actual context doesn't match the one the command needs.
227 *
228 * Case 1: we are in coroutine context, but command does not
229 * have QCO_COROUTINE. We need to drop out of coroutine
230 * context for executing it.
231 *
232 * Case 2: we are outside coroutine context, but command has
233 * QCO_COROUTINE. Can't actually happen, because we get here
234 * outside coroutine context only when executing a command
235 * out of band, and OOB commands never have QCO_COROUTINE.
236 */
237 assert(!oob && qemu_in_coroutine() && !(cmd->options & QCO_COROUTINE));
Kevin Wolf41725fa2020-10-05 17:58:47 +0200238
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200239 QmpDispatchBH data = {
240 .cur_mon = cur_mon,
241 .cmd = cmd,
242 .args = args,
243 .ret = &ret,
244 .errp = &err,
245 .co = qemu_coroutine_self(),
246 };
247 aio_bh_schedule_oneshot(qemu_get_aio_context(), do_qmp_dispatch_bh,
248 &data);
249 qemu_coroutine_yield();
250 }
Markus Armbrusterd3226032020-03-17 12:54:47 +0100251 qobject_unref(args);
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100252 if (err) {
Marc-André Lureaub3fbb322020-03-25 19:47:22 +0100253 /* or assert(!ret) after reviewing all handlers: */
254 qobject_unref(ret);
Markus Armbrusterd3226032020-03-17 12:54:47 +0100255 goto out;
256 }
257
258 if (cmd->options & QCO_NO_SUCCESS_RESP) {
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100259 g_assert(!ret);
Markus Armbrusterd3226032020-03-17 12:54:47 +0100260 return NULL;
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100261 } else if (!ret) {
Markus Armbruster4a883732020-03-17 12:54:49 +0100262 /*
263 * When the command's schema has no 'returns', cmd->fn()
264 * leaves @ret null. The QMP spec calls for an empty object
265 * then; supply it.
266 */
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100267 ret = QOBJECT(qdict_new());
268 }
269
Markus Armbrusterd3226032020-03-17 12:54:47 +0100270 rsp = qdict_new();
271 qdict_put_obj(rsp, "return", ret);
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100272
273out:
Michael Rothab02ab22011-07-19 14:50:37 -0500274 if (err) {
Markus Armbrusterd3226032020-03-17 12:54:47 +0100275 assert(!rsp);
Markus Armbrustercee32792018-07-03 10:53:48 +0200276 rsp = qmp_error_response(err);
Michael Rothab02ab22011-07-19 14:50:37 -0500277 }
278
Markus Armbrusterd3226032020-03-17 12:54:47 +0100279 assert(rsp);
280
281 if (id) {
Marc-André Lureau4eaca8d2019-02-20 16:42:53 +0100282 qdict_put_obj(rsp, "id", qobject_ref(id));
283 }
284
Markus Armbrusterd43b1692018-07-03 10:53:49 +0200285 return rsp;
Michael Rothab02ab22011-07-19 14:50:37 -0500286}