diff options
Diffstat (limited to 'qapi')
| -rw-r--r-- | qapi/block-core.json | 96 | ||||
| -rw-r--r-- | qapi/event.json | 4 | ||||
| -rw-r--r-- | qapi/opts-visitor.c | 23 | ||||
| -rw-r--r-- | qapi/qapi-visit-core.c | 8 | ||||
| -rw-r--r-- | qapi/qmp-dispatch.c | 34 | ||||
| -rw-r--r-- | qapi/qmp-registry.c | 37 | ||||
| -rw-r--r-- | qapi/qobject-input-visitor.c | 209 | ||||
| -rw-r--r-- | qapi/string-input-visitor.c | 97 | ||||
| -rw-r--r-- | qapi/trace-events | 1 |
9 files changed, 331 insertions, 178 deletions
diff --git a/qapi/block-core.json b/qapi/block-core.json index 5f82d35fab..bc0ccd615c 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1304,6 +1304,11 @@ # # @speed: #optional the maximum speed, in bytes per second # +# @filter-node-name: #optional the node name that should be assigned to the +# filter driver that the commit job inserts into the graph +# above @top. If this option is not given, a node name is +# autogenerated. (Since: 2.9) +# # Returns: Nothing on success # If commit or stream is already active on this device, DeviceInUse # If @device does not exist, DeviceNotFound @@ -1323,7 +1328,8 @@ ## { 'command': 'block-commit', 'data': { '*job-id': 'str', 'device': 'str', '*base': 'str', '*top': 'str', - '*backing-file': 'str', '*speed': 'int' } } + '*backing-file': 'str', '*speed': 'int', + '*filter-node-name': 'str' } } ## # @drive-backup: @@ -1671,6 +1677,11 @@ # default 'report' (no limitations, since this applies to # a different block device than @device). # +# @filter-node-name: #optional the node name that should be assigned to the +# filter driver that the mirror job inserts into the graph +# above @device. If this option is not given, a node name is +# autogenerated. (Since: 2.9) +# # Returns: nothing on success. # # Since: 2.6 @@ -1690,7 +1701,8 @@ 'sync': 'MirrorSyncMode', '*speed': 'int', '*granularity': 'uint32', '*buf-size': 'int', '*on-source-error': 'BlockdevOnError', - '*on-target-error': 'BlockdevOnError' } } + '*on-target-error': 'BlockdevOnError', + '*filter-node-name': 'str' } } ## # @block_set_io_throttle: @@ -2111,6 +2123,7 @@ # @replication: Since 2.8 # @ssh: Since 2.8 # @iscsi: Since 2.9 +# @rbd: Since 2.9 # # Since: 2.0 ## @@ -2119,7 +2132,7 @@ 'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed', - 'quorum', 'raw', 'replication', 'ssh', 'vdi', 'vhdx', 'vmdk', + 'quorum', 'raw', 'rbd', 'replication', 'ssh', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] } ## @@ -2625,29 +2638,29 @@ ## # @BlockdevOptionsIscsi: # -# @transport The iscsi transport type +# @transport: The iscsi transport type # -# @portal The address of the iscsi portal +# @portal: The address of the iscsi portal # -# @target The target iqn name +# @target: The target iqn name # -# @lun #optional LUN to connect to. Defaults to 0. +# @lun: #optional LUN to connect to. Defaults to 0. # -# @user #optional User name to log in with. If omitted, no CHAP +# @user: #optional User name to log in with. If omitted, no CHAP # authentication is performed. # -# @password-secret #optional The ID of a QCryptoSecret object providing +# @password-secret: #optional The ID of a QCryptoSecret object providing # the password for the login. This option is required if # @user is specified. # -# @initiator-name #optional The iqn name we want to identify to the target +# @initiator-name: #optional The iqn name we want to identify to the target # as. If this option is not specified, an initiator name is # generated automatically. # -# @header-digest #optional The desired header digest. Defaults to +# @header-digest: #optional The desired header digest. Defaults to # none-crc32c. # -# @timeout #optional Timeout in seconds after which a request will +# @timeout: #optional Timeout in seconds after which a request will # timeout. 0 means no timeout and is the default. # # Driver specific block device options for iscsi @@ -2665,6 +2678,63 @@ '*header-digest': 'IscsiHeaderDigest', '*timeout': 'int' } } + +## +# @RbdAuthSupport: +# +# An enumeration of RBD auth support +# +# Since: 2.9 +## +{ 'enum': 'RbdAuthSupport', + 'data': [ 'cephx', 'none' ] } + + +## +# @RbdAuthMethod: +# +# An enumeration of rados auth_supported types +# +# Since: 2.9 +## +{ 'struct': 'RbdAuthMethod', + 'data': { 'auth': 'RbdAuthSupport' } } + +## +# @BlockdevOptionsRbd: +# +# @pool: Ceph pool name. +# +# @image: Image name in the Ceph pool. +# +# @conf: #optional path to Ceph configuration file. Values +# in the configuration file will be overridden by +# options specified via QAPI. +# +# @snapshot: #optional Ceph snapshot name. +# +# @user: #optional Ceph id name. +# +# @server: #optional Monitor host address and port. This maps +# to the "mon_host" Ceph option. +# +# @auth-supported: #optional Authentication supported. +# +# @password-secret: #optional The ID of a QCryptoSecret object providing +# the password for the login. +# +# Since: 2.9 +## +{ 'struct': 'BlockdevOptionsRbd', + 'data': { 'pool': 'str', + 'image': 'str', + '*conf': 'str', + '*snapshot': 'str', + '*user': 'str', + '*server': ['InetSocketAddress'], + '*auth-supported': ['RbdAuthMethod'], + '*password-secret': 'str' } } + ## # @ReplicationMode: # @@ -2863,7 +2933,7 @@ 'qed': 'BlockdevOptionsGenericCOWFormat', 'quorum': 'BlockdevOptionsQuorum', 'raw': 'BlockdevOptionsRaw', -# TODO rbd: Wait for structured options + 'rbd': 'BlockdevOptionsRbd', 'replication':'BlockdevOptionsReplication', # TODO sheepdog: Wait for structured options 'ssh': 'BlockdevOptionsSsh', diff --git a/qapi/event.json b/qapi/event.json index 970ff0255a..e02852cd8a 100644 --- a/qapi/event.json +++ b/qapi/event.json @@ -488,9 +488,9 @@ # # @action: action that has been taken, currently always "pause" # -# @info: optional information about a panic +# @info: #optional information about a panic (since 2.9) # -# Since: 1.5 (@info since 2.9) +# Since: 1.5 # # Example: # diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 1048bbc84e..026d25b767 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -273,6 +273,16 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) static void +opts_check_list(Visitor *v, Error **errp) +{ + /* + * FIXME should set error when unvisited elements remain. Mostly + * harmless, as the generated visits always visit all elements. + */ +} + + +static void opts_end_list(Visitor *v, void **obj) { OptsVisitor *ov = to_ov(v); @@ -481,23 +491,20 @@ opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { OptsVisitor *ov = to_ov(v); const QemuOpt *opt; - int64_t val; - char *endptr; + int err; opt = lookup_scalar(ov, name, errp); if (!opt) { return; } - val = qemu_strtosz_suffix(opt->str ? opt->str : "", &endptr, - QEMU_STRTOSZ_DEFSUFFIX_B); - if (val < 0 || *endptr) { + err = qemu_strtosz(opt->str ? opt->str : "", NULL, obj); + if (err < 0) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, - "a size value representible as a non-negative int64"); + "a size value"); return; } - *obj = val; processed(ov, name); } @@ -531,6 +538,7 @@ opts_visitor_new(const QemuOpts *opts) { OptsVisitor *ov; + assert(opts); ov = g_malloc0(sizeof *ov); ov->visitor.type = VISITOR_INPUT; @@ -541,6 +549,7 @@ opts_visitor_new(const QemuOpts *opts) ov->visitor.start_list = &opts_start_list; ov->visitor.next_list = &opts_next_list; + ov->visitor.check_list = &opts_check_list; ov->visitor.end_list = &opts_end_list; ov->visitor.type_int64 = &opts_type_int64; diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index e6e93f02e6..43a09d147d 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -90,6 +90,14 @@ GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) return v->next_list(v, tail, size); } +void visit_check_list(Visitor *v, Error **errp) +{ + trace_visit_check_list(v); + if (v->check_list) { + v->check_list(v, errp); + } +} + void visit_end_list(Visitor *v, void **obj) { trace_visit_end_list(v, obj); diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 505eb418ac..dc502129d8 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -28,14 +28,12 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp) bool has_exec_key = false; QDict *dict = NULL; - if (qobject_type(request) != QTYPE_QDICT) { - error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT, - "request is not a dictionary"); + dict = qobject_to_qdict(request); + if (!dict) { + error_setg(errp, "Expected '%s' in QMP input", "object"); return NULL; } - dict = qobject_to_qdict(request); - for (ent = qdict_first(dict); ent; ent = qdict_next(dict, ent)) { arg_name = qdict_entry_key(ent); @@ -43,26 +41,34 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp) if (!strcmp(arg_name, "execute")) { if (qobject_type(arg_obj) != QTYPE_QSTRING) { - error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT_MEMBER, "execute", - "string"); + error_setg(errp, "QMP input object member '%s' expects '%s'", + "execute", "string"); return NULL; } has_exec_key = true; - } else if (strcmp(arg_name, "arguments")) { - error_setg(errp, QERR_QMP_EXTRA_MEMBER, arg_name); + } else if (!strcmp(arg_name, "arguments")) { + if (qobject_type(arg_obj) != QTYPE_QDICT) { + error_setg(errp, "QMP input object member '%s' expects '%s'", + "arguments", "object"); + return NULL; + } + } else { + error_setg(errp, "QMP input object member '%s' is unexpected", + arg_name); return NULL; } } if (!has_exec_key) { - error_setg(errp, QERR_QMP_BAD_INPUT_OBJECT, "execute"); + error_setg(errp, "Expected '%s' in QMP input", "execute"); return NULL; } return dict; } -static QObject *do_qmp_dispatch(QObject *request, Error **errp) +static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request, + Error **errp) { Error *local_err = NULL; const char *command; @@ -76,7 +82,7 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp) } command = qdict_get_str(dict, "execute"); - cmd = qmp_find_command(command); + cmd = qmp_find_command(cmds, command); if (cmd == NULL) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, "The command %s has not been found", command); @@ -116,13 +122,13 @@ QObject *qmp_build_error_object(Error *err) error_get_pretty(err)); } -QObject *qmp_dispatch(QObject *request) +QObject *qmp_dispatch(QmpCommandList *cmds, QObject *request) { Error *err = NULL; QObject *ret; QDict *rsp; - ret = do_qmp_dispatch(request, &err); + ret = do_qmp_dispatch(cmds, request, &err); rsp = qdict_new(); if (err) { diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index e8053686f3..5af484cd9a 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -15,11 +15,8 @@ #include "qemu/osdep.h" #include "qapi/qmp/dispatch.h" -static QTAILQ_HEAD(QmpCommandList, QmpCommand) qmp_commands = - QTAILQ_HEAD_INITIALIZER(qmp_commands); - -void qmp_register_command(const char *name, QmpCommandFunc *fn, - QmpCommandOptions options) +void qmp_register_command(QmpCommandList *cmds, const char *name, + QmpCommandFunc *fn, QmpCommandOptions options) { QmpCommand *cmd = g_malloc0(sizeof(*cmd)); @@ -27,22 +24,22 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn, cmd->fn = fn; cmd->enabled = true; cmd->options = options; - QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node); + QTAILQ_INSERT_TAIL(cmds, cmd, node); } -void qmp_unregister_command(const char *name) +void qmp_unregister_command(QmpCommandList *cmds, const char *name) { - QmpCommand *cmd = qmp_find_command(name); + QmpCommand *cmd = qmp_find_command(cmds, name); - QTAILQ_REMOVE(&qmp_commands, cmd, node); + QTAILQ_REMOVE(cmds, cmd, node); g_free(cmd); } -QmpCommand *qmp_find_command(const char *name) +QmpCommand *qmp_find_command(QmpCommandList *cmds, const char *name) { QmpCommand *cmd; - QTAILQ_FOREACH(cmd, &qmp_commands, node) { + QTAILQ_FOREACH(cmd, cmds, node) { if (strcmp(cmd->name, name) == 0) { return cmd; } @@ -50,11 +47,12 @@ QmpCommand *qmp_find_command(const char *name) return NULL; } -static void qmp_toggle_command(const char *name, bool enabled) +static void qmp_toggle_command(QmpCommandList *cmds, const char *name, + bool enabled) { QmpCommand *cmd; - QTAILQ_FOREACH(cmd, &qmp_commands, node) { + QTAILQ_FOREACH(cmd, cmds, node) { if (strcmp(cmd->name, name) == 0) { cmd->enabled = enabled; return; @@ -62,14 +60,14 @@ static void qmp_toggle_command(const char *name, bool enabled) } } -void qmp_disable_command(const char *name) +void qmp_disable_command(QmpCommandList *cmds, const char *name) { - qmp_toggle_command(name, false); + qmp_toggle_command(cmds, name, false); } -void qmp_enable_command(const char *name) +void qmp_enable_command(QmpCommandList *cmds, const char *name) { - qmp_toggle_command(name, true); + qmp_toggle_command(cmds, name, true); } bool qmp_command_is_enabled(const QmpCommand *cmd) @@ -87,11 +85,12 @@ bool qmp_has_success_response(const QmpCommand *cmd) return !(cmd->options & QCO_NO_SUCCESS_RESP); } -void qmp_for_each_command(qmp_cmd_callback_fn fn, void *opaque) +void qmp_for_each_command(QmpCommandList *cmds, qmp_cmd_callback_fn fn, + void *opaque) { QmpCommand *cmd; - QTAILQ_FOREACH(cmd, &qmp_commands, node) { + QTAILQ_FOREACH(cmd, cmds, node) { fn(cmd, opaque); } } diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c index 0063327b3b..d192727e0b 100644 --- a/qapi/qobject-input-visitor.c +++ b/qapi/qobject-input-visitor.c @@ -21,21 +21,19 @@ #include "qapi/qmp/types.h" #include "qapi/qmp/qerror.h" -#define QIV_STACK_SIZE 1024 - -typedef struct StackObject -{ - QObject *obj; /* Object being visited */ +typedef struct StackObject { + const char *name; /* Name of @obj in its parent, if any */ + QObject *obj; /* QDict or QList being visited */ void *qapi; /* sanity check that caller uses same pointer */ - GHashTable *h; /* If obj is dict: unvisited keys */ - const QListEntry *entry; /* If obj is list: unvisited tail */ + GHashTable *h; /* If @obj is QDict: unvisited keys */ + const QListEntry *entry; /* If @obj is QList: unvisited tail */ + unsigned index; /* If @obj is QList: list index of @entry */ - QSLIST_ENTRY(StackObject) node; + QSLIST_ENTRY(StackObject) node; /* parent */ } StackObject; -struct QObjectInputVisitor -{ +struct QObjectInputVisitor { Visitor visitor; /* Root of visit at visitor creation. */ @@ -45,8 +43,7 @@ struct QObjectInputVisitor * QDict or QList). */ QSLIST_HEAD(, StackObject) stack; - /* True to reject parse in visit_end_struct() if unvisited keys remain. */ - bool strict; + GString *errname; /* Accumulator for full_name() */ }; static QObjectInputVisitor *to_qiv(Visitor *v) @@ -54,9 +51,51 @@ static QObjectInputVisitor *to_qiv(Visitor *v) return container_of(v, QObjectInputVisitor, visitor); } -static QObject *qobject_input_get_object(QObjectInputVisitor *qiv, - const char *name, - bool consume, Error **errp) +static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name, + int n) +{ + StackObject *so; + char buf[32]; + + if (qiv->errname) { + g_string_truncate(qiv->errname, 0); + } else { + qiv->errname = g_string_new(""); + } + + QSLIST_FOREACH(so , &qiv->stack, node) { + if (n) { + n--; + } else if (qobject_type(so->obj) == QTYPE_QDICT) { + g_string_prepend(qiv->errname, name ?: "<anonymous>"); + g_string_prepend_c(qiv->errname, '.'); + } else { + snprintf(buf, sizeof(buf), "[%u]", so->index); + g_string_prepend(qiv->errname, buf); + } + name = so->name; + } + assert(!n); + + if (name) { + g_string_prepend(qiv->errname, name); + } else if (qiv->errname->str[0] == '.') { + g_string_erase(qiv->errname, 0, 1); + } else if (!qiv->errname->str[0]) { + return "<anonymous>"; + } + + return qiv->errname->str; +} + +static const char *full_name(QObjectInputVisitor *qiv, const char *name) +{ + return full_name_nth(qiv, name, 0); +} + +static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv, + const char *name, + bool consume) { StackObject *tos; QObject *qobj; @@ -80,22 +119,37 @@ static QObject *qobject_input_get_object(QObjectInputVisitor *qiv, bool removed = g_hash_table_remove(tos->h, name); assert(removed); } - if (!ret) { - error_setg(errp, QERR_MISSING_PARAMETER, name); - } } else { assert(qobject_type(qobj) == QTYPE_QLIST); assert(!name); - ret = qlist_entry_obj(tos->entry); - assert(ret); + if (tos->entry) { + ret = qlist_entry_obj(tos->entry); + if (consume) { + tos->entry = qlist_next(tos->entry); + } + } else { + ret = NULL; + } if (consume) { - tos->entry = qlist_next(tos->entry); + tos->index++; } } return ret; } +static QObject *qobject_input_get_object(QObjectInputVisitor *qiv, + const char *name, + bool consume, Error **errp) +{ + QObject *obj = qobject_input_try_get_object(qiv, name, consume); + + if (!obj) { + error_setg(errp, QERR_MISSING_PARAMETER, full_name(qiv, name)); + } + return obj; +} + static void qdict_add_key(const char *key, QObject *obj, void *opaque) { GHashTable *h = opaque; @@ -103,22 +157,25 @@ static void qdict_add_key(const char *key, QObject *obj, void *opaque) } static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv, - QObject *obj, void *qapi, - Error **errp) + const char *name, + QObject *obj, void *qapi) { GHashTable *h; StackObject *tos = g_new0(StackObject, 1); assert(obj); + tos->name = name; tos->obj = obj; tos->qapi = qapi; - if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) { + if (qobject_type(obj) == QTYPE_QDICT) { h = g_hash_table_new(g_str_hash, g_str_equal); qdict_iter(qobject_to_qdict(obj), qdict_add_key, h); tos->h = h; - } else if (qobject_type(obj) == QTYPE_QLIST) { + } else { + assert(qobject_type(obj) == QTYPE_QLIST); tos->entry = qlist_first(qobject_to_qlist(obj)); + tos->index = -1; } QSLIST_INSERT_HEAD(&qiv->stack, tos, node); @@ -130,19 +187,15 @@ static void qobject_input_check_struct(Visitor *v, Error **errp) { QObjectInputVisitor *qiv = to_qiv(v); StackObject *tos = QSLIST_FIRST(&qiv->stack); + GHashTableIter iter; + const char *key; assert(tos && !tos->entry); - if (qiv->strict) { - GHashTable *const top_ht = tos->h; - if (top_ht) { - GHashTableIter iter; - const char *key; - - g_hash_table_iter_init(&iter, top_ht); - if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) { - error_setg(errp, QERR_QMP_EXTRA_MEMBER, key); - } - } + + g_hash_table_iter_init(&iter, tos->h); + if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) { + error_setg(errp, "Parameter '%s' is unexpected", + full_name(qiv, key)); } } @@ -170,7 +223,6 @@ static void qobject_input_start_struct(Visitor *v, const char *name, void **obj, { QObjectInputVisitor *qiv = to_qiv(v); QObject *qobj = qobject_input_get_object(qiv, name, true, errp); - Error *err = NULL; if (obj) { *obj = NULL; @@ -179,16 +231,12 @@ static void qobject_input_start_struct(Visitor *v, const char *name, void **obj, return; } if (qobject_type(qobj) != QTYPE_QDICT) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "QDict"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "object"); return; } - qobject_input_push(qiv, qobj, obj, &err); - if (err) { - error_propagate(errp, err); - return; - } + qobject_input_push(qiv, name, qobj, obj); if (obj) { *obj = g_malloc0(size); @@ -204,25 +252,21 @@ static void qobject_input_start_list(Visitor *v, const char *name, QObject *qobj = qobject_input_get_object(qiv, name, true, errp); const QListEntry *entry; + if (list) { + *list = NULL; + } if (!qobj) { return; } if (qobject_type(qobj) != QTYPE_QLIST) { - if (list) { - *list = NULL; - } - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "list"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "array"); return; } - entry = qobject_input_push(qiv, qobj, list, errp); - if (list) { - if (entry) { - *list = g_malloc0(size); - } else { - *list = NULL; - } + entry = qobject_input_push(qiv, name, qobj, list); + if (entry && list) { + *list = g_malloc0(size); } } @@ -230,15 +274,30 @@ static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail, size_t size) { QObjectInputVisitor *qiv = to_qiv(v); - StackObject *so = QSLIST_FIRST(&qiv->stack); + StackObject *tos = QSLIST_FIRST(&qiv->stack); + + assert(tos && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST); - if (!so->entry) { + if (!tos->entry) { return NULL; } tail->next = g_malloc0(size); return tail->next; } +static void qobject_input_check_list(Visitor *v, Error **errp) +{ + QObjectInputVisitor *qiv = to_qiv(v); + StackObject *tos = QSLIST_FIRST(&qiv->stack); + + assert(tos && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST); + + if (tos->entry) { + error_setg(errp, "Only %u list elements expected in %s", + tos->index + 1, full_name_nth(qiv, NULL, 1)); + } +} + static void qobject_input_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, @@ -270,8 +329,8 @@ static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj, } qint = qobject_to_qint(qobj); if (!qint) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "integer"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "integer"); return; } @@ -291,8 +350,8 @@ static void qobject_input_type_uint64(Visitor *v, const char *name, } qint = qobject_to_qint(qobj); if (!qint) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "integer"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "integer"); return; } @@ -311,8 +370,8 @@ static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj, } qbool = qobject_to_qbool(qobj); if (!qbool) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "boolean"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "boolean"); return; } @@ -332,8 +391,8 @@ static void qobject_input_type_str(Visitor *v, const char *name, char **obj, } qstr = qobject_to_qstring(qobj); if (!qstr) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "string"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "string"); return; } @@ -363,8 +422,8 @@ static void qobject_input_type_number(Visitor *v, const char *name, double *obj, return; } - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "number"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "number"); } static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj, @@ -392,15 +451,15 @@ static void qobject_input_type_null(Visitor *v, const char *name, Error **errp) } if (qobject_type(qobj) != QTYPE_QNULL) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "null"); + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, + full_name(qiv, name), "null"); } } static void qobject_input_optional(Visitor *v, const char *name, bool *present) { QObjectInputVisitor *qiv = to_qiv(v); - QObject *qobj = qobject_input_get_object(qiv, name, false, NULL); + QObject *qobj = qobject_input_try_get_object(qiv, name, false); if (!qobj) { *present = false; @@ -413,6 +472,7 @@ static void qobject_input_optional(Visitor *v, const char *name, bool *present) static void qobject_input_free(Visitor *v) { QObjectInputVisitor *qiv = to_qiv(v); + while (!QSLIST_EMPTY(&qiv->stack)) { StackObject *tos = QSLIST_FIRST(&qiv->stack); @@ -421,10 +481,13 @@ static void qobject_input_free(Visitor *v) } qobject_decref(qiv->root); + if (qiv->errname) { + g_string_free(qiv->errname, TRUE); + } g_free(qiv); } -Visitor *qobject_input_visitor_new(QObject *obj, bool strict) +Visitor *qobject_input_visitor_new(QObject *obj) { QObjectInputVisitor *v; @@ -437,6 +500,7 @@ Visitor *qobject_input_visitor_new(QObject *obj, bool strict) v->visitor.end_struct = qobject_input_pop; v->visitor.start_list = qobject_input_start_list; v->visitor.next_list = qobject_input_next_list; + v->visitor.check_list = qobject_input_check_list; v->visitor.end_list = qobject_input_pop; v->visitor.start_alternate = qobject_input_start_alternate; v->visitor.type_int64 = qobject_input_type_int64; @@ -448,7 +512,6 @@ Visitor *qobject_input_visitor_new(QObject *obj, bool strict) v->visitor.type_null = qobject_input_type_null; v->visitor.optional = qobject_input_optional; v->visitor.free = qobject_input_free; - v->strict = strict; v->root = obj; qobject_incref(obj); diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c index 8dfa561252..806b01ae3a 100644 --- a/qapi/string-input-visitor.c +++ b/qapi/string-input-visitor.c @@ -170,6 +170,35 @@ static GenericList *next_list(Visitor *v, GenericList *tail, size_t size) return tail->next; } +static void check_list(Visitor *v, Error **errp) +{ + const StringInputVisitor *siv = to_siv(v); + Range *r; + GList *cur_range; + + if (!siv->ranges || !siv->cur_range) { + return; + } + + r = siv->cur_range->data; + if (!r) { + return; + } + + if (!range_contains(r, siv->cur)) { + cur_range = g_list_next(siv->cur_range); + if (!cur_range) { + return; + } + r = cur_range->data; + if (!r) { + return; + } + } + + error_setg(errp, "Range contains too many values"); +} + static void end_list(Visitor *v, void **obj) { StringInputVisitor *siv = to_siv(v); @@ -182,12 +211,6 @@ static void parse_type_int64(Visitor *v, const char *name, int64_t *obj, { StringInputVisitor *siv = to_siv(v); - if (!siv->string) { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "integer"); - return; - } - if (parse_str(siv, name, errp) < 0) { return; } @@ -242,13 +265,7 @@ static void parse_type_size(Visitor *v, const char *name, uint64_t *obj, Error *err = NULL; uint64_t val; - if (siv->string) { - parse_option_size(name, siv->string, &val, &err); - } else { - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "size"); - return; - } + parse_option_size(name, siv->string, &val, &err); if (err) { error_propagate(errp, err); return; @@ -262,19 +279,17 @@ static void parse_type_bool(Visitor *v, const char *name, bool *obj, { StringInputVisitor *siv = to_siv(v); - if (siv->string) { - if (!strcasecmp(siv->string, "on") || - !strcasecmp(siv->string, "yes") || - !strcasecmp(siv->string, "true")) { - *obj = true; - return; - } - if (!strcasecmp(siv->string, "off") || - !strcasecmp(siv->string, "no") || - !strcasecmp(siv->string, "false")) { - *obj = false; - return; - } + if (!strcasecmp(siv->string, "on") || + !strcasecmp(siv->string, "yes") || + !strcasecmp(siv->string, "true")) { + *obj = true; + return; + } + if (!strcasecmp(siv->string, "off") || + !strcasecmp(siv->string, "no") || + !strcasecmp(siv->string, "false")) { + *obj = false; + return; } error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", @@ -285,13 +300,8 @@ static void parse_type_str(Visitor *v, const char *name, char **obj, Error **errp) { StringInputVisitor *siv = to_siv(v); - if (siv->string) { - *obj = g_strdup(siv->string); - } else { - *obj = NULL; - error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", - "string"); - } + + *obj = g_strdup(siv->string); } static void parse_type_number(Visitor *v, const char *name, double *obj, @@ -302,10 +312,8 @@ static void parse_type_number(Visitor *v, const char *name, double *obj, double val; errno = 0; - if (siv->string) { - val = strtod(siv->string, &endp); - } - if (!siv->string || errno || endp == siv->string || *endp) { + val = strtod(siv->string, &endp); + if (errno || endp == siv->string || *endp) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "number"); return; @@ -314,18 +322,6 @@ static void parse_type_number(Visitor *v, const char *name, double *obj, *obj = val; } -static void parse_optional(Visitor *v, const char *name, bool *present) -{ - StringInputVisitor *siv = to_siv(v); - - if (!siv->string) { - *present = false; - return; - } - - *present = true; -} - static void string_input_free(Visitor *v) { StringInputVisitor *siv = to_siv(v); @@ -339,6 +335,7 @@ Visitor *string_input_visitor_new(const char *str) { StringInputVisitor *v; + assert(str); v = g_malloc0(sizeof(*v)); v->visitor.type = VISITOR_INPUT; @@ -350,8 +347,8 @@ Visitor *string_input_visitor_new(const char *str) v->visitor.type_number = parse_type_number; v->visitor.start_list = start_list; v->visitor.next_list = next_list; + v->visitor.check_list = check_list; v->visitor.end_list = end_list; - v->visitor.optional = parse_optional; v->visitor.free = string_input_free; v->string = str; diff --git a/qapi/trace-events b/qapi/trace-events index 9cbb61b2bd..339cacf0ad 100644 --- a/qapi/trace-events +++ b/qapi/trace-events @@ -8,6 +8,7 @@ visit_end_struct(void *v, void *obj) "v=%p obj=%p" visit_start_list(void *v, const char *name, void *obj, size_t size) "v=%p name=%s obj=%p size=%zu" visit_next_list(void *v, void *tail, size_t size) "v=%p tail=%p size=%zu" +visit_check_list(void *v) "v=%p" visit_end_list(void *v, void *obj) "v=%p obj=%p" visit_start_alternate(void *v, const char *name, void *obj, size_t size, bool promote_int) "v=%p name=%s obj=%p size=%zu promote_int=%d" |