qemu_qapi.c 5.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/*
 * qemu_qapi.c: helper functions for QEMU QAPI schema handling
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include <config.h>

#include "qemu_qapi.h"

#include "viralloc.h"
#include "virstring.h"
#include "virerror.h"
#include "virlog.h"

#define VIR_FROM_THIS VIR_FROM_QEMU

VIR_LOG_INIT("qemu.qemu_qapi");


/**
34
 * virQEMUQAPISchemaObjectGetType:
35 36 37 38 39 40 41 42
 * @field: name of the object containing the requested type
 * @name: name of the requested type
 * @namefield: name of the object property holding @name
 *
 * Helper that selects the type of a QMP schema object member or it's variant
 * member. Returns the type string on success or NULL on error.
 */
static const char *
43 44 45 46
virQEMUQAPISchemaObjectGetType(const char *field,
                               const char *name,
                               const char *namefield,
                               virJSONValuePtr elem)
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
{
    virJSONValuePtr arr;
    virJSONValuePtr cur;
    const char *curname;
    const char *type;
    size_t i;

    if (!(arr = virJSONValueObjectGetArray(elem, field)))
        return NULL;

    for (i = 0; i < virJSONValueArraySize(arr); i++) {
        if (!(cur = virJSONValueArrayGet(arr, i)) ||
            !(curname = virJSONValueObjectGetString(cur, namefield)) ||
            !(type = virJSONValueObjectGetString(cur, "type")))
            continue;

        if (STREQ(name, curname))
            return type;
    }

    return NULL;
}


static virJSONValuePtr
72 73 74
virQEMUQAPISchemaTraverse(const char *baseName,
                          char **query,
                          virHashTablePtr schema)
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
{
    virJSONValuePtr base;
    const char *metatype;

    do {
        if (!(base = virHashLookup(schema, baseName)))
            return NULL;

        if (!*query)
            return base;

        if (!(metatype = virJSONValueObjectGetString(base, "meta-type")))
            return NULL;

        /* flatten arrays by default */
        if (STREQ(metatype, "array")) {
            if (!(baseName = virJSONValueObjectGetString(base, "element-type")))
                return NULL;

            continue;
        } else if (STREQ(metatype, "object")) {
            if (**query == '+')
97 98 99
                baseName = virQEMUQAPISchemaObjectGetType("variants",
                                                          *query + 1,
                                                          "case", base);
100
            else
101 102 103
                baseName = virQEMUQAPISchemaObjectGetType("members",
                                                          *query,
                                                          "name", base);
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123

            if (!baseName)
                return NULL;
        } else if (STREQ(metatype, "command") ||
                   STREQ(metatype, "event")) {
            if (!(baseName = virJSONValueObjectGetString(base, *query)))
                return NULL;
        } else {
            /* alternates, basic types and enums can't be entered */
            return NULL;
        }

        query++;
    } while (*query);

    return base;
}


/**
124
 * virQEMUQAPISchemaPathGet:
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
 * @query: string specifying the required data type (see below)
 * @schema: hash table containing the schema data
 * @entry: filled with the located schema object requested by @query
 *
 * Retrieves the requested schema entry specified by @query to @entry. The
 * @query parameter has the following syntax which is very closely tied to the
 * qemu schema syntax entries separated by slashes with a few special characters:
 *
 * "command_or_event/attribute/subattribute/+variant_discriminator/subattribute"
 *
 * command_or_event: name of the event or attribute to introspect
 * attribute: selects whether arguments or return type should be introspected
 *            ("arg-type" or "ret-type" for commands, "arg-type" for events)
 * subattribute: specifies member name of object types
 * +variant_discriminator: In the case of unionized objects, select a
 *                         specific case to introspect.
 *
 * Array types are automatically flattened to the singular type. Alternate
 * types are currently not supported.
 *
 * The above types can be chained arbitrarily using slashes to construct any
 * path into the schema tree.
 *
 * Returns 0 on success (including if the requested schema was not found) and
 * fills @entry appropriately. On failure returns -1 and sets an appropriate
 * error message.
 */
int
153 154 155
virQEMUQAPISchemaPathGet(const char *query,
                         virHashTablePtr schema,
                         virJSONValuePtr *entry)
156 157 158 159 160 161 162 163 164 165 166 167 168 169
{
    char **elems = NULL;

    *entry = NULL;

    if (!(elems = virStringSplit(query, "/", 0)))
        return -1;

    if (!*elems) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed query string"));
        virStringListFree(elems);
        return -1;
    }

170
    *entry = virQEMUQAPISchemaTraverse(*elems, elems + 1, schema);
171 172 173 174 175 176 177

    virStringListFree(elems);
    return 0;
}


bool
178 179
virQEMUQAPISchemaPathExists(const char *query,
                            virHashTablePtr schema)
180 181 182
{
    virJSONValuePtr entry;

183
    if (virQEMUQAPISchemaPathGet(query, schema, &entry))
184 185 186 187
        return false;

    return !!entry;
}