xref: /openbmc/qemu/qapi/qmp-dispatch.c (revision 1da79ecc)
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 (!qmp_command_available(cmd, &err)) {
171         goto out;
172     }
173 
174     if (!qdict_haskey(dict, "arguments")) {
175         args = qdict_new();
176     } else {
177         args = qdict_get_qdict(dict, "arguments");
178         qobject_ref(args);
179     }
180 
181     assert(!(oob && qemu_in_coroutine()));
182     assert(monitor_cur() == NULL);
183     if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) {
184         monitor_set_cur(qemu_coroutine_self(), cur_mon);
185         cmd->fn(args, &ret, &err);
186         monitor_set_cur(qemu_coroutine_self(), NULL);
187     } else {
188        /*
189         * Actual context doesn't match the one the command needs.
190         *
191         * Case 1: we are in coroutine context, but command does not
192         * have QCO_COROUTINE.  We need to drop out of coroutine
193         * context for executing it.
194         *
195         * Case 2: we are outside coroutine context, but command has
196         * QCO_COROUTINE.  Can't actually happen, because we get here
197         * outside coroutine context only when executing a command
198         * out of band, and OOB commands never have QCO_COROUTINE.
199         */
200         assert(!oob && qemu_in_coroutine() && !(cmd->options & QCO_COROUTINE));
201 
202         QmpDispatchBH data = {
203             .cur_mon    = cur_mon,
204             .cmd        = cmd,
205             .args       = args,
206             .ret        = &ret,
207             .errp       = &err,
208             .co         = qemu_coroutine_self(),
209         };
210         aio_bh_schedule_oneshot(qemu_get_aio_context(), do_qmp_dispatch_bh,
211                                 &data);
212         qemu_coroutine_yield();
213     }
214     qobject_unref(args);
215     if (err) {
216         /* or assert(!ret) after reviewing all handlers: */
217         qobject_unref(ret);
218         goto out;
219     }
220 
221     if (cmd->options & QCO_NO_SUCCESS_RESP) {
222         g_assert(!ret);
223         return NULL;
224     } else if (!ret) {
225         /*
226          * When the command's schema has no 'returns', cmd->fn()
227          * leaves @ret null.  The QMP spec calls for an empty object
228          * then; supply it.
229          */
230         ret = QOBJECT(qdict_new());
231     }
232 
233     rsp = qdict_new();
234     qdict_put_obj(rsp, "return", ret);
235 
236 out:
237     if (err) {
238         assert(!rsp);
239         rsp = qmp_error_response(err);
240     }
241 
242     assert(rsp);
243 
244     if (id) {
245         qdict_put_obj(rsp, "id", qobject_ref(id));
246     }
247 
248     return rsp;
249 }
250