diff options
Diffstat (limited to 'qapi/qmp-dispatch.c')
| -rw-r--r-- | qapi/qmp-dispatch.c | 134 |
1 files changed, 66 insertions, 68 deletions
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index bc264b3c9b..c30c7ff9e1 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -19,20 +19,13 @@ #include "sysemu/runstate.h" #include "qapi/qmp/qbool.h" -static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, +static QDict *qmp_dispatch_check_obj(QDict *dict, bool allow_oob, Error **errp) { const char *exec_key = NULL; const QDictEntry *ent; const char *arg_name; const QObject *arg_obj; - QDict *dict; - - dict = qobject_to(QDict, request); - if (!dict) { - error_setg(errp, "QMP input must be a JSON object"); - return NULL; - } for (ent = qdict_first(dict); ent; ent = qdict_next(dict, ent)) { @@ -75,19 +68,50 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, return dict; } -static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, - bool allow_oob, Error **errp) +QDict *qmp_error_response(Error *err) +{ + QDict *rsp; + + rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }", + QapiErrorClass_str(error_get_class(err)), + error_get_pretty(err)); + error_free(err); + return rsp; +} + +/* + * Does @qdict look like a command to be run out-of-band? + */ +bool qmp_is_oob(const QDict *dict) +{ + return qdict_haskey(dict, "exec-oob") + && !qdict_haskey(dict, "execute"); +} + +QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request, + bool allow_oob) { - Error *local_err = NULL; + Error *err = NULL; bool oob; const char *command; - QDict *args, *dict; - QmpCommand *cmd; + QDict *args; + const QmpCommand *cmd; + QDict *dict; + QObject *id; QObject *ret = NULL; + QDict *rsp = NULL; - dict = qmp_dispatch_check_obj(request, allow_oob, errp); + dict = qobject_to(QDict, request); if (!dict) { - return NULL; + id = NULL; + error_setg(&err, "QMP input must be a JSON object"); + goto out; + } + + id = qdict_get(dict, "id"); + + if (!qmp_dispatch_check_obj(dict, allow_oob, &err)) { + goto out; } command = qdict_get_try_str(dict, "execute"); @@ -99,27 +123,27 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, } cmd = qmp_find_command(cmds, command); if (cmd == NULL) { - error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, + error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND, "The command %s has not been found", command); - return NULL; + goto out; } if (!cmd->enabled) { - error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, + error_set(&err, ERROR_CLASS_COMMAND_NOT_FOUND, "The command %s has been disabled for this instance", command); - return NULL; + goto out; } if (oob && !(cmd->options & QCO_ALLOW_OOB)) { - error_setg(errp, "The command %s does not support OOB", + error_setg(&err, "The command %s does not support OOB", command); - return NULL; + goto out; } if (runstate_check(RUN_STATE_PRECONFIG) && !(cmd->options & QCO_ALLOW_PRECONFIG)) { - error_setg(errp, "The command '%s' isn't permitted in '%s' state", + error_setg(&err, "The command '%s' isn't permitted in '%s' state", cmd->name, RunState_str(RUN_STATE_PRECONFIG)); - return NULL; + goto out; } if (!qdict_haskey(dict, "arguments")) { @@ -128,62 +152,36 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, args = qdict_get_qdict(dict, "arguments"); qobject_ref(args); } + cmd->fn(args, &ret, &err); + qobject_unref(args); + if (err) { + goto out; + } - cmd->fn(args, &ret, &local_err); - if (local_err) { - error_propagate(errp, local_err); - } else if (cmd->options & QCO_NO_SUCCESS_RESP) { + if (cmd->options & QCO_NO_SUCCESS_RESP) { g_assert(!ret); + return NULL; } else if (!ret) { - /* TODO turn into assertion */ + /* + * When the command's schema has no 'returns', cmd->fn() + * leaves @ret null. The QMP spec calls for an empty object + * then; supply it. + */ ret = QOBJECT(qdict_new()); } - qobject_unref(args); - - return ret; -} - -QDict *qmp_error_response(Error *err) -{ - QDict *rsp; - - rsp = qdict_from_jsonf_nofail("{ 'error': { 'class': %s, 'desc': %s } }", - QapiErrorClass_str(error_get_class(err)), - error_get_pretty(err)); - error_free(err); - return rsp; -} - -/* - * Does @qdict look like a command to be run out-of-band? - */ -bool qmp_is_oob(const QDict *dict) -{ - return qdict_haskey(dict, "exec-oob") - && !qdict_haskey(dict, "execute"); -} - -QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request, - bool allow_oob) -{ - Error *err = NULL; - QDict *dict = qobject_to(QDict, request); - QObject *ret, *id = dict ? qdict_get(dict, "id") : NULL; - QDict *rsp; + rsp = qdict_new(); + qdict_put_obj(rsp, "return", ret); - ret = do_qmp_dispatch(cmds, request, allow_oob, &err); +out: if (err) { + assert(!rsp); rsp = qmp_error_response(err); - } else if (ret) { - rsp = qdict_new(); - qdict_put_obj(rsp, "return", ret); - } else { - /* Can only happen for commands with QCO_NO_SUCCESS_RESP */ - rsp = NULL; } - if (rsp && id) { + assert(rsp); + + if (id) { qdict_put_obj(rsp, "id", qobject_ref(id)); } |