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-input-visitor.h" 23 #include "qapi/qobject-output-visitor.h" 24 #include "qapi/qmp/qbool.h" 25 #include "qemu/coroutine.h" 26 #include "qemu/main-loop.h" 27 28 Visitor *qobject_input_visitor_new_qmp(QObject *obj) 29 { 30 Visitor *v = qobject_input_visitor_new(obj); 31 32 visit_set_policy(v, &compat_policy); 33 return v; 34 } 35 36 Visitor *qobject_output_visitor_new_qmp(QObject **result) 37 { 38 Visitor *v = qobject_output_visitor_new(result); 39 40 visit_set_policy(v, &compat_policy); 41 return v; 42 } 43 44 static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob, 45 Error **errp) 46 { 47 const char *exec_key = NULL; 48 const QDictEntry *ent; 49 const char *arg_name; 50 const QObject *arg_obj; 51 52 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 57 if (!strcmp(arg_name, "execute") 58 || (!strcmp(arg_name, "exec-oob") && allow_oob)) { 59 if (qobject_type(arg_obj) != QTYPE_QSTRING) { 60 error_setg(errp, "QMP input member '%s' must be a string", 61 arg_name); 62 return NULL; 63 } 64 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; 70 } else if (!strcmp(arg_name, "arguments")) { 71 if (qobject_type(arg_obj) != QTYPE_QDICT) { 72 error_setg(errp, 73 "QMP input member 'arguments' must be an object"); 74 return NULL; 75 } 76 } else if (!strcmp(arg_name, "id")) { 77 continue; 78 } else { 79 error_setg(errp, "QMP input member '%s' is unexpected", 80 arg_name); 81 return NULL; 82 } 83 } 84 85 if (!exec_key) { 86 error_setg(errp, "QMP input lacks member 'execute'"); 87 return NULL; 88 } 89 90 return dict; 91 } 92 93 QDict *qmp_error_response(Error *err) 94 { 95 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; 102 } 103 104 /* 105 * Does @qdict look like a command to be run out-of-band? 106 */ 107 bool qmp_is_oob(const QDict *dict) 108 { 109 return qdict_haskey(dict, "exec-oob") 110 && !qdict_haskey(dict, "execute"); 111 } 112 113 typedef 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 122 static 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 */ 137 QDict *coroutine_mixed_fn qmp_dispatch(const QmpCommandList *cmds, QObject *request, 138 bool allow_oob, Monitor *cur_mon) 139 { 140 Error *err = NULL; 141 bool oob; 142 const char *command; 143 QDict *args; 144 const QmpCommand *cmd; 145 QDict *dict; 146 QObject *id; 147 QObject *ret = NULL; 148 QDict *rsp = NULL; 149 150 dict = qobject_to(QDict, request); 151 if (!dict) { 152 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)) { 160 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 } 176 if (!compat_policy_input_ok(cmd->special_features, &compat_policy, 177 ERROR_CLASS_COMMAND_NOT_FOUND, 178 "command", command, &err)) { 179 goto out; 180 } 181 if (!cmd->enabled) { 182 error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND, 183 "Command %s has been disabled%s%s", 184 command, 185 cmd->disable_reason ? ": " : "", 186 cmd->disable_reason ?: ""); 187 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 195 if (!qmp_command_available(cmd, &err)) { 196 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 } 205 206 assert(!(oob && qemu_in_coroutine())); 207 assert(monitor_cur() == NULL); 208 if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) { 209 monitor_set_cur(qemu_coroutine_self(), cur_mon); 210 cmd->fn(args, &ret, &err); 211 monitor_set_cur(qemu_coroutine_self(), NULL); 212 } else { 213 /* 214 * Actual context doesn't match the one the command needs. 215 * 216 * Case 1: we are in coroutine context, but command does not 217 * have QCO_COROUTINE. We need to drop out of coroutine 218 * context for executing it. 219 * 220 * Case 2: we are outside coroutine context, but command has 221 * QCO_COROUTINE. Can't actually happen, because we get here 222 * outside coroutine context only when executing a command 223 * out of band, and OOB commands never have QCO_COROUTINE. 224 */ 225 assert(!oob && qemu_in_coroutine() && !(cmd->options & QCO_COROUTINE)); 226 227 QmpDispatchBH data = { 228 .cur_mon = cur_mon, 229 .cmd = cmd, 230 .args = args, 231 .ret = &ret, 232 .errp = &err, 233 .co = qemu_coroutine_self(), 234 }; 235 aio_bh_schedule_oneshot(qemu_get_aio_context(), do_qmp_dispatch_bh, 236 &data); 237 qemu_coroutine_yield(); 238 } 239 qobject_unref(args); 240 if (err) { 241 /* or assert(!ret) after reviewing all handlers: */ 242 qobject_unref(ret); 243 goto out; 244 } 245 246 if (cmd->options & QCO_NO_SUCCESS_RESP) { 247 g_assert(!ret); 248 return NULL; 249 } else if (!ret) { 250 /* 251 * When the command's schema has no 'returns', cmd->fn() 252 * leaves @ret null. The QMP spec calls for an empty object 253 * then; supply it. 254 */ 255 ret = QOBJECT(qdict_new()); 256 } 257 258 rsp = qdict_new(); 259 qdict_put_obj(rsp, "return", ret); 260 261 out: 262 if (err) { 263 assert(!rsp); 264 rsp = qmp_error_response(err); 265 } 266 267 assert(rsp); 268 269 if (id) { 270 qdict_put_obj(rsp, "id", qobject_ref(id)); 271 } 272 273 return rsp; 274 } 275