qemu/qapi/qmp-dispatch.c
<<
>>
Prefs
   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#include "qapi/error.h"
  16#include "qapi/qmp/types.h"
  17#include "qapi/qmp/dispatch.h"
  18#include "qapi/qmp/json-parser.h"
  19#include "qapi/qmp/qjson.h"
  20#include "qapi-types.h"
  21#include "qapi/qmp/qerror.h"
  22
  23static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
  24{
  25    const QDictEntry *ent;
  26    const char *arg_name;
  27    const QObject *arg_obj;
  28    bool has_exec_key = false;
  29    QDict *dict = NULL;
  30
  31    dict = qobject_to_qdict(request);
  32    if (!dict) {
  33        error_setg(errp, "QMP input must be a JSON object");
  34        return NULL;
  35    }
  36
  37    for (ent = qdict_first(dict); ent;
  38         ent = qdict_next(dict, ent)) {
  39        arg_name = qdict_entry_key(ent);
  40        arg_obj = qdict_entry_value(ent);
  41
  42        if (!strcmp(arg_name, "execute")) {
  43            if (qobject_type(arg_obj) != QTYPE_QSTRING) {
  44                error_setg(errp,
  45                           "QMP input member 'execute' must be a string");
  46                return NULL;
  47            }
  48            has_exec_key = true;
  49        } else if (!strcmp(arg_name, "arguments")) {
  50            if (qobject_type(arg_obj) != QTYPE_QDICT) {
  51                error_setg(errp,
  52                           "QMP input member 'arguments' must be an object");
  53                return NULL;
  54            }
  55        } else {
  56            error_setg(errp, "QMP input member '%s' is unexpected",
  57                       arg_name);
  58            return NULL;
  59        }
  60    }
  61
  62    if (!has_exec_key) {
  63        error_setg(errp, "QMP input lacks member 'execute'");
  64        return NULL;
  65    }
  66
  67    return dict;
  68}
  69
  70static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
  71                                Error **errp)
  72{
  73    Error *local_err = NULL;
  74    const char *command;
  75    QDict *args, *dict;
  76    QmpCommand *cmd;
  77    QObject *ret = NULL;
  78
  79    dict = qmp_dispatch_check_obj(request, errp);
  80    if (!dict) {
  81        return NULL;
  82    }
  83
  84    command = qdict_get_str(dict, "execute");
  85    cmd = qmp_find_command(cmds, command);
  86    if (cmd == NULL) {
  87        error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
  88                  "The command %s has not been found", command);
  89        return NULL;
  90    }
  91    if (!cmd->enabled) {
  92        error_setg(errp, "The command %s has been disabled for this instance",
  93                   command);
  94        return NULL;
  95    }
  96
  97    if (!qdict_haskey(dict, "arguments")) {
  98        args = qdict_new();
  99    } else {
 100        args = qdict_get_qdict(dict, "arguments");
 101        QINCREF(args);
 102    }
 103
 104    cmd->fn(args, &ret, &local_err);
 105    if (local_err) {
 106        error_propagate(errp, local_err);
 107    } else if (cmd->options & QCO_NO_SUCCESS_RESP) {
 108        g_assert(!ret);
 109    } else if (!ret) {
 110        ret = QOBJECT(qdict_new());
 111    }
 112
 113    QDECREF(args);
 114
 115    return ret;
 116}
 117
 118QObject *qmp_build_error_object(Error *err)
 119{
 120    return qobject_from_jsonf("{ 'class': %s, 'desc': %s }",
 121                              QapiErrorClass_lookup[error_get_class(err)],
 122                              error_get_pretty(err));
 123}
 124
 125QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request)
 126{
 127    Error *err = NULL;
 128    QObject *ret;
 129    QDict *rsp;
 130
 131    ret = do_qmp_dispatch(cmds, request, &err);
 132
 133    rsp = qdict_new();
 134    if (err) {
 135        qdict_put_obj(rsp, "error", qmp_build_error_object(err));
 136        error_free(err);
 137    } else if (ret) {
 138        qdict_put_obj(rsp, "return", ret);
 139    } else {
 140        QDECREF(rsp);
 141        return NULL;
 142    }
 143
 144    return QOBJECT(rsp);
 145}
 146