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