qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

qmp-dispatch.c (7620B)


      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 *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 }