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