xref: /openbmc/qemu/qapi/qmp-dispatch.c (revision 624fa80c)
1 /*
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 
14 #include "qemu/osdep.h"
15 
16 #include "block/aio.h"
17 #include "qapi/compat-policy.h"
18 #include "qapi/error.h"
19 #include "qapi/qmp/dispatch.h"
20 #include "qapi/qmp/qdict.h"
21 #include "qapi/qmp/qjson.h"
22 #include "qapi/qobject-output-visitor.h"
23 #include "sysemu/runstate.h"
24 #include "qapi/qmp/qbool.h"
25 #include "qemu/coroutine.h"
26 #include "qemu/main-loop.h"
27 
28 CompatPolicy compat_policy;
29 
30 Visitor *qobject_output_visitor_new_qmp(QObject **result)
31 {
32     Visitor *v = qobject_output_visitor_new(result);
33 
34     qobject_output_visitor_set_policy(v, compat_policy.deprecated_output);
35     return v;
36 }
37 
38 static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob,
39                                      Error **errp)
40 {
41     const char *exec_key = NULL;
42     const QDictEntry *ent;
43     const char *arg_name;
44     const QObject *arg_obj;
45 
46     for (ent = qdict_first(dict); ent;
47          ent = qdict_next(dict, ent)) {
48         arg_name = qdict_entry_key(ent);
49         arg_obj = qdict_entry_value(ent);
50 
51         if (!strcmp(arg_name, "execute")
52             || (!strcmp(arg_name, "exec-oob") && allow_oob)) {
53             if (qobject_type(arg_obj) != QTYPE_QSTRING) {
54                 error_setg(errp, "QMP input member '%s' must be a string",
55                            arg_name);
56                 return NULL;
57             }
58             if (exec_key) {
59                 error_setg(errp, "QMP input member '%s' clashes with '%s'",
60                            arg_name, exec_key);
61                 return NULL;
62             }
63             exec_key = arg_name;
64         } else if (!strcmp(arg_name, "arguments")) {
65             if (qobject_type(arg_obj) != QTYPE_QDICT) {
66                 error_setg(errp,
67                            "QMP input member 'arguments' must be an object");
68                 return NULL;
69             }
70         } else if (!strcmp(arg_name, "id")) {
71             continue;
72         } else {
73             error_setg(errp, "QMP input member '%s' is unexpected",
74                        arg_name);
75             return NULL;
76         }
77     }
78 
79     if (!exec_key) {
80         error_setg(errp, "QMP input lacks member 'execute'");
81         return NULL;
82     }
83 
84     return dict;
85 }
86 
87 QDict *qmp_error_response(Error *err)
88 {
89     QDict *rsp;
90 
91     rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }",
92                                   QapiErrorClass_str(error_get_class(err)),
93                                   error_get_pretty(err));
94     error_free(err);
95     return rsp;
96 }
97 
98 /*
99  * Does @qdict look like a command to be run out-of-band?
100  */
101 bool qmp_is_oob(const QDict *dict)
102 {
103     return qdict_haskey(dict, "exec-oob")
104         && !qdict_haskey(dict, "execute");
105 }
106 
107 typedef struct QmpDispatchBH {
108     const QmpCommand *cmd;
109     Monitor *cur_mon;
110     QDict *args;
111     QObject **ret;
112     Error **errp;
113     Coroutine *co;
114 } QmpDispatchBH;
115 
116 static void do_qmp_dispatch_bh(void *opaque)
117 {
118     QmpDispatchBH *data = opaque;
119 
120     assert(monitor_cur() == NULL);
121     monitor_set_cur(qemu_coroutine_self(), data->cur_mon);
122     data->cmd->fn(data->args, data->ret, data->errp);
123     monitor_set_cur(qemu_coroutine_self(), NULL);
124     aio_co_wake(data->co);
125 }
126 
127 /*
128  * Runs outside of coroutine context for OOB commands, but in coroutine
129  * context for everything else.
130  */
131 QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
132                     bool allow_oob, Monitor *cur_mon)
133 {
134     Error *err = NULL;
135     bool oob;
136     const char *command;
137     QDict *args;
138     const QmpCommand *cmd;
139     QDict *dict;
140     QObject *id;
141     QObject *ret = NULL;
142     QDict *rsp = NULL;
143 
144     dict = qobject_to(QDict, request);
145     if (!dict) {
146         id = NULL;
147         error_setg(&err, "QMP input must be a JSON object");
148         goto out;
149     }
150 
151     id = qdict_get(dict, "id");
152 
153     if (!qmp_dispatch_check_obj(dict, allow_oob, &err)) {
154         goto out;
155     }
156 
157     command = qdict_get_try_str(dict, "execute");
158     oob = false;
159     if (!command) {
160         assert(allow_oob);
161         command = qdict_get_str(dict, "exec-oob");
162         oob = true;
163     }
164     cmd = qmp_find_command(cmds, command);
165     if (cmd == NULL) {
166         error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
167                   "The command %s has not been found", command);
168         goto out;
169     }
170     if (!cmd->enabled) {
171         error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND,
172                   "Command %s has been disabled%s%s",
173                   command,
174                   cmd->disable_reason ? ": " : "",
175                   cmd->disable_reason ?: "");
176         goto out;
177     }
178     if (oob && !(cmd->options & QCO_ALLOW_OOB)) {
179         error_setg(&err, "The command %s does not support OOB",
180                    command);
181         goto out;
182     }
183 
184     if (!qmp_command_available(cmd, &err)) {
185         goto out;
186     }
187 
188     if (!qdict_haskey(dict, "arguments")) {
189         args = qdict_new();
190     } else {
191         args = qdict_get_qdict(dict, "arguments");
192         qobject_ref(args);
193     }
194 
195     assert(!(oob && qemu_in_coroutine()));
196     assert(monitor_cur() == NULL);
197     if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) {
198         monitor_set_cur(qemu_coroutine_self(), cur_mon);
199         cmd->fn(args, &ret, &err);
200         monitor_set_cur(qemu_coroutine_self(), NULL);
201     } else {
202        /*
203         * Actual context doesn't match the one the command needs.
204         *
205         * Case 1: we are in coroutine context, but command does not
206         * have QCO_COROUTINE.  We need to drop out of coroutine
207         * context for executing it.
208         *
209         * Case 2: we are outside coroutine context, but command has
210         * QCO_COROUTINE.  Can't actually happen, because we get here
211         * outside coroutine context only when executing a command
212         * out of band, and OOB commands never have QCO_COROUTINE.
213         */
214         assert(!oob && qemu_in_coroutine() && !(cmd->options & QCO_COROUTINE));
215 
216         QmpDispatchBH data = {
217             .cur_mon    = cur_mon,
218             .cmd        = cmd,
219             .args       = args,
220             .ret        = &ret,
221             .errp       = &err,
222             .co         = qemu_coroutine_self(),
223         };
224         aio_bh_schedule_oneshot(qemu_get_aio_context(), do_qmp_dispatch_bh,
225                                 &data);
226         qemu_coroutine_yield();
227     }
228     qobject_unref(args);
229     if (err) {
230         /* or assert(!ret) after reviewing all handlers: */
231         qobject_unref(ret);
232         goto out;
233     }
234 
235     if (cmd->options & QCO_NO_SUCCESS_RESP) {
236         g_assert(!ret);
237         return NULL;
238     } else if (!ret) {
239         /*
240          * When the command's schema has no 'returns', cmd->fn()
241          * leaves @ret null.  The QMP spec calls for an empty object
242          * then; supply it.
243          */
244         ret = QOBJECT(qdict_new());
245     }
246 
247     rsp = qdict_new();
248     qdict_put_obj(rsp, "return", ret);
249 
250 out:
251     if (err) {
252         assert(!rsp);
253         rsp = qmp_error_response(err);
254     }
255 
256     assert(rsp);
257 
258     if (id) {
259         qdict_put_obj(rsp, "id", qobject_ref(id));
260     }
261 
262     return rsp;
263 }
264