1ab02ab2aSMichael Roth /*
2ab02ab2aSMichael Roth * Core Definitions for QAPI/QMP Dispatch
3ab02ab2aSMichael Roth *
4ab02ab2aSMichael Roth * Copyright IBM, Corp. 2011
5ab02ab2aSMichael Roth *
6ab02ab2aSMichael Roth * Authors:
7ab02ab2aSMichael Roth * Anthony Liguori <aliguori@us.ibm.com>
8ab02ab2aSMichael Roth *
9ab02ab2aSMichael Roth * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10ab02ab2aSMichael Roth * See the COPYING.LIB file in the top-level directory.
11ab02ab2aSMichael Roth *
12ab02ab2aSMichael Roth */
13ab02ab2aSMichael Roth
14cbf21151SPeter Maydell #include "qemu/osdep.h"
159ce44e2cSKevin Wolf
169ce44e2cSKevin Wolf #include "block/aio.h"
176dd75472SMarkus Armbruster #include "qapi/compat-policy.h"
18da34e65cSMarkus Armbruster #include "qapi/error.h"
197b1b5d19SPaolo Bonzini #include "qapi/qmp/dispatch.h"
20452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h"
21c7eb39cbSEric Blake #include "qapi/qmp/qjson.h"
22db291641SMarkus Armbruster #include "qapi/qobject-input-visitor.h"
2391fa93e5SMarkus Armbruster #include "qapi/qobject-output-visitor.h"
24cf869d53SPeter Xu #include "qapi/qmp/qbool.h"
259ce44e2cSKevin Wolf #include "qemu/coroutine.h"
269ce44e2cSKevin Wolf #include "qemu/main-loop.h"
27ab02ab2aSMichael Roth
qobject_input_visitor_new_qmp(QObject * obj)28db291641SMarkus Armbruster Visitor *qobject_input_visitor_new_qmp(QObject *obj)
29db291641SMarkus Armbruster {
30db291641SMarkus Armbruster Visitor *v = qobject_input_visitor_new(obj);
31db291641SMarkus Armbruster
32ed29bb28SMarkus Armbruster visit_set_policy(v, &compat_policy);
33db291641SMarkus Armbruster return v;
34db291641SMarkus Armbruster }
35db291641SMarkus Armbruster
qobject_output_visitor_new_qmp(QObject ** result)3691fa93e5SMarkus Armbruster Visitor *qobject_output_visitor_new_qmp(QObject **result)
3791fa93e5SMarkus Armbruster {
3891fa93e5SMarkus Armbruster Visitor *v = qobject_output_visitor_new(result);
3991fa93e5SMarkus Armbruster
40ed29bb28SMarkus Armbruster visit_set_policy(v, &compat_policy);
4191fa93e5SMarkus Armbruster return v;
4291fa93e5SMarkus Armbruster }
4391fa93e5SMarkus Armbruster
qmp_dispatch_check_obj(QDict * dict,bool allow_oob,Error ** errp)44a62c6174SMarkus Armbruster static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob,
45674ed722SMarkus Armbruster Error **errp)
46ab02ab2aSMichael Roth {
4700ecec15SMarkus Armbruster const char *exec_key = NULL;
48ab02ab2aSMichael Roth const QDictEntry *ent;
49ab02ab2aSMichael Roth const char *arg_name;
50ab02ab2aSMichael Roth const QObject *arg_obj;
51ab02ab2aSMichael Roth
52ab02ab2aSMichael Roth for (ent = qdict_first(dict); ent;
53ab02ab2aSMichael Roth ent = qdict_next(dict, ent)) {
54ab02ab2aSMichael Roth arg_name = qdict_entry_key(ent);
55ab02ab2aSMichael Roth arg_obj = qdict_entry_value(ent);
56ab02ab2aSMichael Roth
5700ecec15SMarkus Armbruster if (!strcmp(arg_name, "execute")
5800ecec15SMarkus Armbruster || (!strcmp(arg_name, "exec-oob") && allow_oob)) {
59ab02ab2aSMichael Roth if (qobject_type(arg_obj) != QTYPE_QSTRING) {
6000ecec15SMarkus Armbruster error_setg(errp, "QMP input member '%s' must be a string",
6100ecec15SMarkus Armbruster arg_name);
62ab02ab2aSMichael Roth return NULL;
63ab02ab2aSMichael Roth }
6400ecec15SMarkus Armbruster if (exec_key) {
6500ecec15SMarkus Armbruster error_setg(errp, "QMP input member '%s' clashes with '%s'",
6600ecec15SMarkus Armbruster arg_name, exec_key);
6700ecec15SMarkus Armbruster return NULL;
6800ecec15SMarkus Armbruster }
6900ecec15SMarkus Armbruster exec_key = arg_name;
7074d8c9d9SMarkus Armbruster } else if (!strcmp(arg_name, "arguments")) {
7174d8c9d9SMarkus Armbruster if (qobject_type(arg_obj) != QTYPE_QDICT) {
7210e37839SMarkus Armbruster error_setg(errp,
7310e37839SMarkus Armbruster "QMP input member 'arguments' must be an object");
7474d8c9d9SMarkus Armbruster return NULL;
7574d8c9d9SMarkus Armbruster }
764eaca8deSMarc-André Lureau } else if (!strcmp(arg_name, "id")) {
774eaca8deSMarc-André Lureau continue;
7874d8c9d9SMarkus Armbruster } else {
7910e37839SMarkus Armbruster error_setg(errp, "QMP input member '%s' is unexpected",
8099fb0c53SMarkus Armbruster arg_name);
81ab02ab2aSMichael Roth return NULL;
82ab02ab2aSMichael Roth }
83ab02ab2aSMichael Roth }
84ab02ab2aSMichael Roth
8500ecec15SMarkus Armbruster if (!exec_key) {
8610e37839SMarkus Armbruster error_setg(errp, "QMP input lacks member 'execute'");
87ab02ab2aSMichael Roth return NULL;
88ab02ab2aSMichael Roth }
89ab02ab2aSMichael Roth
90ab02ab2aSMichael Roth return dict;
91ab02ab2aSMichael Roth }
92ab02ab2aSMichael Roth
qmp_error_response(Error * err)93cee32796SMarkus Armbruster QDict *qmp_error_response(Error *err)
9493b91c59SLuiz Capitulino {
95cee32796SMarkus Armbruster QDict *rsp;
96cee32796SMarkus Armbruster
97cee32796SMarkus Armbruster rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }",
98977c736fSMarkus Armbruster QapiErrorClass_str(error_get_class(err)),
99e940f543SMarkus Armbruster error_get_pretty(err));
100cee32796SMarkus Armbruster error_free(err);
101cee32796SMarkus Armbruster return rsp;
10293b91c59SLuiz Capitulino }
10393b91c59SLuiz Capitulino
104cf869d53SPeter Xu /*
10500ecec15SMarkus Armbruster * Does @qdict look like a command to be run out-of-band?
106cf869d53SPeter Xu */
qmp_is_oob(const QDict * dict)1072aa788f5SMarc-André Lureau bool qmp_is_oob(const QDict *dict)
108cf869d53SPeter Xu {
10900ecec15SMarkus Armbruster return qdict_haskey(dict, "exec-oob")
11000ecec15SMarkus Armbruster && !qdict_haskey(dict, "execute");
111cf869d53SPeter Xu }
112cf869d53SPeter Xu
1139ce44e2cSKevin Wolf typedef struct QmpDispatchBH {
1149ce44e2cSKevin Wolf const QmpCommand *cmd;
1159ce44e2cSKevin Wolf Monitor *cur_mon;
1169ce44e2cSKevin Wolf QDict *args;
1179ce44e2cSKevin Wolf QObject **ret;
1189ce44e2cSKevin Wolf Error **errp;
1199ce44e2cSKevin Wolf Coroutine *co;
1209ce44e2cSKevin Wolf } QmpDispatchBH;
1219ce44e2cSKevin Wolf
do_qmp_dispatch_bh(void * opaque)1229ce44e2cSKevin Wolf static void do_qmp_dispatch_bh(void *opaque)
1239ce44e2cSKevin Wolf {
1249ce44e2cSKevin Wolf QmpDispatchBH *data = opaque;
1259ce44e2cSKevin Wolf
1269ce44e2cSKevin Wolf assert(monitor_cur() == NULL);
1279ce44e2cSKevin Wolf monitor_set_cur(qemu_coroutine_self(), data->cur_mon);
1289ce44e2cSKevin Wolf data->cmd->fn(data->args, data->ret, data->errp);
1299ce44e2cSKevin Wolf monitor_set_cur(qemu_coroutine_self(), NULL);
1309ce44e2cSKevin Wolf aio_co_wake(data->co);
1319ce44e2cSKevin Wolf }
1329ce44e2cSKevin Wolf
1339ce44e2cSKevin Wolf /*
1349ce44e2cSKevin Wolf * Runs outside of coroutine context for OOB commands, but in coroutine
1359ce44e2cSKevin Wolf * context for everything else.
1369ce44e2cSKevin Wolf */
qmp_dispatch(const QmpCommandList * cmds,QObject * request,bool allow_oob,Monitor * cur_mon)137a50c99bcSPaolo Bonzini QDict *coroutine_mixed_fn qmp_dispatch(const QmpCommandList *cmds, QObject *request,
13841725fa7SKevin Wolf bool allow_oob, Monitor *cur_mon)
139ab02ab2aSMichael Roth {
140ab02ab2aSMichael Roth Error *err = NULL;
141cf4a0643SMarkus Armbruster bool oob;
142cf4a0643SMarkus Armbruster const char *command;
143cf4a0643SMarkus Armbruster QDict *args;
144f0ccc00bSMarc-André Lureau const QmpCommand *cmd;
145a62c6174SMarkus Armbruster QDict *dict;
146a62c6174SMarkus Armbruster QObject *id;
147cf4a0643SMarkus Armbruster QObject *ret = NULL;
148d3226035SMarkus Armbruster QDict *rsp = NULL;
149ab02ab2aSMichael Roth
150a62c6174SMarkus Armbruster dict = qobject_to(QDict, request);
151cf4a0643SMarkus Armbruster if (!dict) {
152a62c6174SMarkus Armbruster id = NULL;
153a62c6174SMarkus Armbruster error_setg(&err, "QMP input must be a JSON object");
154a62c6174SMarkus Armbruster goto out;
155a62c6174SMarkus Armbruster }
156a62c6174SMarkus Armbruster
157a62c6174SMarkus Armbruster id = qdict_get(dict, "id");
158a62c6174SMarkus Armbruster
159a62c6174SMarkus Armbruster if (!qmp_dispatch_check_obj(dict, allow_oob, &err)) {
160cf4a0643SMarkus Armbruster goto out;
161cf4a0643SMarkus Armbruster }
162cf4a0643SMarkus Armbruster
163cf4a0643SMarkus Armbruster command = qdict_get_try_str(dict, "execute");
164cf4a0643SMarkus Armbruster oob = false;
165cf4a0643SMarkus Armbruster if (!command) {
166cf4a0643SMarkus Armbruster assert(allow_oob);
167cf4a0643SMarkus Armbruster command = qdict_get_str(dict, "exec-oob");
168cf4a0643SMarkus Armbruster oob = true;
169cf4a0643SMarkus Armbruster }
170cf4a0643SMarkus Armbruster cmd = qmp_find_command(cmds, command);
171cf4a0643SMarkus Armbruster if (cmd == NULL) {
172cf4a0643SMarkus Armbruster error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
173cf4a0643SMarkus Armbruster "The command %s has not been found", command);
174cf4a0643SMarkus Armbruster goto out;
175cf4a0643SMarkus Armbruster }
1767ce5fc63SMarkus Armbruster if (!compat_policy_input_ok(cmd->special_features, &compat_policy,
1777ce5fc63SMarkus Armbruster ERROR_CLASS_COMMAND_NOT_FOUND,
1787ce5fc63SMarkus Armbruster "command", command, &err)) {
179d2032598SMarkus Armbruster goto out;
180d2032598SMarkus Armbruster }
181cf4a0643SMarkus Armbruster if (!cmd->enabled) {
182cf4a0643SMarkus Armbruster error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
183c98939daSMarc-André Lureau "Command %s has been disabled%s%s",
184c98939daSMarc-André Lureau command,
185c98939daSMarc-André Lureau cmd->disable_reason ? ": " : "",
186c98939daSMarc-André Lureau cmd->disable_reason ?: "");
187cf4a0643SMarkus Armbruster goto out;
188cf4a0643SMarkus Armbruster }
189cf4a0643SMarkus Armbruster if (oob && !(cmd->options & QCO_ALLOW_OOB)) {
190cf4a0643SMarkus Armbruster error_setg(&err, "The command %s does not support OOB",
191cf4a0643SMarkus Armbruster command);
192cf4a0643SMarkus Armbruster goto out;
193cf4a0643SMarkus Armbruster }
194cf4a0643SMarkus Armbruster
195164dafd1SPaolo Bonzini if (!qmp_command_available(cmd, &err)) {
196cf4a0643SMarkus Armbruster goto out;
197cf4a0643SMarkus Armbruster }
198cf4a0643SMarkus Armbruster
199cf4a0643SMarkus Armbruster if (!qdict_haskey(dict, "arguments")) {
200cf4a0643SMarkus Armbruster args = qdict_new();
201cf4a0643SMarkus Armbruster } else {
202cf4a0643SMarkus Armbruster args = qdict_get_qdict(dict, "arguments");
203cf4a0643SMarkus Armbruster qobject_ref(args);
204cf4a0643SMarkus Armbruster }
20541725fa7SKevin Wolf
2069ce44e2cSKevin Wolf assert(!(oob && qemu_in_coroutine()));
20741725fa7SKevin Wolf assert(monitor_cur() == NULL);
2089ce44e2cSKevin Wolf if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) {
209effd60c8SStefan Hajnoczi if (qemu_in_coroutine()) {
210effd60c8SStefan Hajnoczi /*
211effd60c8SStefan Hajnoczi * Move the coroutine from iohandler_ctx to qemu_aio_context for
212effd60c8SStefan Hajnoczi * executing the command handler so that it can make progress if it
213effd60c8SStefan Hajnoczi * involves an AIO_WAIT_WHILE().
214effd60c8SStefan Hajnoczi */
215*719c6819SStefan Hajnoczi aio_co_schedule(qemu_get_aio_context(), qemu_coroutine_self());
216*719c6819SStefan Hajnoczi qemu_coroutine_yield();
217effd60c8SStefan Hajnoczi }
218effd60c8SStefan Hajnoczi
219e69ee454SKevin Wolf monitor_set_cur(qemu_coroutine_self(), cur_mon);
220cf4a0643SMarkus Armbruster cmd->fn(args, &ret, &err);
221e69ee454SKevin Wolf monitor_set_cur(qemu_coroutine_self(), NULL);
222effd60c8SStefan Hajnoczi
223effd60c8SStefan Hajnoczi if (qemu_in_coroutine()) {
224effd60c8SStefan Hajnoczi /*
225effd60c8SStefan Hajnoczi * Yield and reschedule so the main loop stays responsive.
226effd60c8SStefan Hajnoczi *
227effd60c8SStefan Hajnoczi * Move back to iohandler_ctx so that nested event loops for
228effd60c8SStefan Hajnoczi * qemu_aio_context don't start new monitor commands.
229effd60c8SStefan Hajnoczi */
230*719c6819SStefan Hajnoczi aio_co_schedule(iohandler_get_aio_context(),
231*719c6819SStefan Hajnoczi qemu_coroutine_self());
232*719c6819SStefan Hajnoczi qemu_coroutine_yield();
233effd60c8SStefan Hajnoczi }
2349ce44e2cSKevin Wolf } else {
2359ce44e2cSKevin Wolf /*
2369ce44e2cSKevin Wolf * Actual context doesn't match the one the command needs.
2379ce44e2cSKevin Wolf *
2389ce44e2cSKevin Wolf * Case 1: we are in coroutine context, but command does not
2399ce44e2cSKevin Wolf * have QCO_COROUTINE. We need to drop out of coroutine
2409ce44e2cSKevin Wolf * context for executing it.
2419ce44e2cSKevin Wolf *
2429ce44e2cSKevin Wolf * Case 2: we are outside coroutine context, but command has
2439ce44e2cSKevin Wolf * QCO_COROUTINE. Can't actually happen, because we get here
2449ce44e2cSKevin Wolf * outside coroutine context only when executing a command
2459ce44e2cSKevin Wolf * out of band, and OOB commands never have QCO_COROUTINE.
2469ce44e2cSKevin Wolf */
2479ce44e2cSKevin Wolf assert(!oob && qemu_in_coroutine() && !(cmd->options & QCO_COROUTINE));
2489ce44e2cSKevin Wolf
2499ce44e2cSKevin Wolf QmpDispatchBH data = {
2509ce44e2cSKevin Wolf .cur_mon = cur_mon,
2519ce44e2cSKevin Wolf .cmd = cmd,
2529ce44e2cSKevin Wolf .args = args,
2539ce44e2cSKevin Wolf .ret = &ret,
2549ce44e2cSKevin Wolf .errp = &err,
2559ce44e2cSKevin Wolf .co = qemu_coroutine_self(),
2569ce44e2cSKevin Wolf };
257effd60c8SStefan Hajnoczi aio_bh_schedule_oneshot(iohandler_get_aio_context(), do_qmp_dispatch_bh,
2589ce44e2cSKevin Wolf &data);
2599ce44e2cSKevin Wolf qemu_coroutine_yield();
2609ce44e2cSKevin Wolf }
261d3226035SMarkus Armbruster qobject_unref(args);
262cf4a0643SMarkus Armbruster if (err) {
263b3fbb328SMarc-André Lureau /* or assert(!ret) after reviewing all handlers: */
264b3fbb328SMarc-André Lureau qobject_unref(ret);
265d3226035SMarkus Armbruster goto out;
266d3226035SMarkus Armbruster }
267d3226035SMarkus Armbruster
268d3226035SMarkus Armbruster if (cmd->options & QCO_NO_SUCCESS_RESP) {
269cf4a0643SMarkus Armbruster g_assert(!ret);
270d3226035SMarkus Armbruster return NULL;
271cf4a0643SMarkus Armbruster } else if (!ret) {
2724a883738SMarkus Armbruster /*
2734a883738SMarkus Armbruster * When the command's schema has no 'returns', cmd->fn()
2744a883738SMarkus Armbruster * leaves @ret null. The QMP spec calls for an empty object
2754a883738SMarkus Armbruster * then; supply it.
2764a883738SMarkus Armbruster */
277cf4a0643SMarkus Armbruster ret = QOBJECT(qdict_new());
278cf4a0643SMarkus Armbruster }
279cf4a0643SMarkus Armbruster
280d3226035SMarkus Armbruster rsp = qdict_new();
281d3226035SMarkus Armbruster qdict_put_obj(rsp, "return", ret);
282cf4a0643SMarkus Armbruster
283cf4a0643SMarkus Armbruster out:
284ab02ab2aSMichael Roth if (err) {
285d3226035SMarkus Armbruster assert(!rsp);
286cee32796SMarkus Armbruster rsp = qmp_error_response(err);
287ab02ab2aSMichael Roth }
288ab02ab2aSMichael Roth
289d3226035SMarkus Armbruster assert(rsp);
290d3226035SMarkus Armbruster
291d3226035SMarkus Armbruster if (id) {
2924eaca8deSMarc-André Lureau qdict_put_obj(rsp, "id", qobject_ref(id));
2934eaca8deSMarc-André Lureau }
2944eaca8deSMarc-André Lureau
295d43b1694SMarkus Armbruster return rsp;
296ab02ab2aSMichael Roth }
297