blob: 176b549473c3c0cd1627c1888c88bf9441ca2bd2 [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"
Peter Xucf869d52018-03-10 20:38:05 -060024#include "qapi/qmp/qbool.h"
Kevin Wolf9ce44e22020-10-05 17:58:50 +020025#include "qemu/coroutine.h"
26#include "qemu/main-loop.h"
Michael Rothab02ab22011-07-19 14:50:37 -050027
Markus Armbrusterdb291642021-03-18 16:55:18 +010028Visitor *qobject_input_visitor_new_qmp(QObject *obj)
29{
30 Visitor *v = qobject_input_visitor_new(obj);
31
Markus Armbrustered29bb22021-10-25 06:24:03 +020032 visit_set_policy(v, &compat_policy);
Markus Armbrusterdb291642021-03-18 16:55:18 +010033 return v;
34}
35
Markus Armbruster91fa93e2021-03-18 16:55:11 +010036Visitor *qobject_output_visitor_new_qmp(QObject **result)
37{
38 Visitor *v = qobject_output_visitor_new(result);
39
Markus Armbrustered29bb22021-10-25 06:24:03 +020040 visit_set_policy(v, &compat_policy);
Markus Armbruster91fa93e2021-03-18 16:55:11 +010041 return v;
42}
43
Markus Armbrustera62c6172020-03-17 12:54:48 +010044static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob,
Markus Armbruster69240fe2018-07-03 10:53:43 +020045 Error **errp)
Michael Rothab02ab22011-07-19 14:50:37 -050046{
Markus Armbruster00ecec12018-07-03 10:53:38 +020047 const char *exec_key = NULL;
Michael Rothab02ab22011-07-19 14:50:37 -050048 const QDictEntry *ent;
49 const char *arg_name;
50 const QObject *arg_obj;
Michael Rothab02ab22011-07-19 14:50:37 -050051
Michael Rothab02ab22011-07-19 14:50:37 -050052 for (ent = qdict_first(dict); ent;
53 ent = qdict_next(dict, ent)) {
54 arg_name = qdict_entry_key(ent);
55 arg_obj = qdict_entry_value(ent);
56
Markus Armbruster00ecec12018-07-03 10:53:38 +020057 if (!strcmp(arg_name, "execute")
58 || (!strcmp(arg_name, "exec-oob") && allow_oob)) {
Michael Rothab02ab22011-07-19 14:50:37 -050059 if (qobject_type(arg_obj) != QTYPE_QSTRING) {
Markus Armbruster00ecec12018-07-03 10:53:38 +020060 error_setg(errp, "QMP input member '%s' must be a string",
61 arg_name);
Michael Rothab02ab22011-07-19 14:50:37 -050062 return NULL;
63 }
Markus Armbruster00ecec12018-07-03 10:53:38 +020064 if (exec_key) {
65 error_setg(errp, "QMP input member '%s' clashes with '%s'",
66 arg_name, exec_key);
67 return NULL;
68 }
69 exec_key = arg_name;
Markus Armbruster74d8c9d2017-03-03 13:32:21 +010070 } else if (!strcmp(arg_name, "arguments")) {
71 if (qobject_type(arg_obj) != QTYPE_QDICT) {
Markus Armbruster10e37832017-04-27 10:41:23 +020072 error_setg(errp,
73 "QMP input member 'arguments' must be an object");
Markus Armbruster74d8c9d2017-03-03 13:32:21 +010074 return NULL;
75 }
Marc-André Lureau4eaca8d2019-02-20 16:42:53 +010076 } else if (!strcmp(arg_name, "id")) {
77 continue;
Markus Armbruster74d8c9d2017-03-03 13:32:21 +010078 } else {
Markus Armbruster10e37832017-04-27 10:41:23 +020079 error_setg(errp, "QMP input member '%s' is unexpected",
Markus Armbruster99fb0c52017-03-03 13:32:29 +010080 arg_name);
Michael Rothab02ab22011-07-19 14:50:37 -050081 return NULL;
82 }
83 }
84
Markus Armbruster00ecec12018-07-03 10:53:38 +020085 if (!exec_key) {
Markus Armbruster10e37832017-04-27 10:41:23 +020086 error_setg(errp, "QMP input lacks member 'execute'");
Michael Rothab02ab22011-07-19 14:50:37 -050087 return NULL;
88 }
89
90 return dict;
91}
92
Markus Armbrustercee32792018-07-03 10:53:48 +020093QDict *qmp_error_response(Error *err)
Luiz Capitulino93b91c52012-08-01 16:30:13 -030094{
Markus Armbrustercee32792018-07-03 10:53:48 +020095 QDict *rsp;
96
97 rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }",
98 QapiErrorClass_str(error_get_class(err)),
99 error_get_pretty(err));
100 error_free(err);
101 return rsp;
Luiz Capitulino93b91c52012-08-01 16:30:13 -0300102}
103
Peter Xucf869d52018-03-10 20:38:05 -0600104/*
Markus Armbruster00ecec12018-07-03 10:53:38 +0200105 * Does @qdict look like a command to be run out-of-band?
Peter Xucf869d52018-03-10 20:38:05 -0600106 */
Marc-André Lureau2aa788f2018-08-29 15:40:35 +0200107bool qmp_is_oob(const QDict *dict)
Peter Xucf869d52018-03-10 20:38:05 -0600108{
Markus Armbruster00ecec12018-07-03 10:53:38 +0200109 return qdict_haskey(dict, "exec-oob")
110 && !qdict_haskey(dict, "execute");
Peter Xucf869d52018-03-10 20:38:05 -0600111}
112
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200113typedef struct QmpDispatchBH {
114 const QmpCommand *cmd;
115 Monitor *cur_mon;
116 QDict *args;
117 QObject **ret;
118 Error **errp;
119 Coroutine *co;
120} QmpDispatchBH;
121
122static void do_qmp_dispatch_bh(void *opaque)
123{
124 QmpDispatchBH *data = opaque;
125
126 assert(monitor_cur() == NULL);
127 monitor_set_cur(qemu_coroutine_self(), data->cur_mon);
128 data->cmd->fn(data->args, data->ret, data->errp);
129 monitor_set_cur(qemu_coroutine_self(), NULL);
130 aio_co_wake(data->co);
131}
132
133/*
134 * Runs outside of coroutine context for OOB commands, but in coroutine
135 * context for everything else.
136 */
Paolo Bonzinia50c99b2022-12-16 12:48:26 +0100137QDict *coroutine_mixed_fn qmp_dispatch(const QmpCommandList *cmds, QObject *request,
138 bool allow_oob, Monitor *cur_mon)
Michael Rothab02ab22011-07-19 14:50:37 -0500139{
140 Error *err = NULL;
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100141 bool oob;
142 const char *command;
143 QDict *args;
Marc-André Lureauf0ccc002020-03-16 18:18:24 +0100144 const QmpCommand *cmd;
Markus Armbrustera62c6172020-03-17 12:54:48 +0100145 QDict *dict;
146 QObject *id;
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100147 QObject *ret = NULL;
Markus Armbrusterd3226032020-03-17 12:54:47 +0100148 QDict *rsp = NULL;
Michael Rothab02ab22011-07-19 14:50:37 -0500149
Markus Armbrustera62c6172020-03-17 12:54:48 +0100150 dict = qobject_to(QDict, request);
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100151 if (!dict) {
Markus Armbrustera62c6172020-03-17 12:54:48 +0100152 id = NULL;
153 error_setg(&err, "QMP input must be a JSON object");
154 goto out;
155 }
156
157 id = qdict_get(dict, "id");
158
159 if (!qmp_dispatch_check_obj(dict, allow_oob, &err)) {
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100160 goto out;
161 }
162
163 command = qdict_get_try_str(dict, "execute");
164 oob = false;
165 if (!command) {
166 assert(allow_oob);
167 command = qdict_get_str(dict, "exec-oob");
168 oob = true;
169 }
170 cmd = qmp_find_command(cmds, command);
171 if (cmd == NULL) {
172 error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
173 "The command %s has not been found", command);
174 goto out;
175 }
Markus Armbruster7ce5fc62021-10-28 12:25:19 +0200176 if (!compat_policy_input_ok(cmd->special_features, &compat_policy,
177 ERROR_CLASS_COMMAND_NOT_FOUND,
178 "command", command, &err)) {
179 goto out;
Markus Armbrusterd2032592021-03-18 16:55:17 +0100180 }
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100181 if (!cmd->enabled) {
182 error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
Marc-André Lureauc98939d2021-02-19 12:28:14 +0400183 "Command %s has been disabled%s%s",
184 command,
185 cmd->disable_reason ? ": " : "",
186 cmd->disable_reason ?: "");
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100187 goto out;
188 }
189 if (oob && !(cmd->options & QCO_ALLOW_OOB)) {
190 error_setg(&err, "The command %s does not support OOB",
191 command);
192 goto out;
193 }
194
Paolo Bonzini164dafd2020-10-27 04:44:18 -0400195 if (!qmp_command_available(cmd, &err)) {
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100196 goto out;
197 }
198
199 if (!qdict_haskey(dict, "arguments")) {
200 args = qdict_new();
201 } else {
202 args = qdict_get_qdict(dict, "arguments");
203 qobject_ref(args);
204 }
Kevin Wolf41725fa2020-10-05 17:58:47 +0200205
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200206 assert(!(oob && qemu_in_coroutine()));
Kevin Wolf41725fa2020-10-05 17:58:47 +0200207 assert(monitor_cur() == NULL);
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200208 if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) {
Stefan Hajnoczieffd60c2024-01-18 09:48:23 -0500209 if (qemu_in_coroutine()) {
210 /*
211 * Move the coroutine from iohandler_ctx to qemu_aio_context for
212 * executing the command handler so that it can make progress if it
213 * involves an AIO_WAIT_WHILE().
214 */
Stefan Hajnoczi719c6812024-05-06 15:06:21 -0400215 aio_co_schedule(qemu_get_aio_context(), qemu_coroutine_self());
216 qemu_coroutine_yield();
Stefan Hajnoczieffd60c2024-01-18 09:48:23 -0500217 }
218
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200219 monitor_set_cur(qemu_coroutine_self(), cur_mon);
220 cmd->fn(args, &ret, &err);
221 monitor_set_cur(qemu_coroutine_self(), NULL);
Stefan Hajnoczieffd60c2024-01-18 09:48:23 -0500222
223 if (qemu_in_coroutine()) {
224 /*
225 * Yield and reschedule so the main loop stays responsive.
226 *
227 * Move back to iohandler_ctx so that nested event loops for
228 * qemu_aio_context don't start new monitor commands.
229 */
Stefan Hajnoczi719c6812024-05-06 15:06:21 -0400230 aio_co_schedule(iohandler_get_aio_context(),
231 qemu_coroutine_self());
232 qemu_coroutine_yield();
Stefan Hajnoczieffd60c2024-01-18 09:48:23 -0500233 }
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200234 } else {
235 /*
236 * Actual context doesn't match the one the command needs.
237 *
238 * Case 1: we are in coroutine context, but command does not
239 * have QCO_COROUTINE. We need to drop out of coroutine
240 * context for executing it.
241 *
242 * Case 2: we are outside coroutine context, but command has
243 * QCO_COROUTINE. Can't actually happen, because we get here
244 * outside coroutine context only when executing a command
245 * out of band, and OOB commands never have QCO_COROUTINE.
246 */
247 assert(!oob && qemu_in_coroutine() && !(cmd->options & QCO_COROUTINE));
Kevin Wolf41725fa2020-10-05 17:58:47 +0200248
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200249 QmpDispatchBH data = {
250 .cur_mon = cur_mon,
251 .cmd = cmd,
252 .args = args,
253 .ret = &ret,
254 .errp = &err,
255 .co = qemu_coroutine_self(),
256 };
Stefan Hajnoczieffd60c2024-01-18 09:48:23 -0500257 aio_bh_schedule_oneshot(iohandler_get_aio_context(), do_qmp_dispatch_bh,
Kevin Wolf9ce44e22020-10-05 17:58:50 +0200258 &data);
259 qemu_coroutine_yield();
260 }
Markus Armbrusterd3226032020-03-17 12:54:47 +0100261 qobject_unref(args);
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100262 if (err) {
Marc-André Lureaub3fbb322020-03-25 19:47:22 +0100263 /* or assert(!ret) after reviewing all handlers: */
264 qobject_unref(ret);
Markus Armbrusterd3226032020-03-17 12:54:47 +0100265 goto out;
266 }
267
268 if (cmd->options & QCO_NO_SUCCESS_RESP) {
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100269 g_assert(!ret);
Markus Armbrusterd3226032020-03-17 12:54:47 +0100270 return NULL;
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100271 } else if (!ret) {
Markus Armbruster4a883732020-03-17 12:54:49 +0100272 /*
273 * When the command's schema has no 'returns', cmd->fn()
274 * leaves @ret null. The QMP spec calls for an empty object
275 * then; supply it.
276 */
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100277 ret = QOBJECT(qdict_new());
278 }
279
Markus Armbrusterd3226032020-03-17 12:54:47 +0100280 rsp = qdict_new();
281 qdict_put_obj(rsp, "return", ret);
Markus Armbrustercf4a0642020-03-17 12:54:46 +0100282
283out:
Michael Rothab02ab22011-07-19 14:50:37 -0500284 if (err) {
Markus Armbrusterd3226032020-03-17 12:54:47 +0100285 assert(!rsp);
Markus Armbrustercee32792018-07-03 10:53:48 +0200286 rsp = qmp_error_response(err);
Michael Rothab02ab22011-07-19 14:50:37 -0500287 }
288
Markus Armbrusterd3226032020-03-17 12:54:47 +0100289 assert(rsp);
290
291 if (id) {
Marc-André Lureau4eaca8d2019-02-20 16:42:53 +0100292 qdict_put_obj(rsp, "id", qobject_ref(id));
293 }
294
Markus Armbrusterd43b1692018-07-03 10:53:49 +0200295 return rsp;
Michael Rothab02ab22011-07-19 14:50:37 -0500296}